1132624Smarcel/*
2132624Smarcel * Copyright (c) 2004 Marcel Moolenaar
3132624Smarcel * All rights reserved.
4132624Smarcel *
5132624Smarcel * Redistribution and use in source and binary forms, with or without
6132624Smarcel * modification, are permitted provided that the following conditions
7132624Smarcel * are met:
8132624Smarcel *
9132624Smarcel * 1. Redistributions of source code must retain the above copyright
10132624Smarcel *    notice, this list of conditions and the following disclaimer.
11132624Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12132624Smarcel *    notice, this list of conditions and the following disclaimer in the
13132624Smarcel *    documentation and/or other materials provided with the distribution.
14132624Smarcel *
15132624Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16132624Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17132624Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18132624Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19132624Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20132624Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21132624Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22132624Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23132624Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24132624Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25132624Smarcel */
26132624Smarcel
27132624Smarcel#include <sys/cdefs.h>
28132624Smarcel__FBSDID("$FreeBSD$");
29132624Smarcel
30142151Skan#include <sys/param.h>
31142151Skan#include <sys/proc.h>
32142151Skan#include <sys/sysctl.h>
33142151Skan#include <sys/user.h>
34175808Sjhb#include <err.h>
35178670Sjhb#include <fcntl.h>
36132624Smarcel#include <kvm.h>
37132624Smarcel
38132624Smarcel#include <defs.h>
39178670Sjhb#include <readline/readline.h>
40178670Sjhb#include <readline/tilde.h>
41142151Skan#include <command.h>
42175808Sjhb#include <exec.h>
43149954Smarcel#include <frame-unwind.h>
44178713Sjhb#include <gdb.h>
45178670Sjhb#include <gdbcore.h>
46132624Smarcel#include <gdbthread.h>
47132624Smarcel#include <inferior.h>
48178670Sjhb#include <language.h>
49142151Skan#include <regcache.h>
50178670Sjhb#include <solib.h>
51132624Smarcel#include <target.h>
52178713Sjhb#include <ui-out.h>
53132624Smarcel
54142151Skan#include "kgdb.h"
55142151Skan
56260601Smarcel#ifdef CROSS_DEBUGGER
57260601Smarcel/*
58260601Smarcel * We suppress the call to add_target() of core_ops in corelow.c because if
59260601Smarcel * there are multiple core_stratum targets, the find_core_target() function
60260601Smarcel * won't know which one to return and returns none. We need it to return
61260601Smarcel * our target. We only have to do that when we're building a cross-debugger
62260601Smarcel * because fbsd-threads.c is part of a native debugger and it too defines
63260601Smarcel * coreops_suppress_target with 1 as the initializer.
64260601Smarcel */
65260601Smarcelint coreops_suppress_target = 1;
66260601Smarcel#endif
67260601Smarcel
68246893Smarcelstatic CORE_ADDR stoppcbs;
69246893Smarcel
70178670Sjhbstatic void	kgdb_core_cleanup(void *);
71178670Sjhb
72178670Sjhbstatic char *vmcore;
73132624Smarcelstatic struct target_ops kgdb_trgt_ops;
74132624Smarcel
75178670Sjhbkvm_t *kvm;
76178670Sjhbstatic char kvm_err[_POSIX2_LINE_MAX];
77175808Sjhb
78163439Sjhb#define	KERNOFF		(kgdb_kernbase ())
79285041Skib#define	PINKERNEL(x)	((x) >= KERNOFF)
80163439Sjhb
81291406Sjhbstatic int
82291406Sjhbkgdb_resolve_symbol(const char *name, kvaddr_t *kva)
83291406Sjhb{
84291406Sjhb	struct minimal_symbol *ms;
85291406Sjhb
86291406Sjhb	ms = lookup_minimal_symbol (name, NULL, NULL);
87291406Sjhb	if (ms == NULL)
88291406Sjhb		return (1);
89291406Sjhb
90291406Sjhb	*kva = SYMBOL_VALUE_ADDRESS (ms);
91291525Sjhb	return (0);
92291406Sjhb}
93291406Sjhb
94163439Sjhbstatic CORE_ADDR
95163439Sjhbkgdb_kernbase (void)
96163439Sjhb{
97163439Sjhb	static CORE_ADDR kernbase;
98163439Sjhb	struct minimal_symbol *sym;
99163439Sjhb
100163439Sjhb	if (kernbase == 0) {
101163439Sjhb		sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
102163439Sjhb		if (sym == NULL) {
103163439Sjhb			kernbase = KERNBASE;
104163439Sjhb		} else {
105163439Sjhb			kernbase = SYMBOL_VALUE_ADDRESS (sym);
106163439Sjhb		}
107163439Sjhb	}
108163439Sjhb	return kernbase;
109163439Sjhb}
110163439Sjhb
111178670Sjhbstatic void
112178670Sjhbkgdb_trgt_open(char *filename, int from_tty)
113178670Sjhb{
114178670Sjhb	struct cleanup *old_chain;
115178670Sjhb	struct thread_info *ti;
116178670Sjhb	struct kthr *kt;
117178670Sjhb	kvm_t *nkvm;
118178670Sjhb	char *temp;
119178670Sjhb	int ontop;
120178670Sjhb
121178670Sjhb	target_preopen (from_tty);
122178670Sjhb	if (!filename)
123178670Sjhb		error ("No vmcore file specified.");
124178670Sjhb	if (!exec_bfd)
125178670Sjhb		error ("Can't open a vmcore without a kernel");
126178670Sjhb
127178670Sjhb	filename = tilde_expand (filename);
128178670Sjhb	if (filename[0] != '/') {
129178670Sjhb		temp = concat (current_directory, "/", filename, NULL);
130178670Sjhb		xfree(filename);
131178670Sjhb		filename = temp;
132178670Sjhb	}
133178670Sjhb
134178670Sjhb	old_chain = make_cleanup (xfree, filename);
135178670Sjhb
136291406Sjhb	nkvm = kvm_open2(bfd_get_filename(exec_bfd), filename,
137291406Sjhb	    write_files ? O_RDWR : O_RDONLY, kvm_err, kgdb_resolve_symbol);
138178670Sjhb	if (nkvm == NULL)
139178670Sjhb		error ("Failed to open vmcore: %s", kvm_err);
140178670Sjhb
141178670Sjhb	/* Don't free the filename now and close any previous vmcore. */
142178670Sjhb	discard_cleanups(old_chain);
143178670Sjhb	unpush_target(&kgdb_trgt_ops);
144178670Sjhb
145178670Sjhb	kvm = nkvm;
146178670Sjhb	vmcore = filename;
147178670Sjhb	old_chain = make_cleanup(kgdb_core_cleanup, NULL);
148178670Sjhb
149178670Sjhb	ontop = !push_target (&kgdb_trgt_ops);
150178670Sjhb	discard_cleanups (old_chain);
151178670Sjhb
152178670Sjhb	kgdb_dmesg();
153178670Sjhb
154178670Sjhb	init_thread_list();
155178670Sjhb	kt = kgdb_thr_init();
156178670Sjhb	while (kt != NULL) {
157178713Sjhb		ti = add_thread(pid_to_ptid(kt->tid));
158178670Sjhb		kt = kgdb_thr_next(kt);
159178670Sjhb	}
160178670Sjhb	if (curkthr != 0)
161178713Sjhb		inferior_ptid = pid_to_ptid(curkthr->tid);
162178670Sjhb
163178670Sjhb	if (ontop) {
164178670Sjhb		/* XXX: fetch registers? */
165178670Sjhb		kld_init();
166178670Sjhb		flush_cached_frames();
167178670Sjhb		select_frame (get_current_frame());
168178670Sjhb		print_stack_frame(get_selected_frame(),
169178670Sjhb		    frame_relative_level(get_selected_frame()), 1);
170178670Sjhb	} else
171178670Sjhb		warning(
172178670Sjhb	"you won't be able to access this vmcore until you terminate\n\
173178670Sjhbyour %s; do ``info files''", target_longname);
174178670Sjhb}
175178670Sjhb
176178670Sjhbstatic void
177178670Sjhbkgdb_trgt_close(int quitting)
178178670Sjhb{
179178670Sjhb
180178670Sjhb	if (kvm != NULL) {
181178670Sjhb		inferior_ptid = null_ptid;
182178670Sjhb		CLEAR_SOLIB();
183178670Sjhb		if (kvm_close(kvm) != 0)
184178670Sjhb			warning("cannot close \"%s\": %s", vmcore,
185178670Sjhb			    kvm_geterr(kvm));
186178670Sjhb		kvm = NULL;
187178670Sjhb		xfree(vmcore);
188178670Sjhb		vmcore = NULL;
189178670Sjhb		if (kgdb_trgt_ops.to_sections) {
190178670Sjhb			xfree(kgdb_trgt_ops.to_sections);
191178670Sjhb			kgdb_trgt_ops.to_sections = NULL;
192178670Sjhb			kgdb_trgt_ops.to_sections_end = NULL;
193178670Sjhb		}
194178670Sjhb	}
195178670Sjhb}
196178670Sjhb
197178670Sjhbstatic void
198178670Sjhbkgdb_core_cleanup(void *arg)
199178670Sjhb{
200178670Sjhb
201178670Sjhb	kgdb_trgt_close(0);
202178670Sjhb}
203178670Sjhb
204178670Sjhbstatic void
205