]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_task_thread.c
xnu-792.6.61.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 * 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
72 task_t db_default_task; /* default target task */
73 thread_t db_default_act; /* default target thr_act */
74
75
76
77 /* Prototypes for functions local to this file.
78 */
79 task_t db_lookup_task_id(register int task_id);
80
81 static thread_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 */
90 int
91 db_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 */
115 int
116 db_lookup_task_act(
117 task_t task,
118 thread_t target_act)
119 {
120 register thread_t thr_act;
121 register int act_id;
122
123 act_id = 0;
124 if (queue_first(&task->threads) == 0)
125 return(-1);
126 queue_iterate(&task->threads, thr_act, thread_t, task_threads) {
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 */
139 int
140 db_lookup_act(thread_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);
155 if (task->thread_count == 0)
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 */
167 int force_act_lookup = 0;
168 boolean_t
169 db_check_act_address_valid(thread_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 */
182 task_t
183 db_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 */
205 static thread_t
206 db_lookup_act_id(
207 task_t task,
208 register int act_id)
209 {
210 register thread_t thr_act;
211
212
213 if (act_id > DB_MAX_THREADID)
214 return(THREAD_NULL);
215 if (queue_first(&task->threads) == 0)
216 return(THREAD_NULL);
217 queue_iterate(&task->threads, thr_act, thread_t, task_threads) {
218 if (act_id-- <= 0)
219 return(thr_act);
220 }
221 return(THREAD_NULL);
222 }
223
224 /*
225 * get next parameter from a command line, and check it as a valid
226 * thread address
227 */
228 boolean_t
229 db_get_next_act(
230 thread_t *actp,
231 int position)
232 {
233 db_expr_t value;
234 thread_t thr_act;
235
236 *actp = THREAD_NULL;
237 if (db_expression(&value)) {
238 thr_act = (thread_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 */
255 void
256 db_init_default_act(void)
257 {
258 if (db_lookup_act(db_default_act) < 0) {
259 db_default_act = THREAD_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 */
269 int
270 db_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_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_t) *valuep;
297 if (thr_act != THREAD_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 */
309 int
310 db_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_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])) == THREAD_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 }