This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Fix x86-64 GNU/Linux crashes


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c55a47e7237ebac17df73183d214d90400a49455

commit c55a47e7237ebac17df73183d214d90400a49455
Author: Pedro Alves <palves@redhat.com>
Date:   Thu Jul 13 20:56:42 2017 +0100

    Fix x86-64 GNU/Linux crashes
    
    Ref: https://sourceware.org/ml/gdb-patches/2017-07/msg00162.html
    
    Debugging x86-64 GNU/Linux programs currently crashes GDB in
    tdesc_use_registers during gdbarch initialization:
    
      Program received signal SIGSEGV, Segmentation fault.
      0x0000000001093eaf in htab_remove_elt_with_hash (htab=0x2ef9fa0, element=0x26af960, hash=557151073) at src/libiberty/hashtab.c:728
      728       if (*slot == HTAB_EMPTY_ENTRY)
      (top-gdb) p slot
      $1 = (void **) 0x0
      (top-gdb) bt
      #0  0x0000000001093eaf in htab_remove_elt_with_hash (htab=0x2ef9fa0, element=0x26af960, hash=557151073) at src/libiberty/hashtab.c:728
      #1  0x0000000001093e79 in htab_remove_elt (htab=0x2ef9fa0, element=0x26af960) at src/libiberty/hashtab.c:714
      #2  0x00000000009121b0 in tdesc_use_registers (gdbarch=0x3001240, target_desc=0x2659cb0, early_data=0x2881cb0)
          at src/gdb/target-descriptions.c:1328
      #3  0x000000000047c93e in i386_gdbarch_init (info=..., arches=0x0) at src/gdb/i386-tdep.c:8634
      #4  0x0000000000818d5f in gdbarch_find_by_info (info=...) at src/gdb/gdbarch.c:5394
      #5  0x00000000007198a8 in set_gdbarch_from_file (abfd=0x2f48250) at src/gdb/arch-utils.c:618
      #6  0x00000000007f21cb in exec_file_attach (filename=0x7fffffffddb0 "/home/pedro/gdb/tests/threads", from_tty=1) at src/gdb/exec.c:380
      #7  0x0000000000865c18 in catch_command_errors_const (command=0x7f1d83 <exec_file_attach(char const*, int)>, arg=0x7fffffffddb0 "/home/pedro/gdb/tests/threads",
          from_tty=1) at src/gdb/main.c:403
      #8  0x00000000008669cf in captured_main_1 (context=0x7fffffffd860) at src/gdb/main.c:1035
      #9  0x0000000000866de2 in captured_main (data=0x7fffffffd860) at src/gdb/main.c:1142
      #10 0x0000000000866e24 in gdb_main (args=0x7fffffffd860) at src/gdb/main.c:1160
      #11 0x000000000041312d in main (argc=3, argv=0x7fffffffd968) at src/gdb/gdb.c:32
    
    The direct cause of the crash is that we tried to remove an element
    from the hash which supposedly exists, but does not.  (htab_remove_elt
    shouldn't really crash in this case, but that's secondary.)
    
    The real problem is that early_data passed to tdesc_use_registers
    includes regs from a target description that is not the target_desc,
    which violates its assumptions.  The registers in question are the
    fs_base/gs_base registers, added by amd64_init_abi:
    
          tdesc_numbered_register (feature, tdesc_data_segments,
    		       AMD64_FSBASE_REGNUM, "fs_base");
          tdesc_numbered_register (feature, tdesc_data_segments,
    		       AMD64_GSBASE_REGNUM, "gs_base");
    
    and that happens because amd64_linux_init_abi uses amd64_init_abi as
    helper, but they don't coordinate on which fallback tdesc to use.
    
    amd64_init_abi does:
    
      if (! tdesc_has_registers (tdesc))
        tdesc = tdesc_amd64;
    
    and then adds the fs_base/gs_base registers of the "tdesc_amd64" tdesc
    to the tdesc_arch_data.
    
    After amd64_init_abi returns, amd64_linux_init_abi does:
    
      if (! tdesc_has_registers (tdesc))
        tdesc = tdesc_amd64_linux;
      tdep->tdesc = tdesc;
    
    and we end up tdesc_amd64_linux installed in tdep->tdesc.
    
    The fix is to make sure that amd64_linux_init_abi and amd64_init_abi
    agree on default tdesc, by adding a "default tdesc" parameter to
    amd64_init_abi, instead of having amd64_init_abi hardcode a default.
    With this, amd64_init_abi creates the fs_base/gs_base registers using
    the tdesc_amd64_linux tdesc.
    
    Tested on x86-64 GNU/Linux, -m64.  I don't have an x32 setup handy.
    
    Thanks to John Baldwin, Yao Qi and Simon Marchi for the investigation.
    
    gdb/ChangeLog:
    2017-07-13  Pedro Alves  <palves@redhat.com>
    
    	* amd64-darwin-tdep.c (x86_darwin_init_abi_64): Pass tdesc_amd64
    	as default tdesc.
    	* amd64-dicos-tdep.c (amd64_dicos_init_abi):
    	* amd64-fbsd-tdep.c (amd64fbsd_init_abi):
    	* amd64-linux-tdep.c (amd64_linux_init_abi): Pass
    	tdesc_amd64_linux as default tdesc.  Get final tdesc from the
    	tdep.
    	(amd64_x32_linux_init_abi): Pass tdesc_x32_linux as default tdesc.
    	Get final tdesc from the tdep.
    	* amd64-nbsd-tdep.c (amd64nbsd_init_abi): Pass tdesc_amd64 as
    	default tdesc.
    	* amd64-obsd-tdep.c (amd64obsd_init_abi): Likewise.
    	* amd64-sol2-tdep.c (amd64_sol2_init_abi): Likewise.
    	* amd64-tdep.c (amd64_init_abi): Add 'default_tdesc' parameter.
    	Use it as default tdesc.
    	(amd64_x32_init_abi): Add 'default_tdesc' parameter, and pass it
    	down to amd_init_abi.  No longer handle fallback tdesc here.
    	* amd64-tdep.h (tdesc_x32): Declare.
    	(amd64_init_abi, amd64_x32_init_abi): Add 'default_tdesc'
    	parameter.
    	* amd64-windows-tdep.c (amd64_windows_init_abi): Pass tdesc_amd64
    	as default tdesc.

