On 07/16, Roland McGrath wrote:
Note that currently I am not even trying to do something meaningful
with utrace. My only goal for now is to implement the very basic things
like attach/detach/stop/cont/exit correctly from the remote protocol
pov. And I want to do this rightly, then we will discuss utrace
issues.
Ok. I think you might need select to work on the pseudofile for gdb to be
happy. I'm not sure on the situation about that.
Ah, it is easy to implement ugdb_f_ops-poll(). I think. The only problem
is that gdb doesn't try to use select. Perhaps it sees S_IFREG, I didn't
check.
But, it turns out, the multithreading is not trivial, and nasty. Because,
unless I missed something a) remote protocol is very stupid, and b) gdb
is buggy.
I was going to add the threading support today, but I guess I have to
really ask the questions before I can do this. So I am attaching the
yesterday's version.
Changes:
- cleanups/fixes to make cont/^C really work
- handle tracee's exit
Oleg.
#include linux/module.h
#include linux/proc_fs.h
#include linux/utrace.h
#include linux/regset.h
#include linux/mm.h
#include asm/uaccess.h
static int d_echo;
module_param_named(echo, d_echo, bool, 0);
#define PACKET_SIZE 1024
#define BUFFER_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;
}
static inline int pb_size(struct pbuf *pb)
{
return pb-cur - pb-buf;
}
static inline int pb_room(struct pbuf *pb)
{
return pb-buf + BUFFER_SIZE - pb-cur;
}
static inline void pb_putc(struct pbuf *pb, char c)
{
if (WARN_ON(pb-cur = pb-buf + BUFFER_SIZE-1))
return;
*pb-cur++ = c;
}
static void pb_memcpy(struct pbuf *pb, const void *data, int size)
{
if (WARN_ON(size pb_room(pb)))
return;
memcpy(pb-cur, data, size);
pb-cur += size;
}
static inline void pb_puts(struct pbuf *pb, const char *s)
{
pb_memcpy(pb, s, strlen(s));
}
static inline void pb_putb(struct pbuf *pb, unsigned char val)
{
static char hex[] = 0123456789abcdef;
pb_putc(pb, hex[(val 0xf0) 4]);
pb_putc(pb, hex[(val 0x0f) 0]);
}
static void pb_putbs(struct pbuf *pb, const char *data, int size)
{
while (size--)
pb_putb(pb, *data++);
}
static inline void pb_start(struct pbuf *pb)
{
WARN_ON(pb-pkt);
pb_putc(pb, '$');
pb-pkt = pb-cur;
}
static inline void pb_cancel(struct pbuf *pb)
{
if (WARN_ON(!pb-pkt))
return;
pb-cur = pb-pkt - 1;
pb-pkt = NULL;
}
static void pb_end(struct pbuf *pb)
{
unsigned char csm = 0;
char *pkt = pb-pkt;
pb-pkt = NULL;
if (WARN_ON(!pkt))
return;
while (pkt pb-cur) {
WARN_ON(*pkt == '$' || *pkt == '#');
csm += (unsigned char)*pkt++;
}
pb_putc(pb, '#');
pb_putb(pb, csm);
}
static inline void pb_packs(struct pbuf *pb, const char *s)
{
pb_start(pb);
pb_puts(pb, s);
pb_end(pb);
}
static void __attribute__ ((format(printf, 3, 4)))
__pb_format(struct pbuf *pb, bool whole_pkt, const char *fmt, ...)
{
int room = pb_room(pb), size;
va_list args;
if (whole_pkt)
pb_start(pb);
va_start(args, fmt);
size = vsnprintf(pb-cur, room, fmt, args);
va_end(args);
if (WARN_ON(size room))
return;
pb-cur += size;
if (whole_pkt)
pb_end(pb);
}
#define pb_printf(pb, args...) __pb_format((pb), false, args)
#define pb_packf(pb, args...) __pb_format((pb), true, args)
static inline void *pb_alloc_bs(struct pbuf *pb, int size)
{
if (unlikely(pb_room(pb) 2 * size + 4))
return NULL;
return pb-cur + size;
}
static inline void *pb_alloc_tmp(struct pbuf *pb, int size)
{
if (unlikely(pb_room(pb) size))
return NULL;
return pb-cur + BUFFER_SIZE - size;
}
static inline void pb_flush(struct pbuf *pb, int size)
{
int keep = pb_size(pb) - size;
if (keep)
memmove(pb-buf, pb-buf + size, keep);
pb-cur -= size;
}
static int pb_copy_to_user(struct pbuf *pb, char __user *ubuf, int size)
{
int copy = min(size, pb_size(pb));
if (d_echo)
printk(KERN_INFO = %.*s\n, copy, pb-buf);
if (copy_to_user(ubuf, pb-buf, copy))
return -EFAULT;
pb_flush(pb, copy);
return copy;
}
//
// XXX: TODO: gdb is single-thread, no locking currently.
//
#define T printk(KERN_INFO TRACE: %s:%d\n, __FUNCTION__, __LINE__)
enum {
STOP_RUN,
STOP_REQ,