2016-10-09 21:52:24 +00:00
|
|
|
/* radare - LGPL - Copyright 2009-2016 - pancake */
|
|
|
|
|
|
|
|
#include <r_core.h> // just to get the RPrint instance
|
|
|
|
#include <r_debug.h>
|
|
|
|
#include <r_cons.h>
|
|
|
|
#include <r_reg.h>
|
|
|
|
|
|
|
|
R_API int r_debug_reg_sync(RDebug *dbg, int type, int write) {
|
2016-11-14 22:58:29 +00:00
|
|
|
int i, n, size;
|
2016-11-15 00:12:37 +00:00
|
|
|
if (!dbg || !dbg->reg || !dbg->h) {
|
2016-10-09 21:52:24 +00:00
|
|
|
return false;
|
2016-11-15 00:12:37 +00:00
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
// Theres no point in syncing a dead target
|
2016-11-15 00:12:37 +00:00
|
|
|
if (r_debug_is_dead (dbg)) {
|
2016-10-09 21:52:24 +00:00
|
|
|
return false;
|
2016-11-15 00:12:37 +00:00
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
// Check if the functions needed are available
|
2016-11-15 00:12:37 +00:00
|
|
|
if (write && !dbg->h->reg_write) {
|
2016-10-09 21:52:24 +00:00
|
|
|
return false;
|
2016-11-15 00:12:37 +00:00
|
|
|
}
|
|
|
|
if (!write && !dbg->h->reg_read) {
|
2016-10-09 21:52:24 +00:00
|
|
|
return false;
|
2016-11-15 00:12:37 +00:00
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
// Sync all the types sequentially if asked
|
|
|
|
i = (type == R_REG_TYPE_ALL)? R_REG_TYPE_GPR: type;
|
2016-11-14 22:58:29 +00:00
|
|
|
// Check to get the correct arena when using @ into reg profile (arena!=type)
|
|
|
|
// if request type is positive and the request regset dont have regs
|
|
|
|
if (i >= R_REG_TYPE_GPR && dbg->reg->regset[i].regs->length == 0) {
|
|
|
|
// seek into the other arena for redirections.
|
|
|
|
for (n = R_REG_TYPE_GPR; n < R_REG_TYPE_LAST; n++) {
|
|
|
|
// get regset mask
|
|
|
|
int mask = dbg->reg->regset[n].maskregstype;
|
|
|
|
// convert request arena to mask value
|
|
|
|
int v = ((int)1 << i);
|
|
|
|
// skip checks on same request arena and check if this arena have inside the request arena type
|
|
|
|
if (n != i && (mask & v)) {
|
|
|
|
//eprintf(" req = %i arena = %i mask = %x search = %x \n", i, n, mask, v);
|
|
|
|
//eprintf(" request arena %i found at arena %i\n", i, n );
|
|
|
|
// if this arena have the request arena type, force to use this arena.
|
|
|
|
i = n;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
do {
|
|
|
|
if (write) {
|
|
|
|
ut8 *buf = r_reg_get_bytes (dbg->reg, i, &size);
|
|
|
|
if (!buf || !dbg->h->reg_write (dbg, i, buf, size)) {
|
2016-11-15 00:12:37 +00:00
|
|
|
if (!i) {
|
2016-10-09 21:52:24 +00:00
|
|
|
eprintf ("r_debug_reg: error writing "
|
|
|
|
"registers %d to %d\n", i, dbg->tid);
|
2016-11-15 00:12:37 +00:00
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// int bufsize = R_MAX (1024, dbg->reg->size*2); // i know. its hacky
|
|
|
|
int bufsize = dbg->reg->size;
|
|
|
|
//int bufsize = dbg->reg->regset[i].arena->size;
|
|
|
|
if (bufsize > 0) {
|
2016-11-26 05:05:10 +00:00
|
|
|
ut8 *buf = calloc (1 + 1, bufsize);
|
2016-10-09 21:52:24 +00:00
|
|
|
if (!buf) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//we have already checked dbg->h and dbg->h->reg_read above
|
|
|
|
size = dbg->h->reg_read (dbg, i, buf, bufsize);
|
|
|
|
// we need to check against zero because reg_read can return false
|
|
|
|
if (size > 0) {
|
|
|
|
r_reg_set_bytes (dbg->reg, i, buf, size); //R_MIN (size, bufsize));
|
|
|
|
// free (buf);
|
|
|
|
// return true;
|
|
|
|
}
|
|
|
|
free (buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// DO NOT BREAK R_REG_TYPE_ALL PLEASE
|
|
|
|
// break;
|
|
|
|
// Continue the syncronization or just stop if it was asked only for a single type of regs
|
|
|
|
i++;
|
|
|
|
} while ((type == R_REG_TYPE_ALL) && (i < R_REG_TYPE_LAST));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_reg_list(RDebug *dbg, int type, int size, int rad, const char *use_color) {
|
|
|
|
int i, delta, from, to, cols, n = 0;
|
|
|
|
const char *fmt, *fmt2, *kwhites;
|
|
|
|
RPrint *pr = NULL;
|
|
|
|
int colwidth = 20;
|
|
|
|
RListIter *iter;
|
|
|
|
RRegItem *item;
|
|
|
|
RList *head;
|
|
|
|
ut64 diff;
|
2016-11-14 22:58:29 +00:00
|
|
|
char strvalue[128];
|
2016-10-09 21:52:24 +00:00
|
|
|
if (!dbg || !dbg->reg) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (dbg->corebind.core) {
|
|
|
|
pr = ((RCore*)dbg->corebind.core)->print;
|
|
|
|
}
|
|
|
|
if (!(dbg->reg->bits & size)) {
|
|
|
|
// TODO: verify if 32bit exists, otherwise use 64 or 8?
|
|
|
|
size = 32;
|
|
|
|
}
|
|
|
|
if (dbg->bits & R_SYS_BITS_64) {
|
2016-11-14 22:58:29 +00:00
|
|
|
//fmt = "%s = 0x%08"PFMT64x"%s";
|
|
|
|
fmt = "%s = %s%s";
|
2016-11-20 10:30:15 +00:00
|
|
|
fmt2 = "%s%4s%s %s%s";
|
2016-10-09 21:52:24 +00:00
|
|
|
kwhites = " ";
|
|
|
|
colwidth = dbg->regcols? 20: 25;
|
|
|
|
cols = 3;
|
|
|
|
} else {
|
2016-11-14 22:58:29 +00:00
|
|
|
//fmt = "%s = 0x%08"PFMT64x"%s";
|
|
|
|
fmt = "%s = %s%s";
|
2016-11-20 10:30:15 +00:00
|
|
|
fmt2 = "%s%4s%s %s%s";
|
2016-10-09 21:52:24 +00:00
|
|
|
kwhites = " ";
|
|
|
|
colwidth = 20;
|
|
|
|
cols = 4;
|
|
|
|
}
|
|
|
|
if (dbg->regcols) {
|
|
|
|
cols = dbg->regcols;
|
|
|
|
}
|
|
|
|
if (rad == 'j') {
|
|
|
|
dbg->cb_printf ("{");
|
|
|
|
}
|
2016-11-14 22:58:29 +00:00
|
|
|
// with the new field "arena" into reg items why need
|
|
|
|
// to get all arenas.
|
|
|
|
from = 0;
|
|
|
|
to = R_REG_TYPE_LAST;
|
2016-10-09 21:52:24 +00:00
|
|
|
|
|
|
|
int itmidx = -1;
|
|
|
|
dbg->creg = NULL;
|
|
|
|
for (i = from; i < to; i++) {
|
|
|
|
head = r_reg_get_list (dbg->reg, i);
|
|
|
|
if (!head) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
r_list_foreach (head, iter, item) {
|
|
|
|
ut64 value;
|
2016-11-14 22:58:29 +00:00
|
|
|
utX valueBig;
|
2016-10-09 21:52:24 +00:00
|
|
|
#if 0
|
|
|
|
bool is_arm = dbg->arch && strstr (dbg->arch, "arm");
|
|
|
|
|
|
|
|
/* the thumb flag in the cpsr register shouldnt forbid us to switch between arm or thumb */
|
|
|
|
/* this code must run only after a step maybe ... need some discussion, disabling for now */
|
|
|
|
if (is_arm && (rad == 1 || rad == '*') && item->size == 1) {
|
|
|
|
if (!strcmp (item->name, "tf")) {
|
|
|
|
bool is_thumb = r_reg_get_value (dbg->reg, item);
|
|
|
|
int new_bits = is_thumb? 16: 32;
|
|
|
|
if (dbg->anal->bits != new_bits)
|
|
|
|
dbg->cb_printf ("e asm.bits=%d\n", new_bits);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (type != -1) {
|
|
|
|
if (type != item->type && R_REG_TYPE_FLG != item->type) continue;
|
|
|
|
if (size != 0 && size != item->size) continue;
|
|
|
|
}
|
2016-11-14 22:58:29 +00:00
|
|
|
int regSize = item->size;
|
|
|
|
if (regSize < 80) {
|
|
|
|
value = r_reg_get_value (dbg->reg, item);
|
|
|
|
r_reg_arena_swap (dbg->reg, false);
|
|
|
|
diff = r_reg_get_value (dbg->reg, item);
|
|
|
|
r_reg_arena_swap (dbg->reg, false);
|
|
|
|
delta = value-diff;
|
2016-11-15 23:28:37 +00:00
|
|
|
if (rad == 'j') {
|
|
|
|
snprintf (strvalue, sizeof (strvalue),"%"PFMT64d, value);
|
|
|
|
} else {
|
|
|
|
snprintf (strvalue, sizeof (strvalue),"0x%08"PFMT64x, value);
|
|
|
|
}
|
2016-11-14 22:58:29 +00:00
|
|
|
} else {
|
|
|
|
value = r_reg_get_value_big (dbg->reg, item, &valueBig);
|
2016-11-15 00:12:37 +00:00
|
|
|
switch (regSize) {
|
2016-11-14 22:58:29 +00:00
|
|
|
case 80:
|
2016-11-20 10:30:15 +00:00
|
|
|
snprintf (strvalue, sizeof (strvalue), "0x%04x%016"PFMT64x"", valueBig.v80.High, valueBig.v80.Low);
|
2016-11-14 22:58:29 +00:00
|
|
|
break;
|
|
|
|
case 96:
|
2016-11-15 23:28:37 +00:00
|
|
|
snprintf (strvalue, sizeof (strvalue), "0x%08x%016"PFMT64x"", valueBig.v96.High, valueBig.v96.Low);
|
2016-11-14 22:58:29 +00:00
|
|
|
break;
|
|
|
|
case 128:
|
2016-11-15 23:28:37 +00:00
|
|
|
snprintf (strvalue, sizeof (strvalue), "0x%016"PFMT64x"%016"PFMT64x"", valueBig.v128.High, valueBig.v128.Low);
|
2016-11-14 22:58:29 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
snprintf (strvalue, sizeof (strvalue), "ERROR");
|
|
|
|
}
|
|
|
|
delta = 0; // TODO: calculate delta with big values.
|
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
itmidx++;
|
|
|
|
|
|
|
|
switch (rad) {
|
|
|
|
case 'j':
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf ("%s\"%s\":%s",
|
|
|
|
n?",":"", item->name, strvalue);
|
2016-10-09 21:52:24 +00:00
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
dbg->cb_printf ("f-%s\n", item->name);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case '*':
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf ("f %s 1 0x%s\n",
|
|
|
|
item->name, strvalue);
|
2016-10-09 21:52:24 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
int len, highlight = use_color && pr && pr->cur_enabled && itmidx == pr->cur;
|
|
|
|
char *str, whites[32], content[128];
|
|
|
|
const char *a = "", *b = "";
|
|
|
|
if (highlight) {
|
|
|
|
a = Color_INVERT;
|
|
|
|
b = Color_INVERT_RESET;
|
|
|
|
dbg->creg = item->name;
|
|
|
|
}
|
|
|
|
strcpy (whites, kwhites);
|
|
|
|
if (delta && use_color) {
|
|
|
|
dbg->cb_printf (use_color);
|
|
|
|
}
|
|
|
|
if (item->flags) {
|
|
|
|
str = r_reg_get_bvalue (dbg->reg, item);
|
|
|
|
len = 12 - strlen (str);
|
|
|
|
memset (whites, ' ', sizeof (whites));
|
|
|
|
whites[len] = 0;
|
|
|
|
dbg->cb_printf (" %s%s%s %s%s", a, item->name, b,
|
|
|
|
str, ((n+1)%cols)? whites: "\n");
|
|
|
|
free (str);
|
|
|
|
} else {
|
|
|
|
snprintf (content, sizeof (content),
|
2016-11-14 22:58:29 +00:00
|
|
|
fmt2, "", item->name, "", strvalue, "");
|
2016-10-09 21:52:24 +00:00
|
|
|
len = colwidth - strlen (content);
|
|
|
|
if (len < 0) len = 0;
|
|
|
|
memset (whites, ' ', sizeof (whites));
|
|
|
|
whites[len] = 0;
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf (fmt2, a, item->name, b, strvalue,
|
2016-10-09 21:52:24 +00:00
|
|
|
((n+1)%cols)? whites: "\n");
|
|
|
|
}
|
|
|
|
if (highlight) {
|
|
|
|
dbg->cb_printf (Color_INVERT_RESET);
|
|
|
|
}
|
|
|
|
if (delta && use_color) {
|
|
|
|
dbg->cb_printf (Color_RESET);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (delta) {
|
2016-11-14 22:58:29 +00:00
|
|
|
char woot[512];
|
2016-10-09 21:52:24 +00:00
|
|
|
snprintf (woot, sizeof (woot),
|
2016-11-15 13:40:16 +00:00
|
|
|
" was 0x%"PFMT64x" delta %d\n", diff, delta);
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf (fmt, item->name, strvalue, woot);
|
2016-10-09 21:52:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (delta && use_color) {
|
|
|
|
dbg->cb_printf (use_color);
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf (fmt, item->name, strvalue, Color_RESET"\n");
|
2016-10-09 21:52:24 +00:00
|
|
|
} else {
|
2016-11-14 22:58:29 +00:00
|
|
|
dbg->cb_printf (fmt, item->name, strvalue, "\n");
|
2016-10-09 21:52:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rad == 'j') {
|
|
|
|
dbg->cb_printf ("}\n");
|
|
|
|
} else if (n > 0 && rad == 2 && ((n%cols))) {
|
|
|
|
dbg->cb_printf ("\n");
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API int r_debug_reg_set(struct r_debug_t *dbg, const char *name, ut64 num) {
|
|
|
|
RRegItem *ri;
|
|
|
|
int role = r_reg_get_name_idx (name);
|
|
|
|
if (!dbg || !dbg->reg) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (role != -1) {
|
|
|
|
name = r_reg_get_name (dbg->reg, role);
|
|
|
|
}
|
|
|
|
ri = r_reg_get (dbg->reg, name, R_REG_TYPE_ALL);
|
|
|
|
if (ri) {
|
|
|
|
r_reg_set_value (dbg->reg, ri, num);
|
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_ALL, true);
|
|
|
|
}
|
|
|
|
return (ri != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API ut64 r_debug_reg_get(RDebug *dbg, const char *name) {
|
|
|
|
// ignores errors
|
2016-11-14 22:58:29 +00:00
|
|
|
return r_debug_reg_get_err (dbg, name, NULL, NULL);
|
2016-10-09 21:52:24 +00:00
|
|
|
}
|
|
|
|
|
2016-11-14 22:58:29 +00:00
|
|
|
R_API ut64 r_debug_reg_get_err(RDebug *dbg, const char *name, int *err, utX *value) {
|
2016-10-09 21:52:24 +00:00
|
|
|
RRegItem *ri = NULL;
|
|
|
|
ut64 ret = 0LL;
|
|
|
|
int role = r_reg_get_name_idx (name);
|
|
|
|
const char *pname = name;
|
|
|
|
if (err) *err = 0;
|
|
|
|
if (!dbg || !dbg->reg) {
|
|
|
|
if (err) *err = 1;
|
|
|
|
return UT64_MAX;
|
|
|
|
}
|
|
|
|
if (role != -1) {
|
|
|
|
name = r_reg_get_name (dbg->reg, role);
|
|
|
|
if (!name || *name == '\0') {
|
|
|
|
eprintf ("No debug register profile defined for '%s'.\n", pname);
|
2016-11-14 22:58:29 +00:00
|
|
|
if (err) {
|
|
|
|
*err = 1;
|
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
return UT64_MAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ri = r_reg_get (dbg->reg, name, R_REG_TYPE_ALL);
|
|
|
|
if (ri) {
|
|
|
|
r_debug_reg_sync (dbg, R_REG_TYPE_ALL, false);
|
2016-11-14 22:58:29 +00:00
|
|
|
if (value && ri->size > 64) {
|
|
|
|
if (err) {
|
|
|
|
*err = ri->size;
|
|
|
|
}
|
|
|
|
ret = r_reg_get_value_big (dbg->reg, ri, value);
|
|
|
|
} else {
|
|
|
|
ret = r_reg_get_value (dbg->reg, ri);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (err) {
|
|
|
|
*err = 1;
|
|
|
|
}
|
2016-10-09 21:52:24 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: dup for get_Err!
|
|
|
|
R_API ut64 r_debug_num_callback(RNum *userptr, const char *str, int *ok) {
|
|
|
|
RDebug *dbg = (RDebug *)userptr;
|
|
|
|
// resolve using regnu
|
2016-11-14 22:58:29 +00:00
|
|
|
return r_debug_reg_get_err (dbg, str, ok, NULL);
|
2016-10-09 21:52:24 +00:00
|
|
|
}
|
2016-10-16 00:34:54 +00:00
|
|
|
|