gdbstub initial code, v9

2010-09-08 Thread Oleg Nesterov
Changes:

- partly fix the multitracing problems.

  ugdb still can't work with ptrace, ptrace-utrace.c needs
  changes. But at least multiple udgb tracers can coexist,
  more or less.

  But of course they can confuse each other anyway, no matter
  what ugdb does.

- implement memory writes ($M).

- refactor memory reads to avoid the Too late to report the
  error case.

But, Jan. Implementing the memory writes does not mean breakpoints
automatically start to work!

Yes, gdb writes cc, and yes the tracee reports SIGTRAP. But after
that continue does nothing except $c, and the tracee naturally
gets SIGILL. I expected that, since ugdb doesn't even know the code
was changed, gdb should write the original byte back before continue,
but this doesn't happen.

Tried to understand how this works with gdbserver, but failed so far.
Will continue, but any hint is very much appreciated ;)

Oleg.
#include linux/module.h
#include linux/proc_fs.h
#include linux/utrace.h
#include linux/poll.h
#include linux/mm.h
#include linux/regset.h
#include asm/uaccess.h

static int o_remote_debug;
module_param_named(echo, o_remote_debug, bool, 0);

#define BUFFER_SIZE 1024
#define PACKET_SIZE 1024

struct pbuf {
char*cur, *pkt;
charbuf[BUFFER_SIZE];
};

static inline void pb_init(struct pbuf *pb)
{
pb-cur = pb-buf;
pb-pkt = NULL;
}

enum {
U_STOP_IDLE = 0,
U_STOP_PENDING,
U_STOP_SENT,
};

struct ugdb {
struct list_headu_processes;
struct list_headu_stopped;

int u_stop_state;

struct mutexu_mutex;
spinlock_t  u_slock;

struct ugdb_thread
*u_cur_tinfo,
*u_cur_hg,
*u_cur_hc;

wait_queue_head_t   u_wait;

int u_err;

struct pbuf u_pbuf;
charu_cbuf[PACKET_SIZE];
int u_clen;

sigset_tu_sig_ign;

unsigned int
u_no_ack:1,
u_allstop:1;
};

static inline void ugdb_ck_stopped(struct ugdb *ugdb)
{
spin_lock(ugdb-u_slock);
WARN_ON(!list_empty(ugdb-u_stopped) 
ugdb-u_stop_state == U_STOP_IDLE);
WARN_ON(list_empty(ugdb-u_stopped) 
ugdb-u_stop_state == U_STOP_PENDING);
spin_unlock(ugdb-u_slock);
}

static struct ugdb *ugdb_create(void)
{
struct ugdb *ugdb;
int err;

err = -ENODEV;
// XXX: ugly. proc_reg_open() should take care.
if (!try_module_get(THIS_MODULE))
goto out;

err = -ENOMEM;
ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL);
if (!ugdb)
goto put_module;

INIT_LIST_HEAD(ugdb-u_processes);
INIT_LIST_HEAD(ugdb-u_stopped);

mutex_init(ugdb-u_mutex);
spin_lock_init(ugdb-u_slock);

init_waitqueue_head(ugdb-u_wait);

pb_init(ugdb-u_pbuf);

return ugdb;

put_module:
module_put(THIS_MODULE);
out:
return ERR_PTR(err);
}

#define P_DETACHING (1  1)
#define P_ZOMBIE(1  2)

struct ugdb_process {
int p_pid;
int p_state;

struct list_headp_threads;

struct ugdb *p_ugdb;
struct list_headp_processes;
};

static inline bool process_alive(struct ugdb_process *process)
{
return !(process-p_state  P_ZOMBIE);
}

static inline void mark_process_dead(struct ugdb_process *process)
{
process-p_state |= P_ZOMBIE;
}

static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr)
{
struct ugdb_process *process;

process = kzalloc(sizeof(*process), GFP_KERNEL);
if (!process)
return NULL;

process-p_pid = pid_nr;
process-p_ugdb = ugdb;
INIT_LIST_HEAD(process-p_threads);
list_add_tail(process-p_processes, ugdb-u_processes);

return process;
}

#define T_STOP_RUN  0
#define T_STOP_REQ  (1  0)/* requested by gdb */
#define T_STOP_ALL  (1  1)/* vCont;c:pX.-1, for report_clone */
#define T_STOP_ACK  (1  2)/* visible to vStopped */
#define T_STOP_STOPPED  (1  3)/* reported as stopped to gdb */
/* TASK_TRACED + deactivated ? */

#define T_EV_NONE   0
#define T_EV_EXIT   (1  24)
#define T_EV_SIGN   (2  24)

#define T_EV_TYPE(event)((0xff  24)  (event))
#define T_EV_DATA(event)(~(0xff  24)  (event))

struct ugdb_thread {
int t_tid;
int 

Re: gdbstub initial code, v8

2010-09-08 Thread Oleg Nesterov
On 09/06, Frank Ch. Eigler wrote:

 Oleg Nesterov o...@redhat.com writes:

  [...]
  Therefore until you track some ugdb-specific software(*)
  breakpoints ugdb does not need to support Z0 IMO.  I guess ugdb
  will never have to support these: thread-related(?) and tracepoint
  ones.

  Good! I thought ugdb should somehow handle this all transparently
  for gdb. I thought (I don't know why) that writing int 3 from gdb
  side should be avoided in favour of some better method unknown to me.

 Please note that last year's gdbstub prototype used kernel uprobes as
 an optional gdb breakpoint implementation (i.e., a backend for the Z
 packets).  When/if the lkml uprobes patches actually get merged, ugdb
 should also use them.

Yes, agreed.

Oleg.