1b8021494Sopenharmony_ciDebugging with the VIXL Simulator 2b8021494Sopenharmony_ci================================= 3b8021494Sopenharmony_ci 4b8021494Sopenharmony_ciThe VIXL AArch64 simulator contains a basic debugger which can be used to debug 5b8021494Sopenharmony_cisimulated applications. The debugger supports basic debugging features such as 6b8021494Sopenharmony_cisetting breakpoints, stepping through simulated instructions and printing 7b8021494Sopenharmony_cisimulator specific information, for example: printing the values of a register 8b8021494Sopenharmony_cior printing instructions at specified addresses. 9b8021494Sopenharmony_ci 10b8021494Sopenharmony_ciUsing the Debugger 11b8021494Sopenharmony_ci------------------ 12b8021494Sopenharmony_ci 13b8021494Sopenharmony_ciIn order to use the debugger it first needs to be enabled in the simulator. 14b8021494Sopenharmony_ci 15b8021494Sopenharmony_ci```C++ 16b8021494Sopenharmony_ci Decoder decoder; 17b8021494Sopenharmony_ci Simulator simulator(&decoder); 18b8021494Sopenharmony_ci simulator.SetDebuggerEnabled(true); 19b8021494Sopenharmony_ci``` 20b8021494Sopenharmony_ci 21b8021494Sopenharmony_ciOnce enabled, the debugger will be activated whenever a breakpoint (brk) is 22b8021494Sopenharmony_ciencountered by the simulator. For example: 23b8021494Sopenharmony_ci 24b8021494Sopenharmony_ci```asm 25b8021494Sopenharmony_ci add x1, x0, #5 26b8021494Sopenharmony_ci mov x2, #2 27b8021494Sopenharmony_ci 28b8021494Sopenharmony_ci brk 0 // Debugger activated here. 29b8021494Sopenharmony_ci 30b8021494Sopenharmony_ci sub x3, x1, x2 31b8021494Sopenharmony_ci``` 32b8021494Sopenharmony_ci 33b8021494Sopenharmony_ciFurther breakpoints can be set either programmatically or interactively in the 34b8021494Sopenharmony_cidebugger itself. For example, to set breakpoints programmatically: 35b8021494Sopenharmony_ci 36b8021494Sopenharmony_ci```C++ 37b8021494Sopenharmony_ci // 'func' is an AARCH64 assembly function. 38b8021494Sopenharmony_ci extern "C" void func(); 39b8021494Sopenharmony_ci 40b8021494Sopenharmony_ci Debugger* debugger = simulator.GetDebugger(); 41b8021494Sopenharmony_ci 42b8021494Sopenharmony_ci // Register a breakpoint at a fixed (absolute) address. 43b8021494Sopenharmony_ci debugger->RegisterBreakpoint(0x00007ffbc6d38000); 44b8021494Sopenharmony_ci 45b8021494Sopenharmony_ci // Register a breakpoint to an already existing assembly function. 46b8021494Sopenharmony_ci debugger->RegisterBreakpoint(reinterpret_cast<uint64_t>(&func)); 47b8021494Sopenharmony_ci``` 48b8021494Sopenharmony_ci 49b8021494Sopenharmony_ciOr to set breakpoints interactively once the debugger has been activated: 50b8021494Sopenharmony_ci 51b8021494Sopenharmony_ci```sh 52b8021494Sopenharmony_ci sim> break 0x00007ffbc6d38000 53b8021494Sopenharmony_ci``` 54b8021494Sopenharmony_ci 55b8021494Sopenharmony_ciThe debugger has a variety of useful commands to control program flow (e.g: 56b8021494Sopenharmony_cistep, next, continue) and inspect features of the running simulator (e.g: 57b8021494Sopenharmony_ciprint, trace). To view a list of all supported commands 58b8021494Sopenharmony_ciuse "help" at the debugger prompt. 59b8021494Sopenharmony_ci 60b8021494Sopenharmony_ci```sh 61b8021494Sopenharmony_ci sim> help 62b8021494Sopenharmony_ci``` 63b8021494Sopenharmony_ci 64b8021494Sopenharmony_ciExtending the Debugger 65b8021494Sopenharmony_ci---------------------- 66b8021494Sopenharmony_ci 67b8021494Sopenharmony_ciThe debugger can be extended with custom commands to allow for greater 68b8021494Sopenharmony_ciflexibility in debugging individual applications. This could be used for a 69b8021494Sopenharmony_civariety of applications, for example printing out object specific information 70b8021494Sopenharmony_cifrom an address. 71b8021494Sopenharmony_ci 72b8021494Sopenharmony_ciTo create a custom debugger command, extend the DebuggerCmd class located in 73b8021494Sopenharmony_cidebugger-aarch64.h and implement its methods. 74b8021494Sopenharmony_ci 75b8021494Sopenharmony_ci```C++ 76b8021494Sopenharmony_ci class PrintObjectCmd : public DebuggerCmd { 77b8021494Sopenharmony_ci public: 78b8021494Sopenharmony_ci PrintObjectCmd(Simulator* sim) 79b8021494Sopenharmony_ci : DebuggerCmd(sim, 80b8021494Sopenharmony_ci "printobject", 81b8021494Sopenharmony_ci "po", 82b8021494Sopenharmony_ci "<address>", 83b8021494Sopenharmony_ci "Print a custom object located at the given address.") 84b8021494Sopenharmony_ci {} 85b8021494Sopenharmony_ci 86b8021494Sopenharmony_ci // Called when the command word is given to the interactive debugger. 87b8021494Sopenharmony_ci DebugReturn Action(const std::vector<std::string>& args) override { 88b8021494Sopenharmony_ci // We want exactly 1 argument (an address) given to the printobject 89b8021494Sopenharmony_ci // command. 90b8021494Sopenharmony_ci if (args.size() != 1) { 91b8021494Sopenharmony_ci fprintf(ostream_, "Error: incorrect command format."); 92b8021494Sopenharmony_ci return DebugContinue; 93b8021494Sopenharmony_ci } 94b8021494Sopenharmony_ci 95b8021494Sopenharmony_ci auto addr = Debugger::ParseUint64String(args.front()); 96b8021494Sopenharmony_ci if (addr) { 97b8021494Sopenharmony_ci fprintf(ostream_, "Error: could not get address from string."); 98b8021494Sopenharmony_ci return DebugContinue; 99b8021494Sopenharmony_ci } 100b8021494Sopenharmony_ci 101b8021494Sopenharmony_ci // Convert the address given to a custom object and then print it. 102b8021494Sopenharmony_ci CustomObject object = reinterpret_cast<CustomObject>(*addr); 103b8021494Sopenharmony_ci object.print(); 104b8021494Sopenharmony_ci } 105b8021494Sopenharmony_ci }; 106b8021494Sopenharmony_ci``` 107b8021494Sopenharmony_ci 108b8021494Sopenharmony_ciThen simply register the new command with the debugger. 109b8021494Sopenharmony_ci 110b8021494Sopenharmony_ci```C++ 111b8021494Sopenharmony_ci Debugger* debugger = simulator.GetDebugger(); 112b8021494Sopenharmony_ci 113b8021494Sopenharmony_ci debugger->RegisterCmd<PrintObjectCmd>(); 114b8021494Sopenharmony_ci``` 115