// Utility for finding call instruction coresponding to return address // Copyright (C) 2025 Nguyễn Gia Phong // // This file is part of taosc. // // Taosc is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Taosc is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with taosc. If not, see . #include "helpers.hh" // Dyninst headers #include #include #include #include #include int main (int argc, char** argv) { Dyninst::ParseAPI::SymtabCodeSource cs {parse_args (argc, argv)}; Dyninst::ParseAPI::CodeObject co {&cs}; co.parse (); // parsed functions have same lifetime as co while (!std::cin.eof ()) { Dyninst::Address return_address; std::cin >> std::hex >> return_address; if (std::cin.fail ()) break; auto* const block = find_block (cs, co, return_address); // Each function call creates an interprocedure edge, // hence its basic block ends with the call site. // The control flow then naturally goes to the next basic block // starting with the return address. if (block->start () != return_address) die_for (return_address, "no block found with start address"); if (block->containingFuncs () < 1) die_for (return_address, "no function containing return address"); std::vector functions; block->getFuncs (functions); Dyninst::Address call_address = 0; for (auto* const fun : functions) for (auto* const call_edge : fun->callEdges ()) { auto* const call_block = call_edge->src (); auto* const return_block = fun->getImmediatePostDominator (call_block); if (return_block == nullptr || *return_block != *block) continue; if (call_address != 0) { assert (call_block->last () == call_address); continue; // break if not for the assertion } call_address = call_block->last (); std::cout << std::hex << call_address << '\n'; } if (call_address == 0) die_for (return_address, "no call found for return address"); } if (std::cin.eof ()) return 0; std::cerr << "invalid input\n"; return -1; }