[RFA][PATCH v4 4/5] S/390: Exploit dynamic core regset sections

Andreas Arnez
2013-07-03T17:11:57Z

Exploit dynamic core regset sections on S/390, such that the presence of
the TDB regset in a gcore-written core file depends on the validity of
the TDB registers.

2013-07-03 Andreas Arnez <arnez@linux.vnet.ibm.com>

* s390-tdep.c (gdbarch_tdep): New fields "have_linux_v1" and
"have_linux_v2".
(s390_linux32_regset_sections): Remove array.
(s390_linux32v1_regset_sections): Likewise.
(s390_linux32v2_regset_sections): Likewise.
(s390_linux64_regset_sections): Likewise.
(s390_linux64v1_regset_sections): Likewise.
(s390_linux64v2_regset_sections): Likewise.
(s390x_linux64_regset_sections): Likewise.
(s390x_linux64v1_regset_sections): Likewise.
(s390x_linux64v2_regset_sections): Likewise.
(s390_iterate_over_regset_sections ): New function.
(s390_gdbarch_init): Initialize new tdep fields "have_linux_v1"
and "have_linux_v2". Remove all invocations of
set_gdbarch_core_regset_sections; instead, call
set_gdbarch_iterate_over_regset_sections.

Index: gdb/gdb/s390-tdep.c
===================================================================
--- gdb.orig/gdb/s390-tdep.c
+++ gdb/gdb/s390-tdep.c
@@ -84,6 +84,9 @@ struct gdbarch_tdep

const struct regset *fpregset;
int sizeof_fpregset;
+
+ int have_linux_v1;
+ int have_linux_v2;
};

@@ -673,83 +676,38 @@ static const struct regset s390_tdb_regs
s390_collect_regset
};

-static struct core_regset_section s390_linux32_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390_linux32v1_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-last-break", 8, "s390 last-break address" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390_linux32v2_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-last-break", 8, "s390 last-break address" },
- { ".reg-s390-system-call", 4, "s390 system-call" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64v1_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
- { ".reg-s390-last-break", 8, "s930 last-break address" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390_linux64v2_regset_sections[] =
-{
- { ".reg", s390_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" },
- { ".reg-s390-last-break", 8, "s930 last-break address" },
- { ".reg-s390-system-call", 4, "s390 system-call" },
- { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390x_linux64_regset_sections[] =
-{
- { ".reg", s390x_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { NULL, 0}
-};
-
-static struct core_regset_section s390x_linux64v1_regset_sections[] =
-{
- { ".reg", s390x_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-last-break", 8, "s930 last-break address" },
- { NULL, 0}
-};
+/* Iterate over supported core file register note sections. */

-static struct core_regset_section s390x_linux64v2_regset_sections[] =
+static void
+s390_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
{
- { ".reg", s390x_sizeof_gregset, "general-purpose" },
- { ".reg2", s390_sizeof_fpregset, "floating-point" },
- { ".reg-s390-last-break", 8, "s930 last-break address" },
- { ".reg-s390-system-call", 4, "s390 system-call" },
- { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" },
- { NULL, 0}
-};
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int is_32_bit = tdep->abi == ABI_LINUX_S390 && tdep->gpr_full_regnum == -1;

+ if (cb (".reg", is_32_bit ? s390_sizeof_gregset : s390x_sizeof_gregset,
+ "general-purpose", cb_data))
+ return;
+ if (cb (".reg2", s390_sizeof_fpregset, "floating-point", cb_data))
+ return;
+ if (tdep->abi == ABI_LINUX_S390 && tdep->gpr_full_regnum != -1)
+ if (cb (".reg-s390-high-gprs", 16*4, "s390 GPR upper halves", cb_data))
+ return;
+ if (tdep->have_linux_v1)
+ if (cb (".reg-s390-last-break", 8, "s930 last-break address", cb_data))
+ return;
+ if (tdep->have_linux_v2)
+ {
+ if (cb (".reg-s390-system-call", 4, "s390 system-call", cb_data))
+ return;
+ if (regcache == NULL
+ || REG_VALID == regcache_register_status (regcache,
+ S390_TDB_DWORD0_REGNUM))
+ cb (".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB", cb_data);
+ }
+}

/* Return the appropriate register set for the core section identified
by SECT_NAME and SECT_SIZE. */
@@ -3160,20 +3118,23 @@ s390_gdbarch_init (struct gdbarch_info i
arches = gdbarch_list_lookup_by_info (arches->next, &info))
{
tdep = gdbarch_tdep (arches->gdbarch);
- if (!tdep)
- continue;
- if (tdep->abi != tdep_abi)
- continue;
- if ((tdep->gpr_full_regnum != -1) != have_upper)
- continue;
- if (tdesc_data != NULL)
- tdesc_data_cleanup (tdesc_data);
- return arches->gdbarch;
+ if (tdep
+ && tdep->abi == tdep_abi
+ && (tdep->gpr_full_regnum != -1) == have_upper
+ && tdep->have_linux_v1 == have_linux_v1
+ && tdep->have_linux_v2 == have_linux_v2)
+ {
+ if (tdesc_data != NULL)
+ tdesc_data_cleanup (tdesc_data);
+ return arches->gdbarch;
+ }
}

/* Otherwise create a new gdbarch for the specified machine type. */
tdep = XCALLOC (1, struct gdbarch_tdep);
tdep->abi = tdep_abi;
+ tdep->have_linux_v1 = have_linux_v1;
+ tdep->have_linux_v2 = have_linux_v2;
gdbarch = gdbarch_alloc (&info, tdep);

set_gdbarch_believe_pcc_promotion (gdbarch, 0);
@@ -3204,6 +3165,8 @@ s390_gdbarch_init (struct gdbarch_info i
set_gdbarch_regset_from_core_section (gdbarch,
s390_regset_from_core_section);
set_gdbarch_core_read_description (gdbarch, s390_core_read_description);
+ set_gdbarch_iterate_over_regset_sections (gdbarch,
+ s390_iterate_over_regset_sections);
set_gdbarch_cannot_store_register (gdbarch, s390_cannot_store_register);
set_gdbarch_write_pc (gdbarch, s390_write_pc);
set_gdbarch_pseudo_register_read (gdbarch, s390_pseudo_register_read);
@@ -3271,31 +3234,6 @@ s390_gdbarch_init (struct gdbarch_info i
set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
-
- if (have_upper)
- {
- if (have_linux_v2)
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux64v2_regset_sections);
- else if (have_linux_v1)
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux64v1_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux64_regset_sections);
- }
- else
- {
- if (have_linux_v2)
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux32v2_regset_sections);
- else if (have_linux_v1)
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux32v1_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- s390_linux32_regset_sections);
- }
break;

case ABI_LINUX_ZSERIES:
@@ -3315,16 +3253,6 @@ s390_gdbarch_init (struct gdbarch_info i
s390_address_class_type_flags_to_name);
set_gdbarch_address_class_name_to_type_flags (gdbarch,
s390_address_class_name_to_type_flags);
-
- if (have_linux_v2)
- set_gdbarch_core_regset_sections (gdbarch,
- s390x_linux64v2_regset_sections);
- else if (have_linux_v1)
- set_gdbarch_core_regset_sections (gdbarch,
- s390x_linux64v1_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- s390x_linux64_regset_sections);
break;
}