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.
This commit is contained in:
Markus Metzger 2013-03-18 16:43:05 +01:00
parent 1f3ef5810c
commit ea001bdce2
4 changed files with 109 additions and 28 deletions

View File

@ -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)

View File

@ -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,6 +89,48 @@ frame_unwind_append_unwinder (struct gdbarch *gdbarch,
(*ip)->unwinder = unwinder;
}
/* 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. */
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, unwinder);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
res = unwinder->sniffer (unwinder, this_frame, this_cache);
}
if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR)
{
/* This usually means that not even the PC is available,
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 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. */
@ -98,37 +141,24 @@ 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)
{
struct cleanup *old_cleanup;
volatile struct gdb_exception ex;
int res = 0;
if (frame_unwind_try_unwinder (this_frame, this_cache, entry->unwinder))
return;
old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
res = entry->unwinder->sniffer (entry->unwinder, this_frame,
this_cache);
}
if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR)
{
/* This usually means that not even the PC is available,
thus most unwinders aren't able to determine if they're
the best fit. Keep trying. Fallback prologue unwinders
should always accept the frame. */
}
else if (ex.reason < 0)
throw_exception (ex);
else if (res)
{
discard_cleanups (old_cleanup);
return;
}
do_cleanups (old_cleanup);
}
internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
}

View File

@ -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,

View File

@ -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