]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_task_thread.c
765382c97a4b8d37bf47054b25c177c2143ceedd
[apple/xnu.git] / osfmk / ddb / db_task_thread.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28 /*
29 * HISTORY
30 *
31 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
32 * Import of Mac OS X kernel (~semeria)
33 *
34 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
35 * Import of OSF Mach kernel (~mburg)
36 *
37 * Revision 1.1.16.3 1996/01/09 19:16:26 devrcs
38 * Make db_lookup_task_id() globally available (remove static).
39 * Changed declarations of 'register foo' to 'register int foo'.
40 * [1995/12/01 21:42:37 jfraser]
41 *
42 * Merged '64-bit safe' changes from DEC alpha port.
43 * [1995/11/21 18:03:48 jfraser]
44 *
45 * Revision 1.1.16.2 1994/09/23 01:21:59 ezf
46 * change marker to not FREE
47 * [1994/09/22 21:11:09 ezf]
48 *
49 * Revision 1.1.16.1 1994/06/11 21:12:29 bolinger
50 * Merge up to NMK17.2.
51 * [1994/06/11 20:02:43 bolinger]
52 *
53 * Revision 1.1.14.1 1994/02/08 10:59:02 bernadat
54 * Added support of DB_VAR_SHOW.
55 * [93/08/12 paire]
56 * [94/02/08 bernadat]
57 *
58 * Revision 1.1.12.3 1994/03/17 22:35:35 dwm
59 * The infamous name change: thread_activation + thread_shuttle = thread.
60 * [1994/03/17 21:25:50 dwm]
61 *
62 * Revision 1.1.12.2 1994/01/17 18:08:54 dwm
63 * Add patchable integer force_act_lookup to force successful
64 * lookup, to allow stack trace on orphaned act/thread pairs.
65 * [1994/01/17 16:06:50 dwm]
66 *
67 * Revision 1.1.12.1 1994/01/12 17:50:52 dwm
68 * Coloc: initial restructuring to follow Utah model.
69 * [1994/01/12 17:13:23 dwm]
70 *
71 * Revision 1.1.3.3 1993/07/27 18:28:15 elliston
72 * Add ANSI prototypes. CR #9523.
73 * [1993/07/27 18:13:06 elliston]
74 *
75 * Revision 1.1.3.2 1993/06/02 23:12:39 jeffc
76 * Added to OSF/1 R1.3 from NMK15.0.
77 * [1993/06/02 20:57:24 jeffc]
78 *
79 * Revision 1.1 1992/09/30 02:01:27 robert
80 * Initial revision
81 *
82 * $EndLog$
83 */
84 /* CMU_HIST */
85 /*
86 * Revision 2.2 91/10/09 16:03:04 af
87 * Revision 2.1.3.1 91/10/05 13:07:50 jeffreyh
88 * Created for task/thread handling.
89 * [91/08/29 tak]
90 *
91 * Revision 2.1.3.1 91/10/05 13:07:50 jeffreyh
92 * Created for task/thread handling.
93 * [91/08/29 tak]
94 *
95 */
96 /* CMU_ENDHIST */
97 /*
98 * Mach Operating System
99 * Copyright (c) 1991,1990 Carnegie Mellon University
100 * All Rights Reserved.
101 *
102 * Permission to use, copy, modify and distribute this software and its
103 * documentation is hereby granted, provided that both the copyright
104 * notice and this permission notice appear in all copies of the
105 * software, derivative works or modified versions, and any portions
106 * thereof, and that both notices appear in supporting documentation.
107 *
108 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
109 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
110 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
111 *
112 * Carnegie Mellon requests users of this software to return to
113 *
114 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
115 * School of Computer Science
116 * Carnegie Mellon University
117 * Pittsburgh PA 15213-3890
118 *
119 * any improvements or extensions that they make and grant Carnegie Mellon
120 * the rights to redistribute these changes.
121 */
122 /*
123 */
124
125 #include <kern/kern_types.h>
126 #include <kern/processor.h>
127 #include <machine/db_machdep.h>
128 #include <ddb/db_task_thread.h>
129 #include <ddb/db_variables.h>
130 #include <ddb/db_command.h>
131 #include <ddb/db_expr.h>
132 #include <ddb/db_lex.h>
133 #include <ddb/db_output.h> /* For db_printf() */
134 #include <ddb/db_sym.h>
135
136 /*
137 * Following constants are used to prevent infinite loop of task
138 * or thread search due to the incorrect list.
139 */
140 #define DB_MAX_TASKID 0x10000 /* max # of tasks */
141 #define DB_MAX_THREADID 0x10000 /* max # of threads in a task */
142 #define DB_MAX_PSETS 0x10000 /* max # of processor sets */
143
144 task_t db_default_task; /* default target task */
145 thread_act_t db_default_act; /* default target thr_act */
146
147
148
149 /* Prototypes for functions local to this file.
150 */
151 task_t db_lookup_task_id(register int task_id);
152
153 static thread_act_t db_lookup_act_id(
154 task_t task,
155 register int thread_id);
156
157
158
159 /*
160 * search valid task queue, and return the queue position as the task id
161 */
162 int
163 db_lookup_task(task_t target_task)
164 {
165 register task_t task;
166 register int task_id;
167 register processor_set_t pset = &default_pset;
168 register int npset = 0;
169
170 task_id = 0;
171 if (npset++ >= DB_MAX_PSETS)
172 return(-1);
173 if (queue_first(&pset->tasks) == 0)
174 return(-1);
175 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
176 if (target_task == task)
177 return(task_id);
178 if (task_id++ >= DB_MAX_TASKID)
179 return(-1);
180 }
181 return(-1);
182 }
183
184 /*
185 * search thread queue of the task, and return the queue position
186 */
187 int
188 db_lookup_task_act(
189 task_t task,
190 thread_act_t target_act)
191 {
192 register thread_act_t thr_act;
193 register int act_id;
194
195 act_id = 0;
196 if (queue_first(&task->thr_acts) == 0)
197 return(-1);
198 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
199 if (target_act == thr_act)
200 return(act_id);
201 if (act_id++ >= DB_MAX_THREADID)
202 return(-1);
203 }
204 return(-1);
205 }
206
207 /*
208 * search thr_act queue of every valid task, and return the queue position
209 * as the thread id.
210 */
211 int
212 db_lookup_act(thread_act_t target_act)
213 {
214 register int act_id;
215 register task_t task;
216 register processor_set_t pset = &default_pset;
217 register int ntask = 0;
218 register int npset = 0;
219
220 if (npset++ >= DB_MAX_PSETS)
221 return(-1);
222 if (queue_first(&pset->tasks) == 0)
223 return(-1);
224 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
225 if (ntask++ > DB_MAX_TASKID)
226 return(-1);
227 if (task->thr_act_count == 0)
228 continue;
229 act_id = db_lookup_task_act(task, target_act);
230 if (act_id >= 0)
231 return(act_id);
232 }
233 return(-1);
234 }
235
236 /*
237 * check the address is a valid thread address
238 */
239 int force_act_lookup = 0;
240 boolean_t
241 db_check_act_address_valid(thread_act_t thr_act)
242 {
243 if (!force_act_lookup && db_lookup_act(thr_act) < 0) {
244 db_printf("Bad thr_act address 0x%x\n", thr_act);
245 db_flush_lex();
246 return(FALSE);
247 } else
248 return(TRUE);
249 }
250
251 /*
252 * convert task_id(queue postion) to task address
253 */
254 task_t
255 db_lookup_task_id(register task_id)
256 {
257 register task_t task;
258 register processor_set_t pset = &default_pset;
259 register int npset = 0;
260
261 if (task_id > DB_MAX_TASKID)
262 return(TASK_NULL);
263 if (npset++ >= DB_MAX_PSETS)
264 return(TASK_NULL);
265 if (queue_first(&pset->tasks) == 0)
266 return(TASK_NULL);
267 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
268 if (task_id-- <= 0)
269 return(task);
270 }
271 return(TASK_NULL);
272 }
273
274 /*
275 * convert (task_id, act_id) pair to thr_act address
276 */
277 static thread_act_t
278 db_lookup_act_id(
279 task_t task,
280 register int act_id)
281 {
282 register thread_act_t thr_act;
283
284
285 if (act_id > DB_MAX_THREADID)
286 return(THR_ACT_NULL);
287 if (queue_first(&task->thr_acts) == 0)
288 return(THR_ACT_NULL);
289 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
290 if (act_id-- <= 0)
291 return(thr_act);
292 }
293 return(THR_ACT_NULL);
294 }
295
296 /*
297 * get next parameter from a command line, and check it as a valid
298 * thread address
299 */
300 boolean_t
301 db_get_next_act(
302 thread_act_t *actp,
303 int position)
304 {
305 db_expr_t value;
306 thread_act_t thr_act;
307
308 *actp = THR_ACT_NULL;
309 if (db_expression(&value)) {
310 thr_act = (thread_act_t) value;
311 if (!db_check_act_address_valid(thr_act)) {
312 db_flush_lex();
313 return(FALSE);
314 }
315 } else if (position <= 0) {
316 thr_act = db_default_act;
317 } else
318 return(FALSE);
319 *actp = thr_act;
320 return(TRUE);
321 }
322
323 /*
324 * check the default thread is still valid
325 * ( it is called in entering DDB session )
326 */
327 void
328 db_init_default_act(void)
329 {
330 if (db_lookup_act(db_default_act) < 0) {
331 db_default_act = THR_ACT_NULL;
332 db_default_task = TASK_NULL;
333 } else
334 db_default_task = db_default_act->task;
335 }
336
337 /*
338 * set or get default thread which is used when /t or :t option is specified
339 * in the command line
340 */
341 int
342 db_set_default_act(
343 struct db_variable *vp,
344 db_expr_t *valuep,
345 int flag,
346 db_var_aux_param_t ap) /* unused */
347 {
348 thread_act_t thr_act;
349 int task_id;
350 int act_id;
351
352 if (flag == DB_VAR_SHOW) {
353 db_printf("%#n", db_default_act);
354 task_id = db_lookup_task(db_default_task);
355 if (task_id != -1) {
356 act_id = db_lookup_act(db_default_act);
357 if (act_id != -1) {
358 db_printf(" (task%d.%d)", task_id, act_id);
359 }
360 }
361 return(0);
362 }
363
364 if (flag != DB_VAR_SET) {
365 *valuep = (db_expr_t) db_default_act;
366 return(0);
367 }
368 thr_act = (thread_act_t) *valuep;
369 if (thr_act != THR_ACT_NULL && !db_check_act_address_valid(thr_act))
370 db_error(0);
371 /* NOTREACHED */
372 db_default_act = thr_act;
373 if (thr_act)
374 db_default_task = thr_act->task;
375 return(0);
376 }
377
378 /*
379 * convert $taskXXX[.YYY] type DDB variable to task or thread address
380 */
381 int
382 db_get_task_act(
383 struct db_variable *vp,
384 db_expr_t *valuep,
385 int flag,
386 db_var_aux_param_t ap)
387 {
388 task_t task;
389 thread_act_t thr_act;
390 int task_id;
391
392 if (flag == DB_VAR_SHOW) {
393 db_printf("%#n", db_default_task);
394 task_id = db_lookup_task(db_default_task);
395 if (task_id != -1)
396 db_printf(" (task%d)", task_id);
397 return(0);
398 }
399
400 if (flag != DB_VAR_GET) {
401 db_error("Cannot set to $task variable\n");
402 /* NOTREACHED */
403 }
404 if ((task = db_lookup_task_id(ap->suffix[0])) == TASK_NULL) {
405 db_printf("no such task($task%d)\n", ap->suffix[0]);
406 db_error(0);
407 /* NOTREACHED */
408 }
409 if (ap->level <= 1) {
410 *valuep = (db_expr_t) task;
411 return(0);
412 }
413 if ((thr_act = db_lookup_act_id(task, ap->suffix[1])) == THR_ACT_NULL){
414 db_printf("no such thr_act($task%d.%d)\n",
415 ap->suffix[0], ap->suffix[1]);
416 db_error(0);
417 /* NOTREACHED */
418 }
419 *valuep = (db_expr_t) thr_act;
420 return(0);
421 }