Rizin
unix-like reverse engineering framework and cli tools
desil.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_debug.h>
5 
6 #if 0
7  /* debugesil performs step into + esil conditionals */
8  ESIL conditionals can be used to detect when a specific address is
9  accessed, or a register. Those esil conditionals must be evaluated
10  every iteration to ensure the register values are updated. Think
11  in DebugESIL as software-watchpoints.
12 
13  [read|write|exec]-[reg|mem] [expression]
14 
15  de rw reg eax
16  de-*
17 
18 #expression can be a number or a range(if..is found)
19 #The <=, >=, ==, <, > comparisons are also supported
20 
21 #endif
22 
23 typedef struct {
24  int rwx;
25  int dev;
26  char *expr;
27 } EsilBreak;
28 
29 // TODO: Kill those globals
31 static int has_match = 0;
32 static int prestep = 1; // TODO: make it configurable
33 static ut64 opc = 0;
35 #define EWPS esil_watchpoints
36 #define ESIL dbg->analysis->esil
37 
38 static int exprmatch(RzDebug *dbg, ut64 addr, const char *expr) {
39  char *e = strdup(expr);
40  if (!e) {
41  return 0;
42  }
43  char *p = strstr(e, "..");
44  ut64 a, b;
45  int ret = 0;
46  if (p) {
47  *p = 0;
48  p += 2;
49  a = rz_num_math(dbg->num, e);
50  b = rz_num_math(dbg->num, p);
51  if (a < b) {
52  if (addr >= a && addr <= b) {
53  ret = 1;
54  }
55  } else {
56  if (addr >= b && addr <= a) {
57  ret = 1;
58  }
59  }
60  } else {
61  a = rz_num_math(dbg->num, e);
62  if (addr == a) {
63  ret = 1;
64  }
65  }
66  has_match = ret;
67  free(e);
68  return ret;
69 }
70 
72  EsilBreak *ew;
74  if (!pc) {
76  }
77  rz_list_foreach (EWPS, iter, ew) {
78  if (ew->rwx & RZ_PERM_X) {
79  if (exprmatch(dbg, pc, ew->expr)) {
80  return 1;
81  }
82  }
83  }
84  return 0;
85 }
86 
87 static int esilbreak_mem_read(RzAnalysisEsil *esil, ut64 addr, ut8 *buf, int len) {
88  EsilBreak *ew;
90  eprintf(Color_GREEN "MEM READ 0x%" PFMT64x "\n" Color_RESET, addr);
91  rz_list_foreach (EWPS, iter, ew) {
92  if (ew->rwx & RZ_PERM_R && ew->dev == 'm') {
93  if (exprmatch(dbg, addr, ew->expr)) {
94  has_match = 1;
95  return 1;
96  }
97  }
98  }
99  return 0; // fallback
100 }
101 
102 static int esilbreak_mem_write(RzAnalysisEsil *esil, ut64 addr, const ut8 *buf, int len) {
103  EsilBreak *ew;
104  RzListIter *iter;
105  eprintf(Color_RED "MEM WRTE 0x%" PFMT64x "\n" Color_RESET, addr);
106  rz_list_foreach (EWPS, iter, ew) {
107  if (ew->rwx & RZ_PERM_W && ew->dev == 'm') {
108  if (exprmatch(dbg, addr, ew->expr)) {
109  has_match = 1;
110  return 1;
111  }
112  }
113  }
114  return 1; // fallback
115 }
116 
117 static int esilbreak_reg_read(RzAnalysisEsil *esil, const char *regname, ut64 *num, int *size) {
118  EsilBreak *ew;
119  RzListIter *iter;
120  if (regname[0] >= '0' && regname[0] <= '9') {
121  // eprintf (Color_CYAN"IMM READ %s\n"Color_RESET, regname);
122  return 0;
123  }
124  eprintf(Color_YELLOW "REG READ %s\n" Color_RESET, regname);
125  rz_list_foreach (EWPS, iter, ew) {
126  if (ew->rwx & RZ_PERM_R && ew->dev == 'r') {
127  // XXX: support array of regs in expr
128  if (!strcmp(regname, ew->expr)) {
129  has_match = 1;
130  return 1;
131  }
132  }
133  }
134  return 0; // fallback
135 }
136 
137 static int exprtoken(RzDebug *dbg, char *s, const char *sep, char **o) {
138  char *p = strstr(s, sep);
139  if (p) {
140  *p = 0;
141  p += strlen(sep);
142  *o = p;
143  return 1;
144  }
145  *o = NULL;
146  return 0;
147 }
148 
149 static int exprmatchreg(RzDebug *dbg, const char *regname, const char *expr) {
150  int ret = 0;
151  char *p;
152  char *s = strdup(expr);
153  if (!s) {
154  return 0;
155  }
156  if (!strcmp(regname, s)) {
157  ret = 1;
158  } else {
159 #define CURVAL 0){} \
160  rz_str_trim(s);if (!strcmp(regname,s) && regval
161  ut64 regval = rz_debug_reg_get(dbg, regname);
162  if (exprtoken(dbg, s, ">=", &p)) {
163  if (CURVAL >= rz_num_math(dbg->num, p))
164  ret = 1;
165  } else if (exprtoken(dbg, s, "<=", &p)) {
166  if (CURVAL <= rz_num_math(dbg->num, p))
167  ret = 1;
168  } else if (exprtoken(dbg, s, "==", &p)) {
169  if (CURVAL <= rz_num_math(dbg->num, p))
170  ret = 1;
171  } else if (exprtoken(dbg, s, "<", &p)) {
172  if (CURVAL < rz_num_math(dbg->num, p))
173  ret = 1;
174  } else if (exprtoken(dbg, s, ">", &p)) {
175  if (CURVAL > rz_num_math(dbg->num, p))
176  ret = 1;
177  } else if (exprtoken(dbg, s, " ", &p)) {
178  rz_str_trim(s);
179  if (!strcmp(regname, s)) {
180  ut64 num = rz_num_math(dbg->num, p);
181  ret = exprmatch(dbg, num, s);
182  }
183  } else {
184  if (!strcmp(regname, s)) {
185  ret = 1;
186  }
187  }
188  }
189  free(s);
190  return ret;
191 }
192 
193 static int esilbreak_reg_write(RzAnalysisEsil *esil, const char *regname, ut64 *num) {
194  EsilBreak *ew;
195  RzListIter *iter;
196  if (regname[0] >= '0' && regname[0] <= '9') {
197  // this should never happen
198  // eprintf (Color_BLUE"IMM WRTE %s\n"Color_RESET, regname);
199  return 0;
200  }
201  eprintf(Color_MAGENTA "REG WRTE %s 0x%" PFMT64x "\n" Color_RESET, regname, *num);
202  rz_list_foreach (EWPS, iter, ew) {
203  if ((ew->rwx & RZ_PERM_W) && (ew->dev == 'r')) {
204  // XXX: support array of regs in expr
205  if (exprmatchreg(dbg, regname, ew->expr)) {
206  has_match = 1;
207  return 1;
208  }
209  }
210  }
211  return 1; // fallback
212 }
213 
215  prestep = p;
216 }
217 
220  ut8 obuf[64];
221  int ret = 1;
222  dbg = d;
223  if (!ESIL) {
224  ESIL = rz_analysis_esil_new(32, true, 64);
225  // TODO setup something?
226  if (!ESIL) {
227  return 0;
228  }
229  }
230 
233  dbg->iob.read_at(dbg->iob.io, opc, obuf, sizeof(obuf));
234 
235  // dbg->iob.read_at (dbg->iob.io, npc, buf, sizeof (buf));
236 
237  // dbg->analysis->reg = dbg->reg; // hack
238  ESIL->cb.hook_mem_read = &esilbreak_mem_read;
239  ESIL->cb.hook_mem_write = &esilbreak_mem_write;
240  ESIL->cb.hook_reg_read = &esilbreak_reg_read;
241  ESIL->cb.hook_reg_write = &esilbreak_reg_write;
242 
243  if (prestep) {
244  // required when a exxpression is like <= == ..
245  // otherwise it will stop at the next instruction
246  if (rz_debug_step(dbg, 1) < 1) {
247  eprintf("Step failed\n");
248  return 0;
249  }
251  // npc = rz_debug_reg_get (dbg, dbg->reg->name[RZ_REG_NAME_PC]);
252  }
253 
255  if (esilbreak_check_pc(dbg, opc)) {
256  eprintf("STOP AT 0x%08" PFMT64x "\n", opc);
257  ret = 0;
258  } else {
260  eprintf("0x%08" PFMT64x " %s\n", opc, RZ_STRBUF_SAFEGET(&op.esil));
262  // rz_analysis_esil_dumpstack (ESIL);
264  ret = 1;
265  }
266  }
267  if (!prestep) {
268  if (ret && !has_match) {
269  if (rz_debug_step(dbg, 1) < 1) {
270  eprintf("Step failed\n");
271  return 0;
272  }
274  // npc = rz_debug_reg_get (dbg, dbg->reg->name[RZ_REG_NAME_PC]);
275  }
276  }
277  return ret;
278 }
279 
281  count++;
282  has_match = 0;
284  do {
285  if (rz_cons_is_breaked()) {
286  break;
287  }
288  if (has_match) {
289  eprintf("EsilBreak match at 0x%08" PFMT64x "\n", opc);
290  break;
291  }
292  if (count > 0) {
293  count--;
294  if (!count) {
295  // eprintf ("Limit reached\n");
296  break;
297  }
298  }
299  } while (rz_debug_esil_stepi(dbg));
301  return opc;
302 }
303 
306 }
307 
308 static void ewps_free(EsilBreak *ew) {
309  RZ_FREE(ew->expr);
310  free(ew);
311 }
312 
314  return rz_list_empty(EWPS);
315 }
316 
317 RZ_API void rz_debug_esil_watch(RzDebug *dbg, int rwx, int dev, const char *expr) {
318  if (!EWPS) {
319  EWPS = rz_list_new();
320  if (!EWPS) {
321  return;
322  }
323  EWPS->free = (RzListFree)ewps_free;
324  }
325  EsilBreak *ew = RZ_NEW0(EsilBreak);
326  if (!ew) {
327  RZ_FREE(EWPS);
328  return;
329  }
330  ew->rwx = rwx;
331  ew->dev = dev;
332  ew->expr = strdup(expr);
333  rz_list_append(EWPS, ew);
334 }
335 
338  EWPS = NULL;
339 }
340 
342  EsilBreak *ew;
343  RzListIter *iter;
344  rz_list_foreach (EWPS, iter, ew) {
345  dbg->cb_printf("de %s %c %s\n", rz_str_rwx_i(ew->rwx), ew->dev, ew->expr);
346  }
347 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
#define e(frag)
const lzma_allocator const uint8_t * in
Definition: block.h:527
static RzNumCalcValue expr(RzNum *, RzNumCalc *, int)
Definition: calc.c:167
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static fork write
Definition: sflib.h:33
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
uint32_t ut32
static int prestep
Definition: desil.c:32
static int esilbreak_mem_write(RzAnalysisEsil *esil, ut64 addr, const ut8 *buf, int len)
Definition: desil.c:102
RZ_API ut64 rz_debug_esil_continue(RzDebug *dbg)
Definition: desil.c:304
static ut64 opc
Definition: desil.c:33
RzDebug * dbg
Definition: desil.c:30
#define CURVAL
RZ_API ut64 rz_debug_esil_step(RzDebug *dbg, ut32 count)
Definition: desil.c:280
RZ_API int rz_debug_esil_stepi(RzDebug *d)
Definition: desil.c:218
static int exprmatch(RzDebug *dbg, ut64 addr, const char *expr)
Definition: desil.c:38
RZ_API void rz_debug_esil_prestep(RzDebug *d, int p)
Definition: desil.c:214
static int exprmatchreg(RzDebug *dbg, const char *regname, const char *expr)
Definition: desil.c:149
static int esilbreak_reg_write(RzAnalysisEsil *esil, const char *regname, ut64 *num)
Definition: desil.c:193
static int exprtoken(RzDebug *dbg, char *s, const char *sep, char **o)
Definition: desil.c:137
RZ_API void rz_debug_esil_watch_list(RzDebug *dbg)
Definition: desil.c:341
static int esilbreak_mem_read(RzAnalysisEsil *esil, ut64 addr, ut8 *buf, int len)
Definition: desil.c:87
static int esilbreak_reg_read(RzAnalysisEsil *esil, const char *regname, ut64 *num, int *size)
Definition: desil.c:117
#define ESIL
Definition: desil.c:36
static int esilbreak_check_pc(RzDebug *dbg, ut64 pc)
Definition: desil.c:71
static void ewps_free(EsilBreak *ew)
Definition: desil.c:308
RZ_API int rz_debug_esil_watch_empty(RzDebug *dbg)
Definition: desil.c:313
RzList * esil_watchpoints
Definition: desil.c:34
RZ_API void rz_debug_esil_watch_reset(RzDebug *dbg)
Definition: desil.c:336
RZ_API void rz_debug_esil_watch(RzDebug *dbg, int rwx, int dev, const char *expr)
Definition: desil.c:317
#define EWPS
Definition: desil.c:35
static int has_match
Definition: desil.c:31
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 void rz_analysis_esil_stack_free(RzAnalysisEsil *esil)
Definition: esil.c:3103
RZ_API RzAnalysisEsil * rz_analysis_esil_new(int stacksize, int iotrap, unsigned int addrsize)
Definition: esil.c:85
RZ_API bool rz_analysis_esil_set_pc(RzAnalysisEsil *esil, ut64 addr)
Definition: esil.c:155
RZ_API bool rz_analysis_esil_parse(RzAnalysisEsil *esil, const char *str)
Definition: esil.c:2998
when
Definition: fread.c:45
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
void * mem
Definition: libc.cpp:91
RZ_API int rz_debug_step(RzDebug *dbg, int steps)
Definition: debug.c:962
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 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
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void static offset const char static length static mode static who const char struct statfs static buf unsigned unsigned num
Definition: sflib.h:126
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask dev
Definition: sflib.h:88
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 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
static RzSocket * s
Definition: rtr.c:28
@ RZ_ANALYSIS_OP_MASK_ESIL
Definition: rz_analysis.h:441
#define Color_RESET
Definition: rz_cons.h:617
#define Color_MAGENTA
Definition: rz_cons.h:629
#define Color_GREEN
Definition: rz_cons.h:627
#define Color_RED
Definition: rz_cons.h:623
#define Color_YELLOW
Definition: rz_cons.h:631
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
@ RZ_REG_TYPE_GPR
Definition: rz_reg.h:21
@ RZ_REG_NAME_PC
Definition: rz_reg.h:43
RZ_API const char * rz_str_rwx_i(int rwx)
Definition: str.c:332
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
#define RZ_STRBUF_SAFEGET(sb)
Definition: rz_strbuf.h:18
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
#define RZ_PERM_X
Definition: rz_types.h:95
#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
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125
#define d(i)
Definition: sha256.c:44
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
int dev
Definition: desil.c:25
int rwx
Definition: desil.c:24
char * expr
Definition: desil.c:26
PrintfCallback cb_printf
Definition: rz_debug.h:292
RzAnalysis * analysis
Definition: rz_debug.h:305
RzReg * reg
Definition: rz_debug.h:286
RzIOBind iob
Definition: rz_debug.h:293
RzNum * num
Definition: rz_debug.h:317
RzIOReadAt read_at
Definition: rz_io.h:240
RzIO * io
Definition: rz_io.h:232
char * name[RZ_REG_NAME_LAST]
Definition: rz_reg.h:149
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
eax
Definition: x86-32-avx.s.cs:79
static char * regname(int reg)
Definition: dis.c:71
static unsigned char * obuf
Definition: z80asm.c:36
static int addr
Definition: z80asm.c:58
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115