1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31 32#include <string.h> 33 34#include <mach/boolean.h> 35#include <mach/machine.h> 36 37#include <vm/vm_map.h> 38 39#include <kern/thread.h> 40#include <kern/processor.h> 41#include <kern/task.h> 42 43#include <ppc/cpu_internal.h> 44#include <ppc/exception.h> 45 46#include <machine/asm.h> 47#include <machine/db_machdep.h> 48#include <machine/setjmp.h> 49 50#include <ddb/db_access.h> 51#include <ddb/db_sym.h> 52#include <ddb/db_variables.h> 53#include <ddb/db_command.h> 54#include <ddb/db_task_thread.h> 55#include <ddb/db_output.h> 56 57extern jmp_buf_t *db_recover; 58 59struct savearea ddb_null_kregs; 60 61extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */ 62 63#define DB_NUMARGS_MAX 5 64 65#define INFIXEDSTACK(va) 0 \ 66 67#define INKERNELSTACK(va, th) 1 68 69struct db_ppc_frame { 70 struct db_ppc_frame *f_frame; 71 int pad1; 72 uint32_t f_retaddr; 73 int pad3; 74 int pad4; 75 int pad5; 76 uint32_t f_arg[DB_NUMARGS_MAX]; 77}; 78 79#define TRAP 1 80#define INTERRUPT 2 81#define SYSCALL 3 82 83db_addr_t db_user_trap_symbol_value = 0; 84db_addr_t db_kernel_trap_symbol_value = 0; 85db_addr_t db_interrupt_symbol_value = 0; 86db_addr_t db_return_to_iret_symbol_value = 0; 87db_addr_t db_syscall_symbol_value = 0; 88boolean_t db_trace_symbols_found = FALSE; 89 90static int db_ppc_reg_value( 91 struct db_variable * vp, 92 db_expr_t * val, 93 int flag, 94 db_var_aux_param_t ap); 95static void db_find_trace_symbols(void); 96static int db_numargs( 97 struct db_ppc_frame *fp, 98 task_t task); 99static boolean_t db_find_arg( 100 struct db_ppc_frame *frame, 101 db_addr_t calleepc, 102 task_t task, 103 int narg, 104 db_addr_t *arg); 105static void db_nextframe( 106 struct db_ppc_frame **lfp, 107 struct db_ppc_frame **fp, 108 db_addr_t *ip, 109 int frame_type, 110 thread_act_t thr_act, 111 db_addr_t linkpc); 112 113/* 114 * Machine register set. 115 */ 116struct db_variable db_regs[] = { 117 /* XXX "pc" is an alias to "srr0"... */ 118 { 119 .name = "pc", 120 .valuep = &ddb_regs.save_srr0, 121 .fcn = db_ppc_reg_value, 122 .min_level = 0, 123 .max_level = 0, 124 .low = 0, 125 .high = 0, 126 .hidden_level = TRUE, 127 }, 128 { 129 .name = "srr0", 130 .valuep = &ddb_regs.save_srr0, 131 .fcn = db_ppc_reg_value, 132 .min_level = 0, 133 .max_level = 0, 134 .low = 0, 135 .high = 0, 136 .hidden_level = TRUE, 137 }, 138 { 139 .name = "srr1", 140 .valuep = &ddb_regs.save_srr1, 141 .fcn = db_ppc_reg_value, 142 .min_level = 0, 143 .max_level = 0, 144 .low = 0, 145 .high = 0, 146 .hidden_level = TRUE, 147 }, 148 { 149 .name = "r0", 150 .valuep = &ddb_regs.save_r0, 151 .fcn = db_ppc_reg_value, 152 .min_level = 0, 153 .max_level = 0, 154 .low = 0, 155 .high = 0, 156 .hidden_level = TRUE, 157 }, 158 { 159 .name = "r1", 160 .valuep = &ddb_regs.save_r1, 161 .fcn = db_ppc_reg_value, 162 .min_level = 0, 163 .max_level = 0, 164 .low = 0, 165 .high = 0, 166 .hidden_level = TRUE, 167 }, 168 { 169 .name = "r2", 170 .valuep = &ddb_regs.save_r2, 171 .fcn = db_ppc_reg_value, 172 .min_level = 0, 173 .max_level = 0, 174 .low = 0, 175 .high = 0, 176 .hidden_level = TRUE, 177 }, 178 { 179 .name = "r3", 180 .valuep = &ddb_regs.save_r3, 181 .fcn = db_ppc_reg_value, 182 .min_level = 0, 183 .max_level = 0, 184 .low = 0, 185 .high = 0, 186 .hidden_level = TRUE, 187 }, 188 { 189 .name = "r4", 190 .valuep = &ddb_regs.save_r4, 191 .fcn = db_ppc_reg_value, 192 .min_level = 0, 193 .max_level = 0, 194 .low = 0, 195 .high = 0, 196 .hidden_level = TRUE, 197 }, 198 { 199 .name = "r5", 200 .valuep = &ddb_regs.save_r5, 201 .fcn = db_ppc_reg_value, 202 .min_level = 0, 203 .max_level = 0, 204 .low = 0, 205 .high = 0, 206 .hidden_level = TRUE, 207 }, 208 { 209 .name = "r6", 210 .valuep = &ddb_regs.save_r6, 211 .fcn = db_ppc_reg_value, 212 .min_level = 0, 213 .max_level = 0, 214 .low = 0, 215 .high = 0, 216 .hidden_level = TRUE, 217 }, 218 { 219 .name = "r7", 220 .valuep = &ddb_regs.save_r7, 221 .fcn = db_ppc_reg_value, 222 .min_level = 0, 223 .max_level = 0, 224 .low = 0, 225 .high = 0, 226 .hidden_level = TRUE, 227 }, 228 { 229 .name = "r8", 230 .valuep = &ddb_regs.save_r8, 231 .fcn = db_ppc_reg_value, 232 .min_level = 0, 233 .max_level = 0, 234 .low = 0, 235 .high = 0, 236 .hidden_level = TRUE, 237 }, 238 { 239 .name = "r9", 240 .valuep = &ddb_regs.save_r9, 241 .fcn = db_ppc_reg_value, 242 .min_level = 0, 243 .max_level = 0, 244 .low = 0, 245 .high = 0, 246 .hidden_level = TRUE, 247 }, 248 { 249 .name = "r10", 250 .valuep = &ddb_regs.save_r10, 251 .fcn = db_ppc_reg_value, 252 .min_level = 0, 253 .max_level = 0, 254 .low = 0, 255 .high = 0, 256 .hidden_level = TRUE, 257 }, 258 { 259 .name = "r11", 260 .valuep = &ddb_regs.save_r11, 261 .fcn = db_ppc_reg_value, 262 .min_level = 0, 263 .max_level = 0, 264 .low = 0, 265 .high = 0, 266 .hidden_level = TRUE, 267 }, 268 { 269 .name = "r12", 270 .valuep = &ddb_regs.save_r12, 271 .fcn = db_ppc_reg_value, 272 .min_level = 0, 273 .max_level = 0, 274 .low = 0, 275 .high = 0, 276 .hidden_level = TRUE, 277 }, 278 { 279 .name = "r13", 280 .valuep = &ddb_regs.save_r13, 281 .fcn = db_ppc_reg_value, 282 .min_level = 0, 283 .max_level = 0, 284 .low = 0, 285 .high = 0, 286 .hidden_level = TRUE, 287 }, 288 { 289 .name = "r14", 290 .valuep = &ddb_regs.save_r14, 291 .fcn = db_ppc_reg_value, 292 .min_level = 0, 293 .max_level = 0, 294 .low = 0, 295 .high = 0, 296 .hidden_level = TRUE, 297 }, 298 { 299 .name = "r15", 300 .valuep = &ddb_regs.save_r15, 301 .fcn = db_ppc_reg_value, 302 .min_level = 0, 303 .max_level = 0, 304 .low = 0, 305 .high = 0, 306 .hidden_level = TRUE, 307 }, 308 { 309 .name = "r16", 310 .valuep = &ddb_regs.save_r16, 311 .fcn = db_ppc_reg_value, 312 .min_level = 0, 313 .max_level = 0, 314 .low = 0, 315 .high = 0, 316 .hidden_level = TRUE, 317 }, 318 { 319 .name = "r17", 320 .valuep = &ddb_regs.save_r17, 321 .fcn = db_ppc_reg_value, 322 .min_level = 0, 323 .max_level = 0, 324 .low = 0, 325 .high = 0, 326 .hidden_level = TRUE, 327 }, 328 { 329 .name = "r18", 330 .valuep = &ddb_regs.save_r18, 331 .fcn = db_ppc_reg_value, 332 .min_level = 0, 333 .max_level = 0, 334 .low = 0, 335 .high = 0, 336 .hidden_level = TRUE, 337 }, 338 { 339 .name = "r19", 340 .valuep = &ddb_regs.save_r19, 341 .fcn = db_ppc_reg_value, 342 .min_level = 0, 343 .max_level = 0, 344 .low = 0, 345 .high = 0, 346 .hidden_level = TRUE, 347 }, 348 { 349 .name = "r20", 350 .valuep = &ddb_regs.save_r20, 351 .fcn = db_ppc_reg_value, 352 .min_level = 0, 353 .max_level = 0, 354 .low = 0, 355 .high = 0, 356 .hidden_level = TRUE, 357 }, 358 { 359 .name = "r21", 360 .valuep = &ddb_regs.save_r21, 361 .fcn = db_ppc_reg_value, 362 .min_level = 0, 363 .max_level = 0, 364 .low = 0, 365 .high = 0, 366 .hidden_level = TRUE, 367 }, 368 { 369 .name = "r22", 370 .valuep = &ddb_regs.save_r22, 371 .fcn = db_ppc_reg_value, 372 .min_level = 0, 373 .max_level = 0, 374 .low = 0, 375 .high = 0, 376 .hidden_level = TRUE, 377 }, 378 { 379 .name = "r23", 380 .valuep = &ddb_regs.save_r23, 381 .fcn = db_ppc_reg_value, 382 .min_level = 0, 383 .max_level = 0, 384 .low = 0, 385 .high = 0, 386 .hidden_level = TRUE, 387 }, 388 { 389 .name = "r24", 390 .valuep = &ddb_regs.save_r24, 391 .fcn = db_ppc_reg_value, 392 .min_level = 0, 393 .max_level = 0, 394 .low = 0, 395 .high = 0, 396 .hidden_level = TRUE, 397 }, 398 { 399 .name = "r25", 400 .valuep = &ddb_regs.save_r25, 401 .fcn = db_ppc_reg_value, 402 .min_level = 0, 403 .max_level = 0, 404 .low = 0, 405 .high = 0, 406 .hidden_level = TRUE, 407 }, 408 { 409 .name = "r26", 410 .valuep = &ddb_regs.save_r26, 411 .fcn = db_ppc_reg_value, 412 .min_level = 0, 413 .max_level = 0, 414 .low = 0, 415 .high = 0, 416 .hidden_level = TRUE, 417 }, 418 { 419 .name = "r27", 420 .valuep = &ddb_regs.save_r27, 421 .fcn = db_ppc_reg_value, 422 .min_level = 0, 423 .max_level = 0, 424 .low = 0, 425 .high = 0, 426 .hidden_level = TRUE, 427 }, 428 { 429 .name = "r28", 430 .valuep = &ddb_regs.save_r28, 431 .fcn = db_ppc_reg_value, 432 .min_level = 0, 433 .max_level = 0, 434 .low = 0, 435 .high = 0, 436 .hidden_level = TRUE, 437 }, 438 { 439 .name = "r29", 440 .valuep = &ddb_regs.save_r29, 441 .fcn = db_ppc_reg_value, 442 .min_level = 0, 443 .max_level = 0, 444 .low = 0, 445 .high = 0, 446 .hidden_level = TRUE, 447 }, 448 { 449 .name = "r30", 450 .valuep = &ddb_regs.save_r30, 451 .fcn = db_ppc_reg_value, 452 .min_level = 0, 453 .max_level = 0, 454 .low = 0, 455 .high = 0, 456 .hidden_level = TRUE, 457 }, 458 { 459 .name = "r31", 460 .valuep = &ddb_regs.save_r31, 461 .fcn = db_ppc_reg_value, 462 .min_level = 0, 463 .max_level = 0, 464 .low = 0, 465 .high = 0, 466 .hidden_level = TRUE, 467 }, 468 { 469 .name = "cr", 470 .valuep = (db_expr_t *)&ddb_regs.save_cr, 471 .fcn = db_ppc_reg_value, 472 .min_level = 0, 473 .max_level = 0, 474 .low = 0, 475 .high = 0, 476 .hidden_level = TRUE, 477 }, 478 { 479 .name = "xer", 480 .valuep = &ddb_regs.save_xer, 481 .fcn = db_ppc_reg_value, 482 .min_level = 0, 483 .max_level = 0, 484 .low = 0, 485 .high = 0, 486 .hidden_level = TRUE, 487 }, 488 { 489 .name = "lr", 490 .valuep = &ddb_regs.save_lr, 491 .fcn = db_ppc_reg_value, 492 .min_level = 0, 493 .max_level = 0, 494 .low = 0, 495 .high = 0, 496 .hidden_level = TRUE, 497 }, 498 { 499 .name = "ctr", 500 .valuep = &ddb_regs.save_ctr, 501 .fcn = db_ppc_reg_value, 502 .min_level = 0, 503 .max_level = 0, 504 .low = 0, 505 .high = 0, 506 .hidden_level = TRUE, 507 }, 508}; 509struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 510 511int 512db_ppc_reg_value( 513 struct db_variable *vp, 514 db_expr_t *valuep, 515 int flag, 516 db_var_aux_param_t ap) 517{ 518 db_expr_t *dp = 0; 519 db_expr_t null_reg = 0; 520 uint32_t *dp32; 521 thread_act_t thr_act = ap->thr_act; 522 unsigned int cpu; 523 524 if (db_option(ap->modif, 'u')) { 525 if (thr_act == THR_ACT_NULL) { 526 if ((thr_act = current_thread()) == THR_ACT_NULL) 527 db_error("no user registers\n"); 528 } 529 if (thr_act == current_thread()) { 530 if (IS_USER_TRAP((&ddb_regs))) dp = vp->valuep; 531 else if (INFIXEDSTACK(ddb_regs.save_r1)) 532 db_error("cannot get/set user registers in nested interrupt\n"); 533 } 534 } 535 else { 536 if (thr_act == THR_ACT_NULL || thr_act == current_thread()) { 537 dp = vp->valuep; 538 } 539 else { 540 if (thr_act->kernel_stack) { 541 for (cpu = 0; cpu < real_ncpus; cpu++) { 542 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && 543 cpu_to_processor(cpu)->active_thread == thr_act && 544 PerProcTable[cpu].ppe_vaddr->db_saved_state) { 545 546 dp = (db_expr_t)(((uint32_t)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) + 547 (((uint32_t) vp->valuep) - 548 (uint32_t) &ddb_regs)); 549 break; 550 } 551 } 552 553 if (dp == 0) 554 dp = &null_reg; 555 } 556 else { 557 /* only PC is valid */ 558 if (vp->valuep == &ddb_regs.save_srr0) 559 dp = (db_expr_t *)&thr_act->continuation; 560 else 561 dp = &null_reg; 562 } 563 } 564 } 565 if (dp == 0) { 566 if (!db_option(ap->modif, 'u')) { 567 for (cpu = 0; cpu < real_ncpus; cpu++) { 568 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && 569 cpu_to_processor(cpu)->active_thread == thr_act && 570 PerProcTable[cpu].ppe_vaddr->db_saved_state) { 571 dp = (int *) (((int)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) + 572 (((int) vp->valuep) - (int) &ddb_regs)); 573 break; 574 } 575 } 576 } 577 if (dp == 0) { 578 if (!thr_act || thr_act->machine.pcb == 0) 579 db_error("no pcb\n"); 580 dp = (int *)((int)thr_act->machine.pcb + ((int)vp->valuep - (int)&ddb_regs)); 581 } 582 } 583 584 if(vp->valuep == (db_expr_t *)&ddb_regs.save_cr) { /* Is this the CR we are doing? */ 585 dp32 = (uint32_t *)dp; /* Make this easier */ 586 if (flag == DB_VAR_SET) 587 *dp32 = *valuep; 588 else 589 *valuep = *dp32; 590 } 591 else { /* Normal 64-bit registers */ 592 if (flag == DB_VAR_SET) 593 *dp = *valuep; 594 else 595 *valuep = *(unsigned long long *)dp; 596 } 597 598 return 0; 599} 600 601 602void 603db_find_trace_symbols(void) 604{ 605 db_expr_t value; 606 boolean_t found_some; 607 608 found_some = FALSE; 609 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) { 610 db_user_trap_symbol_value = (db_addr_t) value; 611 found_some = TRUE; 612 } 613 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) { 614 db_kernel_trap_symbol_value = (db_addr_t) value; 615 found_some = TRUE; 616 } 617 if (db_value_of_name(CC_SYM_PREFIX "ihandler", &value)) { 618 db_interrupt_symbol_value = (db_addr_t) value; 619 found_some = TRUE; 620 } 621#if 0 622 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) { 623 db_return_to_iret_symbol_value = (db_addr_t) value; 624 found_some = TRUE; 625 } 626#endif 627 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) { 628 db_syscall_symbol_value = (db_addr_t) value; 629 found_some = TRUE; 630 } 631 if (found_some) 632 db_trace_symbols_found = TRUE; 633} 634 635int 636db_numargs( 637 struct db_ppc_frame *fp, 638 task_t task) 639{ 640 return DB_NUMARGS_MAX; 641} 642 643boolean_t 644db_find_arg( 645 struct db_ppc_frame *fp, 646 db_addr_t calleepc, 647 task_t task, 648 int narg, 649 db_addr_t *arg) 650{ 651 db_addr_t argp; 652 db_addr_t calleep; 653 db_addr_t offset; 654 int i; 655 int inst; 656 char *name; 657 658#if 0 659 db_find_task_sym_and_offset(calleepc, &name, &offset, task); 660 calleep = calleepc-offset; 661 662 for (i = 0; calleep < calleepc; i++, calleep++) { 663 if (!DB_CHECK_ACCESS((int) calleep, 4, task)) { 664 continue; 665 } 666 inst = db_get_task_value(calleep, 4, FALSE, task); 667 if ((inst & 0xffff0000) == (0x907f0000 + (narg << 21)) || 668 (inst & 0xffff0000) == (0x90610000 + (narg << 21))) { 669 argp = (db_addr_t) &(fp->f_arg[narg]); 670 *arg = argp; 671 return TRUE; 672 } 673 } 674#endif 675 return FALSE; 676} 677 678extern int TRAP_TYPES; 679/* 680 * Figure out the next frame up in the call stack. 681 * For trap(), we print the address of the faulting instruction and 682 * proceed with the calling frame. We return the ip that faulted. 683 * If the trap was caused by jumping through a bogus pointer, then 684 * the next line in the backtrace will list some random function as 685 * being called. It should get the argument list correct, though. 686 * It might be possible to dig out from the next frame up the name 687 * of the function that faulted, but that could get hairy. 688 */ 689void 690db_nextframe( 691 struct db_ppc_frame **lfp, /* in/out */ 692 struct db_ppc_frame **fp, /* in/out */ 693 db_addr_t *ip, /* out */ 694 int frame_type, /* in */ 695 thread_act_t thr_act, 696 db_addr_t linkpc) /* in */ 697{ 698 struct savearea *saved_regs; 699 700 task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL; 701 702 switch(frame_type) { 703 case TRAP: 704 db_printf(">>>>> trap <<<<<\n"); 705 goto miss_frame; 706 break; 707 case INTERRUPT: 708 if (*lfp == 0) { 709 db_printf(">>>>> interrupt <<<<<\n"); 710 goto miss_frame; 711 } 712 db_printf(">>>>> interrupt <<<<<\n"); 713 goto miss_frame; 714 break; 715 case SYSCALL: 716 if (thr_act != THR_ACT_NULL && thr_act->machine.pcb) { 717 *ip = (db_addr_t) thr_act->machine.pcb->save_srr0; 718 *fp = (struct db_ppc_frame *) (thr_act->machine.pcb->save_r1); 719 break; 720 } 721 /* falling down for unknown case */ 722 default: 723miss_frame: 724 if(!pmap_find_phys(kernel_pmap, (addr64_t)*fp)) { /* Check if this is valid */ 725 db_printf("Frame not mapped %08X\n",*fp); /* Say not found */ 726 *fp = 0; /* Show not found */ 727 break; /* Out of here */ 728 } 729 730 if ((*fp)->f_frame) 731 *ip = (db_addr_t) 732 db_get_task_value((int)&(*fp)->f_frame->f_retaddr, 733 4, FALSE, task); 734 else 735 *ip = (db_addr_t) 736 db_get_task_value((int)&(*fp)->f_retaddr, 737 4, FALSE, task); 738 739 *lfp = *fp; 740 *fp = (struct db_ppc_frame *) 741 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task); 742 break; 743 } 744} 745 746void 747db_stack_trace_cmd( 748 db_expr_t addr, 749 boolean_t have_addr, 750 db_expr_t count, 751 char *modif) 752{ 753 struct db_ppc_frame *frame, *lastframe; 754 db_addr_t callpc, linkpc, lastcallpc; 755 int frame_type; 756 boolean_t kernel_only = TRUE; 757 boolean_t trace_thread = FALSE; 758 boolean_t trace_all_threads = FALSE; 759 int thcount = 0; 760 char *filename; 761 int linenum; 762 task_t task; 763 thread_act_t th, top_act; 764 int user_frame; 765 int frame_count; 766 jmp_buf_t *prev; 767 jmp_buf_t db_jmp_buf; 768 queue_entry_t act_list; 769 770 if (!db_trace_symbols_found) 771 db_find_trace_symbols(); 772 { 773 char *cp = modif; 774 char c; 775 776 while ((c = *cp++) != 0) { 777 if (c == 't') 778 trace_thread = TRUE; 779 if (c == 'T') { 780 trace_all_threads = TRUE; 781 trace_thread = TRUE; 782 } 783 if (c == 'u') 784 kernel_only = FALSE; 785 } 786 } 787 788 if (trace_all_threads) { 789 if (!have_addr && !trace_thread) { 790 have_addr = TRUE; 791 trace_thread = TRUE; 792 act_list = &(current_task()->threads); 793 addr = (db_expr_t) queue_first(act_list); 794 } 795 else if (trace_thread) { 796 if (have_addr) { 797 if (!db_check_act_address_valid((thread_act_t)addr)) { 798 if (db_lookup_task((task_t)addr) == -1) 799 return; 800 act_list = &(((task_t)addr)->threads); 801 addr = (db_expr_t) queue_first(act_list); 802 } 803 else { 804 act_list = &(((thread_act_t)addr)->task->threads); 805 thcount = db_lookup_task_act(((thread_act_t)addr)->task, 806 (thread_act_t)addr); 807 } 808 } 809 else { 810 th = db_default_act; 811 if (th == THR_ACT_NULL) 812 th = current_thread(); 813 if (th == THR_ACT_NULL) { 814 db_printf("no active thr_act\n"); 815 return; 816 } 817 have_addr = TRUE; 818 act_list = &th->task->threads; 819 addr = (db_expr_t) queue_first(act_list); 820 } 821 } 822 } 823 824 if (count == -1) 825 count = 65535; 826 827next_thread: 828 top_act = THR_ACT_NULL; 829 830 user_frame = 0; 831 frame_count = count; 832 833 if (!have_addr && !trace_thread) { 834 frame = (struct db_ppc_frame *)(ddb_regs.save_r1); 835 callpc = (db_addr_t)ddb_regs.save_srr0; 836 linkpc = (db_addr_t)ddb_regs.save_lr; 837 th = current_thread(); 838 task = (th != THR_ACT_NULL)? th->task: TASK_NULL; 839 } 840 else if (trace_thread) { 841 if (have_addr) { 842 th = (thread_act_t) addr; 843 if (!db_check_act_address_valid(th)) 844 return; 845 } 846 else { 847 th = db_default_act; 848 if (th == THR_ACT_NULL) 849 th = current_thread(); 850 if (th == THR_ACT_NULL) { 851 db_printf("no active thread\n"); 852 return; 853 } 854 } 855 if (trace_all_threads) 856 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n", 857 addr, thcount, th->task->thread_count); 858 859next_activation: 860 user_frame = 0; 861 862 task = th->task; 863 if (th == current_thread()) { 864 frame = (struct db_ppc_frame *)(ddb_regs.save_r1); 865 callpc = (db_addr_t)ddb_regs.save_srr0; 866 linkpc = (db_addr_t)ddb_regs.save_lr; 867 } 868 else { 869 if (th->machine.pcb == 0) { 870 db_printf("thread has no pcb\n"); 871 goto thread_done; 872 } 873 if (th->kernel_stack == 0) { 874 struct savearea *pss = th->machine.pcb; 875 876 db_printf("Continuation "); 877 db_task_printsym((db_expr_t)th->continuation, 878 DB_STGY_PROC, task); 879 db_printf("\n"); 880 frame = (struct db_ppc_frame *) (pss->save_r1); 881 callpc = (db_addr_t) (pss->save_srr0); 882 linkpc = (db_addr_t) (pss->save_lr); 883 } 884 else { 885 int cpu; 886 887 for (cpu = 0; cpu < real_ncpus; cpu++) { 888 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING && 889 cpu_to_processor(cpu)->active_thread == th && 890 PerProcTable[cpu].ppe_vaddr->db_saved_state) { 891 break; 892 } 893 } 894 if (top_act != THR_ACT_NULL) { 895 /* 896 * Trying to get the backtrace of an activation 897 * which is not the top_most one in the RPC chain: 898 * use the activation's pcb. 899 */ 900 struct savearea *pss; 901 902 pss = th->machine.pcb; 903 frame = (struct db_ppc_frame *) (pss->save_r1); 904 callpc = (db_addr_t) (pss->save_srr0); 905 linkpc = (db_addr_t) (pss->save_lr); 906 } else { 907 if (cpu == real_ncpus) { 908 struct savearea *iks; 909 int r; 910 911 iks = th->machine.pcb; 912 prev = db_recover; 913 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { 914 frame = (struct db_ppc_frame *) (iks->save_r1); 915 callpc = (db_addr_t) (iks->save_lr); 916 linkpc = 0; 917 } else { 918 /* 919 * The kernel stack has probably been 920 * paged out (swapped out activation). 921 */ 922 db_recover = prev; 923 if (r == 2) /* 'q' from db_more() */ 924 db_error(0); 925 db_printf("<kernel stack (0x%x) error " 926 "(probably swapped out)>\n", 927 iks); 928 goto next_act; 929 } 930 db_recover = prev; 931 } else { 932 db_printf(">>>>> active on cpu %d <<<<<\n", 933 cpu); 934 frame = (struct db_ppc_frame *) 935 (PerProcTable[cpu].ppe_vaddr->db_saved_state->save_r1); 936 callpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_srr0; 937 linkpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_lr; 938 } 939 } 940 } 941 } 942 } else { 943 frame = (struct db_ppc_frame *)addr; 944 th = (db_default_act)? db_default_act: current_thread(); 945 task = (th != THR_ACT_NULL)? th->task: TASK_NULL; 946 if (frame->f_frame) { 947 callpc = (db_addr_t)db_get_task_value 948 ((int)&frame->f_frame->f_retaddr, 949 4, FALSE, (user_frame) ? task : 0); 950 callpc = callpc-sizeof(callpc); 951 } else 952 callpc =0; 953 linkpc = 0; 954 } 955 956 if (!INKERNELSTACK((unsigned)frame, th)) { 957 db_printf(">>>>> user space <<<<<\n"); 958 if (kernel_only) 959 goto thread_done; 960 user_frame++; 961 } 962 963 lastframe = 0; 964 lastcallpc = (db_addr_t) 0; 965 while (frame_count-- && frame != 0) { 966 int narg = DB_NUMARGS_MAX; 967 int arg; 968 char * name; 969 db_expr_t offset; 970 db_addr_t call_func = 0; 971 int r; 972 db_addr_t off; 973 974 db_symbol_values(NULL, 975 db_search_task_symbol_and_line( 976 callpc, DB_STGY_XTRN, &offset, &filename, 977 &linenum, (user_frame) ? task : 0, &narg), 978 &name, (db_expr_t *)&call_func); 979 if ( name == NULL) { 980 db_find_task_sym_and_offset(callpc, 981 &name, &off, (user_frame) ? task : 0); 982 offset = (db_expr_t) off; 983 } 984 985 if (user_frame == 0) { 986 if (call_func && 987 (call_func == db_user_trap_symbol_value || 988 call_func == db_kernel_trap_symbol_value)) { 989 frame_type = TRAP; 990 narg = 1; 991 } else if (call_func && 992 call_func == db_interrupt_symbol_value) { 993 frame_type = INTERRUPT; 994 goto next_frame; 995 } else if (call_func && 996 call_func == db_syscall_symbol_value) { 997 frame_type = SYSCALL; 998 goto next_frame; 999 } else { 1000 frame_type = 0; 1001 prev = db_recover; 1002 if ((r = _setjmp(db_recover = &db_jmp_buf)) 1003 == 0) { 1004 if (narg < 0) 1005 narg = db_numargs(frame, 1006 (user_frame) ? task : 0); 1007 db_recover = prev; 1008 } else { 1009 db_recover = prev; 1010 goto next_act; 1011 } 1012 } 1013 } else { 1014 frame_type = 0; 1015 prev = db_recover; 1016 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { 1017 if (narg < 0) 1018 narg = db_numargs(frame, 1019 (user_frame) ? task : 0); 1020 db_recover = prev; 1021 } else { 1022 db_recover = prev; 1023 goto next_act; 1024 } 1025 } 1026 1027 if (name == 0 || offset > db_maxoff) { 1028 db_printf("[%08X]0x%08X(", frame, callpc); 1029 } else { 1030 db_printf("[%08X]%s", frame, name); 1031 if (offset) 1032 db_printf("+%llx", offset); 1033 db_printf("("); 1034 }; 1035 1036 narg = db_numargs(frame, (user_frame) ? task : 0); 1037 1038 for (arg = 0; arg < narg; arg++) { 1039 db_addr_t argp; 1040 int value; 1041 boolean_t found; 1042 1043 prev = db_recover; 1044 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { 1045 found = FALSE; 1046 if (lastframe) 1047 found = db_find_arg(frame, lastframe->f_retaddr, 1048 (user_frame) ? task : 0, arg, &argp); 1049 if (found) 1050 value = db_get_task_value(argp, 4, FALSE, 1051 (user_frame) ? task : 0); 1052 } else { 1053 db_recover = prev; 1054 if (r == 2) /* 'q' from db_more() */ 1055 db_error(0); 1056 db_printf("... <stack error>)"); 1057 db_printf("\n"); 1058 goto next_act; 1059 } 1060 db_recover = prev; 1061 if (found) 1062 db_printf("%08X", value); 1063 else 1064 db_printf("??"); 1065 argp = argp + sizeof(argp); 1066 if (arg < narg-1) 1067 db_printf(","); 1068 } 1069 if (arg != narg) 1070 db_printf("..."); 1071 db_printf(")"); 1072 db_printf("\n"); 1073 1074next_frame: 1075 lastcallpc = callpc; 1076 prev = db_recover; 1077 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { 1078 db_nextframe(&lastframe, &frame, &callpc, frame_type, 1079 (user_frame) ? th : THR_ACT_NULL, linkpc); 1080 callpc = callpc-sizeof(callpc); 1081 db_recover = prev; 1082 } else { 1083 db_recover = prev; 1084 frame = 0; 1085 } 1086 linkpc = 0; 1087 1088 if (frame == 0) { 1089next_act: 1090 /* end of chain */ 1091 break; 1092 } 1093 if (!INKERNELSTACK(lastframe, th) || 1094 !INKERNELSTACK((unsigned)frame, th)) 1095 user_frame++; 1096 if (user_frame == 1) { 1097 db_printf(">>>>> user space <<<<<\n"); 1098 if (kernel_only) 1099 break; 1100 } 1101 1102 if (frame <= lastframe) { 1103 if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th))) 1104 continue; 1105 db_printf("Bad frame pointer: 0x%x\n", frame); 1106 break; 1107 } 1108 } 1109 1110thread_done: 1111 if (trace_all_threads) { 1112 if (top_act != THR_ACT_NULL) 1113 th = top_act; 1114 th = (thread_act_t) queue_next(&th->task_threads); 1115 if (! queue_end(act_list, (queue_entry_t) th)) { 1116 db_printf("\n"); 1117 addr = (db_expr_t) th; 1118 thcount++; 1119 goto next_thread; 1120 } 1121 } 1122} 1123