record-btrace: provide xfer_partial target method
Provide the xfer_partial target method for the btrace record target. Only allow memory read accesses to readonly memory while we're replaying, except for inserting and removing breakpoints. 2014-01-16 Markus Metzger <markus.t.metzger@intel.com> * record-btrace.c (record_btrace_xfer_partial) (record_btrace_insert_breakpoint, record_btrace_remove_breakpoint) (record_btrace_allow_memory_access): New. (init_record_btrace_ops): Initialize new methods. * target.c (raw_memory_xfer_partial): Bail out if target reports that this memory is not available.
This commit is contained in:
parent
3db08215d4
commit
633785ff28
3 changed files with 125 additions and 0 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
|
* record-btrace.c (record_btrace_xfer_partial)
|
||||||
|
(record_btrace_insert_breakpoint, record_btrace_remove_breakpoint)
|
||||||
|
(record_btrace_allow_memory_access): New.
|
||||||
|
(init_record_btrace_ops): Initialize new methods.
|
||||||
|
* target.c (raw_memory_xfer_partial): Bail out if target reports
|
||||||
|
that this memory is not available.
|
||||||
|
|
||||||
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
|
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
* target.h (target_ops) <to_insert_breakpoint>
|
* target.h (target_ops) <to_insert_breakpoint>
|
||||||
|
|
|
@ -41,6 +41,9 @@ static struct target_ops record_btrace_ops;
|
||||||
/* A new thread observer enabling branch tracing for the new thread. */
|
/* A new thread observer enabling branch tracing for the new thread. */
|
||||||
static struct observer *record_btrace_thread_observer;
|
static struct observer *record_btrace_thread_observer;
|
||||||
|
|
||||||
|
/* Temporarily allow memory accesses. */
|
||||||
|
static int record_btrace_allow_memory_access;
|
||||||
|
|
||||||
/* Print a record-btrace debug message. Use do ... while (0) to avoid
|
/* Print a record-btrace debug message. Use do ... while (0) to avoid
|
||||||
ambiguities when used in if statements. */
|
ambiguities when used in if statements. */
|
||||||
|
|
||||||
|
@ -752,6 +755,112 @@ record_btrace_is_replaying (void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The to_xfer_partial method of target record-btrace. */
|
||||||
|
|
||||||
|
static LONGEST
|
||||||
|
record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||||
|
const char *annex, gdb_byte *readbuf,
|
||||||
|
const gdb_byte *writebuf, ULONGEST offset,
|
||||||
|
ULONGEST len)
|
||||||
|
{
|
||||||
|
struct target_ops *t;
|
||||||
|
|
||||||
|
/* Filter out requests that don't make sense during replay. */
|
||||||
|
if (!record_btrace_allow_memory_access && record_btrace_is_replaying ())
|
||||||
|
{
|
||||||
|
switch (object)
|
||||||
|
{
|
||||||
|
case TARGET_OBJECT_MEMORY:
|
||||||
|
{
|
||||||
|
struct target_section *section;
|
||||||
|
|
||||||
|
/* We do not allow writing memory in general. */
|
||||||
|
if (writebuf != NULL)
|
||||||
|
return TARGET_XFER_E_UNAVAILABLE;
|
||||||
|
|
||||||
|
/* We allow reading readonly memory. */
|
||||||
|
section = target_section_by_addr (ops, offset);
|
||||||
|
if (section != NULL)
|
||||||
|
{
|
||||||
|
/* Check if the section we found is readonly. */
|
||||||
|
if ((bfd_get_section_flags (section->the_bfd_section->owner,
|
||||||
|
section->the_bfd_section)
|
||||||
|
& SEC_READONLY) != 0)
|
||||||
|
{
|
||||||
|
/* Truncate the request to fit into this section. */
|
||||||
|
len = min (len, section->endaddr - offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TARGET_XFER_E_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward the request. */
|
||||||
|
for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
|
||||||
|
if (ops->to_xfer_partial != NULL)
|
||||||
|
return ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
|
||||||
|
offset, len);
|
||||||
|
|
||||||
|
return TARGET_XFER_E_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The to_insert_breakpoint method of target record-btrace. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
record_btrace_insert_breakpoint (struct target_ops *ops,
|
||||||
|
struct gdbarch *gdbarch,
|
||||||
|
struct bp_target_info *bp_tgt)
|
||||||
|
{
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
int old, ret;
|
||||||
|
|
||||||
|
/* Inserting breakpoints requires accessing memory. Allow it for the
|
||||||
|
duration of this function. */
|
||||||
|
old = record_btrace_allow_memory_access;
|
||||||
|
record_btrace_allow_memory_access = 1;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||||
|
ret = forward_target_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
|
||||||
|
|
||||||
|
record_btrace_allow_memory_access = old;
|
||||||
|
|
||||||
|
if (except.reason < 0)
|
||||||
|
throw_exception (except);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The to_remove_breakpoint method of target record-btrace. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
record_btrace_remove_breakpoint (struct target_ops *ops,
|
||||||
|
struct gdbarch *gdbarch,
|
||||||
|
struct bp_target_info *bp_tgt)
|
||||||
|
{
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
int old, ret;
|
||||||
|
|
||||||
|
/* Removing breakpoints requires accessing memory. Allow it for the
|
||||||
|
duration of this function. */
|
||||||
|
old = record_btrace_allow_memory_access;
|
||||||
|
record_btrace_allow_memory_access = 1;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||||
|
ret = forward_target_remove_breakpoint (ops->beneath, gdbarch, bp_tgt);
|
||||||
|
|
||||||
|
record_btrace_allow_memory_access = old;
|
||||||
|
|
||||||
|
if (except.reason < 0)
|
||||||
|
throw_exception (except);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* The to_fetch_registers method of target record-btrace. */
|
/* The to_fetch_registers method of target record-btrace. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -929,6 +1038,9 @@ init_record_btrace_ops (void)
|
||||||
ops->to_call_history_from = record_btrace_call_history_from;
|
ops->to_call_history_from = record_btrace_call_history_from;
|
||||||
ops->to_call_history_range = record_btrace_call_history_range;
|
ops->to_call_history_range = record_btrace_call_history_range;
|
||||||
ops->to_record_is_replaying = record_btrace_is_replaying;
|
ops->to_record_is_replaying = record_btrace_is_replaying;
|
||||||
|
ops->to_xfer_partial = record_btrace_xfer_partial;
|
||||||
|
ops->to_remove_breakpoint = record_btrace_remove_breakpoint;
|
||||||
|
ops->to_insert_breakpoint = record_btrace_insert_breakpoint;
|
||||||
ops->to_fetch_registers = record_btrace_fetch_registers;
|
ops->to_fetch_registers = record_btrace_fetch_registers;
|
||||||
ops->to_store_registers = record_btrace_store_registers;
|
ops->to_store_registers = record_btrace_store_registers;
|
||||||
ops->to_prepare_to_store = record_btrace_prepare_to_store;
|
ops->to_prepare_to_store = record_btrace_prepare_to_store;
|
||||||
|
|
|
@ -1406,6 +1406,10 @@ raw_memory_xfer_partial (struct target_ops *ops, void *readbuf,
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Stop if the target reports that the memory is not available. */
|
||||||
|
if (res == TARGET_XFER_E_UNAVAILABLE)
|
||||||
|
break;
|
||||||
|
|
||||||
/* We want to continue past core files to executables, but not
|
/* We want to continue past core files to executables, but not
|
||||||
past a running target's memory. */
|
past a running target's memory. */
|
||||||
if (ops->to_has_all_memory (ops))
|
if (ops->to_has_all_memory (ops))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue