From 2bbe3cc10734408c859d08bae15039c6e7ccecf9 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 3 Jul 2007 15:58:42 +0000 Subject: [PATCH] 2007-07-03 Paul Gilliam Thiago Bauermann Joseph S. Myers Daniel Jacobowitz gdb/ * remote.c (remote_check_symbols): Use gdbarch_convert_from_func_ptr_addr. * infcall.c (find_function_addr): Handle function descriptors without debugging information. * ppc-linux-tdep.c (ppc_linux_convert_from_func_ptr_addr): Renamed from ppc64_linux_convert_from_func_ptr_addr. Handle -msecure-plt. (ppc_linux_init_abi): Always set convert_from_func_ptr_addr. * solib-svr4.c (solib_break_names): Remove "._dl_debug_state". (bfd_lookup_symbol): Do not take a SECT_FLAGS argument. Always allow SEC_CODE and SEC_DATA. (enable_break): Update calls. Pass current_target to solib_add. Use gdbarch_convert_from_func_ptr_addr. gdb/gdbserver/ * remote-utils.c (look_up_one_symbol): Handle 'm' packets. --- gdb/ChangeLog | 18 ++++++++ gdb/gdbserver/ChangeLog | 4 ++ gdb/gdbserver/remote-utils.c | 33 ++++++++++++--- gdb/infcall.c | 20 ++++++++- gdb/ppc-linux-tdep.c | 82 +++++++++++++++++++++++++----------- gdb/remote.c | 16 +++++-- gdb/solib-svr4.c | 54 ++++++++++-------------- 7 files changed, 159 insertions(+), 68 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 069c376254e..da6eb144815 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2007-07-03 Paul Gilliam + Thiago Bauermann + Joseph S. Myers + Daniel Jacobowitz + + * remote.c (remote_check_symbols): Use + gdbarch_convert_from_func_ptr_addr. + * infcall.c (find_function_addr): Handle function descriptors + without debugging information. + * ppc-linux-tdep.c (ppc_linux_convert_from_func_ptr_addr): Renamed + from ppc64_linux_convert_from_func_ptr_addr. Handle -msecure-plt. + (ppc_linux_init_abi): Always set convert_from_func_ptr_addr. + * solib-svr4.c (solib_break_names): Remove "._dl_debug_state". + (bfd_lookup_symbol): Do not take a SECT_FLAGS argument. Always + allow SEC_CODE and SEC_DATA. + (enable_break): Update calls. Pass current_target to solib_add. + Use gdbarch_convert_from_func_ptr_addr. + 2007-07-03 Ilko Iliev Daniel Jacobowitz diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 7b78653323a..c5a7b4a72c5 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,7 @@ +2007-07-03 Daniel Jacobowitz + + * remote-utils.c (look_up_one_symbol): Handle 'm' packets. + 2007-07-02 Daniel Jacobowitz * inferiors.c (change_inferior_id): Add comment. diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 95591487ecd..9c407aaac6c 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1109,15 +1109,34 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp) if (len < 0) return -1; + /* We ought to handle pretty much any packet at this point while we + wait for the qSymbol "response". That requires re-entering the + main loop. For now, this is an adequate approximation; allow + GDB to read from memory while it figures out the address of the + symbol. */ + while (own_buf[0] == 'm') + { + CORE_ADDR mem_addr; + unsigned char *mem_buf; + unsigned int mem_len; + + decode_m_packet (&own_buf[1], &mem_addr, &mem_len); + mem_buf = malloc (mem_len); + if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0) + convert_int_to_ascii (mem_buf, own_buf, mem_len); + else + write_enn (own_buf); + free (mem_buf); + if (putpkt (own_buf) < 0) + return -1; + len = getpkt (own_buf); + if (len < 0) + return -1; + } + if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0) { - /* Malformed response. */ - if (remote_debug) - { - fprintf (stderr, "Malformed response to qSymbol, ignoring.\n"); - fflush (stderr); - } - + warning ("Malformed response to qSymbol, ignoring: %s\n", own_buf); return -1; } diff --git a/gdb/infcall.c b/gdb/infcall.c index 537596984c1..e98b566d2ff 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -222,8 +222,24 @@ find_function_addr (struct value *function, struct type **retval_type) if (TYPE_LENGTH (ftype) == 1) funaddr = value_as_address (value_addr (function)); else - /* Handle integer used as address of a function. */ - funaddr = (CORE_ADDR) value_as_long (function); + { + /* Handle function descriptors lacking debug info. */ + int found_descriptor = 0; + if (VALUE_LVAL (function) == lval_memory) + { + CORE_ADDR nfunaddr; + funaddr = value_as_address (value_addr (function)); + nfunaddr = funaddr; + funaddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, + funaddr, + ¤t_target); + if (funaddr != nfunaddr) + found_descriptor = 1; + } + if (!found_descriptor) + /* Handle integer used as address of a function. */ + funaddr = (CORE_ADDR) value_as_long (function); + } value_type = builtin_type_int; } diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 5cf0f236cf8..f5c39ff98cd 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -591,39 +591,73 @@ ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) } -/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG) on PPC64 +/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC GNU/Linux. Usually a function pointer's representation is simply the address - of the function. On GNU/Linux on the 64-bit PowerPC however, a - function pointer is represented by a pointer to a TOC entry. This - TOC entry contains three words, the first word is the address of - the function, the second word is the TOC pointer (r2), and the - third word is the static chain value. Throughout GDB it is - currently assumed that a function pointer contains the address of - the function, which is not easy to fix. In addition, the + of the function. On GNU/Linux on the PowerPC however, a function + pointer may be a pointer to a function descriptor. + + For PPC64, a function descriptor is a TOC entry, in a data section, + which contains three words: the first word is the address of the + function, the second word is the TOC pointer (r2), and the third word + is the static chain value. + + For PPC32, there are two kinds of function pointers: non-secure and + secure. Non-secure function pointers point directly to the + function in a code section and thus need no translation. Secure + ones (from GCC's -msecure-plt option) are in a data section and + contain one word: the address of the function. + + Throughout GDB it is currently assumed that a function pointer contains + the address of the function, which is not easy to fix. In addition, the conversion of a function address to a function pointer would require allocation of a TOC entry in the inferior's memory space, with all its drawbacks. To be able to call C++ virtual methods in the inferior (which are called via function pointers), find_function_addr uses this function to get the function address - from a function pointer. */ + from a function pointer. -/* If ADDR points at what is clearly a function descriptor, transform - it into the address of the corresponding function. Be - conservative, otherwize GDB will do the transformation on any - random addresses such as occures when there is no symbol table. */ + If ADDR points at what is clearly a function descriptor, transform + it into the address of the corresponding function, if needed. Be + conservative, otherwise GDB will do the transformation on any + random addresses such as occur when there is no symbol table. */ static CORE_ADDR -ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, - CORE_ADDR addr, - struct target_ops *targ) +ppc_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, + struct target_ops *targ) { + struct gdbarch_tdep *tdep; struct section_table *s = target_section_by_addr (targ, addr); + char *sect_name = NULL; + + if (!s) + return addr; + + tdep = gdbarch_tdep (gdbarch); + + switch (tdep->wordsize) + { + case 4: + sect_name = ".plt"; + break; + case 8: + sect_name = ".opd"; + break; + default: + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } /* Check if ADDR points to a function descriptor. */ - if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) - return get_target_memory_unsigned (targ, addr, 8); + + /* NOTE: this depends on the coincidence that the address of a functions + entry point is contained in the first word of its function descriptor + for both PPC-64 and for PPC-32 with secure PLTs. */ + if ((strcmp (s->the_bfd_section->name, sect_name) == 0) + && s->the_bfd_section->flags & SEC_DATA) + return get_target_memory_unsigned (targ, addr, tdep->wordsize); return addr; } @@ -907,6 +941,11 @@ ppc_linux_init_abi (struct gdbarch_info info, /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit. */ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); + /* Handle PPC GNU/Linux 64-bit function pointers (which are really + function descriptors) and 32-bit secure PLT entries. */ + set_gdbarch_convert_from_func_ptr_addr + (gdbarch, ppc_linux_convert_from_func_ptr_addr); + if (tdep->wordsize == 4) { /* Until November 2001, gcc did not comply with the 32 bit SysV @@ -934,13 +973,8 @@ ppc_linux_init_abi (struct gdbarch_info info, if (tdep->wordsize == 8) { - /* Handle PPC64 GNU/Linux function pointers (which are really - function descriptors). */ - set_gdbarch_convert_from_func_ptr_addr - (gdbarch, ppc64_linux_convert_from_func_ptr_addr); - set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); - /* Shared library handling. */ + set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); diff --git a/gdb/remote.c b/gdb/remote.c index 050930a3a31..9021d5a777e 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -2259,9 +2259,19 @@ remote_check_symbols (struct objfile *objfile) if (sym == NULL) xsnprintf (msg, get_remote_packet_size (), "qSymbol::%s", &reply[8]); else - xsnprintf (msg, get_remote_packet_size (), "qSymbol:%s:%s", - paddr_nz (SYMBOL_VALUE_ADDRESS (sym)), - &reply[8]); + { + CORE_ADDR sym_addr = SYMBOL_VALUE_ADDRESS (sym); + + /* If this is a function address, return the start of code + instead of any data function descriptor. */ + sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, + sym_addr, + ¤t_target); + + xsnprintf (msg, get_remote_packet_size (), "qSymbol:%s:%s", + paddr_nz (sym_addr), &reply[8]); + } + putpkt (msg); getpkt (&rs->buf, &rs->buf_size, 0); reply = rs->buf; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 7dfe707e6e0..3f6be94fe0b 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -84,16 +84,6 @@ static char *solib_break_names[] = "rtld_db_dlactivity", "_rtld_debug_state", - /* On the 64-bit PowerPC, the linker symbol with the same name as - the C function points to a function descriptor, not to the entry - point. The linker symbol whose name is the C function name - prefixed with a '.' points to the function's entry point. So - when we look through this table, we ignore symbols that point - into the data section (thus skipping the descriptor's symbol), - and eventually try this one, giving us the real entry point - address. */ - "._dl_debug_state", - NULL }; @@ -263,7 +253,7 @@ static char *debug_loader_name; static int match_main (char *); -static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword); +static CORE_ADDR bfd_lookup_symbol (bfd *, char *); /* @@ -273,24 +263,25 @@ static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword); SYNOPSIS - CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) DESCRIPTION An expensive way to lookup the value of a single symbol for bfd's that are only temporary anyway. This is used by the shared library support to find the address of the debugger - interface structures in the shared library. + notification routine in the shared library. - If SECT_FLAGS is non-zero, only match symbols in sections whose - flags include all those in SECT_FLAGS. + The returned symbol may be in a code or data section; functions + will normally be in a code section, but may be in a data section + if this architecture uses function descriptors. Note that 0 is specifically allowed as an error return (no such symbol). */ static CORE_ADDR -bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) +bfd_lookup_symbol (bfd *abfd, char *symname) { long storage_needed; asymbol *sym; @@ -312,9 +303,9 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) { sym = *symbol_table++; if (strcmp (sym->name, symname) == 0 - && (sym->section->flags & sect_flags) == sect_flags) + && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) { - /* Bfd symbols are section relative. */ + /* BFD symbols are section relative. */ symaddr = sym->value + sym->section->vma; break; } @@ -341,9 +332,9 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) sym = *symbol_table++; if (strcmp (sym->name, symname) == 0 - && (sym->section->flags & sect_flags) == sect_flags) + && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) { - /* Bfd symbols are section relative. */ + /* BFD symbols are section relative. */ symaddr = sym->value + sym->section->vma; break; } @@ -1033,7 +1024,7 @@ enable_break (void) /* On a running target, we can get the dynamic linker's base address from the shared library table. */ - solib_add (NULL, 0, NULL, auto_solib_add); + solib_add (NULL, 0, ¤t_target, auto_solib_add); so = master_so_list (); while (so) { @@ -1056,7 +1047,7 @@ enable_break (void) debug_loader_name = xstrdup (buf); debug_loader_offset_p = 1; debug_loader_offset = load_addr; - solib_add (NULL, 0, NULL, auto_solib_add); + solib_add (NULL, 0, ¤t_target, auto_solib_add); } /* Record the relocated start and end address of the dynamic linker @@ -1081,20 +1072,19 @@ enable_break (void) /* Now try to set a breakpoint in the dynamic linker. */ for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++) { - /* On ABI's that use function descriptors, there are usually - two linker symbols associated with each C function: one - pointing at the actual entry point of the machine code, - and one pointing at the function's descriptor. The - latter symbol has the same name as the C function. - - What we're looking for here is the machine code entry - point, so we are only interested in symbols in code - sections. */ - sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep, SEC_CODE); + sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep); if (sym_addr != 0) break; } + if (sym_addr != 0) + /* Convert 'sym_addr' from a function pointer to an address. + Because we pass tmp_bfd_target instead of the current + target, this will always produce an unrelocated value. */ + sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, + sym_addr, + tmp_bfd_target); + /* We're done with both the temporary bfd and target. Remember, closing the target closes the underlying bfd. */ target_close (tmp_bfd_target, 0); -- 2.30.2