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