This is the mail archive of the gdb-patches@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]

5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)


I came up with this patch so I could test the longjmp patches
on x86_64-unknown-linux-gnu and x86-pc-linux-gnu.  It was inspired on 
a 2006 patch by Jan Kratochvil.

I'm not proposing this to go in, as it will brake glibc's where
the pointer mangling is not implemented or is implemented
differently.  Maybe we could get around this 99% of the
times by switching the unmangling algorithm based on glibc's
version, although I don't know how to get at glibc's version.

-- 
Pedro Alves
2008-04-07  Pedro Alves  <pedro@codesourcery.com>

	* target.h (struct target_ops): Add new
	to_get_thread_control_block function pointer.
	(target_get_thread_control_block)
	(target_get_thread_control_block_p): New.
	* target.c (update_current_target): Inherit
	to_get_thread_control_block.

	* i386-tdep.h (i386_get_longjmp_target): Declare.
	* i386-tdep.c (i386_get_longjmp_target): Make public.
	* i386-linux-tdep.c (ror32): New macro.
	(i386_linux_pointer_demangle): New.
	(i386_linux_get_longjmp_target): New.
	* i386-linux-nat.c (i386_linux_get_thread_control_block): New.
	(_initialize_i386_linux_nat): Register
	i386_linux_get_thread_control_block as to_get_thread_control_block
	target method.

	* amd64-tdep.h (amd64_get_longjmp_target): Declare.
	* amd64-tdep.c (amd64_get_longjmp_target): Make public.
	* amd64-linux-tdep.c: Include "target.h" and "inferior.h".
	(ror64): New macro.
	(amd64_linux_pointer_demangle): New.
	(amd64_linux_get_longjmp_target): New.
	(amd64_linux_init_abi): Set tdep->jb_pc_offset.  Register
	amd64_linux_get_longjmp_target as gdbarch_get_longjmp_target
	callback.
	* amd64-linux-nat.c (amd64_linux_get_thread_control_block): New.
	(_initialize_amd64_linux_nat): Register
	amd64_linux_get_thread_control_block as
	to_get_thread_control_block target method.

	* Makefile.in (amd64-linux-nat.o): Update.

---
 gdb/Makefile.in        |    3 ++-
 gdb/amd64-linux-nat.c  |   25 +++++++++++++++++++++++++
 gdb/amd64-linux-tdep.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/amd64-tdep.c       |    2 +-
 gdb/amd64-tdep.h       |    2 ++
 gdb/i386-linux-nat.c   |   32 ++++++++++++++++++++++++++++++++
 gdb/i386-linux-tdep.c  |   43 +++++++++++++++++++++++++++++++++++++++++++
 gdb/i386-tdep.c        |    2 +-
 gdb/i386-tdep.h        |    2 ++
 gdb/target.c           |    1 +
 gdb/target.h           |    7 +++++++
 11 files changed, 165 insertions(+), 3 deletions(-)

Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/i386-tdep.c	2008-04-07 01:32:50.000000000 +0100
@@ -1297,7 +1297,7 @@ i386_unwind_dummy_id (struct gdbarch *gd
    This address is copied into PC.  This routine returns non-zero on
    success.  */
 
-static int
+int
 i386_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   gdb_byte buf[4];
Index: src/gdb/i386-linux-nat.c
===================================================================
--- src.orig/gdb/i386-linux-nat.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/i386-linux-nat.c	2008-04-07 01:32:50.000000000 +0100
@@ -713,6 +713,36 @@ ps_get_thread_area (const struct ps_proc
   *(int *)base = desc[1];
   return PS_OK;
 }
+
+static CORE_ADDR
+i386_linux_get_thread_control_block (ptid_t ptid)
+{
+  int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+  struct regcache *regcache = get_thread_regcache (ptid);
+  void *tcbhead;
+  ULONGEST gs;
+  const int reg_thread_area = 3; /* bits to scale down register value.  */
+  int idx;
+  ps_err_e ps_err;
+  struct ps_prochandle prochandle;
+
+  regcache_cooked_read_unsigned (regcache, I386_GS_REGNUM, &gs);
+
+  /* TODO: We should provide a pseudo-register with this info, and get
+     rid of this target method; or if this interface is the best we
+     can do, ps_get_thread_area should consume from this target
+     method.  */
+
+  idx = gs >> reg_thread_area;
+  prochandle.pid = ptid_get_pid (ptid);
+  ps_err = ps_get_thread_area (&prochandle, prochandle.pid, idx, &tcbhead);
+  if (ps_err != PS_OK)
+    error (_("Error %d while getting the TCB of %s"),
+	   (int) ps_err, target_pid_to_str (ptid));
+
+  return (CORE_ADDR) tcbhead;
+}
+
 
 
 /* The instruction for a GNU/Linux system call is:
@@ -833,6 +863,8 @@ _initialize_i386_linux_nat (void)
   t->to_fetch_registers = i386_linux_fetch_inferior_registers;
   t->to_store_registers = i386_linux_store_inferior_registers;
 
+  t->to_get_thread_control_block = i386_linux_get_thread_control_block;
+
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, i386_linux_new_thread);
Index: src/gdb/i386-linux-tdep.c
===================================================================
--- src.orig/gdb/i386-linux-tdep.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/i386-linux-tdep.c	2008-04-07 01:32:50.000000000 +0100
@@ -402,6 +402,49 @@ static int i386_linux_sc_reg_offset[] =
   0 * 4				/* %gs */
 };
 
