kthr.c revision 210852
11553Srgrimes/*
21553Srgrimes * Copyright (c) 2004 Marcel Moolenaar
31553Srgrimes * All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes *
91553Srgrimes * 1. Redistributions of source code must retain the above copyright
101553Srgrimes *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/kthr.c 210852 2010-08-04 21:02:04Z jhb $");
29
30#include <sys/param.h>
31#include <sys/proc.h>
32#include <sys/types.h>
33#include <sys/signal.h>
34#include <err.h>
35#include <inttypes.h>
36#include <kvm.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include <defs.h>
42#include <frame-unwind.h>
43
44#include "kgdb.h"
45#include <machine/pcb.h>
46
47static CORE_ADDR dumppcb;
48static int dumptid;
49
50static CORE_ADDR stoppcbs;
51static __cpumask_t stopped_cpus;
52
53static struct kthr *first;
54struct kthr *curkthr;
55
56CORE_ADDR
57kgdb_lookup(const char *sym)
58{
59	CORE_ADDR addr;
60	char *name;
61
62	asprintf(&name, "&%s", sym);
63	addr = kgdb_parse(name);
64	free(name);
65	return (addr);
66}
67
68struct kthr *
69kgdb_thr_first(void)
70{
71	return (first);
72}
73
74struct kthr *
75kgdb_thr_init(void)
76{
77	struct proc p;
78	struct thread td;
79	struct kthr *kt;
80	CORE_ADDR addr;
81	uintptr_t paddr;
82
83	while (first != NULL) {
84		kt = first;
85		first = kt->next;
86		free(kt);
87	}
88
89	addr = kgdb_lookup("allproc");
90	if (addr == 0)
91		return (NULL);
92	kvm_read(kvm, addr, &paddr, sizeof(paddr));
93
94	dumppcb = kgdb_lookup("dumppcb");
95	if (dumppcb == 0)
96		return (NULL);
97
98	addr = kgdb_lookup("dumptid");
99	if (addr != 0)
100		kvm_read(kvm, addr, &dumptid, sizeof(dumptid));
101	else
102		dumptid = -1;
103
104	addr = kgdb_lookup("stopped_cpus");
105	if (addr != 0)
106		kvm_read(kvm, addr, &stopped_cpus, sizeof(stopped_cpus));
107	else
108		stopped_cpus = 0;
109
110	stoppcbs = kgdb_lookup("stoppcbs");
111
112	while (paddr != 0) {
113		if (kvm_read(kvm, paddr, &p, sizeof(p)) != sizeof(p)) {
114			warnx("kvm_read: %s", kvm_geterr(kvm));
115			break;
116		}
117		addr = (uintptr_t)TAILQ_FIRST(&p.p_threads);
118		while (addr != 0) {
119			if (kvm_read(kvm, addr, &td, sizeof(td)) !=
120			    sizeof(td)) {
121				warnx("kvm_read: %s", kvm_geterr(kvm));
122				break;
123			}
124			kt = malloc(sizeof(*kt));
125			kt->next = first;
126			kt->kaddr = addr;
127			if (td.td_tid == dumptid)
128				kt->pcb = dumppcb;
129			else if (td.td_state == TDS_RUNNING && ((1 << td.td_oncpu) & stopped_cpus)
130				&& stoppcbs != 0)
131				kt->pcb = (uintptr_t) stoppcbs + sizeof(struct pcb) * td.td_oncpu;
132			else
133				kt->pcb = (uintptr_t)td.td_pcb;
134			kt->kstack = td.td_kstack;
135			kt->tid = td.td_tid;
136			kt->pid = p.p_pid;
137			kt->paddr = paddr;
138			kt->cpu = td.td_oncpu;
139			first = kt;
140			addr = (uintptr_t)TAILQ_NEXT(&td, td_plist);
141		}
142		paddr = (uintptr_t)LIST_NEXT(&p, p_list);
143	}
144	curkthr = kgdb_thr_lookup_tid(dumptid);
145	if (curkthr == NULL)
146		curkthr = first;
147	return (first);
148}
149
150struct kthr *
151kgdb_thr_lookup_tid(int tid)
152{
153	struct kthr *kt;
154
155	kt = first;
156	while (kt != NULL && kt->tid != tid)
157		kt = kt->next;
158	return (kt);
159}
160
161struct kthr *
162kgdb_thr_lookup_taddr(uintptr_t taddr)
163{
164	struct kthr *kt;
165
166	kt = first;
167	while (kt != NULL && kt->kaddr != taddr)
168		kt = kt->next;
169	return (kt);
170}
171
172struct kthr *
173kgdb_thr_lookup_pid(int pid)
174{
175	struct kthr *kt;
176
177	kt = first;
178	while (kt != NULL && kt->pid != pid)
179		kt = kt->next;
180	return (kt);
181}
182
183struct kthr *
184kgdb_thr_lookup_paddr(uintptr_t paddr)
185{
186	struct kthr *kt;
187
188	kt = first;
189	while (kt != NULL && kt->paddr != paddr)
190		kt = kt->next;
191	return (kt);
192}
193
194struct kthr *
195kgdb_thr_next(struct kthr *kt)
196{
197	return (kt->next);
198}
199
200struct kthr *
201kgdb_thr_select(struct kthr *kt)
202{
203	struct kthr *pcur;
204
205	pcur = curkthr;
206	curkthr = kt;
207	return (pcur);
208}
209
210char *
211kgdb_thr_extra_thread_info(int tid)
212{
213	char comm[MAXCOMLEN + 1];
214	char td_name[MAXCOMLEN + 1];
215	struct kthr *kt;
216	struct proc *p;
217	struct thread *t;
218	static char buf[64];
219
220	kt = kgdb_thr_lookup_tid(tid);
221	if (kt == NULL)
222		return (NULL);
223	snprintf(buf, sizeof(buf), "PID=%d", kt->pid);
224	p = (struct proc *)kt->paddr;
225	if (kvm_read(kvm, (uintptr_t)&p->p_comm[0], &comm, sizeof(comm)) !=
226	    sizeof(comm))
227		return (buf);
228	strlcat(buf, ": ", sizeof(buf));
229	strlcat(buf, comm, sizeof(buf));
230	t = (struct thread *)kt->kaddr;
231	if (kvm_read(kvm, (uintptr_t)&t->td_name[0], &td_name,
232	    sizeof(td_name)) == sizeof(td_name) &&
233	    strcmp(comm, td_name) != 0) {
234		strlcat(buf, "/", sizeof(buf));
235		strlcat(buf, td_name, sizeof(buf));
236	}
237	return (buf);
238}
239