/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1986-1987, 1989, 1991-1997, 2000-2012 Free Software
+ Foundation, Inc.
This file is part of GDB.
#include "solist.h"
#include "ppc-tdep.h"
#include "ppc-linux-tdep.h"
+#include "glibc-tdep.h"
#include "trad-frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
#include "features/rs6000/powerpc-isa205-vsx64l.c"
#include "features/rs6000/powerpc-e500l.c"
+/* Shared library operations for PowerPC-Linux. */
+static struct target_so_ops powerpc_so_ops;
+
/* The syscall's XML filename for PPC and PPC64. */
#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
Now we've hit the breakpoint at shr1. (The breakpoint was
reset from the PLT entry to the actual shr1 function after the
shared library was loaded.) Note that the PLT entry has been
- resolved to contain a branch that takes us directly to shr1.
+ resolved to contain a branch that takes us directly to shr1.
(The real one, not the PLT entry.)
(gdb) x/2i 0x100409d4
changed twice.
Now the problem should be obvious. GDB places a breakpoint (a
- trap instruction) on the zero value of the PLT entry for shr1.
+ trap instruction) on the zero value of the PLT entry for shr1.
Later on, after the shared library had been loaded and the PLT
initialized, GDB gets a signal indicating this fact and attempts
(as it always does when it stops) to remove all the breakpoints.
word) to be written back to the now initialized PLT entry thus
destroying a portion of the initialization that had occurred only a
short time ago. When execution continued, the zero word would be
- executed as an instruction an an illegal instruction trap was
+ executed as an instruction an illegal instruction trap was
generated instead. (0 is not a legal instruction.)
The fix for this problem was fairly straightforward. The function
that the latter does not is check to make sure that the breakpoint
location actually contains a breakpoint (trap instruction) prior
to attempting to write back the old contents. If it does contain
- a trap instruction, we allow the old contents to be written back.
+ a trap instruction, we allow the old contents to be written back.
Otherwise, we silently do nothing.
The big question is whether memory_remove_breakpoint () should be
/* If our breakpoint is no longer at the address, this means that the
program modified the code on us, so it is wrong to put back the
- old value */
+ old value. */
if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
- val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
+ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
do_cleanups (cleanup);
return val;
/* An instruction to match. */
struct insn_pattern
{
- unsigned int mask; /* mask the insn with this... */
- unsigned int data; /* ...and see if it matches this. */
+ unsigned int mask; /* mask the insn with this... */
+ unsigned int data; /* ...and see if it matches this. */
int optional; /* If non-zero, this insn may be absent. */
};
return ppc64_desc_entry_point (gdbarch, desc);
}
+/* PLT stub in executable. */
+static struct 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 */
+ { 0, 0, 0 }
+ };
+
+/* PLT stub in shared library. */
+static struct insn_pattern powerpc32_plt_stub_so[] =
+ {
+ { 0xffff0000, 0x817e0000, 0 }, /* lwz r11, xxxx(r30) */
+ { 0xffffffff, 0x7d6903a6, 0 }, /* mtctr r11 */
+ { 0xffffffff, 0x4e800420, 0 }, /* bctr */
+ { 0xffffffff, 0x60000000, 0 }, /* nop */
+ { 0, 0, 0 }
+ };
+#define POWERPC32_PLT_STUB_LEN ARRAY_SIZE (powerpc32_plt_stub)
+
+/* Check if PC is in PLT stub. For non-secure PLT, stub is in .plt
+ section. For secure PLT, stub is in .text and we need to check
+ instruction patterns. */
+
+static int
+powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *sym;
+
+ /* Check whether PC is in the dynamic linker. This also checks
+ whether it is in the .plt section, used by non-PIC executables. */
+ if (svr4_in_dynsym_resolve_code (pc))
+ return 1;
+
+ /* Check if we are in the resolver. */
+ sym = lookup_minimal_symbol_by_pc (pc);
+ if ((strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink") == 0)
+ || (strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink_PLTresolve") == 0))
+ return 1;
+
+ return 0;
+}
+
+/* Follow PLT stub to actual routine. */
+
+static CORE_ADDR
+ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ int insnbuf[POWERPC32_PLT_STUB_LEN];
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR target = 0;
+
+ if (insns_match_pattern (pc, powerpc32_plt_stub, insnbuf))
+ {
+ /* Insn pattern is
+ lis r11, xxxx
+ lwz r11, xxxx(r11)
+ Branch target is in r11. */
+
+ target = (insn_d_field (insnbuf[0]) << 16) | insn_d_field (insnbuf[1]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
+
+ if (insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf))
+ {
+ /* Insn pattern is
+ lwz r11, xxxx(r30)
+ Branch target is in r11. */
+
+ target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30)
+ + insn_d_field (insnbuf[0]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
+
+ return target;
+}
/* Given that we've begun executing a call trampoline at PC, return
the entry point of the function the trampoline will go to. */
for (i = 0; i < 32; i++)
{
int regnum = i + tdep->ppc_gp0_regnum;
- trad_frame_set_reg_addr (this_cache, regnum, gpregs + i * tdep->wordsize);
+ trad_frame_set_reg_addr (this_cache,
+ regnum, gpregs + i * tdep->wordsize);
}
trad_frame_set_reg_addr (this_cache,
gdbarch_pc_regnum (gdbarch),
gdb_byte *buf;
buf = alloca (register_size (gdbarch, regnum));
- regcache_cooked_read (cache->regcache, regnum, buf);
+
+ if (regnum < gdbarch_num_regs (gdbarch))
+ regcache_raw_read (cache->regcache, regnum, buf);
+ else
+ gdbarch_pseudo_register_read (gdbarch, cache->regcache, regnum, buf);
+
return frame_unwind_got_bytes (this_frame, regnum, buf);
}
else if (regnum == SPU_PC_REGNUM)
store_unsigned_integer (buf, 4, byte_order, data->npc);
else
- return 0;
+ return REG_UNAVAILABLE;
- return 1;
+ return REG_VALID;
}
static int
static const struct frame_unwind ppu2spu_unwind = {
ARCH_FRAME,
+ default_frame_unwind_stop_reason,
ppu2spu_this_id,
ppu2spu_prev_register,
NULL,
/* Until November 2001, gcc did not comply with the 32 bit SysV
R4 ABI requirement that structures less than or equal to 8
bytes should be returned in registers. Instead GCC was using
- the the AIX/PowerOpen ABI - everything returned in memory
+ the AIX/PowerOpen ABI - everything returned in memory
(well ignoring vectors that is). When this was corrected, it
wasn't fixed for GNU/Linux native platform. Use the
PowerOpen struct convention. */
ppc_linux_memory_remove_breakpoint);
/* Shared library handling. */
- set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_trampoline_code (gdbarch, ppc_skip_trampoline_code);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
/* Trampolines. */
- tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
- tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &ppc32_linux_sigaction_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &ppc32_linux_sighandler_tramp_frame);
/* BFD target for core files. */
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
else
set_gdbarch_core_regset_sections (gdbarch,
ppc_linux_fp_regset_sections);
+
+ if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
+ {
+ powerpc_so_ops = svr4_so_ops;
+ /* Override dynamic resolve function. */
+ powerpc_so_ops.in_dynsym_resolve_code =
+ powerpc_linux_in_dynsym_resolve_code;
+ }
+ set_solib_ops (gdbarch, &powerpc_so_ops);
+
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
}
if (tdep->wordsize == 8)
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
/* Trampolines. */
- tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
- tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &ppc64_linux_sigaction_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &ppc64_linux_sighandler_tramp_frame);
/* BFD target for core files. */
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
set_gdbarch_core_regset_sections (gdbarch,
ppc64_linux_fp_regset_sections);
}
- set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section);
+ set_gdbarch_regset_from_core_section (gdbarch,
+ ppc_linux_regset_from_core_section);
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
/* Enable TLS support. */