1 /* radare - LGPL - Copyright 2009-2020 - pancake */
2
3 #include <r_core.h>
4 #include <r_debug.h>
5 #include <sdb.h>
6 #define TN_KEY_LEN 32
7 #define TN_KEY_FMT "%"PFMT64u
8 #ifndef SIGKILL
9 #define SIGKILL 9
10 #endif
11
12 #if __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
13 #include "r_heap_glibc.h"
14 #endif
15
16 #if HAVE_JEMALLOC
17 #include "r_heap_jemalloc.h"
18 #include "linux_heap_jemalloc.c"
19 #endif
20
21 void cmd_anal_reg (RCore *core, const char *str);
22
23 static const char *help_msg_d[] = {
24 "Usage:", "d", " # Debug commands",
25 "db", "[?]", "Breakpoints commands",
26 "dbt", "[?]", "Display backtrace based on dbg.btdepth and dbg.btalgo",
27 "dc", "[?]", "Continue execution",
28 "dd", "[?]", "File descriptors (!fd in r1)",
29 "de", "[-sc] [perm] [rm] [e]", "Debug with ESIL (see de?)",
30 "dg", " <file>", "Generate a core-file (WIP)",
31 "dH", " [handler]", "Transplant process to a new handler",
32 "di", "[?]", "Show debugger backend information (See dh)",
33 "dk", "[?]", "List, send, get, set, signal handlers of child",
34 "dL", "[?]", "List or set debugger handler",
35 "dm", "[?]", "Show memory maps",
36 "do", "[?]", "Open process (reload, alias for 'oo')",
37 "doo", "[args]", "Reopen in debug mode with args (alias for 'ood')",
38 "doof", "[file]", "Reopen in debug mode from file (alias for 'oodf')",
39 "doc", "", "Close debug session",
40 "dp", "[?]", "List, attach to process or thread id",
41 "dr", "[?]", "Cpu registers",
42 "ds", "[?]", "Step, over, source line",
43 "dt", "[?]", "Display instruction traces",
44 "dw", " <pid>", "Block prompt until pid dies",
45 #if __WINDOWS__
46 "dW", "", "List process windows",
47 "dWi", "", "Identify window under cursor",
48 #endif
49 "dx", "[?]", "Inject and run code on target process (See gs)",
50 NULL
51 };
52
53 static const char *help_msg_db[] = {
54 "Usage: db", "", " # Breakpoints commands",
55 "db", "", "List breakpoints",
56 "db*", "", "List breakpoints in r commands",
57 "db", " sym.main", "Add breakpoint into sym.main",
58 "db", " <addr>", "Add breakpoint",
59 "dbH", " <addr>", "Add hardware breakpoint",
60 "db-", " <addr>", "Remove breakpoint",
61 "db-*", "", "Remove all the breakpoints",
62 "db.", "", "Show breakpoint info in current offset",
63 "dbj", "", "List breakpoints in JSON format",
64 // "dbi", " 0x848 ecx=3", "stop execution when condition matches",
65 "dbc", " <addr> <cmd>", "Run command when breakpoint is hit",
66 "dbC", " <addr> <cmd>", "Run command but continue until <cmd> returns zero",
67 "dbd", " <addr>", "Disable breakpoint",
68 "dbe", " <addr>", "Enable breakpoint",
69 "dbs", " <addr>", "Toggle breakpoint",
70 "dbf", "", "Put a breakpoint into every no-return function",
71 //
72 "dbm", " <module> <offset>", "Add a breakpoint at an offset from a module's base",
73 "dbn", " [<name>]", "Show or set name for current breakpoint",
74 //
75 "dbi", "", "List breakpoint indexes",
76 "dbi", " <addr>", "Show breakpoint index in givengiven offset",
77 "dbi.", "", "Show breakpoint index in current offset",
78 "dbi-", " <idx>", "Remove breakpoint by index",
79 "dbix", " <idx> [expr]", "Set expression for bp at given index",
80 "dbic", " <idx> <cmd>", "Run command at breakpoint index",
81 "dbie", " <idx>", "Enable breakpoint by index",
82 "dbid", " <idx>", "Disable breakpoint by index",
83 "dbis", " <idx>", "Swap Nth breakpoint",
84 "dbite", " <idx>", "Enable breakpoint Trace by index",
85 "dbitd", " <idx>", "Disable breakpoint Trace by index",
86 "dbits", " <idx>", "Swap Nth breakpoint trace",
87 //
88 "dbh", " x86", "Set/list breakpoint plugin handlers",
89 "dbh-", " <name>", "Remove breakpoint plugin handler",
90 "dbt", "[?]", "Show backtrace. See dbt? for more details",
91 "dbx", " [expr]", "Set expression for bp in current offset",
92 "dbw", " <addr> <r/w/rw>", "Add watchpoint",
93 #if __WINDOWS__
94 "dbW", " <WM_DEFINE> [?|handle|name]", "Set cond. breakpoint on a window message handler",
95 #endif
96 "drx", " number addr len perm", "Modify hardware breakpoint",
97 "drx-", "number", "Clear hardware breakpoint",
98 NULL
99 };
100
101 static const char *help_msg_dbt[] = {
102 "Usage: dbt", "", " # Backtrace commands",
103 "dbt", "", "Display backtrace based on dbg.btdepth and dbg.btalgo",
104 "dbt*", "", "Display backtrace in flags",
105 "dbt=", "", "Display backtrace in one line (see dbt=s and dbt=b for sp or bp)",
106 "dbtv", "", "Display backtrace with local vars if any",
107 "dbtj", "", "Display backtrace in JSON",
108 "dbta", "", "Display ascii-art representation of the stack backtrace",
109 "dbte", " <addr>", "Enable Breakpoint Trace",
110 "dbtd", " <addr>", "Disable Breakpoint Trace",
111 "dbts", " <addr>", "Swap Breakpoint Trace",
112 NULL
113 };
114
115 static const char *help_msg_dbw[] = {
116 "Usage: dbw", "<addr> <r/w/rw>"," # Add watchpoint",
117 NULL
118 };
119
120 static const char *help_msg_dc[] = {
121 "Usage: dc", "", "Execution continuation commands",
122 "dc", "", "Continue execution of all children",
123 "dc", " <pid>", "Continue execution of pid",
124 "dc", "[-pid]", "Stop execution of pid",
125 "dca", " [sym] [sym].", "Continue at every hit on any given symbol",
126 "dcb", "", "Continue back until breakpoint",
127 "dcc", "", "Continue until call (use step into)",
128 "dccu", "", "Continue until unknown call (call reg)",
129 #if __WINDOWS__
130 "dce", "", "Continue execution (pass exception to program)",
131 #endif
132 "dcf", "", "Continue until fork (TODO)",
133 "dck", " <signal> <pid>", "Continue sending signal to process",
134 "dcp", "", "Continue until program code (mapped io section)",
135 "dcr", "", "Continue until ret (uses step over)",
136 "dcs", "[?] <num>", "Continue until syscall",
137 "dct", " <len>", "Traptrace from curseek to len, no argument to list",
138 "dcu", "[?] [..end|addr] ([end])", "Continue until address (or range)",
139 /*"TODO: dcu/dcr needs dbg.untilover=true??",*/
140 /*"TODO: same for only user/libs side, to avoid steping into libs",*/
141 /*"TODO: support for threads?",*/
142 NULL
143 };
144
145 static const char *help_msg_dcs[] = {
146 "Usage:", "dcs", " Continue until syscall",
147 "dcs", "", "Continue until next syscall",
148 "dcs [str]", "", "Continue until next call to the 'str' syscall",
149 "dcs", "*", "Trace all syscalls, a la strace",
150 NULL
151 };
152
153 static const char *help_msg_dcu[] = {
154 "Usage:", "dcu", " Continue until address",
155 "dcu.", "", "Alias for dcu $$ (continue until current address",
156 "dcu", " address", "Continue until address",
157 "dcu", " [..tail]", "Continue until the range",
158 "dcu", " [from] [to]", "Continue until the range",
159 NULL
160 };
161
162 static const char *help_msg_dd[] = {
163 "Usage: dd", "", "Descriptors commands",
164 "dd", "", "List file descriptors",
165 "dd", " <file>", "Open and map that file into the UI",
166 "dd-", "<fd>", "Close stdout fd",
167 "dd*", "", "List file descriptors (in radare commands)",
168 "dds", " <fd> <off>", "Seek given fd)",
169 "ddd", " <fd1> <fd2>", "Dup2 from fd1 to fd2",
170 "ddr", " <fd> <size>", "Read N bytes from fd",
171 "ddw", " <fd> <hexpairs>", "Write N bytes to fd",
172 NULL
173 };
174
175 static const char *help_msg_de[] = {
176 "Usage:", "de", "[-sc] [perm] [rm] [expr]",
177 "de", "", "List esil watchpoints",
178 "de-*", "", "Delete all esil watchpoints",
179 "de", " [perm] [rm] [addr|reg|from..to]", "Stop on condition",
180 "dec", "", "Continue execution until matching expression",
181 "des", "[?] [N]", "Step-in N instructions with esildebug",
182 "desu", " [addr]", "Esildebug until specific address",
183 NULL
184 };
185
186 static const char *help_msg_des[] = {
187 "Usage:", "des", "[u] [arg]",
188 "des", " [N]", "step-in N instructions with esildebug",
189 "desu", " [addr]", "esildebug until specific address",
190 NULL
191 };
192
193 static const char *help_msg_di[] = {
194 "Usage: di", "", "Debugger target information",
195 "di", "", "Show debugger target information",
196 "di*", "", "Same as above, but in r2 commands",
197 "diq", "", "Same as above, but in one line",
198 "dij", "", "Same as above, but in JSON format",
199 "dif", " [$a] [$b]", "Compare two files (or $alias files)",
200 NULL
201 };
202
203 static const char *help_msg_dk[] = {
204 "Usage: dk", "", "Signal commands",
205 "dk", "", "List all signal handlers of child process",
206 "dk", " <signal>", "Send KILL signal to child",
207 "dk", " <signal>=1", "Set signal handler for <signal> in child",
208 "dk?", "<signal>", "Name/signum resolver",
209 "dko", "[?] <signal>", "Reset skip or cont options for given signal",
210 "dko", " <signal> [|skip|cont]", "On signal SKIP handler or CONT into",
211 "dkj", "", "List all signal handlers in JSON",
212 NULL
213 };
214
215 static const char *help_msg_dko[] = {
216 "Usage:", "dko", " # Signal handling commands",
217 "dko", "", "List existing signal handling",
218 "dko", " [signal]", "Clear handling for a signal",
219 "dko", " [signal] [skip|cont]", "Set handling for a signal",
220 NULL
221 };
222
223 static const char *help_msg_dm[] = {
224 "Usage:", "dm", " # Memory maps commands",
225 "dm", "", "List memory maps of target process",
226 "dm", " address size", "Allocate <size> bytes at <address> (anywhere if address is -1) in child process",
227 "dm=", "", "List memory maps of target process (ascii-art bars)",
228 "dm.", "", "Show map name of current address",
229 "dm*", "", "List memmaps in radare commands",
230 "dm-", " address", "Deallocate memory map of <address>",
231 "dmd", "[a] [file]", "Dump current (all) debug map region to a file (from-to.dmp) (see Sd)",
232 "dmh", "[?]", "Show map of heap",
233 "dmi", " [addr|libname] [symname]", "List symbols of target lib",
234 "dmi*", " [addr|libname] [symname]", "List symbols of target lib in radare commands",
235 "dmi.", "", "List closest symbol to the current address",
236 "dmiv", "", "Show address of given symbol for given lib",
237 "dmj", "", "List memmaps in JSON format",
238 "dml", " <file>", "Load contents of file into the current map region",
239 "dmm", "[?][j*]", "List modules (libraries, binaries loaded in memory)",
240 "dmp", "[?] <address> <size> <perms>", "Change page at <address> with <size>, protection <perms> (perm)",
241 "dms", "[?] <id> <mapaddr>", "Take memory snapshot",
242 "dms-", " <id> <mapaddr>", "Restore memory snapshot",
243 "dmS", " [addr|libname] [sectname]", "List sections of target lib",
244 "dmS*", " [addr|libname] [sectname]", "List sections of target lib in radare commands",
245 "dmL", " address size", "Allocate <size> bytes at <address> and promote to huge page",
246 //"dm, " rw- esp 9K", "set 9KB of the stack as read+write (no exec)",
247 "TODO:", "", "map files in process memory. (dmf file @ [addr])",
248 NULL
249 };
250
251 static const char *help_msg_dmi[] = {
252 "Usage: dmi", "", " # List/Load Symbols",
253 "dmi", "[j|q|*] [libname] [symname]", "List symbols of target lib",
254 "dmia", "[j|q|*] [libname]", "List all info of target lib",
255 "dmi*", "", "List symbols of target lib in radare commands",
256 "dmi.", "", "List closest symbol to the current address",
257 "dmiv", "", "Show address of given symbol for given lib",
258 NULL
259 };
260
261 static const char *help_msg_dmm[] = {
262 "Usage:", "dmm", " # Module memory maps commands",
263 "dmm", "", "List modules of target process",
264 "dmm*", "", "List modules of target process (r2 commands)",
265 "dmm.", "", "List memory map of current module",
266 "dmmj", "", "List modules of target process (JSON)",
267 NULL
268 };
269
270 static const char *help_msg_dmp[] = {
271 "Usage:", "dmp", " Change page permissions",
272 "dmp", " [addr] [size] [perms]", "Change permissions",
273 "dmp", " [perms]", "Change dbg.map permissions",
274 NULL
275 };
276
277 static const char *help_msg_do[] = {
278 "Usage:", "do", " # Debug (re)open commands",
279 "do", "", "Open process (reload, alias for 'oo')",
280 "dor", " [rarun2]", "Comma separated list of k=v rarun2 profile options (e dbg.profile)",
281 "doe", "", "Show rarun2 startup profile",
282 "doe!", "", "Edit rarun2 startup profile with $EDITOR",
283 "doo", " [args]", "Reopen in debug mode with args (alias for 'ood')",
284 "doof", " [args]", "Reopen in debug mode from file (alias for 'oodf')",
285 "doc", "", "Close debug session",
286 NULL
287 };
288
289 static const char *help_msg_dp[] = {
290 "Usage:", "dp", " # Process commands",
291 "dp", "", "List current pid and children",
292 "dp", " <pid>", "List children of pid",
293 "dpj", " <pid>", "List children of pid in JSON format",
294 "dpl", "", "List all attachable pids",
295 "dplj", "", "List all attachable pids in JSON format",
296 "dp-", " <pid>", "Detach select pid",
297 "dp=", "<pid>", "Select pid",
298 "dpa", " <pid>", "Attach and select pid",
299 "dpc", "", "Select forked pid (see dbg.forks)",
300 "dpc*", "", "Display forked pid (see dbg.forks)",
301 "dpe", "", "Show path to executable",
302 "dpf", "", "Attach to pid like file fd // HACK",
303 "dpk", " <pid> [<signal>]", "Send signal to process (default 0)",
304 "dpn", "", "Create new process (fork)",
305 "dptn", "", "Create new thread (clone)",
306 "dpt", "", "List threads of current pid",
307 "dptj", "", "List threads of current pid in JSON format",
308 "dpt", " <pid>", "List threads of process",
309 "dptj", " <pid>", "List threads of process in JSON format",
310 "dpt=", "<thread>", "Attach to thread",
311 NULL
312 };
313
314 static const char *help_msg_dr[] = {
315 "Usage: dr", "", "Registers commands",
316 "dr", "", "Show 'gpr' registers",
317 "dr", " <register>=<val>", "Set register value",
318 "dr.", " >$snapshot", "Capture current register values in r2 alias file",
319 "dr,", " [table-query]", "Enumerate registers in table format",
320 "dr8", "[1|2|4|8] [type]", "Display hexdump of gpr arena (WIP)",
321 "dr=", "", "Show registers in columns",
322 "dr?", "<register>", "Show value of given register",
323 "dr??", "", "Same as dr?`drp~=[0]+` # list all reg roles alias names and values",
324 "dra", "[?]", "Manage register arenas. see ara?",
325 "drb", "[1|2|4|8] [type]", "Display hexdump of gpr arena (WIP)",
326 "drc", " [name]", "Related to conditional flag registers",
327 "drC", " [register]", "Show register comments",
328 "drd", "", "Show only different registers",
329 "drf", "", "Show fpu registers (80 bit long double)",
330 "dri", "", "Show inverse registers dump (sorted by value)",
331 "drl", "[j]", "List all register names",
332 "drm", "[?]", "Show multimedia packed registers",
333 // "drm", " xmm0 0 32 = 12", "Set the first 32 bit word of the xmm0 reg to 12", // Do not advertise - broken
334 "dro", "", "Show previous (old) values of registers",
335 "drp", "[?] ", "Display current register profile",
336 "drr", "", "Show registers references (telescoping)",
337 "drrj", "", "Show registers references (telescoping) in JSON format",
338 // TODO: 'drs' to swap register arenas and display old register valuez
339 "drs", "[?]", "Stack register states",
340 "drS", "", "Show the size of the register profile",
341 "drt", "[?]", "Show all register types",
342 "drw"," <hexnum>", "Set contents of the register arena",
343 "drx", "[?]", "Show debug registers",
344 ".dr", "*", "Include common register values in flags",
345 ".dr", "-", "Unflag all registers",
346 NULL
347 };
348
349 static const char *help_msg_drp[] = {
350 "Usage:", "drp", " # Register profile commands",
351 "drp", "", "Show the current register profile",
352 "drp", " [regprofile-file]", "Set the current register profile",
353 "drp", " [gdb] [regprofile-file]", "Parse gdb register profile and dump an r2 profile string",
354 "drpc", "", "Show register profile comments",
355 "drpi", "", "Show internal representation of the register profile",
356 "drp.", "", "Show the current fake size",
357 "drpj", "", "Show the current register profile (JSON)",
358 "drps", " [new fake size]", "Set the fake size",
359 NULL
360 };
361
362 static const char *help_msg_drs[] = {
363 "Usage:", "drs", "register states commands",
364 "drs", "", "list register stack",
365 "drs", "+", "push register state",
366 "drs", "-", "pop register state",
367 NULL
368 };
369
370 static const char *help_msg_drt[] = {
371 "Usage:", "drt", " [type] [size] # debug register types",
372 "drt", "", "List all available register types",
373 "drt", " [size]", "Show all regs in the profile of size",
374 "drt", " 16", "Show 16 bit registers",
375 "drt", " [type]", "Show all regs in the profile of this type",
376 "drt", " all", "Show all registers",
377 "drt", " fpu", "Show fpu registers",
378 "drt", " [type] [size]", "Same as above for type and size",
379 "drt", " [type] [size]", "Same as above for type and size",
380 "drt*", "", "List flags in r commands",
381 NULL
382 };
383
384 static const char *help_msg_drx[] = {
385 "Usage: drx", "", "Hardware breakpoints commands",
386 "drx", "", "List all (x86?) hardware breakpoints",
387 "drx", " <number> <address> <length> <perms>", "Modify hardware breakpoint",
388 "drx-", "<number>", "Clear hardware breakpoint",
389 NULL
390 };
391
392
393 static const char *help_msg_drm[] = {
394 "Usage: drm", " [reg] [idx] [wordsize] [= value]", "Show multimedia packed registers",
395 "drm", "", "Show XMM registers",
396 "drm", " xmm0", "Show all packings of xmm0",
397 "drm", " xmm0 0 32 = 12", "Set the first 32 bit word of the xmm0 reg to 12",
398 "drmb", " [reg]", "Show registers as bytes",
399 "drmw", " [reg]", "Show registers as words",
400 "drmd", " [reg]", "Show registers as doublewords",
401 "drmq", " [reg]", "Show registers as quadwords",
402 "drmq", " xmm0~[0]", "Show first quadword of xmm0",
403 "drmf", " [reg]", "Show registers as 32-bit floating point",
404 "drml", " [reg]", "Show registers as 64-bit floating point",
405 "drmyb", " [reg]", "Show YMM registers as bytes",
406 "drmyw", " [reg]", "Show YMM registers as words",
407 "drmyd", " [reg]", "Show YMM registers as doublewords",
408 "drmyq", " [reg]", "Show YMM registers as quadwords",
409 "drmq", " ymm0~[3]", "Show fourth quadword of ymm0",
410 "drmyf", " [reg]", "Show YMM registers as 32-bit floating point",
411 "drmyl", " [reg]", "Show YMM registers as 64-bit floating point",
412 NULL
413 };
414
415 static const char *help_msg_ds[] = {
416 "Usage: ds", "", "Step commands",
417 "ds", "", "Step one instruction",
418 "ds", " <num>", "Step <num> instructions",
419 "dsb", "", "Step back one instruction",
420 "dsf", "", "Step until end of frame",
421 "dsi", " <cond>", "Continue until condition matches",
422 "dsl", "", "Step one source line",
423 "dsl", " <num>", "Step <num> source lines",
424 "dso", " <num>", "Step over <num> instructions",
425 "dsp", "", "Step into program (skip libs)",
426 "dss", " <num>", "Skip <num> step instructions",
427 "dsu", "[?] <address>", "Step until <address>. See 'dsu?' for other step until cmds.",
428 NULL
429 };
430
431 static const char *help_msg_dsu[] = {
432 "Usage: dsu", "", "Step until commands",
433 "dsu", " <address>", "Step until <address>",
434 "dsui", "[r] <instr>", "Step until an instruction that matches <instr>, use dsuir for regex match",
435 "dsuo", " <optype> [<optype> ...]", "Step until an instr matches one of the <optype>s.",
436 "dsue", " <esil>", "Step until <esil> expression matches",
437 "dsuf", " <flag>", "Step until pc == <flag> matching name",
438 NULL
439 };
440
441 static const char *help_msg_dt[] = {
442 "Usage: dt", "", "Trace commands",
443 "dt", "", "List all traces ",
444 "dt", " [addr]", "Show trace info at address",
445 "dt%", "", "TODO",
446 "dt*", "", "List all traced opcode offsets",
447 "dt+"," [addr] [times]", "Add trace for address N times",
448 "dt-", "", "Reset traces (instruction/calls)",
449 "dt=", "", "Show ascii-art color bars with the debug trace ranges",
450 "dta", " 0x804020 ...", "Only trace given addresses",
451 "dtc[?][addr]|([from] [to] [addr])", "", "Trace call/ret",
452 "dtd", "[qi] [nth-start]", "List all traced disassembled (quiet, instructions)",
453 "dte", "[?]", "Show esil trace logs",
454 "dtg", "", "Graph call/ret trace",
455 "dtg*", "", "Graph in agn/age commands. use .dtg*;aggi for visual",
456 "dtgi", "", "Interactive debug trace",
457 "dts", "[?]", "Trace sessions",
458 "dtt", " [tag]", "Select trace tag (no arg unsets)",
459 NULL
460 };
461
462 static const char *help_msg_dte[] = {
463 "Usage:", "dte", " Show esil trace logs",
464 "dte", "", "Esil trace log for a single instruction",
465 "dte", " [idx]", "Show commands for that index log",
466 "dte", "-*", "Delete all esil traces",
467 "dtei", "", "Esil trace log single instruction",
468 "dtek", " [sdb query]", "Esil trace log single instruction from sdb",
469 NULL
470 };
471
472 static const char *help_msg_dts[] = {
473 "Usage:", "dts[*]", "",
474 "dts+", "", "Start trace session",
475 "dts-", "", "Stop trace session",
476 "dtst", " [dir] ", "Save trace sessions to disk",
477 "dtsf", " [dir] ", "Read trace sessions from disk",
478 "dtsm", "", "List current memory map and hash",
479 NULL
480 };
481
482 static const char *help_msg_dx[] = {
483 "Usage: dx", "", " # Code injection commands",
484 "dx", " <opcode>...", "Inject opcodes",
485 "dxa", " nop", "Assemble code and inject",
486 "dxe", " egg-expr", "Compile egg expression and inject it",
487 "dxr", " <opcode>...", "Inject opcodes and restore state",
488 "dxs", " write 1, 0x8048, 12", "Syscall injection (see gs)",
489 "\nExamples:", "", "",
490 "dx", " 9090", "Inject two x86 nop",
491 "\"dxa mov eax,6;mov ebx,0;int 0x80\"", "", "Inject and restore state",
492 NULL
493 };
494
495 static const char *help_msg_dL[] = {
496 "Usage: dL", "", " # List or set debugger handler",
497 "dL", "", "List debugger handlers",
498 "dLq", "", "List debugger handlers in quiet mode",
499 "dLj", "", "List debugger handlers in json mode",
500 "dL", " <handler>", "Set debugger handler",
501 NULL
502 };
503
504 struct dot_trace_ght {
505 RGraph *graph;
506 Sdb *graphnodes;
507 };
508
509 struct trace_node {
510 ut64 addr;
511 int refs;
512 };
513
cmd_debug_init(RCore * core,RCmdDesc * parent)514 static void cmd_debug_init(RCore *core, RCmdDesc *parent) {
515 DEFINE_CMD_DESCRIPTOR (core, d);
516 DEFINE_CMD_DESCRIPTOR (core, db);
517 DEFINE_CMD_DESCRIPTOR (core, dbt);
518 DEFINE_CMD_DESCRIPTOR (core, dc);
519 DEFINE_CMD_DESCRIPTOR (core, dcs);
520 DEFINE_CMD_DESCRIPTOR (core, dcu);
521 DEFINE_CMD_DESCRIPTOR (core, dd);
522 DEFINE_CMD_DESCRIPTOR (core, de);
523 DEFINE_CMD_DESCRIPTOR (core, des);
524 DEFINE_CMD_DESCRIPTOR (core, di);
525 DEFINE_CMD_DESCRIPTOR (core, dk);
526 DEFINE_CMD_DESCRIPTOR (core, dko);
527 DEFINE_CMD_DESCRIPTOR (core, dm);
528 DEFINE_CMD_DESCRIPTOR (core, dmi);
529 DEFINE_CMD_DESCRIPTOR (core, dmm);
530 DEFINE_CMD_DESCRIPTOR (core, dmp);
531 DEFINE_CMD_DESCRIPTOR (core, do);
532 DEFINE_CMD_DESCRIPTOR (core, dp);
533 DEFINE_CMD_DESCRIPTOR (core, dr);
534 DEFINE_CMD_DESCRIPTOR (core, drp);
535 DEFINE_CMD_DESCRIPTOR (core, drs);
536 DEFINE_CMD_DESCRIPTOR (core, drt);
537 DEFINE_CMD_DESCRIPTOR (core, drx);
538 DEFINE_CMD_DESCRIPTOR (core, ds);
539 DEFINE_CMD_DESCRIPTOR (core, dt);
540 DEFINE_CMD_DESCRIPTOR (core, dte);
541 DEFINE_CMD_DESCRIPTOR (core, dts);
542 DEFINE_CMD_DESCRIPTOR (core, dx);
543 }
544
545 // XXX those tmp files are never removed and we shuoldnt use files for this
setRarunProfileString(RCore * core,const char * str)546 static void setRarunProfileString(RCore *core, const char *str) {
547 char *file = r_file_temp ("rarun2");
548 char *s = strdup (str);
549 r_config_set (core->config, "dbg.profile", file);
550 r_str_replace_char (s, ',', '\n');
551 r_file_dump (file, (const ut8*)s, strlen (s), 0);
552 r_file_dump (file, (const ut8*)"\n", 1, 1);
553 free (file);
554 }
555
cmd_debug_cont_syscall(RCore * core,const char * _str)556 static void cmd_debug_cont_syscall (RCore *core, const char *_str) {
557 // TODO : handle more than one stopping syscall
558 int i, *syscalls = NULL;
559 int count = 0;
560 if (_str && *_str) {
561 char *str = strdup (_str);
562 count = r_str_word_set0 (str);
563 syscalls = calloc (sizeof (int), count);
564 for (i = 0; i < count; i++) {
565 const char *sysnumstr = r_str_word_get0 (str, i);
566 int sig = (int)r_num_math (core->num, sysnumstr);
567 if (sig == -1) { // trace ALL syscalls
568 syscalls[i] = -1;
569 } else if (sig == 0) {
570 sig = r_syscall_get_num (core->anal->syscall, sysnumstr);
571 if (sig == -1) {
572 eprintf ("Unknown syscall number\n");
573 free (str);
574 free (syscalls);
575 return;
576 }
577 syscalls[i] = sig;
578 }
579 }
580 eprintf ("Running child until syscalls:");
581 for (i = 0; i < count; i++) {
582 eprintf ("%d ", syscalls[i]);
583 }
584 eprintf ("\n");
585 free (str);
586 } else {
587 eprintf ("Running child until next syscall\n");
588 }
589 r_reg_arena_swap (core->dbg->reg, true);
590 r_debug_continue_syscalls (core->dbg, syscalls, count);
591 free (syscalls);
592 }
593
showreg(RCore * core,const char * str)594 static int showreg(RCore *core, const char *str) {
595 int size = 0;
596 RRegItem *r = 0;
597 const char *rname = str;
598 // check for alias reg
599 int role = r_reg_get_name_idx (str);
600 if (role != -1) {
601 rname = r_reg_get_name (core->dbg->reg, role);
602 }
603 r = r_reg_get (core->dbg->reg, rname , -1);
604 if (r) {
605 ut64 off;
606 utX value;
607 if (r->size > 64) {
608 off = r_reg_get_value_big (core->dbg->reg, r, &value);
609 switch (r->size) {
610 case 80:
611 r_cons_printf ("0x%04x%016"PFMT64x"\n", value.v80.High, value.v80.Low);
612 break;
613 case 96:
614 r_cons_printf ("0x%08x%016"PFMT64x"\n", value.v96.High, value.v96.Low);
615 break;
616 case 128:
617 r_cons_printf ("0x%016"PFMT64x"%016"PFMT64x"\n", value.v128.High, value.v128.Low);
618 break;
619 case 256:
620 r_cons_printf ("0x%016"PFMT64x"%016"PFMT64x"%016"PFMT64x"%016"PFMT64x"\n",
621 value.v256.High.High, value.v256.High.Low, value.v256.Low.High, value.v256.Low.Low);
622 break;
623 default:
624 r_cons_printf ("Error while retrieving reg '%s' of %i bits\n", str +1, r->size);
625 }
626 } else {
627 off = r_reg_get_value (core->dbg->reg, r);
628 r_cons_printf ("0x%08"PFMT64x "\n", off);
629 }
630 return r->size;
631 }
632 char *arg = strchr (str + 1, ' ');
633 if (arg && size == 0) {
634 size = atoi (arg + 1);
635 } else {
636 size = atoi (str + 1);
637 }
638 return size;
639 }
640
get_graphtrace_node(RGraph * g,Sdb * nodes,struct trace_node * tn)641 static RGraphNode *get_graphtrace_node (RGraph *g, Sdb *nodes, struct trace_node *tn) {
642 RGraphNode *gn;
643 char tn_key[TN_KEY_LEN];
644
645 snprintf (tn_key, TN_KEY_LEN, TN_KEY_FMT, tn->addr);
646 gn = (RGraphNode *)(size_t)sdb_num_get (nodes, tn_key, NULL);
647 if (!gn) {
648 gn = r_graph_add_node (g, tn);
649 sdb_num_set (nodes, tn_key, (ut64)(size_t)gn, 0);
650 }
651 return gn;
652 }
653
dot_trace_create_node(RTreeNode * n,RTreeVisitor * vis)654 static void dot_trace_create_node (RTreeNode *n, RTreeVisitor *vis) {
655 struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
656 struct trace_node *tn = n->data;
657 if (tn) get_graphtrace_node (data->graph, data->graphnodes, tn);
658 }
659
dot_trace_discover_child(RTreeNode * n,RTreeVisitor * vis)660 static void dot_trace_discover_child (RTreeNode *n, RTreeVisitor *vis) {
661 struct dot_trace_ght *data = (struct dot_trace_ght *)vis->data;
662 RGraph *g = data->graph;
663 Sdb *gnodes = data->graphnodes;
664 RTreeNode *parent = n->parent;
665 struct trace_node *tn = n->data;
666 struct trace_node *tn_parent = parent->data;
667
668 if (tn && tn_parent) {
669 RGraphNode *gn = get_graphtrace_node (g, gnodes, tn);
670 RGraphNode *gn_parent = get_graphtrace_node (g, gnodes, tn_parent);
671
672 if (!r_graph_adjacent (g, gn_parent, gn))
673 r_graph_add_edge (g, gn_parent, gn);
674 }
675 }
676
dot_trace_traverse(RCore * core,RTree * t,int fmt)677 static void dot_trace_traverse(RCore *core, RTree *t, int fmt) {
678 const char *gfont = r_config_get (core->config, "graph.font");
679 struct dot_trace_ght aux_data;
680 RTreeVisitor vis = { 0 };
681 const RList *nodes;
682 RListIter *iter;
683 RGraphNode *n;
684
685 if (fmt == 'i') {
686 r_core_cmd0 (core, "ag-;.dtg*;aggi");
687 return;
688 }
689 aux_data.graph = r_graph_new ();
690 aux_data.graphnodes = sdb_new0 ();
691
692 /* build a callgraph from the execution trace */
693 vis.data = &aux_data;
694 vis.pre_visit = (RTreeNodeVisitCb)dot_trace_create_node;
695 vis.discover_child = (RTreeNodeVisitCb)dot_trace_discover_child;
696 r_tree_bfs (t, &vis);
697
698 /* traverse the callgraph to print the dot file */
699 nodes = r_graph_get_nodes (aux_data.graph);
700 if (fmt == 0) {
701 r_cons_printf ("digraph code {\n"
702 "graph [bgcolor=white];\n"
703 " node [color=lightgray, style=filled"
704 " shape=box fontname=\"%s\" fontsize=\"8\"];\n", gfont);
705 }
706 r_list_foreach (nodes, iter, n) {
707 struct trace_node *tn = (struct trace_node *)n->data;
708 const RList *neighbours = r_graph_get_neighbours (aux_data.graph, n);
709 RListIter *it_n;
710 RGraphNode *w;
711
712 if (!fmt && tn) {
713 r_cons_printf ("\"0x%08"PFMT64x"\" [URL=\"0x%08"PFMT64x
714 "\" color=\"lightgray\" label=\"0x%08"PFMT64x
715 " (%d)\"]\n", tn->addr, tn->addr, tn->addr, tn->refs);
716 }
717 r_list_foreach (neighbours, it_n, w) {
718 struct trace_node *tv = (struct trace_node *)w->data;
719
720 if (tv && tn) {
721 if (fmt) {
722 r_cons_printf ("agn 0x%08"PFMT64x"\n", tn->addr);
723 r_cons_printf ("agn 0x%08"PFMT64x"\n", tv->addr);
724 r_cons_printf ("age 0x%08"PFMT64x" 0x%08"PFMT64x"\n",
725 tn->addr, tv->addr);
726 } else {
727 r_cons_printf ("\"0x%08"PFMT64x"\" -> \"0x%08"PFMT64x
728 "\" [color=\"red\"];\n", tn->addr, tv->addr);
729 }
730 }
731 }
732 }
733 if (!fmt) {
734 r_cons_printf ("}\n");
735 }
736
737 r_graph_free (aux_data.graph);
738 sdb_free (aux_data.graphnodes);
739 }
740
741 /* TODO: refactor all those step_until* function into a single one
742 * TODO: handle when the process is dead
743 * TODO: handle ^C */
744
step_until(RCore * core,ut64 addr)745 static int step_until(RCore *core, ut64 addr) {
746 ut64 off = r_debug_reg_get (core->dbg, "PC");
747 if (!off) {
748 eprintf ("Cannot 'drn PC'\n");
749 return false;
750 }
751 if (!addr) {
752 eprintf ("Cannot continue until address 0\n");
753 return false;
754 }
755 r_cons_break_push (NULL, NULL);
756 do {
757 if (r_cons_is_breaked ()) {
758 core->break_loop = true;
759 break;
760 }
761 if (r_debug_is_dead (core->dbg)) {
762 core->break_loop = true;
763 break;
764 }
765 r_debug_step (core->dbg, 1);
766 off = r_debug_reg_get (core->dbg, "PC");
767 // check breakpoint here
768 } while (off != addr);
769 r_cons_break_pop ();
770 return true;
771 }
772
step_until_esil(RCore * core,const char * esilstr)773 static int step_until_esil(RCore *core, const char *esilstr) {
774 if (!core || !esilstr || !core->dbg || !core->dbg->anal \
775 || !core->dbg->anal->esil) {
776 eprintf ("Not initialized %p. Run 'aei' first.\n", core->anal->esil);
777 return false;
778 }
779 r_cons_break_push (NULL, NULL);
780 for (;;) {
781 if (r_cons_is_breaked ()) {
782 core->break_loop = true;
783 break;
784 }
785 if (r_debug_is_dead (core->dbg)) {
786 core->break_loop = true;
787 break;
788 }
789 r_debug_step (core->dbg, 1);
790 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false);
791 if (r_anal_esil_condition (core->anal->esil, esilstr)) {
792 eprintf ("ESIL BREAK!\n");
793 break;
794 }
795 }
796 r_cons_break_pop ();
797 return true;
798 }
799
is_repeatable_inst(RCore * core,ut64 addr)800 static bool is_repeatable_inst(RCore *core, ut64 addr) {
801 // we have read the bytes already
802 RAnalOp *op = r_core_op_anal (core, addr, R_ANAL_OP_MASK_ALL);
803 bool ret = op && ((op->prefix & R_ANAL_OP_PREFIX_REP) || (op->prefix & R_ANAL_OP_PREFIX_REPNE));
804 r_anal_op_free (op);
805 return ret;
806 }
807
step_until_inst(RCore * core,const char * instr,bool regex)808 static int step_until_inst(RCore *core, const char *instr, bool regex) {
809 RAsmOp asmop;
810 ut8 buf[32];
811 ut64 pc;
812 int ret;
813 bool is_x86 = r_str_startswith (r_config_get (core->config, "asm.arch"), "x86");
814
815 instr = r_str_trim_head_ro (instr);
816 if (!core || !instr|| !core->dbg) {
817 eprintf ("Wrong state\n");
818 return false;
819 }
820 r_cons_break_push (NULL, NULL);
821 for (;;) {
822 if (r_cons_is_breaked ()) {
823 break;
824 }
825 if (r_debug_is_dead (core->dbg)) {
826 break;
827 }
828 pc = r_debug_reg_get (core->dbg, "PC");
829 if (is_x86 && is_repeatable_inst (core, pc)) {
830 r_debug_step_over (core->dbg, 1);
831 } else {
832 r_debug_step (core->dbg, 1);
833 }
834 pc = r_debug_reg_get (core->dbg, "PC");
835 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false);
836 /* TODO: disassemble instruction and strstr */
837 r_asm_set_pc (core->rasm, pc);
838 // TODO: speedup if instructions are in the same block as the previous
839 r_io_read_at (core->io, pc, buf, sizeof (buf));
840 ret = r_asm_disassemble (core->rasm, &asmop, buf, sizeof (buf));
841 eprintf ("0x%08"PFMT64x" %d %s\n", pc, ret, r_asm_op_get_asm (&asmop)); // asmop.buf_asm);
842 if (ret > 0) {
843 const char *buf_asm = r_asm_op_get_asm (&asmop);
844 if (regex) {
845 if (r_regex_match (instr, "e", buf_asm)) {
846 eprintf ("Stop.\n");
847 break;
848 }
849 } else {
850 if (strstr (buf_asm, instr)) {
851 eprintf ("Stop.\n");
852 break;
853 }
854 }
855 }
856 }
857 r_cons_break_pop ();
858 return true;
859 }
860
step_until_optype(RCore * core,const char * _optypes)861 static int step_until_optype(RCore *core, const char *_optypes) {
862 RAnalOp op;
863 ut8 buf[32];
864 ut64 pc;
865 int res = true;
866
867 RList *optypes_list = NULL;
868 RListIter *iter;
869 char *optype, *optypes = strdup (r_str_trim_head_ro ((char *) _optypes));
870
871 if (!core || !core->dbg) {
872 eprintf ("Wrong state\n");
873 res = false;
874 goto end;
875 }
876 if (!optypes || !*optypes) {
877 eprintf ("Missing optypes. Usage example: 'dsuo ucall ujmp'\n");
878 res = false;
879 goto end;
880 }
881
882 bool debugMode = r_config_get_i (core->config, "cfg.debug");
883 optypes_list = r_str_split_list (optypes, " ", 0);
884
885 r_cons_break_push (NULL, NULL);
886 for (;;) {
887 if (r_cons_is_breaked ()) {
888 core->break_loop = true;
889 break;
890 }
891 if (debugMode) {
892 if (r_debug_is_dead (core->dbg)) {
893 core->break_loop = true;
894 break;
895 }
896 r_debug_step (core->dbg, 1);
897 pc = r_debug_reg_get (core->dbg, core->dbg->reg->name[R_REG_NAME_PC]);
898 // 'Copy' from r_debug_step_soft
899 if (!core->dbg->iob.read_at) {
900 eprintf ("ERROR\n");
901 res = false;
902 goto cleanup_after_push;
903 }
904 if (!core->dbg->iob.read_at (core->dbg->iob.io, pc, buf, sizeof (buf))) {
905 eprintf ("ERROR\n");
906 res = false;
907 goto cleanup_after_push;
908 }
909 } else {
910 r_core_esil_step (core, UT64_MAX, NULL, NULL, false);
911 pc = r_reg_getv (core->anal->reg, "PC");
912 }
913 r_io_read_at (core->io, pc, buf, sizeof (buf));
914
915 if (!r_anal_op (core->dbg->anal, &op, pc, buf, sizeof (buf), R_ANAL_OP_MASK_BASIC)) {
916 eprintf ("Error: r_anal_op failed\n");
917 res = false;
918 goto cleanup_after_push;
919 }
920
921 // This is slow because we do lots of strcmp's.
922 // To improve this, the function r_anal_optype_string_to_int should be implemented
923 // I also don't check if the opcode type exists.
924 const char *optype_str = r_anal_optype_to_string (op.type);
925 r_list_foreach (optypes_list, iter, optype) {
926 if (!strcmp (optype_str, optype)) {
927 goto cleanup_after_push;
928 }
929 }
930 }
931
932 cleanup_after_push:
933 r_cons_break_pop ();
934 end:
935 free (optypes);
936 r_list_free (optypes_list);
937 return res;
938 }
939
step_until_flag(RCore * core,const char * instr)940 static int step_until_flag(RCore *core, const char *instr) {
941 const RList *list;
942 RListIter *iter;
943 RFlagItem *f;
944 ut64 pc;
945
946 instr = r_str_trim_head_ro (instr);
947 if (!core || !instr || !core->dbg) {
948 eprintf ("Wrong state\n");
949 return false;
950 }
951 r_cons_break_push (NULL, NULL);
952 for (;;) {
953 if (r_cons_is_breaked ()) {
954 break;
955 }
956 if (r_debug_is_dead (core->dbg)) {
957 break;
958 }
959 r_debug_step (core->dbg, 1);
960 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false);
961 pc = r_debug_reg_get (core->dbg, "PC");
962 list = r_flag_get_list (core->flags, pc);
963 r_list_foreach (list, iter, f) {
964 if (!instr|| !*instr || (f->realname && strstr(f->realname, instr))) {
965 r_cons_printf ("[ 0x%08"PFMT64x" ] %s\n",
966 f->offset, f->realname);
967 goto beach;
968 }
969 }
970 }
971 beach:
972 r_cons_break_pop ();
973 return true;
974 }
975
976 /* until end of frame */
step_until_eof(RCore * core)977 static int step_until_eof(RCore *core) {
978 int maxLoops = 200000;
979 ut64 off, now = r_debug_reg_get (core->dbg, "SP");
980 r_cons_break_push (NULL, NULL);
981 do {
982 // XXX (HACK!)
983 r_debug_step_over (core->dbg, 1);
984 off = r_debug_reg_get (core->dbg, "SP");
985 // check breakpoint here
986 if (--maxLoops < 0) {
987 eprintf ("Step loop limit exceeded\n");
988 break;
989 }
990 } while (off <= now);
991 r_cons_break_pop ();
992 return true;
993 }
994
step_line(RCore * core,int times)995 static int step_line(RCore *core, int times) {
996 char file[512], file2[512];
997 int find_meta, line = -1, line2 = -1;
998 char *tmp_ptr = NULL;
999 ut64 off = r_debug_reg_get (core->dbg, "PC");
1000 if (off == 0LL) {
1001 eprintf ("Cannot 'drn PC'\n");
1002 return false;
1003 }
1004 file[0] = 0;
1005 file2[0] = 0;
1006 if (r_bin_addr2line (core->bin, off, file, sizeof (file), &line)) {
1007 char* ptr = r_file_slurp_line (file, line, 0);
1008 eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file, line);
1009 eprintf ("--> %s\n", ptr);
1010 find_meta = false;
1011 free (ptr);
1012 } else {
1013 eprintf ("--> Stepping until dwarf line\n");
1014 find_meta = true;
1015 }
1016 do {
1017 r_debug_step (core->dbg, 1);
1018 off = r_debug_reg_get (core->dbg, "PC");
1019 if (!r_bin_addr2line (core->bin, off, file2, sizeof (file2), &line2)) {
1020 if (find_meta)
1021 continue;
1022 eprintf ("Cannot retrieve dwarf info at 0x%08"PFMT64x"\n", off);
1023 return false;
1024 }
1025 } while (!strcmp (file, file2) && line == line2);
1026
1027 eprintf ("--> 0x%08"PFMT64x" %s : %d\n", off, file2, line2);
1028 tmp_ptr = r_file_slurp_line (file2, line2, 0);
1029 eprintf ("--> %s\n", tmp_ptr);
1030 free (tmp_ptr);
1031
1032 return true;
1033 }
1034
cmd_debug_pid(RCore * core,const char * input)1035 static void cmd_debug_pid(RCore *core, const char *input) {
1036 int pid, sig;
1037 const char *ptr;
1038 switch (input[1]) {
1039 case '\0': // "dp"
1040 eprintf ("Selected: %d %d\n", core->dbg->pid, core->dbg->tid);
1041 r_debug_pid_list (core->dbg, core->dbg->pid, 0);
1042 break;
1043 case '-': // "dp-"
1044 if (input[2]== ' ') {
1045 r_debug_detach (core->dbg, r_num_math (core->num, input + 2));
1046 } else {
1047 r_debug_detach (core->dbg, core->dbg->pid);
1048 }
1049 break;
1050 case 'c': // "dpc"
1051 if (core->dbg->forked_pid != -1) {
1052 if (input[2] == '*') {
1053 eprintf ("dp %d\n", core->dbg->forked_pid);
1054 } else {
1055 r_debug_select (core->dbg, core->dbg->forked_pid, core->dbg->tid);
1056 core->dbg->main_pid = core->dbg->forked_pid;
1057 core->dbg->n_threads = 0;
1058 core->dbg->forked_pid = -1;
1059 }
1060 } else {
1061 eprintf ("No recently forked children\n");
1062 }
1063 break;
1064 case 'k': // "dpk"
1065 /* stop, print, pass -- just use flags*/
1066 /* XXX: not for threads? signal is for a whole process!! */
1067 /* XXX: but we want fine-grained access to process resources */
1068 pid = atoi (input + 2);
1069 if (pid > 0) {
1070 ptr = r_str_trim_head_ro (input + 2);
1071 ptr = strchr (ptr, ' ');
1072 sig = ptr? atoi (ptr + 1): 0;
1073 eprintf ("Sending signal '%d' to pid '%d'\n", sig, pid);
1074 r_debug_kill (core->dbg, pid, false, sig);
1075 } else eprintf ("cmd_debug_pid: Invalid arguments (%s)\n", input);
1076 break;
1077 case 'n': // "dpn"
1078 eprintf ("TODO: debug_fork: %d\n", r_debug_child_fork (core->dbg));
1079 break;
1080 case 't': // "dpt"
1081 switch (input[2]) {
1082 case '\0': // "dpt"
1083 r_debug_thread_list (core->dbg, core->dbg->pid, 0);
1084 break;
1085 case 'j': // "dptj"
1086 if (input[3] != ' ') { // "dptj"
1087 r_debug_thread_list (core->dbg, core->dbg->pid, 'j');
1088 } else { // "dptj "
1089 r_debug_thread_list (core->dbg, atoi (input + 3), 'j');
1090 }
1091 break;
1092 case ' ': // "dpt "
1093 r_debug_thread_list (core->dbg, atoi (input + 2), 0);
1094 break;
1095 case '=': // "dpt="
1096 r_debug_select (core->dbg, core->dbg->pid,
1097 (int) r_num_math (core->num, input + 3));
1098 break;
1099 case 'n': // "dptn"
1100 eprintf ("TODO: debug_clone: %d\n", r_debug_child_clone (core->dbg));
1101 break;
1102 case '?': // "dpt?"
1103 default:
1104 r_core_cmd_help (core, help_msg_dp);
1105 break;
1106 }
1107 break;
1108 case 'a': // "dpa"
1109 if (input[2]) {
1110 r_debug_attach (core->dbg, (int) r_num_math (
1111 core->num, input + 2));
1112 } else {
1113 if (core->io && core->io->desc) {
1114 r_debug_attach (core->dbg,
1115 r_io_fd_get_pid (core->io, core->io->desc->fd));
1116 }
1117 }
1118 r_debug_select (core->dbg, core->dbg->pid, core->dbg->tid);
1119 r_config_set_i (core->config, "dbg.swstep",
1120 (core->dbg->h && !core->dbg->h->canstep));
1121 r_core_cmdf (core, "=!pid %d", core->dbg->pid);
1122 break;
1123 case 'f': // "dpf"
1124 if (core->io && core->io->desc) {
1125 r_debug_select (core->dbg, r_io_fd_get_pid (core->io, core->io->desc->fd),
1126 r_io_fd_get_tid (core->io, core->io->desc->fd));
1127 }
1128 break;
1129 case '=': // "dp="
1130 r_debug_select (core->dbg,
1131 (int) r_num_math (core->num, input + 2), core->dbg->tid);
1132 core->dbg->main_pid = r_num_math (core->num, input + 2);
1133 break;
1134 case 'l': // "dpl"
1135 switch (input[2]) {
1136 case '\0': // "dpl"
1137 r_debug_pid_list (core->dbg, 0, 0);
1138 break;
1139 case 'j': // "dplj"
1140 r_debug_pid_list (core->dbg, 0, 'j');
1141 break;
1142 }
1143 break;
1144 case 'j': // "dpj"
1145 switch (input[2]) {
1146 case '\0': // "dpj"
1147 r_debug_pid_list (core->dbg, core->dbg->pid, 'j');
1148 break;
1149 case ' ': // "dpj "
1150 r_debug_pid_list (core->dbg,
1151 (int) R_MAX (0, (int)r_num_math (core->num, input + 2)), 'j');
1152 break;
1153 }
1154 break;
1155 case 'e': // "dpe"
1156 {
1157 int pid = (input[2] == ' ')? atoi (input + 2): core->dbg->pid;
1158 char *exe = r_sys_pid_to_path (pid);
1159 if (exe) {
1160 r_cons_println (exe);
1161 free (exe);
1162 }
1163 }
1164 break;
1165 case ' ': // "dp "
1166 r_debug_pid_list (core->dbg,
1167 (int) R_MAX (0, (int)r_num_math (core->num, input + 2)), 0);
1168 break;
1169 case '?': // "dp?"
1170 default:
1171 r_core_cmd_help (core, help_msg_dp);
1172 break;
1173 }
1174 }
1175
cmd_debug_backtrace(RCore * core,const char * input)1176 static void cmd_debug_backtrace(RCore *core, const char *input) {
1177 RAnalOp analop;
1178 ut64 addr, len = r_num_math (core->num, input);
1179 if (!len) {
1180 r_bp_traptrace_list (core->dbg->bp);
1181 } else {
1182 ut64 oaddr = 0LL;
1183 eprintf ("Trap tracing 0x%08"PFMT64x"-0x%08"PFMT64x"\n",
1184 core->offset, core->offset+len);
1185 r_reg_arena_swap (core->dbg->reg, true);
1186 r_bp_traptrace_reset (core->dbg->bp, true);
1187 r_bp_traptrace_add (core->dbg->bp, core->offset, core->offset+len);
1188 r_bp_traptrace_enable (core->dbg->bp, true);
1189 do {
1190 ut8 buf[32];
1191 r_debug_continue (core->dbg);
1192 addr = r_debug_reg_get (core->dbg, "PC");
1193 if (!addr) {
1194 eprintf ("pc=0\n");
1195 break;
1196 }
1197 if (addr == oaddr) {
1198 eprintf ("pc=opc\n");
1199 break;
1200 }
1201 oaddr = addr;
1202 /* XXX Bottleneck..we need to reuse the bytes read by traptrace */
1203 // XXX Do asm.arch should define the max size of opcode?
1204 r_io_read_at (core->io, addr, buf, 32); // XXX longer opcodes?
1205 r_anal_op (core->anal, &analop, addr, buf, sizeof (buf), R_ANAL_OP_MASK_BASIC);
1206 } while (r_bp_traptrace_at (core->dbg->bp, addr, analop.size));
1207 r_bp_traptrace_enable (core->dbg->bp, false);
1208 }
1209 }
1210
grab_bits(RCore * core,const char * arg,int * pcbits2)1211 static int grab_bits(RCore *core, const char *arg, int *pcbits2) {
1212 int pcbits = atoi (arg);
1213 if (pcbits2) {
1214 *pcbits2 = 0;
1215 }
1216 if (pcbits < 1) {
1217 if (!strcmp (r_config_get (core->config, "asm.arch"), "avr")) {
1218 pcbits = 8;
1219 if (pcbits2) {
1220 *pcbits2 = 32;
1221 }
1222 } else {
1223 const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
1224 RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
1225 if (reg) {
1226 if (core->rasm->bits != reg->size)
1227 pcbits = reg->size;
1228 }
1229 }
1230 }
1231 return pcbits ? pcbits : core->anal->bits;
1232 }
1233
1234 #define MAX_MAP_SIZE 1024*1024*512
dump_maps(RCore * core,int perm,const char * filename)1235 static int dump_maps(RCore *core, int perm, const char *filename) {
1236 RDebugMap *map;
1237 RListIter *iter;
1238 r_debug_map_sync (core->dbg); // update process memory maps
1239 ut64 addr = core->offset;
1240 int do_dump = false;
1241 int ret = !r_list_empty (core->dbg->maps);
1242 r_list_foreach (core->dbg->maps, iter, map) {
1243 do_dump = false;
1244 if (perm == -1) {
1245 if (addr >= map->addr && addr < map->addr_end) {
1246 do_dump = true;
1247 }
1248 } else if (perm == 0) {
1249 do_dump = true;
1250 } else if (perm == (map->perm & perm)) {
1251 do_dump = true;
1252 }
1253 if (do_dump) {
1254 ut8 *buf = malloc (map->size);
1255 //TODO: use mmap here. we need a portable implementation
1256 if (!buf) {
1257 eprintf ("Cannot allocate 0x%08"PFMT64x" bytes\n", map->size);
1258 free (buf);
1259 /// XXX: TODO: read by blocks!!1
1260 continue;
1261 }
1262 if (map->size > MAX_MAP_SIZE) {
1263 eprintf ("Do not dumping 0x%08"PFMT64x" because it's too big\n", map->addr);
1264 free (buf);
1265 continue;
1266 }
1267 r_io_read_at (core->io, map->addr, buf, map->size);
1268 char *file = filename
1269 ? strdup (filename)
1270 : r_str_newf ("0x%08"PFMT64x"-0x%08"PFMT64x"-%s.dmp",
1271 map->addr, map->addr_end, r_str_rwx_i (map->perm));
1272 if (!r_file_dump (file, buf, map->size, 0)) {
1273 eprintf ("Cannot write '%s'\n", file);
1274 ret = 0;
1275 } else {
1276 eprintf ("Dumped %d byte(s) into %s\n", (int)map->size, file);
1277 }
1278 free (file);
1279 free (buf);
1280 }
1281 }
1282 //eprintf ("No debug region found here\n");
1283 return ret;
1284 }
1285
cmd_debug_modules(RCore * core,int mode)1286 static void cmd_debug_modules(RCore *core, int mode) { // "dmm"
1287 ut64 addr = core->offset;
1288 RDebugMap *map;
1289 RList *list;
1290 RListIter *iter;
1291
1292 /* avoid processing the list if the user only wants help */
1293 if (mode == '?') {
1294 show_help:
1295 r_core_cmd_help (core, help_msg_dmm);
1296 return;
1297 }
1298 PJ *pj = NULL;
1299 if (mode == 'j') {
1300 pj = r_core_pj_new (core);
1301 if (!pj) {
1302 return;
1303 }
1304 pj_a (pj);
1305 }
1306 // TODO: honor mode
1307 list = r_debug_modules_list (core->dbg);
1308 r_list_foreach (list, iter, map) {
1309 switch (mode) {
1310 case 0:
1311 r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s\n", map->addr, map->addr_end, map->file);
1312 break;
1313 case '.':
1314 if (addr >= map->addr && addr < map->addr_end) {
1315 r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s\n", map->addr, map->addr_end, map->file);
1316 goto beach;
1317 }
1318 break;
1319 case 'j':
1320 {
1321 /* Escape backslashes (e.g. for Windows). */
1322 pj_o (pj);
1323 pj_kn (pj, "addr", map->addr);
1324 pj_kn (pj, "addr_end", map->addr_end);
1325 pj_ks (pj, "file", map->file);
1326 pj_ks (pj, "name", map->name);
1327 pj_end (pj);
1328 }
1329 break;
1330 case ':':
1331 case '*':
1332 if (mode == '*' || (mode == ':' && \
1333 addr>=map->addr && addr < map->addr_end)) {
1334 /* Escape backslashes (e.g. for Windows). */
1335 char *escaped_path = r_str_escape (map->file);
1336 char *filtered_name = strdup (map->name);
1337 r_name_filter (filtered_name, 0);
1338 r_cons_printf ("f mod.%s = 0x%08"PFMT64x"\n",
1339 filtered_name, map->addr);
1340 r_cons_printf ("oba 0x%08"PFMT64x" %s\n", map->addr, escaped_path);
1341 // r_cons_printf (".!rabin2 -rsB 0x%08"PFMT64x" \"%s\"\n", map->addr, escaped_path);
1342 free (escaped_path);
1343 free (filtered_name);
1344 }
1345 break;
1346 default:
1347 pj_free (pj);
1348 r_list_free (list);
1349 goto show_help;
1350 /* not reached */
1351 }
1352 }
1353 beach:
1354 if (mode == 'j') {
1355 pj_end (pj);
1356 r_cons_println (pj_string (pj));
1357 }
1358 pj_free (pj);
1359 r_list_free (list);
1360 }
1361
1362 #if __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
1363
1364 static int cmd_dbg_map_heap_glibc_32(RCore *core, const char *input);
1365 static int cmd_dbg_map_heap_glibc_64(RCore *core, const char *input);
1366 #endif // __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
1367 #if __WINDOWS__
1368 static int cmd_debug_map_heap_win(RCore *core, const char *input);
1369 #endif // __WINDOWS__
1370
1371
addroflib(RCore * core,const char * libname)1372 static ut64 addroflib(RCore *core, const char *libname) {
1373 RListIter *iter;
1374 RDebugMap *map;
1375 if (!core || !libname) {
1376 return UT64_MAX;
1377 }
1378 r_debug_map_sync (core->dbg);
1379 // RList *list = r_debug_native_modules_get (core->dbg);
1380 RList *list = r_debug_modules_list (core->dbg);
1381 r_list_foreach (list, iter, map) {
1382 if (strstr (r_file_basename(map->name), libname)) {
1383 return map->addr;
1384 }
1385 }
1386 r_list_foreach (core->dbg->maps, iter, map) {
1387 if (strstr (r_file_basename(map->name), libname)) {
1388 return map->addr;
1389 }
1390 }
1391 return UT64_MAX;
1392 }
1393
get_closest_map(RCore * core,ut64 addr)1394 static RDebugMap *get_closest_map(RCore *core, ut64 addr) {
1395 RListIter *iter;
1396 RDebugMap *map;
1397
1398 r_debug_map_sync (core->dbg);
1399 RList *list = r_debug_modules_list (core->dbg);
1400 r_list_foreach (list, iter, map) {
1401 if (addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) {
1402 return map;
1403 }
1404 }
1405 r_list_foreach (core->dbg->maps, iter, map) {
1406 if (addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) {
1407 return map;
1408 }
1409 }
1410 return NULL;
1411 }
1412
r_debug_heap(RCore * core,const char * input)1413 static int r_debug_heap(RCore *core, const char *input) {
1414 const char *m = r_config_get (core->config, "dbg.malloc");
1415 if (m && !strcmp ("glibc", m)) {
1416 #if __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
1417 if (core->rasm->bits == 64) {
1418 cmd_dbg_map_heap_glibc_64 (core, input + 1);
1419 } else {
1420 cmd_dbg_map_heap_glibc_32 (core, input + 1);
1421 }
1422 #else
1423 eprintf ("glibc not supported for this platform\n");
1424 #endif
1425 #if HAVE_JEMALLOC
1426 } else if (m && !strcmp ("jemalloc", m)) {
1427 if (core->rasm->bits == 64) {
1428 cmd_dbg_map_jemalloc_64 (core, input + 1);
1429 } else {
1430 cmd_dbg_map_jemalloc_32 (core, input + 1);
1431 }
1432 #endif
1433 } else {
1434 #if __WINDOWS__
1435 cmd_debug_map_heap_win (core, input + 1);
1436 #else
1437 eprintf ("MALLOC algorithm not supported\n");
1438 return false;
1439 #endif
1440 }
1441 return true;
1442 }
1443
get_bin_info(RCore * core,const char * file,ut64 baseaddr,PJ * pj,int mode,bool symbols_only,RCoreBinFilter * filter)1444 static bool get_bin_info(RCore *core, const char *file, ut64 baseaddr, PJ *pj, int mode, bool symbols_only, RCoreBinFilter *filter) {
1445 int fd;
1446 if ((fd = r_io_fd_open (core->io, file, R_PERM_R, 0)) == -1) {
1447 return false;
1448 }
1449 RBinOptions opt = { 0 };
1450 opt.fd = fd;
1451 opt.sz = r_io_fd_size (core->io, fd);
1452 opt.baseaddr = baseaddr;
1453 RBinFile *obf = r_bin_cur (core->bin);
1454 if (!r_bin_open_io (core->bin, &opt)) {
1455 r_io_fd_close (core->io, fd);
1456 return false;
1457 }
1458 int action = R_CORE_BIN_ACC_ALL & ~R_CORE_BIN_ACC_INFO;
1459 if (symbols_only || filter->name) {
1460 action = R_CORE_BIN_ACC_SYMBOLS;
1461 } else if (mode == R_MODE_SET || mode == R_MODE_RADARE) {
1462 action &= ~R_CORE_BIN_ACC_ENTRIES & ~R_CORE_BIN_ACC_MAIN;
1463 }
1464 r_core_bin_info (core, action, pj, mode, 1, filter, NULL);
1465 RBinFile *bf = r_bin_cur (core->bin);
1466 r_bin_file_delete (core->bin, bf->id);
1467 r_bin_file_set_cur_binfile (core->bin, obf);
1468 r_io_fd_close (core->io, fd);
1469 return true;
1470 }
1471
cmd_debug_map(RCore * core,const char * input)1472 static int cmd_debug_map(RCore *core, const char *input) {
1473 RListIter *iter;
1474 RDebugMap *map;
1475 ut64 addr = core->offset;
1476
1477 switch (input[0]) {
1478 case '.': // "dm."
1479 r_debug_map_list (core->dbg, addr, input);
1480 break;
1481 case 'm': // "dmm"
1482 if (!strcmp (input + 1, ".*")) {
1483 cmd_debug_modules (core, ':');
1484 } else cmd_debug_modules (core, input[1]);
1485 break;
1486 case '?': // "dm?"
1487 r_core_cmd_help (core, help_msg_dm);
1488 break;
1489 case 'p': // "dmp"
1490 if (input[1] == '?') {
1491 r_core_cmd_help (core, help_msg_dmp);
1492 } else if (input[1] == ' ') {
1493 int perms;
1494 char *p, *q;
1495 ut64 size = 0, addr;
1496 p = strchr (input + 2, ' ');
1497 if (p) {
1498 *p++ = 0;
1499 q = strchr (p, ' ');
1500 if (q) {
1501 *q++ = 0;
1502 addr = r_num_math (core->num, input + 2);
1503 size = r_num_math (core->num, p);
1504 perms = r_str_rwx (q);
1505 // eprintf ("(%s)(%s)(%s)\n", input + 2, p, q);
1506 // eprintf ("0x%08"PFMT64x" %d %o\n", addr, (int) size, perms);
1507 r_debug_map_protect (core->dbg, addr, size, perms);
1508 } else eprintf ("See dmp?\n");
1509 } else {
1510 r_debug_map_sync (core->dbg); // update process memory maps
1511 addr = UT64_MAX;
1512 r_list_foreach (core->dbg->maps, iter, map) {
1513 if (core->offset >= map->addr && core->offset < map->addr_end) {
1514 addr = map->addr;
1515 size = map->size;
1516 break;
1517 }
1518 }
1519 perms = r_str_rwx (input + 2);
1520 if (addr != UT64_MAX && perms >= 0) {
1521 r_debug_map_protect (core->dbg, addr, size, perms);
1522 } else {
1523 eprintf ("See dmp?\n");
1524 }
1525 }
1526 } else {
1527 eprintf ("See dmp?\n");
1528 }
1529 break;
1530 case 'd': // "dmd"
1531 switch (input[1]) {
1532 case 'a': return dump_maps (core, 0, NULL);
1533 case 'w': return dump_maps (core, R_PERM_RW, NULL);
1534 case ' ': return dump_maps (core, -1, input + 2);
1535 case 0: return dump_maps (core, -1, NULL);
1536 case '?':
1537 default:
1538 eprintf ("Usage: dmd[aw] - dump (all-or-writable) debug maps\n");
1539 break;
1540 }
1541 break;
1542 case 'l': // "dml"
1543 if (input[1] != ' ') {
1544 eprintf ("Usage: dml [file]\n");
1545 return false;
1546 }
1547 r_debug_map_sync (core->dbg); // update process memory maps
1548 r_list_foreach (core->dbg->maps, iter, map) {
1549 if (addr >= map->addr && addr < map->addr_end) {
1550 size_t sz;
1551 char *buf = r_file_slurp (input + 2, &sz);
1552 //TODO: use mmap here. we need a portable implementation
1553 if (!buf) {
1554 eprintf ("Cannot allocate 0x%08"PFMT64x" byte(s)\n", map->size);
1555 return false;
1556 }
1557 r_io_write_at (core->io, map->addr, (const ut8*)buf, sz);
1558 if (sz != map->size)
1559 eprintf ("File size differs from region size (%"PFMT64u" vs %"PFMT64d")\n",
1560 (ut64)sz, map->size);
1561 eprintf ("Loaded %"PFMT64u" byte(s) into the map region at 0x%08"PFMT64x"\n",
1562 (ut64)sz, map->addr);
1563 free (buf);
1564 return true;
1565 }
1566 }
1567 eprintf ("No debug region found here\n");
1568 return false;
1569 case 'i': // "dmi"
1570 switch (input[1]) {
1571 case '\0': // "dmi" alias of "dmm"
1572 r_core_cmd (core, "dmm", 0);
1573 break;
1574 case ' ': // "dmi "
1575 case '*': // "dmi*"
1576 case 'v': // "dmiv"
1577 case 'j': // "dmij"
1578 case 'q': // "dmiq"
1579 case 'a': // "dmia"
1580 {
1581 const char *libname = NULL, *symname = NULL, *a0;
1582 int mode;
1583 ut64 baddr = 0LL;
1584 char *ptr;
1585 int i = 1;
1586 bool symbols_only = true;
1587 if (input[1] == 'a') {
1588 symbols_only = false;
1589 input++;
1590 }
1591 PJ *pj = NULL;
1592 switch (input[1]) {
1593 case 's':
1594 mode = R_MODE_SET;
1595 break;
1596 case '*':
1597 mode = R_MODE_RADARE;
1598 break;
1599 case 'j':
1600 mode = R_MODE_JSON;
1601 pj = r_core_pj_new (core);
1602 if (!pj) {
1603 return false;
1604 }
1605 break;
1606 case 'q':
1607 mode = input[2] == 'q' ? input++, R_MODE_SIMPLEST : R_MODE_SIMPLE;
1608 break;
1609 default:
1610 mode = R_MODE_PRINT;
1611 break;
1612 }
1613 ptr = strdup (r_str_trim_head_ro (input + 2));
1614 if (!ptr || !*ptr) {
1615 r_core_cmd (core, "dmm", 0);
1616 free (ptr);
1617 break;
1618 }
1619 if (symbols_only) {
1620 i = r_str_word_set0 (ptr);
1621 }
1622 switch (i) {
1623 case 2:
1624 symname = r_str_word_get0 (ptr, 1);
1625 // fall through
1626 case 1:
1627 a0 = r_str_word_get0 (ptr, 0);
1628 addr = r_num_get (core->num, a0);
1629 if (!addr || addr == UT64_MAX) {
1630 libname = r_str_word_get0 (ptr, 0);
1631 }
1632 break;
1633 }
1634 if (libname && !addr) {
1635 addr = addroflib (core, r_file_basename (libname));
1636 if (addr == UT64_MAX) {
1637 eprintf ("Unknown library, or not found in dm\n");
1638 }
1639 }
1640 map = get_closest_map (core, addr);
1641 if (map) {
1642 RCoreBinFilter filter;
1643 filter.offset = 0LL;
1644 filter.name = (char *)symname;
1645 baddr = map->addr;
1646
1647 if (libname) {
1648 const char *file = map->file? map->file: map->name;
1649 char *newfile = NULL;
1650 if (!r_file_exists (file)) {
1651 newfile = r_file_temp ("memlib");
1652 if (newfile) {
1653 file = newfile;
1654 r_core_cmdf (core, "wtf %s 0x%"PFMT64x" @ 0x%"PFMT64x" 2> %s",
1655 file, map->size, baddr, R_SYS_DEVNULL);
1656 }
1657 }
1658 get_bin_info (core, file, baddr, pj, mode, symbols_only, &filter);
1659 if (newfile) {
1660 if (!r_file_rm (newfile)) {
1661 eprintf ("Error when removing %s\n", newfile);
1662 }
1663 free (newfile);
1664 }
1665 } else {
1666 r_bin_set_baddr (core->bin, map->addr);
1667 r_core_bin_info (core, R_CORE_BIN_ACC_SYMBOLS, pj, input[1] == '*', true, &filter, NULL);
1668 r_bin_set_baddr (core->bin, baddr);
1669 }
1670 }
1671 if (mode == R_MODE_JSON) {
1672 r_cons_println (pj_string (pj));
1673 pj_free (pj);
1674 }
1675 free (ptr);
1676 }
1677 break;
1678 case '.': // "dmi."
1679 {
1680 map = get_closest_map (core, addr);
1681 if (map) {
1682 ut64 closest_addr = UT64_MAX;
1683 RList *symbols = r_bin_get_symbols (core->bin);
1684 RBinSymbol *symbol, *closest_symbol = NULL;
1685
1686 r_list_foreach (symbols, iter, symbol) {
1687 if (symbol->vaddr > addr) {
1688 if (symbol->vaddr - addr < closest_addr) {
1689 closest_addr = symbol->vaddr - addr;
1690 closest_symbol = symbol;
1691 }
1692 } else {
1693 if (addr - symbol->vaddr < closest_addr) {
1694 closest_addr = addr - symbol->vaddr;
1695 closest_symbol = symbol;
1696 }
1697 }
1698 }
1699 if (closest_symbol) {
1700 RCoreBinFilter filter;
1701 filter.offset = 0LL;
1702 filter.name = (char *) closest_symbol->name;
1703
1704 r_bin_set_baddr (core->bin, map->addr);
1705 r_core_bin_info (core, R_CORE_BIN_ACC_SYMBOLS, NULL, false, true, &filter, NULL);
1706 }
1707 }
1708 }
1709 break;
1710 default:
1711 r_core_cmd_help (core, help_msg_dmi);
1712 break;
1713 }
1714 break;
1715 case 'S': // "dmS"
1716 { // Move to a separate function
1717 const char *libname = NULL, *sectname = NULL, *mode = "";
1718 ut64 baddr = 0LL;
1719 char *ptr;
1720 int i;
1721
1722 if (input[1]=='*') {
1723 ptr = strdup (r_str_trim_head_ro ((char*)input + 2));
1724 mode = "-r ";
1725 } else {
1726 ptr = strdup (r_str_trim_head_ro ((char*)input + 1));
1727 }
1728 i = r_str_word_set0 (ptr);
1729
1730 addr = UT64_MAX;
1731 switch (i) {
1732 case 2: // get section name
1733 sectname = r_str_word_get0 (ptr, 1);
1734 /* fallthrou */
1735 case 1: // get addr|libname
1736 if (IS_DIGIT (*ptr)) {
1737 const char *a0 = r_str_word_get0 (ptr, 0);
1738 addr = r_num_math (core->num, a0);
1739 } else {
1740 addr = UT64_MAX;
1741 }
1742 if (!addr || addr == UT64_MAX) {
1743 libname = r_str_word_get0 (ptr, 0);
1744 }
1745 break;
1746 }
1747 r_debug_map_sync (core->dbg); // update process memory maps
1748 RList *list = r_debug_modules_list (core->dbg);
1749 r_list_foreach (list, iter, map) {
1750 if ((!libname ||
1751 (addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) ||
1752 (libname != NULL && (strstr (map->name, libname))))) {
1753 baddr = map->addr;
1754 char *res;
1755 const char *file = map->file? map->file: map->name;
1756 char *name = r_str_escape ((char *)r_file_basename (file));
1757 char *filesc = r_str_escape (file);
1758 /* TODO: do not spawn. use RBin API */
1759 if (sectname) {
1760 char *sect = r_str_escape (sectname);
1761 res = r_sys_cmd_strf ("env RABIN2_PREFIX=\"%s\" rabin2 %s-B 0x%08"
1762 PFMT64x" -S \"%s\" | grep \"%s\"", name, mode, baddr, filesc, sect);
1763 free (sect);
1764 } else {
1765 res = r_sys_cmd_strf ("env RABIN2_PREFIX=\"%s\" rabin2 %s-B 0x%08"
1766 PFMT64x" -S \"%s\"", name, mode, baddr, filesc);
1767 }
1768 free (filesc);
1769 r_cons_println (res);
1770 free(name);
1771 free (res);
1772 if (libname || addr != UT64_MAX) { //only single match requested
1773 break;
1774 }
1775 }
1776 }
1777 free (ptr);
1778 }
1779 break;
1780 case ' ': // "dm "
1781 {
1782 int size;
1783 char *p = strchr (input + 2, ' ');
1784 if (p) {
1785 *p++ = 0;
1786 addr = r_num_math (core->num, input + 1);
1787 size = r_num_math (core->num, p);
1788 r_debug_map_alloc (core->dbg, addr, size, false);
1789 } else {
1790 eprintf ("Usage: dm addr size\n");
1791 return false;
1792 }
1793 }
1794 break;
1795 case '-': // "dm-"
1796 if (input[1] != ' ') {
1797 eprintf ("|ERROR| Usage: dm- [addr]\n");
1798 break;
1799 }
1800 addr = r_num_math (core->num, input + 2);
1801 r_list_foreach (core->dbg->maps, iter, map) {
1802 if (addr >= map->addr && addr < map->addr_end) {
1803 r_debug_map_dealloc(core->dbg, map);
1804 r_debug_map_sync (core->dbg);
1805 return true;
1806 }
1807 }
1808 eprintf ("The address doesn't match with any map.\n");
1809 break;
1810 case 'L': // "dmL"
1811 {
1812 int size;
1813 char *p = strchr (input + 2, ' ');
1814 if (p) {
1815 *p++ = 0;
1816 addr = r_num_math (core->num, input + 1);
1817 size = r_num_math (core->num, p);
1818 r_debug_map_alloc (core->dbg, addr, size, true);
1819 } else {
1820 eprintf ("Usage: dmL addr size\n");
1821 return false;
1822 }
1823 }
1824 break;
1825 case '\0': // "dm"
1826 case '*': // "dm*"
1827 case 'j': // "dmj"
1828 case 'q': // "dmq"
1829 r_debug_map_sync (core->dbg); // update process memory maps
1830 r_debug_map_list (core->dbg, core->offset, input);
1831 break;
1832 case '=': // "dm="
1833 r_debug_map_sync (core->dbg);
1834 r_debug_map_list_visual (core->dbg, core->offset, input,
1835 r_config_get_i (core->config, "scr.color"));
1836 break;
1837 case 'h': // "dmh"
1838 (void)r_debug_heap (core, input);
1839 break;
1840 }
1841 return true;
1842 }
1843
1844 #if __linux__ && __GNU_LIBRARY__ && __GLIBC__ && __GLIBC_MINOR__
1845 #include "linux_heap_glibc.c"
1846 #elif __WINDOWS__
1847 #include "windows_heap.c"
1848 #endif
1849
1850 HEAPTYPE(ut64);
1851
regcmp(const void * a,const void * b)1852 static int regcmp(const void *a, const void *b) {
1853 const ut64 *A = (const ut64*)a;
1854 const ut64 *B = (const ut64*)b;
1855 if (*A > *B) {
1856 return 1;
1857 }
1858 if (*A == *B) {
1859 return 0;
1860 }
1861 return -1;
1862 }
1863
regcb(void * u,const ut64 k,const void * v)1864 static bool regcb(void *u, const ut64 k, const void *v) {
1865 RList *sorted = (RList*) u;
1866 ut64 *n = ut64_new (k);
1867 r_list_add_sorted (sorted, n, regcmp);
1868 return true;
1869 }
1870
r_core_debug_ri(RCore * core,RReg * reg,int mode)1871 R_API void r_core_debug_ri(RCore *core, RReg *reg, int mode) {
1872 RList *list = r_reg_get_list (reg, R_REG_TYPE_GPR);
1873 RListIter *iter;
1874 RRegItem *r;
1875 HtUP *db = ht_up_new0 ();
1876
1877 r_list_foreach (list, iter, r) {
1878 if (r->size != core->rasm->bits) {
1879 continue;
1880 }
1881 ut64 value = r_reg_get_value (reg, r);
1882 RList *list = ht_up_find (db, value, NULL);
1883 if (!list) {
1884 list = r_list_newf (NULL);
1885 ht_up_update (db, value, list);
1886 }
1887 r_list_append (list, r->name);
1888 }
1889
1890 RList *sorted = r_list_newf (free);
1891 ht_up_foreach (db, regcb, sorted);
1892 ut64 *addr;
1893 r_list_foreach (sorted, iter, addr) {
1894 int rwx = 0;
1895 RDebugMap *map = r_debug_map_get (core->dbg, *addr);
1896 if (map) {
1897 rwx = map->perm;
1898 }
1899 r_cons_printf (" %s ", r_str_rwx_i (rwx));
1900
1901 r_cons_printf ("0x%08"PFMT64x" ", *addr);
1902 RList *list = ht_up_find (db, *addr, NULL);
1903 if (list) {
1904 RListIter *iter;
1905 const char *r;
1906 r_cons_strcat (Color_YELLOW);
1907 r_list_foreach (list, iter, r) {
1908 r_cons_printf (" %s", r);
1909 }
1910 r_cons_strcat (Color_RESET);
1911 char *rrstr = r_core_anal_hasrefs (core, *addr, true);
1912 if (rrstr && *rrstr && strchr (rrstr, 'R')) {
1913 r_cons_printf (" ;%s"Color_RESET, rrstr);
1914 }
1915 r_cons_newline ();
1916 }
1917 }
1918 r_list_free (sorted);
1919 ht_up_free (db);
1920 }
1921
r_core_debug_rr(RCore * core,RReg * reg,int mode)1922 R_API void r_core_debug_rr(RCore *core, RReg *reg, int mode) {
1923 char *color = "";
1924 char *colorend = "";
1925 int had_colors = r_config_get_i (core->config, "scr.color");
1926 bool use_colors = had_colors != 0;
1927 int delta = 0;
1928 ut64 diff, value;
1929 int bits = core->rasm->bits;
1930 //XXX: support other RRegisterType
1931 RList *list = r_reg_get_list (reg, R_REG_TYPE_GPR);
1932 RListIter *iter;
1933 RRegItem *r;
1934 RTable *t = r_core_table (core, "regs");
1935
1936 if (mode == 'j') {
1937 r_config_set_i (core->config, "scr.color", false);
1938 use_colors = 0;
1939 }
1940
1941 if (use_colors) {
1942 #undef ConsP
1943 #define ConsP(x) (core->cons && core->cons->context->pal.x) ? core->cons->context->pal.x
1944 color = ConsP(creg): Color_BWHITE;
1945 colorend = Color_RESET;
1946 }
1947
1948 r_table_set_columnsf (t, "ssss", "role", "reg", "value", "refstr");
1949 r_list_foreach (list, iter, r) {
1950 if (r->size != bits) {
1951 continue;
1952 }
1953
1954 value = r_reg_get_value (core->dbg->reg, r);
1955 delta = 0;
1956 int regSize = r->size;
1957 //XXX: support larger regSize
1958 if (regSize < 80) {
1959 r_reg_arena_swap (core->dbg->reg, false);
1960 diff = r_reg_get_value (core->dbg->reg, r);
1961 r_reg_arena_swap (core->dbg->reg, false);
1962 delta = value-diff;
1963 }
1964
1965 const char *role = "";
1966 int i;
1967 for (i = 0; i < R_REG_NAME_LAST; i++) {
1968 const char *t = r_reg_get_name (reg, i);
1969 if (t && !strcmp (t, r->name)) {
1970 role = r_reg_get_role (i);
1971 }
1972 }
1973
1974 char *namestr = NULL;
1975 char *valuestr = NULL;
1976 if (delta && use_colors) {
1977 namestr = r_str_newf ("%s%s%s", color, r->name, colorend);
1978 valuestr = r_str_newf ("%s%"PFMT64x"%s", color, value, colorend);
1979 } else {
1980 namestr = r_str_new (r->name);
1981 valuestr = r_str_newf ("%"PFMT64x, value);
1982 }
1983
1984 char *rrstr = r_core_anal_hasrefs (core, value, true);
1985 if (!rrstr) {
1986 rrstr = strdup ("");
1987 }
1988
1989 r_table_add_rowf (t, "ssss", role, namestr, valuestr, rrstr);
1990 free (namestr);
1991 free (valuestr);
1992 free (rrstr);
1993 }
1994
1995 char *s = (mode == 'j')? r_table_tojson (t): r_table_tostring (t);
1996 r_cons_print (s);
1997 free (s);
1998 r_table_free (t);
1999
2000 if (had_colors) {
2001 r_config_set_i (core->config, "scr.color", had_colors);
2002 }
2003 }
2004
show_drpi(RCore * core)2005 static void show_drpi(RCore *core) {
2006 int i;
2007 RListIter *iter;
2008 RRegItem *ri;
2009 r_cons_printf ("Aliases (Reg->name)\n");
2010 for (i = 0; i < R_REG_NAME_LAST; i++) {
2011 r_cons_printf ("%d %s %s\n", i, r_reg_get_role (i), core->anal->reg->name[i]);
2012 }
2013 for (i = 0; i < R_REG_TYPE_LAST; i++) {
2014 const char *nmi = r_reg_get_type (i);
2015 r_cons_printf ("regset %d (%s)\n", i, nmi);
2016 RRegSet *rs = &core->anal->reg->regset[i];
2017 r_cons_printf ("* arena %s size %d\n", r_reg_get_type (i), rs->arena->size);
2018 r_list_foreach (rs->regs, iter, ri) {
2019 const char *tpe = r_reg_get_type (ri->type);
2020 const char *arn = r_reg_get_type (ri->arena);
2021 r_cons_printf (" %s %s @ %s (offset: %d size: %d)", ri->name, tpe, arn, ri->offset / 8, ri->size / 8);
2022 if ((ri->offset / 8) + (ri->size / 8) > rs->arena->size) {
2023 r_cons_printf (" *OVERFLOW*");
2024 }
2025 r_cons_newline ();
2026 }
2027 }
2028 }
2029
cmd_reg_profile(RCore * core,char from,const char * str)2030 static void cmd_reg_profile(RCore *core, char from, const char *str) { // "arp" and "drp"
2031 const char *ptr;
2032 RReg *r = r_config_get_i (core->config, "cfg.debug")? core->dbg->reg: core->anal->reg;
2033 switch (str[1]) {
2034 case '\0': // "drp" "arp"
2035 if (r->reg_profile_str) {
2036 r_cons_println (r->reg_profile_str);
2037 } else {
2038 eprintf ("No register profile defined. Try 'dr.'\n");
2039 }
2040 break;
2041 case 'c': // "drpc" "arpc"
2042 if (core->dbg->reg->reg_profile_cmt) {
2043 r_cons_println (r->reg_profile_cmt);
2044 }
2045 break;
2046 case 'g': // "drpg" "arpg"
2047 ptr = r_str_trim_head_ro (str + 2);
2048 if (!R_STR_ISEMPTY (ptr)) {
2049 char *r2profile = r_reg_parse_gdb_profile (ptr);
2050 if (r2profile) {
2051 r_cons_println (r2profile);
2052 core->num->value = 0;
2053 free (r2profile);
2054 } else {
2055 core->num->value = 1;
2056 eprintf ("Warning: Cannot parse gdb profile.\n");
2057 }
2058 } else {
2059 eprintf ("Usage: arpg [gdb-reg-profile]\n");
2060 }
2061 break;
2062 case ' ': // "drp " "arp "
2063 ptr = r_str_trim_head_ro (str + 2);
2064 r_reg_set_profile (r, ptr);
2065 r_debug_plugin_set_reg_profile (core->dbg, ptr);
2066 break;
2067 case '.': { // "drp."
2068 RRegSet *rs = r_reg_regset_get (r, R_REG_TYPE_GPR);
2069 if (rs) {
2070 eprintf ("size = %d\n", rs->arena->size);
2071 }
2072 }
2073 break;
2074 case 'i': // "drpi" "arpi"
2075 show_drpi (core);
2076 break;
2077 case 's': // "drps" "arps"
2078 if (str[2] == ' ') {
2079 ut64 n = r_num_math (core->num, str+2);
2080 // TODO: move this thing into the r_reg API
2081 RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
2082 if (rs && n>0) {
2083 RListIter *iter;
2084 RRegArena *arena;
2085 r_list_foreach (rs->pool, iter, arena) {
2086 ut8 *newbytes = calloc (1, n);
2087 if (newbytes) {
2088 free (arena->bytes);
2089 arena->bytes = newbytes;
2090 arena->size = n;
2091 } else {
2092 eprintf ("Cannot allocate %d\n", (int)n);
2093 }
2094 }
2095 } else {
2096 eprintf ("Invalid arena size\n");
2097 }
2098 } else {
2099 RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
2100 if (rs) {
2101 r_cons_printf ("%d\n", rs->arena->size);
2102 } else eprintf ("Cannot find GPR register arena.\n");
2103 }
2104 break;
2105 case 'j': // "drpj" "arpj"
2106 {
2107 // "drpj" .. dup from "arpj"
2108 RListIter *iter;
2109 RRegItem *r;
2110 int i;
2111 PJ *pj = r_core_pj_new (core);
2112 if (!pj) {
2113 return;
2114 }
2115 pj_o (pj);
2116 pj_k (pj, "alias_info");
2117 pj_a (pj);
2118 for (i = 0; i < R_REG_NAME_LAST; i++) {
2119 if (core->dbg->reg->name[i]) {
2120 pj_o (pj);
2121 pj_kn (pj, "role", i);
2122 pj_ks (pj, "role_str", r_reg_get_role (i));
2123 pj_ks (pj, "reg", core->dbg->reg->name[i]);
2124 pj_end (pj);
2125 }
2126 }
2127 pj_end (pj);
2128 pj_k (pj, "reg_info");
2129 pj_a (pj);
2130 for (i = 0; i < R_REG_TYPE_LAST; i++) {
2131 r_list_foreach (core->dbg->reg->regset[i].regs, iter, r) {
2132 pj_o (pj);
2133 pj_kn (pj, "type", r->type);
2134 pj_ks (pj, "type_str", r_reg_get_type (r->type));
2135 pj_ks (pj, "name", r->name);
2136 pj_kn (pj, "size", r->size);
2137 pj_kn (pj, "offset", r->offset);
2138 pj_end (pj);
2139 }
2140 }
2141 pj_end (pj); // "]"
2142 pj_end (pj); // "}"
2143 r_cons_printf ("%s", pj_string (pj));
2144 pj_free (pj);
2145 }
2146 break;
2147 case '?': // "drp?" "arp?"
2148 default:
2149 {
2150 const char *from_a[] = { "arp", "arpi", "arpg", "arp.", "arpj", "arps" };
2151 // TODO #7967 help refactor
2152 const char **help_msg = help_msg_drp;
2153 if (from == 'a') {
2154 help_msg[1] = help_msg[3] = help_msg[6] = help_msg[9] = from_a[0];
2155 help_msg[12] = from_a[1];
2156 help_msg[15] = from_a[2];
2157 help_msg[18] = from_a[3];
2158 help_msg[21] = from_a[4];
2159 }
2160 r_core_cmd_help (core, help_msg);
2161 break;
2162 }
2163 }
2164 }
2165
2166
2167 #if 0
2168 static int showreg(RCore *core, const char *str, bool use_color) {
2169 ut64 off;
2170 utX value;
2171 int err;
2172 int bits = atoi (str);
2173 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false); //R_REG_TYPE_GPR, false);
2174 if (bits) {
2175 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, str[0], use_color? Color_GREEN: NULL);
2176 } else {
2177 off = r_debug_reg_get_err (core->dbg, str + 1, &err, &value);
2178 core->num->value = off;
2179 switch (err) {
2180 case 0:
2181 r_cons_printf ("0x%08"PFMT64x"\n", off);
2182 break;
2183 case 1:
2184 r_cons_printf ("Unknown register '%s'\n", str + 1);
2185 break;
2186 case 80:
2187 r_cons_printf ("0x%04x%016"PFMT64x"\n", value.v80.High, value.v80.Low);
2188 break;
2189 case 96:
2190 r_cons_printf ("0x%08x%016"PFMT64x"\n", value.v96.High, value.v96.Low);
2191 break;
2192 case 128:
2193 r_cons_printf ("0x%016"PFMT64x"%016"PFMT64x"\n", value.v128.High, value.v128.Low);
2194 break;
2195 default:
2196 r_cons_printf ("Error %i while retrieving '%s' \n", err, str + 1);
2197 core->num->value = 0;
2198 }
2199 }
2200 return bits;
2201 }
2202 #endif
2203
2204 // helpers for packed registers
2205 #define NUM_PACK_TYPES 6
2206 #define NUM_INT_PACK_TYPES 4
2207 int pack_sizes[NUM_PACK_TYPES] = { 8, 16, 32, 64, 32, 64 };
2208 char *pack_format[NUM_PACK_TYPES] = { "%s0x%02" PFMT64x, "%s0x%04" PFMT64x, "%s0x%08" PFMT64x,
2209 "%s0x%016" PFMT64x, "%s%lf" , "%s%lf" };
2210 #define pack_print(i, reg, pack_type_index) r_cons_printf (pack_format[pack_type_index], i != 0 ? " " : "", reg);
2211
cmd_debug_reg_print_packed_reg(RCore * core,RRegItem * item,char explicit_size,char * pack_show)2212 static void cmd_debug_reg_print_packed_reg(RCore *core, RRegItem *item, char explicit_size, char* pack_show) {
2213 int pi, i;
2214 for (pi = 0; pi < NUM_PACK_TYPES; pi++) {
2215 if (!explicit_size || pack_show[pi]) {
2216 for (i = 0; i < item->packed_size / pack_sizes[pi]; i++) {
2217 ut64 res = r_reg_get_pack(core->dbg->reg, item, i, pack_sizes[pi]);
2218 if( pi > NUM_INT_PACK_TYPES-1) { // are we printing int or double?
2219 if (pack_sizes[pi] == 64) {
2220 double dres;
2221 memcpy ((void*)&dres, (void*)&res, 8);
2222 pack_print (i, dres, pi);
2223 } else if (pack_sizes[pi] == 32) {
2224 float fres;
2225 memcpy ((void*)&fres, (void*)&res, 4);
2226 pack_print (i, fres, pi);
2227 }
2228 } else {
2229 pack_print (i, res, pi);
2230 }
2231 }
2232 r_cons_newline ();
2233 }
2234 }
2235 }
2236
__table_format_string(RTable * t,int fmt)2237 static char *__table_format_string(RTable *t, int fmt) {
2238 switch (fmt) {
2239 case 'j': return r_table_tojson (t);
2240 case 's': return r_table_tostring (t);
2241 }
2242 return r_table_tofancystring (t);
2243 }
2244
__tableRegList(RCore * core,RReg * reg,const char * str)2245 static void __tableRegList (RCore *core, RReg *reg, const char *str) {
2246 int i;
2247 RRegItem *e;
2248 RTable *t = r_core_table (core, "regprofile");
2249 RTableColumnType *typeString = r_table_type ("string");
2250 RTableColumnType *typeNumber = r_table_type ("number");
2251 RTableColumnType *typeBoolean = r_table_type ("boolean");
2252 r_table_add_column (t, typeNumber, "offset", 0);
2253 r_table_add_column (t, typeNumber, "size", 0);
2254 r_table_add_column (t, typeNumber, "psize", 0);
2255 r_table_add_column (t, typeNumber, "index", 0);
2256 r_table_add_column (t, typeNumber, "arena", 0);
2257 r_table_add_column (t, typeBoolean, "float", 0);
2258 r_table_add_column (t, typeString, "name", 0);
2259 r_table_add_column (t, typeString, "flags", 0);
2260 r_table_add_column (t, typeString, "comment", 0);
2261 for (i = 0; i < R_REG_TYPE_LAST; i++) {
2262 RList *list = r_reg_get_list (reg, i);
2263 RListIter *iter;
2264 r_list_foreach (list, iter, e) {
2265 // sdb_fmt is not thread safe
2266 r_table_add_row (t,
2267 sdb_fmt ("%d", e->offset),
2268 sdb_fmt ("%d", e->size),
2269 sdb_fmt ("%d", e->packed_size),
2270 sdb_fmt ("%d", e->index),
2271 sdb_fmt ("%d", i),
2272 r_str_bool (e->is_float),
2273 r_str_get (e->name),
2274 r_str_get (e->flags),
2275 r_str_get (e->comment),
2276 NULL
2277 );
2278 }
2279 }
2280 const char fmt = *str++;
2281 const char *q = str;
2282 if (r_table_query (t, q)) {
2283 char *s = __table_format_string (t, fmt);
2284 r_cons_printf ("%s\n", s);
2285 free (s);
2286 }
2287 r_table_free (t);
2288 }
2289
cmd_debug_reg(RCore * core,const char * str)2290 static void cmd_debug_reg(RCore *core, const char *str) {
2291 char *arg;
2292 struct r_reg_item_t *r;
2293 const char *name, *use_color;
2294 size_t i;
2295 int size, type = R_REG_TYPE_GPR;
2296 int bits = (core->dbg->bits & R_SYS_BITS_64)? 64: 32;
2297 int use_colors = r_config_get_i (core->config, "scr.color");
2298 int newbits = atoi ((str&&*str)? str + 1: "");
2299 if (newbits > 0) {
2300 bits = newbits;
2301 }
2302 if (use_colors) {
2303 #undef ConsP
2304 #define ConsP(x) (core->cons && core->cons->context->pal.x)? core->cons->context->pal.x
2305 use_color = ConsP(creg): Color_BWHITE;
2306 } else {
2307 use_color = NULL;
2308 }
2309 if (!str) {
2310 str = "";
2311 }
2312 switch (str[0]) {
2313 case 'C': // "drC"
2314 {
2315 const bool json_out = str[1] == 'j';
2316 name = r_str_trim_head_ro (json_out ? str + 3 : str + 2);
2317 if (name) {
2318 r = r_reg_get (core->dbg->reg, name , -1);
2319 if (r) {
2320 if (json_out) {
2321 PJ *pj = r_core_pj_new (core);
2322 if (!pj) {
2323 return;
2324 }
2325 pj_o (pj);
2326 if (r->comment) {
2327 pj_ks (pj, r->name, r->comment);
2328 } else {
2329 pj_knull (pj, r->name);
2330 }
2331 pj_end (pj);
2332 const char *s = pj_string (pj);
2333 r_cons_println (s);
2334 pj_free (pj);
2335 } else {
2336 if (r->comment) {
2337 r_cons_printf ("%s\n", r->comment);
2338 } else {
2339 eprintf ("Register %s doesn't have any comments\n", name);
2340 }
2341 }
2342 } else {
2343 eprintf ("Register %s not found\n", name);
2344 }
2345 } else {
2346 eprintf ("usage: drC [register]\n");
2347 }
2348 }
2349 break;
2350 case '-': // "dr-"
2351 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, NULL, '-', 0);
2352 break;
2353 case '?': // "dr?"
2354 if (str[1]) {
2355 RListIter *iter;
2356 char *all = (char *)r_str_trim_head_ro (str + 1);
2357 if (!strcmp (all, "?")) { // "dr??"
2358 all = r_core_cmd_str (core, "drp~=[0]");
2359 all = r_str_replace (all, "\n", " ", 1);
2360 } else {
2361 all = strdup (all);
2362 }
2363 char *arg;
2364 RList *args = r_str_split_list (all, " ", 0);
2365 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, false); //R_REG_TYPE_GPR, false);
2366 int count = r_list_length (args);
2367 r_list_foreach (args, iter, arg) {
2368 ut64 off = r_debug_reg_get (core->dbg, arg);
2369 if (count == 1) {
2370 r_cons_printf ("0x%08"PFMT64x"\n", off);
2371 } else {
2372 int type = r_reg_get_name_idx (arg);
2373 const char *r = arg;
2374 if (type != -1) {
2375 r = r_reg_get_name (core->dbg->reg, type);
2376 }
2377 r_cons_printf ("%3s %3s 0x%08"PFMT64x"\n", arg, r, off);
2378 }
2379 core->num->value = off;
2380 }
2381 free (all);
2382 r_list_free (args);
2383 } else {
2384 r_core_cmd_help (core, help_msg_dr);
2385 }
2386 break;
2387 case 'l': // "drl[j]"
2388 {
2389 const bool json_out = str[1] == 'j';
2390 RRegSet *rs = r_reg_regset_get (core->dbg->reg, R_REG_TYPE_GPR);
2391 if (rs) {
2392 RRegItem *r;
2393 RListIter *iter;
2394 i = 0;
2395 PJ *pj = NULL;
2396 if (json_out) {
2397 pj = r_core_pj_new (core);
2398 if (!pj) {
2399 return;
2400 }
2401 pj_a (pj);
2402 }
2403 r_list_foreach (rs->regs, iter, r) {
2404 if (json_out) {
2405 pj_s (pj, r->name);
2406 i++;
2407 } else {
2408 r_cons_println (r->name);
2409 }
2410 }
2411 if (json_out) {
2412 pj_end (pj);
2413 const char *s = pj_string (pj);
2414 r_cons_println (s);
2415 pj_free (pj);
2416 }
2417 }
2418 }
2419 break;
2420 case '8': // "dr8"
2421 case 'b': // "drb"
2422 {
2423 int len, type = R_REG_TYPE_GPR;
2424 arg = strchr (str, ' ');
2425 if (arg) {
2426 char *string = r_str_trim_dup (arg + 1);
2427 if (string) {
2428 type = r_reg_type_by_name (string);
2429 if (type == -1 && string[0] != 'a') {
2430 type = R_REG_TYPE_GPR;
2431 }
2432 free (string);
2433 }
2434 }
2435 ut8 *buf = r_reg_get_bytes (core->dbg->reg, type, &len);
2436 if (str[0] == '8') {
2437 r_print_bytes (core->print, buf, len, "%02x");
2438 } else {
2439 switch (str[1]) {
2440 case '1':
2441 r_print_hexdump (core->print, 0ll, buf, len, 8, 1, 1);
2442 break;
2443 case '2':
2444 r_print_hexdump (core->print, 0ll, buf, len, 16, 2, 1);
2445 break;
2446 case '4':
2447 r_print_hexdump (core->print, 0ll, buf, len, 32, 4, 1);
2448 break;
2449 case '8':
2450 r_print_hexdump (core->print, 0ll, buf, len, 64, 8, 1);
2451 break;
2452 default:
2453 if (core->rasm->bits == 64) {
2454 r_print_hexdump (core->print, 0ll, buf, len, 64, 8, 1);
2455 } else {
2456 r_print_hexdump (core->print, 0ll, buf, len, 32, 4, 1);
2457 }
2458 break;
2459 }
2460 }
2461 free (buf);
2462 }
2463 break;
2464 case 'c': // "drc"
2465 // todo: set flag values with drc zf=1
2466 if (str[1] == '=') {
2467 RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
2468 if (rf) {
2469 r_cons_printf ("s:%d z:%d c:%d o:%d p:%d\n",
2470 rf->s, rf->z, rf->c, rf->o, rf->p);
2471 free (rf);
2472 }
2473 } else if (strchr (str, '=')) {
2474 char *a = strdup (r_str_trim_head_ro (str + 1));
2475 char *eq = strchr (a, '=');
2476 if (eq) {
2477 *eq++ = 0;
2478 char *k = a;
2479 r_str_trim (a);
2480 bool v = !strcmp (eq, "true") || atoi (eq);
2481 int type = r_reg_cond_from_string (k);
2482 if (type != -1) {
2483 RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
2484 if (rf) {
2485 r_reg_cond_bits_set (core->dbg->reg, type, rf, v);
2486 r_reg_cond_apply (core->dbg->reg, rf);
2487 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, true);
2488 free (rf);
2489 }
2490 } else {
2491 eprintf ("Unknown condition register\n");
2492 }
2493 }
2494 free (a);
2495 } else {
2496 RRegItem *r;
2497 const char *name = r_str_trim_head_ro (str + 1);
2498 if (*name && name[1]) {
2499 r = r_reg_cond_get (core->dbg->reg, name);
2500 if (r) {
2501 r_cons_println (r->name);
2502 } else {
2503 int id = r_reg_cond_from_string (name);
2504 RRegFlags* rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
2505 if (rf) {
2506 int o = r_reg_cond_bits (core->dbg->reg, id, rf);
2507 core->num->value = o;
2508 // orly?
2509 r_cons_printf ("%d\n", o);
2510 free (rf);
2511 } else eprintf ("unknown conditional or flag register\n");
2512 }
2513 } else {
2514 RRegFlags *rf = r_reg_cond_retrieve (core->dbg->reg, NULL);
2515 if (rf) {
2516 if (*name=='=') {
2517 for (i=0; i<R_REG_COND_LAST; i++) {
2518 r_cons_printf ("%s:%d ",
2519 r_reg_cond_to_string (i),
2520 r_reg_cond_bits (core->dbg->reg, i, rf));
2521 }
2522 r_cons_newline ();
2523 } else {
2524 for (i=0; i<R_REG_COND_LAST; i++) {
2525 r_cons_printf ("%d %s\n",
2526 r_reg_cond_bits (core->dbg->reg, i, rf),
2527 r_reg_cond_to_string (i));
2528 }
2529 }
2530 free (rf);
2531 }
2532 }
2533 }
2534 break;
2535 case 'x': // "drx"
2536 switch (str[1]) {
2537 case '\0':
2538 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2539 r_debug_drx_list (core->dbg);
2540 break;
2541 case '-':
2542 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2543 r_debug_drx_unset (core->dbg, atoi (str + 2));
2544 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
2545 break;
2546 case ' ': {
2547 char *s = strdup (str+2);
2548 char sl, n, perm;
2549 int len;
2550 ut64 off;
2551
2552 sl = r_str_word_set0 (s);
2553 if (sl == 4) {
2554 #define arg(x) r_str_word_get0(s,x)
2555 n = (char)r_num_math (core->num, arg(0));
2556 off = r_num_math (core->num, arg(1));
2557 len = (int)r_num_math (core->num, arg(2));
2558 perm = (char)r_str_rwx (arg (3));
2559 if (len == -1) {
2560 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2561 r_debug_drx_set (core->dbg, n, 0, 0, 0, 0);
2562 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
2563 } else {
2564 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, false);
2565 r_debug_drx_set (core->dbg, n, off, len, perm, 0);
2566 r_debug_reg_sync (core->dbg, R_REG_TYPE_DRX, true);
2567 }
2568 } else {
2569 eprintf ("|usage: drx n [address] [length] [perm]\n");
2570 }
2571 free (s);
2572 } break;
2573 case '?':
2574 default:
2575 r_core_cmd_help (core, help_msg_drx);
2576 break;
2577 }
2578 break;
2579 case 's': // "drs"
2580 switch (str[1]) {
2581 case '\0': // "drs"
2582 r_cons_printf ("%d\n", r_list_length (
2583 core->dbg->reg->regset[0].pool));
2584 break;
2585 case '-': // "drs-"
2586 r_reg_arena_pop (core->dbg->reg);
2587 // restore debug registers if in debugger mode
2588 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, true);
2589 break;
2590 case '+': // "drs+"
2591 r_reg_arena_push (core->dbg->reg);
2592 break;
2593 case '?': // "drs?"
2594 default:
2595 r_core_cmd_help (core, help_msg_drs);
2596 break;
2597 }
2598 break;
2599 case 'm': // "drm"
2600 if (str[1]=='?') {
2601 r_core_cmd_help (core, help_msg_drm);
2602 } else if (str[1] == ' ' || str[1] == 'b' || str[1] == 'd' || str[1] == 'w' || str[1] == 'q' || str[1] == 'l'
2603 || str[1] == 'f' || (str[1] == 'y' && str[2] != '\x00')) {
2604 char explicit_index = 0;
2605 char explicit_size = 0;
2606 char explicit_name = 0;
2607 char pack_show[NUM_PACK_TYPES] = { 0, 0, 0, 0, 0, 0};
2608 int index = 0;
2609 int size = 0; // auto
2610 char *q, *p, *name;
2611 char *eq = NULL;
2612 RRegisterType reg_type = R_REG_TYPE_XMM;
2613 if ((str[1] == ' ' && str[2] != '\x00') || (str[1] == 'y' && str[2] == ' ' && str[3] != '\x00')) {
2614 if (str[1] == 'y') { // support `drmy ymm0` and `drm ymm0`
2615 str = str + 1;
2616 }
2617 name = strdup (str + 2);
2618 explicit_name = 1;
2619 eq = strchr (name, '=');
2620 if (eq) {
2621 *eq++ = 0;
2622 }
2623 p = strchr (name, ' ');
2624 if (p) {
2625 *p++ = 0;
2626 q = strchr (p, ' ');
2627 if (p[0] != '*') {
2628 // do not show whole register
2629 explicit_index = 1;
2630 index = r_num_math (core->num, p);
2631 }
2632 if (q) {
2633 *q++ = 0;
2634 size = r_num_math (core->num, q);
2635 for (i = 0; i < NUM_PACK_TYPES; i++) {
2636 if (size == pack_sizes[i]) {
2637 explicit_size = 1;
2638 pack_show[i] = 1;
2639 }
2640 }
2641 if (!explicit_size) {
2642 eprintf ("Unsupported wordsize %d\n", size);
2643 break;
2644 }
2645 }
2646 }
2647 } else {
2648 explicit_size = 1;
2649 if (str[1] == 'y') {
2650 reg_type = R_REG_TYPE_YMM;
2651 str = str + 1;
2652 }
2653 if (str[2] == ' ' && str[3] != '\x00') {
2654 name = strdup (str + 3);
2655 explicit_name = 1;
2656 }
2657 switch (str[1]) {
2658 case 'b': // "drmb"
2659 size = pack_sizes[0];
2660 pack_show[0] = 1;
2661 break;
2662 case 'w': // "drmw"
2663 size = pack_sizes[1];
2664 pack_show[1] = 1;
2665 break;
2666 case 'd': // "drmd"
2667 size = pack_sizes[2];
2668 pack_show[2] = 1;
2669 break;
2670 case 'q': // "drmq"
2671 size = pack_sizes[3];
2672 pack_show[3] = 1;
2673 break;
2674 case 'f': // "drmf"
2675 size = pack_sizes[4];
2676 pack_show[4] = 1;
2677 break;
2678 case 'l': // "drml"
2679 size = pack_sizes[5];
2680 pack_show[5] = 1;
2681 break;
2682 default:
2683 eprintf ("Unkown comamnd");
2684 return;
2685 }
2686 }
2687 if (explicit_name) {
2688 RRegItem *item = r_reg_get (core->dbg->reg, name, -1);
2689 if (item) {
2690 if (eq) {
2691 // TODO: support setting YMM registers
2692 if (reg_type == R_REG_TYPE_YMM) {
2693 eprintf ("Setting ymm registers not supported yet!\n");
2694 } else {
2695 ut64 val = r_num_math (core->num, eq);
2696 r_reg_set_pack (core->dbg->reg, item, index, size, val);
2697 r_debug_reg_sync (core->dbg, reg_type, true);
2698 }
2699 } else {
2700 r_debug_reg_sync (core->dbg, reg_type, false);
2701 if (!explicit_index) {
2702 cmd_debug_reg_print_packed_reg (core, item, explicit_size, pack_show);
2703 } else {
2704 ut64 res = r_reg_get_pack (core->dbg->reg, item, index, size);
2705 // print selected index / wordsize
2706 r_cons_printf ("0x%08" PFMT64x "\n", res);
2707 }
2708 }
2709 } else {
2710 eprintf ("cannot find multimedia register '%s'\n", name);
2711 }
2712 free (name);
2713 } else {
2714 // explicit size no name
2715 RListIter *iter;
2716 RRegItem *item;
2717 RList *head;
2718 r_debug_reg_sync (core->dbg, reg_type, false);
2719 head = r_reg_get_list (core->dbg->reg, reg_type);
2720 if (head) {
2721 r_list_foreach (head, iter, item) {
2722 if (item->type != reg_type) {
2723 continue;
2724 }
2725 r_cons_printf ("%-5s = ", item->name);
2726 cmd_debug_reg_print_packed_reg (core, item, explicit_size, pack_show);
2727 }
2728 }
2729 }
2730 } else { // drm # no arg
2731 if (str[1] == 'y') { // drmy
2732 r_debug_reg_sync (core->dbg, R_REG_TYPE_YMM, false);
2733 r_debug_reg_list (core->dbg, R_REG_TYPE_YMM, 256, NULL, 0, 0);
2734 } else { // drm
2735 r_debug_reg_sync (core->dbg, R_REG_TYPE_XMM, false);
2736 r_debug_reg_list (core->dbg, R_REG_TYPE_XMM, 128, NULL, 0, 0);
2737 }
2738 }
2739 //r_debug_drx_list (core->dbg);
2740 break;
2741 case 'f': // "drf"
2742 //r_debug_drx_list (core->dbg);
2743 if (str[1]=='?') {
2744 eprintf ("usage: drf [fpureg] [= value]\n");
2745 } else if (str[1]==' ') {
2746 char *p, *name = strdup (str + 2);
2747 char *eq = strchr (name, '=');
2748 if (eq) {
2749 *eq++ = 0;
2750 }
2751 p = strchr (name, ' ');
2752 if (p) {
2753 *p++ = 0;
2754 }
2755 RRegItem *item = r_reg_get (core->dbg->reg, name, -1);
2756 if (item) {
2757 if (eq) {
2758 long double val = 0.0f;
2759 #if __windows__
2760 double dval = 0.0f;
2761 sscanf (eq, "%lf", (double*)&dval);
2762 val = dval;
2763 #else
2764 sscanf (eq, "%Lf", &val);
2765 #endif
2766 r_reg_set_double (core->dbg->reg, item, val);
2767 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, true);
2768 r_debug_reg_sync (core->dbg, R_REG_TYPE_FPU, true);
2769 } else {
2770 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
2771 r_debug_reg_sync (core->dbg, R_REG_TYPE_FPU, false);
2772 long double res = r_reg_get_longdouble (core->dbg->reg, item);
2773 r_cons_printf ("%Lf\n", res);
2774 }
2775 } else {
2776 /* note, that negative type forces sync to print the regs from the backend */
2777 eprintf ("cannot find multimedia register '%s'\n", name);
2778 }
2779 free (name);
2780 } else {
2781 //TODO: Do not use this hack to print fpu register
2782 r_debug_reg_sync (core->dbg, -R_REG_TYPE_FPU, false);
2783 }
2784 break;
2785 case 'p': // "drp"
2786 cmd_reg_profile (core, 'd', str);
2787 break;
2788 case 't': { // "drt"
2789 char rad = 0;
2790 switch (str[1]) {
2791 case '\0': // "drt"
2792 for (i = 0; (name = r_reg_get_type (i)); i++) {
2793 r_cons_println (name);
2794 }
2795 break;
2796 case 'j': // "drtj"
2797 case '*': // "drt*"
2798 rad = str[1];
2799 str++;
2800 if (rad == 'j' && !str[1]) {
2801 PJ *pj = r_core_pj_new (core);
2802 if (!pj) {
2803 break;
2804 }
2805 pj_a (pj);
2806 for (i = 0; (name = r_reg_get_type (i)); i++) {
2807 pj_s (pj, name);
2808 }
2809 pj_end (pj);
2810 r_cons_println (pj_string (pj));
2811 pj_free (pj);
2812 break;
2813 }
2814 // fallthrough
2815 case ' ': // "drt "
2816 {
2817 int role = r_reg_get_name_idx (str+2);
2818 const char *regname = r_reg_get_name (core->dbg->reg, role);
2819 if (!regname) {
2820 regname = str + 2;
2821 }
2822 size = atoi (regname);
2823 if (size < 1) {
2824 char *arg = strchr (str + 2, ' ');
2825 size = 0;
2826 if (arg) {
2827 *arg++ = 0;
2828 size = atoi (arg);
2829 }
2830 type = r_reg_type_by_name (str + 2);
2831 r_debug_reg_sync (core->dbg, type, false);
2832 r_debug_reg_list (core->dbg, type, size, NULL, rad, use_color);
2833 } else {
2834 if (type != R_REG_TYPE_LAST) {
2835 r_debug_reg_sync (core->dbg, type, false);
2836 r_debug_reg_list (core->dbg, type, size, NULL, rad, use_color);
2837 } else {
2838 eprintf ("cmd_debug_reg: unknown type\n");
2839 }
2840 }
2841 break;
2842 }
2843 case '?': // "drt?"
2844 default:
2845 r_core_cmd_help (core, help_msg_drt);
2846 break;
2847 }
2848 }
2849 break;
2850 case 'n': // "drn"
2851 {
2852 char *foo = strdup (str+2);
2853 r_str_case (foo, true);
2854 name = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (foo));
2855 if (name && *name) {
2856 r_cons_println (name);
2857 } else eprintf ("oops. try drn [pc|sp|bp|a0|a1|a2|a3|a4|r0|r1|zf|sf|nf|of]\n");
2858 free (foo);
2859 }
2860 break;
2861 case 'd': // "drd"
2862 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, NULL, 3, use_color); // xxx detect which one is current usage
2863 break;
2864 case 'o': // "dro"
2865 r_reg_arena_swap (core->dbg->reg, false);
2866 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, NULL, 0, use_color); // xxx detect which one is current usage
2867 r_reg_arena_swap (core->dbg->reg, false);
2868 break;
2869 case ',': // "dr,"
2870 if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2871 __tableRegList (core, core->dbg->reg, str + 1);
2872 } else {
2873 eprintf ("cannot retrieve registers from pid %d\n", core->dbg->pid);
2874 }
2875 break;
2876 case '=': // "dr="
2877 {
2878 int pcbits2, pcbits = grab_bits (core, str + 1, &pcbits2);
2879 if (r_config_get_i (core->config, "cfg.debug")) {
2880 if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2881 if (pcbits && pcbits != bits) {
2882 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, NULL, '=', use_color); // xxx detect which one is current usage
2883 }
2884 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, NULL, '=', use_color); // xxx detect which one is current usage
2885 if (pcbits2) {
2886 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits2, NULL, '=', use_color); // xxx detect which one is current usage
2887 }
2888 } //else eprintf ("cannot retrieve registers from pid %d\n", core->dbg->pid);
2889 } else {
2890 RReg *orig = core->dbg->reg;
2891 core->dbg->reg = core->anal->reg;
2892 if (pcbits && pcbits != bits)
2893 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, NULL, '=', use_color); // xxx detect which one is current usage
2894 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, bits, NULL, '=', use_color); // xxx detect which one is current usage
2895 core->dbg->reg = orig;
2896 }
2897 }
2898 break;
2899 case '.':
2900 if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2901 int pcbits2, pcbits = grab_bits (core, str + 1, &pcbits2);
2902 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, NULL, '.', use_color);
2903 if (pcbits2) {
2904 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits2, NULL, '.', use_color);
2905 }
2906 }
2907 break;
2908 case '*': // "dr*"
2909 if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2910 int pcbits2, pcbits = grab_bits (core, str + 1, &pcbits2);
2911 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, NULL, '*', use_color);
2912 if (pcbits2) {
2913 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits2, NULL, '*', use_color);
2914 }
2915 r_flag_space_pop (core->flags);
2916 }
2917 break;
2918 case 'i': // "dri"
2919 r_core_debug_ri (core, core->dbg->reg, 0);
2920 break;
2921 case 'r': // "drr"
2922 switch (str[1]) {
2923 case 'j': // "drrj"
2924 r_core_debug_rr (core, core->dbg->reg, 'j');
2925 break;
2926 default:
2927 r_core_debug_rr (core, core->dbg->reg, 0);
2928 break;
2929 }
2930 break;
2931 case 'j': // "drj"
2932 case '\0': // "dr"
2933 if (r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false)) {
2934 int pcbits = core->anal->bits;
2935 const char *pcname = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
2936 RRegItem *reg = r_reg_get (core->anal->reg, pcname, 0);
2937 if (reg) {
2938 if (core->rasm->bits != reg->size) {
2939 pcbits = reg->size;
2940 }
2941 }
2942 if (str[0] == 'j') {
2943 PJ *pj = r_core_pj_new (core);
2944 if (!pj) {
2945 return;
2946 }
2947 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, pj, 'j', use_color);
2948 } else {
2949 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, pcbits, NULL, 0, use_color);
2950 }
2951 } else {
2952 eprintf ("cannot retrieve registers from pid %d\n", core->dbg->pid);
2953 }
2954 break;
2955 case ' ': // "dr"
2956 arg = strchr (str + 1, '=');
2957 if (arg) {
2958 *arg = 0;
2959 char *string = r_str_trim_dup (str + 1);
2960 const char *regname = r_reg_get_name (core->dbg->reg, r_reg_get_name_idx (string));
2961 if (!regname) {
2962 regname = string;
2963 }
2964 r = r_reg_get (core->dbg->reg, regname, -1); //R_REG_TYPE_GPR);
2965 if (r) {
2966 if (r->flags) {
2967 r_cons_printf ("0x%08"PFMT64x" ->",
2968 r_reg_get_value (core->dbg->reg, r));
2969 r_reg_set_bvalue (core->dbg->reg, r, arg+1);
2970 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, true);
2971 r_cons_printf ("0x%08"PFMT64x"\n",
2972 r_reg_get_value (core->dbg->reg, r));
2973 } else {
2974 r_cons_printf ("0x%08"PFMT64x" ->",
2975 r_reg_get_value (core->dbg->reg, r));
2976 r_reg_set_value (core->dbg->reg, r,
2977 r_num_math (core->num, arg+1));
2978 r_debug_reg_sync (core->dbg, R_REG_TYPE_ALL, true);
2979 r_cons_printf ("0x%08"PFMT64x"\n",
2980 r_reg_get_value (core->dbg->reg, r));
2981 }
2982 } else {
2983 eprintf ("unknown register '%s'\n", string);
2984 }
2985 free (string);
2986 // update flags here
2987 r_core_cmdf (core, ".dr*%d", bits);
2988 return;
2989 }
2990
2991 size = atoi (str + 1);
2992 if (size) {
2993 r_debug_reg_list (core->dbg, R_REG_TYPE_GPR, size, NULL, str[0], use_color);
2994 } else {
2995 char *comma = strchr (str + 1, ',');
2996 if (comma) {
2997 char *args = strdup (str + 1);
2998 char argc = r_str_split (args, ',');
2999 for (i = 0; i < argc; i++) {
3000 showreg (core, r_str_word_get0 (args, i));
3001 }
3002 free (args);
3003 } else {
3004 showreg (core, str + 1);
3005 }
3006 }
3007 }
3008 }
3009
backtrace_vars(RCore * core,RList * frames)3010 static void backtrace_vars(RCore *core, RList *frames) {
3011 RDebugFrame *f;
3012 RListIter *iter;
3013 // anal vs debug ?
3014 const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
3015 const char *bp = r_reg_get_name (core->anal->reg, R_REG_NAME_BP);
3016 if (!sp) {
3017 sp = "SP";
3018 }
3019 if (!bp) {
3020 bp = "BP";
3021 }
3022 RReg *r = core->anal->reg;
3023 ut64 dsp = r_reg_getv (r, sp);
3024 ut64 dbp = r_reg_getv (r, bp);
3025 int n = 0;
3026 r_list_foreach (frames, iter, f) {
3027 ut64 s = f->sp ? f->sp : dsp;
3028 ut64 b = f->bp ? f->bp : dbp;
3029 r_reg_setv (r, bp, s);
3030 r_reg_setv (r, sp, b);
3031 //////////
3032 char flagdesc[1024], flagdesc2[1024];
3033 RFlagItem *fi = r_flag_get_at (core->flags, f->addr, true);
3034 flagdesc[0] = flagdesc2[0] = 0;
3035 if (fi) {
3036 if (fi->offset != f->addr) {
3037 int delta = (int)(f->addr - fi->offset);
3038 if (delta > 0) {
3039 snprintf (flagdesc, sizeof (flagdesc),
3040 "%s+%d", fi->name, delta);
3041 } else if (delta < 0) {
3042 snprintf (flagdesc, sizeof (flagdesc),
3043 "%s%d", fi->name, delta);
3044 } else {
3045 snprintf (flagdesc, sizeof (flagdesc),
3046 "%s", fi->name);
3047 }
3048 } else {
3049 snprintf (flagdesc, sizeof (flagdesc),
3050 "%s", fi->name);
3051 }
3052 }
3053 //////////
3054 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, f->addr, 0);
3055 // char *str = r_str_newf ("[frame %d]", n);
3056 r_cons_printf ("%d 0x%08"PFMT64x" sp: 0x%08"PFMT64x" %-5d"
3057 "[%s] %s %s\n", n, f->addr, f->sp, (int)f->size,
3058 fcn ? fcn->name : "??", flagdesc, flagdesc2);
3059 eprintf ("afvd @ 0x%"PFMT64x"\n", f->addr);
3060 r_cons_push();
3061 char *res = r_core_cmd_strf (core, "afvd@0x%"PFMT64x, f->addr);
3062 r_cons_pop();
3063 r_cons_printf ("%s", res);
3064 free (res);
3065 n++;
3066 }
3067 r_reg_setv (r, bp, dbp);
3068 r_reg_setv (r, sp, dsp);
3069 }
3070
asciiart_backtrace(RCore * core,RList * frames)3071 static void asciiart_backtrace(RCore *core, RList *frames) {
3072 // TODO: show local variables
3073 // TODO: show function/flags/symbols related
3074 // TODO: show contents of stack
3075 // TODO: honor scr.color
3076 RDebugFrame *f;
3077 RListIter *iter;
3078 bool mymap = false;
3079 // anal vs debug ?
3080 const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
3081 const char *bp = r_reg_get_name (core->anal->reg, R_REG_NAME_BP);
3082 if (!sp) {
3083 sp = "SP";
3084 }
3085 if (!bp) {
3086 bp = "BP";
3087 }
3088 ut64 dsp = r_reg_getv (core->anal->reg, sp);
3089 ut64 dbp = r_reg_getv (core->anal->reg, bp);
3090 RDebugMap *map = r_debug_map_get (core->dbg, dsp);
3091 if (!map) {
3092 mymap = true;
3093 map = R_NEW0 (RDebugMap);
3094 map->addr = UT64_MAX;
3095 map->addr_end = UT64_MAX;
3096 }
3097
3098 r_cons_printf ("0x%016"PFMT64x" STACK END ^^^\n", map->addr);
3099 r_cons_printf ("0x%016"PFMT64x" STACK POINTER: %s\n", dsp, sp);
3100 r_cons_printf (" .------------------------.\n");
3101 int n = 0;
3102 r_list_foreach (frames, iter, f) {
3103 ut64 s = f->sp ? f->sp : dsp;
3104 ut64 b = f->bp ? f->bp : dbp;
3105 char *str = r_str_newf ("[frame %d]", n);
3106 r_cons_printf ("0x%016"PFMT64x" |%4s %10s | ; size %" PFMTDPTR "\n", s, sp, str, (ptrdiff_t)(s - b));
3107 free (str);
3108 r_cons_printf (" | ... |\n");
3109 r_cons_printf ("0x%016"PFMT64x" |%4s 0x%016"PFMT64x" | %s\n", b, bp, f->addr, "; return address");
3110 r_cons_printf (" )------------------------(\n");
3111 // eprintf ("0x%08llx 0x%08llx 0x%08llx\n", f->addr, s, b);
3112 n++;
3113 }
3114 r_cons_printf (" | ... |\n");
3115 r_cons_printf (" `------------------------'\n");
3116 r_cons_printf ("0x%016"PFMT64x" STACK BOTTOM\n", map->addr_end);
3117 if (mymap) {
3118 r_debug_map_free (map);
3119 }
3120 }
3121
get_backtrace_info(RCore * core,RDebugFrame * frame,ut64 addr,char ** flagdesc,char ** flagdesc2,char ** pcstr,char ** spstr)3122 static void get_backtrace_info(RCore* core, RDebugFrame* frame, ut64 addr, char** flagdesc, char** flagdesc2, char** pcstr, char** spstr) {
3123 RFlagItem *f = r_flag_get_at (core->flags, frame->addr, true);
3124 *flagdesc = NULL;
3125 *flagdesc2 = NULL;
3126 if (f) {
3127 if (f->offset != addr) {
3128 int delta = (int)(frame->addr - f->offset);
3129 if (delta > 0) {
3130 *flagdesc = r_str_newf ("%s+%d", f->name, delta);
3131 } else if (delta < 0) {
3132 *flagdesc = r_str_newf ("%s%d", f->name, delta);
3133 } else {
3134 *flagdesc = r_str_newf ("%s", f->name);
3135 }
3136 } else {
3137 *flagdesc = r_str_newf ("%s", f->name);
3138 }
3139 }
3140 f = r_flag_get_at (core->flags, frame->addr, true);
3141 if (f && !strchr (f->name, '.')) {
3142 f = r_flag_get_at (core->flags, frame->addr - 1, true);
3143 }
3144 if (f) {
3145 if (f->offset != addr) {
3146 int delta = (int)(frame->addr - 1 - f->offset);
3147 if (delta > 0) {
3148 *flagdesc2 = r_str_newf ("%s+%d", f->name, delta + 1);
3149 } else if (delta < 0) {
3150 *flagdesc2 = r_str_newf ("%s%d", f->name, delta + 1);
3151 } else {
3152 *flagdesc2 = r_str_newf ("%s+1", f->name);
3153 }
3154 } else {
3155 *flagdesc2 = r_str_newf ("%s", f->name);
3156 }
3157 }
3158 if (!r_str_cmp (*flagdesc, *flagdesc2, -1)) {
3159 free (*flagdesc2);
3160 *flagdesc2 = NULL;
3161 }
3162 if (pcstr && spstr) {
3163 if (core->dbg->bits & R_SYS_BITS_64) {
3164 *pcstr = r_str_newf ("0x%-16" PFMT64x, frame->addr);
3165 *spstr = r_str_newf ("0x%-16" PFMT64x, frame->sp);
3166 } else if (core->dbg->bits & R_SYS_BITS_32) {
3167 *pcstr = r_str_newf ("0x%-8" PFMT64x, frame->addr);
3168 *spstr = r_str_newf ("0x%-8" PFMT64x, frame->sp);
3169 } else {
3170 *pcstr = r_str_newf ("0x%" PFMT64x, frame->addr);
3171 *spstr = r_str_newf ("0x%" PFMT64x, frame->sp);
3172 }
3173 }
3174 }
3175
static_debug_stop(void * u)3176 static void static_debug_stop(void *u) {
3177 RDebug *dbg = (RDebug *)u;
3178 r_debug_stop (dbg);
3179 }
3180
core_cmd_dbi(RCore * core,const char * input,const ut64 idx)3181 static void core_cmd_dbi(RCore *core, const char *input, const ut64 idx) {
3182 int i;
3183 char *p;
3184 RBreakpointItem *bpi;
3185 switch (input[2]) {
3186 case ' ': // "dbi."
3187 {
3188 const int index = r_bp_get_index_at (core->dbg->bp, idx);
3189 if (index != -1) {
3190 r_cons_printf ("%d\n", index);
3191 }
3192 }
3193 break;
3194 case '-': // "dbi-"
3195 {
3196 if (!r_bp_del_index (core->dbg->bp, idx)) {
3197 eprintf ("Breakpoint with index %d not found\n", (int)idx);
3198 }
3199 }
3200 break;
3201 case '.': // "dbi."
3202 {
3203 const int index = r_bp_get_index_at (core->dbg->bp, core->offset);
3204 if (index != -1) {
3205 r_cons_printf ("%d\n", index);
3206 }
3207 }
3208 break;
3209 case 0: // "dbi"
3210 for (i = 0; i < core->dbg->bp->bps_idx_count; i++) {
3211 if ((bpi = core->dbg->bp->bps_idx[i])) {
3212 r_cons_printf ("%d 0x%08"PFMT64x" E:%d T:%d\n",
3213 i, bpi->addr, bpi->enabled, bpi->trace);
3214 }
3215 }
3216 break;
3217 case 'x': // "dbix"
3218 if (input[3] == ' ') {
3219 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3220 char *expr = strchr (input + 4, ' ');
3221 if (expr) {
3222 free (bpi->expr);
3223 bpi->expr = strdup (expr);
3224 }
3225 }
3226 r_cons_printf ("%d\n", (int)idx);
3227 } else {
3228 for (i = 0; i < core->dbg->bp->bps_idx_count; i++) {
3229 RBreakpointItem *bp = core->dbg->bp->bps_idx[i];
3230 if (bp) {
3231 r_cons_printf ("%d 0x%08"PFMT64x" %s\n", i, bp->addr, bp->expr);
3232 }
3233 }
3234 }
3235 break;
3236 case 'c': // "dbic"
3237 p = strchr (input + 3, ' ');
3238 if (p) {
3239 char *q = strchr (p + 1, ' ');
3240 if (q) {
3241 *q++ = 0;
3242 ut64 addr = r_num_math (core->num, p);
3243 bpi = r_bp_get_index (core->dbg->bp, addr);
3244 if (bpi) {
3245 bpi->data = strdup (q);
3246 } else {
3247 eprintf ("Cannot set command\n");
3248 }
3249 } else {
3250 eprintf ("|Usage: dbic # cmd\n");
3251 }
3252 } else {
3253 eprintf ("|Usage: dbic # cmd\n");
3254 }
3255 break;
3256 case 'e': // "dbie"
3257 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3258 bpi->enabled = true;
3259 } else {
3260 eprintf ("Cannot unset tracepoint\n");
3261 }
3262 break;
3263 case 'd': // "dbid"
3264 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3265 bpi->enabled = false;
3266 } else {
3267 eprintf ("Cannot unset tracepoint\n");
3268 }
3269 break;
3270 case 's': // "dbis"
3271 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3272 bpi->enabled = !!!bpi->enabled;
3273 } else {
3274 eprintf ("Cannot unset tracepoint\n");
3275 }
3276 break;
3277 case 't': // "dbite" "dbitd" ...
3278 switch (input[3]) {
3279 case 'e':
3280 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3281 bpi->trace = true;
3282 } else {
3283 eprintf ("Cannot unset tracepoint\n");
3284 }
3285 break;
3286 case 'd':
3287 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3288 bpi->trace = false;
3289 } else eprintf ("Cannot unset tracepoint\n");
3290 break;
3291 case 's':
3292 if ((bpi = r_bp_get_index (core->dbg->bp, idx))) {
3293 bpi->trace = !!!bpi->trace;
3294 } else {
3295 eprintf ("Cannot unset tracepoint\n");
3296 }
3297 break;
3298 }
3299 break;
3300 }
3301 }
3302
3303 #if __WINDOWS__
3304 #include "..\debug\p\native\windows\windows_message.h"
3305 #endif
3306
3307 #define DB_ARG(x) r_str_word_get0(str, x)
add_breakpoint(RCore * core,const char * input,bool hwbp,bool watch)3308 static void add_breakpoint(RCore *core, const char *input, bool hwbp, bool watch) {
3309 RBreakpointItem *bpi;
3310 ut64 addr;
3311 int i = 0;
3312
3313 char *str = strdup (r_str_trim_head_ro (input + 1));
3314 int sl = r_str_word_set0 (str);
3315 // For dbw every second argument is 'rw', so we need to skip it.
3316 for (; i < sl; i += 1 + (watch ? 1 : 0)) {
3317 if (*DB_ARG (i) == '-') {
3318 r_bp_del (core->dbg->bp, r_num_math (core->num, DB_ARG (i) + 1));
3319 } else {
3320 int rw = 0;
3321 if (watch) {
3322 if (sl % 2 == 0) {
3323 if (!strcmp (DB_ARG (i + 1), "r")) {
3324 rw = R_BP_PROT_READ;
3325 } else if (!strcmp (DB_ARG (i + 1), "w")) {
3326 rw = R_BP_PROT_WRITE;
3327 } else if (!strcmp (DB_ARG (i + 1), "rw")) {
3328 rw = R_BP_PROT_ACCESS;
3329 } else {
3330 r_core_cmd_help (core, help_msg_dbw);
3331 break;
3332 }
3333 } else {
3334 r_core_cmd_help (core, help_msg_dbw);
3335 break;
3336 }
3337 }
3338 addr = r_num_math (core->num, DB_ARG (i));
3339 bpi = r_debug_bp_add (core->dbg, addr, hwbp, watch, rw, NULL, 0);
3340 if (bpi) {
3341 free (bpi->name);
3342 if (!strcmp (DB_ARG (i), "$$")) {
3343 RFlagItem *f = r_core_flag_get_by_spaces (core->flags, addr);
3344 if (f) {
3345 if (addr > f->offset) {
3346 bpi->name = r_str_newf ("%s+0x%" PFMT64x, f->name, addr - f->offset);
3347 } else {
3348 bpi->name = strdup (f->name);
3349 }
3350 } else {
3351 bpi->name = r_str_newf ("0x%08" PFMT64x, addr);
3352 }
3353 } else {
3354 bpi->name = strdup (DB_ARG (i));
3355 }
3356 } else {
3357 eprintf ("Cannot set breakpoint at '%s'\n", DB_ARG (i));
3358 }
3359 }
3360 }
3361
3362 free (str);
3363 }
3364
r_core_cmd_bp(RCore * core,const char * input)3365 static void r_core_cmd_bp(RCore *core, const char *input) {
3366 RBreakpointItem *bpi;
3367 int i, hwbp = r_config_get_i (core->config, "dbg.hwbp");
3368 RDebugFrame *frame;
3369 RListIter *iter;
3370 const char *p;
3371 bool watch = false;
3372 RList *list;
3373 ut64 addr, idx;
3374 p = strchr (input, ' ');
3375 addr = p? r_num_math (core->num, p + 1): UT64_MAX;
3376 idx = addr; // 0 is valid index
3377 if (!addr) {
3378 addr = UT64_MAX;
3379 }
3380 char *str = NULL;
3381
3382 switch (input[1]) {
3383 case '.':
3384 if (input[2]) {
3385 ut64 addr = r_num_tail (core->num, core->offset, input + 2);
3386 bpi = r_debug_bp_add (core->dbg, addr, hwbp, false, 0, NULL, 0);
3387 if (!bpi) {
3388 eprintf ("Unable to add breakpoint (%s)\n", input + 2);
3389 }
3390 } else {
3391 bpi = r_bp_get_at (core->dbg->bp, core->offset);
3392 if (bpi) {
3393 r_cons_printf ("breakpoint %s %s %s\n",
3394 r_str_rwx_i (bpi->perm),
3395 bpi->enabled ? "enabled" : "disabled",
3396 r_str_get (bpi->name));
3397 }
3398 }
3399 break;
3400 case 'f':
3401 {
3402 RList *symbols = r_bin_get_symbols (core->bin);
3403 RBinSymbol *symbol;
3404 r_list_foreach (symbols, iter, symbol) {
3405 if (symbol->type && !strcmp (symbol->type, R_BIN_TYPE_FUNC_STR)) {
3406 if (r_anal_noreturn_at (core->anal, symbol->vaddr)) {
3407 bpi = r_debug_bp_add (core->dbg, symbol->vaddr, hwbp, false, 0, NULL, 0);
3408 if (bpi) {
3409 bpi->name = r_str_newf ("%s.%s", "sym", symbol->name);
3410 } else {
3411 eprintf ("Unable to add a breakpoint"
3412 "into a noreturn function %s at addr 0x%"PFMT64x"\n",
3413 symbol->name, symbol->vaddr);
3414 }
3415 }
3416 }
3417 }
3418 }
3419 break;
3420 case 'x': // "dbx"
3421 if (input[2] == ' ') {
3422 if (addr == UT64_MAX) {
3423 addr = core->offset;
3424 }
3425 bpi = r_bp_get_at (core->dbg->bp, addr);
3426 if (bpi) {
3427 free (bpi->expr);
3428 bpi->expr = strdup (input + 3);
3429 }
3430 } else {
3431 RBreakpointItem *bp;
3432 r_list_foreach (core->dbg->bp->bps, iter, bp) {
3433 r_cons_printf ("0x%08"PFMT64x" %s\n", bp->addr, r_str_get (bp->expr));
3434 }
3435 }
3436 break;
3437 case 't': // "dbt"
3438 switch (input[2]) {
3439 case 'v': // "dbtv"
3440 list = r_debug_frames (core->dbg, addr);
3441 backtrace_vars (core, list);
3442 r_list_free (list);
3443 break;
3444 case 'a': // "dbta"
3445 list = r_debug_frames (core->dbg, addr);
3446 asciiart_backtrace (core, list);
3447 r_list_free (list);
3448 break;
3449 case 'e': // "dbte"
3450 for (p = input + 3; *p == ' '; p++) {
3451 /* nothing to do here */
3452 }
3453 if (*p == '*') {
3454 r_bp_set_trace_all (core->dbg->bp,true);
3455 } else if (!r_bp_set_trace (core->dbg->bp, addr, true)) {
3456 eprintf ("Cannot set tracepoint\n");
3457 }
3458 break;
3459 case 'd': // "dbtd"
3460 for (p = input + 3; *p==' ';p++) {
3461 //nothing to see here
3462 }
3463 if (*p == '*') {
3464 r_bp_set_trace_all (core->dbg->bp, false);
3465 } else if (!r_bp_set_trace (core->dbg->bp, addr, false)) {
3466 eprintf ("Cannot unset tracepoint\n");
3467 }
3468 break;
3469 case 's': // "dbts"
3470 bpi = r_bp_get_at (core->dbg->bp, addr);
3471 if (bpi) {
3472 bpi->trace = !!!bpi->trace;
3473 } else {
3474 eprintf ("Cannot unset tracepoint\n");
3475 }
3476 break;
3477 case 'j': { // "dbtj"
3478 PJ *pj = r_core_pj_new (core);
3479 if (!pj) {
3480 return;
3481 }
3482 addr = UT64_MAX;
3483 if (input[2] == ' ' && input[3]) {
3484 addr = r_num_math (core->num, input + 2);
3485 }
3486 i = 0;
3487 list = r_debug_frames (core->dbg, addr);
3488 pj_a (pj);
3489 r_list_foreach (list, iter, frame) {
3490 char *flagdesc, *flagdesc2, *desc;
3491 get_backtrace_info (core, frame, addr, &flagdesc, &flagdesc2, NULL, NULL);
3492 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, frame->addr, 0);
3493 desc = r_str_newf ("%s%s", r_str_get (flagdesc), r_str_get (flagdesc2));
3494 pj_o (pj);
3495 pj_ki (pj, "idx", i);
3496 pj_kn (pj, "pc", frame->addr);
3497 pj_kn (pj, "sp", frame->sp);
3498 pj_ki (pj, "frame_size", frame->size);
3499 pj_ks (pj, "fname", fcn ? fcn->name : "");
3500 pj_ks (pj, "desc", desc);
3501 pj_end (pj);
3502 i++;
3503 free (flagdesc);
3504 free (flagdesc2);
3505 free (desc);
3506 }
3507 pj_end (pj);
3508 r_cons_println (pj_string (pj));
3509 pj_free (pj);
3510 r_list_free (list);
3511 break;
3512 }
3513 case '=': // dbt=
3514 addr = UT64_MAX;
3515 if (input[2] == ' ' && input[3]) {
3516 addr = r_num_math (core->num, input + 2);
3517 }
3518 i = 0;
3519 list = r_debug_frames (core->dbg, addr);
3520 r_list_reverse (list);
3521 r_list_foreach (list, iter, frame) {
3522 switch (input[3]) {
3523 case 0:
3524 r_cons_printf ("%s0x%08"PFMT64x,
3525 (i ? " " : ""), frame->addr);
3526 break;
3527 case 's':
3528 r_cons_printf ("%s0x%08"PFMT64x,
3529 (i ? " " : ""), frame->sp);
3530 break;
3531 case 'b':
3532 r_cons_printf ("%s0x%08"PFMT64x,
3533 (i ? " " : ""), frame->bp);
3534 break;
3535 case '?':
3536 default:
3537 r_core_cmd0 (core, "db?~dbt");
3538 break;
3539 }
3540 i++;
3541 }
3542 r_cons_newline ();
3543 r_list_free (list);
3544 break;
3545 case '*': // dbt*
3546 addr = UT64_MAX;
3547 if (input[2] == ' ' && input[3]) {
3548 addr = r_num_math (core->num, input + 2);
3549 }
3550 i = 0;
3551 list = r_debug_frames (core->dbg, addr);
3552 r_list_reverse (list);
3553 r_cons_printf ("f-bt.*\n");
3554 r_list_foreach (list, iter, frame) {
3555 r_cons_printf ("f bt.frame%d = 0x%08"PFMT64x"\n", i, frame->addr);
3556 r_cons_printf ("f bt.frame%d.stack %d 0x%08"PFMT64x"\n", i, frame->size, frame->sp);
3557 i++;
3558 }
3559 r_list_free (list);
3560 break;
3561 case 0: // "dbt" -- backtrace
3562 addr = UT64_MAX;
3563 if (input[2] == ' ' && input[3]) {
3564 addr = r_num_math (core->num, input + 2);
3565 }
3566 i = 0;
3567 list = r_debug_frames (core->dbg, addr);
3568 r_list_foreach (list, iter, frame) {
3569 char *flagdesc, *flagdesc2, *pcstr, *spstr;
3570 get_backtrace_info (core, frame, addr, &flagdesc, &flagdesc2, &pcstr, &spstr);
3571 RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, frame->addr, 0);
3572 r_cons_printf ("%d %s sp: %s %-5d"
3573 "[%s] %s %s\n", i++,
3574 pcstr, spstr,
3575 (int)frame->size,
3576 fcn ? fcn->name : "??",
3577 r_str_get (flagdesc),
3578 r_str_get (flagdesc2));
3579 free (flagdesc);
3580 free (flagdesc2);
3581 free (pcstr);
3582 free (spstr);
3583 }
3584 r_list_free (list);
3585 break;
3586 case '?':
3587 default:
3588 r_core_cmd_help (core, help_msg_dbt);
3589 break;
3590 }
3591 break;
3592 case 'b': // "dbb"
3593 if (input[2]) {
3594 core->dbg->bp->delta = (st64)r_num_math (core->num, input + 2);
3595 } else {
3596 r_cons_printf ("%"PFMT64d"\n", core->dbg->bp->delta);
3597 }
3598 break;
3599 case 'm': // "dbm"
3600 if (input[2] && input[3]) {
3601 char *string = strdup (input + 3);
3602 char *module = NULL;
3603 st64 delta = 0;
3604
3605 module = strtok (string, " ");
3606 delta = (ut64)r_num_math (core->num, strtok (NULL, ""));
3607 bpi = r_debug_bp_add (core->dbg, 0, hwbp, false, 0, module, delta);
3608 if (!bpi) {
3609 eprintf ("Cannot set breakpoint.\n");
3610 }
3611 free (string);
3612 }
3613 break;
3614 case 'j': r_bp_list (core->dbg->bp, 'j'); break;
3615 case '*': r_bp_list (core->dbg->bp, 1); break;
3616 case '\0': r_bp_list (core->dbg->bp, 0); break;
3617 case '-': // "db-"
3618 if (input[2] == '*') {
3619 r_bp_del_all (core->dbg->bp);
3620 } else {
3621 #define DB_ARG(x) r_str_word_get0(str, x)
3622 char *str = strdup (r_str_trim_head_ro (input +2));
3623 int i = 0;
3624 int sl = r_str_word_set0 (str);
3625 for ( ; i < sl; i++) {
3626 const ut64 addr = r_num_math (core->num, DB_ARG (i));
3627 r_bp_del (core->dbg->bp, addr);
3628 }
3629 free (str);
3630 }
3631 break;
3632 case 'c': // "dbc"
3633 if (input[2] == ' ') {
3634 char *inp = strdup (input + 3);
3635 if (inp) {
3636 char *arg = strchr (inp, ' ');
3637 if (arg) {
3638 *arg++ = 0;
3639 addr = r_num_math (core->num, inp);
3640 bpi = r_bp_get_at (core->dbg->bp, addr);
3641 if (bpi) {
3642 free (bpi->data);
3643 bpi->data = strdup (arg);
3644 } else {
3645 eprintf ("No breakpoint defined at 0x%08"PFMT64x"\n", addr);
3646 }
3647 } else {
3648 eprintf ("- Missing argument\n");
3649 }
3650 free (inp);
3651 } else {
3652 eprintf ("Cannot strdup. Your heap is fucked up\n");
3653 }
3654 } else {
3655 eprintf ("Use: dbc [addr] [command]\n");
3656 }
3657 break;
3658 case 'C': // "dbC"
3659 if (input[2] == ' ') {
3660 char *inp = strdup (input + 3);
3661 if (inp) {
3662 char *arg = strchr (inp, ' ');
3663 if (arg) {
3664 *arg++ = 0;
3665 addr = r_num_math (core->num, inp);
3666 bpi = r_bp_get_at (core->dbg->bp, addr);
3667 if (bpi) {
3668 free (bpi->cond);
3669 bpi->cond = strdup (arg);
3670 } else {
3671 eprintf ("No breakpoint defined at 0x%08"PFMT64x"\n", addr);
3672 }
3673 } else {
3674 eprintf ("1 Missing argument\n");
3675 }
3676 free (inp);
3677 } else {
3678 eprintf ("Cannot strdup. Your heap is fucked up\n");
3679 }
3680 } else {
3681 eprintf ("Use: dbC [addr] [command]\n");
3682 }
3683 break;
3684 case 's': // "dbs"
3685 addr = r_num_math (core->num, input + 2);
3686 bpi = r_bp_get_at (core->dbg->bp, addr);
3687 if (bpi) {
3688 //bp->enabled = !bp->enabled;
3689 // XXX(jjd): this ^^ is what I would think toggling means...
3690 r_bp_del (core->dbg->bp, addr);
3691 } else {
3692 // XXX(jjd): does t his need an address validity check??
3693 bpi = r_debug_bp_add (core->dbg, addr, hwbp, false, 0, NULL, 0);
3694 if (!bpi) {
3695 eprintf ("Cannot set breakpoint (%s)\n", input + 2);
3696 }
3697 }
3698 r_bp_enable (core->dbg->bp, r_num_math (core->num, input + 2), true, 0);
3699 break;
3700 case 'n': // "dbn"
3701 bpi = r_bp_get_at (core->dbg->bp, core->offset);
3702 if (input[2] == ' ') {
3703 if (bpi) {
3704 free (bpi->name);
3705 bpi->name = strdup (input + 3);
3706 } else {
3707 eprintf ("Cannot find breakpoint at "
3708 "0x%08"PFMT64x"\n", core->offset);
3709 }
3710 } else {
3711 if (bpi && bpi->name) {
3712 r_cons_println (bpi->name);
3713 }
3714 }
3715 break;
3716 case 'e': // "dbe"
3717 for (p = input + 2; *p == ' '; p++);
3718 if (*p == '*') r_bp_enable_all (core->dbg->bp,true);
3719 else {
3720 for (; *p && *p != ' '; p++);
3721 r_bp_enable (core->dbg->bp, r_num_math (core->num, input + 2), true, r_num_math (core->num, p));
3722 }
3723 break;
3724 case 'd': // "dbd"
3725 for (p = input + 2; *p == ' '; p++);
3726 if (*p == '*') r_bp_enable_all (core->dbg->bp, false);
3727 else {
3728 for (; *p && *p != ' '; p++);
3729 r_bp_enable (core->dbg->bp, r_num_math (core->num, input + 2), false, r_num_math (core->num, p));
3730 }
3731 break;
3732 case 'h': // "dbh"
3733 switch (input[2]) {
3734 case 0:
3735 r_bp_plugin_list (core->dbg->bp);
3736 break;
3737 case ' ':
3738 if (input[3]) {
3739 if (!r_bp_use (core->dbg->bp, input + 3, core->anal->bits)) {
3740 eprintf ("Invalid name: '%s'.\n", input + 3);
3741 }
3742 }
3743 break;
3744 case '-':
3745 if (input[3]) {
3746 if (!r_bp_plugin_del (core->dbg->bp, input + 3)) {
3747 eprintf ("Invalid name: '%s'.\n", input + 3);
3748 }
3749 }
3750 break;
3751 case '?':
3752 default:
3753 eprintf ("Usage: dh [plugin-name] # select a debug handler plugin\n");
3754 break;
3755 }
3756 break;
3757 #if __WINDOWS__
3758 case 'W': // "dbW"
3759 if (input[2] == ' ') {
3760 if (r_w32_add_winmsg_breakpoint (core->dbg, input + 3)) {
3761 r_cons_print ("Breakpoint set.\n");
3762 } else {
3763 r_cons_print ("Breakpoint not set.\n");
3764 }
3765 }
3766 break;
3767 #endif
3768 case 'w': // "dbw"
3769 add_breakpoint (core, input + 1, hwbp, true);
3770 break;
3771 case 'H': // "dbH"
3772 add_breakpoint (core, input + 1, true, watch);
3773 break;
3774 case ' ': // "db"
3775 add_breakpoint (core, input + 1, hwbp, watch);
3776 break;
3777 case 'i':
3778 core_cmd_dbi (core, input, idx);
3779 break;
3780 case '?':
3781 default:
3782 r_core_cmd_help (core, help_msg_db);
3783 break;
3784 }
3785 free (str);
3786 }
3787
add_trace_tree_child(Sdb * db,RTree * t,RTreeNode * cur,ut64 addr)3788 static RTreeNode *add_trace_tree_child (Sdb *db, RTree *t, RTreeNode *cur, ut64 addr) {
3789 struct trace_node *t_node;
3790 char dbkey[TN_KEY_LEN];
3791
3792 snprintf (dbkey, TN_KEY_LEN, TN_KEY_FMT, addr);
3793 t_node = (struct trace_node *)(size_t)sdb_num_get (db, dbkey, NULL);
3794 if (!t_node) {
3795 t_node = R_NEW0 (struct trace_node);
3796 t_node->addr = addr;
3797 t_node->refs = 1;
3798 sdb_num_set (db, dbkey, (ut64)(size_t)t_node, 0);
3799 } else {
3800 t_node->refs++;
3801 }
3802 return r_tree_add_node (t, cur, t_node);
3803 }
3804
3805 static RCore *_core = NULL;
3806
trace_traverse_pre(RTreeNode * n,RTreeVisitor * vis)3807 static void trace_traverse_pre (RTreeNode *n, RTreeVisitor *vis) {
3808 const char *name = "";
3809 struct trace_node *tn = n->data;
3810 unsigned int i;
3811 if (!tn) return;
3812 for (i = 0; i < n->depth - 1; i++) {
3813 r_cons_printf (" ");
3814 }
3815 if (_core) {
3816 RFlagItem *f = r_flag_get_at (_core->flags, tn->addr, true);
3817 if (f) {
3818 name = f->name;
3819 }
3820 }
3821 r_cons_printf (" 0x%08"PFMT64x" refs %d %s\n", tn->addr, tn->refs, name);
3822 }
3823
trace_traverse(RTree * t)3824 static void trace_traverse (RTree *t) {
3825 RTreeVisitor vis = { 0 };
3826
3827 /* clear the line on stderr, because somebody has written there */
3828 fprintf (stderr, "\x1b[2K\r");
3829 fflush (stderr);
3830 vis.pre_visit = (RTreeNodeVisitCb)trace_traverse_pre;
3831 r_tree_dfs (t, &vis);
3832 }
3833
do_debug_trace_calls(RCore * core,ut64 from,ut64 to,ut64 final_addr)3834 static void do_debug_trace_calls(RCore *core, ut64 from, ut64 to, ut64 final_addr) {
3835 bool trace_libs = r_config_get_i (core->config, "dbg.trace.libs");
3836 bool shallow_trace = r_config_get_i (core->config, "dbg.trace.inrange");
3837 Sdb *tracenodes = core->dbg->tracenodes;
3838 RTree *tr = core->dbg->tree;
3839 RDebug *dbg = core->dbg;
3840 ut64 debug_to = UT64_MAX;
3841 RTreeNode *cur;
3842 ut64 addr = 0;
3843 int n = 0;
3844
3845 if (!trace_libs) {
3846 #if NOOP
3847 RList *bounds = r_core_get_boundaries_prot (core, -1, "dbg.program", "search");
3848 r_list_free (bounds);
3849 #endif
3850 }
3851
3852 /* set root if not already present */
3853 r_tree_add_node (tr, NULL, NULL);
3854 cur = tr->root;
3855
3856 while (true) {
3857 ut8 buf[32];
3858 RAnalOp aop;
3859 int addr_in_range;
3860
3861 if (r_cons_is_breaked()) {
3862 break;
3863 }
3864 if (r_debug_is_dead (dbg)) {
3865 break;
3866 }
3867 if (debug_to != UT64_MAX && !r_debug_continue_until (dbg, debug_to)) {
3868 break;
3869 }
3870 if (!r_debug_step (dbg, 1)) {
3871 break;
3872 }
3873 debug_to = UT64_MAX;
3874 if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)) {
3875 break;
3876 }
3877 addr = r_debug_reg_get (dbg, "PC");
3878 if (addr == final_addr) {
3879 //we finished the tracing so break the loop
3880 break;
3881 }
3882 addr_in_range = addr >= from && addr < to;
3883
3884 r_io_read_at (core->io, addr, buf, sizeof (buf));
3885 r_anal_op (core->anal, &aop, addr, buf, sizeof (buf), R_ANAL_OP_MASK_BASIC);
3886 eprintf ("%d %"PFMT64x"\r", n++, addr);
3887 switch (aop.type) {
3888 case R_ANAL_OP_TYPE_UCALL:
3889 case R_ANAL_OP_TYPE_ICALL:
3890 case R_ANAL_OP_TYPE_RCALL:
3891 case R_ANAL_OP_TYPE_IRCALL:
3892 {
3893 ut64 called_addr;
3894 int called_in_range;
3895 // store regs
3896 // step into
3897 // get pc
3898 r_debug_step (dbg, 1);
3899 r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
3900 called_addr = r_debug_reg_get (dbg, "PC");
3901 called_in_range = called_addr >= from && called_addr < to;
3902 if (!called_in_range && addr_in_range && !shallow_trace) {
3903 debug_to = addr + aop.size;
3904 }
3905 if (addr_in_range || shallow_trace) {
3906 cur = add_trace_tree_child (tracenodes, tr, cur, addr);
3907 if (debug_to != UT64_MAX) {
3908 cur = cur->parent;
3909 }
3910 }
3911 // TODO: push pc+aop.length into the call path stack
3912 break;
3913 }
3914 case R_ANAL_OP_TYPE_CALL:
3915 {
3916 int called_in_range = aop.jump >= from && aop.jump < to;
3917 if (!called_in_range && addr_in_range && !shallow_trace) {
3918 debug_to = aop.addr + aop.size;
3919 }
3920 if (addr_in_range || shallow_trace) {
3921 cur = add_trace_tree_child (tracenodes, tr, cur, addr);
3922 if (debug_to != UT64_MAX) {
3923 cur = cur->parent;
3924 }
3925 }
3926 break;
3927 }
3928 case R_ANAL_OP_TYPE_RET:
3929 #if 0
3930 // TODO: we must store ret value for each call in the graph path to do this check
3931 r_debug_step (dbg, 1);
3932 r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
3933 addr = r_debug_reg_get (dbg, "PC");
3934 // TODO: step into and check return address if correct
3935 // if not correct we are hijacking the control flow (exploit!)
3936 #endif
3937 if (cur != tr->root) {
3938 cur = cur->parent;
3939 }
3940 #if 0
3941 if (addr != gn->addr) {
3942 eprintf ("Oops. invalid return address 0x%08"PFMT64x
3943 "\n0x%08"PFMT64x"\n", addr, gn->addr);
3944 }
3945 #endif
3946 break;
3947 }
3948 }
3949 }
3950
debug_trace_calls(RCore * core,const char * input)3951 static void debug_trace_calls(RCore *core, const char *input) {
3952 RBreakpointItem *bp_final = NULL;
3953 int t = core->dbg->trace->enabled;
3954 ut64 from = 0, to = UT64_MAX, final_addr = UT64_MAX;
3955
3956 if (r_debug_is_dead (core->dbg)) {
3957 eprintf ("No process to debug.");
3958 return;
3959 }
3960 if (*input == ' ') {
3961 input = r_str_trim_head_ro (input);
3962 ut64 first_n = r_num_math (core->num, input);
3963 input = strchr (input, ' ');
3964 if (input) {
3965 input = r_str_trim_head_ro (input);
3966 from = first_n;
3967 to = r_num_math (core->num, input);
3968 input = strchr (input, ' ');
3969 if (input) {
3970 input = r_str_trim_head_ro (input);
3971 final_addr = r_num_math (core->num, input);
3972 }
3973 } else {
3974 final_addr = first_n;
3975 }
3976 }
3977 core->dbg->trace->enabled = 0;
3978 r_cons_break_push (static_debug_stop, core->dbg);
3979 r_reg_arena_swap (core->dbg->reg, true);
3980 if (final_addr != UT64_MAX) {
3981 int hwbp = r_config_get_i (core->config, "dbg.hwbp");
3982 bp_final = r_debug_bp_add (core->dbg, final_addr, hwbp, false, 0, NULL, 0);
3983 if (!bp_final) {
3984 eprintf ("Cannot set breakpoint at final address (%"PFMT64x")\n", final_addr);
3985 }
3986 }
3987 do_debug_trace_calls (core, from, to, final_addr);
3988 if (bp_final) {
3989 r_bp_del (core->dbg->bp, final_addr);
3990 }
3991 _core = core;
3992 trace_traverse (core->dbg->tree);
3993 core->dbg->trace->enabled = t;
3994 r_cons_break_pop ();
3995 }
3996
r_core_debug_esil(RCore * core,const char * input)3997 static void r_core_debug_esil (RCore *core, const char *input) {
3998 switch (input[0]) {
3999 case '\0': // "de"
4000 // list
4001 r_debug_esil_watch_list (core->dbg);
4002 break;
4003 case ' ': // "de "
4004 {
4005 char *line = strdup (input + 1);
4006 char *p, *q;
4007 int done = 0;
4008 int perm = 0, dev = 0;
4009 p = strchr (line, ' ');
4010 if (p) {
4011 *p++ = 0;
4012 if (strchr (line, 'r')) perm |= R_PERM_R;
4013 if (strchr (line, 'w')) perm |= R_PERM_W;
4014 if (strchr (line, 'x')) perm |= R_PERM_X;
4015 q = strchr (p, ' ');
4016 if (q) {
4017 *q++ = 0;
4018 dev = p[0];
4019 r_debug_esil_watch (core->dbg, perm, dev, q);
4020 done = 1;
4021 }
4022 }
4023 if (!done) {
4024 const char *help_de_msg[] = {
4025 "Usage:", "de", " [perm] [reg|mem] [expr]",
4026 NULL
4027 };
4028 r_core_cmd_help (core, help_de_msg);
4029 }
4030 free (line);
4031 }
4032 break;
4033 case '-': // "de-"
4034 r_debug_esil_watch_reset (core->dbg);
4035 break;
4036 case 'c': // "dec"
4037 if (r_debug_esil_watch_empty (core->dbg)) {
4038 eprintf ("Error: no esil watchpoints defined\n");
4039 } else {
4040 r_core_cmd0 (core, "aei");
4041 r_debug_esil_prestep (core->dbg, r_config_get_i (core->config, "esil.prestep"));
4042 r_debug_esil_continue (core->dbg);
4043 }
4044 break;
4045 case 's': // "des"
4046 if (input[1] == 'u' && input[2] == ' ') { // "desu"
4047 ut64 addr, naddr, fin = r_num_math (core->num, input + 2);
4048 r_core_cmd0 (core, "aei");
4049 addr = r_debug_reg_get (core->dbg, "PC");
4050 while (addr != fin) {
4051 r_debug_esil_prestep (core->dbg, r_config_get_i (
4052 core->config, "esil.prestep"));
4053 r_debug_esil_step (core->dbg, 1);
4054 naddr = r_debug_reg_get (core->dbg, "PC");
4055 if (naddr == addr) {
4056 eprintf ("Detected loophole\n");
4057 break;
4058 }
4059 addr = naddr;
4060 }
4061 } else if (input[1] == '?' || !input[1]) {
4062 r_core_cmd_help (core, help_msg_des);
4063 } else {
4064 r_core_cmd0 (core, "aei");
4065 r_debug_esil_prestep (core->dbg, r_config_get_i (core->config, "esil.prestep"));
4066 // continue
4067 r_debug_esil_step (core->dbg, r_num_math (core->num, input + 1));
4068 }
4069 break;
4070 case '?': // "de?"
4071 default:
4072 {
4073 r_core_cmd_help (core, help_msg_de);
4074 // TODO #7967 help refactor: move to detail
4075 r_cons_printf ("Examples:\n"
4076 " de r r rip # stop when reads rip\n"
4077 " de rw m ADDR # stop when read or write in ADDR\n"
4078 " de w r rdx # stop when rdx register is modified\n"
4079 " de x m FROM..TO # stop when rip in range\n");
4080 }
4081 break;
4082 }
4083 }
4084
r_core_debug_kill(RCore * core,const char * input)4085 static void r_core_debug_kill (RCore *core, const char *input) {
4086 if (!input || *input=='?') {
4087 if (input && input[1]) {
4088 const char *signame, *arg = input + 1;
4089 int signum = atoi (arg);
4090 if (signum > 0) {
4091 signame = r_signal_to_string (signum);
4092 if (signame)
4093 r_cons_println (signame);
4094 } else {
4095 signum = r_signal_from_string (arg);
4096 if (signum > 0) {
4097 r_cons_printf ("%d\n", signum);
4098 }
4099 }
4100 } else {
4101 r_core_cmd_help (core, help_msg_dk);
4102 }
4103 } else if (*input=='o') {
4104 switch (input[1]) {
4105 case 0: // "dko" - list signal skip/conts
4106 r_debug_signal_list (core->dbg, 1);
4107 break;
4108 case ' ': // dko SIGNAL
4109 if (input[2]) {
4110 char *p, *name = strdup (input + 2);
4111 int signum = atoi (name);
4112 p = strchr (name, ' ');
4113 if (p) *p++ = 0; /* got SIGNAL and an action */
4114 // Actions:
4115 // - pass
4116 // - trace
4117 // - stop
4118 if (signum<1) signum = r_signal_from_string (name);
4119 if (signum>0) {
4120 if (!p || !p[0]) { // stop (the usual)
4121 r_debug_signal_setup (core->dbg, signum, 0);
4122 } else if (*p == 's') { // skip
4123 r_debug_signal_setup (core->dbg, signum, R_DBG_SIGNAL_SKIP);
4124 } else if (*p == 'c') { // cont
4125 r_debug_signal_setup (core->dbg, signum, R_DBG_SIGNAL_CONT);
4126 } else {
4127 eprintf ("Invalid option: %s\n", p);
4128 }
4129 } else {
4130 eprintf ("Invalid signal: %s\n", input + 2);
4131 }
4132 free (name);
4133 break;
4134 }
4135 /* fall through */
4136 case '?':
4137 default:
4138 {
4139 r_core_cmd_help (core, help_msg_dko);
4140 // TODO #7967 help refactor: move to detail
4141 r_cons_println ("NOTE: [signal] can be a number or a string that resolves with dk?\n"
4142 " skip means do not enter into the signal handler\n"
4143 " continue means enter into the signal handler");
4144 }
4145 }
4146 } else if (*input == 'j') {
4147 core->dbg->pj = r_core_pj_new (core);
4148 r_debug_signal_list (core->dbg, 2);
4149 pj_free (core->dbg->pj);
4150 core->dbg->pj = NULL;
4151 } else if (!*input) {
4152 r_debug_signal_list (core->dbg, 0);
4153 #if 0
4154 RListIter *iter;
4155 RDebugSignal *ds;
4156 eprintf ("TODO: list signal handlers of child\n");
4157 RList *list = r_debug_kill_list (core->dbg);
4158 r_list_foreach (list, iter, ds) {
4159 // TODO: resolve signal name by number and show handler offset
4160 eprintf ("--> %d\n", ds->num);
4161 }
4162 r_list_free (list);
4163 #endif
4164 } else {
4165 int sig = atoi (input);
4166 char *p = strchr (input, '=');
4167 if (p) {
4168 r_debug_kill_setup (core->dbg, sig, r_num_math (core->num, p+1));
4169 } else {
4170 r_debug_kill (core->dbg, core->dbg->pid, core->dbg->tid, sig);
4171 }
4172 }
4173 }
4174
is_x86_call(RDebug * dbg,ut64 addr)4175 static bool is_x86_call(RDebug *dbg, ut64 addr) {
4176 ut8 buf[3];
4177 ut8 *op = buf;
4178 (void)dbg->iob.read_at (dbg->iob.io, addr, buf, R_ARRAY_SIZE (buf));
4179 switch (buf[0]) { /* Segment override prefixes */
4180 case 0x65:
4181 case 0x64:
4182 case 0x26:
4183 case 0x3e:
4184 case 0x36:
4185 case 0x2e:
4186 op++;
4187 }
4188 if (op[0] == 0xe8) {
4189 return true;
4190 }
4191 if (op[0] == 0xff /* bits 4-5 (from right) of next byte must be 01 */
4192 && (op[1] & 0x30) == 0x10) {
4193 return true;
4194 }
4195 /* ... */
4196 return false;
4197 }
4198
is_x86_ret(RDebug * dbg,ut64 addr)4199 static bool is_x86_ret(RDebug *dbg, ut64 addr) {
4200 ut8 buf[1];
4201 (void)dbg->iob.read_at (dbg->iob.io, addr, buf, R_ARRAY_SIZE (buf));
4202 switch (buf[0]) {
4203 case 0xc3:
4204 case 0xcb:
4205 case 0xc2:
4206 case 0xca:
4207 return true;
4208 default:
4209 return false;
4210 }
4211 /* Possibly incomplete with regard to instruction prefixes */
4212 }
4213
cmd_dcu(RCore * core,const char * input)4214 static bool cmd_dcu (RCore *core, const char *input) {
4215 const char *ptr = NULL;
4216 ut64 from, to, pc;
4217 bool dcu_range = false;
4218 bool invalid = (!input[0] || !input[1] || !input[2]);
4219 if (invalid || (input[2] != ' ' && input[2] != '.')) {
4220 r_core_cmd_help (core, help_msg_dcu);
4221 return false;
4222 }
4223 to = UT64_MAX;
4224 if (input[2] == '.') {
4225 ptr = strchr (input + 3, ' ');
4226 if (ptr) { // TODO: put '\0' in *ptr to avoid
4227 from = r_num_tail (core->num, core->offset, input + 2);
4228 if (ptr[1]=='.') {
4229 to = r_num_tail (core->num, core->offset, ptr+2);
4230 } else {
4231 to = r_num_math (core->num, ptr+1);
4232 }
4233 dcu_range = true;
4234 } else {
4235 from = r_num_tail (core->num, core->offset, input + 2);
4236 }
4237 } else {
4238 ptr = strchr (input + 3, ' ');
4239 if (ptr) { // TODO: put '\0' in *ptr to avoid
4240 from = r_num_math (core->num, input + 3);
4241 if (ptr[1]=='.') {
4242 to = r_num_tail (core->num, core->offset, ptr+2);
4243 } else {
4244 to = r_num_math (core->num, ptr+1);
4245 }
4246 dcu_range = true;
4247 } else {
4248 from = r_num_math (core->num, input + 3);
4249 }
4250 }
4251 if (core->num->nc.errors && r_cons_is_interactive ()) {
4252 eprintf ("Cannot continue until unknown address '%s'\n", core->num->nc.calc_buf);
4253 return false;
4254 }
4255 if (to == UT64_MAX) {
4256 to = from;
4257 }
4258 if (dcu_range) {
4259 r_cons_break_push (NULL, NULL);
4260 do {
4261 if (r_cons_is_breaked ()) {
4262 break;
4263 }
4264 r_debug_step (core->dbg, 1);
4265 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4266 pc = r_debug_reg_get (core->dbg, "PC");
4267 eprintf ("Continue 0x%08"PFMT64x" > 0x%08"PFMT64x" < 0x%08"PFMT64x"\n",
4268 from, pc, to);
4269 } while (pc < from || pc > to);
4270 r_cons_break_pop ();
4271 } else {
4272 ut64 addr = from;
4273 if (!strcmp (core->dbg->btalgo, "trace") && core->dbg->arch
4274 && !strcmp (core->dbg->arch, "x86") && core->dbg->bits == 4) {
4275 unsigned long steps = 0;
4276 long level = 0;
4277 const char *pc_name = core->dbg->reg->name[R_REG_NAME_PC];
4278 ut64 prev_pc = UT64_MAX;
4279 bool prev_call = false;
4280 bool prev_ret = false;
4281 const char *sp_name = core->dbg->reg->name[R_REG_NAME_SP];
4282 ut64 old_sp, cur_sp;
4283 r_cons_break_push (NULL, NULL);
4284 r_list_free (core->dbg->call_frames);
4285 core->dbg->call_frames = r_list_new ();
4286 core->dbg->call_frames->free = free;
4287 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4288 old_sp = r_debug_reg_get (core->dbg, sp_name);
4289 while (true) {
4290 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4291 pc = r_debug_reg_get (core->dbg, pc_name);
4292 if (prev_call) {
4293 ut32 ret_addr;
4294 RDebugFrame *frame = R_NEW0 (RDebugFrame);
4295 cur_sp = r_debug_reg_get (core->dbg, sp_name);
4296 (void)core->dbg->iob.read_at (core->dbg->iob.io, cur_sp, (ut8 *)&ret_addr,
4297 sizeof (ret_addr));
4298 frame->addr = ret_addr;
4299 frame->size = old_sp - cur_sp;
4300 frame->sp = cur_sp;
4301 frame->bp = old_sp;
4302 r_list_prepend (core->dbg->call_frames, frame);
4303 eprintf ("%ld Call from 0x%08"PFMT64x" to 0x%08"PFMT64x" ret 0x%08"PFMT32x"\n",
4304 level, prev_pc, pc, ret_addr);
4305 level++;
4306 old_sp = cur_sp;
4307 prev_call = false;
4308 } else if (prev_ret) {
4309 RDebugFrame *head = r_list_get_bottom (core->dbg->call_frames);
4310 if (head && head->addr != pc) {
4311 eprintf ("*");
4312 } else {
4313 r_list_pop_head (core->dbg->call_frames);
4314 eprintf ("%ld", level);
4315 level--;
4316 }
4317 eprintf (" Ret from 0x%08"PFMT64x" to 0x%08"PFMT64x"\n",
4318 prev_pc, pc);
4319 prev_ret = false;
4320 }
4321 if (steps % 500 == 0 || pc == addr) {
4322 eprintf ("At 0x%08"PFMT64x" after %lu steps\n", pc, steps);
4323 }
4324 if (r_cons_is_breaked () || r_debug_is_dead (core->dbg) || pc == addr) {
4325 break;
4326 }
4327 if (is_x86_call (core->dbg, pc)) {
4328 prev_pc = pc;
4329 prev_call = true;
4330 } else if (is_x86_ret (core->dbg, pc)) {
4331 prev_pc = pc;
4332 prev_ret = true;
4333 }
4334 r_debug_step (core->dbg, 1);
4335 steps++;
4336 }
4337 r_cons_break_pop ();
4338 return true;
4339 }
4340 eprintf ("Continue until 0x%08"PFMT64x" using %d bpsize\n", addr, core->dbg->bpsize);
4341 r_reg_arena_swap (core->dbg->reg, true);
4342 if (r_bp_add_sw (core->dbg->bp, addr, core->dbg->bpsize, R_BP_PROT_EXEC)) {
4343 if (r_debug_is_dead (core->dbg)) {
4344 eprintf ("Cannot continue, run ood?\n");
4345 } else {
4346 r_debug_continue (core->dbg);
4347 }
4348 r_bp_del (core->dbg->bp, addr);
4349 } else {
4350 eprintf ("Cannot set breakpoint of size %d at 0x%08"PFMT64x"\n",
4351 core->dbg->bpsize, addr);
4352 }
4353 }
4354 return true;
4355 }
4356
cmd_debug_continue(RCore * core,const char * input)4357 static int cmd_debug_continue (RCore *core, const char *input) {
4358 int pid, old_pid, signum;
4359 char *ptr;
4360 // TODO: we must use this for step 'ds' too maybe...
4361 switch (input[1]) {
4362 case 0: // "dc"
4363 r_reg_arena_swap (core->dbg->reg, true);
4364 #if __linux__
4365 core->dbg->continue_all_threads = true;
4366 #endif
4367 if (r_debug_is_dead (core->dbg)) {
4368 eprintf ("Cannot continue, run ood?\n");
4369 break;
4370 }
4371 r_debug_continue (core->dbg);
4372 break;
4373 case 'a': // "dca"
4374 eprintf ("TODO: dca\n");
4375 break;
4376 case 'b': // "dcb"
4377 {
4378 if (!core->dbg->session) {
4379 eprintf ("Error: Session has not started\n");
4380 break;
4381 }
4382 if (!r_debug_continue_back (core->dbg)) {
4383 eprintf ("cannot continue back\n");
4384 }
4385 break;
4386 }
4387 #if __WINDOWS__
4388 case 'e': // "dce"
4389 r_reg_arena_swap (core->dbg->reg, true);
4390 r_debug_continue_pass_exception (core->dbg);
4391 break;
4392 #endif
4393 case 'f': // "dcf"
4394 eprintf ("[+] Running 'dcs vfork fork clone' behind the scenes...\n");
4395 // we should stop in fork and vfork syscalls
4396 //TODO: multiple syscalls not handled yet
4397 // r_core_cmd0 (core, "dcs vfork fork");
4398 r_core_cmd0 (core, "dcs vfork fork clone");
4399 break;
4400 case 'c': // "dcc"
4401 r_reg_arena_swap (core->dbg->reg, true);
4402 if (input[2] == 'u') {
4403 r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_UCALL, 0);
4404 } else {
4405 r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_CALL, 0);
4406 }
4407 break;
4408 case 'r':
4409 r_reg_arena_swap (core->dbg->reg, true);
4410 r_debug_continue_until_optype (core->dbg, R_ANAL_OP_TYPE_RET, 1);
4411 break;
4412 case 'k':
4413 // select pid and r_debug_continue_kill (core->dbg,
4414 r_reg_arena_swap (core->dbg->reg, true);
4415 signum = r_num_math (core->num, input + 2);
4416 ptr = strchr (input + 3, ' ');
4417 if (ptr) {
4418 int old_pid = core->dbg->pid;
4419 int old_tid = core->dbg->tid;
4420 int pid = atoi (ptr+1);
4421 int tid = pid; // XXX
4422 *ptr = 0;
4423 r_debug_select (core->dbg, pid, tid);
4424 r_debug_continue_kill (core->dbg, signum);
4425 r_debug_select (core->dbg, old_pid, old_tid);
4426 } else {
4427 r_debug_continue_kill (core->dbg, signum);
4428 }
4429 break;
4430 case 's': // "dcs"
4431 switch (input[2]) {
4432 case '*':
4433 cmd_debug_cont_syscall (core, "-1");
4434 break;
4435 case ' ':
4436 cmd_debug_cont_syscall (core, input + 3);
4437 break;
4438 case '\0':
4439 cmd_debug_cont_syscall (core, NULL);
4440 break;
4441 default:
4442 case '?':
4443 r_core_cmd_help (core, help_msg_dcs);
4444 break;
4445 }
4446 break;
4447 case 'p': // "dcp"
4448 { // XXX: this is very slow
4449 RIOMap *s;
4450 ut64 pc;
4451 int n = 0;
4452 bool t = core->dbg->trace->enabled;
4453 core->dbg->trace->enabled = false;
4454 r_cons_break_push (static_debug_stop, core->dbg);
4455 do {
4456 r_debug_step (core->dbg, 1);
4457 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4458 pc = r_debug_reg_get (core->dbg, "PC");
4459 eprintf (" %d %"PFMT64x"\r", n++, pc);
4460 s = r_io_map_get (core->io, pc);
4461 if (r_cons_is_breaked ()) {
4462 break;
4463 }
4464 } while (!s);
4465 eprintf ("\n");
4466 core->dbg->trace->enabled = t;
4467 r_cons_break_pop ();
4468 return 1;
4469 }
4470 case 'u': // "dcu"
4471 if (input[2] == '?') {
4472 r_core_cmd_help (core, help_msg_dcu);
4473 } else if (input[2] == '.') {
4474 cmd_dcu (core, "cu $$");
4475 } else {
4476 cmd_dcu (core, input);
4477 }
4478 break;
4479 case ' ':
4480 old_pid = core->dbg->pid;
4481 pid = atoi (input + 2);
4482 r_reg_arena_swap (core->dbg->reg, true);
4483 r_debug_select (core->dbg, pid, core->dbg->tid);
4484 r_debug_continue (core->dbg);
4485 r_debug_select (core->dbg, old_pid, core->dbg->tid);
4486 break;
4487 case 't':
4488 cmd_debug_backtrace (core, input + 2);
4489 break;
4490 case '?': // "dc?"
4491 default:
4492 r_core_cmd_help (core, help_msg_dc);
4493 return 0;
4494 }
4495 return 1;
4496 }
4497
get_corefile_name(const char * raw_name,int pid)4498 static char *get_corefile_name (const char *raw_name, int pid) {
4499 return (!*raw_name)?
4500 r_str_newf ("core.%u", pid) :
4501 r_str_trim_dup (raw_name);
4502 }
4503
cmd_debug_step(RCore * core,const char * input)4504 static int cmd_debug_step (RCore *core, const char *input) {
4505 ut64 addr = core->offset;;
4506 ut8 buf[64];
4507 RAnalOp aop;
4508 int i, times = 1;
4509 char *ptr = strchr (input, ' ');
4510 if (ptr) {
4511 times = r_num_math (core->num, ptr + 1);
4512 }
4513 if (times < 1) {
4514 times = 1;
4515 }
4516 switch (input[1]) {
4517 case 0: // "ds"
4518 case ' ':
4519 if (r_config_get_i (core->config, "cfg.debug")) {
4520 r_reg_arena_swap (core->dbg->reg, true);
4521 // sync registers for BSD PT_STEP/PT_CONT
4522 // XXX(jjd): is this necessary?
4523 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4524 ut64 pc = r_debug_reg_get (core->dbg, "PC");
4525 r_debug_trace_pc (core->dbg, pc);
4526 if (!r_debug_step (core->dbg, times)) {
4527 eprintf ("Step failed\n");
4528 core->break_loop = true;
4529 }
4530 } else {
4531 r_core_cmdf (core, "%daes", R_MAX (1, times));
4532 }
4533 break;
4534 case 'i': // "dsi"
4535 if (input[2] == ' ') {
4536 int n = 0;
4537 r_cons_break_push (static_debug_stop, core->dbg);
4538 do {
4539 if (r_cons_is_breaked ()) {
4540 break;
4541 }
4542 r_debug_step (core->dbg, 1);
4543 if (r_debug_is_dead (core->dbg)) {
4544 core->break_loop = true;
4545 break;
4546 }
4547 r_core_cmd0 (core, ".dr*");
4548 n++;
4549 } while (!r_num_conditional (core->num, input + 3));
4550 r_cons_break_pop ();
4551 eprintf ("Stopped after %d instructions\n", n);
4552 } else {
4553 eprintf ("3 Missing argument\n");
4554 }
4555 break;
4556 case 'f': // "dsf"
4557 step_until_eof (core);
4558 break;
4559 case 'u': // "dsu"
4560 switch (input[2]) {
4561 case 'f': // dsuf
4562 step_until_flag (core, input + 3);
4563 break;
4564 case 'i': // dsui
4565 if (input[3] == 'r') {
4566 step_until_inst (core, input + 4, true);
4567 }
4568 else {
4569 step_until_inst (core, input + 3, false);
4570 }
4571 break;
4572 case 'e': // dsue
4573 step_until_esil (core, input + 3);
4574 break;
4575 case 'o': // dsuo
4576 step_until_optype (core, input + 3);
4577 break;
4578 case ' ': // dsu <address>
4579 r_reg_arena_swap (core->dbg->reg, true);
4580 step_until (core, r_num_math (core->num, input + 2)); // XXX dupped by times
4581 break;
4582 default:
4583 r_core_cmd_help (core, help_msg_dsu);
4584 return 0;
4585 }
4586 break;
4587 case 'p': // "dsp"
4588 r_reg_arena_swap (core->dbg->reg, true);
4589 for (i = 0; i < times; i++) {
4590 ut8 buf[64];
4591 ut64 addr;
4592 RAnalOp aop;
4593 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4594 addr = r_debug_reg_get (core->dbg, "PC");
4595 r_io_read_at (core->io, addr, buf, sizeof (buf));
4596 r_anal_op (core->anal, &aop, addr, buf, sizeof (buf), R_ANAL_OP_MASK_BASIC);
4597 if (aop.type == R_ANAL_OP_TYPE_CALL) {
4598 RBinObject *o = r_bin_cur_object (core->bin);
4599 RBinSection *s = r_bin_get_section_at (o, aop.jump, true);
4600 if (!s) {
4601 r_debug_step_over (core->dbg, times);
4602 continue;
4603 }
4604 }
4605 r_debug_step (core->dbg, 1);
4606 }
4607 break;
4608 case 's': // "dss"
4609 {
4610 char delb[128] = R_EMPTY;
4611 addr = r_debug_reg_get (core->dbg, "PC");
4612 RBreakpointItem *bpi = r_bp_get_at (core->dbg->bp, addr);
4613 sprintf(delb, "db 0x%"PFMT64x"", addr);
4614 r_reg_arena_swap (core->dbg->reg, true);
4615 for (i = 0; i < times; i++) {
4616 r_debug_reg_sync (core->dbg, R_REG_TYPE_GPR, false);
4617 r_io_read_at (core->io, addr, buf, sizeof (buf));
4618 r_anal_op (core->anal, &aop, addr, buf, sizeof (buf), R_ANAL_OP_MASK_BASIC);
4619 #if 0
4620 if (aop.jump != UT64_MAX && aop.fail != UT64_MAX) {
4621 eprintf ("Don't know how to skip this instruction\n");
4622 if (bpi) r_core_cmd0 (core, delb);
4623 break;
4624 }
4625 #endif
4626 addr += aop.size;
4627 }
4628 r_debug_reg_set (core->dbg, "PC", addr);
4629 r_reg_setv (core->anal->reg, "PC", addr);
4630 r_core_cmd0 (core, ".dr*");
4631 if (bpi) {
4632 r_core_cmd0 (core, delb);
4633 }
4634 break;
4635 }
4636 case 'o': // "dso"
4637 if (r_config_get_i (core->config, "dbg.skipover")) {
4638 r_core_cmdf (core, "dss%s", input + 2);
4639 } else {
4640 if (r_config_get_i (core->config, "cfg.debug")) {
4641 char delb[128] = R_EMPTY;
4642 addr = r_debug_reg_get (core->dbg, "PC");
4643 RBreakpointItem *bpi = r_bp_get_at (core->dbg->bp, addr);
4644 sprintf(delb, "db 0x%"PFMT64x"", addr);
4645 r_bp_del (core->dbg->bp, addr);
4646 r_reg_arena_swap (core->dbg->reg, true);
4647 r_debug_step_over (core->dbg, times);
4648 if (bpi) r_core_cmd0 (core, delb);
4649 } else {
4650 r_core_cmdf (core, "aeso%s", input + 2);
4651 }
4652 }
4653 break;
4654 case 'b': // "dsb"
4655 if (r_config_get_i (core->config, "cfg.debug")) {
4656 if (!core->dbg->session) {
4657 eprintf ("Session has not started\n");
4658 } else if (r_debug_step_back (core->dbg, times) < 0) {
4659 eprintf ("Error: stepping back failed\n");
4660 }
4661 } else {
4662 if (r_core_esil_step_back (core)) {
4663 r_core_cmd0 (core, ".dr*");
4664 } else {
4665 eprintf ("cannot step back\n");
4666 }
4667 }
4668 break;
4669 case 'l': // "dsl"
4670 r_reg_arena_swap (core->dbg->reg, true);
4671 step_line (core, times);
4672 break;
4673 case '?': // "ds?"
4674 default:
4675 r_core_cmd_help (core, help_msg_ds);
4676 return 0;
4677 }
4678 return 1;
4679 }
4680
getFileData(RCore * core,const char * arg)4681 static ut8*getFileData(RCore *core, const char *arg) {
4682 if (*arg == '$') {
4683 return (ut8*) r_cmd_alias_get (core->rcmd, arg, 1);
4684 }
4685 return (ut8*)r_file_slurp (arg, NULL);
4686 }
4687
consumeBuffer(RBuffer * buf,const char * cmd,const char * errmsg)4688 static void consumeBuffer(RBuffer *buf, const char *cmd, const char *errmsg) {
4689 if (!buf) {
4690 if (errmsg) {
4691 r_cons_printf ("%s\n", errmsg);
4692 }
4693 return;
4694 }
4695 if (cmd) {
4696 r_cons_printf ("%s", cmd);
4697 }
4698 int i;
4699 r_buf_seek (buf, 0, R_BUF_SET);
4700 for (i = 0; i < r_buf_size (buf); i++) {
4701 r_cons_printf ("%02x", r_buf_read8 (buf));
4702 }
4703 r_cons_printf ("\n");
4704 }
4705
cmd_debug(void * data,const char * input)4706 static int cmd_debug(void *data, const char *input) {
4707 RCore *core = (RCore *)data;
4708 RDebugTracepoint *t;
4709 int follow = 0;
4710 const char *ptr;
4711 ut64 addr;
4712 int min;
4713 RListIter *iter;
4714 RList *list;
4715 RDebugPid *p;
4716 RDebugTracepoint *trace;
4717 RAnalOp *op;
4718
4719 if (r_sandbox_enable (0)) {
4720 eprintf ("Debugger commands disabled in sandbox mode\n");
4721 return 0;
4722 }
4723 if (!strncmp (input, "ate", 3)) {
4724 char str[128];
4725 str[0] = 0;
4726 r_print_date_get_now (core->print, str);
4727 r_cons_println (str);
4728 return 0;
4729 }
4730
4731 switch (input[0]) {
4732 case 't':
4733 // TODO: define ranges? to display only some traces, allow to scroll on this disasm? ~.. ?
4734 switch (input[1]) {
4735 case '\0': // "dt"
4736 r_debug_trace_list (core->dbg, 0, core->offset);
4737 break;
4738 case '=': // "dt="
4739 r_debug_trace_list (core->dbg, '=', core->offset);
4740 break;
4741 case 'q': // "dtq"
4742 r_debug_trace_list (core->dbg, 'q', core->offset);
4743 break;
4744 case '*': // "dt*"
4745 r_debug_trace_list (core->dbg, 1, core->offset);
4746 break;
4747 case ' ': // "dt [addr]"
4748 if ((t = r_debug_trace_get (core->dbg,
4749 r_num_math (core->num, input + 3)))) {
4750 r_cons_printf ("offset = 0x%" PFMT64x "\n", t->addr);
4751 r_cons_printf ("opsize = %d\n", t->size);
4752 r_cons_printf ("times = %d\n", t->times);
4753 r_cons_printf ("count = %d\n", t->count);
4754 //TODO cons_printf("time = %d\n", t->tm);
4755 }
4756 break;
4757 case 'a': // "dta"
4758 r_debug_trace_at (core->dbg, input + 3);
4759 break;
4760 case 't': // "dtt"
4761 r_debug_trace_tag (core->dbg, atoi (input + 3));
4762 break;
4763 case 'c': // "dtc"
4764 if (input[2] == '?') {
4765 r_cons_println ("Usage: dtc [addr] ([from] [to] [addr]) - trace calls in debugger");
4766 } else {
4767 debug_trace_calls (core, input + 2);
4768 }
4769 break;
4770 case 'd': // "dtd"
4771 min = r_num_math (core->num, input + 3);
4772 if (input[2] == 'q') { // "dtdq"
4773 int n = 0;
4774 r_list_foreach (core->dbg->trace->traces, iter, trace) {
4775 if (n >= min) {
4776 r_cons_printf ("%d ", trace->count);
4777 r_cons_printf ("0x%08"PFMT64x"\n", trace->addr);
4778 break;
4779 }
4780 n++;
4781 }
4782 } else if (input[2] == 'i') {
4783 int n = 0;
4784 r_list_foreach (core->dbg->trace->traces, iter, trace) {
4785 op = r_core_anal_op (core, trace->addr, R_ANAL_OP_MASK_BASIC | R_ANAL_OP_MASK_DISASM);
4786 if (n >= min) {
4787 r_cons_printf ("%d %s\n", trace->count, op->mnemonic);
4788 }
4789 n++;
4790 r_anal_op_free (op);
4791 }
4792 } else if (input[2] == ' ') {
4793 int n = 0;
4794 r_list_foreach (core->dbg->trace->traces, iter, trace) {
4795 op = r_core_anal_op (core, trace->addr, R_ANAL_OP_MASK_BASIC | R_ANAL_OP_MASK_DISASM);
4796 if (n >= min) {
4797 r_cons_printf ("0x%08"PFMT64x" %s\n", trace->addr, op->mnemonic);
4798 }
4799 n++;
4800 r_anal_op_free (op);
4801 }
4802 } else {
4803 // TODO: reimplement using the api
4804 //r_core_cmd0 (core, "pd 1 @@= `dtq`");
4805 r_list_foreach (core->dbg->trace->traces, iter, trace) {
4806 op = r_core_anal_op (core, trace->addr, R_ANAL_OP_MASK_BASIC | R_ANAL_OP_MASK_DISASM);
4807 r_cons_printf ("0x%08"PFMT64x" %s\n", trace->addr, op->mnemonic);
4808 r_anal_op_free (op);
4809 }
4810 }
4811 break;
4812 case 'g': // "dtg"
4813 dot_trace_traverse (core, core->dbg->tree, input[2]);
4814 break;
4815 case '-': // "dt-"
4816 r_tree_reset (core->dbg->tree);
4817 r_debug_trace_free (core->dbg->trace);
4818 r_debug_tracenodes_reset (core->dbg);
4819 core->dbg->trace = r_debug_trace_new ();
4820 break;
4821 case '+': // "dt+"
4822 if (input[2] == '+') { // "dt++"
4823 char *a, *s = r_str_trim_dup (input + 3);
4824 RList *args = r_str_split_list (s, " ", 0);
4825 RListIter *iter;
4826 r_list_foreach (args, iter, a) {
4827 ut64 addr = r_num_get (NULL, a);
4828 (void)r_debug_trace_add (core->dbg, addr, 1);
4829 }
4830 r_list_free (args);
4831 free (s);
4832 } else {
4833 ptr = input + 2;
4834 addr = r_num_math (core->num, ptr);
4835 ptr = strchr (ptr, ' ');
4836 int count = 1;
4837 if (ptr) {
4838 count = r_num_math (core->num, ptr + 1);
4839 }
4840 RAnalOp *op = r_core_op_anal (core, addr, R_ANAL_OP_MASK_HINT);
4841 if (op) {
4842 RDebugTracepoint *tp = r_debug_trace_add (core->dbg, addr, op->size);
4843 if (!tp) {
4844 r_anal_op_free (op);
4845 break;
4846 }
4847 tp->count = count;
4848 r_anal_trace_bb (core->anal, addr);
4849 r_anal_op_free (op);
4850 } else {
4851 eprintf ("Cannot analyze opcode at 0x%08" PFMT64x "\n", addr);
4852 }
4853 }
4854 break;
4855 case 'e': // "dte"
4856 if (!core->anal->esil) {
4857 int stacksize = r_config_get_i (core->config, "esil.stack.depth");
4858 int romem = r_config_get_i (core->config, "esil.romem");
4859 int stats = r_config_get_i (core->config, "esil.stats");
4860 int iotrap = r_config_get_i (core->config, "esil.iotrap");
4861 int nonull = r_config_get_i (core->config, "esil.nonull");
4862 unsigned int addrsize = r_config_get_i (core->config, "esil.addr.size");
4863 if (!(core->anal->esil = r_anal_esil_new (stacksize, iotrap, addrsize))) {
4864 return 0;
4865 }
4866 r_anal_esil_setup (core->anal->esil, core->anal, romem, stats, nonull);
4867 }
4868 switch (input[2]) {
4869 case 0: // "dte"
4870 r_anal_esil_trace_list (core->anal->esil);
4871 break;
4872 case 'i': { // "dtei"
4873 ut64 addr = r_num_math (core->num, input + 3);
4874 if (!addr) {
4875 addr = core->offset;
4876 }
4877 RAnalOp *op = r_core_anal_op (core, addr, R_ANAL_OP_MASK_ESIL);
4878 if (op) {
4879 r_anal_esil_trace_op (core->anal->esil, op);
4880 }
4881 r_anal_op_free (op);
4882 } break;
4883 case '-': // "dte-"
4884 if (!strcmp (input + 3, "*")) {
4885 if (core->anal->esil) {
4886 sdb_free (core->anal->esil->trace->db);
4887 core->anal->esil->trace->db = sdb_new0 ();
4888 }
4889 } else {
4890 eprintf ("TODO: dte- cannot delete specific logs. Use dte-*\n");
4891 }
4892 break;
4893 case ' ': { // "dte "
4894 int idx = atoi (input + 3);
4895 r_anal_esil_trace_show (
4896 core->anal->esil, idx);
4897 } break;
4898 case 'k': // "dtek"
4899 if (input[3] == ' ') {
4900 char *s = sdb_querys (core->anal->esil->trace->db,
4901 NULL, 0, input + 4);
4902 r_cons_println (s);
4903 free (s);
4904 } else {
4905 eprintf ("Usage: dtek [query]\n");
4906 }
4907 break;
4908 default:
4909 r_core_cmd_help (core, help_msg_dte);
4910 }
4911 break;
4912 case 's': // "dts"
4913 switch (input[2]) {
4914 case '+': // "dts+"
4915 if (r_debug_is_dead (core->dbg)) {
4916 eprintf ("Cannot start session outside of debug mode, run ood?\n");
4917 break;
4918 }
4919 if (core->dbg->session) {
4920 eprintf ("Session already started\n");
4921 break;
4922 }
4923 core->dbg->session = r_debug_session_new ();
4924 r_debug_add_checkpoint (core->dbg);
4925 break;
4926 case '-': // "dts-"
4927 if (!core->dbg->session) {
4928 eprintf ("No session started\n");
4929 break;
4930 }
4931 r_debug_session_free (core->dbg->session);
4932 core->dbg->session = NULL;
4933 break;
4934 case 't': // "dtst"
4935 if (!core->dbg->session) {
4936 eprintf ("No session started\n");
4937 break;
4938 }
4939 r_debug_session_save (core->dbg->session, input + 4);
4940 break;
4941 case 'f': // "dtsf"
4942 if (core->dbg->session) {
4943 r_debug_session_free (core->dbg->session);
4944 core->dbg->session = NULL;
4945 }
4946 core->dbg->session = r_debug_session_new ();
4947 r_debug_session_load (core->dbg, input + 4);
4948 break;
4949 case 'm': // "dtsm"
4950 if (core->dbg->session) {
4951 r_debug_session_list_memory (core->dbg);
4952 }
4953 break;
4954 default:
4955 r_core_cmd_help (core, help_msg_dts);
4956 }
4957 break;
4958 case '?':
4959 default:
4960 {
4961 r_core_cmd_help (core, help_msg_dt);
4962 r_cons_printf ("Current Tag: %d\n", core->dbg->trace->tag);
4963 }
4964 break;
4965 }
4966 break;
4967 case 'd': // "ddd"
4968 switch (input[1]) {
4969 case '\0': // "ddd"
4970 r_debug_desc_list (core->dbg, 0);
4971 break;
4972 case '*': // "dtd*"
4973 r_debug_desc_list (core->dbg, 1);
4974 break;
4975 case 's': // "dtds"
4976 {
4977 ut64 off = UT64_MAX;
4978 int fd = atoi (input + 2);
4979 char *str = strchr (input + 2, ' ');
4980 if (str) off = r_num_math (core->num, str+1);
4981 if (off == UT64_MAX || !r_debug_desc_seek (core->dbg, fd, off)) {
4982 RBuffer *buf = r_core_syscallf (core, "lseek", "%d, 0x%"PFMT64x", %d", fd, off, 0);
4983 consumeBuffer (buf, "dx ", "Cannot seek");
4984 }
4985 }
4986 break;
4987 case 't': // "ddt" <ttypath>
4988 r_core_cmdf (core, "dd-0");
4989 break;
4990 case 'd': // "ddd"
4991 {
4992 ut64 newfd = UT64_MAX;
4993 int fd = atoi (input + 2);
4994 char *str = strchr (input + 3, ' ');
4995 if (str) newfd = r_num_math (core->num, str+1);
4996 if (newfd == UT64_MAX || !r_debug_desc_dup (core->dbg, fd, newfd)) {
4997 RBuffer *buf = r_core_syscallf (core, "dup2", "%d, %d", fd, (int)newfd);
4998 if (buf) {
4999 consumeBuffer (buf, "dx ", NULL);
5000 } else {
5001 eprintf ("Cannot dup %d %d\n", fd, (int)newfd);
5002 }
5003 }
5004 }
5005 break;
5006 case 'r':
5007 {
5008 ut64 off = UT64_MAX;
5009 ut64 len = UT64_MAX;
5010 int fd = atoi (input + 2);
5011 char *str = strchr (input + 2, ' ');
5012 if (str) off = r_num_math (core->num, str+1);
5013 if (str) str = strchr (str+1, ' ');
5014 if (str) len = r_num_math (core->num, str+1);
5015 if (len == UT64_MAX || off == UT64_MAX || \
5016 !r_debug_desc_read (core->dbg, fd, off, len)) {
5017 consumeBuffer (r_core_syscallf (core, "read", "%d, 0x%"PFMT64x", %d",
5018 fd, off, (int)len), "dx ", "Cannot read");
5019 }
5020 }
5021 break;
5022 case 'w':
5023 {
5024 ut64 off = UT64_MAX;
5025 ut64 len = UT64_MAX;
5026 int fd = atoi (input + 2);
5027 char *str = strchr (input + 2, ' ');
5028 if (str) off = r_num_math (core->num, str+1);
5029 if (str) str = strchr (str+1, ' ');
5030 if (str) len = r_num_math (core->num, str+1);
5031 if (len == UT64_MAX || off == UT64_MAX || \
5032 !r_debug_desc_write (core->dbg, fd, off, len)) {
5033 RBuffer *buf = r_core_syscallf (core, "write", "%d, 0x%"PFMT64x", %d", fd, off, (int)len);
5034 consumeBuffer (buf, "dx ", "Cannot write");
5035 }
5036 }
5037 break;
5038 case '-': // "dd-"
5039 // close file
5040 //r_core_syscallf (core, "close", "%d", atoi (input + 2));
5041 {
5042 int fd = atoi (input + 2);
5043 //r_core_cmdf (core, "dxs close %d", (int)r_num_math ( core->num, input + 2));
5044 RBuffer *buf = r_core_syscallf (core, "close", "%d", fd);
5045 consumeBuffer (buf, "dx ", "Cannot close");
5046 }
5047 break;
5048 case ' ': // "dd"
5049 // TODO: handle read, readwrite, append
5050 {
5051 RBuffer *buf = r_core_syscallf (core, "open", "%s, %d, %d", input + 2, 2, 0644);
5052 consumeBuffer (buf, "dx ", "Cannot open");
5053 }
5054 // open file
5055 break;
5056 case '?':
5057 default:
5058 r_core_cmd_help (core, help_msg_dd);
5059 break;
5060 }
5061 break;
5062 case 's':
5063 if (cmd_debug_step (core, input)) {
5064 follow = r_config_get_i (core->config, "dbg.follow");
5065 }
5066 break;
5067 case 'b':
5068 r_core_cmd_bp (core, input);
5069 break;
5070 case 'H':
5071 eprintf ("TODO: transplant process\n");
5072 break;
5073 case 'c': // "dc"
5074 r_cons_break_push (static_debug_stop, core->dbg);
5075 (void)cmd_debug_continue (core, input);
5076 follow = r_config_get_i (core->config, "dbg.follow");
5077 r_cons_break_pop ();
5078 break;
5079 case 'm': // "dm"
5080 cmd_debug_map (core, input + 1);
5081 break;
5082 case 'r': // "dr"
5083 if (r_config_get_i (core->config, "cfg.debug") || input[1] == '?') {
5084 cmd_debug_reg (core, input + 1);
5085 } else {
5086 cmd_anal_reg (core, input + 1);
5087 }
5088 //r_core_cmd (core, "|reg", 0);
5089 break;
5090 case 'p': // "dp"
5091 cmd_debug_pid (core, input);
5092 break;
5093 case 'L': // "dL"
5094 switch (input[1]) {
5095 case 'q':
5096 r_debug_plugin_list (core->dbg, input[1]);
5097 break;
5098 case 'j':
5099 core->dbg->pj = r_core_pj_new (core);
5100 r_debug_plugin_list (core->dbg, 'j');
5101 pj_free (core->dbg->pj);
5102 core->dbg->pj = NULL;
5103 break;
5104 case '?':
5105 r_core_cmd_help (core, help_msg_dL);
5106 break;
5107 case ' ': {
5108 char *str = r_str_trim_dup (input + 2);
5109 r_config_set (core->config, "dbg.backend", str);
5110 // implicit by config.set r_debug_use (core->dbg, str);
5111 free (str);
5112 }
5113 break;
5114 default:
5115 r_debug_plugin_list (core->dbg, 0);
5116 break;
5117 }
5118 break;
5119 case 'i': // "di"
5120 {
5121 RDebugInfo *rdi = r_debug_info (core->dbg, input + 2);
5122 RDebugReasonType stop = r_debug_stop_reason (core->dbg);
5123 char *escaped_str;
5124 switch (input[1]) {
5125 case '\0': // "di"
5126 #define P r_cons_printf
5127 #define PS(X, Y) {escaped_str = r_str_escape (Y);r_cons_printf(X, escaped_str);free(escaped_str);}
5128 if (rdi) {
5129 const char *s = r_signal_to_string (core->dbg->reason.signum);
5130 P ("type=%s\n", r_debug_reason_to_string (core->dbg->reason.type));
5131 P ("signal=%s\n", r_str_get_fail (s, "none"));
5132 P ("signum=%d\n", core->dbg->reason.signum);
5133 P ("sigpid=%d\n", core->dbg->reason.tid);
5134 P ("addr=0x%"PFMT64x"\n", core->dbg->reason.addr);
5135 P ("bp_addr=0x%"PFMT64x"\n", core->dbg->reason.bp_addr);
5136 P ("inbp=%s\n", r_str_bool (core->dbg->reason.bp_addr));
5137 P ("baddr=0x%"PFMT64x"\n", r_debug_get_baddr (core->dbg, NULL));
5138 P ("pid=%d\n", rdi->pid);
5139 P ("tid=%d\n", rdi->tid);
5140 P ("stopaddr=0x%"PFMT64x"\n", core->dbg->stopaddr);
5141 if (rdi->uid != -1) {
5142 P ("uid=%d\n", rdi->uid);
5143 }
5144 if (rdi->gid != -1) {
5145 P ("gid=%d\n", rdi->gid);
5146 }
5147 if (rdi->usr) {
5148 P ("usr=%s\n", rdi->usr);
5149 }
5150 if (rdi->exe && *rdi->exe) {
5151 P ("exe=%s\n", rdi->exe);
5152 }
5153 if (rdi->cmdline && *rdi->cmdline) {
5154 P ("cmdline=%s\n", rdi->cmdline);
5155 }
5156 if (rdi->cwd && *rdi->cwd) {
5157 P ("cwd=%s\n", rdi->cwd);
5158 }
5159 if (rdi->kernel_stack && *rdi->kernel_stack) {
5160 P ("kernel_stack=\n%s\n", rdi->kernel_stack);
5161 }
5162 }
5163 if (stop != -1) {
5164 P ("stopreason=%d\n", stop);
5165 }
5166 break;
5167 case 'f': // "dif" "diff"
5168 if (input[1] == '?') {
5169 eprintf ("Usage: dif $a $b # diff two alias files\n");
5170 } else {
5171 char *arg = strchr (input, ' ');
5172 if (arg) {
5173 arg = strdup (r_str_trim_head_ro (arg + 1));
5174 char *arg2 = strchr (arg, ' ');
5175 if (arg2) {
5176 *arg2++ = 0;
5177 ut8 *a = getFileData (core, arg);
5178 ut8 *b = getFileData (core, arg2);
5179 if (a && b) {
5180 int al = strlen ((const char*)a);
5181 int bl = strlen ((const char*)b);
5182 RDiff *d = r_diff_new ();
5183 char *uni = r_diff_buffers_to_string (d, a, al, b, bl);
5184 r_cons_printf ("%s\n", uni);
5185 r_diff_free (d);
5186 free (uni);
5187 } else {
5188 eprintf ("Cannot open those alias files\n");
5189 }
5190 }
5191 free (arg);
5192 } else {
5193 eprintf ("Usage: dif $a $b # diff two alias files\n");
5194 }
5195 }
5196 break;
5197 case '*': // "di*"
5198 if (rdi) {
5199 r_cons_printf ("f dbg.signal = %d\n", core->dbg->reason.signum);
5200 r_cons_printf ("f dbg.sigpid = %d\n", core->dbg->reason.tid);
5201 r_cons_printf ("f dbg.inbp = %d\n", core->dbg->reason.bp_addr? 1: 0);
5202 r_cons_printf ("f dbg.sigaddr = 0x%"PFMT64x"\n", core->dbg->reason.addr);
5203 r_cons_printf ("f dbg.baddr = 0x%"PFMT64x"\n", r_debug_get_baddr (core->dbg, NULL));
5204 r_cons_printf ("f dbg.pid = %d\n", rdi->pid);
5205 r_cons_printf ("f dbg.tid = %d\n", rdi->tid);
5206 r_cons_printf ("f dbg.uid = %d\n", rdi->uid);
5207 r_cons_printf ("f dbg.gid = %d\n", rdi->gid);
5208 }
5209 break;
5210 case 'j': // "dij"
5211 P ("{");
5212 if (rdi) {
5213 const char *s = r_signal_to_string (core->dbg->reason.signum);
5214 P ("\"type\":\"%s\",", r_debug_reason_to_string (core->dbg->reason.type));
5215 P ("\"signal\":\"%s\",", r_str_get_fail (s, "none"));
5216 P ("\"signum\":%d,", core->dbg->reason.signum);
5217 P ("\"sigpid\":%d,", core->dbg->reason.tid);
5218 P ("\"addr\":%"PFMT64d",", core->dbg->reason.addr);
5219 P ("\"inbp\":%s,", r_str_bool (core->dbg->reason.bp_addr));
5220 P ("\"baddr\":%"PFMT64d",", r_debug_get_baddr (core->dbg, NULL));
5221 P ("\"stopaddr\":%"PFMT64d",", core->dbg->stopaddr);
5222 P ("\"pid\":%d,", rdi->pid);
5223 P ("\"tid\":%d,", rdi->tid);
5224 P ("\"uid\":%d,", rdi->uid);
5225 P ("\"gid\":%d,", rdi->gid);
5226 if (rdi->usr) {
5227 PS("\"usr\":\"%s\",", rdi->usr);
5228 }
5229 if (rdi->exe) {
5230 PS("\"exe\":\"%s\",", rdi->exe);
5231 }
5232 if (rdi->cmdline) {
5233 PS ("\"cmdline\":\"%s\",", rdi->cmdline);
5234 }
5235 if (rdi->cwd) {
5236 PS ("\"cwd\":\"%s\",", rdi->cwd);
5237 }
5238 }
5239 P ("\"stopreason\":%d}\n", stop);
5240 break;
5241 #undef P
5242 #undef PS
5243 case 'q':
5244 {
5245 const char *r = r_debug_reason_to_string (core->dbg->reason.type);
5246 if (!r) {
5247 r = "none";
5248 }
5249 r_cons_printf ("%s at 0x%08"PFMT64x"\n", r, core->dbg->stopaddr);
5250 }
5251 break;
5252 case '?': // "di?"
5253 default:
5254 r_core_cmd_help (core, help_msg_di);
5255 break;
5256 }
5257 r_debug_info_free (rdi);
5258 }
5259 break;
5260 case 'e': // "de"
5261 r_core_debug_esil (core, input + 1);
5262 break;
5263 case 'g': // "dg"
5264 if (core->dbg->h && core->dbg->h->gcore) {
5265 if (core->dbg->pid == -1) {
5266 eprintf ("Not debugging, can't write core.\n");
5267 break;
5268 }
5269 char *corefile = get_corefile_name (input + 1, core->dbg->pid);
5270 eprintf ("Writing to file '%s'\n", corefile);
5271 r_file_rm (corefile);
5272 RBuffer *dst = r_buf_new_file (corefile, O_RDWR | O_CREAT, 0644);
5273 if (dst) {
5274 if (!core->dbg->h->gcore (core->dbg, dst)) {
5275 eprintf ("dg: coredump failed\n");
5276 }
5277 r_buf_free (dst);
5278 } else {
5279 perror ("r_buf_new_file");
5280 }
5281 free (corefile);
5282 }
5283 break;
5284 case 'k': // "dk"
5285 r_core_debug_kill (core, input + 1);
5286 break;
5287 case 'o': // "do"
5288 switch (input[1]) {
5289 case '\0': // "do"
5290 r_core_file_reopen (core, input[1] ? input + 2: NULL, 0, 1);
5291 break;
5292 case 'e': // "doe"
5293 switch (input[2]) {
5294 case '\0': // "doe"
5295 if (core->io->envprofile) {
5296 r_cons_println (core->io->envprofile);
5297 }
5298 break;
5299 case '!': // "doe!"
5300 {
5301 char *out = r_core_editor (core, NULL, core->io->envprofile);
5302 if (out) {
5303 free (core->io->envprofile);
5304 core->io->envprofile = out;
5305 eprintf ("%s\n", core->io->envprofile);
5306 }
5307 } break;
5308 default:
5309 break;
5310 }
5311 break;
5312 case 'r': // "dor" : rarun profile
5313 if (input[2] == ' ') {
5314 setRarunProfileString (core, input + 3);
5315 } else {
5316 // TODO use the api
5317 r_sys_cmd ("rarun2 -h");
5318 }
5319 break;
5320 case 'o': // "doo" : reopen in debug mode
5321 if (input[2] == 'f') { // "doof" : reopen in debug mode from the given file
5322 r_config_set_i (core->config, "cfg.debug", true);
5323 r_core_cmd0 (core, sdb_fmt ("oodf %s", input + 3));
5324 } else {
5325 r_core_file_reopen_debug (core, input + 2);
5326 }
5327 break;
5328 case 'c': // "doc" : close current debug session
5329 if (!core || !core->io || !core->io->desc || !r_config_get_i (core->config, "cfg.debug")) {
5330 eprintf ("No open debug session\n");
5331 break;
5332 }
5333 // Stop trace session
5334 if (core->dbg->session) {
5335 r_debug_session_free (core->dbg->session);
5336 core->dbg->session = NULL;
5337 }
5338 // Kill debugee and all child processes
5339 if (core->dbg && core->dbg->h && core->dbg->h->pids && core->dbg->pid != -1) {
5340 list = core->dbg->h->pids (core->dbg, core->dbg->pid);
5341 if (list) {
5342 r_list_foreach (list, iter, p) {
5343 r_debug_kill (core->dbg, p->pid, p->pid, SIGKILL);
5344 r_debug_detach (core->dbg, p->pid);
5345 }
5346 } else {
5347 r_debug_kill (core->dbg, core->dbg->pid, core->dbg->pid, SIGKILL);
5348 r_debug_detach (core->dbg, core->dbg->pid);
5349 }
5350 }
5351 // Remove registers from the flag list
5352 r_core_cmd0 (core, ".dr-*");
5353 // Reopen and rebase the original file
5354 r_core_cmd0 (core, "oo");
5355 break;
5356 case '?': // "do?"
5357 default:
5358 r_core_cmd_help (core, help_msg_do);
5359 break;
5360 }
5361 break;
5362 #if __WINDOWS__
5363 case 'W': // "dW"
5364 if (input[1] == 'i') {
5365 r_w32_identify_window ();
5366 } else {
5367 r_w32_print_windows (core->dbg);
5368 }
5369 break;
5370 #endif
5371 case 'w': // "dw"
5372 r_cons_break_push (static_debug_stop, core->dbg);
5373 for (;!r_cons_is_breaked ();) {
5374 int pid = atoi (input + 1);
5375 //int opid = core->dbg->pid = pid;
5376 int res = r_debug_kill (core->dbg, pid, 0, 0);
5377 if (!res) {
5378 break;
5379 }
5380 r_sys_usleep (200);
5381 }
5382 r_cons_break_pop ();
5383 break;
5384 case 'x': // "dx"
5385 switch (input[1]) {
5386 case ' ': { // "dx "
5387 ut8 bytes[4096];
5388 if (strlen (input + 2) < 4096){
5389 int bytes_len = r_hex_str2bin (input + 2, bytes);
5390 if (bytes_len>0) r_debug_execute (core->dbg,
5391 bytes, bytes_len, 0);
5392 else eprintf ("Invalid hexpairs\n");
5393 } else eprintf ("Injection opcodes so long\n");
5394 break;
5395 }
5396 case 'a': { // "dxa"
5397 RAsmCode *acode;
5398 r_asm_set_pc (core->rasm, core->offset);
5399 acode = r_asm_massemble (core->rasm, input + 2);
5400 if (acode) {
5401 r_reg_arena_push (core->dbg->reg);
5402 r_debug_execute (core->dbg, acode->bytes, acode->len, 0);
5403 r_reg_arena_pop (core->dbg->reg);
5404 }
5405 r_asm_code_free (acode);
5406 break;
5407 }
5408 case 'e': { // "dxe"
5409 REgg *egg = core->egg;
5410 RBuffer *b;
5411 const char *asm_arch = r_config_get (core->config, "asm.arch");
5412 int asm_bits = r_config_get_i (core->config, "asm.bits");
5413 const char *asm_os = r_config_get (core->config, "asm.os");
5414 r_egg_setup (egg, asm_arch, asm_bits, 0, asm_os);
5415 r_egg_reset (egg);
5416 r_egg_load (egg, input + 1, 0);
5417 r_egg_compile (egg);
5418 b = r_egg_get_bin (egg);
5419 r_asm_set_pc (core->rasm, core->offset);
5420 r_reg_arena_push (core->dbg->reg);
5421 ut64 tmpsz;
5422 const ut8 *tmp = r_buf_data (b, &tmpsz);
5423 r_debug_execute (core->dbg, tmp, tmpsz, 0);
5424 r_reg_arena_pop (core->dbg->reg);
5425 break;
5426 }
5427 case 'r': // "dxr"
5428 r_reg_arena_push (core->dbg->reg);
5429 if (input[2] == ' ') {
5430 ut8 bytes[4096];
5431 if (strlen (input + 2) < 4096){
5432 int bytes_len = r_hex_str2bin (input + 2,
5433 bytes);
5434 if (bytes_len > 0) {
5435 r_debug_execute (core->dbg,
5436 bytes, bytes_len,
5437 0);
5438 } else {
5439 eprintf ("Invalid hexpairs\n");
5440 }
5441 } else eprintf ("Injection opcodes so long\n");
5442 }
5443 r_reg_arena_pop (core->dbg->reg);
5444 break;
5445 case 's': // "dxs"
5446 if (input[2]) {
5447 char *str;
5448 r_cons_push ();
5449 str = r_core_cmd_str (core, sdb_fmt ("gs %s", input + 2));
5450 r_cons_pop ();
5451 r_core_cmdf (core, "dx %s", str); //`gs %s`", input + 2);
5452 free (str);
5453 } else {
5454 eprintf ("Missing parameter used in gs by dxs\n");
5455 }
5456 break;
5457 case '?': // "dx?"
5458 default:
5459 r_core_cmd_help (core, help_msg_dx);
5460 break;
5461 }
5462 break;
5463 case '?': // "d?"
5464 default:
5465 r_core_cmd_help (core, help_msg_d);
5466 break;
5467 }
5468 if (follow > 0) {
5469 ut64 pc = r_debug_reg_get (core->dbg, "PC");
5470 if ((pc < core->offset) || (pc > (core->offset + follow))) {
5471 r_core_cmd0 (core, "sr PC");
5472 }
5473 }
5474 return 0;
5475 }
5476