add infrastructure for function passes
Ported existing passes to the new pass interface, now working properly.
This commit is contained in:
parent
d61f4e0a2f
commit
d7b3fd0de8
|
@ -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<uint32_t> m_queue;
|
||||
bool m_allowDiscovery;
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
template<typename T>
|
||||
struct Queue
|
||||
{
|
||||
Queue();
|
||||
Queue(): pending {}, seen {} {}
|
||||
|
||||
bool empty() const {
|
||||
return pending.empty();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue