about summary refs log tree commit diff
path: root/helpers.cc
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-10-14 17:57:29 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-10-15 02:03:06 +0900
commit5562397b73d4cde06e773f00485e16406853e1fd (patch)
tree4865b7ce60e93188f69fd72482e3c079546f25b0 /helpers.cc
parent85ea96211914b97c8ef8735a61c68489e0d010ce (diff)
downloadtaosc-5562397b73d4cde06e773f00485e16406853e1fd.tar.gz
Rework patch action searching
Diffstat (limited to 'helpers.cc')
-rw-r--r--helpers.cc89
1 files changed, 89 insertions, 0 deletions
diff --git a/helpers.cc b/helpers.cc
new file mode 100644
index 0000000..c02957e
--- /dev/null
+++ b/helpers.cc
@@ -0,0 +1,89 @@
+// 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 <https://www.gnu.org/licenses/>.
+
+// Dyninst headers
+#include <CFG.h>
+#include <CodeObject.h>
+
+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 <cassert>
+#include <cstdlib>
+#include <filesystem>
+#include <iostream>
+#include <set>
+#include <string>
+#include <utility>
+
+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
+die_for (Address address, std::string const& message)
+{
+  std::cerr << message << ' ' << std::hex << address << '\n';
+  std::exit (1);
+}
+
+/// Find next basic block's entry after given address, reparsing if necessary
+static Block*
+next_block (CodeObject& co, CodeRegion* region, Address address)
+{
+  auto* blk = co.findBlockByEntry (region, address);
+  if (blk != nullptr)
+    return blk;
+  co.parse (address, true);
+  blk = co.findBlockByEntry (region, address);
+  return (blk != nullptr) ? blk : co.findNextBlock (region, address);
+}
+
+Block*
+find_block (CodeSource& cs, CodeObject& co, Address address)
+{
+  if (!cs.isCode (address))
+    die_for (address, "no instruction at");
+  std::set <CodeRegion*> regions;
+  if (cs.findRegions (address, regions) != 1)
+    die_for (address, "not exactly 1 region found for instruction at");
+  for (auto* region : regions)
+    {
+      std::set <Block*> blocks;
+      if (co.findBlocks (region, address, blocks) > 0)
+        for (auto* blk : blocks) // TODO: choose the best block
+          return blk;
+      auto* blk = next_block (co, region, region->low ());
+      while (blk != nullptr && address > blk->last ())
+        blk = next_block (co, region, blk->end ());
+      if (blk == nullptr)
+        die_for (address, "no block found for instruction at");
+      assert (address >= blk->start () && address < blk->end ());
+      return blk;
+    }
+  std::unreachable ();
+}