gdbstub initial code, v5

2010-08-20 Thread Oleg Nesterov
On 08/19, Oleg Nesterov wrote:

 Next step: handle exit correctly and report W/S. I misunderstood
 what gdbserver does when the main thread exits, it is not stupid
 as I wrongly thought.

Yes, in non-stop mode gdbserver reports W/X;process:PID when the
last thread exits. This makes sense, so does ugdb.

But,

==
All, please ack/nack the behavioral difference!

When the main thread exits, gdbserver still exposes it to gdb as
a running process. It is visible via info threads, you can switch
to this thread, $Tp or $Hx result in OK as if this thread is alive.
gdbserver even pretends that $vCont;x:DEAD_THEAD works, although
this thread obviously can never report something.

I don't think this is really right. This just confuses the user, and
imho this should be considered like the minor bug.

ugdb doesn't do this. If the main thread exits - it exits like any
other thread. I played with gdb, it seems to handle this case fine.

==

Problems:

- I forgot to implement the attach to the thread group
  with the dead leader. Next time.

- The exit code (Wxx) can be wrong in mt-case.

  The problem is, -report_death can't safely access
  -group_exit_code with kernel  2.6.35. This is
  solveable.

Roland, sorry, I ignored your emails for today. It is not easy to me
to switch between ugdb an utrace ;)

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;

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

static inline void ugdb_ck_stopped(struct ugdb *ugdb)
{
// XXX: temporary racy check
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);
}

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)
{
struct ugdb_process *process;

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

process-p_pid = pid;
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 

Re: gdbstub initial code, v4

2010-08-20 Thread Oleg Nesterov
On 08/19, Roland McGrath wrote:

  Note the second attachment, GDBCAT. It is just the simple perl
  script which connects /proc/ugdb to tcp port. It can be used for
  remote debugging via tcp, or with (unpatched) gdb which can't do
  select() on /proc/ugdb.

 bash$ nc -l 2000  /proc/ugdb 

Yes, this works,

  Actually, it is more convenient to use
  it in any case, at least for logging purposes.

 (gdb) set remote debug 1

set debug remote 1. Yes, I tried this. Very, very inconvenient.
In this case the debugging output is mixed with the normal output,

Also: you can't save to file, can't filter packets, can't add
the packet for debugging (not implemented yet).

But yes, it is not strictly necessary, nc should work too.

Oleg.