Add Power 10 PLT instruction patterns

Message ID 1984418036f52962c1436bafdcc720c8fa2ce699.camel@us.ibm.com
State New
Headers show
Series
  • Add Power 10 PLT instruction patterns
Related show

Commit Message

Mike Frysinger via Gdb-patches June 4, 2021, 3:28 p.m.
GDB maintainers:

The following patch add the PLT patterns for Power 10.

The patch has been tested on Power 10.  The regression tests all pass. 
Additional manual testing has been done to verify the instruction
sequences are correctly matched.

Please take a look at the patch and let me know if it is acceptable to
commit.  Thanks.

               Carl Love

---------------------------------------------------------

gdb/ChangeLog:

2021-06-06  Carl Love  <cel@us.ibm.com>

	* ppc-tdep.h: New extern ppc_insn_prefix_dform.
	* ppc64-tdep.c: New defines prefix, insn_md, insn_x, insn_xo.
	New functions ppc64_plt_pcrel_entry_point, ppc64_pcrel_linkage1_target,
	ppc64_pcrel_linkage2_target.
	New ppc instruction patterns ppc64_standard_linkage9,
	ppc64_standard_linkage10, 	ppc64_standard_linkage11,
	ppc64_standard_linkage12.
	Add ppc64_standard_linkage9, ppc64_standard_linkage10,
	ppc64_standard_linkage11, ppc64_standard_linkage12 to define MAX
	expression.
	(ppc64_skip_trampoline_code_1): Add if statement checks for
	ppc64_standard_linkage9, ppc64_standard_linkage10,
	ppc64_standard_linkage11, ppc64_standard_linkage12.
	* New function ppc_insn_prefix_dform.
---
 gdb/ppc-tdep.h    |   2 +
 gdb/ppc64-tdep.c  | 194 +++++++++++++++++++++++++++++++++++++++++++++-
 gdb/rs6000-tdep.c |   8 ++
 3 files changed, 201 insertions(+), 3 deletions(-)

-- 
2.27.0

Comments

Mike Frysinger via Gdb-patches June 7, 2021, 12:54 p.m. | #1
On Fri, Jun 04, 2021 at 08:28:15AM -0700, Carl Love wrote:
> gdb/ChangeLog:

> 

> 2021-06-06  Carl Love  <cel@us.ibm.com>

> 

> 	* ppc-tdep.h: New extern ppc_insn_prefix_dform.

> 	* ppc64-tdep.c: New defines prefix, insn_md, insn_x, insn_xo.

> 	New functions ppc64_plt_pcrel_entry_point, ppc64_pcrel_linkage1_target,

> 	ppc64_pcrel_linkage2_target.

> 	New ppc instruction patterns ppc64_standard_linkage9,

> 	ppc64_standard_linkage10, 	ppc64_standard_linkage11,

> 	ppc64_standard_linkage12.

> 	Add ppc64_standard_linkage9, ppc64_standard_linkage10,

> 	ppc64_standard_linkage11, ppc64_standard_linkage12 to define MAX

> 	expression.

> 	(ppc64_skip_trampoline_code_1): Add if statement checks for

> 	ppc64_standard_linkage9, ppc64_standard_linkage10,

> 	ppc64_standard_linkage11, ppc64_standard_linkage12.

> 	* New function ppc_insn_prefix_dform.


The patch is OK.  Please format the ChangeLog according to the
usual rules, in particular each new or changed "entity" should go
in parentheses, like e.g. so:

 	* ppc-tdep.h (ppc_insn_prefix_dform): Declare.
 	* ppc64-tdep.c (prefix, insn_md, insn_x, insn_xo): New macros.
 	(ppc64_plt_pcrel_entry_point, ppc64_pcrel_linkage1_target,
 	ppc64_pcrel_linkage2_target): New functions.
 	(ppc64_standard_linkage9, ppc64_standard_linkage10,
	ppc64_standard_linkage11, ppc64_standard_linkage12): New variables.
 	(ppc64_skip_trampoline_code_1): Handle
 	ppc64_standard_linkage9, ppc64_standard_linkage10,
 	ppc64_standard_linkage11, and ppc64_standard_linkage12.
 	* rs6000-tdep.c (ppc_insn_prefix_dform): New function.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

Patch

diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h
index 77b6ab154f4..1e0754f7692 100644
--- a/gdb/ppc-tdep.h
+++ b/gdb/ppc-tdep.h
@@ -426,6 +426,8 @@  extern int ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc,
 extern CORE_ADDR ppc_insn_d_field (unsigned int insn);
 
 extern CORE_ADDR ppc_insn_ds_field (unsigned int insn);
+extern CORE_ADDR ppc_insn_prefix_dform (unsigned int insn1,
+					unsigned int insn2);
 
 extern int ppc_process_record (struct gdbarch *gdbarch,
 			       struct regcache *regcache, CORE_ADDR addr);
diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c
index 74873a6999e..1dd94f20ab6 100644
--- a/gdb/ppc64-tdep.c
+++ b/gdb/ppc64-tdep.c
@@ -49,6 +49,38 @@ 
    | (((unsigned (spr)) & 0x3e0) << 6)                     \
    | (((unsigned (xo)) & 0x3ff) << 1))
 
+#define prefix(a, b, R, do)				   \
+  (((0x1) << 26)					   \
+   | (((unsigned (a)) & 0x3) << 24)			   \
+   | (((unsigned (b)) & 0x1) << 23)			   \
+   | (((unsigned (R)) & 0x1) << 20)			   \
+   | ((unsigned (do)) & 0x3ffff))
+
+#define insn_md(opcd, ra, rs, sh, me, rc)	       	   \
+  ((((unsigned (opcd)) & 0x3f) << 26)			   \
+   | (((unsigned (rs)) & 0x1f) << 21)			   \
+   | (((unsigned (ra)) & 0x1f) << 16)			   \
+   | (((unsigned (sh)) & 0x3e) << 11)			   \
+   | (((unsigned (me)) & 0x3f) << 25)			   \
+   | (((unsigned (sh)) & 0x1)  << 1)			   \
+   | ((unsigned (rc)) & 0x1))
+
+#define insn_x(opcd, rt, ra, rb, opc2)			   \
+  ((((unsigned (opcd)) & 0x3f) << 26)			   \
+   | (((unsigned (rt)) & 0x1f) << 21)			   \
+   | (((unsigned (ra)) & 0x1f) << 16)			   \
+   | (((unsigned (rb)) & 0x3e) << 11)			   \
+   | (((unsigned (opc2)) & 0x3FF) << 1))
+
+#define insn_xo(opcd, rt, ra, rb, oe, rc, opc2)		   \
+  ((((unsigned (opcd)) & 0x3f) << 26)			   \
+   | (((unsigned (rt)) & 0x1f) << 21)			   \
+   | (((unsigned (ra)) & 0x1f) << 16)			   \
+   | (((unsigned (rb)) & 0x3e) << 11)			   \
+   | (((unsigned (oe)) & 0x1) << 10)			   \
+   | (((unsigned (opc2)) & 0x1FF) << 1)			   \
+   | (((unsigned (rc)))))
+
 /* PLT_OFF is the TOC-relative offset of a 64-bit PowerPC PLT entry.
    Return the function's entry point.  */
 
@@ -75,6 +107,18 @@  ppc64_plt_entry_point (struct frame_info *frame, CORE_ADDR plt_off)
   return read_memory_unsigned_integer (tocp + plt_off, 8, byte_order);
 }
 
+static CORE_ADDR
+ppc64_plt_pcrel_entry_point (struct frame_info *frame, CORE_ADDR plt_off,
+			     CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  /* Execution direction doesn't matter, entry is pc + plt_off either way.
+     The first word of the PLT entry is the function entry point.  */
+  return read_memory_unsigned_integer (pc + plt_off, 8, byte_order);
+}
+
 /* Patterns for the standard linkage functions.  These are built by
    build_plt_stub in bfd/elf64-ppc.c.  */
 