+/* Rotate right X by N bits.  */
+#define ror32(x, n) (((x) >> ((int) (n))) | ((x) << (32 - (int) (n))))
+
+static CORE_ADDR
+i386_linux_pointer_demangle (CORE_ADDR address)
+{
+  CORE_ADDR tcbhead;
+  CORE_ADDR pointer_guard;
+  gdb_byte buf[4];
+
+  /* The pointer guard is stored in tcbhead, at
+     offsetof (tcbhead_t, pointer_guard).  */
+
+  if (!target_get_thread_control_block_p ())
+    /* Nothing we can do.  */
+    return address;
+
+  tcbhead = target_get_thread_control_block (inferior_ptid);
+
+  /* Wear sunglasses, please.  This is private data.  */
+
+  read_memory (tcbhead + 0x18 /* offsetof (tcbhead_t, pointer_guard) */,
+	       buf, 4);
+  pointer_guard = extract_unsigned_integer (buf, 4);
+
+  address = ror32 (address, 9);
+  address ^= pointer_guard;
+  return address;
+}
+
+/* glibc pointer mangles the PC in jmp_buf.  We unmangle it here.  */
+
+static int
+i386_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  if (!i386_get_longjmp_target (frame, pc))
+    return 0;
+
+  *pc = i386_linux_pointer_demangle (*pc);
+
+  return 1;
+}
+
 static void
 i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
Index: src/gdb/i386-tdep.h
===================================================================
--- src.orig/gdb/i386-tdep.h	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/i386-tdep.h	2008-04-07 01:32:50.000000000 +0100
@@ -200,6 +200,8 @@ extern void i386_elf_init_abi (struct gd
 
 /* Initialize a SVR4 architecture variant.  */
 extern void i386_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
+
+extern int i386_get_longjmp_target (struct frame_info *, CORE_ADDR *);
 
 
 /* Functions and variables exported from i386bsd-tdep.c.  */
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/target.h	2008-04-07 01:32:50.000000000 +0100
@@ -432,6 +432,8 @@ struct target_ops
 					      CORE_ADDR load_module_addr,
 					      CORE_ADDR offset);
 
+    CORE_ADDR (*to_get_thread_control_block) (ptid_t ptid);
+
     /* Request that OPS transfer up to LEN 8-bit bytes of the target's
        OBJECT.  The OFFSET, for a seekable object, specifies the
        starting point.  The ANNEX can be used to provide additional
@@ -1018,6 +1020,11 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_get_thread_local_address_p() \
     (target_get_thread_local_address != NULL)
 
+/* TCB.  */
+#define target_get_thread_control_block \
+    (current_target.to_get_thread_control_block)
+#define target_get_thread_control_block_p() \
+    (current_target.to_get_thread_control_block != NULL)
 
 /* Hardware watchpoint interfaces.  */
 
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/target.c	2008-04-07 01:32:50.000000000 +0100
@@ -468,6 +468,7 @@ update_current_target (void)
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
+      INHERIT (to_get_thread_control_block, t);
       /* Do not inherit to_read_description.  */
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
Index: src/gdb/amd64-linux-nat.c
===================================================================
--- src.orig/gdb/amd64-linux-nat.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/amd64-linux-nat.c	2008-04-07 01:32:50.000000000 +0100
@@ -388,6 +388,29 @@ ps_get_thread_area (const struct ps_proc
     }
   return PS_ERR;               /* ptrace failed.  */
 }
+
+static CORE_ADDR
+amd64_linux_get_thread_control_block (ptid_t ptid)
+{
+  int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+  struct regcache *regcache = get_thread_regcache (ptid);
+  void *tcbhead;
+  ps_err_e ps_err;
+  struct ps_prochandle prochandle;
+  int idx = FS;
+
+  /* TODO: We should provide a pseudo-register with this info, and get
+     rid of this target method; or if this interface is the best we
+     can do, ps_get_thread_area should consume from this target
+     method.  */
+  prochandle.pid = ptid_get_pid (ptid);
+  ps_err = ps_get_thread_area (&prochandle, prochandle.pid, idx, &tcbhead);
+  if (ps_err != PS_OK)
+    error (_("Error %d while getting the TCB of %s"),
+	   (int) ps_err, target_pid_to_str (ptid));
+
+  return (CORE_ADDR) tcbhead;
+}
 
 
 static void (*super_post_startup_inferior) (ptid_t ptid);
