db_thread.c revision 160312
1/*-
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    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 AUTHOR ``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 AUTHOR 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/sys/ddb/db_thread.c 160312 2006-07-12 21:22:44Z jhb $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kdb.h>
33#include <sys/proc.h>
34
35#include <machine/pcb.h>
36
37#include <ddb/ddb.h>
38#include <ddb/db_command.h>
39#include <ddb/db_sym.h>
40
41static db_expr_t hex2dec(db_expr_t expr);
42
43void
44db_print_thread(void)
45{
46	pid_t pid;
47
48	pid = -1;
49	if (kdb_thread->td_proc != NULL)
50		pid = kdb_thread->td_proc->p_pid;
51	db_printf("[thread pid %d tid %ld ]\n", pid, (long)kdb_thread->td_tid);
52}
53
54void
55db_set_thread(db_expr_t tid, boolean_t hastid, db_expr_t cnt, char *mod)
56{
57	struct thread *thr;
58	db_expr_t radix;
59	int err;
60
61	/*
62	 * We parse our own arguments. We don't like the default radix.
63	 */
64	radix = db_radix;
65	db_radix = 10;
66	hastid = db_expression(&tid);
67	db_radix = radix;
68	db_skip_to_eol();
69
70	if (hastid) {
71		thr = kdb_thr_lookup(tid);
72		if (thr != NULL) {
73			err = kdb_thr_select(thr);
74			if (err != 0) {
75				db_printf("unable to switch to thread %ld\n",
76				    (long)thr->td_tid);
77				return;
78			}
79			db_dot = PC_REGS();
80		} else {
81			db_printf("%d: invalid thread\n", (int)tid);
82			return;
83		}
84	}
85
86	db_print_thread();
87	db_print_loc_and_inst(PC_REGS());
88}
89
90void
91db_show_threads(db_expr_t addr, boolean_t hasaddr, db_expr_t cnt, char *mod)
92{
93	jmp_buf jb;
94	void *prev_jb;
95	struct thread *thr;
96
97	thr = kdb_thr_first();
98	while (!db_pager_quit && thr != NULL) {
99		db_printf("  %6ld (%p)  ", (long)thr->td_tid, thr);
100		prev_jb = kdb_jmpbuf(jb);
101		if (setjmp(jb) == 0) {
102			if (db_trace_thread(thr, 1) != 0)
103				db_printf("***\n");
104		}
105		kdb_jmpbuf(prev_jb);
106		thr = kdb_thr_next(thr);
107	}
108}
109
110/*
111 * Take the parsed expression value from the command line that was parsed
112 * as a hexadecimal value and convert it as if the expression was parsed
113 * as a decimal value.  Returns -1 if the expression was not a valid
114 * decimal value.
115 */
116static db_expr_t
117hex2dec(db_expr_t expr)
118{
119	uintptr_t x, y;
120	db_expr_t val;
121
122	y = 1;
123	val = 0;
124	x = expr;
125	while (x != 0) {
126		if (x % 16 > 9)
127			return (-1);
128		val += (x % 16) * (y);
129		x >>= 4;
130		y *= 10;
131	}
132	return (val);
133}
134
135/*
136 * Lookup a thread based on a db expression address.  We assume that the
137 * address was parsed in hexadecimal.  We reparse the address in decimal
138 * first and try to treat it as a thread ID to find an associated thread.
139 * If that fails and check_pid is true, we terat the decimal value as a
140 * PID.  If that matches a process, we return the first thread in that
141 * process.  Otherwise, we treat the addr as a pointer to a thread.
142 */
143struct thread *
144db_lookup_thread(db_expr_t addr, boolean_t check_pid)
145{
146	struct thread *td;
147	db_expr_t decaddr;
148	struct proc *p;
149
150	/*
151	 * If the parsed address was not a valid decimal expression,
152	 * assume it is a thread pointer.
153	 */
154	decaddr = hex2dec(addr);
155	if (decaddr == -1)
156		return ((struct thread *)addr);
157
158	td = kdb_thr_lookup(decaddr);
159	if (td != NULL)
160		return (td);
161	if (check_pid) {
162		LIST_FOREACH(p, &allproc, p_list) {
163			if (p->p_pid == decaddr)
164				return (FIRST_THREAD_IN_PROC(p));
165		}
166		LIST_FOREACH(p, &zombproc, p_list) {
167			if (p->p_pid == decaddr)
168				return (FIRST_THREAD_IN_PROC(p));
169		}
170	}
171	return ((struct thread *)addr);
172}
173
174/*
175 * Lookup a process based on a db expression address.  We assume that the
176 * address was parsed in hexadecimal.  We reparse the address in decimal
177 * first and try to treat it as a PID to find an associated process.
178 * If that fails we treat the addr as a pointer to a process.
179 */
180struct proc *
181db_lookup_proc(db_expr_t addr)
182{
183	db_expr_t decaddr;
184	struct proc *p;
185
186	decaddr = hex2dec(addr);
187	if (decaddr != -1) {
188		LIST_FOREACH(p, &allproc, p_list) {
189			if (p->p_pid == decaddr)
190				return (p);
191		}
192		LIST_FOREACH(p, &zombproc, p_list) {
193			if (p->p_pid == decaddr)
194				return (p);
195		}
196	}
197	return ((struct proc *)addr);
198}
199