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