]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/db_trace.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / osfmk / i386 / db_trace.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
59#include <string.h>
60
61#include <mach/boolean.h>
62#include <vm/vm_map.h>
63#include <kern/thread.h>
64#include <kern/task.h>
65
66#include <machine/asm.h>
67#include <machine/db_machdep.h>
68#include <machine/setjmp.h>
69#include <mach/machine.h>
0c530ab8
A
70#include <mach/kmod.h>
71
72#include <i386/mp.h>
73#include <i386/pio.h>
74#include <i386/cpuid.h>
75#include <i386/proc_reg.h>
76#include <i386/machine_routines.h>
1c79356b
A
77
78#include <ddb/db_access.h>
79#include <ddb/db_sym.h>
80#include <ddb/db_variables.h>
81#include <ddb/db_command.h>
82#include <ddb/db_task_thread.h>
83#include <ddb/db_output.h>
84
85extern jmp_buf_t *db_recover;
b0d623f7 86struct x86_kernel_state ddb_null_kregs;
0c530ab8 87extern kmod_info_t *kmod;
1c79356b 88
1c79356b
A
89
90/*
91 * Stack trace.
92 */
93
0c530ab8 94#define INKERNELSTACK(va, th) 1
8f6c56a5 95
0c530ab8 96#define DB_NUMARGS_MAX 5
1c79356b
A
97
98struct i386_frame {
99 struct i386_frame *f_frame;
100 int f_retaddr;
101 int f_arg0;
102};
103
104#define TRAP 1
105#define INTERRUPT 2
106#define SYSCALL 3
107
108db_addr_t db_user_trap_symbol_value = 0;
109db_addr_t db_kernel_trap_symbol_value = 0;
110db_addr_t db_interrupt_symbol_value = 0;
111db_addr_t db_return_to_iret_symbol_value = 0;
112db_addr_t db_syscall_symbol_value = 0;
113boolean_t db_trace_symbols_found = FALSE;
114
115struct i386_kregs {
116 char *name;
0c530ab8 117 unsigned int offset;
1c79356b 118} i386_kregs[] = {
b0d623f7
A
119 { "ebx", (unsigned int)(&((struct x86_kernel_state *)0)->k_ebx) },
120 { "esp", (unsigned int)(&((struct x86_kernel_state *)0)->k_esp) },
121 { "ebp", (unsigned int)(&((struct x86_kernel_state *)0)->k_ebp) },
122 { "edi", (unsigned int)(&((struct x86_kernel_state *)0)->k_edi) },
123 { "esi", (unsigned int)(&((struct x86_kernel_state *)0)->k_esi) },
124 { "eip", (unsigned int)(&((struct x86_kernel_state *)0)->k_eip) },
0c530ab8 125 { 0 }
1c79356b
A
126};
127
128/* Forward */
129
0c530ab8 130extern unsigned int * db_lookup_i386_kreg(
1c79356b
A
131 char *name,
132 int *kregp);
133extern int db_i386_reg_value(
134 struct db_variable * vp,
135 db_expr_t * val,
136 int flag,
137 db_var_aux_param_t ap);
138extern void db_find_trace_symbols(void);
139extern int db_numargs(
140 struct i386_frame *fp,
141 task_t task);
142extern void db_nextframe(
143 struct i386_frame **lfp,
144 struct i386_frame **fp,
145 db_addr_t *ip,
146 int frame_type,
91447636 147 thread_t thr_act);
1c79356b
A
148extern int _setjmp(
149 jmp_buf_t * jb);
150
151/*
152 * Machine register set.
153 */
154struct db_variable db_regs[] = {
0c530ab8
A
155 { "cs", (unsigned int *)&ddb_regs.cs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
156 { "ds", (unsigned int *)&ddb_regs.ds, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
157 { "es", (unsigned int *)&ddb_regs.es, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
158 { "fs", (unsigned int *)&ddb_regs.fs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
159 { "gs", (unsigned int *)&ddb_regs.gs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
160 { "ss", (unsigned int *)&ddb_regs.ss, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
161 { "eax",(unsigned int *)&ddb_regs.eax, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
162 { "ecx",(unsigned int *)&ddb_regs.ecx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
163 { "edx",(unsigned int *)&ddb_regs.edx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
164 { "ebx",(unsigned int *)&ddb_regs.ebx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
165 { "esp",(unsigned int *)&ddb_regs.uesp,db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
166 { "ebp",(unsigned int *)&ddb_regs.ebp, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
167 { "esi",(unsigned int *)&ddb_regs.esi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
168 { "edi",(unsigned int *)&ddb_regs.edi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
169 { "eip",(unsigned int *)&ddb_regs.eip, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
170 { "efl",(unsigned int *)&ddb_regs.efl, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }
1c79356b
A
171};
172struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
173
0c530ab8 174unsigned int *
1c79356b
A
175db_lookup_i386_kreg(
176 char *name,
177 int *kregp)
178{
179 register struct i386_kregs *kp;
180
181 for (kp = i386_kregs; kp->name; kp++) {
182 if (strcmp(name, kp->name) == 0)
0c530ab8 183 return((unsigned int *)((int)kregp + kp->offset));
1c79356b
A
184 }
185 return(0);
186}
187
188int
189db_i386_reg_value(
190 struct db_variable *vp,
191 db_expr_t *valuep,
192 int flag,
193 db_var_aux_param_t ap)
194{
195 extern char etext;
0c530ab8 196 unsigned int *dp = 0;
1c79356b 197 db_expr_t null_reg = 0;
91447636 198 register thread_t thr_act = ap->thr_act;
1c79356b
A
199
200 if (db_option(ap->modif, 'u')) {
91447636
A
201 if (thr_act == THREAD_NULL) {
202 if ((thr_act = current_thread()) == THREAD_NULL)
1c79356b
A
203 db_error("no user registers\n");
204 }
91447636 205 if (thr_act == current_thread()) {
1c79356b
A
206 if (IS_USER_TRAP(&ddb_regs, &etext))
207 dp = vp->valuep;
1c79356b
A
208 }
209 } else {
91447636 210 if (thr_act == THREAD_NULL || thr_act == current_thread()) {
1c79356b
A
211 dp = vp->valuep;
212 } else {
0c530ab8
A
213 if (thr_act &&
214 (thr_act->continuation != THREAD_CONTINUE_NULL) &&
215 thr_act->kernel_stack) {
1c79356b
A
216 int cpu;
217
91447636
A
218 for (cpu = 0; cpu < real_ncpus; cpu++) {
219 if (cpu_datap(cpu)->cpu_running == TRUE &&
0c530ab8
A
220 cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) {
221 dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) +
222 (((unsigned int) vp->valuep) -
223 (unsigned int) &ddb_regs));
1c79356b
A
224 break;
225 }
226 }
0c530ab8 227 if (dp == 0 && thr_act)
1c79356b 228 dp = db_lookup_i386_kreg(vp->name,
0c530ab8 229 (unsigned int *)(STACK_IKS(thr_act->kernel_stack)));
1c79356b
A
230 if (dp == 0)
231 dp = &null_reg;
0c530ab8
A
232 } else if (thr_act &&
233 (thr_act->continuation != THREAD_CONTINUE_NULL)) {
234 /* only EIP is valid */
235 if (vp->valuep == (unsigned int *) &ddb_regs.eip) {
236 dp = (unsigned int *)(&thr_act->continuation);
237 } else {
1c79356b
A
238 dp = &null_reg;
239 }
240 }
241 }
242 }
243 if (dp == 0) {
244 int cpu;
245
246 if (!db_option(ap->modif, 'u')) {
91447636
A
247 for (cpu = 0; cpu < real_ncpus; cpu++) {
248 if (cpu_datap(cpu)->cpu_running == TRUE &&
0c530ab8
A
249 cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) {
250 dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) +
251 (((unsigned int) vp->valuep) -
252 (unsigned int) &ddb_regs));
1c79356b
A
253 break;
254 }
255 }
256 }
257 if (dp == 0) {
91447636 258 if (!thr_act || thr_act->machine.pcb == 0)
1c79356b 259 db_error("no pcb\n");
0c530ab8
A
260 dp = (unsigned int *)((unsigned int)(thr_act->machine.pcb->iss) +
261 ((unsigned int)vp->valuep - (unsigned int)&ddb_regs));
1c79356b
A
262 }
263 }
264 if (flag == DB_VAR_SET)
265 *dp = *valuep;
266 else
267 *valuep = *dp;
268 return(0);
269}
270
271void
272db_find_trace_symbols(void)
273{
274 db_expr_t value;
275 boolean_t found_some;
276
277 found_some = FALSE;
278 if (db_value_of_name(CC_SYM_PREFIX "user_trap", &value)) {
279 db_user_trap_symbol_value = (db_addr_t) value;
280 found_some = TRUE;
281 }
282 if (db_value_of_name(CC_SYM_PREFIX "kernel_trap", &value)) {
283 db_kernel_trap_symbol_value = (db_addr_t) value;
284 found_some = TRUE;
285 }
286 if (db_value_of_name(CC_SYM_PREFIX "interrupt", &value)) {
287 db_interrupt_symbol_value = (db_addr_t) value;
288 found_some = TRUE;
289 }
290 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
291 db_return_to_iret_symbol_value = (db_addr_t) value;
292 found_some = TRUE;
293 }
294 if (db_value_of_name(CC_SYM_PREFIX "syscall", &value)) {
295 db_syscall_symbol_value = (db_addr_t) value;
296 found_some = TRUE;
297 }
298 if (found_some)
299 db_trace_symbols_found = TRUE;
300}
301
302/*
303 * Figure out how many arguments were passed into the frame at "fp".
304 */
305int db_numargs_default = 5;
306
307int
308db_numargs(
309 struct i386_frame *fp,
310 task_t task)
311{
312 int *argp;
313 int inst;
314 int args;
315 extern char etext;
316
317 argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
318 if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
319 args = db_numargs_default;
320 else if (!DB_CHECK_ACCESS((int)argp, 4, task))
321 args = db_numargs_default;
322 else {
323 inst = db_get_task_value((int)argp, 4, FALSE, task);
324 if ((inst & 0xff) == 0x59) /* popl %ecx */
325 args = 1;
326 else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
327 args = ((inst >> 16) & 0xff) / 4;
328 else
329 args = db_numargs_default;
330 }
331 return (args);
332}
333
334struct interrupt_frame {
335 struct i386_frame *if_frame; /* point to next frame */
336 int if_retaddr; /* return address to _interrupt */
337 int if_unit; /* unit number */
338 int if_spl; /* saved spl */
339 int if_iretaddr; /* _return_to_{iret,iret_i} */
340 int if_edx; /* old sp(iret) or saved edx(iret_i) */
341 int if_ecx; /* saved ecx(iret_i) */
342 int if_eax; /* saved eax(iret_i) */
343 int if_eip; /* saved eip(iret_i) */
344 int if_cs; /* saved cs(iret_i) */
345 int if_efl; /* saved efl(iret_i) */
346};
347
2d21ac55
A
348extern const char *trap_type[];
349extern int TRAP_TYPES;
350
1c79356b
A
351/*
352 * Figure out the next frame up in the call stack.
353 * For trap(), we print the address of the faulting instruction and
354 * proceed with the calling frame. We return the ip that faulted.
355 * If the trap was caused by jumping through a bogus pointer, then
356 * the next line in the backtrace will list some random function as
357 * being called. It should get the argument list correct, though.
358 * It might be possible to dig out from the next frame up the name
359 * of the function that faulted, but that could get hairy.
360 */
361void
362db_nextframe(
363 struct i386_frame **lfp, /* in/out */
364 struct i386_frame **fp, /* in/out */
365 db_addr_t *ip, /* out */
366 int frame_type, /* in */
91447636 367 thread_t thr_act) /* in */
1c79356b 368{
2d21ac55 369 x86_saved_state32_t *iss32;
1c79356b 370 struct interrupt_frame *ifp;
91447636 371 task_t task = (thr_act != THREAD_NULL)? thr_act->task: TASK_NULL;
1c79356b
A
372
373 switch(frame_type) {
374 case TRAP:
2d21ac55
A
375 /*
376 * We know that trap() has 1 argument and we know that
377 * it is an (strcut x86_saved_state32_t *).
378 */
379 iss32 = (x86_saved_state32_t *)
380 db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
381
382 if (iss32->trapno >= 0 && iss32->trapno < TRAP_TYPES) {
383 db_printf(">>>>> %s trap at ",
384 trap_type[iss32->trapno]);
385 } else {
386 db_printf(">>>>> trap (number %d) at ",
387 iss32->trapno & 0xffff);
388 }
389 db_task_printsym(iss32->eip, DB_STGY_PROC, task);
390 db_printf(" <<<<<\n");
391 *fp = (struct i386_frame *)iss32->ebp;
392 *ip = (db_addr_t)iss32->eip;
393 break;
394
1c79356b 395 case INTERRUPT:
2d21ac55
A
396 if (*lfp == 0) {
397 db_printf(">>>>> interrupt <<<<<\n");
398 goto miss_frame;
399 }
400 db_printf(">>>>> interrupt at ");
401 ifp = (struct interrupt_frame *)(*lfp);
402 *fp = ifp->if_frame;
403 if (ifp->if_iretaddr == db_return_to_iret_symbol_value) {
404 *ip = ((x86_saved_state32_t *)ifp->if_edx)->eip;
405 } else
406 *ip = (db_addr_t)ifp->if_eip;
407 db_task_printsym(*ip, DB_STGY_PROC, task);
408 db_printf(" <<<<<\n");
409 break;
410
1c79356b 411 case SYSCALL:
2d21ac55
A
412 if (thr_act != THREAD_NULL && thr_act->machine.pcb) {
413 iss32 = (x86_saved_state32_t *)thr_act->machine.pcb->iss;
0c530ab8 414
2d21ac55
A
415 *ip = (db_addr_t)(iss32->eip);
416 *fp = (struct i386_frame *)(iss32->ebp);
417 }
418 break;
419
420 default: /* falling down for unknown case */
421miss_frame:
422 *ip = (db_addr_t)
423 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
424 *lfp = *fp;
425 *fp = (struct i386_frame *)
426 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
427 break;
1c79356b
A
428 }
429}
430
431void
432db_stack_trace_cmd(
433 db_expr_t addr,
434 boolean_t have_addr,
435 db_expr_t count,
436 char *modif)
437{
438 struct i386_frame *frame, *lastframe;
0c530ab8 439 x86_saved_state32_t *iss32;
1c79356b
A
440 int *argp;
441 db_addr_t callpc, lastcallpc;
442 int frame_type;
443 boolean_t kernel_only = TRUE;
444 boolean_t trace_thread = FALSE;
445 boolean_t trace_all_threads = FALSE;
446 int thcount = 0;
447 char *filename;
448 int linenum;
449 task_t task;
91447636 450 thread_t th, top_act;
1c79356b
A
451 int user_frame;
452 int frame_count;
453 jmp_buf_t *prev;
454 jmp_buf_t db_jmp_buf;
455 queue_entry_t act_list;
456
457 if (!db_trace_symbols_found)
458 db_find_trace_symbols();
459
460 {
461 register char *cp = modif;
462 register char c;
463
464 while ((c = *cp++) != 0) {
465 if (c == 't')
466 trace_thread = TRUE;
467 if (c == 'T') {
468 trace_all_threads = TRUE;
469 trace_thread = TRUE;
470 }
471 if (c == 'u')
472 kernel_only = FALSE;
473 }
474 }
475
476 if (trace_all_threads) {
477 if (!have_addr && !trace_thread) {
478 have_addr = TRUE;
479 trace_thread = TRUE;
0c530ab8 480 act_list = &(current_task()->threads);
1c79356b
A
481 addr = (db_expr_t) queue_first(act_list);
482 } else if (trace_thread) {
483 if (have_addr) {
91447636 484 if (!db_check_act_address_valid((thread_t)addr)) {
1c79356b
A
485 if (db_lookup_task((task_t)addr) == -1)
486 return;
0c530ab8 487 act_list = &(((task_t)addr)->threads);
1c79356b
A
488 addr = (db_expr_t) queue_first(act_list);
489 } else {
0c530ab8 490 act_list = &(((thread_t)addr)->task->threads);
91447636
A
491 thcount = db_lookup_task_act(((thread_t)addr)->task,
492 (thread_t)addr);
1c79356b
A
493 }
494 } else {
495 th = db_default_act;
91447636
A
496 if (th == THREAD_NULL)
497 th = current_thread();
498 if (th == THREAD_NULL) {
1c79356b
A
499 db_printf("no active thr_act\n");
500 return;
501 }
502 have_addr = TRUE;
0c530ab8 503 act_list = &th->task->threads;
1c79356b
A
504 addr = (db_expr_t) queue_first(act_list);
505 }
506 }
507 }
508
509 if (count == -1)
510 count = 65535;
511
2d21ac55 512next_thread:
91447636 513 top_act = THREAD_NULL;
1c79356b
A
514
515 user_frame = 0;
516 frame_count = count;
517
518 if (!have_addr && !trace_thread) {
519 frame = (struct i386_frame *)ddb_regs.ebp;
520 callpc = (db_addr_t)ddb_regs.eip;
91447636
A
521 th = current_thread();
522 task = (th != THREAD_NULL)? th->task: TASK_NULL;
0c530ab8 523 db_printf("thread 0x%x, current_thread() is 0x%x, ebp is 0x%x, eip is 0x%x\n", th, current_thread(), ddb_regs.ebp, ddb_regs.eip);
1c79356b
A
524 } else if (trace_thread) {
525 if (have_addr) {
91447636 526 th = (thread_t) addr;
0c530ab8
A
527 if (!db_check_act_address_valid(th)) {
528 return;
529 }
1c79356b
A
530 } else {
531 th = db_default_act;
91447636
A
532 if (th == THREAD_NULL)
533 th = current_thread();
534 if (th == THREAD_NULL) {
1c79356b
A
535 db_printf("no active thread\n");
536 return;
537 }
538 }
539 if (trace_all_threads)
540 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
0c530ab8 541 addr, thcount, th->task->thread_count);
1c79356b
A
542
543 next_activation:
544 user_frame = 0;
0c530ab8 545// kprintf("th is %x, current_thread() is %x, ddb_regs.ebp is %x ddb_regs.eip is %x\n", th, current_thread(), ddb_regs.ebp, ddb_regs.eip);
1c79356b 546 task = th->task;
91447636 547 if (th == current_thread()) {
1c79356b
A
548 frame = (struct i386_frame *)ddb_regs.ebp;
549 callpc = (db_addr_t)ddb_regs.eip;
550 } else {
91447636 551 if (th->machine.pcb == 0) {
1c79356b
A
552 db_printf("thread has no pcb\n");
553 return;
554 }
0c530ab8 555 if (!th) {
6601e61a 556 db_printf("thread has no shuttle\n");
0c530ab8 557
1c79356b 558 goto thread_done;
1c79356b 559 }
0c530ab8
A
560 else if ( (th->continuation != THREAD_CONTINUE_NULL) ||
561 th->kernel_stack == 0) {
1c79356b
A
562
563 db_printf("Continuation ");
0c530ab8 564 db_task_printsym((db_expr_t)th->continuation,
1c79356b
A
565 DB_STGY_PROC, task);
566 db_printf("\n");
0c530ab8
A
567
568 iss32 = (x86_saved_state32_t *)th->machine.pcb->iss;
569
2d21ac55
A
570 frame = (struct i386_frame *) (iss32->ebp);
571 callpc = (db_addr_t) (iss32->eip);
0c530ab8 572
1c79356b
A
573 } else {
574 int cpu;
575
91447636
A
576 for (cpu = 0; cpu < real_ncpus; cpu++) {
577 if (cpu_datap(cpu)->cpu_running == TRUE &&
0c530ab8
A
578 cpu_datap(cpu)->cpu_active_thread == th &&
579 cpu_datap(cpu)->cpu_kdb_saved_state) {
1c79356b
A
580 break;
581 }
582 }
91447636 583 if (top_act != THREAD_NULL) {
1c79356b
A
584 /*
585 * Trying to get the backtrace of an activation
586 * which is not the top_most one in the RPC chain:
587 * use the activation's pcb.
588 */
0c530ab8
A
589 iss32 = (x86_saved_state32_t *)th->machine.pcb->iss;
590
2d21ac55
A
591 frame = (struct i386_frame *) (iss32->ebp);
592 callpc = (db_addr_t) (iss32->eip);
1c79356b 593 } else {
0c530ab8 594 if (cpu == real_ncpus) {
b0d623f7 595 register struct x86_kernel_state *iks;
1c79356b
A
596 int r;
597
0c530ab8 598 iks = STACK_IKS(th->kernel_stack);
1c79356b
A
599 prev = db_recover;
600 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
601 frame = (struct i386_frame *) (iks->k_ebp);
602 callpc = (db_addr_t) (iks->k_eip);
603 } else {
604 /*
605 * The kernel stack has probably been
606 * paged out (swapped out activation).
607 */
608 db_recover = prev;
609 if (r == 2) /* 'q' from db_more() */
610 db_error(0);
611 db_printf("<kernel stack (0x%x) error "
612 "(probably swapped out)>\n",
613 iks);
614 goto thread_done;
615 }
616 db_recover = prev;
617 } else {
618 db_printf(">>>>> active on cpu %d <<<<<\n",
619 cpu);
0c530ab8
A
620
621 iss32 = (x86_saved_state32_t *)cpu_datap(cpu)->cpu_kdb_saved_state;
622
2d21ac55
A
623 frame = (struct i386_frame *) (iss32->ebp);
624 callpc = (db_addr_t) (iss32->eip);
625 }
1c79356b
A
626 }
627 }
628 }
1c79356b
A
629 } else {
630 frame = (struct i386_frame *)addr;
91447636
A
631 th = (db_default_act)? db_default_act: current_thread();
632 task = (th != THREAD_NULL)? th->task: TASK_NULL;
1c79356b
A
633 callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr,
634 4,
635 FALSE,
636 (user_frame) ? task : 0);
637 }
638
639 if (!INKERNELSTACK((unsigned)frame, th)) {
640 db_printf(">>>>> user space <<<<<\n");
641 if (kernel_only)
642 goto thread_done;
643 user_frame++;
1c79356b
A
644 }
645
646 lastframe = 0;
647 lastcallpc = (db_addr_t) 0;
648 while (frame_count-- && frame != 0) {
0c530ab8 649 int narg = DB_NUMARGS_MAX;
1c79356b
A
650 char * name;
651 db_expr_t offset;
652 db_addr_t call_func = 0;
653 int r;
0c530ab8
A
654 db_addr_t off;
655
1c79356b
A
656 db_symbol_values(NULL,
657 db_search_task_symbol_and_line(
658 callpc,
659 DB_STGY_XTRN,
660 &offset,
661 &filename,
662 &linenum,
663 (user_frame) ? task : 0,
664 &narg),
665 &name, (db_expr_t *)&call_func);
0c530ab8
A
666 if ( name == NULL) {
667 db_find_task_sym_and_offset(callpc,
668 &name, &off, (user_frame) ? task : 0);
669 offset = (db_expr_t) off;
670 }
671
1c79356b 672 if (user_frame == 0) {
0c530ab8 673 if (call_func && call_func == db_user_trap_symbol_value ||
1c79356b
A
674 call_func == db_kernel_trap_symbol_value) {
675 frame_type = TRAP;
676 narg = 1;
0c530ab8
A
677 } else if (call_func &&
678 call_func == db_interrupt_symbol_value) {
1c79356b
A
679 frame_type = INTERRUPT;
680 goto next_frame;
0c530ab8 681 } else if (call_func && call_func == db_syscall_symbol_value) {
1c79356b
A
682 frame_type = SYSCALL;
683 goto next_frame;
684 } else {
685 frame_type = 0;
686 prev = db_recover;
687 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
688 if (narg < 0)
689 narg = db_numargs(frame,
690 (user_frame) ? task : 0);
691 db_recover = prev;
692 } else {
693 db_recover = prev;
694 goto thread_done;
695 }
696 }
697 } else {
698 frame_type = 0;
699 prev = db_recover;
700 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
701 if (narg < 0)
702 narg = db_numargs(frame,
703 (user_frame) ? task : 0);
704 db_recover = prev;
705 } else {
706 db_recover = prev;
707 goto thread_done;
708 }
709 }
710
711 if (name == 0 || offset > db_maxoff) {
712 db_printf("0x%x 0x%x(", frame, callpc);
713 offset = 0;
714 } else
715 db_printf("0x%x %s(", frame, name);
716
717 argp = &frame->f_arg0;
718 while (narg > 0) {
719 int value;
720
721 prev = db_recover;
722 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
723 value = db_get_task_value((int)argp,
724 4,
725 FALSE,
726 (user_frame) ? task : 0);
727 } else {
728 db_recover = prev;
729 if (r == 2) /* 'q' from db_more() */
730 db_error(0);
731 db_printf("... <stack error>)");
732 if (offset)
733 db_printf("+%x", offset);
734 if (filename) {
735 db_printf(" [%s", filename);
736 if (linenum > 0)
737 db_printf(":%d", linenum);
738 db_printf("]");
739 }
740 db_printf("\n");
741 goto thread_done;
742 }
743 db_recover = prev;
744 db_printf("%x", value);
745 argp++;
746 if (--narg != 0)
747 db_printf(",");
748 }
749 if (narg < 0)
750 db_printf("...");
751 db_printf(")");
752 if (offset) {
753 db_printf("+%x", offset);
754 }
755 if (filename) {
756 db_printf(" [%s", filename);
757 if (linenum > 0)
758 db_printf(":%d", linenum);
759 db_printf("]");
760 }
761 db_printf("\n");
762
2d21ac55 763next_frame:
1c79356b
A
764 lastcallpc = callpc;
765 db_nextframe(&lastframe, &frame, &callpc, frame_type,
91447636 766 (user_frame) ? th : THREAD_NULL);
1c79356b
A
767
768 if (frame == 0) {
0c530ab8 769 if (th->task_threads.prev != THREAD_NULL) {
91447636 770 if (top_act == THREAD_NULL)
1c79356b 771 top_act = th;
0c530ab8 772 th = th->task_threads.prev;
1c79356b
A
773 db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
774 th,
775 db_lookup_task(th->task),
776 db_lookup_task_act(th->task, th));
777 goto next_activation;
778 }
779 /* end of chain */
780 break;
781 }
782 if (!INKERNELSTACK(lastframe, th) ||
783 !INKERNELSTACK((unsigned)frame, th))
784 user_frame++;
785 if (user_frame == 1) {
786 db_printf(">>>>> user space <<<<<\n");
787 if (kernel_only)
788 break;
1c79356b
A
789 }
790 if (frame <= lastframe) {
791 if ((INKERNELSTACK(lastframe, th) &&
0c530ab8 792 !INKERNELSTACK(frame, th)))
1c79356b
A
793 continue;
794 db_printf("Bad frame pointer: 0x%x\n", frame);
795 break;
796 }
797 }
798
2d21ac55 799thread_done:
1c79356b 800 if (trace_all_threads) {
91447636 801 if (top_act != THREAD_NULL)
1c79356b 802 th = top_act;
0c530ab8 803 th = (thread_t) queue_next(&th->task_threads);
1c79356b
A
804 if (! queue_end(act_list, (queue_entry_t) th)) {
805 db_printf("\n");
806 addr = (db_expr_t) th;
807 thcount++;
808 goto next_thread;
809
810 }
811 }
812}
0c530ab8 813
b0d623f7 814extern mach_vm_size_t kdp_machine_vm_read(mach_vm_address_t, caddr_t, mach_vm_size_t);
0c530ab8
A
815extern boolean_t kdp_trans_off;
816/*
817 * Print out 256 bytes of real storage
818 *
819 * dr [entaddr]
820 */
2d21ac55
A
821void
822db_display_real(db_expr_t addr, boolean_t have_addr, db_expr_t count,
823 char *modif)
824{
0c530ab8
A
825 int i;
826 unsigned int xbuf[8];
827 unsigned read_result = 0;
828/* Print 256 bytes */
829 for(i=0; i<8; i++) {
830
2d21ac55 831/*
b0d623f7 832 * Do a physical read using kdp_machine_vm_read(), rather than replicating the same
0c530ab8
A
833 * facility
834 */
835 kdp_trans_off = 1;
b0d623f7 836 read_result = kdp_machine_vm_read(addr, &xbuf[0], 32);
0c530ab8
A
837 kdp_trans_off = 0;
838
839 if (read_result != 32)
840 db_printf("Unable to read address\n");
841 else
842 db_printf("%016llX %08X %08X %08X %08X %08X %08X %08X %08X\n", addr, /* Print a line */
843 xbuf[0], xbuf[1], xbuf[2], xbuf[3],
844 xbuf[4], xbuf[5], xbuf[6], xbuf[7]);
845 addr = addr + 0x00000020; /* Point to next address */
846 }
847 db_next = addr;
848}
849
850/*
851 * Displays all of the kmods in the system.
852 *
2d21ac55 853 * dk
0c530ab8
A
854 */
855void
2d21ac55
A
856db_display_kmod(__unused db_expr_t addr, __unused boolean_t have_addr,
857 __unused db_expr_t count, __unused char *modif)
0c530ab8
A
858{
859
860 kmod_info_t *kmd;
861 unsigned int strt, end;
862
863 kmd = kmod; /* Start at the start */
864
865 db_printf("info addr start - end name ver\n");
866
867 while (kmd) { /* Dump 'em all */
868 strt = (unsigned int) kmd->address + kmd->hdr_size;
869 end = (unsigned int) kmd->address + kmd->size;
870 db_printf("%08X %08X %08X - %08X: %s, %s\n",
871 kmd, kmd->address, strt, end, kmd->name, kmd->version);
872 kmd = kmd->next;
873 }
2d21ac55 874}
0c530ab8 875
2d21ac55
A
876void
877db_display_iokit(__unused db_expr_t addr, __unused boolean_t have_addr,
878 __unused db_expr_t count, __unused char *modif)
879{
0c530ab8 880}