aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame-unwind.h
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2018-09-07 20:04:44 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2018-12-19 20:59:38 +0000
commit8bcb5208976448aab20df7dd50e9286ef1f7e22c (patch)
tree60b911587b7c7a0e77aed216bad3a5dcd81777dc /gdb/frame-unwind.h
parentb9519cfe9828b9ee5a73e74b4be83d46f33e6886 (diff)
downloadgdb-8bcb5208976448aab20df7dd50e9286ef1f7e22c.zip
gdb-8bcb5208976448aab20df7dd50e9286ef1f7e22c.tar.gz
gdb-8bcb5208976448aab20df7dd50e9286ef1f7e22c.tar.bz2
gdb: Add default frame methods to gdbarch
Supply default gdbarch methods for gdbarch_dummy_id, gdbarch_unwind_pc, and gdbarch_unwind_sp. This patch doesn't actually convert any targets to use these methods, and so, there will be no user visible changes after this commit. The implementations for default_dummy_id and default_unwind_sp are fairly straight forward, these just take on the pattern used by most targets. Once these default methods are in place then most targets will be able to switch over. The implementation for default_unwind_pc is also fairly straight forward, but maybe needs some explanation. This patch has gone through a number of iterations: https://sourceware.org/ml/gdb-patches/2018-03/msg00165.html https://sourceware.org/ml/gdb-patches/2018-03/msg00306.html https://sourceware.org/ml/gdb-patches/2018-06/msg00090.html https://sourceware.org/ml/gdb-patches/2018-09/msg00127.html and the implementation of default_unwind_pc has changed over this time. Originally, I took an implementation like this: CORE_ADDR default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { int pc_regnum = gdbarch_pc_regnum (gdbarch); return frame_unwind_register_unsigned (next_frame, pc_regnum); } This is basically a clone of default_unwind_sp, but using $pc. It was pointed out that we could potentially do better, and in version 2 the implementation became: CORE_ADDR default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { struct type *type; int pc_regnum; CORE_ADDR addr; struct value *value; pc_regnum = gdbarch_pc_regnum (gdbarch); value = frame_unwind_register_value (next_frame, pc_regnum); type = builtin_type (gdbarch)->builtin_func_ptr; addr = extract_typed_address (value_contents_all (value), type); addr = gdbarch_addr_bits_remove (gdbarch, addr); release_value (value); value_free (value); return addr; } The idea was to try split out some of the steps of unwinding the $pc, steps that are on some (or many) targets no-ops, and so allow targets that do override these methods, to make use of default_unwind_pc. This implementation remained in place for version 2, 3, and 4. However, I realised that I'd made a mistake, most targets simply use frame_unwind_register_unsigned to unwind the $pc, and this throws an error if the register value is optimized out or unavailable. My new proposed implementation doesn't do this, I was going to end up breaking many targets. I considered duplicating the code from frame_unwind_register_unsigned that throws the errors into my new default_unwind_pc, however, this felt really overly complex. So, what I instead went with was to simply revert back to using frame_unwind_register_unsigned. Almost all existing targets already use this. Some of the ones that don't can be converted to, which means almost all targets could end up using the default. One addition I have made over the version 1 implementation is to add a call to gdbarch_addr_bits_remove. For most targets this is a no-op, but for a handful, having this call in place will mean that they can use the default method. After all this, the new default_unwind_pc now looks like this: CORE_ADDR default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { int pc_regnum = gdbarch_pc_regnum (gdbarch); CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, pc_regnum); pc = gdbarch_addr_bits_remove (gdbarch, pc); return pc; } gdb/ChangeLog: * gdb/dummy-frame.c (default_dummy_id): Defined new function. * gdb/dummy-frame.h (default_dummy_id): Declare new function. * gdb/frame-unwind.c (default_unwind_pc): Define new function. (default_unwind_sp): Define new function. * gdb/frame-unwind.h (default_unwind_pc): Declare new function. (default_unwind_sp): Declare new function. * gdb/frame.c (frame_unwind_pc): Assume gdbarch_unwind_pc is available. (get_frame_sp): Assume that gdbarch_unwind_sp is available. * gdb/gdbarch.c: Regenerate. * gdb/gdbarch.h: Regenerate. * gdb/gdbarch.sh: Update definition of dummy_id, unwind_pc, and unwind_sp. Add additional header files to be included in generated file.
Diffstat (limited to 'gdb/frame-unwind.h')
-rw-r--r--gdb/frame-unwind.h12
1 files changed, 12 insertions, 0 deletions
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index af220f7..3ca3fdf 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -70,6 +70,18 @@ enum unwind_stop_reason
default_frame_unwind_stop_reason (struct frame_info *this_frame,
void **this_cache);
+/* A default unwind_pc callback that simply unwinds the register identified
+ by GDBARCH_PC_REGNUM. */
+
+extern CORE_ADDR default_unwind_pc (struct gdbarch *gdbarch,
+ struct frame_info *next_frame);
+
+/* A default unwind_sp callback that simply unwinds the register identified
+ by GDBARCH_SP_REGNUM. */
+
+extern CORE_ADDR default_unwind_sp (struct gdbarch *gdbarch,
+ struct frame_info *next_frame);
+
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
use THIS frame, and through it the NEXT frame's register unwind
method, to determine the frame ID of THIS frame.