fxos/lib/passes/print.cpp

206 lines
5.1 KiB
C++

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/passes/print.h>
#include <fxos/vspace.h>
#include <fxos/util/format.h>
#include <cstdarg>
#include <cstring>
namespace FxOS {
PrintPass::PrintPass(Disassembly &disasm):
InstructionPass(disasm), m_symtables {}, m_last_address {0xffffffff}
{
/* Default parameters: all 0 */
/* Use an OS observer to describe syscalls in header lines */
m_os = disasm.vspace.os_analysis();
/* Use the symbol tables from the virtual space */
m_symtables.push_back(disasm.vspace.symbols);
}
bool PrintPass::analyzeInstruction(uint32_t pc, Instruction &i)
{
/* Ellipsis if there is a gap since last instruction */
if(m_last_address + 1 != 0 && pc != m_last_address + 2)
printf(" ...\n");
/* Preliminary syscall number */
int syscall_id;
if(m_os && (syscall_id = m_os->find_syscall(pc)) >= 0) {
printf("\n<%%%03x", syscall_id);
auto maybe_str = symquery(Symbol::Syscall, syscall_id);
if(maybe_str)
printf(" %s", (*maybe_str).c_str());
printf(">\n");
}
/* Raw data if instruction cannot be decoded */
printf(" %08x: %04x", pc, (i.inst ? i.inst->opcode : i.opcode));
if(!i.inst) {
printf("\n");
m_last_address = pc;
return true;
}
/* Mnemonic */
static char const *suffixes[5] = {"", ".b", ".w", "", ".l"};
char const *suffix = suffixes[(i.inst->opsize <= 4) ? i.inst->opsize : 0];
int spacing
= i.inst->arg_count ? 8 - strlen(i.inst->mnemonic) - strlen(suffix) : 0;
printf(" %s%s%*s", i.inst->mnemonic, suffix, spacing, "");
/* Arguments */
for(size_t n = 0; n < i.inst->arg_count; n++) {
AsmArgument const &arg = i.inst->args[n];
Argument const &a = i.args[n];
if(n)
printf(", ");
queue(arg.str());
if(arg.kind == AsmArgument::PcJump)
pcjumploc(a);
else if(arg.kind == AsmArgument::PcRel)
pcrelloc(a);
else if(arg.kind == AsmArgument::PcAddr)
pcaddrloc(a);
queue_flush();
}
printf("\n");
m_last_address = pc;
return true;
}
std::optional<std::string> PrintPass::symquery(
Symbol::Type type, uint32_t value)
{
for(int i = m_symtables.size() - 1; i >= 0; i--) {
SymbolTable const &st = m_symtables[i];
auto maybe_str = st.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(Argument const &a)
{
if(!RelConstDomain().is_constant(a.location))
return;
if(promote_pcjump_loc == Never)
return;
queue(format("<%s>", a.location.str()), promote_pcjump_loc == Promote);
syscall(a);
}
void PrintPass::pcrelloc(Argument const &a)
{
if(!RelConstDomain().is_constant(a.location))
return;
if(promote_pcrel_loc == Never)
return;
queue(format("<%s>", a.location.str()), promote_pcrel_loc == Promote);
pcrelval(a);
}
void PrintPass::pcrelval(Argument const &a)
{
if(!a.value)
return;
if(promote_pcrel_value == Never)
return;
queue(a.value.str(), promote_pcrel_value == Promote);
syscall(a);
}
void PrintPass::syscall(Argument const &a)
{
if(!a.value)
return;
/* If this is not a syscall, try to display as a symbol instead */
if(promote_syscall == Never || a.syscall_id < 0) {
symbol(a);
return;
}
queue(format("%%%03x", a.syscall_id), promote_syscall == Promote);
syscallname(a);
}
void PrintPass::syscallname(Argument const &a)
{
if(a.syscall_id < 0)
return;
auto maybe_name = symquery(Symbol::Syscall, a.syscall_id);
if(!maybe_name)
return;
queue(*maybe_name, promote_syscallname == Promote);
}
void PrintPass::symbol(Argument const &a)
{
if(!a.value)
return;
auto maybe_name
= symquery(Symbol::Address, RelConstDomain().constant_value(a.value));
if(!maybe_name)
return;
queue(*maybe_name, promote_symbol == Promote);
}
void PrintPass::pcaddrloc(Argument const &a)
{
if(!RelConstDomain().is_constant(a.location))
return;
if(promote_pcaddr_loc == Never)
return;
queue(format("<%s>", a.location.str()), promote_pcaddr_loc == Promote);
}
} /* namespace FxOS */