Re: problems with v3 (Was: gdbstub initial code, v3)

2010-08-13 Thread Roland McGrath
 I seem to understand the problem(s). I am a bit surprized. Basically
 I have the questions about almost every utrace_ function. I'll try
 to recheck and summarize my concerns tomorrow with a fresh head, I
 hope I missed something.

Ok.  That stuff about pure kernel implementation issues doesn't need
to go to the archer list and Tom, only to utrace-devel.


Thanks,
Roland



Re: gdbstub initial code, v3

2010-08-12 Thread Frank Ch. Eigler

oleg wrote:

 [...]
   - It doesn't support all-stop mode.
 Please tell me if this is needed. I hope not, this needs
 a lot of nasty complications :/
 [...]

As opposed to non-stop mode?  I'm pretty sure all-stop will be needed
as that is the common  default gdb usage model.


- FChE



problems with v3 (Was: gdbstub initial code, v3)

2010-08-12 Thread Oleg Nesterov
On 08/11, Tom Tromey wrote:

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

 Oleg So, the patch below fixes the problem, and gdb + /proc/ugdb seems
 Oleg to work.

 Oleg Indeed, gdb sees that this fd is not pipe/tcp and uses the hardwire
 Oleg serial_ops, but hardwire_readchar() doesn't play well with select().

 Oleg Please teach gdb to use poll/select ?

 I looked at this a little bit.  It seems to me that the hardwire stuff
 is for talking to ttys, and we instead want gdb to be using the pipe code.

I didn't verify this, but I don't think so. Please look at pipe_open().
Perhaps it makes sense to serial_add_interface(ugdb), I dunno.


OK. I was going to add some cleanups and send the new version today.
But after some testing (without gdb) I hit the kernel crashes. This
makes me think that probably something is wrong ;)

As usual, I can't blame my code. I am still investigating, the crash
is not easy to reproduce, but so far I _suspect_ the problems in utrace
code. At least utrace_barrier()-signal_pending() is definitely not
right.

Will continue tomorrow.

Oleg.



Re: gdbstub initial code, v3

2010-08-12 Thread Roland McGrath
 Indeed, gdb sees that this fd is not pipe/tcp and uses the hardwire
 serial_ops, but hardwire_readchar() doesn't play well with select().
 
 Please teach gdb to use poll/select ?

If it makes it easier, could use:

bash$ nc -l -U /tmp/socket  /proc/ugdb 
(gdb) target remote |nc -U /tmp/socket

for the moment.  Silly of course, but just not to be blocked on cleaning up
gdb's serial-device handling to be more nicely nonblocking.


Thanks,
Roland



gdbstub initial code, v3

2010-08-11 Thread Oleg Nesterov
Please see the attached ugdb.c.

It supports multiple inferiors/threads, stop/cont, clone/exit.
It doesn't report W/X when the process exits yet, but this is
only because I'd like to discuss the current problems with the
exited leader first, then implement this as a separate change.

Any code review is very much appreciated.

Problems:

- It doesn't support all-stop mode.

  Please tell me if this is needed. I hope not, this needs
  a lot of nasty complications :/

- We should discuss utrace limitations: UTRACE_RESUME
  races/problems, utrace_prepare_examine() issues.

- I just finished this code, and it doesn't work with gdb ;)

  I will investigate tomorrow, but I am almost sure gdb is
  wrong.

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)

struct ugdb_process {
int p_pid;
int p_state;

struct list_headp_threads;

struct ugdb *p_ugdb;
struct list_headp_processes;
};

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  3)/* reported as stopped to gdb */
/* TASK_TRACED + deactivated ? */

struct ugdb_thread {
int t_tid;
int t_stop_state;

struct ugdb *t_ugdb;
struct ugdb_process *t_process;

struct list_headt_threads;
struct list_headt_stopped;

struct pid  *t_spid;

// create/attach border
struct utrace_engine*t_engine;
};

static inline struct task_struct *thread_to_task(struct ugdb_thread *thread)
{
return pid_task(thread-t_spid, PIDTYPE_PID);
}

static struct ugdb_thread *ugdb_create_thread(struct ugdb_process *process,
struct pid *spid)
{
struct ugdb_thread *thread;

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

thread-t_tid =