diff mbox

Match speculative execution barriers in PowerPC PLT stubs

Message ID 20180124064423.GO20622@bubble.grove.modra.org
State New
Headers show

Commit Message

Alan Modra Jan. 24, 2018, 6:44 a.m. UTC
This patch teaches gdb about the PLT stub code emitted by
ld --no-speculate-indirect-jumps.  Regression tested
powerpc64-linux, powerpc-linux and powerpc64le-linux.  OK?

	* ppc-linux-tdep.c (powerpc32_plt_stub): Match stub with
	speculative execution barrier.
	(powerpc32_plt_stub_so_1, powerpc32_plt_stub_so_2): Likewise.
	(ppc_skip_trampoline_code): Scan backwards 6 insns.  Check that
	either "bctr" or "crset eq" is present in PLT stubs.
	* ppc64-tdep.c (ppc64_standard_linkage4): Match stub with
	speculative execution barrier.
	(ppc64_standard_linkage5): Likewise
	(ppc64_standard_linkage7, ppc64_standard_linkage8): Likewise.
	(ppc64_skip_trampoline_code_1): Check that either "bctr" or
	"crset eq" is present.
diff mbox

Patch

diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index ed0ea13..541df39 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -256,24 +256,28 @@  ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
 				      readbuf, writebuf);
 }
 
-/* PLT stub in an executable.  */
+/* PLT stub in an executable.  The form with an execution barrier has
+   two more insns following the "crset eq" that we don't check.  */
 static const struct ppc_insn_pattern powerpc32_plt_stub[] =
   {
     { 0xffff0000, 0x3d600000, 0 },	/* lis   r11, xxxx	 */
     { 0xffff0000, 0x816b0000, 0 },	/* lwz   r11, xxxx(r11)  */
     { 0xffffffff, 0x7d6903a6, 0 },	/* mtctr r11		 */
-    { 0xffffffff, 0x4e800420, 0 },	/* bctr			 */
+    { 0xffffffff, 0x4e800420, 1 },	/* bctr <option 1>	 */
+    { 0xffffffff, 0x4c421242, 1 },	/* crset eq <option 2>	 */
     {          0,          0, 0 }
   };
 
-/* PLT stubs in a shared library or PIE.
+/* PLT stubs in a shared library or PIE.  As above, "crset eq" is
+   followed by two more insns.
    The first variant is used when the PLT entry is within +/-32k of
    the GOT pointer (r30).  */
 static const struct ppc_insn_pattern powerpc32_plt_stub_so_1[] =
   {
     { 0xffff0000, 0x817e0000, 0 },	/* lwz   r11, xxxx(r30)  */
     { 0xffffffff, 0x7d6903a6, 0 },	/* mtctr r11		 */
-    { 0xffffffff, 0x4e800420, 0 },	/* bctr			 */
+    { 0xffffffff, 0x4e800420, 1 },	/* bctr <option 1>	 */
+    { 0xffffffff, 0x4c421242, 1 },	/* crset eq <option 2>	 */
     {          0,          0, 0 }
   };
 
@@ -284,7 +288,8 @@  static const struct ppc_insn_pattern powerpc32_plt_stub_so_2[] =
     { 0xffff0000, 0x3d7e0000, 0 },	/* addis r11, r30, xxxx  */
     { 0xffff0000, 0x816b0000, 0 },	/* lwz   r11, xxxx(r11)  */
     { 0xffffffff, 0x7d6903a6, 0 },	/* mtctr r11		 */
-    { 0xffffffff, 0x4e800420, 0 },	/* bctr			 */
+    { 0xffffffff, 0x4e800420, 1 },	/* bctr <option 1>	 */
+    { 0xffffffff, 0x4c421242, 1 },	/* crset eq <option 2>	 */
     {          0,          0, 0 }
   };
 
@@ -320,7 +325,7 @@  powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
 
    When the execution direction is EXEC_REVERSE, scan backward to
    check whether we are in the middle of a PLT stub.  Currently,
-   we only look-behind at most 4 instructions (the max length of a PLT
+   we only look-behind at most 6 instructions (the max length of a PLT
    stub sequence.  */
 
 static CORE_ADDR
@@ -337,11 +342,12 @@  ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
   /* When reverse-debugging, scan backward to check whether we are
      in the middle of trampoline code.  */
   if (execution_direction == EXEC_REVERSE)
-    scan_limit = 4;	/* At most 4 instructions.  */
+    scan_limit = 6;	/* At most 6 instructions.  */
 
   for (i = 0; i < scan_limit; i++)
     {
-      if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
+      if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf)
+	  && (insnbuf[3] != 0 || insnbuf[4] != 0))
 	{
 	  /* Calculate PLT entry address from
 	     lis   r11, xxxx
@@ -349,9 +355,10 @@  ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 	  target = ((ppc_insn_d_field (insnbuf[0]) << 16)
 		    + ppc_insn_d_field (insnbuf[1]));
 	}
-      else if (i < ARRAY_SIZE (powerpc32_plt_stub_so_1) - 1
+      else if (i < ARRAY_SIZE (powerpc32_plt_stub_so_1)
 	       && ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so_1,
-					   insnbuf))
+					   insnbuf)
+	       && (insnbuf[2] != 0 || insnbuf[3] != 0))
 	{
 	  /* Calculate PLT entry address from
 	     lwz   r11, xxxx(r30).  */
@@ -360,7 +367,8 @@  ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 						   tdep->ppc_gp0_regnum + 30));
 	}
       else if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so_2,
-					insnbuf))
+					insnbuf)
+	       && (insnbuf[3] != 0 || insnbuf[4] != 0))
 	{
 	  /* Calculate PLT entry address from
 	     addis r11, r30, xxxx
diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c
index 5d8ccb4..1249a4d 100644
--- a/gdb/ppc64-tdep.c
+++ b/gdb/ppc64-tdep.c
@@ -236,6 +236,9 @@  static const struct ppc_insn_pattern ppc64_standard_linkage4[] =
     /* cmpldi r2, 0 <optional> */
     { -1, 0x28220000, 1 },
 
+    /* crset eq <optional> */
+    { -1, 0x4c421242, 1 },
+
     { 0, 0, 0 }
   };
 
@@ -275,6 +278,9 @@  static const struct ppc_insn_pattern ppc64_standard_linkage5[] =
     /* cmpldi r2, 0 <optional> */
     { -1, 0x28220000, 1 },
 
+    /* crset eq <optional> */
+    { -1, 0x4c421242, 1 },
+
     { 0, 0, 0 }
   };
 
@@ -313,8 +319,11 @@  static const struct ppc_insn_pattern ppc64_standard_linkage7[] =
     /* mtctr r12 */
     { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
 
-    /* bctr */
-    { -1, 0x4e800420, 0 },
+    /* bctr <optional> */
+    { -1, 0x4e800420, 1 },
+
+    /* crset eq <optional> */
+    { -1, 0x4c421242, 1 },
 
     { 0, 0, 0 }
   };
@@ -336,8 +345,11 @@  static const struct ppc_insn_pattern ppc64_standard_linkage8[] =
     /* mtctr r12 */
     { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
 
-    /* bctr */
-    { -1, 0x4e800420, 0 },
+    /* bctr <optional> */
+    { -1, 0x4e800420, 1 },
+
+    /* crset eq <optional> */
+    { -1, 0x4c421242, 1 },
 
     { 0, 0, 0 }
   };
@@ -463,12 +475,15 @@  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
-	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns))
+      if (i < ARRAY_SIZE (ppc64_standard_linkage8)
+	  && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8,
+				      insns)
+	  && (insns[4] != 0 || insns[5] != 0))
 	pc = ppc64_standard_linkage4_target (frame, insns);
-      else if (i < ARRAY_SIZE (ppc64_standard_linkage7) - 1
+      else if (i < ARRAY_SIZE (ppc64_standard_linkage7)
 	       && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7,
-					   insns))
+					   insns)
+	       && (insns[3] != 0 || insns[4] != 0))
 	pc = ppc64_standard_linkage3_target (frame, insns);
       else if (i < ARRAY_SIZE (ppc64_standard_linkage6) - 1
 	       && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6,
@@ -477,12 +492,12 @@  ppc64_skip_trampoline_code_1 (struct frame_info *frame, CORE_ADDR pc)
       else if (i < ARRAY_SIZE (ppc64_standard_linkage5) - 1
 	       && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5,
 					   insns)
-	       && (insns[8] != 0 || insns[9] != 0))
+	       && (insns[8] != 0 || insns[9] != 0 || insns[10] != 0))
 	pc = ppc64_standard_linkage3_target (frame, insns);
       else if (i < ARRAY_SIZE (ppc64_standard_linkage4) - 1
 	       && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4,
 					   insns)
-	       && (insns[9] != 0 || insns[10] != 0))
+	       && (insns[9] != 0 || insns[10] != 0 || insns[11] != 0))
 	pc = ppc64_standard_linkage4_target (frame, insns);
       else if (i < ARRAY_SIZE (ppc64_standard_linkage3) - 1
 	       && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3,