@@ -342,6 +386,110 @@  static const struct ppc_insn_pattern ppc64_standard_linkage8[] =
     { 0, 0, 0 }
   };
 
+/* Power 10 ELFv2 PLT call stubs */
+static const struct ppc_insn_pattern ppc64_standard_linkage9[] =
+  {
+    /* std   %r2,0+40(%r1)   <optional> */
+    { insn_ds (-1, -1, -1, 0, 1), insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* pld r12, <any> */
+    { prefix (-1, -1, 1, 0), prefix (0, 0, 1, 0), 0 },
+    { insn_d (-1, -1, -1, 0), insn_d (57, 12, 0, 0), 0 },
+
+    /* mtctr r12  */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr   */
+    { (unsigned) -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+static const struct ppc_insn_pattern ppc64_standard_linkage10[] =
+  {
+    /* std   %r2,0+40(%r1)    <optional> */
+    { insn_ds (-1, -1, -1, 0, 1), insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* paddi r12,<any> */
+    { prefix (-1, -1, 1, 0), prefix (2, 0, 1, 0), 0 },
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 0, 0), 0 },
+
+    /* mtctr r12  <optional> */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr   */
+    { (unsigned) -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+static const struct ppc_insn_pattern ppc64_standard_linkage11[] =
+  {
+    /* std   %r2,0+40(%r1)   <optional> */
+    { insn_ds (-1, -1, -1, 0, 1), insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* li %r11,0     <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 11, 0, 0), 1 },
+
+    /* sldi  %r11,%r11,34   <eq to rldicr rx,ry,n, 63-n> <optional>  */
+    { insn_md (-1, -1, -1, 0, 0, 1), insn_md (30, 11, 11, 34, 63-34, 0), 1 },
+
+    /* paddi r12, <any> */
+    { prefix (-1, -1, 1, 0), prefix (2, 0, 1, 0), 0 },
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 0, 0), 0 },
+
+    /* ldx   %r12,%r11,%r12  <optional> */
+    { (unsigned) -1, insn_x (31, 12, 11, 12, 21), 1 },
+
+    /* add   %r12,%r11,%r12  <optional> */
+    { (unsigned) -1, insn_xo (31, 12, 11, 12, 0, 0, 40), 1 },
+
+    /* mtctr r12   */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr   */ // 13, 14, 15, 16
+    { (unsigned) -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+static const struct ppc_insn_pattern ppc64_standard_linkage12[] =
+  {
+    /* std   %r2,0+40(%r1)    <optional>  */
+    { insn_ds (-1, -1, -1, 0, 1), insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* lis %r11,xxx@ha <equivalent addis rx, 0, val> */
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* ori   %r11,%r11,xxx@l */
+    { insn_d (-1, -1, -1, 0), insn_d (24, 11, 11, 0), 0 },
+
+    /* sldi  %r11,%r11,34 <optional> */
+    { (unsigned) -1, insn_md (30, 11, 11, 34, 63-34, 0), 1 },
+
+    /*paddi r12,<any> */
+    { prefix (-1, -1, 1, 0), prefix (2, 0, 1, 0), 0 },
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 0, 0), 0 },
+
+    /* sldi  %r11,%r11,34 <optional> */
+    { (unsigned) -1, insn_md (30, 11, 11, 34, 63-34, 0), 1 },
+
+    /* ldx   %r12,%r11,%r12 <optional> */
+    { (unsigned) -1, insn_x (31, 12, 11, 12, 21), 1 },
+
+    /* add   %r12,%r11,%r12 <optional> */
+    { (unsigned) -1, insn_xo (31, 12, 11, 12, 0, 0, 40), 1 },
+
+    /* mtctr r12  */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr  */ // 17, 18, 19, 20
+    { (unsigned) -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
 /* When the dynamic linker is doing lazy symbol resolution, the first
    call to a function in another object will go like this:
 
@@ -432,6 +580,29 @@  ppc64_standard_linkage4_target (struct frame_info *frame, unsigned int *insn)
   return ppc64_plt_entry_point (frame, plt_off);
 }
 
+static CORE_ADDR
+ppc64_pcrel_linkage1_target (struct frame_info *frame, unsigned int *insn,
+			     CORE_ADDR pc)
+{
+  /* insn[0] is for the std instruction.  */
+  CORE_ADDR plt_off = ppc_insn_prefix_dform (insn[1], insn[2]);
+
+  return ppc64_plt_pcrel_entry_point (frame, plt_off, pc);
+}
+
+static CORE_ADDR
+ppc64_pcrel_linkage2_target (struct frame_info *frame, unsigned int *insn,
+			     CORE_ADDR pc)
+{
+  CORE_ADDR plt_off;
+
+  /* insn[0] is for the std instruction.
+     insn[1] is for the  li r11 instruction  */
+  plt_off = ppc_insn_prefix_dform (insn[2], insn[3]);
+
+  return ppc64_plt_pcrel_entry_point (frame, plt_off, pc);
+}
+
 
 /* Given that we've begun executing a call trampoline at PC, return
    the entry point of the function the trampoline will go to.
@@ -447,10 +618,15 @@  ppc64_skip_trampoline_code_1 (struct frame_info *frame, CORE_ADDR pc)
 				    ARRAY_SIZE (ppc64_standard_linkage2)),
 			       MAX (ARRAY_SIZE (ppc64_standard_linkage3),
 				    ARRAY_SIZE (ppc64_standard_linkage4))),
-			  MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5),
+		      MAX(MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5),
 				    ARRAY_SIZE (ppc64_standard_linkage6)),
 			       MAX (ARRAY_SIZE (ppc64_standard_linkage7),
-				    ARRAY_SIZE (ppc64_standard_linkage8))))
+				    ARRAY_SIZE (ppc64_standard_linkage8))),
+		          MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage9),
+				    ARRAY_SIZE (ppc64_standard_linkage10)),
+		               MAX (ARRAY_SIZE (ppc64_standard_linkage11),
+				    ARRAY_SIZE (ppc64_standard_linkage12)))))
+
 		     - 1];
   CORE_ADDR target;
   int scan_limit, i;
@@ -463,7 +639,19 @@  ppc64_skip_trampoline_code_1 (struct frame_info *frame, CORE_ADDR pc)
 
   for (i = 0; i < scan_limit; i++)
     {
-      if (i < ARRAY_SIZE (ppc64_standard_linkage8) - 1
+      if (i < ARRAY_SIZE (ppc64_standard_linkage12) - 1
+	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage12, insns))
+	pc = ppc64_pcrel_linkage1_target (frame, insns, pc);
+      else if (i < ARRAY_SIZE (ppc64_standard_linkage11) - 1
+	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage11, insns))
+	pc = ppc64_pcrel_linkage2_target (frame, insns, pc);
+      else if (i < ARRAY_SIZE (ppc64_standard_linkage10) - 1
+	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage10, insns))
+	pc = ppc64_pcrel_linkage1_target (frame, insns, pc);
+      else if (i < ARRAY_SIZE (ppc64_standard_linkage9) - 1
+	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage9, insns))
+	pc = ppc64_pcrel_linkage1_target (frame, insns, pc);
+      else if (i < ARRAY_SIZE (ppc64_standard_linkage8) - 1
 	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns))
 	pc = ppc64_standard_linkage4_target (frame, insns);
       else if (i < ARRAY_SIZE (ppc64_standard_linkage7) - 1
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 347014d6c2f..f05252a81b7 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -7368,6 +7368,14 @@  ppc_insn_ds_field (unsigned int insn)
   return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
 }
 
+CORE_ADDR
+ppc_insn_prefix_dform (unsigned int insn1, unsigned int insn2)
+{
+  /* result is 34-bits  */
+  return (CORE_ADDR) ((((insn1 & 0x3ffff) ^ 0x20000) - 0x20000) << 16)
+    | (CORE_ADDR)(insn2 & 0xffff);
+}
+
 /* Initialization code.  */
 
 void _initialize_rs6000_tdep ();