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
56178670Sjhbstatic void	kgdb_core_cleanup(void *);
57178670Sjhb
58178670Sjhbstatic char *vmcore;
59132624Smarcelstatic struct target_ops kgdb_trgt_ops;
60132624Smarcel
61178670Sjhbkvm_t *kvm;
62178670Sjhbstatic char kvm_err[_POSIX2_LINE_MAX];
63175808Sjhb
64163439Sjhb#define	KERNOFF		(kgdb_kernbase ())
65163439Sjhb#define	INKERNEL(x)	((x) >= KERNOFF)
66163439Sjhb
67163439Sjhbstatic CORE_ADDR
68163439Sjhbkgdb_kernbase (void)
69163439Sjhb{
70163439Sjhb	static CORE_ADDR kernbase;
71163439Sjhb	struct minimal_symbol *sym;
72163439Sjhb
73163439Sjhb	if (kernbase == 0) {
74163439Sjhb		sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
75163439Sjhb		if (sym == NULL) {
76163439Sjhb			kernbase = KERNBASE;
77163439Sjhb		} else {
78163439Sjhb			kernbase = SYMBOL_VALUE_ADDRESS (sym);
79163439Sjhb		}
80163439Sjhb	}
81163439Sjhb	return kernbase;
82163439Sjhb}
83163439Sjhb
84178670Sjhbstatic void
85178670Sjhbkgdb_trgt_open(char *filename, int from_tty)
86178670Sjhb{
87178670Sjhb	struct cleanup *old_chain;
88178670Sjhb	struct thread_info *ti;
89178670Sjhb	struct kthr *kt;
90178670Sjhb	kvm_t *nkvm;
91178670Sjhb	char *temp;
92178670Sjhb	int ontop;
93178670Sjhb
94178670Sjhb	target_preopen (from_tty);
95178670Sjhb	if (!filename)
96178670Sjhb		error ("No vmcore file specified.");
97178670Sjhb	if (!exec_bfd)
98178670Sjhb		error ("Can't open a vmcore without a kernel");
99178670Sjhb
100178670Sjhb	filename = tilde_expand (filename);
101178670Sjhb	if (filename[0] != '/') {
102178670Sjhb		temp = concat (current_directory, "/", filename, NULL);
103178670Sjhb		xfree(filename);
104178670Sjhb		filename = temp;
105178670Sjhb	}
106178670Sjhb
107178670Sjhb	old_chain = make_cleanup (xfree, filename);
108178670Sjhb
109178670Sjhb	nkvm = kvm_openfiles(bfd_get_filename(exec_bfd), filename, NULL,
110178670Sjhb	    write_files ? O_RDWR : O_RDONLY, kvm_err);
111178670Sjhb	if (nkvm == NULL)
112178670Sjhb		error ("Failed to open vmcore: %s", kvm_err);
113178670Sjhb
114178670Sjhb	/* Don't free the filename now and close any previous vmcore. */
115178670Sjhb	discard_cleanups(old_chain);
116178670Sjhb	unpush_target(&kgdb_trgt_ops);
117178670Sjhb
118178670Sjhb	kvm = nkvm;
119178670Sjhb	vmcore = filename;
120178670Sjhb	old_chain = make_cleanup(kgdb_core_cleanup, NULL);
121178670Sjhb
122178670Sjhb	ontop = !push_target (&kgdb_trgt_ops);
123178670Sjhb	discard_cleanups (old_chain);
124178670Sjhb
125178670Sjhb	kgdb_dmesg();
126178670Sjhb
127178670Sjhb	init_thread_list();
128178670Sjhb	kt = kgdb_thr_init();
129178670Sjhb	while (kt != NULL) {
130178713Sjhb		ti = add_thread(pid_to_ptid(kt->tid));
131178670Sjhb		kt = kgdb_thr_next(kt);
132178670Sjhb	}
133178670Sjhb	if (curkthr != 0)
134178713Sjhb		inferior_ptid = pid_to_ptid(curkthr->tid);
135178670Sjhb
136178670Sjhb	if (ontop) {
137178670Sjhb		/* XXX: fetch registers? */
138178670Sjhb		kld_init();
139178670Sjhb		flush_cached_frames();
140178670Sjhb		select_frame (get_current_frame());
141178670Sjhb		print_stack_frame(get_selected_frame(),
142178670Sjhb		    frame_relative_level(get_selected_frame()), 1);
143178670Sjhb	} else
144178670Sjhb		warning(
145178670Sjhb	"you won't be able to access this vmcore until you terminate\n\
146178670Sjhbyour %s; do ``info files''", target_longname);
147178670Sjhb}
148178670Sjhb
149178670Sjhbstatic void
150178670Sjhbkgdb_trgt_close(int quitting)
151178670Sjhb{
152178670Sjhb
153178670Sjhb	if (kvm != NULL) {
154178670Sjhb		inferior_ptid = null_ptid;
155178670Sjhb		CLEAR_SOLIB();
156178670Sjhb		if (kvm_close(kvm) != 0)
157178670Sjhb			warning("cannot close \"%s\": %s", vmcore,
158178670Sjhb			    kvm_geterr(kvm));
159178670Sjhb		kvm = NULL;
160178670Sjhb		xfree(vmcore);
161178670Sjhb		vmcore = NULL;
162178670Sjhb		if (kgdb_trgt_ops.to_sections) {
163178670Sjhb			xfree(kgdb_trgt_ops.to_sections);
164178670Sjhb			kgdb_trgt_ops.to_sections = NULL;
165178670Sjhb			kgdb_trgt_ops.to_sections_end = NULL;
166178670Sjhb		}
167178670Sjhb	}
168178670Sjhb}
169178670Sjhb
170178670Sjhbstatic void
171178670Sjhbkgdb_core_cleanup(void *arg)
172178670Sjhb{
173178670Sjhb
174178670Sjhb	kgdb_trgt_close(0);
175178670Sjhb}
176178670Sjhb
177178670Sjhbstatic void
178178670Sjhbkgdb_trgt_detach(char *args, int from_tty)
179178670Sjhb{
180178670Sjhb
181178670Sjhb	if (args)
182178670Sjhb		error ("Too many arguments");
183178670Sjhb	unpush_target(&kgdb_trgt_ops);
184178670Sjhb	reinit_frame_cache();
185178670Sjhb	if (from_tty)
186178670Sjhb		printf_filtered("No vmcore file now.\n");
187178670Sjhb}
188178670Sjhb
189148802Smarcelstatic char *
190148802Smarcelkgdb_trgt_extra_thread_info(struct thread_info *ti)
191148802Smarcel{
192142151Skan
193178713Sjhb	return (kgdb_thr_extra_thread_info(ptid_get_pid(ti->ptid)));
194142151Skan}
195142151Skan
196148802Smarcelstatic void
197148802Smarcelkgdb_trgt_files_info(struct target_ops *target)
198132624Smarcel{
199148802Smarcel
200178670Sjhb	printf_filtered ("\t`%s', ", vmcore);
201178670Sjhb	wrap_here ("        ");
202178670Sjhb	printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore");
203132624Smarcel}
204132624Smarcel
205132624Smarcelstatic void
206132624Smarcelkgdb_trgt_find_new_threads(void)
207132624Smarcel{
208148802Smarcel	struct target_ops *tb;
209148802Smarcel
210148802Smarcel	if (kvm != NULL)
211148802Smarcel		return;
212148802Smarcel
213148802Smarcel	tb = find_target_beneath(&kgdb_trgt_ops);
214148802Smarcel	if (tb->to_find_new_threads != NULL)
215148802Smarcel		tb->to_find_new_threads();
216132624Smarcel}
217132624Smarcel
218132624Smarcelstatic char *
219132624Smarcelkgdb_trgt_pid_to_str(ptid_t ptid)
220132624Smarcel{
221142151Skan	static char buf[33];
222132624Smarcel
223178713Sjhb	snprintf(buf, sizeof(buf), "Thread %d", ptid_get_pid(ptid));
224132624Smarcel	return (buf);
225132624Smarcel}
226132624Smarcel
227132624Smarcelstatic int
228132624Smarcelkgdb_trgt_thread_alive(ptid_t ptid)
229132624Smarcel{
230178713Sjhb	return (kgdb_thr_lookup_tid(ptid_get_pid(ptid)) != NULL);
231132624Smarcel}
232132624Smarcel
233132624Smarcelstatic int
234132624Smarcelkgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write,
235148802Smarcel    struct mem_attrib *attrib, struct target_ops *target)
236132624Smarcel{
237148802Smarcel	struct target_ops *tb;
238132624Smarcel
239148802Smarcel	if (kvm != NULL) {
240148802Smarcel		if (len == 0)
241148802Smarcel			return (0);
242148802Smarcel		if (!write)
243148802Smarcel			return (kvm_read(kvm, memaddr, myaddr, len));
244148802Smarcel		else
245148802Smarcel			return (kvm_write(kvm, memaddr, myaddr, len));
246142151Skan	}
247148802Smarcel	tb = find_target_beneath(target);
248148802Smarcel	return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb));
249142151Skan}
250142151Skan
251178670Sjhbstatic int
252178670Sjhbkgdb_trgt_ignore_breakpoints(CORE_ADDR addr, char *contents)
253178670Sjhb{
254178670Sjhb
255178670Sjhb	return 0;
256178670Sjhb}
257178670Sjhb
258163439Sjhbstatic void
259178713Sjhbkgdb_switch_to_thread(int tid)
260163439Sjhb{
261178713Sjhb	char buf[16];
262178713Sjhb	int thread_id;
263163439Sjhb
264178713Sjhb	thread_id = pid_to_thread_id(pid_to_ptid(tid));
265178713Sjhb	if (thread_id == 0)
266178713Sjhb		error ("invalid tid");
267178713Sjhb	snprintf(buf, sizeof(buf), "%d", thread_id);
268178713Sjhb	gdb_thread_select(uiout, buf);
269163439Sjhb}
270163439Sjhb
271163439Sjhbstatic void
272163439Sjhbkgdb_set_proc_cmd (char *arg, int from_tty)
273163439Sjhb{
274163439Sjhb	CORE_ADDR addr;
275163439Sjhb	struct kthr *thr;
276163439Sjhb
277163439Sjhb	if (!arg)
278163439Sjhb		error_no_arg ("proc address for the new context");
279163439Sjhb
280163439Sjhb	if (kvm == NULL)
281178713Sjhb		error ("only supported for core file target");
282163439Sjhb
283163439Sjhb	addr = (CORE_ADDR) parse_and_eval_address (arg);
284163439Sjhb
285163439Sjhb	if (!INKERNEL (addr)) {
286163439Sjhb		thr = kgdb_thr_lookup_pid((int)addr);
287163439Sjhb		if (thr == NULL)
288163439Sjhb			error ("invalid pid");
289163439Sjhb	} else {
290163439Sjhb		thr = kgdb_thr_lookup_paddr(addr);
291163439Sjhb		if (thr == NULL)
292163439Sjhb			error("invalid proc address");
293163439Sjhb	}
294178713Sjhb	kgdb_switch_to_thread(thr->tid);
295163439Sjhb}
296163439Sjhb
297163439Sjhbstatic void
298163439Sjhbkgdb_set_tid_cmd (char *arg, int from_tty)
299163439Sjhb{
300163439Sjhb	CORE_ADDR addr;
301163439Sjhb	struct kthr *thr;
302163439Sjhb
303163439Sjhb	if (!arg)
304163439Sjhb		error_no_arg ("TID or thread address for the new context");
305163439Sjhb
306163439Sjhb	addr = (CORE_ADDR) parse_and_eval_address (arg);
307163439Sjhb
308178713Sjhb	if (kvm != NULL && INKERNEL (addr)) {
309163439Sjhb		thr = kgdb_thr_lookup_taddr(addr);
310163439Sjhb		if (thr == NULL)
311163439Sjhb			error("invalid thread address");
312178713Sjhb		addr = thr->tid;
313163439Sjhb	}
314178713Sjhb	kgdb_switch_to_thread(addr);
315163439Sjhb}
316163439Sjhb
317178670Sjhbint fbsdcoreops_suppress_target = 1;
318178670Sjhb
319132624Smarcelvoid
320178670Sjhbinitialize_kgdb_target(void)
321132624Smarcel{
322132624Smarcel
323132624Smarcel	kgdb_trgt_ops.to_magic = OPS_MAGIC;
324132624Smarcel	kgdb_trgt_ops.to_shortname = "kernel";
325178670Sjhb	kgdb_trgt_ops.to_longname = "kernel core dump file";
326178670Sjhb	kgdb_trgt_ops.to_doc =
327178670Sjhb    "Use a vmcore file as a target.  Specify the filename of the vmcore file.";
328178670Sjhb	kgdb_trgt_ops.to_stratum = core_stratum;
329132624Smarcel	kgdb_trgt_ops.to_has_memory = 1;
330132624Smarcel	kgdb_trgt_ops.to_has_registers = 1;
331132624Smarcel	kgdb_trgt_ops.to_has_stack = 1;
332132624Smarcel
333178670Sjhb	kgdb_trgt_ops.to_open = kgdb_trgt_open;
334178670Sjhb	kgdb_trgt_ops.to_close = kgdb_trgt_close;
335178670Sjhb	kgdb_trgt_ops.to_attach = find_default_attach;
336178670Sjhb	kgdb_trgt_ops.to_detach = kgdb_trgt_detach;
337132624Smarcel	kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
338132624Smarcel	kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
339148802Smarcel	kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
340132624Smarcel	kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads;
341132624Smarcel	kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
342132624Smarcel	kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers;
343132624Smarcel	kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
344132624Smarcel	kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory;
345178670Sjhb	kgdb_trgt_ops.to_insert_breakpoint = kgdb_trgt_ignore_breakpoints;
346178670Sjhb	kgdb_trgt_ops.to_remove_breakpoint = kgdb_trgt_ignore_breakpoints;
347175808Sjhb
348132624Smarcel	add_target(&kgdb_trgt_ops);
349132624Smarcel
350163439Sjhb	add_com ("proc", class_obscure, kgdb_set_proc_cmd,
351163439Sjhb	   "Set current process context");
352163439Sjhb	add_com ("tid", class_obscure, kgdb_set_tid_cmd,
353163439Sjhb	   "Set current thread context");
354132624Smarcel}
355