You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
9.7 KiB
231 lines
9.7 KiB
6 years ago
|
commit db9077b7275e86637218a7a7d165cb85a4de116f
|
||
|
Author: Alan Modra <amodra@gmail.com>
|
||
|
Date: Mon Dec 11 17:31:11 2017 +1030
|
||
|
|
||
|
PR22576, ppc64_skip_trampoline_code uses wrong r2 for EXEC_REVERSE
|
||
|
|
||
|
The TOC pointer register, r2, on powerpc64 is generally not mentioned
|
||
|
in debug info. It is saved and restored by call linkage code, and
|
||
|
set to the callee value either by call stub code (ELFv1) or in the
|
||
|
callee global entry point code (ELFv2). A call stub uses the caller
|
||
|
TOC pointer to access the PLT. So for gdb to read the correct PLT
|
||
|
entry in order to determine the destination of the trampoline, gdb
|
||
|
needs to know the caller r2. When skipping over trampolines in the
|
||
|
normal forward direction, the caller r2 is simply the current value of
|
||
|
r2 (at the start of the trampoline). However, when reversing over
|
||
|
trampolines the current value of r2 is that for the callee. Using
|
||
|
that value results in wild reads of memory rather than the correct PLT
|
||
|
entry.
|
||
|
|
||
|
This patch corrects the value of r2 by using the value saved on the
|
||
|
stack for reverse execution. Note that in reverse execution mode it
|
||
|
isn't really necessary for skip_trampoline_code to return the actual
|
||
|
destination, so we're doing a little more work than needed here. Any
|
||
|
non-zero return value would do (and it would be nicer if the interface
|
||
|
was changed to return the start of the stub).
|
||
|
|
||
|
PR tdep/22576
|
||
|
* ppc64-tdep.c (ppc64_plt_entry_point): Rewrite to take TOC-relative
|
||
|
PLT offset, and retrieve r2 from stack when executing in reverse.
|
||
|
(ppc64_standard_linkage1_target): Drop pc param. Calculate offset
|
||
|
rather than PLT address.
|
||
|
(ppc64_standard_linkage2_target): Likewise.
|
||
|
(ppc64_standard_linkage3_target): Likewise.
|
||
|
(ppc64_standard_linkage4_target): Likewise.
|
||
|
(ppc64_skip_trampoline_code_1): Adjust to suit.
|
||
|
|
||
|
### a/gdb/ChangeLog
|
||
|
### b/gdb/ChangeLog
|
||
|
## -1,3 +1,15 @@
|
||
|
+2017-12-12 Alan Modra <amodra@gmail.com>
|
||
|
+
|
||
|
+ PR tdep/22576
|
||
|
+ * ppc64-tdep.c (ppc64_plt_entry_point): Rewrite to take TOC-relative
|
||
|
+ PLT offset, and retrieve r2 from stack when executing in reverse.
|
||
|
+ (ppc64_standard_linkage1_target): Drop pc param. Calculate offset
|
||
|
+ rather than PLT address.
|
||
|
+ (ppc64_standard_linkage2_target): Likewise.
|
||
|
+ (ppc64_standard_linkage3_target): Likewise.
|
||
|
+ (ppc64_standard_linkage4_target): Likewise.
|
||
|
+ (ppc64_skip_trampoline_code_1): Adjust to suit.
|
||
|
+
|
||
|
2017-12-11 Simon Marchi <simon.marchi@ericsson.com>
|
||
|
|
||
|
PR gdb/22556
|
||
|
--- a/gdb/ppc64-tdep.c
|
||
|
+++ b/gdb/ppc64-tdep.c
|
||
|
@@ -49,15 +49,30 @@
|
||
|
| (((spr) & 0x3e0) << 6) \
|
||
|
| (((xo) & 0x3ff) << 1))
|
||
|
|
||
|
-/* If PLT is the address of a 64-bit PowerPC PLT entry,
|
||
|
- return the function's entry point. */
|
||
|
+/* PLT_OFF is the TOC-relative offset of a 64-bit PowerPC PLT entry.
|
||
|
+ Return the function's entry point. */
|
||
|
|
||
|
static CORE_ADDR
|
||
|
-ppc64_plt_entry_point (struct gdbarch *gdbarch, CORE_ADDR plt)
|
||
|
+ppc64_plt_entry_point (struct frame_info *frame, CORE_ADDR plt_off)
|
||
|
{
|
||
|
+ struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||
|
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
|
+ CORE_ADDR tocp;
|
||
|
+
|
||
|
+ if (execution_direction == EXEC_REVERSE)
|
||
|
+ {
|
||
|
+ /* If executing in reverse, r2 will have been stored to the stack. */
|
||
|
+ CORE_ADDR sp = get_frame_register_unsigned (frame,
|
||
|
+ tdep->ppc_gp0_regnum + 1);
|
||
|
+ unsigned int sp_off = tdep->elf_abi == POWERPC_ELF_V1 ? 40 : 24;
|
||
|
+ tocp = read_memory_unsigned_integer (sp + sp_off, 8, byte_order);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ tocp = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 2);
|
||
|
+
|
||
|
/* The first word of the PLT entry is the function entry point. */
|
||
|
- return (CORE_ADDR) read_memory_unsigned_integer (plt, 8, byte_order);
|
||
|
+ return read_memory_unsigned_integer (tocp + plt_off, 8, byte_order);
|
||
|
}
|
||
|
|
||
|
/* Patterns for the standard linkage functions. These are built by
|
||
|
@@ -377,74 +392,44 @@ static struct ppc_insn_pattern ppc64_standard_linkage8[] =
|
||
|
the linkage function. */
|
||
|
|
||
|
/* If the current thread is about to execute a series of instructions
|
||
|
- at PC matching the ppc64_standard_linkage pattern, and INSN is the result
|
||
|
+ matching the ppc64_standard_linkage pattern, and INSN is the result
|
||
|
from that pattern match, return the code address to which the
|
||
|
standard linkage function will send them. (This doesn't deal with
|
||
|
dynamic linker lazy symbol resolution stubs.) */
|
||
|
|
||
|
static CORE_ADDR
|
||
|
-ppc64_standard_linkage1_target (struct frame_info *frame,
|
||
|
- CORE_ADDR pc, unsigned int *insn)
|
||
|
+ppc64_standard_linkage1_target (struct frame_info *frame, unsigned int *insn)
|
||
|
{
|
||
|
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
|
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
|
-
|
||
|
- /* 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]));
|
||
|
+ CORE_ADDR plt_off = ((ppc_insn_d_field (insn[0]) << 16)
|
||
|
+ + ppc_insn_ds_field (insn[2]));
|
||
|
|
||
|
- return ppc64_plt_entry_point (gdbarch, plt);
|
||
|
+ return ppc64_plt_entry_point (frame, plt_off);
|
||
|
}
|
||
|
|
||
|
static CORE_ADDR
|
||
|
-ppc64_standard_linkage2_target (struct frame_info *frame,
|
||
|
- CORE_ADDR pc, unsigned int *insn)
|
||
|
+ppc64_standard_linkage2_target (struct frame_info *frame, unsigned int *insn)
|
||
|
{
|
||
|
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
|
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
|
-
|
||
|
- /* 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]));
|
||
|
+ CORE_ADDR plt_off = ((ppc_insn_d_field (insn[1]) << 16)
|
||
|
+ + ppc_insn_ds_field (insn[3]));
|
||
|
|
||
|
- return ppc64_plt_entry_point (gdbarch, plt);
|
||
|
+ return ppc64_plt_entry_point (frame, plt_off);
|
||
|
}
|
||
|
|
||
|
static CORE_ADDR
|
||
|
-ppc64_standard_linkage3_target (struct frame_info *frame,
|
||
|
- CORE_ADDR pc, unsigned int *insn)
|
||
|
+ppc64_standard_linkage3_target (struct frame_info *frame, unsigned int *insn)
|
||
|
{
|
||
|
- struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
|
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||
|
+ CORE_ADDR plt_off = ppc_insn_ds_field (insn[1]);
|
||
|
|
||
|
- /* 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]));
|
||
|
-
|
||
|
- return ppc64_plt_entry_point (gdbarch, plt);
|
||
|
+ return ppc64_plt_entry_point (frame, plt_off);
|
||
|
}
|
||
|
|
||
|
static CORE_ADDR
|
||
|
-ppc64_standard_linkage4_target (struct frame_info *frame,
|
||
|
- CORE_ADDR pc, unsigned int *insn)
|
||
|
+ppc64_standard_linkage4_target (struct frame_info *frame, 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]));
|
||
|
+ CORE_ADDR plt_off = ((ppc_insn_d_field (insn[1]) << 16)
|
||
|
+ + ppc_insn_ds_field (insn[2]));
|
||
|
|
||
|
- return ppc64_plt_entry_point (gdbarch, plt);
|
||
|
+ return ppc64_plt_entry_point (frame, plt_off);
|
||
|
}
|
||
|
|
||
|
|
||
|
@@ -480,39 +465,39 @@ ppc64_skip_trampoline_code_1 (struct frame_info *frame, CORE_ADDR pc)
|
||
|
{
|
||
|
if (i < ARRAY_SIZE (ppc64_standard_linkage8) - 1
|
||
|
&& ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns))
|
||
|
- pc = ppc64_standard_linkage4_target (frame, pc, insns);
|
||
|
+ pc = ppc64_standard_linkage4_target (frame, insns);
|
||
|
else if (i < ARRAY_SIZE (ppc64_standard_linkage7) - 1
|
||
|
&& ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7,
|
||
|
insns))
|
||
|
- pc = ppc64_standard_linkage3_target (frame, pc, insns);
|
||
|
+ 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,
|
||
|
insns))
|
||
|
- pc = ppc64_standard_linkage4_target (frame, pc, insns);
|
||
|
+ pc = ppc64_standard_linkage4_target (frame, insns);
|
||
|
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))
|
||
|
- pc = ppc64_standard_linkage3_target (frame, pc, insns);
|
||
|
+ 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))
|
||
|
- pc = ppc64_standard_linkage4_target (frame, pc, insns);
|
||
|
+ 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,
|
||
|
insns)
|
||
|
&& (insns[8] != 0 || insns[9] != 0))
|
||
|
- pc = ppc64_standard_linkage3_target (frame, pc, insns);
|
||
|
+ pc = ppc64_standard_linkage3_target (frame, insns);
|
||
|
else if (i < ARRAY_SIZE (ppc64_standard_linkage2) - 1
|
||
|
&& ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2,
|
||
|
insns)
|
||
|
&& (insns[10] != 0 || insns[11] != 0))
|
||
|
- pc = ppc64_standard_linkage2_target (frame, pc, insns);
|
||
|
+ pc = ppc64_standard_linkage2_target (frame, insns);
|
||
|
else if (i < ARRAY_SIZE (ppc64_standard_linkage1) - 1
|
||
|
&& ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1,
|
||
|
insns))
|
||
|
- pc = ppc64_standard_linkage1_target (frame, pc, insns);
|
||
|
+ pc = ppc64_standard_linkage1_target (frame, insns);
|
||
|
else
|
||
|
{
|
||
|
/* Scan backward one more instructions if doesn't match. */
|