From d7b3fd0de87144a695225c614531afe9e913f650 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Tue, 5 Apr 2022 11:02:56 +0100 Subject: [PATCH] add infrastructure for function passes Ported existing passes to the new pass interface, now working properly. --- include/fxos/disassembly.h | 6 ++++++ include/fxos/passes/cfg.h | 8 ++++---- include/fxos/passes/pcrel.h | 4 ++-- include/fxos/passes/print.h | 4 ++-- include/fxos/passes/syscall.h | 4 ++-- include/fxos/util/Queue.h | 2 +- lib/disassembly.cpp | 33 ++++++++++++++++++++++++--------- lib/passes/cfg.cpp | 6 +++--- lib/passes/pcrel.cpp | 4 ++-- lib/passes/print.cpp | 5 ++--- lib/passes/syscall.cpp | 4 ++-- shell/a.cpp | 6 +++--- shell/d.cpp | 8 ++++---- 13 files changed, 57 insertions(+), 37 deletions(-) diff --git a/include/fxos/disassembly.h b/include/fxos/disassembly.h index 83f5d7f..c505dcd 100644 --- a/include/fxos/disassembly.h +++ b/include/fxos/disassembly.h @@ -187,6 +187,11 @@ class InstructionPass: public DisassemblyPass public: InstructionPass(Disassembly &disasm); + /* If set, this pass loads instructions from the disassembly automatically. + This is useful for passes that explore new functions. By default, + queueing new instructions is not allowed to avoid bugs. */ + void setAllowDiscovery(bool allowDiscovery); + /* Analyze the whole disassembly in increasing address order */ bool analyzeAllInstructions(); @@ -203,6 +208,7 @@ public: private: Queue m_queue; + bool m_allowDiscovery; }; } /* namespace FxOS */ diff --git a/include/fxos/passes/cfg.h b/include/fxos/passes/cfg.h index 3202397..a77cf92 100644 --- a/include/fxos/passes/cfg.h +++ b/include/fxos/passes/cfg.h @@ -24,11 +24,11 @@ // the CPU will run [mov #1, r4] while performing the branch to pc+120 in order // to fill an otherwise-unfillable pipeline cycle. This is annoying for all // kinds of reasons, and fxos handles this by acting as if the mov itself had -// pc+120 as an uncondition successor. +// pc+120 as an unconditional successor. // // This could be tricky for the abstract interpreter because the jump target // has to be computed using the state at the jump instruction, not the one at -// the delay slot. Luckily all delayed jumps are no-ops in termsof state, so +// the delay slot. Luckily all delayed jumps are no-ops in terms of state, so // the confusion has no effect. // // Note that jumping into a delay slot will activate the jump in fxos, which is @@ -48,11 +48,11 @@ namespace FxOS { -class CfgPass: public DisassemblyPass +class CfgPass: public InstructionPass { public: CfgPass(Disassembly &disasm); - bool analyze(uint32_t pc, Instruction &inst) override; + bool analyzeInstruction(uint32_t pc, Instruction &inst) override; }; } /* namespace FxOS */ diff --git a/include/fxos/passes/pcrel.h b/include/fxos/passes/pcrel.h index 8137987..f02d014 100644 --- a/include/fxos/passes/pcrel.h +++ b/include/fxos/passes/pcrel.h @@ -24,11 +24,11 @@ namespace FxOS { -class PcrelPass: public InstructionDisassemblyPass +class PcrelPass: public InstructionPass { public: PcrelPass(Disassembly &disasm); - bool analyze(uint32_t pc, Instruction &inst) override; + bool analyzeInstruction(uint32_t pc, Instruction &inst) override; }; } /* namespace FxOS */ diff --git a/include/fxos/passes/print.h b/include/fxos/passes/print.h index 939468b..47a65a2 100644 --- a/include/fxos/passes/print.h +++ b/include/fxos/passes/print.h @@ -44,11 +44,11 @@ namespace FxOS { class OS; -class PrintPass: public InstructionDisassemblyPass +class PrintPass: public InstructionPass { public: PrintPass(Disassembly &disasm); - bool analyze(uint32_t pc, Instruction &inst) override; + bool analyzeInstruction(uint32_t pc, Instruction &inst) override; //--- // Print pass parameters diff --git a/include/fxos/passes/syscall.h b/include/fxos/passes/syscall.h index e7fcddf..17d5cca 100644 --- a/include/fxos/passes/syscall.h +++ b/include/fxos/passes/syscall.h @@ -19,11 +19,11 @@ namespace FxOS { -class SyscallPass: public InstructionDisassemblyPass +class SyscallPass: public InstructionPass { public: SyscallPass(Disassembly &disasm, OS *os); - bool analyze(uint32_t pc, Instruction &inst) override; + bool analyzeInstruction(uint32_t pc, Instruction &inst) override; private: OS *m_os; diff --git a/include/fxos/util/Queue.h b/include/fxos/util/Queue.h index bf0088f..a69ff3b 100644 --- a/include/fxos/util/Queue.h +++ b/include/fxos/util/Queue.h @@ -16,7 +16,7 @@ template struct Queue { - Queue(); + Queue(): pending {}, seen {} {} bool empty() const { return pending.empty(); diff --git a/lib/disassembly.cpp b/lib/disassembly.cpp index a807894..7e13555 100644 --- a/lib/disassembly.cpp +++ b/lib/disassembly.cpp @@ -163,8 +163,9 @@ bool FunctionPass::analyzeFunctionRecursively(uint32_t pc) while(!m_queue.empty()) { uint32_t pc = m_queue.pop(); Function *next = m_disasm.getFunctionAt(pc); - ok &= this->analyzeFunction(*next); - this->enqueueSubfunctions(*next); + if(this->analyzeFunction(*next)) + this->enqueueSubfunctions(*next); + else ok = false; } return ok; @@ -187,10 +188,15 @@ void FunctionPass::updateSubfunctions(Function &func) //--- InstructionPass::InstructionPass(Disassembly &disasm): - DisassemblyPass(disasm) + DisassemblyPass(disasm), m_allowDiscovery {false} { } +void InstructionPass::setAllowDiscovery(bool allowDiscovery) +{ + m_allowDiscovery = allowDiscovery; +} + bool InstructionPass::analyzeAllInstructions() { bool ok = true; @@ -208,14 +214,23 @@ bool InstructionPass::analyzeFunction(uint32_t pc) while(!m_queue.empty()) { uint32_t pc = m_queue.pop(); - if(!m_disasm.instructions.count(pc)) { - FxOS_log(ERR, "no instruction at %08x", pc); - continue; + Instruction *i = nullptr; + + if(m_allowDiscovery) { + i = &m_disasm.readins(pc); + } + else { + if(!m_disasm.instructions.count(pc)) { + FxOS_log(ERR, "no instruction at %08x", pc); + continue; + } + + i = &m_disasm.instructions.at(pc); } - Instruction &i = m_disasm.instructions.at(pc); - ok &= this->analyzeInstruction(pc, i); - this->enqueueSuccessors(pc, i); + if(this->analyzeInstruction(pc, *i)) + this->enqueueSuccessors(pc, *i); + else ok = false; } return ok; diff --git a/lib/passes/cfg.cpp b/lib/passes/cfg.cpp index 26efe8f..371d631 100644 --- a/lib/passes/cfg.cpp +++ b/lib/passes/cfg.cpp @@ -13,11 +13,12 @@ namespace FxOS { CfgPass::CfgPass(Disassembly &disasm): - DisassemblyPass(disasm, "cfg") + InstructionPass(disasm) { + this->setAllowDiscovery(true); } -bool CfgPass::analyze(uint32_t pc, Instruction &i) +bool CfgPass::analyzeInstruction(uint32_t pc, Instruction &i) { /* Don't explore successors if the instruction cannot be decoded, not even pc+2. This will prevent wild overshoot. */ @@ -87,7 +88,6 @@ bool CfgPass::analyze(uint32_t pc, Instruction &i) i.jmptarget = jmptarget; } - enqueue_unseen_successors(pc, i); return true; } diff --git a/lib/passes/pcrel.cpp b/lib/passes/pcrel.cpp index 6eeb4e5..c7e5d28 100644 --- a/lib/passes/pcrel.cpp +++ b/lib/passes/pcrel.cpp @@ -11,11 +11,11 @@ namespace FxOS { PcrelPass::PcrelPass(Disassembly &disasm): - InstructionDisassemblyPass(disasm, "pcrel") + InstructionPass(disasm) { } -bool PcrelPass::analyze(uint32_t pc, Instruction &ci) +bool PcrelPass::analyzeInstruction(uint32_t pc, Instruction &ci) { AsmInstruction const *i = ci.inst; if(!i) diff --git a/lib/passes/print.cpp b/lib/passes/print.cpp index d456571..1b161e5 100644 --- a/lib/passes/print.cpp +++ b/lib/passes/print.cpp @@ -15,8 +15,7 @@ namespace FxOS { PrintPass::PrintPass(Disassembly &disasm): - InstructionDisassemblyPass(disasm, "print"), m_symtables(), - m_last_address(0xffffffff) + InstructionPass(disasm), m_symtables {}, m_last_address {0xffffffff} { /* Default parameters: all 0 */ @@ -27,7 +26,7 @@ PrintPass::PrintPass(Disassembly &disasm): m_symtables.push_back(disasm.space.symbols); } -bool PrintPass::analyze(uint32_t pc, Instruction &i) +bool PrintPass::analyzeInstruction(uint32_t pc, Instruction &i) { /* Ellipsis if there is a gap since last instruction */ diff --git a/lib/passes/syscall.cpp b/lib/passes/syscall.cpp index aef6877..2b9f20d 100644 --- a/lib/passes/syscall.cpp +++ b/lib/passes/syscall.cpp @@ -10,11 +10,11 @@ namespace FxOS { SyscallPass::SyscallPass(Disassembly &disasm, OS *os): - InstructionDisassemblyPass(disasm, "syscall"), m_os(os) + InstructionPass(disasm), m_os {os} { } -bool SyscallPass::analyze(uint32_t pc, Instruction &ci) +bool SyscallPass::analyzeInstruction(uint32_t pc, Instruction &ci) { /* Nothing to do if no syscall table is provided! */ if(!m_os) diff --git a/shell/a.cpp b/shell/a.cpp index 87448a1..dbea009 100644 --- a/shell/a.cpp +++ b/shell/a.cpp @@ -243,7 +243,7 @@ static void ad_disassemble_all(VirtualSpace &space, uint32_t entry = addresses[i]; printr("[cfg %d/%zu] Disassembling %08x...", i+1, addresses.size(), entry); - if(!p.run(entry)) { + if(!p.analyzeFunction(entry)) { FxOS_log(ERR, "while processing %08x", entry); errors++; if(!force) break; @@ -256,7 +256,7 @@ static void ad_disassemble_all(VirtualSpace &space, else if(pass == "pcrel") { printr("[pcrel] Resolving PC-relative addressing modes..."); PcrelPass p(space.disasm); - if(!p.run()) { + if(!p.analyzeAllInstructions()) { errors++; if(!force) break; } @@ -266,7 +266,7 @@ static void ad_disassemble_all(VirtualSpace &space, OS *os = space.os_analysis(); if(os) { SyscallPass p(space.disasm, os); - if(!p.run()) { + if(!p.analyzeAllInstructions()) { errors++; if(!force) break; } diff --git a/shell/d.cpp b/shell/d.cpp index 1060fab..d9c2cc1 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -26,19 +26,19 @@ static void disassemble(Session &session, Disassembly &disasm, if(pass == "cfg") { CfgPass p(disasm); - ok = p.run(address); + ok = p.analyzeFunction(address); } else if(pass == "pcrel") { PcrelPass p(disasm); - ok = p.run(); + ok = p.analyzeAllInstructions(); } else if(pass == "syscall") { OS *os = session.current_space->os_analysis(); if(os) { SyscallPass p(disasm, os); - ok = p.run(); + ok = p.analyzeAllInstructions(); } } else if(pass == "print") @@ -53,7 +53,7 @@ static void disassemble(Session &session, Disassembly &disasm, p.promote_symbol = PrintPass::Append; p.promote_pcaddr_loc = PrintPass::Promote; - ok = p.run(); + ok = p.analyzeAllInstructions(); } else {