diff --git a/fxos/main.cpp b/fxos/main.cpp index 8a40012..398c12d 100644 --- a/fxos/main.cpp +++ b/fxos/main.cpp @@ -21,82 +21,67 @@ namespace fs = std::filesystem; using namespace FxOS; using namespace FxOS::Log; -static char const *help_string = R"( -usage: fxos library [-t] [-a] - fxos info - fxos disasm [options...] - fxos analyze [-f] [-s] [-a] [-r] [options...] +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 fx9860g and fxcg50-like CASIO calculators, using an -editable database of platform, syscall, and OS knowledge. +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 + -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 -A is either: - A target in library (eg "fx@3.10") - -f An arbitrary file which is loaded as ROM +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. -LIBRARY COMMAND + Selectors: + -t<>, --targets<> Print all targets + -a<>, --asm<> Print all assembler instruction sets -Prints out the contents of the library. If an option is set, the results are -printed in a simple easily-parsable form without header. +fxos info<> <

TARGET<>> + Print adentification and basic information about an OS image: version, + platform, date, checksums... -Selectors: - -t, --targets Print all targets - -a, --asm Print all assembler instruction sets + Target specification: + <

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

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

TARGET<>> <

LOCATION<>> [options...] + Disassemble and annotate code with relative address targets, syscalls, + control flow, propagated constants and hints about memory structure. -Identify an OS image: version, platform, date, checksums... + 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 -DISASM COMMAND + 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); -Disassemble and annotate code with relative address targets, syscalls, control -flow, propagated constants and hints about memory structure. - -Location specifiers: -

Start disassembling at this address (hexa) -
: Disassemble exactly the specified region. is an - hexadecimal number optionally followed by k, M, or G. - % Start disassembling at this syscall's address (hexa) - Disassemble this library symbol (typically a syscall name). - Note that
takes precedence if ambiguous. - -Disassembly options: - -p 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 explore the function. - -ANALYZE COMMAND - -Dig an address or syscall number. Finds syscall references, 4-aligned -occurrences, memory region... - -Analysis modes: - -f, --full Run all analysis passes on (same as -sar) - -s, --syscall Run syscall ID analysis - -a, --address Run code/data address analyis - -r, --register Run peripheral register analysis - -Analysis options: - --occurrences Show at most occurrences (integer or "all") -)"+1; +/* fxos analyze [-f] [-s] [-a] [-r] [options...] + -f, --full Run all analysis passes on (same as -sar) + -s, --syscall Run syscall ID analysis + -a, --address Run code/data address analyis + -r, --register Run peripheral register analysis */ #define usage(exitcode) { \ std::cerr << help_string; \ - return exitcode; \ + return exitcode; \ } //--- diff --git a/include/fxos/util.h b/include/fxos/util.h index 6aaeb44..532fa5f 100644 --- a/include/fxos/util.h +++ b/include/fxos/util.h @@ -49,6 +49,9 @@ std::string format(std::string const &format, Args && ... args) return format_do(format, format_convert(std::forward(args))...); } +/* Format a string with colors */ +std::string colors(std::string str); + /* An object extracted from a target, which has a virtual address */ template struct Addressable diff --git a/lib/util.cpp b/lib/util.cpp index 2a6c241..870d6fd 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,30 @@ namespace fs = std::filesystem; +std::string colors(std::string str) +{ + std::map colors = { + // Gray, Red, Green, Yello, Blue, Magenta, Cyan, White + {'A',"30;1"}, {'R',"31;1"}, {'G',"32;1"}, {'Y',"33;1"}, + {'B',"34;1"}, {'M',"35;1"}, {'C',"36;1"}, {'W',"37;1"}, + // Same but without bold + {'a',"30"}, {'r',"31"}, {'g',"32"}, {'y',"33"}, + {'b',"34"}, {'m',"35"}, {'c',"36"}, {'w',"37"}, + // Italic, parameter shortcut + {'i',"3"}, {'P',"32m\x1b[3"}, + }; + bool show = isatty(STDOUT_FILENO); + + for(size_t i = 0; i < str.size() - 2; i++) { + if(str[i] == '<' && str[i+1] == '>') + str.replace(i, 2, show ? "\x1b[0m" : ""); + else if(str[i] == '<' && str[i+2] == '>' && colors.count(str[i+1])) + str.replace(i, 3, show ? "\x1b[" + colors[str[i+1]] + "m" : ""); + } + + return str; +} + Buffer::Buffer(): size {0}, data {nullptr}, path {"(none)"} {