arch-utils: Make the last endianness actually chosen sticky

Message ID alpine.DEB.2.00.1610132235410.31859@tp.orcam.me.uk
State Superseded
Headers

Commit Message

Maciej W. Rozycki Oct. 14, 2016, 1:12 p.m. UTC
  Use the last endianness explicitly selected, either by choosing a binary 
file or with the `set endian' command, for future automatic selection.

As observed with the `gdb.base/step-over-no-symbols.exp' test case when
discarding the binary file even while connected to a live target the
endianness automatically selected is reset to the GDB target's default,
even if it does not match the endianness of the target being talked to.

For example with a little-endian MIPS target and the default endianness
being big we get this:

(gdb) file .../gdb/testsuite/outputs/gdb.base/step-over-no-symbols/step-over-no-symbols
Reading symbols from .../gdb/testsuite/outputs/gdb.base/step-over-no-symbols/step-over-no-symbols...done.
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break main
Breakpoint 1 at 0x400840: file .../gdb/testsuite/gdb.base/start.c, line 34.
[...]
(gdb) continue
Continuing.

Breakpoint 1, main () at .../gdb/testsuite/gdb.base/start.c:34
34	  foo();
(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) file
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
No executable file now.
Discard symbol table from `.../gdb/testsuite/outputs/gdb.base/step-over-no-symbols/step-over-no-symbols'? (y or n) y
No symbol file now.
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: purging symbols
p /x $pc
$1 = 0x40084000
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: get before PC
break *$pc
Breakpoint 2 at 0x40084000
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: break *$pc
set displaced-stepping off
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: set displaced-stepping off
stepi
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0x40084000

Command aborted.
(gdb) FAIL: gdb.base/step-over-no-symbols.exp: displaced=off: stepi
p /x $pc
$2 = 0x40084000
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: get after PC
FAIL: gdb.base/step-over-no-symbols.exp: displaced=off: advanced
Remote debugging from host ...
monitor exit
(gdb) Killing process(es): ...
testcase .../gdb/testsuite/gdb.base/step-over-no-symbols.exp completed in 2 seconds

which shows that with the removal of the executable debugged the 
endianness of $pc still at `main' gets swapped and the value in that 
register is now incorrectly interpreted as 0x40084000 rather than 
0x400840 as shown earlier on with the `break' command.  Consequently the 
debug session no longer works as expected, until the endianness is 
overridden with an explicit `set endian little' command.

This will happen while working with any target hardware whose endianness 
does not match the default GDB target's endianness guessed and recorded 
for a later use in `initialize_current_architecture'.

Given that within a single run of GDB it is more likely that consecutive
target connections will use the same endianness than that the endianness
will be swapped between connections, it makes sense to preserve the last
endianness explicitly selected as the automatic default.  It will make a
session like above, where an executable is removed, work correctly and
will retain the endianness for a further reconnection to the target.  

And the new automatic default will still be overridden by subsequently 
choosing a binary to debug, or with an explicit `set endian' command.

With the change in place the test case above completes successfully:

(gdb) continue
Continuing.

Breakpoint 1, main () at .../gdb/testsuite/gdb.base/start.c:34
34	  foo();
(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) file
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
No executable file now.
Discard symbol table from `.../gdb/testsuite/outputs/gdb.base/step-over-no-symbols/step-over-no-symbols'? (y or n) y
No symbol file now.
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: purging symbols
p /x $pc
warning: GDB can't find the start of the function at 0x400840.

    GDB is unable to find the start of the function at 0x400840
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0x400840 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.
$1 = 0x400840
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: get before PC
break *$pc
Breakpoint 2 at 0x400840
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: break *$pc
set displaced-stepping off
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: set displaced-stepping off
stepi
warning: GDB can't find the start of the function at 0x4007f8.
0x004007f8 in ?? ()
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: stepi
p /x $pc
$2 = 0x4007f8
(gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=off: get after PC
PASS: gdb.base/step-over-no-symbols.exp: displaced=off: advanced
Remote debugging from host ...
monitor exit
(gdb) Killing process(es): ...
testcase .../gdb/testsuite/gdb.base/step-over-no-symbols.exp completed in 2 seconds

	gdb/
	* arch-utils.c (gdbarch_info_fill): Set `default_byte_order' to
	the endianness selected.

	gdb/testsuite
	* gdb.base/endian.exp: New test.
	* gdb.base/endian.c: New test source.
