gdb: fix disassembler regressions for 32-bit arm
authorAndrew Burgess <aburgess@redhat.com>
Sat, 6 Nov 2021 09:50:36 +0000 (09:50 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 30 Nov 2021 12:20:09 +0000 (12:20 +0000)
After this commit:

  commit 76b43c9b5c2b275cbf4f927bfc25984410cb5dd5
  Date:   Tue Oct 5 15:10:12 2021 +0100

      gdb: improve error reporting from the disassembler

We started seeing FAILs in the gdb.base/all-architectures*.exp tests,
when running on a 32-bit ARM target, though I suspect running on any
target that compiles such that bfd_vma is 32-bits would also trigger
the failures.

The problem is that the test is expected GDB's disassembler to print
an error like this:

  Cannot access memory at address 0x0

However, after the above commit we see an error like:

  unknown disassembler error (error = -1)

The reason for this is this code in opcodes/i386-dis.c (in the
print_insn function):

  if (address_mode == mode_64bit && sizeof (bfd_vma) < 8)
    {
      (*info->fprintf_func) (info->stream,
                             _("64-bit address is disabled"));
      return -1;
    }

This code effectively disallows us from ever disassembling 64-bit x86
code if we compiled GDB with a 32-bit bfd_vma.  Notice we return
-1 (indicating a failure to disassemble), but never call the
memory_error_func callback.

Prior to the above commit GDB, when it received the -1 return value
would assume that a memory error had occurred and just print whatever
value happened to be in the memory error address variable, the default
value of 0 just happened to be fine because the test had asked GDB to
do this 'disassemble 0x0,+4'.

If we instead change the test to do 'disassemble 0x100,+4' then GDB
would (previously) have still reported:

  Cannot access memory at address 0x0

which makes far less sense.

In this commit I propose to fix this issue by changing the test to
accept either the "Cannot access memory ..." string, or the newer
"unknown disassembler error ..." string.  With this change done the
test now passes.

However, there is one weakness with this strategy; if GDB broke such
that we _always_ reported "unknown disassembler error ..." we would
never notice.  This clearly would be bad.  To avoid this issue I have
adjusted the all-architectures*.exp tests so that, when we disassemble
for the default architecture (the one selected by "auto") we _only_
expect to get the "Cannot access memory ..." error string.

[ Note: In an ideal world we should be able to disassemble any
  architecture at all times.  There's no reason why the 64-bit x86
  disassembler requires a 64-bit bfd_vma, other than the code happens
  to be written that way.  We could rewrite the disassemble to not
  have this requirement, but, I don't plan to do that any time soon. ]

Further, I have changed the all-architectures*.exp test so that we now
disassemble at address 0x100, this should avoid us being able to pass
by printing a default address of 0x0.  I did originally change the
address we disassembled at to 0x4, however, some architectures,
e.g. ia64, have a default instruction alignment that is greater than
4, so would still round down to 0x0.  I could have just picked 0x8 as
an address, but I figured that 0x100 was likely to satisfy most
architectures alignment requirements.

gdb/testsuite/gdb.base/all-architectures.exp.tcl

index 967aa108665125aa40e5d0b5f10dc9aabc5a45c4..c247d13e581c6a43f5701b013729b3a4e5ffc933 100644 (file)
@@ -135,6 +135,8 @@ if {[lsearch $supported_archs "arm"] >= 0} {
     gdb_assert {[llength $supported_arm_abi] != 0} "at least one arm abi"
 }
 
+set default_architecture "i386"
+
 # Exercise printing float, double and long double.
 
 proc print_floats {} {
@@ -148,15 +150,27 @@ proc print_floats {} {
     gdb_test_internal "print 1.0f" " = 1" "print, float"
 }
 
-# Run tests on the current architecture.
+# Run tests on the current architecture ARCH.
 
-proc do_arch_tests {} {
+proc do_arch_tests {arch} {
     print_floats
 
+    # When we disassemble using the default architecture then we
+    # expect that the only error we should get from the disassembler
+    # is a memory error.
+    #
+    # When we force the architecture to something other than the
+    # default then we might get the message about unknown errors, this
+    # happens if the libopcodes disassembler returns -1 without first
+    # registering a memory error.
+    set pattern "Cannot access memory at address 0x100"
+    if { $arch != $::default_architecture } {
+       set pattern "(($pattern)|(unknown disassembler error \\(error = -1\\)))"
+    }
+
     # GDB can't access memory because there is no loaded executable
     # nor live inferior.
-    gdb_test_internal "disassemble 0x0,+4" \
-       "Cannot access memory at address 0x0"
+    gdb_test_internal "disassemble 0x100,+4" "${pattern}"
 }
 
 # Given we can't change arch, osabi, endianness, etc. atomically, we
@@ -303,9 +317,9 @@ with_test_prefix "tests" {
                # Run testing axis CUR_AXIS.  This is a recursive
                # procedure that tries all combinations of options of
                # all the testing axes.
-               proc run_axis {all_axes cur_axis} {
+               proc run_axis {all_axes cur_axis arch} {
                    if {$cur_axis == [llength $all_axes]} {
-                       do_arch_tests
+                       do_arch_tests $arch
                        return
                    }
 
@@ -318,12 +332,12 @@ with_test_prefix "tests" {
                    foreach v $options {
                        with_test_prefix "$var=$v" {
                            gdb_test_no_output_osabi "$cmd $v" "$cmd"
-                           run_axis $all_axes [expr $cur_axis + 1]
+                           run_axis $all_axes [expr $cur_axis + 1] $arch
                        }
                    }
                }
 
-               run_axis $all_axes 0
+               run_axis $all_axes 0 $arch
            }
        }
     }