cynix

x86 UNIX-like OS
git clone git://git.2f30.org/cynix
Log | Files | Refs | README | LICENSE

kdb.c (10796B)


      1 /*
      2  *  core/kdb.c
      3  *
      4  *  Copyright (C) 2010 stateless
      5  */
      6 
      7 #include <common.h>
      8 #include <kdb.h>
      9 #include <tty.h>
     10 #include <heap.h>
     11 #include <string.h>
     12 #include <errno.h>
     13 #include <syscall.h>
     14 #include <x86.h>
     15 #include <pci.h>
     16 #include <tss.h>
     17 #include <stdlib.h>
     18 #include <ctype.h>
     19 #include <elf.h>
     20 #include <rtl8139.h>
     21 #include <pipe.h>
     22 #include <rtc.h>
     23 
     24 #define ENV_REPORT
     25 
     26 enum {
     27 	CMD_SIZE = 512
     28 };
     29 
     30 static void kdb_loop(void);
     31 
     32 static int kdb_cmd_help(int argc, char **argv);
     33 static int kdb_cmd_exit(int argc, char **argv);
     34 static int kdb_cmd_reboot(int argc, char **argv);
     35 static int kdb_cmd_lspci(int argc, char **argv);
     36 static int kdb_cmd_ps(int argc, char **argv);
     37 static int kdb_cmd_cpuid(int argc, char **argv);
     38 static int kdb_cmd_heapdump(int argc, char **argv);
     39 static int kdb_cmd_hexdump(int argc, char **argv);
     40 static int kdb_cmd_write(int argc, char **argv);
     41 static int kdb_cmd_symlookup(int argc, char **argv);
     42 static int kdb_cmd_dumpregs(int argc, char **argv);
     43 static int kdb_cmd_exec(int argc, char **argv);
     44 static int kdb_cmd_ls(int argc, char **argv);
     45 static int kdb_cmd_dumpframe(int argc, char **argv);
     46 static int kdb_cmd_macaddr(int argc, char **argv);
     47 static int kdb_cmd_test(int argc, char **argv);
     48 static int kdb_cmd_dumpmap(int argc, char **argv);
     49 
     50 static struct trapframe_t cframe;
     51 static char *cmd;
     52 
     53 static struct {
     54 	const char *name;
     55 	const char *desc;
     56 	int (*fnp)(int argc, char **argv);
     57 } kdb_cmds[] = {
     58 	{ "help", "Show this help menu.", kdb_cmd_help },
     59 	{ "exit", "Quit the debugger.", kdb_cmd_exit },
     60 	{ "reboot", "Reboot the machine.", kdb_cmd_reboot },
     61 	{ "lspci", "Perform a PCI enumeration.", kdb_cmd_lspci },
     62 	{ "ps", "Dump the scheduler's runqueue.", kdb_cmd_ps },
     63 	{ "cpuid", "Dump CPU info.", kdb_cmd_cpuid },
     64 	{ "heapdump", "Dump the kernel's heap allocation/deallocation lists.", kdb_cmd_heapdump },
     65 	{ "hexdump", "Do a hexdump of a specific memory range.", kdb_cmd_hexdump },
     66 	{ "write", "Write a specific value in a range of addresses.", kdb_cmd_write },
     67 	{ "symlookup", "Match an address to a symbol name.", kdb_cmd_symlookup },
     68 	{ "dumpregs", "Dump the system's registers.", kdb_cmd_dumpregs },
     69 	{ "exec", "Execute an ELF file.", kdb_cmd_exec },
     70 	{ "ls", "List directory contents.", kdb_cmd_ls },
     71 	{ "dumpframe", "Dump the last saved trapframe.", kdb_cmd_dumpframe },
     72 	{ "mac-addr", "Dump the mac-address.", kdb_cmd_macaddr },
     73 	{ "dumpmap", "Dump memory mappings.", kdb_cmd_dumpmap },
     74 	{ "test", "Testing routine.", kdb_cmd_test }
     75 };
     76 
     77 void
     78 set_trapframe(struct trapframe_t *tframe)
     79 {
     80 	cframe = *tframe;
     81 }
     82 
     83 void
     84 kdb_enter(void)
     85 {
     86 	cmd = kmalloc(CMD_SIZE);
     87 	if (IS_ERR(cmd))
     88 		return;
     89 	memset(cmd, 0, CMD_SIZE);
     90 	ccurr_col(BLACK, WHITE);
     91 	clear_scr();
     92 	printf("type help for a list of commands.\n");
     93 	kdb_loop();
     94 }
     95 
     96 static char **
     97 parse_cmd(int *argc)
     98 {
     99 	int f, i;
    100 	char *p, **argv, *tmp, *arg;
    101 	*argc = 0;
    102 
    103 	for (f = 1, p = cmd; *p; ++p) {
    104 		if (!f && *p == ' ') {
    105 			++*argc;
    106 			f = 1;
    107 			continue;
    108 		}
    109 		if (f && *p != ' ')
    110 			f = 0;
    111 	}
    112 	if (!f)
    113 		++*argc;
    114 	argv = kmalloc((*argc + 1) * sizeof(char *));
    115 	if (IS_ERR(argv))
    116 		panic("oom");
    117 	for (p = cmd; *p; ++p, tmp = p)
    118 		; /* nothing */
    119 	for (p = cmd; *p; ++p)
    120 		if (*p == ' ')
    121 			*p = '\0';
    122 	for (i = 0, f = 1, p = cmd; p < tmp; ++p) {
    123 		if (!f && *p == '\0') {
    124 			f = 1;
    125 			argv[i++] = arg;
    126 			continue;
    127 		}
    128 		if (f && *p) {
    129 			f = 0;
    130 			arg = p;
    131 		}
    132 	}
    133 	if (!f)
    134 		argv[i] = arg;
    135 	argv[*argc] = NULL;
    136 	return argv;
    137 }
    138 
    139 static char *
    140 prepare_cmd(void)
    141 {
    142 	char *p;
    143 
    144 	p = &cmd[CMD_SIZE - 1];
    145 	while (p != cmd) {
    146 		if (*p == '\n') {
    147 			*p-- = '\0';
    148 			continue;
    149 		}
    150 		--p;
    151 	}
    152 	while (*p != ' ') ++p;
    153 	*p = '\0';
    154 	return p;
    155 }
    156 
    157 static void
    158 trimstr(char *s)
    159 {
    160 	char *ptr = s;
    161 
    162 	while (*ptr == ' ') ++ptr;
    163 	memmove(s, ptr, strlen(s) - (ptr - s));
    164 	memset(s + strlen(s) - (ptr - s), 0, ptr - s);
    165 	ptr = s + strlen(s) - 1;
    166 	while (*ptr == ' ') --ptr;
    167 	if (*ptr) {
    168 		++ptr;
    169 		*ptr = '\0';
    170 	}
    171 }
    172 
    173 static void
    174 kdb_loop(void)
    175 {
    176 	size_t i;
    177 	char *p;
    178 	ssize_t r;
    179 	int argc, ret;
    180 	char **argv;
    181 
    182 	do {
    183 again:
    184 		update_cursor(cursor_y, 2);
    185 		printf("> ");
    186 		r = sys_read(0, cmd, CMD_SIZE - 1);
    187 		cmd[r] = '\0';
    188 		p = cmd;
    189 		trimstr(p);
    190 		for (; *p; ++p)
    191 			if (!isspace(*p))
    192 				break;
    193 		if (*p == '\0')
    194 			goto again;
    195 		p = prepare_cmd();
    196 		for (i = 0; i <
    197 				sizeof(kdb_cmds) / sizeof(kdb_cmds[0]); ++i) {
    198 			if (!strcmp(cmd, kdb_cmds[i].name)) {
    199 				*p = ' ';
    200 				argv = parse_cmd(&argc);
    201 				if (!kdb_cmds[i].fnp)
    202 					panic("%s: is not initialized properly!",
    203 					      kdb_cmds[i].name);
    204 				ret = kdb_cmds[i].fnp(argc, argv);
    205 #ifdef ENV_REPORT
    206 				if (ret < 0) {
    207 					printf("FAIL: %d", ret);
    208 					if (ret <= -1 && ret >= -44)
    209 						printf(":%s", sys_errlist[-ret - 1]);
    210 					putchar('\n');
    211 				}
    212 #endif
    213 				kfree(argv);
    214 				goto again;
    215 			}
    216 		}
    217 		p = cmd;
    218 		while (isspace(*p)) ++p;
    219 		printf("%s: command not found\n", p);
    220 	} while (1);
    221 }
    222 
    223 static int
    224 kdb_cmd_help(int argc, char **argv)
    225 {
    226 	size_t i;
    227 
    228 	if (argc != 1) {
    229 		printf("usage: %s\n", argv[0]);
    230 		return -EINVAL;
    231 	}
    232 
    233 	printf("Command list\n");
    234 	for (i = 0; i < sizeof(kdb_cmds) / sizeof(kdb_cmds[0]); ++i)
    235 		printf("  %s -- %s\n", kdb_cmds[i].name, kdb_cmds[i].desc);
    236 	return 0;
    237 }
    238 
    239 static int
    240 kdb_cmd_exit(int argc, char **argv)
    241 {
    242 	if (argc != 1) {
    243 		printf("usage: %s\n", argv[0]);
    244 		return -EINVAL;
    245 	}
    246 	sys_exit(0);
    247 	return 0;
    248 }
    249 
    250 static int
    251 kdb_cmd_reboot(int argc, char **argv)
    252 {
    253 	if (argc != 1) {
    254 		printf("usage: %s\n", argv[0]);
    255 		return -EINVAL;
    256 	}
    257 	outb(0x64, 0xfe);
    258 	cli();
    259 	hlt();
    260 	return 0;
    261 }
    262 
    263 static int
    264 kdb_cmd_lspci(int argc, char **argv)
    265 {
    266 	if (argc != 1) {
    267 		printf("usage: %s\n", argv[0]);
    268 		return -EINVAL;
    269 	}
    270 	lspci();
    271 	return 0;
    272 }
    273 
    274 static int
    275 kdb_cmd_ps(int argc, char **argv)
    276 {
    277 	if (argc != 1) {
    278 		printf("usage: %s\n", argv[0]);
    279 		return -EINVAL;
    280 	}
    281 	ps();
    282 	return 0;
    283 }
    284 
    285 static int
    286 kdb_cmd_cpuid(int argc, char **argv)
    287 {
    288 	if (argc != 1) {
    289 		printf("usage: %s\n", argv[0]);
    290 		return -EINVAL;
    291 	}
    292 	do_cpuid();
    293 	return 0;
    294 }
    295 
    296 static int
    297 kdb_cmd_heapdump(int argc, char **argv)
    298 {
    299 	if (argc != 1) {
    300 		printf("usage: %s\n", argv[0]);
    301 		return -EINVAL;
    302 	}
    303 	walk_heap_lists();
    304 	return 0;
    305 }
    306 
    307 static int
    308 kdb_cmd_hexdump(int argc, char **argv)
    309 {
    310 	uint32_t addr, len;
    311 
    312 	if (argc != 3) {
    313 		printf("usage: %s memory-address len\n", argv[0]);
    314 		printf("NOTE: all arguments are specified in hex\n");
    315 		return -EINVAL;
    316 	}
    317 	addr = strtoul(argv[1], NULL, 16);
    318 	len = strtoul(argv[2], NULL, 16);
    319 	hexdump((const void *)addr, len);
    320 	return 0;
    321 }
    322 
    323 static int
    324 kdb_cmd_write(int argc, char **argv)
    325 {
    326 	uint32_t val, low, high, *p;
    327 
    328 	if (argc != 4) {
    329 		printf("usage: %s value low-addr high-addr\n", argv[0]);
    330 		printf("NOTE: the range is [low-addr, high-addr), all arguments are specified in hex\n");
    331 		return -EINVAL;
    332 	}
    333 	val = strtoul(argv[1], NULL, 16);
    334 	low = strtoul(argv[2], NULL, 16);
    335 	high = strtoul(argv[3], NULL, 16);
    336 	if (high <= low) {
    337 		printf("high-addr can't be lower or equal to low-addr\n");
    338 		return -EINVAL;
    339 	}
    340 	p = (uint32_t *)low;
    341 	while (p < (uint32_t *)high)
    342 		*p++ = val;
    343 	return 0;
    344 }
    345 
    346 static int
    347 kdb_cmd_symlookup(int argc, char **argv)
    348 {
    349 	uint32_t addr;
    350 	const char *sym;
    351 
    352 	if (argc != 2) {
    353 		printf("usage: %s symbol-address\n", argv[0]);
    354 		printf("NOTE: the address must be specified in hex\n");
    355 		return -EINVAL;
    356 	}
    357 	addr = strtoul(argv[1], NULL, 16);
    358 	sym = find_symbol(addr);
    359 	printf("%s => %s\n", argv[1], (!sym) ? "unknown" : sym);
    360 	return 0;
    361 }
    362 
    363 /* TODO: add more regs */
    364 static int
    365 kdb_cmd_dumpregs(int argc, char **argv)
    366 {
    367 	uint32_t eax, ebx, ecx, edx, esp, ebp;
    368 	uint32_t edi, esi;
    369 
    370 	if (argc != 1) {
    371 		printf("usage: %s\n", argv[0]);
    372 		return -EINVAL;
    373 	}
    374 
    375 	asm volatile ("movl %%eax, %0" : "=r"(eax));
    376 	asm volatile ("movl %%ebx, %0" : "=r"(ebx));
    377 	asm volatile ("movl %%ecx, %0" : "=r"(ecx));
    378 	asm volatile ("movl %%edx, %0" : "=r"(edx));
    379 	asm volatile ("movl %%esp, %0" : "=r"(esp));
    380 	asm volatile ("movl %%ebp, %0" : "=r"(ebp));
    381 	asm volatile ("movl %%esi, %0" : "=r"(esi));
    382 	asm volatile ("movl %%edi, %0" : "=r"(edi));
    383 
    384 	printf("eax = 0x%08lx\nebx = 0x%08lx\necx = 0x%08lx\n",
    385 	       eax, ebx, ecx);
    386 	printf("edx = 0x%08lx\nesp = 0x%08lx\nebp = 0x%08lx\n",
    387 	       edx, esp, ebp);
    388 	printf("esi = 0x%08lx\nedi = 0x%08lx\n",
    389 	       esi, edi);
    390 	return 0;
    391 }
    392 
    393 static int
    394 kdb_cmd_exec(int argc, char **argv)
    395 {
    396 	pid_t pid;
    397 	int ret, status;
    398 
    399 	if (argc != 2) {
    400 		printf("usage: %s filename\n", argv[0]);
    401 		return -EINVAL;
    402 	}
    403 
    404 	pid = sys_fork();
    405 	if (pid < 0)
    406 		return pid;
    407 	if (!pid) {
    408 		ret = sys_execve(argv[1], NULL, NULL);
    409 		sys_exit(ret);
    410 	} else {
    411 		while (1) {
    412 			if ((ret = sys_waitpid(-1, &status, WNOHANG)) < 0)
    413 				break;
    414 		}
    415 	}
    416 	printf("child exited with error code %d\n", status);
    417 	return 0;
    418 }
    419 
    420 static int
    421 kdb_cmd_ls(int argc, char **argv)
    422 {
    423 	char buf[256];
    424 	DIR *dirp;
    425 	struct dirent_t *dirent;
    426 	struct stat stbuf;
    427 	int ret;
    428 
    429 	if (argc != 1) {
    430 		printf("usage: %s\n", argv[0]);
    431 		return -EINVAL;
    432 	}
    433 
    434 	dirp = opendir("/");
    435 	if (!dirp)
    436 		return -errno;
    437 	dirent = sys_readdir(dirp);
    438 	printf("%-12s%-12s%-12s%-12s\n", "FILENAME", "TYPE", "UID", "GID");
    439 	while (dirent) {
    440 		if (!strcmp(dirent->d_name, ".")
    441 				|| !strcmp(dirent->d_name, ".."))
    442 			goto out;
    443 		bzero(buf, 256);
    444 		buf[0] = '/';
    445 		strncpy(buf + 1, dirent->d_name, 255);
    446 		buf[255] = '\0';
    447 		if (!stat(buf, &stbuf)) {
    448 			printf("%-12s%-12s%-12d%-12d\n",
    449 			       dirent->d_name,
    450 			       S_ISREG(stbuf.st_mode) ? "FILE" : "DIR",
    451 			       stbuf.st_uid,
    452 			       stbuf.st_gid);
    453 		}
    454 out:
    455 		dirent = readdir(dirp);
    456 	}
    457 	ret = closedir(dirp);
    458 	if (ret < 0)
    459 		return -errno;
    460 	return 0;
    461 }
    462 
    463 static int
    464 kdb_cmd_dumpframe(int argc, char **argv)
    465 {
    466 	if (argc != 1) {
    467 		printf("usage: %s\n", argv[0]);
    468 		return -EINVAL;
    469 	}
    470 	DUMP_STACK_REGS(cframe);
    471 	return 0;
    472 }
    473 
    474 static int
    475 kdb_cmd_macaddr(int argc, char **argv)
    476 {
    477 	const uint8_t *mac_addr;
    478 
    479 	if (argc != 1) {
    480 		printf("usage: %s\n", argv[0]);
    481 		return -EINVAL;
    482 	}
    483 	mac_addr = get_mac_addr();
    484 	if (!mac_addr) {
    485 		info("no mac-addr?\n");
    486 		return -ENODEV;
    487 	}
    488 	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
    489 	       mac_addr[0],
    490 	       mac_addr[1],
    491 	       mac_addr[2],
    492 	       mac_addr[3],
    493 	       mac_addr[4],
    494 	       mac_addr[5]
    495 	      );
    496 	return 0;
    497 }
    498 
    499 static int
    500 kdb_cmd_dumpmap(int argc, char **argv)
    501 {
    502 	if (argc != 1) {
    503 		printf("usage: %s\n", argv[0]);
    504 		return -EINVAL;
    505 	}
    506 	dump_mappings();
    507 	return 0;
    508 }
    509 
    510 static int
    511 kdb_cmd_test(int argc, char **argv)
    512 {
    513 	ssize_t r;
    514 	int pipefd[2];
    515 	char buf[32];
    516 	pid_t pid;
    517 
    518 	if (argc != 1) {
    519 		printf("usage: %s\n", argv[0]);
    520 		return -EINVAL;
    521 	}
    522 
    523 	bzero(buf, sizeof buf);
    524 	if (sys_pipe(pipefd) < 0)
    525 		panic("sys_pipe failed");
    526 	pid = sys_fork();
    527 	if (!pid) {
    528 		assert(!sys_close(pipefd[1]));
    529 		sleep(1);
    530 		r = sys_read(pipefd[0], buf, 13);
    531 		if (r < 0)
    532 			kerror(-r);
    533 		if (r)
    534 			printf("%s", buf);
    535 		sys_exit(0);
    536 	}
    537 	assert(!sys_close(pipefd[0]));
    538 	assert(sys_write(pipefd[1], "hello", 5) == 5);
    539 	assert(sys_write(pipefd[1], ", world\n", 8) == 8);
    540 	return 0;
    541 }
    542