//--- // fxos.passes.print: Print disassembly //--- #include #include #include namespace FxOS { PrintPass::PrintPass(Disassembly &disasm, std::vector const &symtables): InstructionDisassemblyPass(disasm, "print"), m_symtables(symtables) { /* Default parameters: all 0 */ /* Use an OS observer to describe syscalls in header lines */ Target &t = disasm.target(); try { m_os = std::make_unique(t); } catch(std::exception &) {} } void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci) { Instruction const &i = ci.inst; /* Preliminary syscall number */ int syscall_id; if(m_os && (syscall_id = m_os->find_syscall(pc)) >= 0) { printf("\n<%%%03x", syscall_id); auto maybe_str = symquery(Symbol::Syscall, syscall_id); if(maybe_str) printf(" %s", (*maybe_str).c_str()); printf(">\n"); } /* Mnemonic */ static std::map suffixes = { { 1, ".b" }, { 2, ".w" }, { 4, ".l" } }; std::string mnemonic = i.mnemonic + suffixes[i.opsize]; if(i.args.size()) mnemonic += std::string(8 - mnemonic.size(), ' '); printf(" %08x: %04x %s", pc, ci.inst.opcode, mnemonic.c_str()); /* Arguments */ for(size_t n = 0; n < i.args.size(); n++) { Argument const &a = i.args[n]; ConcreteInstructionArg const &arg = ci.args[n]; if(n) printf(", "); if(a.kind == Argument::PcJump) { queue(a.str()); pcjumploc(arg); queue_flush(); } else if(a.kind == Argument::PcRel) { queue(a.str()); pcrelloc(arg); queue_flush(); } else if(a.kind == Argument::PcAddr) { queue(a.str()); pcaddrloc(arg); queue_flush(); } else { queue(a.str()); queue_flush(); } } printf("\n"); } std::optional PrintPass::symquery(Symbol::Type type, uint32_t value) { for(int i = m_symtables.size() - 1; i >= 0; i--) { auto maybe_str = m_symtables[i].query(type, value); if(maybe_str) return maybe_str; } return std::nullopt; } void PrintPass::queue(std::string str, bool override) { if(override && m_messages.size()) m_messages.pop_back(); m_messages.push_back(str); } void PrintPass::queue_flush() { for(size_t i = 0; i < m_messages.size(); i++) { if(i != 0) printf(" "); printf("%s", m_messages[i].c_str()); } m_messages.clear(); } void PrintPass::pcjumploc(ConcreteInstructionArg const &arg) { if(!RelConstDomain().is_constant(arg.location)) return; if(promote_pcjump_loc == Never) return; queue(format("<%s>", arg.location.str()), promote_pcjump_loc==Promote); syscall(arg); } void PrintPass::pcrelloc(ConcreteInstructionArg const &arg) { if(!RelConstDomain().is_constant(arg.location)) return; if(promote_pcrel_loc == Never) return; queue(format("<%s>", arg.location.str()), promote_pcrel_loc==Promote); pcrelval(arg); } void PrintPass::pcrelval(ConcreteInstructionArg const &arg) { if(!arg.value || arg.value.type->kind() != DataType::Integer) return; if(promote_pcrel_value == Never) return; queue(arg.value.str(), promote_pcrel_value==Promote); syscall(arg); } void PrintPass::syscall(ConcreteInstructionArg const &arg) { if(!arg.value || arg.value.type->kind() != DataType::Integer) return; /* If this is not a syscall, try to display as a symbol instead */ if(promote_syscall == Never || arg.syscall_id < 0) { symbol(arg); return; } queue(format("%%%03x", arg.syscall_id), promote_syscall==Promote); syscallname(arg); } void PrintPass::syscallname(ConcreteInstructionArg const &arg) { if(arg.syscall_id < 0) return; auto maybe_name = symquery(Symbol::Syscall, arg.syscall_id); if(!maybe_name) return; queue(*maybe_name, promote_syscallname==Promote); } void PrintPass::symbol(ConcreteInstructionArg const &arg) { if(!arg.value || arg.value.type->kind() != DataType::Integer) return; auto maybe_name = symquery(Symbol::Address, arg.value.uinteger()); if(!maybe_name) return; queue(*maybe_name, promote_symbol==Promote); } void PrintPass::pcaddrloc(ConcreteInstructionArg const &arg) { if(!RelConstDomain().is_constant(arg.location)) return; if(promote_pcaddr_loc == Never) return; queue(format("<%s>", arg.location.str()), promote_pcaddr_loc==Promote); } } /* namespace FxOS */