]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ddb/db_task_thread.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / osfmk / ddb / db_task_thread.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
1c79356b
A
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50/*
51 */
52
53#include <kern/kern_types.h>
54#include <kern/processor.h>
55#include <machine/db_machdep.h>
56#include <ddb/db_task_thread.h>
57#include <ddb/db_variables.h>
58#include <ddb/db_command.h>
59#include <ddb/db_expr.h>
60#include <ddb/db_lex.h>
61#include <ddb/db_output.h> /* For db_printf() */
62#include <ddb/db_sym.h>
63
64/*
65 * Following constants are used to prevent infinite loop of task
66 * or thread search due to the incorrect list.
67 */
68#define DB_MAX_TASKID 0x10000 /* max # of tasks */
69#define DB_MAX_THREADID 0x10000 /* max # of threads in a task */
70#define DB_MAX_PSETS 0x10000 /* max # of processor sets */
71
72task_t db_default_task; /* default target task */
73thread_act_t db_default_act; /* default target thr_act */
74
75
76
77/* Prototypes for functions local to this file.
78 */
79task_t db_lookup_task_id(register int task_id);
80
81static thread_act_t db_lookup_act_id(
82 task_t task,
83 register int thread_id);
84
85
86
87/*
88 * search valid task queue, and return the queue position as the task id
89 */
90int
91db_lookup_task(task_t target_task)
92{
93 register task_t task;
94 register int task_id;
95 register processor_set_t pset = &default_pset;
96 register int npset = 0;
97
98 task_id = 0;
99 if (npset++ >= DB_MAX_PSETS)
100 return(-1);
101 if (queue_first(&pset->tasks) == 0)
102 return(-1);
103 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
104 if (target_task == task)
105 return(task_id);
106 if (task_id++ >= DB_MAX_TASKID)
107 return(-1);
108 }
109 return(-1);
110}
111
112/*
113 * search thread queue of the task, and return the queue position
114 */
115int
116db_lookup_task_act(
117 task_t task,
118 thread_act_t target_act)
119{
120 register thread_act_t thr_act;
121 register int act_id;
122
123 act_id = 0;
55e303ae 124 if (queue_first(&task->threads) == 0)
1c79356b 125 return(-1);
55e303ae 126 queue_iterate(&task->threads, thr_act, thread_act_t, task_threads) {
1c79356b
A
127 if (target_act == thr_act)
128 return(act_id);
129 if (act_id++ >= DB_MAX_THREADID)
130 return(-1);
131 }
132 return(-1);
133}
134
135/*
136 * search thr_act queue of every valid task, and return the queue position
137 * as the thread id.
138 */
139int
140db_lookup_act(thread_act_t target_act)
141{
142 register int act_id;
143 register task_t task;
144 register processor_set_t pset = &default_pset;
145 register int ntask = 0;
146 register int npset = 0;
147
148 if (npset++ >= DB_MAX_PSETS)
149 return(-1);
150 if (queue_first(&pset->tasks) == 0)
151 return(-1);
152 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
153 if (ntask++ > DB_MAX_TASKID)
154 return(-1);
55e303ae 155 if (task->thread_count == 0)
1c79356b
A
156 continue;
157 act_id = db_lookup_task_act(task, target_act);
158 if (act_id >= 0)
159 return(act_id);
160 }
161 return(-1);
162}
163
164/*
165 * check the address is a valid thread address
166 */
167int force_act_lookup = 0;
168boolean_t
169db_check_act_address_valid(thread_act_t thr_act)
170{
171 if (!force_act_lookup && db_lookup_act(thr_act) < 0) {
172 db_printf("Bad thr_act address 0x%x\n", thr_act);
173 db_flush_lex();
174 return(FALSE);
175 } else
176 return(TRUE);
177}
178
179/*
180 * convert task_id(queue postion) to task address
181 */
182task_t
183db_lookup_task_id(register task_id)
184{
185 register task_t task;
186 register processor_set_t pset = &default_pset;
187 register int npset = 0;
188
189 if (task_id > DB_MAX_TASKID)
190 return(TASK_NULL);
191 if (npset++ >= DB_MAX_PSETS)
192 return(TASK_NULL);
193 if (queue_first(&pset->tasks) == 0)
194 return(TASK_NULL);
195 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
196 if (task_id-- <= 0)
197 return(task);
198 }
199 return(TASK_NULL);
200}
201
202/*
203 * convert (task_id, act_id) pair to thr_act address
204 */
205static thread_act_t
206db_lookup_act_id(
207 task_t task,
208 register int act_id)
209{
210 register thread_act_t thr_act;
211
212
213 if (act_id > DB_MAX_THREADID)
214 return(THR_ACT_NULL);
55e303ae 215 if (queue_first(&task->threads) == 0)
1c79356b 216 return(THR_ACT_NULL);
55e303ae 217 queue_iterate(&task->threads, thr_act, thread_act_t, task_threads) {
1c79356b
A
218 if (act_id-- <= 0)
219 return(thr_act);
220 }
221 return(THR_ACT_NULL);
222}
223
224/*
225 * get next parameter from a command line, and check it as a valid
226 * thread address
227 */
228boolean_t
229db_get_next_act(
230 thread_act_t *actp,
231 int position)
232{
233 db_expr_t value;
234 thread_act_t thr_act;
235
236 *actp = THR_ACT_NULL;
237 if (db_expression(&value)) {
238 thr_act = (thread_act_t) value;
239 if (!db_check_act_address_valid(thr_act)) {
240 db_flush_lex();
241 return(FALSE);
242 }
243 } else if (position <= 0) {
244 thr_act = db_default_act;
245 } else
246 return(FALSE);
247 *actp = thr_act;
248 return(TRUE);
249}
250
251/*
252 * check the default thread is still valid
253 * ( it is called in entering DDB session )
254 */
255void
256db_init_default_act(void)
257{
258 if (db_lookup_act(db_default_act) < 0) {
259 db_default_act = THR_ACT_NULL;
260 db_default_task = TASK_NULL;
261 } else
262 db_default_task = db_default_act->task;
263}
264
265/*
266 * set or get default thread which is used when /t or :t option is specified
267 * in the command line
268 */
269int
270db_set_default_act(
271 struct db_variable *vp,
272 db_expr_t *valuep,
273 int flag,
274 db_var_aux_param_t ap) /* unused */
275{
276 thread_act_t thr_act;
277 int task_id;
278 int act_id;
279
280 if (flag == DB_VAR_SHOW) {
281 db_printf("%#n", db_default_act);
282 task_id = db_lookup_task(db_default_task);
283 if (task_id != -1) {
284 act_id = db_lookup_act(db_default_act);
285 if (act_id != -1) {
286 db_printf(" (task%d.%d)", task_id, act_id);
287 }
288 }
289 return(0);
290 }
291
292 if (flag != DB_VAR_SET) {
293 *valuep = (db_expr_t) db_default_act;
294 return(0);
295 }
296 thr_act = (thread_act_t) *valuep;
297 if (thr_act != THR_ACT_NULL && !db_check_act_address_valid(thr_act))
298 db_error(0);
299 /* NOTREACHED */
300 db_default_act = thr_act;
301 if (thr_act)
302 db_default_task = thr_act->task;
303 return(0);
304}
305
306/*
307 * convert $taskXXX[.YYY] type DDB variable to task or thread address
308 */
309int
310db_get_task_act(
311 struct db_variable *vp,
312 db_expr_t *valuep,
313 int flag,
314 db_var_aux_param_t ap)
315{
316 task_t task;
317 thread_act_t thr_act;
318 int task_id;
319
320 if (flag == DB_VAR_SHOW) {
321 db_printf("%#n", db_default_task);
322 task_id = db_lookup_task(db_default_task);
323 if (task_id != -1)
324 db_printf(" (task%d)", task_id);
325 return(0);
326 }
327
328 if (flag != DB_VAR_GET) {
329 db_error("Cannot set to $task variable\n");
330 /* NOTREACHED */
331 }
332 if ((task = db_lookup_task_id(ap->suffix[0])) == TASK_NULL) {
333 db_printf("no such task($task%d)\n", ap->suffix[0]);
334 db_error(0);
335 /* NOTREACHED */
336 }
337 if (ap->level <= 1) {
338 *valuep = (db_expr_t) task;
339 return(0);
340 }
341 if ((thr_act = db_lookup_act_id(task, ap->suffix[1])) == THR_ACT_NULL){
342 db_printf("no such thr_act($task%d.%d)\n",
343 ap->suffix[0], ap->suffix[1]);
344 db_error(0);
345 /* NOTREACHED */
346 }
347 *valuep = (db_expr_t) thr_act;
348 return(0);
349}