From c04bd4920aeb2b476412ae8c5731cfbcf7e2dcdf Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 19 Jul 2006 02:17:23 +0000 Subject: * blockframe.c (find_pc_partial_function): Use the minimal symbol size to control the cache entry, if available. * minsyms.c (lookup_minimal_symbol_by_pc_section): Handle minimal symbols with zero and non-zero sizes differently. * gdb.arch/i386-size.c, gdb.arch/i386-size.exp: New files. --- gdb/ChangeLog | 7 +++ gdb/blockframe.c | 43 ++++++++------ gdb/minsyms.c | 107 +++++++++++++++++++++++++++-------- gdb/testsuite/ChangeLog | 4 ++ gdb/testsuite/gdb.arch/i386-size.c | 50 ++++++++++++++++ gdb/testsuite/gdb.arch/i386-size.exp | 89 +++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 42 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/i386-size.c create mode 100644 gdb/testsuite/gdb.arch/i386-size.exp (limited to 'gdb') diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5fd306f8076..ef7d2b98f0a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2006-07-18 Daniel Jacobowitz + + * blockframe.c (find_pc_partial_function): Use the minimal symbol + size to control the cache entry, if available. + * minsyms.c (lookup_minimal_symbol_by_pc_section): Handle minimal + symbols with zero and non-zero sizes differently. + 2006-07-18 Daniel Jacobowitz * linux-thread-db.c (td_thr_getfpregs_p, td_thr_getgregs_p) diff --git a/gdb/blockframe.c b/gdb/blockframe.c index dbb1b4343e3..ba298c3f61f 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -280,27 +280,34 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, cache_pc_function_name = DEPRECATED_SYMBOL_NAME (msymbol); cache_pc_function_section = section; - /* Use the lesser of the next minimal symbol in the same section, or - the end of the section, as the end of the function. */ + /* If the minimal symbol has a size, use it for the cache. + Otherwise use the lesser of the next minimal symbol in the same + section, or the end of the section, as the end of the + function. */ - /* Step over other symbols at this same address, and symbols in - other sections, to find the next symbol in this section with - a different address. */ - - for (i = 1; DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL; i++) + if (MSYMBOL_SIZE (msymbol) != 0) + cache_pc_function_high = cache_pc_function_low + MSYMBOL_SIZE (msymbol); + else { - if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol) - && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol)) - break; - } + /* Step over other symbols at this same address, and symbols in + other sections, to find the next symbol in this section with + a different address. */ - if (DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL - && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr) - cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i); - else - /* We got the start address from the last msymbol in the objfile. - So the end address is the end of the section. */ - cache_pc_function_high = osect->endaddr; + for (i = 1; DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL; i++) + { + if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol) + && SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol)) + break; + } + + if (DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL + && SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr) + cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i); + else + /* We got the start address from the last msymbol in the objfile. + So the end address is the end of the section. */ + cache_pc_function_high = osect->endaddr; + } return_cached_value: diff --git a/gdb/minsyms.c b/gdb/minsyms.c index e8ef95ef83d..ae4c23a1132 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -412,6 +412,8 @@ lookup_minimal_symbol_by_pc_section (CORE_ADDR pc, asection *section) if (objfile->minimal_symbol_count > 0) { + int best_zero_sized = -1; + msymbol = objfile->msymbols; lo = 0; hi = objfile->minimal_symbol_count - 1; @@ -461,34 +463,91 @@ lookup_minimal_symbol_by_pc_section (CORE_ADDR pc, asection *section) == SYMBOL_VALUE_ADDRESS (&msymbol[hi + 1]))) hi++; + /* Skip various undesirable symbols. */ + while (hi >= 0) + { + /* Skip any absolute symbols. This is apparently + what adb and dbx do, and is needed for the CM-5. + There are two known possible problems: (1) on + ELF, apparently end, edata, etc. are absolute. + Not sure ignoring them here is a big deal, but if + we want to use them, the fix would go in + elfread.c. (2) I think shared library entry + points on the NeXT are absolute. If we want + special handling for this it probably should be + triggered by a special mst_abs_or_lib or some + such. */ + + if (msymbol[hi].type == mst_abs) + { + hi--; + continue; + } + + /* If SECTION was specified, skip any symbol from + wrong section. */ + if (section + /* Some types of debug info, such as COFF, + don't fill the bfd_section member, so don't + throw away symbols on those platforms. */ + && SYMBOL_BFD_SECTION (&msymbol[hi]) != NULL + && SYMBOL_BFD_SECTION (&msymbol[hi]) != section) + { + hi--; + continue; + } + + /* If the minimal symbol has a zero size, save it + but keep scanning backwards looking for one with + a non-zero size. A zero size may mean that the + symbol isn't an object or function (e.g. a + label), or it may just mean that the size was not + specified. */ + if (MSYMBOL_SIZE (&msymbol[hi]) == 0 + && best_zero_sized == -1) + { + best_zero_sized = hi; + hi--; + continue; + } + + /* Otherwise, this symbol must be as good as we're going + to get. */ + break; + } + + /* If HI has a zero size, and best_zero_sized is set, + then we had two or more zero-sized symbols; prefer + the first one we found (which may have a higher + address). Also, if we ran off the end, be sure + to back up. */ + if (best_zero_sized != -1 + && (hi < 0 || MSYMBOL_SIZE (&msymbol[hi]) == 0)) + hi = best_zero_sized; + + /* If the minimal symbol has a non-zero size, and this + PC appears to be outside the symbol's contents, then + refuse to use this symbol. If we found a zero-sized + symbol with an address greater than this symbol's, + use that instead. We assume that if symbols have + specified sizes, they do not overlap. */ + + if (hi >= 0 + && MSYMBOL_SIZE (&msymbol[hi]) != 0 + && pc >= (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) + + MSYMBOL_SIZE (&msymbol[hi]))) + { + if (best_zero_sized != -1) + hi = best_zero_sized; + else + /* Go on to the next object file. */ + continue; + } + /* The minimal symbol indexed by hi now is the best one in this objfile's minimal symbol table. See if it is the best one overall. */ - /* Skip any absolute symbols. This is apparently what adb - and dbx do, and is needed for the CM-5. There are two - known possible problems: (1) on ELF, apparently end, edata, - etc. are absolute. Not sure ignoring them here is a big - deal, but if we want to use them, the fix would go in - elfread.c. (2) I think shared library entry points on the - NeXT are absolute. If we want special handling for this - it probably should be triggered by a special - mst_abs_or_lib or some such. */ - while (hi >= 0 - && msymbol[hi].type == mst_abs) - --hi; - - /* If "section" specified, skip any symbol from wrong section */ - /* This is the new code that distinguishes it from the old function */ - if (section) - while (hi >= 0 - /* Some types of debug info, such as COFF, - don't fill the bfd_section member, so don't - throw away symbols on those platforms. */ - && SYMBOL_BFD_SECTION (&msymbol[hi]) != NULL - && SYMBOL_BFD_SECTION (&msymbol[hi]) != section) - --hi; - if (hi >= 0 && ((best_symbol == NULL) || (SYMBOL_VALUE_ADDRESS (best_symbol) < diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 7f49b3d2eb7..0a50407fbf5 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2006-07-18 Daniel Jacobowitz + + * gdb.arch/i386-size.c, gdb.arch/i386-size.exp: New files. + 2006-07-18 Daniel Jacobowitz * gdb.threads/print-threads.exp: Use gdb_breakpoint. diff --git a/gdb/testsuite/gdb.arch/i386-size.c b/gdb/testsuite/gdb.arch/i386-size.c new file mode 100644 index 00000000000..80357ddbfa7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-size.c @@ -0,0 +1,50 @@ +/* Symbol size test program. + + Copyright 2006 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef SYMBOL_PREFIX +#define SYMBOL(str) SYMBOL_PREFIX #str +#else +#define SYMBOL(str) #str +#endif + +void +trap (void) +{ + asm ("int $0x03"); +} + +/* Jump from a function with its symbol size set, to a function + named by a local label. If GDB does not look at the sizes of + symbols, we will still appear to be in the first function. */ + +asm(".text\n" + " .align 8\n" + " .globl " SYMBOL (main) "\n" + SYMBOL (main) ":\n" + " pushl %ebp\n" + " mov %esp, %ebp\n" + " call .Lfunc\n" + " ret\n" + " .size " SYMBOL (main) ", .-" SYMBOL (main) "\n" + ".Lfunc:\n" + " pushl %ebp\n" + " mov %esp, %ebp\n" + " call " SYMBOL (trap) "\n"); diff --git a/gdb/testsuite/gdb.arch/i386-size.exp b/gdb/testsuite/gdb.arch/i386-size.exp new file mode 100644 index 00000000000..dcf67e995e7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-size.exp @@ -0,0 +1,89 @@ +# Copyright 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@gnu.org + +# This file is part of the gdb testsuite. + +if $tracelevel { + strace $tracelevel +} + +# Test that GDB can see the sizes of symbols. + +if ![istarget "i?86-*-*"] then { + verbose "Skipping i386 unwinder tests." + return +} + +set testfile "i386-size" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# some targets have leading underscores on assembly symbols. +# TODO: detect this automatically +set additional_flags "" +if [istarget "i?86-*-cygwin*"] then { + set additional_flags "additional_flags=-DSYMBOL_PREFIX=\"_\"" +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable [list debug $additional_flags]] != "" } { + untested "i386-size" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# We use gdb_run_cmd so this stands a chance to work for remote +# targets too. +gdb_run_cmd + +gdb_expect { + -re "Program received signal SIGTRAP.*$gdb_prompt $" { + pass "run past main" + } + -re ".*$gdb_prompt $" { + fail "run past main" + } + timeout { + fail "run past main (timeout)" + } +} + +set message "backtrace shows no function" +gdb_test_multiple "backtrace 10" $message { + -re "#1\[ \t]*$hex in main.*$gdb_prompt $" { + fail $message + } + -re "#1\[ \t]*$hex in \\?\\? \\(\\).*$gdb_prompt $" { + pass $message + } +} + +set message "disassemble stops at end of main" +gdb_test_multiple "disassemble main" $message { + -re "call.*.*$gdb_prompt $" { + fail $message + } + -re ":\[ \t\]+ret\[ \t\r\n\]+End of.*$gdb_prompt $" { + pass $message + } +} -- cgit v1.2.1