PowerPC64 ELFv2 trampoline match
authorAlan Modra <amodra@gmail.com>
Mon, 11 Nov 2013 03:44:40 +0000 (14:14 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 15 Nov 2013 00:02:06 +0000 (10:32 +1030)
ELFv2 needs different plt call stubs to ELFv1, register usage differs
too.  When I added these to ld I changed register usage in the ELFv1
stubs as well, simplifying the linker code and (perhaps) future
maintenance.  All well and good, but this means gdb needs to cope with
more stub variants.  This patch also handles skipping over addis/addi
setting up r2 in ELFv2 global entry code.  We want breakpoints to be
set past this point to catch calls via the local entry point.

* ppc64-tdep.c (ppc64_plt_entry_point): Renamed from..
(ppc64_desc_entry_point): ..this.  Update comments here and at
call points.
(ppc64_standard_linkage1, ppc64_standard_linkage2,
ppc64_standard_linkage3): Update comments.
(ppc64_standard_linkage4, ppc64_standard_linkage5,
(ppc64_standard_linkage6, ppc64_standard_linkage7): New insn
patterns.
(ppc64_standard_linkage4_target): New function.
(ppc64_skip_trampoline_code): Skip ELFv2 patterns too.
* rs6000-tdep.c (skip_prologue): Skip ELFv2 r2 setup.  Correct
nop match.  Fix comment wrap.

gdb/ChangeLog
gdb/ppc64-tdep.c
gdb/rs6000-tdep.c

index de158799654dd6a87d8ff20b8c8decd1de3d9324..5ff75fecffa9d553205767dffb65bc1a000143db 100644 (file)
@@ -1,3 +1,18 @@
+2013-11-15  Alan Modra  <amodra@gmail.com>
+
+       * ppc64-tdep.c (ppc64_plt_entry_point): Renamed from..
+       (ppc64_desc_entry_point): ..this.  Update comments here and at
+       call points.
+       (ppc64_standard_linkage1, ppc64_standard_linkage2,
+       ppc64_standard_linkage3): Update comments.
+       (ppc64_standard_linkage4, ppc64_standard_linkage5,
+       (ppc64_standard_linkage6, ppc64_standard_linkage7): New insn
+       patterns.
+       (ppc64_standard_linkage4_target): New function.
+       (ppc64_skip_trampoline_code): Skip ELFv2 patterns too.
+       * rs6000-tdep.c (skip_prologue): Skip ELFv2 r2 setup.  Correct
+       nop match.  Fix comment wrap.
+
 2013-11-14  Pedro Alves  <palves@redhat.com>
 
        * infrun.c (handle_signal_stop): Move STOP_QUIETLY,
 
 2013-11-07  Phil Muldoon  <pmuldoon@redhat.com>
 
-        PR python/15747
-        * python/py-cmd.c: Add COMPLETE_EXPRESSION constant.
+       PR python/15747
+       * python/py-cmd.c: Add COMPLETE_EXPRESSION constant.
 
 2013-11-07  Phil Muldoon  <pmuldoon@redhat.com>
 
        (discard_pending_stop_replies): Return early if notif_state is
        NULL.  Adjust.  Don't check INF is NULL.
        (remote_notif_get_pending_events): Adjust.
-       (discard_pending_stop_replies_in_queue): New function.
+       (discard_pending_stop_replies_in_queue): New function.
        (remote_wait_ns): Likewise.
 
 2013-10-04  Yao Qi  <yao@codesourcery.com>
             Pedro Alves  <palves@redhat.com>
 
        * symfile.c (add_symbol_file_command): Error out on unknown
-        option.  Handle EXPECTING_SEC_ADDR/EXPECTING_SEC_NAME before '-'
-        options and collapse into single conditional branch.
+       option.  Handle EXPECTING_SEC_ADDR/EXPECTING_SEC_NAME before '-'
+       options and collapse into single conditional branch.
 
 2013-09-03  Luis Machado  <lgustavo@codesourcery.com>
 
index a2098fee345972625d93c40b4b8ca312cabc00c1..174ab7c253fff138a807b157af571c577848ab71 100644 (file)
    | (((spr) & 0x3e0) << 6)                     \
    | (((xo) & 0x3ff) << 1))
 
-/* If DESC is the address of a 64-bit PowerPC FreeBSD function
-   descriptor, return the descriptor's entry point.  */
+/* If PLT is the address of a 64-bit PowerPC PLT entry,
+   return the function's entry point.  */
 
 static CORE_ADDR
-ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
+ppc64_plt_entry_point (struct gdbarch *gdbarch, CORE_ADDR plt)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  /* The first word of the descriptor is the entry point.  */
-  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order);
+  /* The first word of the PLT entry is the function entry point.  */
+  return (CORE_ADDR) read_memory_unsigned_integer (plt, 8, byte_order);
 }
 
 /* Patterns for the standard linkage functions.  These are built by
    build_plt_stub in bfd/elf64-ppc.c.  */
 
-/* Old PLT call stub.  */
+/* Old ELFv1 PLT call stub.  */
 
 static struct ppc_insn_pattern ppc64_standard_linkage1[] =
   {
@@ -96,7 +96,7 @@ static struct ppc_insn_pattern ppc64_standard_linkage1[] =
     { 0, 0, 0 }
   };
 
-/* Current PLT call stub to access PLT entries more than +/- 32k from r2.
+/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2.
    Also supports older stub with different placement of std 2,40(1),
    a stub that omits the std 2,40(1), and both versions of power7
    thread safety read barriers.  Note that there are actually two more
@@ -144,7 +144,7 @@ static struct ppc_insn_pattern ppc64_standard_linkage2[] =
     { 0, 0, 0 }
   };
 
-/* Current PLT call stub to access PLT entries within +/- 32k of r2.  */
+/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2.  */
 
 static struct ppc_insn_pattern ppc64_standard_linkage3[] =
   {
@@ -181,6 +181,128 @@ static struct ppc_insn_pattern ppc64_standard_linkage3[] =
     { 0, 0, 0 }
   };
 
+/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2.
+   A more modern variant of ppc64_standard_linkage2 differing in
+   register usage.  */
+
+static struct ppc_insn_pattern ppc64_standard_linkage4[] =
+  {
+    /* std r2, 40(r1) <optional> */
+    { -1, insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* addis r11, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 },
+
+    /* ld r12, <any>(r11) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 },
+
+    /* addi r11, r11, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 11, 11, 0), 1 },
+
+    /* mtctr r12 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* xor r2, r12, r12 <optional> */
+    { -1, 0x7d826278, 1 },
+
+    /* add r11, r11, r2 <optional> */
+    { -1, 0x7d6b1214, 1 },
+
+    /* ld r2, <any>(r11) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 11, 0, 0), 0 },
+
+    /* ld r11, <any>(r11) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 11, 0, 0), 1 },
+
+    /* bctr <optional> */
+    { -1, 0x4e800420, 1 },
+
+    /* cmpldi r2, 0 <optional> */
+    { -1, 0x28220000, 1 },
+
+    { 0, 0, 0 }
+  };
+
+/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2.
+   A more modern variant of ppc64_standard_linkage3 differing in
+   register usage.  */
+
+static struct ppc_insn_pattern ppc64_standard_linkage5[] =
+  {
+    /* std r2, 40(r1) <optional> */
+    { -1, insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* ld r12, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 },
+
+    /* addi r2, r2, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
+
+    /* mtctr r12 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* xor r11, r12, r12 <optional> */
+    { -1, 0x7d8b6278, 1 },
+
+    /* add r2, r2, r11 <optional> */
+    { -1, 0x7c425a14, 1 },
+
+    /* ld r11, <any>(r2) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 },
+
+    /* ld r2, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
+
+    /* bctr <optional> */
+    { -1, 0x4e800420, 1 },
+
+    /* cmpldi r2, 0 <optional> */
+    { -1, 0x28220000, 1 },
+
+    { 0, 0, 0 }
+  };
+
+/* ELFv2 PLT call stub to access PLT entries more than +/- 32k from r2.  */
+
+static struct ppc_insn_pattern ppc64_standard_linkage6[] =
+  {
+    /* std r2, 24(r1) <optional> */
+    { -1, insn_ds (62, 2, 1, 24, 0), 1 },
+
+    /* addis r11, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 },
+
+    /* ld r12, <any>(r11) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 },
+
+    /* mtctr r12 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+/* ELFv2 PLT call stub to access PLT entries within +/- 32k of r2.  */
+
+static struct ppc_insn_pattern ppc64_standard_linkage7[] =
+  {
+    /* std r2, 24(r1) <optional> */
+    { -1, insn_ds (62, 2, 1, 40, 0), 1 },
+
+    /* ld r12, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 },
+
+    /* mtctr r12 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 },
+
+    /* bctr */
+    { -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:
 
@@ -243,16 +365,14 @@ ppc64_standard_linkage1_target (struct frame_info *frame,
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* The address of the function descriptor this linkage function
-     references.  */
-  CORE_ADDR desc
+  /* The address of the PLT entry this linkage function references.  */
+  CORE_ADDR plt
     = ((CORE_ADDR) get_frame_register_unsigned (frame,
                                                tdep->ppc_gp0_regnum + 2)
        + (ppc_insn_d_field (insn[0]) << 16)
        + ppc_insn_ds_field (insn[2]));
 
-  /* The first word of the descriptor is the entry point.  Return that.  */
-  return ppc64_desc_entry_point (gdbarch, desc);
+  return ppc64_plt_entry_point (gdbarch, plt);
 }
 
 static CORE_ADDR
@@ -262,16 +382,14 @@ ppc64_standard_linkage2_target (struct frame_info *frame,
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* The address of the function descriptor this linkage function
-     references.  */
-  CORE_ADDR desc
+  /* The address of the PLT entry this linkage function references.  */
+  CORE_ADDR plt
     = ((CORE_ADDR) get_frame_register_unsigned (frame,
                                                tdep->ppc_gp0_regnum + 2)
        + (ppc_insn_d_field (insn[1]) << 16)
        + ppc_insn_ds_field (insn[3]));
 
-  /* The first word of the descriptor is the entry point.  Return that.  */
-  return ppc64_desc_entry_point (gdbarch, desc);
+  return ppc64_plt_entry_point (gdbarch, plt);
 }
 
 static CORE_ADDR
@@ -281,15 +399,28 @@ ppc64_standard_linkage3_target (struct frame_info *frame,
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* The address of the function descriptor this linkage function
-     references.  */
-  CORE_ADDR desc
+  /* The address of the PLT entry this linkage function references.  */
+  CORE_ADDR plt
     = ((CORE_ADDR) get_frame_register_unsigned (frame,
                                                tdep->ppc_gp0_regnum + 2)
        + ppc_insn_ds_field (insn[1]));
 
-  /* The first word of the descriptor is the entry point.  Return that.  */
-  return ppc64_desc_entry_point (gdbarch, desc);
+  return ppc64_plt_entry_point (gdbarch, plt);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage4_target (struct frame_info *frame,
+                               CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  CORE_ADDR plt
+    = ((CORE_ADDR) get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 2)
+       + (ppc_insn_d_field (insn[1]) << 16)
+       + ppc_insn_ds_field (insn[2]));
+
+  return ppc64_plt_entry_point (gdbarch, plt);
 }
 
 
@@ -300,13 +431,27 @@ CORE_ADDR
 ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
-  unsigned int insns[MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1),
-                              ARRAY_SIZE (ppc64_standard_linkage2)),
-                         ARRAY_SIZE (ppc64_standard_linkage3)) - 1];
+  unsigned int insns[MAX (MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1),
+                                   ARRAY_SIZE (ppc64_standard_linkage2)),
+                              MAX (ARRAY_SIZE (ppc64_standard_linkage3),
+                                   ARRAY_SIZE (ppc64_standard_linkage4))),
+                         MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5),
+                                   ARRAY_SIZE (ppc64_standard_linkage6)),
+                              ARRAY_SIZE (ppc64_standard_linkage7))) - 1];
   CORE_ADDR target;
 
-  if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns)
-      && (insns[8] != 0 || insns[9] != 0))
+  if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns))
+    pc = ppc64_standard_linkage3_target (frame, pc, insns);
+  else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns))
+    pc = ppc64_standard_linkage4_target (frame, pc, insns);
+  else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5, insns)
+          && (insns[8] != 0 || insns[9] != 0))
+    pc = ppc64_standard_linkage3_target (frame, pc, insns);
+  else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4, insns)
+          && (insns[9] != 0 || insns[10] != 0))
+    pc = ppc64_standard_linkage4_target (frame, pc, insns);
+  else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns)
+          && (insns[8] != 0 || insns[9] != 0))
     pc = ppc64_standard_linkage3_target (frame, pc, insns);
   else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns)
           && (insns[10] != 0 || insns[11] != 0))
index c561bc8209f7e2a618914a4e7f5ce7678741a19b..477e29e8f3bb089e894996601b0ceec2cb834660 100644 (file)
@@ -1616,7 +1616,19 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
          continue;
 
        }
-      else if ((op & 0xffff0000) == 0x60000000)
+      else if ((op & 0xffff0000) == 0x3c4c0000
+              || (op & 0xffff0000) == 0x3c400000
+              || (op & 0xffff0000) == 0x38420000)
+       {
+         /* .  0:      addis 2,12,.TOC.-0b@ha
+            .          addi 2,2,.TOC.-0b@l
+            or
+            .          lis 2,.TOC.@ha
+            .          addi 2,2,.TOC.@l
+            used by ELFv2 global entry points to set up r2.  */
+         continue;
+       }
+      else if (op == 0x60000000)
         {
          /* nop */
          /* Allow nops in the prologue, but do not consider them to
@@ -1627,8 +1639,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 
        }
       else if ((op & 0xffff0000) == 0x3c000000)
-       {                       /* addis 0,0,NUM, used
-                                  for >= 32k frames */
+       {                       /* addis 0,0,NUM, used for >= 32k frames */
          fdata->offset = (op & 0x0000ffff) << 16;
          fdata->frameless = 0;
           r0_contains_arg = 0;
@@ -1636,8 +1647,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
 
        }
       else if ((op & 0xffff0000) == 0x60000000)
-       {                       /* ori 0,0,NUM, 2nd ha
-                                  lf of >= 32k frames */
+       {                       /* ori 0,0,NUM, 2nd half of >= 32k frames */
          fdata->offset |= (op & 0x0000ffff);
          fdata->frameless = 0;
           r0_contains_arg = 0;