From: Andreas Arnez <arnez@linux.vnet.ibm.com>
To: gdb-patches@sourceware.org
Cc: Ulrich.Weigand@de.ibm.com
Subject: [RFA][PATCH v4 3/5] Dynamic core regset sections support
Date: Wed, 03 Jul 2013 17:04:00 -0000 [thread overview]
Message-ID: <87mwq3inht.fsf@br87z6lw.de.ibm.com> (raw)
In-Reply-To: <87zju3intq.fsf@br87z6lw.de.ibm.com> (Andreas Arnez's message of "Wed, 03 Jul 2013 18:57:05 +0200")
Introduce a new way of specifying core file register note sections on
GNU/Linux targets. So far the target-dependent code provides a static
list of supported register note sections. This change enables the use
of an iterator function instead. The existing "static list" interface
is preserved.
A dynamic selection of regset sections is needed on z/Architecture
systems with transactional-execution support. With the static
approach, gcore always writes the TDB regset into the core file, even
if the inferior was stopped outside transactions and thus the TDB
registers are currently invalid. This results in writing zeroes,
which is wrong.
The use of an iterator function can also reduce complexity in the tdep
code for targets with many different register set combinations.
2013-07-03 Andreas Arnez <arnez@linux.vnet.ibm.com>
* regset.h (regset_iterate_over_sections): New function
declaration.
* regset.c (regset_iterate_over_sections): New function.
* gdbarch.sh: Add typedef for iterate_over_regset_sections_cb.
Support predicate functions with invalid_p.
(function_list): Add iterate_over_regset_sections.
* gdbarch.h: Regenerate.
* gdbarch.c: Regenerate.
* linux-tdep.c (linux_collect_regset_section_cb_data): New
structure.
(linux_collect_regset_section_cb): New function.
(linux_collect_thread_registers): Replace loop by iteration
through gdbarch_iterate_over_regset_sections.
(linux_make_corefile_notes_1): Adjust check.
* corelow.c (get_core_registers_cb): New function.
(get_core_registers): Instead of looping through the list returned
by gdbarch_core_regset_sections, iterate get_core_registers_cb via
gdbarch_iterate_over_regset_sections.
Index: gdb/gdb/gdbarch.sh
===================================================================
--- gdb.orig/gdb/gdbarch.sh
+++ gdb/gdb/gdbarch.sh
@@ -99,9 +99,7 @@ EOF
esac
case "${class}" in
- F | V | M )
- case "${invalid_p}" in
- "" )
+ F | V | M )
if test -n "${predefault}"
then
#invalid_p="gdbarch->${function} == ${predefault}"
@@ -114,12 +112,6 @@ EOF
predicate="gdbarch->${function} != NULL"
fi
;;
- * )
- echo "Predicate function ${function} with invalid_p." 1>&2
- kill $$
- exit 1
- ;;
- esac
esac
# PREDEFAULT is a valid fallback definition of MEMBER when
@@ -635,7 +627,15 @@ F:CORE_ADDR:fetch_pointer_argument:struc
# name SECT_NAME and size SECT_SIZE.
M:const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
-# Supported register notes in a core file.
+# Iterate over all supported register notes in a core file. For each
+# supported register note section, the iterator must call CB and pass
+# CB_DATA unchanged. If CB returns non-zero, the iterator must stop.
+# If REGCACHE is not NULL, the iterator can limit the supported
+# register note sections based on the current register values.
+# Otherwise it should enumerate all supported register note sections.
+M:void:iterate_over_regset_sections:iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache:cb, cb_data, regcache:::regset_iterate_over_sections:gdbarch->core_regset_sections && !gdbarch->iterate_over_regset_sections
+# Old way of specifying supported register notes in a core file, as a
+# static list. This overrides the iterator function above.
v:struct core_regset_section *:core_regset_sections:const char *name, int len::::::host_address_to_string (gdbarch->core_regset_sections)
# Create core file notes
@@ -992,12 +992,6 @@ EOF
do
eval echo \"\ \ \ \ ${r}=\${${r}}\"
done
- if class_is_predicate_p && fallback_default_p
- then
- echo "Error: predicate function ${function} can not have a non- multi-arch default" 1>&2
- kill $$
- exit 1
- fi
if [ "x${invalid_p}" = "x0" -a -n "${postdefault}" ]
then
echo "Error: postdefault is useless when invalid_p=0" 1>&2
@@ -1120,6 +1114,9 @@ extern struct gdbarch startup_gdbarch;
typedef int (iterate_over_objfiles_in_search_order_cb_ftype)
(struct objfile *objfile, void *cb_data);
+
+typedef int (iterate_over_regset_sections_cb)
+ (const char *sect_name, int size, const char *human_name, void *cb_data);
EOF
# function typedef's
@@ -1432,6 +1429,7 @@ cat <<EOF
#include "gdb_obstack.h"
#include "observer.h"
#include "regcache.h"
+#include "regset.h"
#include "objfiles.h"
/* Static function declarations */
@@ -1700,14 +1698,14 @@ do
if [ "x${invalid_p}" = "x0" ]
then
printf " /* Skip verify of ${function}, invalid_p == 0 */\n"
- elif class_is_predicate_p
- then
- printf " /* Skip verify of ${function}, has predicate. */\n"
# FIXME: See do_read for potential simplification
elif [ -n "${invalid_p}" -a -n "${postdefault}" ]
then
printf " if (${invalid_p})\n"
printf " gdbarch->${function} = ${postdefault};\n"
+ elif class_is_predicate_p
+ then
+ printf " /* Skip verify of ${function}, has predicate. */\n"
elif [ -n "${predefault}" -a -n "${postdefault}" ]
then
printf " if (gdbarch->${function} == ${predefault})\n"
Index: gdb/gdb/linux-tdep.c
===================================================================
--- gdb.orig/gdb/linux-tdep.c
+++ gdb/gdb/linux-tdep.c
@@ -1010,6 +1010,54 @@ linux_make_mappings_corefile_notes (stru
return note_data;
}
+/* Structure for passing information from
+ linux_collect_thread_registers via an iterator to
+ linux_collect_regset_section_cb. */
+
+struct linux_collect_regset_section_cb_data
+{
+ struct gdbarch *gdbarch;
+ const struct regcache *regcache;
+ bfd *obfd;
+ char *note_data;
+ int *note_size;
+ unsigned long lwp;
+ enum gdb_signal stop_signal;
+};
+
+/* Callback for iterate_over_regset_sections that records a single
+ regset in the corefile note section. */
+
+static int
+linux_collect_regset_section_cb (const char *sect_name, int size,
+ const char *human_name, void *cb_data)
+{
+ const struct regset *regset;
+ char *buf;
+ struct linux_collect_regset_section_cb_data *data = cb_data;
+
+ regset = gdbarch_regset_from_core_section (data->gdbarch, sect_name, size);
+ gdb_assert (regset && regset->collect_regset);
+
+ buf = xmalloc (size);
+ regset->collect_regset (regset, data->regcache, -1, buf, size);
+
+ /* PRSTATUS still needs to be treated specially. */
+ if (strcmp (sect_name, ".reg") == 0)
+ data->note_data = (char *) elfcore_write_prstatus
+ (data->obfd, data->note_data, data->note_size, data->lwp,
+ gdb_signal_to_host (data->stop_signal), buf);
+ else
+ data->note_data = (char *) elfcore_write_register_note
+ (data->obfd, data->note_data, data->note_size,
+ sect_name, buf, size);
+ xfree (buf);
+
+ if (!data->note_data)
+ return 1; /* Abort iteration. */
+ return 0;
+}
+
/* Records the thread's register state for the corefile note
section. */
@@ -1020,47 +1068,24 @@ linux_collect_thread_registers (const st
enum gdb_signal stop_signal)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct core_regset_section *sect_list;
- unsigned long lwp;
+ struct linux_collect_regset_section_cb_data data;
- sect_list = gdbarch_core_regset_sections (gdbarch);
- gdb_assert (sect_list);
+ data.gdbarch = gdbarch;
+ data.regcache = regcache;
+ data.obfd = obfd;
+ data.note_data = note_data;
+ data.note_size = note_size;
+ data.stop_signal = stop_signal;
/* For remote targets the LWP may not be available, so use the TID. */
- lwp = ptid_get_lwp (ptid);
- if (!lwp)
- lwp = ptid_get_tid (ptid);
-
- while (sect_list->sect_name != NULL)
- {
- const struct regset *regset;
- char *buf;
-
- regset = gdbarch_regset_from_core_section (gdbarch,
- sect_list->sect_name,
- sect_list->size);
- gdb_assert (regset && regset->collect_regset);
-
- buf = xmalloc (sect_list->size);
- regset->collect_regset (regset, regcache, -1, buf, sect_list->size);
-
- /* PRSTATUS still needs to be treated specially. */
- if (strcmp (sect_list->sect_name, ".reg") == 0)
- note_data = (char *) elfcore_write_prstatus
- (obfd, note_data, note_size, lwp,
- gdb_signal_to_host (stop_signal), buf);
- else
- note_data = (char *) elfcore_write_register_note
- (obfd, note_data, note_size,
- sect_list->sect_name, buf, sect_list->size);
- xfree (buf);
- sect_list++;
-
- if (!note_data)
- return NULL;
- }
-
- return note_data;
+ data.lwp = ptid_get_lwp (ptid);
+ if (!data.lwp)
+ data.lwp = ptid_get_tid (ptid);
+
+ gdbarch_iterate_over_regset_sections (gdbarch,
+ linux_collect_regset_section_cb,
+ &data, regcache);
+ return data.note_data;
}
/* Fetch the siginfo data for the current thread, if it exists. If
@@ -1440,7 +1465,7 @@ linux_make_corefile_notes_1 (struct gdba
converted to gdbarch_core_regset_sections, we no longer need to fall back
to the target method at this point. */
- if (!gdbarch_core_regset_sections (gdbarch))
+ if (!gdbarch_iterate_over_regset_sections_p (gdbarch))
return target_make_corefile_notes (obfd, note_size);
else
return linux_make_corefile_notes (gdbarch, obfd, note_size,
Index: gdb/gdb/gdbarch.c
===================================================================
--- gdb.orig/gdb/gdbarch.c
+++ gdb/gdb/gdbarch.c
@@ -49,6 +49,7 @@
#include "gdb_obstack.h"
#include "observer.h"
#include "regcache.h"
+#include "regset.h"
#include "objfiles.h"
/* Static function declarations */
@@ -236,6 +237,7 @@ struct gdbarch
gdbarch_register_reggroup_p_ftype *register_reggroup_p;
gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+ gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections;
struct core_regset_section * core_regset_sections;
gdbarch_make_corefile_notes_ftype *make_corefile_notes;
gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo;
@@ -408,6 +410,7 @@ struct gdbarch startup_gdbarch =
default_register_reggroup_p, /* register_reggroup_p */
0, /* fetch_pointer_argument */
0, /* regset_from_core_section */
+ 0, /* iterate_over_regset_sections */
0, /* core_regset_sections */
0, /* make_corefile_notes */
0, /* elfcore_write_linux_prpsinfo */
@@ -712,6 +715,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of register_reggroup_p, invalid_p == 0 */
/* Skip verify of fetch_pointer_argument, has predicate. */
/* Skip verify of regset_from_core_section, has predicate. */
+ if (gdbarch->core_regset_sections && !gdbarch->iterate_over_regset_sections)
+ gdbarch->iterate_over_regset_sections = regset_iterate_over_sections;
/* Skip verify of make_corefile_notes, has predicate. */
/* Skip verify of elfcore_write_linux_prpsinfo, has predicate. */
/* Skip verify of find_memory_regions, has predicate. */
@@ -1102,6 +1107,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: iterate_over_objfiles_in_search_order = <%s>\n",
host_address_to_string (gdbarch->iterate_over_objfiles_in_search_order));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_iterate_over_regset_sections_p() = %d\n",
+ gdbarch_iterate_over_regset_sections_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: iterate_over_regset_sections = <%s>\n",
+ host_address_to_string (gdbarch->iterate_over_regset_sections));
+ fprintf_unfiltered (file,
"gdbarch_dump: long_bit = %s\n",
plongest (gdbarch->long_bit));
fprintf_unfiltered (file,
@@ -3345,6 +3356,30 @@ set_gdbarch_regset_from_core_section (st
gdbarch->regset_from_core_section = regset_from_core_section;
}
+int
+gdbarch_iterate_over_regset_sections_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->iterate_over_regset_sections != NULL;
+}
+
+void
+gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->iterate_over_regset_sections != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_iterate_over_regset_sections called\n");
+ gdbarch->iterate_over_regset_sections (gdbarch, cb, cb_data, regcache);
+}
+
+void
+set_gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ gdbarch_iterate_over_regset_sections_ftype iterate_over_regset_sections)
+{
+ gdbarch->iterate_over_regset_sections = iterate_over_regset_sections;
+}
+
struct core_regset_section *
gdbarch_core_regset_sections (struct gdbarch *gdbarch)
{
Index: gdb/gdb/gdbarch.h
===================================================================
--- gdb.orig/gdb/gdbarch.h
+++ gdb/gdb/gdbarch.h
@@ -85,6 +85,9 @@ extern struct gdbarch startup_gdbarch;
typedef int (iterate_over_objfiles_in_search_order_cb_ftype)
(struct objfile *objfile, void *cb_data);
+typedef int (iterate_over_regset_sections_cb)
+ (const char *sect_name, int size, const char *human_name, void *cb_data);
+
/* The following are pre-initialized by GDBARCH. */
@@ -724,7 +727,21 @@ typedef const struct regset * (gdbarch_r
extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);
-/* Supported register notes in a core file. */
+/* Iterate over all supported register notes in a core file. For each
+ supported register note section, the iterator must call CB and pass
+ CB_DATA unchanged. If CB returns non-zero, the iterator must stop.
+ If REGCACHE is not NULL, the iterator can limit the supported
+ register note sections based on the current register values.
+ Otherwise it should enumerate all supported register note sections. */
+
+extern int gdbarch_iterate_over_regset_sections_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_iterate_over_regset_sections_ftype) (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache);
+extern void gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache);
+extern void set_gdbarch_iterate_over_regset_sections (struct gdbarch *gdbarch, gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections);
+
+/* Old way of specifying supported register notes in a core file, as a
+ static list. This overrides the iterator function above. */
extern struct core_regset_section * gdbarch_core_regset_sections (struct gdbarch *gdbarch);
extern void set_gdbarch_core_regset_sections (struct gdbarch *gdbarch, struct core_regset_section * core_regset_sections);
Index: gdb/gdb/regset.h
===================================================================
--- gdb.orig/gdb/regset.h
+++ gdb/gdb/regset.h
@@ -66,4 +66,11 @@ extern struct regset *regset_alloc (stru
supply_regset_ftype *supply_regset,
collect_regset_ftype *collect_regset);
+/* Iterate over the list of regsets specified with
+ gdbarch_set_core_regset_sections. */
+extern void regset_iterate_over_sections (struct gdbarch *arch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache);
+
#endif /* regset.h */
Index: gdb/gdb/corelow.c
===================================================================
--- gdb.orig/gdb/corelow.c
+++ gdb/gdb/corelow.c
@@ -547,6 +547,24 @@ get_core_register_section (struct regcac
bfd_section_vma (core_bfd, section)));
}
+/* Callback for get_core_registers that handles a single core file
+ register note section. */
+
+static int
+get_core_registers_cb (const char *sect_name, int size,
+ const char *human_name, void *cb_data)
+{
+ struct regcache *regcache = (struct regcache *) cb_data;
+
+ if (strcmp (sect_name, ".reg") == 0)
+ get_core_register_section (regcache, sect_name, 0, human_name, 1);
+ else if (strcmp (sect_name, ".reg2") == 0)
+ get_core_register_section (regcache, sect_name, 2, human_name, 0);
+ else
+ get_core_register_section (regcache, sect_name, 3, human_name, 0);
+
+ return 0;
+}
/* Get the registers out of a core file. This is the machine-
independent part. Fetch_core_registers is the machine-dependent
@@ -559,8 +577,8 @@ static void
get_core_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
- struct core_regset_section *sect_list;
int i;
+ struct gdbarch *gdbarch;
if (!(core_gdbarch && gdbarch_regset_from_core_section_p (core_gdbarch))
&& (core_vec == NULL || core_vec->core_read_registers == NULL))
@@ -570,23 +588,11 @@ get_core_registers (struct target_ops *o
return;
}
- sect_list = gdbarch_core_regset_sections (get_regcache_arch (regcache));
- if (sect_list)
- while (sect_list->sect_name != NULL)
- {
- if (strcmp (sect_list->sect_name, ".reg") == 0)
- get_core_register_section (regcache, sect_list->sect_name,
- 0, sect_list->human_name, 1);
- else if (strcmp (sect_list->sect_name, ".reg2") == 0)
- get_core_register_section (regcache, sect_list->sect_name,
- 2, sect_list->human_name, 0);
- else
- get_core_register_section (regcache, sect_list->sect_name,
- 3, sect_list->human_name, 0);
-
- sect_list++;
- }
-
+ gdbarch = get_regcache_arch (regcache);
+ if (gdbarch_iterate_over_regset_sections_p (gdbarch))
+ gdbarch_iterate_over_regset_sections (gdbarch,
+ get_core_registers_cb,
+ (void *) regcache, NULL);
else
{
get_core_register_section (regcache,
Index: gdb/gdb/regset.c
===================================================================
--- gdb.orig/gdb/regset.c
+++ gdb/gdb/regset.c
@@ -42,3 +42,25 @@ regset_alloc (struct gdbarch *arch,
return regset;
}
+
+/* Iterate over the list of regsets specified with
+ gdbarch_set_core_regset_sections. This is a convenience function
+ for targets which do not need a complex iterator. */
+
+void
+regset_iterate_over_sections (struct gdbarch *arch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+ struct core_regset_section *sect_list;
+
+ sect_list = gdbarch_core_regset_sections (arch);
+ while (sect_list->sect_name != NULL)
+ {
+ if (cb (sect_list->sect_name, sect_list->size,
+ sect_list->human_name, cb_data))
+ return;
+ sect_list++;
+ }
+}
next prev parent reply other threads:[~2013-07-03 17:04 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-03 16:57 [RFA][PATCH v4 0/5] Add TDB regset support Andreas Arnez
2013-07-03 17:00 ` [RFA][PATCH v4 1/5] S/390 regmap rework Andreas Arnez
2013-07-15 14:46 ` Luis Machado
2013-07-15 17:15 ` Andreas Arnez
2013-07-03 17:02 ` [RFA][PATCH v4 2/5] S/390: Add TDB regset Andreas Arnez
2013-07-03 19:25 ` Eli Zaretskii
2013-07-03 17:04 ` Andreas Arnez [this message]
2013-07-03 17:11 ` [RFA][PATCH v4 4/5] S/390: Exploit dynamic core regset sections Andreas Arnez
2013-07-03 17:21 ` [RFA][PATCH v4 5/5] PowerPC: " Andreas Arnez
2013-07-08 15:44 ` [ping] [RFA][PATCH v4 0/5] Add TDB regset support Andreas Arnez
2013-07-15 8:49 ` [ping 2] " Andreas Arnez
2013-07-15 13:27 ` Luis Machado
2013-07-15 15:34 ` Andreas Arnez
2013-07-15 15:40 ` Luis Machado
2013-07-15 16:30 ` Andreas Arnez
2013-07-16 15:26 ` Andreas Arnez
2013-07-16 16:03 ` Ulrich Weigand
2013-07-16 17:06 ` Andreas Arnez
2013-07-15 15:58 ` Mark Kettenis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87mwq3inht.fsf@br87z6lw.de.ibm.com \
--to=arnez@linux.vnet.ibm.com \
--cc=Ulrich.Weigand@de.ibm.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox