From baae986a40eb2ed6d612436586bfa7dd1d88702d Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 17 Jan 2019 15:29:43 +0000 Subject: [PATCH] Update objdump's --disassemble= feature so that if is a function, the entire function will be disassembled, regardless of the presence of interveening symbols. * objdump.c (disassemble_section): When disassembling from a symbol only stop at the next symbol if the original symbol was not a function symbol. Otherwise continue disassembling until a new function is reached. * testsuite/binutils-all/objdump.exp: Add tests of extended functionality. * testsuite/binutils-all/disasm.s: New test source file. --- binutils/ChangeLog | 10 ++ binutils/NEWS | 2 +- binutils/doc/binutils.texi | 8 +- binutils/objdump.c | 101 ++++++++++++++++---- binutils/testsuite/binutils-all/disasm.s | 24 +++++ binutils/testsuite/binutils-all/objdump.exp | 93 +++++++++++++++++- 6 files changed, 213 insertions(+), 25 deletions(-) create mode 100644 binutils/testsuite/binutils-all/disasm.s diff --git a/binutils/ChangeLog b/binutils/ChangeLog index bec3ddcd138..2e17bab1e94 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +2019-01-17 Nick Clifton + + * objdump.c (disassemble_section): When disassembling from a + symbol only stop at the next symbol if the original symbol was not + a function symbol. Otherwise continue disassembling until a new + function is reached. + * testsuite/binutils-all/objdump.exp: Add tests of extended + functionality. + * testsuite/binutils-all/disasm.s: New test source file. + 2019-01-16 Kito Cheng Nelson Chu diff --git a/binutils/NEWS b/binutils/NEWS index 56bd7400d2d..0b8cc8e18b9 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -13,7 +13,7 @@ * Objdump's --disassemble option can now take a parameter, specifying the starting symbol for disassembly. Disassembly will continue from this - symbol up to the next symbol. + symbol up to the next symbol or the end of the function. * The MIPS port now supports the Loongson 2K1000 processor which implements the MIPS64r2 ISA, the Loongson-mmi ASE, Loongson-cam ASE, Loongson-ext ASE, diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 5664b9c7a56..49101888f5a 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -2230,9 +2230,11 @@ with ctags tool. Display the assembler mnemonics for the machine instructions from the input file. This option only disassembles those sections which are expected to contain instructions. If the optional @var{symbol} -argument is given, then display the assembler mnemonics only from -@var{symbol} up to next symbol. If there are no matches for -@var{symbol} then nothing will be displayed. +argument is given, then display the assembler mnemonics starting at +@var{symbol}. If @var{symbol} is a function name then disassembly +will stop at the end of the function, otherwise it will stop when the +next symbol is encountered. If there are no matches for @var{symbol} +then nothing will be displayed. @item -D @itemx --disassemble-all diff --git a/binutils/objdump.c b/binutils/objdump.c index 2300a66a8ae..872539068ca 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -2211,6 +2211,13 @@ disassemble_section (bfd *abfd, asection *section, void *inf) long rel_count; bfd_vma rel_offset; unsigned long addr_offset; + bfd_boolean do_print; + enum loop_control + { + stop_offset_reached, + function_sym, + next_sym + } loop_until; /* Sections that do not contain machine code are not normally disassembled. */ @@ -2328,13 +2335,15 @@ disassemble_section (bfd *abfd, asection *section, void *inf) the symbol we have just found. Then print the symbol and find the next symbol on. Repeat until we have disassembled the entire section or we have reached the end of the address range we are interested in. */ + do_print = paux->symbol == NULL; + loop_until = stop_offset_reached; + while (addr_offset < stop_offset) { bfd_vma addr; asymbol *nextsym; bfd_vma nextstop_offset; bfd_boolean insns; - bfd_boolean do_print = TRUE; addr = section->vma + addr_offset; addr = ((addr & ((sign_adjust << 1) - 1)) ^ sign_adjust) - sign_adjust; @@ -2360,20 +2369,80 @@ disassemble_section (bfd *abfd, asection *section, void *inf) pinfo->symtab_pos = -1; } + /* If we are only disassembling from a specific symbol, + check to see if we should start or stop displaying. */ if (sym && paux->symbol) { - const char *name = bfd_asymbol_name (sym); - char *alloc = NULL; - - if (do_demangle && name[0] != '\0') + if (do_print) { - /* Demangle the name. */ - alloc = bfd_demangle (abfd, name, demangle_flags); - if (alloc != NULL) - name = alloc; + /* See if we should stop printing. */ + switch (loop_until) + { + case function_sym: + if (sym->flags & BSF_FUNCTION) + do_print = FALSE; + break; + + case stop_offset_reached: + /* Handled by the while loop. */ + break; + + case next_sym: + /* FIXME: There is an implicit assumption here + that the name of sym is different from + paux->symbol. */ + if (! bfd_is_local_label (abfd, sym)) + do_print = FALSE; + break; + } + } + else + { + const char * name = bfd_asymbol_name (sym); + char * alloc = NULL; + + if (do_demangle && name[0] != '\0') + { + /* Demangle the name. */ + alloc = bfd_demangle (abfd, name, demangle_flags); + if (alloc != NULL) + name = alloc; + } + + /* We are not currently printing. Check to see + if the current symbol matches the requested symbol. */ + if (streq (name, paux->symbol)) + { + do_print = TRUE; + + if (sym->flags & BSF_FUNCTION) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && ((elf_symbol_type *) sym)->internal_elf_sym.st_size > 0) + { + /* Sym is a function symbol with a size associated + with it. Turn on automatic disassembly for the + next VALUE bytes. */ + stop_offset = addr_offset + + ((elf_symbol_type *) sym)->internal_elf_sym.st_size; + loop_until = stop_offset_reached; + } + else + { + /* Otherwise we need to tell the loop heuristic to + loop until the next function symbol is encountered. */ + loop_until = function_sym; + } + } + else + { + /* Otherwise loop until the next symbol is encountered. */ + loop_until = next_sym; + } + } + + free (alloc); } - do_print = streq (name, paux->symbol); - free (alloc); } if (! prefix_addresses && do_print) @@ -2438,13 +2507,9 @@ disassemble_section (bfd *abfd, asection *section, void *inf) insns = FALSE; if (do_print) - { - disassemble_bytes (pinfo, paux->disassemble_fn, insns, data, - addr_offset, nextstop_offset, - rel_offset, &rel_pp, rel_ppend); - if (paux->symbol) - break; - } + disassemble_bytes (pinfo, paux->disassemble_fn, insns, data, + addr_offset, nextstop_offset, + rel_offset, &rel_pp, rel_ppend); addr_offset = nextstop_offset; sym = nextsym; diff --git a/binutils/testsuite/binutils-all/disasm.s b/binutils/testsuite/binutils-all/disasm.s new file mode 100644 index 00000000000..7dccf9a3163 --- /dev/null +++ b/binutils/testsuite/binutils-all/disasm.s @@ -0,0 +1,24 @@ + .text + + .globl start_of_text +start_of_text: + .type start_of_text, "function" + .long 1 + .size start_of_text, . - start_of_text + + .globl func +func: + .type func, "function" + .long 2 + .global global_non_func_sym +global_non_func_sym: + .long 3 +local_non_func_sym: + .long 4 + .size func, . - func + + .globl next_func +next_func: + .type next_func, "function" + .long 5 + .size next_func, . - next_func diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp index 50c81ba3d53..dd2e9bb02d0 100644 --- a/binutils/testsuite/binutils-all/objdump.exp +++ b/binutils/testsuite/binutils-all/objdump.exp @@ -62,7 +62,7 @@ if [regexp $want $got] then { if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then { - fail "objdump (assembling)" + fail "objdump (assembling bintest.s)" return } if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest2.o]} then { @@ -280,8 +280,95 @@ proc test_objdump_d_sym { testfile dumpfile } { } test_objdump_d_sym $testfile $testfile -if { [ remote_file host exists $testarchive ] } then { - test_objdump_d_sym $testarchive bintest2.o + +proc test_objdump_d_func_sym { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS + + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS --disassemble=func --disassemble-zeroes $testfile"] + + set want "$dumpfile:.*Disassembly of section" + if ![regexp $want $got] then { + fail "objdump --disassemble=func $testfile: No disassembly title" + return + } + + set want "$dumpfile:.*00+0 " + if [regexp $want $got] then { + fail "objdump --disassemble=func $testfile: First symbol displayed, when it should be absent" + return + } + + set want "$dumpfile:.*00+. " + if ![regexp $want $got] then { + fail "objdump --disassemble=func $testfile: Disassembly does not start at function symbol" + return + } + + set want "$dumpfile:.*00+. " + if ![regexp $want $got] then { + fail "objdump --disassemble=func $testfile: Non function symbol not displayed" + return + } + + set want "$dumpfile:.*00+. " + if [regexp $want $got] then { + fail "objdump --disassemble=func $testfile: Disassembly did not stop at the next function" + return + } + + pass "objdump --disassemble=func $testfile" +} + +proc test_objdump_d_non_func_sym { testfile dumpfile } { + global OBJDUMP + global OBJDUMPFLAGS + + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS --disassemble=global_non_func_sym $testfile"] + + set want "$dumpfile:.*Disassembly of section" + if ![regexp $want $got] then { + fail "objdump --disassemble=non_func $testfile: No disassembly title" + return + } + + set want "$dumpfile:.*00+0 " + if [regexp $want $got] then { + fail "objdump --disassemble=non_func $testfile: First symbol displayed, when it should be absent" + return + } + + set want "$dumpfile:.*00+. " + if ![regexp $want $got] then { + fail "objdump --disassemble=non_func $testfile: Non function symbol not displayed" + return + } + + set want "$dumpfile:.*00+. " + if [regexp $want $got] then { + fail "objdump --disassemble=non_func $testfile: Disassembly did not stop at the next symbol" + return + } + + pass "objdump --disassemble=non_func $testfile" +} + +# Extra test for ELF format - check that --disassemble=func disassembles +# all of func, and does not stop at the next symbol. +if { [is_elf_format] } then { + + if {![binutils_assemble $srcdir/$subdir/disasm.s tmpdir/disasm.o]} then { + fail "objdump --disassemble=func (assembling disasm.s)" + } else { + if [is_remote host] { + set elftestfile [remote_download host tmpdir/disasm.o] + } else { + set elftestfile tmpdir/disasm.o + } + + test_objdump_d_func_sym $elftestfile $elftestfile + test_objdump_d_non_func_sym $elftestfile $elftestfile + } }