1 // Copyright 2023, VIXL authors 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #ifndef VIXL_AARCH64_DEBUGGER_AARCH64_H_ 28 #define VIXL_AARCH64_DEBUGGER_AARCH64_H_ 29 30 #include <optional> 31 #include <unordered_set> 32 #include <vector> 33 34 #include "../cpu-features.h" 35 #include "../globals-vixl.h" 36 #include "../utils-vixl.h" 37 38 #include "abi-aarch64.h" 39 #include "cpu-features-auditor-aarch64.h" 40 #include "disasm-aarch64.h" 41 #include "instructions-aarch64.h" 42 #include "simulator-aarch64.h" 43 #include "simulator-constants-aarch64.h" 44 45 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64 46 47 namespace vixl { 48 namespace aarch64 { 49 50 class Simulator; 51 52 enum DebugReturn { DebugContinue, DebugExit }; 53 54 55 // A debugger command that performs some action when used by the simulator 56 // debugger. 57 class DebuggerCmd { 58 public: 59 DebuggerCmd(Simulator* sim, 60 std::string cmd_word, 61 std::string cmd_alias, 62 std::string usage, 63 std::string description); ~DebuggerCmd()64 virtual ~DebuggerCmd() {} 65 66 // Perform some action based on the arguments passed in. Returns true if the 67 // debugger should exit after the action, false otherwise. 68 virtual DebugReturn Action(const std::vector<std::string>& args) = 0; 69 70 // Return the command word. GetCommandWord()71 std::string_view GetCommandWord() { return command_word_; } 72 // Return the alias for this command. Returns an empty string if this command 73 // has no alias. GetCommandAlias()74 std::string_view GetCommandAlias() { return command_alias_; } 75 // Return this commands usage. GetArgsString()76 std::string_view GetArgsString() { return args_str_; } 77 // Return this commands description. GetDescription()78 std::string_view GetDescription() { return description_; } 79 80 protected: 81 // Simulator which this command will be performed on. 82 Simulator* sim_; 83 // Stream to output the result of the command to. 84 FILE* ostream_; 85 // Command word that, when given to the interactive debugger, calls Action. 86 std::string command_word_; 87 // Optional alias for the command_word. 88 std::string command_alias_; 89 // Optional string showing the arguments that can be passed to the command. 90 std::string args_str_; 91 // Optional description of the command. 92 std::string description_; 93 }; 94 95 96 // 97 // Base debugger command handlers: 98 // 99 100 101 class HelpCmd : public DebuggerCmd { 102 public: HelpCmd(Simulator * sim)103 HelpCmd(Simulator* sim) 104 : DebuggerCmd(sim, "help", "h", "", "Display this help message.") {} 105 106 DebugReturn Action(const std::vector<std::string>& args) override; 107 }; 108 109 110 class BreakCmd : public DebuggerCmd { 111 public: BreakCmd(Simulator * sim)112 BreakCmd(Simulator* sim) 113 : DebuggerCmd(sim, 114 "break", 115 "b", 116 "<address>", 117 "Set or remove a breakpoint.") {} 118 119 DebugReturn Action(const std::vector<std::string>& args) override; 120 }; 121 122 123 class StepCmd : public DebuggerCmd { 124 public: StepCmd(Simulator * sim)125 StepCmd(Simulator* sim) 126 : DebuggerCmd(sim, 127 "step", 128 "s", 129 "[<n>]", 130 "Step n instructions, default step 1 instruction.") {} 131 132 DebugReturn Action(const std::vector<std::string>& args) override; 133 }; 134 135 136 class ContinueCmd : public DebuggerCmd { 137 public: ContinueCmd(Simulator * sim)138 ContinueCmd(Simulator* sim) 139 : DebuggerCmd(sim, 140 "continue", 141 "c", 142 "", 143 "Exit the debugger and continue executing instructions.") {} 144 145 DebugReturn Action(const std::vector<std::string>& args) override; 146 }; 147 148 149 class PrintCmd : public DebuggerCmd { 150 public: PrintCmd(Simulator * sim)151 PrintCmd(Simulator* sim) 152 : DebuggerCmd(sim, 153 "print", 154 "p", 155 "<register|all|system>", 156 "Print the contents of a register, all registers or all" 157 " system registers.") {} 158 159 DebugReturn Action(const std::vector<std::string>& args) override; 160 }; 161 162 163 class TraceCmd : public DebuggerCmd { 164 public: TraceCmd(Simulator * sim)165 TraceCmd(Simulator* sim) 166 : DebuggerCmd(sim, 167 "trace", 168 "t", 169 "", 170 "Start/stop memory and register tracing.") {} 171 172 DebugReturn Action(const std::vector<std::string>& args) override; 173 }; 174 175 176 class GdbCmd : public DebuggerCmd { 177 public: GdbCmd(Simulator * sim)178 GdbCmd(Simulator* sim) 179 : DebuggerCmd(sim, 180 "gdb", 181 "g", 182 "", 183 "Enter an already running instance of gdb.") {} 184 185 DebugReturn Action(const std::vector<std::string>& args) override; 186 }; 187 188 189 // A debugger for the Simulator which takes input from the user in order to 190 // control the running of the Simulator. 191 class Debugger { 192 public: 193 // A pair consisting of a register character (e.g: W, X, V) and a register 194 // code (e.g: 0, 1 ...31) which represents a single parsed register. 195 // 196 // Note: the register character is guaranteed to be upper case. 197 using RegisterParsedFormat = std::pair<char, unsigned>; 198 199 Debugger(Simulator* sim); 200 201 // Set the input stream, from which commands are read, to a custom stream. SetInputStream(std::istream * stream)202 void SetInputStream(std::istream* stream) { input_stream_ = stream; } 203 204 // Register a new command for the debugger. 205 template <class T> 206 void RegisterCmd(); 207 208 // Set a breakpoint at the given address. RegisterBreakpoint(uint64_t addr)209 void RegisterBreakpoint(uint64_t addr) { breakpoints_.insert(addr); } 210 // Remove a breakpoint at the given address. RemoveBreakpoint(uint64_t addr)211 void RemoveBreakpoint(uint64_t addr) { breakpoints_.erase(addr); } 212 // Return true if the address is the location of a breakpoint. IsBreakpoint(uint64_t addr)213 bool IsBreakpoint(uint64_t addr) const { 214 return (breakpoints_.find(addr) != breakpoints_.end()); 215 } 216 // Return true if the simulator pc is a breakpoint. 217 bool IsAtBreakpoint() const; 218 219 // Main loop for the debugger. Keep prompting for user inputted debugger 220 // commands and try to execute them until a command is given that exits the 221 // interactive debugger. 222 void Debug(); 223 224 // Get an unsigned integer value from a string and return it in 'value'. 225 // Base is used to determine the numeric base of the number to be read, 226 // i.e: 8 for octal, 10 for decimal, 16 for hexadecimal and 0 for 227 // auto-detect. Return true if an integer value was found, false otherwise. 228 static std::optional<uint64_t> ParseUint64String(std::string_view uint64_str, 229 int base = 0); 230 231 // Get a register from a string and return it in 'reg'. Return true if a 232 // valid register character and code (e.g: W0, X29, V31) was found, false 233 // otherwise. 234 static std::optional<RegisterParsedFormat> ParseRegString( 235 std::string_view reg_str); 236 237 // Print the usage of each debugger command. 238 void PrintUsage(); 239 240 private: 241 // Split a string based on the separator given (a single space character by 242 // default) and return as a std::vector of strings. 243 static std::vector<std::string> Tokenize(std::string_view input_line, 244 char separator = ' '); 245 246 // Try to execute a single debugger command. 247 DebugReturn ExecDebugCommand(const std::vector<std::string>& tokenized_cmd); 248 249 // Return true if the string is zero, i.e: all characters in the string 250 // (other than prefixes) are zero. 251 static bool IsZeroUint64String(std::string_view uint64_str, int base); 252 253 // The simulator that this debugger acts on. 254 Simulator* sim_; 255 256 // A vector of all commands recognised by the debugger. 257 std::vector<std::unique_ptr<DebuggerCmd>> debugger_cmds_; 258 259 // Input stream from which commands are read. Default is std::cin. 260 std::istream* input_stream_; 261 262 // Output stream from the simulator. 263 FILE* ostream_; 264 265 // A list of all instruction addresses that, when executed by the 266 // simulator, will start the interactive debugger if it hasn't already. 267 std::unordered_set<uint64_t> breakpoints_; 268 }; 269 270 271 } // namespace aarch64 272 } // namespace vixl 273 274 #endif // VIXL_INCLUDE_SIMULATOR_AARCH64 275 276 #endif // VIXL_AARCH64_DEBUGGER_AARCH64_H_ 277