3485 lines
105 KiB
C
3485 lines
105 KiB
C
// SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_cmd.h>
|
|
#include <rz_util/rz_log.h>
|
|
#include <rz_util/rz_num.h>
|
|
#include <rz_util/rz_regex.h>
|
|
#include <rz_core.h>
|
|
#include <rz_debug.h>
|
|
#include <sdb.h>
|
|
#include <cmd_descs.h>
|
|
|
|
#define TN_KEY_LEN 32
|
|
#define TN_KEY_FMT "%" PFMT64u
|
|
|
|
#include "rz_heap_jemalloc.h"
|
|
|
|
#include "../core_private.h"
|
|
|
|
#define CMD_CHECK_DEBUG_DEAD(core) \
|
|
do { \
|
|
if (rz_debug_is_dead(core->dbg)) { \
|
|
rz_cons_println("Debugging is not enabled. Run ood?"); \
|
|
return RZ_CMD_STATUS_ERROR; \
|
|
} \
|
|
} while (0)
|
|
|
|
struct dot_trace_ght {
|
|
RzGraph /*<struct trace_node *, None *>*/ *graph;
|
|
Sdb *graphnodes;
|
|
};
|
|
|
|
struct trace_node {
|
|
ut64 addr;
|
|
int refs;
|
|
};
|
|
|
|
// XXX those tmp files are never removed and we shuoldnt use files for this
|
|
static void set_profile_string(RzCore *core, const char *str) {
|
|
char *file = rz_str_dup(rz_config_get(core->config, "dbg.profile"));
|
|
if (RZ_STR_ISEMPTY(file)) {
|
|
free(file);
|
|
file = rz_file_temp("rz-run");
|
|
rz_config_set(core->config, "dbg.profile", file);
|
|
}
|
|
rz_file_dump(file, (const ut8 *)str, (int)strlen(str), 0);
|
|
rz_file_dump(file, (const ut8 *)"\n", 1, 1);
|
|
free(file);
|
|
}
|
|
|
|
static void cmd_debug_cont_syscall(RzCore *core, const char *_str) {
|
|
// TODO : handle more than one stopping syscall
|
|
int i, *syscalls = NULL;
|
|
int count = 0;
|
|
if (_str && *_str) {
|
|
char *str = rz_str_dup(_str);
|
|
count = rz_str_word_set0(str);
|
|
syscalls = calloc(sizeof(int), count);
|
|
for (i = 0; i < count; i++) {
|
|
const char *sysnumstr = rz_str_word_get0(str, i);
|
|
int sig = (int)rz_num_math(core->num, sysnumstr);
|
|
if (sig == -1) { // trace ALL syscalls
|
|
syscalls[i] = -1;
|
|
} else if (sig == 0) {
|
|
RzSyscall *sysc = rz_analysis_get_syscall(core->analysis);
|
|
if (!rz_syscall_get_num(sysc, sysnumstr, &sig)) {
|
|
RZ_LOG_ERROR("core: Unknown syscall number\n");
|
|
free(str);
|
|
free(syscalls);
|
|
return;
|
|
}
|
|
syscalls[i] = sig;
|
|
}
|
|
}
|
|
rz_cons_printf("Running child until syscalls:");
|
|
for (i = 0; i < count; i++) {
|
|
rz_cons_printf("%d ", syscalls[i]);
|
|
}
|
|
rz_cons_printf("\n");
|
|
free(str);
|
|
} else {
|
|
RZ_LOG_WARN("core: Running child until next syscall\n");
|
|
}
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
rz_debug_continue_syscalls(core->dbg, syscalls, count);
|
|
free(syscalls);
|
|
}
|
|
|
|
static RzGraphNode *get_graphtrace_node(RzGraph /*<struct trace_node *, None *>*/ *g, Sdb *nodes, struct trace_node *tn) {
|
|
RzGraphNode *gn;
|
|
char tn_key[TN_KEY_LEN];
|
|
|
|
snprintf(tn_key, TN_KEY_LEN, TN_KEY_FMT, tn->addr);
|
|
gn = (RzGraphNode *)(size_t)sdb_num_get(nodes, tn_key);
|
|
if (gn) {
|
|
return gn;
|
|
}
|
|
if (rz_graph_add_node(g, tn, &gn) != RZ_GRAPH_STATUS_ERR) {
|
|
sdb_num_set(nodes, tn_key, (ut64)(size_t)gn);
|
|
}
|
|
return gn;
|
|
}
|
|
|
|
static void dot_trace_create_node(RTreeNode *n, RTreeVisitor *vis) {
|
|
struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
|
|
struct trace_node *tn = n->data;
|
|
if (tn)
|
|
get_graphtrace_node(data->graph, data->graphnodes, tn);
|
|
}
|
|
|
|
static void dot_trace_discover_child(RTreeNode *n, RTreeVisitor *vis) {
|
|
struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
|
|
RzGraph *g = data->graph;
|
|
Sdb *gnodes = data->graphnodes;
|
|
RTreeNode *parent = n->parent;
|
|
struct trace_node *tn = n->data;
|
|
struct trace_node *tn_parent = parent->data;
|
|
|
|
if (tn && tn_parent) {
|
|
RzGraphNode *gn = get_graphtrace_node(g, gnodes, tn);
|
|
RzGraphNode *gn_parent = get_graphtrace_node(g, gnodes, tn_parent);
|
|
|
|
if (rz_graph_has_edge(g, gn_parent, gn) == RZ_GRAPH_STATUS_MISSING_EDGE)
|
|
rz_graph_add_edge(g, gn_parent, gn, NULL);
|
|
}
|
|
}
|
|
|
|
static void dot_trace_traverse(RzCore *core, RTree *t, int fmt) {
|
|
const char *gfont = rz_config_get(core->config, "graph.font");
|
|
struct dot_trace_ght aux_data;
|
|
RTreeVisitor vis = { 0 };
|
|
RzGraphNode *n;
|
|
|
|
if (fmt == 'i') {
|
|
rz_core_agraph_reset(core);
|
|
rz_core_cmd0(core, ".dtg*");
|
|
rz_core_agraph_print_interactive(core);
|
|
return;
|
|
}
|
|
aux_data.graph = rz_graph_new(RZ_GRAPH_IMPL_LIST, NULL, NULL, NULL);
|
|
aux_data.graphnodes = sdb_new0();
|
|
|
|
/* build a callgraph from the execution trace */
|
|
vis.data = &aux_data;
|
|
vis.pre_visit = (RTreeNodeVisitCb)dot_trace_create_node;
|
|
vis.discover_child = (RTreeNodeVisitCb)dot_trace_discover_child;
|
|
rz_tree_bfs(t, &vis);
|
|
|
|
/* traverse the callgraph to print the dot file */
|
|
RzIterator *it_nodes = rz_graph_get_nodes(aux_data.graph);
|
|
if (!it_nodes) {
|
|
RZ_LOG_ERROR("Failed to get graph nodes\n");
|
|
rz_graph_free(aux_data.graph);
|
|
sdb_free(aux_data.graphnodes);
|
|
return;
|
|
}
|
|
|
|
if (fmt == 0) {
|
|
rz_cons_printf("digraph code {\n"
|
|
"graph [bgcolor=white];\n"
|
|
" node [color=lightgray, style=filled"
|
|
" shape=box fontname=\"%s\" fontsize=\"8\"];\n",
|
|
gfont);
|
|
}
|
|
rz_iterator_foreach(it_nodes, n) {
|
|
const struct trace_node *tn = rz_graph_node_get_data(n);
|
|
RzGraphNode *w;
|
|
|
|
if (!fmt && tn) {
|
|
rz_cons_printf("\"0x%08" PFMT64x "\" [URL=\"0x%08" PFMT64x
|
|
"\" color=\"lightgray\" label=\"0x%08" PFMT64x
|
|
" (%d)\"]\n",
|
|
tn->addr, tn->addr, tn->addr, tn->refs);
|
|
}
|
|
|
|
RzIterator *it_neighbours = rz_graph_out_neighbors(aux_data.graph, n);
|
|
if (!it_neighbours) {
|
|
continue;
|
|
}
|
|
|
|
rz_iterator_foreach(it_neighbours, w) {
|
|
const struct trace_node *tv = rz_graph_node_get_data(w);
|
|
|
|
if (tv && tn) {
|
|
if (fmt) {
|
|
rz_cons_printf("agn 0x%08" PFMT64x "\n", tn->addr);
|
|
rz_cons_printf("agn 0x%08" PFMT64x "\n", tv->addr);
|
|
rz_cons_printf("age 0x%08" PFMT64x " 0x%08" PFMT64x "\n",
|
|
tn->addr, tv->addr);
|
|
} else {
|
|
rz_cons_printf("\"0x%08" PFMT64x "\" -> \"0x%08" PFMT64x
|
|
"\" [color=\"red\"];\n",
|
|
tn->addr, tv->addr);
|
|
}
|
|
}
|
|
}
|
|
rz_iterator_free(it_neighbours);
|
|
}
|
|
rz_iterator_free(it_nodes);
|
|
|
|
if (!fmt) {
|
|
rz_cons_printf("}\n");
|
|
}
|
|
|
|
rz_graph_free(aux_data.graph);
|
|
sdb_free(aux_data.graphnodes);
|
|
}
|
|
|
|
/* TODO: refactor all those step_until* function into a single one
|
|
* TODO: handle when the process is dead
|
|
* TODO: handle ^C */
|
|
|
|
static int step_until(RzCore *core, ut64 addr) {
|
|
ut64 off = rz_debug_reg_get(core->dbg, "PC");
|
|
if (!off) {
|
|
RZ_LOG_ERROR("core: Cannot 'drn PC'\n");
|
|
return false;
|
|
}
|
|
if (!addr) {
|
|
RZ_LOG_ERROR("core: Cannot continue until address 0\n");
|
|
return false;
|
|
}
|
|
rz_cons_break_push(NULL, NULL);
|
|
do {
|
|
if (rz_cons_is_breaked()) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
rz_debug_step(core->dbg, 1);
|
|
off = rz_debug_reg_get(core->dbg, "PC");
|
|
// check breakpoint here
|
|
} while (off != addr);
|
|
rz_core_reg_update_flags(core);
|
|
rz_cons_break_pop();
|
|
return true;
|
|
}
|
|
|
|
static int step_until_esil(RzCore *core, const char *esilstr) {
|
|
RzAnalysisEsil *esil = rz_analysis_get_esil(core->analysis);
|
|
if (!esil || !esilstr || !core->dbg || !core->dbg->analysis) {
|
|
RZ_LOG_ERROR("core: Not initialized %p. Run 'aei' first.\n", esil);
|
|
return false;
|
|
}
|
|
rz_cons_break_push(NULL, NULL);
|
|
for (;;) {
|
|
if (rz_cons_is_breaked()) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
rz_debug_step(core->dbg, 1);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_ANY, false);
|
|
if (rz_analysis_esil_condition(esil, esilstr)) {
|
|
RZ_LOG_WARN("core: esil condition breakpoint!\n");
|
|
break;
|
|
}
|
|
}
|
|
rz_core_reg_update_flags(core);
|
|
rz_cons_break_pop();
|
|
return true;
|
|
}
|
|
|
|
static bool is_repeatable_inst(RzCore *core, ut64 addr) {
|
|
// we have read the bytes already
|
|
RzAnalysisOp *op = rz_core_op_analysis(core, addr, RZ_ANALYSIS_OP_MASK_ALL);
|
|
bool ret = op && ((op->prefix & RZ_ANALYSIS_OP_PREFIX_REP) || (op->prefix & RZ_ANALYSIS_OP_PREFIX_REPNE));
|
|
rz_analysis_op_free(op);
|
|
return ret;
|
|
}
|
|
|
|
static bool step_until_inst(RzCore *core, const char *instr, bool regex) {
|
|
rz_return_val_if_fail(core, false);
|
|
instr = rz_str_trim_head_ro(instr);
|
|
if (!instr || !core->dbg) {
|
|
RZ_LOG_ERROR("wrong debugger state\n");
|
|
return false;
|
|
}
|
|
ut8 buf[32];
|
|
ut64 pc;
|
|
int ret;
|
|
bool is_x86 = rz_str_startswith(rz_config_get(core->config, "asm.arch"), "x86");
|
|
rz_cons_break_push(NULL, NULL);
|
|
for (;;) {
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
break;
|
|
}
|
|
pc = rz_debug_reg_get(core->dbg, "PC");
|
|
if (is_x86 && is_repeatable_inst(core, pc)) {
|
|
rz_debug_step_over(core->dbg, 1);
|
|
} else {
|
|
rz_debug_step(core->dbg, 1);
|
|
}
|
|
pc = rz_debug_reg_get(core->dbg, "PC");
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_ANY, false);
|
|
/* TODO: disassemble instruction and strstr */
|
|
rz_asm_set_pc(core->rasm, pc);
|
|
// TODO: speedup if instructions are in the same block as the previous
|
|
rz_io_read_at_mapped(core->io, pc, buf, sizeof(buf));
|
|
RzAsmOp asmop = { 0 };
|
|
ret = rz_asm_disassemble(core->rasm, &asmop, buf, sizeof(buf));
|
|
rz_cons_printf("0x%08" PFMT64x " %d %s\n", pc, ret, rz_asm_op_get_asm(&asmop)); // asmop.buf_asm);
|
|
if (ret > 0) {
|
|
const char *buf_asm = rz_asm_op_get_asm(&asmop);
|
|
if (regex) {
|
|
if (rz_regex_contains(instr, buf_asm, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT)) {
|
|
rz_asm_op_fini(&asmop);
|
|
break;
|
|
}
|
|
} else {
|
|
if (strstr(buf_asm, instr)) {
|
|
rz_asm_op_fini(&asmop);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
rz_asm_op_fini(&asmop);
|
|
}
|
|
}
|
|
rz_core_reg_update_flags(core);
|
|
rz_cons_break_pop();
|
|
return true;
|
|
}
|
|
|
|
static bool step_until_optype(RzCore *core, RzList /*<char *>*/ *optypes_list) {
|
|
RzAnalysisOp op = { 0 };
|
|
ut8 buf[32];
|
|
ut64 pc;
|
|
int res = true;
|
|
|
|
RzListIter *iter;
|
|
char *optype;
|
|
|
|
if (!core || !core->dbg) {
|
|
RZ_LOG_ERROR("wrong state\n");
|
|
res = false;
|
|
goto end;
|
|
}
|
|
if (!optypes_list) {
|
|
RZ_LOG_ERROR("missing optypes. Usage example: 'dsuo ucall ujmp'\n");
|
|
res = false;
|
|
goto end;
|
|
}
|
|
|
|
bool debugMode = rz_config_get_b(core->config, "cfg.debug");
|
|
|
|
rz_cons_break_push(NULL, NULL);
|
|
for (;;) {
|
|
if (rz_cons_is_breaked()) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
if (debugMode) {
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
rz_debug_step(core->dbg, 1);
|
|
pc = rz_debug_reg_get_by_role(core->dbg, RZ_REG_NAME_PC);
|
|
// 'Copy' from rz_debug_step_soft
|
|
if (!core->dbg->iob.read_at) {
|
|
RZ_LOG_ERROR("ERROR\n");
|
|
res = false;
|
|
goto cleanup_after_push;
|
|
}
|
|
if (!core->dbg->iob.read_at(core->dbg->iob.io, pc, buf, sizeof(buf))) {
|
|
RZ_LOG_ERROR("ERROR\n");
|
|
res = false;
|
|
goto cleanup_after_push;
|
|
}
|
|
} else {
|
|
rz_core_esil_step(core, UT64_MAX, NULL, NULL, false);
|
|
RzReg *rreg = rz_analysis_get_reg(core->analysis);
|
|
pc = rz_reg_getv(rreg, "PC");
|
|
}
|
|
rz_io_read_at_mapped(core->io, pc, buf, sizeof(buf));
|
|
rz_analysis_op_init(&op);
|
|
if (rz_analysis_op(core->dbg->analysis, &op, pc, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_BASIC) < 1) {
|
|
RZ_LOG_ERROR("rz_analysis_op failed\n");
|
|
res = false;
|
|
goto cleanup_after_push;
|
|
}
|
|
|
|
// This is slow because we do lots of strcmp's.
|
|
// To improve this, the function rz_analysis_optype_string_to_int should be implemented
|
|
// I also don't check if the opcode type exists.
|
|
const char *optype_str = rz_analysis_optype_to_string(op.type);
|
|
rz_list_foreach (optypes_list, iter, optype) {
|
|
if (!strcmp(optype_str, optype)) {
|
|
goto cleanup_after_push;
|
|
}
|
|
}
|
|
rz_analysis_op_fini(&op);
|
|
}
|
|
|
|
cleanup_after_push:
|
|
rz_analysis_op_fini(&op);
|
|
rz_core_reg_update_flags(core);
|
|
rz_cons_break_pop();
|
|
end:
|
|
return res;
|
|
}
|
|
|
|
static int step_until_flag(RzCore *core, const char *flagstr) {
|
|
const RzList *list;
|
|
RzListIter *iter;
|
|
RzFlagItem *flag;
|
|
ut64 pc;
|
|
|
|
if (!core || !flagstr || !core->dbg) {
|
|
RZ_LOG_ERROR("wrong state\n");
|
|
return false;
|
|
}
|
|
rz_cons_break_push(NULL, NULL);
|
|
for (;;) {
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
break;
|
|
}
|
|
rz_debug_step(core->dbg, 1);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_ANY, false);
|
|
pc = rz_debug_reg_get(core->dbg, "PC");
|
|
list = rz_flag_get_list(core->flags, pc);
|
|
rz_list_foreach (list, iter, flag) {
|
|
if (flag->realname && strstr(flag->realname, flagstr)) {
|
|
rz_cons_printf("[ 0x%08" PFMT64x " ] %s\n",
|
|
flag->offset, flag->realname);
|
|
goto beach;
|
|
}
|
|
}
|
|
}
|
|
beach:
|
|
rz_core_reg_update_flags(core);
|
|
rz_cons_break_pop();
|
|
return true;
|
|
}
|
|
|
|
static bool step_line(RzCore *core, int times) {
|
|
char file[512], file2[512];
|
|
int find_meta, line = -1, line2 = -1;
|
|
char *tmp_ptr = NULL;
|
|
ut64 off = rz_debug_reg_get(core->dbg, "PC");
|
|
if (off == 0LL) {
|
|
RZ_LOG_ERROR("cannot 'drn PC'\n");
|
|
return false;
|
|
}
|
|
file[0] = 0;
|
|
file2[0] = 0;
|
|
RzBinObject *o = rz_bin_cur_object(core->bin);
|
|
RzBinSourceLineInfo *sl = o ? o->lines : NULL;
|
|
if (sl && rz_bin_source_line_addr2line(sl, off, file, sizeof(file), &line)) {
|
|
char *ptr = rz_file_slurp_line(file, line, 0);
|
|
RZ_LOG_INFO("--> 0x%08" PFMT64x " %s : %d\n", off, file, line);
|
|
RZ_LOG_INFO("--> %s\n", ptr);
|
|
find_meta = false;
|
|
free(ptr);
|
|
} else {
|
|
RZ_LOG_INFO("--> Stepping until dwarf line\n");
|
|
find_meta = true;
|
|
}
|
|
do {
|
|
rz_debug_step(core->dbg, 1);
|
|
off = rz_debug_reg_get(core->dbg, "PC");
|
|
if (!(sl && rz_bin_source_line_addr2line(sl, off, file2, sizeof(file2), &line2))) {
|
|
if (find_meta) {
|
|
continue;
|
|
}
|
|
rz_core_reg_update_flags(core);
|
|
RZ_LOG_ERROR("cannot retrieve dwarf info at 0x%08" PFMT64x "\n", off);
|
|
return false;
|
|
}
|
|
} while (!strcmp(file, file2) && line == line2);
|
|
|
|
RZ_LOG_INFO("--> 0x%08" PFMT64x " %s : %d\n", off, file2, line2);
|
|
tmp_ptr = rz_file_slurp_line(file2, line2, 0);
|
|
RZ_LOG_INFO("--> %s\n", tmp_ptr);
|
|
free(tmp_ptr);
|
|
rz_core_reg_update_flags(core);
|
|
return true;
|
|
}
|
|
|
|
static void cmd_debug_backtrace(RzCore *core, ut64 len) {
|
|
RzAnalysisOp aop = { 0 };
|
|
ut64 addr;
|
|
if (!len) {
|
|
rz_bp_traptrace_list(core->dbg->bp);
|
|
} else {
|
|
ut64 oaddr = 0LL;
|
|
rz_cons_printf("Trap tracing 0x%08" PFMT64x "-0x%08" PFMT64x "\n",
|
|
core->offset, core->offset + len);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
rz_bp_traptrace_reset(core->dbg->bp, true);
|
|
rz_bp_traptrace_add(core->dbg->bp, core->offset, core->offset + len);
|
|
rz_bp_traptrace_enable(core->dbg->bp, true);
|
|
do {
|
|
ut8 buf[32];
|
|
rz_debug_continue(core->dbg);
|
|
addr = rz_debug_reg_get(core->dbg, "PC");
|
|
if (!addr) {
|
|
rz_cons_printf("pc=0\n");
|
|
break;
|
|
}
|
|
if (addr == oaddr) {
|
|
rz_cons_printf("pc=opc\n");
|
|
break;
|
|
}
|
|
oaddr = addr;
|
|
/* XXX Bottleneck..we need to reuse the bytes read by traptrace */
|
|
// XXX Do asm.arch should define the max size of opcode?
|
|
rz_io_read_at_mapped(core->io, addr, buf, 32); // XXX longer opcodes?
|
|
rz_analysis_op_fini(&aop);
|
|
rz_analysis_op_init(&aop);
|
|
rz_analysis_op(core->analysis, &aop, addr, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_BASIC);
|
|
} while (rz_bp_traptrace_at(core->dbg->bp, addr, aop.size));
|
|
rz_analysis_op_fini(&aop);
|
|
rz_bp_traptrace_enable(core->dbg->bp, false);
|
|
}
|
|
}
|
|
|
|
#define MAX_MAP_SIZE (1024 * 1024 * 512)
|
|
static int dump_maps(RzCore *core, int perm, const char *filename) {
|
|
RzDebugMap *map;
|
|
RzListIter *iter;
|
|
rz_debug_map_sync(core->dbg); // update process memory maps
|
|
ut64 addr = core->offset;
|
|
int ret = !rz_list_empty(core->dbg->maps);
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (perm == -1) {
|
|
if (addr < map->addr || addr >= map->addr_end) {
|
|
continue;
|
|
}
|
|
} else if (perm != 0 && perm != (map->perm & perm)) {
|
|
continue;
|
|
}
|
|
|
|
ut8 *buf = RZ_NEWS(ut8, map->size);
|
|
// TODO: use mmap here. we need a portable implementation
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " bytes\n", map->size);
|
|
free(buf);
|
|
/// XXX: TODO: read by blocks!!1
|
|
continue;
|
|
}
|
|
if (map->size > MAX_MAP_SIZE) {
|
|
RZ_LOG_ERROR("core: map size is too big to be dumped (0x%08" PFMT64x " > 0x%08x)\n", map->addr, MAX_MAP_SIZE);
|
|
free(buf);
|
|
continue;
|
|
}
|
|
rz_io_read_at_mapped(core->io, map->addr, buf, map->size);
|
|
char *file = filename
|
|
? rz_str_dup(filename)
|
|
: rz_str_newf("0x%08" PFMT64x "-0x%08" PFMT64x "-%s.dmp",
|
|
map->addr, map->addr_end, rz_str_rwx_i(map->perm));
|
|
if (!rz_file_dump(file, buf, map->size, 0)) {
|
|
RZ_LOG_ERROR("core: Cannot write '%s'\n", file);
|
|
ret = 0;
|
|
} else {
|
|
RZ_LOG_WARN("core: Dumped %d byte(s) into %s\n", (int)map->size, file);
|
|
}
|
|
free(file);
|
|
free(buf);
|
|
}
|
|
// eprintf ("No debug region found here\n");
|
|
return ret;
|
|
}
|
|
|
|
#define MAX_MAP_SIZE (1024 * 1024 * 512)
|
|
static int dump_io_maps(RzCore *core, int perm, const char *filename) {
|
|
RzPVector *maps = rz_io_maps(core->io);
|
|
ut64 addr = core->offset;
|
|
int ret = !rz_pvector_empty(maps);
|
|
void **it;
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
ut64 map_addr = map->itv.addr;
|
|
ut64 map_size = map->itv.size;
|
|
ut64 map_end = map_addr + map_size;
|
|
|
|
if (perm == -1) {
|
|
if (addr < map_addr || addr >= map_end) {
|
|
continue;
|
|
}
|
|
} else if (perm != 0 && perm != (map->perm & perm)) {
|
|
continue;
|
|
}
|
|
|
|
ut8 *buf = RZ_NEWS(ut8, map_size);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " bytes\n", map_size);
|
|
continue;
|
|
}
|
|
if (map_size > MAX_MAP_SIZE) {
|
|
RZ_LOG_ERROR("core: map size is too big to be dumped (0x%08" PFMT64x " > 0x%08x)\n", map_addr, MAX_MAP_SIZE);
|
|
free(buf);
|
|
continue;
|
|
}
|
|
rz_io_read_at_mapped(core->io, map_addr, buf, map_size);
|
|
char *file = filename
|
|
? rz_str_dup(filename)
|
|
: rz_str_newf("0x%08" PFMT64x "-0x%08" PFMT64x "-%s.dmp",
|
|
map_addr, map_end, rz_str_rwx_i(map->perm));
|
|
if (!rz_file_dump(file, buf, map_size, 0)) {
|
|
RZ_LOG_ERROR("core: Cannot write '%s'\n", file);
|
|
ret = 0;
|
|
} else {
|
|
RZ_LOG_WARN("core: Dumped %d byte(s) into %s\n", (int)map_size, file);
|
|
}
|
|
free(file);
|
|
free(buf);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void cmd_debug_current_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
|
|
ut64 addr = core->offset;
|
|
RzDebugMap *map;
|
|
RzList *list;
|
|
RzListIter *iter;
|
|
PJ *pj = state->d.pj;
|
|
RzOutputMode mode = state->mode;
|
|
rz_cmd_state_output_array_start(state);
|
|
list = rz_debug_modules_list(core->dbg);
|
|
rz_list_foreach (list, iter, map) {
|
|
if (!(addr >= map->addr && addr < map->addr_end)) {
|
|
continue;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->addr, map->addr_end, map->file);
|
|
} else if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", map->addr);
|
|
pj_kn(pj, "addr_end", map->addr_end);
|
|
pj_ks(pj, "file", map->file);
|
|
pj_end(pj);
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_list_free(list);
|
|
}
|
|
|
|
static void cmd_debug_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
|
|
RzDebugMap *map;
|
|
RzList *list;
|
|
RzListIter *iter;
|
|
PJ *pj = state->d.pj;
|
|
RzOutputMode mode = state->mode;
|
|
rz_cmd_state_output_array_start(state);
|
|
list = rz_debug_modules_list(core->dbg);
|
|
rz_list_foreach (list, iter, map) {
|
|
if (mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->addr, map->addr_end, map->file);
|
|
} else if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
/* Escape backslashes (e.g. for Windows). */
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", map->addr);
|
|
pj_kn(pj, "addr_end", map->addr_end);
|
|
pj_ks(pj, "file", map->file);
|
|
pj_ks(pj, "name", map->name);
|
|
pj_end(pj);
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_list_free(list);
|
|
}
|
|
|
|
static RZ_OWN RzPVector /*<RzIOMap *>*/ *io_map_list(RzCore *core) { // "dmm"
|
|
RzPVector *maps = rz_io_maps(core->io);
|
|
RzPVector *ret = rz_pvector_new(NULL);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
char *lastname = NULL;
|
|
void **it;
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
continue;
|
|
}
|
|
if (!RZ_STR_EQ(lastname, file)) {
|
|
rz_pvector_push(ret, map);
|
|
free(lastname);
|
|
lastname = rz_str_dup(file);
|
|
}
|
|
}
|
|
free(lastname);
|
|
return ret;
|
|
}
|
|
|
|
static void cmd_io_current_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
|
|
ut64 addr = core->offset;
|
|
RzPVector *maps = io_map_list(core);
|
|
void **it;
|
|
PJ *pj = state->d.pj;
|
|
RzOutputMode mode = state->mode;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
ut64 map_addr = map->itv.addr;
|
|
ut64 map_end = map_addr + map->itv.size;
|
|
if (!(addr >= map_addr && addr < map_end)) {
|
|
continue;
|
|
}
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
file = map->name;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map_addr, map_end, file);
|
|
} else if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", map_addr);
|
|
pj_kn(pj, "addr_end", map_end);
|
|
pj_ks(pj, "file", file);
|
|
pj_end(pj);
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_pvector_free(maps);
|
|
}
|
|
|
|
static void cmd_io_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
|
|
RzPVector *maps;
|
|
void **it;
|
|
PJ *pj = state->d.pj;
|
|
RzOutputMode mode = state->mode;
|
|
rz_cmd_state_output_array_start(state);
|
|
|
|
maps = io_map_list(core);
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
file = map->name;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->itv.addr, map->itv.addr + map->itv.size, file);
|
|
} else if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
/* Escape backslashes (e.g. for Windows). */
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", map->itv.addr);
|
|
pj_kn(pj, "addr_end", map->itv.addr + map->itv.size);
|
|
pj_ks(pj, "name", file);
|
|
pj_end(pj);
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_pvector_free(maps);
|
|
}
|
|
|
|
static ut64 addroflib(RzCore *core, const char *libname) {
|
|
RzListIter *iter;
|
|
RzDebugMap *map;
|
|
if (!core || !libname) {
|
|
return UT64_MAX;
|
|
}
|
|
rz_debug_map_sync(core->dbg);
|
|
// RzList *list = rz_debug_native_modules_get (core->dbg);
|
|
RzList *list = rz_debug_modules_list(core->dbg);
|
|
rz_list_foreach (list, iter, map) {
|
|
if (strstr(rz_file_basename(map->name), libname)) {
|
|
return map->addr;
|
|
}
|
|
}
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (strstr(rz_file_basename(map->name), libname)) {
|
|
return map->addr;
|
|
}
|
|
}
|
|
return UT64_MAX;
|
|
}
|
|
|
|
static RzDebugMap *get_closest_map(RzCore *core, ut64 addr) {
|
|
RzListIter *iter;
|
|
RzDebugMap *map;
|
|
|
|
rz_debug_map_sync(core->dbg);
|
|
RzList *list = rz_debug_modules_list(core->dbg);
|
|
rz_list_foreach (list, iter, map) {
|
|
if (addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) {
|
|
return map;
|
|
}
|
|
}
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) {
|
|
return map;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static RzIOMap *get_io_map_from_lib_name(RzCore *core, const char *lib_name) {
|
|
if (!core || !lib_name) {
|
|
return NULL;
|
|
}
|
|
const char *basename = rz_file_basename(lib_name);
|
|
if (!basename) {
|
|
return NULL;
|
|
}
|
|
RzIOMap *result = NULL;
|
|
RzPVector *maps = io_map_list(core);
|
|
void **it;
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (file && strstr(rz_file_basename(file), basename)) {
|
|
result = map;
|
|
break;
|
|
}
|
|
}
|
|
rz_pvector_free(maps);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
// Fall back to all IO maps
|
|
maps = rz_io_maps(core->io);
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (file && strstr(rz_file_basename(file), basename)) {
|
|
return map;
|
|
}
|
|
}
|
|
RZ_LOG_ERROR("Unknown library '%s' not found\n", lib_name);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* \brief Hacky way to get the binary information of a file.
|
|
* It opens \p file into the current core->bin (backing up the previous pointer)
|
|
* and reads the information.
|
|
* Then closes it again and restores the old core-bin pointer.
|
|
*/
|
|
static bool get_bin_info(RzCore *core, const char *file, ut64 baseaddr,
|
|
RzCmdStateOutput *state, int action, RzCoreBinFilter *filter) {
|
|
int fd;
|
|
if ((fd = rz_io_fd_open(core->io, file, RZ_PERM_R, 0)) == -1) {
|
|
RZ_LOG_ERROR("Failed to open file: %s\n", file);
|
|
return false;
|
|
}
|
|
RzBinOptions opt = { 0 };
|
|
opt.obj_opts.elf_load_sections = true;
|
|
opt.obj_opts.elf_checks_sections = true;
|
|
opt.obj_opts.elf_checks_segments = true;
|
|
opt.fd = fd;
|
|
opt.sz = rz_io_fd_size(core->io, fd);
|
|
opt.obj_opts.baseaddr = baseaddr;
|
|
RzBinFile *obf = rz_bin_cur(core->bin);
|
|
RzBinFile *bf = rz_bin_open_io(core->bin, &opt);
|
|
if (!bf) {
|
|
RZ_LOG_ERROR("Failed to create RzBinFile for: %s\n", file);
|
|
rz_io_fd_close(core->io, fd);
|
|
return false;
|
|
}
|
|
rz_core_bin_print(core, bf, action, filter, state, NULL);
|
|
// rz_bin_object_new() registers bf->sdb under core->bin->sdb ("cur" and
|
|
// "fd.<fd>") and takes an extra reference. Restoring the previous binfile
|
|
// below only updates bin->cur, so drop every reference to this temporary sdb
|
|
// here, otherwise it dangles in core->bin->sdb and is double-freed on teardown.
|
|
while (sdb_ns_unset(core->bin->sdb, NULL, bf->sdb)) {
|
|
;
|
|
}
|
|
sdb_free(bf->sdb);
|
|
rz_bin_file_delete(core->bin, bf);
|
|
rz_bin_file_set_obj(obf, obf->o);
|
|
rz_bin_set_cur_binfile(core->bin, obf);
|
|
rz_io_fd_close(core->io, fd);
|
|
return true;
|
|
}
|
|
|
|
// dm
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
// dm is oml when file is a core dump
|
|
if (rz_core_is_core_dump(core)) {
|
|
return rz_open_maps_list_handler(core, argc, argv, state);
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_debug_map_sync(core->dbg); // update process memory maps
|
|
rz_core_debug_map_print(core, core->offset, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dm+
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_allocate_maps_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
RZ_LOG_ERROR("Cannot allocate maps in core dump mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
ut64 addr = core->offset;
|
|
int size = (int)rz_num_math(core->num, argv[1]);
|
|
rz_debug_map_alloc(core->dbg, addr, size, false);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmm
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
cmd_io_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
cmd_debug_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmm.
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_current_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
cmd_io_current_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
cmd_debug_current_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dm-
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_deallocate_map_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
RZ_LOG_ERROR("Cannot deallocate maps in core dump mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzListIter *iter;
|
|
RzDebugMap *map;
|
|
ut64 addr = core->offset;
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (addr >= map->addr && addr < map->addr_end) {
|
|
rz_debug_map_dealloc(core->dbg, map);
|
|
rz_debug_map_sync(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
}
|
|
RZ_LOG_ERROR("core: The address doesn't match with any map.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
// dm=
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_ascii_handler(RzCore *core, int argc, const char **argv) {
|
|
// dm= is oml= when file is a core dump
|
|
if (rz_core_is_core_dump(core)) {
|
|
return rz_open_maps_list_ascii_handler(core, argc, argv);
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_debug_map_sync(core->dbg);
|
|
rz_debug_map_list_visual(core->dbg, core->offset, argv[0] + 2,
|
|
rz_config_get_i(core->config, "scr.color"));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dm.
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_map_current_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
// dm. is oml. when file is a core dump
|
|
if (rz_core_is_core_dump(core)) {
|
|
return rz_open_maps_list_cur_handler(core, argc, argv, state);
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
ut64 addr = core->offset;
|
|
// RZ_OUTPUT_MODE_LONG is workaround for '.'
|
|
rz_cmd_state_output_init(state, RZ_OUTPUT_MODE_LONG, core);
|
|
rz_core_debug_map_print(core, addr, state);
|
|
rz_cmd_state_output_print(state);
|
|
rz_cmd_state_output_fini(state);
|
|
rz_cons_flush();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmd
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_handler(RzCore *core, int argc, const char **argv) {
|
|
|
|
if (rz_core_is_core_dump(core)) {
|
|
if (argc == 2) {
|
|
dump_io_maps(core, -1, argv[1]);
|
|
} else if (argc == 1) {
|
|
dump_io_maps(core, -1, NULL);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
if (argc == 2) {
|
|
dump_maps(core, -1, argv[1]);
|
|
} else if (argc == 1) {
|
|
dump_maps(core, -1, NULL);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmda
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_all_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
dump_io_maps(core, 0, NULL);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
dump_maps(core, 0, NULL);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmdw
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_writable_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
dump_io_maps(core, RZ_PERM_RW, NULL);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
dump_maps(core, RZ_PERM_RW, NULL);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static RzDebugMap *get_debug_map_from_lib_name(RzCore *core, const char *lib_name) {
|
|
ut64 addr = addroflib(core, rz_file_basename(lib_name));
|
|
if (addr == UT64_MAX) {
|
|
RZ_LOG_ERROR("Unknown library '%s' not found\n", lib_name);
|
|
return NULL;
|
|
}
|
|
|
|
RzDebugMap *map = get_closest_map(core, addr);
|
|
if (!map) {
|
|
RZ_LOG_ERROR("Didn't find library map at 0x%" PFMT64x "\n", addr);
|
|
return NULL;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dmi_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
|
|
if (argc == 1) {
|
|
// Effectively an alias for 'dmm'
|
|
if (rz_core_is_core_dump(core)) {
|
|
cmd_io_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
cmd_debug_modules(core, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
const char *lib_name = argc >= 2 ? argv[1] : NULL;
|
|
const char *sym_name = argc == 3 ? argv[2] : NULL;
|
|
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = sym_name };
|
|
int action = RZ_CORE_BIN_ACC_SYMBOLS;
|
|
|
|
if (rz_core_is_core_dump(core)) {
|
|
RzIOMap *map = get_io_map_from_lib_name(core, lib_name);
|
|
if (!map) {
|
|
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
file = map->name;
|
|
}
|
|
if (!get_bin_info(core, file, map->itv.addr, state, action, &filter)) {
|
|
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzDebugMap *map = get_debug_map_from_lib_name(core, lib_name);
|
|
if (!map) {
|
|
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *file = map->file ? map->file : map->name;
|
|
if (!get_bin_info(core, file, map->addr, state, action, &filter)) {
|
|
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dmi_all_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
if (argc == 1) {
|
|
// Effectively an alias for 'dmm'
|
|
if (rz_core_is_core_dump(core)) {
|
|
cmd_io_modules(core, state);
|
|
rz_cmd_state_output_print(state);
|
|
rz_cons_flush();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
cmd_debug_modules(core, state);
|
|
rz_cmd_state_output_print(state);
|
|
rz_cons_flush();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
const char *lib_name = argv[1];
|
|
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = NULL };
|
|
int action = RZ_CORE_BIN_ACC_ALL & ~RZ_CORE_BIN_ACC_INFO;
|
|
|
|
if (rz_core_is_core_dump(core)) {
|
|
RzIOMap *map = get_io_map_from_lib_name(core, lib_name);
|
|
if (!map) {
|
|
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
file = map->name;
|
|
}
|
|
if (!get_bin_info(core, file, map->itv.addr, state, action, &filter)) {
|
|
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzDebugMap *map = get_debug_map_from_lib_name(core, lib_name);
|
|
if (!map) {
|
|
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *file = map->file ? map->file : map->name;
|
|
if (!get_bin_info(core, file, map->addr, state, action, &filter)) {
|
|
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dmi_closest_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzBinObject *obj = rz_bin_cur_object(core->bin);
|
|
if (!obj) {
|
|
RZ_LOG_ERROR("No object present.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const RzPVector *symbols = rz_bin_object_get_symbols(obj);
|
|
if (!symbols) {
|
|
RZ_LOG_ERROR("Failed to get symbols from object.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 addr = core->offset;
|
|
ut64 closest_addr = UT64_MAX;
|
|
RzBinSymbol *symbol, *closest_symbol = NULL;
|
|
void **iter;
|
|
rz_pvector_foreach (symbols, iter) {
|
|
symbol = *iter;
|
|
if (symbol->vaddr > addr) {
|
|
if (symbol->vaddr - addr < closest_addr) {
|
|
closest_addr = symbol->vaddr - addr;
|
|
closest_symbol = symbol;
|
|
}
|
|
} else {
|
|
if (addr - symbol->vaddr < closest_addr) {
|
|
closest_addr = addr - symbol->vaddr;
|
|
closest_symbol = symbol;
|
|
}
|
|
}
|
|
}
|
|
if (!closest_symbol) {
|
|
RZ_LOG_ERROR("Did not found any symbol close to 0x%" PFMT64x "\n", addr);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzBinFile *bf = rz_bin_cur(core->bin);
|
|
if (!bf) {
|
|
RZ_LOG_ERROR("Failed to get current binary file.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = closest_symbol->name };
|
|
rz_core_bin_print(core, bf, RZ_CORE_BIN_ACC_SYMBOLS, &filter, state, NULL);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dmp
|
|
RZ_IPI RzCmdStatus rz_debug_memory_permission_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
RZ_LOG_ERROR("Cannot change memory permissions in core dump mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzListIter *iter;
|
|
RzDebugMap *map;
|
|
ut64 addr = 0, size = 0;
|
|
int perms;
|
|
if (argc == 3) { // dmp <size> <perms> @ <addr>
|
|
addr = core->offset;
|
|
size = rz_num_math(core->num, argv[1]);
|
|
perms = rz_str_rwx(argv[2]);
|
|
rz_debug_map_protect(core->dbg, addr, (int)size, perms);
|
|
} else if (argc == 2) { // dmp <perms>
|
|
addr = UT64_MAX;
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (core->offset >= map->addr && core->offset < map->addr_end) {
|
|
addr = map->addr;
|
|
size = map->size;
|
|
break;
|
|
}
|
|
}
|
|
perms = rz_str_rwx(argv[1]);
|
|
if (addr != UT64_MAX && perms >= 0) {
|
|
rz_debug_map_protect(core->dbg, addr, (int)size, perms);
|
|
} else {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void rz_cmd_debug_dmS_handler_printer(ut64 baddr, const char *file, const char *sectname, RzOutputMode mode) {
|
|
char *res;
|
|
char *name = rz_str_escape((char *)rz_file_basename(file));
|
|
char *filesc = rz_str_escape(file);
|
|
char *old_prefix = rz_sys_getenv("RZ_BIN_PREFIX");
|
|
rz_sys_setenv("RZ_BIN_PREFIX", name);
|
|
|
|
const char *json_flag = (mode == RZ_OUTPUT_MODE_JSON) ? " -j" : "";
|
|
|
|
if (sectname && mode != RZ_OUTPUT_MODE_JSON) {
|
|
char *sect = rz_str_escape(sectname);
|
|
res = rz_sys_cmd_strf("rz-bin%s -B 0x%08" PFMT64x " -S \"%s\" | grep \"%s\"", json_flag, baddr, filesc, sect);
|
|
free(sect);
|
|
} else {
|
|
res = rz_sys_cmd_strf("rz-bin%s -B 0x%08" PFMT64x " -S \"%s\"", json_flag, baddr, filesc);
|
|
}
|
|
if (res) {
|
|
rz_str_remove_char(res, '\r');
|
|
}
|
|
rz_sys_setenv("RZ_BIN_PREFIX", old_prefix);
|
|
free(old_prefix);
|
|
free(filesc);
|
|
if (res) {
|
|
rz_cons_println(res);
|
|
}
|
|
free(name);
|
|
free(res);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dmS_handler(RzCore *core, int argc, const char **argv, RzOutputMode m) {
|
|
ut64 addr;
|
|
const char *libname = NULL, *sectname = NULL;
|
|
ut64 baddr = 0LL;
|
|
addr = UT64_MAX;
|
|
if (argc == 3) {
|
|
sectname = argv[2];
|
|
}
|
|
if (argc >= 2) {
|
|
if (IS_DIGIT(*argv[1])) {
|
|
const char *a0 = argv[1];
|
|
addr = rz_num_math(core->num, a0);
|
|
} else {
|
|
addr = UT64_MAX;
|
|
}
|
|
if (!addr || addr == UT64_MAX) {
|
|
libname = argv[1];
|
|
}
|
|
}
|
|
|
|
if (rz_core_is_core_dump(core)) {
|
|
RzPVector *maps = io_map_list(core);
|
|
void **it;
|
|
rz_pvector_foreach (maps, it) {
|
|
RzIOMap *map = *it;
|
|
ut64 map_addr = map->itv.addr;
|
|
ut64 map_end = map_addr + map->itv.size;
|
|
if ((!libname ||
|
|
(addr != UT64_MAX && (addr >= map_addr && addr < map_end)) ||
|
|
(libname != NULL && (strstr(map->name, libname))))) {
|
|
baddr = map_addr;
|
|
const char *file = rz_core_io_map_file_path_or_relative(map);
|
|
if (!file) {
|
|
file = map->name;
|
|
}
|
|
rz_cmd_debug_dmS_handler_printer(baddr, file, sectname, m);
|
|
if (libname || addr != UT64_MAX) { // only single match requested
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
rz_pvector_free(maps);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzDebugMap *map;
|
|
RzListIter *iter;
|
|
rz_debug_map_sync(core->dbg); // update process memory maps
|
|
RzList *list = rz_debug_modules_list(core->dbg);
|
|
rz_list_foreach (list, iter, map) {
|
|
if ((!libname ||
|
|
(addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) ||
|
|
(libname != NULL && (strstr(map->name, libname))))) {
|
|
baddr = map->addr;
|
|
const char *file = map->file ? map->file : map->name;
|
|
rz_cmd_debug_dmS_handler_printer(baddr, file, sectname, m);
|
|
if (libname || addr != UT64_MAX) { // only single match requested
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dml
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dml_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
RZ_LOG_ERROR("Cannot load into memory in core dump mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzListIter *iter;
|
|
RzDebugMap *map;
|
|
ut64 addr = core->offset;
|
|
rz_debug_map_sync(core->dbg); // update process memory maps
|
|
rz_list_foreach (core->dbg->maps, iter, map) {
|
|
if (addr >= map->addr && addr < map->addr_end) {
|
|
size_t sz;
|
|
char *buf = rz_file_slurp(argv[1], &sz);
|
|
// TODO: use mmap here. we need a portable implementation
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " byte(s)\n", map->size);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_write_at(core->io, map->addr, (const ut8 *)buf, sz);
|
|
if (sz != map->size) {
|
|
RZ_LOG_WARN("core: File size differs from region size (%" PFMT64u " vs %" PFMT64d ")\n",
|
|
(ut64)sz, map->size);
|
|
}
|
|
rz_cons_printf("Loaded %" PFMT64u " byte(s) into the map region at 0x%08" PFMT64x "\n",
|
|
(ut64)sz, map->addr);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
}
|
|
RZ_LOG_ERROR("core: No debug region found here\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
// dmL
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_dmL_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_core_is_core_dump(core)) {
|
|
RZ_LOG_ERROR("Cannot allocate maps in core dump mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
int size;
|
|
ut64 addr;
|
|
addr = core->offset;
|
|
size = (int)rz_num_math(core->num, argv[1]);
|
|
rz_debug_map_alloc(core->dbg, addr, size, true);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// "dmhja"
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_a_handler(RzCore *core, int argc, const char **argv) {
|
|
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
|
|
|
|
if (has_specified_arena) {
|
|
if (!rz_num_is_valid_input(core->num, argv[1])) {
|
|
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 arena_addr = rz_num_math(core->num, argv[1]);
|
|
return rz_heap_jemalloc_cmd_a(core, has_specified_arena, arena_addr);
|
|
}
|
|
|
|
if (!rz_core_is_core_dump(core)) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
}
|
|
return rz_heap_jemalloc_cmd_a(core, has_specified_arena, 0);
|
|
}
|
|
|
|
// "dmhjb"
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_b_handler(RzCore *core, int argc, const char **argv) {
|
|
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
|
|
bool has_bin_info = argc > 2 && RZ_STR_ISNOTEMPTY(argv[2]);
|
|
|
|
if (has_specified_arena) {
|
|
ut64 arena_addr = 0;
|
|
ut64 bin_info_addr = 0;
|
|
if (!has_bin_info) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_num_is_valid_input(core->num, argv[1])) {
|
|
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_num_is_valid_input(core->num, argv[2])) {
|
|
RZ_LOG_ERROR("Invalid bin info address '%s'\n", argv[2]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
arena_addr = rz_num_math(core->num, argv[1]);
|
|
bin_info_addr = rz_num_math(core->num, argv[2]);
|
|
|
|
return rz_heap_jemalloc_cmd_b(core, has_specified_arena, arena_addr, has_bin_info, bin_info_addr);
|
|
}
|
|
|
|
if (!rz_core_is_core_dump(core)) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
}
|
|
|
|
return rz_heap_jemalloc_cmd_b(core, has_specified_arena, 0, has_bin_info, 0);
|
|
}
|
|
|
|
// "dmhjc"
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_c_handler(RzCore *core, int argc, const char **argv) {
|
|
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
|
|
|
|
if (has_specified_arena) {
|
|
if (!rz_num_is_valid_input(core->num, argv[1])) {
|
|
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 arena_addr = rz_num_math(core->num, argv[1]);
|
|
return rz_heap_jemalloc_cmd_c(core, has_specified_arena, arena_addr);
|
|
}
|
|
|
|
if (!rz_core_is_core_dump(core)) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
}
|
|
return rz_heap_jemalloc_cmd_c(core, has_specified_arena, 0);
|
|
}
|
|
|
|
// "dmhje" - Find extent for malloc address
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_e_handler(RzCore *core, int argc, const char **argv) {
|
|
bool has_addr = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
|
|
|
|
if (has_addr) {
|
|
if (!rz_num_is_valid_input(core->num, argv[1])) {
|
|
RZ_LOG_ERROR("Invalid address '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 lookup_addr = rz_num_math(core->num, argv[1]);
|
|
return rz_heap_jemalloc_cmd_e(core, has_addr, lookup_addr);
|
|
}
|
|
|
|
if (!rz_core_is_core_dump(core)) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
}
|
|
return rz_heap_jemalloc_cmd_e(core, has_addr, 0);
|
|
}
|
|
|
|
// "dmhjei" - Display extent info
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_ei_handler(RzCore *core, int argc, const char **argv) {
|
|
bool has_addr = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
|
|
ut64 extent_addr = 0;
|
|
|
|
if (!has_addr) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_num_is_valid_input(core->num, argv[1])) {
|
|
RZ_LOG_ERROR("Invalid extent address '%s'\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
extent_addr = rz_num_math(core->num, argv[1]);
|
|
|
|
return rz_heap_jemalloc_cmd_ei(core, has_addr, extent_addr);
|
|
}
|
|
|
|
static void backtrace_vars(RzCore *core, RzList /*<RzDebugFrame *>*/ *frames) {
|
|
RzDebugFrame *f;
|
|
RzListIter *iter;
|
|
// analysis vs debug ?
|
|
RzReg *r = rz_analysis_get_reg(core->analysis);
|
|
const char *sp = rz_reg_get_name(r, RZ_REG_NAME_SP);
|
|
const char *bp = rz_reg_get_name(r, RZ_REG_NAME_BP);
|
|
if (!sp) {
|
|
sp = "SP";
|
|
}
|
|
if (!bp) {
|
|
bp = "BP";
|
|
}
|
|
ut64 dsp = rz_reg_getv(r, sp);
|
|
ut64 dbp = rz_reg_getv(r, bp);
|
|
int n = 0;
|
|
rz_list_foreach (frames, iter, f) {
|
|
ut64 s = f->sp ? f->sp : dsp;
|
|
ut64 b = f->bp ? f->bp : dbp;
|
|
rz_reg_setv(r, bp, s);
|
|
rz_reg_setv(r, sp, b);
|
|
//////////
|
|
char *flagdesc = rz_core_addr_get_flag_offset(core->flags, f->addr);
|
|
//////////
|
|
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, f->addr, 0);
|
|
// char *str = rz_str_newf ("[frame %d]", n);
|
|
rz_cons_printf("%d 0x%08" PFMT64x " sp: 0x%08" PFMT64x " %-5d"
|
|
"[%s] %s\n",
|
|
n, f->addr, f->sp, (int)f->size,
|
|
fcn ? fcn->name : "??", flagdesc ? flagdesc : "");
|
|
free(flagdesc);
|
|
rz_cons_push();
|
|
char *res = rz_core_analysis_all_vars_display(core, fcn, true);
|
|
rz_cons_pop();
|
|
rz_cons_printf("%s", res);
|
|
free(res);
|
|
n++;
|
|
}
|
|
rz_reg_setv(r, bp, dbp);
|
|
rz_reg_setv(r, sp, dsp);
|
|
}
|
|
|
|
static void asciiart_backtrace(RzCore *core, RzList /*<RzDebugFrame *>*/ *frames) {
|
|
// TODO: show local variables
|
|
// TODO: show function/flags/symbols related
|
|
// TODO: show contents of stack
|
|
// TODO: honor scr.color
|
|
RzDebugFrame *f;
|
|
RzListIter *iter;
|
|
bool mymap = false;
|
|
// analysis vs debug ?
|
|
RzReg *rreg = rz_analysis_get_reg(core->analysis);
|
|
const char *sp = rz_reg_get_name(rreg, RZ_REG_NAME_SP);
|
|
const char *bp = rz_reg_get_name(rreg, RZ_REG_NAME_BP);
|
|
if (!sp) {
|
|
sp = "SP";
|
|
}
|
|
if (!bp) {
|
|
bp = "BP";
|
|
}
|
|
ut64 dsp = rz_reg_getv(rreg, sp);
|
|
ut64 dbp = rz_reg_getv(rreg, bp);
|
|
RzDebugMap *map = rz_debug_map_get(core->dbg, dsp);
|
|
if (!map) {
|
|
mymap = true;
|
|
map = RZ_NEW0(RzDebugMap);
|
|
map->addr = UT64_MAX;
|
|
map->addr_end = UT64_MAX;
|
|
}
|
|
|
|
rz_cons_printf("0x%016" PFMT64x " STACK END ^^^\n", map->addr);
|
|
rz_cons_printf("0x%016" PFMT64x " STACK POINTER: %s\n", dsp, sp);
|
|
rz_cons_printf(" .------------------------.\n");
|
|
int n = 0;
|
|
rz_list_foreach (frames, iter, f) {
|
|
ut64 s = f->sp ? f->sp : dsp;
|
|
ut64 b = f->bp ? f->bp : dbp;
|
|
char *str = rz_str_newf("[frame %d]", n);
|
|
rz_cons_printf("0x%016" PFMT64x " |%4s %10s | ; size %" PFMTDPTR "\n", s, sp, str, (ptrdiff_t)(s - b));
|
|
free(str);
|
|
rz_cons_printf(" | ... |\n");
|
|
rz_cons_printf("0x%016" PFMT64x " |%4s 0x%016" PFMT64x " | %s\n", b, bp, f->addr, "; return address");
|
|
rz_cons_printf(" )------------------------(\n");
|
|
// eprintf ("0x%08" PFMT64x " 0x%08" PFMT64x " 0x%08" PFMT64x "\n", f->addr, s, b);
|
|
n++;
|
|
}
|
|
rz_cons_printf(" | ... |\n");
|
|
rz_cons_printf(" `------------------------'\n");
|
|
rz_cons_printf("0x%016" PFMT64x " STACK BOTTOM\n", map->addr_end);
|
|
if (mymap) {
|
|
rz_debug_map_free(map);
|
|
}
|
|
}
|
|
|
|
RZ_IPI void rz_core_static_debug_stop(void *u) {
|
|
RzDebug *dbg = (RzDebug *)u;
|
|
rz_debug_stop(dbg);
|
|
}
|
|
|
|
#if __WINDOWS__
|
|
#include "..\debug\p\native\windows\windows_message.h"
|
|
#endif
|
|
|
|
RZ_IPI void rz_core_debug_bp_add(RzCore *core, ut64 addr, const char *arg_perm, const char *arg_size, bool hwbp, bool watch) {
|
|
RzBreakpointItem *bpi;
|
|
int rw = 0;
|
|
ut64 size = 0;
|
|
|
|
if (watch) {
|
|
rw = rz_str_rwx(arg_perm);
|
|
rw &= RZ_PERM_RWX; // filter out the rwx bits only
|
|
if (rw == 0) {
|
|
RZ_LOG_WARN("Invalid permissions provided for setting watchpoint. Defaulting to \"rw\".\n");
|
|
rw = RZ_PERM_RW;
|
|
}
|
|
}
|
|
if (arg_size) {
|
|
size = rz_num_math(core->num, arg_size);
|
|
}
|
|
bpi = rz_debug_bp_add(core->dbg, addr, size, hwbp, watch, rw, NULL, 0);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Cannot set breakpoint at 0x%" PFMT64x "\n", addr);
|
|
return;
|
|
}
|
|
RzFlagItem *f = rz_core_flag_get_by_spaces(core->flags, addr);
|
|
if (f) {
|
|
if (addr > f->offset) {
|
|
char *name = rz_str_newf("%s+0x%" PFMT64x, f->name, addr - f->offset);
|
|
rz_bp_item_set_name(bpi, name);
|
|
free(name);
|
|
} else {
|
|
rz_bp_item_set_name(bpi, f->name);
|
|
}
|
|
} else {
|
|
char *name = rz_str_newf("0x%08" PFMT64x, addr);
|
|
rz_bp_item_set_name(bpi, name);
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
static RTreeNode *add_trace_tree_child(HtUP *ht, RTree *t, RTreeNode *cur, ut64 addr) {
|
|
struct trace_node *t_node = ht_up_find(ht, addr, NULL);
|
|
if (!t_node) {
|
|
t_node = RZ_NEW0(struct trace_node);
|
|
if (t_node) {
|
|
t_node->addr = addr;
|
|
t_node->refs = 1;
|
|
ht_up_insert(ht, addr, t_node);
|
|
}
|
|
} else {
|
|
t_node->refs++;
|
|
}
|
|
return rz_tree_add_node(t, cur, t_node);
|
|
}
|
|
|
|
static RzCore *_core = NULL;
|
|
|
|
static void trace_traverse_pre(RTreeNode *n, RTreeVisitor *vis) {
|
|
struct trace_node *tn = n->data;
|
|
unsigned int i;
|
|
if (!tn)
|
|
return;
|
|
for (i = 0; i < n->depth - 1; i++) {
|
|
rz_cons_printf(" ");
|
|
}
|
|
char *name = NULL;
|
|
if (_core) {
|
|
name = rz_core_addr_get_flag_offset(_core->flags, tn->addr);
|
|
}
|
|
rz_cons_printf(" 0x%08" PFMT64x " refs %d %s\n", tn->addr, tn->refs, name ? name : "");
|
|
free(name);
|
|
}
|
|
|
|
static void trace_traverse(RTree *t) {
|
|
RTreeVisitor vis = { 0 };
|
|
|
|
/* clear the line on stderr, because somebody has written there */
|
|
fprintf(stderr, "\x1b[2K\r");
|
|
fflush(stderr);
|
|
vis.pre_visit = (RTreeNodeVisitCb)trace_traverse_pre;
|
|
rz_tree_dfs(t, &vis);
|
|
}
|
|
|
|
static void do_debug_trace_calls(RzCore *core, ut64 from, ut64 to, ut64 final_addr) {
|
|
bool shallow_trace = rz_config_get_b(core->config, "dbg.trace.inrange");
|
|
HtUP *tracenodes = core->dbg->tracenodes;
|
|
RTree *tr = core->dbg->tree;
|
|
RzDebug *dbg = core->dbg;
|
|
ut64 debug_to = UT64_MAX;
|
|
RTreeNode *cur;
|
|
ut64 addr = 0;
|
|
int n = 0;
|
|
|
|
/* set root if not already present */
|
|
rz_tree_add_node(tr, NULL, NULL);
|
|
cur = tr->root;
|
|
|
|
while (true) {
|
|
ut8 buf[32];
|
|
RzAnalysisOp aop = { 0 };
|
|
int addr_in_range;
|
|
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
if (rz_debug_is_dead(dbg)) {
|
|
break;
|
|
}
|
|
if (debug_to != UT64_MAX && !rz_debug_continue_until(dbg, debug_to)) {
|
|
break;
|
|
}
|
|
if (!rz_debug_step(dbg, 1)) {
|
|
break;
|
|
}
|
|
debug_to = UT64_MAX;
|
|
if (!rz_debug_reg_sync(dbg, RZ_REG_TYPE_GPR, false)) {
|
|
break;
|
|
}
|
|
addr = rz_debug_reg_get(dbg, "PC");
|
|
if (addr == final_addr) {
|
|
// we finished the tracing so break the loop
|
|
break;
|
|
}
|
|
addr_in_range = addr >= from && addr < to;
|
|
|
|
rz_io_read_at_mapped(core->io, addr, buf, sizeof(buf));
|
|
rz_analysis_op_init(&aop);
|
|
rz_analysis_op(core->analysis, &aop, addr, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_BASIC);
|
|
eprintf("%d %" PFMT64x "\r", n++, addr);
|
|
switch (aop.type) {
|
|
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_ICALL:
|
|
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_IRCALL: {
|
|
ut64 called_addr;
|
|
int called_in_range;
|
|
// store regs
|
|
// step into
|
|
// get pc
|
|
rz_debug_step(dbg, 1);
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_GPR, false);
|
|
called_addr = rz_debug_reg_get(dbg, "PC");
|
|
called_in_range = called_addr >= from && called_addr < to;
|
|
if (!called_in_range && addr_in_range && !shallow_trace) {
|
|
debug_to = addr + aop.size;
|
|
}
|
|
if (addr_in_range || shallow_trace) {
|
|
cur = add_trace_tree_child(tracenodes, tr, cur, addr);
|
|
if (debug_to != UT64_MAX) {
|
|
cur = cur->parent;
|
|
}
|
|
}
|
|
// TODO: push pc+aop.length into the call path stack
|
|
break;
|
|
}
|
|
case RZ_ANALYSIS_OP_TYPE_CALL: {
|
|
int called_in_range = aop.jump >= from && aop.jump < to;
|
|
if (!called_in_range && addr_in_range && !shallow_trace) {
|
|
debug_to = aop.addr + aop.size;
|
|
}
|
|
if (addr_in_range || shallow_trace) {
|
|
cur = add_trace_tree_child(tracenodes, tr, cur, addr);
|
|
if (debug_to != UT64_MAX) {
|
|
cur = cur->parent;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case RZ_ANALYSIS_OP_TYPE_RET:
|
|
if (cur != tr->root) {
|
|
cur = cur->parent;
|
|
}
|
|
break;
|
|
}
|
|
rz_analysis_op_fini(&aop);
|
|
}
|
|
}
|
|
|
|
static void debug_trace_calls(RzCore *core, ut64 from, ut64 to, ut64 final_addr) {
|
|
RzBreakpointItem *bp_final = NULL;
|
|
int t = core->dbg->trace->enabled;
|
|
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
RZ_LOG_ERROR("core: No process to debug.\n");
|
|
return;
|
|
}
|
|
core->dbg->trace->enabled = 0;
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
if (final_addr != UT64_MAX) {
|
|
bool hwbp = rz_config_get_b(core->config, "dbg.hwbp");
|
|
bp_final = rz_debug_bp_add(core->dbg, final_addr, 0, hwbp, false, 0, NULL, 0);
|
|
if (!bp_final) {
|
|
RZ_LOG_ERROR("core: Cannot set breakpoint at final address (%" PFMT64x ")\n", final_addr);
|
|
}
|
|
}
|
|
do_debug_trace_calls(core, from, to, final_addr);
|
|
if (bp_final) {
|
|
rz_bp_del(core->dbg->bp, final_addr);
|
|
}
|
|
_core = core;
|
|
trace_traverse(core->dbg->tree);
|
|
core->dbg->trace->enabled = t;
|
|
rz_cons_break_pop();
|
|
}
|
|
|
|
// dsu
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
step_until(core, rz_num_math(core->num, argv[1]));
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsui
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_instr_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!step_until_inst(core, argv[1], false)) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsuir
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_instr_regex_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!step_until_inst(core, argv[1], true)) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsuo
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_optype_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *optypes_list = rz_list_new_from_array((const void **)argv + 1, argc - 1);
|
|
step_until_optype(core, optypes_list);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
rz_list_free(optypes_list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsue
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_esil_handler(RzCore *core, int argc, const char **argv) {
|
|
step_until_esil(core, argv[1]);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsuf
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_until_flag_handler(RzCore *core, int argc, const char **argv) {
|
|
step_until_flag(core, argv[1]);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dt
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_handler(RzCore *core, int argc, const char **argv) {
|
|
RzDebugTracepoint *t = rz_debug_trace_get(core->dbg, core->offset);
|
|
if (!t) {
|
|
RZ_LOG_ERROR("Cannot find any debug trace at address %" PFMT64x ".\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_cons_printf("offset = 0x%" PFMT64x "\n", t->addr);
|
|
rz_cons_printf("opsize = %d\n", t->size);
|
|
rz_cons_printf("times = %d\n", t->times);
|
|
rz_cons_printf("count = %d\n", t->count);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtl
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_traces_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_debug_trace_print(core->dbg, state, core->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtl=
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_traces_ascii_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_debug_traces_ascii(core->dbg, core->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dt+
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_add_handler(RzCore *core, int argc, const char **argv) {
|
|
int count = argc > 1 ? rz_num_math(core->num, argv[1]) : 1;
|
|
RzAnalysisOp *op = rz_core_op_analysis(core, core->offset, RZ_ANALYSIS_OP_MASK_HINT);
|
|
if (!op) {
|
|
RZ_LOG_ERROR("Cannot analyze opcode at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RzDebugTracepoint *tp = rz_debug_trace_add(core->dbg, core->offset, op->size);
|
|
if (!tp) {
|
|
rz_analysis_op_free(op);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
tp->count = count;
|
|
rz_analysis_op_free(op);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dt++
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_add_addrs_handler(RzCore *core, int argc, const char **argv) {
|
|
for (int i = 1; i < argc; ++i) {
|
|
ut64 addr = rz_num_get(NULL, argv[i]);
|
|
RzDebugTracepoint *t = rz_debug_trace_add(core->dbg, addr, 1);
|
|
if (!t) {
|
|
RZ_LOG_ERROR("Cannot add trace at address %" PFMT64x ".\n", addr);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dt-
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_traces_reset_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_tree_reset(core->dbg->tree);
|
|
rz_debug_trace_free(core->dbg->trace);
|
|
rz_debug_tracenodes_reset(core->dbg);
|
|
core->dbg->trace = rz_debug_trace_new();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtc
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_calls_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 from = argc > 1 ? rz_num_math(core->num, argv[1]) : 0;
|
|
ut64 to = argc > 2 ? rz_num_math(core->num, argv[2]) : UT64_MAX;
|
|
ut64 addr = argc > 3 ? rz_num_math(core->num, argv[3]) : UT64_MAX;
|
|
|
|
debug_trace_calls(core, from, to, addr);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dte
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_esil_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_analysis_esil_init(core);
|
|
int idx = rz_num_math(core->num, argv[1]);
|
|
RzAnalysisEsil *esil = rz_analysis_get_esil(core->analysis);
|
|
rz_analysis_esil_trace_show(esil, idx);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtel
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_esils_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_analysis_esil_init(core);
|
|
RzAnalysisEsil *esil = rz_analysis_get_esil(core->analysis);
|
|
rz_analysis_esil_trace_list(esil);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dte-*
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_traces_esil_delete_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_analysis_esil_init(core);
|
|
RzAnalysisEsil *esil = rz_analysis_get_esil(core->analysis);
|
|
if (esil) {
|
|
rz_pvector_free(esil->trace->instructions);
|
|
esil->trace->instructions = rz_pvector_new((RzPVectorFree)rz_analysis_il_trace_instruction_free);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtei
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_traces_esil_i_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_analysis_esil_init(core);
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, core->offset, RZ_ANALYSIS_OP_MASK_ESIL);
|
|
if (!op) {
|
|
RZ_LOG_ERROR("Cannot analyze opcode at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzAnalysisEsil *esil = rz_analysis_get_esil(core->analysis);
|
|
const char *eexpr = rz_strbuf_get(&op->esil);
|
|
rz_analysis_esil_trace_op(esil, op->addr, eexpr);
|
|
rz_analysis_op_free(op);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtg
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_graph_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
dot_trace_traverse(core, core->dbg->tree, rz_output_mode_to_char(mode));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtgi
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_interactive_handler(RzCore *core, int argc, const char **argv) {
|
|
dot_trace_traverse(core, core->dbg->tree, 'i');
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dts+
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_start_trace_session_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
RZ_LOG_ERROR("Cannot start session outside of debug mode, run ood?\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (core->dbg->session) {
|
|
RZ_LOG_ERROR("Session already started\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
core->dbg->session = rz_debug_session_new();
|
|
rz_debug_add_checkpoint(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dts-
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_stop_trace_session_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!core->dbg->session) {
|
|
RZ_LOG_ERROR("No session started\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_debug_session_free(core->dbg->session);
|
|
core->dbg->session = NULL;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtst
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_save_trace_session_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!core->dbg->session) {
|
|
RZ_LOG_ERROR("No session started\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_debug_session_save(core->dbg->session, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtsf
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_load_trace_session_handler(RzCore *core, int argc, const char **argv) {
|
|
if (core->dbg->session) {
|
|
rz_debug_session_free(core->dbg->session);
|
|
core->dbg->session = NULL;
|
|
}
|
|
core->dbg->session = rz_debug_session_new();
|
|
rz_debug_session_load(core->dbg, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtsm
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_list_trace_session_mmap_handler(RzCore *core, int argc, const char **argv) {
|
|
if (core->dbg->session) {
|
|
rz_debug_session_list_memory(core->dbg);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dtt
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_trace_tag_handler(RzCore *core, int argc, const char **argv) {
|
|
int tag = rz_num_math(core->num, argv[1]);
|
|
rz_debug_trace_tag(core->dbg, tag);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void consumeBuffer(RzBuffer *buf, const char *cmd, const char *errmsg) {
|
|
if (!buf) {
|
|
if (errmsg) {
|
|
rz_cons_printf("%s\n", errmsg);
|
|
}
|
|
return;
|
|
}
|
|
if (cmd) {
|
|
rz_cons_printf("%s", cmd);
|
|
}
|
|
int i;
|
|
rz_buf_seek(buf, 0, RZ_BUF_SET);
|
|
for (i = 0; i < rz_buf_size(buf); i++) {
|
|
ut8 tmp;
|
|
if (!rz_buf_read8(buf, &tmp)) {
|
|
return;
|
|
}
|
|
rz_cons_printf("%02x", tmp);
|
|
}
|
|
rz_cons_printf("\n");
|
|
}
|
|
|
|
// db
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
bool hwbp = rz_config_get_b(core->config, "dbg.hwbp");
|
|
rz_core_debug_bp_add(core, core->offset, NULL, NULL, hwbp, false);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbl
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_list_bp_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_return_val_if_fail(state && core->dbg && core->dbg->bp, RZ_CMD_STATUS_ERROR);
|
|
RzBreakpointItem *b;
|
|
RzListIter *iter;
|
|
PJ *pj = state->d.pj;
|
|
RzTable *t = state->d.t;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cmd_state_output_set_columnsf(state, "XXdsssssssss", "start", "end", "size",
|
|
"perm", "hwsw", "type", "state", "valid", "cmd", "cond", "name", "module");
|
|
|
|
rz_list_foreach (core->dbg->bp->bps, iter, b) {
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("0x%08" PFMT64x " - 0x%08" PFMT64x
|
|
" %d %s %s %s %s %s cmd=\"%s\" cond=\"%s\" "
|
|
"name=\"%s\" module=\"%s\"\n",
|
|
b->addr, b->addr + b->size, b->size,
|
|
rz_str_rwx_i(b->perm),
|
|
b->hw ? "hw" : "sw",
|
|
b->trace ? "trace" : "break",
|
|
b->enabled ? "enabled" : "disabled",
|
|
rz_bp_is_valid(core->dbg->bp, b) ? "valid" : "invalid",
|
|
rz_str_get(b->data),
|
|
rz_str_get(b->cond),
|
|
rz_str_get(b->name),
|
|
rz_str_get(b->module_name));
|
|
break;
|
|
case RZ_OUTPUT_MODE_TABLE:
|
|
rz_table_add_rowf(t, "XXdsssssssss", b->addr, b->addr + b->size, b->size,
|
|
rz_str_rwx_i(b->perm), b->hw ? "hw" : "sw", b->trace ? "trace" : "break",
|
|
b->enabled ? "enabled" : "disabled", rz_bp_is_valid(core->dbg->bp, b) ? "valid" : "invalid",
|
|
rz_str_get(b->data), rz_str_get(b->cond), rz_str_get(b->name), rz_str_get(b->module_name));
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(pj);
|
|
pj_kN(pj, "addr", b->addr);
|
|
pj_ki(pj, "size", b->size);
|
|
pj_ks(pj, "perm", rz_str_rwx_i(b->perm));
|
|
pj_kb(pj, "hw", b->hw);
|
|
pj_kb(pj, "trace", b->trace);
|
|
pj_kb(pj, "enabled", b->enabled);
|
|
pj_kb(pj, "valid", rz_bp_is_valid(core->dbg->bp, b));
|
|
pj_ks(pj, "data", rz_str_get(b->data));
|
|
pj_ks(pj, "cond", rz_str_get(b->cond));
|
|
pj_end(pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_cons_printf("0x%08" PFMT64x "\n", b->addr);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbH
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_hw_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_debug_bp_add(core, core->offset, NULL, NULL, true, false);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// db-
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_remove_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_del(core->dbg->bp, core->offset)) {
|
|
RZ_LOG_ERROR("Failed to delete breakpoint at 0x%" PFMT64x "\n", core->offset);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// db-*
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_remove_all_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_del_all(core->dbg->bp)) {
|
|
RZ_LOG_ERROR("Failed to delete all breakpoints\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// db.
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_show_cur_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *cur = rz_bp_get_at(core->dbg->bp, core->offset);
|
|
if (!cur) {
|
|
rz_cons_printf("No breakpoint found at current offset (0x%" PFMT64x ")\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("breakpoint %s %s %s\n", rz_str_rwx_i(cur->perm), cur->enabled ? "enabled" : "disabled", cur->name ? cur->name : "");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbc
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_command_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bp = rz_bp_get_at(core->dbg->bp, core->offset);
|
|
if (!bp) {
|
|
RZ_LOG_ERROR("No breakpoint defined at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_bp_item_set_data(bp, argv[1])) {
|
|
RZ_LOG_ERROR("Failed to set data for breakpoint at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbC
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_cond_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bp = rz_bp_get_at(core->dbg->bp, core->offset);
|
|
if (!bp) {
|
|
RZ_LOG_ERROR("No breakpoint defined at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_bp_item_set_cond(bp, argv[1])) {
|
|
RZ_LOG_ERROR("Failed to set condition for breakpoint at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbd
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_disable_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_enable(core->dbg->bp, core->offset, false, 1)) {
|
|
RZ_LOG_ERROR("Failed to disable breakpoint at 0x%" PFMT64x "\n", core->offset);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbe
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_enable_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_enable(core->dbg->bp, core->offset, true, 1)) { // correct value of count?
|
|
RZ_LOG_ERROR("Failed to enable breakpoint at 0x%" PFMT64x "\n", core->offset);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbs
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_toggle_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_debug_breakpoint_toggle(core, core->offset);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbf
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_bp_noreturn_func_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_debug_bp_add_noreturn_func(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbm
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_bp_module_handler(RzCore *core, int argc, const char **argv) {
|
|
bool hwbp = rz_config_get_b(core->config, "dbg.hwbp");
|
|
ut64 delta = rz_num_math(core->num, argv[2]);
|
|
RzBreakpointItem *bp = rz_debug_bp_add(core->dbg, 0, 0, hwbp, false, 0, argv[1], delta);
|
|
if (!bp) {
|
|
RZ_LOG_ERROR("Cannot set breakpoint.\n");
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbn
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_name_bp_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bp = rz_bp_get_at(core->dbg->bp, core->offset);
|
|
if (!bp) {
|
|
RZ_LOG_ERROR("No breakpoint found at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
} else if (argc == 1) {
|
|
if (bp->name) {
|
|
rz_cons_println(bp->name);
|
|
}
|
|
} else if (argc == 2) {
|
|
rz_bp_item_set_name(bp, argv[1]);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbi
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_show_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
const int index = rz_bp_get_index_at(core->dbg->bp, core->offset);
|
|
if (index == -1) {
|
|
RZ_LOG_ERROR("No breakpoint found at %" PFMT64x "\n", core->offset);
|
|
} else {
|
|
rz_cons_printf("%d\n", index);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbil
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_list_bp_indexes_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
RzListIter *iter;
|
|
unsigned int index = 0;
|
|
rz_list_foreach (core->dbg->bp->bps, iter, bpi) {
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint at index %d\n", index);
|
|
} else {
|
|
rz_cons_printf("%d 0x%08" PFMT64x " E:%d T:%d\n", index, bpi->addr, bpi->enabled, bpi->trace);
|
|
}
|
|
index++;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbi-
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_remove_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 addr;
|
|
for (int i = 1; i < argc; i++) {
|
|
addr = rz_num_math(core->num, argv[i]);
|
|
if (!rz_bp_del_index(core->dbg->bp, addr)) {
|
|
RZ_LOG_ERROR("No breakpoint found at %" PFMT64x "\n", addr);
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbix
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_set_expr_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
RzBreakpointItem *bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
rz_bp_item_set_expr(bpi, argv[2]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbic
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_run_command_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
RzBreakpointItem *bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
rz_bp_item_set_data(bpi, argv[2]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbie
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_enable_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->enabled = true;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbid
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_disable_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->enabled = false;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbis
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_toggle_bp_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->enabled = !bpi->enabled;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbite
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_enable_bp_trace_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->trace = true;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbitd
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_disable_bp_trace_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->trace = false;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbits
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_toggle_bp_trace_index_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi;
|
|
int index = rz_num_math(core->num, argv[1]);
|
|
bpi = rz_bp_get_index(core->dbg->bp, index);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("Unable to find breakpoint with index %d\n", index);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bpi->trace = !bpi->enabled;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbh
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_bp_plugin_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_return_val_if_fail(core, RZ_CMD_STATUS_ERROR);
|
|
RzIterator *iter = rz_asm_plugin_iterator(core->rasm);
|
|
RzList *plugin_list = rz_list_new_from_iterator(iter);
|
|
if (!plugin_list) {
|
|
rz_iterator_free(iter);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_list_sort(plugin_list, (RzListComparator)rz_asm_plugin_cmp, NULL);
|
|
RzListIter *it;
|
|
const RzAsmPlugin *ap;
|
|
|
|
rz_list_foreach (plugin_list, it, ap) {
|
|
if (!ap->sw_breakpoint) {
|
|
continue;
|
|
}
|
|
rz_cons_printf("%s\n", ap->name);
|
|
}
|
|
|
|
rz_list_free(plugin_list);
|
|
rz_iterator_free(iter);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbt
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_display_bt_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzList *list = rz_core_debug_backtraces(core);
|
|
if (!list) {
|
|
RZ_LOG_ERROR("Unable to find debug backtrace frames\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzOutputMode mode = state->mode;
|
|
|
|
int i = 0;
|
|
RzListIter *iter;
|
|
RzBacktrace *bt;
|
|
PJ *pj = state->d.pj;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cmd_state_output_set_columnsf(state, "dxxdss", "idx", "pc", "sp", "frame_size", "fname", "desc");
|
|
rz_list_foreach (list, iter, bt) {
|
|
switch (mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD: {
|
|
rz_cons_printf("%d %s sp: %s %-5d"
|
|
"[%s]%s%s%s%s\n",
|
|
i++, bt->pcstr, bt->spstr, bt->frame->size, bt->fcn ? bt->fcn->name : "??",
|
|
bt->flagdesc ? " " : "", rz_str_get(bt->flagdesc),
|
|
bt->flagdesc2 ? " " : "", rz_str_get(bt->flagdesc2));
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_JSON: {
|
|
pj_o(pj);
|
|
pj_ki(pj, "idx", i);
|
|
pj_kn(pj, "pc", bt->frame->addr);
|
|
pj_kn(pj, "sp", bt->frame->sp);
|
|
pj_ki(pj, "frame_size", bt->frame->size);
|
|
pj_ks(pj, "fname", bt->fcn ? bt->fcn->name : "");
|
|
pj_ks(pj, "desc", bt->desc);
|
|
pj_end(pj);
|
|
i++;
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_TABLE: {
|
|
rz_table_add_rowf(state->d.t, "dxxdss", i, bt->frame->addr, bt->frame->sp, bt->frame->size,
|
|
bt->fcn ? bt->fcn->name : "", bt->desc);
|
|
i++;
|
|
break;
|
|
}
|
|
case RZ_OUTPUT_MODE_QUIET: {
|
|
rz_cons_printf("%s\n", bt->pcstr);
|
|
break;
|
|
}
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbt=
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_display_bt_oneline_handler(RzCore *core, int argc, const char **argv) {
|
|
int mode = 0;
|
|
if (argc > 1) {
|
|
if (!strcmp(argv[1], "b")) {
|
|
mode = 1;
|
|
} else if (!strcmp(argv[1], "s")) {
|
|
mode = 2;
|
|
}
|
|
}
|
|
RzList *list = rz_debug_frames(core->dbg, UT64_MAX);
|
|
if (!list) {
|
|
RZ_LOG_ERROR("Unable to find debug backtrace frames\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int i = 0;
|
|
RzListIter *iter;
|
|
RzDebugFrame *frame;
|
|
rz_list_reverse(list);
|
|
rz_list_foreach (list, iter, frame) {
|
|
if (i != 0) {
|
|
rz_cons_printf(" ");
|
|
}
|
|
switch (mode) {
|
|
case 0:
|
|
rz_cons_printf("0x08%" PFMT64x, frame->addr);
|
|
break;
|
|
case 1:
|
|
rz_cons_printf("0x08%" PFMT64x, frame->bp);
|
|
break;
|
|
case 2:
|
|
rz_cons_printf("0x08%" PFMT64x, frame->sp);
|
|
break;
|
|
}
|
|
}
|
|
rz_cons_newline();
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbtv
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_display_bt_local_vars_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *list = rz_debug_frames(core->dbg, UT64_MAX);
|
|
if (!list) {
|
|
RZ_LOG_ERROR("Unable to find debug backtrace frames\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
backtrace_vars(core, list);
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbta
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_display_bt_ascii_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *list = rz_debug_frames(core->dbg, UT64_MAX);
|
|
if (!list) {
|
|
RZ_LOG_ERROR("Unable to find debug backtrace frames\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
asciiart_backtrace(core, list);
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbte
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_bt_enable_bp_trace_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_set_trace(core->dbg->bp, core->offset, true)) {
|
|
RZ_LOG_ERROR("Failed to enable trace for breakpoint at 0x%" PFMT64x "\n", core->offset);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbtd
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_bt_disable_bp_trace_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_bp_set_trace(core->dbg->bp, core->offset, false)) {
|
|
RZ_LOG_ERROR("Failed to enable trace for breakpoint at 0x%" PFMT64x "\n", core->offset);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbts
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_bt_toggle_bp_trace_handler(RzCore *core, int argc, const char **argv) {
|
|
RzBreakpointItem *bpi = rz_bp_get_in(core->dbg->bp, core->offset, 0);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("No breakpoint found at 0x%" PFMT64x "\n", core->offset);
|
|
} else {
|
|
bpi->trace = !bpi->trace;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbx
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_bp_set_expr_cur_offset_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc == 1) {
|
|
RzBreakpointItem *bpi;
|
|
RzListIter *iter;
|
|
rz_list_foreach (core->dbg->bp->bps, iter, bpi) {
|
|
rz_cons_printf("0x%08" PFMT64x " %s\n", bpi->addr, rz_str_get(bpi->expr));
|
|
}
|
|
} else if (argc == 2) {
|
|
RzBreakpointItem *bpi = rz_bp_get_at(core->dbg->bp, core->offset);
|
|
if (!bpi) {
|
|
RZ_LOG_ERROR("No breakpoint found at current offset: 0x%" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!rz_bp_item_set_expr(bpi, argv[1])) {
|
|
RZ_LOG_ERROR("Failed to set expression\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbw
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_add_watchpoint_handler(RzCore *core, int argc, const char **argv) {
|
|
bool hwbp = rz_config_get_b(core->config, "dbg.hwbp");
|
|
rz_core_debug_bp_add(core, core->offset, argv[1], argc > 2 ? argv[2] : NULL, hwbp, true);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dbW
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_set_cond_bp_win_handler(RzCore *core, int argc, const char **argv) {
|
|
#if __WINDOWS__
|
|
bool res;
|
|
if (argc > 2) {
|
|
res = rz_w32_add_winmsg_breakpoint(core->dbg, argv[1], argv[2]);
|
|
} else {
|
|
res = rz_w32_add_winmsg_breakpoint(core->dbg, argv[1], NULL);
|
|
}
|
|
if (res) {
|
|
rz_cons_print("Breakpoint set.\n");
|
|
} else {
|
|
rz_cons_print("Breakpoint not set.\n");
|
|
}
|
|
#else
|
|
RZ_LOG_ERROR("This command is only meant for Windows systems and cannot be used by your system\n");
|
|
#endif
|
|
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dc
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_execution_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
if (argc == 2) {
|
|
int old_pid = core->dbg->pid;
|
|
// using rz_num instead of atoi
|
|
int pid = rz_num_math(core->num, argv[1]);
|
|
rz_debug_select(core->dbg, pid, core->dbg->tid);
|
|
rz_core_debug_continue(core);
|
|
rz_debug_select(core->dbg, old_pid, core->dbg->tid);
|
|
} else {
|
|
rz_core_debug_continue(core);
|
|
}
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcb
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_back_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
if (!rz_debug_continue_back(core->dbg)) {
|
|
RZ_LOG_ERROR("core: cannot continue back\n");
|
|
rz_cons_break_pop();
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcc
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_call_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
|
|
rz_debug_continue_until_optype(core->dbg, RZ_ANALYSIS_OP_TYPE_CALL, 0);
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcco
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_call_over_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
|
|
rz_debug_continue_until_optype(core->dbg, RZ_ANALYSIS_OP_TYPE_CALL, 1);
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dccu
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_unknown_call_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
rz_debug_continue_until_optype(core->dbg, RZ_ANALYSIS_OP_TYPE_UCALL, 0);
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dce
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_exception_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
rz_debug_continue_pass_exception(core->dbg);
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcf
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_fork_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
RZ_LOG_WARN("core: Running 'dcs vfork fork clone' behind the scenes...\n");
|
|
// we should stop in fork, vfork, and clone syscalls
|
|
cmd_debug_cont_syscall(core, "vfork fork clone");
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dck
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_send_signal_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
int signum = rz_num_math(core->num, argv[1]);
|
|
|
|
if (argc == 3) {
|
|
int old_pid = core->dbg->pid;
|
|
int old_tid = core->dbg->tid;
|
|
int pid = rz_num_math(core->num, argv[2]);
|
|
int tid = pid; // XXX
|
|
rz_debug_select(core->dbg, pid, tid);
|
|
rz_debug_continue_kill(core->dbg, signum);
|
|
rz_debug_select(core->dbg, old_pid, old_tid);
|
|
} else {
|
|
rz_debug_continue_kill(core->dbg, signum);
|
|
}
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcp
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_mapped_io_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
RzIOMap *s;
|
|
ut64 pc;
|
|
int n = 0;
|
|
bool t = core->dbg->trace->enabled;
|
|
core->dbg->trace->enabled = false;
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
do {
|
|
rz_debug_step(core->dbg, 1);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_GPR, false);
|
|
pc = rz_debug_reg_get(core->dbg, "PC");
|
|
rz_cons_printf(" %d %" PFMT64x "\r", n++, pc);
|
|
rz_cons_flush();
|
|
s = rz_io_map_get(core->io, pc);
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
} while (!s);
|
|
rz_cons_printf("\n");
|
|
core->dbg->trace->enabled = t;
|
|
rz_cons_break_pop();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcr
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_ret_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
rz_debug_continue_until_optype(core->dbg, RZ_ANALYSIS_OP_TYPE_RET, 1);
|
|
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dct
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_traptrace_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
if (argc == 1) {
|
|
cmd_debug_backtrace(core, 0);
|
|
} else {
|
|
cmd_debug_backtrace(core, rz_num_math(core->num, argv[1]));
|
|
}
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcs
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_syscall_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
if (argc > 1) {
|
|
if (!strcmp(argv[1], "*")) {
|
|
cmd_debug_cont_syscall(core, "-1");
|
|
} else {
|
|
cmd_debug_cont_syscall(core, argv[1]);
|
|
}
|
|
} else {
|
|
cmd_debug_cont_syscall(core, NULL);
|
|
}
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dcu
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_continue_until_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
ut64 addr = rz_num_math(core->num, argv[1]);
|
|
RZ_LOG_INFO("Continue until 0x%" PFMT64x "\n", addr);
|
|
bool success = rz_core_debug_continue_until(core, addr);
|
|
rz_cons_break_pop();
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return success ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_handler_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_core_debug_plugins_print(core, state);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_handler_set_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(rz_config_set(core->config, "dbg.backend", argv[1]));
|
|
}
|
|
|
|
// dor
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_process_profile_handler(RzCore *core, int argc, const char **argv) {
|
|
RzList *list = rz_list_new();
|
|
int i;
|
|
for (i = 1; i < argc; i++) {
|
|
RzList *l = rz_str_split_duplist_n(argv[i], "=", 1, false);
|
|
if (!l) {
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
size_t llen = rz_list_length(l);
|
|
if (llen < 2) {
|
|
rz_list_free(list);
|
|
rz_list_free(l);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *key = rz_list_get_n(l, 0);
|
|
char *val = rz_list_get_n(l, 1);
|
|
if (RZ_STR_ISEMPTY(key) || RZ_STR_ISEMPTY(val)) {
|
|
RZ_LOG_ERROR("Make sure to use the format <key>=<value> without spaces.\n");
|
|
rz_list_free(l);
|
|
continue;
|
|
}
|
|
rz_list_append(list, (void *)argv[i]);
|
|
rz_list_free(l);
|
|
}
|
|
char *str = rz_list_to_str(list, '\n', true);
|
|
set_profile_string(core, str);
|
|
free(str);
|
|
rz_list_free(list);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// doe
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_process_profile_edit_handler(RzCore *core, int argc, const char **argv) {
|
|
char *out = rz_core_editor(core, NULL, core->io->envprofile);
|
|
if (!out) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
free(core->io->envprofile);
|
|
core->io->envprofile = out;
|
|
rz_cons_printf("%s\n", core->io->envprofile);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// doc
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_process_close_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
return bool2status(rz_core_debug_process_close(core));
|
|
}
|
|
|
|
// ds
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_handler(RzCore *core, int argc, const char **argv) {
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
bool ret = rz_core_debug_step_one(core, times);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
// dsb
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_back_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
bool ret = rz_core_debug_step_back(core, times);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
// dsf
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_frame_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
bool ret = rz_core_debug_step_until_frame(core);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
// dsi
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_cond_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
int n = 0;
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
do {
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
rz_debug_step(core->dbg, 1);
|
|
if (rz_debug_is_dead(core->dbg)) {
|
|
core->break_loop = true;
|
|
break;
|
|
}
|
|
rz_core_reg_update_flags(core);
|
|
n++;
|
|
} while (!rz_num_conditional(core->num, argv[1]));
|
|
rz_cons_break_pop();
|
|
RZ_LOG_INFO("stopped after %d instructions\n", n);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dsl
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_line_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
bool ret = step_line(core, times);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
// dso
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_over_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
bool ret = rz_core_debug_step_over(core, times);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
// dsp
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_prog_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
rz_reg_arena_swap(core->dbg->reg, true);
|
|
ut8 buf[64];
|
|
for (int i = 0; i < times; i++) {
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_GPR, false);
|
|
ut64 addr = rz_debug_reg_get(core->dbg, "PC");
|
|
rz_io_read_at_mapped(core->io, addr, buf, sizeof(buf));
|
|
RzAnalysisOp aop = { 0 };
|
|
rz_analysis_op_init(&aop);
|
|
rz_analysis_op(core->analysis, &aop, addr, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_BASIC);
|
|
if (aop.type == RZ_ANALYSIS_OP_TYPE_CALL) {
|
|
RzBinObject *o = rz_bin_cur_object(core->bin);
|
|
RzBinSection *s = rz_bin_get_section_at(o, aop.jump, true);
|
|
if (!s) {
|
|
rz_debug_step_over(core->dbg, times);
|
|
rz_analysis_op_fini(&aop);
|
|
continue;
|
|
}
|
|
}
|
|
rz_analysis_op_fini(&aop);
|
|
rz_debug_step(core->dbg, 1);
|
|
}
|
|
rz_core_reg_update_flags(core);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// dss
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_step_skip_handler(RzCore *core, int argc, const char **argv) {
|
|
CMD_CHECK_DEBUG_DEAD(core);
|
|
const int times = (int)rz_num_math(core->num, argv[1]);
|
|
bool ret = rz_core_debug_step_skip(core, times);
|
|
rz_core_dbg_follow_seek_register(core);
|
|
return bool2status(ret);
|
|
}
|
|
|
|
#define CMD_REGS_PREFIX debug
|
|
#define CMD_REGS_REG_PATH core->dbg->reg
|
|
static bool cmd_regs_sync(RzCore *core, RzRegisterType type, bool write) {
|
|
return rz_debug_reg_sync(core->dbg, type, write);
|
|
}
|
|
#define CMD_REGS_SYNC cmd_regs_sync
|
|
#include "cmd_regs_meta.inc"
|
|
#undef CMD_REGS_PREFIX
|
|
#undef CMD_REGS_REG_PATH
|
|
#undef CMD_REGS_SYNC
|
|
|
|
RZ_IPI void rz_core_debug_ri(RzCore *core) {
|
|
const RzList *list = rz_reg_get_list(core->dbg->reg, RZ_REG_TYPE_GPR);
|
|
rz_regs_show_valgroup(core, core->dbg->reg, cmd_regs_sync, list);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_debug_drx_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc <= 1) {
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, false);
|
|
rz_debug_drx_list(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
if (argc != 5) {
|
|
return RZ_CMD_STATUS_WRONG_ARGS;
|
|
}
|
|
int n = (int)rz_num_math(core->num, argv[1]);
|
|
ut64 off = rz_num_math(core->num, argv[2]);
|
|
int len = (int)rz_num_math(core->num, argv[3]);
|
|
int perm = rz_str_rwx(argv[4]);
|
|
if (len == -1) {
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, false);
|
|
rz_debug_drx_set(core->dbg, n, 0, 0, 0, 0);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, true);
|
|
} else {
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, false);
|
|
rz_debug_drx_set(core->dbg, n, off, len, perm, 0);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, true);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_debug_drx_unset_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_return_val_if_fail(argc > 1, RZ_CMD_STATUS_WRONG_ARGS);
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, false);
|
|
rz_debug_drx_unset(core->dbg, atoi(argv[1] + 2));
|
|
rz_debug_reg_sync(core->dbg, RZ_REG_TYPE_DRX, true);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_debug_info_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzDebugInfo *rdi = rz_debug_info(core->dbg, NULL);
|
|
RzDebugReasonType stop = rz_debug_stop_reason(core->dbg);
|
|
PJ *pj = state->d.pj;
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
if (rdi) {
|
|
const char *s = rz_signal_to_string(core->dbg->reason.signum);
|
|
rz_cons_printf("type=%s\n", rz_debug_reason_to_string(core->dbg->reason.type));
|
|
rz_cons_printf("signal=%s\n", s ? s : "none");
|
|
rz_cons_printf("signum=%d\n", core->dbg->reason.signum);
|
|
rz_cons_printf("sigpid=%d\n", core->dbg->reason.tid);
|
|
rz_cons_printf("addr=0x%" PFMT64x "\n", core->dbg->reason.addr);
|
|
rz_cons_printf("bp_addr=0x%" PFMT64x "\n", core->dbg->reason.bp_addr);
|
|
rz_cons_printf("inbp=%s\n", rz_str_bool(core->dbg->reason.bp_addr));
|
|
rz_cons_printf("baddr=0x%" PFMT64x "\n", rz_debug_get_baddr(core->dbg, NULL));
|
|
rz_cons_printf("pid=%d\n", rdi->pid);
|
|
rz_cons_printf("tid=%d\n", rdi->tid);
|
|
rz_cons_printf("stopaddr=0x%" PFMT64x "\n", core->dbg->stopaddr);
|
|
if (rdi->uid != -1) {
|
|
rz_cons_printf("uid=%d\n", rdi->uid);
|
|
}
|
|
if (rdi->gid != -1) {
|
|
rz_cons_printf("gid=%d\n", rdi->gid);
|
|
}
|
|
if (rdi->usr) {
|
|
rz_cons_printf("usr=%s\n", rdi->usr);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->exe)) {
|
|
rz_cons_printf("exe=%s\n", rdi->exe);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->cmdline)) {
|
|
rz_cons_printf("cmdline=%s\n", rdi->cmdline);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->cwd)) {
|
|
rz_cons_printf("cwd=%s\n", rdi->cwd);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->kernel_stack)) {
|
|
rz_cons_printf("kernel_stack=\n%s\n", rdi->kernel_stack);
|
|
}
|
|
}
|
|
if (stop != -1) {
|
|
rz_cons_printf("stopreason=%d\n", stop);
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(pj);
|
|
if (rdi) {
|
|
const char *s = rz_signal_to_string(core->dbg->reason.signum);
|
|
pj_ks(pj, "type", rz_debug_reason_to_string(core->dbg->reason.type));
|
|
pj_ks(pj, "signal", s ? s : "none");
|
|
pj_kn(pj, "signum", core->dbg->reason.signum);
|
|
pj_kn(pj, "sigpid", core->dbg->reason.tid);
|
|
pj_kn(pj, "addr", core->dbg->reason.addr);
|
|
pj_ks(pj, "inbp", rz_str_bool(core->dbg->reason.bp_addr));
|
|
pj_kn(pj, "baddr", rz_debug_get_baddr(core->dbg, NULL));
|
|
pj_kn(pj, "stopaddr", core->dbg->stopaddr);
|
|
pj_kN(pj, "pid", rdi->pid);
|
|
pj_kN(pj, "tid", rdi->tid);
|
|
pj_kN(pj, "uid", rdi->uid);
|
|
pj_kN(pj, "gid", rdi->gid);
|
|
if (RZ_STR_ISNOTEMPTY(rdi->usr)) {
|
|
pj_ks(pj, "usr", rdi->usr);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->exe)) {
|
|
pj_ks(pj, "exe", rdi->exe);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->cmdline)) {
|
|
pj_ks(pj, "cmdline", rdi->cmdline);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->cwd)) {
|
|
pj_ks(pj, "cwd", rdi->cwd);
|
|
}
|
|
if (RZ_STR_ISNOTEMPTY(rdi->kernel_stack)) {
|
|
pj_ks(pj, "kernel_stack", rdi->kernel_stack);
|
|
}
|
|
}
|
|
pj_kn(pj, "stopreason", stop);
|
|
pj_end(pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET: {
|
|
const char *r = rz_debug_reason_to_string(core->dbg->reason.type);
|
|
if (!r) {
|
|
r = "none";
|
|
}
|
|
rz_cons_printf("%s at 0x%08" PFMT64x "\n", r, core->dbg->stopaddr);
|
|
break;
|
|
}
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
rz_debug_info_free(rdi);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : core->dbg->pid;
|
|
return bool2status(rz_core_debug_pid_print(core->dbg, pid, state));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_attachable_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return bool2status(rz_core_debug_pid_print(core->dbg, 0, state));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_thread_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : core->dbg->pid;
|
|
return bool2status(rz_core_debug_thread_print(core->dbg, pid, state));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_attach_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : 0;
|
|
if (pid < 0) {
|
|
RZ_LOG_ERROR("Invalid PID %d\n", pid);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bool has_active_session = rz_core_is_debug(core) ||
|
|
(core->dbg->cur && core->dbg->cur->pids && core->dbg->pid != -1);
|
|
if (has_active_session && rz_cons_is_interactive() &&
|
|
!rz_cons_yesno('n', "core: A debug session is already active. Do you want to attach to another process? (y/N) ")) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_debug_attach(core, pid);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_detach_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : core->dbg->pid;
|
|
rz_debug_detach(core->dbg, pid);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_attach_fd_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!core->file || !core->io) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_debug_select(core->dbg, rz_io_fd_get_pid(core->io, core->file->fd),
|
|
rz_io_fd_get_tid(core->io, core->file->fd));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_select_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = rz_num_math(core->num, argv[1]);
|
|
rz_debug_select(core->dbg, pid, core->dbg->tid);
|
|
core->dbg->main_pid = pid;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_thread_select_handler(RzCore *core, int argc, const char **argv) {
|
|
int tid = rz_num_math(core->num, argv[1]);
|
|
rz_debug_select(core->dbg, core->dbg->pid, tid);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_select_forked_handler(RzCore *core, int argc, const char **argv) {
|
|
if (core->dbg->forked_pid == -1) {
|
|
RZ_LOG_ERROR("core: No recently forked children\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_debug_select(core->dbg, core->dbg->forked_pid, core->dbg->tid);
|
|
core->dbg->main_pid = core->dbg->forked_pid;
|
|
core->dbg->n_threads = 0;
|
|
core->dbg->forked_pid = -1;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_display_forked_handler(RzCore *core, int argc, const char **argv) {
|
|
if (core->dbg->forked_pid == -1) {
|
|
RZ_LOG_ERROR("core: No recently forked children\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("dp %d\n", core->dbg->forked_pid);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_executable_path_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : core->dbg->pid;
|
|
char *exe = rz_sys_pid_to_path(pid);
|
|
if (!exe) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println(exe);
|
|
free(exe);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_pid_signal_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = rz_num_math(core->num, argv[1]);
|
|
int sig = argc > 2 ? rz_num_math(core->num, argv[2]) : 0;
|
|
RZ_LOG_WARN("core: Sending signal '%d' to pid '%d'\n", sig, pid);
|
|
rz_debug_kill(core->dbg, pid, false, sig);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static bool debug_inject_opcode(RzCore *core, const char *opcode) {
|
|
if (strlen(opcode) >= 4096) {
|
|
RZ_LOG_ERROR("core: the opcodes to inject are too long (> 2048 bytes)\n");
|
|
return false;
|
|
}
|
|
ut8 bytes[4096];
|
|
int bytes_len = rz_hex_str2bin(opcode, bytes);
|
|
if (bytes_len <= 0) {
|
|
RZ_LOG_ERROR("core: Invalid hexpairs\n");
|
|
return false;
|
|
}
|
|
rz_debug_execute(core->dbg, bytes, bytes_len, 0);
|
|
return true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_inject_opcode_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(debug_inject_opcode(core, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_inject_assembly_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAsmCode *acode;
|
|
rz_asm_set_pc(core->rasm, core->offset);
|
|
acode = rz_asm_massemble(core->rasm, argv[1]);
|
|
if (acode) {
|
|
rz_reg_arena_push(core->dbg->reg);
|
|
rz_debug_execute(core->dbg, acode->bytes, acode->len, 0);
|
|
rz_reg_arena_pop(core->dbg->reg);
|
|
}
|
|
rz_asm_code_free(acode);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_inject_egg_handler(RzCore *core, int argc, const char **argv) {
|
|
RzEgg *egg = core->egg;
|
|
RzBuffer *b;
|
|
const char *asm_arch = rz_config_get(core->config, "asm.arch");
|
|
int asm_bits = rz_config_get_i(core->config, "asm.bits");
|
|
const char *asm_os = rz_config_get(core->config, "asm.os");
|
|
rz_egg_setup(egg, asm_arch, asm_bits, 0, asm_os);
|
|
rz_egg_reset(egg);
|
|
rz_egg_load(egg, argv[1], 0);
|
|
rz_egg_compile(egg);
|
|
b = rz_egg_get_bin(egg);
|
|
rz_asm_set_pc(core->rasm, core->offset);
|
|
rz_reg_arena_push(core->dbg->reg);
|
|
ut64 tmpsz;
|
|
const ut8 *tmp = rz_buf_data(b, &tmpsz);
|
|
rz_debug_execute(core->dbg, tmp, tmpsz, 0);
|
|
rz_reg_arena_pop(core->dbg->reg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_inject_opcode_restore_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_reg_arena_push(core->dbg->reg);
|
|
bool result = debug_inject_opcode(core, argv[1]);
|
|
rz_reg_arena_pop(core->dbg->reg);
|
|
return bool2status(result);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_inject_syscall_handler(RzCore *core, int argc, const char **argv) {
|
|
// TODO: Use the API instead of the command
|
|
char *str = rz_core_cmd_str(core, rz_str_newf("gs %s", argv[1]));
|
|
bool result = debug_inject_opcode(core, str);
|
|
free(str);
|
|
return bool2status(result);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_open_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd = rz_num_math(core->num, argv[1]);
|
|
RzBuffer *buf = rz_core_syscallf(core, "open", "%d, %d, %d", fd, 2, 0644);
|
|
consumeBuffer(buf, "dx ", "Cannot open");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_close_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd = rz_num_math(core->num, argv[1]);
|
|
RzBuffer *buf = rz_core_syscallf(core, "close", "%d", fd);
|
|
consumeBuffer(buf, "dx ", "Cannot close");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return bool2status(rz_core_debug_desc_print(core->dbg, state));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_seek_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd = rz_num_math(core->num, argv[1]);
|
|
ut64 off = rz_num_math(core->num, argv[2]);
|
|
if (off == UT64_MAX || !rz_debug_desc_seek(core->dbg, fd, off)) {
|
|
RzBuffer *buf = rz_core_syscallf(core, "lseek", "%d, 0x%" PFMT64x ", %d", fd, off, 0);
|
|
consumeBuffer(buf, "dx ", "Cannot seek");
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_dup_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd_src = rz_num_math(core->num, argv[1]);
|
|
int fd_dst = rz_num_math(core->num, argv[2]);
|
|
if (fd_dst == UT64_MAX || !rz_debug_desc_dup(core->dbg, fd_src, fd_dst)) {
|
|
RzBuffer *buf = rz_core_syscallf(core, "dup2", "%d, %d", fd_src, fd_dst);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: Cannot dup %d %d\n", fd_src, fd_dst);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
consumeBuffer(buf, "dx ", NULL);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_read_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd = rz_num_math(core->num, argv[1]);
|
|
ut64 off = rz_num_math(core->num, argv[2]);
|
|
ut64 len = rz_num_math(core->num, argv[3]);
|
|
if (len == UT64_MAX || off == UT64_MAX ||
|
|
!rz_debug_desc_read(core->dbg, fd, off, len)) {
|
|
consumeBuffer(rz_core_syscallf(core, "read", "%d, 0x%" PFMT64x ", %d",
|
|
fd, off, (int)len),
|
|
"dx ", "Cannot read");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_descriptor_write_handler(RzCore *core, int argc, const char **argv) {
|
|
int fd = rz_num_math(core->num, argv[1]);
|
|
ut64 off = rz_num_math(core->num, argv[2]);
|
|
ut64 len = rz_num_math(core->num, argv[3]);
|
|
if (len == UT64_MAX || off == UT64_MAX ||
|
|
!rz_debug_desc_write(core->dbg, fd, off, len)) {
|
|
RzBuffer *buf = rz_core_syscallf(core, "write", "%d, 0x%" PFMT64x ", %d", fd, off, (int)len);
|
|
consumeBuffer(buf, "dx ", "Cannot write");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_core_dump_generate_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!core->dbg->cur || !core->dbg->cur->gcore || core->dbg->pid == -1) {
|
|
RZ_LOG_ERROR("core: Not debugging, can't write core file.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *corefile = argc > 1 ? rz_str_dup(argv[1]) : rz_str_newf("core.%u", core->dbg->pid);
|
|
RZ_LOG_WARN("core: Writing to file '%s'\n", corefile);
|
|
rz_file_rm(corefile);
|
|
RzBuffer *dst = rz_buf_new_file(corefile, O_RDWR | O_CREAT, 0644);
|
|
if (!dst) {
|
|
RZ_LOG_WARN("core: Cannot create new file '%s'\n", corefile);
|
|
free(corefile);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (!core->dbg->cur->gcore(core->dbg, corefile, dst)) {
|
|
RZ_LOG_ERROR("core: dg: coredump failed\n");
|
|
free(corefile);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_buf_free(dst);
|
|
free(corefile);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_wait_handler(RzCore *core, int argc, const char **argv) {
|
|
int pid = argc > 1 ? rz_num_math(core->num, argv[1]) : core->dbg->pid;
|
|
rz_cons_break_push(rz_core_static_debug_stop, core->dbg);
|
|
for (; !rz_cons_is_breaked();) {
|
|
int res = rz_debug_kill(core->dbg, pid, 0, 0);
|
|
if (!res) {
|
|
break;
|
|
}
|
|
rz_sys_usleep(200);
|
|
}
|
|
rz_cons_break_pop();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_windows_list_handler(RzCore *core, int argc, const char **argv) {
|
|
#if __WINDOWS__
|
|
rz_w32_print_windows(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
#else
|
|
RZ_LOG_ERROR("This command works only on Microsoft Windows\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
#endif
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_window_identify_handler(RzCore *core, int argc, const char **argv) {
|
|
#if __WINDOWS__
|
|
rz_w32_identify_window();
|
|
return RZ_CMD_STATUS_OK;
|
|
#else
|
|
RZ_LOG_ERROR("This command works only on Microsoft Windows\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
#endif
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_add_handler(RzCore *core, int argc, const char **argv) {
|
|
int perm = rz_str_rwx(argv[1]);
|
|
int kind = (int)argv[2][0];
|
|
rz_debug_esil_watch(core->dbg, perm, kind, argv[3]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_debug_esil_watch_reset(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_debug_esil_watch_print(core->dbg, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_continue_handler(RzCore *core, int argc, const char **argv) {
|
|
if (rz_debug_esil_watch_empty(core->dbg)) {
|
|
RZ_LOG_ERROR("core: Error: no esil watchpoints defined\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_analysis_esil_reinit(core);
|
|
rz_debug_esil_prestep(core->dbg, rz_config_get_b(core->config, "esil.prestep"));
|
|
rz_debug_esil_continue(core->dbg);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_step_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_analysis_esil_reinit(core);
|
|
rz_debug_esil_prestep(core->dbg, rz_config_get_b(core->config, "esil.prestep"));
|
|
rz_debug_esil_step(core->dbg, rz_num_math(core->num, argv[1]));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_esil_step_until_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 fin = rz_num_math(core->num, argv[1]);
|
|
rz_core_analysis_esil_reinit(core);
|
|
ut64 addr = rz_debug_reg_get(core->dbg, "PC");
|
|
while (addr != fin) {
|
|
rz_debug_esil_prestep(core->dbg, rz_config_get_b(core->config, "esil.prestep"));
|
|
rz_debug_esil_step(core->dbg, 1);
|
|
ut64 naddr = rz_debug_reg_get(core->dbg, "PC");
|
|
if (naddr == addr) {
|
|
RZ_LOG_WARN("core: Detected loophole\n");
|
|
break;
|
|
}
|
|
addr = naddr;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_signal_handler(RzCore *core, int argc, const char **argv) {
|
|
int signum = rz_num_math(core->num, argv[1]);
|
|
rz_debug_kill(core->dbg, core->dbg->pid, core->dbg->tid, signum);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_signal_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
rz_core_debug_signal_print(core->dbg, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_signal_name_handler(RzCore *core, int argc, const char **argv) {
|
|
int signum = rz_num_math(core->num, argv[1]);
|
|
const char *signame = rz_signal_to_string(signum);
|
|
if (!signame) {
|
|
RZ_LOG_ERROR("Invalid signal number\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println(signame);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_signal_number_handler(RzCore *core, int argc, const char **argv) {
|
|
int signum = rz_signal_from_string(argv[1]);
|
|
if (signum <= 0) {
|
|
RZ_LOG_ERROR("Invalid signal name\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%d\n", signum);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_debug_signal_option_handler(RzCore *core, int argc, const char **argv) {
|
|
int signum = rz_num_math(core->num, argv[1]);
|
|
if (!strcmp(argv[2], "skip")) {
|
|
rz_debug_signal_setup(core->dbg, signum, RZ_DBG_SIGNAL_SKIP);
|
|
} else if (!strcmp(argv[2], "reset")) {
|
|
// Reset the signal
|
|
rz_debug_signal_setup(core->dbg, signum, 0);
|
|
} else if (!strcmp(argv[2], "continue")) {
|
|
rz_debug_signal_setup(core->dbg, signum, RZ_DBG_SIGNAL_CONT);
|
|
} else {
|
|
RZ_LOG_ERROR("core: Invalid option: %s\n", argv[2]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|