forked from Imagelibrary/binutils-gdb
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:
@@ -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>
|
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
* record-btrace.c (record_btrace_fetch_registers)
|
* record-btrace.c (record_btrace_fetch_registers)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "gdb_assert.h"
|
#include "gdb_assert.h"
|
||||||
#include "gdb_obstack.h"
|
#include "gdb_obstack.h"
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
static struct gdbarch_data *frame_unwind_data;
|
static struct gdbarch_data *frame_unwind_data;
|
||||||
|
|
||||||
@@ -88,6 +89,48 @@ frame_unwind_append_unwinder (struct gdbarch *gdbarch,
|
|||||||
(*ip)->unwinder = unwinder;
|
(*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
|
/* Iterate through sniffers for THIS_FRAME frame until one returns with an
|
||||||
unwinder implementation. THIS_FRAME->UNWIND must be NULL, it will get set
|
unwinder implementation. THIS_FRAME->UNWIND must be NULL, it will get set
|
||||||
by this function. Possibly initialize THIS_CACHE. */
|
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 gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||||
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
|
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
|
||||||
struct frame_unwind_table_entry *entry;
|
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)
|
for (entry = table->list; entry != NULL; entry = entry->next)
|
||||||
{
|
if (frame_unwind_try_unwinder (this_frame, this_cache, entry->unwinder))
|
||||||
struct cleanup *old_cleanup;
|
return;
|
||||||
volatile struct gdb_exception ex;
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
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"));
|
internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
gdb/target.c
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");
|
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
|
static int
|
||||||
deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len,
|
deprecated_debug_xfer_memory (CORE_ADDR memaddr, bfd_byte *myaddr, int len,
|
||||||
int write, struct mem_attrib *attrib,
|
int write, struct mem_attrib *attrib,
|
||||||
|
|||||||
11
gdb/target.h
11
gdb/target.h
@@ -900,6 +900,11 @@ struct target_ops
|
|||||||
non-empty annex. */
|
non-empty annex. */
|
||||||
int (*to_augmented_libraries_svr4_read) (void);
|
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;
|
int to_magic;
|
||||||
/* Need sub-structure for target machine related rather than comm related?
|
/* 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);
|
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
|
/* 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
|
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
|
if there's a mismatch, and -1 if an error is encountered while
|
||||||
|
|||||||
Reference in New Issue
Block a user