780 lines
29 KiB
Diff
780 lines
29 KiB
Diff
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
|
|
From: Keith Seitz <keiths@redhat.com>
|
|
Date: Fri, 11 Jan 2019 17:02:17 -0500
|
|
Subject: gdb-rhbz1187581-power8-regs-not-in-8.2-12of15.patch
|
|
|
|
;; [PowerPC] Add support for EBB and PMU registers
|
|
;; Edjunior Barbosa Machado and Pedro Franco de Carvalho, RH BZ 1187581m
|
|
|
|
[PowerPC] Add support for EBB and PMU registers
|
|
|
|
This patch adds support for registers of the Event Based Branching and
|
|
Performance Monitoring Units for the powerpc linux native and core
|
|
file targets, and for the powerpc linux server stub.
|
|
|
|
All three EBB registers are accessible. Only a subset of the PMU
|
|
registers can be accessed through ptrace. Because of this, the PMU
|
|
registers are enumerated individually in gdbarch_tdep, as opposed to
|
|
having a single "have_pmu" flag. This is intended to make it easier
|
|
to add additional PMU registers in the future, since checking a
|
|
"have_pmu" flag elsewhere in the code would no longer be correct. The
|
|
tdesc feature is named org.gnu.gdb.power.linux.pmu because of this.
|
|
|
|
It's unclear if it makes sense to save and restore these registers
|
|
across function calls, since some of them can be modified
|
|
asynchronously. They are also not tracked in record-replay mode.
|
|
|
|
The kernel can return ENODATA when ptrace is used to get the EBB
|
|
registers, unless a linux performance event that uses EBB is open in
|
|
the inferior. For this reason, the "fill" functions in the server
|
|
stub for the ebb register sets is not implemented.
|
|
|
|
Since gdbserver writes all registers in one go before resuming the
|
|
inferior, this error would not be detected at the time the user tries
|
|
to write to one of the registers on the client side, and gdbserver
|
|
would print out warnings every time it resumes the inferior when no
|
|
ebb performance event is opened, so there is currently no
|
|
straightforward way to handle this case. This means the ebb registers
|
|
in the client-side regcache can become dirty when the user tries to
|
|
write to them, until the inferior is resumed and stopped again.
|
|
|
|
A related issue is that 'G' packets used to write to unrelated
|
|
registers will include bad data for the EBB registers if they are
|
|
unavailable, since no register status information is included in the
|
|
'G' packet. This data won't be written to the inferior by the
|
|
gdbserver stub because the "fill" functions are not implemented, and
|
|
currently the gdbserver stub doesn't change the status of the
|
|
registers in its own regcache in response to 'G' packets.
|
|
|
|
Another limitation for the ebb registers is that traceframes don't
|
|
record if registers are available or not, so if these registers are
|
|
collected when a tracepoint is hit and the inferior has no ebb event
|
|
opened, the user will see zero values for all of them, instead of the
|
|
usual <unavailable>.
|
|
|
|
Because these registers are often unavailable, trying to store them
|
|
with target_store_registers with -1 for the regno argument (all
|
|
registers) would almost always fail, so they are ignored in this case.
|
|
|
|
gdb/ChangeLog:
|
|
2018-10-26 Edjunior Barbosa Machado <emachado@linux.vnet.ibm.com>
|
|
Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
|
|
|
|
* arch/ppc-linux-common.h (PPC_LINUX_SIZEOF_EBBREGSET)
|
|
(PPC_LINUX_SIZEOF_PMUREGSET): Declare.
|
|
* nat/ppc-linux.h (PPC_FEATURE2_EBB, NT_PPC_EBB, NT_PPC_PMU):
|
|
Define if not already defined.
|
|
* features/rs6000/power-ebb.xml: New file.
|
|
* features/rs6000/power-linux-pmu.xml: New file.
|
|
* features/rs6000/powerpc-isa207-vsx32l.xml: Include ebb and pmu
|
|
features.
|
|
* features/rs6000/powerpc-isa207-vsx64l.xml: Likewise.
|
|
* features/rs6000/powerpc-isa207-vsx32l.c: Re-generate.
|
|
* features/rs6000/powerpc-isa207-vsx64l.c: Re-generate.
|
|
* regformats/rs6000/powerpc-isa207-vsx32l.dat: Re-generate.
|
|
* regformats/rs6000/powerpc-isa207-vsx64l.dat: Re-generate.
|
|
* ppc-linux-nat.c (fetch_register, fetch_ppc_registers): Call
|
|
fetch_regset with ebb and pmu regsets.
|
|
(store_register, store_ppc_registers): Call store_regset with ebb
|
|
and pmu regsets.
|
|
(ppc_linux_nat_target::read_description): Set isa207 field in the
|
|
features struct if ebb and pmu are avaiable.
|
|
* ppc-linux-tdep.c (ppc32_regmap_ebb, ppc32_regmap_pmu)
|
|
(ppc32_linux_ebbregset, ppc32_linux_pmuregset): New globals.
|
|
(ppc_linux_iterate_over_regset_sections): Call back with the ebb
|
|
and pmu regsets.
|
|
(ppc_linux_core_read_description): Check if the pmu section is
|
|
present and set isa207 in the features struct.
|
|
* ppc-linux-tdep.h (ppc32_linux_ebbregset)
|
|
(ppc32_linux_pmuregset): Declare.
|
|
* ppc-tdep.h (struct gdbarch_tdep) <ppc_mmcr0_regnum>: New field.
|
|
<ppc_mmcr2_regnum, ppc_siar_regnum, ppc_sdar_regnum>: New fields.
|
|
<ppc_sier_regnum>: New field.
|
|
(enum): <PPC_BESCR_REGNUM, PPC_EBBHR_REGNUM, PPC_EBBRR_REGNUM>:
|
|
New enum values.
|
|
<PPC_MMCR0_REGNUM, PPC_MMCR2_REGNUM, PPC_SIAR_REGNUM>: New enum
|
|
values.
|
|
<PPC_SDAR_REGNUM, PPC_SIER_REGNUM>: New enum values.
|
|
(PPC_IS_EBB_REGNUM, PPC_IS_PMU_REGNUM): Define.
|
|
* rs6000-tdep.c (rs6000_gdbarch_init): Look for and validate the
|
|
ebb and pmu features.
|
|
|
|
gdb/gdbserver/ChangeLog:
|
|
2018-10-26 Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
|
|
|
|
* configure.srv (powerpc*-*-linux*): Add rs6000/power-ebb.xml and
|
|
rs6000/power-linux-pmu.xml to srv_xmlfiles.
|
|
* linux-ppc-low.c (ppc_store_ebbregset, ppc_fill_pmuregset)
|
|
(ppc_store_pmuregset): New functions.
|
|
(ppc_regsets): Add entries for ebb and pmu regsets.
|
|
(ppc_arch_setup): Set isa207 in features struct if the ebb and
|
|
pmu regsets are available. Set sizes for these regsets.
|
|
|
|
gdb/doc/ChangeLog:
|
|
2018-10-26 Pedro Franco de Carvalho <pedromfc@linux.ibm.com>
|
|
|
|
* gdb.texinfo (PowerPC Features): Describe new features
|
|
"org.gnu.gdb.power.ebb" and "org.gnu.gdb.power.linux.pmu".
|
|
|
|
diff --git a/gdb/arch/ppc-linux-common.h b/gdb/arch/ppc-linux-common.h
|
|
--- a/gdb/arch/ppc-linux-common.h
|
|
+++ b/gdb/arch/ppc-linux-common.h
|
|
@@ -33,6 +33,8 @@ struct target_desc;
|
|
#define PPC_LINUX_SIZEOF_PPRREGSET 8
|
|
#define PPC_LINUX_SIZEOF_DSCRREGSET 8
|
|
#define PPC_LINUX_SIZEOF_TARREGSET 8
|
|
+#define PPC_LINUX_SIZEOF_EBBREGSET (3*8)
|
|
+#define PPC_LINUX_SIZEOF_PMUREGSET (5*8)
|
|
|
|
/* Check if the hwcap auxv entry indicates that isa205 is supported. */
|
|
bool ppc_linux_has_isa205 (CORE_ADDR hwcap);
|
|
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
|
|
--- a/gdb/doc/gdb.texinfo
|
|
+++ b/gdb/doc/gdb.texinfo
|
|
@@ -42564,6 +42564,15 @@ contain the 64-bit register @samp{dscr}.
|
|
The @samp{org.gnu.gdb.power.tar} feature is optional. It should
|
|
contain the 64-bit register @samp{tar}.
|
|
|
|
+The @samp{org.gnu.gdb.power.ebb} feature is optional. It should
|
|
+contain registers @samp{bescr}, @samp{ebbhr} and @samp{ebbrr}, all
|
|
+64-bit wide.
|
|
+
|
|
+The @samp{org.gnu.gdb.power.linux.pmu} feature is optional. It should
|
|
+contain registers @samp{mmcr0}, @samp{mmcr2}, @samp{siar}, @samp{sdar}
|
|
+and @samp{sier}, all 64-bit wide. This is the subset of the isa 2.07
|
|
+server PMU registers provided by @sc{gnu}/Linux.
|
|
+
|
|
@node S/390 and System z Features
|
|
@subsection S/390 and System z Features
|
|
@cindex target descriptions, S/390 features
|
|
diff --git a/gdb/features/rs6000/power-ebb.xml b/gdb/features/rs6000/power-ebb.xml
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/gdb/features/rs6000/power-ebb.xml
|
|
@@ -0,0 +1,14 @@
|
|
+<?xml version="1.0"?>
|
|
+<!-- Copyright (C) 2018 Free Software Foundation, Inc.
|
|
+
|
|
+ Copying and distribution of this file, with or without modification,
|
|
+ are permitted in any medium without royalty provided the copyright
|
|
+ notice and this notice are preserved. -->
|
|
+
|
|
+<!-- POWER8 Event-based Branching Registers. -->
|
|
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
|
+<feature name="org.gnu.gdb.power.ebb">
|
|
+ <reg name="bescr" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="ebbhr" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="ebbrr" bitsize="64" type="uint64" save-restore="no"/>
|
|
+</feature>
|
|
diff --git a/gdb/features/rs6000/power-linux-pmu.xml b/gdb/features/rs6000/power-linux-pmu.xml
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/gdb/features/rs6000/power-linux-pmu.xml
|
|
@@ -0,0 +1,17 @@
|
|
+<?xml version="1.0"?>
|
|
+<!-- Copyright (C) 2018 Free Software Foundation, Inc.
|
|
+
|
|
+ Copying and distribution of this file, with or without modification,
|
|
+ are permitted in any medium without royalty provided the copyright
|
|
+ notice and this notice are preserved. -->
|
|
+
|
|
+<!-- Subset of the POWER8 ISA 2.07 Performance Monitor Registers
|
|
+ provided by Linux. -->
|
|
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
|
+<feature name="org.gnu.gdb.power.linux.pmu">
|
|
+ <reg name="mmcr0" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="mmcr2" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="siar" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="sdar" bitsize="64" type="uint64" save-restore="no"/>
|
|
+ <reg name="sier" bitsize="64" type="uint64" save-restore="no"/>
|
|
+</feature>
|
|
diff --git a/gdb/features/rs6000/powerpc-isa207-vsx32l.c b/gdb/features/rs6000/powerpc-isa207-vsx32l.c
|
|
--- a/gdb/features/rs6000/powerpc-isa207-vsx32l.c
|
|
+++ b/gdb/features/rs6000/powerpc-isa207-vsx32l.c
|
|
@@ -199,5 +199,17 @@ initialize_tdesc_powerpc_isa207_vsx32l (void)
|
|
feature = tdesc_create_feature (result, "org.gnu.gdb.power.tar");
|
|
tdesc_create_reg (feature, "tar", 141, 1, NULL, 64, "uint64");
|
|
|
|
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.ebb");
|
|
+ tdesc_create_reg (feature, "bescr", 142, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "ebbhr", 143, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "ebbrr", 144, 0, NULL, 64, "uint64");
|
|
+
|
|
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux.pmu");
|
|
+ tdesc_create_reg (feature, "mmcr0", 145, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "mmcr2", 146, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "siar", 147, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "sdar", 148, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "sier", 149, 0, NULL, 64, "uint64");
|
|
+
|
|
tdesc_powerpc_isa207_vsx32l = result;
|
|
}
|
|
diff --git a/gdb/features/rs6000/powerpc-isa207-vsx32l.xml b/gdb/features/rs6000/powerpc-isa207-vsx32l.xml
|
|
--- a/gdb/features/rs6000/powerpc-isa207-vsx32l.xml
|
|
+++ b/gdb/features/rs6000/powerpc-isa207-vsx32l.xml
|
|
@@ -16,4 +16,6 @@
|
|
<xi:include href="power-ppr.xml"/>
|
|
<xi:include href="power-dscr.xml"/>
|
|
<xi:include href="power-tar.xml"/>
|
|
+ <xi:include href="power-ebb.xml"/>
|
|
+ <xi:include href="power-linux-pmu.xml"/>
|
|
</target>
|
|
diff --git a/gdb/features/rs6000/powerpc-isa207-vsx64l.c b/gdb/features/rs6000/powerpc-isa207-vsx64l.c
|
|
--- a/gdb/features/rs6000/powerpc-isa207-vsx64l.c
|
|
+++ b/gdb/features/rs6000/powerpc-isa207-vsx64l.c
|
|
@@ -199,5 +199,17 @@ initialize_tdesc_powerpc_isa207_vsx64l (void)
|
|
feature = tdesc_create_feature (result, "org.gnu.gdb.power.tar");
|
|
tdesc_create_reg (feature, "tar", 141, 1, NULL, 64, "uint64");
|
|
|
|
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.ebb");
|
|
+ tdesc_create_reg (feature, "bescr", 142, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "ebbhr", 143, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "ebbrr", 144, 0, NULL, 64, "uint64");
|
|
+
|
|
+ feature = tdesc_create_feature (result, "org.gnu.gdb.power.linux.pmu");
|
|
+ tdesc_create_reg (feature, "mmcr0", 145, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "mmcr2", 146, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "siar", 147, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "sdar", 148, 0, NULL, 64, "uint64");
|
|
+ tdesc_create_reg (feature, "sier", 149, 0, NULL, 64, "uint64");
|
|
+
|
|
tdesc_powerpc_isa207_vsx64l = result;
|
|
}
|
|
diff --git a/gdb/features/rs6000/powerpc-isa207-vsx64l.xml b/gdb/features/rs6000/powerpc-isa207-vsx64l.xml
|
|
--- a/gdb/features/rs6000/powerpc-isa207-vsx64l.xml
|
|
+++ b/gdb/features/rs6000/powerpc-isa207-vsx64l.xml
|
|
@@ -16,4 +16,6 @@
|
|
<xi:include href="power-ppr.xml"/>
|
|
<xi:include href="power-dscr.xml"/>
|
|
<xi:include href="power-tar.xml"/>
|
|
+ <xi:include href="power-ebb.xml"/>
|
|
+ <xi:include href="power-linux-pmu.xml"/>
|
|
</target>
|
|
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
|
|
--- a/gdb/gdbserver/configure.srv
|
|
+++ b/gdb/gdbserver/configure.srv
|
|
@@ -249,6 +249,8 @@ case "${target}" in
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/power-dscr.xml"
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/power-ppr.xml"
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/power-tar.xml"
|
|
+ srv_xmlfiles="${srv_xmlfiles} rs6000/power-ebb.xml"
|
|
+ srv_xmlfiles="${srv_xmlfiles} rs6000/power-linux-pmu.xml"
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-e500l.xml"
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml"
|
|
srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64l.xml"
|
|
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
|
|
--- a/gdb/gdbserver/linux-ppc-low.c
|
|
+++ b/gdb/gdbserver/linux-ppc-low.c
|
|
@@ -545,6 +545,61 @@ ppc_store_tarregset (struct regcache *regcache, const void *buf)
|
|
supply_register_by_name (regcache, "tar", tar);
|
|
}
|
|
|
|
+/* Event-Based Branching regset store function. Unless the inferior
|
|
+ has a perf event open, ptrace can return in error when reading and
|
|
+ writing to the regset, with ENODATA. For reading, the registers
|
|
+ will correctly show as unavailable. For writing, gdbserver
|
|
+ currently only caches any register writes from P and G packets and
|
|
+ the stub always tries to write all the regsets when resuming the
|
|
+ inferior, which would result in frequent warnings. For this
|
|
+ reason, we don't define a fill function. This also means that the
|
|
+ client-side regcache will be dirty if the user tries to write to
|
|
+ the EBB registers. G packets that the client sends to write to
|
|
+ unrelated registers will also include data for EBB registers, even
|
|
+ if they are unavailable. */
|
|
+
|
|
+static void
|
|
+ppc_store_ebbregset (struct regcache *regcache, const void *buf)
|
|
+{
|
|
+ const char *regset = (const char *) buf;
|
|
+
|
|
+ /* The order in the kernel regset is: EBBRR, EBBHR, BESCR. In the
|
|
+ .dat file is BESCR, EBBHR, EBBRR. */
|
|
+ supply_register_by_name (regcache, "ebbrr", ®set[0]);
|
|
+ supply_register_by_name (regcache, "ebbhr", ®set[8]);
|
|
+ supply_register_by_name (regcache, "bescr", ®set[16]);
|
|
+}
|
|
+
|
|
+/* Performance Monitoring Unit regset fill function. */
|
|
+
|
|
+static void
|
|
+ppc_fill_pmuregset (struct regcache *regcache, void *buf)
|
|
+{
|
|
+ char *regset = (char *) buf;
|
|
+
|
|
+ /* The order in the kernel regset is SIAR, SDAR, SIER, MMCR2, MMCR0.
|
|
+ In the .dat file is MMCR0, MMCR2, SIAR, SDAR, SIER. */
|
|
+ collect_register_by_name (regcache, "siar", ®set[0]);
|
|
+ collect_register_by_name (regcache, "sdar", ®set[8]);
|
|
+ collect_register_by_name (regcache, "sier", ®set[16]);
|
|
+ collect_register_by_name (regcache, "mmcr2", ®set[24]);
|
|
+ collect_register_by_name (regcache, "mmcr0", ®set[32]);
|
|
+}
|
|
+
|
|
+/* Performance Monitoring Unit regset store function. */
|
|
+
|
|
+static void
|
|
+ppc_store_pmuregset (struct regcache *regcache, const void *buf)
|
|
+{
|
|
+ const char *regset = (const char *) buf;
|
|
+
|
|
+ supply_register_by_name (regcache, "siar", ®set[0]);
|
|
+ supply_register_by_name (regcache, "sdar", ®set[8]);
|
|
+ supply_register_by_name (regcache, "sier", ®set[16]);
|
|
+ supply_register_by_name (regcache, "mmcr2", ®set[24]);
|
|
+ supply_register_by_name (regcache, "mmcr0", ®set[32]);
|
|
+}
|
|
+
|
|
static void
|
|
ppc_fill_vsxregset (struct regcache *regcache, void *buf)
|
|
{
|
|
@@ -654,6 +709,10 @@ static struct regset_info ppc_regsets[] = {
|
|
fetch them every time, but still fall back to PTRACE_PEEKUSER for the
|
|
general registers. Some kernels support these, but not the newer
|
|
PPC_PTRACE_GETREGS. */
|
|
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_EBB, 0, EXTENDED_REGS,
|
|
+ NULL, ppc_store_ebbregset },
|
|
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PMU, 0, EXTENDED_REGS,
|
|
+ ppc_fill_pmuregset, ppc_store_pmuregset },
|
|
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_TAR, 0, EXTENDED_REGS,
|
|
ppc_fill_tarregset, ppc_store_tarregset },
|
|
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PPC_PPR, 0, EXTENDED_REGS,
|
|
@@ -734,8 +793,13 @@ ppc_arch_setup (void)
|
|
features.ppr_dscr = true;
|
|
if ((ppc_hwcap2 & PPC_FEATURE2_ARCH_2_07)
|
|
&& (ppc_hwcap2 & PPC_FEATURE2_TAR)
|
|
+ && (ppc_hwcap2 & PPC_FEATURE2_EBB)
|
|
&& ppc_check_regset (tid, NT_PPC_TAR,
|
|
- PPC_LINUX_SIZEOF_TARREGSET))
|
|
+ PPC_LINUX_SIZEOF_TARREGSET)
|
|
+ && ppc_check_regset (tid, NT_PPC_EBB,
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET)
|
|
+ && ppc_check_regset (tid, NT_PPC_PMU,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET))
|
|
features.isa207 = true;
|
|
}
|
|
|
|
@@ -798,6 +862,14 @@ ppc_arch_setup (void)
|
|
regset->size = (features.isa207 ?
|
|
PPC_LINUX_SIZEOF_TARREGSET : 0);
|
|
break;
|
|
+ case NT_PPC_EBB:
|
|
+ regset->size = (features.isa207 ?
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET : 0);
|
|
+ break;
|
|
+ case NT_PPC_PMU:
|
|
+ regset->size = (features.isa207 ?
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET : 0);
|
|
+ break;
|
|
default:
|
|
break;
|
|
}
|
|
diff --git a/gdb/nat/ppc-linux.h b/gdb/nat/ppc-linux.h
|
|
--- a/gdb/nat/ppc-linux.h
|
|
+++ b/gdb/nat/ppc-linux.h
|
|
@@ -60,6 +60,9 @@
|
|
#ifndef PPC_FEATURE2_TAR
|
|
#define PPC_FEATURE2_TAR 0x04000000
|
|
#endif
|
|
+#ifndef PPC_FEATURE2_EBB
|
|
+#define PPC_FEATURE2_EBB 0x10000000
|
|
+#endif
|
|
|
|
/* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a
|
|
configure time check. Some older glibc's (for instance 2.2.1)
|
|
@@ -106,6 +109,16 @@
|
|
#define NT_PPC_DSCR 0x105
|
|
#endif
|
|
|
|
+/* Event Based Branch Registers. */
|
|
+#ifndef NT_PPC_EBB
|
|
+#define NT_PPC_EBB 0x106
|
|
+#endif
|
|
+
|
|
+/* Performance Monitor Registers. */
|
|
+#ifndef NT_PPC_PMU
|
|
+#define NT_PPC_PMU 0x107
|
|
+#endif
|
|
+
|
|
/* Return the wordsize of the target, either 4 or 8 bytes. */
|
|
int ppc_linux_target_wordsize (int tid);
|
|
|
|
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
|
|
--- a/gdb/ppc-linux-nat.c
|
|
+++ b/gdb/ppc-linux-nat.c
|
|
@@ -667,6 +667,24 @@ fetch_register (struct regcache *regcache, int tid, int regno)
|
|
&ppc32_linux_tarregset);
|
|
return;
|
|
}
|
|
+ else if (PPC_IS_EBB_REGNUM (regno))
|
|
+ {
|
|
+ gdb_assert (tdep->have_ebb);
|
|
+
|
|
+ fetch_regset (regcache, tid, NT_PPC_EBB,
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET,
|
|
+ &ppc32_linux_ebbregset);
|
|
+ return;
|
|
+ }
|
|
+ else if (PPC_IS_PMU_REGNUM (regno))
|
|
+ {
|
|
+ gdb_assert (tdep->ppc_mmcr0_regnum != -1);
|
|
+
|
|
+ fetch_regset (regcache, tid, NT_PPC_PMU,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ &ppc32_linux_pmuregset);
|
|
+ return;
|
|
+ }
|
|
|
|
if (regaddr == -1)
|
|
{
|
|
@@ -875,6 +893,14 @@ fetch_ppc_registers (struct regcache *regcache, int tid)
|
|
fetch_regset (regcache, tid, NT_PPC_TAR,
|
|
PPC_LINUX_SIZEOF_TARREGSET,
|
|
&ppc32_linux_tarregset);
|
|
+ if (tdep->have_ebb)
|
|
+ fetch_regset (regcache, tid, NT_PPC_EBB,
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET,
|
|
+ &ppc32_linux_ebbregset);
|
|
+ if (tdep->ppc_mmcr0_regnum != -1)
|
|
+ fetch_regset (regcache, tid, NT_PPC_PMU,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ &ppc32_linux_pmuregset);
|
|
}
|
|
|
|
/* Fetch registers from the child process. Fetch all registers if
|
|
@@ -1082,6 +1108,24 @@ store_register (const struct regcache *regcache, int tid, int regno)
|
|
&ppc32_linux_tarregset);
|
|
return;
|
|
}
|
|
+ else if (PPC_IS_EBB_REGNUM (regno))
|
|
+ {
|
|
+ gdb_assert (tdep->have_ebb);
|
|
+
|
|
+ store_regset (regcache, tid, regno, NT_PPC_EBB,
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET,
|
|
+ &ppc32_linux_ebbregset);
|
|
+ return;
|
|
+ }
|
|
+ else if (PPC_IS_PMU_REGNUM (regno))
|
|
+ {
|
|
+ gdb_assert (tdep->ppc_mmcr0_regnum != -1);
|
|
+
|
|
+ store_regset (regcache, tid, regno, NT_PPC_PMU,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ &ppc32_linux_pmuregset);
|
|
+ return;
|
|
+ }
|
|
|
|
if (regaddr == -1)
|
|
return;
|
|
@@ -1308,6 +1352,15 @@ store_ppc_registers (const struct regcache *regcache, int tid)
|
|
store_regset (regcache, tid, -1, NT_PPC_TAR,
|
|
PPC_LINUX_SIZEOF_TARREGSET,
|
|
&ppc32_linux_tarregset);
|
|
+
|
|
+ if (tdep->ppc_mmcr0_regnum != -1)
|
|
+ store_regset (regcache, tid, -1, NT_PPC_PMU,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ &ppc32_linux_pmuregset);
|
|
+
|
|
+ /* Because the EBB registers can be unavailable, attempts to store
|
|
+ them here would cause this function to fail most of the time, so
|
|
+ we ignore them. */
|
|
}
|
|
|
|
/* Fetch the AT_HWCAP entry from the aux vector. */
|
|
@@ -2439,7 +2492,10 @@ ppc_linux_nat_target::read_description ()
|
|
features.ppr_dscr = true;
|
|
if ((hwcap2 & PPC_FEATURE2_ARCH_2_07)
|
|
&& (hwcap2 & PPC_FEATURE2_TAR)
|
|
- && check_regset (tid, NT_PPC_TAR, PPC_LINUX_SIZEOF_TARREGSET))
|
|
+ && (hwcap2 & PPC_FEATURE2_EBB)
|
|
+ && check_regset (tid, NT_PPC_TAR, PPC_LINUX_SIZEOF_TARREGSET)
|
|
+ && check_regset (tid, NT_PPC_EBB, PPC_LINUX_SIZEOF_EBBREGSET)
|
|
+ && check_regset (tid, NT_PPC_PMU, PPC_LINUX_SIZEOF_PMUREGSET))
|
|
features.isa207 = true;
|
|
}
|
|
|
|
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
|
|
--- a/gdb/ppc-linux-tdep.c
|
|
+++ b/gdb/ppc-linux-tdep.c
|
|
@@ -599,6 +599,44 @@ const struct regset ppc32_linux_tarregset = {
|
|
regcache_collect_regset
|
|
};
|
|
|
|
+/* Event-Based Branching regmap. */
|
|
+
|
|
+static const struct regcache_map_entry ppc32_regmap_ebb[] =
|
|
+ {
|
|
+ { 1, PPC_EBBRR_REGNUM, 8 },
|
|
+ { 1, PPC_EBBHR_REGNUM, 8 },
|
|
+ { 1, PPC_BESCR_REGNUM, 8 },
|
|
+ { 0 }
|
|
+ };
|
|
+
|
|
+/* Event-Based Branching regset. */
|
|
+
|
|
+const struct regset ppc32_linux_ebbregset = {
|
|
+ ppc32_regmap_ebb,
|
|
+ regcache_supply_regset,
|
|
+ regcache_collect_regset
|
|
+};
|
|
+
|
|
+/* Performance Monitoring Unit regmap. */
|
|
+
|
|
+static const struct regcache_map_entry ppc32_regmap_pmu[] =
|
|
+ {
|
|
+ { 1, PPC_SIAR_REGNUM, 8 },
|
|
+ { 1, PPC_SDAR_REGNUM, 8 },
|
|
+ { 1, PPC_SIER_REGNUM, 8 },
|
|
+ { 1, PPC_MMCR2_REGNUM, 8 },
|
|
+ { 1, PPC_MMCR0_REGNUM, 8 },
|
|
+ { 0 }
|
|
+ };
|
|
+
|
|
+/* Performance Monitoring Unit regset. */
|
|
+
|
|
+const struct regset ppc32_linux_pmuregset = {
|
|
+ ppc32_regmap_pmu,
|
|
+ regcache_supply_regset,
|
|
+ regcache_collect_regset
|
|
+};
|
|
+
|
|
const struct regset *
|
|
ppc_linux_gregset (int wordsize)
|
|
{
|
|
@@ -674,6 +712,22 @@ ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
|
|
cb (".reg-ppc-tar", PPC_LINUX_SIZEOF_TARREGSET,
|
|
PPC_LINUX_SIZEOF_TARREGSET,
|
|
&ppc32_linux_tarregset, "Target Address Register", cb_data);
|
|
+
|
|
+ /* EBB registers are unavailable when ptrace returns ENODATA. Check
|
|
+ availability when generating a core file (regcache != NULL). */
|
|
+ if (tdep->have_ebb)
|
|
+ if (regcache == NULL
|
|
+ || REG_VALID == regcache->get_register_status (PPC_BESCR_REGNUM))
|
|
+ cb (".reg-ppc-ebb", PPC_LINUX_SIZEOF_EBBREGSET,
|
|
+ PPC_LINUX_SIZEOF_EBBREGSET,
|
|
+ &ppc32_linux_ebbregset, "Event-based Branching Registers",
|
|
+ cb_data);
|
|
+
|
|
+ if (tdep->ppc_mmcr0_regnum != -1)
|
|
+ cb (".reg-ppc-pmu", PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ PPC_LINUX_SIZEOF_PMUREGSET,
|
|
+ &ppc32_linux_pmuregset, "Performance Monitor Registers",
|
|
+ cb_data);
|
|
}
|
|
|
|
static void
|
|
@@ -1089,6 +1143,7 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
|
|
asection *ppr = bfd_get_section_by_name (abfd, ".reg-ppc-ppr");
|
|
asection *dscr = bfd_get_section_by_name (abfd, ".reg-ppc-dscr");
|
|
asection *tar = bfd_get_section_by_name (abfd, ".reg-ppc-tar");
|
|
+ asection *pmu = bfd_get_section_by_name (abfd, ".reg-ppc-pmu");
|
|
|
|
if (! section)
|
|
return NULL;
|
|
@@ -1124,7 +1179,12 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
|
|
if (ppr && dscr)
|
|
{
|
|
features.ppr_dscr = true;
|
|
- if (tar)
|
|
+
|
|
+ /* We don't require the EBB note section to be present in the
|
|
+ core file to select isa207 because these registers could have
|
|
+ been unavailable when the core file was created. They will
|
|
+ be in the tdep but will show as unavailable. */
|
|
+ if (tar && pmu)
|
|
features.isa207 = true;
|
|
}
|
|
|
|
diff --git a/gdb/ppc-linux-tdep.h b/gdb/ppc-linux-tdep.h
|
|
--- a/gdb/ppc-linux-tdep.h
|
|
+++ b/gdb/ppc-linux-tdep.h
|
|
@@ -48,5 +48,7 @@ int ppc_linux_trap_reg_p (struct gdbarch *gdbarch);
|
|
extern const struct regset ppc32_linux_pprregset;
|
|
extern const struct regset ppc32_linux_dscrregset;
|
|
extern const struct regset ppc32_linux_tarregset;
|
|
+extern const struct regset ppc32_linux_ebbregset;
|
|
+extern const struct regset ppc32_linux_pmuregset;
|
|
|
|
#endif /* PPC_LINUX_TDEP_H */
|
|
diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h
|
|
--- a/gdb/ppc-tdep.h
|
|
+++ b/gdb/ppc-tdep.h
|
|
@@ -265,6 +265,15 @@ struct gdbarch_tdep
|
|
/* Decimal 128 registers. */
|
|
int ppc_dl0_regnum; /* First Decimal128 argument register pair. */
|
|
|
|
+ int have_ebb;
|
|
+
|
|
+ /* PMU registers. */
|
|
+ int ppc_mmcr0_regnum;
|
|
+ int ppc_mmcr2_regnum;
|
|
+ int ppc_siar_regnum;
|
|
+ int ppc_sdar_regnum;
|
|
+ int ppc_sier_regnum;
|
|
+
|
|
/* Offset to ABI specific location where link register is saved. */
|
|
int lr_frame_offset;
|
|
|
|
@@ -321,12 +330,31 @@ enum {
|
|
PPC_PPR_REGNUM = 172,
|
|
PPC_DSCR_REGNUM = 173,
|
|
PPC_TAR_REGNUM = 174,
|
|
+
|
|
+ /* EBB registers. */
|
|
+ PPC_BESCR_REGNUM = 175,
|
|
+ PPC_EBBHR_REGNUM = 176,
|
|
+ PPC_EBBRR_REGNUM = 177,
|
|
+
|
|
+ /* PMU registers. */
|
|
+ PPC_MMCR0_REGNUM = 178,
|
|
+ PPC_MMCR2_REGNUM = 179,
|
|
+ PPC_SIAR_REGNUM = 180,
|
|
+ PPC_SDAR_REGNUM = 181,
|
|
+ PPC_SIER_REGNUM = 182,
|
|
+
|
|
PPC_NUM_REGS
|
|
};
|
|
|
|
/* Big enough to hold the size of the largest register in bytes. */
|
|
#define PPC_MAX_REGISTER_SIZE 64
|
|
|
|
+#define PPC_IS_EBB_REGNUM(i) \
|
|
+ ((i) >= PPC_BESCR_REGNUM && (i) <= PPC_EBBRR_REGNUM)
|
|
+
|
|
+#define PPC_IS_PMU_REGNUM(i) \
|
|
+ ((i) >= PPC_MMCR0_REGNUM && (i) <= PPC_SIER_REGNUM)
|
|
+
|
|
/* An instruction to match. */
|
|
|
|
struct ppc_insn_pattern
|
|
diff --git a/gdb/regformats/rs6000/powerpc-isa207-vsx32l.dat b/gdb/regformats/rs6000/powerpc-isa207-vsx32l.dat
|
|
--- a/gdb/regformats/rs6000/powerpc-isa207-vsx32l.dat
|
|
+++ b/gdb/regformats/rs6000/powerpc-isa207-vsx32l.dat
|
|
@@ -145,3 +145,11 @@ expedite:r1,pc
|
|
64:ppr
|
|
64:dscr
|
|
64:tar
|
|
+64:bescr
|
|
+64:ebbhr
|
|
+64:ebbrr
|
|
+64:mmcr0
|
|
+64:mmcr2
|
|
+64:siar
|
|
+64:sdar
|
|
+64:sier
|
|
diff --git a/gdb/regformats/rs6000/powerpc-isa207-vsx64l.dat b/gdb/regformats/rs6000/powerpc-isa207-vsx64l.dat
|
|
--- a/gdb/regformats/rs6000/powerpc-isa207-vsx64l.dat
|
|
+++ b/gdb/regformats/rs6000/powerpc-isa207-vsx64l.dat
|
|
@@ -145,3 +145,11 @@ expedite:r1,pc
|
|
64:ppr
|
|
64:dscr
|
|
64:tar
|
|
+64:bescr
|
|
+64:ebbhr
|
|
+64:ebbrr
|
|
+64:mmcr0
|
|
+64:mmcr2
|
|
+64:siar
|
|
+64:sdar
|
|
+64:sier
|
|
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
|
|
--- a/gdb/rs6000-tdep.c
|
|
+++ b/gdb/rs6000-tdep.c
|
|
@@ -5871,7 +5871,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|
enum powerpc_elf_abi elf_abi = POWERPC_ELF_AUTO;
|
|
int have_fpu = 0, have_spe = 0, have_mq = 0, have_altivec = 0;
|
|
int have_dfp = 0, have_vsx = 0, have_ppr = 0, have_dscr = 0;
|
|
- int have_tar = 0;
|
|
+ int have_tar = 0, have_ebb = 0, have_pmu = 0;
|
|
int tdesc_wordsize = -1;
|
|
const struct target_desc *tdesc = info.target_desc;
|
|
struct tdesc_arch_data *tdesc_data = NULL;
|
|
@@ -6211,6 +6211,64 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|
}
|
|
else
|
|
have_tar = 0;
|
|
+
|
|
+ /* Event-based Branching Registers. */
|
|
+ feature = tdesc_find_feature (tdesc,
|
|
+ "org.gnu.gdb.power.ebb");
|
|
+ if (feature != NULL)
|
|
+ {
|
|
+ static const char *const ebb_regs[] = {
|
|
+ "bescr", "ebbhr", "ebbrr"
|
|
+ };
|
|
+
|
|
+ valid_p = 1;
|
|
+ for (i = 0; i < ARRAY_SIZE (ebb_regs); i++)
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_BESCR_REGNUM + i,
|
|
+ ebb_regs[i]);
|
|
+ if (!valid_p)
|
|
+ {
|
|
+ tdesc_data_cleanup (tdesc_data);
|
|
+ return NULL;
|
|
+ }
|
|
+ have_ebb = 1;
|
|
+ }
|
|
+ else
|
|
+ have_ebb = 0;
|
|
+
|
|
+ /* Subset of the ISA 2.07 Performance Monitor Registers provided
|
|
+ by Linux. */
|
|
+ feature = tdesc_find_feature (tdesc,
|
|
+ "org.gnu.gdb.power.linux.pmu");
|
|
+ if (feature != NULL)
|
|
+ {
|
|
+ valid_p = 1;
|
|
+
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_MMCR0_REGNUM,
|
|
+ "mmcr0");
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_MMCR2_REGNUM,
|
|
+ "mmcr2");
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_SIAR_REGNUM,
|
|
+ "siar");
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_SDAR_REGNUM,
|
|
+ "sdar");
|
|
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
|
|
+ PPC_SIER_REGNUM,
|
|
+ "sier");
|
|
+
|
|
+ if (!valid_p)
|
|
+ {
|
|
+ tdesc_data_cleanup (tdesc_data);
|
|
+ return NULL;
|
|
+ }
|
|
+ have_pmu = 1;
|
|
+ }
|
|
+ else
|
|
+ have_pmu = 0;
|
|
}
|
|
|
|
/* If we have a 64-bit binary on a 32-bit target, complain. Also
|
|
@@ -6408,6 +6466,20 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|
tdep->ppc_ppr_regnum = have_ppr ? PPC_PPR_REGNUM : -1;
|
|
tdep->ppc_dscr_regnum = have_dscr ? PPC_DSCR_REGNUM : -1;
|
|
tdep->ppc_tar_regnum = have_tar ? PPC_TAR_REGNUM : -1;
|
|
+ tdep->have_ebb = have_ebb;
|
|
+
|
|
+ /* If additional pmu registers are added, care must be taken when
|
|
+ setting new fields in the tdep below, to maintain compatibility
|
|
+ with features that only provide some of the registers. Currently
|
|
+ gdb access to the pmu registers is only supported in linux, and
|
|
+ linux only provides a subset of the pmu registers defined in the
|
|
+ architecture. */
|
|
+
|
|
+ tdep->ppc_mmcr0_regnum = have_pmu ? PPC_MMCR0_REGNUM : -1;
|
|
+ tdep->ppc_mmcr2_regnum = have_pmu ? PPC_MMCR2_REGNUM : -1;
|
|
+ tdep->ppc_siar_regnum = have_pmu ? PPC_SIAR_REGNUM : -1;
|
|
+ tdep->ppc_sdar_regnum = have_pmu ? PPC_SDAR_REGNUM : -1;
|
|
+ tdep->ppc_sier_regnum = have_pmu ? PPC_SIER_REGNUM : -1;
|
|
|
|
set_gdbarch_pc_regnum (gdbarch, PPC_PC_REGNUM);
|
|
set_gdbarch_sp_regnum (gdbarch, PPC_R0_REGNUM + 1);
|