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