rizin/libr/debug/dreg.c
Rick Altherr 9e440fb1b4 dreg: Fix printing of 16-bit x86 segment registers
'ar seg' ends up calling r_debug_reg_list() with size=0.  This should
disable filtering of matches by size per the inner loop iterating over
the registers.  An earlier check to ensure the requested size is valid
for this register set fails to allow for size=0 and will force it to
size=32 instead.  When in 16-bit mode, that will cause no registers to
be printed.
2017-11-20 03:06:40 -05:00

330 lines
8.7 KiB
C

/* radare - LGPL - Copyright 2009-2017 - 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) {
int i, n, size;
if (!dbg || !dbg->reg || !dbg->h) {
return false;
}
// Theres no point in syncing a dead target
if (r_debug_is_dead (dbg)) {
return false;
}
// Check if the functions needed are available
if (write && !dbg->h->reg_write) {
return false;
}
if (!write && !dbg->h->reg_read) {
return false;
}
// Sync all the types sequentially if asked
i = (type == R_REG_TYPE_ALL)? R_REG_TYPE_GPR: type;
// 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 && !dbg->reg->regset[i].regs->length) {
// 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;
}
}
}
do {
if (write) {
ut8 *buf = r_reg_get_bytes (dbg->reg, i, &size);
if (!buf || !dbg->h->reg_write (dbg, i, buf, size)) {
if (!i) {
eprintf ("r_debug_reg: error writing "
"registers %d to %d\n", i, dbg->tid);
}
free (buf);
return false;
}
free (buf);
} 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) {
ut8 *buf = calloc (1 + 1, bufsize);
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;
char strvalue[128];
if (!dbg || !dbg->reg) {
return false;
}
if (dbg->corebind.core) {
pr = ((RCore*)dbg->corebind.core)->print;
}
if (size != 0 && !(dbg->reg->bits & size)) {
// TODO: verify if 32bit exists, otherwise use 64 or 8?
size = 32;
}
if (dbg->bits & R_SYS_BITS_64) {
//fmt = "%s = 0x%08"PFMT64x"%s";
fmt = "%s = %s%s";
fmt2 = "%s%4s%s %s%s";
kwhites = " ";
colwidth = dbg->regcols? 20: 25;
cols = 3;
} else {
//fmt = "%s = 0x%08"PFMT64x"%s";
fmt = "%s = %s%s";
fmt2 = "%s%4s%s %s%s";
kwhites = " ";
colwidth = 20;
cols = 4;
}
if (dbg->regcols) {
cols = dbg->regcols;
}
if (rad == 'j') {
dbg->cb_printf ("{");
}
// with the new field "arena" into reg items why need
// to get all arenas.
from = 0;
to = R_REG_TYPE_LAST;
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;
utX valueBig;
if (type != -1) {
if (type != item->type && R_REG_TYPE_FLG != item->type) {
continue;
}
if (size != 0 && size != item->size) {
continue;
}
}
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;
if (rad == 'j') {
snprintf (strvalue, sizeof (strvalue),"%"PFMT64d, value);
} else {
snprintf (strvalue, sizeof (strvalue),"0x%08"PFMT64x, value);
}
} else {
value = r_reg_get_value_big (dbg->reg, item, &valueBig);
switch (regSize) {
case 80:
snprintf (strvalue, sizeof (strvalue), "0x%04x%016"PFMT64x"", valueBig.v80.High, valueBig.v80.Low);
break;
case 96:
snprintf (strvalue, sizeof (strvalue), "0x%08x%016"PFMT64x"", valueBig.v96.High, valueBig.v96.Low);
break;
case 128:
snprintf (strvalue, sizeof (strvalue), "0x%016"PFMT64x"%016"PFMT64x"", valueBig.v128.High, valueBig.v128.Low);
break;
default:
snprintf (strvalue, sizeof (strvalue), "ERROR");
}
delta = 0; // TODO: calculate delta with big values.
}
itmidx++;
switch (rad) {
case 'j':
dbg->cb_printf ("%s\"%s\":%s",
n?",":"", item->name, strvalue);
break;
case '-':
dbg->cb_printf ("f-%s\n", item->name);
break;
case 'R':
dbg->cb_printf ("aer %s = %s\n", item->name, strvalue);
break;
case 1:
case '*':
dbg->cb_printf ("f %s 1 %s\n", item->name, strvalue);
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 ("%s", 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),
fmt2, "", item->name, "", strvalue, "");
len = colwidth - strlen (content);
if (len < 0) len = 0;
memset (whites, ' ', sizeof (whites));
whites[len] = 0;
dbg->cb_printf (fmt2, a, item->name, b, strvalue,
((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) {
char woot[512];
snprintf (woot, sizeof (woot),
" was 0x%"PFMT64x" delta %d\n", diff, delta);
dbg->cb_printf (fmt, item->name, strvalue, woot);
}
break;
default:
if (delta && use_color) {
dbg->cb_printf (use_color);
dbg->cb_printf (fmt, item->name, strvalue, Color_RESET"\n");
} else {
dbg->cb_printf (fmt, item->name, strvalue, "\n");
}
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
return r_debug_reg_get_err (dbg, name, NULL, NULL);
}
R_API ut64 r_debug_reg_get_err(RDebug *dbg, const char *name, int *err, utX *value) {
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);
if (err) {
*err = 1;
}
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);
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;
}
}
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
return r_debug_reg_get_err (dbg, str, ok, NULL);
}