From 1082c451d2beb20596ae37becb6a9baaa08515ff Mon Sep 17 00:00:00 2001 From: Dr-Carlos Date: Mon, 5 Dec 2022 15:43:58 +1030 Subject: [PATCH 1/4] Remove _dr and add token options to atom and expr --- shell/d.cpp | 122 +++++++++++++++++++++++------------------------ shell/parser.cpp | 13 +++-- shell/parser.h | 4 +- 3 files changed, 71 insertions(+), 68 deletions(-) diff --git a/shell/d.cpp b/shell/d.cpp index 79aacb6..cf96982 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -69,72 +69,78 @@ static void disassemble(Session &session, Disassembly &disasm, // d //--- -static uint32_t parse_d(Session &session, Parser &parser) +struct _d_args +{ + std::optional address; + std::optional range; +}; + +static _d_args parse_d(Session &session, Parser &parser) { if(!session.current_space) - return 0; + return {}; + uint32_t address = session.current_space->cursor; - if(!parser.at_end()) - address = parser.expr(session.current_space); + if(!parser.at_end()) { + Token t = parser.lookahead(); + + try { + Range range = parser.range(session.current_space); + parser.end(); + return {{}, range}; + } + catch(...) { + address = parser.expr(session.current_space, t); + } + } parser.end(); - return address; + return {address, {}}; } -void _d(Session &session, uint32_t address) +void _d(Session &session, std::optional address_opt, + std::optional range_opt) { if(!session.current_space) return; FxOS::Disassembly disasm(*session.current_space); - if(address & 1) { - fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", address, - address + 1); - address++; + if(address_opt.has_value()) { + uint32_t address = address_opt.value(); + + if(address & 1) { + fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", + address, address + 1); + address++; + } + + disassemble(session, disasm, + {"cfg", "pcrel", /*"constprop",*/ "syscall", "print"}, address); } + else if(range_opt.has_value()) { + Range range = range_opt.value(); + if(range.start & 1) { + fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", + range.start, range.start + 1); + range.start++; + } + if(range.end & 1) { + fmt::print("address 0x{:08x} is odd, ending at 0x{:08x}\n", + range.end, range.end - 1); + range.end--; + } - disassemble(session, disasm, - {"cfg", "pcrel", /*"constprop",*/ "syscall", "print"}, address); -} + if(range.start >= range.end) + return; -//--- -// dr -//--- + /* Load the block into memory */ + for(uint32_t pc = range.start; pc < range.end; pc += 2) + disasm.getInstructionAt(pc, true); -static Range parse_dr(Session &session, Parser &parser) -{ - Range range = parser.range(session.current_space); - parser.end(); - return range; -} - -void _dr(Session &session, Range range) -{ - if(!session.current_space) - return; - FxOS::Disassembly disasm(*session.current_space); - - if(range.start & 1) { - fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", - range.start, range.start + 1); - range.start++; + disassemble(session, disasm, + {"pcrel", /*"constprop",*/ "syscall", "print"}, -1); } - if(range.end & 1) { - fmt::print("address 0x{:08x} is odd, ending at 0x{:08x}\n", range.end, - range.end - 1); - range.end--; - } - - if(range.start >= range.end) - return; - - /* Load the block into memory */ - for(uint32_t pc = range.start; pc < range.end; pc += 2) - disasm.getInstructionAt(pc, true); - - disassemble( - session, disasm, {"pcrel", /*"constprop",*/ "syscall", "print"}, -1); } //--- @@ -142,9 +148,13 @@ void _dr(Session &session, Range range) //--- static ShellCommand _d_cmd( - "d", [](Session &s, Parser &p) { _d(s, parse_d(s, p)); }, + "d", + [](Session &s, Parser &p) { + auto args = parse_d(s, p); + _d(s, args.address, args.range); + }, [](Session &s, Parser &p) { parse_d(s, p); }, "Disassemble", R"( -d [
] +d [] Disassembles code starting at the specified address, exploring branches until function terminators, invalid instructions, or dynamically-computed jumps. The @@ -159,15 +169,3 @@ The following disassembler passes are run: pcrel Computes PC-relative addresses (eg mov.l, mova, bf, bra...) syscall Annotates uses of syscall table entries with the syscall number )"); - -static ShellCommand _dr_cmd( - "dr", [](Session &s, Parser &p) { _dr(s, parse_dr(s, p)); }, - [](Session &s, Parser &p) { parse_dr(s, p); }, "Disassemble Range", R"( -dr [] - -Disassembles an explicit region of memory. This is similar to d, except that -the disassembled code is pre-loaded from the region instead of being explored -by the cfg pass. See d? for more information. - -Like d, this command does not extend the virtual space's main disassembly. -)"); diff --git a/shell/parser.cpp b/shell/parser.cpp index 1fa09a2..8c81f27 100644 --- a/shell/parser.cpp +++ b/shell/parser.cpp @@ -304,9 +304,14 @@ void Parser::accept_options() // Parsing rules for expressions //--- -long Parser::atom() +long Parser::atom(std::optional token) { - Token t = expect({'$', '(', '-', T::SYMBOL, T::NUM, T::SYSCALL}); + Token t; + + if(token.has_value()) + t = token.value(); + else + t = expect({'$', '(', '-', T::SYMBOL, T::NUM, T::SYSCALL}); if(t.type == T::SYMBOL) { /* TODO: Specify the space that symbols are taken from */ @@ -390,10 +395,10 @@ long Parser::term() return v; } -long Parser::expr(VirtualSpace *space) +long Parser::expr(VirtualSpace *space, std::optional token) { m_expr_space = space; - long val = atom(); + long val = atom(token); m_expr_space = nullptr; return val; } diff --git a/shell/parser.h b/shell/parser.h index 9de9771..92dc0e7 100644 --- a/shell/parser.h +++ b/shell/parser.h @@ -141,7 +141,7 @@ public: /* Read a numerical constant, or an expression. Expression uses the space to access the program counter and query symbol values */ long num(); - long expr(VirtualSpace *space); + long expr(VirtualSpace *space, std::optional token={}); /* Read a range; again $ and symbols are interpreted. If (before) and (after) are both specified, a single value will also be accepted, and the range [value+before, value.after) will be returned. */ @@ -191,7 +191,7 @@ private: /* Parsing rules for expressions */ long term(); long factor(); - long atom(); + long atom(std::optional token={}); /* true if we're completing a partial command, false if we're parsing a finished one */ From 2f2e4bb1d5bb60ea906aab2dd3c056db5e5256b4 Mon Sep 17 00:00:00 2001 From: Dr-Carlos Date: Sat, 17 Dec 2022 20:35:29 +1030 Subject: [PATCH 2/4] shell: provide parser with expr_or_range() function --- shell/d.cpp | 13 ++++++------- shell/parser.cpp | 40 +++++++++++++++++++++------------------- shell/parser.h | 5 ++++- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/shell/d.cpp b/shell/d.cpp index cf96982..2468ae1 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -83,15 +83,14 @@ static _d_args parse_d(Session &session, Parser &parser) uint32_t address = session.current_space->cursor; if(!parser.at_end()) { - Token t = parser.lookahead(); + auto v = parser.expr_or_range(session.current_space); - try { - Range range = parser.range(session.current_space); - parser.end(); - return {{}, range}; + if(std::holds_alternative(v)) { + address = std::get(v); } - catch(...) { - address = parser.expr(session.current_space, t); + else { + // TODO: Use an args struct etc. This is placeholder. + address = std::get(v).start; } } diff --git a/shell/parser.cpp b/shell/parser.cpp index 8c81f27..7a7e41d 100644 --- a/shell/parser.cpp +++ b/shell/parser.cpp @@ -142,24 +142,7 @@ void Parser::dump_command() { while(!at_end()) { Token t = m_la; - - if(t.type == T::NUM) - fmt::print("NUM {:#x}\n", t.value.NUM); - else if(t.type == T::SYSCALL) - fmt::print("SYSCALL %{:04x}\n", t.value.NUM); - else if(t.type == T::SYMBOL) - fmt::print("SYMBOL '{}'\n", t.value.STRING); - else if(t.type == T::OPTION) - fmt::print("OPTION '{}'\n", t.value.STRING); - else if(t.type == T::STRING) - fmt::print("STRING '{}'\n", t.value.STRING); - else if(t.type == '>') - fmt::print(">>\n"); - else if(t.type == '<') - fmt::print("<<\n"); - else - fmt::print("{}\n", (char)t.type); - + fmt::print("{}\n", t.str()); feed(); } } @@ -246,7 +229,7 @@ Range Parser::range(VirtualSpace *space, long before, long after) { long start = expr(space); - /* Accept non-rangs if (before) and (after) are provided */ + /* Accept non-ranges if (before) and (after) are provided */ if(m_la.type != ':' && m_la.type != '.' && before >= 0 && after >= 0) return {start - before, start + after}; @@ -259,6 +242,25 @@ Range Parser::range(VirtualSpace *space, long before, long after) return r; } +std::variant Parser::expr_or_range(VirtualSpace *space) +{ + long start = expr(space); + + if(m_la.type == ':') { + expect(':'); + long length = expr(space); + return (Range){start, start + length}; + } + else if(m_la.type == '.') { + expect('.'); + long end = expr(space); + return (Range){start, end}; + } + else { + return (long)start; + } +} + FxOS::MemoryRegion Parser::region(VirtualSpace *space, long before, long after) { if(m_la.type == '$' || m_la.type == '(' || m_la.type == '-' diff --git a/shell/parser.h b/shell/parser.h index 92dc0e7..46660cc 100644 --- a/shell/parser.h +++ b/shell/parser.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -144,8 +145,10 @@ public: long expr(VirtualSpace *space, std::optional token={}); /* Read a range; again $ and symbols are interpreted. If (before) and (after) are both specified, a single value will also be accepted, and - the range [value+before, value.after) will be returned. */ + the range [value-before, value+after) will be returned. */ Range range(VirtualSpace *space, long before=-1, long after=-1); + /* Read an expression or a range */ + std::variant expr_or_range(VirtualSpace *space); /* Read a memory region (allows both ranges and symbolic names) */ FxOS::MemoryRegion region(VirtualSpace *space, long before=-1, long after=-1); From c66ae1d5c6b5342ed2dce0bbfa25ce6ba4ebe24b Mon Sep 17 00:00:00 2001 From: Dr-Carlos Date: Sat, 17 Dec 2022 20:31:59 +1030 Subject: [PATCH 3/4] _d: use expr_or_range to allow addresses or ranges --- shell/d.cpp | 43 ++++++++++++++++++++++--------------------- shell/parser.cpp | 13 ++++--------- shell/parser.h | 4 ++-- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/shell/d.cpp b/shell/d.cpp index 2468ae1..d688680 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -77,25 +77,25 @@ struct _d_args static _d_args parse_d(Session &session, Parser &parser) { + _d_args args; + if(!session.current_space) return {}; - uint32_t address = session.current_space->cursor; + args.address = session.current_space->cursor; + args.range = {}; if(!parser.at_end()) { auto v = parser.expr_or_range(session.current_space); - if(std::holds_alternative(v)) { - address = std::get(v); - } - else { - // TODO: Use an args struct etc. This is placeholder. - address = std::get(v).start; - } + if(std::holds_alternative(v)) + args.address = std::get(v); + else + args.range = std::get(v); } parser.end(); - return {address, {}}; + return args; } void _d(Session &session, std::optional address_opt, @@ -105,19 +105,8 @@ void _d(Session &session, std::optional address_opt, return; FxOS::Disassembly disasm(*session.current_space); - if(address_opt.has_value()) { - uint32_t address = address_opt.value(); - if(address & 1) { - fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", - address, address + 1); - address++; - } - - disassemble(session, disasm, - {"cfg", "pcrel", /*"constprop",*/ "syscall", "print"}, address); - } - else if(range_opt.has_value()) { + if(range_opt.has_value()) { Range range = range_opt.value(); if(range.start & 1) { fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", @@ -140,6 +129,18 @@ void _d(Session &session, std::optional address_opt, disassemble(session, disasm, {"pcrel", /*"constprop",*/ "syscall", "print"}, -1); } + else if(address_opt.has_value()) { + uint32_t address = address_opt.value(); + + if(address & 1) { + fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", + address, address + 1); + address++; + } + + disassemble(session, disasm, + {"cfg", "pcrel", /*"constprop",*/ "syscall", "print"}, address); + } } //--- diff --git a/shell/parser.cpp b/shell/parser.cpp index 7a7e41d..c826ca2 100644 --- a/shell/parser.cpp +++ b/shell/parser.cpp @@ -306,14 +306,9 @@ void Parser::accept_options() // Parsing rules for expressions //--- -long Parser::atom(std::optional token) +long Parser::atom() { - Token t; - - if(token.has_value()) - t = token.value(); - else - t = expect({'$', '(', '-', T::SYMBOL, T::NUM, T::SYSCALL}); + Token t = expect({'$', '(', '-', T::SYMBOL, T::NUM, T::SYSCALL}); if(t.type == T::SYMBOL) { /* TODO: Specify the space that symbols are taken from */ @@ -397,10 +392,10 @@ long Parser::term() return v; } -long Parser::expr(VirtualSpace *space, std::optional token) +long Parser::expr(VirtualSpace *space) { m_expr_space = space; - long val = atom(token); + long val = atom(); m_expr_space = nullptr; return val; } diff --git a/shell/parser.h b/shell/parser.h index 46660cc..693df9f 100644 --- a/shell/parser.h +++ b/shell/parser.h @@ -142,7 +142,7 @@ public: /* Read a numerical constant, or an expression. Expression uses the space to access the program counter and query symbol values */ long num(); - long expr(VirtualSpace *space, std::optional token={}); + long expr(VirtualSpace *space); /* Read a range; again $ and symbols are interpreted. If (before) and (after) are both specified, a single value will also be accepted, and the range [value-before, value+after) will be returned. */ @@ -194,7 +194,7 @@ private: /* Parsing rules for expressions */ long term(); long factor(); - long atom(std::optional token={}); + long atom(); /* true if we're completing a partial command, false if we're parsing a finished one */ From 111620a649387bd914419e11566a648b2bec03fe Mon Sep 17 00:00:00 2001 From: Dr-Carlos Date: Sun, 18 Dec 2022 07:22:09 +1030 Subject: [PATCH 4/4] _d: determine address or range in _d --- shell/d.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/shell/d.cpp b/shell/d.cpp index d688680..d892089 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -71,8 +71,7 @@ static void disassemble(Session &session, Disassembly &disasm, struct _d_args { - std::optional address; - std::optional range; + std::variant location; }; static _d_args parse_d(Session &session, Parser &parser) @@ -82,32 +81,23 @@ static _d_args parse_d(Session &session, Parser &parser) if(!session.current_space) return {}; - args.address = session.current_space->cursor; - args.range = {}; - - if(!parser.at_end()) { - auto v = parser.expr_or_range(session.current_space); - - if(std::holds_alternative(v)) - args.address = std::get(v); - else - args.range = std::get(v); - } + args.location = parser.at_end() + ? session.current_space->cursor + : parser.expr_or_range(session.current_space); parser.end(); return args; } -void _d(Session &session, std::optional address_opt, - std::optional range_opt) +void _d(Session &session, std::variant location) { if(!session.current_space) return; FxOS::Disassembly disasm(*session.current_space); - if(range_opt.has_value()) { - Range range = range_opt.value(); + if(std::holds_alternative(location)) { + Range range = std::get(location); if(range.start & 1) { fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", range.start, range.start + 1); @@ -129,8 +119,8 @@ void _d(Session &session, std::optional address_opt, disassemble(session, disasm, {"pcrel", /*"constprop",*/ "syscall", "print"}, -1); } - else if(address_opt.has_value()) { - uint32_t address = address_opt.value(); + else { + uint32_t address = std::get(location); if(address & 1) { fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n", @@ -151,7 +141,7 @@ static ShellCommand _d_cmd( "d", [](Session &s, Parser &p) { auto args = parse_d(s, p); - _d(s, args.address, args.range); + _d(s, args.location); }, [](Session &s, Parser &p) { parse_d(s, p); }, "Disassemble", R"( d []