| 259 | } |
| 260 | |
| 261 | IRProgram LifterRegistry::lift_program(const CFGBuilder& cfg) const { |
| 262 | IRProgram prog; |
| 263 | prog.arch = cfg.arch(); |
| 264 | prog.entry_va = cfg.base_va(); |
| 265 | |
| 266 | ZydisDecoder decoder{}; |
| 267 | const auto mm = (cfg.arch() == Arch::X64) ? ZYDIS_MACHINE_MODE_LONG_64 : ZYDIS_MACHINE_MODE_LEGACY_32; |
| 268 | const auto sw = (cfg.arch() == Arch::X64) ? ZYDIS_STACK_WIDTH_64 : ZYDIS_STACK_WIDTH_32; |
| 269 | if (ZYAN_FAILED(ZydisDecoderInit(&decoder, mm, sw))) { |
| 270 | throw Error("ZydisDecoderInit failed"); |
| 271 | } |
| 272 | |
| 273 | const auto code = cfg.code(); |
| 274 | const auto base = cfg.base_va(); |
| 275 | |
| 276 | // collect every unsupported mnemonic, then report them all after |
| 277 | // the full pass |
| 278 | std::set<std::string> unsupported_mnems; |
| 279 | |
| 280 | prog.blocks.reserve(cfg.blocks().size()); |
| 281 | const auto& cfg_blocks = cfg.blocks(); |
| 282 | for (std::size_t bi = 0; bi < cfg_blocks.size(); ++bi) { |
| 283 | const auto& cb = cfg_blocks[bi]; |
| 284 | IRBlock blk; |
| 285 | blk.id = static_cast<std::uint32_t>(prog.blocks.size()); |
| 286 | blk.start_va = cb.start_va; |
| 287 | prog.va_to_block.emplace_back(cb.start_va, blk.id); |
| 288 | |
| 289 | IRBuilder builder{blk}; |
| 290 | for (std::uint64_t va : cb.insn_vas) { |
| 291 | const std::size_t off = static_cast<std::size_t>(va - base); |
| 292 | const std::size_t avail = code.size - off; |
| 293 | |
| 294 | ZydisDecodedInstruction insn{}; |
| 295 | ZydisDecodedOperand ops[ZYDIS_MAX_OPERAND_COUNT]{}; |
| 296 | if (ZYAN_FAILED(ZydisDecoderDecodeFull( |
| 297 | &decoder, |
| 298 | code.data + off, |
| 299 | avail, |
| 300 | &insn, |
| 301 | ops |
| 302 | ))) { |
| 303 | throw Error("decoder failed mid-lift"); |
| 304 | } |
| 305 | |
| 306 | LiftContext ctx{ |
| 307 | cfg.arch(), |
| 308 | va, |
| 309 | va + insn.length, |
| 310 | insn, |
| 311 | ops, |
| 312 | cfg, |
| 313 | &prog, |
| 314 | }; |
| 315 | |
| 316 | const auto* lf = find(insn.mnemonic); |
| 317 | if (!lf) { |
| 318 | // record and skip so the rest of the lift can keep |