Diff:
---
 gdb/ChangeLog            | 25 +++++++++++++++++++++++++
 gdb/amd64-darwin-tdep.c  |  2 +-
 gdb/amd64-dicos-tdep.c   |  2 +-
 gdb/amd64-fbsd-tdep.c    |  2 +-
 gdb/amd64-linux-tdep.c   | 16 +++++-----------
 gdb/amd64-nbsd-tdep.c    |  2 +-
 gdb/amd64-obsd-tdep.c    |  2 +-
 gdb/amd64-sol2-tdep.c    |  2 +-
 gdb/amd64-tdep.c         | 15 ++++++---------
 gdb/amd64-tdep.h         | 13 +++++++++++--
 gdb/amd64-windows-tdep.c |  2 +-
 11 files changed, 54 insertions(+), 29 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 37fe06e..3210957 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,28 @@
+2017-07-13  Pedro Alves  <palves@redhat.com>
+
+	* amd64-darwin-tdep.c (x86_darwin_init_abi_64): Pass tdesc_amd64
+	as default tdesc.
+	* amd64-dicos-tdep.c (amd64_dicos_init_abi):
+	* amd64-fbsd-tdep.c (amd64fbsd_init_abi):
+	* amd64-linux-tdep.c (amd64_linux_init_abi): Pass
+	tdesc_amd64_linux as default tdesc.  Get final tdesc from the
+	tdep.
+	(amd64_x32_linux_init_abi): Pass tdesc_x32_linux as default tdesc.
+	Get final tdesc from the tdep.
+	* amd64-nbsd-tdep.c (amd64nbsd_init_abi): Pass tdesc_amd64 as
+	default tdesc.
+	* amd64-obsd-tdep.c (amd64obsd_init_abi): Likewise.
+	* amd64-sol2-tdep.c (amd64_sol2_init_abi): Likewise.
+	* amd64-tdep.c (amd64_init_abi): Add 'default_tdesc' parameter.
+	Use it as default tdesc.
+	(amd64_x32_init_abi): Add 'default_tdesc' parameter, and pass it
+	down to amd_init_abi.  No longer handle fallback tdesc here.
+	* amd64-tdep.h (tdesc_x32): Declare.
+	(amd64_init_abi, amd64_x32_init_abi): Add 'default_tdesc'
+	parameter.
+	* amd64-windows-tdep.c (amd64_windows_init_abi): Pass tdesc_amd64
+	as default tdesc.
+
 2017-07-13  Andreas Arnez  <arnez@linux.vnet.ibm.com>
 
 	* s390-linux-tdep.c (s390_process_record): Add support for
