mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 11:26: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");
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -286,7 +286,19 @@ public:
|
||||
* @brief Attach to a given pid from a debug session
|
||||
*/
|
||||
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
|
||||
* @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()
|
||||
{
|
||||
QJsonArray stackValues = Core()->getStack().array();
|
||||
QList<QJsonObject> stackItems = Core()->getStack();
|
||||
|
||||
beginResetModel();
|
||||
values.clear();
|
||||
for (const QJsonValue &value : stackValues) {
|
||||
QJsonObject stackItem = value.toObject();
|
||||
for (const QJsonObject &stackItem : stackItems) {
|
||||
Item item;
|
||||
|
||||
item.offset = stackItem["addr"].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"];
|
||||
if (!refObject.isUndefined()) { // check that the key exists
|
||||
QString ref = refObject.toString();
|
||||
if (ref.contains("ascii") && ref.count("-->") == 1) {
|
||||
ref = Core()->cmdj(QString("pszj @ [%1]").arg(item.offset)).object().value("string").toString();
|
||||
}
|
||||
item.description = ref;
|
||||
|
||||
|
||||
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));
|
||||
// Set the description's color according to the last item type
|
||||
if (type == "ascii" || !string.isEmpty()) {
|
||||
item.descriptionColor = ConfigColor("comment");
|
||||
} else if (type == "program") {
|
||||
item.descriptionColor = ConfigColor("fname");
|
||||
} else if (type == "library") {
|
||||
item.descriptionColor = ConfigColor("floc");
|
||||
} else if (type == "stack") {
|
||||
item.descriptionColor = ConfigColor("offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
values.push_back(item);
|
||||
|
Loading…
Reference in New Issue
Block a user