2015-07-21 04:06:00 +00:00
|
|
|
/* radare - LGPL - Copyright 2015 - pancake */
|
|
|
|
|
|
|
|
#include <r_debug.h>
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* debugesil performs step into + esil conditionals */
|
|
|
|
ESIL conditionals can be used to detect when a specific address is
|
|
|
|
accessed, or a register. Those esil conditionals must be evaluated
|
|
|
|
every iteration to ensure the register values are updated. Think
|
|
|
|
in DebugESIL as software-watchpoints.
|
2016-05-24 20:22:15 +00:00
|
|
|
|
2015-07-21 04:06:00 +00:00
|
|
|
[read|write|exec]-[reg|mem] [expression]
|
|
|
|
|
|
|
|
de rw reg eax
|
|
|
|
de-*
|
|
|
|
|
|
|
|
# expression can be a number or a range (if .. is found)
|
|
|
|
# The <=, >=, ==, <, > comparisons are also supported
|
2016-05-24 20:22:15 +00:00
|
|
|
|
2015-07-21 04:06:00 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int rwx;
|
|
|
|
int dev;
|
|
|
|
char *expr;
|
|
|
|
} EsilBreak;
|
|
|
|
|
|
|
|
// TODO: Kill those globals
|
|
|
|
RDebug *dbg = NULL;
|
|
|
|
static int has_match = 0;
|
|
|
|
static int prestep = 1; // TODO: make it configurable
|
|
|
|
static ut64 opc = 0;
|
|
|
|
RList *esil_watchpoints = NULL;
|
|
|
|
#define EWPS esil_watchpoints
|
|
|
|
#define ESIL dbg->anal->esil
|
|
|
|
|
|
|
|
static int exprmatch (RDebug *dbg, ut64 addr, const char *expr) {
|
|
|
|
char *e = strdup (expr);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!e) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
char *p = strstr (e, "..");
|
|
|
|
ut64 a,b;
|
|
|
|
int ret = 0;
|
|
|
|
if (p) {
|
|
|
|
*p = 0;
|
|
|
|
p += 2;
|
|
|
|
a = r_num_math (dbg->num, e);
|
|
|
|
b = r_num_math (dbg->num, p);
|
|
|
|
if (a<b) {
|
2018-09-13 08:17:26 +00:00
|
|
|
if (addr >= a && addr <= b) {
|
2015-07-21 04:06:00 +00:00
|
|
|
ret = 1;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
} else {
|
2018-09-13 08:17:26 +00:00
|
|
|
if (addr >= b && addr <= a) {
|
2015-07-21 04:06:00 +00:00
|
|
|
ret = 1;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
a = r_num_math (dbg->num, e);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (addr == a) {
|
2015-07-21 04:06:00 +00:00
|
|
|
ret = 1;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
}
|
|
|
|
has_match = ret;
|
|
|
|
free (e);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int esilbreak_check_pc (RDebug *dbg, ut64 pc) {
|
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!pc) {
|
|
|
|
pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2018-09-21 00:16:54 +00:00
|
|
|
if (ew->rwx & R_PERM_X) {
|
2018-09-13 08:17:26 +00:00
|
|
|
if (exprmatch (dbg, pc, ew->expr)) {
|
2015-07-21 04:06:00 +00:00
|
|
|
return 1;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int esilbreak_mem_read(RAnalEsil *esil, ut64 addr, ut8 *buf, int len) {
|
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
2016-03-31 11:08:39 +00:00
|
|
|
eprintf (Color_GREEN"MEM READ 0x%"PFMT64x"\n"Color_RESET, addr);
|
2015-07-21 04:06:00 +00:00
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2018-09-21 00:16:54 +00:00
|
|
|
if (ew->rwx & R_PERM_R && ew->dev == 'm') {
|
2015-07-21 04:06:00 +00:00
|
|
|
if (exprmatch (dbg, addr, ew->expr)) {
|
|
|
|
has_match = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; // fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
static int esilbreak_mem_write(RAnalEsil *esil, ut64 addr, const ut8 *buf, int len) {
|
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
2016-03-31 11:08:39 +00:00
|
|
|
eprintf (Color_RED"MEM WRTE 0x%"PFMT64x"\n"Color_RESET, addr);
|
2015-07-21 04:06:00 +00:00
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2018-09-21 00:16:54 +00:00
|
|
|
if (ew->rwx & R_PERM_W && ew->dev == 'm') {
|
2015-07-21 04:06:00 +00:00
|
|
|
if (exprmatch (dbg, addr, ew->expr)) {
|
|
|
|
has_match = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1; // fallback
|
|
|
|
}
|
|
|
|
|
2015-09-14 00:08:31 +00:00
|
|
|
static int esilbreak_reg_read(RAnalEsil *esil, const char *regname, ut64 *num, int *size) {
|
2015-07-21 04:06:00 +00:00
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
|
|
|
if (regname[0]>='0' && regname[0]<='9') {
|
|
|
|
//eprintf (Color_CYAN"IMM READ %s\n"Color_RESET, regname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
eprintf (Color_YELLOW"REG READ %s\n"Color_RESET, regname);
|
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2018-09-21 00:16:54 +00:00
|
|
|
if (ew->rwx & R_PERM_R && ew->dev == 'r') {
|
2015-07-21 04:06:00 +00:00
|
|
|
// XXX: support array of regs in expr
|
|
|
|
if (!strcmp (regname, ew->expr)) {
|
|
|
|
has_match = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; // fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
static int exprtoken(RDebug *dbg, char *s, const char *sep, char **o) {
|
|
|
|
char *p = strstr (s, sep);
|
|
|
|
if (p) {
|
|
|
|
*p = 0;
|
|
|
|
p += strlen (sep);
|
|
|
|
*o = p;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*o = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int exprmatchreg (RDebug *dbg, const char *regname, const char *expr) {
|
|
|
|
int ret = 0;
|
|
|
|
char *p;
|
|
|
|
char *s = strdup (expr);
|
2017-09-10 23:22:21 +00:00
|
|
|
if (!s) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
if (!strcmp (regname, s)) {
|
|
|
|
ret = 1;
|
|
|
|
} else {
|
2016-06-10 01:12:07 +00:00
|
|
|
#define CURVAL 0){}r_str_trim_head_tail (s);if (!strcmp(regname,s) && regval
|
2016-11-14 22:58:29 +00:00
|
|
|
ut64 regval = r_debug_reg_get_err (dbg, regname, NULL, NULL);
|
2015-07-21 04:06:00 +00:00
|
|
|
if (exprtoken (dbg, s, ">=", &p)) {
|
|
|
|
if (CURVAL >= r_num_math (dbg->num, p))
|
|
|
|
ret = 1;
|
|
|
|
} else if (exprtoken (dbg, s, "<=", &p)) {
|
|
|
|
if (CURVAL <= r_num_math (dbg->num, p))
|
|
|
|
ret = 1;
|
|
|
|
} else if (exprtoken (dbg, s, "==", &p)) {
|
|
|
|
if (CURVAL <= r_num_math (dbg->num, p))
|
|
|
|
ret = 1;
|
|
|
|
} else if (exprtoken (dbg, s, "<", &p)) {
|
|
|
|
if (CURVAL < r_num_math (dbg->num, p))
|
|
|
|
ret = 1;
|
|
|
|
} else if (exprtoken (dbg, s, ">", &p)) {
|
|
|
|
if (CURVAL > r_num_math (dbg->num, p))
|
|
|
|
ret = 1;
|
|
|
|
} else if (exprtoken (dbg, s, " ", &p)) {
|
2016-06-10 01:12:07 +00:00
|
|
|
r_str_trim_head_tail (s);
|
2015-07-21 04:06:00 +00:00
|
|
|
if (!strcmp (regname, s)) {
|
|
|
|
ut64 num = r_num_math (dbg->num, p);
|
|
|
|
ret = exprmatch (dbg, num, s);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!strcmp (regname, s)) {
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (s);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-10-18 14:59:38 +00:00
|
|
|
static int esilbreak_reg_write(RAnalEsil *esil, const char *regname, ut64 *num) {
|
2015-07-21 04:06:00 +00:00
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
2017-09-10 23:22:21 +00:00
|
|
|
if (regname[0] >= '0' && regname[0] <= '9') {
|
2015-07-21 04:06:00 +00:00
|
|
|
// wtf this should never happen
|
|
|
|
//eprintf (Color_BLUE"IMM WRTE %s\n"Color_RESET, regname);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-10-18 14:59:38 +00:00
|
|
|
eprintf (Color_MAGENTA"REG WRTE %s 0x%"PFMT64x"\n"Color_RESET, regname, *num);
|
2015-07-21 04:06:00 +00:00
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2018-09-21 00:16:54 +00:00
|
|
|
if ((ew->rwx & R_PERM_W) && (ew->dev == 'r')) {
|
2015-07-21 04:06:00 +00:00
|
|
|
// XXX: support array of regs in expr
|
|
|
|
if (exprmatchreg (dbg, regname, ew->expr)) {
|
|
|
|
has_match = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1; // fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_esil_prestep (RDebug *d, int p) {
|
|
|
|
prestep = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_esil_stepi (RDebug *d) {
|
|
|
|
RAnalOp op;
|
|
|
|
ut8 obuf[64];
|
|
|
|
int ret = 1;
|
|
|
|
dbg = d;
|
|
|
|
if (!ESIL) {
|
Fix #9595 (#9673)
* Added an address mask inside the RAnalEsil struct in order to be sure that the address accessed is relevant with the asm.bits of the file + Changed the calls to r_anal_esil_new
* Corrected the addrmask in r_anal_esil_new
* RTTI: Read MSVC Complete Object Locator
* RTTI: Read MSVC Class Hierarchy Descriptor
* VTable End on Reference
* RTTI: Read MSVC Type Descriptor
* RTTI: Read MSVC Base Class Array, Better Printing
* Add anal.cpp.abi
* Minor Code Style Changes in RTTI
* Fix rahash2 entropy to show non truncated double (#9629)
* Anal - whitespace fixes
* Honor CFLAGS on the static build test compilation (#9677)
* change coding style tab width to 4 (#9670)
* Meson: use more built-in options (#9678)
* Add support for extended regex in asm search (#9675)
* Fix #9665 - Backwardly handle scr.color={bool}
* Fix #9676 - Infinite loop in ecs with scr.color=2
* Adding help for redirection (#9679)
* Refactores function r_str_split_list to receive the character to split by (#9672)
* Fix #9666 - lines with comments do not use Unicode reflines
* Fix uninitialized optypes_list issue in cmd_debug
* update asan.sh to actually take the env for ASAN
* removed incorrect return (#9685)
* Fix UB in ESIL
* Initial import of the CoreUndo API and uc command
* Initial implementation of cmd.pdc to select pseudo-decompiler
* Handle recursive pdc calls
* Fix RPrint.strconv_mode memleak
* Fix leaks in RSyscall.srdb
* Use r_syscall_ref to avoid dblfree-or-leak issue
* Arm thumb/thumb selector for the armass (#9681)
* added function to translate number to imm12
* added function to get thumb shifts easily
* added selector, newfangled implementation of adc
* add bitmask for command suffixes
* added new routine for parsing suffixes to opcodes. Error check added in getnum. Bugfixes.
* Few improvements to 8051 memory mapping (#9686)
* update memory map when idata/sfr/xdata regs change
* set address space name on map
* fix regression, remove debug output
* fix regression, enable map name
* Some fixups for #9682 (#9688)
* Fix: coredump generation for huge programs (#9680)
* Refix #9666 - lines with comments do not use Unicode reflines
* Removed code unnecessary due to dcf3db025085c45124ec21890550a4ef19bd015c
* Fixed free const warning
* Fix another memleak in RSyscall
* Fix more memleaks
* Fix leak in RConsPal.rainbow
* Fix 18K leak in anal.x86.cs
* Fix some more memleaks in disasm and fix issue in str overlap
* Fix memleak in RCore.anal_refs and fix regression
* Revert "Fix some more memleaks in disasm and fix issue in str overlap"
This reverts commit a902df837b0d499e1723179ed5c957c078703b51.
* Fix memleak regressions
* Bring back another memleak fix
* Fix an undefined behaviour in RParse.filter
* Fix memleaks in disasm.c
* Add cundo.c to Meson (#9694)
* Bring back an ugly buffer pack access issue to make it work
* Cast to void * in R_FREE (#9692)
* Set anal.cpp.abi to msvc for pe
* Add better help for av
* Split avr into avr and avra
* Make av, avr and avra breakable
* Add RTTI struct specific print functions
* RTTI: Support MSVC x86_64
* PE: Fix too short section name.
* PDB: define a constant to store the max length of a section name and use id.
* PDB: dump the size of structure and union in JSON mode.
* Fix cast issue in eprintf for debug.core.linux
* Move the asm and anal plugins for x86.udis to extras
Available via r2pm -ci udis86
* Remove more udis86 references
* Fix warnings
* fix pcache ptr-fuckup
* Fix defragger theme
* Fix crash in asl and fix its behaviour
* Fix memory leak in blaze anal and silent a warning
* Implement ?q to be like ?v but in quiet mode
* Fix Meson build
* Add missing 8, 16, 32 bit registers (and flags) for the linux-arm64 debugger reg profile
* Fix 'Cannot find function at UT64_MAX message'
* Add some Pingu to fortunes.fun
* Loading Core (x86, x86_64, aarch64) (#9669)
* Ragg2-cc -> Ragg2 merge (#9658)
- change of 'access' function for 'r_file_exists' for windows portability
- several changes in the way ragg2.c is done, see PR #9658 pancake comments
- change function for the remove of 'file'.text
- open changed for r_file_dump
- some elt of cEnv_t are now const
- skip all the pointers verification in set_cEnv but do them in check_cEnv instead
- add 2 r_str_sanitize for file and CC in parseCFile
- rewrite the removal of .o, .tmp, .bin, .s files, with cleaner code
- changed the long command with sed and grep to 2 C functions.
- The function parseCompiled that basically does what the command was doing
- And r_str_stripLines that is equivalent to "grep -v" (maybe we should put this one in str.c ?)
- simplify a bit getCompiler function with a const char* array
- add ternary operator for armOrMips condition
- use r_file_path for finding path to compilers
- new file created in libr/egg which contains all the C file parser
- modifications of 2 files to match the change :
- libr/egg/r_egg.h
- libr/egg/Makefile
- the function r_str_stripLine is simplier (the mallocs wasn't needed)
- the function r_str_stripLine is moved to libr/util/str.c
- libr/include/r_util/r_str.h is changed accordingly
* Revert bd3465c9a3fbeddf83980dc07eaac588320f7d (warning remains fixed)
This reverts commit titled "Fixed free const warning".
* Added an address mask inside the RAnalEsil struct in order to be sure that the address accessed is relevant with the asm.bits of the file + Changed the calls to r_anal_esil_new
* Corrected the addrmask in r_anal_esil_new
* Cleanup expressions in esil.c (addr &=...)
* Corrected r_anal_esil_new definition in r_anal.h
* Added an address size max in the ESIL config (maximum address size reachable by the ESIL VM)
2018-03-16 09:45:17 +00:00
|
|
|
ESIL = r_anal_esil_new (32, true, 64);
|
2015-07-21 04:06:00 +00:00
|
|
|
// TODO setup something?
|
2017-09-10 23:22:21 +00:00
|
|
|
if (!ESIL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
}
|
|
|
|
|
2016-07-12 20:15:19 +00:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2015-07-21 04:06:00 +00:00
|
|
|
opc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
dbg->iob.read_at (dbg->iob.io, opc, obuf, sizeof (obuf));
|
|
|
|
|
|
|
|
//dbg->iob.read_at (dbg->iob.io, npc, buf, sizeof (buf));
|
|
|
|
|
|
|
|
//dbg->anal->reg = dbg->reg; // hack
|
|
|
|
ESIL->cb.hook_mem_read = &esilbreak_mem_read;
|
|
|
|
ESIL->cb.hook_mem_write = &esilbreak_mem_write;
|
|
|
|
ESIL->cb.hook_reg_read = &esilbreak_reg_read;
|
|
|
|
ESIL->cb.hook_reg_write = &esilbreak_reg_write;
|
|
|
|
|
|
|
|
if (prestep) {
|
|
|
|
// required when a exxpression is like <= == ..
|
|
|
|
// otherwise it will stop at the next instruction
|
|
|
|
if (r_debug_step (dbg, 1)<1) {
|
|
|
|
eprintf ("Step failed\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2016-07-12 20:15:19 +00:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2015-07-21 04:06:00 +00:00
|
|
|
// npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
}
|
|
|
|
|
2018-05-28 04:45:53 +00:00
|
|
|
if (r_anal_op (dbg->anal, &op, opc, obuf, sizeof (obuf), R_ANAL_OP_MASK_ESIL)) {
|
2015-07-21 04:06:00 +00:00
|
|
|
if (esilbreak_check_pc (dbg, opc)) {
|
|
|
|
eprintf ("STOP AT 0x%08"PFMT64x"\n", opc);
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
2015-09-14 09:31:54 +00:00
|
|
|
r_anal_esil_set_pc (ESIL, opc);
|
2015-07-21 04:06:00 +00:00
|
|
|
eprintf ("0x%08"PFMT64x" %s\n", opc, R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
(void)r_anal_esil_parse (ESIL, R_STRBUF_SAFEGET (&op.esil));
|
|
|
|
//r_anal_esil_dumpstack (ESIL);
|
|
|
|
r_anal_esil_stack_free (ESIL);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!prestep) {
|
|
|
|
if (ret && !has_match) {
|
|
|
|
if (r_debug_step (dbg, 1)<1) {
|
|
|
|
eprintf ("Step failed\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2016-07-12 20:15:19 +00:00
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
|
2015-07-21 04:06:00 +00:00
|
|
|
// npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API ut64 r_debug_esil_step(RDebug *dbg, ut32 count) {
|
|
|
|
count++;
|
|
|
|
has_match = 0;
|
2016-11-20 18:20:14 +00:00
|
|
|
r_cons_break_push (NULL, NULL);
|
2015-07-21 04:06:00 +00:00
|
|
|
do {
|
2016-11-20 18:20:14 +00:00
|
|
|
if (r_cons_is_breaked ()) {
|
2015-07-21 04:06:00 +00:00
|
|
|
break;
|
2016-11-20 18:20:14 +00:00
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
if (has_match) {
|
|
|
|
eprintf ("EsilBreak match at 0x%08"PFMT64x"\n", opc);
|
|
|
|
break;
|
|
|
|
}
|
2016-11-20 18:20:14 +00:00
|
|
|
if (count > 0) {
|
2015-07-21 04:06:00 +00:00
|
|
|
count--;
|
|
|
|
if (!count) {
|
|
|
|
//eprintf ("Limit reached\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (r_debug_esil_stepi (dbg));
|
2016-11-20 18:20:14 +00:00
|
|
|
r_cons_break_pop ();
|
2015-07-21 04:06:00 +00:00
|
|
|
return opc;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API ut64 r_debug_esil_continue (RDebug *dbg) {
|
|
|
|
return r_debug_esil_step (dbg, UT32_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ewps_free(EsilBreak *ew) {
|
2018-11-14 20:23:20 +00:00
|
|
|
R_FREE (ew->expr);
|
2015-07-21 04:06:00 +00:00
|
|
|
free (ew);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_esil_watch_empty(RDebug *dbg) {
|
|
|
|
return r_list_empty (EWPS);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_esil_watch(RDebug *dbg, int rwx, int dev, const char *expr) {
|
|
|
|
if (!EWPS) {
|
|
|
|
EWPS = r_list_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!EWPS) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
EWPS->free = (RListFree)ewps_free;
|
|
|
|
}
|
|
|
|
EsilBreak *ew = R_NEW0 (EsilBreak);
|
2016-05-24 20:22:15 +00:00
|
|
|
if (!ew) {
|
|
|
|
R_FREE (EWPS);
|
|
|
|
return;
|
|
|
|
}
|
2015-07-21 04:06:00 +00:00
|
|
|
ew->rwx = rwx;
|
|
|
|
ew->dev = dev;
|
|
|
|
ew->expr = strdup (expr);
|
|
|
|
r_list_append (EWPS, ew);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_esil_watch_reset(RDebug *dbg) {
|
|
|
|
r_list_free (EWPS);
|
|
|
|
EWPS = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_debug_esil_watch_list(RDebug *dbg) {
|
|
|
|
EsilBreak *ew;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (EWPS, iter, ew) {
|
2015-08-08 18:15:13 +00:00
|
|
|
dbg->cb_printf ("de %s %c %s\n", r_str_rwx_i (ew->rwx), ew->dev, ew->expr);
|
2015-07-21 04:06:00 +00:00
|
|
|
}
|
|
|
|
}
|