• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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