* 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
@ 2008-04-07 6:31 Pedro Alves
0 siblings, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2008-04-07 6:31 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 484 bytes --]
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
[-- Attachment #2: longjmp_linux_x86_amd64_pointer_demangle.diff --]
[-- Type: text/x-diff, Size: 13466 bytes --]
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;
+}
+
\f
/* 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 *);
\f
/* 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;
+}
\f
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);
\f
/* 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];
^ permalink raw reply [flat|nested] 8+ messages in thread* 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
@ 2008-04-07 3:21 Pedro Alves
2008-04-07 23:02 ` Pedro Alves
0 siblings, 1 reply; 8+ messages in thread
From: Pedro Alves @ 2008-04-07 3:21 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 484 bytes --]
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
[-- Attachment #2: longjmp_linux_x86_amd64_pointer_demangle.diff --]
[-- Type: text/x-diff, Size: 13466 bytes --]
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;
+}
+
\f
/* 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 *);
\f
/* 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;
+}
\f
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);
\f
/* 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];
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-07 3:21 Pedro Alves
@ 2008-04-07 23:02 ` Pedro Alves
2008-04-14 19:02 ` Daniel Jacobowitz
0 siblings, 1 reply; 8+ messages in thread
From: Pedro Alves @ 2008-04-07 23:02 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 745 bytes --]
A Monday 07 April 2008 03:36:27, Pedro Alves wrote:
> 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.
Ooops, I only noticed now that due to a last-minute copy-pasting
I ended up posting a patch that missed a call to
set_gdbarch_get_longjmp_target on x86-pc-linux-gnu.
Updated patch attached.
--
Pedro Alves
[-- Attachment #2: longjmp_linux_x86_amd64_pointer_demangle.diff --]
[-- Type: text/x-diff, Size: 13904 bytes --]
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_init_abi): Register i386_linux_get_longjmp_target as
gdbarch_get_longjmp_target callback.
* 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 | 44 ++++++++++++++++++++++++++++++++++++++++++++
gdb/i386-tdep.c | 2 +-
gdb/i386-tdep.h | 2 ++
gdb/target.c | 1 +
gdb/target.h | 7 +++++++
11 files changed, 166 insertions(+), 3 deletions(-)
Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c 2008-04-07 13:50:57.000000000 +0100
+++ src/gdb/i386-tdep.c 2008-04-07 23:13:41.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 02:41:06.000000000 +0100
+++ src/gdb/i386-linux-nat.c 2008-04-07 13:50:58.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;
+}
+
\f
/* 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 02:41:05.000000000 +0100
+++ src/gdb/i386-linux-tdep.c 2008-04-07 23:19:23.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)
{
@@ -423,6 +466,7 @@ i386_linux_init_abi (struct gdbarch_info
tdep->sizeof_gregset = 17 * 4;
tdep->jb_pc_offset = 20; /* From <bits/setjmp.h>. */
+ set_gdbarch_get_longjmp_target (gdbarch, i386_linux_get_longjmp_target);
tdep->sigtramp_p = i386_linux_sigtramp_p;
tdep->sigcontext_addr = i386_linux_sigcontext_addr;
Index: src/gdb/i386-tdep.h
===================================================================
--- src.orig/gdb/i386-tdep.h 2008-04-07 02:41:05.000000000 +0100
+++ src/gdb/i386-tdep.h 2008-04-07 23:13:41.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 *);
\f
/* Functions and variables exported from i386bsd-tdep.c. */
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2008-04-07 02:41:06.000000000 +0100
+++ src/gdb/target.h 2008-04-07 13:50:58.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 02:41:06.000000000 +0100
+++ src/gdb/target.c 2008-04-07 13:50:58.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 02:41:05.000000000 +0100
+++ src/gdb/amd64-linux-nat.c 2008-04-07 13:50:58.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;
+}
\f
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 02:41:06.000000000 +0100
+++ src/gdb/amd64-linux-tdep.c 2008-04-07 23:13:41.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 13:50:56.000000000 +0100
+++ src/gdb/Makefile.in 2008-04-07 13:50:59.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 02:41:05.000000000 +0100
+++ src/gdb/amd64-tdep.h 2008-04-07 23:13:41.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);
\f
/* Variables exported from amd64nbsd-tdep.c. */
Index: src/gdb/amd64-tdep.c
===================================================================
--- src.orig/gdb/amd64-tdep.c 2008-04-07 13:50:57.000000000 +0100
+++ src/gdb/amd64-tdep.c 2008-04-07 23:13:41.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];
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-07 23:02 ` Pedro Alves
@ 2008-04-14 19:02 ` Daniel Jacobowitz
2008-04-14 19:24 ` Pedro Alves
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Jacobowitz @ 2008-04-14 19:02 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Mon, Apr 07, 2008 at 11:25:50PM +0100, Pedro Alves wrote:
> A Monday 07 April 2008 03:36:27, Pedro Alves wrote:
> > 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.
Darn, and you got my hopes up. I figured you'd come up with a clever
solution to this when I saw the patch subject.
Glibc stores the key in %fs:POINTER_GUARD, from whence we can
retrieve it, as in this patch. It also stores it in
__pointer_chk_guard_local (local to ld.so), and __pointer_chk_guard
(exported, but only on platfroms which do not put it in the TCB).
If you have an unstripped ld.so, you can retrieve it from that symbol.
Maybe that is good enough for now, and we can seek a better long-term
solution separately. Also, the location of the guard does not
definitively answer the question of whether it is used to mangle
jmp_bufs. ARM and MIPS don't use it at all. Perhaps we should
manually call setjmp to determine if the pointer is mangled?
Heck, from there we could deduce the canary and make this a single
glibc-specific method!
RMS asked us about a way to expose pointer mangling to gdb ages ago.
I believe Jan made this work via libthread_db, which I would prefer to
avoid (remote debugging, for instance). Failing that, I think we're
stuck with the symbol table.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-14 19:02 ` Daniel Jacobowitz
@ 2008-04-14 19:24 ` Pedro Alves
2008-04-14 19:56 ` Daniel Jacobowitz
0 siblings, 1 reply; 8+ messages in thread
From: Pedro Alves @ 2008-04-14 19:24 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
A Monday 14 April 2008 19:58:43, Daniel Jacobowitz wrote:
> On Mon, Apr 07, 2008 at 11:25:50PM +0100, Pedro Alves wrote:
> > A Monday 07 April 2008 03:36:27, Pedro Alves wrote:
> > > 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.
>
> Darn, and you got my hopes up. I figured you'd come up with a clever
> solution to this when I saw the patch subject.
>
Eh, sorry for not being cleverer :-)
Well, my main motivation was to get longjmp working in
non-stop mode, I made this patch just so I could test it.
> Glibc stores the key in %fs:POINTER_GUARD, from whence we can
> retrieve it, as in this patch. It also stores it in
> __pointer_chk_guard_local (local to ld.so), and __pointer_chk_guard
> (exported, but only on platfroms which do not put it in the TCB).
>
> If you have an unstripped ld.so, you can retrieve it from that symbol.
The key is not enough. There's also a 'rotate right' involved. That
seems to have changed through time, as Jan's patch didn't handle the ror,
just the xor.
> Maybe that is good enough for now, and we can seek a better long-term
> solution separately. Also, the location of the guard does not
> definitively answer the question of whether it is used to mangle
> jmp_bufs. ARM and MIPS don't use it at all.
True. I had thought that a solution based on detecting the
glibc version and demangling accordingly would be enough.
Why isn't it so? Is it plain impossible to
extract glibc's version?
> Perhaps we should
> manually call setjmp to determine if the pointer is mangled?
> Heck, from there we could deduce the canary and make this a single
> glibc-specific method!
>
I actually thought of doing this, but I seem to have grown
an aversion to the inferior function calls (due to them
not being async), so I never tried it, go figure.
This would have to be arch dependant, and would have to cope
with multiple versions or the algorithm. Does it mangle? Is it
a plan xor? It is rotated? By how many bits? Not so
much over-complicated tough.
> RMS asked us about a way to expose pointer mangling to gdb ages ago.
> I believe Jan made this work via libthread_db, which I would prefer to
> avoid (remote debugging, for instance). Failing that, I think we're
> stuck with the symbol table.
As I said, getting at the pointer_guard value is not enough.
--
Pedro Alves
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-14 19:24 ` Pedro Alves
@ 2008-04-14 19:56 ` Daniel Jacobowitz
2008-04-15 12:54 ` Daniel Jacobowitz
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Jacobowitz @ 2008-04-14 19:56 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Mon, Apr 14, 2008 at 08:20:06PM +0100, Pedro Alves wrote:
> The key is not enough. There's also a 'rotate right' involved. That
> seems to have changed through time, as Jan's patch didn't handle the ror,
> just the xor.
Yes, that does seem to be new (2007-02-01).
You could do this even more evilly. Do it by setting a breakpoint on
setjmp, recording information before and after, and then deleting the
breakpoint until we re-run. Yes, this is getting excessive. But
there shouldn't ever be a call to longjmp without a call to setjmp
first.
> > Maybe that is good enough for now, and we can seek a better long-term
> > solution separately. Also, the location of the guard does not
> > definitively answer the question of whether it is used to mangle
> > jmp_bufs. ARM and MIPS don't use it at all.
>
> True. I had thought that a solution based on detecting the
> glibc version and demangling accordingly would be enough.
>
> Why isn't it so? Is it plain impossible to
> extract glibc's version?
There's no interface for it. It's there, but only in the unstripped
symbol table like __pointer_chk_guard:
(gdb) x/s &__libc_version
0x2aaaab8f8cd8 <__libc_version>: "2.7"
That's not very fine-grained, either. And feature tests are more
robust than version tests, since they'd detect an unsupported
algorithm. I admit that the feature test is much harder...
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-14 19:56 ` Daniel Jacobowitz
@ 2008-04-15 12:54 ` Daniel Jacobowitz
2008-04-15 14:40 ` Pedro Alves
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Jacobowitz @ 2008-04-15 12:54 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
On Mon, Apr 14, 2008 at 03:30:49PM -0400, Daniel Jacobowitz wrote:
> You could do this even more evilly. Do it by setting a breakpoint on
> setjmp, recording information before and after, and then deleting the
> breakpoint until we re-run. Yes, this is getting excessive. But
> there shouldn't ever be a call to longjmp without a call to setjmp
> first.
Thinking about this more, how hard would it be to single-step through
longjmp instead? I'm sure there will be some platform where it
doesn't work, and that platform can use the current get_longjmp_target
mechanism, but for glibc platforms we could just step and see where we
end up, then decide whether to continue or stop.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64)
2008-04-15 12:54 ` Daniel Jacobowitz
@ 2008-04-15 14:40 ` Pedro Alves
0 siblings, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2008-04-15 14:40 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: gdb-patches
A Tuesday 15 April 2008 13:31:03, Daniel Jacobowitz wrote:
> On Mon, Apr 14, 2008 at 03:30:49PM -0400, Daniel Jacobowitz wrote:
> > You could do this even more evilly. Do it by setting a breakpoint on
> > setjmp, recording information before and after, and then deleting the
> > breakpoint until we re-run. Yes, this is getting excessive. But
> > there shouldn't ever be a call to longjmp without a call to setjmp
> > first.
>
> Thinking about this more, how hard would it be to single-step through
> longjmp instead?
That's how I used to do it manually whenever I wanted to step through
a gdb `error' call (it works on x86_64-unknown-linux-gnu at least), and
that's what I believe the ecs->handling_longjmp writer was trying to
achieve (someday when it would be finished).
If should be doable, but will take more work. you want to step
until you get to an outer frame than the longjmp frame -- you may have
to go through siglongjmp etc. infrun.c isn't ready to handle that,
as it stops stepping whenever you enter a new frame.
> I'm sure there will be some platform where it
> doesn't work, and that platform can use the current get_longjmp_target
> mechanism, but for glibc platforms we could just step and see where we
> end up, then decide whether to continue or stop.
Not sure what's easier, but should be doable as well, if the platform
enables stepping all the way through.
--
Pedro Alves
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-04-15 13:37 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-07 6:31 5/5 - handle glibc pointer mangling jmp_bufs (x86/x86_64) Pedro Alves
-- strict thread matches above, loose matches on Subject: below --
2008-04-07 3:21 Pedro Alves
2008-04-07 23:02 ` Pedro Alves
2008-04-14 19:02 ` Daniel Jacobowitz
2008-04-14 19:24 ` Pedro Alves
2008-04-14 19:56 ` Daniel Jacobowitz
2008-04-15 12:54 ` Daniel Jacobowitz
2008-04-15 14:40 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox