| Index: gdb/ppc-linux-tdep.c
|
| diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
|
| index b6470fec8dd6cf439a4d41aad6730792a0886371..ccded83f11ae4a8e5827fd334ed4f51a5caece7b 100644
|
| --- a/gdb/ppc-linux-tdep.c
|
| +++ b/gdb/ppc-linux-tdep.c
|
| @@ -37,6 +37,7 @@
|
| #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"
|
| @@ -49,6 +50,14 @@
|
| #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 "features/rs6000/powerpc-32l.c"
|
| #include "features/rs6000/powerpc-altivec32l.c"
|
| #include "features/rs6000/powerpc-cell32l.c"
|
| @@ -65,6 +74,9 @@
|
| #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"
|
| @@ -229,7 +241,7 @@ ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
|
| 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)
|
| {
|
| @@ -239,7 +251,7 @@ ppc_linux_return_value (struct gdbarch *gdbarch, struct type *func_type,
|
| && 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);
|
| }
|
|
|
| @@ -599,6 +611,86 @@ ppc64_standard_linkage3_target (struct frame_info *frame,
|
| 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 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 (sym != NULL
|
| + && (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. */
|
| @@ -1192,6 +1284,75 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
|
| }
|
| }
|
|
|
| +/* 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 (OP_REGISTER);
|
| + str.ptr = regname;
|
| + str.length = len;
|
| + write_exp_string (str);
|
| + write_exp_elt_opcode (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. */
|
|
|
| @@ -1509,6 +1670,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
| /* 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_prefix (gdbarch, "i");
|
| + set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
|
| + set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
|
| + 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
|
| @@ -1524,7 +1694,7 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
| 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);
|
|
|
| @@ -1555,6 +1725,17 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
| 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)
|
| @@ -1642,6 +1823,8 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
| 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. */
|
|
|