main.c revision 147570
1/* 2 * Copyright (c) 2004 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 147570 2005-06-24 00:50:12Z peter $"); 29 30#include <sys/param.h> 31#include <sys/stat.h> 32#include <sys/types.h> 33#include <sys/ioctl.h> 34#include <sys/resource.h> 35#include <sys/select.h> 36#include <sys/time.h> 37#include <sys/wait.h> 38#include <errno.h> 39#include <err.h> 40#include <fcntl.h> 41#include <inttypes.h> 42#include <kvm.h> 43#include <limits.h> 44#include <paths.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49 50/* libgdb stuff. */ 51#include <defs.h> 52#include <frame.h> 53#include <inferior.h> 54#include <interps.h> 55#include <cli-out.h> 56#include <main.h> 57#include <target.h> 58#include <top.h> 59#include <bfd.h> 60#include <gdbcore.h> 61 62extern void (*init_ui_hook)(char *); 63 64extern void symbol_file_add_main (char *args, int from_tty); 65 66#include "kgdb.h" 67 68kvm_t *kvm; 69 70static int dumpnr; 71static int verbose; 72 73static char crashdir[PATH_MAX]; 74static char *kernel; 75static char *remote; 76static char *vmcore; 77 78static void (*kgdb_new_objfile_chain)(struct objfile * objfile); 79 80static void 81usage(void) 82{ 83 84 fprintf(stderr, 85 "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n" 86 "\t[kernel [core]]\n", getprogname()); 87 exit(1); 88} 89 90static void 91kernel_from_dumpnr(int nr) 92{ 93 char path[PATH_MAX]; 94 FILE *info; 95 char *s; 96 struct stat st; 97 int l; 98 99 /* 100 * If there's a kernel image right here in the crash directory, then 101 * use it. The kernel image is either called kernel.<nr> or is in a 102 * subdirectory kernel.<nr> and called kernel. The latter allows us 103 * to collect the modules in the same place. 104 */ 105 snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr); 106 if (stat(path, &st) == 0) { 107 if (S_ISREG(st.st_mode)) { 108 kernel = strdup(path); 109 return; 110 } 111 if (S_ISDIR(st.st_mode)) { 112 snprintf(path, sizeof(path), "%s/kernel.%d/kernel", 113 crashdir, nr); 114 if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { 115 kernel = strdup(path); 116 return; 117 } 118 } 119 } 120 121 /* 122 * No kernel image here. Parse the dump header. The kernel object 123 * directory can be found there and we probably have the kernel 124 * image still in it. The object directory may also have a kernel 125 * with debugging info (called kernel.debug). If we have a debug 126 * kernel, use it. 127 */ 128 snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr); 129 info = fopen(path, "r"); 130 if (info == NULL) { 131 warn(path); 132 return; 133 } 134 while (fgets(path, sizeof(path), info) != NULL) { 135 l = strlen(path); 136 if (l > 0 && path[l - 1] == '\n') 137 path[--l] = '\0'; 138 if (strncmp(path, " ", 4) == 0) { 139 s = strchr(path, ':'); 140 s = (s == NULL) ? path + 4 : s + 1; 141 l = snprintf(path, sizeof(path), "%s/kernel.debug", s); 142 if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) { 143 path[l - 6] = '\0'; 144 if (stat(path, &st) == -1 || 145 !S_ISREG(st.st_mode)) 146 break; 147 } 148 kernel = strdup(path); 149 break; 150 } 151 } 152 fclose(info); 153} 154 155static void 156kgdb_new_objfile(struct objfile *objfile) 157{ 158#if 0 159 printf("XXX: %s(%p)\n", __func__, objfile); 160 if (objfile != NULL) { 161 goto out; 162 } 163 164out: 165#endif 166 if (kgdb_new_objfile_chain != NULL) 167 kgdb_new_objfile_chain(objfile); 168} 169 170static void 171kgdb_init_target(void) 172{ 173 bfd *kern_bfd; 174 int kern_desc; 175 176 kern_desc = open(kernel, O_RDONLY); 177 if (kern_desc == -1) 178 errx(1, "couldn't open a kernel image"); 179 180 kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc); 181 if (kern_bfd == NULL) { 182 close(kern_desc); 183 errx(1, "\"%s\": can't open to probe ABI: %s.", kernel, 184 bfd_errmsg (bfd_get_error ())); 185 } 186 bfd_set_cacheable(kern_bfd, 1); 187 188 if (!bfd_check_format (kern_bfd, bfd_object)) { 189 bfd_close(kern_bfd); 190 errx(1, "\"%s\": not in executable format: %s", kernel, 191 bfd_errmsg(bfd_get_error())); 192 } 193 194 set_gdbarch_from_file (kern_bfd); 195 bfd_close(kern_bfd); 196 197 symbol_file_add_main (kernel, 0); 198 if (remote) 199 push_remote_target (remote, 0); 200 else 201 kgdb_target(); 202} 203 204static void 205kgdb_interp_command_loop(void *data) 206{ 207 static int once = 0; 208 209 if (!once) { 210 once = 1; 211 kgdb_init_target(); 212 kgdb_target(); 213 print_stack_frame (get_selected_frame (), 214 frame_relative_level (get_selected_frame ()), 1); 215 } 216 command_loop(); 217} 218 219static void 220kgdb_init(char *argv0 __unused) 221{ 222 static struct interp_procs procs = { 223 NULL, 224 NULL, 225 NULL, 226 NULL, 227 NULL, 228 kgdb_interp_command_loop 229 }; 230 struct interp *kgdb; 231 kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs); 232 interp_add(kgdb); 233 234 set_prompt("(kgdb) "); 235 kgdb_new_objfile_chain = target_new_objfile_hook; 236 target_new_objfile_hook = kgdb_new_objfile; 237} 238 239int 240main(int argc, char *argv[]) 241{ 242 char path[PATH_MAX]; 243 struct stat st; 244 struct captured_main_args args; 245 char *s; 246 int a, ch, quiet; 247 248 dumpnr = -1; 249 250 strlcpy(crashdir, "/var/crash", sizeof(crashdir)); 251 s = getenv("KGDB_CRASH_DIR"); 252 if (s != NULL) 253 strlcpy(crashdir, s, sizeof(crashdir)); 254 255 /* Convert long options into short options. */ 256 for (a = 1; a < argc; a++) { 257 s = argv[a]; 258 if (s[0] == '-') { 259 s++; 260 /* Long options take either 1 or 2 dashes. */ 261 if (s[0] == '-') 262 s++; 263 if (strcmp(s, "quiet") == 0) 264 argv[a] = "-q"; 265 else if (strcmp(s, "fullname") == 0) 266 argv[a] = "-f"; 267 } 268 } 269 270 quiet = 0; 271 272 while ((ch = getopt(argc, argv, "ac:d:fn:qr:v")) != -1) { 273 switch (ch) { 274 case 'a': 275 annotation_level++; 276 break; 277 case 'c': /* use given core file. */ 278 if (vmcore != NULL) { 279 warnx("option %c: can only be specified once", 280 optopt); 281 usage(); 282 /* NOTREACHED */ 283 } 284 vmcore = strdup(optarg); 285 break; 286 case 'd': /* lookup dumps in given directory. */ 287 strlcpy(crashdir, optarg, sizeof(crashdir)); 288 break; 289 case 'f': 290 annotation_level = 1; 291 break; 292 case 'n': /* use dump with given number. */ 293 dumpnr = strtol(optarg, &s, 0); 294 if (dumpnr < 0 || *s != '\0') { 295 warnx("option %c: invalid kernel dump number", 296 optopt); 297 usage(); 298 /* NOTREACHED */ 299 } 300 break; 301 case 'q': 302 quiet = 1; 303 break; 304 case 'r': /* use given device for remote session. */ 305 if (remote != NULL) { 306 warnx("option %c: can only be specified once", 307 optopt); 308 usage(); 309 /* NOTREACHED */ 310 } 311 remote = strdup(optarg); 312 break; 313 case 'v': /* increase verbosity. */ 314 verbose++; 315 break; 316 case '?': 317 default: 318 usage(); 319 } 320 } 321 322 if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) + 323 ((remote != NULL) ? 1 : 0) > 1) { 324 warnx("options -c, -n and -r are mutually exclusive"); 325 usage(); 326 /* NOTREACHED */ 327 } 328 329 if (verbose > 1) 330 warnx("using %s as the crash directory", crashdir); 331 332 if (argc > optind) 333 kernel = strdup(argv[optind++]); 334 335 if (argc > optind && (dumpnr >= 0 || remote != NULL)) { 336 warnx("options -n and -r do not take a core file. Ignored"); 337 optind = argc; 338 } 339 340 if (dumpnr >= 0) { 341 snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr); 342 if (stat(path, &st) == -1) 343 err(1, path); 344 if (!S_ISREG(st.st_mode)) 345 errx(1, "%s: not a regular file", path); 346 vmcore = strdup(path); 347 } else if (remote != NULL && remote[0] != ':' && remote[0] != '|') { 348 if (stat(remote, &st) != 0) { 349 snprintf(path, sizeof(path), "/dev/%s", remote); 350 if (stat(path, &st) != 0) { 351 err(1, "%s", remote); 352 /* NOTREACHED */ 353 } 354 free(remote); 355 remote = strdup(path); 356 } 357 if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { 358 errx(1, "%s: not a special file, FIFO or socket", 359 remote); 360 /* NOTREACHED */ 361 } 362 } else if (argc > optind) { 363 if (vmcore == NULL) 364 vmcore = strdup(argv[optind++]); 365 if (argc > optind) 366 warnx("multiple core files specified. Ignored"); 367 } else if (vmcore == NULL && kernel == NULL) { 368 vmcore = strdup(_PATH_MEM); 369 kernel = strdup(getbootfile()); 370 } 371 372 if (verbose) { 373 if (vmcore != NULL) 374 warnx("core file: %s", vmcore); 375 if (remote != NULL) 376 warnx("device file: %s", remote); 377 if (kernel != NULL) 378 warnx("kernel image: %s", kernel); 379 } 380 381 /* 382 * At this point we must either have a core file or have a kernel 383 * with a remote target. 384 */ 385 if (remote != NULL && kernel == NULL) { 386 warnx("remote debugging requires a kernel"); 387 usage(); 388 /* NOTREACHED */ 389 } 390 if (vmcore == NULL && remote == NULL) { 391 warnx("need a core file or a device for remote debugging"); 392 usage(); 393 /* NOTREACHED */ 394 } 395 396 /* If we don't have a kernel image yet, try to find one. */ 397 if (kernel == NULL) { 398 if (dumpnr >= 0) 399 kernel_from_dumpnr(dumpnr); 400 401 if (kernel == NULL) 402 errx(1, "couldn't find a suitable kernel image"); 403 if (verbose) 404 warnx("kernel image: %s", kernel); 405 } 406 407 if (remote == NULL) { 408 s = malloc(_POSIX2_LINE_MAX); 409 kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s); 410 if (kvm == NULL) 411 errx(1, s); 412 kgdb_thr_init(); 413 } 414 415 /* The libgdb code uses optind too. Reset it... */ 416 optind = 0; 417 418 memset (&args, 0, sizeof args); 419 args.argv = argv; 420 args.argc = 1 + quiet; 421 if (quiet) 422 argv[1] = "-q"; 423 argv[args.argc] = NULL; 424 args.use_windows = 0; 425 args.interpreter_p = "kgdb"; 426 427 init_ui_hook = kgdb_init; 428 429 return (gdb_main(&args)); 430} 431