about summary refs log tree commit diff
path: root/trace-call.cc
blob: 2b374cc46d84e5ce7019dff18b496348a4edb4c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 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 <https://www.gnu.org/licenses/>.

#include "helpers.hh"

// Dyninst headers
#include <CFG.h>
#include <CodeObject.h>

#include <cassert>
#include <iostream>
#include <vector>

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 <Dyninst::ParseAPI::Function*> 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)
        warn (return_address, "no call found for return address");
    }
  if (std::cin.eof ())
    return 0;
  std::cerr << "invalid input\n";
  return -1;
}