* linux-i386-low.c (ps_get_thread_area): New.
* linux-x86-64-low.c (ps_get_thread_area): New. * linux-low.c: Include <sys/syscall.h>. (linux_kill_one_process): Don't kill the first thread here. (linux_kill): Kill the first thread here. (kill_lwp): New function. (send_sigstop, linux_send_signal): Use it. * proc-service.c: Clean up #ifdefs. (fpregset_info): Delete. (ps_lgetregs): Update and enable implementation. (ps_lsetregs, ps_lgetfpregs, ps_lsetfpregs): Remove disabled implementations. * remote-utils.c (struct sym_cache, symbol_cache): New. (input_interrupt): Print a clearer message. (async_io_enabled): New variable. (enable_async_io, disable_async_io): Use it. Update comments. (look_up_one_symbol): Use the symbol cache. * thread-db.c (thread_db_look_up_symbols): New function. (thread_db_init): Update comments. Call thread_db_look_up_symbols.
This commit is contained in:
parent
f6de3c42a3
commit
fd5008162e
7 changed files with 241 additions and 101 deletions
|
@ -1,3 +1,25 @@
|
|||
2004-10-16 Daniel Jacobowitz <dan@debian.org>
|
||||
|
||||
* linux-i386-low.c (ps_get_thread_area): New.
|
||||
* linux-x86-64-low.c (ps_get_thread_area): New.
|
||||
* linux-low.c: Include <sys/syscall.h>.
|
||||
(linux_kill_one_process): Don't kill the first thread here.
|
||||
(linux_kill): Kill the first thread here.
|
||||
(kill_lwp): New function.
|
||||
(send_sigstop, linux_send_signal): Use it.
|
||||
* proc-service.c: Clean up #ifdefs.
|
||||
(fpregset_info): Delete.
|
||||
(ps_lgetregs): Update and enable implementation.
|
||||
(ps_lsetregs, ps_lgetfpregs, ps_lsetfpregs): Remove disabled
|
||||
implementations.
|
||||
* remote-utils.c (struct sym_cache, symbol_cache): New.
|
||||
(input_interrupt): Print a clearer message.
|
||||
(async_io_enabled): New variable.
|
||||
(enable_async_io, disable_async_io): Use it. Update comments.
|
||||
(look_up_one_symbol): Use the symbol cache.
|
||||
* thread-db.c (thread_db_look_up_symbols): New function.
|
||||
(thread_db_init): Update comments. Call thread_db_look_up_symbols.
|
||||
|
||||
2004-10-16 Daniel Jacobowitz <dan@debian.org>
|
||||
|
||||
* configure.in: Test for -rdynamic.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* GNU/Linux/i386 specific low level interface, for the remote server for GDB.
|
||||
Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
|
||||
Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
@ -23,10 +23,30 @@
|
|||
#include "linux-low.h"
|
||||
#include "i387-fp.h"
|
||||
|
||||
/* Correct for all GNU/Linux targets (for quite some time). */
|
||||
#define GDB_GREGSET_T elf_gregset_t
|
||||
#define GDB_FPREGSET_T elf_fpregset_t
|
||||
|
||||
#ifndef HAVE_ELF_FPREGSET_T
|
||||
/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
|
||||
via <sys/procfs.h>. */
|
||||
#ifdef HAVE_LINUX_ELF_H
|
||||
#include <linux/elf.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../gdb_proc_service.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#ifdef HAVE_SYS_REG_H
|
||||
#include <sys/reg.h>
|
||||
#endif
|
||||
|
||||
#ifndef PTRACE_GET_THREAD_AREA
|
||||
#define PTRACE_GET_THREAD_AREA 25
|
||||
#endif
|
||||
|
||||
/* This module only supports access to the general purpose registers. */
|
||||
|
||||
#define i386_num_regs 16
|
||||
|
@ -43,6 +63,22 @@ static int i386_regmap[] =
|
|||
DS * 4, ES * 4, FS * 4, GS * 4
|
||||
};
|
||||
|
||||
/* Called by libthread_db. */
|
||||
|
||||
ps_err_e
|
||||
ps_get_thread_area (const struct ps_prochandle *ph,
|
||||
lwpid_t lwpid, int idx, void **base)
|
||||
{
|
||||
unsigned int desc[4];
|
||||
|
||||
if (ptrace (PTRACE_GET_THREAD_AREA, lwpid,
|
||||
(void *) idx, (unsigned long) &desc) < 0)
|
||||
return PS_ERR;
|
||||
|
||||
*(int *)base = desc[1];
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
i386_cannot_store_register (int regno)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
/* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
|
||||
however. This requires changing the ID in place when we go from !using_threads
|
||||
|
@ -223,6 +224,13 @@ linux_kill_one_process (struct inferior_list_entry *entry)
|
|||
struct process_info *process = get_thread_process (thread);
|
||||
int wstat;
|
||||
|
||||
/* We avoid killing the first thread here, because of a Linux kernel (at
|
||||
least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before
|
||||
the children get a chance to be reaped, it will remain a zombie
|
||||
forever. */
|
||||
if (entry == all_threads.head)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
ptrace (PTRACE_KILL, pid_of (process), 0, 0);
|
||||
|
@ -235,7 +243,21 @@ linux_kill_one_process (struct inferior_list_entry *entry)
|
|||
static void
|
||||
linux_kill (void)
|
||||
{
|
||||
struct thread_info *thread = (struct thread_info *) all_threads.head;
|
||||
struct process_info *process = get_thread_process (thread);
|
||||
int wstat;
|
||||
|
||||
for_each_inferior (&all_threads, linux_kill_one_process);
|
||||
|
||||
/* See the comment in linux_kill_one_process. We did not kill the first
|
||||
thread in the list, so do so now. */
|
||||
do
|
||||
{
|
||||
ptrace (PTRACE_KILL, pid_of (process), 0, 0);
|
||||
|
||||
/* Make sure it died. The loop is most likely unnecessary. */
|
||||
wstat = linux_wait_for_event (thread);
|
||||
} while (WIFSTOPPED (wstat));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -709,6 +731,30 @@ retry:
|
|||
return ((unsigned char) WSTOPSIG (w));
|
||||
}
|
||||
|
||||
/* Send a signal to an LWP. For LinuxThreads, kill is enough; however, if
|
||||
thread groups are in use, we need to use tkill. */
|
||||
|
||||
static int
|
||||
kill_lwp (int lwpid, int signo)
|
||||
{
|
||||
static int tkill_failed;
|
||||
|
||||
errno = 0;
|
||||
|
||||
#ifdef SYS_tkill
|
||||
if (!tkill_failed)
|
||||
{
|
||||
int ret = syscall (SYS_tkill, lwpid, signo);
|
||||
if (errno != ENOSYS)
|
||||
return ret;
|
||||
errno = 0;
|
||||
tkill_failed = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return kill (lwpid, signo);
|
||||
}
|
||||
|
||||
static void
|
||||
send_sigstop (struct inferior_list_entry *entry)
|
||||
{
|
||||
|
@ -728,7 +774,7 @@ send_sigstop (struct inferior_list_entry *entry)
|
|||
if (debug_threads)
|
||||
fprintf (stderr, "Sending sigstop to process %d\n", process->head.id);
|
||||
|
||||
kill (process->head.id, SIGSTOP);
|
||||
kill_lwp (process->head.id, SIGSTOP);
|
||||
process->sigstop_sent = 1;
|
||||
}
|
||||
|
||||
|
@ -1388,10 +1434,10 @@ linux_send_signal (int signum)
|
|||
struct process_info *process;
|
||||
|
||||
process = get_thread_process (current_inferior);
|
||||
kill (process->lwpid, signum);
|
||||
kill_lwp (process->lwpid, signum);
|
||||
}
|
||||
else
|
||||
kill (signal_pid, signum);
|
||||
kill_lwp (signal_pid, signum);
|
||||
}
|
||||
|
||||
/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GNU/Linux/x86-64 specific low level interface, for the remote server
|
||||
for GDB.
|
||||
Copyright 2002
|
||||
Copyright 2002, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
@ -24,10 +24,29 @@
|
|||
#include "linux-low.h"
|
||||
#include "i387-fp.h"
|
||||
|
||||
/* Correct for all GNU/Linux targets (for quite some time). */
|
||||
#define GDB_GREGSET_T elf_gregset_t
|
||||
#define GDB_FPREGSET_T elf_fpregset_t
|
||||
|
||||
#ifndef HAVE_ELF_FPREGSET_T
|
||||
/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
|
||||
via <sys/procfs.h>. */
|
||||
#ifdef HAVE_LINUX_ELF_H
|
||||
#include <linux/elf.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../gdb_proc_service.h"
|
||||
|
||||
#include <sys/reg.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
/* This definition comes from prctl.h, but some kernels may not have it. */
|
||||
#ifndef PTRACE_ARCH_PRCTL
|
||||
#define PTRACE_ARCH_PRCTL 30
|
||||
#endif
|
||||
|
||||
static int x86_64_regmap[] = {
|
||||
RAX * 8, RBX * 8, RCX * 8, RDX * 8,
|
||||
RSI * 8, RDI * 8, RBP * 8, RSP * 8,
|
||||
|
@ -39,6 +58,28 @@ static int x86_64_regmap[] = {
|
|||
|
||||
#define X86_64_NUM_GREGS (sizeof(x86_64_regmap)/sizeof(int))
|
||||
|
||||
/* Called by libthread_db. */
|
||||
|
||||
ps_err_e
|
||||
ps_get_thread_area (const struct ps_prochandle *ph,
|
||||
lwpid_t lwpid, int idx, void **base)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case FS:
|
||||
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
|
||||
return PS_OK;
|
||||
break;
|
||||
case GS:
|
||||
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
|
||||
return PS_OK;
|
||||
break;
|
||||
default:
|
||||
return PS_BADADDR;
|
||||
}
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
static void
|
||||
x86_64_fill_gregset (void *buf)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* libthread_db helper functions for the remote server for GDB.
|
||||
Copyright 2002
|
||||
Copyright 2002, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Contributed by MontaVista Software.
|
||||
|
@ -48,11 +48,11 @@ typedef void *gdb_ps_read_buf_t;
|
|||
typedef const void *gdb_ps_write_buf_t;
|
||||
typedef size_t gdb_ps_size_t;
|
||||
|
||||
/* FIXME redo this right */
|
||||
#if 0
|
||||
#ifndef HAVE_LINUX_REGSETS
|
||||
#error HAVE_LINUX_REGSETS required!
|
||||
#else
|
||||
#ifdef HAVE_LINUX_REGSETS
|
||||
#define HAVE_REGSETS
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REGSETS
|
||||
static struct regset_info *
|
||||
gregset_info(void)
|
||||
{
|
||||
|
@ -67,22 +67,6 @@ gregset_info(void)
|
|||
|
||||
return &target_regsets[i];
|
||||
}
|
||||
|
||||
static struct regset_info *
|
||||
fpregset_info(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (target_regsets[i].size != -1)
|
||||
{
|
||||
if (target_regsets[i].type == FP_REGS)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return &target_regsets[i];
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Search for the symbol named NAME within the object named OBJ within
|
||||
|
@ -128,9 +112,8 @@ ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
|
|||
ps_err_e
|
||||
ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
|
||||
{
|
||||
#if 0
|
||||
#ifdef HAVE_REGSETS
|
||||
struct thread_info *reg_inferior, *save_inferior;
|
||||
void *regcache;
|
||||
|
||||
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
|
||||
lwpid);
|
||||
|
@ -140,16 +123,14 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
|
|||
save_inferior = current_inferior;
|
||||
current_inferior = reg_inferior;
|
||||
|
||||
regcache = new_register_cache ();
|
||||
the_target->fetch_registers (0, regcache);
|
||||
gregset_info()->fill_function (gregset, regcache);
|
||||
free_register_cache (regcache);
|
||||
the_target->fetch_registers (0);
|
||||
gregset_info()->fill_function (gregset);
|
||||
|
||||
current_inferior = save_inferior;
|
||||
return PS_OK;
|
||||
#endif
|
||||
/* FIXME */
|
||||
#else
|
||||
return PS_ERR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the general registers of LWP LWPID within the target process PH
|
||||
|
@ -158,27 +139,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
|
|||
ps_err_e
|
||||
ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
|
||||
{
|
||||
#if 0
|
||||
struct thread_info *reg_inferior, *save_inferior;
|
||||
void *regcache;
|
||||
|
||||
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
|
||||
if (reg_inferior == NULL)
|
||||
return PS_ERR;
|
||||
|
||||
save_inferior = current_inferior;
|
||||
current_inferior = reg_inferior;
|
||||
|
||||
regcache = new_register_cache ();
|
||||
gregset_info()->store_function (gregset, regcache);
|
||||
the_target->store_registers (0, regcache);
|
||||
free_register_cache (regcache);
|
||||
|
||||
current_inferior = save_inferior;
|
||||
|
||||
return PS_OK;
|
||||
#endif
|
||||
/* FIXME */
|
||||
/* Unneeded. */
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
|
@ -189,27 +150,7 @@ ps_err_e
|
|||
ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
|
||||
gdb_prfpregset_t *fpregset)
|
||||
{
|
||||
#if 0
|
||||
struct thread_info *reg_inferior, *save_inferior;
|
||||
void *regcache;
|
||||
|
||||
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
|
||||
if (reg_inferior == NULL)
|
||||
return PS_ERR;
|
||||
|
||||
save_inferior = current_inferior;
|
||||
current_inferior = reg_inferior;
|
||||
|
||||
regcache = new_register_cache ();
|
||||
the_target->fetch_registers (0, regcache);
|
||||
fpregset_info()->fill_function (fpregset, regcache);
|
||||
free_register_cache (regcache);
|
||||
|
||||
current_inferior = save_inferior;
|
||||
|
||||
return PS_OK;
|
||||
#endif
|
||||
/* FIXME */
|
||||
/* Unneeded. */
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
|
@ -220,27 +161,7 @@ ps_err_e
|
|||
ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
|
||||
const gdb_prfpregset_t *fpregset)
|
||||
{
|
||||
#if 0
|
||||
struct thread_info *reg_inferior, *save_inferior;
|
||||
void *regcache;
|
||||
|
||||
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
|
||||
if (reg_inferior == NULL)
|
||||
return PS_ERR;
|
||||
|
||||
save_inferior = current_inferior;
|
||||
current_inferior = reg_inferior;
|
||||
|
||||
regcache = new_register_cache ();
|
||||
fpregset_info()->store_function (fpregset, regcache);
|
||||
the_target->store_registers (0, regcache);
|
||||
free_register_cache (regcache);
|
||||
|
||||
current_inferior = save_inferior;
|
||||
|
||||
return PS_OK;
|
||||
#endif
|
||||
/* FIXME */
|
||||
/* Unneeded. */
|
||||
return PS_ERR;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,17 @@
|
|||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* A cache entry for a successfully looked-up symbol. */
|
||||
struct sym_cache
|
||||
{
|
||||
const char *name;
|
||||
CORE_ADDR addr;
|
||||
struct sym_cache *next;
|
||||
};
|
||||
|
||||
/* The symbol cache. */
|
||||
static struct sym_cache *symbol_cache;
|
||||
|
||||
int remote_debug = 0;
|
||||
struct ui_file *gdb_stdlog;
|
||||
|
||||
|
@ -353,13 +364,14 @@ input_interrupt (int unused)
|
|||
if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0)
|
||||
{
|
||||
int cc;
|
||||
char c;
|
||||
char c = 0;
|
||||
|
||||
cc = read (remote_desc, &c, 1);
|
||||
|
||||
if (cc != 1 || c != '\003')
|
||||
{
|
||||
fprintf (stderr, "input_interrupt, cc = %d c = %d\n", cc, c);
|
||||
fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
|
||||
cc, c, c);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -385,16 +397,33 @@ unblock_async_io (void)
|
|||
sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
|
||||
}
|
||||
|
||||
/* Asynchronous I/O support. SIGIO must be enabled when waiting, in order to
|
||||
accept Control-C from the client, and must be disabled when talking to
|
||||
the client. */
|
||||
|
||||
/* Current state of asynchronous I/O. */
|
||||
static int async_io_enabled;
|
||||
|
||||
/* Enable asynchronous I/O. */
|
||||
void
|
||||
enable_async_io (void)
|
||||
{
|
||||
if (async_io_enabled)
|
||||
return;
|
||||
|
||||
signal (SIGIO, input_interrupt);
|
||||
async_io_enabled = 1;
|
||||
}
|
||||
|
||||
/* Disable asynchronous I/O. */
|
||||
void
|
||||
disable_async_io (void)
|
||||
{
|
||||
if (!async_io_enabled)
|
||||
return;
|
||||
|
||||
signal (SIGIO, SIG_IGN);
|
||||
async_io_enabled = 0;
|
||||
}
|
||||
|
||||
/* Returns next char from remote GDB. -1 if error. */
|
||||
|
@ -692,11 +721,23 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
|
|||
convert_ascii_to_int (&from[i++], to, *len_ptr);
|
||||
}
|
||||
|
||||
/* Ask GDB for the address of NAME, and return it in ADDRP if found.
|
||||
Returns 1 if the symbol is found, 0 if it is not, -1 on error. */
|
||||
|
||||
int
|
||||
look_up_one_symbol (const char *name, CORE_ADDR *addrp)
|
||||
{
|
||||
char own_buf[266], *p, *q;
|
||||
int len;
|
||||
struct sym_cache *sym;
|
||||
|
||||
/* Check the cache first. */
|
||||
for (sym = symbol_cache; sym; sym = sym->next)
|
||||
if (strcmp (name, sym->name) == 0)
|
||||
{
|
||||
*addrp = sym->addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Send the request. */
|
||||
strcpy (own_buf, "qSymbol:");
|
||||
|
@ -731,6 +772,13 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
|
|||
return 0;
|
||||
|
||||
decode_address (addrp, p, q - p);
|
||||
|
||||
/* Save the symbol in our cache. */
|
||||
sym = malloc (sizeof (*sym));
|
||||
sym->name = strdup (name);
|
||||
sym->addr = *addrp;
|
||||
sym->next = symbol_cache;
|
||||
symbol_cache = sym;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -312,11 +312,36 @@ thread_db_find_new_threads (void)
|
|||
error ("Cannot find new threads: %s", thread_db_err_str (err));
|
||||
}
|
||||
|
||||
/* Cache all future symbols that thread_db might request. We can not
|
||||
request symbols at arbitrary states in the remote protocol, only
|
||||
when the client tells us that new symbols are available. So when
|
||||
we load the thread library, make sure to check the entire list. */
|
||||
|
||||
static void
|
||||
thread_db_look_up_symbols (void)
|
||||
{
|
||||
const char **sym_list = td_symbol_list ();
|
||||
CORE_ADDR unused;
|
||||
|
||||
for (sym_list = td_symbol_list (); *sym_list; sym_list++)
|
||||
look_up_one_symbol (*sym_list, &unused);
|
||||
}
|
||||
|
||||
int
|
||||
thread_db_init ()
|
||||
{
|
||||
int err;
|
||||
|
||||
/* FIXME drow/2004-10-16: This is the "overall process ID", which
|
||||
GNU/Linux calls tgid, "thread group ID". When we support
|
||||
attaching to threads, the original thread may not be the correct
|
||||
thread. We would have to get the process ID from /proc for NPTL.
|
||||
For LinuxThreads we could do something similar: follow the chain
|
||||
of parent processes until we find the highest one we're attached
|
||||
to, and use its tgid.
|
||||
|
||||
This isn't the only place in gdbserver that assumes that the first
|
||||
process in the list is the thread group leader. */
|
||||
proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
|
||||
|
||||
err = td_ta_new (&proc_handle, &thread_agent);
|
||||
|
@ -332,6 +357,7 @@ thread_db_init ()
|
|||
if (thread_db_enable_reporting () == 0)
|
||||
return 0;
|
||||
thread_db_find_new_threads ();
|
||||
thread_db_look_up_symbols ();
|
||||
return 1;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue