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: x32 ABI Support (was Re: Three weeks to branching (gdb 7.5 release))


On Mon, May 28, 2012 at 2:18 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, May 28, 2012 at 1:26 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> Date: Sun, 20 May 2012 15:48:54 -0700
>>> From: "H.J. Lu" <hjl.tools@gmail.com>
>>>
>>> Does this one look OK. ?I extracted x32_init_abi from amd64_x32_init_abi
>>> since amd64_x32_linux_init_abi can't call amd64_init_abi after
>>> calling amd64_linux_init_abi.
>>
>> I guess multiple-inheritance is a bad idea, even when implemented in C ;)
>>
>> I really do think that amd64_x32_linux_init_abi() should call
>> amd64_x32_init_abi(). ?That way it is immediately obvious that the OS-specific ABI inherits everything from the generic ABI.
>
> X32 kernel interface are highly OS specific. ?Different OSes can implement
> very different kernel interfaces. ?The only generic x32 bits are
>
> ?struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>
> ?tdep->num_dword_regs = 17;
>
> ?set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
>
> ?set_gdbarch_long_bit (gdbarch, 32);
> ?set_gdbarch_ptr_bit (gdbarch, 32);
>
> They are the same for all x32 OSes since they are determined by
> hardware, not OS.
>
>> In order too avoid too much code duplication, the common bits should
>> be split out from amd64_linux_init_abi() into a seperate function that
>> gets called from both amd64_linux_init_abi() and
>> amd64_x32_linux_init_abi(). ?As I wrote earlier, it isn't entirely
>> obvious that everything in amd64_linix_init_abi() applies to the x32
>> ABI. ?So we should be conservative in moving stuff into the common
>> function. ?In fact it might be a good idea to start out with something
>> like the attached diff, and gradually move things over.
>
> Linux x32 kernel interface shares > 90% of Linux amd64 kernel
> interface (309 system calls out of 337 are the same). ?See
> 64-bit system call table in Linux kernel 3.4:
>
> http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=blob;f=arch/x86/syscalls/syscall_64.tbl;h=dd29a9ea27c560a9d2fcb6e1c2983f8b8e9be407;hb=HEAD
>
> I believe we should start with sharing everything between Linux/x32
> and Linux/amd64. ?We can update x32 part as we go.
>
>> Cheers,
>>
>> Mark
>>
>> Index: amd64-linux-tdep.c
>> ===================================================================
>> RCS file: /cvs/src/src/gdb/amd64-linux-tdep.c,v
>> retrieving revision 1.50
>> diff -u -p -r1.50 amd64-linux-tdep.c
>> --- amd64-linux-tdep.c ?12 May 2012 08:54:03 -0000 ? ? ?1.50
>> +++ amd64-linux-tdep.c ?28 May 2012 20:24:28 -0000
>> @@ -1298,8 +1298,6 @@ amd64_linux_init_abi (struct gdbarch_inf
>>
>> ? gdb_assert (tdesc_data);
>>
>> - ?linux_init_abi (info, gdbarch);
>> -
>> ? tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
>> ? tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
>> ? tdep->sizeof_gregset = 27 * 8;
>> @@ -1323,6 +1321,8 @@ amd64_linux_init_abi (struct gdbarch_inf
>> ? if (!valid_p)
>> ? ? return;
>>
>> + ?linux_init_abi (info, gdbarch);
>> +
>> ? tdep->sigtramp_p = amd64_linux_sigtramp_p;
>> ? tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
>> ? tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
>> @@ -1543,6 +1543,44 @@ amd64_linux_init_abi (struct gdbarch_inf
>>
>> ? tdep->i386_syscall_record = amd64_linux_syscall_record;
>> ?}
>> +
>> +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;
>> +
>> + ?gdb_assert (tdesc_data);
>> +
>> + ?tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
>> + ?tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
>> + ?tdep->sizeof_gregset = 27 * 8;
>> +
>> + ?amd64_x32_init_abi (info, gdbarch);
>> +
>> + ?/* 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;
>> +
>> + ?feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
>> + ?if (feature == NULL)
>> + ? ?return;
>> +
>> + ?valid_p = tdesc_numbered_register (feature, tdesc_data,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?AMD64_LINUX_ORIG_RAX_REGNUM,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"orig_rax");
>> + ?if (!valid_p)
>> + ? ?return;
>> +
>> + ?linux_init_abi (info, gdbarch);
>> +
>> + ?/* GNU/Linux uses SVR4-style shared libraries. ?*/
>> + ?set_solib_svr4_fetch_link_map_offsets
>> + ? ?(gdbarch, svr4_ilp32_fetch_link_map_offsets);
>> +}
>
> These won't work for x32. ?We have to copy almost everything in
> amd64_linux_init_abi.
>
>> +void
>> +amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> + ?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;
>> +
>> + ?tdep->num_dword_regs = 17;
>> + ?set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
>> +
>> + ?set_gdbarch_long_bit (gdbarch, 32);
>> + ?set_gdbarch_ptr_bit (gdbarch, 32);
>> +}
>>
>
> I think this is the wrong approach for x32 support. We should
> break amd64_x32_init_abi into 2 parts:
>
> 1. OS specific part. ?It should be private to amd64-tdep.c.
> 2. Generic part. ?It should be exported from amd64-tdep.c and can
> be used by all x32 OSes.
>
> Thanks.
>
>

Here is the updated patch.  I added amd64_x32_init for generic x32
setting.  It can be used by all x32 init_abi functions.  Since
tdep->tdesc can't be changed after being used, I renamed
amd64_init_abi/amd64_init_abi to amd64_init/amd64_linux_init
to take an  argument to set tdep->tdesc properly.  OK for trunk?

Thanks.


-- 
H.J.
---
2012-05-31  Mark Kettenis  <kettenis@gnu.org>
	    H.J. Lu  <hongjiu.lu@intel.com>

	* amd64-linux-tdep.c (amd64_linux_init_abi): Renamed to ...
	(amd64_linux_init): This.  Add an argument, amd64_linux_tdesc.
	(amd64_linux_init_abi): Call amd64_linux_init.
	(amd64_x32_linux_init_abi): New function.
	(_initialize_amd64_linux_tdep): Register bfd_mach_x64_32 with
	amd64_x32_linux_init_abi.

	* amd64-tdep.c (amd64_dword_names): Add "eip".
	(amd64_x32_pseudo_register_type): New function.
	(amd64_x32_init): Likewise.
	(amd64_x32_init_abi): Likewise.
	(amd64_init_abi): Renamed to ...
	(amd64_init): This. Add an argument, amd64_tdesc.
	(amd64_init_abi): Call amd64_init.

	* amd64-tdep.h (amd64_x32_init_abi): New prototype.
	(amd64_x32_init): Likewise.

	* i386-tdep.c (i386_pseudo_register_type): Make it global.

	* i386-tdep.h (i386_pseudo_register_type): New prototype.

diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 42dc89a..23bf318 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1288,7 +1288,8 @@ amd64_linux_core_read_description (struct
gdbarch *gdbarch,
 }

 static void
-amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+amd64_linux_init (struct gdbarch_info info, struct gdbarch *gdbarch,
+		  const struct target_desc *amd64_linux_tdesc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   const struct target_desc *tdesc = info.target_desc;
@@ -1310,9 +1311,10 @@ amd64_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
   set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS);

   if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_amd64_linux;
+    tdesc = amd64_linux_tdesc;
   tdep->tdesc = tdesc;

+  /* tdep->tdesc can't be changed after being used here.  */
   feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux");
   if (feature == NULL)
     return;
@@ -1543,6 +1545,24 @@ amd64_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)

   tdep->i386_syscall_record = amd64_linux_syscall_record;
 }
+
+static void
+amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  amd64_linux_init (info, gdbarch, tdesc_amd64_linux);
+}
+
+static void
+amd64_x32_linux_init_abi (struct gdbarch_info info,
+			  struct gdbarch *gdbarch)
+{
+  amd64_linux_init (info, gdbarch, tdesc_x32_linux);
+  amd64_x32_init (gdbarch);
+
+   /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+}



 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -1553,6 +1573,8 @@ _initialize_amd64_linux_tdep (void)
 {
   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
 			  GDB_OSABI_LINUX, amd64_linux_init_abi);
