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