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]

Re: [patch] Support bionic's jmp_buf.


On Mon, 2012-05-21 at 14:59 -0300, Thiago Jung Bauermann wrote:
> On Mon, 2012-05-21 at 12:38 +0100, Pedro Alves wrote:
> > On 05/21/2012 01:35 AM, Thiago Jung Bauermann wrote:
> > > I'm using the ELF interpreter field to identify an Android binary (the
> > > program loader is /system/bin/linker).
> > 
> > 
> > Urgh.  Isn't there a better way?  This doesn't work with shared libraries,
> > for starters.
> 
> There is. I thought of adding an Android flag to .note.ABI-tag and I
> even have a patch ready which adds it to Android  binaries. I gave up on
> it because I thought it was overkill but I can certainly use that if
> using the interpreter field is a worse solution.

I submitted a patch to bionic which adds a .note.ABI-tag to Android
binaries:

https://android-review.googlesource.com/37590

The note has a flag which is set to 1 if the binary is for the Android
platform.

The patch was accepted by the Google engineers and applied to their
internal tree. It wasn't merged yet to the AOSP tree because of
conflicts with some of their internal patches, but will be in the near
future.

The patch below checks the .note.ABI-tag if it is present. If it is not,
then it will fall back to checking the interpreter field. WDYT?

-- 
[]'s
Thiago Jung Bauermann
Linaro Toolchain Working Group


2012-06-24  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.
	* osabi.c (check_note): Remove static keyword.
	* osabi.h (check_note): New prototype.
	* 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..eac7602 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -33,6 +33,7 @@
 #include "tramp-frame.h"
 #include "breakpoint.h"
 #include "auxv.h"
+#include "elf/common.h"
 
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
@@ -105,6 +106,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 +1180,85 @@ 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;
+
+  if (exec_bfd
+      && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
+    {
+      struct bfd_section *abi_tag;
+
+      abi_tag = bfd_get_section_by_name (exec_bfd, ".note.ABI-tag");
+      if (abi_tag != NULL)
+	{
+	  int sect_size = bfd_section_size (exec_bfd, abi_tag);
+	  gdb_byte *note;
+
+	  note = alloca (sect_size);
+	  bfd_get_section_contents (exec_bfd, abi_tag, note, 0, sect_size);
+
+	  /* Android's .note.ABI-tag has two 32 bit integers after the
+	     kernel version, so it's description size is 24 bytes.  */
+	  if (!check_note (exec_bfd, abi_tag, note, "GNU", 24, NT_GNU_ABI_TAG))
+	    return 0;
+
+	  /* Check the OS.  */
+	  if (bfd_h_get_32 (exec_bfd, note + 16) != GNU_ABI_TAG_LINUX)
+	    return 0;
+
+	  /* Check the the OS variant (1 means Android).  */
+	  if (bfd_h_get_32 (exec_bfd, note + 32) != 1)
+	    return 0;
+
+	  return 1;
+	}
+    }
+
+  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 +1293,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/osabi.c b/gdb/osabi.c
index faffe30..9d3eef4 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -372,7 +372,7 @@ gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
 /* Return non-zero if NOTE matches NAME, DESCSZ and TYPE.  */
 
-static int
+int
 check_note (bfd *abfd, asection *sect, const char *note,
 	    const char *name, unsigned long descsz, unsigned long type)
 {
diff --git a/gdb/osabi.h b/gdb/osabi.h
index ced2fa5..ec3b948 100644
--- a/gdb/osabi.h
+++ b/gdb/osabi.h
@@ -54,4 +54,8 @@ const char *gdbarch_osabi_name (enum gdb_osabi);
    via bfd_map_over_sections.  */
 void generic_elf_osabi_sniff_abi_tag_sections (bfd *, asection *, void *);
 
+/* Return non-zero if NOTE matches NAME, DESCSZ and TYPE.  */
+int check_note (bfd *abfd, asection *sect, const char *note,
+		const char *name, unsigned long descsz, unsigned long type);
+
 #endif /* OSABI_H */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 307e483..cd3be82 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;
 
@@ -1528,7 +1528,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 */



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