diff --git a/fxos/main.cpp b/fxos/main.cpp deleted file mode 100644 index ca52dee..0000000 --- a/fxos/main.cpp +++ /dev/null @@ -1,76 +0,0 @@ -static std::string help_string = colors(R"( -usage: fxos<> [library<>|info<>|disasm<>|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: - -3<>, --sh3<> Assume SH3 OS and platform (default: SH4) - -4<>, --sh4<> Assume SH4 OS and platform (default: SH4) - -v<>, --verbose<> Print logs about what's happening - -fxos library<> [-t<>] [-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: - -t<>, --targets<> Print all targets - -a<>, --asm<> Print all assembler instruction sets - -fxos info<> <

TARGET<>> - Print adentification and basic information about an OS image: version, - platform, date, checksums... - - Target specification: - <

TARGET-NAME<>> Named target in library (eg. "fx@3.10") - -f<> <

FILE<>> Arbitrary file which is loaded as ROM - -fxos disasm<> <

TARGET<>> <

LOCATION<>> [options...] - Disassemble and annotate code with relative address targets, syscalls, - control flow, propagated constants and hints about memory structure. - - Location specifiers: - <

ADDRESS<>> Start disassembling at this address (hexa) - <

ADDRESS<>>:<

LEN<>> Disassemble exactly the specified region.

len<> is an - hexadecimal number optionally followed by k, M, or G. - %<

SYSCALL-ID<>> Start disassembling at this syscall's address (hexa) - <

SYMBOL<>> Disassemble this library symbol (typically syscall name). - A name which is valid hexadecimal is treated as

ADDRESS<>. - Disassembly options: - -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 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 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; - } -} diff --git a/include/fxos/disasm-passes/cfg.h b/include/fxos/disasm-passes/cfg.h index 13979b5..3cfff91 100644 --- a/include/fxos/disasm-passes/cfg.h +++ b/include/fxos/disasm-passes/cfg.h @@ -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 */ diff --git a/include/fxos/disasm-passes/pcrel.h b/include/fxos/disasm-passes/pcrel.h index 58a9895..183ffc5 100644 --- a/include/fxos/disasm-passes/pcrel.h +++ b/include/fxos/disasm-passes/pcrel.h @@ -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 */ diff --git a/include/fxos/disasm-passes/print.h b/include/fxos/disasm-passes/print.h index abebaf4..1da9ffa 100644 --- a/include/fxos/disasm-passes/print.h +++ b/include/fxos/disasm-passes/print.h @@ -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 diff --git a/include/fxos/disasm-passes/syscall.h b/include/fxos/disasm-passes/syscall.h index e3dd28b..e638d63 100644 --- a/include/fxos/disasm-passes/syscall.h +++ b/include/fxos/disasm-passes/syscall.h @@ -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; diff --git a/include/fxos/disassembly.h b/include/fxos/disassembly.h index 562fea8..0fef5c7 100644 --- a/include/fxos/disassembly.h +++ b/include/fxos/disassembly.h @@ -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 */ diff --git a/include/fxos/errors.h b/include/fxos/errors.h deleted file mode 100644 index 8fd74b1..0000000 --- a/include/fxos/errors.h +++ /dev/null @@ -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 -#include -#include - -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 */ diff --git a/include/fxos/util/log.h b/include/fxos/util/log.h index 9c619de..3f19f02 100644 --- a/include/fxos/util/log.h +++ b/include/fxos/util/log.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 */ diff --git a/include/fxos/vspace.h b/include/fxos/vspace.h index ca44885..6ce88c6 100644 --- a/include/fxos/vspace.h +++ b/include/fxos/vspace.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 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 diff --git a/lib/disassembly.cpp b/lib/disassembly.cpp index bb94aa4..3189f25 100644 --- a/lib/disassembly.cpp +++ b/lib/disassembly.cpp @@ -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 */ diff --git a/lib/load-asm.l b/lib/load-asm.l index 53e4a6b..52e12ba 100644 --- a/lib/load-asm.l +++ b/lib/load-asm.l @@ -1,8 +1,8 @@ %{ #include #include -#include #include +#include #include #include @@ -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); } <> { 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) { diff --git a/lib/os.cpp b/lib/os.cpp index 1a16504..24c0290 100644 --- a/lib/os.cpp +++ b/lib/os.cpp @@ -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; diff --git a/lib/passes/cfg.cpp b/lib/passes/cfg.cpp index 18eabac..7d83576 100644 --- a/lib/passes/cfg.cpp +++ b/lib/passes/cfg.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include 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 */ diff --git a/lib/passes/pcrel.cpp b/lib/passes/pcrel.cpp index bb2465b..ff419e5 100644 --- a/lib/passes/pcrel.cpp +++ b/lib/passes/pcrel.cpp @@ -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 */ diff --git a/lib/passes/print.cpp b/lib/passes/print.cpp index 3a3087d..51cbe87 100644 --- a/lib/passes/print.cpp +++ b/lib/passes/print.cpp @@ -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 PrintPass::symquery(Symbol::Type type, diff --git a/lib/passes/syscall.cpp b/lib/passes/syscall.cpp index 672600a..1f8404f 100644 --- a/lib/passes/syscall.cpp +++ b/lib/passes/syscall.cpp @@ -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 */ diff --git a/lib/util/log.cpp b/lib/util/log.cpp index 4d0be64..8ecc943 100644 --- a/lib/util/log.cpp +++ b/lib/util/log.cpp @@ -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 << " "; diff --git a/lib/vspace.cpp b/lib/vspace.cpp index 46a2df5..9c2bee5 100644 --- a/lib/vspace.cpp +++ b/lib/vspace.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -17,18 +16,24 @@ bool AbstractMemory::covers(MemoryRegion const ®ion) const noexcept Addressable 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 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 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 AbstractMemory::read_i16(uint32_t addr) const Addressable 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 AbstractMemory::read_u16(uint32_t addr) const Addressable 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 AbstractMemory::read_i32(uint32_t addr) const Addressable 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 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++) { diff --git a/shell/d.cpp b/shell/d.cpp index 5b72595..1f20d17 100644 --- a/shell/d.cpp +++ b/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); } //--- diff --git a/shell/errors.h b/shell/errors.h index 3e9138b..82edc8c 100644 --- a/shell/errors.h +++ b/shell/errors.h @@ -5,7 +5,7 @@ #ifndef FXOS_ERRORS_H #define FXOS_ERRORS_H -#include +#include #include #include @@ -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 */ diff --git a/shell/lexer.l b/shell/lexer.l index f9cdec2..4b9dab1 100644 --- a/shell/lexer.l +++ b/shell/lexer.l @@ -1,6 +1,7 @@ %{ #include "parser.h" +#include "errors.h" #include #include #include @@ -8,7 +9,6 @@ #include #include -#include /* 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 */ diff --git a/shell/parser.cpp b/shell/parser.cpp index a430e95..07de872 100644 --- a/shell/parser.cpp +++ b/shell/parser.cpp @@ -122,7 +122,7 @@ void Parser::exhaust_until_separator() try { feed(); } - catch(FxOS::SyntaxError const &e) {} + catch(SyntaxError const &e) {} } }