* ppc-tdep.h (ppc_insns_match_pattern): Update prototype.

* rs6000-tdep.c (read_insn): Add frame param, don't assume big-endian.
	(ppc_insns_match_pattern): Add frame param.  Avoid multiple
	target mem reads on optional insns.
	* ppc-linux-tdep.c (ppc_skip_trampoline_code): Update
	ppc_insns_match_pattern calls.
	* ppc64-tdep.c (ppc64_standard_linkage2, ppc64_standard_linkage3):
	Add match for power7 thread safety insns, and new order of
	std 2,40(1) insn.  Correct code shown for _dl_runtime_resolve
	invocation in comment, and update rest of comment.
	(PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN,
	PPC64_STANDARD_LINKAGE3_LEN): Delete.
	(ppc64_standard_linkage2_target): Update insn offsets.
	(ppc64_skip_trampoline_code): Use a single insn buffer.  Match newer
	stubs first.  Update calls.
This commit is contained in:
Alan Modra 2013-06-04 02:44:35 +00:00
parent 404e278f8d
commit 845d47080b
5 changed files with 128 additions and 73 deletions

View File

@ -1,3 +1,21 @@
2013-06-04 Alan Modra <amodra@gmail.com>
* ppc-tdep.h (ppc_insns_match_pattern): Update prototype.
* rs6000-tdep.c (read_insn): Add frame param, don't assume big-endian.
(ppc_insns_match_pattern): Add frame param. Avoid multiple
target mem reads on optional insns.
* ppc-linux-tdep.c (ppc_skip_trampoline_code): Update
ppc_insns_match_pattern calls.
* ppc64-tdep.c (ppc64_standard_linkage2, ppc64_standard_linkage3):
Add match for power7 thread safety insns, and new order of
std 2,40(1) insn. Correct code shown for _dl_runtime_resolve
invocation in comment, and update rest of comment.
(PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN,
PPC64_STANDARD_LINKAGE3_LEN): Delete.
(ppc64_standard_linkage2_target): Update insn offsets.
(ppc64_skip_trampoline_code): Use a single insn buffer. Match newer
stubs first. Update calls.
2013-06-04 Yao Qi <yao@codesourcery.com>
* solib.c (solib_find): Don't need dir separator if path has

View File

@ -361,7 +361,7 @@ ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR target = 0;
if (ppc_insns_match_pattern (pc, powerpc32_plt_stub, insnbuf))
if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
{
/* Insn pattern is
lis r11, xxxx
@ -373,7 +373,7 @@ ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
target = read_memory_unsigned_integer (target, 4, byte_order);
}
if (ppc_insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf))
if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf))
{
/* Insn pattern is
lwz r11, xxxx(r30)

View File

@ -300,9 +300,9 @@ struct ppc_insn_pattern
int optional; /* If non-zero, this insn may be absent. */
};
extern int ppc_insns_match_pattern (CORE_ADDR pc,
extern int ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc,
struct ppc_insn_pattern *pattern,
unsigned int *insn);
unsigned int *insns);
extern CORE_ADDR ppc_insn_d_field (unsigned int insn);
extern CORE_ADDR ppc_insn_ds_field (unsigned int insn);

View File

