diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-12-04 20:36:09 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2005-12-04 20:36:09 +0000 |
commit | 855285a7671aca79b64b58cc81aa4838bb4a8860 (patch) | |
tree | 371e92f52b1ea327c2526bb570aa68190e072d37 /gnu/usr.bin | |
parent | 8f92ccf32d35daa299b8702171a6c321de61556a (diff) |
amd64 threads support.
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r-- | gnu/usr.bin/binutils/gdb/amd64obsd-tdep.c | 190 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/gdb/valops.c | 47 |
2 files changed, 197 insertions, 40 deletions
diff --git a/gnu/usr.bin/binutils/gdb/amd64obsd-tdep.c b/gnu/usr.bin/binutils/gdb/amd64obsd-tdep.c index 198c87e4a28..04589538ae2 100644 --- a/gnu/usr.bin/binutils/gdb/amd64obsd-tdep.c +++ b/gnu/usr.bin/binutils/gdb/amd64obsd-tdep.c @@ -22,7 +22,10 @@ #include "defs.h" #include "frame.h" #include "gdbcore.h" +#include "symtab.h" +#include "objfiles.h" #include "osabi.h" +#include "regcache.h" #include "regset.h" #include "target.h" @@ -32,6 +35,7 @@ #include "amd64-tdep.h" #include "i387-tdep.h" #include "solib-svr4.h" +#include "bsd-uthread.h" /* Support for core dumps. */ @@ -40,7 +44,7 @@ amd64obsd_supply_regset (const struct regset *regset, struct regcache *regcache, int regnum, const void *regs, size_t len) { - const struct gdbarch_tdep *tdep = regset->descr; + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE); @@ -61,11 +65,7 @@ amd64obsd_regset_from_core_section (struct gdbarch *gdbarch, && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE) { if (tdep->gregset == NULL) - { - tdep->gregset = XMALLOC (struct regset); - tdep->gregset->descr = tdep; - tdep->gregset->supply_regset = amd64obsd_supply_regset; - } + tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL); return tdep->gregset; } @@ -75,11 +75,16 @@ amd64obsd_regset_from_core_section (struct gdbarch *gdbarch, /* Support for signal handlers. */ +/* Default page size. */ static const int amd64obsd_page_size = 4096; +/* Return whether the frame preceding NEXT_FRAME corresponds to an + OpenBSD sigtramp routine. */ + static int -amd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name) +amd64obsd_sigtramp_p (struct frame_info *next_frame) { + CORE_ADDR pc = frame_pc_unwind (next_frame); CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); const char sigreturn[] = { @@ -87,18 +92,30 @@ amd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name) 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ 0xcd, 0x80 /* int $0x80 */ }; - char *buf; + size_t buflen = (sizeof sigreturn) + 1; + char *name, *buf; - if (name) + /* If the function has a valid symbol name, it isn't a + trampoline. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (name != NULL) + return 0; + + /* If the function lives in a valid section (even without a starting + point) it isn't a trampoline. */ + if (find_pc_section (pc) != NULL) return 0; /* If we can't read the instructions at START_PC, return zero. */ - buf = alloca (sizeof sigreturn); - if (target_read_memory (start_pc + 0x7, buf, sizeof sigreturn)) + buf = alloca ((sizeof sigreturn) + 1); + if (!safe_frame_unwind_memory (next_frame, start_pc + 6, buf, buflen)) return 0; - /* Check for sigreturn(2). */ - if (memcmp (buf, sigreturn, sizeof sigreturn)) + /* Check for sigreturn(2). Depending on how the assembler encoded + the `movq %rsp, %rdi' instruction, the code starts at offset 6 or + 7. */ + if (memcmp (buf, sigreturn, sizeof sigreturn) + && memcpy (buf + 1, sigreturn, sizeof sigreturn)) return 0; return 1; @@ -110,9 +127,25 @@ amd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name) static CORE_ADDR amd64obsd_sigcontext_addr (struct frame_info *next_frame) { + CORE_ADDR pc = frame_pc_unwind (next_frame); + ULONGEST offset = (pc & (amd64obsd_page_size - 1)); + /* The %rsp register points at `struct sigcontext' upon entry of a - signal trampoline. */ - return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); + signal trampoline. The relevant part of the trampoline is + + call *%rax + movq %rsp, %rdi + pushq %rdi + movq $SYS_sigreturn,%rax + int $0x80 + + (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq' + instruction clobbers %rsp, but its value is saved in `%rdi'. */ + + if (offset > 5) + return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM); + else + return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); } /* OpenBSD 3.5 or later. */ @@ -178,6 +211,127 @@ static int amd64obsd_sc_reg_offset[] = 15 * 8 /* %gs */ }; +/* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c. */ +static int amd64obsd_uthread_reg_offset[] = +{ + 19 * 8, /* %rax */ + 16 * 8, /* %rbx */ + 18 * 8, /* %rcx */ + 17 * 8, /* %rdx */ + 14 * 8, /* %rsi */ + 13 * 8, /* %rdi */ + 15 * 8, /* %rbp */ + -1, /* %rsp */ + 12 * 8, /* %r8 ... */ + 11 * 8, + 10 * 8, + 9 * 8, + 8 * 8, + 7 * 8, + 6 * 8, + 5 * 8, /* ... %r15 */ + 20 * 8, /* %rip */ + 4 * 8, /* %eflags */ + 21 * 8, /* %cs */ + -1, /* %ss */ + 3 * 8, /* %ds */ + 2 * 8, /* %es */ + 1 * 8, /* %fs */ + 0 * 8 /* %gs */ +}; + +/* Offset within the thread structure where we can find the saved + stack pointer (%esp). */ +#define AMD64OBSD_UTHREAD_RSP_OFFSET 400 + +static void +amd64obsd_supply_uthread (struct regcache *regcache, + int regnum, CORE_ADDR addr) +{ + CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET; + CORE_ADDR sp = 0; + char buf[8]; + int i; + + gdb_assert (regnum >= -1); + + if (regnum == -1 || regnum == AMD64_RSP_REGNUM) + { + int offset; + + /* Fetch stack pointer from thread structure. */ + sp = read_memory_unsigned_integer (sp_addr, 8); + + /* Adjust the stack pointer such that it looks as if we just + returned from _thread_machdep_switch. */ + offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8; + store_unsigned_integer (buf, 8, sp + offset); + regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf); + } + + for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++) + { + if (amd64obsd_uthread_reg_offset[i] != -1 + && (regnum == -1 || regnum == i)) + { + /* Fetch stack pointer from thread structure (if we didn't + do so already). */ + if (sp == 0) + sp = read_memory_unsigned_integer (sp_addr, 8); + + /* Read the saved register from the stack frame. */ + read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8); + regcache_raw_supply (regcache, i, buf); + } + } +} + +static void +amd64obsd_collect_uthread (const struct regcache *regcache, + int regnum, CORE_ADDR addr) +{ + CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET; + CORE_ADDR sp = 0; + char buf[8]; + int i; + + gdb_assert (regnum >= -1); + + if (regnum == -1 || regnum == AMD64_RSP_REGNUM) + { + int offset; + + /* Calculate the stack pointer (frame pointer) that will be + stored into the thread structure. */ + offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8; + regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf); + sp = extract_unsigned_integer (buf, 8) - offset; + + /* Store the stack pointer. */ + write_memory_unsigned_integer (sp_addr, 8, sp); + + /* The stack pointer was (potentially) modified. Make sure we + build a proper stack frame. */ + regnum = -1; + } + + for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++) + { + if (amd64obsd_uthread_reg_offset[i] != -1 + && (regnum == -1 || regnum == i)) + { + /* Fetch stack pointer from thread structure (if we didn't + calculate it already). */ + if (sp == 0) + sp = read_memory_unsigned_integer (sp_addr, 8); + + /* Write the register into the stack frame. */ + regcache_raw_collect (regcache, i, buf); + write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8); + } + } +} + static void amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -195,11 +349,15 @@ amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->jb_pc_offset = 7 * 8; - set_gdbarch_pc_in_sigtramp (gdbarch, amd64obsd_pc_in_sigtramp); + tdep->sigtramp_p = amd64obsd_sigtramp_p; tdep->sigcontext_addr = amd64obsd_sigcontext_addr; tdep->sc_reg_offset = amd64obsd_sc_reg_offset; tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset); + /* OpenBSD provides a user-level threads implementation. */ + bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread); + bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread); + /* OpenBSD uses SVR4-style shared libraries. */ set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); diff --git a/gnu/usr.bin/binutils/gdb/valops.c b/gnu/usr.bin/binutils/gdb/valops.c index 575c9a335ea..13ad2b5548f 100644 --- a/gnu/usr.bin/binutils/gdb/valops.c +++ b/gnu/usr.bin/binutils/gdb/valops.c @@ -132,37 +132,36 @@ struct value * find_function_in_inferior (const char *name) { struct symbol *sym; + struct minimal_symbol *msymbol; + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0, NULL); if (sym != NULL) { if (SYMBOL_CLASS (sym) != LOC_BLOCK) - { - error ("\"%s\" exists in this program but is not a function.", - name); - } - return value_of_variable (sym, NULL); + error (_("\"%s\" exists in this program but is not a function."), + name); + + if (TYPE_PROTOTYPED (SYMBOL_TYPE (sym))) + return value_of_variable (sym, NULL); } - else + + msymbol = lookup_minimal_symbol (name, NULL, NULL); + if (msymbol != NULL) { - struct minimal_symbol *msymbol = lookup_minimal_symbol (name, NULL, NULL); - if (msymbol != NULL) - { - struct type *type; - CORE_ADDR maddr; - type = lookup_pointer_type (builtin_type_char); - type = lookup_function_type (type); - type = lookup_pointer_type (type); - maddr = SYMBOL_VALUE_ADDRESS (msymbol); - return value_from_pointer (type, maddr); - } - else - { - if (!target_has_execution) - error ("evaluation of this expression requires the target program to be active"); - else - error ("evaluation of this expression requires the program to have a function \"%s\".", name); - } + struct type *type; + CORE_ADDR maddr; + + type = lookup_pointer_type (builtin_type_char); + type = lookup_function_type (type); + type = lookup_pointer_type (type); + maddr = SYMBOL_VALUE_ADDRESS (msymbol); + return value_from_pointer (type, maddr); } + + if (!target_has_execution) + error ("evaluation of this expression requires the target program to be active"); + else + error ("evaluation of this expression requires the program to have a function \"%s\".", name); } /* Allocate NBYTES of space in the inferior using the inferior's malloc |