add infrastructure for function passes

Ported existing passes to the new pass interface, now working properly.
This commit is contained in:
Lephenixnoir 2022-04-05 11:02:56 +01:00
parent d61f4e0a2f
commit d7b3fd0de8
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
13 changed files with 57 additions and 37 deletions

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -16,7 +16,7 @@
template<typename T>
struct Queue
{
Queue();
Queue(): pending {}, seen {} {}
bool empty() const {
return pending.empty();

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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 */

View File

@ -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)

View File

@ -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;
}

View File

@ -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
{