xref: /dragonfly/gnu/usr.bin/gdb/kgdb/kthr.c (revision e69ec5f0)
18b6a428fSSimon Schubert /*
28b6a428fSSimon Schubert  * Copyright (c) 2004 Marcel Moolenaar
38b6a428fSSimon Schubert  * All rights reserved.
48b6a428fSSimon Schubert  *
58b6a428fSSimon Schubert  * Redistribution and use in source and binary forms, with or without
68b6a428fSSimon Schubert  * modification, are permitted provided that the following conditions
78b6a428fSSimon Schubert  * are met:
88b6a428fSSimon Schubert  *
98b6a428fSSimon Schubert  * 1. Redistributions of source code must retain the above copyright
108b6a428fSSimon Schubert  *    notice, this list of conditions and the following disclaimer.
118b6a428fSSimon Schubert  * 2. Redistributions in binary form must reproduce the above copyright
128b6a428fSSimon Schubert  *    notice, this list of conditions and the following disclaimer in the
138b6a428fSSimon Schubert  *    documentation and/or other materials provided with the distribution.
148b6a428fSSimon Schubert  *
158b6a428fSSimon Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
168b6a428fSSimon Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
178b6a428fSSimon Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
188b6a428fSSimon Schubert  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
198b6a428fSSimon Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
208b6a428fSSimon Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
218b6a428fSSimon Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
228b6a428fSSimon Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238b6a428fSSimon Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
248b6a428fSSimon Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258b6a428fSSimon Schubert  *
26f17ea84bSSimon Schubert  * $FreeBSD: src/gnu/usr.bin/gdb/kgdb/kthr.c,v 1.12 2008/05/01 20:36:48 jhb Exp $
278b6a428fSSimon Schubert  */
288b6a428fSSimon Schubert 
298b6a428fSSimon Schubert #include <sys/cdefs.h>
308b6a428fSSimon Schubert 
318b6a428fSSimon Schubert #include <sys/param.h>
328b6a428fSSimon Schubert #include <machine/globaldata.h>
338b6a428fSSimon Schubert #include <sys/user.h>
348b6a428fSSimon Schubert #include <sys/types.h>
358b6a428fSSimon Schubert #include <sys/signal.h>
368b6a428fSSimon Schubert #include <err.h>
378b6a428fSSimon Schubert #include <inttypes.h>
388b6a428fSSimon Schubert #include <kvm.h>
398b6a428fSSimon Schubert #include <stdio.h>
408b6a428fSSimon Schubert #include <stdlib.h>
41f17ea84bSSimon Schubert #include <string.h>
428b6a428fSSimon Schubert 
438b6a428fSSimon Schubert #include <defs.h>
448b6a428fSSimon Schubert #include <frame-unwind.h>
45f17ea84bSSimon Schubert #include <inferior.h>
468b6a428fSSimon Schubert 
478b6a428fSSimon Schubert #include "kgdb.h"
488b6a428fSSimon Schubert 
49a938cc15SJohn Marino static CORE_ADDR dumppcb;
50c33252afSJohn Marino static CORE_ADDR dumptid;
518b6a428fSSimon Schubert 
528b6a428fSSimon Schubert static struct kthr *first;
538b6a428fSSimon Schubert struct kthr *curkthr;
548b6a428fSSimon Schubert 
55c33252afSJohn Marino #define LIVESYS_DUMPTID	10
56c33252afSJohn Marino 
57a938cc15SJohn Marino CORE_ADDR
kgdb_lookup(const char * sym)58f17ea84bSSimon Schubert kgdb_lookup(const char *sym)
59f17ea84bSSimon Schubert {
60f17ea84bSSimon Schubert 	struct nlist nl[2];
61f17ea84bSSimon Schubert 
62a938cc15SJohn Marino 	nl[0].n_name = (char *)(CORE_ADDR)sym;
63f17ea84bSSimon Schubert 	nl[1].n_name = NULL;
64f17ea84bSSimon Schubert 	if (kvm_nlist(kvm, nl) != 0)
65f17ea84bSSimon Schubert 		return (0);
66f17ea84bSSimon Schubert 	return (nl[0].n_value);
67f17ea84bSSimon Schubert }
68f17ea84bSSimon Schubert 
698b6a428fSSimon Schubert struct kthr *
kgdb_thr_first(void)708b6a428fSSimon Schubert kgdb_thr_first(void)
718b6a428fSSimon Schubert {
728b6a428fSSimon Schubert 	return (first);
738b6a428fSSimon Schubert }
748b6a428fSSimon Schubert 
758b6a428fSSimon Schubert struct kthr *
kgdb_thr_init(void)768b6a428fSSimon Schubert kgdb_thr_init(void)
778b6a428fSSimon Schubert {
788b6a428fSSimon Schubert 	struct proc p;
798b6a428fSSimon Schubert 	struct thread td;
80f17ea84bSSimon Schubert 	struct lwp lwp;
818b6a428fSSimon Schubert 	struct mdglobaldata gd;
828b6a428fSSimon Schubert 	struct kthr *kt;
83*e69ec5f0SMatthew Dillon 	CORE_ADDR addr, paddr, prvspace, gdptr;
848b6a428fSSimon Schubert 	int cpu, ncpus;
858b6a428fSSimon Schubert 
86f17ea84bSSimon Schubert 	while (first != NULL) {
87f17ea84bSSimon Schubert 		kt = first;
88f17ea84bSSimon Schubert 		first = kt->next;
89f17ea84bSSimon Schubert 		free(kt);
90f17ea84bSSimon Schubert 	}
91f17ea84bSSimon Schubert 
92f17ea84bSSimon Schubert 	addr = kgdb_lookup("_ncpus");
938b6a428fSSimon Schubert 	if (addr == 0)
948b6a428fSSimon Schubert 		return (NULL);
958b6a428fSSimon Schubert 	kvm_read(kvm, addr, &ncpus, sizeof(ncpus));
968b6a428fSSimon Schubert 
97f17ea84bSSimon Schubert 	dumppcb = kgdb_lookup("_dumppcb");
988b6a428fSSimon Schubert 	if (dumppcb == 0)
998b6a428fSSimon Schubert 		return (NULL);
1008b6a428fSSimon Schubert 
101f17ea84bSSimon Schubert 	prvspace = kgdb_lookup("_CPU_prvspace");
1028b6a428fSSimon Schubert 	if (prvspace == 0)
1038b6a428fSSimon Schubert 		return (NULL);
1048b6a428fSSimon Schubert 
105f17ea84bSSimon Schubert 	addr = kgdb_lookup("_dumpthread");
1068b6a428fSSimon Schubert 	if (addr != 0) {
1078b6a428fSSimon Schubert 		kvm_read(kvm, addr, &dumptid, sizeof(dumptid));
1088b6a428fSSimon Schubert 	} else {
1098b6a428fSSimon Schubert 		/*
1108b6a428fSSimon Schubert 		 * XXX Well then.  We don't know who dumped us.
1118b6a428fSSimon Schubert 		 * We could do some fancy stack matching, but
1128b6a428fSSimon Schubert 		 * I doubt this will work.  For now just use
1138b6a428fSSimon Schubert 		 * cpu0's curthread.
1148b6a428fSSimon Schubert 		 *
1158b6a428fSSimon Schubert 		 * Actually we don't even know if we were dumped
116c33252afSJohn Marino 		 * or if we are live.  Find out by querying "dumping".
1178b6a428fSSimon Schubert 		 */
1188b6a428fSSimon Schubert 		int dumping = 0;
1198b6a428fSSimon Schubert 
120f17ea84bSSimon Schubert 		addr = kgdb_lookup("_dumping");
1218b6a428fSSimon Schubert 		kvm_read(kvm, addr, &dumping, sizeof(dumping));
1228b6a428fSSimon Schubert 		if (dumping) {
123*e69ec5f0SMatthew Dillon 			kvm_read(kvm, prvspace + 0, &gdptr, sizeof(gdptr));
124*e69ec5f0SMatthew Dillon 			kvm_read(kvm, gdptr +
1258b6a428fSSimon Schubert 				 offsetof(struct privatespace, mdglobaldata),
1268b6a428fSSimon Schubert 				 &gd, sizeof(struct mdglobaldata));
127c33252afSJohn Marino 			dumptid = (CORE_ADDR)gd.mi.gd_curthread;
1288b6a428fSSimon Schubert 		} else {
1298b6a428fSSimon Schubert 			/* We must be a live system */
130c33252afSJohn Marino 			dumptid = LIVESYS_DUMPTID;
1318b6a428fSSimon Schubert 		}
1328b6a428fSSimon Schubert 	}
1338b6a428fSSimon Schubert 
1348b6a428fSSimon Schubert 	for (cpu = 0; cpu < ncpus; cpu++) {
135*e69ec5f0SMatthew Dillon 		kvm_read(kvm, prvspace + cpu * sizeof(void *),
136*e69ec5f0SMatthew Dillon 			 &gdptr, sizeof(gdptr));
137*e69ec5f0SMatthew Dillon 		kvm_read(kvm, gdptr +
1388b6a428fSSimon Schubert 			 offsetof(struct privatespace, mdglobaldata),
1398b6a428fSSimon Schubert 			 &gd, sizeof(struct mdglobaldata));
1408b6a428fSSimon Schubert 
1418b6a428fSSimon Schubert 		addr = (uintptr_t)TAILQ_FIRST(&gd.mi.gd_tdallq);
1428b6a428fSSimon Schubert 		while (addr != 0) {
143701b4372SMatthew Dillon 			if (kvm_read(kvm, addr, &td, sizeof(td)) != sizeof(td)) {
144701b4372SMatthew Dillon 				warnx("kvm_read: %s, while accessing thread",
145701b4372SMatthew Dillon 				      kvm_geterr(kvm));
146701b4372SMatthew Dillon 				break;
147701b4372SMatthew Dillon 			}
1488b6a428fSSimon Schubert 			kt = malloc(sizeof(*kt));
1498b6a428fSSimon Schubert 			kt->next = first;
1508b6a428fSSimon Schubert 			kt->kaddr = addr;
151c33252afSJohn Marino 			kt->tid = addr;
1528b6a428fSSimon Schubert 			kt->pcb = (kt->tid == dumptid) ? dumppcb :
1538b6a428fSSimon Schubert 			    (uintptr_t)td.td_pcb;
1548b6a428fSSimon Schubert 			kt->kstack = (uintptr_t)td.td_kstack;
1558b6a428fSSimon Schubert 			if (td.td_proc != NULL) {
1568b6a428fSSimon Schubert 				paddr = (uintptr_t)td.td_proc;
1578b6a428fSSimon Schubert 				if (kvm_read(kvm, paddr, &p, sizeof(p)) != sizeof(p))
1588b6a428fSSimon Schubert 					warnx("kvm_read: %s", kvm_geterr(kvm));
1598b6a428fSSimon Schubert 				kt->pid = p.p_pid;
1608b6a428fSSimon Schubert 				kt->paddr = paddr;
161f17ea84bSSimon Schubert 				addr = (uintptr_t)td.td_lwp;
162f17ea84bSSimon Schubert 				if (kvm_read(kvm, addr, &lwp, sizeof(lwp)) != sizeof(lwp))
163f17ea84bSSimon Schubert 					warnx("kvm_read: %s", kvm_geterr(kvm));
164f17ea84bSSimon Schubert 				kt->lwpid = lwp.lwp_tid;
1658b6a428fSSimon Schubert 			} else {
1668b6a428fSSimon Schubert 				/*
1678b6a428fSSimon Schubert 				 * XXX for some stupid reason, gdb uses pid == -1
1688b6a428fSSimon Schubert 				 * as a marker for "dead" threads, so we have to
1698b6a428fSSimon Schubert 				 * hook all kernel threads on a different pid :/
1708b6a428fSSimon Schubert 				 */
1718b6a428fSSimon Schubert 				kt->pid = -2;
1728b6a428fSSimon Schubert 				kt->paddr = 0;
173f10d6f65SSimon Schubert 				/*
174f10d6f65SSimon Schubert 				 * We are a kernel thread, so our td_pcb is
175f10d6f65SSimon Schubert 				 * not used anyways.  An exception is the
176f10d6f65SSimon Schubert 				 * dumping thread.
177eecd52b2SSascha Wildner 				 * kt->pcb == 0 is a marker for
178f10d6f65SSimon Schubert 				 * "non-dumping kernel thread".
179f10d6f65SSimon Schubert 				 */
180f10d6f65SSimon Schubert 				if (kt->tid != dumptid)
181eecd52b2SSascha Wildner 					kt->pcb = 0;
1828b6a428fSSimon Schubert 			}
1838b6a428fSSimon Schubert 			first = kt;
1848b6a428fSSimon Schubert 			addr = (uintptr_t)TAILQ_NEXT(&td, td_allq);
1858b6a428fSSimon Schubert 		}
1868b6a428fSSimon Schubert 	}
1878b6a428fSSimon Schubert 
1888b6a428fSSimon Schubert 	curkthr = kgdb_thr_lookup_tid(dumptid);
1898b6a428fSSimon Schubert 	if (curkthr == NULL)
1908b6a428fSSimon Schubert 		curkthr = first;
1918b6a428fSSimon Schubert 	return (first);
1928b6a428fSSimon Schubert }
1938b6a428fSSimon Schubert 
1948b6a428fSSimon Schubert struct kthr *
kgdb_thr_lookup_tid(CORE_ADDR tid)195c33252afSJohn Marino kgdb_thr_lookup_tid(CORE_ADDR tid)
1968b6a428fSSimon Schubert {
1978b6a428fSSimon Schubert 	struct kthr *kt;
1988b6a428fSSimon Schubert 
1998b6a428fSSimon Schubert 	kt = first;
2008b6a428fSSimon Schubert 	while (kt != NULL && kt->tid != tid)
2018b6a428fSSimon Schubert 		kt = kt->next;
2028b6a428fSSimon Schubert 	return (kt);
2038b6a428fSSimon Schubert }
2048b6a428fSSimon Schubert 
2058b6a428fSSimon Schubert struct kthr *
kgdb_thr_lookup_taddr(uintptr_t taddr)2068b6a428fSSimon Schubert kgdb_thr_lookup_taddr(uintptr_t taddr)
2078b6a428fSSimon Schubert {
2088b6a428fSSimon Schubert 	struct kthr *kt;
2098b6a428fSSimon Schubert 
2108b6a428fSSimon Schubert 	kt = first;
2118b6a428fSSimon Schubert 	while (kt != NULL && kt->kaddr != taddr)
2128b6a428fSSimon Schubert 		kt = kt->next;
2138b6a428fSSimon Schubert 	return (kt);
2148b6a428fSSimon Schubert }
2158b6a428fSSimon Schubert 
2168b6a428fSSimon Schubert struct kthr *
kgdb_thr_lookup_pid(int pid)2178b6a428fSSimon Schubert kgdb_thr_lookup_pid(int pid)
2188b6a428fSSimon Schubert {
2198b6a428fSSimon Schubert 	struct kthr *kt;
2208b6a428fSSimon Schubert 
2218b6a428fSSimon Schubert 	kt = first;
2228b6a428fSSimon Schubert 	while (kt != NULL && kt->pid != pid)
2238b6a428fSSimon Schubert 		kt = kt->next;
2248b6a428fSSimon Schubert 	return (kt);
2258b6a428fSSimon Schubert }
2268b6a428fSSimon Schubert 
2278b6a428fSSimon Schubert struct kthr *
kgdb_thr_lookup_paddr(uintptr_t paddr)2288b6a428fSSimon Schubert kgdb_thr_lookup_paddr(uintptr_t paddr)
2298b6a428fSSimon Schubert {
2308b6a428fSSimon Schubert 	struct kthr *kt;
2318b6a428fSSimon Schubert 
2328b6a428fSSimon Schubert 	kt = first;
2338b6a428fSSimon Schubert 	while (kt != NULL && kt->paddr != paddr)
2348b6a428fSSimon Schubert 		kt = kt->next;
2358b6a428fSSimon Schubert 	return (kt);
2368b6a428fSSimon Schubert }
2378b6a428fSSimon Schubert 
2388b6a428fSSimon Schubert struct kthr *
kgdb_thr_next(struct kthr * kt)2398b6a428fSSimon Schubert kgdb_thr_next(struct kthr *kt)
2408b6a428fSSimon Schubert {
2418b6a428fSSimon Schubert 	return (kt->next);
2428b6a428fSSimon Schubert }
2438b6a428fSSimon Schubert 
2448b6a428fSSimon Schubert struct kthr *
kgdb_thr_select(struct kthr * kt)2458b6a428fSSimon Schubert kgdb_thr_select(struct kthr *kt)
2468b6a428fSSimon Schubert {
2478b6a428fSSimon Schubert 	struct kthr *pcur;
2488b6a428fSSimon Schubert 
2498b6a428fSSimon Schubert 	pcur = curkthr;
2508b6a428fSSimon Schubert 	curkthr = kt;
2518b6a428fSSimon Schubert 	return (pcur);
2528b6a428fSSimon Schubert }
2538b6a428fSSimon Schubert 
2548b6a428fSSimon Schubert char *
kgdb_thr_extra_thread_info(CORE_ADDR tid)255c33252afSJohn Marino kgdb_thr_extra_thread_info(CORE_ADDR tid)
2568b6a428fSSimon Schubert {
257c33252afSJohn Marino #if 0 /* Information already provided */
2588b6a428fSSimon Schubert 	struct kthr *kt;
259f17ea84bSSimon Schubert 	static char buf[64];
260c33252afSJohn Marino 	struct proc *p;
261c33252afSJohn Marino 	char comm[MAXCOMLEN + 1];
2628b6a428fSSimon Schubert 
2638b6a428fSSimon Schubert 	kt = kgdb_thr_lookup_tid(tid);
2648b6a428fSSimon Schubert 	if (kt == NULL)
2658b6a428fSSimon Schubert 		return (NULL);
266f17ea84bSSimon Schubert 
267c33252afSJohn Marino 	snprintf(buf, sizeof(buf), "PID=%d", kt->pid);
268c33252afSJohn Marino 	p = (struct proc *)kt->paddr;
269c33252afSJohn Marino 	if (kvm_read(kvm, (uintptr_t)&p->p_comm[0], &comm, sizeof(comm)) ==
270c33252afSJohn Marino 		sizeof(comm)) {
271c33252afSJohn Marino 		strlcat(buf, ": ", sizeof(buf));
272c33252afSJohn Marino 		strlcat(buf, comm, sizeof(buf));
273c33252afSJohn Marino 	}
274c33252afSJohn Marino 	return (buf);
27550a61867SJohn Marino #endif
276f17ea84bSSimon Schubert 	return (NULL);
277f17ea84bSSimon Schubert }
278f17ea84bSSimon Schubert 
279f17ea84bSSimon Schubert char *
kgdb_thr_pid_to_str(ptid_t ptid)280f17ea84bSSimon Schubert kgdb_thr_pid_to_str(ptid_t ptid)
281f17ea84bSSimon Schubert {
282f17ea84bSSimon Schubert 	char comm[MAXCOMLEN + 1];
283f17ea84bSSimon Schubert 	struct kthr *kt;
284f17ea84bSSimon Schubert 	struct proc *p;
285f17ea84bSSimon Schubert 	struct thread *t;
286f17ea84bSSimon Schubert 	static char buf[64];
287c33252afSJohn Marino 	CORE_ADDR tid;
288f17ea84bSSimon Schubert 
289f17ea84bSSimon Schubert 	tid = ptid_get_tid(ptid);
290f17ea84bSSimon Schubert 	if (tid == 0)
291f17ea84bSSimon Schubert 		kt = kgdb_thr_lookup_pid(ptid_get_pid(ptid));
292f17ea84bSSimon Schubert 	else
293f17ea84bSSimon Schubert 		kt = kgdb_thr_lookup_tid(tid);
294f17ea84bSSimon Schubert 
295f17ea84bSSimon Schubert 	if (kt == NULL)
2968b6a428fSSimon Schubert 		return (NULL);
2978b6a428fSSimon Schubert 
298f17ea84bSSimon Schubert 	buf[0] = 0;
299f17ea84bSSimon Schubert 
300f17ea84bSSimon Schubert 	if (kt->pid != -2) {
301f17ea84bSSimon Schubert 		snprintf(buf, sizeof(buf), "pid %d", kt->pid);
302f17ea84bSSimon Schubert 
303f17ea84bSSimon Schubert 		if (tid != 0)
304f17ea84bSSimon Schubert 			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
305c33252afSJohn Marino 				 "/%ld", kt->lwpid);
306f17ea84bSSimon Schubert 
307f17ea84bSSimon Schubert 		p = (struct proc *)kt->paddr;
308f17ea84bSSimon Schubert 		if (kvm_read(kvm, (uintptr_t)&p->p_comm[0], &comm, sizeof(comm)) !=
309f17ea84bSSimon Schubert 		    sizeof(comm))
310f17ea84bSSimon Schubert 			return (buf);
311f17ea84bSSimon Schubert 
312f17ea84bSSimon Schubert 		strlcat(buf, ", ", sizeof(buf));
313f17ea84bSSimon Schubert 		strlcat(buf, comm, sizeof(buf));
314f17ea84bSSimon Schubert 	} else {
315f17ea84bSSimon Schubert 		strcpy(buf, "kernel");
316f17ea84bSSimon Schubert 
317f17ea84bSSimon Schubert 		if (tid != 0) {
318f17ea84bSSimon Schubert 			t = (struct thread *)kt->kaddr;
319f17ea84bSSimon Schubert 			if (kvm_read(kvm, (uintptr_t)&t->td_comm[0], &comm,
320f17ea84bSSimon Schubert 			    sizeof(comm)) == sizeof(comm)) {
321f17ea84bSSimon Schubert 				strlcat(buf, " ", sizeof(buf));
322f17ea84bSSimon Schubert 				strlcat(buf, comm, sizeof(buf));
323f17ea84bSSimon Schubert 			}
324f17ea84bSSimon Schubert 		}
325f17ea84bSSimon Schubert 	}
326f17ea84bSSimon Schubert 
327f17ea84bSSimon Schubert 	return (buf);
3288b6a428fSSimon Schubert }
329