Re: gdbstub initial code, v5

2010-08-24 Thread Oleg Nesterov
On 08/23, Oleg Nesterov wrote:

 However. I spent all Monday trying to resolve the new bug, and
 so far I do not understand what happens. Extremely hard to reproduce,
 and the kernel just hangs silently, without any message.
 So far I suspect the proble in utrace.c, but this time I am not sure.

Solved. This was scheduler bug fixed in 2.6.35, but I used 2.6.34.
This is really funny. This bug (PF_STARTING lockup) was found and
fixed by me  Peter.

Oh. But I hit yet another problem, BUG_ON() in __utrace_engine_release().
Again, it is not reproducible, I saw it only once in dmesg and I do
not even know for sure what I was doing.

I'll contiue tomorrow, but if I won't be able to quickly resolve
this problem I am going to ignore it for now. This time I think
ugdb is wrong.

Oleg.



Re: gdbstub initial code, v5

2010-08-24 Thread Roland McGrath
 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.

This is sort of consistent with the kernel treatment.  The main thread
stays around as a zombie, acting as a moniker for the whole process.  But
indeed that is not actually useful for any thread-granularity control or
information (well, there is the dead thread's usage stats, but that's all).

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

I tend to agree, but don't think it's a big issue either way, really.

 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.

Sounds good to me!

   - 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.

Don't even worry about it.  If there is something trivial to do that makes
it better for earlier kernels, then go ahead.  But if the easy thing to do
gives correct results on =2.6.35 and racily wrong or random results on
older kernels, then we can just live with that.


Thanks,
Roland



Re: gdbstub initial code, v5

2010-08-23 Thread Oleg Nesterov
Just a small report to explain what I am doing...

On 08/20, Oleg Nesterov wrote:

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

Almost done, but we should avoid the races with exec somehow.
But this is minor.

I tried to test this code as much as I can. Again, I do not use
gdb at all, I am using the scripts which try to really stress ugdb.

Found 2 bugs in ugdb.ko, the second one is not nice but at least
I have the temporary fix.

However. I spent all Monday trying to resolve the new bug, and
so far I do not understand what happens. Extremely hard to reproduce,
and the kernel just hangs silently, without any message.
So far I suspect the proble in utrace.c, but this time I am not sure.

Will continue tomorrow...

Oleg.



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