2016-09-01 19:11:46 +02:00
|
|
|
/* radare - LGPL - Copyright 2009-2016 - pancake, jduck, TheLemonMan, saucec0de */
|
2009-02-05 22:08:46 +01:00
|
|
|
|
|
|
|
#include <r_debug.h>
|
2016-09-01 19:11:46 +02:00
|
|
|
#include <r_core.h>
|
2010-03-12 18:46:11 +01:00
|
|
|
#include <signal.h>
|
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
#if __WINDOWS__
|
|
|
|
void w32_break_process(void *);
|
|
|
|
#endif
|
|
|
|
|
2013-06-14 02:51:33 +02:00
|
|
|
R_LIB_VERSION(r_debug);
|
|
|
|
|
2014-09-17 14:57:33 +02:00
|
|
|
// Size of the lookahead buffers used in r_debug functions
|
|
|
|
#define DBG_BUF_SIZE 512
|
|
|
|
|
2014-06-04 04:12:11 +02:00
|
|
|
R_API RDebugInfo *r_debug_info(RDebug *dbg, const char *arg) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (!dbg || !dbg->h || !dbg->h->info) {
|
2014-06-04 04:12:11 +02:00
|
|
|
return NULL;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-06-04 04:12:11 +02:00
|
|
|
return dbg->h->info (dbg, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_info_free (RDebugInfo *rdi) {
|
|
|
|
free (rdi->cwd);
|
|
|
|
free (rdi->exe);
|
|
|
|
free (rdi->cmdline);
|
2015-10-12 18:49:16 +02:00
|
|
|
free (rdi->libname);
|
2014-06-04 04:12:11 +02:00
|
|
|
}
|
|
|
|
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Recoiling after a breakpoint has two stages:
|
|
|
|
* 1. remove the breakpoint and fix the program counter.
|
|
|
|
* 2. on resume, single step once and then replace the breakpoint.
|
|
|
|
*
|
|
|
|
* Thus, we have two functions to handle these situations.
|
|
|
|
* r_debug_bp_hit handles stage 1.
|
|
|
|
* r_debug_recoil handles stage 2.
|
|
|
|
*/
|
2016-07-01 16:06:13 -05:00
|
|
|
static int r_debug_bp_hit(RDebug *dbg, RRegItem *pc_ri, ut64 pc, RBreakpointItem **pb) {
|
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 03:34:45 -05:00
|
|
|
RBreakpointItem *b;
|
|
|
|
|
2016-07-09 01:41:56 -04:00
|
|
|
if (!pb) {
|
|
|
|
eprintf ("BreakpointItem is NULL!\n");
|
|
|
|
return false;
|
|
|
|
}
|
2016-07-01 16:06:13 -05:00
|
|
|
/* initialize the output parameter */
|
2016-07-09 01:41:56 -04:00
|
|
|
*pb = NULL;
|
2016-07-01 16:06:13 -05:00
|
|
|
|
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 03:34:45 -05:00
|
|
|
/* if we are tracing, update the tracing data */
|
|
|
|
if (dbg->trace->enabled) {
|
|
|
|
r_debug_trace_pc (dbg, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove all sw breakpoints for now. we'll set them back in stage 2
|
|
|
|
*
|
|
|
|
* this is necessary because while stopped we don't want any breakpoints in
|
|
|
|
* the code messing up our analysis.
|
|
|
|
*/
|
|
|
|
if (!r_bp_restore (dbg->bp, false)) { // unset sw breakpoints
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* if we are recoiling, tell r_debug_step that we ignored a breakpoint
|
|
|
|
* event */
|
|
|
|
if (!dbg->swstep && dbg->recoil_mode != R_DBG_RECOIL_NONE) {
|
|
|
|
dbg->reason.bp_addr = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-19 02:10:43 +02:00
|
|
|
/* The MIPS ptrace has a different behaviour */
|
|
|
|
# if __mips__
|
|
|
|
/* see if we really have a breakpoint here... */
|
|
|
|
b = r_bp_get_at (dbg->bp, pc);
|
|
|
|
if (!b) { /* we don't. nothing left to do */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
# else
|
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 03:34:45 -05:00
|
|
|
/* see if we really have a breakpoint here... */
|
|
|
|
b = r_bp_get_at (dbg->bp, pc - dbg->bpsize);
|
|
|
|
if (!b) { /* we don't. nothing left to do */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the pc value back */
|
|
|
|
pc -= b->size;
|
|
|
|
if (!r_reg_set_value (dbg->reg, pc_ri, pc)) {
|
|
|
|
eprintf ("failed to set PC!\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, true)) {
|
|
|
|
eprintf ("cannot set registers!\n");
|
|
|
|
return false;
|
|
|
|
}
|
2016-09-19 02:10:43 +02:00
|
|
|
# endif
|
|
|
|
|
|
|
|
*pb = b;
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* if we are on a software stepping breakpoint, we hide what is going on... */
|
|
|
|
if (b->swstep) {
|
|
|
|
dbg->reason.bp_addr = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setup our stage 2 */
|
|
|
|
dbg->reason.bp_addr = b->addr;
|
|
|
|
|
|
|
|
/* inform the user of what happened */
|
2016-09-01 19:11:46 +02:00
|
|
|
if (dbg->hitinfo) {
|
|
|
|
eprintf ("hit %spoint at: %"PFMT64x "\n",
|
|
|
|
b->trace ? "trace" : "break", pc);
|
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* now that we've cleaned up after the breakpoint, call the other
|
|
|
|
* potential breakpoint handlers
|
|
|
|
*/
|
|
|
|
if (dbg->corebind.core && dbg->corebind.bphit) {
|
|
|
|
dbg->corebind.bphit (dbg->corebind.core, b);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable all software breakpoints */
|
|
|
|
static int r_debug_bps_enable(RDebug *dbg) {
|
|
|
|
/* restore all sw breakpoints. we are about to step/continue so these need
|
|
|
|
* to be in place. */
|
|
|
|
if (!r_bp_restore (dbg->bp, true))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* done recoiling... */
|
|
|
|
dbg->recoil_mode = R_DBG_RECOIL_NONE;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* replace breakpoints before we continue execution
|
|
|
|
*
|
|
|
|
* this is called from r_debug_step_hard or r_debug_continue_kill
|
|
|
|
*
|
|
|
|
* this is a trick process because of breakpoints/tracepoints.
|
|
|
|
*
|
|
|
|
* if a breakpoint was just hit, we need step over that instruction before
|
|
|
|
* allowing the caller to proceed as desired.
|
|
|
|
*
|
|
|
|
* if the user wants to step, the single step here does the job.
|
|
|
|
*/
|
|
|
|
static int r_debug_recoil(RDebug *dbg, RDebugRecoilMode rc_mode) {
|
|
|
|
/* if bp_addr is not set, we must not have actually hit a breakpoint */
|
|
|
|
if (!dbg->reason.bp_addr) {
|
|
|
|
return r_debug_bps_enable (dbg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* don't do anything if we already are recoiling */
|
|
|
|
if (dbg->recoil_mode != R_DBG_RECOIL_NONE) {
|
|
|
|
/* the first time recoil is called with swstep, we just need to
|
|
|
|
* look up the bp and step past it.
|
|
|
|
* the second time it's called, the new sw breakpoint should exist
|
|
|
|
* so we just restore all except what we originally hit and reset.
|
|
|
|
*/
|
|
|
|
if (dbg->swstep) {
|
|
|
|
if (!r_bp_restore_except (dbg->bp, true, dbg->reason.bp_addr)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-03-21 03:18:10 +01:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2015-06-09 00:47:13 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* otherwise, avoid recursion */
|
|
|
|
return true;
|
2015-08-29 14:01:38 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* we have entered recoil! */
|
|
|
|
dbg->recoil_mode = rc_mode;
|
|
|
|
|
|
|
|
/* step over the place with the breakpoint and let the caller resume */
|
|
|
|
if (r_debug_step (dbg, 1) != 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* when stepping away from a breakpoint during recoil in stepping mode,
|
|
|
|
* the r_debug_bp_hit function tells us that it was called
|
|
|
|
* innapropriately by setting bp_addr back to zero. however, recoil_mode
|
|
|
|
* is still set. we use this condition to know not to proceed but
|
|
|
|
* pretend as if we had.
|
|
|
|
*/
|
|
|
|
if (!dbg->reason.bp_addr && dbg->recoil_mode == R_DBG_RECOIL_STEP) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r_debug_bps_enable (dbg);
|
2010-03-12 18:46:11 +01:00
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
|
2016-07-14 22:37:33 +02:00
|
|
|
static int get_bpsz_arch(RDebug *dbg) {
|
|
|
|
#define CMP_ARCH(x) strncmp (dbg->arch, (x), R_MIN (len_arch, strlen ((x))))
|
|
|
|
int bpsz , len_arch = strlen (dbg->arch);
|
|
|
|
if (!CMP_ARCH ("arm")) {
|
|
|
|
//TODO add better handle arm/thumb
|
2016-07-14 09:39:04 -04:00
|
|
|
bpsz = 4;
|
2016-07-14 22:37:33 +02:00
|
|
|
} else if (!CMP_ARCH ("mips")) {
|
2016-07-14 09:39:04 -04:00
|
|
|
bpsz = 4;
|
2016-07-14 22:37:33 +02:00
|
|
|
} else if (!CMP_ARCH ("ppc")) {
|
2016-07-14 09:39:04 -04:00
|
|
|
bpsz = 4;
|
2016-07-14 22:37:33 +02:00
|
|
|
} else if (!CMP_ARCH ("sparc")) {
|
2016-07-14 09:39:04 -04:00
|
|
|
bpsz = 4;
|
2016-07-14 22:37:33 +02:00
|
|
|
} else if (!CMP_ARCH ("sh")) {
|
2016-07-14 09:39:04 -04:00
|
|
|
bpsz = 2;
|
|
|
|
} else {
|
|
|
|
bpsz = 1;
|
|
|
|
}
|
2016-07-14 22:37:33 +02:00
|
|
|
return bpsz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add a breakpoint with some typical values */
|
|
|
|
R_API RBreakpointItem *r_debug_bp_add(RDebug *dbg, ut64 addr, int hw, char *module, st64 m_delta) {
|
|
|
|
int bpsz = get_bpsz_arch (dbg);
|
2016-05-16 01:00:11 +02:00
|
|
|
RBreakpointItem *bpi;
|
2016-06-15 14:50:32 -05:00
|
|
|
const char *module_name = module;
|
2016-06-19 14:04:23 +02:00
|
|
|
RListIter *iter;
|
|
|
|
RDebugMap *map;
|
2016-06-15 14:50:32 -05:00
|
|
|
|
2016-05-16 01:00:11 +02:00
|
|
|
if (!addr && module) {
|
|
|
|
bool detect_module, valid = false;
|
|
|
|
int perm;
|
2016-06-15 14:50:32 -05:00
|
|
|
|
2016-05-16 01:00:11 +02:00
|
|
|
if (m_delta) {
|
2016-06-15 14:50:32 -05:00
|
|
|
detect_module = false;
|
2016-05-16 01:00:11 +02:00
|
|
|
RList *list = r_debug_modules_list (dbg);
|
|
|
|
r_list_foreach (list, iter, map) {
|
|
|
|
if (strstr (map->file, module)) {
|
|
|
|
addr = map->addr + m_delta;
|
2016-06-15 14:50:32 -05:00
|
|
|
module_name = map->file;
|
2016-05-16 01:00:11 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2016-06-15 14:50:32 -05:00
|
|
|
//module holds the address
|
2016-05-16 01:00:11 +02:00
|
|
|
addr = (ut64)r_num_math (dbg->num, module);
|
|
|
|
if (!addr) return NULL;
|
|
|
|
detect_module = true;
|
|
|
|
}
|
|
|
|
r_debug_map_sync (dbg);
|
|
|
|
r_list_foreach (dbg->maps, iter, map) {
|
|
|
|
if (addr >= map->addr && addr < map->addr_end) {
|
2016-06-15 14:50:32 -05:00
|
|
|
valid = true;
|
2016-05-16 01:00:11 +02:00
|
|
|
if (detect_module) {
|
2016-06-15 14:50:32 -05:00
|
|
|
module_name = map->file;
|
2016-05-16 01:00:11 +02:00
|
|
|
m_delta = addr - map->addr;
|
|
|
|
}
|
|
|
|
perm = ((map->perm & 1) << 2) | (map->perm & 2) | ((map->perm & 4) >> 2);
|
|
|
|
if (!(perm & R_BP_PROT_EXEC))
|
2016-06-15 14:50:32 -05:00
|
|
|
eprintf ("WARNING: setting bp within mapped memory without exec perm\n");
|
2016-05-16 01:00:11 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!valid) {
|
2016-06-15 14:50:32 -05:00
|
|
|
eprintf ("WARNING: module's base addr + delta is not a valid address\n");
|
2016-05-16 01:00:11 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2016-06-19 14:04:23 +02:00
|
|
|
if (!module) {
|
|
|
|
//express db breakpoints as dbm due to ASLR when saving into project
|
|
|
|
r_debug_map_sync (dbg);
|
|
|
|
r_list_foreach (dbg->maps, iter, map) {
|
|
|
|
if (addr >= map->addr && addr < map->addr_end) {
|
|
|
|
module_name = map->file;
|
|
|
|
m_delta = addr - map->addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-16 01:00:11 +02:00
|
|
|
bpi = hw
|
2016-06-15 14:50:32 -05:00
|
|
|
? r_bp_add_hw (dbg->bp, addr, bpsz, R_BP_PROT_EXEC)
|
|
|
|
: r_bp_add_sw (dbg->bp, addr, bpsz, R_BP_PROT_EXEC);
|
2016-05-16 01:00:11 +02:00
|
|
|
if (bpi) {
|
2016-06-15 14:50:32 -05:00
|
|
|
if (module_name) {
|
|
|
|
bpi->module_name = strdup (module_name);
|
|
|
|
bpi->name = r_str_newf ("%s+0x%" PFMT64x, module_name, m_delta);
|
|
|
|
}
|
2016-05-16 01:00:11 +02:00
|
|
|
bpi->module_delta = m_delta;
|
|
|
|
}
|
|
|
|
return bpi;
|
|
|
|
}
|
|
|
|
|
2016-10-16 02:34:54 +02:00
|
|
|
static const char *r_debug_str_callback(RNum *userptr, ut64 off, int *ok) {
|
2016-10-21 01:24:40 +02:00
|
|
|
// RDebug *dbg = (RDebug *)userptr;
|
|
|
|
eprintf ("STR CALLBACK WTF WTF WTF\n");
|
2016-10-16 02:34:54 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-05-24 12:07:54 +02:00
|
|
|
R_API RDebug *r_debug_new(int hard) {
|
2015-01-30 02:07:47 +01:00
|
|
|
RDebug *dbg = R_NEW0 (RDebug);
|
2016-12-09 22:18:53 +01:00
|
|
|
if (!dbg) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-07-21 06:06:00 +02:00
|
|
|
// R_SYS_ARCH
|
2015-10-22 03:11:03 +02:00
|
|
|
dbg->arch = strdup (R_SYS_ARCH);
|
2015-07-21 06:06:00 +02:00
|
|
|
dbg->bits = R_SYS_BITS;
|
|
|
|
dbg->trace_forks = 1;
|
2016-06-16 21:20:18 -05:00
|
|
|
dbg->forked_pid = -1;
|
2015-07-21 06:06:00 +02:00
|
|
|
dbg->trace_clone = 0;
|
2016-12-09 22:18:53 +01:00
|
|
|
dbg->trace_aftersyscall = true;
|
2015-07-21 06:06:00 +02:00
|
|
|
R_FREE (dbg->btalgo);
|
|
|
|
dbg->trace_execs = 0;
|
|
|
|
dbg->anal = NULL;
|
|
|
|
dbg->snaps = r_list_newf (r_debug_snap_free);
|
|
|
|
dbg->pid = -1;
|
|
|
|
dbg->bpsize = 1;
|
|
|
|
dbg->tid = -1;
|
|
|
|
dbg->tree = r_tree_new ();
|
|
|
|
dbg->tracenodes = sdb_new0 ();
|
|
|
|
dbg->swstep = 0;
|
2015-09-14 02:08:31 +02:00
|
|
|
dbg->stop_all_threads = false;
|
2015-07-21 06:06:00 +02:00
|
|
|
dbg->trace = r_debug_trace_new ();
|
2015-08-08 14:15:13 -04:00
|
|
|
dbg->cb_printf = (void *)printf;
|
2015-07-21 06:06:00 +02:00
|
|
|
dbg->reg = r_reg_new ();
|
2016-10-16 02:34:54 +02:00
|
|
|
dbg->num = r_num_new (r_debug_num_callback, r_debug_str_callback, dbg);
|
2015-07-21 06:06:00 +02:00
|
|
|
dbg->h = NULL;
|
2015-08-29 14:01:38 +02:00
|
|
|
dbg->threads = NULL;
|
2016-09-01 19:11:46 +02:00
|
|
|
dbg->hitinfo = 1;
|
2015-07-21 06:06:00 +02:00
|
|
|
/* TODO: needs a redesign? */
|
|
|
|
dbg->maps = r_debug_map_list_new ();
|
|
|
|
dbg->maps_user = r_debug_map_list_new ();
|
|
|
|
r_debug_signal_init (dbg);
|
|
|
|
if (hard) {
|
|
|
|
dbg->bp = r_bp_new ();
|
|
|
|
r_debug_plugin_init (dbg);
|
2015-09-14 02:08:31 +02:00
|
|
|
dbg->bp->iob.init = false;
|
2009-09-15 13:24:28 +02:00
|
|
|
}
|
2010-01-19 11:25:17 +01:00
|
|
|
return dbg;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2015-06-09 00:47:13 +02:00
|
|
|
static int free_tracenodes_entry (RDebug *dbg, const char *k, const char *v) {
|
|
|
|
ut64 v_num = r_num_get (NULL, v);
|
|
|
|
free((void *)(size_t)v_num);
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2015-06-09 00:47:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_tracenodes_reset (RDebug *dbg) {
|
|
|
|
sdb_foreach (dbg->tracenodes, (SdbForeachCallback)free_tracenodes_entry, dbg);
|
|
|
|
sdb_reset (dbg->tracenodes);
|
|
|
|
}
|
|
|
|
|
2014-06-05 03:46:17 +02:00
|
|
|
R_API RDebug *r_debug_free(RDebug *dbg) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg) {
|
|
|
|
// TODO: free it correctly.. we must ensure this is an instance and not a reference..
|
|
|
|
r_bp_free (dbg->bp);
|
|
|
|
//r_reg_free(&dbg->reg);
|
|
|
|
r_list_free (dbg->snaps);
|
|
|
|
r_list_free (dbg->maps);
|
|
|
|
r_list_free (dbg->maps_user);
|
|
|
|
r_list_free (dbg->threads);
|
|
|
|
r_num_free (dbg->num);
|
|
|
|
sdb_free (dbg->sgnls);
|
|
|
|
r_tree_free (dbg->tree);
|
|
|
|
sdb_foreach (dbg->tracenodes, (SdbForeachCallback)free_tracenodes_entry, dbg);
|
|
|
|
sdb_free (dbg->tracenodes);
|
2016-12-01 09:09:59 +01:00
|
|
|
r_list_free (dbg->plugins);
|
2016-05-15 10:40:57 +02:00
|
|
|
free (dbg->btalgo);
|
2016-06-01 12:23:10 +02:00
|
|
|
r_debug_trace_free (dbg->trace);
|
|
|
|
dbg->trace = NULL;
|
2016-05-15 10:40:57 +02:00
|
|
|
free (dbg->arch);
|
|
|
|
free (dbg->glob_libs);
|
|
|
|
free (dbg->glob_unlibs);
|
|
|
|
free (dbg);
|
|
|
|
}
|
2009-08-22 03:11:33 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-05-06 00:59:10 +02:00
|
|
|
R_API int r_debug_attach(RDebug *dbg, int pid) {
|
2015-09-14 02:08:31 +02:00
|
|
|
int ret = false;
|
2010-01-21 02:38:52 +01:00
|
|
|
if (dbg && dbg->h && dbg->h->attach) {
|
2011-05-06 00:59:10 +02:00
|
|
|
ret = dbg->h->attach (dbg, pid);
|
2010-11-17 02:31:56 +01:00
|
|
|
if (ret != -1) {
|
2016-02-25 01:55:16 +01:00
|
|
|
//eprintf ("Attached debugger to pid = %d, tid = %d\n", pid, ret);
|
2010-11-17 02:31:56 +01:00
|
|
|
r_debug_select (dbg, pid, ret); //dbg->pid, dbg->tid);
|
2016-02-06 19:53:29 +01:00
|
|
|
}
|
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-10-20 18:04:26 +02:00
|
|
|
/* stop execution of child process */
|
|
|
|
R_API int r_debug_stop(RDebug *dbg) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->stop) {
|
2011-10-20 18:04:26 +02:00
|
|
|
return dbg->h->stop (dbg);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2011-10-20 18:04:26 +02:00
|
|
|
}
|
|
|
|
|
2015-12-04 02:57:56 +01:00
|
|
|
R_API bool r_debug_set_arch(RDebug *dbg, const char *arch, int bits) {
|
2015-10-22 03:11:03 +02:00
|
|
|
if (arch && dbg && dbg->h) {
|
2015-10-22 04:48:56 +02:00
|
|
|
bool rc = r_sys_arch_match (dbg->h->arch, arch);
|
2015-10-22 03:11:03 +02:00
|
|
|
if (rc) {
|
2011-09-22 09:52:00 +02:00
|
|
|
switch (bits) {
|
|
|
|
case 32:
|
2015-08-31 13:54:24 +02:00
|
|
|
if (dbg->h->bits & R_SYS_BITS_32) {
|
|
|
|
dbg->bits = R_SYS_BITS_32;
|
|
|
|
}
|
2011-09-22 09:52:00 +02:00
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
dbg->bits = R_SYS_BITS_64;
|
|
|
|
break;
|
|
|
|
}
|
2015-08-31 13:54:24 +02:00
|
|
|
if (!dbg->h->bits) {
|
2012-07-05 16:02:12 +00:00
|
|
|
dbg->bits = dbg->h->bits;
|
2015-08-31 13:54:24 +02:00
|
|
|
} else if (!(dbg->h->bits & dbg->bits)) {
|
2015-09-22 01:49:14 +02:00
|
|
|
dbg->bits = dbg->h->bits & R_SYS_BITS_64;
|
2016-06-20 23:42:08 +02:00
|
|
|
if (!dbg->bits) {
|
2015-09-22 01:49:14 +02:00
|
|
|
dbg->bits = dbg->h->bits & R_SYS_BITS_32;
|
2016-06-20 23:42:08 +02:00
|
|
|
}
|
|
|
|
if (!dbg->bits) {
|
2015-09-22 01:49:14 +02:00
|
|
|
dbg->bits = R_SYS_BITS_32;
|
2016-06-20 23:42:08 +02:00
|
|
|
}
|
2015-08-31 13:54:24 +02:00
|
|
|
}
|
2015-10-22 03:11:03 +02:00
|
|
|
free (dbg->arch);
|
|
|
|
dbg->arch = strdup (arch);
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2011-05-06 00:59:10 +02:00
|
|
|
}
|
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2011-05-06 00:59:10 +02:00
|
|
|
}
|
|
|
|
|
2015-08-29 14:01:38 +02:00
|
|
|
/*
|
2010-02-05 12:21:37 +01:00
|
|
|
* Save 4096 bytes from %esp
|
|
|
|
* TODO: Add support for reverse stack architectures
|
2013-04-16 04:01:39 +02:00
|
|
|
* Also known as r_debug_inject()
|
2010-02-05 12:21:37 +01:00
|
|
|
*/
|
2013-04-16 04:01:39 +02:00
|
|
|
R_API ut64 r_debug_execute(RDebug *dbg, const ut8 *buf, int len, int restore) {
|
2010-02-05 12:21:37 +01:00
|
|
|
int orig_sz;
|
|
|
|
ut8 stackbackup[4096];
|
|
|
|
ut8 *backup, *orig = NULL;
|
2010-09-18 02:51:17 +02:00
|
|
|
RRegItem *ri, *risp, *ripc;
|
2010-02-05 12:21:37 +01:00
|
|
|
ut64 rsp, rpc, ra0 = 0LL;
|
2011-05-20 20:42:25 +02:00
|
|
|
if (r_debug_is_dead (dbg))
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2010-02-05 12:21:37 +01:00
|
|
|
ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR);
|
2013-04-16 04:01:39 +02:00
|
|
|
risp = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_SP], R_REG_TYPE_GPR);
|
2010-02-05 12:21:37 +01:00
|
|
|
if (ripc) {
|
2015-09-14 02:08:31 +02:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2010-02-05 12:21:37 +01:00
|
|
|
orig = r_reg_get_bytes (dbg->reg, -1, &orig_sz);
|
2016-09-19 13:44:47 +01:00
|
|
|
if (!orig) {
|
2010-02-05 12:21:37 +01:00
|
|
|
eprintf ("Cannot get register arena bytes\n");
|
|
|
|
return 0LL;
|
|
|
|
}
|
|
|
|
rpc = r_reg_get_value (dbg->reg, ripc);
|
|
|
|
rsp = r_reg_get_value (dbg->reg, risp);
|
|
|
|
|
|
|
|
backup = malloc (len);
|
2016-09-19 13:44:47 +01:00
|
|
|
if (!backup) {
|
2014-04-25 23:04:02 +00:00
|
|
|
free (orig);
|
2010-02-05 12:21:37 +01:00
|
|
|
return 0LL;
|
2014-04-25 23:04:02 +00:00
|
|
|
}
|
2010-02-05 12:21:37 +01:00
|
|
|
dbg->iob.read_at (dbg->iob.io, rpc, backup, len);
|
|
|
|
dbg->iob.read_at (dbg->iob.io, rsp, stackbackup, len);
|
|
|
|
|
2014-09-26 13:57:03 +02:00
|
|
|
r_bp_add_sw (dbg->bp, rpc+len, dbg->bpsize, R_BP_PROT_EXEC);
|
2010-02-05 12:21:37 +01:00
|
|
|
|
|
|
|
/* execute code here */
|
|
|
|
dbg->iob.write_at (dbg->iob.io, rpc, buf, len);
|
2016-05-15 10:40:57 +02:00
|
|
|
//r_bp_add_sw (dbg->bp, rpc+len, 4, R_BP_PROT_EXEC);
|
2010-02-05 12:21:37 +01:00
|
|
|
r_debug_continue (dbg);
|
2016-05-15 10:40:57 +02:00
|
|
|
//r_bp_del (dbg->bp, rpc+len);
|
2010-02-05 12:21:37 +01:00
|
|
|
/* TODO: check if stopped in breakpoint or not */
|
|
|
|
|
|
|
|
r_bp_del (dbg->bp, rpc+len);
|
|
|
|
dbg->iob.write_at (dbg->iob.io, rpc, backup, len);
|
2013-04-16 04:01:39 +02:00
|
|
|
if (restore) {
|
|
|
|
dbg->iob.write_at (dbg->iob.io, rsp, stackbackup, len);
|
|
|
|
}
|
2010-02-05 12:21:37 +01:00
|
|
|
|
2015-09-14 02:08:31 +02:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2010-02-05 12:21:37 +01:00
|
|
|
ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_A0], R_REG_TYPE_GPR);
|
|
|
|
ra0 = r_reg_get_value (dbg->reg, ri);
|
2013-04-16 04:01:39 +02:00
|
|
|
if (restore) {
|
2016-03-24 14:10:33 +06:00
|
|
|
r_reg_read_regs (dbg->reg, orig, orig_sz);
|
2013-04-16 04:01:39 +02:00
|
|
|
} else {
|
|
|
|
r_reg_set_value (dbg->reg, ripc, rpc);
|
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, true);
|
2010-02-05 12:21:37 +01:00
|
|
|
free (backup);
|
|
|
|
free (orig);
|
2010-04-14 13:02:23 +02:00
|
|
|
eprintf ("ra0=0x%08"PFMT64x"\n", ra0);
|
2010-02-05 12:21:37 +01:00
|
|
|
} else eprintf ("r_debug_execute: Cannot get program counter\n");
|
|
|
|
return (ra0);
|
|
|
|
}
|
|
|
|
|
2010-02-22 12:42:43 +01:00
|
|
|
R_API int r_debug_startv(struct r_debug_t *dbg, int argc, char **argv) {
|
2010-02-05 12:21:37 +01:00
|
|
|
/* TODO : r_debug_startv unimplemented */
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2015-11-17 00:57:22 +01:00
|
|
|
R_API int r_debug_start(RDebug *dbg, const char *cmd) {
|
2010-02-22 12:42:43 +01:00
|
|
|
/* TODO: this argc/argv parser is done in r_io */
|
2009-08-22 01:54:24 +00:00
|
|
|
// TODO: parse cmd and generate argc and argv
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2015-11-17 00:57:22 +01:00
|
|
|
R_API int r_debug_detach(RDebug *dbg, int pid) {
|
2009-02-05 22:08:46 +01:00
|
|
|
if (dbg->h && dbg->h->detach)
|
2016-01-22 10:53:58 +01:00
|
|
|
return dbg->h->detach (dbg, pid);
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2010-04-11 01:46:07 +02:00
|
|
|
R_API int r_debug_select(RDebug *dbg, int pid, int tid) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (tid < 0) {
|
2014-08-31 18:09:25 +02:00
|
|
|
tid = pid;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-08-31 18:09:25 +02:00
|
|
|
|
2015-08-17 00:12:54 +02:00
|
|
|
if (pid != -1 && tid != -1) {
|
2016-09-13 03:25:15 +02:00
|
|
|
if (pid != dbg->pid || tid != dbg->tid) {
|
|
|
|
eprintf ("= attach %d %d\n", pid, tid);
|
|
|
|
}
|
2015-08-17 00:12:54 +02:00
|
|
|
} else {
|
|
|
|
if (dbg->pid != -1)
|
|
|
|
eprintf ("Child %d is dead\n", dbg->pid);
|
|
|
|
}
|
2014-08-31 18:09:25 +02:00
|
|
|
|
|
|
|
if (dbg->h && dbg->h->select && !dbg->h->select (pid, tid))
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-08-31 18:09:25 +02:00
|
|
|
|
2016-06-16 15:56:21 -05:00
|
|
|
r_io_system (dbg->iob.io, sdb_fmt (0, "pid %d", pid));
|
|
|
|
|
2009-02-05 22:08:46 +01:00
|
|
|
dbg->pid = pid;
|
|
|
|
dbg->tid = tid;
|
2014-08-31 18:09:25 +02:00
|
|
|
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2015-08-17 00:12:54 +02:00
|
|
|
R_API const char *r_debug_reason_to_string(int type) {
|
|
|
|
switch (type) {
|
|
|
|
case R_DEBUG_REASON_DEAD: return "dead";
|
2015-08-17 00:55:07 +02:00
|
|
|
case R_DEBUG_REASON_ABORT: return "abort";
|
|
|
|
case R_DEBUG_REASON_SEGFAULT: return "segfault";
|
2015-08-17 00:12:54 +02:00
|
|
|
case R_DEBUG_REASON_NONE: return "none";
|
|
|
|
case R_DEBUG_REASON_SIGNAL: return "signal";
|
|
|
|
case R_DEBUG_REASON_BREAKPOINT: return "breakpoint";
|
2016-07-01 16:06:13 -05:00
|
|
|
case R_DEBUG_REASON_TRACEPOINT: return "tracepoint";
|
2015-08-17 00:12:54 +02:00
|
|
|
case R_DEBUG_REASON_READERR: return "read-error";
|
|
|
|
case R_DEBUG_REASON_WRITERR: return "write-error";
|
|
|
|
case R_DEBUG_REASON_DIVBYZERO: return "div-by-zero";
|
|
|
|
case R_DEBUG_REASON_ILLEGAL: return "illegal";
|
|
|
|
case R_DEBUG_REASON_UNKNOWN: return "unknown";
|
|
|
|
case R_DEBUG_REASON_ERROR: return "error";
|
|
|
|
case R_DEBUG_REASON_NEW_PID: return "new-pid";
|
|
|
|
case R_DEBUG_REASON_NEW_TID: return "new-tid";
|
|
|
|
case R_DEBUG_REASON_NEW_LIB: return "new-lib";
|
|
|
|
case R_DEBUG_REASON_EXIT_PID: return "exit-pid";
|
|
|
|
case R_DEBUG_REASON_EXIT_TID: return "exit-tid";
|
|
|
|
case R_DEBUG_REASON_EXIT_LIB: return "exit-lib";
|
|
|
|
case R_DEBUG_REASON_TRAP: return "trap";
|
|
|
|
case R_DEBUG_REASON_SWI: return "software-interrupt";
|
|
|
|
case R_DEBUG_REASON_INT: return "interrupt";
|
|
|
|
case R_DEBUG_REASON_FPU: return "fpu";
|
|
|
|
case R_DEBUG_REASON_STEP: return "step";
|
|
|
|
}
|
|
|
|
return "unhandled";
|
|
|
|
}
|
|
|
|
|
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 03:34:45 -05:00
|
|
|
R_API RDebugReasonType r_debug_stop_reason(RDebug *dbg) {
|
2009-02-05 22:08:46 +01:00
|
|
|
// TODO: return reason to stop debugging
|
|
|
|
// - new process
|
|
|
|
// - trap instruction
|
|
|
|
// - illegal instruction
|
|
|
|
// - fpu exception
|
2010-09-20 14:02:45 +02:00
|
|
|
// return dbg->reason
|
2015-08-17 00:12:54 +02:00
|
|
|
return dbg->reason.type;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
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 03:34:45 -05:00
|
|
|
/*
|
|
|
|
* wait for an event to happen on the selected pid/tid
|
|
|
|
*
|
|
|
|
* Returns R_DEBUG_REASON_*
|
|
|
|
*/
|
2016-09-01 19:11:46 +02:00
|
|
|
R_API RDebugReasonType r_debug_wait(RDebug *dbg, RBreakpointItem **bp) {
|
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 03:34:45 -05:00
|
|
|
RDebugReasonType reason = R_DEBUG_REASON_ERROR;
|
|
|
|
if (!dbg) {
|
|
|
|
return reason;
|
|
|
|
}
|
|
|
|
|
2016-09-01 19:11:46 +02:00
|
|
|
if (bp) {
|
|
|
|
*bp = NULL;
|
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
/* default to unknown */
|
2015-08-17 00:12:54 +02:00
|
|
|
dbg->reason.type = R_DEBUG_REASON_UNKNOWN;
|
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 03:34:45 -05:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
|
|
|
return R_DEBUG_REASON_DEAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if our debugger plugin has wait */
|
2014-05-10 02:47:50 +02:00
|
|
|
if (dbg->h && dbg->h->wait) {
|
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 03:34:45 -05:00
|
|
|
reason = dbg->h->wait (dbg, dbg->pid);
|
|
|
|
if (reason == R_DEBUG_REASON_DEAD) {
|
2011-05-20 20:42:25 +02:00
|
|
|
eprintf ("\n==> Process finished\n\n");
|
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 03:34:45 -05:00
|
|
|
// XXX(jjd): TODO: handle fallback or something else
|
|
|
|
//r_debug_select (dbg, -1, -1);
|
|
|
|
return R_DEBUG_REASON_DEAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* propagate errors from the plugin */
|
|
|
|
if (reason == R_DEBUG_REASON_ERROR) {
|
|
|
|
return R_DEBUG_REASON_ERROR;
|
2011-05-20 20:42:25 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* read general purpose registers */
|
|
|
|
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)) {
|
|
|
|
return R_DEBUG_REASON_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the underlying stop reason is a breakpoint, call the handlers */
|
|
|
|
if (reason == R_DEBUG_REASON_BREAKPOINT || reason == R_DEBUG_REASON_STEP) {
|
|
|
|
RRegItem *pc_ri;
|
2016-07-01 16:06:13 -05:00
|
|
|
RBreakpointItem *b = NULL;
|
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 03:34:45 -05:00
|
|
|
ut64 pc;
|
|
|
|
|
|
|
|
/* get the program coounter */
|
|
|
|
pc_ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], -1);
|
|
|
|
if (!pc_ri) { /* couldn't find PC?! */
|
|
|
|
return R_DEBUG_REASON_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the value */
|
|
|
|
pc = r_reg_get_value (dbg->reg, pc_ri);
|
|
|
|
|
2016-07-01 16:06:13 -05:00
|
|
|
if (!r_debug_bp_hit (dbg, pc_ri, pc, &b)) {
|
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 03:34:45 -05:00
|
|
|
return R_DEBUG_REASON_ERROR;
|
|
|
|
}
|
|
|
|
|
2016-07-01 16:06:13 -05:00
|
|
|
/* if we hit a tracing breakpoint, we need to continue in
|
|
|
|
* whatever mode the user desired. */
|
2016-09-01 19:11:46 +02:00
|
|
|
if (dbg->corebind.core && b && b->cond) {
|
|
|
|
if (bp) {
|
|
|
|
*bp = b;
|
|
|
|
}
|
|
|
|
reason = R_DEBUG_REASON_COND;
|
|
|
|
}
|
2016-07-01 16:06:13 -05:00
|
|
|
if (b && b->trace) {
|
|
|
|
reason = R_DEBUG_REASON_TRACEPOINT;
|
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
dbg->reason.type = reason;
|
|
|
|
if (reason == R_DEBUG_REASON_SIGNAL && dbg->reason.signum != -1) {
|
2013-09-18 02:11:23 +02:00
|
|
|
/* handle signal on continuations here */
|
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 03:34:45 -05:00
|
|
|
eprintf ("got signal...\n");
|
2015-08-17 00:12:54 +02:00
|
|
|
int what = r_debug_signal_what (dbg, dbg->reason.signum);
|
|
|
|
const char *name = r_debug_signal_resolve_i (dbg, dbg->reason.signum);
|
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 03:34:45 -05:00
|
|
|
if (name && strcmp ("SIGTRAP", name)) {
|
2015-01-12 02:52:12 +01:00
|
|
|
r_cons_printf ("[+] signal %d aka %s received %d\n",
|
2015-08-17 00:12:54 +02:00
|
|
|
dbg->reason.signum, name, what);
|
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 03:34:45 -05:00
|
|
|
}
|
2013-09-18 02:11:23 +02:00
|
|
|
}
|
2009-04-15 11:09:36 +00:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
return reason;
|
2009-04-01 00:28:13 +00:00
|
|
|
}
|
|
|
|
|
2010-11-11 03:13:44 +01:00
|
|
|
R_API int r_debug_step_soft(RDebug *dbg) {
|
|
|
|
ut8 buf[32];
|
2016-08-27 19:19:58 +02:00
|
|
|
ut64 pc, sp, r;
|
2014-09-15 14:38:28 +02:00
|
|
|
ut64 next[2];
|
2010-11-11 03:13:44 +01:00
|
|
|
RAnalOp op;
|
2014-09-17 13:28:07 +02:00
|
|
|
int br, i, ret;
|
2014-09-15 14:38:28 +02:00
|
|
|
union {
|
|
|
|
ut64 r64;
|
|
|
|
ut32 r32[2];
|
2014-09-17 13:28:07 +02:00
|
|
|
} sp_top;
|
2016-08-28 13:56:29 +02:00
|
|
|
union {
|
|
|
|
ut64 r64;
|
|
|
|
ut32 r32[2];
|
|
|
|
} memval;
|
2014-09-15 14:38:28 +02:00
|
|
|
|
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 03:34:45 -05:00
|
|
|
if (dbg->recoil_mode == R_DBG_RECOIL_NONE) {
|
|
|
|
dbg->recoil_mode = R_DBG_RECOIL_STEP;
|
|
|
|
}
|
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
|
|
|
|
pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
sp = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_SP]);
|
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
if (!dbg->iob.read_at) {
|
2016-02-06 19:53:29 +01:00
|
|
|
return false;
|
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)) < 0) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
|
|
|
if (!r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf))) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
|
|
|
if (op.type == R_ANAL_OP_TYPE_ILL) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
switch (op.type) {
|
2015-07-21 06:06:00 +02:00
|
|
|
case R_ANAL_OP_TYPE_RET:
|
|
|
|
dbg->iob.read_at (dbg->iob.io, sp, (ut8 *)&sp_top, 8);
|
|
|
|
next[0] = (dbg->bits == R_SYS_BITS_32) ? sp_top.r32[0] : sp_top.r64;
|
|
|
|
br = 1;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CJMP:
|
|
|
|
case R_ANAL_OP_TYPE_CCALL:
|
|
|
|
next[0] = op.jump;
|
|
|
|
next[1] = op.fail;
|
|
|
|
br = 2;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_CALL:
|
|
|
|
case R_ANAL_OP_TYPE_JMP:
|
|
|
|
next[0] = op.jump;
|
|
|
|
br = 1;
|
|
|
|
break;
|
2016-09-22 13:42:06 +02:00
|
|
|
case R_ANAL_OP_TYPE_RJMP:
|
|
|
|
case R_ANAL_OP_TYPE_RCALL:
|
|
|
|
r = r_debug_reg_get (dbg,op.reg);
|
|
|
|
next[0] = r;
|
|
|
|
br = 1;
|
|
|
|
break;
|
|
|
|
case R_ANAL_OP_TYPE_IRCALL:
|
|
|
|
case R_ANAL_OP_TYPE_IRJMP:
|
|
|
|
r = r_debug_reg_get (dbg,op.reg);
|
|
|
|
if (dbg->iob.read_at (dbg->iob.io, r, (ut8*)&memval, 8) <0 ) {
|
|
|
|
next[0] = op.addr + op.size;
|
|
|
|
} else {
|
|
|
|
next[0] = (dbg->bits == R_SYS_BITS_32) ? memval.r32[0] : memval.r64;
|
|
|
|
}
|
|
|
|
br = 1;
|
|
|
|
break;
|
2016-08-27 19:19:58 +02:00
|
|
|
case R_ANAL_OP_TYPE_UCALL:
|
2016-09-22 13:42:06 +02:00
|
|
|
case R_ANAL_OP_TYPE_MJMP:
|
2016-08-28 13:56:29 +02:00
|
|
|
if (op.ireg) {
|
|
|
|
r = r_debug_reg_get (dbg,op.ireg);
|
|
|
|
} else {
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
if (dbg->iob.read_at (dbg->iob.io,
|
|
|
|
r*op.scale + op.disp, (ut8*)&memval, 8) <0 ) {
|
2016-08-27 19:19:58 +02:00
|
|
|
next[0] = op.addr + op.size;
|
2016-08-28 13:56:29 +02:00
|
|
|
} else {
|
|
|
|
next[0] = (dbg->bits == R_SYS_BITS_32) ? memval.r32[0] : memval.r64;
|
2016-08-27 19:19:58 +02:00
|
|
|
}
|
|
|
|
br = 1;
|
|
|
|
break;
|
2016-09-22 13:42:06 +02:00
|
|
|
case R_ANAL_OP_TYPE_UJMP:
|
2015-07-21 06:06:00 +02:00
|
|
|
default:
|
|
|
|
next[0] = op.addr + op.size;
|
|
|
|
br = 1;
|
|
|
|
break;
|
2014-09-15 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
for (i = 0; i < br; i++) {
|
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 03:34:45 -05:00
|
|
|
RBreakpointItem *bpi = r_bp_add_sw (dbg->bp, next[i], dbg->bpsize, R_BP_PROT_EXEC);
|
|
|
|
if (bpi) {
|
|
|
|
bpi->swstep = true;
|
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
|
2014-09-17 13:28:07 +02:00
|
|
|
ret = r_debug_continue (dbg);
|
2010-11-11 03:13:44 +01:00
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
for (i = 0; i < br; i++) {
|
2014-09-15 14:38:28 +02:00
|
|
|
r_bp_del (dbg->bp, next[i]);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
|
2014-09-17 13:28:07 +02:00
|
|
|
return ret;
|
2010-11-11 03:13:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_step_hard(RDebug *dbg) {
|
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 03:34:45 -05:00
|
|
|
RDebugReasonType reason;
|
|
|
|
|
2015-08-17 00:12:54 +02:00
|
|
|
dbg->reason.type = R_DEBUG_REASON_STEP;
|
2016-05-15 10:40:57 +02:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* only handle recoils when not already in recoil mode. */
|
|
|
|
if (dbg->recoil_mode == R_DBG_RECOIL_NONE) {
|
|
|
|
/* handle the stage-2 of breakpoints */
|
|
|
|
if (!r_debug_recoil (dbg, R_DBG_RECOIL_STEP)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* recoil already stepped once, so we don't step again. */
|
|
|
|
if (dbg->recoil_mode == R_DBG_RECOIL_STEP) {
|
|
|
|
dbg->recoil_mode = R_DBG_RECOIL_NONE;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
if (!dbg->h->step (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2016-09-01 19:11:46 +02:00
|
|
|
reason = r_debug_wait (dbg, NULL);
|
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 03:34:45 -05:00
|
|
|
/* TODO: handle better */
|
|
|
|
if (reason == R_DEBUG_REASON_ERROR) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (reason == R_DEBUG_REASON_DEAD || r_debug_is_dead (dbg)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2010-11-11 03:13:44 +01:00
|
|
|
}
|
|
|
|
|
2010-09-23 20:42:35 +02:00
|
|
|
R_API int r_debug_step(RDebug *dbg, int steps) {
|
2016-06-23 03:19:39 -05:00
|
|
|
int ret, steps_taken = 0;
|
2014-09-17 13:28:07 +02:00
|
|
|
|
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 03:34:45 -05:00
|
|
|
/* who calls this without giving a positive number? */
|
|
|
|
if (steps < 1) {
|
|
|
|
steps = 1;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
if (!dbg || !dbg->h) {
|
|
|
|
return steps_taken;
|
|
|
|
}
|
|
|
|
|
2015-08-17 00:12:54 +02:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2015-08-17 00:12:54 +02:00
|
|
|
}
|
2014-09-17 13:28:07 +02:00
|
|
|
|
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 03:34:45 -05:00
|
|
|
dbg->reason.type = R_DEBUG_REASON_STEP;
|
2014-09-17 14:57:33 +02:00
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
for (; steps_taken < steps; steps_taken++) {
|
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 03:34:45 -05:00
|
|
|
if (dbg->swstep) {
|
|
|
|
ret = r_debug_step_soft (dbg);
|
|
|
|
} else {
|
|
|
|
ret = r_debug_step_hard (dbg);
|
|
|
|
}
|
2014-09-17 13:28:07 +02:00
|
|
|
if (!ret) {
|
|
|
|
eprintf ("Stepping failed!\n");
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2015-08-17 00:12:54 +02:00
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
dbg->steps++;
|
|
|
|
dbg->reason.type = R_DEBUG_REASON_STEP;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
2016-06-23 03:19:39 -05:00
|
|
|
|
|
|
|
return steps_taken;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2010-02-05 12:21:37 +01:00
|
|
|
R_API void r_debug_io_bind(RDebug *dbg, RIO *io) {
|
|
|
|
r_io_bind (io, &dbg->bp->iob);
|
|
|
|
r_io_bind (io, &dbg->iob);
|
|
|
|
}
|
|
|
|
|
2010-05-24 12:07:54 +02:00
|
|
|
R_API int r_debug_step_over(RDebug *dbg, int steps) {
|
2010-05-24 17:51:51 +02:00
|
|
|
RAnalOp op;
|
2016-06-28 05:24:30 +02:00
|
|
|
ut64 buf_pc, pc, ins_size;
|
2014-09-17 14:57:33 +02:00
|
|
|
ut8 buf[DBG_BUF_SIZE];
|
2016-06-23 03:19:39 -05:00
|
|
|
int steps_taken = 0;
|
2014-09-17 14:57:33 +02:00
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
|
|
|
return steps_taken;
|
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
if (steps < 1) {
|
2014-09-17 14:57:33 +02:00
|
|
|
steps = 1;
|
2016-06-23 03:19:39 -05:00
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
|
2011-10-09 04:15:32 +02:00
|
|
|
if (dbg->h && dbg->h->step_over) {
|
2016-06-23 03:19:39 -05:00
|
|
|
for (; steps_taken < steps; steps_taken++)
|
2011-10-09 04:15:32 +02:00
|
|
|
if (!dbg->h->step_over (dbg))
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
|
|
|
return steps_taken;
|
2011-10-09 04:15:32 +02:00
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
|
|
|
|
if (!dbg->anal || !dbg->reg)
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2014-09-17 14:57:33 +02:00
|
|
|
|
|
|
|
// Initial refill
|
|
|
|
buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
|
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
for (; steps_taken < steps; steps_taken++) {
|
2014-09-17 14:57:33 +02:00
|
|
|
pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
2015-08-29 14:01:38 +02:00
|
|
|
// Try to keep the buffer full
|
|
|
|
if (pc - buf_pc > sizeof (buf)) {
|
2014-09-17 14:57:33 +02:00
|
|
|
buf_pc = pc;
|
|
|
|
dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
|
2012-05-30 11:14:41 +02:00
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
// Analyze the opcode
|
|
|
|
if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) {
|
|
|
|
eprintf ("Decode error at %"PFMT64x"\n", pc);
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2014-09-17 14:57:33 +02:00
|
|
|
}
|
2016-06-28 05:24:30 +02:00
|
|
|
if (op.fail == -1) {
|
|
|
|
ins_size = pc + op.size;
|
|
|
|
} else {
|
|
|
|
// Use op.fail here instead of pc+op.size to enforce anal backends to fill in this field
|
|
|
|
ins_size = op.fail;
|
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
// Skip over all the subroutine calls
|
2016-09-22 15:31:05 +02:00
|
|
|
if ((op.type & R_ANAL_OP_TYPE_MASK) == R_ANAL_OP_TYPE_CALL ||
|
|
|
|
(op.type & R_ANAL_OP_TYPE_MASK) == R_ANAL_OP_TYPE_UCALL) {
|
2016-06-28 05:24:30 +02:00
|
|
|
if (!r_debug_continue_until (dbg, ins_size)) {
|
2014-09-17 15:18:54 +02:00
|
|
|
eprintf ("Could not step over call @ 0x%"PFMT64x"\n", pc);
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2014-09-17 14:57:33 +02:00
|
|
|
}
|
2014-10-23 00:46:19 +02:00
|
|
|
} else if ((op.prefix & (R_ANAL_OP_PREFIX_REP | R_ANAL_OP_PREFIX_REPNE | R_ANAL_OP_PREFIX_LOCK))) {
|
|
|
|
//eprintf ("REP: skip to next instruction...\n");
|
2016-06-28 05:24:30 +02:00
|
|
|
if (!r_debug_continue_until (dbg, ins_size)) {
|
2014-10-23 00:46:19 +02:00
|
|
|
eprintf ("step over failed over rep\n");
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2014-10-23 00:46:19 +02:00
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
} else {
|
|
|
|
r_debug_step (dbg, 1);
|
|
|
|
}
|
2014-09-17 14:57:33 +02:00
|
|
|
}
|
|
|
|
|
2016-06-23 03:19:39 -05:00
|
|
|
return steps_taken;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
2015-08-13 14:02:11 +02:00
|
|
|
|
2010-05-24 12:07:54 +02:00
|
|
|
R_API int r_debug_continue_kill(RDebug *dbg, int sig) {
|
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 03:34:45 -05:00
|
|
|
RDebugReasonType reason, ret = false;
|
2016-09-01 19:11:46 +02:00
|
|
|
RBreakpointItem *bp = NULL;
|
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 03:34:45 -05:00
|
|
|
|
2016-05-15 10:40:57 +02:00
|
|
|
if (!dbg) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-05-05 18:08:01 +02:00
|
|
|
#if __WINDOWS__
|
2016-11-20 19:20:14 +01:00
|
|
|
r_cons_break_push (w32_break_process, dbg);
|
2015-05-05 18:08:01 +02:00
|
|
|
#endif
|
2014-10-30 00:21:25 +01:00
|
|
|
repeat:
|
2016-05-15 10:40:57 +02:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-05-10 02:47:20 +02:00
|
|
|
if (dbg->h && dbg->h->cont) {
|
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 03:34:45 -05:00
|
|
|
/* handle the stage-2 of breakpoints */
|
2016-11-20 19:20:14 +01:00
|
|
|
if (!r_debug_recoil (dbg, R_DBG_RECOIL_CONTINUE)) {
|
|
|
|
#if __WINDOWS__
|
|
|
|
r_cons_break_pop ();
|
|
|
|
#endif
|
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 03:34:45 -05:00
|
|
|
return false;
|
2016-11-20 19:20:14 +01:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
/* tell the inferior to go! */
|
2011-04-03 16:38:24 +02:00
|
|
|
ret = dbg->h->cont (dbg, dbg->pid, dbg->tid, sig);
|
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 03:34:45 -05:00
|
|
|
//XXX(jjd): why? //dbg->reason.signum = 0;
|
|
|
|
|
2016-09-01 19:11:46 +02:00
|
|
|
reason = r_debug_wait (dbg, &bp);
|
|
|
|
if (dbg->corebind.core) {
|
|
|
|
RCore *core = (RCore *)dbg->corebind.core;
|
|
|
|
RNum *num = core->num;
|
|
|
|
if (reason == R_DEBUG_REASON_COND) {
|
2016-12-19 16:44:51 +01:00
|
|
|
if (bp && bp->cond && dbg->corebind.cmd) {
|
2016-09-01 19:11:46 +02:00
|
|
|
dbg->corebind.cmd (dbg->corebind.core, bp->cond);
|
|
|
|
}
|
|
|
|
if (num->value) {
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 03:34:45 -05:00
|
|
|
|
2015-05-05 18:08:01 +02:00
|
|
|
#if __WINDOWS__
|
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 03:34:45 -05:00
|
|
|
if (reason != R_DEBUG_REASON_DEAD) {
|
|
|
|
// XXX(jjd): returning a thread id?!
|
2015-08-12 12:57:36 +02:00
|
|
|
ret = dbg->tid;
|
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
if (reason == R_DEBUG_REASON_NEW_LIB ||
|
|
|
|
reason == R_DEBUG_REASON_EXIT_LIB) {
|
2015-10-15 22:50:06 +02:00
|
|
|
goto repeat;
|
|
|
|
}
|
2015-05-05 18:08:01 +02:00
|
|
|
#endif
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* if continuing killed the inferior, we won't be able to get
|
|
|
|
* the registers.. */
|
|
|
|
if (reason == R_DEBUG_REASON_DEAD || r_debug_is_dead (dbg)) {
|
2016-11-20 19:20:14 +01:00
|
|
|
#if __WINDOWS__
|
|
|
|
r_cons_break_pop ();
|
|
|
|
#endif
|
2016-02-06 19:53:29 +01:00
|
|
|
return false;
|
2014-10-30 00:21:25 +01:00
|
|
|
}
|
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 03:34:45 -05:00
|
|
|
|
2016-07-01 16:06:13 -05:00
|
|
|
/* if we hit a tracing breakpoint, we need to continue in
|
|
|
|
* whatever mode the user desired. */
|
|
|
|
if (reason == R_DEBUG_REASON_TRACEPOINT) {
|
|
|
|
r_debug_step (dbg, 1);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
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 03:34:45 -05:00
|
|
|
/* choose the thread that was returned from the continue function */
|
|
|
|
// XXX(jjd): there must be a cleaner way to do this...
|
2010-03-11 01:04:59 +01:00
|
|
|
r_debug_select (dbg, dbg->pid, ret);
|
2014-12-12 00:34:53 +01:00
|
|
|
sig = 0; // clear continuation after signal if needed
|
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 03:34:45 -05:00
|
|
|
|
|
|
|
/* handle general signals here based on the return from the wait
|
|
|
|
* function */
|
2016-09-20 03:25:06 -04:00
|
|
|
if (dbg->reason.signum != -1) {
|
2015-08-17 00:12:54 +02:00
|
|
|
int what = r_debug_signal_what (dbg, dbg->reason.signum);
|
2014-12-12 00:34:53 +01:00
|
|
|
if (what & R_DBG_SIGNAL_CONT) {
|
2015-08-17 00:12:54 +02:00
|
|
|
sig = dbg->reason.signum;
|
2014-12-12 00:34:53 +01:00
|
|
|
eprintf ("Continue into the signal %d handler\n", sig);
|
|
|
|
goto repeat;
|
|
|
|
} else if (what & R_DBG_SIGNAL_SKIP) {
|
|
|
|
// skip signal. requires skipping one instruction
|
|
|
|
ut8 buf[64];
|
|
|
|
RAnalOp op = {0};
|
2016-04-08 00:54:15 +02:00
|
|
|
ut64 pc = r_debug_reg_get (dbg, "PC");
|
2014-12-12 00:34:53 +01:00
|
|
|
dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf));
|
|
|
|
r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf));
|
2016-02-06 19:53:29 +01:00
|
|
|
if (op.size > 0) {
|
2015-08-17 00:12:54 +02:00
|
|
|
const char *signame = r_debug_signal_resolve_i (dbg, dbg->reason.signum);
|
2016-04-08 00:54:15 +02:00
|
|
|
r_debug_reg_set (dbg, "PC", pc+op.size);
|
2014-12-12 00:34:53 +01:00
|
|
|
eprintf ("Skip signal %d handler %s\n",
|
2015-08-17 00:12:54 +02:00
|
|
|
dbg->reason.signum, signame);
|
2014-12-12 00:34:53 +01:00
|
|
|
goto repeat;
|
2016-02-06 19:53:29 +01:00
|
|
|
} else {
|
2016-04-08 00:54:15 +02:00
|
|
|
ut64 pc = r_debug_reg_get (dbg, "PC");
|
2014-12-12 00:34:53 +01:00
|
|
|
eprintf ("Stalled with an exception at 0x%08"PFMT64x"\n", pc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-03-22 02:36:00 +00:00
|
|
|
}
|
2016-11-20 19:20:14 +01:00
|
|
|
#if __WINDOWS__
|
|
|
|
r_cons_break_pop ();
|
|
|
|
#endif
|
2009-02-05 22:08:46 +01:00
|
|
|
return ret;
|
2016-11-20 19:20:14 +01:00
|
|
|
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2010-05-24 12:07:54 +02:00
|
|
|
R_API int r_debug_continue(RDebug *dbg) {
|
2015-08-17 00:12:54 +02:00
|
|
|
return r_debug_continue_kill (dbg, 0); //dbg->reason.signum);
|
2010-01-19 11:25:17 +01:00
|
|
|
}
|
|
|
|
|
2010-06-04 00:56:44 +02:00
|
|
|
R_API int r_debug_continue_until_nontraced(RDebug *dbg) {
|
|
|
|
eprintf ("TODO\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2010-06-04 00:56:44 +02:00
|
|
|
}
|
|
|
|
|
2010-05-24 17:51:51 +02:00
|
|
|
R_API int r_debug_continue_until_optype(RDebug *dbg, int type, int over) {
|
|
|
|
int ret, n = 0;
|
2014-09-15 14:38:28 +02:00
|
|
|
ut64 pc, buf_pc = 0;
|
2010-05-24 12:07:54 +02:00
|
|
|
RAnalOp op;
|
2014-09-17 14:57:33 +02:00
|
|
|
ut8 buf[DBG_BUF_SIZE];
|
2012-05-30 11:14:41 +02:00
|
|
|
|
2015-08-17 00:12:54 +02:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2015-08-17 00:12:54 +02:00
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
|
2015-08-29 14:01:38 +02:00
|
|
|
if (!dbg->anal || !dbg->reg) {
|
2014-09-15 14:38:28 +02:00
|
|
|
eprintf ("Undefined pointer at dbg->anal\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-09-15 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2014-10-13 14:52:33 +02:00
|
|
|
r_debug_step (dbg, 1);
|
2015-09-14 02:08:31 +02:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2014-10-13 14:52:33 +02:00
|
|
|
|
2014-09-15 14:38:28 +02:00
|
|
|
// Initial refill
|
|
|
|
buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
|
|
|
|
|
2014-10-13 05:02:24 +02:00
|
|
|
// step first, we dont want to check current optype
|
2014-09-15 14:38:28 +02:00
|
|
|
for (;;) {
|
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 03:34:45 -05:00
|
|
|
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false))
|
|
|
|
break;
|
|
|
|
|
2014-09-15 14:38:28 +02:00
|
|
|
pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
2015-08-29 14:01:38 +02:00
|
|
|
// Try to keep the buffer full
|
|
|
|
if (pc - buf_pc > sizeof (buf)) {
|
2014-09-15 14:38:28 +02:00
|
|
|
buf_pc = pc;
|
|
|
|
dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
|
|
|
|
}
|
|
|
|
// Analyze the opcode
|
|
|
|
if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) {
|
|
|
|
eprintf ("Decode error at %"PFMT64x"\n", pc);
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-09-15 14:38:28 +02:00
|
|
|
}
|
2015-08-29 14:01:38 +02:00
|
|
|
if (op.type == type)
|
2014-09-15 14:38:28 +02:00
|
|
|
break;
|
|
|
|
// Step over and repeat
|
2016-05-15 10:40:57 +02:00
|
|
|
ret = over
|
|
|
|
? r_debug_step_over (dbg, 1)
|
|
|
|
: r_debug_step (dbg, 1);
|
2014-09-15 14:38:28 +02:00
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
eprintf ("r_debug_step: failed\n");
|
|
|
|
break;
|
2012-05-30 11:14:41 +02:00
|
|
|
}
|
2014-09-15 14:38:28 +02:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
2010-05-24 12:07:54 +02:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2014-08-01 12:07:08 +02:00
|
|
|
R_API int r_debug_continue_until(RDebug *dbg, ut64 addr) {
|
2014-09-16 15:09:22 +02:00
|
|
|
int has_bp;
|
|
|
|
ut64 pc;
|
|
|
|
|
|
|
|
if (r_debug_is_dead (dbg))
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-09-16 15:09:22 +02:00
|
|
|
|
|
|
|
// Check if there was another breakpoint set at addr
|
2014-10-28 02:28:58 +01:00
|
|
|
has_bp = r_bp_get_in (dbg->bp, addr, R_BP_PROT_EXEC) != NULL;
|
2014-09-16 15:09:22 +02:00
|
|
|
if (!has_bp)
|
2014-09-26 13:57:03 +02:00
|
|
|
r_bp_add_sw (dbg->bp, addr, dbg->bpsize, R_BP_PROT_EXEC);
|
2014-09-16 15:09:22 +02:00
|
|
|
|
|
|
|
// Continue until the bp is reached
|
|
|
|
for (;;) {
|
|
|
|
if (r_debug_is_dead (dbg))
|
|
|
|
break;
|
|
|
|
pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
if (pc == addr)
|
|
|
|
break;
|
2015-01-12 17:47:34 +01:00
|
|
|
if (r_bp_get_at (dbg->bp, pc))
|
2016-06-15 14:50:32 -05:00
|
|
|
break;
|
2014-09-16 15:09:22 +02:00
|
|
|
r_debug_continue (dbg);
|
2014-08-01 12:07:08 +02:00
|
|
|
}
|
2014-09-16 15:09:22 +02:00
|
|
|
// Clean up if needed
|
2016-05-15 10:40:57 +02:00
|
|
|
if (!has_bp) {
|
2014-09-16 15:09:22 +02:00
|
|
|
r_bp_del (dbg->bp, addr);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2009-02-05 22:08:46 +01:00
|
|
|
}
|
|
|
|
|
2015-04-18 10:35:57 +02:00
|
|
|
static int show_syscall(RDebug *dbg, const char *sysreg) {
|
2014-06-14 02:01:03 +02:00
|
|
|
const char *sysname;
|
2015-04-18 10:35:57 +02:00
|
|
|
char regname[8];
|
|
|
|
int reg, i, args;
|
|
|
|
RSyscallItem *si;
|
|
|
|
reg = (int)r_debug_reg_get (dbg, sysreg);
|
|
|
|
si = r_syscall_get (dbg->anal->syscall, reg, -1);
|
|
|
|
if (si) {
|
|
|
|
sysname = si->name? si->name: "unknown";
|
|
|
|
args = si->args;
|
|
|
|
} else {
|
|
|
|
sysname = "unknown";
|
|
|
|
args = 3;
|
|
|
|
}
|
|
|
|
eprintf ("--> %s 0x%08"PFMT64x" syscall %d %s (", sysreg,
|
2016-04-08 00:54:15 +02:00
|
|
|
r_debug_reg_get (dbg, "PC"), reg, sysname);
|
2015-04-18 10:35:57 +02:00
|
|
|
for (i=0; i<args; i++) {
|
|
|
|
ut64 val;
|
2015-10-31 01:57:52 +01:00
|
|
|
snprintf (regname, sizeof (regname)-1, "A%d", i);
|
2015-04-18 10:35:57 +02:00
|
|
|
val = r_debug_reg_get (dbg, regname);
|
|
|
|
if (((st64)val<0) && ((st64)val>-0xffff)) {
|
|
|
|
eprintf ("%"PFMT64d"%s", val, (i+1==args)?"":" ");
|
|
|
|
} else {
|
|
|
|
eprintf ("0x%"PFMT64x"%s", val, (i+1==args)?"":" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eprintf (")\n");
|
|
|
|
r_syscall_item_free (si);
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_continue_syscalls(RDebug *dbg, int *sc, int n_sc) {
|
2016-05-15 10:40:57 +02:00
|
|
|
int i, err, reg, ret = false;
|
2016-09-26 13:38:30 +02:00
|
|
|
if (!dbg || !dbg->h || r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-09-26 13:38:30 +02:00
|
|
|
}
|
2014-06-14 02:01:03 +02:00
|
|
|
if (!dbg->h->contsc) {
|
|
|
|
/* user-level syscall tracing */
|
|
|
|
r_debug_continue_until_optype (dbg, R_ANAL_OP_TYPE_SWI, 0);
|
2015-10-31 01:57:52 +01:00
|
|
|
return show_syscall (dbg, "A0");
|
2014-06-14 02:01:03 +02:00
|
|
|
}
|
|
|
|
|
2015-09-14 02:08:31 +02:00
|
|
|
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)) {
|
2014-06-14 02:01:03 +02:00
|
|
|
eprintf ("--> cannot read registers\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
reg = (int)r_debug_reg_get_err (dbg, "SN", &err, NULL);
|
2016-05-15 10:40:57 +02:00
|
|
|
if (err) {
|
|
|
|
eprintf ("Cannot find 'sn' register for current arch-os.\n");
|
|
|
|
return -1;
|
2014-06-14 02:01:03 +02:00
|
|
|
}
|
|
|
|
for (;;) {
|
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 03:34:45 -05:00
|
|
|
RDebugReasonType reason;
|
|
|
|
|
2015-04-19 13:39:10 +02:00
|
|
|
if (r_cons_singleton()->breaked)
|
|
|
|
break;
|
|
|
|
#if __linux__
|
|
|
|
// step is needed to avoid dupped contsc results
|
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 03:34:45 -05:00
|
|
|
/* XXX(jjd): actually one stop is before the syscall, the other is
|
|
|
|
* after. this allows you to inspect the arguments before and the
|
|
|
|
* return value after... */
|
2015-04-19 13:39:10 +02:00
|
|
|
r_debug_step (dbg, 1);
|
|
|
|
#endif
|
2014-06-14 02:01:03 +02:00
|
|
|
dbg->h->contsc (dbg, dbg->pid, 0); // TODO handle return value
|
2014-10-09 18:31:55 +02:00
|
|
|
// wait until continuation
|
2016-09-01 19:11:46 +02:00
|
|
|
reason = r_debug_wait (dbg, NULL);
|
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 03:34:45 -05:00
|
|
|
if (reason == R_DEBUG_REASON_DEAD || r_debug_is_dead (dbg)) {
|
|
|
|
break;
|
|
|
|
}
|
2016-09-26 13:38:30 +02:00
|
|
|
#if 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 03:34:45 -05:00
|
|
|
if (reason != R_DEBUG_REASON_STEP) {
|
2016-09-26 13:38:30 +02:00
|
|
|
eprintf ("astep\n");
|
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 03:34:45 -05:00
|
|
|
break;
|
|
|
|
}
|
2016-09-26 13:38:30 +02:00
|
|
|
#endif
|
2015-09-14 02:08:31 +02:00
|
|
|
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)) {
|
2015-04-19 13:39:10 +02:00
|
|
|
eprintf ("--> cannot sync regs, process is probably dead\n");
|
2014-06-14 02:01:03 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2016-01-13 22:25:08 +01:00
|
|
|
reg = show_syscall (dbg, "SN");
|
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 03:34:45 -05:00
|
|
|
if (n_sc == -1) {
|
2014-10-09 18:31:55 +02:00
|
|
|
continue;
|
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 03:34:45 -05:00
|
|
|
}
|
2014-10-09 18:31:55 +02:00
|
|
|
if (n_sc == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
for (i = 0; i < n_sc; i++) {
|
|
|
|
if (sc[i] == reg) {
|
2014-06-14 02:01:03 +02:00
|
|
|
return reg;
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2010-05-24 12:07:54 +02:00
|
|
|
}
|
2014-06-14 02:01:03 +02:00
|
|
|
// TODO: must use r_core_cmd(as)..import code from rcore
|
2010-03-04 01:46:25 +01:00
|
|
|
}
|
2009-02-05 22:08:46 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-06-14 02:01:03 +02:00
|
|
|
R_API int r_debug_continue_syscall(RDebug *dbg, int sc) {
|
|
|
|
return r_debug_continue_syscalls (dbg, &sc, 1);
|
|
|
|
}
|
|
|
|
|
2010-01-21 02:38:52 +01:00
|
|
|
// TODO: remove from here? this is code injection!
|
2012-12-07 12:03:53 +01:00
|
|
|
R_API int r_debug_syscall(RDebug *dbg, int num) {
|
2016-05-15 10:40:57 +02:00
|
|
|
bool ret = true;
|
2010-05-24 12:07:54 +02:00
|
|
|
if (dbg->h->contsc) {
|
2011-04-03 16:38:24 +02:00
|
|
|
ret = dbg->h->contsc (dbg, dbg->pid, num);
|
2010-05-24 12:07:54 +02:00
|
|
|
}
|
2010-09-23 20:42:35 +02:00
|
|
|
eprintf ("TODO: show syscall information\n");
|
2010-03-12 18:46:11 +01:00
|
|
|
/* r2rc task? ala inject? */
|
2015-09-14 02:08:31 +02:00
|
|
|
return (int)ret;
|
2009-09-10 20:51:34 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 12:03:53 +01:00
|
|
|
R_API int r_debug_kill(RDebug *dbg, int pid, int tid, int sig) {
|
2016-10-30 12:16:46 +01:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2016-10-30 12:16:46 +01:00
|
|
|
}
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg->h && dbg->h->kill) {
|
|
|
|
return dbg->h->kill (dbg, pid, tid, sig);
|
|
|
|
}
|
2016-08-25 18:26:59 +00:00
|
|
|
eprintf ("Backend does not implement kill()\n");
|
2016-05-15 10:40:57 +02:00
|
|
|
return false;
|
2009-04-01 22:44:43 +00:00
|
|
|
}
|
2010-02-02 11:09:52 +01:00
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API RList *r_debug_frames(RDebug *dbg, ut64 at) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->frames) {
|
2012-06-14 02:18:15 +02:00
|
|
|
return dbg->h->frames (dbg, at);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2010-03-02 11:18:49 +01:00
|
|
|
return NULL;
|
2010-02-02 11:09:52 +01:00
|
|
|
}
|
2010-11-18 11:41:17 +01:00
|
|
|
|
|
|
|
/* TODO: Implement fork and clone */
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_child_fork(RDebug *dbg) {
|
2010-11-18 11:41:17 +01:00
|
|
|
//if (dbg && dbg->h && dbg->h->frames)
|
|
|
|
//return dbg->h->frames (dbg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_child_clone(RDebug *dbg) {
|
2010-11-18 11:41:17 +01:00
|
|
|
//if (dbg && dbg->h && dbg->h->frames)
|
|
|
|
//return dbg->h->frames (dbg);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-20 20:42:25 +02:00
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_is_dead(RDebug *dbg) {
|
2015-08-17 00:12:54 +02:00
|
|
|
int is_dead = (dbg->pid == -1);
|
2016-04-22 20:55:44 -04:00
|
|
|
if (!is_dead && dbg->h && dbg->h->kill) {
|
|
|
|
is_dead = !dbg->h->kill (dbg, dbg->pid, false, 0);
|
|
|
|
}
|
2015-08-17 00:12:54 +02:00
|
|
|
if (is_dead) {
|
|
|
|
dbg->reason.type = R_DEBUG_REASON_DEAD;
|
|
|
|
}
|
|
|
|
return is_dead;
|
2011-05-20 20:42:25 +02:00
|
|
|
}
|
2011-11-25 04:32:32 +01:00
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_map_protect(RDebug *dbg, ut64 addr, int size, int perms) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->map_protect) {
|
2011-11-25 04:32:32 +01:00
|
|
|
return dbg->h->map_protect (dbg, addr, size, perms);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2011-11-25 04:32:32 +01:00
|
|
|
}
|
2014-01-28 04:38:02 +01:00
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API void r_debug_drx_list(RDebug *dbg) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->drx) {
|
2014-01-28 04:38:02 +01:00
|
|
|
dbg->h->drx (dbg, 0, 0, 0, 0, 0);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2014-01-28 04:38:02 +01:00
|
|
|
}
|
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_drx_set(RDebug *dbg, int idx, ut64 addr, int len, int rwx, int g) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->drx) {
|
2014-01-28 04:38:02 +01:00
|
|
|
return dbg->h->drx (dbg, idx, addr, len, rwx, g);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-01-28 04:38:02 +01:00
|
|
|
}
|
|
|
|
|
2016-01-29 18:52:53 -05:00
|
|
|
R_API int r_debug_drx_unset(RDebug *dbg, int idx) {
|
2016-05-15 10:40:57 +02:00
|
|
|
if (dbg && dbg->h && dbg->h->drx) {
|
2014-01-28 04:38:02 +01:00
|
|
|
return dbg->h->drx (dbg, idx, 0, -1, 0, 0);
|
2016-05-15 10:40:57 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-01-28 04:38:02 +01:00
|
|
|
}
|