get rid of exceptions in the library, use explicit errors
This commit is contained in:
parent
50963d7c20
commit
a9660da767
|
@ -1,76 +0,0 @@
|
|||
static std::string help_string = colors(R"(
|
||||
usage: <R>fxos<> [<R>library<>|<R>info<>|<R>disasm<>|<R>analyze<>]
|
||||
|
||||
fxos is a reverse-engineering tool that disassembles and analyzes SuperH
|
||||
programs and OS dumps for CASIO calculators of the fx-9860G and fx-CG 50
|
||||
families, using an editable database of platform, syscall, and OS knowledge.
|
||||
|
||||
General options:
|
||||
<R>-3<>, <R>--sh3<> Assume SH3 OS and platform (default: SH4)
|
||||
<R>-4<>, <R>--sh4<> Assume SH4 OS and platform (default: SH4)
|
||||
<R>-v<>, <R>--verbose<> Print logs about what's happening
|
||||
|
||||
<R>fxos library<> [<R>-t<>] [<R>-a<>]
|
||||
Prints out the contents of the library. If an option is set, the results are
|
||||
printed in a simple easily-parsable form without header.
|
||||
|
||||
Selectors:
|
||||
<R>-t<>, <R>--targets<> Print all targets
|
||||
<R>-a<>, <R>--asm<> Print all assembler instruction sets
|
||||
|
||||
<R>fxos info<> <<P>TARGET<>>
|
||||
Print adentification and basic information about an OS image: version,
|
||||
platform, date, checksums...
|
||||
|
||||
Target specification:
|
||||
<<P>TARGET-NAME<>> Named target in library (eg. "fx@3.10")
|
||||
<R>-f<> <<P>FILE<>> Arbitrary file which is loaded as ROM
|
||||
|
||||
<R>fxos disasm<> <<P>TARGET<>> <<P>LOCATION<>> [options...]
|
||||
Disassemble and annotate code with relative address targets, syscalls,
|
||||
control flow, propagated constants and hints about memory structure.
|
||||
|
||||
Location specifiers:
|
||||
<<P>ADDRESS<>> Start disassembling at this address (hexa)
|
||||
<<P>ADDRESS<>>:<<P>LEN<>> Disassemble exactly the specified region. <P>len<> is an
|
||||
hexadecimal number optionally followed by k, M, or G.
|
||||
%<<P>SYSCALL-ID<>> Start disassembling at this syscall's address (hexa)
|
||||
<<P>SYMBOL<>> Disassemble this library symbol (typically syscall name).
|
||||
A name which is valid hexadecimal is treated as <P>ADDRESS<>.
|
||||
Disassembly options:
|
||||
<R>-p<> <<P>PASSES<>> Execute the specified comma-separated list of passes
|
||||
Available passes:
|
||||
cfg Build the control flow graph (always required)
|
||||
pcrel Resolve PC-relative references as their target address
|
||||
cstprop Propagate constants by abstract interpretation
|
||||
syscall Annotate code with reverse syscalls
|
||||
|
||||
The default sequence of passes is <W>cfg,pcrel,cstprop,syscall<>. When
|
||||
disassembling a function (ie. no size specified on the command-line), the cfg
|
||||
pass is always executed to obtain the code of the function.
|
||||
)"+1);
|
||||
|
||||
int main_disassembly(int argc, char **argv)
|
||||
{
|
||||
std::vector<std::string> passes {
|
||||
"cfg", "pcrel", "constprop", "syscall", "print"
|
||||
};
|
||||
if(passes.back() != "print") passes.push_back("print");
|
||||
|
||||
try
|
||||
{
|
||||
int rc = disassembly(lib, space, ref, passes);
|
||||
if(log_getminlevel() <= LEVEL_LOG) malloc_stats();
|
||||
return rc;
|
||||
}
|
||||
catch(LangError &e)
|
||||
{
|
||||
log(ERR "%08x: %s", e.addr(), e.what());
|
||||
return 1;
|
||||
}
|
||||
catch(AddressError &e)
|
||||
{
|
||||
log(ERR "%08x[%d]: %s", e.addr(), e.size(), e.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ class CfgPass: public DisassemblyPass
|
|||
{
|
||||
public:
|
||||
CfgPass(Disassembly &disasm);
|
||||
void analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
bool analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -17,7 +17,7 @@ class PcrelPass: public InstructionDisassemblyPass
|
|||
{
|
||||
public:
|
||||
PcrelPass(Disassembly &disasm);
|
||||
void analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
bool analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -19,7 +19,7 @@ class PrintPass: public InstructionDisassemblyPass
|
|||
{
|
||||
public:
|
||||
PrintPass(Disassembly &disasm);
|
||||
void analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
bool analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
|
||||
//---
|
||||
// Print pass parameters
|
||||
|
|
|
@ -20,7 +20,7 @@ class SyscallPass: public InstructionDisassemblyPass
|
|||
public:
|
||||
SyscallPass(Disassembly &disasm, OS *os);
|
||||
|
||||
void analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
bool analyze(uint32_t pc, ConcreteInstruction &inst) override;
|
||||
|
||||
private:
|
||||
OS *m_os;
|
||||
|
|
|
@ -147,10 +147,10 @@ public:
|
|||
|
||||
/* Analyze a single instruction, probably updating the annotations and
|
||||
the state of the pass itself. */
|
||||
virtual void analyze(uint32_t pc, ConcreteInstruction &inst) = 0;
|
||||
virtual bool analyze(uint32_t pc, ConcreteInstruction &inst) = 0;
|
||||
|
||||
/* Run the pass from the given entry point */
|
||||
virtual void run(uint32_t entry_pc);
|
||||
virtual bool run(uint32_t entry_pc);
|
||||
|
||||
protected:
|
||||
/* Add an instruction to the queue to analyze next */
|
||||
|
@ -185,7 +185,7 @@ public:
|
|||
|
||||
/* Runs the pass from the first instruction currently loaded, all the
|
||||
way down to the bottom, as if always using enqueue_next(). */
|
||||
virtual void run();
|
||||
virtual bool run();
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
//---
|
||||
// fxos.errors: Exception specification
|
||||
//
|
||||
// fxos uses the following exception classes when reporting errors.
|
||||
//
|
||||
// Fatal errors (caught by main):
|
||||
// std::logic_error Internal consistency, fxos is broken
|
||||
// FxOS::LimitError fxos doesn't know how to handle the input
|
||||
// FxOS::LangError Program is invalid or database too poor
|
||||
//
|
||||
// Recoverable errors:
|
||||
// std::runtime_error External errors (fi. file access)
|
||||
// FxOS::SyntaxError Invalid fxos data file syntax (file is skipped)
|
||||
// FxOS::AddressError Invalid virtual address (not bound)
|
||||
//---
|
||||
|
||||
#ifndef LIBFXOS_ERRORS_H
|
||||
#define LIBFXOS_ERRORS_H
|
||||
|
||||
#include <fxos/util/format.h>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace FxOS {
|
||||
|
||||
/* Syntax errors for fxos data files. This is always an external error, and
|
||||
reported to the user as an error message. */
|
||||
class SyntaxError: public std::exception
|
||||
{
|
||||
public:
|
||||
/* Specifies the file and line of the exception */
|
||||
SyntaxError(char const *file, int line, char const *what):
|
||||
m_file(file), m_line(line), m_what(what) {}
|
||||
|
||||
/* Provides access to these objects */
|
||||
char const *file() const noexcept {
|
||||
return m_file;
|
||||
}
|
||||
int line() const noexcept {
|
||||
return m_line;
|
||||
}
|
||||
char const *what() const noexcept override {
|
||||
return m_what;
|
||||
}
|
||||
|
||||
/* Additional friendly formatter */
|
||||
std::string str() const noexcept {
|
||||
return format("%s:%d: %s", m_file, m_line, m_what);
|
||||
}
|
||||
|
||||
private:
|
||||
char const *m_file;
|
||||
int m_line;
|
||||
char const *m_what;
|
||||
};
|
||||
|
||||
/* Language errors for the disassembler. These are either bugs in fxos or
|
||||
caused by corrupted code files. */
|
||||
class LangError: public std::exception
|
||||
{
|
||||
public:
|
||||
LangError(uint32_t address, char const *what):
|
||||
m_addr(address), m_what(what) {}
|
||||
|
||||
uint32_t addr() const noexcept {
|
||||
return m_addr;
|
||||
}
|
||||
char const *what() const noexcept override {
|
||||
return m_what;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_addr;
|
||||
char const *m_what;
|
||||
};
|
||||
|
||||
/* Address errors */
|
||||
class AddressError: public std::exception
|
||||
{
|
||||
public:
|
||||
static constexpr char const *default_message = "unmapped address";
|
||||
|
||||
AddressError(uint32_t address, int size,
|
||||
char const *what = default_message):
|
||||
m_addr(address), m_size(size), m_what(what) {}
|
||||
|
||||
uint32_t addr() const noexcept {
|
||||
return m_addr;
|
||||
}
|
||||
int size() const noexcept {
|
||||
return m_size;
|
||||
}
|
||||
char const *what() const noexcept override {
|
||||
return m_what;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_addr;
|
||||
int m_size;
|
||||
char const *m_what;
|
||||
};
|
||||
|
||||
/* Limitations of fxos */
|
||||
class LimitError: public std::exception
|
||||
{
|
||||
public:
|
||||
LimitError(char const *what): m_what(what) {}
|
||||
|
||||
char const *what() const noexcept override {
|
||||
return m_what;
|
||||
}
|
||||
|
||||
private:
|
||||
char const *m_what;
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
||||
#endif /* LIBFXOS_ERRORS_H */
|
|
@ -44,7 +44,7 @@ void logmsg(int level, char const *file, int line, char const *func,
|
|||
} /* namespace FxOS */
|
||||
|
||||
#define FxOS_log(level, fmt, ...) \
|
||||
FxOS::logmsg(LOG_LEVEL_ ## level, __FILE__, __LINE__, __func__, \
|
||||
FxOS::logmsg(FxOS::LOG_LEVEL_ ## level, __FILE__, __LINE__, __func__, \
|
||||
format(fmt, ##__VA_ARGS__))
|
||||
|
||||
#endif /* FXOS_UTIL_LOG_H */
|
||||
|
|
|
@ -32,7 +32,8 @@ public:
|
|||
virtual char const *translate(uint32_t addr, int size=1) const = 0;
|
||||
|
||||
/* Returns the data located at the provided virtual address, and indicates
|
||||
how much is available in *size. */
|
||||
how much is available in *size. The pointer is null if [addr] itself is
|
||||
not covered, in which case *size is also set to 0. */
|
||||
virtual char const *translate_dynamic(uint32_t addr, int *size) const = 0;
|
||||
|
||||
/* Read data from the memory. The following methods read data of
|
||||
|
@ -42,12 +43,12 @@ public:
|
|||
When reading data, provide a virtual address. The address is saved
|
||||
in the returned object for later printing or inspection. The
|
||||
returned object Addressable<T> automatically converts to T when
|
||||
used, and supports operator & which returns the original address.
|
||||
used, and supports [.address] which returns the original address.
|
||||
|
||||
The size parameter is only meaningful for variable-sized types such
|
||||
as string, and ignored for fixed-size types such as integers. If the
|
||||
desired object is not within the range of the simulated memory,
|
||||
throws std::out_of_range. */
|
||||
desired object is not within the range of the simulated memory, returns
|
||||
a dummy value of address -1. You should check the range beforehand! */
|
||||
|
||||
/* Read integers with signed or unsigned extension. These functions do
|
||||
not check alignment, because exceptionally the processor supports
|
||||
|
|
|
@ -164,7 +164,7 @@ void DisassemblyPass::enqueue_all_successors(uint32_t pc,
|
|||
}
|
||||
}
|
||||
|
||||
void DisassemblyPass::run(uint32_t entry_pc)
|
||||
bool DisassemblyPass::run(uint32_t entry_pc)
|
||||
{
|
||||
enqueue(entry_pc);
|
||||
|
||||
|
@ -176,12 +176,14 @@ void DisassemblyPass::run(uint32_t entry_pc)
|
|||
m_next.erase(m_next.find(pc));
|
||||
|
||||
ConcreteInstruction &ci = m_disasm.readins(pc);
|
||||
analyze(pc, ci);
|
||||
if(!analyze(pc, ci))
|
||||
return false;
|
||||
|
||||
m_seen.insert(pc);
|
||||
}
|
||||
|
||||
if(m_name != "") m_disasm.passes.insert(m_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -193,12 +195,14 @@ InstructionDisassemblyPass::InstructionDisassemblyPass(Disassembly &disasm,
|
|||
{
|
||||
}
|
||||
|
||||
void InstructionDisassemblyPass::run()
|
||||
bool InstructionDisassemblyPass::run()
|
||||
{
|
||||
for(auto &pair: m_disasm.instructions())
|
||||
{
|
||||
analyze(pair.first, pair.second);
|
||||
if(!analyze(pair.first, pair.second))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
%{
|
||||
#include <fxos/lang.h>
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/errors.h>
|
||||
#include <fxos/util/format.h>
|
||||
#include <fxos/util/log.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
|
@ -47,18 +47,8 @@ struct Pattern {
|
|||
/* Current file name */
|
||||
static std::string filename;
|
||||
|
||||
/* Error messages and exceptions */
|
||||
static void err(char const *format, ...)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buf, 256, format, args);
|
||||
va_end(args);
|
||||
|
||||
throw FxOS::SyntaxError(filename.c_str(), yylineno, buf);
|
||||
}
|
||||
#define err(fmt, ...) \
|
||||
FxOS_log(ERR, "%s:%d: " fmt, filename, yylineno, ##__VA_ARGS__)
|
||||
|
||||
%}
|
||||
|
||||
|
@ -121,7 +111,7 @@ space [ \t]+
|
|||
|
||||
{mnemonic} { yylval = strdup(yytext); return MNEMONIC; }
|
||||
|
||||
. { err("lex error near '%s'", yytext); }
|
||||
. { err("lex error near %s", yytext); }
|
||||
<<EOF>> { return -1; }
|
||||
|
||||
%%
|
||||
|
@ -305,7 +295,11 @@ int load_instructions(Buffer const &file)
|
|||
if(line >= 0 && (yylineno != line || t == PATTERN || t == -1))
|
||||
{
|
||||
/* Finalize current instruction */
|
||||
if(!mnemonic) err("%d: missing mnemonic", line);
|
||||
if(!mnemonic)
|
||||
{
|
||||
err("missing mnemonic at line %d", line);
|
||||
break;
|
||||
}
|
||||
|
||||
Pattern p = make_pattern(code);
|
||||
total += instantiate(p, mnemonic, argtoken1,argtoken2);
|
||||
|
@ -330,7 +324,8 @@ int load_instructions(Buffer const &file)
|
|||
}
|
||||
else if(!mnemonic)
|
||||
{
|
||||
err("%d: missing mnemonic", line);
|
||||
err("missing mnemonic at line %d", line);
|
||||
break;
|
||||
}
|
||||
else if(!argtoken1)
|
||||
{
|
||||
|
|
|
@ -166,8 +166,11 @@ void OS::parse_footer()
|
|||
uint32_t addr = this->footer + 8;
|
||||
this->langdata = 0;
|
||||
|
||||
while(!memcmp(s.translate(addr, 8), "Langdata", 8))
|
||||
while(1)
|
||||
{
|
||||
void const *entry = s.translate(addr, 8);
|
||||
if(!entry || memcmp(entry, "Langdata", 8) != 0)
|
||||
break;
|
||||
this->langdata++;
|
||||
addr += 0x30;
|
||||
}
|
||||
|
@ -190,6 +193,8 @@ static uint32_t accumulate_range(VirtualSpace const &m_space,
|
|||
while(start < end) {
|
||||
int size;
|
||||
uint8_t *buf = (uint8_t *)m_space.translate_dynamic(start, &size);
|
||||
if(!buf || size <= 0)
|
||||
break;
|
||||
|
||||
if(start + size > end)
|
||||
size = end - start;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <fxos/disasm-passes/cfg.h>
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/errors.h>
|
||||
#include <fxos/util/log.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace FxOS {
|
||||
|
@ -14,11 +14,15 @@ CfgPass::CfgPass(Disassembly &disasm):
|
|||
{
|
||||
}
|
||||
|
||||
void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
bool CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
{
|
||||
/* Don't explore successors if the instruction cannot be decoded, not
|
||||
even pc+2. This will prevent wild overshoot. */
|
||||
if(!ci.inst) return;
|
||||
if(!ci.inst)
|
||||
{
|
||||
FxOS_log(ERR, "invalid instruction as %08x: %04x", pc, ci.opcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compute the jump target for jump instructions. This is easy because
|
||||
they are all trivially computable. (...If they are not we dub them
|
||||
|
@ -30,7 +34,10 @@ void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
auto &args = ci.inst->args;
|
||||
|
||||
if(ci.inst->arg_count != 1 || args[0].kind != Argument::PcJump)
|
||||
throw LangError(pc, "invalid jump instruction");
|
||||
{
|
||||
FxOS_log(ERR, "invalid jump instruction at %08x", pc);
|
||||
return false;
|
||||
}
|
||||
|
||||
jmptarget = (pc+4) + args[0].disp;
|
||||
|
||||
|
@ -40,7 +47,9 @@ void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
|
||||
/* Check that it's not in a delay slot */
|
||||
if(target.delayslot)
|
||||
throw LimitError("jump into a delay slot!");
|
||||
throw std::logic_error(format("%08x jumps into %08x, which is a "
|
||||
"delay slot - this is unsupported by fxos and will produce "
|
||||
"garbage analysis! (x_x)", pc, jmptarget));
|
||||
}
|
||||
|
||||
/* If this instruction is in a delay slot, check its type. A valid
|
||||
|
@ -49,7 +58,10 @@ void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
if(ci.delayslot)
|
||||
{
|
||||
if(!ci.inst->isvaliddelayslot())
|
||||
throw LangError(pc, "invalid delay slot");
|
||||
{
|
||||
FxOS_log(ERR, "invalid delay slot at %08x", pc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Handle normal instructions */
|
||||
else if(!ci.inst->isdelayed())
|
||||
|
@ -64,9 +76,14 @@ void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
{
|
||||
ConcreteInstruction &slot = m_disasm.readins(pc+2);
|
||||
if(slot.leader)
|
||||
throw LimitError("leader in a delay slot!");
|
||||
throw std::logic_error(format("%08x is a leader and also a delay "
|
||||
"slot - this is unsupported by fxos and will produce garbage "
|
||||
"analysis! (x_x)", pc+2));
|
||||
if(!slot.inst->isvaliddelayslot())
|
||||
throw LangError(pc+2, "invalid delay slot");
|
||||
{
|
||||
FxOS_log(ERR, "invalid delay slot at %08x", pc+2);
|
||||
return false;
|
||||
}
|
||||
|
||||
slot.delayslot = true;
|
||||
slot.terminal = ci.inst->isterminal();
|
||||
|
@ -76,6 +93,7 @@ void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
}
|
||||
|
||||
enqueue_unseen_successors(pc, ci);
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -11,10 +11,11 @@ PcrelPass::PcrelPass(Disassembly &disasm):
|
|||
{
|
||||
}
|
||||
|
||||
void PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
bool PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
{
|
||||
Instruction const *i = ci.inst;
|
||||
if(!i) return;
|
||||
if(!i)
|
||||
return false;
|
||||
|
||||
for(size_t n = 0; n < i->arg_count; n++)
|
||||
{
|
||||
|
@ -32,11 +33,18 @@ void PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
VirtualSpace &space = m_disasm.space();
|
||||
uint32_t v = -1;
|
||||
|
||||
if(i->opsize == 2) v = space.read_i16(addr);
|
||||
if(i->opsize == 4) v = space.read_i32(addr);
|
||||
|
||||
ca.value = DataValue(IntegerType::u32);
|
||||
ca.value.write(0, 4, v);
|
||||
if(i->opsize == 2 && v.covers(addr, 2))
|
||||
{
|
||||
v = space.read_i16(addr);
|
||||
ca.value = DataValue(IntegerType::u32);
|
||||
ca.value.write(0, 4, v);
|
||||
}
|
||||
if(i->opsize == 4 && v.covers(addr, 4))
|
||||
{
|
||||
v = space.read_i32(addr);
|
||||
ca.value = DataValue(IntegerType::u32);
|
||||
ca.value.write(0, 4, v);
|
||||
}
|
||||
}
|
||||
else if(a.kind == Argument::PcJump)
|
||||
{
|
||||
|
@ -60,6 +68,8 @@ void PcrelPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
ca.value.write(0, 4, addr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -24,7 +24,7 @@ PrintPass::PrintPass(Disassembly &disasm):
|
|||
m_symtables.push_back(disasm.space().symbols);
|
||||
}
|
||||
|
||||
void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
bool PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
||||
{
|
||||
Instruction const *i = ci.inst;
|
||||
|
||||
|
@ -53,7 +53,7 @@ void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
{
|
||||
printf("\n");
|
||||
m_last_address = pc;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Mnemonic */
|
||||
|
@ -100,6 +100,7 @@ void PrintPass::analyze(uint32_t pc, ConcreteInstruction &ci)
|
|||
|
||||
printf("\n");
|
||||
m_last_address = pc;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::string> PrintPass::symquery(Symbol::Type type,
|
||||
|
|
|
@ -11,13 +11,15 @@ SyscallPass::SyscallPass(Disassembly &disasm, OS *os):
|
|||
{
|
||||
}
|
||||
|
||||
void SyscallPass::analyze([[maybe_unused]] uint32_t pc,ConcreteInstruction &ci)
|
||||
bool SyscallPass::analyze([[maybe_unused]] uint32_t pc,ConcreteInstruction &ci)
|
||||
{
|
||||
/* Nothing to do if no syscall table is provided! */
|
||||
if(!m_os) return;
|
||||
if(!m_os)
|
||||
return true;
|
||||
|
||||
Instruction const *i = ci.inst;
|
||||
if(!i) return;
|
||||
if(!i)
|
||||
return false;
|
||||
|
||||
for(size_t n = 0; n < i->arg_count; n++)
|
||||
{
|
||||
|
@ -46,6 +48,8 @@ void SyscallPass::analyze([[maybe_unused]] uint32_t pc,ConcreteInstruction &ci)
|
|||
if(sid >= 0) ca.syscall_id = sid;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
|
@ -67,7 +67,7 @@ void logmsg(int level, char const *file, int line, char const *func,
|
|||
if(level == LOG_LEVEL_WRN)
|
||||
std::cerr << "warning: ";
|
||||
if(level == LOG_LEVEL_ERR)
|
||||
std::cerr << "err: ";
|
||||
std::cerr << "\x1b[31;1merror:\x1b[0m ";
|
||||
}
|
||||
else std::cerr << " ";
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <fxos/vspace.h>
|
||||
#include <fxos/errors.h>
|
||||
#include <fxos/os.h>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -17,18 +16,24 @@ bool AbstractMemory::covers(MemoryRegion const ®ion) const noexcept
|
|||
Addressable<int8_t> AbstractMemory::read_i8(uint32_t addr) const
|
||||
{
|
||||
int8_t *i8 = (int8_t *)translate(addr, 1);
|
||||
if(!i8)
|
||||
return Addressable((int8_t)-1);
|
||||
return Addressable(addr, *i8);
|
||||
}
|
||||
|
||||
Addressable<uint8_t> AbstractMemory::read_u8(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u8 = (uint8_t *)translate(addr, 1);
|
||||
if(!u8)
|
||||
return Addressable((uint8_t)-1);
|
||||
return Addressable(addr, *u8);
|
||||
}
|
||||
|
||||
Addressable<int16_t> AbstractMemory::read_i16(uint32_t addr) const
|
||||
{
|
||||
uint8_t *i16 = (uint8_t *)translate(addr, 2);
|
||||
if(!i16)
|
||||
return Addressable((int16_t)-1);
|
||||
int16_t v = (i16[0] << 8) | i16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
@ -36,6 +41,8 @@ Addressable<int16_t> AbstractMemory::read_i16(uint32_t addr) const
|
|||
Addressable<uint16_t> AbstractMemory::read_u16(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u16 = (uint8_t *)translate(addr, 2);
|
||||
if(!u16)
|
||||
return Addressable((uint16_t)-1);
|
||||
uint16_t v = (u16[0] << 8) | u16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
@ -43,6 +50,8 @@ Addressable<uint16_t> AbstractMemory::read_u16(uint32_t addr) const
|
|||
Addressable<int32_t> AbstractMemory::read_i32(uint32_t addr) const
|
||||
{
|
||||
uint8_t *i32 = (uint8_t *)translate(addr, 4);
|
||||
if(!i32)
|
||||
return Addressable((int32_t)-1);
|
||||
int32_t v = (i32[0] << 24) | (i32[1] << 16) | (i32[2] << 8) | i32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
@ -50,6 +59,8 @@ Addressable<int32_t> AbstractMemory::read_i32(uint32_t addr) const
|
|||
Addressable<uint32_t> AbstractMemory::read_u32(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u32 = (uint8_t *)translate(addr, 4);
|
||||
if(!u32)
|
||||
return Addressable((uint32_t)-1);
|
||||
uint32_t v = (u32[0] << 24) | (u32[1] << 16) | (u32[2] << 8) | u32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
@ -58,6 +69,8 @@ Addressable<std::string> AbstractMemory::read_str(uint32_t addr, size_t len)
|
|||
const
|
||||
{
|
||||
char const *str = translate(addr, len);
|
||||
if(!str)
|
||||
return Addressable(std::string());
|
||||
return Addressable(addr, std::string(str, len));
|
||||
}
|
||||
|
||||
|
@ -76,7 +89,7 @@ Binding::Binding(MemoryRegion source_region, Buffer source_buffer):
|
|||
|
||||
bool Binding::covers(uint32_t addr, int size) const noexcept
|
||||
{
|
||||
return addr >= region.start && addr + size <= region.end;
|
||||
return size >= 0 && addr >= region.start && addr + size <= region.end;
|
||||
}
|
||||
|
||||
bool Binding::covers(MemoryRegion const &r) const noexcept
|
||||
|
@ -100,13 +113,13 @@ char const *Binding::translate_dynamic(uint32_t addr, int *size) const
|
|||
uint32_t Binding::search(uint32_t start, uint32_t end, void const *pattern,
|
||||
int size) const
|
||||
{
|
||||
if(end < start || !covers(start, end - start)) return end;
|
||||
if(start + size > end) return end;
|
||||
|
||||
void const *data = translate(start);
|
||||
void const *data = translate(start, end-start);
|
||||
if(!data)
|
||||
return end;
|
||||
void const *occurrence = memmem(data, end - start, pattern, size);
|
||||
|
||||
if(!occurrence) return end;
|
||||
if(!occurrence)
|
||||
return end;
|
||||
return start + ((char *)occurrence - (char *)data);
|
||||
}
|
||||
|
||||
|
@ -172,8 +185,7 @@ char const *VirtualSpace::translate(uint32_t addr, int size) const
|
|||
char const *ptr = it->translate(addr, size);
|
||||
if(ptr) return ptr;
|
||||
}
|
||||
|
||||
throw AddressError(addr, size);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char const *VirtualSpace::translate_dynamic(uint32_t addr, int *size) const
|
||||
|
@ -183,18 +195,15 @@ char const *VirtualSpace::translate_dynamic(uint32_t addr, int *size) const
|
|||
char const *ptr = it->translate_dynamic(addr, size);
|
||||
if(ptr) return ptr;
|
||||
}
|
||||
|
||||
throw AddressError(addr, 1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t VirtualSpace::search(uint32_t start, uint32_t end,void const *pattern,
|
||||
int size) const
|
||||
uint32_t VirtualSpace::search(uint32_t start, uint32_t end,
|
||||
void const *pattern, int size) const
|
||||
{
|
||||
uint32_t occurrence;
|
||||
if(end < start || !covers(start, end - start))
|
||||
{
|
||||
throw AddressError(start, end-start);
|
||||
}
|
||||
return end;
|
||||
|
||||
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
|
||||
{
|
||||
|
|
27
shell/d.cpp
27
shell/d.cpp
|
@ -21,22 +21,24 @@ static void disassemble(Session &session, Disassembly &disasm,
|
|||
Timer timer;
|
||||
timer.start();
|
||||
|
||||
bool ok;
|
||||
|
||||
if(pass == "cfg")
|
||||
{
|
||||
CfgPass p(disasm);
|
||||
p.run(address);
|
||||
ok = p.run(address);
|
||||
}
|
||||
else if(pass == "pcrel")
|
||||
{
|
||||
PcrelPass p(disasm);
|
||||
p.run();
|
||||
ok = p.run();
|
||||
}
|
||||
else if(pass == "syscall")
|
||||
{
|
||||
OS *os = session.current_space->os_analysis();
|
||||
if(os) {
|
||||
SyscallPass p(disasm, os);
|
||||
p.run();
|
||||
ok = p.run();
|
||||
}
|
||||
}
|
||||
else if(pass == "print")
|
||||
|
@ -51,10 +53,21 @@ static void disassemble(Session &session, Disassembly &disasm,
|
|||
p.promote_symbol = PrintPass::Append;
|
||||
p.promote_pcaddr_loc = PrintPass::Promote;
|
||||
|
||||
p.run();
|
||||
ok = p.run();
|
||||
}
|
||||
else
|
||||
{
|
||||
FxOS_log(ERR, "unknown pass <%s>", pass);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
FxOS_log(LOG, "Finished pass <%s> in %s", pass, timer.format_time());
|
||||
|
||||
if(!ok) {
|
||||
FxOS_log(ERR, "pass <%s> failed", pass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +101,7 @@ void _d(Session &session, uint32_t address)
|
|||
}
|
||||
|
||||
disassemble(session, disasm,
|
||||
{ "cfg", "pcrel", "constprop", "syscall", "print" }, address);
|
||||
{ "cfg", "pcrel", /*"constprop",*/ "syscall", "print" }, address);
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -125,8 +138,8 @@ void _dr(Session &session, Range range)
|
|||
for(uint32_t pc = range.start; pc < range.end; pc += 2)
|
||||
disasm.readins(pc);
|
||||
|
||||
disassemble(session, disasm, { "pcrel", "constprop", "syscall", "print" },
|
||||
-1);
|
||||
disassemble(session, disasm, { "pcrel", /*"constprop",*/ "syscall",
|
||||
"print" }, -1);
|
||||
}
|
||||
|
||||
//---
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#ifndef FXOS_ERRORS_H
|
||||
#define FXOS_ERRORS_H
|
||||
|
||||
#include <fxos/errors.h>
|
||||
#include <fxos/util/format.h>
|
||||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
|
||||
|
@ -29,4 +29,34 @@ private:
|
|||
std::string m_what;
|
||||
};
|
||||
|
||||
/* Syntax errors for commands. */
|
||||
class SyntaxError: public std::exception
|
||||
{
|
||||
public:
|
||||
/* Specifies the file and line of the exception */
|
||||
SyntaxError(char const *file, int line, char const *what):
|
||||
m_file(file), m_line(line), m_what(what) {}
|
||||
|
||||
/* Provides access to these objects */
|
||||
char const *file() const noexcept {
|
||||
return m_file;
|
||||
}
|
||||
int line() const noexcept {
|
||||
return m_line;
|
||||
}
|
||||
char const *what() const noexcept override {
|
||||
return m_what;
|
||||
}
|
||||
|
||||
/* Additional friendly formatter */
|
||||
std::string str() const noexcept {
|
||||
return format("%s:%d: %s", m_file, m_line, m_what);
|
||||
}
|
||||
|
||||
private:
|
||||
char const *m_file;
|
||||
int m_line;
|
||||
char const *m_what;
|
||||
};
|
||||
|
||||
#endif /* FXOS_ERRORS_H */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
%{
|
||||
|
||||
#include "parser.h"
|
||||
#include "errors.h"
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <cctype>
|
||||
|
@ -8,7 +9,6 @@
|
|||
#include <deque>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fxos/errors.h>
|
||||
|
||||
/* Values to attach to the token */
|
||||
typedef Token::Attribute YYSTYPE;
|
||||
|
@ -101,7 +101,7 @@ static void err(char const *format, ...)
|
|||
va_end(args);
|
||||
|
||||
Input const &in = lex_current_input();
|
||||
throw FxOS::SyntaxError(in.filename.c_str(), in.line, buf);
|
||||
throw SyntaxError(in.filename.c_str(), in.line, buf);
|
||||
}
|
||||
|
||||
/* Parse numerical values */
|
||||
|
|
|
@ -122,7 +122,7 @@ void Parser::exhaust_until_separator()
|
|||
try {
|
||||
feed();
|
||||
}
|
||||
catch(FxOS::SyntaxError const &e) {}
|
||||
catch(SyntaxError const &e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue