From 2379f9c475505ecedc97607b39af7184bd67aa88 Mon Sep 17 00:00:00 2001 From: Faraz Shahbazker Date: Fri, 3 May 2019 18:21:49 -0700 Subject: [PATCH] Sign-extend start and stop address inputs to objdump For targets that treat addresses as signed (MIPS/SH64), user-specified start/stop address limits cannot be compared directly to section VMAs. We must sign-extend user-specified 32-bit address limits which have bit 31 set for such targets. binutils/ * objdump.c (sign_extend_address): New function. (dump_bfd): Sign-extend user-specified start/stop addresses for targets that need it. * testsuite/binutils-all/objdump.exp: Add tests for objdump with start and stop addresses in higher address ranges. --- binutils/ChangeLog | 8 +++ binutils/objdump.c | 26 ++++++++++ binutils/testsuite/binutils-all/objdump.exp | 54 +++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b3140a94bb..ecbe75973a 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,11 @@ +2019-05-08 Faraz Shahbazker + + * objdump.c (sign_extend_address): New function. + (dump_bfd): Sign-extend user-specified start/stop addresses + for targets that need it. + * testsuite/binutils-all/objdump.exp: Add tests for objdump + with start and stop addresses in higher address ranges. + 2019-05-01 Matthew Malcomson * testsuite/binutils-all/objdump.exp: Correct executable diff --git a/binutils/objdump.c b/binutils/objdump.c index 644638c321..05d503e514 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -3749,11 +3749,25 @@ adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, } } +/* Return the sign-extended form of an ARCH_SIZE sized VMA. */ + +static bfd_vma +sign_extend_address (bfd *abfd ATTRIBUTE_UNUSED, + bfd_vma vma, + unsigned arch_size) +{ + bfd_vma mask; + mask = (bfd_vma) 1 << (arch_size - 1); + return (((vma & ((mask << 1) - 1)) ^ mask) - mask); +} + /* Dump selected contents of ABFD. */ static void dump_bfd (bfd *abfd, bfd_boolean is_mainfile) { + const struct elf_backend_data * bed; + if (bfd_big_endian (abfd)) byte_get = byte_get_big_endian; else if (bfd_little_endian (abfd)) @@ -3784,6 +3798,18 @@ dump_bfd (bfd *abfd, bfd_boolean is_mainfile) } } + /* Adjust user-specified start and stop limits for targets that use + signed addresses. */ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && (bed = get_elf_backend_data (abfd)) != NULL + && bed->sign_extend_vma) + { + start_address = sign_extend_address (abfd, start_address, + bed->s->arch_size); + stop_address = sign_extend_address (abfd, stop_address, + bed->s->arch_size); + } + /* If we are adjusting section VMA's, change them all now. Changing the BFD information is a hack. However, we must do it, or bfd_find_nearest_line will not do the right thing. */ diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp index 94ff015020..f25946ca08 100644 --- a/binutils/testsuite/binutils-all/objdump.exp +++ b/binutils/testsuite/binutils-all/objdump.exp @@ -672,6 +672,60 @@ if {[is_elf_format]} then { test_follow_debuglink "--dwarf=follow-links --headers --wide" objdump.WK3 } +# Test objdump output with start and stop address limits for the specified +# dump option + +proc test_objdump_limited { testfile dopt want start stop } { + global OBJDUMP + global OBJDUMPFLAGS + + set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS $dopt --start-address 0x$start --stop-address 0x$stop $testfile"] + + if [regexp $want $got] then { + pass "objdump $dopt --start-address 0x$start --stop-address 0x$stop ($testfile)" + } else { + fail "objdump $dopt --start-address 0x$start --stop-address 0x$stop ($testfile)" + } +} + +# Test objdump -d --start-address M --stop-address N + +proc test_objdump_disas_limited { testfile start stop } { + set want "$testfile:\[ \]*file format.*Disassembly of section .text:\n.*\[ \]*$start:.*" + test_objdump_limited $testfile -d $want $start $stop +} + +# Test objdump -s --start-address M --stop-address N + +proc test_objdump_content_limited { testfile start stop } { + set want "$testfile:\[ \]*file format.*Contents of section .text:\n\[ \]*$start .*" + test_objdump_limited $testfile -s $want $start $stop +} + +# Test objdump with --start-address and --stop-address options for higher +# address ranges which may be sign-extended on targets that treat addresses +# as signed. We only check that objdump produces some dump output at the +# specified start address as a proxy for correct enforcement of the +# start/stop limits. + +if {[is_elf_format]} then { + # generate a copy of the test object with .text repositioned + if { [binutils_run $OBJCOPY "--change-section-address .text=0x80000000 tmpdir/bintest.o tmpdir/bintest_signed.o"] != "" } { + fail "Failed to reposition .text to 0x80000000 (tmpdir/bintest.o -> tmpdir/bintest_signed.o)" + return + } + + if [is_remote host] { + set testfile3 [remote_download host tmpdir/bintest_signed.o] + } else { + set testfile3 tmpdir/bintest_signed.o + } + + test_objdump_content_limited $testfile3 "80000004" "80000008" + test_objdump_disas_limited $testfile3 "80000004" "80000008" + remote_file host delete $testfile3 +} + # Options which are not tested: -a -D -R -T -x -l --stabs # I don't see any generic way to test any of these other than -a. # Tests could be written for specific targets, and that should be done