fxos, _if: add insufficient call analysis
We look for constants in call instruction parameters, but this only works for jsr because the register argument in [jmp @rn] is not known to be a constant yet (some static analysis required).
This commit is contained in:
parent
df4bba2c1a
commit
2dbd910379
|
@ -108,6 +108,10 @@ struct Instruction
|
|||
|
||||
struct Function
|
||||
{
|
||||
/* Create a bare function with no detailed information */
|
||||
Function(uint32_t pc);
|
||||
|
||||
/* Function's entry point */
|
||||
uint32_t address;
|
||||
|
||||
/* List of subfunctions called. TODO: Not yet populated by anyone */
|
||||
|
@ -188,6 +192,8 @@ struct Disassembly
|
|||
bool hasFunctionAt(uint32_t pc);
|
||||
/* Find a function by address; returns nullptr if not yet defined */
|
||||
Function *getFunctionAt(uint32_t pc);
|
||||
/* Find a function and create it empty if it's not yet defined */
|
||||
Function *getOrCreateFunctionAt(uint32_t pc);
|
||||
|
||||
|
||||
// Claim information
|
||||
|
|
|
@ -175,6 +175,8 @@ struct AsmInstruction
|
|||
bool isjump() const noexcept;
|
||||
/* Check whether it's a conditional jump */
|
||||
bool iscondjump() const noexcept;
|
||||
/* Check whether instruction is a function call */
|
||||
bool iscall() const noexcept;
|
||||
/* Check whether instruction has a delay slot */
|
||||
bool isdelayed() const noexcept;
|
||||
/* Check whether instruction can be used in a delay slot */
|
||||
|
|
|
@ -51,6 +51,14 @@ Instruction::Instruction(uint16_t opcode):
|
|||
{
|
||||
}
|
||||
|
||||
//---
|
||||
// Function information
|
||||
//---
|
||||
|
||||
Function::Function(uint32_t pc): address {pc}
|
||||
{
|
||||
}
|
||||
|
||||
//---
|
||||
// Dynamic claims
|
||||
//---
|
||||
|
@ -146,6 +154,15 @@ Function *Disassembly::getFunctionAt(uint32_t pc)
|
|||
return &it->second;
|
||||
}
|
||||
|
||||
Function *Disassembly::getOrCreateFunctionAt(uint32_t pc)
|
||||
{
|
||||
if(!this->hasFunctionAt(pc)) {
|
||||
Function f(pc);
|
||||
this->functions.insert({pc, f});
|
||||
}
|
||||
return this->getFunctionAt(pc);
|
||||
}
|
||||
|
||||
std::vector<Claim const *> Disassembly::findClaimConflicts(
|
||||
uint32_t address, int size, int max)
|
||||
{
|
||||
|
|
|
@ -261,6 +261,12 @@ bool AsmInstruction::iscondjump() const noexcept
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AsmInstruction::iscall() const noexcept
|
||||
{
|
||||
return !strcmp(mnemonic, "jsr") || !strcmp(mnemonic, "bsr")
|
||||
|| !strcmp(mnemonic, "bsrf");
|
||||
}
|
||||
|
||||
bool AsmInstruction::isdelayed() const noexcept
|
||||
{
|
||||
char const *v[] = {
|
||||
|
|
|
@ -103,13 +103,35 @@ bool CfgPass::exploreFunction(uint32_t pc)
|
|||
m_lastFunction = pc;
|
||||
m_claimedInstructions.clear();
|
||||
|
||||
if(!m_disasm.hasFunctionAt(pc)) {
|
||||
// TODO: Have proper function creation methods in Disassembly
|
||||
Function func = {.address = pc, .callTargets = {}};
|
||||
m_disasm.functions[pc] = func;
|
||||
Function *func = m_disasm.getOrCreateFunctionAt(pc);
|
||||
if(!this->analyzeFunction(pc))
|
||||
return false;
|
||||
|
||||
RelConstDomain RCD;
|
||||
|
||||
/* Look for call targets */
|
||||
for(uint32_t pc: m_claimedInstructions) {
|
||||
Instruction const *ci = m_disasm.getInstructionAt(pc);
|
||||
if(!ci)
|
||||
continue;
|
||||
AsmInstruction const &i = *ci->inst;
|
||||
|
||||
/* Find function call instructions */
|
||||
if(i.isterminal() || !i.iscall() || i.arg_count < 1)
|
||||
continue;
|
||||
|
||||
/* The target must be known */
|
||||
if(!RCD.is_constant(ci->args[0].location))
|
||||
continue;
|
||||
|
||||
uint32_t target = RCD.constant_value(ci->args[0].location);
|
||||
auto &v = func->callTargets;
|
||||
|
||||
if(std::find(v.begin(), v.end(), target) == v.end())
|
||||
func->callTargets.push_back(target);
|
||||
}
|
||||
|
||||
return this->analyzeFunction(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::set<Claim> CfgPass::resultClaims()
|
||||
|
|
62
shell/i.cpp
62
shell/i.cpp
|
@ -42,6 +42,56 @@ void _ic(Session &session, struct _ic_args const &args)
|
|||
}
|
||||
}
|
||||
|
||||
//---
|
||||
// if
|
||||
//---
|
||||
|
||||
struct _if_args
|
||||
{
|
||||
std::vector<uint32_t> addresses;
|
||||
};
|
||||
|
||||
static struct _if_args parse_if(Session &session, Parser &parser)
|
||||
{
|
||||
_if_args args;
|
||||
|
||||
while(!parser.at_end())
|
||||
args.addresses.push_back(parser.expr(session.current_space));
|
||||
|
||||
parser.end();
|
||||
return args;
|
||||
}
|
||||
|
||||
void _if(Session &session, struct _if_args const &args)
|
||||
{
|
||||
if(!session.current_space)
|
||||
return;
|
||||
Disassembly &disasm = session.current_space->disasm;
|
||||
|
||||
if(!args.addresses.size()) {
|
||||
fmt::print("{} functions\n", disasm.functions.size());
|
||||
}
|
||||
|
||||
for(uint32_t address: args.addresses) {
|
||||
Function *func = disasm.getFunctionAt(address);
|
||||
if(!func) {
|
||||
FxOS_log(ERR, "no function at 0x{:08x}", address);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Promote address to syscall, name, etc.
|
||||
fmt::print("0x{:08x}:\n", address);
|
||||
fmt::print(" callTargets:\n");
|
||||
|
||||
auto &ct = func->callTargets;
|
||||
// TODO: Promote address to syscall, name, etc.
|
||||
for(uint32_t pc: ct)
|
||||
fmt::print(" 0x{:08x}\n", pc);
|
||||
if(!ct.size())
|
||||
fmt::print(" (none)\n");
|
||||
}
|
||||
}
|
||||
|
||||
//---
|
||||
// io
|
||||
//---
|
||||
|
@ -384,6 +434,18 @@ usually generated by analysis commands and allow sections of the OS to be
|
|||
marked as part of functions, data, interrupt handlers, etc.
|
||||
)");
|
||||
|
||||
static ShellCommand _if_cmd(
|
||||
"if", [](Session &s, Parser &p) {
|
||||
auto args = parse_if(s, p);
|
||||
_if(s, args);
|
||||
},
|
||||
[](Session &s, Parser &p) { parse_if(s, p); }, "Info Function", R"(
|
||||
if [<function>...]
|
||||
|
||||
Prints information about functions. Without arguments, prints vspace-level
|
||||
statistics. With arguments, prints detailed function info.
|
||||
)");
|
||||
|
||||
static ShellCommand _io_cmd(
|
||||
"io", [](Session &s, Parser &p) { _io(s, parse_io(s, p)); },
|
||||
[](Session &s, Parser &p) { parse_io(s, p); }, "Info OS", R"(
|
||||
|
|
Loading…
Reference in New Issue