+  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32,
+			  GDB_OSABI_LINUX, amd64_x32_linux_init_abi);

   /* Initialize the Linux target description.  */
   initialize_tdesc_amd64_linux ();
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index df91a51..47f8019 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -258,9 +258,32 @@ static const char *amd64_word_names[] =
 static const char *amd64_dword_names[] =
 {
   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
-  "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
+  "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
+  "eip"
 };

+/* Return the GDB type object for the "standard" data type of data in
+   register REGNUM.  Only used for x32.  */
+
+static struct type *
+amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  /* Use pointer types for ebp, esp and eip registers in x32.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  switch (regnum - tdep->eax_regnum)
+    {
+    default:
+      break;
+    case AMD64_RBP_REGNUM:	/* ebp  */
+    case AMD64_RSP_REGNUM:	/* esp	*/
+      return builtin_type (gdbarch)->builtin_data_ptr;
+    case AMD64_RIP_REGNUM:	/* eip */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+    }
+
+  return i386_pseudo_register_type (gdbarch, regnum);
+}
+
 /* Return the name of register REGNUM.  */

 static const char *
@@ -2606,8 +2629,9 @@ static const int amd64_record_regmap[] =
   AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM
 };

-void
-amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+static void
+amd64_init (struct gdbarch_info info, struct gdbarch *gdbarch,
+	    const struct target_desc *amd64_tdesc)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   const struct target_desc *tdesc = info.target_desc;
@@ -2617,12 +2641,13 @@ amd64_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
   tdep->sizeof_fpregset = I387_SIZEOF_FXSAVE;

   if (! tdesc_has_registers (tdesc))
-    tdesc = tdesc_amd64;
+    tdesc = amd64_tdesc;
   tdep->tdesc = tdesc;

   tdep->num_core_regs = AMD64_NUM_GREGS + I387_NUM_REGS;
   tdep->register_names = amd64_register_names;

+  /* tdep->tdesc can't be changed after being used here.  */
   if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx") != NULL)
     {
       tdep->ymmh_register_names = amd64_ymmh_names;
@@ -2730,6 +2755,32 @@ amd64_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
 					i386_stap_parse_special_token);
 }

+void
+amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  amd64_init (info, gdbarch, tdesc_amd64);
+}
+
+void
+amd64_x32_init (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  tdep->num_dword_regs = 17;
+
+  set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
+
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_ptr_bit (gdbarch, 32);
+}
+
+void
+amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  amd64_init (info, gdbarch, tdesc_x32);
+  amd64_x32_init (gdbarch);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 void _initialize_amd64_tdep (void);

diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index 1ed109c..ce47ae7 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -80,6 +80,9 @@ extern void amd64_displaced_step_fixup (struct
gdbarch *gdbarch,
 					struct regcache *regs);

 extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
+extern void amd64_x32_init_abi (struct gdbarch_info info,
+				struct gdbarch *gdbarch);
+extern void amd64_x32_init (struct gdbarch *gdbarch);

 /* Fill register REGNUM in REGCACHE with the appropriate
    floating-point or SSE register value from *FXSAVE.  If REGNUM is
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 5b04505..6333556 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2780,7 +2780,7 @@ i386_mmx_type (struct gdbarch *gdbarch)
 /* Return the GDB type object for the "standard" data type of data in
    register REGNUM.  */

-static struct type *
+struct type *
 i386_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 {
   if (i386_mmx_regnum_p (gdbarch, regnum))
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index f297ae7..a12b1f5 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -307,6 +307,7 @@ extern int i386_dword_regnum_p (struct gdbarch
*gdbarch, int regnum);
 extern int i386_xmm_regnum_p (struct gdbarch *gdbarch, int regnum);
 extern int i386_ymm_regnum_p (struct gdbarch *gdbarch, int regnum);

+extern struct type *i386_pseudo_register_type (struct gdbarch *, int);
 extern const char *i386_pseudo_register_name (struct gdbarch *gdbarch,
 					      int regnum);


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