// Helper functions // Copyright (C) 2024-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 . // Dyninst headers #include #include using Address = Dyninst::Address; using Block = Dyninst::ParseAPI::Block; using CodeObject = Dyninst::ParseAPI::CodeObject; using CodeRegion = Dyninst::ParseAPI::CodeRegion; using CodeSource = Dyninst::ParseAPI::SymtabCodeSource; #include #include #include #include #include #include #include char const* parse_args (int argc, char const* const* argv) { if (argc == 2) return argv[1]; std::filesystem::path prog {argv[0]}; std::cerr << "Usage: " << prog.filename ().string () << " EXECUTABLE\n"; std::exit (1); } void warn (Address address, std::string const& message) { std::cerr << message << ' ' << std::hex << address << '\n'; } [[noreturn]] void die_for (Address address, std::string const& message) { warn (address, message); std::exit (1); } static CodeRegion* find_region (CodeSource& cs, Address address) { if (!cs.isCode (address)) die_for (address, "no instruction at"); std::set regions; if (cs.findRegions (address, regions) != 1) die_for (address, "not exactly one region found spanning"); for (auto* const cr : regions) return cr; std::unreachable (); } /// Find next basic block's entry after given address, reparsing if necessary static Block* next_block (CodeObject& co, CodeRegion* cr, Address address) { auto* blk = co.findBlockByEntry (cr, address); if (blk != nullptr) return blk; co.parse (address, true); blk = co.findBlockByEntry (cr, address); return (blk != nullptr) ? blk : co.findNextBlock (cr, address); } Block* find_block (CodeSource& cs, CodeObject& co, Address address) { auto* const cr = find_region (cs, address); std::set blocks; if (co.findBlocks (cr, address, blocks) > 0) { if (blocks.size () > 1) die_for (address, "more than one block found spanning"); for (auto* const blk : blocks) return blk; } auto* blk = next_block (co, cr, cr->low ()); while (blk != nullptr && address > blk->last ()) blk = next_block (co, cr, blk->end ()); if (blk == nullptr) die_for (address, "no block found spanning"); assert (address >= blk->start () && address < blk->end ()); return blk; }