/* 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-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "solib.h"
#include "solist.h"
#include "ppc-tdep.h"
+#include "ppc64-tdep.h"
#include "ppc-linux-tdep.h"
+#include "glibc-tdep.h"
#include "trad-frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
#include "observer.h"
#include "auxv.h"
#include "elf/common.h"
+#include "elf/ppc64.h"
#include "exceptions.h"
#include "arch-utils.h"
#include "spu-tdep.h"
#include "xml-syscall.h"
#include "linux-tdep.h"
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "cli/cli-utils.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+#include "elf-bfd.h" /* for elfcore_write_* */
+
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
#include "features/rs6000/powerpc-cell32l.c"
#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"
program modified the code on us, so it is wrong to put back the
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;
which were added later, do get returned in a register though. */
static enum return_value_convention
-ppc_linux_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *valtype, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
&& TYPE_VECTOR (valtype)))
return RETURN_VALUE_STRUCT_CONVENTION;
else
- return ppc_sysv_abi_return_value (gdbarch, func_type, valtype, regcache,
+ return ppc_sysv_abi_return_value (gdbarch, function, valtype, regcache,
readbuf, writebuf);
}
-/* Macros for matching instructions. Note that, since all the
- operands are masked off before they're or-ed into the instruction,
- you can use -1 to make masks. */
-
-#define insn_d(opcd, rts, ra, d) \
- ((((opcd) & 0x3f) << 26) \
- | (((rts) & 0x1f) << 21) \
- | (((ra) & 0x1f) << 16) \
- | ((d) & 0xffff))
-
-#define insn_ds(opcd, rts, ra, d, xo) \
- ((((opcd) & 0x3f) << 26) \
- | (((rts) & 0x1f) << 21) \
- | (((ra) & 0x1f) << 16) \
- | ((d) & 0xfffc) \
- | ((xo) & 0x3))
-
-#define insn_xfx(opcd, rts, spr, xo) \
- ((((opcd) & 0x3f) << 26) \
- | (((rts) & 0x1f) << 21) \
- | (((spr) & 0x1f) << 16) \
- | (((spr) & 0x3e0) << 6) \
- | (((xo) & 0x3ff) << 1))
-
-/* Read a PPC instruction from memory. PPC instructions are always
- big-endian, no matter what endianness the program is running in, so
- we can't use read_memory_integer or one of its friends here. */
-static unsigned int
-read_insn (CORE_ADDR pc)
-{
- unsigned char buf[4];
-
- read_memory (pc, buf, 4);
- return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-}
-
-
-/* An instruction to match. */
-struct insn_pattern
-{
- 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 non-zero if the instructions at PC match the series
- described in PATTERN, or zero otherwise. PATTERN is an array of
- 'struct insn_pattern' objects, terminated by an entry whose mask is
- zero.
-
- When the match is successful, fill INSN[i] with what PATTERN[i]
- matched. If PATTERN[i] is optional, and the instruction wasn't
- present, set INSN[i] to 0 (which is not a valid PPC instruction).
- INSN should have as many elements as PATTERN. Note that, if
- PATTERN contains optional instructions which aren't present in
- memory, then INSN will have holes, so INSN[i] isn't necessarily the
- i'th instruction in memory. */
-static int
-insns_match_pattern (CORE_ADDR pc,
- struct insn_pattern *pattern,
- unsigned int *insn)
-{
- int i;
-
- for (i = 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
- return 0;
- }
-
- return 1;
-}
-
-
-/* Return the 'd' field of the d-form instruction INSN, properly
- sign-extended. */
-static CORE_ADDR
-insn_d_field (unsigned int insn)
-{
- return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000);
-}
-
-
-/* Return the 'ds' field of the ds-form instruction INSN, with the two
- zero bits concatenated at the right, and properly
- sign-extended. */
-static CORE_ADDR
-insn_ds_field (unsigned int insn)
-{
- return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
-}
-
-
-/* If DESC is the address of a 64-bit PowerPC GNU/Linux function
- descriptor, return the descriptor's entry point. */
-static CORE_ADDR
-ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
-{
- 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);
-}
-
-
-/* Pattern for the standard linkage function. These are built by
- build_plt_stub in elf64-ppc.c, whose GLINK argument is always
- zero. */
-static struct insn_pattern ppc64_standard_linkage1[] =
- {
- /* 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 },
-
- /* ld r11, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
-
- /* addis r12, r12, 1 <optional> */
- { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
-
- /* ld r2, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
-
- /* addis r12, r12, 1 <optional> */
- { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
-
- /* mtctr r11 */
- { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
-
- /* ld r11, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
-
- /* bctr */
- { -1, 0x4e800420, 0 },
-
- { 0, 0, 0 }
- };
-#define PPC64_STANDARD_LINKAGE1_LEN \
- (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0]))
-
-static struct insn_pattern ppc64_standard_linkage2[] =
- {
- /* 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 },
-
- /* ld r11, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
-
- /* addi r12, r12, <any> <optional> */
- { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 },
-
- /* mtctr r11 */
- { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
-
- /* ld r2, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
-
- /* ld r11, <any>(r12) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
-
- /* bctr */
- { -1, 0x4e800420, 0 },
-
- { 0, 0, 0 }
- };
-#define PPC64_STANDARD_LINKAGE2_LEN \
- (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
-
-static struct insn_pattern ppc64_standard_linkage3[] =
- {
- /* std r2, 40(r1) */
- { -1, insn_ds (62, 2, 1, 40, 0), 0 },
-
- /* ld r11, <any>(r2) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
-
- /* addi r2, r2, <any> <optional> */
- { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
-
- /* mtctr r11 */
- { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
-
- /* ld r11, <any>(r2) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
-
- /* ld r2, <any>(r2) */
- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
-
- /* bctr */
- { -1, 0x4e800420, 0 },
-
- { 0, 0, 0 }
- };
-#define PPC64_STANDARD_LINKAGE3_LEN \
- (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0]))
-
-
-/* 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)
-
- - The linkage function loads the entry point (and other stuff) 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
-
- - 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:
-
- 10000c98: 38 00 00 00 li r0,0
- 10000c9c: 4b ff ff dc b 10000c78
-
- - The common glink0 code then transfers control to the dynamic
- 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
-
- Eventually, this code will figure out how to skip all of this,
- including the dynamic linker. At the moment, we just get through
- 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
- 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)
-{
- 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
- = ((CORE_ADDR) get_frame_register_unsigned (frame,
- tdep->ppc_gp0_regnum + 2)
- + (insn_d_field (insn[0]) << 16)
- + insn_ds_field (insn[2]));
-
- /* The first word of the descriptor is the entry point. Return that. */
- return ppc64_desc_entry_point (gdbarch, desc);
-}
-
static struct core_regset_section ppc_linux_vsx_regset_sections[] =
{
{ ".reg", 48 * 4, "general-purpose" },
{ NULL, 0}
};
-static CORE_ADDR
-ppc64_standard_linkage2_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);
+/* PLT stub in executable. */
+static 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 */
+ { 0, 0, 0 }
+ };
- /* The address of the function descriptor this linkage function
- references. */
- CORE_ADDR desc
- = ((CORE_ADDR) get_frame_register_unsigned (frame,
- tdep->ppc_gp0_regnum + 2)
- + (insn_d_field (insn[0]) << 16)
- + insn_ds_field (insn[2]));
+/* PLT stub in shared library. */
+static struct ppc_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)
- /* The first word of the descriptor is the entry point. Return that. */
- return ppc64_desc_entry_point (gdbarch, desc);
-}
+/* 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 CORE_ADDR
-ppc64_standard_linkage3_target (struct frame_info *frame,
- CORE_ADDR pc, unsigned int *insn)
+static int
+powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc)
{
- 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
- = ((CORE_ADDR) get_frame_register_unsigned (frame,
- tdep->ppc_gp0_regnum + 2)
- + insn_ds_field (insn[1]));
+ struct bound_minimal_symbol sym;
- /* The first word of the descriptor is the entry point. Return that. */
- return ppc64_desc_entry_point (gdbarch, desc);
-}
+ /* 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 (sym.minsym != NULL
+ && (strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym), "__glink") == 0
+ || strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym),
+ "__glink_PLTresolve") == 0))
+ return 1;
-/* Given that we've begun executing a call trampoline at PC, return
- the entry point of the function the trampoline will go to. */
-static 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];
- CORE_ADDR target;
-
- if (insns_match_pattern (pc, ppc64_standard_linkage1,
- ppc64_standard_linkage1_insn))
- pc = ppc64_standard_linkage1_target (frame, pc,
- ppc64_standard_linkage1_insn);
- else if (insns_match_pattern (pc, ppc64_standard_linkage2,
- ppc64_standard_linkage2_insn))
- pc = ppc64_standard_linkage2_target (frame, pc,
- ppc64_standard_linkage2_insn);
- else if (insns_match_pattern (pc, ppc64_standard_linkage3,
- ppc64_standard_linkage3_insn))
- pc = ppc64_standard_linkage3_target (frame, pc,
- ppc64_standard_linkage3_insn);
- else
- return 0;
-
- /* The PLT descriptor will either point to the already resolved target
- address, or else to a glink stub. As the latter carry synthetic @plt
- symbols, find_solib_trampoline_target should be able to resolve them. */
- target = find_solib_trampoline_target (frame, pc);
- return target? target : pc;
+ return 0;
}
-
-/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64
- GNU/Linux.
-
- Usually a function pointer's representation is simply the address
- of the function. On GNU/Linux on the PowerPC however, a function
- pointer may be a pointer to a function descriptor.
-
- For PPC64, a function descriptor is a TOC entry, in a data section,
- which contains three words: the first word is the address of the
- function, the second word is the TOC pointer (r2), and the third word
- is the static chain value.
-
- Throughout GDB it is currently assumed that a function pointer contains
- the address of the function, which is not easy to fix. In addition, the
- conversion of a function address to a function pointer would
- require allocation of a TOC entry in the inferior's memory space,
- with all its drawbacks. To be able to call C++ virtual methods in
- the inferior (which are called via function pointers),
- find_function_addr uses this function to get the function address
- from a function pointer.
-
- If ADDR points at what is clearly a function descriptor, transform
- it into the address of the corresponding function, if needed. Be
- conservative, otherwise GDB will do the transformation on any
- random addresses such as occur when there is no symbol table. */
+/* Follow PLT stub to actual routine. */
static CORE_ADDR
-ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
- CORE_ADDR addr,
- struct target_ops *targ)
+ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
+ unsigned 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);
- struct target_section *s = target_section_by_addr (targ, addr);
+ CORE_ADDR target = 0;
+
+ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
+ {
+ /* Insn pattern is
+ lis r11, xxxx
+ lwz r11, xxxx(r11)
+ Branch target is in r11. */
+
+ target = (ppc_insn_d_field (insnbuf[0]) << 16)
+ | ppc_insn_d_field (insnbuf[1]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
- /* Check if ADDR points to a function descriptor. */
- if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
+ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf))
{
- /* There may be relocations that need to be applied to the .opd
- section. Unfortunately, this function may be called at a time
- where these relocations have not yet been performed -- this can
- happen for example shortly after a library has been loaded with
- dlopen, but ld.so has not yet applied the relocations.
-
- To cope with both the case where the relocation has been applied,
- and the case where it has not yet been applied, we do *not* read
- the (maybe) relocated value from target memory, but we instead
- read the non-relocated value from the BFD, and apply the relocation
- offset manually.
-
- This makes the assumption that all .opd entries are always relocated
- by the same offset the section itself was relocated. This should
- always be the case for GNU/Linux executables and shared libraries.
- Note that other kind of object files (e.g. those added via
- add-symbol-files) will currently never end up here anyway, as this
- function accesses *target* sections only; only the main exec and
- shared libraries are ever added to the target. */
-
- gdb_byte buf[8];
- int res;
-
- res = bfd_get_section_contents (s->bfd, s->the_bfd_section,
- &buf, addr - s->addr, 8);
- if (res != 0)
- return extract_unsigned_integer (buf, 8, byte_order)
- - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
- }
-
- return addr;
+ /* Insn pattern is
+ lwz r11, xxxx(r30)
+ Branch target is in r11. */
+
+ target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30)
+ + ppc_insn_d_field (insnbuf[0]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
+
+ return target;
}
/* Wrappers to handle Linux-only registers. */
static const struct regset ppc32_linux_gregset = {
&ppc32_linux_reg_offsets,
ppc_linux_supply_gregset,
- ppc_linux_collect_gregset,
- NULL
+ ppc_linux_collect_gregset
};
static const struct regset ppc64_linux_gregset = {
&ppc64_linux_reg_offsets,
ppc_linux_supply_gregset,
- ppc_linux_collect_gregset,
- NULL
+ ppc_linux_collect_gregset
};
static const struct regset ppc32_linux_fpregset = {
&ppc32_linux_reg_offsets,
ppc_supply_fpregset,
- ppc_collect_fpregset,
- NULL
+ ppc_collect_fpregset
};
static const struct regset ppc32_linux_vrregset = {
&ppc32_linux_reg_offsets,
ppc_supply_vrregset,
- ppc_collect_vrregset,
- NULL
+ ppc_collect_vrregset
};
static const struct regset ppc32_linux_vsxregset = {
&ppc32_linux_reg_offsets,
ppc_supply_vsxregset,
- ppc_collect_vsxregset,
- NULL
+ ppc_collect_vsxregset
};
const struct regset *
}
+/* Implementation of `gdbarch_elf_make_msymbol_special', as defined in
+ gdbarch.h. This implementation is used for the ELFv2 ABI only. */
+
+static void
+ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+{
+ elf_symbol_type *elf_sym = (elf_symbol_type *)sym;
+
+ /* If the symbol is marked as having a local entry point, set a target
+ flag in the msymbol. We currently only support local entry point
+ offsets of 8 bytes, which is the only entry point offset ever used
+ by current compilers. If/when other offsets are ever used, we will
+ have to use additional target flag bits to store them. */
+ switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other))
+ {
+ default:
+ break;
+ case 8:
+ MSYMBOL_TARGET_FLAG_1 (msym) = 1;
+ break;
+ }
+}
+
+/* Implementation of `gdbarch_skip_entrypoint', as defined in
+ gdbarch.h. This implementation is used for the ELFv2 ABI only. */
+
+static CORE_ADDR
+ppc_elfv2_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct bound_minimal_symbol fun;
+ int local_entry_offset = 0;
+
+ fun = lookup_minimal_symbol_by_pc (pc);
+ if (fun.minsym == NULL)
+ return pc;
+
+ /* See ppc_elfv2_elf_make_msymbol_special for how local entry point
+ offset values are encoded. */
+ if (MSYMBOL_TARGET_FLAG_1 (fun.minsym))
+ local_entry_offset = 8;
+
+ if (BMSYMBOL_VALUE_ADDRESS (fun) <= pc
+ && pc < BMSYMBOL_VALUE_ADDRESS (fun) + local_entry_offset)
+ return BMSYMBOL_VALUE_ADDRESS (fun) + local_entry_offset;
+
+ return pc;
+}
+
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+ gdbarch.h. */
+
+static int
+ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == 'i' /* Literal number. */
+ || (isdigit (*s) && s[1] == '('
+ && isdigit (s[2])) /* Displacement. */
+ || (*s == '(' && isdigit (s[1])) /* Register indirection. */
+ || isdigit (*s)); /* Register value. */
+}
+
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+ gdbarch.h. */
+
+static int
+ppc_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ if (isdigit (*p->arg))
+ {
+ /* This temporary pointer is needed because we have to do a lookahead.
+ We could be dealing with a register displacement, and in such case
+ we would not need to do anything. */
+ const char *s = p->arg;
+ char *regname;
+ int len;
+ struct stoken str;
+
+ while (isdigit (*s))
+ ++s;
+
+ if (*s == '(')
+ {
+ /* It is a register displacement indeed. Returning 0 means we are
+ deferring the treatment of this case to the generic parser. */
+ return 0;
+ }
+
+ len = s - p->arg;
+ regname = alloca (len + 2);
+ regname[0] = 'r';
+
+ strncpy (regname + 1, p->arg, len);
+ ++len;
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (&p->pstate, str);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
+
+ p->arg = s;
+ }
+ else
+ {
+ /* All the other tokens should be handled correctly by the generic
+ parser. */
+ return 0;
+ }
+
+ return 1;
+}
+
/* Cell/B.E. active SPE context tracking support. */
static struct objfile *spe_context_objfile = NULL;
static void
ppc_linux_spe_context_lookup (struct objfile *objfile)
{
- struct minimal_symbol *sym;
+ struct bound_minimal_symbol sym;
if (!objfile)
{
}
sym = lookup_minimal_symbol ("__spe_current_active_context", NULL, objfile);
- if (sym)
+ if (sym.minsym)
{
spe_context_objfile = objfile;
spe_context_lm_addr = svr4_fetch_objfile_link_map (objfile);
- spe_context_offset = SYMBOL_VALUE_ADDRESS (sym);
+ spe_context_offset = BMSYMBOL_VALUE_ADDRESS (sym);
spe_context_cache_ptid = minus_one_ptid;
spe_context_cache_address = 0;
return;
struct target_ops *target = ¤t_target;
volatile struct gdb_exception ex;
- while (target && !target->to_get_thread_local_address)
- target = find_target_beneath (target);
- if (!target)
- return 0;
-
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
/* We do not call target_translate_tls_address here, because
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
+ static const char *const stap_integer_prefixes[] = { "i", NULL };
+ static const char *const stap_register_indirection_prefixes[] = { "(",
+ NULL };
+ static const char *const stap_register_indirection_suffixes[] = { ")",
+ NULL };
linux_init_abi (info, gdbarch);
/* Get the syscall number from the arch's register. */
set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+ /* SystemTap functions. */
+ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
+ set_gdbarch_stap_register_indirection_prefixes (gdbarch,
+ stap_register_indirection_prefixes);
+ set_gdbarch_stap_register_indirection_suffixes (gdbarch,
+ stap_register_indirection_suffixes);
+ set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ ppc_stap_parse_special_token);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
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);
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)
{
- /* Handle PPC GNU/Linux 64-bit function pointers (which are really
- function descriptors). */
- set_gdbarch_convert_from_func_ptr_addr
- (gdbarch, ppc64_linux_convert_from_func_ptr_addr);
+ if (tdep->elf_abi == POWERPC_ELF_V1)
+ {
+ /* Handle PPC GNU/Linux 64-bit function pointers (which are really
+ function descriptors). */
+ set_gdbarch_convert_from_func_ptr_addr
+ (gdbarch, ppc64_convert_from_func_ptr_addr);
+
+ set_gdbarch_elf_make_msymbol_special
+ (gdbarch, ppc64_elf_make_msymbol_special);
+ }
+ else
+ {
+ set_gdbarch_elf_make_msymbol_special
+ (gdbarch, ppc_elfv2_elf_make_msymbol_special);
+
+ set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint);
+ }
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
set_gdbarch_core_regset_sections (gdbarch,
ppc64_linux_fp_regset_sections);
}
+
+ /* PPC32 uses a different prpsinfo32 compared to most other Linux
+ archs. */
+ if (tdep->wordsize == 4)
+ set_gdbarch_elfcore_write_linux_prpsinfo (gdbarch,
+ elfcore_write_ppc_linux_prpsinfo32);
+
set_gdbarch_regset_from_core_section (gdbarch,
ppc_linux_regset_from_core_section);
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
set_gdbarch_displaced_step_location (gdbarch,
ppc_linux_displaced_step_location);
}
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
/* Provide a prototype to silence -Wmissing-prototypes. */