Lazily and dynamically create i386-linux target descriptions
authorYao Qi <yao.qi@linaro.org>
Wed, 26 Jul 2017 13:39:54 +0000 (14:39 +0100)
committerYao Qi <yao.qi@linaro.org>
Wed, 26 Jul 2017 13:39:54 +0000 (14:39 +0100)
Instead of using pre-generated target descriptions, this patch
changes GDB to lazily and dynamically create target descriptions
according to the target hardware capability (xcr0 in i386).
This support any combination of target features.

Some reg in target description has "regnum" attribute, so its register
number is got from the attribute value instead from sequential allocation.

  <reg name="xmm0" bitsize="128" type="vec128" regnum="32"/>

when target description is created, it should match the regnum, so this
patch adds a new field m_next_regnum to track it, if attribute number is
greater than the m_next_regnum, print the code to set register number
explicitly.

gdb:

2017-07-26  Yao Qi  <yao.qi@linaro.org>

* i386-linux-tdep.c: Don't include features/i386/i386-*linux.c.
Include features/i386/32bit-*.c.
(i386_linux_read_description): Generate target description if it
doesn't exist.
(_initialize_i386_linux_tdep): Don't call _initialize_tdesc_i386
functions.
* features/i386/32bit-linux.c: Re-generated.
* features/i386/32bit-sse.c: Likewise.
* target-descriptions.c (print_c_feature::visit): Print code to
set register number if needed.
(print_c_feature) <m_next_regnum>: New field.

gdb/ChangeLog
gdb/features/i386/32bit-linux.c
gdb/features/i386/32bit-sse.c
gdb/i386-linux-tdep.c
gdb/target-descriptions.c

index 0f4ec4695946aaae917038125aa2aa495cbfb6a1..77c74f20f8baa651cf21f7ae16945071ab2fed5c 100644 (file)
@@ -1,3 +1,17 @@
+2017-07-26  Yao Qi  <yao.qi@linaro.org>
+
+       * i386-linux-tdep.c: Don't include features/i386/i386-*linux.c.
+       Include features/i386/32bit-*.c.
+       (i386_linux_read_description): Generate target description if it
+       doesn't exist.
+       (_initialize_i386_linux_tdep): Don't call _initialize_tdesc_i386
+       functions.
+       * features/i386/32bit-linux.c: Re-generated.
+       * features/i386/32bit-sse.c: Likewise.
+       * target-descriptions.c (print_c_feature::visit): Print code to
+       set register number if needed.
+       (print_c_feature) <m_next_regnum>: New field.
+
 2017-07-26  Yao Qi  <yao.qi@linaro.org>
 
        * features/Makefile (CFILES): Rename with TDESC_CFILES.
index 686a2f114a0d155eb09728b4482c70182c521e7d..1b50882c6c8bda6f8f0a4a92e805665b42884112 100644 (file)
@@ -9,6 +9,7 @@ create_feature_i386_32bit_linux (struct target_desc *result, long regnum)
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.i386.linux");
+  regnum = 41;
   tdesc_create_reg (feature, "orig_eax", regnum++, 1, NULL, 32, "int");
   return regnum;
 }
index 032623e2431ea3c32e6e480006a2ccc4b023e51c..c0684fbdccee4c7d3d1bc8d0a5a637f448d67485 100644 (file)
@@ -61,6 +61,7 @@ create_feature_i386_32bit_sse (struct target_desc *result, long regnum)
   tdesc_add_flag (type, 12, "PM");
   tdesc_add_flag (type, 15, "FZ");
 
+  regnum = 32;
   tdesc_create_reg (feature, "xmm0", regnum++, 1, NULL, 128, "vec128");
   tdesc_create_reg (feature, "xmm1", regnum++, 1, NULL, 128, "vec128");
   tdesc_create_reg (feature, "xmm2", regnum++, 1, NULL, 128, "vec128");
index e986d6feaa669c3021fa11571cd65b0fd02df701..4c0f597a689b60ddb8e5b4197f9660d56b6d5241 100644 (file)
 
 #include "record-full.h"
 #include "linux-record.h"
-#include "features/i386/i386-linux.c"
-#include "features/i386/i386-mmx-linux.c"
-#include "features/i386/i386-mpx-linux.c"
-#include "features/i386/i386-avx-mpx-linux.c"
-#include "features/i386/i386-avx-linux.c"
-#include "features/i386/i386-avx-avx512-linux.c"
-#include "features/i386/i386-avx-mpx-avx512-pku-linux.c"
+
+#include "features/i386/32bit-core.c"
+#include "features/i386/32bit-sse.c"
+#include "features/i386/32bit-linux.c"
+#include "features/i386/32bit-avx.c"
+#include "features/i386/32bit-mpx.c"
+#include "features/i386/32bit-avx512.c"
+#include "features/i386/32bit-pkeys.c"
 
 /* Return non-zero, when the register is in the corresponding register
    group.  Put the LINUX_ORIG_EAX register in the system group.  */
@@ -683,27 +684,50 @@ i386_linux_core_read_xcr0 (bfd *abfd)
 const struct target_desc *
 i386_linux_read_description (uint64_t xcr0)
 {
-  switch ((xcr0 & X86_XSTATE_ALL_MASK))
+  if (xcr0 == 0)
+    return NULL;
+
+  static struct target_desc *i386_linux_tdescs \
+    [2/*X87*/][2/*SSE*/][2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
+  struct target_desc **tdesc;
+
+  tdesc = &i386_linux_tdescs[(xcr0 & X86_XSTATE_X87) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_SSE) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_MPX) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
+    [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];
+
+  if (*tdesc == NULL)
     {
-    case X86_XSTATE_AVX_MPX_AVX512_PKU_MASK:
-      return tdesc_i386_avx_mpx_avx512_pku_linux;
-    case X86_XSTATE_AVX_AVX512_MASK:
-      return tdesc_i386_avx_avx512_linux;
-    case X86_XSTATE_MPX_MASK:
-      return tdesc_i386_mpx_linux;
-    case X86_XSTATE_AVX_MPX_MASK:
-      return tdesc_i386_avx_mpx_linux;
-    case X86_XSTATE_AVX_MASK:
-      return tdesc_i386_avx_linux;
-    case X86_XSTATE_SSE_MASK:
-      return tdesc_i386_linux;
-    case X86_XSTATE_X87_MASK:
-      return tdesc_i386_mmx_linux;
-    default:
-      break;
+      *tdesc = allocate_target_description ();
+      set_tdesc_architecture (*tdesc, bfd_scan_arch ("i386"));
+      set_tdesc_osabi (*tdesc, osabi_from_tdesc_string ("GNU/Linux"));
+
+      long regnum = 0;
+
+      if (xcr0 & X86_XSTATE_X87)
+       regnum = create_feature_i386_32bit_core (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_SSE)
+       regnum = create_feature_i386_32bit_sse (*tdesc, regnum);
+
+      regnum = create_feature_i386_32bit_linux (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_AVX)
+       regnum = create_feature_i386_32bit_avx (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_MPX)
+       regnum = create_feature_i386_32bit_mpx (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_AVX512)
+       regnum = create_feature_i386_32bit_avx512 (*tdesc, regnum);
+
+      if (xcr0 & X86_XSTATE_PKRU)
+       regnum = create_feature_i386_32bit_pkeys (*tdesc, regnum);
     }
 
-  return NULL;
+  return *tdesc;
 }
 
 /* Get Linux/x86 target description from core dump.  */
@@ -1092,13 +1116,4 @@ _initialize_i386_linux_tdep (void)
 {
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
                          i386_linux_init_abi);
-
-  /* Initialize the Linux target description.  */
-  initialize_tdesc_i386_linux ();
-  initialize_tdesc_i386_mmx_linux ();
-  initialize_tdesc_i386_avx_linux ();
-  initialize_tdesc_i386_mpx_linux ();
-  initialize_tdesc_i386_avx_mpx_linux ();
-  initialize_tdesc_i386_avx_avx512_linux ();
-  initialize_tdesc_i386_avx_mpx_avx512_pku_linux ();
 }
index 5fd07ef045116ad36eeb730d8e89f0f315d3bcbe..333cbd89ab7c1337af35dc611da1f012f94c8931 100644 (file)
@@ -2104,6 +2104,48 @@ public:
 
   void visit (const tdesc_reg *reg) override
   {
+    /* Most "reg" in XML target descriptions don't have "regnum"
+       attribute, so the register number is allocated sequentially.
+       In case that reg has "regnum" attribute, register number
+       should be set by that explicitly.  */
+
+    if (reg->target_regnum < m_next_regnum)
+      {
+       /* The integrity check, it can catch some errors on register
+          number collision, like this,
+
+         <reg name="x0" bitsize="32"/>
+         <reg name="x1" bitsize="32"/>
+         <reg name="x2" bitsize="32"/>
+         <reg name="x3" bitsize="32"/>
+         <reg name="ps" bitsize="32" regnum="3"/>
+
+         but it also has false negatives.  The target description
+         below is correct,
+
+         <reg name="x1" bitsize="32" regnum="1"/>
+         <reg name="x3" bitsize="32" regnum="3"/>
+         <reg name="x2" bitsize="32" regnum="2"/>
+         <reg name="x4" bitsize="32" regnum="4"/>
+
+         but it is not a good practice, so still error on this,
+         and also print the message so that it can be saved in the
+         generated c file.  */
+
+       printf_unfiltered ("ERROR: \"regnum\" attribute %ld ",
+                          reg->target_regnum);
+       printf_unfiltered ("is not the largest number (%d).\n",
+                          m_next_regnum);
+       error (_("\"regnum\" attribute %ld is not the largest number (%d)."),
+              reg->target_regnum, m_next_regnum);
+      }
+
+    if (reg->target_regnum > m_next_regnum)
+      {
+       printf_unfiltered ("  regnum = %ld;\n", reg->target_regnum);
+       m_next_regnum = reg->target_regnum;
+      }
+
     printf_unfiltered ("  tdesc_create_reg (feature, \"%s\", regnum++, %d, ",
                       reg->name, reg->save_restore);
     if (reg->group)
@@ -2111,8 +2153,13 @@ public:
     else
       printf_unfiltered ("NULL, ");
     printf_unfiltered ("%d, \"%s\");\n", reg->bitsize, reg->type);
+
+    m_next_regnum++;
   }
 
+private:
+  /* The register number to use for the next register we see.  */
+  int m_next_regnum = 0;
 };
 
 static void