---
Hi,

 I think it would make sense for execution target backends, including the 
remote target in particular, to supply GDB with endianness information, 
however we don't currently do it and even if we update our protocols to 
have that information supplied, old remote stubs will not change and will 
not provide it.  So I think it makes sense to make the default follow the 
last selection as based on my experience I believe in real debug scenarios 
it's more likely that a subsequent session will talk to the same target
hardware which will continue using the same endianness than that the new
target connected to will revert to the GDB's hardcoded default.

 There is another test suite progression from this patch, although its
connection to this change seems a bit obscure to me:

-FAIL: gdb.server/server-exec-info.exp: info files
+PASS: gdb.server/server-exec-info.exp: info files

or with the details included:

(gdb) PASS: gdb.server/server-exec-info.exp: set sysroot remote:
info files
Remote serial target in gdb-specific protocol:
Debugging a target over a serial line.
(gdb) FAIL: gdb.server/server-exec-info.exp: info files

vs:

(gdb) PASS: gdb.server/server-exec-info.exp: set sysroot remote:
info files
Remote serial target in gdb-specific protocol:
Debugging a target over a serial line.
	While running this, GDB does not access memory from...
Local exec file:
	<no file loaded>
(gdb) PASS: gdb.server/server-exec-info.exp: info files

I suspect an exception is thrown as inaccessible memory is reached and 
terminates the processing of the `info files' command prematurely.

 No regressions in `mips-mti-linux-gnu' o32 cross-testing with `gdbserver' 
across targets of either endianness.

 OK to apply?

  Maciej

gdb-default-byte-order.diff
  

Comments

Maciej W. Rozycki Nov. 8, 2016, 8:45 a.m. UTC | #1
On Fri, 14 Oct 2016, Maciej W. Rozycki wrote:

> 	gdb/
> 	* arch-utils.c (gdbarch_info_fill): Set `default_byte_order' to
> 	the endianness selected.
> 
> 	gdb/testsuite
> 	* gdb.base/endian.exp: New test.
> 	* gdb.base/endian.c: New test source.

 Can I ask for <https://patchwork.sourceware.org/patch/16504/> to be 
reviewed?

  Maciej
  
Doug Evans Nov. 8, 2016, 10:49 p.m. UTC | #2
On Tue, Nov 8, 2016 at 12:45 AM, Maciej W. Rozycki <macro@imgtec.com> wrote:
> On Fri, 14 Oct 2016, Maciej W. Rozycki wrote:
>
>>       gdb/
>>       * arch-utils.c (gdbarch_info_fill): Set `default_byte_order' to
>>       the endianness selected.
>>
>>       gdb/testsuite
>>       * gdb.base/endian.exp: New test.
>>       * gdb.base/endian.c: New test source.
>
>  Can I ask for <https://patchwork.sourceware.org/patch/16504/> to be
> reviewed?

Hi.

This is fine with me.
[I can imagine oddities if someone was doing multi-inferior debugging
with different endiannesses, but that's a rare situation, and I don't
think any oddities if they exist are killers.]

I tested it on amd64-linux just as a sanity check.

I think a NEWS entry is required.

I'm kinda thinking an addition to the "Choosing Target Byte Order"
would be nice, but it's not mandatory. [If we do so, I think to do it
right you would have to document a whole lot more than just
this simple addition, and I don't like imposing on you that
burden. If you want to take it on, great of course.
But to me it's not necessary for this patch to go in.]
  

Patch

