From c1c1be2d2cf6592ffe9a152679e59f45bed684f1 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 29 Feb 2020 11:22:26 +0100 Subject: [PATCH] support for mova, and more responsible OS creation --- fxos/disassembly.cpp | 6 +++++- include/fxos/disasm-passes/print.h | 3 +++ include/fxos/disassembly.h | 10 ++++++++-- include/fxos/lang.h | 4 +++- lib/disassembly.cpp | 12 ++++++----- lib/lang.cpp | 10 ++++++++++ lib/library.cpp | 32 ++++++++++-------------------- lib/load-asm.l | 4 ++++ lib/passes/cfg.cpp | 2 +- lib/passes/pcrel.cpp | 15 +++++++++++++- lib/passes/print.cpp | 20 +++++++++++++++++-- lib/passes/syscall.cpp | 2 +- 12 files changed, 85 insertions(+), 35 deletions(-) diff --git a/fxos/disassembly.cpp b/fxos/disassembly.cpp index 7713976..5d356b6 100644 --- a/fxos/disassembly.cpp +++ b/fxos/disassembly.cpp @@ -22,7 +22,10 @@ int disassembly(Library &library, Target &target, char const *ref, /* Observe the target only if it has an OS mapped */ std::unique_ptr os; - if(target.covers(MemoryRegion::ROM)) os = std::make_unique(target); + try { + os = std::make_unique(target); + } + catch(std::exception &) {} /* Parameters inside the ref */ uint32_t address = -1; @@ -142,6 +145,7 @@ int disassembly(Library &library, Target &target, char const *ref, p.promote_syscall = PrintPass::Promote; p.promote_syscallname = PrintPass::Append; p.promote_symbol = PrintPass::Append; + p.promote_pcaddr_loc = PrintPass::Promote; p.run(); } diff --git a/include/fxos/disasm-passes/print.h b/include/fxos/disasm-passes/print.h index cc93912..ab10be9 100644 --- a/include/fxos/disasm-passes/print.h +++ b/include/fxos/disasm-passes/print.h @@ -49,6 +49,8 @@ public: int promote_syscallname; /* Promote an integer to a symbol */ int promote_symbol; + /* In a mova, promote "pc+" to the computed address */ + int promote_pcaddr_loc; /* TODO: More print pass parameters */ @@ -73,6 +75,7 @@ private: void syscall(ConcreteInstructionArg const &); void syscallname(ConcreteInstructionArg const &); void symbol(ConcreteInstructionArg const &); + void pcaddrloc(ConcreteInstructionArg const &); }; } /* namespace FxOS */ diff --git a/include/fxos/disassembly.h b/include/fxos/disassembly.h index 0cb681d..1b2ca2b 100644 --- a/include/fxos/disassembly.h +++ b/include/fxos/disassembly.h @@ -113,6 +113,9 @@ public: return m_target; } + /* List of passes that have run so far */ + std::set passes; + private: /* Underlying target */ Target &m_target; @@ -127,7 +130,7 @@ private: class DisassemblyPass { public: - DisassemblyPass(Disassembly &disasm); + DisassemblyPass(Disassembly &disasm, std::string name=""); /* Analyze a single instruction, probably updating the annotations and the state of the pass itself. */ @@ -156,13 +159,16 @@ private: /* Visited blocks */ std::set m_seen; + + /* Name of pass */ + std::string m_name; }; /* A disassembly pass that observes each instruction independently */ class InstructionDisassemblyPass: public DisassemblyPass { public: - InstructionDisassemblyPass(Disassembly &disasm); + InstructionDisassemblyPass(Disassembly &disasm, std::string name=""); /* Runs the pass from the first instruction currently loaded, all the way down to the bottom, as if always using enqueue_next(). */ diff --git a/include/fxos/lang.h b/include/fxos/lang.h index ebbd353..c95403f 100644 --- a/include/fxos/lang.h +++ b/include/fxos/lang.h @@ -70,6 +70,7 @@ struct Argument ArrayDeref, /* @(r0,rn) or @(r0,gbr) */ PcRel, /* @(disp,pc) with 4-alignment correction */ PcJump, /* pc+disp */ + PcAddr, /* pc+disp with special delayed slot semantics */ Imm, /* #imm */ }; @@ -84,7 +85,7 @@ struct Argument CpuRegister base; /* Index register. Valid for ArrayDeref */ CpuRegister index; - /* Displacement in bytes. Valid for StructDeref, PcRel and PcJump */ + /* Displacement in bytes. For StructDeref, PcRel, PcJump, and PcAddr */ int disp; /* Operation size. Generally a multiplier for disp */ int opsize; @@ -102,6 +103,7 @@ Argument Argument_StructDeref(int disp, int opsize, CpuRegister base); Argument Argument_ArrayDeref(CpuRegister index, CpuRegister base); Argument Argument_PcRel(int disp, int opsize); Argument Argument_PcJump(int disp); +Argument Argument_PcAddr(int disp); Argument Argument_Imm(int imm); /* Assembler instruction */ diff --git a/lib/disassembly.cpp b/lib/disassembly.cpp index 380cf53..601ec24 100644 --- a/lib/disassembly.cpp +++ b/lib/disassembly.cpp @@ -45,7 +45,7 @@ ConcreteInstruction::ConcreteInstruction(Instruction const &inst): //--- Disassembly::Disassembly(Target &target): - m_target {target}, m_instructions {} + passes {}, m_target {target}, m_instructions {} { } @@ -106,8 +106,8 @@ ConcreteInstruction &Disassembly::readins(uint32_t pc) // Base pass //--- -DisassemblyPass::DisassemblyPass(Disassembly &disasm): - m_disasm(disasm) +DisassemblyPass::DisassemblyPass(Disassembly &disasm, std::string name): + m_disasm(disasm), m_name(name) { } @@ -171,14 +171,16 @@ void DisassemblyPass::run(uint32_t entry_pc) m_seen.insert(pc); } + + if(m_name != "") m_disasm.passes.insert(m_name); } //--- // Base instruction-level pass //--- -InstructionDisassemblyPass::InstructionDisassemblyPass(Disassembly &disasm): - DisassemblyPass(disasm) +InstructionDisassemblyPass::InstructionDisassemblyPass(Disassembly &disasm, + std::string name): DisassemblyPass(disasm, name) { } diff --git a/lib/lang.cpp b/lib/lang.cpp index f57d1d2..22f2425 100644 --- a/lib/lang.cpp +++ b/lib/lang.cpp @@ -142,6 +142,14 @@ Argument Argument_PcJump(int disp) return arg; } +Argument Argument_PcAddr(int disp) +{ + Argument arg; + arg.kind = Argument::PcAddr; + arg.disp = disp; + return arg; +} + Argument Argument_Imm(int imm) { Argument arg; @@ -172,6 +180,8 @@ std::string Argument::str() const return format("@(%d,pc)", disp); case Argument::PcJump: return format("pc+%d", disp); + case Argument::PcAddr: + return format("pc+%u", disp); case Argument::Imm: return format("#%d", imm); default: diff --git a/lib/library.cpp b/lib/library.cpp index ed42dd7..b121255 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -27,7 +27,12 @@ void Library::explore(std::string path) fs::recursive_directory_iterator it(path); for(auto &file: it) { - if(!fs::is_directory(file)) load(file.path()); + if(!fs::is_directory(file)) try { + load(file.path()); + } + catch(FxOS::SyntaxError &e) { + log(ERR "%s", e.str()); + } } } catch(fs::filesystem_error &e) @@ -63,13 +68,8 @@ void Library::load(std::string path) if(type == "assembly") { - try { - int total = load_asm(file, offset, line); - m_asmtables.push_back(std::make_pair(h["name"],total)); - } - catch(FxOS::SyntaxError &e) { - log(ERR "%s", e.str()); - } + int total = load_asm(file, offset, line); + m_asmtables.push_back(std::make_pair(h["name"],total)); } else if(type == "target") { @@ -79,22 +79,12 @@ void Library::load(std::string path) return; } - try { - m_targets[h["name"]] = load_target(file, offset, line); - } - catch(FxOS::SyntaxError &e) { - log(ERR "%s", e.str()); - } + m_targets[h["name"]] = load_target(file, offset, line); } else if(type == "symbols") { - try { - SymbolTable st = load_symbols(file, offset, line); - m_symtables.push_back(st); - } - catch(FxOS::SyntaxError &e) { - log(ERR "%s", e.str()); - } + SymbolTable st = load_symbols(file, offset, line); + m_symtables.push_back(st); } else { diff --git a/lib/load-asm.l b/lib/load-asm.l index 8fef585..8ac1af7 100644 --- a/lib/load-asm.l +++ b/lib/load-asm.l @@ -22,6 +22,8 @@ enum Token { SR, PR, GBR, VBR, DBR, SSR, SPC, SGR, MACH, MACL, /* PC-relative jumps and displacements (with 4-alignment correction) */ JUMP8, JUMP12, AT_DPC, + /* PC-relative address access (without memory access) */ + DPC, /* Immediate operands */ IMM, /* Memory access with post-increment and pre-decrement */ @@ -83,6 +85,7 @@ space [ \t]+ "rm" { return RM; } "jump8" { return JUMP8; } "jump12" { return JUMP12; } +"pc+disp" { return DPC; } "@(disp,"[ ]*"pc)" { return AT_DPC; } "@rn" { return AT_RN; } "@rm" { return AT_RM; } @@ -208,6 +211,7 @@ static Argument make_arg(int token, int opsize, int m, int n, int d, int i) case MACL: return Argument_Reg(Reg::MACL); case JUMP8: return Argument_PcJump(d8 * 2); case JUMP12: return Argument_PcJump(d12 * 2); + case DPC: return Argument_PcAddr(d * 4); case IMM: return Argument_Imm(i8); case AT_RN: return Argument_Deref(Rn); case AT_RM: return Argument_Deref(Rm); diff --git a/lib/passes/cfg.cpp b/lib/passes/cfg.cpp index 2cfbafb..ff04af4 100644 --- a/lib/passes/cfg.cpp +++ b/lib/passes/cfg.cpp @@ -13,7 +13,7 @@ using namespace FxOS::Log; namespace FxOS { CfgPass::CfgPass(Disassembly &disasm): - DisassemblyPass(disasm) + DisassemblyPass(disasm, "cfg") { } diff --git a/lib/passes/pcrel.cpp b/lib/passes/pcrel.cpp index 3dad01f..4846c07 100644 --- a/lib/passes/pcrel.cpp +++ b/lib/passes/pcrel.cpp @@ -7,7 +7,7 @@ namespace FxOS { PcrelPass::PcrelPass(Disassembly &disasm): - InstructionDisassemblyPass(disasm) + InstructionDisassemblyPass(disasm, "pcrel") { } @@ -45,6 +45,19 @@ void PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci) ca.value = DataValue(IntegerType::u32); ca.value.write(0, 4, addr); } + else if(a.kind == Argument::PcAddr + && m_disasm.passes.count("cfg")) + { + uint32_t addr = (pc & ~3) + 4 + a.disp; + + /* SH3 manual says that the semantics of mova change in + a delay slot. GNU as: "yeah but sorry they don't" */ +// if(ci.delayslot) addr = (ci.jmptarget&~3) + 4 + a.disp; + + ca.location = RelConstDomain().constant(addr); + ca.value = DataValue(IntegerType::u32); + ca.value.write(0, 4, addr); + } } } diff --git a/lib/passes/print.cpp b/lib/passes/print.cpp index f484524..c91e2a4 100644 --- a/lib/passes/print.cpp +++ b/lib/passes/print.cpp @@ -11,14 +11,16 @@ namespace FxOS { PrintPass::PrintPass(Disassembly &disasm, std::vector const &symtables): - InstructionDisassemblyPass(disasm), m_symtables(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(); - if(t.covers(MemoryRegion::ROM)) + try { m_os = std::make_unique(t); + } + catch(std::exception &) {} } void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci) @@ -70,6 +72,12 @@ void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci) pcrelloc(arg); queue_flush(); } + else if(a.kind == Argument::PcAddr) + { + queue(a.str()); + pcaddrloc(arg); + queue_flush(); + } else { queue(a.str()); @@ -173,4 +181,12 @@ void PrintPass::symbol(ConcreteInstructionArg const &arg) 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 */ diff --git a/lib/passes/syscall.cpp b/lib/passes/syscall.cpp index d033c9c..f81e4b9 100644 --- a/lib/passes/syscall.cpp +++ b/lib/passes/syscall.cpp @@ -7,7 +7,7 @@ namespace FxOS { SyscallPass::SyscallPass(Disassembly &disasm, OS *os): - InstructionDisassemblyPass(disasm), m_os(os) + InstructionDisassemblyPass(disasm, "syscall"), m_os(os) { }