• 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 "../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