//---------------------------------------------------------------------------// // 1100101 |_ mov #0, r4 __ // // 11 |_ <0xb380 %5c4> / _|_ _____ ___ // // 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // // |_ base# + offset |_| /_\_\___/__/ // //---------------------------------------------------------------------------// #include #include #include #include #include namespace FxOS { PrintPass::PrintPass(Disassembly &disasm): InstructionPass(disasm), m_symtables {}, m_last_address {0xffffffff} { /* Default parameters: all 0 */ /* Use an OS observer to describe syscalls in header lines */ m_os = disasm.vspace.os_analysis(); /* Use the symbol tables from the virtual space */ m_symtables.push_back(disasm.vspace.symbols); } bool PrintPass::analyzeInstruction(uint32_t pc, Instruction &i) { /* Ellipsis if there is a gap since last instruction */ if(m_last_address + 1 != 0 && pc != m_last_address + 2) printf(" ...\n"); /* 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"); } /* Raw data if instruction cannot be decoded */ printf(" %08x: %04x", pc, (i.inst ? i.inst->opcode : i.opcode)); if(!i.inst) { printf("\n"); m_last_address = pc; return true; } /* Mnemonic */ static char const *suffixes[5] = {"", ".b", ".w", "", ".l"}; char const *suffix = suffixes[(i.inst->opsize <= 4) ? i.inst->opsize : 0]; int spacing = i.inst->arg_count ? 8 - strlen(i.inst->mnemonic) - strlen(suffix) : 0; printf(" %s%s%*s", i.inst->mnemonic, suffix, spacing, ""); /* Arguments */ for(size_t n = 0; n < i.inst->arg_count; n++) { AsmArgument const &arg = i.inst->args[n]; Argument const &a = i.args[n]; if(n) printf(", "); queue(arg.str()); if(arg.kind == AsmArgument::PcJump) pcjumploc(a); else if(arg.kind == AsmArgument::PcRel) pcrelloc(a); else if(arg.kind == AsmArgument::PcAddr) pcaddrloc(a); queue_flush(); } printf("\n"); m_last_address = pc; return true; } std::optional PrintPass::symquery( Symbol::Type type, uint32_t value) { for(int i = m_symtables.size() - 1; i >= 0; i--) { SymbolTable const &st = m_symtables[i]; auto maybe_str = st.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(Argument const &a) { if(!RelConstDomain().is_constant(a.location)) return; if(promote_pcjump_loc == Never) return; queue(format("<%s>", a.location.str()), promote_pcjump_loc == Promote); syscall(a); } void PrintPass::pcrelloc(Argument const &a) { if(!RelConstDomain().is_constant(a.location)) return; if(promote_pcrel_loc == Never) return; queue(format("<%s>", a.location.str()), promote_pcrel_loc == Promote); pcrelval(a); } void PrintPass::pcrelval(Argument const &a) { if(!a.value) return; if(promote_pcrel_value == Never) return; queue(a.value.str(), promote_pcrel_value == Promote); syscall(a); } void PrintPass::syscall(Argument const &a) { if(!a.value) return; /* If this is not a syscall, try to display as a symbol instead */ if(promote_syscall == Never || a.syscall_id < 0) { symbol(a); return; } queue(format("%%%03x", a.syscall_id), promote_syscall == Promote); syscallname(a); } void PrintPass::syscallname(Argument const &a) { if(a.syscall_id < 0) return; auto maybe_name = symquery(Symbol::Syscall, a.syscall_id); if(!maybe_name) return; queue(*maybe_name, promote_syscallname == Promote); } void PrintPass::symbol(Argument const &a) { if(!a.value) return; auto maybe_name = symquery(Symbol::Address, RelConstDomain().constant_value(a.value)); if(!maybe_name) return; queue(*maybe_name, promote_symbol == Promote); } void PrintPass::pcaddrloc(Argument const &a) { if(!RelConstDomain().is_constant(a.location)) return; if(promote_pcaddr_loc == Never) return; queue(format("<%s>", a.location.str()), promote_pcaddr_loc == Promote); } } /* namespace FxOS */