/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986-2013 Free Software Foundation, Inc.
+ Copyright (C) 1986-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "observer.h"
#include "auxv.h"
#include "elf/common.h"
-#include "exceptions.h"
+#include "elf/ppc64.h"
#include "arch-utils.h"
#include "spu-tdep.h"
#include "xml-syscall.h"
ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- CORE_ADDR addr = bp_tgt->placed_address;
+ CORE_ADDR addr = bp_tgt->reqstd_address;
const unsigned char *bp;
int val;
int bplen;
readbuf, writebuf);
}
-static struct core_regset_section ppc_linux_vsx_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { ".reg-ppc-vsx", 256, "POWER7 VSX" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_vmx_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_fp_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { ".reg-ppc-vsx", 256, "POWER7 VSX" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_fp_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { NULL, 0}
-};
-
/* PLT stub in executable. */
static struct ppc_insn_pattern powerpc32_plt_stub[] =
{
/* Check if we are in the resolver. */
sym = lookup_minimal_symbol_by_pc (pc);
if (sym.minsym != NULL
- && (strcmp (SYMBOL_LINKAGE_NAME (sym.minsym), "__glink") == 0
- || strcmp (SYMBOL_LINKAGE_NAME (sym.minsym),
+ && (strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym), "__glink") == 0
+ || strcmp (MSYMBOL_LINKAGE_NAME (sym.minsym),
"__glink_PLTresolve") == 0))
return 1;
struct regcache *regcache,
int regnum, const void *gregs, size_t len)
{
- const struct ppc_reg_offsets *offsets = regset->descr;
+ const struct ppc_reg_offsets *offsets = regset->regmap;
ppc_supply_gregset (regset, regcache, regnum, gregs, len);
const struct regcache *regcache,
int regnum, void *gregs, size_t len)
{
- const struct ppc_reg_offsets *offsets = regset->descr;
+ const struct ppc_reg_offsets *offsets = regset->regmap;
/* Clear areas in the linux gregset not written elsewhere. */
if (regnum == -1)
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 *
return &ppc32_linux_fpregset;
}
-static const struct regset *
-ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
- const char *sect_name, size_t sect_size)
+/* Iterate over supported core file register note sections. */
+
+static void
+ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (core_arch);
- if (strcmp (sect_name, ".reg") == 0)
- {
- if (tdep->wordsize == 4)
- return &ppc32_linux_gregset;
- else
- return &ppc64_linux_gregset;
- }
- if (strcmp (sect_name, ".reg2") == 0)
- return &ppc32_linux_fpregset;
- if (strcmp (sect_name, ".reg-ppc-vmx") == 0)
- return &ppc32_linux_vrregset;
- if (strcmp (sect_name, ".reg-ppc-vsx") == 0)
- return &ppc32_linux_vsxregset;
- return NULL;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int have_altivec = tdep->ppc_vr0_regnum != -1;
+ int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
+ if (tdep->wordsize == 4)
+ cb (".reg", 48 * 4, &ppc32_linux_gregset, NULL, cb_data);
+ else
+ cb (".reg", 48 * 8, &ppc64_linux_gregset, NULL, cb_data);
+
+ cb (".reg2", 264, &ppc32_linux_fpregset, NULL, cb_data);
+
+ if (have_altivec)
+ cb (".reg-ppc-vmx", 544, &ppc32_linux_vrregset, "ppc Altivec", cb_data);
+
+ if (have_vsx)
+ cb (".reg-ppc-vsx", 256, &ppc32_linux_vsxregset, "POWER7 VSX", cb_data);
}
static void
}
}
+
+/* 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. */
error (_("Invalid register name `%s' on expression `%s'."),
regname, p->saved_arg);
- write_exp_elt_opcode (OP_REGISTER);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
str.ptr = regname;
str.length = len;
- write_exp_string (str);
- write_exp_elt_opcode (OP_REGISTER);
+ write_exp_string (&p->pstate, str);
+ write_exp_elt_opcode (&p->pstate, OP_REGISTER);
p->arg = s;
}
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);
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_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,
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
- set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
+ set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
else
set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
- /* Supported register sections. */
- if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.vsx"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc_linux_vsx_regset_sections);
- else if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.altivec"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc_linux_vmx_regset_sections);
- 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;
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_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);
+ 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);
(gdbarch, svr4_lp64_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
- set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
+ set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC64);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpcle");
else
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
-
- /* Supported register sections. */
- if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.vsx"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_vsx_regset_sections);
- else if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.altivec"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_vmx_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_fp_regset_sections);
}
/* PPC32 uses a different prpsinfo32 compared to most other Linux
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_iterate_over_regset_sections (gdbarch,
+ ppc_linux_iterate_over_regset_sections);
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,