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
56246893Smarcelstatic CORE_ADDR stoppcbs;
57246893Smarcel
58178670Sjhbstatic void	kgdb_core_cleanup(void *);
59178670Sjhb
60178670Sjhbstatic char *vmcore;
61132624Smarcelstatic struct target_ops kgdb_trgt_ops;
62132624Smarcel
63178670Sjhbkvm_t *kvm;
64178670Sjhbstatic char kvm_err[_POSIX2_LINE_MAX];
65175808Sjhb
66163439Sjhb#define	KERNOFF		(kgdb_kernbase ())
67286305Skib#define	PINKERNEL(x)	((x) >= KERNOFF)
68163439Sjhb
69163439Sjhbstatic CORE_ADDR
70163439Sjhbkgdb_kernbase (void)
71163439Sjhb{
72163439Sjhb	static CORE_ADDR kernbase;
73163439Sjhb	struct minimal_symbol *sym;
74163439Sjhb
75163439Sjhb	if (kernbase == 0) {
76163439Sjhb		sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
77163439Sjhb		if (sym == NULL) {
78163439Sjhb			kernbase = KERNBASE;
79163439Sjhb		} else {
80163439Sjhb			kernbase = SYMBOL_VALUE_ADDRESS (sym);
81163439Sjhb		}
82163439Sjhb	}
83163439Sjhb	return kernbase;
84163439Sjhb}
85163439Sjhb
86178670Sjhbstatic void
87178670Sjhbkgdb_trgt_open(char *filename, int from_tty)
88178670Sjhb{
89178670Sjhb	struct cleanup *old_chain;
90178670Sjhb	struct thread_info *ti;
91178670Sjhb	struct kthr *kt;
92178670Sjhb	kvm_t *nkvm;
93178670Sjhb	char *temp;
94178670Sjhb	int ontop;
95178670Sjhb
96178670Sjhb	target_preopen (from_tty);
97178670Sjhb	if (!filename)
98178670Sjhb		error ("No vmcore file specified.");
99178670Sjhb	if (!exec_bfd)
100178670Sjhb		error ("Can't open a vmcore without a kernel");
101178670Sjhb
102178670Sjhb	filename = tilde_expand (filename);
103178670Sjhb	if (filename[0] != '/') {
104178670Sjhb		temp = concat (current_directory, "/", filename, NULL);
105178670Sjhb		xfree(filename);
106178670Sjhb		filename = temp;
107178670Sjhb	}
108178670Sjhb
109178670Sjhb	old_chain = make_cleanup (xfree, filename);
110178670Sjhb
111178670Sjhb	nkvm = kvm_openfiles(bfd_get_filename(exec_bfd), filename, NULL,
112178670Sjhb	    write_files ? O_RDWR : O_RDONLY, kvm_err);
113178670Sjhb	if (nkvm == NULL)
114178670Sjhb		error ("Failed to open vmcore: %s", kvm_err);
115178670Sjhb
116178670Sjhb	/* Don't free the filename now and close any previous vmcore. */
117178670Sjhb	discard_cleanups(old_chain);
118178670Sjhb	unpush_target(&kgdb_trgt_ops);
119178670Sjhb
120178670Sjhb	kvm = nkvm;
121178670Sjhb	vmcore = filename;
122178670Sjhb	old_chain = make_cleanup(kgdb_core_cleanup, NULL);
123178670Sjhb
124178670Sjhb	ontop = !push_target (&kgdb_trgt_ops);
125178670Sjhb	discard_cleanups (old_chain);
126178670Sjhb
127178670Sjhb	kgdb_dmesg();
128178670Sjhb
129178670Sjhb	init_thread_list();
130178670Sjhb	kt = kgdb_thr_init();
131178670Sjhb	while (kt != NULL) {
132178713Sjhb		ti = add_thread(pid_to_ptid(kt->tid));
133178670Sjhb		kt = kgdb_thr_next(kt);
134178670Sjhb	}
135178670Sjhb	if (curkthr != 0)
136178713Sjhb		inferior_ptid = pid_to_ptid(curkthr->tid);
137178670Sjhb
138178670Sjhb	if (ontop) {
139178670Sjhb		/* XXX: fetch registers? */
140178670Sjhb		kld_init();
141178670Sjhb		flush_cached_frames();
142178670Sjhb		select_frame (get_current_frame());
143178670Sjhb		print_stack_frame(get_selected_frame(),
144178670Sjhb		    frame_relative_level(get_selected_frame()), 1);
145178670Sjhb	} else
146178670Sjhb		warning(
147178670Sjhb	"you won't be able to access this vmcore until you terminate\n\
148178670Sjhbyour %s; do ``info files''", target_longname);
149178670Sjhb}
150178670Sjhb
151178670Sjhbstatic void
152178670Sjhbkgdb_trgt_close(int quitting)
153178670Sjhb{
154178670Sjhb
155178670Sjhb	if (kvm != NULL) {
156178670Sjhb		inferior_ptid = null_ptid;
157178670Sjhb		CLEAR_SOLIB();
158178670Sjhb		if (kvm_close(kvm) != 0)
159178670Sjhb			warning("cannot close \"%s\": %s", vmcore,
160178670Sjhb			    kvm_geterr(kvm));
161178670Sjhb		kvm = NULL;
162178670Sjhb		xfree(vmcore);
163178670Sjhb		vmcore = NULL;
164178670Sjhb		if (kgdb_trgt_ops.to_sections) {
165178670Sjhb			xfree(kgdb_trgt_ops.to_sections);
166178670Sjhb			kgdb_trgt_ops.to_sections = NULL;
167178670Sjhb			kgdb_trgt_ops.to_sections_end = NULL;
168178670Sjhb		}
169178670Sjhb	}
170178670Sjhb}
171178670Sjhb
172178670Sjhbstatic void
173178670Sjhbkgdb_core_cleanup(void *arg)
174178670Sjhb{
175178670Sjhb
176178670Sjhb	kgdb_trgt_close(0);
177178670Sjhb}
178178670Sjhb
179178670Sjhbstatic void
180178670Sjhbkgdb_trgt_detach(char *args, int from_tty)
181178670Sjhb{
182178670Sjhb
183178670Sjhb	if (args)
184178670Sjhb		error ("Too many arguments");
185178670Sjhb	unpush_target(&kgdb_trgt_ops);
186178670Sjhb	reinit_frame_cache();
187178670Sjhb	if (from_tty)
188178670Sjhb		printf_filtered("No vmcore file now.\n");
189178670Sjhb}
190178670Sjhb
191148802Smarcelstatic char *
192148802Smarcelkgdb_trgt_extra_thread_info(struct thread_info *ti)
193148802Smarcel{
194142151Skan
195178713Sjhb	return (kgdb_thr_extra_thread_info(ptid_get_pid(ti->ptid)));
196142151Skan}
197142151Skan
198148802Smarcelstatic void
199148802Smarcelkgdb_trgt_files_info(struct target_ops *target)
200132624Smarcel{
201148802Smarcel
202178670Sjhb	printf_filtered ("\t`%s', ", vmcore);
203178670Sjhb	wrap_here ("        ");
204178670Sjhb	printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore");
205132624Smarcel}
206132624Smarcel
207132624Smarcelstatic void
208132624Smarcelkgdb_trgt_find_new_threads(void)
209132624Smarcel{
210148802Smarcel	struct target_ops *tb;
211148802Smarcel
212148802Smarcel	if (kvm != NULL)
213148802Smarcel		return;
214148802Smarcel
215148802Smarcel	tb = find_target_beneath(&kgdb_trgt_ops);
216148802Smarcel	if (tb->to_find_new_threads != NULL)
217148802Smarcel		tb->to_find_new_threads();
218132624Smarcel}
219132624Smarcel
220132624Smarcelstatic char *
221132624Smarcelkgdb_trgt_pid_to_str(ptid_t ptid)
222132624Smarcel{
223142151Skan	static char buf[33];
224132624Smarcel
225178713Sjhb	snprintf(buf, sizeof(buf), "Thread %d", ptid_get_pid(ptid));
226132624Smarcel	return (buf);
227132624Smarcel}
228132624Smarcel
229132624Smarcelstatic int
230132624Smarcelkgdb_trgt_thread_alive(ptid_t ptid)
231132624Smarcel{
232178713Sjhb	return (kgdb_thr_lookup_tid(ptid_get_pid(ptid)) != NULL);
233132624Smarcel}
234132624Smarcel
235132624Smarcelstatic int
236132624Smarcelkgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write,
237148802Smarcel    struct mem_attrib *attrib, struct target_ops *target)
238132624Smarcel{
239148802Smarcel	struct target_ops *tb;
240132624Smarcel
241148802Smarcel	if (kvm != NULL) {
242148802Smarcel		if (len == 0)
243148802Smarcel			return (0);
244148802Smarcel		if (!write)
245148802Smarcel			return (kvm_read(kvm, memaddr, myaddr, len));
246148802Smarcel		else
247148802Smarcel			return (kvm_write(kvm, memaddr, myaddr, len));
248142151Skan	}
249148802Smarcel	tb = find_target_beneath(target);
250148802Smarcel	return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb));
251142151Skan}
252142151Skan
253178670Sjhbstatic int
254178670Sjhbkgdb_trgt_ignore_breakpoints(CORE_ADDR addr, char *contents)
255178670Sjhb{
256178670Sjhb
257178670Sjhb	return 0;
258178670Sjhb}
259178670Sjhb
260163439Sjhbstatic void
261178713Sjhbkgdb_switch_to_thread(int tid)
262163439Sjhb{
263178713Sjhb	char buf[16];
264178713Sjhb	int thread_id;
265163439Sjhb
266178713Sjhb	thread_id = pid_to_thread_id(pid_to_ptid(tid));
267178713Sjhb	if (thread_id == 0)
268178713Sjhb		error ("invalid tid");
269178713Sjhb	snprintf(buf, sizeof(buf), "%d", thread_id);
270178713Sjhb	gdb_thread_select(uiout, buf);
271163439Sjhb}
272163439Sjhb
273163439Sjhbstatic void
274163439Sjhbkgdb_set_proc_cmd (char *arg, int from_tty)
275163439Sjhb{
276163439Sjhb	CORE_ADDR addr;
277163439Sjhb	struct kthr *thr;
278163439Sjhb
279163439Sjhb	if (!arg)
280163439Sjhb		error_no_arg ("proc address for the new context");
281163439Sjhb
282163439Sjhb	if (kvm == NULL)
283178713Sjhb		error ("only supported for core file target");
284163439Sjhb
285163439Sjhb	addr = (CORE_ADDR) parse_and_eval_address (arg);
286163439Sjhb
287286305Skib	if (!PINKERNEL (addr)) {
288163439Sjhb		thr = kgdb_thr_lookup_pid((int)addr);
289163439Sjhb		if (thr == NULL)
290163439Sjhb			error ("invalid pid");
291163439Sjhb	} else {
292163439Sjhb		thr = kgdb_thr_lookup_paddr(addr);
293163439Sjhb		if (thr == NULL)
294163439Sjhb			error("invalid proc address");
295163439Sjhb	}
296178713Sjhb	kgdb_switch_to_thread(thr->tid);
297163439Sjhb}
298163439Sjhb
299163439Sjhbstatic void
300163439Sjhbkgdb_set_tid_cmd (char *arg, int from_tty)
301163439Sjhb{
302163439Sjhb	CORE_ADDR addr;
303163439Sjhb	struct kthr *thr;
304163439Sjhb
305163439Sjhb	if (!arg)
306163439Sjhb		error_no_arg ("TID or thread address for the new context");
307163439Sjhb
308163439Sjhb	addr = (CORE_ADDR) parse_and_eval_address (arg);
309163439Sjhb
310286305Skib	if (kvm != NULL && PINKERNEL (addr)) {
311163439Sjhb		thr = kgdb_thr_lookup_taddr(addr);
312163439Sjhb		if (thr == NULL)
313163439Sjhb			error("invalid thread address");
314178713Sjhb		addr = thr->tid;
315163439Sjhb	}
316178713Sjhb	kgdb_switch_to_thread(addr);
317163439Sjhb}
318163439Sjhb
319178670Sjhbint fbsdcoreops_suppress_target = 1;
320178670Sjhb
321132624Smarcelvoid
322178670Sjhbinitialize_kgdb_target(void)
323132624Smarcel{
324132624Smarcel
325132624Smarcel	kgdb_trgt_ops.to_magic = OPS_MAGIC;
326132624Smarcel	kgdb_trgt_ops.to_shortname = "kernel";
327178670Sjhb	kgdb_trgt_ops.to_longname = "kernel core dump file";
328178670Sjhb	kgdb_trgt_ops.to_doc =
329178670Sjhb    "Use a vmcore file as a target.  Specify the filename of the vmcore file.";
330178670Sjhb	kgdb_trgt_ops.to_stratum = core_stratum;
331132624Smarcel	kgdb_trgt_ops.to_has_memory = 1;
332132624Smarcel	kgdb_trgt_ops.to_has_registers = 1;
333132624Smarcel	kgdb_trgt_ops.to_has_stack = 1;
334132624Smarcel
335178670Sjhb	kgdb_trgt_ops.to_open = kgdb_trgt_open;
336178670Sjhb	kgdb_trgt_ops.to_close = kgdb_trgt_close;
337178670Sjhb	kgdb_trgt_ops.to_attach = find_default_attach;
338178670Sjhb	kgdb_trgt_ops.to_detach = kgdb_trgt_detach;
339132624Smarcel	kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
340132624Smarcel	kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
341148802Smarcel	kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
342132624Smarcel	kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads;
343132624Smarcel	kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
344132624Smarcel	kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers;
345132624Smarcel	kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
346132624Smarcel	kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory;
347178670Sjhb	kgdb_trgt_ops.to_insert_breakpoint = kgdb_trgt_ignore_breakpoints;
348178670Sjhb	kgdb_trgt_ops.to_remove_breakpoint = kgdb_trgt_ignore_breakpoints;
349175808Sjhb
350132624Smarcel	add_target(&kgdb_trgt_ops);
351132624Smarcel
352163439Sjhb	add_com ("proc", class_obscure, kgdb_set_proc_cmd,
353163439Sjhb	   "Set current process context");
354163439Sjhb	add_com ("tid", class_obscure, kgdb_set_tid_cmd,
355163439Sjhb	   "Set current thread context");
356132624Smarcel}
357246893Smarcel
358246893SmarcelCORE_ADDR
359246893Smarcelkgdb_trgt_stop_pcb(u_int cpuid, u_int pcbsz)
360246893Smarcel{
361246893Smarcel	static int once = 0;
362246893Smarcel
363246893Smarcel	if (stoppcbs == 0 && !once) {
364246893Smarcel		once = 1;
365246893Smarcel		stoppcbs = kgdb_lookup("stoppcbs");
366246893Smarcel	}
367246893Smarcel	if (stoppcbs == 0)
368246893Smarcel		return 0;
369246893Smarcel
370246893Smarcel	return (stoppcbs + pcbsz * cpuid);
371246893Smarcel}
372