This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] Support bionic's jmp_buf.
- From: Thiago Jung Bauermann <thiago dot bauermann at linaro dot org>
- To: gdb-patches ml <gdb-patches at sourceware dot org>
- Date: Sun, 20 May 2012 21:35:28 -0300
- Subject: [patch] Support bionic's jmp_buf.
Hello,
Android uses a libc (bionic) which is derived from BSD instead of glibc,
and stores the PC value at a different location in the jump buffer than
regular arm-linux. Also, since there's no PC mangling this code works
even without SystemTap probes.
I'm using the ELF interpreter field to identify an Android binary (the
program loader is /system/bin/linker). Also, I had to change
gdbarch_tdep->jb_pc to a function so that the code to determine which
kind of program we are dealing with runs when the value is actually
needed. This is because by the time arm_linux_init_abi is called
exec_bfd hasn't been set yet so there's no way to peek at the ELF
interpreter field.
This patch fixes gdb.base/longjmp.exp.
There are no regressions on arm-linux native, arm-linux remote or
i386-linux native.
Ok?
--
[]'s
Thiago Jung Bauermann
Linaro Toolchain Working Group
2012-05-20 Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Support bionic's jmp_buf.
* arm-linux-tdep.c (ARM_LINUX_JB_PC_ANDROID): New macro.
(is_target_linux_android): New function.
(arm_linux_jb_pc): Likewise.
(arm_linux_init_abi): Set tdep->jb_pc to arm_linux_jb_pc
instead of determining the jb_pc value right away.
* arm-tdep.c (arm_get_longjmp_target): Call tdep->jb_pc.
(arm_gdbarch_init): tdep->jb_pc is now a pointer. Assign it
and test its value accordingly.
* arm-tdep.h (struct gdbarch_tdep): Change jb_pc to a
function pointer.
* arm-wince-tdep.c (arm_wince_jb_pc): New function.
(arm_wince_init_abi): Set tdep->jb_pc to arm_wince_jb_pc.
* armnbsd-tdep.c (arm_netbsd_jb_pc): New function.
(arm_netbsd_init_abi_common): Set tdep->jb_pc to arm_netbsd_jb_pc.
* armobsd-tdep.c (arm_obsd_jb_pc): New function.
(armobsd_init_abi): Set tdep->jb_pc to arm_obsd_jb_pc.
* solib-svr4.c (find_program_interpreter): Remove static keyword.
Rename to ...
(find_elf_program_interpreter): ... this.
* solib-svr4.h (find_program_interpreter): New prototype.
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index f4eaa5c..b9d67b0 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -105,6 +105,7 @@ static const char arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa0 };
#define ARM_LINUX_JB_ELEMENT_SIZE INT_REGISTER_SIZE
#define ARM_LINUX_JB_PC_FPA 21
#define ARM_LINUX_JB_PC_EABI 9
+#define ARM_LINUX_JB_PC_ANDROID 29
/*
Dynamic Linking on ARM GNU/Linux
@@ -1178,6 +1179,54 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
return 1;
}
+/* Determines whether the inferior is an Android application. */
+
+static int
+is_target_linux_android (void)
+{
+ int ret = 0;
+ gdb_byte *interp;
+
+ interp = find_elf_program_interpreter ();
+ if (interp)
+ {
+ ret = !strcmp (interp, "/system/bin/linker");
+ xfree (interp);
+ }
+
+ return ret;
+}
+
+/* Implements the gdbarch_tdep.jb_pc function in arm-tdep.h. */
+
+static CORE_ADDR
+arm_linux_jb_pc (struct gdbarch_tdep *tdep)
+{
+ int jb_pc;
+
+ switch (tdep->fp_model)
+ {
+ case ARM_FLOAT_FPA:
+ jb_pc = ARM_LINUX_JB_PC_FPA;
+ break;
+ case ARM_FLOAT_SOFT_FPA:
+ case ARM_FLOAT_SOFT_VFP:
+ case ARM_FLOAT_VFP:
+ jb_pc = ARM_LINUX_JB_PC_EABI;
+ break;
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ _("arm_linux_init_abi: Floating point model not supported"));
+ break;
+ }
+
+ if (is_target_linux_android ())
+ jb_pc = ARM_LINUX_JB_PC_ANDROID;
+
+ return jb_pc;
+}
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -1212,22 +1261,7 @@ arm_linux_init_abi (struct gdbarch_info info,
if (tdep->fp_model == ARM_FLOAT_AUTO)
tdep->fp_model = ARM_FLOAT_FPA;
- switch (tdep->fp_model)
- {
- case ARM_FLOAT_FPA:
- tdep->jb_pc = ARM_LINUX_JB_PC_FPA;
- break;
- case ARM_FLOAT_SOFT_FPA:
- case ARM_FLOAT_SOFT_VFP:
- case ARM_FLOAT_VFP:
- tdep->jb_pc = ARM_LINUX_JB_PC_EABI;
- break;
- default:
- internal_error
- (__FILE__, __LINE__,
- _("arm_linux_init_abi: Floating point model not supported"));
- break;
- }
+ tdep->jb_pc = arm_linux_jb_pc;
tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
set_solib_svr4_fetch_link_map_offsets
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index df5dea7..d1aa6b5 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -9083,12 +9083,13 @@ arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
struct gdbarch *gdbarch = get_frame_arch (frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR jb_addr;
+ CORE_ADDR jb_addr, jb_pc;
char buf[INT_REGISTER_SIZE];
-
+
jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
+ jb_pc = tdep->jb_pc (tdep);
- if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
+ if (target_read_memory (jb_addr + jb_pc * tdep->jb_elt_size, buf,
INT_REGISTER_SIZE))
return 0;
@@ -10132,7 +10133,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* This should be low enough for everything. */
tdep->lowest_pc = 0x20;
- tdep->jb_pc = -1; /* Longjump support not enabled by default. */
+ tdep->jb_pc = NULL; /* Longjump support not enabled by default. */
/* The default, for both APCS and AAPCS, is to return small
structures in registers. */
@@ -10236,7 +10237,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
if (tdep->fp_model == ARM_FLOAT_AUTO)
tdep->fp_model = ARM_FLOAT_SOFT_FPA;
- if (tdep->jb_pc >= 0)
+ if (tdep->jb_pc != NULL)
set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
/* Floating point sizes and format. */
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 97596d5..b95d548 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -185,9 +185,9 @@ struct gdbarch_tdep
const char *thumb2_breakpoint;
int thumb2_breakpoint_size;
- int jb_pc; /* Offset to PC value in jump buffer.
- If this is negative, longjmp support
- will be disabled. */
+ /* Return offset to PC value in jump buffer. If this is NULL, longjmp
+ support will be disabled. */
+ CORE_ADDR (*jb_pc) (struct gdbarch_tdep *tdep);
size_t jb_elt_size; /* And the size of each entry in the buf. */
/* Convention for returning structures. */
diff --git a/gdb/arm-wince-tdep.c b/gdb/arm-wince-tdep.c
index 5bc6473..ce04ba0 100644
--- a/gdb/arm-wince-tdep.c
+++ b/gdb/arm-wince-tdep.c
@@ -111,6 +111,14 @@ arm_wince_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
return pc;
}
+/* Implements the gdbarch_tdep.jb_pc function in arm-tdep.h. */
+
+static CORE_ADDR
+arm_wince_jb_pc (struct gdbarch_tdep *tdep)
+{
+ return ARM_WINCE_JB_PC;
+}
+
static void
arm_wince_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -124,7 +132,7 @@ arm_wince_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
- tdep->jb_pc = ARM_WINCE_JB_PC;
+ tdep->jb_pc = arm_wince_jb_pc;
tdep->jb_elt_size = ARM_WINCE_JB_ELEMENT_SIZE;
/* On ARM WinCE char defaults to signed. */
diff --git a/gdb/armnbsd-tdep.c b/gdb/armnbsd-tdep.c
index 19aa000..144bd85 100644
--- a/gdb/armnbsd-tdep.c
+++ b/gdb/armnbsd-tdep.c
@@ -36,6 +36,14 @@ static const char arm_nbsd_arm_be_breakpoint[] = {0xe6, 0x00, 0x00, 0x11};
static const char arm_nbsd_thumb_le_breakpoint[] = {0xfe, 0xde};
static const char arm_nbsd_thumb_be_breakpoint[] = {0xde, 0xfe};
+/* Implements the gdbarch_tdep.jb_pc function in arm-tdep.h. */
+
+static CORE_ADDR
+arm_netbsd_jb_pc (struct gdbarch_tdep *tdep)
+{
+ return ARM_NBSD_JB_PC;
+}
+
static void
arm_netbsd_init_abi_common (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -64,7 +72,7 @@ arm_netbsd_init_abi_common (struct gdbarch_info info,
_("arm_gdbarch_init: bad byte order for float format"));
}
- tdep->jb_pc = ARM_NBSD_JB_PC;
+ tdep->jb_pc = arm_netbsd_jb_pc;
tdep->jb_elt_size = ARM_NBSD_JB_ELEMENT_SIZE;
/* Single stepping. */
diff --git a/gdb/armobsd-tdep.c b/gdb/armobsd-tdep.c
index fab4e42..e48eeaa 100644
--- a/gdb/armobsd-tdep.c
+++ b/gdb/armobsd-tdep.c
@@ -74,6 +74,14 @@ static const struct tramp_frame armobsd_sigframe =
static const char arm_obsd_thumb_le_breakpoint[] = {0xfe, 0xdf};
static const char arm_obsd_thumb_be_breakpoint[] = {0xdf, 0xfe};
+/* Implements the gdbarch_tdep.jb_pc function in arm-tdep.h. */
+
+static CORE_ADDR
+armobsd_jb_pc (struct gdbarch_tdep *tdep)
+{
+ return 24;
+}
+
static void
armobsd_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -90,7 +98,7 @@ armobsd_init_abi (struct gdbarch_info info,
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
- tdep->jb_pc = 24;
+ tdep->jb_pc = armobsd_jb_pc;
tdep->jb_elt_size = 4;
set_gdbarch_regset_from_core_section
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 69d3cb5..24f224f 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -496,8 +496,8 @@ read_program_header (int type, int *p_sect_size, int *p_arch_size)
/* Return program interpreter string. */
-static gdb_byte *
-find_program_interpreter (void)
+gdb_byte *
+find_elf_program_interpreter (void)
{
gdb_byte *buf = NULL;
@@ -1520,7 +1520,7 @@ enable_break (struct svr4_info *info, int from_tty)
/* Find the program interpreter; if not found, warn the user and drop
into the old breakpoint at symbol code. */
- interp_name = find_program_interpreter ();
+ interp_name = find_elf_program_interpreter ();
if (interp_name)
{
CORE_ADDR load_addr = 0;
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index f9a02c9..87f088d 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -84,4 +84,7 @@ extern struct link_map_offsets *svr4_lp64_fetch_link_map_offsets (void);
SVR4 run time loader. */
int svr4_in_dynsym_resolve_code (CORE_ADDR pc);
+/* Return program interpreter string. */
+gdb_byte *find_elf_program_interpreter (void);
+
#endif /* solib-svr4.h */