@ -59,9 +59,10 @@ ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order);
}
/* Pattern for the standard linkage function. These are built by
build_plt_stub in elf64-ppc.c, whose GLINK argument is always
zero. */
/* Patterns for the standard linkage functions. These are built by
build_plt_stub in bfd/elf64-ppc.c. */
/* Old PLT call stub. */
static struct ppc_insn_pattern ppc64_standard_linkage1[] =
{
@ -95,15 +96,23 @@ static struct ppc_insn_pattern ppc64_standard_linkage1[] =
{ 0, 0, 0 }
};
#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1)
/* Current 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
instructions following "cmpldi r2, 0", "bnectr+" and "b <glink_i>",
but there isn't any need to match them. */
static struct ppc_insn_pattern ppc64_standard_linkage2[] =
{
/* std r2, 40(r1) <optional> */
{ -1, insn_ds (62, 2, 1, 40, 0), 1 },
/* addis r12, r2, <any> */
{ insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
/* std r2, 40(r1) */
{ -1, insn_ds (62, 2, 1, 40, 0), 0 },
/* std r2, 40(r1) <optional> */
{ -1, insn_ds (62, 2, 1, 40, 0), 1 },
/* ld r11, <any>(r12) */
{ insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
@ -114,24 +123,33 @@ static struct ppc_insn_pattern ppc64_standard_linkage2[] =
/* mtctr r11 */
{ insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
/* xor r11, r11, r11 <optional> */
{ -1, 0x7d6b5a78, 1 },
/* add r12, r12, r11 <optional> */
{ -1, 0x7d8c5a14, 1 },
/* ld r2, <any>(r12) */
{ insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
/* ld r11, <any>(r12) <optional> */
{ insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
/* bctr */
{ -1, 0x4e800420, 0 },
/* bctr <optional> */
{ -1, 0x4e800420, 1 },
/* cmpldi r2, 0 <optional> */
{ -1, 0x28220000, 1 },
{ 0, 0, 0 }
};
#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2)
/* Current PLT call stub to access PLT entries within +/- 32k of r2. */
static struct ppc_insn_pattern ppc64_standard_linkage3[] =
{
/* std r2, 40(r1) */
{ -1, insn_ds (62, 2, 1, 40, 0), 0 },
/* std r2, 40(r1) <optional> */
{ -1, insn_ds (62, 2, 1, 40, 0), 1 },
/* ld r11, <any>(r2) */
{ insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
@ -142,56 +160,71 @@ static struct ppc_insn_pattern ppc64_standard_linkage3[] =
/* mtctr r11 */
{ insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
/* xor r11, r11, r11 <optional> */
{ -1, 0x7d6b5a78, 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 */
{ -1, 0x4e800420, 0 },
/* bctr <optional> */
{ -1, 0x4e800420, 1 },
/* cmpldi r2, 0 <optional> */
{ -1, 0x28220000, 1 },
{ 0, 0, 0 }
};
#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3)
/* When the dynamic linker is doing lazy symbol resolution, the first
call to a function in another object will go like this:
- The user's function calls the linkage function:
100007c4: 4b ff fc d5 bl 10000498
100007c8: e8 41 00 28 ld r2,40(r1)
100003d4: 4b ff ff ad bl 10000380 <nnnn.plt_call.printf>
100003d8: e8 41 00 28 ld r2,40(r1)
- The linkage function loads the entry point (and other stuff) from
the function descriptor in the PLT, and jumps to it:
- The linkage function loads the entry point and toc pointer from
the function descriptor in the PLT, and jumps to it:
10000498: 3d 82 00 00 addis r12,r2,0
1000049c: f8 41 00 28 std r2,40(r1)
100004a0: e9 6c 80 98 ld r11,-32616(r12)
100004a4: e8 4c 80 a0 ld r2,-32608(r12)
100004a8: 7d 69 03 a6 mtctr r11
100004ac: e9 6c 80 a8 ld r11,-32600(r12)
100004b0: 4e 80 04 20 bctr
<nnnn.plt_call.printf>:
10000380: f8 41 00 28 std r2,40(r1)
10000384: e9 62 80 78 ld r11,-32648(r2)
10000388: 7d 69 03 a6 mtctr r11
1000038c: e8 42 80 80 ld r2,-32640(r2)
10000390: 28 22 00 00 cmpldi r2,0
10000394: 4c e2 04 20 bnectr+
10000398: 48 00 03 a0 b 10000738 <printf@plt>
- But since this is the first time that PLT entry has been used, it
sends control to its glink entry. That loads the number of the
PLT entry and jumps to the common glink0 code:
sends control to its glink entry. That loads the number of the
PLT entry and jumps to the common glink0 code:
10000c98: 38 00 00 00 li r0,0
10000c9c: 4b ff ff dc b 10000c78
<printf@plt>:
10000738: 38 00 00 01 li r0,1
1000073c: 4b ff ff bc b 100006f8 <__glink_PLTresolve>
- The common glink0 code then transfers control to the dynamic
linker's fixup code:
linker's fixup code:
10000c78: e8 41 00 28 ld r2,40(r1)
10000c7c: 3d 82 00 00 addis r12,r2,0
10000c80: e9 6c 80 80 ld r11,-32640(r12)
10000c84: e8 4c 80 88 ld r2,-32632(r12)
10000c88: 7d 69 03 a6 mtctr r11
10000c8c: e9 6c 80 90 ld r11,-32624(r12)
10000c90: 4e 80 04 20 bctr
100006f0: 0000000000010440 .quad plt0 - (. + 16)
<__glink_PLTresolve>:
100006f8: 7d 88 02 a6 mflr r12
100006fc: 42 9f 00 05 bcl 20,4*cr7+so,10000700
10000700: 7d 68 02 a6 mflr r11
10000704: e8 4b ff f0 ld r2,-16(r11)
10000708: 7d 88 03 a6 mtlr r12
1000070c: 7d 82 5a 14 add r12,r2,r11
10000710: e9 6c 00 00 ld r11,0(r12)
10000714: e8 4c 00 08 ld r2,8(r12)
10000718: 7d 69 03 a6 mtctr r11
1000071c: e9 6c 00 10 ld r11,16(r12)
10000720: 4e 80 04 20 bctr
Eventually, this code will figure out how to skip all of this,
including the dynamic linker. At the moment, we just get through
@ -234,8 +267,8 @@ ppc64_standard_linkage2_target (struct frame_info *frame,
CORE_ADDR desc
= ((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]));
+ (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);
@ -266,23 +299,20 @@ ppc64_standard_linkage3_target (struct frame_info *frame,
CORE_ADDR
ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN];
unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN];
unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN];
#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];
CORE_ADDR target;
if (ppc_insns_match_pattern (pc, ppc64_standard_linkage1,
ppc64_standard_linkage1_insn))
pc = ppc64_standard_linkage1_target (frame, pc,
ppc64_standard_linkage1_insn);
else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage2,
ppc64_standard_linkage2_insn))
pc = ppc64_standard_linkage2_target (frame, pc,
ppc64_standard_linkage2_insn);
else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage3,
ppc64_standard_linkage3_insn))
pc = ppc64_standard_linkage3_target (frame, pc,
ppc64_standard_linkage3_insn);
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))
pc = ppc64_standard_linkage2_target (frame, pc, insns);
else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1, insns))
pc = ppc64_standard_linkage1_target (frame, pc, insns);
else
return 0;

View File

@ -4238,14 +4238,15 @@ show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value);
}
/* Read a PPC instruction from memory. PPC instructions are always
big-endian, no matter what endianness the program is running in, so
we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer. */
/* Read a PPC instruction from memory. */
static unsigned int
read_insn (CORE_ADDR pc)
read_insn (struct frame_info *frame, CORE_ADDR pc)
{
return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
struct gdbarch *gdbarch = get_frame_arch (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
return read_memory_unsigned_integer (pc, 4, byte_order);
}
/* Return non-zero if the instructions at PC match the series
@ -4262,19 +4263,25 @@ read_insn (CORE_ADDR pc)
i'th instruction in memory. */
int
ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern,
unsigned int *insn)
ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc,
struct ppc_insn_pattern *pattern,
unsigned int *insns)
{
int i;
unsigned int insn;
for (i = 0; pattern[i].mask; i++)
for (i = 0, insn = 0; pattern[i].mask; i++)
{
insn[i] = read_insn (pc);
if ((insn[i] & pattern[i].mask) == pattern[i].data)
pc += 4;
else if (pattern[i].optional)
insn[i] = 0;
else
if (insn == 0)
insn = read_insn (frame, pc);
insns[i] = 0;
if ((insn & pattern[i].mask) == pattern[i].data)
{
insns[i] = insn;
pc += 4;
insn = 0;
}
else if (!pattern[i].optional)
return 0;
}