Browse Source

frame, backtrace: allow targets to supply a frame unwinder

Allow targets to supply their own target-specific frame unwinders; one for
normal frames and one for tailcall frames.  If a target-specific unwinder
is supplied, it will be chosen before any other unwinder.

The original patch has been split into this and the next two patches.

gdb/
2013-02-11  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* frame-unwind.c: Include target.h.
	(frame_unwind_try_unwinder): New function with code from ...
	(frame_unwind_find_by_frame): ... here.  New variable
	unwinder_from_target, call also target_get_unwinder)
	(target_get_tailcall_unwinder, and frame_unwind_try_unwinder for it.
	* target.c (target_get_unwinder, target_get_tailcall_unwinder): New.
	* target.h (struct target_ops): New fields to_get_unwinder and
	to_get_tailcall_unwinder.
	(target_get_unwinder, target_get_tailcall_unwinder): New declarations.
gdb-7.8-branch
Markus Metzger 14 years ago
parent
commit
ea001bdce2
  1. 12
      gdb/ChangeLog
  2. 62
      gdb/frame-unwind.c
  3. 28
      gdb/target.c
  4. 11
      gdb/target.h

12
gdb/ChangeLog

@ -1,3 +1,15 @@
2014-01-16 Jan Kratochvil <jan.kratochvil@redhat.com>
* frame-unwind.c: Include target.h.
(frame_unwind_try_unwinder): New function with code from ...
(frame_unwind_find_by_frame): ... here. New variable
unwinder_from_target, call also target_get_unwinder)
(target_get_tailcall_unwinder, and frame_unwind_try_unwinder for it.
* target.c (target_get_unwinder, target_get_tailcall_unwinder): New.
* target.h (struct target_ops): New fields to_get_unwinder and
to_get_tailcall_unwinder.
(target_get_unwinder, target_get_tailcall_unwinder): New declarations.
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
* record-btrace.c (record_btrace_fetch_registers)

62
gdb/frame-unwind.c

@ -27,6 +27,7 @@
#include "exceptions.h"
#include "gdb_assert.h"
#include "gdb_obstack.h"
#include "target.h"
static struct gdbarch_data *frame_unwind_data;
@ -88,29 +89,23 @@ frame_unwind_append_unwinder (struct gdbarch *gdbarch,
(*ip)->unwinder = unwinder;
}
/* Iterate through sniffers for THIS_FRAME frame until one returns with an
unwinder implementation. THIS_FRAME->UNWIND must be NULL, it will get set
by this function. Possibly initialize THIS_CACHE. */
void
frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
struct frame_unwind_table_entry *entry;
/* Call SNIFFER from UNWINDER. If it succeeded set UNWINDER for
THIS_FRAME and return 1. Otherwise the function keeps THIS_FRAME
unchanged and returns 0. */
for (entry = table->list; entry != NULL; entry = entry->next)
static int
frame_unwind_try_unwinder (struct frame_info *this_frame, void **this_cache,
const struct frame_unwind *unwinder)
{
struct cleanup *old_cleanup;
volatile struct gdb_exception ex;
int res = 0;
old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
old_cleanup = frame_prepare_for_sniffer (this_frame, unwinder);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
res = entry->unwinder->sniffer (entry->unwinder, this_frame,
this_cache);
res = unwinder->sniffer (unwinder, this_frame, this_cache);
}
if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR)
{
@ -118,17 +113,52 @@ frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
thus most unwinders aren't able to determine if they're
the best fit. Keep trying. Fallback prologue unwinders
should always accept the frame. */
do_cleanups (old_cleanup);
return 0;
}
else if (ex.reason < 0)
throw_exception (ex);
else if (res)
{
discard_cleanups (old_cleanup);
return;
return 1;
}
else
{
do_cleanups (old_cleanup);
return 0;
}
gdb_assert_not_reached ("frame_unwind_try_unwinder");
}
/* Iterate through sniffers for THIS_FRAME frame until one returns with an
unwinder implementation. THIS_FRAME->UNWIND must be NULL, it will get set
by this function. Possibly initialize THIS_CACHE. */
void
frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
struct frame_unwind_table_entry *entry;
const struct frame_unwind *unwinder_from_target;
unwinder_from_target = target_get_unwinder ();
if (unwinder_from_target != NULL
&& frame_unwind_try_unwinder (this_frame, this_cache,
unwinder_from_target))
return;
unwinder_from_target = target_get_tailcall_unwinder ();
if (unwinder_from_target != NULL
&& frame_unwind_try_unwinder (this_frame, this_cache,
unwinder_from_target))
return;
for (entry = table->list; entry != NULL; entry = entry->next)
if (frame_unwind_try_unwinder (this_frame, this_cache, entry->unwinder))
return;
internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
}

28
gdb/target.c

@ -4471,6 +4471,34 @@ debug_to_prepare_to_store (struct target_ops *self, struct regcache *regcache)
fprintf_unfiltered (gdb_stdlog, "target_prepare_to_store ()\n");
}
/* See target.h. */
const struct frame_unwind *
target_get_unwinder (void)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_get_unwinder != NULL)
return t->to_get_unwinder;
return NULL;
}
/* See target.h. */
const struct frame_unwind *
target_get_tailcall_unwinder (void)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
if (t->to_get_tailcall_unwinder != NULL)
return t->to_get_tailcall_unwinder;
return NULL;
}
static int
deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len,
int write, struct mem_attrib *attrib,

11
gdb/target.h

@ -900,6 +900,11 @@ struct target_ops
non-empty annex. */
int (*to_augmented_libraries_svr4_read) (void);
/* Those unwinders are tried before any other arch unwinders. Use NULL if
it is not used. */
const struct frame_unwind *to_get_unwinder;
const struct frame_unwind *to_get_tailcall_unwinder;
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@ -1791,6 +1796,12 @@ extern char *target_fileio_read_stralloc (const char *filename);
extern int target_core_of_thread (ptid_t ptid);
/* See to_get_unwinder in struct target_ops. */
extern const struct frame_unwind *target_get_unwinder (void);
/* See to_get_tailcall_unwinder in struct target_ops. */
extern const struct frame_unwind *target_get_tailcall_unwinder (void);
/* Verify that the memory in the [MEMADDR, MEMADDR+SIZE) range matches
the contents of [DATA,DATA+SIZE). Returns 1 if there's a match, 0
if there's a mismatch, and -1 if an error is encountered while

Loading…
Cancel
Save