X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fi386-linux-nat.c;h=94d9ab393bd16a0967e6924f14d821188d8131dc;hb=56059d66d7b85c52a1f4021c0124d773da59752f;hp=49149830e8495b56b01ac77a43d397699e874bf2;hpb=756ed20662a5a24a1e20d6b73ecd7aa5527ecdb9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 49149830e8..94d9ab393b 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -1,5 +1,5 @@ /* Native-dependent code for Linux/x86. - Copyright 1999, 2000 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -21,12 +21,9 @@ #include "defs.h" #include "inferior.h" #include "gdbcore.h" +#include "regcache.h" -/* For i386_linux_skip_solib_resolver. */ -#include "symtab.h" -#include "symfile.h" -#include "objfiles.h" - +#include "gdb_assert.h" #include #include #include @@ -35,6 +32,26 @@ #include #endif +#ifdef HAVE_SYS_DEBUGREG_H +#include +#endif + +#ifndef DR_FIRSTADDR +#define DR_FIRSTADDR 0 +#endif + +#ifndef DR_LASTADDR +#define DR_LASTADDR 3 +#endif + +#ifndef DR_STATUS +#define DR_STATUS 6 +#endif + +#ifndef DR_CONTROL +#define DR_CONTROL 7 +#endif + /* Prototypes for supply_gregset etc. */ #include "gregset.h" @@ -44,17 +61,6 @@ /* Prototypes for local functions. */ static void dummy_sse_values (void); -/* On Linux, threads are implemented as pseudo-processes, in which - case we may be tracing more than one process at a time. In that - case, inferior_pid will contain the main process ID and the - individual thread (process) ID mashed together. These macros are - used to separate them out. These definitions should be overridden - if thread support is included. */ - -#if !defined (PIDGET) /* Default definition for PIDGET/TIDGET. */ -#define PIDGET(PID) PID -#define TIDGET(PID) 0 -#endif /* The register sets used in Linux ELF core-dumps are identical to the @@ -114,6 +120,26 @@ int have_ptrace_getfpxregs = ; +/* Support for the user struct. */ + +/* Return the address of register REGNUM. BLOCKEND is the value of + u.u_ar0, which should point to the registers. */ + +CORE_ADDR +register_u_addr (CORE_ADDR blockend, int regnum) +{ + return (blockend + 4 * regmap[regnum]); +} + +/* Return the size of the user struct. */ + +int +kernel_u_size (void) +{ + return (sizeof (struct user)); +} + + /* Fetching registers directly from the U area, one at a time. */ /* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'. @@ -138,9 +164,7 @@ int have_ptrace_getfpxregs = #endif /* Registers we shouldn't try to fetch. */ -#if !defined (CANNOT_FETCH_REGISTER) -#define CANNOT_FETCH_REGISTER(regno) 0 -#endif +#define OLD_CANNOT_FETCH_REGISTER(regno) ((regno) >= NUM_GREGS) /* Fetch one register. */ @@ -155,7 +179,7 @@ fetch_register (int regno) char buf[MAX_REGISTER_RAW_SIZE]; int tid; - if (CANNOT_FETCH_REGISTER (regno)) + if (OLD_CANNOT_FETCH_REGISTER (regno)) { memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ supply_register (regno, buf); @@ -163,8 +187,8 @@ fetch_register (int regno) } /* Overload thread id onto process id */ - if ((tid = TIDGET (inferior_pid)) == 0) - tid = inferior_pid; /* no thread id, just use process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ offset = U_REGS_OFFSET; @@ -198,7 +222,7 @@ old_fetch_inferior_registers (int regno) } else { - for (regno = 0; regno < ARCH_NUM_REGS; regno++) + for (regno = 0; regno < NUM_REGS; regno++) { fetch_register (regno); } @@ -206,9 +230,7 @@ old_fetch_inferior_registers (int regno) } /* Registers we shouldn't try to store. */ -#if !defined (CANNOT_STORE_REGISTER) -#define CANNOT_STORE_REGISTER(regno) 0 -#endif +#define OLD_CANNOT_STORE_REGISTER(regno) ((regno) >= NUM_GREGS) /* Store one register. */ @@ -222,14 +244,14 @@ store_register (int regno) unsigned int offset; /* Offset of registers within the u area. */ int tid; - if (CANNOT_STORE_REGISTER (regno)) + if (OLD_CANNOT_STORE_REGISTER (regno)) { return; } /* Overload thread id onto process id */ - if ((tid = TIDGET (inferior_pid)) == 0) - tid = inferior_pid; /* no thread id, just use process id */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* no thread id, just use process id */ offset = U_REGS_OFFSET; @@ -262,7 +284,7 @@ old_store_inferior_registers (int regno) } else { - for (regno = 0; regno < ARCH_NUM_REGS; regno++) + for (regno = 0; regno < NUM_REGS; regno++) { store_register (regno); } @@ -273,7 +295,7 @@ old_store_inferior_registers (int regno) /* Transfering the general-purpose registers between GDB, inferiors and core files. */ -/* Fill GDB's register array with the genereal-purpose register values +/* Fill GDB's register array with the general-purpose register values in *GREGSETP. */ void @@ -478,7 +500,15 @@ store_fpxregs (int tid, int regno) return 0; if (ptrace (PTRACE_GETFPXREGS, tid, 0, &fpxregs) == -1) - perror_with_name ("Couldn't read floating-point and SSE registers"); + { + if (errno == EIO) + { + have_ptrace_getfpxregs = 0; + return 0; + } + + perror_with_name ("Couldn't read floating-point and SSE registers"); + } fill_fpxregset (&fpxregs, regno); @@ -518,6 +548,26 @@ static void dummy_sse_values (void) {} /* Transferring arbitrary registers between GDB and inferior. */ +/* Check if register REGNO in the child process is accessible. + If we are accessing registers directly via the U area, only the + general-purpose registers are available. + All registers should be accessible if we have GETREGS support. */ + +int +cannot_fetch_register (int regno) +{ + if (! have_ptrace_getregs) + return OLD_CANNOT_FETCH_REGISTER (regno); + return 0; +} +int +cannot_store_register (int regno) +{ + if (! have_ptrace_getregs) + return OLD_CANNOT_STORE_REGISTER (regno); + return 0; +} + /* Fetch register REGNO from the child process. If REGNO is -1, do this for all registers (including the floating point and SSE registers). */ @@ -536,8 +586,8 @@ fetch_inferior_registers (int regno) } /* Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_pid)) == 0) - tid = inferior_pid; /* Not a threaded program. */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ /* Use the PTRACE_GETFPXREGS request whenever possible, since it transfers more registers in one system call, and we'll cache the @@ -581,7 +631,8 @@ fetch_inferior_registers (int regno) return; } - internal_error ("Got request for bad register number %d.", regno); + internal_error (__FILE__, __LINE__, + "Got request for bad register number %d.", regno); } /* Store register REGNO back into the child process. If REGNO is -1, @@ -601,8 +652,8 @@ store_inferior_registers (int regno) } /* Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_pid)) == 0) - tid = inferior_pid; /* Not a threaded program. */ + if ((tid = TIDGET (inferior_ptid)) == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ /* Use the PTRACE_SETFPXREGS requests whenever possible, since it transfers more registers in one system call. But remember that @@ -634,7 +685,83 @@ store_inferior_registers (int regno) return; } - internal_error ("Got request to store bad register number %d.", regno); + internal_error (__FILE__, __LINE__, + "Got request to store bad register number %d.", regno); +} + + +static unsigned long +i386_linux_dr_get (int regnum) +{ + int tid; + unsigned long value; + + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); + + /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the + ptrace call fails breaks debugging remote targets. The correct + way to fix this is to add the hardware breakpoint and watchpoint + stuff to the target vectore. For now, just return zero if the + ptrace call fails. */ + errno = 0; + value = ptrace (PT_READ_U, tid, + offsetof (struct user, u_debugreg[regnum]), 0); + if (errno != 0) +#if 0 + perror_with_name ("Couldn't read debug register"); +#else + return 0; +#endif + + return value; +} + +static void +i386_linux_dr_set (int regnum, unsigned long value) +{ + int tid; + + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); + + errno = 0; + ptrace (PT_WRITE_U, tid, + offsetof (struct user, u_debugreg[regnum]), value); + if (errno != 0) + perror_with_name ("Couldn't write debug register"); +} + +void +i386_linux_dr_set_control (unsigned long control) +{ + i386_linux_dr_set (DR_CONTROL, control); +} + +void +i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) +{ + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + i386_linux_dr_set (DR_FIRSTADDR + regnum, addr); +} + +void +i386_linux_dr_reset_addr (int regnum) +{ + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L); +} + +unsigned long +i386_linux_dr_get_status (void) +{ + return i386_linux_dr_get (DR_STATUS); } @@ -741,19 +868,21 @@ static const unsigned char linux_syscall[] = { 0xcd, 0x80 }; If SIGNAL is nonzero, give it that signal. */ void -child_resume (int pid, int step, enum target_signal signal) +child_resume (ptid_t ptid, int step, enum target_signal signal) { + int pid = PIDGET (ptid); + int request = PTRACE_CONT; if (pid == -1) /* Resume all threads. */ /* I think this only gets used in the non-threaded case, where "resume - all threads" and "resume inferior_pid" are the same. */ - pid = inferior_pid; + all threads" and "resume inferior_ptid" are the same. */ + pid = PIDGET (inferior_ptid); if (step) { - CORE_ADDR pc = read_pc_pid (pid); + CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid)); unsigned char buf[LINUX_SYSCALL_LEN]; request = PTRACE_SINGLESTEP; @@ -770,7 +899,8 @@ child_resume (int pid, int step, enum target_signal signal) if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0 && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0) { - int syscall = read_register_pid (LINUX_SYSCALL_REGNUM, pid); + int syscall = read_register_pid (LINUX_SYSCALL_REGNUM, + pid_to_ptid (pid)); /* Then check the system call number. */ if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn) @@ -778,7 +908,7 @@ child_resume (int pid, int step, enum target_signal signal) CORE_ADDR sp = read_register (SP_REGNUM); CORE_ADDR addr = sp; unsigned long int eflags; - + if (syscall == SYS_rt_sigreturn) addr = read_memory_integer (sp + 8, 4) + 20; @@ -797,98 +927,6 @@ child_resume (int pid, int step, enum target_signal signal) } -/* Calling functions in shared libraries. */ -/* FIXME: kettenis/2000-03-05: Doesn't this belong in a - target-dependent file? The function - `i386_linux_skip_solib_resolver' is mentioned in - `config/i386/tm-linux.h'. */ - -/* Find the minimal symbol named NAME, and return both the minsym - struct and its objfile. This probably ought to be in minsym.c, but - everything there is trying to deal with things like C++ and - SOFUN_ADDRESS_MAYBE_TURQUOISE, ... Since this is so simple, it may - be considered too special-purpose for general consumption. */ - -static struct minimal_symbol * -find_minsym_and_objfile (char *name, struct objfile **objfile_p) -{ - struct objfile *objfile; - - ALL_OBJFILES (objfile) - { - struct minimal_symbol *msym; - - ALL_OBJFILE_MSYMBOLS (objfile, msym) - { - if (SYMBOL_NAME (msym) - && STREQ (SYMBOL_NAME (msym), name)) - { - *objfile_p = objfile; - return msym; - } - } - } - - return 0; -} - -static CORE_ADDR -skip_hurd_resolver (CORE_ADDR pc) -{ - /* The HURD dynamic linker is part of the GNU C library, so many - GNU/Linux distributions use it. (All ELF versions, as far as I - know.) An unresolved PLT entry points to "_dl_runtime_resolve", - which calls "fixup" to patch the PLT, and then passes control to - the function. - - We look for the symbol `_dl_runtime_resolve', and find `fixup' in - the same objfile. If we are at the entry point of `fixup', then - we set a breakpoint at the return address (at the top of the - stack), and continue. - - It's kind of gross to do all these checks every time we're - called, since they don't change once the executable has gotten - started. But this is only a temporary hack --- upcoming versions - of Linux will provide a portable, efficient interface for - debugging programs that use shared libraries. */ - - struct objfile *objfile; - struct minimal_symbol *resolver - = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile); - - if (resolver) - { - struct minimal_symbol *fixup - = lookup_minimal_symbol ("fixup", 0, objfile); - - if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc) - return (SAVED_PC_AFTER_CALL (get_current_frame ())); - } - - return 0; -} - -/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c. - This function: - 1) decides whether a PLT has sent us into the linker to resolve - a function reference, and - 2) if so, tells us where to set a temporary breakpoint that will - trigger when the dynamic linker is done. */ - -CORE_ADDR -i386_linux_skip_solib_resolver (CORE_ADDR pc) -{ - CORE_ADDR result; - - /* Plug in functions for other kinds of resolvers here. */ - result = skip_hurd_resolver (pc); - if (result) - return result; - - return 0; -} - - /* Register that we are able to handle Linux ELF core file formats. */ static struct core_fns linux_elf_core_fns =