main.c revision 175416
1184610Salfred/* 2184610Salfred * Copyright (c) 2004 Marcel Moolenaar 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 9184610Salfred * 1. Redistributions of source code must retain the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer. 11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer in the 13184610Salfred * documentation and/or other materials provided with the distribution. 14184610Salfred * 15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27184610Salfred#include <sys/cdefs.h> 28184610Salfred__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 175416 2008-01-17 21:43:12Z jhb $"); 29184610Salfred 30184610Salfred#include <sys/param.h> 31184610Salfred#include <sys/stat.h> 32184610Salfred#include <sys/types.h> 33184610Salfred#include <sys/ioctl.h> 34184610Salfred#include <sys/resource.h> 35184610Salfred#include <sys/select.h> 36184610Salfred#include <sys/time.h> 37184610Salfred#include <sys/wait.h> 38184610Salfred#include <errno.h> 39184610Salfred#include <err.h> 40184610Salfred#include <fcntl.h> 41184610Salfred#include <inttypes.h> 42184610Salfred#include <kvm.h> 43184610Salfred#include <limits.h> 44184610Salfred#include <paths.h> 45184610Salfred#include <stdio.h> 46184610Salfred#include <stdlib.h> 47184610Salfred#include <string.h> 48184610Salfred#include <unistd.h> 49184610Salfred 50184610Salfred/* libgdb stuff. */ 51184610Salfred#include <defs.h> 52184610Salfred#include <frame.h> 53184610Salfred#include <frame-unwind.h> 54184610Salfred#include <inferior.h> 55184610Salfred#include <interps.h> 56184610Salfred#include <cli-out.h> 57184610Salfred#include <main.h> 58184610Salfred#include <target.h> 59184610Salfred#include <top.h> 60184610Salfred#include <bfd.h> 61184610Salfred#include <gdbcore.h> 62184610Salfred 63184610Salfredextern void (*init_ui_hook)(char *); 64184610Salfred 65184610Salfredextern frame_unwind_sniffer_ftype *kgdb_sniffer_kluge; 66184610Salfred 67184610Salfredextern void symbol_file_add_main (char *args, int from_tty); 68184610Salfred 69184610Salfred#include "kgdb.h" 70184610Salfred 71184610Salfredkvm_t *kvm; 72184610Salfredstatic char kvm_err[_POSIX2_LINE_MAX]; 73184610Salfred 74184610Salfredstatic int dumpnr; 75184610Salfredstatic int verbose; 76184610Salfred 77184610Salfredstatic char crashdir[PATH_MAX]; 78184610Salfredchar *kernel; 79184610Salfredstatic char *remote; 80184610Salfredstatic char *vmcore; 81188622Sthompsa 82188622Sthompsastatic void (*kgdb_new_objfile_chain)(struct objfile * objfile); 83184610Salfred 84184610Salfredstatic void 85184610Salfredkgdb_atexit(void) 86184610Salfred{ 87184610Salfred if (kvm != NULL) 88184610Salfred kvm_close(kvm); 89184610Salfred} 90184610Salfred 91184610Salfredstatic void 92184610Salfredusage(void) 93184610Salfred{ 94184610Salfred 95184610Salfred fprintf(stderr, 96184610Salfred "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n" 97184610Salfred "\t[kernel [core]]\n", getprogname()); 98184610Salfred exit(1); 99184610Salfred} 100184610Salfred 101184610Salfredstatic void 102184610Salfredkernel_from_dumpnr(int nr) 103184610Salfred{ 104188622Sthompsa char path[PATH_MAX]; 105184610Salfred FILE *info; 106184610Salfred char *s; 107184610Salfred struct stat st; 108184610Salfred int l; 109184610Salfred 110184610Salfred /* 111184610Salfred * If there's a kernel image right here in the crash directory, then 112184610Salfred * use it. The kernel image is either called kernel.<nr> or is in a 113184610Salfred * subdirectory kernel.<nr> and called kernel. The latter allows us 114188622Sthompsa * to collect the modules in the same place. 115184610Salfred */ 116184610Salfred snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr); 117184610Salfred if (stat(path, &st) == 0) { 118184610Salfred if (S_ISREG(st.st_mode)) { 119184610Salfred kernel = strdup(path); 120184610Salfred return; 121184610Salfred } 122184610Salfred if (S_ISDIR(st.st_mode)) { 123184610Salfred snprintf(path, sizeof(path), "%s/kernel.%d/kernel", 124184610Salfred crashdir, nr); 125184610Salfred if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { 126184610Salfred kernel = strdup(path); 127188622Sthompsa return; 128184610Salfred } 129184610Salfred } 130184610Salfred } 131184610Salfred 132184610Salfred /* 133184610Salfred * No kernel image here. Parse the dump header. The kernel object 134184610Salfred * directory can be found there and we probably have the kernel 135184610Salfred * image still in it. The object directory may also have a kernel 136184610Salfred * with debugging info (called kernel.debug). If we have a debug 137184610Salfred * kernel, use it. 138184610Salfred */ 139184610Salfred snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr); 140184610Salfred info = fopen(path, "r"); 141184610Salfred if (info == NULL) { 142184610Salfred warn(path); 143184610Salfred return; 144184610Salfred } 145184610Salfred while (fgets(path, sizeof(path), info) != NULL) { 146184610Salfred l = strlen(path); 147184610Salfred if (l > 0 && path[l - 1] == '\n') 148184610Salfred path[--l] = '\0'; 149184610Salfred if (strncmp(path, " ", 4) == 0) { 150184610Salfred s = strchr(path, ':'); 151184610Salfred s = (s == NULL) ? path + 4 : s + 1; 152184610Salfred l = snprintf(path, sizeof(path), "%s/kernel.debug", s); 153184610Salfred if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) { 154184610Salfred path[l - 6] = '\0'; 155184610Salfred if (stat(path, &st) == -1 || 156184610Salfred !S_ISREG(st.st_mode)) 157184610Salfred break; 158184610Salfred } 159184610Salfred kernel = strdup(path); 160184610Salfred break; 161184610Salfred } 162184610Salfred } 163184610Salfred fclose(info); 164184610Salfred} 165184610Salfred 166184610Salfredstatic void 167184610Salfredkgdb_new_objfile(struct objfile *objfile) 168184610Salfred{ 169184610Salfred#if 0 170184610Salfred printf("XXX: %s(%p)\n", __func__, objfile); 171184610Salfred if (objfile != NULL) { 172184610Salfred goto out; 173188622Sthompsa } 174184610Salfred 175184610Salfredout: 176184610Salfred#endif 177184610Salfred if (kgdb_new_objfile_chain != NULL) 178184610Salfred kgdb_new_objfile_chain(objfile); 179184610Salfred} 180184610Salfred 181184610SalfredCORE_ADDR 182184610Salfredkgdb_parse(const char *exp) 183184610Salfred{ 184184610Salfred struct cleanup *old_chain; 185184610Salfred struct expression *expr; 186184610Salfred struct value *val; 187184610Salfred char *s; 188184610Salfred CORE_ADDR n; 189184610Salfred 190184610Salfred s = strdup(exp); 191184610Salfred old_chain = make_cleanup(free_current_contents, &expr); 192184610Salfred expr = parse_expression(s); 193184610Salfred val = (expr != NULL) ? evaluate_expression(expr) : NULL; 194184610Salfred n = (val != NULL) ? value_as_address(val) : 0; 195184610Salfred do_cleanups(old_chain); 196184610Salfred free(s); 197184610Salfred return (n); 198184610Salfred} 199184610Salfred 200184610Salfred#define MSGBUF_SEQ_TO_POS(size, seq) ((seq) % (size)) 201184610Salfred 202184610Salfredstatic void 203184610Salfredkgdb_init_target(void) 204184610Salfred{ 205184610Salfred CORE_ADDR bufp; 206184610Salfred bfd *kern_bfd; 207184610Salfred int size, rseq, wseq; 208184610Salfred int kern_desc; 209184610Salfred char c; 210184610Salfred 211184610Salfred kern_desc = open(kernel, O_RDONLY); 212184610Salfred if (kern_desc == -1) 213184610Salfred errx(1, "couldn't open a kernel image"); 214184610Salfred 215184610Salfred kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc); 216184610Salfred if (kern_bfd == NULL) { 217184610Salfred close(kern_desc); 218184610Salfred errx(1, "\"%s\": can't open to probe ABI: %s.", kernel, 219184610Salfred bfd_errmsg (bfd_get_error ())); 220184610Salfred } 221184610Salfred bfd_set_cacheable(kern_bfd, 1); 222184610Salfred 223184610Salfred if (!bfd_check_format (kern_bfd, bfd_object)) { 224184610Salfred bfd_close(kern_bfd); 225184610Salfred errx(1, "\"%s\": not in executable format: %s", kernel, 226184610Salfred bfd_errmsg(bfd_get_error())); 227184610Salfred } 228184610Salfred 229184610Salfred set_gdbarch_from_file (kern_bfd); 230184610Salfred bfd_close(kern_bfd); 231184610Salfred 232184610Salfred symbol_file_add_main (kernel, 0); 233184610Salfred if (remote) 234184610Salfred push_remote_target (remote, 0); 235184610Salfred else 236184610Salfred kgdb_target(); 237184610Salfred 238184610Salfred /* 239184610Salfred * Display the unread portion of the message buffer. This gives the 240184610Salfred * user a some initial data to work from. 241184610Salfred */ 242184610Salfred bufp = kgdb_parse("msgbufp->msg_ptr"); 243184610Salfred size = (int)kgdb_parse("msgbufp->msg_size"); 244184610Salfred rseq = (int)kgdb_parse("msgbufp->msg_rseq"); 245184610Salfred wseq = (int)kgdb_parse("msgbufp->msg_wseq"); 246184610Salfred rseq = MSGBUF_SEQ_TO_POS(size, rseq); 247184610Salfred wseq = MSGBUF_SEQ_TO_POS(size, wseq); 248184610Salfred if (bufp == 0 || size == 0 || rseq == wseq) 249184610Salfred return; 250184610Salfred 251184610Salfred printf("\nUnread portion of the kernel message buffer:\n"); 252184610Salfred while (rseq < wseq) { 253184610Salfred read_memory(bufp + rseq, &c, 1); 254184610Salfred putchar(c); 255184610Salfred rseq++; 256184610Salfred if (rseq == size) 257184610Salfred rseq = 0; 258184610Salfred } 259184610Salfred if (c != '\n') 260184610Salfred putchar('\n'); 261184610Salfred putchar('\n'); 262184610Salfred} 263184610Salfred 264184610Salfredstatic void 265184610Salfredkgdb_interp_command_loop(void *data) 266184610Salfred{ 267184610Salfred static int once = 0; 268184610Salfred 269184610Salfred if (!once) { 270184610Salfred once = 1; 271184610Salfred kgdb_init_target(); 272184610Salfred print_stack_frame(get_selected_frame(), 273184610Salfred frame_relative_level(get_selected_frame()), 1); 274184610Salfred } 275184610Salfred command_loop(); 276184610Salfred} 277184610Salfred 278188622Sthompsastatic void 279184610Salfredkgdb_init(char *argv0 __unused) 280184610Salfred{ 281184610Salfred static struct interp_procs procs = { 282184610Salfred NULL, 283184610Salfred NULL, 284184610Salfred NULL, 285184610Salfred NULL, 286184610Salfred NULL, 287184610Salfred kgdb_interp_command_loop 288184610Salfred }; 289184610Salfred struct interp *kgdb; 290184610Salfred kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs); 291184610Salfred interp_add(kgdb); 292184610Salfred 293184610Salfred set_prompt("(kgdb) "); 294184610Salfred kgdb_new_objfile_chain = target_new_objfile_hook; 295184610Salfred target_new_objfile_hook = kgdb_new_objfile; 296184610Salfred} 297188622Sthompsa 298184610Salfredint 299184610Salfredmain(int argc, char *argv[]) 300184610Salfred{ 301184610Salfred char path[PATH_MAX]; 302184610Salfred struct stat st; 303184610Salfred struct captured_main_args args; 304184610Salfred char *s; 305184610Salfred int a, ch, quiet, writecore; 306184610Salfred 307184610Salfred dumpnr = -1; 308184610Salfred 309184610Salfred strlcpy(crashdir, "/var/crash", sizeof(crashdir)); 310184610Salfred s = getenv("KGDB_CRASH_DIR"); 311184610Salfred if (s != NULL) 312184610Salfred strlcpy(crashdir, s, sizeof(crashdir)); 313184610Salfred 314184610Salfred /* Convert long options into short options. */ 315184610Salfred for (a = 1; a < argc; a++) { 316184610Salfred s = argv[a]; 317184610Salfred if (s[0] == '-') { 318184610Salfred s++; 319184610Salfred /* Long options take either 1 or 2 dashes. */ 320184610Salfred if (s[0] == '-') 321184610Salfred s++; 322184610Salfred if (strcmp(s, "quiet") == 0) 323184610Salfred argv[a] = "-q"; 324184610Salfred else if (strcmp(s, "fullname") == 0) 325184610Salfred argv[a] = "-f"; 326184610Salfred } 327184610Salfred } 328184610Salfred 329184610Salfred quiet = 0; 330184610Salfred writecore = 0; 331184610Salfred 332184610Salfred while ((ch = getopt(argc, argv, "ac:d:fn:qr:vw")) != -1) { 333184610Salfred switch (ch) { 334184610Salfred case 'a': 335184610Salfred annotation_level++; 336184610Salfred break; 337184610Salfred case 'c': /* use given core file. */ 338184610Salfred if (vmcore != NULL) { 339184610Salfred warnx("option %c: can only be specified once", 340184610Salfred optopt); 341184610Salfred usage(); 342184610Salfred /* NOTREACHED */ 343184610Salfred } 344184610Salfred vmcore = strdup(optarg); 345184610Salfred break; 346184610Salfred case 'd': /* lookup dumps in given directory. */ 347184610Salfred strlcpy(crashdir, optarg, sizeof(crashdir)); 348184610Salfred break; 349184610Salfred case 'f': 350184610Salfred annotation_level = 1; 351184610Salfred break; 352184610Salfred case 'n': /* use dump with given number. */ 353184610Salfred dumpnr = strtol(optarg, &s, 0); 354184610Salfred if (dumpnr < 0 || *s != '\0') { 355184610Salfred warnx("option %c: invalid kernel dump number", 356184610Salfred optopt); 357184610Salfred usage(); 358184610Salfred /* NOTREACHED */ 359184610Salfred } 360184610Salfred break; 361184610Salfred case 'q': 362184610Salfred quiet = 1; 363184610Salfred break; 364184610Salfred case 'r': /* use given device for remote session. */ 365184610Salfred if (remote != NULL) { 366184610Salfred warnx("option %c: can only be specified once", 367184610Salfred optopt); 368184610Salfred usage(); 369184610Salfred /* NOTREACHED */ 370184610Salfred } 371184610Salfred remote = strdup(optarg); 372184610Salfred break; 373184610Salfred case 'v': /* increase verbosity. */ 374184610Salfred verbose++; 375184610Salfred break; 376184610Salfred case 'w': /* core file is writeable. */ 377184610Salfred writecore = 1; 378184610Salfred break; 379184610Salfred case '?': 380184610Salfred default: 381184610Salfred usage(); 382184610Salfred } 383184610Salfred } 384184610Salfred 385184610Salfred if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) + 386184610Salfred ((remote != NULL) ? 1 : 0) > 1) { 387184610Salfred warnx("options -c, -n and -r are mutually exclusive"); 388184610Salfred usage(); 389184610Salfred /* NOTREACHED */ 390184610Salfred } 391184610Salfred 392184610Salfred if (verbose > 1) 393184610Salfred warnx("using %s as the crash directory", crashdir); 394184610Salfred 395184610Salfred if (argc > optind) 396184610Salfred kernel = strdup(argv[optind++]); 397184610Salfred 398184610Salfred if (argc > optind && (dumpnr >= 0 || remote != NULL)) { 399184610Salfred warnx("options -n and -r do not take a core file. Ignored"); 400184610Salfred optind = argc; 401184610Salfred } 402184610Salfred 403184610Salfred if (dumpnr >= 0) { 404184610Salfred snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr); 405184610Salfred if (stat(path, &st) == -1) 406184610Salfred err(1, path); 407184610Salfred if (!S_ISREG(st.st_mode)) 408184610Salfred errx(1, "%s: not a regular file", path); 409184610Salfred vmcore = strdup(path); 410184610Salfred } else if (remote != NULL && remote[0] != ':' && remote[0] != '|') { 411184610Salfred if (stat(remote, &st) != 0) { 412184610Salfred snprintf(path, sizeof(path), "/dev/%s", remote); 413184610Salfred if (stat(path, &st) != 0) { 414184610Salfred err(1, "%s", remote); 415184610Salfred /* NOTREACHED */ 416184610Salfred } 417184610Salfred free(remote); 418184610Salfred remote = strdup(path); 419184610Salfred } 420184610Salfred if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { 421184610Salfred errx(1, "%s: not a special file, FIFO or socket", 422184610Salfred remote); 423184610Salfred /* NOTREACHED */ 424184610Salfred } 425188622Sthompsa } else if (argc > optind) { 426184610Salfred if (vmcore == NULL) 427184610Salfred vmcore = strdup(argv[optind++]); 428184610Salfred if (argc > optind) 429184610Salfred warnx("multiple core files specified. Ignored"); 430184610Salfred } else if (vmcore == NULL && kernel == NULL) { 431184610Salfred vmcore = strdup(_PATH_MEM); 432184610Salfred kernel = strdup(getbootfile()); 433184610Salfred } 434184610Salfred 435184610Salfred if (verbose) { 436184610Salfred if (vmcore != NULL) 437184610Salfred warnx("core file: %s", vmcore); 438184610Salfred if (remote != NULL) 439184610Salfred warnx("device file: %s", remote); 440184610Salfred if (kernel != NULL) 441184610Salfred warnx("kernel image: %s", kernel); 442184610Salfred } 443184610Salfred 444184610Salfred /* 445184610Salfred * At this point we must either have a core file or have a kernel 446184610Salfred * with a remote target. 447184610Salfred */ 448184610Salfred if (remote != NULL && kernel == NULL) { 449184610Salfred warnx("remote debugging requires a kernel"); 450184610Salfred usage(); 451184610Salfred /* NOTREACHED */ 452184610Salfred } 453184610Salfred if (vmcore == NULL && remote == NULL) { 454184610Salfred warnx("need a core file or a device for remote debugging"); 455184610Salfred usage(); 456184610Salfred /* NOTREACHED */ 457188622Sthompsa } 458184610Salfred 459184610Salfred /* If we don't have a kernel image yet, try to find one. */ 460184610Salfred if (kernel == NULL) { 461184610Salfred if (dumpnr >= 0) 462184610Salfred kernel_from_dumpnr(dumpnr); 463184610Salfred 464184610Salfred if (kernel == NULL) 465184610Salfred errx(1, "couldn't find a suitable kernel image"); 466184610Salfred if (verbose) 467184610Salfred warnx("kernel image: %s", kernel); 468184610Salfred } 469184610Salfred 470184610Salfred if (remote == NULL) { 471184610Salfred kvm = kvm_openfiles(kernel, vmcore, NULL, 472184610Salfred writecore ? O_RDWR : O_RDONLY, kvm_err); 473184610Salfred if (kvm == NULL) 474184610Salfred errx(1, kvm_err); 475184610Salfred atexit(kgdb_atexit); 476184610Salfred kgdb_thr_init(); 477184610Salfred } 478184610Salfred 479184610Salfred /* The libgdb code uses optind too. Reset it... */ 480184610Salfred optind = 0; 481184610Salfred 482184610Salfred memset (&args, 0, sizeof args); 483184610Salfred args.argv = argv; 484184610Salfred args.argc = 1 + quiet; 485188622Sthompsa if (quiet) 486184610Salfred argv[1] = "-q"; 487184610Salfred argv[args.argc] = NULL; 488184610Salfred args.use_windows = 0; 489184610Salfred args.interpreter_p = "kgdb"; 490184610Salfred 491187184Sthompsa init_ui_hook = kgdb_init; 492187184Sthompsa 493184610Salfred kgdb_sniffer_kluge = kgdb_trgt_trapframe_sniffer; 494184610Salfred 495184610Salfred return (gdb_main(&args)); 496184610Salfred} 497184610Salfred