// Phase-2 smoke driver for the Ghidra SSA lifter (fold::binary::liftFunctionToPcode). // Reads a raw function-bytes file and prints the lifted fold::ir::pcode ops. // // pcode_lift // #include #include #include #include #include #include #include #include "fold/binary/ghidra_lifter.hpp" namespace { const char* spaceName(fold::ir::pcode::Space s) { using S = fold::ir::pcode::Space; switch (s) { case S::Constant: return "const"; case S::Register: return "reg"; case S::Memory: return "ram"; case S::Unique: return "uniq"; case S::StackBase: return "stack"; case S::Other: return "other"; } return "?"; } void printVn(const fold::ir::pcode::Varnode& v) { std::cout << '(' << spaceName(v.space) << ",0x" << std::hex << v.offset << std::dec << ',' << v.size << ')'; } } // namespace void dump(const fold::binary::LiftRequest& req, const fold::ir::pcode::Function& fn, const char* level) { std::cout << "=== " << level << ": '" << fn.name << "' @ 0x" << std::hex << fn.entry << std::dec << " — " << fn.ops.size() << " ops ===\n"; for (const auto& op : fn.ops) { std::cout << " 0x" << std::hex << op.address << std::dec << " "; if (op.out) { printVn(*op.out); std::cout << " = "; } std::cout << fold::ir::pcode::opName(op.op); for (const auto& in : op.in) { std::cout << ' '; printVn(in); } if (!op.in_buffer_sizes.empty()) { std::cout << " bufsizes["; for (std::size_t i = 0; i < op.in_buffer_sizes.size(); ++i) std::cout << (i ? "," : "") << op.in_buffer_sizes[i]; std::cout << ']'; } if (!op.in_buffer_offsets.empty()) { std::cout << " bufoffs["; for (std::size_t i = 0; i < op.in_buffer_offsets.size(); ++i) std::cout << (i ? "," : "") << op.in_buffer_offsets[i]; std::cout << ']'; } std::cout << '\n'; } } int main(int argc, char** argv) { if (argc != 6) { std::cerr << "usage: " << argv[0] << " \n"; return 2; } const std::string specs_dir = argv[1]; const std::string sla_path = argv[2]; fold::binary::LiftRequest req; req.language_id = argv[3]; req.base = std::strtoull(argv[4], nullptr, 16); req.name = "smoke"; std::ifstream bf(argv[5], std::ios::binary); if (!bf) { std::cerr << "cannot open bytes file: " << argv[5] << '\n'; return 2; } const std::vector raw((std::istreambuf_iterator(bf)), std::istreambuf_iterator()); req.bytes.assign(raw.begin(), raw.end()); // Optional sink prototypes for SSA arg recovery, e.g. // FOLD_SINK_TARGETS="0x5fc=gets,0x620=strcpy" if (const char* env = std::getenv("FOLD_SINK_TARGETS")) { std::string s(env); std::size_t pos = 0; while (pos < s.size()) { const std::size_t comma = s.find(',', pos); const std::string tok = s.substr(pos, comma == std::string::npos ? comma : comma - pos); const std::size_t eq = tok.find('='); if (eq != std::string::npos) req.sink_targets.emplace_back(std::strtoull(tok.c_str(), nullptr, 16), tok.substr(eq + 1)); if (comma == std::string::npos) break; pos = comma + 1; } } std::string err_raw; if (auto fn = fold::binary::liftRaw(req, sla_path, &err_raw)) dump(req, *fn, "RAW"); else std::cerr << "raw lift failed: " << err_raw << '\n'; std::string err_ssa; if (auto fn = fold::binary::liftSSA(req, specs_dir, &err_ssa)) dump(req, *fn, "SSA"); else std::cerr << "ssa lift failed: " << err_ssa << '\n'; return 0; }