diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 3c13ba6d87..1a0ddf3e01 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,13 @@ +2006-05-09 Nathan Sidwell + + * configure.srv (m68k*-*-uclinux*): New target. + * linux-low.c (linux_create_inferior): Use vfork on mmuless systems. + (linux_resume_one_process): Remove extraneous cast. + (linux_read_offsets): New. + (linux_target_op): Add linux_read_offsets on mmuless systems. + * server.c (handle_query): Add qOffsets logic. + * target.h (struct target_ops): Add read_offsets. + 2006-03-15 Daniel Jacobowitz * linux-mips-low.c: Include and "gdb_proc_service.h". diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index e2d52c09e7..ca41c17947 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -54,6 +54,12 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes ;; + m68*-*-uclinux*) srv_regobj=reg-m68k.o + srv_tgtobj="linux-low.o linux-m68k-low.o" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; mips*-*-linux*) srv_regobj=reg-mips.o srv_tgtobj="linux-low.o linux-mips-low.o" srv_linux_usrregs=yes diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 8518484fa7..08f1d89466 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -140,7 +140,11 @@ linux_create_inferior (char *program, char **allargs) void *new_process; int pid; +#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) + pid = vfork (); +#else pid = fork (); +#endif if (pid < 0) perror_with_name ("fork"); @@ -896,7 +900,7 @@ linux_resume_one_process (struct inferior_list_entry *entry, if (debug_threads && the_low_target.get_pc != NULL) { fprintf (stderr, " "); - (long) (*the_low_target.get_pc) (); + (*the_low_target.get_pc) (); } /* If we have pending signals, consume one unless we are trying to reinsert @@ -1550,6 +1554,51 @@ linux_stopped_data_address (void) return 0; } +#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) +#if defined(__mcoldfire__) +/* These should really be defined in the kernel's ptrace.h header. */ +#define PT_TEXT_ADDR 49*4 +#define PT_DATA_ADDR 50*4 +#define PT_TEXT_END_ADDR 51*4 +#endif + +/* Under uClinux, programs are loaded at non-zero offsets, which we need + to tell gdb about. */ + +static int +linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p) +{ +#if defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) && defined(PT_TEXT_END_ADDR) + unsigned long text, text_end, data; + int pid = get_thread_process (current_inferior)->head.id; + + errno = 0; + + text = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_ADDR, 0); + text_end = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_END_ADDR, 0); + data = ptrace (PTRACE_PEEKUSER, pid, (long)PT_DATA_ADDR, 0); + + if (errno == 0) + { + /* Both text and data offsets produced at compile-time (and so + used by gdb) are relative to the beginning of the program, + with the data segment immediately following the text segment. + However, the actual runtime layout in memory may put the data + somewhere else, so when we send gdb a data base-address, we + use the real data base address and subtract the compile-time + data base-address from it (which is just the length of the + text segment). BSS immediately follows data in both + cases. */ + *text_p = text; + *data_p = data - (text_end - text); + + return 1; + } +#endif + return 0; +} +#endif + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -1569,6 +1618,9 @@ static struct target_ops linux_target_ops = { linux_remove_watchpoint, linux_stopped_by_watchpoint, linux_stopped_data_address, +#if defined(__UCLIBC__) && !defined(__UCLIBC_HAS_MMU__) + linux_read_offsets, +#endif }; static void diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 0722e5996e..51b87642a8 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -129,6 +129,20 @@ handle_query (char *own_buf) } } + if (the_target->read_offsets != NULL + && strcmp ("qOffsets", own_buf) == 0) + { + CORE_ADDR text, data; + + if (the_target->read_offsets (&text, &data)) + sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX", + (long)text, (long)data, (long)data); + else + write_enn (own_buf); + + return; + } + if (the_target->read_auxv != NULL && strncmp ("qPart:auxv:read::", own_buf, 17) == 0) { diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 7f65d3dbe4..6c9a4d7baa 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -156,6 +156,11 @@ struct target_ops CORE_ADDR (*stopped_data_address) (void); + /* Reports the text, data offsets of the executable. This is + needed for uclinux where the executable is relocated during load + time. */ + + int (*read_offsets) (CORE_ADDR *text, CORE_ADDR *data); }; extern struct target_ops *the_target;