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:
Lephenixnoir 2023-08-20 20:22:12 +02:00
parent df4bba2c1a
commit 2dbd910379
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 120 additions and 5 deletions

View File

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

View File

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

View File

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

View File

@ -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[] = {

View File

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

View File

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