1 /*
2  * Copyright (c) 2012-2018 Ali Mashtizadeh
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <stdbool.h>
18 #include <stdint.h>
19 #include <string.h>
20 
21 #include <sys/kassert.h>
22 #include <sys/kdebug.h>
23 
24 #include "../dev/console.h"
25 
26 #define DEBUG_MAX_LINE		128
27 #define DEBUG_MAX_ARGS		16
28 
29 void
Debug_PrintHex(const char * data,size_t length,off_t off,size_t limit)30 Debug_PrintHex(const char *data, size_t length, off_t off, size_t limit)
31 {
32     const size_t row_size = 16;
33     bool stop = false;
34 
35     size_t row;
36     for (row = 0; !stop; row++) {
37 	size_t ix = row * row_size;
38 	if (ix >= limit || ix >= length)
39 	    return;
40 
41 	kprintf("%08lx  ", (uintptr_t)data+ix);
42 	size_t col;
43 	for (col = 0; col < row_size; col++) {
44 	    size_t ixc = ix + col;
45 	    if ((limit != 0 && ixc >= limit) || ixc >= length) {
46 		stop = true;
47 		for (; col < row_size; col++) {
48 		    kprintf("   ");
49 		}
50 		break;
51 	    }
52 	    ixc += off;
53 
54 	    kprintf("%02X ", (unsigned char)data[ixc]);
55 	}
56 	kprintf("  |");
57 
58 	for (col = 0; col < row_size; col++) {
59 	    size_t ixc = ix + col;
60 	    if ((limit != 0 && ixc >= limit) || ixc >= length) {
61 		stop = true;
62 		for (; col < row_size; col++) {
63 		    kprintf(" ");
64 		}
65 		break;
66 	    }
67 	    ixc += off;
68 
69 	    unsigned char c = (unsigned char)data[ixc];
70 	    if (c >= 0x20 && c < 0x7F)
71 		kprintf("%c", c);
72 	    else
73 		kprintf(".");
74 	}
75 	kprintf("|");
76 	kprintf("\n");
77     }
78 }
79 
80 uint64_t
Debug_GetValue(uintptr_t addr,int size,bool isSigned)81 Debug_GetValue(uintptr_t addr, int size, bool isSigned)
82 {
83     switch (size)
84     {
85 	case 1: {
86 	    uint8_t *val = (uint8_t *)addr;
87 	    if (isSigned && ((*val & 0x80) == 0x80)) {
88 		return (uint64_t)*val | 0xFFFFFFFFFFFFFF00ULL;
89 	    }
90 	    return *val;
91 	}
92 	case 2: {
93 	    uint16_t *val = (uint16_t *)addr;
94 	    if (isSigned && ((*val & 0x8000) == 0x8000)) {
95 		return (uint64_t)*val | 0xFFFFFFFFFFFF0000ULL;
96 	    }
97 	    return *val;
98 	}
99 	case 4: {
100 	    uint32_t *val = (uint32_t *)addr;
101 	    if (isSigned && ((*val & 0x80000000) == 0x80000000)) {
102 		return (uint64_t)*val | 0xFFFFFFFF00000000ULL;
103 	    }
104 	    return *val;
105 	}
106 	case 8: {
107 	    uint64_t *val = (uint64_t *)addr;
108 	    return *val;
109 	}
110 	default: {
111 	    kprintf("Debug_GetValue: Unknown size parameter '%d'\n", size);
112 	    return (uint64_t)-1;
113 	}
114     }
115 }
116 
117 void
Debug_PrintSymbol(uintptr_t off,int strategy)118 Debug_PrintSymbol(uintptr_t off, int strategy)
119 {
120     kprintf("0x%llx", off);
121 }
122 
123 uint64_t
Debug_StrToInt(const char * s)124 Debug_StrToInt(const char *s)
125 {
126     int i = 0;
127     int base = 10;
128     uint64_t val = 0;
129 
130     if (s[0] == '0' && s[1] == 'x')
131     {
132 	base = 16;
133 	i = 2;
134     }
135 
136     while (s[i] != '\0') {
137 	if (s[i] >= '0' && s[i] <= '9') {
138 	    val = val * base + (uint64_t)(s[i] - '0');
139 	} else if (s[i] >= 'a' && s[i] <= 'f') {
140 	    if (base != 16)
141 		kprintf("Not base 16!\n");
142 	    val = val * base + (uint64_t)(s[i] - 'a' + 10);
143 	} else if (s[i] >= 'A' && s[i] <= 'F') {
144 	    if (base != 16)
145 		kprintf("Not base 16!\n");
146 	    val = val * base + (uint64_t)(s[i] - 'A' + 10);
147 	} else {
148 	    kprintf("Not a number!\n");
149 	}
150 	i++;
151     }
152 
153     return val;
154 }
155 
156 uint64_t
Debug_SymbolToInt(const char * s)157 Debug_SymbolToInt(const char *s)
158 {
159     if (*s >= '0' || *s <= '9')
160 	return Debug_StrToInt(s);
161 
162     kprintf("Unknown symbol '%s'\n");
163     return 0;
164 }
165 
166 #define PHELP(_cmd, _msg) kprintf("%-16s %s\n", _cmd, _msg)
167 
168 extern DebugCommand __kdbgcmd_start[];
169 extern DebugCommand __kdbgcmd_end[];
170 
171 static void
Debug_Help(int argc,const char * argv[])172 Debug_Help(int argc, const char *argv[])
173 {
174     int i;
175     uintptr_t commands = (uintptr_t)&__kdbgcmd_end - (uintptr_t)&__kdbgcmd_start;
176     commands /= sizeof(DebugCommand);
177     DebugCommand *cmds = (DebugCommand *)&__kdbgcmd_start;
178 
179     kprintf("Commands:\n");
180     for (i = 0; i < commands; i++)
181     {
182 	kprintf("%-16s %s\n", cmds[i].name, cmds[i].description);
183     }
184 
185     PHELP("continue", "Continue execution");
186 }
187 
188 REGISTER_DBGCMD(help, "Display the list of commands", Debug_Help);
189 
190 static void
Debug_Echo(int argc,const char * argv[])191 Debug_Echo(int argc, const char *argv[])
192 {
193     int i;
194 
195     for (i = 1; i < argc; i++)
196     {
197 	kprintf("%s ", argv[i]);
198     }
199     kprintf("\n");
200 }
201 
202 REGISTER_DBGCMD(echo, "Echo arguments", Debug_Echo);
203 
204 static void
Debug_Dump(int argc,const char * argv[])205 Debug_Dump(int argc, const char *argv[])
206 {
207     uint64_t off, len;
208 
209     if (argc != 3)
210     {
211 	kprintf("Dump requires 3 arguments\n");
212 	return;
213     }
214 
215     off = Debug_SymbolToInt(argv[1]);
216     len = Debug_SymbolToInt(argv[2]);
217     kprintf("Dump 0x%llx 0x%llx\n", off, len);
218     Debug_PrintHex((const char *)off, len, 0, len);
219 }
220 
221 REGISTER_DBGCMD(dump, "Dump a region of memory", Debug_Dump);
222 
223 static void
Debug_Disasm(int argc,const char * argv[])224 Debug_Disasm(int argc, const char *argv[])
225 {
226     uintptr_t off;
227     int len = 1;
228 
229     if (argc != 2 && argc != 3) {
230 	kprintf("Disasm requires 2 or 3 arguments\n");
231 	return;
232     }
233 
234     off = Debug_SymbolToInt(argv[1]);
235     if (argc == 3)
236 	len = Debug_SymbolToInt(argv[2]);
237     kprintf("Disassembly 0x%llx:\n", off);
238 
239     for (; len > 0; len--)
240     {
241 	off = db_disasm(off, false);
242     }
243 }
244 
245 REGISTER_DBGCMD(disasm, "Disassemble", Debug_Disasm);
246 
247 void
Debug_Prompt()248 Debug_Prompt()
249 {
250     int argc;
251     char *argv[DEBUG_MAX_ARGS];
252     char *nextArg, *last;
253     char buf[DEBUG_MAX_LINE];
254 
255     kprintf("Entered Debugger!\n");
256 
257     /*
258      * DebugCommand must be 128 bytes for the Section array to align properly
259      */
260     ASSERT(sizeof(DebugCommand) == 128);
261 
262     while (1) {
263 	kprintf("kdbg> ");
264 
265 	// read input
266 	Console_Gets((char *)&buf, DEBUG_MAX_LINE);
267 
268 	// parse input
269 	nextArg = strtok_r(buf, " \t\r\n", &last);
270 	for (argc = 0; argc < DEBUG_MAX_ARGS; argc++) {
271 	    if (nextArg == NULL)
272 		break;
273 
274 	    argv[argc] = nextArg;
275 	    nextArg = strtok_r(NULL, " \t\r\n", &last);
276 	}
277 
278 	if (strcmp(argv[0], "continue") == 0) {
279 	    return; // Continue
280 	} else {
281 	    // execute command
282 	    int i;
283 	    uintptr_t commands = (uintptr_t)&__kdbgcmd_end - (uintptr_t)&__kdbgcmd_start;
284 	    commands /= sizeof(DebugCommand);
285 	    DebugCommand *cmds = (DebugCommand *)&__kdbgcmd_start;
286 	    bool found = false;
287 
288 	    for (i = 0; i < commands; i++)
289 	    {
290 		if (strcmp(argv[0], cmds[i].name) == 0)
291 		{
292 		    cmds[i].func(argc, (const char **)argv);
293 		    found = true;
294 		}
295 	    }
296 
297 	    if (strcmp(argv[0], "") == 0)
298 		continue;
299 
300 	    if (!found)
301 		kprintf("Unknown command '%s'\n", argv[0]);
302 	}
303     }
304 }
305 
306