@@ -431,6 +454,8 @@ _initialize_amd64_linux_nat (void)
   t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
   t->to_store_registers = amd64_linux_store_inferior_registers;
 
+  t->to_get_thread_control_block = amd64_linux_get_thread_control_block;
+
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
Index: src/gdb/amd64-linux-tdep.c
===================================================================
--- src.orig/gdb/amd64-linux-tdep.c	2008-04-07 01:32:42.000000000 +0100
+++ src/gdb/amd64-linux-tdep.c	2008-04-07 01:33:11.000000000 +0100
@@ -34,6 +34,9 @@
 #include "amd64-tdep.h"
 #include "solib-svr4.h"
 
+#include "target.h"
+#include "inferior.h"
+
 /* Mapping between the general-purpose registers in `struct user'
    format and GDB's register cache layout.  */
 
@@ -257,6 +260,49 @@ amd64_linux_write_pc (struct regcache *r
   regcache_cooked_write_unsigned (regcache, AMD64_LINUX_ORIG_RAX_REGNUM, -1);
 }
 
+/* Rotate right X by N bits.  */
+#define ror64(x, n) (((x) >> ((int) (n))) | ((x) << (64 - (int) (n))))
+
+static CORE_ADDR
+amd64_linux_pointer_demangle (CORE_ADDR address)
+{
+  CORE_ADDR tcbhead;
+  CORE_ADDR pointer_guard;
+  gdb_byte buf[8];
+
+  /* The pointer guard is stored in tcbhead, at
+     offsetof (tcbhead_t, pointer_guard).  */
+
+  if (!target_get_thread_control_block_p ())
+    /* Nothing we can do.  */
+    return address;
+
+  tcbhead = target_get_thread_control_block (inferior_ptid);
+
+  /* Wear sunglasses, please.  This is private data.  */
+
+  read_memory (tcbhead + 0x30 /* offsetof (tcbhead_t, pointer_guard) */,
+	       buf, 8);
+  pointer_guard = extract_unsigned_integer (buf, 8);
+
+  address = ror64 (address, 17);
+  address ^= pointer_guard;
+  return address;
+}
+
+/* glibc pointer mangles the PC in jmp_buf.  We unmangle it here.  */
+
+static int
+amd64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  if (!amd64_get_longjmp_target (frame, pc))
+    return 0;
+
+  *pc = amd64_linux_pointer_demangle (*pc);
+
+  return 1;
+}
+
 static void
 amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -273,6 +319,9 @@ amd64_linux_init_abi (struct gdbarch_inf
   tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
   tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
 
+  tdep->jb_pc_offset = 7 * 8;
+  set_gdbarch_get_longjmp_target (gdbarch, amd64_linux_get_longjmp_target);
+
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
     (gdbarch, svr4_lp64_fetch_link_map_offsets);
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/Makefile.in	2008-04-07 01:32:50.000000000 +0100
@@ -1860,7 +1860,8 @@ amd64fbsd-tdep.o: amd64fbsd-tdep.c $(def
 amd64-linux-nat.o: amd64-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
 	$(regcache_h) $(linux_nat_h) $(gdb_assert_h) $(gdb_string_h) \
 	$(gdb_proc_service_h) $(gregset_h) $(amd64_tdep_h) \
-	$(i386_linux_tdep_h) $(amd64_nat_h) $(amd64_linux_tdep_h)
+	$(i386_linux_tdep_h) $(amd64_nat_h) $(amd64_linux_tdep_h) \
+	$(target_h) $(inferior_h)
 amd64-linux-tdep.o: amd64-linux-tdep.c $(defs_h) $(frame_h) $(gdbcore_h) \
 	$(regcache_h) $(osabi_h) $(symtab_h) $(gdb_string_h) $(amd64_tdep_h) \
 	$(solib_svr4_h) $(gdbtypes_h) $(reggroups_h) $(amd64_linux_tdep_h)
Index: src/gdb/amd64-tdep.h
===================================================================
--- src.orig/gdb/amd64-tdep.h	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/amd64-tdep.h	2008-04-07 01:32:50.000000000 +0100
@@ -83,6 +83,8 @@ extern void amd64_supply_fxsave (struct 
 
 extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
 				  void *fxsave);
+
+extern int amd64_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc);
 
 
 /* Variables exported from amd64nbsd-tdep.c.  */
Index: src/gdb/amd64-tdep.c
===================================================================
--- src.orig/gdb/amd64-tdep.c	2008-04-07 01:31:55.000000000 +0100
+++ src/gdb/amd64-tdep.c	2008-04-07 01:32:50.000000000 +0100
@@ -1107,7 +1107,7 @@ amd64_regset_from_core_section (struct g
    address is copied into PC.  This routine returns non-zero on
    success.  */
 
-static int
+int
 amd64_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   gdb_byte buf[8];

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