* regstate retrieval in ELF corefiles * remove rzbin call from cmd_debug * increase FP_LAYOUT to 128
192 lines
5.8 KiB
C
192 lines
5.8 KiB
C
// SPDX-FileCopyrightText: 2009-2018 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_core.h> // just to get the RzPrint instance
|
|
#include <rz_debug.h>
|
|
#include <rz_cons.h>
|
|
#include <rz_reg.h>
|
|
|
|
static bool rz_debug_reg_sync_from_regstate(RzDebug *dbg) {
|
|
if (!dbg || !dbg->corebind.core) {
|
|
return false;
|
|
}
|
|
RzCore *core = (RzCore *)dbg->corebind.core;
|
|
RzBinFile *bf = rz_bin_cur(core->bin);
|
|
if (!bf || !bf->o || !bf->o->regstate) {
|
|
return false;
|
|
}
|
|
RzReg *areg = core->analysis ? rz_analysis_get_reg(core->analysis) : NULL;
|
|
const char *profile = areg ? areg->reg_profile_str : NULL;
|
|
if (!RZ_STR_ISEMPTY(profile)) {
|
|
rz_reg_set_profile_string(dbg->reg, profile);
|
|
}
|
|
return rz_reg_arena_set_bytes(dbg->reg, bf->o->regstate) == 0;
|
|
}
|
|
|
|
RZ_API int rz_debug_reg_sync(RzDebug *dbg, int type, int write) {
|
|
int i, n, size;
|
|
if (!dbg || !dbg->reg) {
|
|
return false;
|
|
}
|
|
|
|
if (!write && (!dbg->cur || (!dbg->cur->reg_read && !dbg->cur->sync_registers) || rz_debug_is_dead(dbg))) {
|
|
if (rz_debug_reg_sync_from_regstate(dbg)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// There's no point in syncing a dead target
|
|
if (rz_debug_is_dead(dbg)) {
|
|
return false;
|
|
}
|
|
if (!dbg->cur) {
|
|
return false;
|
|
}
|
|
// Check if the functions needed are available
|
|
if (write && !dbg->cur->reg_write && !dbg->cur->sync_registers) {
|
|
return false;
|
|
}
|
|
if (!write && !dbg->cur->reg_read && !dbg->cur->sync_registers) {
|
|
return false;
|
|
}
|
|
|
|
bool errored = false;
|
|
if (dbg->cur->sync_registers) {
|
|
if (!dbg->cur->sync_registers(dbg, dbg->reg, write)) {
|
|
RZ_LOG_ERROR("debug: sync: failed to sync registers (%s debugger)\n", write ? "to" : "from");
|
|
errored = true;
|
|
}
|
|
return !errored;
|
|
}
|
|
|
|
// Sync all the types sequentially if asked
|
|
i = (type == RZ_REG_TYPE_ANY) ? RZ_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 don't have regs
|
|
if (i >= RZ_REG_TYPE_GPR && dbg->reg->regset[i].regs && !dbg->reg->regset[i].regs->length) {
|
|
// seek into the other arena for redirections.
|
|
for (n = RZ_REG_TYPE_GPR; n < RZ_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 = rz_reg_get_bytes(dbg->reg, i, &size);
|
|
if (!buf || !dbg->cur->reg_write(dbg, i, buf, size)) {
|
|
if (i == RZ_REG_TYPE_GPR) {
|
|
eprintf("rz_debug_reg: error writing "
|
|
"registers %d to %d\n",
|
|
i, dbg->tid);
|
|
}
|
|
if (type != RZ_REG_TYPE_ANY || i == RZ_REG_TYPE_GPR) {
|
|
free(buf);
|
|
return false;
|
|
}
|
|
}
|
|
free(buf);
|
|
} else {
|
|
// int bufsize = RZ_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->cur->reg_read(dbg, i, buf, bufsize);
|
|
// we need to check against zero because reg_read can return false
|
|
if (size > 0) {
|
|
rz_reg_set_bytes(dbg->reg, i, buf, size); // RZ_MIN (size, bufsize));
|
|
// free (buf);
|
|
// return true;
|
|
}
|
|
free(buf);
|
|
}
|
|
}
|
|
// DO NOT BREAK RZ_REG_TYPE_ANY PLEASE
|
|
// break;
|
|
// Continue the synchronization or just stop if it was asked only for a single type of regs
|
|
i++;
|
|
} while ((type == RZ_REG_TYPE_ANY) && (i < RZ_REG_TYPE_LAST));
|
|
return true;
|
|
}
|
|
|
|
RZ_API int rz_debug_reg_set(struct rz_debug_t *dbg, const char *name, ut64 num) {
|
|
RzRegItem *ri = rz_reg_get_by_role_or_name(dbg->reg, name);
|
|
if (!ri) {
|
|
return false;
|
|
}
|
|
rz_reg_set_value(dbg->reg, ri, num);
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_ANY, true);
|
|
return true;
|
|
}
|
|
|
|
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name) {
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_ANY, false);
|
|
return rz_reg_getv_by_role_or_name(dbg->reg, name);
|
|
}
|
|
|
|
/**
|
|
* Get the value of the register with the given role, including syncing first.
|
|
*/
|
|
RZ_API ut64 rz_debug_reg_get_by_role(RZ_NONNULL RzDebug *dbg, RzRegisterId role) {
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_ANY, false);
|
|
RzRegItem *ri = rz_reg_get_by_role(dbg->reg, role);
|
|
if (!ri) {
|
|
if (role == RZ_REG_NAME_PC) {
|
|
// Debug generally requires the existence of a PC register,
|
|
// other registers may be optional.
|
|
RZ_LOG_ERROR("debug: no PC register known");
|
|
}
|
|
return 0;
|
|
}
|
|
return rz_reg_get_value(dbg->reg, ri);
|
|
}
|
|
|
|
RZ_API ut64 rz_debug_num_callback(RzNum *userptr, const char *str, int *ok) {
|
|
RzDebug *dbg = (RzDebug *)userptr;
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_ANY, false);
|
|
RzRegItem *ri = rz_reg_get_by_role_or_name(dbg->reg, str);
|
|
if (!ri) {
|
|
*ok = 0;
|
|
return UT64_MAX;
|
|
}
|
|
*ok = 1;
|
|
return rz_reg_get_value(dbg->reg, ri);
|
|
}
|
|
|
|
/**
|
|
* Load the register profile from the current plugin into dbg->reg and
|
|
* if successful also sync all register contents into it.
|
|
*
|
|
* \return whether the register profile was provided by the plugin
|
|
*/
|
|
RZ_API bool rz_debug_reg_profile_sync(RzDebug *dbg) {
|
|
rz_return_val_if_fail(dbg, false);
|
|
if (dbg->cur->reg_profile) {
|
|
char *p = dbg->cur->reg_profile(dbg);
|
|
if (p) {
|
|
rz_reg_set_profile_string(dbg->reg, p);
|
|
rz_debug_reg_sync(dbg, RZ_REG_TYPE_ANY, false);
|
|
free(p);
|
|
} else {
|
|
// May happen when the plugin does not yet have enough info
|
|
// to determine the reg profile
|
|
rz_reg_set_profile_string(dbg->reg, "");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|