2018-06-19 09:24:56 +00:00
|
|
|
/* radare2 - LGPL - Copyright 2009-2018 - pancake */
|
2009-02-05 21:08:46 +00:00
|
|
|
|
|
|
|
#include <r_bp.h>
|
2017-05-26 00:43:26 +00:00
|
|
|
#include <config.h>
|
2009-04-13 22:47:02 +00:00
|
|
|
|
2013-06-15 00:56:25 +00:00
|
|
|
R_LIB_VERSION (r_bp);
|
|
|
|
|
2015-08-29 12:01:38 +00:00
|
|
|
static struct r_bp_plugin_t *bp_static_plugins[] =
|
2009-04-13 22:47:02 +00:00
|
|
|
{ R_BP_STATIC_PLUGINS };
|
2009-02-05 21:08:46 +00:00
|
|
|
|
2014-09-17 13:47:05 +00:00
|
|
|
static void r_bp_item_free (RBreakpointItem *b) {
|
2015-08-16 23:43:45 +00:00
|
|
|
free (b->name);
|
2014-09-17 13:47:05 +00:00
|
|
|
free (b->bbytes);
|
|
|
|
free (b->obytes);
|
2016-05-15 23:00:11 +00:00
|
|
|
free (b->module_name);
|
2016-09-01 17:11:46 +00:00
|
|
|
free (b->data);
|
|
|
|
free (b->cond);
|
2014-09-17 13:47:05 +00:00
|
|
|
free (b);
|
|
|
|
}
|
|
|
|
|
2010-05-20 15:40:58 +00:00
|
|
|
R_API RBreakpoint *r_bp_new() {
|
2014-10-28 10:14:30 +00:00
|
|
|
int i;
|
2017-05-26 00:43:26 +00:00
|
|
|
RBreakpointPlugin *static_plugin;
|
|
|
|
RBreakpoint *bp = R_NEW0 (RBreakpoint);
|
|
|
|
if (!bp) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-28 10:14:30 +00:00
|
|
|
bp->bps_idx_count = 16;
|
|
|
|
bp->bps_idx = R_NEWS0 (RBreakpointItem*, bp->bps_idx_count);
|
|
|
|
bp->stepcont = R_BP_CONT_NORMAL;
|
|
|
|
bp->traces = r_bp_traptrace_new ();
|
2015-08-08 18:15:13 +00:00
|
|
|
bp->cb_printf = (PrintfCallback)printf;
|
2014-10-28 10:14:30 +00:00
|
|
|
bp->bps = r_list_newf ((RListFree)r_bp_item_free);
|
|
|
|
bp->plugins = r_list_newf ((RListFree)free);
|
2017-08-20 08:39:10 +00:00
|
|
|
bp->nhwbps = 0;
|
2015-08-29 12:01:38 +00:00
|
|
|
for (i = 0; bp_static_plugins[i]; i++) {
|
2014-10-28 10:14:30 +00:00
|
|
|
static_plugin = R_NEW (RBreakpointPlugin);
|
|
|
|
memcpy (static_plugin, bp_static_plugins[i],
|
|
|
|
sizeof (RBreakpointPlugin));
|
|
|
|
r_bp_plugin_add (bp, static_plugin);
|
2010-01-21 01:38:52 +00:00
|
|
|
}
|
2014-10-28 10:14:30 +00:00
|
|
|
memset (&bp->iob, 0, sizeof (bp->iob));
|
2010-01-21 01:38:52 +00:00
|
|
|
return bp;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API RBreakpoint *r_bp_free(RBreakpoint *bp) {
|
2014-09-17 13:47:05 +00:00
|
|
|
r_list_free (bp->bps);
|
|
|
|
r_list_free (bp->plugins);
|
2015-08-29 07:58:57 +00:00
|
|
|
r_list_free (bp->traces);
|
2016-04-13 11:54:23 +00:00
|
|
|
free (bp->bps_idx);
|
2010-01-21 01:38:52 +00:00
|
|
|
free (bp);
|
2009-09-13 22:37:28 +00:00
|
|
|
return NULL;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API int r_bp_get_bytes(RBreakpoint *bp, ut8 *buf, int len, int endian, int idx) {
|
2009-04-12 22:46:44 +00:00
|
|
|
int i;
|
|
|
|
struct r_bp_arch_t *b;
|
|
|
|
if (bp->cur) {
|
2014-09-26 11:57:03 +00:00
|
|
|
// find matching size breakpoint
|
2015-06-01 14:18:29 +00:00
|
|
|
repeat:
|
2017-12-03 17:57:42 +00:00
|
|
|
for (i = 0; i < bp->cur->nbps; i++) {
|
2014-09-26 11:57:03 +00:00
|
|
|
b = &bp->cur->bps[i];
|
2015-06-22 10:23:38 +00:00
|
|
|
if (bp->cur->bps[i].bits) {
|
2017-05-26 00:43:26 +00:00
|
|
|
if (bp->bits != bp->cur->bps[i].bits) {
|
2015-06-22 10:23:38 +00:00
|
|
|
continue;
|
2017-05-26 00:43:26 +00:00
|
|
|
}
|
2015-06-22 10:23:38 +00:00
|
|
|
}
|
2016-09-06 10:02:38 +00:00
|
|
|
if (bp->cur->bps[i].length == len && bp->cur->bps[i].endian == endian) {
|
2014-09-26 11:57:03 +00:00
|
|
|
memcpy (buf, b->bytes, b->length);
|
2010-01-21 01:38:52 +00:00
|
|
|
return b->length;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-01 14:18:29 +00:00
|
|
|
if (len != 4) {
|
|
|
|
len = 4;
|
|
|
|
goto repeat;
|
|
|
|
}
|
2014-09-26 11:57:03 +00:00
|
|
|
/* if not found try to pad with the first one */
|
|
|
|
b = &bp->cur->bps[0];
|
|
|
|
if (len % b->length) {
|
|
|
|
eprintf ("No matching bpsize\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-02 16:01:18 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
2015-08-29 12:01:38 +00:00
|
|
|
memcpy (buf + i, b->bytes, b->length);
|
2014-09-26 11:57:03 +00:00
|
|
|
}
|
|
|
|
return b->length;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
2010-01-21 01:38:52 +00:00
|
|
|
return 0;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 01:28:58 +00:00
|
|
|
R_API RBreakpointItem *r_bp_get_at(RBreakpoint *bp, ut64 addr) {
|
2010-07-12 23:20:57 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RBreakpointItem *b;
|
2015-08-29 12:01:38 +00:00
|
|
|
r_list_foreach(bp->bps, iter, b) {
|
2018-06-19 09:24:56 +00:00
|
|
|
if (b->addr == addr) {
|
2010-07-12 23:20:57 +00:00
|
|
|
return b;
|
2018-06-19 09:24:56 +00:00
|
|
|
}
|
2015-08-29 12:01:38 +00:00
|
|
|
}
|
2010-07-12 23:20:57 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-05-15 08:40:57 +00:00
|
|
|
static inline bool inRange(RBreakpointItem *b, ut64 addr) {
|
|
|
|
return (addr >= b->addr && addr < (b->addr + b->size));
|
|
|
|
}
|
|
|
|
|
2018-09-21 00:16:54 +00:00
|
|
|
static inline bool matchProt(RBreakpointItem *b, int perm) {
|
|
|
|
return (!perm || (perm && b->perm));
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 00:16:54 +00:00
|
|
|
R_API RBreakpointItem *r_bp_get_in(RBreakpoint *bp, ut64 addr, int perm) {
|
2010-06-29 23:13:09 +00:00
|
|
|
RBreakpointItem *b;
|
2011-05-11 18:08:19 +00:00
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (bp->bps, iter, b) {
|
2018-09-21 00:16:54 +00:00
|
|
|
// eprintf ("---ataddr--- 0x%08"PFMT64x" %d %d %x\n", b->addr, b->size, b->recoil, b->perm);
|
|
|
|
// Check addr within range and provided perm matches (or null)
|
|
|
|
if (inRange (b, addr) && matchProt (b, perm)) {
|
2010-01-21 01:38:52 +00:00
|
|
|
return b;
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
2010-01-21 01:38:52 +00:00
|
|
|
return NULL;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 22:36:40 +00:00
|
|
|
R_API RBreakpointItem *r_bp_enable(RBreakpoint *bp, ut64 addr, int set, int count) {
|
2014-10-28 10:14:30 +00:00
|
|
|
RBreakpointItem *b = r_bp_get_in (bp, addr, 0);
|
|
|
|
if (b) {
|
|
|
|
b->enabled = set;
|
2018-04-14 22:36:40 +00:00
|
|
|
b->togglehits = count;
|
2014-10-28 10:14:30 +00:00
|
|
|
return b;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
2009-04-15 10:01:12 +00:00
|
|
|
return NULL;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 15:59:45 +00:00
|
|
|
R_API int r_bp_enable_all(RBreakpoint *bp, int set) {
|
|
|
|
RListIter *iter;
|
|
|
|
RBreakpointItem *b;
|
|
|
|
r_list_foreach (bp->bps, iter, b) {
|
|
|
|
b->enabled = set;
|
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2014-10-28 15:59:45 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API int r_bp_stepy_continuation(RBreakpoint *bp) {
|
2009-09-13 22:37:28 +00:00
|
|
|
// TODO: implement
|
|
|
|
return bp->stepcont;
|
|
|
|
}
|
|
|
|
|
2018-06-19 09:07:16 +00:00
|
|
|
static void unlinkBreakpoint(RBreakpoint *bp, RBreakpointItem *b) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < bp->bps_idx_count; i++) {
|
|
|
|
if (bp->bps_idx[i] == b) {
|
|
|
|
bp->bps_idx[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_list_delete_data (bp->bps, b);
|
|
|
|
}
|
|
|
|
|
2009-04-12 22:46:44 +00:00
|
|
|
/* TODO: detect overlapping of breakpoints */
|
2018-09-21 00:16:54 +00:00
|
|
|
static RBreakpointItem *r_bp_add(RBreakpoint *bp, const ut8 *obytes, ut64 addr, int size, int hw, int perm) {
|
2009-04-12 22:46:44 +00:00
|
|
|
int ret;
|
2010-06-29 23:13:09 +00:00
|
|
|
RBreakpointItem *b;
|
2016-05-15 08:40:57 +00:00
|
|
|
if (addr == UT64_MAX || size < 1) {
|
2016-01-22 09:53:58 +00:00
|
|
|
return NULL;
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
2018-09-21 00:16:54 +00:00
|
|
|
if (r_bp_get_in (bp, addr, perm)) {
|
2010-01-21 01:38:52 +00:00
|
|
|
eprintf ("Breakpoint already set at this address.\n");
|
2009-04-12 22:46:44 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-28 10:14:30 +00:00
|
|
|
b = r_bp_item_new (bp);
|
2019-12-06 09:52:26 +00:00
|
|
|
if (!b) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-13 02:59:44 +00:00
|
|
|
b->addr = addr + bp->delta;
|
2019-12-06 09:52:26 +00:00
|
|
|
if (bp->baddr > addr) {
|
|
|
|
eprintf ("base addr should not be larger than the breakpoint address.\n");
|
|
|
|
}
|
|
|
|
b->delta = addr - bp->baddr;
|
2009-04-12 22:46:44 +00:00
|
|
|
b->size = size;
|
2015-09-14 00:08:31 +00:00
|
|
|
b->enabled = true;
|
2018-09-21 00:16:54 +00:00
|
|
|
b->perm = perm;
|
2009-04-12 22:46:44 +00:00
|
|
|
b->hw = hw;
|
Major rework to the native debugger (esp on Linux) (#5185)
The major contribution here is completely re-worked breakpoint hit/recoil
handling. This work fixes #4907 and lays the ground work for future native
debugger improvements (multi-threading, etc).
* Give a human friendly type to enums
* Change many wait functions to return RDebugReasonType
* Better return checking (from r_debug_reg_sync, r_bp_restore)
* Optimized register synchronization
* Lots of comments and whitespace changes
* Improved inferior death detection
Handle EXIT_PID events differently than DEAD process events
* Move breakpoint/recoil handling to wait/cont/step
Rather than handing breakpoint related things inside cmd_debug.c, do that
inside the r_debug API functions. This seems like the most logical place for it
to live since it should apply to just about any platform/architecture. This
also centralizes calling into "cmd.bp" handling via the CoreBind callback.
* Track how the caller wishes to continue
It turns out that handling break point recoils is very complicated. The ptrace
API on Linux returns SIGTRAP for just about every type of operation (not just
breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are
single-stepping or continuing and whether or not we are inside the recoil.
* Proper handling for swstep=true
Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil
case there. Move the recoil handling from r_debug_step to r_debug_step_hard
only.
For the swstep=true case, special handling is required inside r_debug_recoil.
By resetting all of the breakpoints except the one we just hit, we ensure we
can step the original instruction and hit the new swstep breakpoint. Add a new
bp function called r_bp_restore_except to do this.
To make matters worse, we cannot use a BreakpointItem pointer because that
leads to a use-after-free condition. Instead, we the breakpoint address
instead.
Now breakpoints should work regardless of the swtep setting.
* Always call the recoil before continuing
Some callers of r_debug_continue might not have ever inserted any breakpoints
before. If we don't restore breakpoints before each call to the underlying
continue we won't hit them.
* Hide software step breakpoint events from the user
When a breakpoint even happens due to a software-step, hide it from the user.
They aren't really breakpoints as far as they are concerned.
* Improve process exit handling on Linux
There are three types of process exiting events on Linux:
1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to
prevent it from exiting, but it can be used to inspect the pre-exit state.
2. The process can exit for a variety of reasons and we can notice when we call
waitpid(2).
3. The process could die randomly on us :-/
On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely
on Linux to find out the process is already dead.
* Check more bits within waitpid status
We can often make a decision about what happened strictly by looking at the
status returned from waitpid. In other cases, we need to call
r_debug_handle_signals.
If we reach the end of this function without knowing what happened, consider it
an error.
2016-06-22 08:34:45 +00:00
|
|
|
// NOTE: for hw breakpoints there are no bytes to save/restore
|
2014-10-28 08:59:36 +00:00
|
|
|
if (!hw) {
|
2015-08-29 12:01:38 +00:00
|
|
|
b->bbytes = calloc (size + 16, 1);
|
2018-06-19 09:07:16 +00:00
|
|
|
if (!b->bbytes) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-01-21 01:38:52 +00:00
|
|
|
if (obytes) {
|
2010-06-29 23:13:09 +00:00
|
|
|
b->obytes = malloc (size);
|
2018-06-19 09:07:16 +00:00
|
|
|
if (!b->obytes) {
|
|
|
|
free (b->bbytes);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-01-21 01:38:52 +00:00
|
|
|
memcpy (b->obytes, obytes, size);
|
2015-08-29 12:01:38 +00:00
|
|
|
} else {
|
|
|
|
b->obytes = NULL;
|
|
|
|
}
|
2010-01-21 01:38:52 +00:00
|
|
|
/* XXX: endian .. use bp->endian */
|
2016-09-06 10:02:38 +00:00
|
|
|
ret = r_bp_get_bytes (bp, b->bbytes, size, bp->endian, 0);
|
Major rework to the native debugger (esp on Linux) (#5185)
The major contribution here is completely re-worked breakpoint hit/recoil
handling. This work fixes #4907 and lays the ground work for future native
debugger improvements (multi-threading, etc).
* Give a human friendly type to enums
* Change many wait functions to return RDebugReasonType
* Better return checking (from r_debug_reg_sync, r_bp_restore)
* Optimized register synchronization
* Lots of comments and whitespace changes
* Improved inferior death detection
Handle EXIT_PID events differently than DEAD process events
* Move breakpoint/recoil handling to wait/cont/step
Rather than handing breakpoint related things inside cmd_debug.c, do that
inside the r_debug API functions. This seems like the most logical place for it
to live since it should apply to just about any platform/architecture. This
also centralizes calling into "cmd.bp" handling via the CoreBind callback.
* Track how the caller wishes to continue
It turns out that handling break point recoils is very complicated. The ptrace
API on Linux returns SIGTRAP for just about every type of operation (not just
breakpoints getting hit). Add the "recoil_mode" flag to indicate whether we are
single-stepping or continuing and whether or not we are inside the recoil.
* Proper handling for swstep=true
Since r_debug_step_soft calls r_debug_continue, it's already hitting the recoil
case there. Move the recoil handling from r_debug_step to r_debug_step_hard
only.
For the swstep=true case, special handling is required inside r_debug_recoil.
By resetting all of the breakpoints except the one we just hit, we ensure we
can step the original instruction and hit the new swstep breakpoint. Add a new
bp function called r_bp_restore_except to do this.
To make matters worse, we cannot use a BreakpointItem pointer because that
leads to a use-after-free condition. Instead, we the breakpoint address
instead.
Now breakpoints should work regardless of the swtep setting.
* Always call the recoil before continuing
Some callers of r_debug_continue might not have ever inserted any breakpoints
before. If we don't restore breakpoints before each call to the underlying
continue we won't hit them.
* Hide software step breakpoint events from the user
When a breakpoint even happens due to a software-step, hide it from the user.
They aren't really breakpoints as far as they are concerned.
* Improve process exit handling on Linux
There are three types of process exiting events on Linux:
1. PTRACE_EVENT_EXIT occurs just before a process exits. It's not possible to
prevent it from exiting, but it can be used to inspect the pre-exit state.
2. The process can exit for a variety of reasons and we can notice when we call
waitpid(2).
3. The process could die randomly on us :-/
On Windows, h->wait will return R_DEBUG_REASON_EXIT_PID, but it's more likely
on Linux to find out the process is already dead.
* Check more bits within waitpid status
We can often make a decision about what happened strictly by looking at the
status returned from waitpid. In other cases, we need to call
r_debug_handle_signals.
If we reach the end of this function without knowing what happened, consider it
an error.
2016-06-22 08:34:45 +00:00
|
|
|
if (ret != size) {
|
|
|
|
eprintf ("Cannot get breakpoint bytes. No architecture selected?\n");
|
2018-06-19 09:07:16 +00:00
|
|
|
unlinkBreakpoint (bp, b);
|
2010-01-21 01:38:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
b->recoil = ret;
|
|
|
|
}
|
2009-04-12 22:46:44 +00:00
|
|
|
bp->nbps++;
|
2010-06-29 23:13:09 +00:00
|
|
|
r_list_append (bp->bps, b);
|
2009-04-12 22:46:44 +00:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2018-09-21 00:16:54 +00:00
|
|
|
R_API int r_bp_add_fault(RBreakpoint *bp, ut64 addr, int size, int perm) {
|
2009-12-24 02:17:53 +00:00
|
|
|
// TODO
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2009-12-24 02:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 00:16:54 +00:00
|
|
|
R_API RBreakpointItem* r_bp_add_sw(RBreakpoint *bp, ut64 addr, int size, int perm) {
|
2010-06-29 23:13:09 +00:00
|
|
|
RBreakpointItem *item;
|
2009-09-13 22:37:28 +00:00
|
|
|
ut8 *bytes;
|
2016-05-15 08:40:57 +00:00
|
|
|
if (size < 1) {
|
2016-01-22 09:53:58 +00:00
|
|
|
size = 1;
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
|
|
|
if (!(bytes = calloc (1, size))) {
|
2016-01-22 09:53:58 +00:00
|
|
|
return NULL;
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
|
|
|
memset (bytes, 0, size);
|
|
|
|
if (bp->iob.read_at) {
|
2016-01-22 09:53:58 +00:00
|
|
|
bp->iob.read_at (bp->iob.io, addr, bytes, size);
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
2018-09-21 00:16:54 +00:00
|
|
|
item = r_bp_add (bp, bytes, addr, size, R_BP_TYPE_SW, perm);
|
2010-01-21 01:38:52 +00:00
|
|
|
free (bytes);
|
2009-09-13 22:37:28 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2018-09-21 00:16:54 +00:00
|
|
|
R_API RBreakpointItem* r_bp_add_hw(RBreakpoint *bp, ut64 addr, int size, int perm) {
|
|
|
|
return r_bp_add (bp, NULL, addr, size, R_BP_TYPE_HW, perm);
|
2009-09-13 22:37:28 +00:00
|
|
|
}
|
|
|
|
|
2014-05-08 15:38:29 +00:00
|
|
|
R_API int r_bp_del_all(RBreakpoint *bp) {
|
2020-01-05 14:55:24 +00:00
|
|
|
int i;
|
2016-05-15 08:40:57 +00:00
|
|
|
if (!r_list_empty (bp->bps)) {
|
|
|
|
r_list_purge (bp->bps);
|
2020-01-05 14:55:24 +00:00
|
|
|
for (i = 0; i < bp->bps_idx_count; i++) {
|
|
|
|
bp->bps_idx[i] = NULL;
|
|
|
|
}
|
2016-05-15 08:40:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2014-05-08 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API int r_bp_del(RBreakpoint *bp, ut64 addr) {
|
2010-06-29 23:13:09 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RBreakpointItem *b;
|
2012-02-14 17:10:52 +00:00
|
|
|
/* No _safe loop necessary because we return immediately after the delete. */
|
2010-06-29 23:13:09 +00:00
|
|
|
r_list_foreach (bp->bps, iter, b) {
|
2009-04-12 22:46:44 +00:00
|
|
|
if (b->addr == addr) {
|
2018-06-19 09:07:16 +00:00
|
|
|
unlinkBreakpoint (bp, b);
|
|
|
|
// r_list_delete (bp->bps, iter);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2009-04-11 21:22:20 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API int r_bp_set_trace(RBreakpoint *bp, ut64 addr, int set) {
|
2014-10-28 10:14:30 +00:00
|
|
|
RBreakpointItem *b = r_bp_get_in (bp, addr, 0);
|
|
|
|
if (b) {
|
|
|
|
b->trace = set;
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2009-04-15 10:01:12 +00:00
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2009-09-13 22:37:28 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 15:59:45 +00:00
|
|
|
R_API int r_bp_set_trace_all(RBreakpoint *bp, int set) {
|
|
|
|
RListIter *iter;
|
|
|
|
RBreakpointItem *b;
|
|
|
|
r_list_foreach (bp->bps, iter, b) {
|
|
|
|
b->trace = set;
|
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2014-10-28 15:59:45 +00:00
|
|
|
}
|
2018-06-19 09:34:13 +00:00
|
|
|
|
2009-09-13 22:37:28 +00:00
|
|
|
// TODO: deprecate
|
2010-03-03 12:34:38 +00:00
|
|
|
R_API int r_bp_list(RBreakpoint *bp, int rad) {
|
2009-09-13 22:37:28 +00:00
|
|
|
int n = 0;
|
2010-06-29 23:13:09 +00:00
|
|
|
RBreakpointItem *b;
|
|
|
|
RListIter *iter;
|
2018-06-19 09:07:16 +00:00
|
|
|
if (rad == 'j') {
|
|
|
|
bp->cb_printf ("[");
|
|
|
|
}
|
2012-02-27 02:07:32 +00:00
|
|
|
//eprintf ("Breakpoint list:\n");
|
2010-06-29 23:13:09 +00:00
|
|
|
r_list_foreach (bp->bps, iter, b) {
|
2015-02-01 01:53:18 +00:00
|
|
|
switch (rad) {
|
|
|
|
case 0:
|
2015-10-13 02:59:44 +00:00
|
|
|
bp->cb_printf ("0x%08"PFMT64x" - 0x%08"PFMT64x \
|
2020-01-04 00:54:24 +00:00
|
|
|
" %d %c%c%c %s %s %s %s cmd=\"%s\" cond=\"%s\" " \
|
2016-05-15 23:00:11 +00:00
|
|
|
"name=\"%s\" module=\"%s\"\n",
|
2015-08-29 12:01:38 +00:00
|
|
|
b->addr, b->addr + b->size, b->size,
|
2018-09-21 00:16:54 +00:00
|
|
|
((b->perm & R_BP_PROT_READ) | (b->perm & R_BP_PROT_ACCESS)) ? 'r' : '-',
|
|
|
|
((b->perm & R_BP_PROT_WRITE)| (b->perm & R_BP_PROT_ACCESS)) ? 'w' : '-',
|
|
|
|
(b->perm & R_BP_PROT_EXEC) ? 'x' : '-',
|
2015-08-29 12:01:38 +00:00
|
|
|
b->hw ? "hw": "sw",
|
|
|
|
b->trace ? "trace" : "break",
|
|
|
|
b->enabled ? "enabled" : "disabled",
|
2020-01-04 00:54:24 +00:00
|
|
|
r_bp_is_valid (bp, b) ? "valid" : "invalid",
|
2016-09-01 17:11:46 +00:00
|
|
|
r_str_get2 (b->data),
|
|
|
|
r_str_get2 (b->cond),
|
|
|
|
r_str_get2 (b->name),
|
|
|
|
r_str_get2 (b->module_name));
|
2015-02-01 01:53:18 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 'r':
|
|
|
|
case '*':
|
|
|
|
// TODO: add command, tracing, enable, ..
|
2016-05-15 23:00:11 +00:00
|
|
|
if (b->module_name) {
|
|
|
|
bp->cb_printf ("dbm %s %"PFMT64d"\n", b->module_name, b->module_delta);
|
2017-08-20 08:39:10 +00:00
|
|
|
} else {
|
2016-05-15 23:00:11 +00:00
|
|
|
bp->cb_printf ("db 0x%08"PFMT64x"\n", b->addr);
|
|
|
|
}
|
2015-02-01 01:53:18 +00:00
|
|
|
//b->trace? "trace": "break",
|
|
|
|
//b->enabled? "enabled": "disabled",
|
|
|
|
// b->data? b->data: "");
|
|
|
|
break;
|
|
|
|
case 'j':
|
2016-06-16 20:57:10 +00:00
|
|
|
bp->cb_printf ("%s{\"addr\":%"PFMT64d",\"size\":%d,"
|
|
|
|
"\"prot\":\"%c%c%c\",\"hw\":%s,"
|
|
|
|
"\"trace\":%s,\"enabled\":%s,"
|
2020-01-04 00:54:24 +00:00
|
|
|
"\"valid\":%s,\"data\":\"%s\","
|
2016-09-01 17:11:46 +00:00
|
|
|
"\"cond\":\"%s\"}",
|
2015-08-29 12:01:38 +00:00
|
|
|
iter->p ? "," : "",
|
2015-02-01 01:53:18 +00:00
|
|
|
b->addr, b->size,
|
2018-09-21 00:16:54 +00:00
|
|
|
(b->perm & R_BP_PROT_READ) ? 'r' : '-',
|
|
|
|
(b->perm & R_BP_PROT_WRITE) ? 'w' : '-',
|
|
|
|
(b->perm & R_BP_PROT_EXEC) ? 'x' : '-',
|
2015-08-29 12:01:38 +00:00
|
|
|
b->hw ? "true" : "false",
|
|
|
|
b->trace ? "true" : "false",
|
|
|
|
b->enabled ? "true" : "false",
|
2020-01-04 00:54:24 +00:00
|
|
|
r_bp_is_valid (bp, b) ? "true" : "false",
|
2016-09-01 17:11:46 +00:00
|
|
|
r_str_get2 (b->data),
|
|
|
|
r_str_get2 (b->cond));
|
2015-02-01 01:53:18 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-04-12 22:46:44 +00:00
|
|
|
/* TODO: Show list of pids and trace points, conditionals */
|
2009-09-13 22:37:28 +00:00
|
|
|
n++;
|
2009-04-12 22:46:44 +00:00
|
|
|
}
|
2015-08-29 12:01:38 +00:00
|
|
|
if (rad == 'j') {
|
2015-08-08 18:15:13 +00:00
|
|
|
bp->cb_printf ("]\n");
|
2015-02-01 01:53:18 +00:00
|
|
|
}
|
2009-09-13 22:37:28 +00:00
|
|
|
return n;
|
2009-02-05 21:08:46 +00:00
|
|
|
}
|
2014-10-28 10:14:30 +00:00
|
|
|
|
|
|
|
R_API RBreakpointItem *r_bp_item_new (RBreakpoint *bp) {
|
|
|
|
int i, j;
|
|
|
|
/* find empty slot */
|
2015-08-29 12:01:38 +00:00
|
|
|
for (i = 0; i < bp->bps_idx_count; i++) {
|
2014-10-28 10:14:30 +00:00
|
|
|
if (!bp->bps_idx[i]) {
|
|
|
|
goto return_slot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* allocate new slot */
|
2019-06-20 04:45:00 +00:00
|
|
|
bp->bps_idx_count += 16; // allocate space for 16 more bps
|
2018-06-19 09:34:13 +00:00
|
|
|
RBreakpointItem **newbps = realloc (bp->bps_idx, bp->bps_idx_count * sizeof (RBreakpointItem*));
|
|
|
|
if (newbps) {
|
|
|
|
bp->bps_idx = newbps;
|
|
|
|
} else {
|
2019-06-20 04:45:00 +00:00
|
|
|
bp->bps_idx_count -= 16; // allocate space for 16 more bps
|
2018-06-19 09:34:13 +00:00
|
|
|
}
|
2015-08-29 12:01:38 +00:00
|
|
|
for (j = i; j < bp->bps_idx_count; j++) {
|
2014-10-28 10:14:30 +00:00
|
|
|
bp->bps_idx[j] = NULL;
|
2015-08-29 12:01:38 +00:00
|
|
|
}
|
2016-05-15 08:40:57 +00:00
|
|
|
return_slot:
|
2014-10-28 10:14:30 +00:00
|
|
|
/* empty slot */
|
|
|
|
return (bp->bps_idx[i] = R_NEW0 (RBreakpointItem));
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API RBreakpointItem *r_bp_get_index(RBreakpoint *bp, int idx) {
|
2016-05-15 08:40:57 +00:00
|
|
|
if (idx >= 0 && idx < bp->bps_idx_count) {
|
2014-10-28 10:14:30 +00:00
|
|
|
return bp->bps_idx[idx];
|
2016-05-15 08:40:57 +00:00
|
|
|
}
|
2014-10-28 10:14:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-19 09:24:56 +00:00
|
|
|
R_API int r_bp_get_index_at (RBreakpoint *bp, ut64 addr) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i< bp->bps_idx_count; i++) {
|
|
|
|
if (bp->bps_idx[i] && bp->bps_idx[i]->addr == addr) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-28 10:14:30 +00:00
|
|
|
R_API int r_bp_del_index(RBreakpoint *bp, int idx) {
|
2015-08-29 12:01:38 +00:00
|
|
|
if (idx >= 0 && idx < bp->bps_idx_count) {
|
2014-10-28 10:14:30 +00:00
|
|
|
r_list_delete_data (bp->bps, bp->bps_idx[idx]);
|
2020-01-05 14:55:24 +00:00
|
|
|
bp->bps_idx[idx] = 0;
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2014-10-28 10:14:30 +00:00
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2014-10-28 10:14:30 +00:00
|
|
|
}
|
2017-12-03 17:57:42 +00:00
|
|
|
|
|
|
|
R_API int r_bp_size(RBreakpoint *bp) {
|
|
|
|
RBreakpointArch *bpa;
|
|
|
|
int i, bpsize = 8;
|
2018-09-26 17:05:44 +00:00
|
|
|
if (!bp || !bp->cur) {
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-03 17:57:42 +00:00
|
|
|
for (i = 0; bp->cur->bps[i].bytes; i++) {
|
|
|
|
bpa = &bp->cur->bps[i];
|
2017-12-10 10:28:33 +00:00
|
|
|
if (bpa->bits && bpa->bits != bp->bits) {
|
2017-12-03 17:57:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (bpa->length < bpsize) {
|
|
|
|
bpsize = bpa->length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bpsize;
|
|
|
|
}
|
2020-01-04 00:54:24 +00:00
|
|
|
|
|
|
|
// Check if the breakpoint is in a valid map
|
|
|
|
R_API bool r_bp_is_valid(RBreakpoint *bp, RBreakpointItem *b) {
|
|
|
|
if (!bp->bpinmaps) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bp->corebind.isMapped (bp->corebind.core, b->addr, b->perm);
|
|
|
|
}
|