mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 19:36:11 +00:00
Add a custom telescoping function and improve StackWidget's output (#1990)
* Add a custom telescoping function and improve StackWidget's output * Use colors from the color configuration for stackswidget * Improve telescoping output
This commit is contained in:
parent
f1f64b0f55
commit
830e9cd947
@ -1139,9 +1139,144 @@ QJsonDocument CutterCore::getSignatureInfo()
|
|||||||
return cmdj("iCj");
|
return cmdj("iCj");
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument CutterCore::getStack(int size)
|
QList<QJsonObject> CutterCore::getStack(int size, int depth)
|
||||||
{
|
{
|
||||||
return cmdj("pxrj " + QString::number(size) + " @ r:SP");
|
QList<QJsonObject> stack;
|
||||||
|
if (!currentlyDebugging) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
CORE_LOCK();
|
||||||
|
bool ret;
|
||||||
|
RVA addr = cmd("dr SP").toULongLong(&ret, 16);
|
||||||
|
if (!ret) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base = core->anal->bits;
|
||||||
|
for (int i = 0; i < size; i += base / 8) {
|
||||||
|
if ((base == 32 && addr + i >= UT32_MAX) || (base == 16 && addr + i >= UT16_MAX)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.append(getAddrRefs(addr + i, depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) {
|
||||||
|
QJsonObject json;
|
||||||
|
if (depth < 1 || addr == UT64_MAX) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
CORE_LOCK();
|
||||||
|
int bits = core->assembler->bits;
|
||||||
|
QByteArray buf = QByteArray();
|
||||||
|
ut64 type = r_core_anal_address(core, addr);
|
||||||
|
|
||||||
|
json["addr"] = QString::number(addr);
|
||||||
|
|
||||||
|
// Search for the section the addr is in, avoid duplication for heap/stack with type
|
||||||
|
if(!(type & R_ANAL_ADDR_TYPE_HEAP || type & R_ANAL_ADDR_TYPE_STACK)) {
|
||||||
|
// Attempt to find the address within a map
|
||||||
|
RDebugMap *map = r_debug_map_get(core->dbg, addr);
|
||||||
|
if (map && map->name && map->name[0]) {
|
||||||
|
json["mapname"] = map->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBinSection *sect = r_bin_get_section_at(r_bin_cur_object (core->bin), addr, true);
|
||||||
|
if (sect && sect->name[0]) {
|
||||||
|
json["section"] = sect->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the address points to a register
|
||||||
|
RFlagItem *fi = r_flag_get_i(core->flags, addr);
|
||||||
|
if (fi) {
|
||||||
|
RRegItem *r = r_reg_get(core->dbg->reg, fi->name, -1);
|
||||||
|
if (r) {
|
||||||
|
json["reg"] = r->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find the address within a function
|
||||||
|
RAnalFunction *fcn = r_anal_get_fcn_in(core->anal, addr, 0);
|
||||||
|
if (fcn) {
|
||||||
|
json["fcn"] = fcn->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update type and permission information
|
||||||
|
if (type != 0) {
|
||||||
|
if (type & R_ANAL_ADDR_TYPE_HEAP) {
|
||||||
|
json["type"] = "heap";
|
||||||
|
} else if (type & R_ANAL_ADDR_TYPE_STACK) {
|
||||||
|
json["type"] = "stack";
|
||||||
|
} else if (type & R_ANAL_ADDR_TYPE_PROGRAM) {
|
||||||
|
json["type"] = "program";
|
||||||
|
} else if (type & R_ANAL_ADDR_TYPE_LIBRARY) {
|
||||||
|
json["type"] = "library";
|
||||||
|
} else if (type & R_ANAL_ADDR_TYPE_ASCII) {
|
||||||
|
json["type"] = "ascii";
|
||||||
|
} else if (type & R_ANAL_ADDR_TYPE_SEQUENCE) {
|
||||||
|
json["type"] = "sequence";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString perms = "";
|
||||||
|
if (type & R_ANAL_ADDR_TYPE_READ) {
|
||||||
|
perms += "r";
|
||||||
|
}
|
||||||
|
if (type & R_ANAL_ADDR_TYPE_WRITE) {
|
||||||
|
perms += "w";
|
||||||
|
}
|
||||||
|
if (type & R_ANAL_ADDR_TYPE_EXEC) {
|
||||||
|
RAsmOp op;
|
||||||
|
buf.resize(32);
|
||||||
|
perms += "x";
|
||||||
|
// Instruction disassembly
|
||||||
|
r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
|
||||||
|
r_asm_set_pc(core->assembler, addr);
|
||||||
|
r_asm_disassemble(core->assembler, &op, (unsigned char*)buf.data(), buf.size());
|
||||||
|
json["asm"] = r_asm_op_get_asm(&op);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!perms.isEmpty()) {
|
||||||
|
json["perms"] = perms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to telescope further if depth permits it
|
||||||
|
if ((type & R_ANAL_ADDR_TYPE_READ) && !(type & R_ANAL_ADDR_TYPE_EXEC)) {
|
||||||
|
buf.resize(64);
|
||||||
|
ut32 *n32 = (ut32 *)buf.data();
|
||||||
|
ut64 *n64 = (ut64 *)buf.data();
|
||||||
|
r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
|
||||||
|
ut64 n = (bits == 64)? *n64: *n32;
|
||||||
|
// The value of the next address will serve as an indication that there's more to
|
||||||
|
// telescope if we have reached the depth limit
|
||||||
|
json["value"] = QString::number(n);
|
||||||
|
if (depth && n != addr) {
|
||||||
|
// Make sure we aren't telescoping the same address
|
||||||
|
QJsonObject ref = getAddrRefs(n, depth - 1);
|
||||||
|
if (!ref.empty() && !ref["type"].isNull()) {
|
||||||
|
// If the dereference of the current pointer is an ascii character we
|
||||||
|
// might have a string in this address
|
||||||
|
if (ref["type"].toString().contains("ascii")) {
|
||||||
|
buf.resize(128);
|
||||||
|
r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
|
||||||
|
QString strVal = QString(buf);
|
||||||
|
// Indicate that the string is longer than the printed value
|
||||||
|
if (strVal.size() == buf.size()) {
|
||||||
|
strVal += "...";
|
||||||
|
}
|
||||||
|
json["string"] = strVal;
|
||||||
|
}
|
||||||
|
json["ref"] = ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument CutterCore::getProcessThreads(int pid)
|
QJsonDocument CutterCore::getProcessThreads(int pid)
|
||||||
|
@ -286,7 +286,19 @@ public:
|
|||||||
* @brief Attach to a given pid from a debug session
|
* @brief Attach to a given pid from a debug session
|
||||||
*/
|
*/
|
||||||
void setCurrentDebugProcess(int pid);
|
void setCurrentDebugProcess(int pid);
|
||||||
QJsonDocument getStack(int size = 0x100);
|
/**
|
||||||
|
* @brief Returns a list of stack address and their telescoped references
|
||||||
|
* @param size number of bytes to scan
|
||||||
|
* @param depth telescoping depth
|
||||||
|
*/
|
||||||
|
QList<QJsonObject> getStack(int size = 0x100, int depth = 6);
|
||||||
|
/**
|
||||||
|
* @brief Recursively dereferences pointers starting at the specified address
|
||||||
|
* up to a given depth
|
||||||
|
* @param addr telescoping addr
|
||||||
|
* @param depth telescoping depth
|
||||||
|
*/
|
||||||
|
QJsonObject getAddrRefs(RVA addr, int depth);
|
||||||
/**
|
/**
|
||||||
* @brief Get a list of a given process's threads
|
* @brief Get a list of a given process's threads
|
||||||
* @param pid The pid of the process, -1 for the currently debugged process
|
* @param pid The pid of the process, -1 for the currently debugged process
|
||||||
|
@ -144,37 +144,66 @@ StackModel::StackModel(QObject *parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility function to check if a telescoped item exists and add it with prefixes to the desc
|
||||||
|
static inline const QString append_var(QString &dst, const QString val, const QString prepend_val,
|
||||||
|
const QString append_val)
|
||||||
|
{
|
||||||
|
if (!val.isEmpty()) {
|
||||||
|
dst += prepend_val + val + append_val;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
void StackModel::reload()
|
void StackModel::reload()
|
||||||
{
|
{
|
||||||
QJsonArray stackValues = Core()->getStack().array();
|
QList<QJsonObject> stackItems = Core()->getStack();
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
values.clear();
|
values.clear();
|
||||||
for (const QJsonValue &value : stackValues) {
|
for (const QJsonObject &stackItem : stackItems) {
|
||||||
QJsonObject stackItem = value.toObject();
|
|
||||||
Item item;
|
Item item;
|
||||||
|
|
||||||
item.offset = stackItem["addr"].toVariant().toULongLong();
|
item.offset = stackItem["addr"].toVariant().toULongLong();
|
||||||
item.value = RAddressString(stackItem["value"].toVariant().toULongLong());
|
item.value = RAddressString(stackItem["value"].toVariant().toULongLong());
|
||||||
|
|
||||||
|
QJsonObject refItem = stackItem["ref"].toObject();
|
||||||
|
if (!refItem.empty()) {
|
||||||
|
QString str = refItem["string"].toVariant().toString();
|
||||||
|
if (!str.isEmpty()) {
|
||||||
|
item.description = str;
|
||||||
|
item.descriptionColor = ConfigColor("comment");
|
||||||
|
} else {
|
||||||
|
QString type, string;
|
||||||
|
do {
|
||||||
|
item.description += " ->";
|
||||||
|
append_var(item.description, refItem["reg"].toVariant().toString(), " @", "");
|
||||||
|
append_var(item.description, refItem["mapname"].toVariant().toString(), " (", ")");
|
||||||
|
append_var(item.description, refItem["section"].toVariant().toString(), " (", ")");
|
||||||
|
append_var(item.description, refItem["func"].toVariant().toString(), " ", "");
|
||||||
|
type = append_var(item.description, refItem["type"].toVariant().toString(), " ", "");
|
||||||
|
append_var(item.description, refItem["perms"].toVariant().toString(), " ", "");
|
||||||
|
append_var(item.description, refItem["asm"].toVariant().toString(), " \"", "\"");
|
||||||
|
string = append_var(item.description, refItem["string"].toVariant().toString(), " ", "");
|
||||||
|
if (!string.isNull()) {
|
||||||
|
// There is no point in adding ascii and addr info after a string
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!refItem["value"].isNull()) {
|
||||||
|
append_var(item.description, RAddressString(refItem["value"].toVariant().toULongLong()), " ", "");
|
||||||
|
}
|
||||||
|
refItem = refItem["ref"].toObject();
|
||||||
|
} while (!refItem.empty());
|
||||||
|
|
||||||
QJsonValue refObject = stackItem["ref"];
|
// Set the description's color according to the last item type
|
||||||
if (!refObject.isUndefined()) { // check that the key exists
|
if (type == "ascii" || !string.isEmpty()) {
|
||||||
QString ref = refObject.toString();
|
item.descriptionColor = ConfigColor("comment");
|
||||||
if (ref.contains("ascii") && ref.count("-->") == 1) {
|
} else if (type == "program") {
|
||||||
ref = Core()->cmdj(QString("pszj @ [%1]").arg(item.offset)).object().value("string").toString();
|
item.descriptionColor = ConfigColor("fname");
|
||||||
}
|
} else if (type == "library") {
|
||||||
item.description = ref;
|
item.descriptionColor = ConfigColor("floc");
|
||||||
|
} else if (type == "stack") {
|
||||||
|
item.descriptionColor = ConfigColor("offset");
|
||||||
if (refObject.toString().contains("ascii") && refObject.toString().count("-->") == 1) {
|
}
|
||||||
item.descriptionColor = QVariant(QColor(243, 156, 17));
|
|
||||||
} else if (ref.contains("program R X") && ref.count("-->") == 0) {
|
|
||||||
item.descriptionColor = QVariant(QColor(Qt::red));
|
|
||||||
} else if (ref.contains("stack") && ref.count("-->") == 0) {
|
|
||||||
item.descriptionColor = QVariant(QColor(Qt::cyan));
|
|
||||||
} else if (ref.contains("library") && ref.count("-->") == 0) {
|
|
||||||
item.descriptionColor = QVariant(QColor(Qt::green));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
values.push_back(item);
|
values.push_back(item);
|
||||||
|
Loading…
Reference in New Issue
Block a user