#include "fxos-cli.h" #include #include #include #include #include #include #include #include #include #include using namespace FxOS; using namespace FxOS::Log; int disassembly(Library &library, Target &target, char const *ref, std::vector passes) { Disassembly disasm(target); int len=0; /* Observe the target only if it has an OS mapped */ std::unique_ptr os; if(target.covers(MemoryRegion::ROM)) os = std::make_unique(target); /* Parameters inside the ref */ uint32_t address = -1; uint32_t blocklen; int syscall_id; char blockmul[2] = { 0 }; enum { RefNone=0, RefSyscall, RefAddress, RefBlock } reftype = RefNone; /* Parse different flavors of references. %: syscall */ if(sscanf(ref, "%%%x", &syscall_id) == 1) reftype = RefSyscall; /* Pure hexa: address */ else if(sscanf(ref, "%x%n", &address, &len) == 1 && !ref[len]) reftype = RefAddress; /* Hexa with a size: a block */ else if(sscanf(ref,"%x:%x%n",&address,&blocklen,&len)==2 && !ref[len]) reftype = RefBlock; /* Variant of block size that includes a letter k/M/G (note that the "%[]" specifier never matches empty strings */ else if(sscanf(ref, "%x:%x%1[kMG]%n", &address, &blocklen, blockmul, &len) == 3 && !ref[len]) { reftype = RefBlock; int mul = blockmul[0]; if(mul == 'k') blocklen <<= 10; if(mul == 'M') blocklen <<= 20; if(mul == 'G') blocklen <<= 30; } /* Anything else: look up symbols */ else { std::string name = ref; for(auto const &symtable: library.sym_tables()) { std::optional sym = symtable.lookup(name); if(!sym) continue; if(sym->type == Symbol::Syscall) reftype = RefSyscall, syscall_id = sym->value; if(sym->type == Symbol::Address) reftype = RefAddress, address = sym->value; break; } } /* Now try to load the address for this reference */ if(reftype == RefSyscall) { if(!os) { log(ERR "cannot disassemble syscall %s: target does " "not have an OS mapped", ref); return 1; } if(syscall_id >= os->syscall_count()) { log(ERR "this OS only has %#x syscalls", os->syscall_count()); return 1; } address = os->syscall(syscall_id); } if(reftype == RefAddress || reftype == RefBlock) { if(address & 1) { log(WRN "address %08x is odd, will start at %08x", address, address+1); address++; } } if(reftype == RefBlock) { /* Load the block into memory */ for(uint32_t pc = address; pc < address + blocklen; pc += 2) { disasm.readins(pc); } } if(reftype == RefNone) { log(ERR "cannot interpret '%s' (not a syscall id, not an " "address, and no such symbol in library)", ref); return 1; } for(auto pass: passes) { auto start = timer_start(); log(LOG "Running pass %s...\\", pass); if(pass == "cfg" && reftype != RefBlock) { CfgPass p(disasm); p.run(address); } else if(pass == "pcrel") { PcrelPass p(disasm); p.run(); } else if(pass == "syscall") { SyscallPass p(disasm, os.get()); p.run(); } else if(pass == "print") { PrintPass p(disasm, library.sym_tables()); p.promote_pcjump_loc = PrintPass::Promote; p.promote_pcrel_loc = PrintPass::Promote; p.promote_pcrel_value = PrintPass::Promote; p.promote_syscall = PrintPass::Promote; p.promote_syscallname = PrintPass::Append; p.promote_symbol = PrintPass::Append; p.run(); } log(LOG "%s", timer_format(timer_end(start))); } return 0; }