fxos/lib/passes/print.cpp
Lephenixnoir d5c5fa6aeb
implement the syscall pass, and symbol resolution
New features:
* The syscall pass now resolves syscalls for the input target, provided
  that an OS is mapped on the ROM region.
* Formalized the variations of print's arguments as a sequence (tree, to
  be precise) of /promotions/.
* Added a short notion of Symbol and SymbolTable, and a loader for them.
  Data files of type "symbol" are read as such and provide name to
  syscalls or arbitrary addresses.

Code changes:
* The disassembly operation of the command-line interface is now finally
  in its own file with more room.
* Encoded the tree structure of promotions as a sequence of (mainly
  tail-calling) inter-calling methods in the print pass.
2020-02-15 18:42:14 +01:00

168 lines
3.5 KiB
C++

//---
// fxos.passes.print: Print disassembly
//---
#include <fxos/disasm-passes/print.h>
#include <fxos/disassembly.h>
#include <cstdarg>
namespace FxOS {
PrintPass::PrintPass(Disassembly &disasm,
std::vector<SymbolTable> const &symtables):
DisassemblyPass(disasm), m_symtables(symtables)
{
/* Default parameter set */
/* All 0 */
}
void PrintPass::run(void)
{
for(auto &pair: m_disasm.instructions())
{
analyze(pair.first, pair.second);
}
}
void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci)
{
Instruction const &i = ci.inst;
/* Mnemonic */
static std::map<int, std::string> suffixes = {
{ 1, ".b" }, { 2, ".w" }, { 4, ".l" } };
std::string mnemonic = i.mnemonic + suffixes[i.opsize];
if(i.args.size())
mnemonic += std::string(8 - mnemonic.size(), ' ');
printf(" %08x: %04x %s", pc, ci.inst.opcode, mnemonic.c_str());
/* Arguments */
for(size_t n = 0; n < i.args.size(); n++)
{
Argument const &a = i.args[n];
ConcreteInstructionArg const &arg = ci.args[n];
if(n) printf(", ");
if(a.kind == Argument::PcJump)
{
queue(a.str());
pcjumploc(arg);
queue_flush();
}
else if(a.kind == Argument::PcRel)
{
queue(a.str());
pcrelloc(arg);
queue_flush();
}
else
{
queue(a.str());
queue_flush();
}
}
printf("\n");
}
std::optional<std::string> PrintPass::symquery(Symbol::Type type,
uint32_t value)
{
for(int i = m_symtables.size() - 1; i >= 0; i--)
{
auto maybe_str = m_symtables[i].query(type, value);
if(maybe_str) return maybe_str;
}
return std::nullopt;
}
void PrintPass::queue(std::string str, bool override)
{
if(override && m_messages.size())
m_messages.pop_back();
m_messages.push_back(str);
}
void PrintPass::queue_flush()
{
for(size_t i = 0; i < m_messages.size(); i++)
{
if(i != 0) printf(" ");
printf("%s", m_messages[i].c_str());
}
m_messages.clear();
}
void PrintPass::pcjumploc(ConcreteInstructionArg const &arg)
{
if(!RelConstDomain().is_constant(arg.location)) return;
if(promote_pcjump_loc == Never) return;
queue(format("<%s>", arg.location.str()), promote_pcjump_loc==Promote);
syscall(arg);
}
void PrintPass::pcrelloc(ConcreteInstructionArg const &arg)
{
if(!RelConstDomain().is_constant(arg.location)) return;
if(promote_pcrel_loc == Never) return;
queue(format("<%s>", arg.location.str()), promote_pcrel_loc==Promote);
pcrelval(arg);
}
void PrintPass::pcrelval(ConcreteInstructionArg const &arg)
{
if(!arg.value || arg.value.type->kind() != DataType::Integer) return;
if(promote_pcrel_value == Never) return;
queue(arg.value.str(), promote_pcrel_value==Promote);
syscall(arg);
}
void PrintPass::syscall(ConcreteInstructionArg const &arg)
{
if(!arg.value || arg.value.type->kind() != DataType::Integer) return;
/* If this is not a syscall, try to display as a symbol instead */
if(promote_syscall == Never || arg.syscall_id < 0)
{
symbol(arg);
return;
}
queue(format("%%%03x", arg.syscall_id), promote_syscall==Promote);
syscallname(arg);
}
void PrintPass::syscallname(ConcreteInstructionArg const &arg)
{
if(arg.syscall_id < 0) return;
auto maybe_name = symquery(Symbol::Syscall, arg.syscall_id);
if(!maybe_name) return;
queue(*maybe_name, promote_syscallname==Promote);
}
void PrintPass::symbol(ConcreteInstructionArg const &arg)
{
if(!arg.value || arg.value.type->kind() != DataType::Integer) return;
auto maybe_name = symquery(Symbol::Address, arg.value.uinteger());
if(!maybe_name) return;
queue(*maybe_name, promote_symbol==Promote);
}
} /* namespace FxOS */