diff --git a/gdb/amd64-darwin-tdep.c b/gdb/amd64-darwin-tdep.c
index db400cd..be26d9e 100644
--- a/gdb/amd64-darwin-tdep.c
+++ b/gdb/amd64-darwin-tdep.c
@@ -99,7 +99,7 @@ x86_darwin_init_abi_64 (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   tdep->struct_return = reg_struct_return;
 
diff --git a/gdb/amd64-dicos-tdep.c b/gdb/amd64-dicos-tdep.c
index ee40891..7bdb167 100644
--- a/gdb/amd64-dicos-tdep.c
+++ b/gdb/amd64-dicos-tdep.c
@@ -25,7 +25,7 @@
 static void
 amd64_dicos_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   dicos_init_abi (gdbarch);
 }
diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c
index 48bb209..ad4d787 100644
--- a/gdb/amd64-fbsd-tdep.c
+++ b/gdb/amd64-fbsd-tdep.c
@@ -217,7 +217,7 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (amd64fbsd_r_reg_offset);
   tdep->sizeof_gregset = 22 * 8;
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   tdep->sigtramp_p = amd64fbsd_sigtramp_p;
   tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr;
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 4ef0f78..cf24789 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1863,7 +1863,6 @@ static void
 amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  const struct target_desc *tdesc = info.target_desc;
   struct tdesc_arch_data *tdesc_data
     = (struct tdesc_arch_data *) info.tdep_info;
   const struct tdesc_feature *feature;
@@ -1875,15 +1874,13 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
   tdep->sizeof_gregset = 27 * 8;
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64_linux);
+
+  const target_desc *tdesc = tdep->tdesc;
 
   /* Reserve a number for orig_rax.  */
   set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS);
 
-  if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_amd64_linux;
-  tdep->tdesc = tdesc;
-
   feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
   if (feature == NULL)
     return;
@@ -2080,7 +2077,6 @@ static void
 amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  const struct target_desc *tdesc = info.target_desc;
   struct tdesc_arch_data *tdesc_data
     = (struct tdesc_arch_data *) info.tdep_info;
   const struct tdesc_feature *feature;
@@ -2092,14 +2088,12 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
   tdep->sizeof_gregset = 27 * 8;
 
-  amd64_x32_init_abi (info, gdbarch);
+  amd64_x32_init_abi (info, gdbarch, tdesc_x32_linux);
 
   /* Reserve a number for orig_rax.  */
   set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS);
 
-  if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_x32_linux;
-  tdep->tdesc = tdesc;
+  const target_desc *tdesc = tdep->tdesc;
 
   feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
   if (feature == NULL)
diff --git a/gdb/amd64-nbsd-tdep.c b/gdb/amd64-nbsd-tdep.c
index db6f19f..02bf427 100644
--- a/gdb/amd64-nbsd-tdep.c
+++ b/gdb/amd64-nbsd-tdep.c
@@ -103,7 +103,7 @@ amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
   tdep->sizeof_gregset = 26 * 8;
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   tdep->jb_pc_offset = 7 * 8;
 
diff --git a/gdb/amd64-obsd-tdep.c b/gdb/amd64-obsd-tdep.c
index 72895b6..ad90c20 100644
--- a/gdb/amd64-obsd-tdep.c
+++ b/gdb/amd64-obsd-tdep.c
@@ -419,7 +419,7 @@ amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
   obsd_init_abi (info, gdbarch);
 
   /* Initialize general-purpose register set details.  */
diff --git a/gdb/amd64-sol2-tdep.c b/gdb/amd64-sol2-tdep.c
index 51fe9db..ca474db 100644
--- a/gdb/amd64-sol2-tdep.c
+++ b/gdb/amd64-sol2-tdep.c
@@ -99,7 +99,7 @@ amd64_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (amd64_sol2_gregset_reg_offset);
   tdep->sizeof_gregset = 28 * 8;
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   tdep->sigtramp_p = amd64_sol2_sigtramp_p;
   tdep->sigcontext_addr = amd64_sol2_mcontext_addr;
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 9ff7dfc..6171bc5 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -3005,7 +3005,8 @@ static const int amd64_record_regmap[] =
 };
 
 void
-amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
+		target_desc *default_tdesc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   const struct target_desc *tdesc = info.target_desc;
@@ -3022,7 +3023,7 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->fpregset = &amd64_fpregset;
 
   if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_amd64;
+    tdesc = default_tdesc;
   tdep->tdesc = tdesc;
 
   tdep->num_core_regs = AMD64_NUM_GREGS + I387_NUM_REGS;
@@ -3196,16 +3197,12 @@ amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 }
 
 void
-amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
+		    target_desc *default_tdesc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  const struct target_desc *tdesc = info.target_desc;
-
-  amd64_init_abi (info, gdbarch);
 
-  if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_x32;
-  tdep->tdesc = tdesc;
+  amd64_init_abi (info, gdbarch, default_tdesc);
 
   tdep->num_dword_regs = 17;
   set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index 87f0ba3..d4c6c9a 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -88,6 +88,7 @@ enum amd64_regnum
 #define AMD64_NUM_REGS		(AMD64_GSBASE_REGNUM + 1)
 
 extern struct target_desc *tdesc_amd64;
+extern struct target_desc *tdesc_x32;
 
 extern struct displaced_step_closure *amd64_displaced_step_copy_insn
   (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to,
@@ -97,9 +98,17 @@ extern void amd64_displaced_step_fixup (struct gdbarch *gdbarch,
 					CORE_ADDR from, CORE_ADDR to,
 					struct regcache *regs);
 
-extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
+/* Initialize the ABI for amd64.  Uses DEFAULT_TDESC as fallback
+   tdesc, if INFO does not specify one.  */
+extern void amd64_init_abi (struct gdbarch_info info,
+			    struct gdbarch *gdbarch,
+			    target_desc *default_tdesc);
+
+/* Initialize the ABI for x32.  Uses DEFAULT_TDESC as fallback tdesc,
+   if INFO does not specify one.  */
 extern void amd64_x32_init_abi (struct gdbarch_info info,
-				struct gdbarch *gdbarch);
+				struct gdbarch *gdbarch,
+				target_desc *default_tdesc);
 extern const struct target_desc *amd64_target_description (uint64_t xcr0);
 
 /* Fill register REGNUM in REGCACHE with the appropriate
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index f1acdb9..9158282 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1224,7 +1224,7 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   */
   frame_unwind_append_unwinder (gdbarch, &amd64_windows_frame_unwind);
 
-  amd64_init_abi (info, gdbarch);
+  amd64_init_abi (info, gdbarch, tdesc_amd64);
 
   windows_init_abi (info, gdbarch);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]