// 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;
}