xref: /freebsd/sys/kern/subr_kdb.c (revision 40c9966a37377d4ac5c532f5aa27441730f320b1)
19454b2d8SWarner Losh /*-
2cbc17435SMarcel Moolenaar  * Copyright (c) 2004 The FreeBSD Project
3cbc17435SMarcel Moolenaar  * All rights reserved.
4cbc17435SMarcel Moolenaar  *
5cbc17435SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
6cbc17435SMarcel Moolenaar  * modification, are permitted provided that the following conditions
7cbc17435SMarcel Moolenaar  * are met:
8cbc17435SMarcel Moolenaar  *
9cbc17435SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
10cbc17435SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
11cbc17435SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
12cbc17435SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
13cbc17435SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
14cbc17435SMarcel Moolenaar  *
15cbc17435SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16cbc17435SMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17cbc17435SMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18cbc17435SMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19cbc17435SMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20cbc17435SMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21cbc17435SMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22cbc17435SMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23cbc17435SMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24cbc17435SMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25cbc17435SMarcel Moolenaar  */
26cbc17435SMarcel Moolenaar 
27cbc17435SMarcel Moolenaar #include <sys/cdefs.h>
28cbc17435SMarcel Moolenaar __FBSDID("$FreeBSD$");
29cbc17435SMarcel Moolenaar 
30f0c6706dSPeter Wemm #include "opt_kdb.h"
31f0c6706dSPeter Wemm 
32cbc17435SMarcel Moolenaar #include <sys/param.h>
33cbc17435SMarcel Moolenaar #include <sys/systm.h>
34cbc17435SMarcel Moolenaar #include <sys/kdb.h>
35cbc17435SMarcel Moolenaar #include <sys/kernel.h>
36cbc17435SMarcel Moolenaar #include <sys/malloc.h>
37cbc17435SMarcel Moolenaar #include <sys/pcpu.h>
38cbc17435SMarcel Moolenaar #include <sys/proc.h>
39cbc17435SMarcel Moolenaar #include <sys/smp.h>
40cbc17435SMarcel Moolenaar #include <sys/sysctl.h>
41cbc17435SMarcel Moolenaar 
42cbc17435SMarcel Moolenaar #include <machine/kdb.h>
43cbc17435SMarcel Moolenaar #include <machine/pcb.h>
44cbc17435SMarcel Moolenaar 
4558553b99SJohn Baldwin #ifdef SMP
4658553b99SJohn Baldwin #if defined (__i386__) || defined(__amd64__)
4758553b99SJohn Baldwin #define	HAVE_STOPPEDPCBS
48fdc9713bSDoug White #include <machine/smp.h>
49fdc9713bSDoug White #endif
50fdc9713bSDoug White #endif
51fdc9713bSDoug White 
52cbc17435SMarcel Moolenaar int kdb_active = 0;
53cbc17435SMarcel Moolenaar void *kdb_jmpbufp = NULL;
54cbc17435SMarcel Moolenaar struct kdb_dbbe *kdb_dbbe = NULL;
55cbc17435SMarcel Moolenaar struct pcb kdb_pcb;
56cbc17435SMarcel Moolenaar struct pcb *kdb_thrctx = NULL;
57cbc17435SMarcel Moolenaar struct thread *kdb_thread = NULL;
58cbc17435SMarcel Moolenaar struct trapframe *kdb_frame = NULL;
59cbc17435SMarcel Moolenaar 
60cbc17435SMarcel Moolenaar KDB_BACKEND(null, NULL, NULL, NULL);
61cbc17435SMarcel Moolenaar SET_DECLARE(kdb_dbbe_set, struct kdb_dbbe);
62cbc17435SMarcel Moolenaar 
63cbc17435SMarcel Moolenaar static int kdb_sysctl_available(SYSCTL_HANDLER_ARGS);
64cbc17435SMarcel Moolenaar static int kdb_sysctl_current(SYSCTL_HANDLER_ARGS);
65cbc17435SMarcel Moolenaar static int kdb_sysctl_enter(SYSCTL_HANDLER_ARGS);
6640c9966aSPeter Wemm static int kdb_sysctl_panic(SYSCTL_HANDLER_ARGS);
6740c9966aSPeter Wemm static int kdb_sysctl_trap(SYSCTL_HANDLER_ARGS);
68cbc17435SMarcel Moolenaar 
69cbc17435SMarcel Moolenaar SYSCTL_NODE(_debug, OID_AUTO, kdb, CTLFLAG_RW, NULL, "KDB nodes");
70cbc17435SMarcel Moolenaar 
71cbc17435SMarcel Moolenaar SYSCTL_PROC(_debug_kdb, OID_AUTO, available, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
72cbc17435SMarcel Moolenaar     kdb_sysctl_available, "A", "list of available KDB backends");
73cbc17435SMarcel Moolenaar 
74cbc17435SMarcel Moolenaar SYSCTL_PROC(_debug_kdb, OID_AUTO, current, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
75cbc17435SMarcel Moolenaar     kdb_sysctl_current, "A", "currently selected KDB backend");
76cbc17435SMarcel Moolenaar 
77cbc17435SMarcel Moolenaar SYSCTL_PROC(_debug_kdb, OID_AUTO, enter, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
78cbc17435SMarcel Moolenaar     kdb_sysctl_enter, "I", "set to enter the debugger");
79cbc17435SMarcel Moolenaar 
8040c9966aSPeter Wemm SYSCTL_PROC(_debug_kdb, OID_AUTO, panic, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
8140c9966aSPeter Wemm     kdb_sysctl_panic, "I", "set to panic the kernel");
8240c9966aSPeter Wemm 
8340c9966aSPeter Wemm SYSCTL_PROC(_debug_kdb, OID_AUTO, trap, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
8440c9966aSPeter Wemm     kdb_sysctl_trap, "I", "set cause a page fault");
8540c9966aSPeter Wemm 
86d8939d82SRobert Watson /*
87d8939d82SRobert Watson  * Flag indicating whether or not to IPI the other CPUs to stop them on
88d8939d82SRobert Watson  * entering the debugger.  Sometimes, this will result in a deadlock as
89d8939d82SRobert Watson  * stop_cpus() waits for the other cpus to stop, so we allow it to be
90d8939d82SRobert Watson  * disabled.
91d8939d82SRobert Watson  */
92d8939d82SRobert Watson #ifdef SMP
93d8939d82SRobert Watson static int kdb_stop_cpus = 1;
94d8939d82SRobert Watson SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus, CTLTYPE_INT | CTLFLAG_RW,
95d8939d82SRobert Watson     &kdb_stop_cpus, 0, "");
96d963815bSRobert Watson TUNABLE_INT("debug.kdb.stop_cpus", &kdb_stop_cpus);
97d8939d82SRobert Watson #endif
98d8939d82SRobert Watson 
99cbc17435SMarcel Moolenaar static int
100cbc17435SMarcel Moolenaar kdb_sysctl_available(SYSCTL_HANDLER_ARGS)
101cbc17435SMarcel Moolenaar {
102cbc17435SMarcel Moolenaar 	struct kdb_dbbe *be, **iter;
103cbc17435SMarcel Moolenaar 	char *avail, *p;
104cbc17435SMarcel Moolenaar 	ssize_t len, sz;
105cbc17435SMarcel Moolenaar 	int error;
106cbc17435SMarcel Moolenaar 
107cbc17435SMarcel Moolenaar 	sz = 0;
108cbc17435SMarcel Moolenaar 	SET_FOREACH(iter, kdb_dbbe_set) {
109cbc17435SMarcel Moolenaar 		be = *iter;
110cbc17435SMarcel Moolenaar 		if (be->dbbe_active == 0)
111cbc17435SMarcel Moolenaar 			sz += strlen(be->dbbe_name) + 1;
112cbc17435SMarcel Moolenaar 	}
113cbc17435SMarcel Moolenaar 	sz++;
114cbc17435SMarcel Moolenaar 	avail = malloc(sz, M_TEMP, M_WAITOK);
115cbc17435SMarcel Moolenaar 	p = avail;
116f742a1edSStephan Uphoff 	*p = '\0';
117f742a1edSStephan Uphoff 
118cbc17435SMarcel Moolenaar 	SET_FOREACH(iter, kdb_dbbe_set) {
119cbc17435SMarcel Moolenaar 		be = *iter;
120cbc17435SMarcel Moolenaar 		if (be->dbbe_active == 0) {
121cbc17435SMarcel Moolenaar 			len = snprintf(p, sz, "%s ", be->dbbe_name);
122cbc17435SMarcel Moolenaar 			p += len;
123cbc17435SMarcel Moolenaar 			sz -= len;
124cbc17435SMarcel Moolenaar 		}
125cbc17435SMarcel Moolenaar 	}
126cbc17435SMarcel Moolenaar 	KASSERT(sz >= 0, ("%s", __func__));
127cbc17435SMarcel Moolenaar 	error = sysctl_handle_string(oidp, avail, 0, req);
128cbc17435SMarcel Moolenaar 	free(avail, M_TEMP);
129cbc17435SMarcel Moolenaar 	return (error);
130cbc17435SMarcel Moolenaar }
131cbc17435SMarcel Moolenaar 
132cbc17435SMarcel Moolenaar static int
133cbc17435SMarcel Moolenaar kdb_sysctl_current(SYSCTL_HANDLER_ARGS)
134cbc17435SMarcel Moolenaar {
135cbc17435SMarcel Moolenaar 	char buf[16];
136cbc17435SMarcel Moolenaar 	int error;
137cbc17435SMarcel Moolenaar 
138a8bfba1aSMarcel Moolenaar 	if (kdb_dbbe != NULL) {
139cbc17435SMarcel Moolenaar 		strncpy(buf, kdb_dbbe->dbbe_name, sizeof(buf));
140cbc17435SMarcel Moolenaar 		buf[sizeof(buf) - 1] = '\0';
141a8bfba1aSMarcel Moolenaar 	} else
142a8bfba1aSMarcel Moolenaar 		*buf = '\0';
143cbc17435SMarcel Moolenaar 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
144cbc17435SMarcel Moolenaar 	if (error != 0 || req->newptr == NULL)
145cbc17435SMarcel Moolenaar 		return (error);
146cbc17435SMarcel Moolenaar 	if (kdb_active)
147cbc17435SMarcel Moolenaar 		return (EBUSY);
1483bcd2440SMarcel Moolenaar 	return (kdb_dbbe_select(buf));
149cbc17435SMarcel Moolenaar }
150cbc17435SMarcel Moolenaar 
151cbc17435SMarcel Moolenaar static int
152cbc17435SMarcel Moolenaar kdb_sysctl_enter(SYSCTL_HANDLER_ARGS)
153cbc17435SMarcel Moolenaar {
154cbc17435SMarcel Moolenaar 	int error, i;
155cbc17435SMarcel Moolenaar 
156cbc17435SMarcel Moolenaar 	error = sysctl_wire_old_buffer(req, sizeof(int));
157cbc17435SMarcel Moolenaar 	if (error == 0) {
158cbc17435SMarcel Moolenaar 		i = 0;
159cbc17435SMarcel Moolenaar 		error = sysctl_handle_int(oidp, &i, 0, req);
160cbc17435SMarcel Moolenaar 	}
161cbc17435SMarcel Moolenaar 	if (error != 0 || req->newptr == NULL)
162cbc17435SMarcel Moolenaar 		return (error);
163cbc17435SMarcel Moolenaar 	if (kdb_active)
164cbc17435SMarcel Moolenaar 		return (EBUSY);
165cbc17435SMarcel Moolenaar 	kdb_enter("sysctl debug.kdb.enter");
166cbc17435SMarcel Moolenaar 	return (0);
167cbc17435SMarcel Moolenaar }
168cbc17435SMarcel Moolenaar 
16940c9966aSPeter Wemm static int
17040c9966aSPeter Wemm kdb_sysctl_panic(SYSCTL_HANDLER_ARGS)
17140c9966aSPeter Wemm {
17240c9966aSPeter Wemm 	int error, i;
17340c9966aSPeter Wemm 
17440c9966aSPeter Wemm 	error = sysctl_wire_old_buffer(req, sizeof(int));
17540c9966aSPeter Wemm 	if (error == 0) {
17640c9966aSPeter Wemm 		i = 0;
17740c9966aSPeter Wemm 		error = sysctl_handle_int(oidp, &i, 0, req);
17840c9966aSPeter Wemm 	}
17940c9966aSPeter Wemm 	if (error != 0 || req->newptr == NULL)
18040c9966aSPeter Wemm 		return (error);
18140c9966aSPeter Wemm 	panic("kdb_sysctl_panic");
18240c9966aSPeter Wemm 	return (0);
18340c9966aSPeter Wemm }
18440c9966aSPeter Wemm 
18540c9966aSPeter Wemm static int
18640c9966aSPeter Wemm kdb_sysctl_trap(SYSCTL_HANDLER_ARGS)
18740c9966aSPeter Wemm {
18840c9966aSPeter Wemm 	int error, i;
18940c9966aSPeter Wemm 	int *addr = (int *)0x10;
19040c9966aSPeter Wemm 
19140c9966aSPeter Wemm 	error = sysctl_wire_old_buffer(req, sizeof(int));
19240c9966aSPeter Wemm 	if (error == 0) {
19340c9966aSPeter Wemm 		i = 0;
19440c9966aSPeter Wemm 		error = sysctl_handle_int(oidp, &i, 0, req);
19540c9966aSPeter Wemm 	}
19640c9966aSPeter Wemm 	if (error != 0 || req->newptr == NULL)
19740c9966aSPeter Wemm 		return (error);
19840c9966aSPeter Wemm 	return (*addr);
19940c9966aSPeter Wemm }
20040c9966aSPeter Wemm 
201cbc17435SMarcel Moolenaar /*
202cbc17435SMarcel Moolenaar  * Solaris implements a new BREAK which is initiated by a character sequence
203cbc17435SMarcel Moolenaar  * CR ~ ^b which is similar to a familiar pattern used on Sun servers by the
204cbc17435SMarcel Moolenaar  * Remote Console.
205cbc17435SMarcel Moolenaar  *
206cbc17435SMarcel Moolenaar  * Note that this function may be called from almost anywhere, with interrupts
207cbc17435SMarcel Moolenaar  * disabled and with unknown locks held, so it must not access data other than
208cbc17435SMarcel Moolenaar  * its arguments.  Its up to the caller to ensure that the state variable is
209cbc17435SMarcel Moolenaar  * consistent.
210cbc17435SMarcel Moolenaar  */
211cbc17435SMarcel Moolenaar 
212cbc17435SMarcel Moolenaar #define	KEY_CR		13	/* CR '\r' */
213cbc17435SMarcel Moolenaar #define	KEY_TILDE	126	/* ~ */
214cbc17435SMarcel Moolenaar #define	KEY_CRTLB	2	/* ^B */
215cbc17435SMarcel Moolenaar 
216cbc17435SMarcel Moolenaar int
217cbc17435SMarcel Moolenaar kdb_alt_break(int key, int *state)
218cbc17435SMarcel Moolenaar {
219cbc17435SMarcel Moolenaar 	int brk;
220cbc17435SMarcel Moolenaar 
221cbc17435SMarcel Moolenaar 	brk = 0;
222cbc17435SMarcel Moolenaar 	switch (key) {
223cbc17435SMarcel Moolenaar 	case KEY_CR:
224cbc17435SMarcel Moolenaar 		*state = KEY_TILDE;
225cbc17435SMarcel Moolenaar 		break;
226cbc17435SMarcel Moolenaar 	case KEY_TILDE:
227cbc17435SMarcel Moolenaar 		*state = (*state == KEY_TILDE) ? KEY_CRTLB : 0;
228cbc17435SMarcel Moolenaar 		break;
229cbc17435SMarcel Moolenaar 	case KEY_CRTLB:
230cbc17435SMarcel Moolenaar 		if (*state == KEY_CRTLB)
231cbc17435SMarcel Moolenaar 			brk = 1;
232cbc17435SMarcel Moolenaar 		/* FALLTHROUGH */
233cbc17435SMarcel Moolenaar 	default:
234cbc17435SMarcel Moolenaar 		*state = 0;
235cbc17435SMarcel Moolenaar 		break;
236cbc17435SMarcel Moolenaar 	}
237cbc17435SMarcel Moolenaar 	return (brk);
238cbc17435SMarcel Moolenaar }
239cbc17435SMarcel Moolenaar 
240cbc17435SMarcel Moolenaar /*
241cbc17435SMarcel Moolenaar  * Print a backtrace of the calling thread. The backtrace is generated by
242cbc17435SMarcel Moolenaar  * the selected debugger, provided it supports backtraces. If no debugger
243cbc17435SMarcel Moolenaar  * is selected or the current debugger does not support backtraces, this
244cbc17435SMarcel Moolenaar  * function silently returns.
245cbc17435SMarcel Moolenaar  */
246cbc17435SMarcel Moolenaar 
247cbc17435SMarcel Moolenaar void
248cbc17435SMarcel Moolenaar kdb_backtrace()
249cbc17435SMarcel Moolenaar {
250cbc17435SMarcel Moolenaar 
251cbc17435SMarcel Moolenaar 	if (kdb_dbbe != NULL && kdb_dbbe->dbbe_trace != NULL) {
252cbc17435SMarcel Moolenaar 		printf("KDB: stack backtrace:\n");
253cbc17435SMarcel Moolenaar 		kdb_dbbe->dbbe_trace();
254cbc17435SMarcel Moolenaar 	}
255cbc17435SMarcel Moolenaar }
256cbc17435SMarcel Moolenaar 
257cbc17435SMarcel Moolenaar /*
2583bcd2440SMarcel Moolenaar  * Set/change the current backend.
2593bcd2440SMarcel Moolenaar  */
2603bcd2440SMarcel Moolenaar 
2613bcd2440SMarcel Moolenaar int
2623bcd2440SMarcel Moolenaar kdb_dbbe_select(const char *name)
2633bcd2440SMarcel Moolenaar {
2643bcd2440SMarcel Moolenaar 	struct kdb_dbbe *be, **iter;
2653bcd2440SMarcel Moolenaar 
2663bcd2440SMarcel Moolenaar 	SET_FOREACH(iter, kdb_dbbe_set) {
2673bcd2440SMarcel Moolenaar 		be = *iter;
2683bcd2440SMarcel Moolenaar 		if (be->dbbe_active == 0 && strcmp(be->dbbe_name, name) == 0) {
2693bcd2440SMarcel Moolenaar 			kdb_dbbe = be;
2703bcd2440SMarcel Moolenaar 			return (0);
2713bcd2440SMarcel Moolenaar 		}
2723bcd2440SMarcel Moolenaar 	}
2733bcd2440SMarcel Moolenaar 	return (EINVAL);
2743bcd2440SMarcel Moolenaar }
2753bcd2440SMarcel Moolenaar 
2763bcd2440SMarcel Moolenaar /*
277cbc17435SMarcel Moolenaar  * Enter the currently selected debugger. If a message has been provided,
278cbc17435SMarcel Moolenaar  * it is printed first. If the debugger does not support the enter method,
279cbc17435SMarcel Moolenaar  * it is entered by using breakpoint(), which enters the debugger through
280cbc17435SMarcel Moolenaar  * kdb_trap().
281cbc17435SMarcel Moolenaar  */
282cbc17435SMarcel Moolenaar 
283cbc17435SMarcel Moolenaar void
284cbc17435SMarcel Moolenaar kdb_enter(const char *msg)
285cbc17435SMarcel Moolenaar {
286cbc17435SMarcel Moolenaar 
287cbc17435SMarcel Moolenaar 	if (kdb_dbbe != NULL && kdb_active == 0) {
288cbc17435SMarcel Moolenaar 		if (msg != NULL)
289cbc17435SMarcel Moolenaar 			printf("KDB: enter: %s\n", msg);
290cbc17435SMarcel Moolenaar 		breakpoint();
291cbc17435SMarcel Moolenaar 	}
292cbc17435SMarcel Moolenaar }
293cbc17435SMarcel Moolenaar 
294cbc17435SMarcel Moolenaar /*
295cbc17435SMarcel Moolenaar  * Initialize the kernel debugger interface.
296cbc17435SMarcel Moolenaar  */
297cbc17435SMarcel Moolenaar 
298cbc17435SMarcel Moolenaar void
299cbc17435SMarcel Moolenaar kdb_init()
300cbc17435SMarcel Moolenaar {
301cbc17435SMarcel Moolenaar 	struct kdb_dbbe *be, **iter;
302cbc17435SMarcel Moolenaar 	int cur_pri, pri;
303cbc17435SMarcel Moolenaar 
304cbc17435SMarcel Moolenaar 	kdb_active = 0;
305cbc17435SMarcel Moolenaar 	kdb_dbbe = NULL;
306cbc17435SMarcel Moolenaar 	cur_pri = -1;
307cbc17435SMarcel Moolenaar 	SET_FOREACH(iter, kdb_dbbe_set) {
308cbc17435SMarcel Moolenaar 		be = *iter;
309cbc17435SMarcel Moolenaar 		pri = (be->dbbe_init != NULL) ? be->dbbe_init() : -1;
310cbc17435SMarcel Moolenaar 		be->dbbe_active = (pri >= 0) ? 0 : -1;
311cbc17435SMarcel Moolenaar 		if (pri > cur_pri) {
312cbc17435SMarcel Moolenaar 			cur_pri = pri;
313cbc17435SMarcel Moolenaar 			kdb_dbbe = be;
314cbc17435SMarcel Moolenaar 		}
315cbc17435SMarcel Moolenaar 	}
316cbc17435SMarcel Moolenaar 	if (kdb_dbbe != NULL) {
317cbc17435SMarcel Moolenaar 		printf("KDB: debugger backends:");
318cbc17435SMarcel Moolenaar 		SET_FOREACH(iter, kdb_dbbe_set) {
319cbc17435SMarcel Moolenaar 			be = *iter;
320cbc17435SMarcel Moolenaar 			if (be->dbbe_active == 0)
321cbc17435SMarcel Moolenaar 				printf(" %s", be->dbbe_name);
322cbc17435SMarcel Moolenaar 		}
323cbc17435SMarcel Moolenaar 		printf("\n");
324cbc17435SMarcel Moolenaar 		printf("KDB: current backend: %s\n",
325cbc17435SMarcel Moolenaar 		    kdb_dbbe->dbbe_name);
326cbc17435SMarcel Moolenaar 	}
327cbc17435SMarcel Moolenaar }
328cbc17435SMarcel Moolenaar 
329cbc17435SMarcel Moolenaar /*
330cbc17435SMarcel Moolenaar  * Handle contexts.
331cbc17435SMarcel Moolenaar  */
332cbc17435SMarcel Moolenaar 
333cbc17435SMarcel Moolenaar void *
334cbc17435SMarcel Moolenaar kdb_jmpbuf(jmp_buf new)
335cbc17435SMarcel Moolenaar {
336cbc17435SMarcel Moolenaar 	void *old;
337cbc17435SMarcel Moolenaar 
338cbc17435SMarcel Moolenaar 	old = kdb_jmpbufp;
339cbc17435SMarcel Moolenaar 	kdb_jmpbufp = new;
340cbc17435SMarcel Moolenaar 	return (old);
341cbc17435SMarcel Moolenaar }
342cbc17435SMarcel Moolenaar 
343cbc17435SMarcel Moolenaar void
344cbc17435SMarcel Moolenaar kdb_reenter(void)
345cbc17435SMarcel Moolenaar {
346cbc17435SMarcel Moolenaar 
347cbc17435SMarcel Moolenaar 	if (!kdb_active || kdb_jmpbufp == NULL)
348cbc17435SMarcel Moolenaar 		return;
349cbc17435SMarcel Moolenaar 
350cbc17435SMarcel Moolenaar 	longjmp(kdb_jmpbufp, 1);
351cbc17435SMarcel Moolenaar 	/* NOTREACHED */
352cbc17435SMarcel Moolenaar }
353cbc17435SMarcel Moolenaar 
354cbc17435SMarcel Moolenaar /*
355cbc17435SMarcel Moolenaar  * Thread related support functions.
356cbc17435SMarcel Moolenaar  */
357cbc17435SMarcel Moolenaar 
358cbc17435SMarcel Moolenaar struct pcb *
359cbc17435SMarcel Moolenaar kdb_thr_ctx(struct thread *thr)
360fdc9713bSDoug White {
36158553b99SJohn Baldwin #ifdef HAVE_STOPPEDPCBS
362fdc9713bSDoug White 	struct pcpu *pc;
3636b1e0d75SJohn Baldwin 	u_int cpuid;
36458553b99SJohn Baldwin #endif
365fdc9713bSDoug White 
366fdc9713bSDoug White 	if (thr == curthread)
3676b1e0d75SJohn Baldwin 		return (&kdb_pcb);
368fdc9713bSDoug White 
36958553b99SJohn Baldwin #ifdef HAVE_STOPPEDPCBS
370fdc9713bSDoug White 	SLIST_FOREACH(pc, &cpuhead, pc_allcpu)  {
371fdc9713bSDoug White 		cpuid = pc->pc_cpuid;
37258553b99SJohn Baldwin 		if (pc->pc_curthread == thr && (stopped_cpus & (1 << cpuid)))
3736b1e0d75SJohn Baldwin 			return (&stoppcbs[cpuid]);
374fdc9713bSDoug White 	}
37558553b99SJohn Baldwin #endif
3766b1e0d75SJohn Baldwin 	return (thr->td_pcb);
377fdc9713bSDoug White }
378cbc17435SMarcel Moolenaar 
379cbc17435SMarcel Moolenaar struct thread *
380cbc17435SMarcel Moolenaar kdb_thr_first(void)
381cbc17435SMarcel Moolenaar {
382cbc17435SMarcel Moolenaar 	struct proc *p;
383cbc17435SMarcel Moolenaar 	struct thread *thr;
384cbc17435SMarcel Moolenaar 
385cbc17435SMarcel Moolenaar 	p = LIST_FIRST(&allproc);
386cbc17435SMarcel Moolenaar 	while (p != NULL) {
387cbc17435SMarcel Moolenaar 		if (p->p_sflag & PS_INMEM) {
388cbc17435SMarcel Moolenaar 			thr = FIRST_THREAD_IN_PROC(p);
389cbc17435SMarcel Moolenaar 			if (thr != NULL)
390cbc17435SMarcel Moolenaar 				return (thr);
391cbc17435SMarcel Moolenaar 		}
392cbc17435SMarcel Moolenaar 		p = LIST_NEXT(p, p_list);
393cbc17435SMarcel Moolenaar 	}
394cbc17435SMarcel Moolenaar 	return (NULL);
395cbc17435SMarcel Moolenaar }
396cbc17435SMarcel Moolenaar 
397cbc17435SMarcel Moolenaar struct thread *
3983d4f3136SMarcel Moolenaar kdb_thr_from_pid(pid_t pid)
3993d4f3136SMarcel Moolenaar {
4003d4f3136SMarcel Moolenaar 	struct proc *p;
4013d4f3136SMarcel Moolenaar 
4023d4f3136SMarcel Moolenaar 	p = LIST_FIRST(&allproc);
4033d4f3136SMarcel Moolenaar 	while (p != NULL) {
4043d4f3136SMarcel Moolenaar 		if (p->p_sflag & PS_INMEM && p->p_pid == pid)
4053d4f3136SMarcel Moolenaar 			return (FIRST_THREAD_IN_PROC(p));
4063d4f3136SMarcel Moolenaar 		p = LIST_NEXT(p, p_list);
4073d4f3136SMarcel Moolenaar 	}
4083d4f3136SMarcel Moolenaar 	return (NULL);
4093d4f3136SMarcel Moolenaar }
4103d4f3136SMarcel Moolenaar 
4113d4f3136SMarcel Moolenaar struct thread *
4123d4f3136SMarcel Moolenaar kdb_thr_lookup(lwpid_t tid)
413cbc17435SMarcel Moolenaar {
414cbc17435SMarcel Moolenaar 	struct thread *thr;
415cbc17435SMarcel Moolenaar 
416cbc17435SMarcel Moolenaar 	thr = kdb_thr_first();
417cbc17435SMarcel Moolenaar 	while (thr != NULL && thr->td_tid != tid)
418cbc17435SMarcel Moolenaar 		thr = kdb_thr_next(thr);
419cbc17435SMarcel Moolenaar 	return (thr);
420cbc17435SMarcel Moolenaar }
421cbc17435SMarcel Moolenaar 
422cbc17435SMarcel Moolenaar struct thread *
423cbc17435SMarcel Moolenaar kdb_thr_next(struct thread *thr)
424cbc17435SMarcel Moolenaar {
425cbc17435SMarcel Moolenaar 	struct proc *p;
426cbc17435SMarcel Moolenaar 
427cbc17435SMarcel Moolenaar 	p = thr->td_proc;
428cbc17435SMarcel Moolenaar 	thr = TAILQ_NEXT(thr, td_plist);
429cbc17435SMarcel Moolenaar 	do {
430cbc17435SMarcel Moolenaar 		if (thr != NULL)
431cbc17435SMarcel Moolenaar 			return (thr);
432cbc17435SMarcel Moolenaar 		p = LIST_NEXT(p, p_list);
433cbc17435SMarcel Moolenaar 		if (p != NULL && (p->p_sflag & PS_INMEM))
434cbc17435SMarcel Moolenaar 			thr = FIRST_THREAD_IN_PROC(p);
435cbc17435SMarcel Moolenaar 	} while (p != NULL);
436cbc17435SMarcel Moolenaar 	return (NULL);
437cbc17435SMarcel Moolenaar }
438cbc17435SMarcel Moolenaar 
439cbc17435SMarcel Moolenaar int
440cbc17435SMarcel Moolenaar kdb_thr_select(struct thread *thr)
441cbc17435SMarcel Moolenaar {
442cbc17435SMarcel Moolenaar 	if (thr == NULL)
443cbc17435SMarcel Moolenaar 		return (EINVAL);
444cbc17435SMarcel Moolenaar 	kdb_thread = thr;
445cbc17435SMarcel Moolenaar 	kdb_thrctx = kdb_thr_ctx(thr);
446cbc17435SMarcel Moolenaar 	return (0);
447cbc17435SMarcel Moolenaar }
448cbc17435SMarcel Moolenaar 
449cbc17435SMarcel Moolenaar /*
450cbc17435SMarcel Moolenaar  * Enter the debugger due to a trap.
451cbc17435SMarcel Moolenaar  */
452cbc17435SMarcel Moolenaar 
453cbc17435SMarcel Moolenaar int
454cbc17435SMarcel Moolenaar kdb_trap(int type, int code, struct trapframe *tf)
455cbc17435SMarcel Moolenaar {
456d8939d82SRobert Watson #ifdef SMP
457d8939d82SRobert Watson 	int did_stop_cpus;
458d8939d82SRobert Watson #endif
459cbc17435SMarcel Moolenaar 	int handled;
460cbc17435SMarcel Moolenaar 
461cbc17435SMarcel Moolenaar 	if (kdb_dbbe == NULL || kdb_dbbe->dbbe_trap == NULL)
462cbc17435SMarcel Moolenaar 		return (0);
463cbc17435SMarcel Moolenaar 
464cbc17435SMarcel Moolenaar 	/* We reenter the debugger through kdb_reenter(). */
465cbc17435SMarcel Moolenaar 	if (kdb_active)
466cbc17435SMarcel Moolenaar 		return (0);
467cbc17435SMarcel Moolenaar 
468cbc17435SMarcel Moolenaar 	critical_enter();
469cbc17435SMarcel Moolenaar 
470cbc17435SMarcel Moolenaar 	kdb_active++;
471cbc17435SMarcel Moolenaar 
472cbc17435SMarcel Moolenaar #ifdef SMP
473d8939d82SRobert Watson 	if ((did_stop_cpus = kdb_stop_cpus) != 0)
474cbc17435SMarcel Moolenaar 		stop_cpus(PCPU_GET(other_cpus));
475cbc17435SMarcel Moolenaar #endif
476cbc17435SMarcel Moolenaar 
477e6aa7232SMarcel Moolenaar 	kdb_frame = tf;
478e6aa7232SMarcel Moolenaar 
479cbc17435SMarcel Moolenaar 	/* Let MD code do its thing first... */
480cbc17435SMarcel Moolenaar 	kdb_cpu_trap(type, code);
481cbc17435SMarcel Moolenaar 
482ddf41225SMarcel Moolenaar 	makectx(tf, &kdb_pcb);
483ddf41225SMarcel Moolenaar 	kdb_thr_select(curthread);
484ddf41225SMarcel Moolenaar 
485cbc17435SMarcel Moolenaar 	handled = kdb_dbbe->dbbe_trap(type, code);
486cbc17435SMarcel Moolenaar 
487cbc17435SMarcel Moolenaar #ifdef SMP
488d8939d82SRobert Watson 	if (did_stop_cpus)
489cbc17435SMarcel Moolenaar 		restart_cpus(stopped_cpus);
490cbc17435SMarcel Moolenaar #endif
491cbc17435SMarcel Moolenaar 
492cbc17435SMarcel Moolenaar 	kdb_active--;
493cbc17435SMarcel Moolenaar 
494cbc17435SMarcel Moolenaar 	critical_exit();
495cbc17435SMarcel Moolenaar 
496cbc17435SMarcel Moolenaar 	return (handled);
497cbc17435SMarcel Moolenaar }
498