Rizin
unix-like reverse engineering framework and cli tools
trace.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2008-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_debug.h>
5 
6 /* Old debug trace implementation */
9  if (!t) {
10  return NULL;
11  }
12  t->tag = 1; // UT32_MAX;
13  t->addresses = NULL;
14  t->enabled = false;
15  t->traces = rz_list_new();
16  if (!t->traces) {
18  return NULL;
19  }
20  t->traces->free = free;
21  t->ht = ht_pp_new0();
22  if (!t->ht) {
24  return NULL;
25  }
26  return t;
27 }
28 
30  if (!trace) {
31  return;
32  }
33  rz_list_purge(trace->traces);
34  free(trace->traces);
35  ht_pp_free(trace->ht);
36  RZ_FREE(trace);
37 }
38 
39 // TODO: added overlap/mask support here...
40 // TODO: think about tagged traces
42  // if (tag>0 && tag<31) core->dbg->trace->tag = 1<<(sz-1);
43  return (dbg->trace->tag = (tag > 0) ? tag : UT32_MAX);
44 }
45 
47  RzListIter *it, *it_tmp;
49  ut8 buf_pc[32];
50 
51  // Analyze current instruction
53  if (!dbg->iob.read_at) {
54  return false;
55  }
56  if (!dbg->iob.read_at(dbg->iob.io, pc, buf_pc, sizeof(buf_pc))) {
57  return false;
58  }
60  if (!dbg->cur_op) {
61  return false;
62  }
63  if (rz_analysis_op(dbg->analysis, dbg->cur_op, pc, buf_pc, sizeof(buf_pc), RZ_ANALYSIS_OP_MASK_VAL) < 1) {
65  dbg->cur_op = NULL;
66  return false;
67  }
68 
69  // resolve mem write address
70  rz_list_foreach_safe (dbg->cur_op->access, it, it_tmp, val) {
71  switch (val->type) {
73  if (!(val->access & RZ_ANALYSIS_ACC_W)) {
75  }
76  break;
78  if (val->memref > 32) {
79  eprintf("Error: adding changes to %d bytes in memory.\n", val->memref);
81  break;
82  }
83 
84  if (val->access & RZ_ANALYSIS_ACC_W) {
85  // resolve memory address
86  ut64 addr = 0;
87  addr += val->delta;
88  if (val->seg) {
89  addr += rz_reg_get_value(dbg->reg, val->seg);
90  }
91  if (val->reg) {
92  addr += rz_reg_get_value(dbg->reg, val->reg);
93  }
94  if (val->regdelta) {
95  int mul = val->mul ? val->mul : 1;
96  addr += mul * rz_reg_get_value(dbg->reg, val->regdelta);
97  }
98  // resolve address into base for ins_after
99  val->base = addr;
100  } else {
102  }
103  default:
104  break;
105  }
106  }
107  return true;
108 }
109 
112  RzListIter *it;
114 
115  // Add reg/mem write change
117  rz_list_foreach (dbg->cur_op->access, it, val) {
118  if (!(val->access & RZ_ANALYSIS_ACC_W)) {
119  continue;
120  }
121 
122  switch (val->type) {
123  case RZ_ANALYSIS_VAL_REG: {
124  if (!val->reg) {
125  RZ_LOG_ERROR("invalid register, unable to trace register state\n");
126  continue;
127  }
128  ut64 data = rz_reg_get_value(dbg->reg, val->reg);
129 
130  // add reg write
131  rz_debug_session_add_reg_change(dbg->session, val->reg->arena, val->reg->offset, data);
132  break;
133  }
134  case RZ_ANALYSIS_VAL_MEM: {
135  ut8 buf[32] = { 0 };
136  if (!dbg->iob.read_at(dbg->iob.io, val->base, buf, val->memref)) {
137  eprintf("Error reading memory at 0x%" PFMT64x "\n", val->base);
138  break;
139  }
140 
141  // add mem write
142  size_t i;
143  for (i = 0; i < val->memref; i++) {
145  }
146  break;
147  }
148  default:
149  break;
150  }
151  }
153  dbg->cur_op = NULL;
154  return true;
155 }
156 
157 /*
158  * something happened at the given pc that we need to trace
159  */
161  ut8 buf[32];
162  RzAnalysisOp op = { 0 };
163  if (!dbg->iob.is_valid_offset(dbg->iob.io, pc, 0)) {
164  eprintf("trace_pc: cannot read memory at 0x%" PFMT64x "\n", pc);
165  return false;
166  }
167  (void)dbg->iob.read_at(dbg->iob.io, pc, buf, sizeof(buf));
168  if (rz_analysis_op(dbg->analysis, &op, pc, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_ESIL) < 1) {
169  eprintf("trace_pc: cannot get opcode size at 0x%" PFMT64x "\n", pc);
170  return false;
171  }
174  return true;
175 }
176 
178  static ut64 oldpc = UT64_MAX; // Must trace the previously traced instruction
179  if (dbg->trace->enabled) {
180  if (dbg->analysis->esil) {
182  } else {
183  if (dbg->verbose) {
184  eprintf("Run aeim to get dbg->analysis->esil initialized\n");
185  }
186  }
187  }
188  if (oldpc != UT64_MAX) {
189  rz_debug_trace_add(dbg, oldpc, op->size); // XXX review what this line really do
190  }
191  oldpc = op->addr;
192 }
193 
194 RZ_API void rz_debug_trace_at(RzDebug *dbg, const char *str) {
195  // TODO: parse offsets and so use ut64 instead of strstr()
196  free(dbg->trace->addresses);
197  dbg->trace->addresses = (str && *str) ? strdup(str) : NULL;
198 }
199 
201  int tag = dbg->trace->tag;
202  return ht_pp_find(dbg->trace->ht,
203  sdb_fmt("trace.%d.%" PFMT64x, tag, addr), NULL);
204 }
205 
206 static int cmpaddr(const void *_a, const void *_b) {
207  const RzListInfo *a = _a, *b = _b;
208  return (rz_itv_begin(a->pitv) > rz_itv_begin(b->pitv)) ? 1 : (rz_itv_begin(a->pitv) < rz_itv_begin(b->pitv)) ? -1
209  : 0;
210 }
211 
212 /***
213  * Get all trace info
214  * @param dbg core->dbg
215  * @param offset offset of address
216  * @return a RzList of RzListInfo
217  */
220  int tag = dbg->trace->tag;
221  RzListIter *iter;
222  RzList *info_list = rz_list_new();
223  if (!info_list) {
224  return NULL;
225  }
226 
227  RzDebugTracepoint *trace;
228  rz_list_foreach (dbg->trace->traces, iter, trace) {
229  if (trace->tag && !(tag & trace->tag)) {
230  continue;
231  }
233  if (!info) {
234  rz_list_free(info_list);
235  return NULL;
236  }
237  info->pitv = (RzInterval){ trace->addr, trace->size };
238  info->vitv = info->pitv;
239  info->perm = -1;
240  info->name = rz_str_newf("%d", trace->times);
241  info->extra = rz_str_newf("%d", trace->count);
242  rz_list_append(info_list, info);
243  }
244 
245  rz_list_sort(info_list, cmpaddr);
246  return info_list;
247 }
248 
249 // XXX: find better name, make it public?
251  if (dbg->trace->addresses) {
252  char addr_str[32];
253  snprintf(addr_str, sizeof(addr_str), "0x%08" PFMT64x, addr);
254  if (!strstr(dbg->trace->addresses, addr_str)) {
255  return false;
256  }
257  }
258  return true;
259 }
260 
262  RzDebugTracepoint *tp;
263  int tag = dbg->trace->tag;
265  return NULL;
266  }
269  if (!tp) {
270  return NULL;
271  }
272  tp->stamp = rz_time_now();
273  tp->addr = addr;
274  tp->tags = tag;
275  tp->size = size;
276  tp->count = ++dbg->trace->count;
277  tp->times = 1;
279  ht_pp_update(dbg->trace->ht,
280  sdb_fmt("trace.%d.%" PFMT64x, tag, addr), tp);
281  return tp;
282 }
283 
285  RzDebugTrace *t = dbg->trace;
286  rz_list_purge(t->traces);
287  ht_pp_free(t->ht);
288  t->ht = ht_pp_new0();
289  t->traces = rz_list_new();
290  t->traces->free = free;
291 }
RZ_API void rz_analysis_trace_bb(RzAnalysis *analysis, ut64 addr)
Definition: analysis.c:377
lzma_index ** i
Definition: index.h:629
static RzILOpEffect * mul(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:539
ut16 val
Definition: armass64_const.h:6
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RzDebug * dbg
Definition: desil.c:30
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name)
Definition: dreg.c:99
RZ_API int rz_debug_reg_sync(RzDebug *dbg, int type, int write)
Definition: dreg.c:9
RZ_API bool rz_debug_session_add_reg_change(RzDebugSession *session, int arena, ut64 offset, ut64 data)
Definition: dsession.c:218
RZ_API bool rz_debug_session_add_mem_change(RzDebugSession *session, ut64 addr, ut8 data)
Definition: dsession.c:233
RZ_API void rz_analysis_esil_trace_op(RzAnalysisEsil *esil, RZ_NONNULL RzAnalysisOp *op)
Definition: esil_trace.c:271
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
Definition: list.c:162
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API void rz_list_purge(RZ_NONNULL RzList *list)
Empties the list without freeing the list pointer.
Definition: list.c:120
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
RZ_API void rz_analysis_op_free(void *op)
Definition: op.c:61
RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op)
Definition: op.c:37
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API ut64 rz_reg_get_value(RzReg *reg, RzRegItem *item)
Definition: rvalue.c:114
@ RZ_ANALYSIS_VAL_REG
Definition: rz_analysis.h:768
@ RZ_ANALYSIS_VAL_MEM
Definition: rz_analysis.h:769
@ RZ_ANALYSIS_OP_MASK_VAL
Definition: rz_analysis.h:442
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
@ RZ_ANALYSIS_ACC_W
Definition: rz_analysis.h:763
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
static ut64 rz_itv_begin(RzInterval itv)
Definition: rz_itv.h:34
struct rz_interval_t RzInterval
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
@ RZ_REG_TYPE_ANY
Definition: rz_reg.h:35
@ RZ_REG_NAME_PC
Definition: rz_reg.h:43
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API ut64 rz_time_now(void)
Returns the current time in microseconds.
Definition: time.c:88
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define UT32_MAX
Definition: rz_types_base.h:99
#define UT64_MAX
Definition: rz_types_base.h:86
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
struct rz_analysis_esil_t * esil
Definition: rz_analysis.h:584
bool verbose
Definition: rz_debug.h:319
RzDebugSession * session
Definition: rz_debug.h:311
RzDebugTrace * trace
Definition: rz_debug.h:281
RzAnalysis * analysis
Definition: rz_debug.h:305
RzAnalysisOp * cur_op
Definition: rz_debug.h:310
RzReg * reg
Definition: rz_debug.h:286
RzIOBind iob
Definition: rz_debug.h:293
RzList * traces
Definition: rz_debug.h:220
char * addresses
Definition: rz_debug.h:226
RzIOReadAt read_at
Definition: rz_io.h:240
RzIOIsValidOff is_valid_offset
Definition: rz_io.h:257
RzIO * io
Definition: rz_io.h:232
RzListFree free
Definition: rz_list.h:21
char * name[RZ_REG_NAME_LAST]
Definition: rz_reg.h:149
RZ_API void rz_debug_trace_at(RzDebug *dbg, const char *str)
Definition: trace.c:194
RZ_API int rz_debug_trace_tag(RzDebug *dbg, int tag)
Definition: trace.c:41
RZ_API RZ_OWN RzList * rz_debug_traces_info(RzDebug *dbg, ut64 offset)
Definition: trace.c:218
RZ_API RzDebugTracepoint * rz_debug_trace_add(RzDebug *dbg, ut64 addr, int size)
Definition: trace.c:261
RZ_API RzDebugTracepoint * rz_debug_trace_get(RzDebug *dbg, ut64 addr)
Definition: trace.c:200
RZ_API void rz_debug_trace_free(RzDebugTrace *trace)
Definition: trace.c:29
RZ_API RzDebugTrace * rz_debug_trace_new(void)
Definition: trace.c:7
RZ_API void rz_debug_trace_op(RzDebug *dbg, RzAnalysisOp *op)
Definition: trace.c:177
RZ_API bool rz_debug_trace_ins_after(RzDebug *dbg)
Definition: trace.c:110
RZ_API int rz_debug_trace_pc(RzDebug *dbg, ut64 pc)
Definition: trace.c:160
static int rz_debug_trace_is_traceable(RzDebug *dbg, ut64 addr)
Definition: trace.c:250
RZ_API bool rz_debug_trace_ins_before(RzDebug *dbg)
Definition: trace.c:46
static int cmpaddr(const void *_a, const void *_b)
Definition: trace.c:206
RZ_API void rz_debug_trace_reset(RzDebug *dbg)
Definition: trace.c:284
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58