diff --git a/rizin b/rizin index 215e4925..a9c59ce1 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 215e49253d3a35e1aae340b7ae8465018254ae87 +Subproject commit a9c59ce1ddc44c498b6a9a02e36989a34f184286 diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index c66a862e..2fbf603d 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -53,11 +53,8 @@ void CallGraphView::showExportDialog() void CallGraphView::showAddress(RVA address) { if (global) { - auto addressMappingIt = addressMapping.find(address); - if (addressMappingIt != addressMapping.end()) { - selectBlockWithId(addressMappingIt->second); - showBlock(blocks[addressMappingIt->second]); - } + selectBlockWithId(address); + showBlock(blocks[address]); } else if (address != this->address) { this->address = address; refreshView(); @@ -72,53 +69,72 @@ void CallGraphView::refreshView() SimpleTextGraphView::refreshView(); } +static inline bool isBetween(ut64 a, ut64 x, ut64 b) +{ + return (a == UT64_MAX || a <= x) && (b == UT64_MAX || x <= b); +} + +using PRzList = std::unique_ptr; + void CallGraphView::loadCurrentGraph() { blockContent.clear(); blocks.clear(); - CutterJson nodes = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); + const ut64 from = Core()->getConfigi("graph.from"); + const ut64 to = Core()->getConfigi("graph.to"); + const bool usenames = Core()->getConfigb("graph.json.usenames"); - QHash idMapping; + auto edges = std::unordered_set {}; + auto addFunction = [&](RzAnalysisFunction *fcn) { + GraphLayout::GraphBlock block; + block.entry = fcn->addr; - auto getId = [&](const QString &name) -> uint64_t { - auto nextId = idMapping.size(); - auto &itemId = idMapping[name]; - if (idMapping.size() != nextId) { - itemId = nextId; + auto xrefs = PRzList { rz_analysis_function_get_xrefs_from(fcn), rz_list_free }; + auto calls = std::unordered_set(); + for (const auto &xref : CutterRzList(xrefs.get())) { + const auto x = xref->to; + if (!(xref->type == RZ_ANALYSIS_XREF_TYPE_CALL && calls.find(x) == calls.end())) { + continue; + } + calls.insert(x); + block.edges.emplace_back(x); + edges.insert(x); } - return itemId; + + QString name = usenames ? fcn->name : RzAddressString(fcn->addr); + addBlock(std::move(block), name, fcn->addr); }; - for (CutterJson block : nodes) { - QString name = block["name"].toString(); - - auto edges = block["imports"]; - GraphLayout::GraphBlock layoutBlock; - layoutBlock.entry = getId(name); - for (auto edge : edges) { - auto targetName = edge.toString(); - auto targetId = getId(targetName); - layoutBlock.edges.emplace_back(targetId); + if (global) { + for (const auto &fcn : CutterRzList(Core()->core()->analysis->fcns)) { + if (!isBetween(from, fcn->addr, to)) { + continue; + } + addFunction(fcn); + } + } else { + const auto &fcn = Core()->functionIn(address); + if (fcn) { + addFunction(fcn); } - - // it would be good if address came directly from json instead of having to lookup by name - addBlock(std::move(layoutBlock), name, Core()->num(name)); } - for (auto it = idMapping.begin(), end = idMapping.end(); it != end; ++it) { - if (blocks.find(it.value()) == blocks.end()) { - GraphLayout::GraphBlock block; - block.entry = it.value(); - addBlock(std::move(block), it.key(), Core()->num(it.key())); + + for (const auto &x : edges) { + if (blockContent.find(x) != blockContent.end()) { + continue; } + GraphLayout::GraphBlock block; + block.entry = x; + QString flagName = Core()->flagAt(x); + QString name = usenames + ? (!flagName.isEmpty() ? flagName : QString("unk.%0").arg(RzAddressString(x))) + : RzAddressString(x); + addBlock(std::move(block), name, x); } if (blockContent.empty() && !global) { - addBlock({}, RzAddressString(address), address); - } - - addressMapping.clear(); - for (auto &it : blockContent) { - addressMapping[it.second.address] = it.first; + const auto name = RzAddressString(address); + addBlock({}, name, address); } computeGraphPlacement(); diff --git a/src/widgets/CallGraph.h b/src/widgets/CallGraph.h index 8085fdcf..2d348266 100644 --- a/src/widgets/CallGraph.h +++ b/src/widgets/CallGraph.h @@ -22,7 +22,6 @@ public: protected: bool global; ///< is this a global or function callgraph RVA address = RVA_INVALID; ///< function address if this is not a global callgraph - std::unordered_map addressMapping; ///< mapping from addresses to block id void loadCurrentGraph() override; void restoreCurrentBlock() override;