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