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 "../globals-vixl.h" 35 #include "../utils-vixl.h" 36 #include "cpu-features.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_view cmd_word, 61 std::string_view cmd_alias, 62 std::string_view usage, 63 std::string_view 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 AllocatorWrapper allocator_; 82 83 // Simulator which this command will be performed on. 84 Simulator* sim_; 85 // Stream to output the result of the command to. 86 FILE* ostream_; 87 // Command word that, when given to the interactive debugger, calls Action. 88 String command_word_; 89 // Optional alias for the command_word. 90 String command_alias_; 91 // Optional string showing the arguments that can be passed to the command. 92 String args_str_; 93 // Optional description of the command. 94 String description_; 95 }; 96 97 98 // 99 // Base debugger command handlers: 100 // 101 102 103 class HelpCmd : public DebuggerCmd { 104 public: HelpCmd(Simulator * sim)105 HelpCmd(Simulator* sim) 106 : DebuggerCmd(sim, "help", "h", "", "Display this help message.") {} 107 108 DebugReturn Action(const std::vector<std::string>& args) override; 109 }; 110 111 112 class BreakCmd : public DebuggerCmd { 113 public: BreakCmd(Simulator * sim)114 BreakCmd(Simulator* sim) 115 : DebuggerCmd(sim, 116 "break", 117 "b", 118 "<address>", 119 "Set or remove a breakpoint.") {} 120 121 DebugReturn Action(const std::vector<std::string>& args) override; 122 }; 123 124 125 class StepCmd : public DebuggerCmd { 126 public: StepCmd(Simulator * sim)127 StepCmd(Simulator* sim) 128 : DebuggerCmd(sim, 129 "step", 130 "s", 131 "[<n>]", 132 "Step n instructions, default step 1 instruction.") {} 133 134 DebugReturn Action(const std::vector<std::string>& args) override; 135 }; 136 137 138 class ContinueCmd : public DebuggerCmd { 139 public: ContinueCmd(Simulator * sim)140 ContinueCmd(Simulator* sim) 141 : DebuggerCmd(sim, 142 "continue", 143 "c", 144 "", 145 "Exit the debugger and continue executing instructions.") {} 146 147 DebugReturn Action(const std::vector<std::string>& args) override; 148 }; 149 150 151 class PrintCmd : public DebuggerCmd { 152 public: PrintCmd(Simulator * sim)153 PrintCmd(Simulator* sim) 154 : DebuggerCmd(sim, 155 "print", 156 "p", 157 "<register|all|system>", 158 "Print the contents of a register, all registers or all" 159 " system registers.") {} 160 161 DebugReturn Action(const std::vector<std::string>& args) override; 162 }; 163 164 165 class TraceCmd : public DebuggerCmd { 166 public: TraceCmd(Simulator * sim)167 TraceCmd(Simulator* sim) 168 : DebuggerCmd(sim, 169 "trace", 170 "t", 171 "", 172 "Start/stop memory and register tracing.") {} 173 174 DebugReturn Action(const std::vector<std::string>& args) override; 175 }; 176 177 178 class GdbCmd : public DebuggerCmd { 179 public: GdbCmd(Simulator * sim)180 GdbCmd(Simulator* sim) 181 : DebuggerCmd(sim, 182 "gdb", 183 "g", 184 "", 185 "Enter an already running instance of gdb.") {} 186 187 DebugReturn Action(const std::vector<std::string>& args) override; 188 }; 189 190 191 // A debugger for the Simulator which takes input from the user in order to 192 // control the running of the Simulator. 193 class Debugger { 194 public: 195 // A pair consisting of a register character (e.g: W, X, V) and a register 196 // code (e.g: 0, 1 ...31) which represents a single parsed register. 197 // 198 // Note: the register character is guaranteed to be upper case. 199 using RegisterParsedFormat = std::pair<char, unsigned>; 200 201 Debugger(Simulator* sim); 202 203 // Set the input stream, from which commands are read, to a custom stream. SetInputStream(std::istream * stream)204 void SetInputStream(std::istream* stream) { input_stream_ = stream; } 205 206 // Register a new command for the debugger. 207 template <class T> 208 void RegisterCmd(); 209 210 // Set a breakpoint at the given address. RegisterBreakpoint(uint64_t addr)211 void RegisterBreakpoint(uint64_t addr) { breakpoints_.insert(addr); } 212 // Remove a breakpoint at the given address. RemoveBreakpoint(uint64_t addr)213 void RemoveBreakpoint(uint64_t addr) { breakpoints_.erase(addr); } 214 // Return true if the address is the location of a breakpoint. IsBreakpoint(uint64_t addr)215 bool IsBreakpoint(uint64_t addr) const { 216 return (breakpoints_.find(addr) != breakpoints_.end()); 217 } 218 // Return true if the simulator pc is a breakpoint. 219 bool IsAtBreakpoint() const; 220 221 // Main loop for the debugger. Keep prompting for user inputted debugger 222 // commands and try to execute them until a command is given that exits the 223 // interactive debugger. 224 void Debug(); 225 226 // Get an unsigned integer value from a string and return it in 'value'. 227 // Base is used to determine the numeric base of the number to be read, 228 // i.e: 8 for octal, 10 for decimal, 16 for hexadecimal and 0 for 229 // auto-detect. Return true if an integer value was found, false otherwise. 230 static std::optional<uint64_t> ParseUint64String(std::string_view uint64_str, 231 int base = 0); 232 233 // Get a register from a string and return it in 'reg'. Return true if a 234 // valid register character and code (e.g: W0, X29, V31) was found, false 235 // otherwise. 236 static std::optional<RegisterParsedFormat> ParseRegString( 237 std::string_view reg_str); 238 239 // Print the usage of each debugger command. 240 void PrintUsage(); 241 242 private: 243 // Split a string based on the separator given (a single space character by 244 // default) and return as a std::vector of strings. 245 static std::vector<std::string> Tokenize(std::string_view input_line, 246 char separator = ' '); 247 248 // Try to execute a single debugger command. 249 DebugReturn ExecDebugCommand(const std::vector<std::string>& tokenized_cmd); 250 251 // Return true if the string is zero, i.e: all characters in the string 252 // (other than prefixes) are zero. 253 static bool IsZeroUint64String(std::string_view uint64_str, int base); 254 255 // The simulator that this debugger acts on. 256 Simulator* sim_; 257 258 // A vector of all commands recognised by the debugger. 259 #ifndef VIXL_USE_PANDA_ALLOC 260 std::vector<std::unique_ptr<DebuggerCmd>> debugger_cmds_; 261 #else 262 Vector<DebuggerCmd*> debugger_cmds_; 263 #endif 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 UnorderedSet<uint64_t> breakpoints_; 268 269 // Input stream from which commands are read. Default is std::cin. 270 std::istream* input_stream_; 271 272 // Output stream from the simulator. 273 FILE* ostream_; 274 }; 275 276 277 } // namespace aarch64 278 } // namespace vixl 279 280 #endif // VIXL_INCLUDE_SIMULATOR_AARCH64 281 282 #endif // VIXL_AARCH64_DEBUGGER_AARCH64_H_ 283