src/arm/debugger/cli-debugger.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "cli-debugger.h"
7
8#ifdef USE_CLI_DEBUGGER
9#include "arm/debugger/debugger.h"
10#include "arm/debugger/memory-debugger.h"
11#include "arm/decoder.h"
12#include "core/core.h"
13#include "debugger/cli-debugger.h"
14
15static void _printStatus(struct CLIDebuggerSystem*);
16
17static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
18static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*);
19static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*);
20static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*);
21static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*);
22
23static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode);
24static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode);
25
26static struct CLIDebuggerCommandSummary _armCommands[] = {
27 { "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
28 { "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
29 { "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
30 { "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
31 { "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
32 { "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
33 { "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
34 { "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
35 { "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" },
36 { "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" },
37 { "w/r", _writeRegister, CLIDVParse, "Write a register" },
38 { 0, 0, 0, 0 }
39};
40
41static inline void _printPSR(union PSR psr) {
42 printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
43 psr.n ? 'N' : '-',
44 psr.z ? 'Z' : '-',
45 psr.c ? 'C' : '-',
46 psr.v ? 'V' : '-',
47 psr.i ? 'I' : '-',
48 psr.f ? 'F' : '-',
49 psr.t ? 'T' : '-');
50}
51
52static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
53 struct ARMCore* cpu = debugger->p->d.core->cpu;
54 _disassembleMode(debugger->p, dv, cpu->executionMode);
55}
56
57static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
58 _disassembleMode(debugger, dv, MODE_ARM);
59}
60
61static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
62 _disassembleMode(debugger, dv, MODE_THUMB);
63}
64
65static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) {
66 struct ARMCore* cpu = debugger->d.core->cpu;
67 uint32_t address;
68 int size;
69 int wordSize;
70
71 if (mode == MODE_ARM) {
72 wordSize = WORD_SIZE_ARM;
73 } else {
74 wordSize = WORD_SIZE_THUMB;
75 }
76
77 if (!dv || dv->type != CLIDV_INT_TYPE) {
78 address = cpu->gprs[ARM_PC] - wordSize;
79 } else {
80 address = dv->intValue;
81 dv = dv->next;
82 }
83
84 if (!dv || dv->type != CLIDV_INT_TYPE) {
85 size = 1;
86 } else {
87 size = dv->intValue;
88 dv = dv->next; // TODO: Check for excess args
89 }
90
91 int i;
92 for (i = 0; i < size; ++i) {
93 address += _printLine(debugger, address, mode);
94 }
95}
96
97static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
98 char disassembly[48];
99 struct ARMInstructionInfo info;
100 printf("%08X: ", address);
101 if (mode == MODE_ARM) {
102 uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address);
103 ARMDecodeARM(instruction, &info);
104 ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
105 printf("%08X\t%s\n", instruction, disassembly);
106 return WORD_SIZE_ARM;
107 } else {
108 struct ARMInstructionInfo info2;
109 struct ARMInstructionInfo combined;
110 uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
111 uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
112 ARMDecodeThumb(instruction, &info);
113 ARMDecodeThumb(instruction2, &info2);
114 if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
115 ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
116 printf("%04X %04X\t%s\n", instruction, instruction2, disassembly);
117 return WORD_SIZE_THUMB * 2;
118 } else {
119 ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
120 printf("%04X \t%s\n", instruction, disassembly);
121 return WORD_SIZE_THUMB;
122 }
123 }
124}
125
126static void _printStatus(struct CLIDebuggerSystem* debugger) {
127 struct ARMCore* cpu = debugger->p->d.core->cpu;
128 int r;
129 for (r = 0; r < 4; ++r) {
130 printf("%08X %08X %08X %08X\n",
131 cpu->gprs[r << 2],
132 cpu->gprs[(r << 2) + 1],
133 cpu->gprs[(r << 2) + 2],
134 cpu->gprs[(r << 2) + 3]);
135 }
136 _printPSR(cpu->cpsr);
137 int instructionLength;
138 enum ExecutionMode mode = cpu->cpsr.t;
139 if (mode == MODE_ARM) {
140 instructionLength = WORD_SIZE_ARM;
141 } else {
142 instructionLength = WORD_SIZE_THUMB;
143 }
144 _printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode);
145}
146
147static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
148 struct ARMCore* cpu = debugger->d.core->cpu;
149 if (!dv || dv->type != CLIDV_INT_TYPE) {
150 printf("%s\n", ERROR_MISSING_ARGS);
151 return;
152 }
153 if (!dv->next || dv->next->type != CLIDV_INT_TYPE) {
154 printf("%s\n", ERROR_MISSING_ARGS);
155 return;
156 }
157 uint32_t regid = dv->intValue;
158 uint32_t value = dv->next->intValue;
159 if (regid >= ARM_PC) {
160 return;
161 }
162 cpu->gprs[regid] = value;
163}
164
165static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
166 if (!dv || dv->type != CLIDV_INT_TYPE) {
167 printf("%s\n", ERROR_MISSING_ARGS);
168 return;
169 }
170 uint32_t address = dv->intValue;
171 ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM);
172}
173
174static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
175 if (!dv || dv->type != CLIDV_INT_TYPE) {
176 printf("%s\n", ERROR_MISSING_ARGS);
177 return;
178 }
179 uint32_t address = dv->intValue;
180 ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB);
181}
182
183static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
184 struct ARMCore* cpu = debugger->p->d.core->cpu;
185 if (strcmp(name, "sp") == 0) {
186 return cpu->gprs[ARM_SP];
187 }
188 if (strcmp(name, "lr") == 0) {
189 return cpu->gprs[ARM_LR];
190 }
191 if (strcmp(name, "pc") == 0) {
192 return cpu->gprs[ARM_PC];
193 }
194 if (strcmp(name, "cpsr") == 0) {
195 return cpu->cpsr.packed;
196 }
197 // TODO: test if mode has SPSR
198 if (strcmp(name, "spsr") == 0) {
199 return cpu->spsr.packed;
200 }
201 if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') {
202 int reg = atoi(&name[1]);
203 if (reg < 16) {
204 return cpu->gprs[reg];
205 }
206 }
207 dv->type = CLIDV_ERROR_TYPE;
208 return 0;
209}
210
211void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
212 debugger->printStatus = _printStatus;
213 debugger->disassemble = _disassemble;
214 debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier;
215 debugger->platformName = "ARM";
216 debugger->platformCommands = _armCommands;
217}
218
219#endif