get rid of exceptions in the library, use explicit errors

This commit is contained in:
Lephenixnoir 2022-03-27 13:59:49 +01:00
parent 50963d7c20
commit a9660da767
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
22 changed files with 171 additions and 276 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region) 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++)
{

View File

@ -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);
}
//---

View File

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

View File

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

View File

@ -122,7 +122,7 @@ void Parser::exhaust_until_separator()
try {
feed();
}
catch(FxOS::SyntaxError const &e) {}
catch(SyntaxError const &e) {}
}
}