AMD64 - Fix kgdb for kernel core files.
[dragonfly.git] / gnu / usr.bin / gdb / kgdb / kgdb.c
CommitLineData
8b6a428f
SS
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 * $FreeBSD: src/gnu/usr.bin/gdb/kgdb/main.c,v 1.11 2006/01/04 23:17:52 kan Exp $
0c3d4888 27 * $DragonFly: src/gnu/usr.bin/gdb/kgdb/kgdb.c,v 1.3 2008/01/14 21:36:38 corecode Exp $
8b6a428f
SS
28 */
29
30#include <sys/cdefs.h>
31
32#include <sys/param.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <sys/ioctl.h>
36#include <sys/resource.h>
37#include <sys/select.h>
38#include <sys/time.h>
39#include <sys/wait.h>
c499d304 40#include <sys/msgbuf.h>
8b6a428f
SS
41#include <errno.h>
42#include <err.h>
43#include <fcntl.h>
44#include <inttypes.h>
45#include <kvm.h>
46#include <limits.h>
47#include <paths.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52#include <linker_set.h>
53
54/* libgdb stuff. */
55#include <defs.h>
56#include <frame.h>
57#include <frame-unwind.h>
58#include <inferior.h>
59#include <interps.h>
60#include <cli-out.h>
61#include <main.h>
62#include <target.h>
63#include <top.h>
64#include <bfd.h>
65#include <gdbcore.h>
66#include <target.h>
67
68extern void symbol_file_add_main (char *args, int from_tty);
69
70#include "kgdb.h"
71
72kvm_t *kvm;
73static char kvm_err[_POSIX2_LINE_MAX];
74
75static int dumpnr;
76static int verbose;
77
78static char crashdir[PATH_MAX];
79static char *kernel;
80static char *remote;
81static char *vmcore;
82
83static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
84
c499d304
SS
85uintptr_t
86lookup(const char *sym)
87{
88 struct nlist nl[2];
89
90 nl[0].n_name = (char *)(uintptr_t)sym;
91 nl[1].n_name = NULL;
92 if (kvm_nlist(kvm, nl) != 0) {
93 warnx("kvm_nlist(%s): %s", sym, kvm_geterr(kvm));
94 return (0);
95 }
96 return (nl[0].n_value);
97}
98
8b6a428f
SS
99static void
100kgdb_atexit(void)
101{
102 if (kvm != NULL)
103 kvm_close(kvm);
104}
105
106static void
107usage(void)
108{
109
110 fprintf(stderr,
111 "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
112 "\t[kernel [core]]\n", getprogname());
113 exit(1);
114}
115
116static void
117kernel_from_dumpnr(int nr)
118{
119 char path[PATH_MAX];
120 FILE *info;
121 char *s;
122 struct stat st;
123 int l;
124
125 /*
126 * If there's a kernel image right here in the crash directory, then
127 * use it. The kernel image is either called kernel.<nr> or is in a
128 * subdirectory kernel.<nr> and called kernel. The latter allows us
129 * to collect the modules in the same place.
130 */
131 snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
132 if (stat(path, &st) == 0) {
133 if (S_ISREG(st.st_mode)) {
134 kernel = strdup(path);
135 return;
136 }
137 if (S_ISDIR(st.st_mode)) {
138 snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
139 crashdir, nr);
140 if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
141 kernel = strdup(path);
142 return;
143 }
144 }
145 }
146
147 /*
148 * No kernel image here. Parse the dump header. The kernel object
149 * directory can be found there and we probably have the kernel
150 * image still in it. The object directory may also have a kernel
151 * with debugging info (called kernel.debug). If we have a debug
152 * kernel, use it.
153 */
154 snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
155 info = fopen(path, "r");
156 if (info == NULL) {
157 warn(path);
158 return;
159 }
160 while (fgets(path, sizeof(path), info) != NULL) {
161 l = strlen(path);
162 if (l > 0 && path[l - 1] == '\n')
163 path[--l] = '\0';
164 if (strncmp(path, " ", 4) == 0) {
165 s = strchr(path, ':');
166 s = (s == NULL) ? path + 4 : s + 1;
167 l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
168 if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
169 path[l - 6] = '\0';
170 if (stat(path, &st) == -1 ||
171 !S_ISREG(st.st_mode))
172 break;
173 }
174 kernel = strdup(path);
175 break;
176 }
177 }
178 fclose(info);
179}
180
181static void
182kgdb_new_objfile(struct objfile *objfile)
183{
184#if 0
185 printf("XXX: %s(%p)\n", __func__, objfile);
186 if (objfile != NULL) {
187 goto out;
188 }
189
190out:
191#endif
192 if (kgdb_new_objfile_chain != NULL)
193 kgdb_new_objfile_chain(objfile);
194}
195
196static CORE_ADDR
197kgdb_parse(const char *exp)
198{
199 struct cleanup *old_chain;
200 struct expression *expr;
201 struct value *val;
202 char *s;
203 CORE_ADDR n;
204
205 s = strdup(exp);
206 old_chain = make_cleanup(free_current_contents, &expr);
207 expr = parse_expression(s);
208 val = (expr != NULL) ? evaluate_expression(expr) : NULL;
209 n = (val != NULL) ? value_as_address(val) : 0;
210 do_cleanups(old_chain);
211 free(s);
212 return (n);
213}
214
215#define MSGBUF_SEQ_TO_POS(size, seq) ((seq) % (size))
216
3cdd3f79
MD
217/*
218 * Fake-up because kernel may not have an ABI tag.
219 */
220static int
221kgdb_dummy_sniffer(bfd *bfd)
222{
223 return(GDB_OSABI_DRAGONFLY_ELF);
224}
225
226
8b6a428f
SS
227static void
228kgdb_init_target(void)
229{
230 bfd *kern_bfd;
231 int kern_desc;
232
3cdd3f79
MD
233 gdbarch_register_osabi_sniffer(bfd_arch_i386, bfd_target_elf_flavour,
234 kgdb_dummy_sniffer);
235
8b6a428f
SS
236 kern_desc = open(kernel, O_RDONLY);
237 if (kern_desc == -1)
238 errx(1, "couldn't open a kernel image");
239
240 kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc);
241 if (kern_bfd == NULL) {
242 close(kern_desc);
243 errx(1, "\"%s\": can't open to probe ABI: %s.", kernel,
244 bfd_errmsg (bfd_get_error ()));
245 }
246 bfd_set_cacheable(kern_bfd, 1);
247
248 if (!bfd_check_format (kern_bfd, bfd_object)) {
249 bfd_close(kern_bfd);
250 errx(1, "\"%s\": not in executable format: %s", kernel,
251 bfd_errmsg(bfd_get_error()));
252 }
253
254 set_gdbarch_from_file (kern_bfd);
255 bfd_close(kern_bfd);
256
257 frame_unwind_prepend_unwinder(current_gdbarch, &kgdb_trgt_trapframe_unwind);
258
259 symbol_file_add_main (kernel, 0);
260 if (remote)
261 push_remote_target (remote, 0);
262 else
263 kgdb_target();
264}
265
266static void
267kgdb_display_msgbuf(void)
268{
c499d304
SS
269 uintptr_t addr;
270 struct msgbuf *bufp, buf;
271 size_t rseq, wseq;
8b6a428f
SS
272 char c;
273
274 /*
275 * Display the unread portion of the message buffer. This gives the
276 * user a some initial data to work from.
277 */
c499d304
SS
278 addr = lookup("_msgbufp");
279 if (addr == 0)
280 return;
281 read_memory((CORE_ADDR)addr, (char *)&bufp, sizeof(bufp));
282 read_memory((CORE_ADDR)bufp, (char *)&buf, sizeof(buf));
283 if (buf.msg_size == 0 || buf.msg_bufr == buf.msg_bufx)
8b6a428f 284 return;
c499d304
SS
285 rseq = MSGBUF_SEQ_TO_POS(buf.msg_size, buf.msg_bufr);
286 wseq = MSGBUF_SEQ_TO_POS(buf.msg_size, buf.msg_bufx);
8b6a428f
SS
287
288 printf("\nUnread portion of the kernel message buffer:\n");
289 while (rseq < wseq) {
c499d304 290 read_memory((CORE_ADDR)buf.msg_ptr + rseq, &c, 1);
8b6a428f
SS
291 putchar(c);
292 rseq++;
c499d304 293 if (rseq == buf.msg_size)
8b6a428f
SS
294 rseq = 0;
295 }
296 if (c != '\n')
297 putchar('\n');
298 putchar('\n');
299}
300
301static void
302kgdb_init(char *argv0 __unused)
303{
304 kgdb_init_target();
305
306 set_prompt("(kgdb) ");
307 kgdb_display_msgbuf();
0c3d4888
SS
308 print_stack_frame(get_selected_frame(NULL),
309 frame_relative_level(get_selected_frame(NULL)), 1);
8b6a428f
SS
310}
311
312int
313main(int argc, char *argv[])
314{
315 char path[PATH_MAX];
316 struct stat st;
317 struct captured_main_args args;
318 char *s;
319 int a, ch, quiet, writecore;
320
321 dumpnr = -1;
322
323 strlcpy(crashdir, "/var/crash", sizeof(crashdir));
324 s = getenv("KGDB_CRASH_DIR");
325 if (s != NULL)
326 strlcpy(crashdir, s, sizeof(crashdir));
327
328 /* Convert long options into short options. */
329 for (a = 1; a < argc; a++) {
330 s = argv[a];
331 if (s[0] == '-') {
332 s++;
333 /* Long options take either 1 or 2 dashes. */
334 if (s[0] == '-')
335 s++;
336 if (strcmp(s, "quiet") == 0)
337 argv[a] = "-q";
338 else if (strcmp(s, "fullname") == 0)
339 argv[a] = "-f";
340 }
341 }
342
343 quiet = 0;
344 writecore = 0;
345
346 while ((ch = getopt(argc, argv, "ac:d:fn:qr:vw")) != -1) {
347 switch (ch) {
348 case 'a':
349 annotation_level++;
350 break;
351 case 'c': /* use given core file. */
352 if (vmcore != NULL) {
353 warnx("option %c: can only be specified once",
354 optopt);
355 usage();
356 /* NOTREACHED */
357 }
358 vmcore = strdup(optarg);
359 break;
360 case 'd': /* lookup dumps in given directory. */
361 strlcpy(crashdir, optarg, sizeof(crashdir));
362 break;
363 case 'f':
364 annotation_level = 1;
365 break;
366 case 'n': /* use dump with given number. */
367 dumpnr = strtol(optarg, &s, 0);
368 if (dumpnr < 0 || *s != '\0') {
369 warnx("option %c: invalid kernel dump number",
370 optopt);
371 usage();
372 /* NOTREACHED */
373 }
374 break;
375 case 'q':
376 quiet = 1;
377 break;
378 case 'r': /* use given device for remote session. */
379 if (remote != NULL) {
380 warnx("option %c: can only be specified once",
381 optopt);
382 usage();
383 /* NOTREACHED */
384 }
385 remote = strdup(optarg);
386 break;
387 case 'v': /* increase verbosity. */
388 verbose++;
389 break;
390 case 'w': /* core file is writeable. */
391 writecore = 1;
392 break;
393 case '?':
394 default:
395 usage();
396 }
397 }
398
399 if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
400 ((remote != NULL) ? 1 : 0) > 1) {
401 warnx("options -c, -n and -r are mutually exclusive");
402 usage();
403 /* NOTREACHED */
404 }
405
406 if (verbose > 1)
407 warnx("using %s as the crash directory", crashdir);
408
409 if (argc > optind)
410 kernel = strdup(argv[optind++]);
411
412 if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
413 warnx("options -n and -r do not take a core file. Ignored");
414 optind = argc;
415 }
416
417 if (dumpnr >= 0) {
418 snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
419 if (stat(path, &st) == -1)
420 err(1, path);
421 if (!S_ISREG(st.st_mode))
422 errx(1, "%s: not a regular file", path);
423 vmcore = strdup(path);
424 } else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
425 if (stat(remote, &st) != 0) {
426 snprintf(path, sizeof(path), "/dev/%s", remote);
427 if (stat(path, &st) != 0) {
428 err(1, "%s", remote);
429 /* NOTREACHED */
430 }
431 free(remote);
432 remote = strdup(path);
433 }
434 if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
435 errx(1, "%s: not a special file, FIFO or socket",
436 remote);
437 /* NOTREACHED */
438 }
439 } else if (argc > optind) {
440 if (vmcore == NULL)
441 vmcore = strdup(argv[optind++]);
442 if (argc > optind)
443 warnx("multiple core files specified. Ignored");
444 } else if (vmcore == NULL && kernel == NULL) {
445 vmcore = strdup(_PATH_MEM);
446 kernel = strdup(getbootfile());
447 }
448
449 if (verbose) {
450 if (vmcore != NULL)
451 warnx("core file: %s", vmcore);
452 if (remote != NULL)
453 warnx("device file: %s", remote);
454 if (kernel != NULL)
455 warnx("kernel image: %s", kernel);
456 }
457
458 /*
459 * At this point we must either have a core file or have a kernel
460 * with a remote target.
461 */
462 if (remote != NULL && kernel == NULL) {
463 warnx("remote debugging requires a kernel");
464 usage();
465 /* NOTREACHED */
466 }
467 if (vmcore == NULL && remote == NULL) {
468 warnx("need a core file or a device for remote debugging");
469 usage();
470 /* NOTREACHED */
471 }
472
473 /* If we don't have a kernel image yet, try to find one. */
474 if (kernel == NULL) {
475 if (dumpnr >= 0)
476 kernel_from_dumpnr(dumpnr);
477
478 if (kernel == NULL)
479 errx(1, "couldn't find a suitable kernel image");
480 if (verbose)
481 warnx("kernel image: %s", kernel);
482 }
483
484 if (remote == NULL) {
485 kvm = kvm_openfiles(kernel, vmcore, NULL,
486 writecore ? O_RDWR : O_RDONLY, kvm_err);
487 if (kvm == NULL)
488 errx(1, kvm_err);
489 atexit(kgdb_atexit);
490 kgdb_thr_init();
491 }
492
493 /* The libgdb code uses optind too. Reset it... */
494 optind = 0;
495
496 memset (&args, 0, sizeof args);
497 args.argv = argv;
498 args.argc = 1 + quiet;
499 if (quiet)
500 argv[1] = "-q";
501 argv[args.argc] = NULL;
502 args.use_windows = 0;
503 args.interpreter_p = INTERP_CONSOLE;
504
505 deprecated_init_ui_hook = kgdb_init;
506
507 return (gdb_main(&args));
508}