Index: binutils/gdb/arch-utils.c
===================================================================
--- binutils.orig/gdb/arch-utils.c	2016-10-14 02:40:40.587665608 +0100
+++ binutils/gdb/arch-utils.c	2016-10-14 03:48:32.492283480 +0100
@@ -787,6 +787,8 @@  gdbarch_info_fill (struct gdbarch_info *
   if (info->byte_order == BFD_ENDIAN_UNKNOWN)
     info->byte_order = default_byte_order;
   info->byte_order_for_code = info->byte_order;
+  /* Wire the default to the last selected byte order.  */
+  default_byte_order = info->byte_order;
 
   /* "(gdb) set osabi ...".  Handled by gdbarch_lookup_osabi.  */
   /* From the manual override, or from file.  */
Index: binutils/gdb/testsuite/gdb.base/endian.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils/gdb/testsuite/gdb.base/endian.c	2016-10-14 03:48:32.521146892 +0100
@@ -0,0 +1,22 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2016 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+int
+main (void)
+{
+  return 0;
+}
Index: binutils/gdb/testsuite/gdb.base/endian.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils/gdb/testsuite/gdb.base/endian.exp	2016-10-14 05:10:27.523711889 +0100
@@ -0,0 +1,96 @@ 
+# Copyright (C) 2016 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 3 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, see <http://www.gnu.org/licenses/>.
+
+# Contributed by Imagination Technologies, written by Maciej W. Rozycki.
+
+# Test automatic endianness selection.
+
+standard_testfile
+
+set en_auto "The target endianness is set automatically"
+set en_set "The target is assumed to be"
+
+clean_restart
+
+# First check that the automatic endianness is updated
+# with the `set endian' command.
+gdb_test "set endian auto" \
+    "$en_auto \\\(currently \(\?:big\|little\) endian\\\)" \
+    "default target endianness"
+gdb_test "set endian big" "$en_set big endian" \
+    "set target endianness"
+gdb_test "set endian auto" "$en_auto \\\(currently big endian\\\)" \
+    "auto target endianness"
+gdb_test "set endian little" "$en_set little endian" \
+    "set target endianness little"
+gdb_test "set endian auto" "$en_auto \\\(currently little endian\\\)" \
+    "auto target endianness little"
+gdb_test "set endian big" "$en_set big endian" \
+    "set target endianness big"
+gdb_test "set endian auto" "$en_auto \\\(currently big endian\\\)" \
+    "auto target endianness big"
+
+if { [build_executable ${testfile}.exp $testfile] } {
+    gdb_suppress_entire_file "$pf_prefix cannot build executable"
+}
+
+if { [gdb_file_cmd $binfile] } {
+    gdb_suppress_entire_file "$pf_prefix cannot select executable"
+}
+set test "get target endianness"
+if { [gdb_test_multiple "show endian" "$test" {
+    -re "$en_auto \\\(currently \(big\|little\) endian\\\).*$gdb_prompt" {
+	set endian $expect_out(1,string)
+	pass "$test"
+    }
+}] } {
+    gdb_suppress_entire_file \
+	"$pf_prefix cannot determine executable endianness"
+    set endian ""
+}
+
+# Now check that the automatic endianness is updated
+# according to the executable selected.
+if { [gdb_unload] } {
+    gdb_suppress_entire_file "$pf_prefix cannot unselect executable"
+}
+gdb_test "set endian big" "$en_set big endian" \
+    "override target endianness big"
+gdb_test "set endian auto" "$en_auto \\\(currently big endian\\\)" \
+    "override auto target endianness big"
+if { [gdb_file_cmd $binfile] } {
+    gdb_suppress_entire_file "$pf_prefix cannot select executable"
+}
+gdb_test "show endian" "$en_auto \\\(currently $endian endian\\\)" \
+    "previously big default executable endianness"
+if { [gdb_unload] } {
+    gdb_suppress_entire_file "$pf_prefix cannot unselect executable"
+}
+gdb_test "show endian" "$en_auto \\\(currently $endian endian\\\)" \
+    "previously big default no executable endianness"
+gdb_test "set endian little" "$en_set little endian" \
+    "override target endianness little"
+gdb_test "set endian auto" "$en_auto \\\(currently little endian\\\)" \
+    "override auto target endianness little"
+if { [gdb_file_cmd $binfile] } {
+    gdb_suppress_entire_file "$pf_prefix cannot select executable"
+}
+gdb_test "show endian" "$en_auto \\\(currently $endian endian\\\)" \
+    "previously little default executable endianness"
+if { [gdb_unload] } {
+    gdb_suppress_entire_file "$pf_prefix cannot unselect executable"
+}
+gdb_test "show endian" "$en_auto \\\(currently $endian endian\\\)" \
+    "previously little default no executable endianness"