1/* $NetBSD: stackframe.c,v 1.3 2007/02/28 04:21:51 thorpej Exp $ */ 2 3/* Contributed to the NetBSD foundation by Cherry G. Mathew <cherry@mahiti.org> 4 * This file contains routines to use decoded unwind descriptor entries 5 * to build a stack configuration. The unwinder consults the stack 6 * configuration to fetch registers used to unwind the frame. 7 * References: 8 * [1] section. 11.4.2.6., Itanium Software Conventions and 9 * Runtime Architecture Guide. 10 */ 11 12#include <sys/cdefs.h> 13#include <sys/param.h> 14#include <sys/systm.h> 15 16 17#include <ia64/unwind/decode.h> 18#include <ia64/unwind/stackframe.h> 19 20//#define UNWIND_DIAGNOSTIC 21 22/* Global variables: 23 array of struct recordchain 24 size of record chain array. 25*/ 26struct recordchain strc[MAXSTATERECS]; 27int rec_cnt = 0; 28 29/* Build a recordchain of a region, given the pointer to unwind table 30 * entry, and the number of entries to decode. 31 */ 32 33void buildrecordchain(uint64_t unwind_infop, struct recordchain *xxx) 34{ 35 36 37 uint64_t unwindstart, unwindend; 38 uint64_t unwindlen; 39 uint64_t region_len = 0; 40 bool region_type = false; /* Prologue */ 41 42 struct unwind_hdr_t { 43 uint64_t uwh; 44 } *uwhp = (void *) unwind_infop; 45 46 char *nextrecp, *recptr = (char *) unwind_infop + sizeof(uint64_t); 47 48 unwindstart = (uint64_t) recptr; 49 50 if (UNW_VER(uwhp->uwh) != 1) { 51 printf("Wrong unwind version! \n"); 52 return; 53 } 54 55 unwindlen = UNW_LENGTH(uwhp->uwh) * sizeof(uint64_t); 56 unwindend = unwindstart + unwindlen; 57 58#ifdef UNWIND_DIAGNOSTIC 59 printf("recptr = %p \n", recptr); 60 printf("unwindlen = %lx \n", unwindlen); 61 printf("unwindend = %lx \n", unwindend); 62#endif 63 64 /* XXX: Ignore zero length records. */ 65 66 67 for(rec_cnt = 0; rec_cnt < MAXSTATERECS && (uint64_t)recptr < unwindend; 68 rec_cnt++) { 69 if ((nextrecp = unwind_decode_R1(recptr, &strc[rec_cnt].udesc))){ 70 region_len = strc[rec_cnt].udesc.R1.rlen; 71 region_type = strc[rec_cnt].udesc.R1.r; 72 strc[rec_cnt].type = R1; 73 recptr = nextrecp; 74 continue; 75 } 76 77 if ((nextrecp = unwind_decode_R2(recptr, &strc[rec_cnt].udesc))){ 78 region_len = strc[rec_cnt].udesc.R2.rlen; 79 region_type = false; /* R2 regions are prologue regions */ 80 strc[rec_cnt].type = R2; 81 recptr = nextrecp; 82 continue; 83 } 84 85 if ((nextrecp = unwind_decode_R3(recptr, &strc[rec_cnt].udesc))){ 86 region_len = strc[rec_cnt].udesc.R3.rlen; 87 region_type = strc[rec_cnt].udesc.R3.r; 88 strc[rec_cnt].type = R3; 89 recptr = nextrecp; 90 continue; 91 } 92 93 if(region_type == false) { /* Prologue Region */ 94 if ((nextrecp = unwind_decode_P1(recptr, &strc[rec_cnt].udesc))){ 95 strc[rec_cnt].type = P1; 96 recptr = nextrecp; 97 continue; 98 } 99 100 if ((nextrecp = unwind_decode_P2(recptr, &strc[rec_cnt].udesc))){ 101 strc[rec_cnt].type = P2; 102 recptr = nextrecp; 103 continue; 104 } 105 106 if ((nextrecp = unwind_decode_P3(recptr, &strc[rec_cnt].udesc))){ 107 strc[rec_cnt].type = P3; 108 recptr = nextrecp; 109 continue; 110 } 111 112 113 if ((nextrecp = unwind_decode_P4(recptr, &strc[rec_cnt].udesc, region_len))){ 114 strc[rec_cnt].type = P4; 115 recptr = nextrecp; 116 break; 117 } 118 119 120 if ((nextrecp = unwind_decode_P5(recptr, &strc[rec_cnt].udesc))){ 121 strc[rec_cnt].type = P5; 122 recptr = nextrecp; 123 continue; 124 } 125 126 if ((nextrecp = unwind_decode_P6(recptr, &strc[rec_cnt].udesc))){ 127 strc[rec_cnt].type = P6; 128 recptr = nextrecp; 129 continue; 130 } 131 132 if ((nextrecp = unwind_decode_P7(recptr, &strc[rec_cnt].udesc))){ 133 strc[rec_cnt].type = P7; 134 recptr = nextrecp; 135 continue; 136 } 137 138 if ((nextrecp = unwind_decode_P8(recptr, &strc[rec_cnt].udesc))){ 139 strc[rec_cnt].type = P8; 140 recptr = nextrecp; 141 continue; 142 } 143 144 if ((nextrecp = unwind_decode_P9(recptr, &strc[rec_cnt].udesc))){ 145 strc[rec_cnt].type = P9; 146 recptr = nextrecp; 147 continue; 148 } 149 150 if ((nextrecp = unwind_decode_P10(recptr, &strc[rec_cnt].udesc))){ 151 strc[rec_cnt].type = P10; 152 recptr = nextrecp; 153 continue; 154 } 155 156 printf("Skipping prologue desc slot :: %d \n", rec_cnt); 157 } 158 159 else { 160 161 if ((nextrecp = unwind_decode_B1(recptr, &strc[rec_cnt].udesc))){ 162 strc[rec_cnt].type = B1; 163 recptr = nextrecp; 164 continue; 165 } 166 167 if ((nextrecp = unwind_decode_B2(recptr, &strc[rec_cnt].udesc))){ 168 strc[rec_cnt].type = B2; 169 recptr = nextrecp; 170 continue; 171 } 172 173 if ((nextrecp = unwind_decode_B3(recptr, &strc[rec_cnt].udesc))){ 174 strc[rec_cnt].type = B3; 175 recptr = nextrecp; 176 continue; 177 } 178 179 if ((nextrecp = unwind_decode_B4(recptr, &strc[rec_cnt].udesc))){ 180 strc[rec_cnt].type = B4; 181 recptr = nextrecp; 182 continue; 183 } 184 185 if ((nextrecp = unwind_decode_X1(recptr, &strc[rec_cnt].udesc))){ 186 strc[rec_cnt].type = X1; 187 recptr = nextrecp; 188 continue; 189 } 190 191 if ((nextrecp = unwind_decode_X2(recptr, &strc[rec_cnt].udesc))){ 192 strc[rec_cnt].type = X2; 193 recptr = nextrecp; 194 continue; 195 } 196 197 198 if ((nextrecp = unwind_decode_X3(recptr, &strc[rec_cnt].udesc))){ 199 strc[rec_cnt].type = X3; 200 recptr = nextrecp; 201 continue; 202 } 203 204 if ((nextrecp = unwind_decode_X4(recptr, &strc[rec_cnt].udesc))){ 205 strc[rec_cnt].type = X4; 206 recptr = nextrecp; 207 continue; 208 } 209 210 printf("Skipping body desc slot :: %d \n", rec_cnt); 211 212 213 } 214 } 215 216#ifdef UNWIND_DIAGNOSTIC 217 int i; 218 for(i = 0;i < rec_cnt;i++) { 219 dump_recordchain(&strc[i]); 220 } 221 222#endif /* UNWIND_DIAGNOSTIC */ 223 224} 225 226 227 228 229/* Debug support: dump a record chain entry */ 230void dump_recordchain(struct recordchain *rchain) 231{ 232 233 switch(rchain->type) { 234 case R1: 235 236 237 printf("\t R1:"); 238 if(rchain->udesc.R1.r) 239 printf("body ("); 240 else 241 printf("prologue ("); 242 printf("rlen = %ld) \n", rchain->udesc.R1.rlen); 243 break; 244 245 case R2: 246 printf("\t R2:"); 247 printf("prologue_gr ("); 248 printf("mask = %x, ", rchain->udesc.R2.mask); 249 printf("grsave = %d, ", rchain->udesc.R2.grsave); 250 printf("rlen = %ld )\n", rchain->udesc.R2.rlen); 251 break; 252 253 case R3: 254 printf("\t R3:"); 255 if(rchain->udesc.R3.r) 256 printf("body ("); 257 else 258 printf("prologue ("); 259 printf("rlen = %ld )\n", rchain->udesc.R3.rlen); 260 break; 261 262 case P1: 263 printf("\t\tP1:"); 264 printf("br_mem (brmask = %x) \n", rchain->udesc.P1.brmask); 265 break; 266 267 case P2: 268 printf("\t\tP2:"); 269 printf("br_gr(brmask = %x, ", rchain->udesc.P2.brmask); 270 printf("gr = %d ) \n", rchain->udesc.P2.gr); 271 break; 272 273 case P3: 274 printf("\t\tP3:"); 275 switch(rchain->udesc.P3.r) { 276 case 0: 277 printf("psp_gr"); 278 break; 279 case 1: 280 printf("rp_gr"); 281 break; 282 case 2: 283 printf("pfs_gr"); 284 break; 285 case 3: 286 printf("preds_gr"); 287 break; 288 case 4: 289 printf("unat_gr"); 290 break; 291 case 5: 292 printf("lc_gr"); 293 break; 294 case 6: 295 printf("rp_br"); 296 break; 297 case 7: 298 printf("rnat_gr"); 299 break; 300 case 8: 301 printf("bsp_gr"); 302 break; 303 case 9: 304 printf("bspstore_gr"); 305 break; 306 case 10: 307 printf("fpsr_gr"); 308 break; 309 case 11: 310 printf("priunat_gr"); 311 break; 312 default: 313 printf("unknown desc: %d", rchain->udesc.P3.r); 314 315 } 316 printf("(gr/br = %d) \n", rchain->udesc.P3.grbr); 317 318 break; 319 320 case P4: 321 printf("P4: (unimplemented): \n"); 322 break; 323 324 case P5: 325 printf("\t\tP5:"); 326 printf("frgr_mem(grmask = %x, frmask = %x )\n", 327 rchain->udesc.P5.grmask, rchain->udesc.P5.frmask); 328 break; 329 330 case P6: 331 printf("\t\tP6: "); 332 if(rchain->udesc.P6.r) 333 printf("gr_mem( "); 334 else 335 printf("fr_mem( "); 336 printf("rmask = %x) \n", rchain->udesc.P6.rmask); 337 break; 338 339 case P7: 340 printf("\t\tP7:"); 341 switch(rchain->udesc.P7.r) { 342 case 0: 343 printf("memstack_f( "); 344 printf("t = %ld, ", rchain->udesc.P7.t); 345 printf("size = %ld) \n", rchain->udesc.P7.size); 346 break; 347 case 1: 348 printf("memstack_v( "); 349 printf("t = %ld) \n", rchain->udesc.P7.t); 350 break; 351 case 2: 352 printf("spillbase( "); 353 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 354 break; 355 case 3: 356 printf("psp_sprel( "); 357 printf("spoff = %ld) \n", rchain->udesc.P7.t); 358 break; 359 case 4: 360 printf("rp_when( "); 361 printf("t = %ld) \n", rchain->udesc.P7.t); 362 break; 363 case 5: 364 printf("rp_psprel( "); 365 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 366 break; 367 case 6: 368 printf("pfs_when( "); 369 printf("t = %ld) \n", rchain->udesc.P7.t); 370 break; 371 case 7: 372 printf("pfs_psprel( "); 373 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 374 break; 375 case 8: 376 printf("preds_when( "); 377 printf("t = %ld) \n", rchain->udesc.P7.t); 378 break; 379 case 9: 380 printf("preds_psprel( "); 381 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 382 break; 383 case 10: 384 printf("lc_when( "); 385 printf("t = %ld) \n", rchain->udesc.P7.t); 386 break; 387 case 11: 388 printf("lc_psprel( "); 389 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 390 break; 391 case 12: 392 printf("unat_when( "); 393 printf("t = %ld) \n", rchain->udesc.P7.t); 394 break; 395 case 13: 396 printf("unat_psprel( "); 397 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 398 break; 399 case 14: 400 printf("fpsr_when( "); 401 printf("t = %ld) \n", rchain->udesc.P7.t); 402 break; 403 case 15: 404 printf("fpsr_psprel( "); 405 printf("pspoff = %ld) \n", rchain->udesc.P7.t); 406 break; 407 default: 408 printf("unknown \n"); 409 } 410 411 break; 412 413 case P8: 414 printf("\t\tP8:"); 415 switch(rchain->udesc.P8.r) { 416 case 1: 417 printf("rp_sprel( "); 418 printf("spoff = %ld) \n", rchain->udesc.P8.t); 419 break; 420 case 2: 421 printf("pfs_sprel( "); 422 printf("spoff = %ld) \n", rchain->udesc.P8.t); 423 break; 424 case 3: 425 printf("preds_sprel( "); 426 printf("spoff = %ld) \n", rchain->udesc.P8.t); 427 break; 428 case 4: 429 printf("lc_sprel( "); 430 printf("spoff = %ld) \n", rchain->udesc.P8.t); 431 break; 432 case 5: 433 printf("unat_sprel( "); 434 printf("spoff = %ld) \n", rchain->udesc.P8.t); 435 break; 436 case 6: 437 printf("fpsr_sprel( "); 438 printf("spoff = %ld) \n", rchain->udesc.P8.t); 439 break; 440 case 7: 441 printf("bsp_when( "); 442 printf("t = %ld) \n", rchain->udesc.P8.t); 443 break; 444 case 8: 445 printf("bsp_psprel( "); 446 printf("pspoff = %ld) \n", rchain->udesc.P8.t); 447 break; 448 case 9: 449 printf("bsp_sprel( "); 450 printf("spoff = %ld) \n", rchain->udesc.P8.t); 451 break; 452 case 10: 453 printf("bspstore_when( "); 454 printf("t = %ld) \n", rchain->udesc.P8.t); 455 break; 456 case 11: 457 printf("bspstore_psprel( "); 458 printf("pspoff = %ld) \n", rchain->udesc.P8.t); 459 break; 460 case 12: 461 printf("bspstore_sprel( "); 462 printf("spoff = %ld) \n", rchain->udesc.P8.t); 463 break; 464 case 13: 465 printf("rnat_when( "); 466 printf("t = %ld) \n", rchain->udesc.P8.t); 467 break; 468 case 14: 469 printf("rnat_psprel( "); 470 printf("pspoff = %ld) \n", rchain->udesc.P8.t); 471 break; 472 case 15: 473 printf("rnat_sprel( "); 474 printf("spoff = %ld) \n", rchain->udesc.P8.t); 475 break; 476 case 16: 477 printf("priunat_when_gr( "); 478 printf("t = %ld) \n", rchain->udesc.P8.t); 479 break; 480 case 17: 481 printf("priunat_psprel( "); 482 printf("pspoff = %ld) \n", rchain->udesc.P8.t); 483 break; 484 case 18: 485 printf("priunat_sprel( "); 486 printf("spoff = %ld) \n", rchain->udesc.P8.t); 487 break; 488 case 19: 489 printf("priunat_when_mem( "); 490 printf("t = %ld) \n", rchain->udesc.P8.t); 491 break; 492 493 default: 494 printf("unknown \n"); 495 } 496 497 break; 498 499 case P9: 500 printf("\t\tP9:"); 501 printf("(grmask = %x, gr = %d) \n", 502 rchain->udesc.P9.grmask, rchain->udesc.P9.gr); 503 break; 504 505 case P10: 506 printf("\t\tP10:"); 507 printf("(abi: "); 508 switch(rchain->udesc.P10.abi) { 509 case 0: 510 printf("Unix SVR4) \n"); 511 break; 512 case 1: 513 printf("HP-UX) \n"); 514 break; 515 default: 516 printf("Other) \n"); 517 } 518 break; 519 520 case B1: 521 printf("\t\tB1:"); 522 if(rchain->udesc.B1.r) 523 printf("copy_state( "); 524 else 525 printf("label_state( "); 526 printf("label = %d) \n", rchain->udesc.B1.label); 527 528 break; 529 530 case B2: 531 printf("\t\tB2:"); 532 printf("(ecount = %d, t = %ld)\n", 533 rchain->udesc.B2.ecount, rchain->udesc.B2.t); 534 535 break; 536 537 case B3: 538 printf("\t\tB3:"); 539 printf("(t = %ld, ecount = %ld) \n", 540 rchain->udesc.B3.t, rchain->udesc.B3.ecount); 541 542 break; 543 544 case B4: 545 printf("\t\tB4:"); 546 if(rchain->udesc.B4.r) 547 printf("copy_state( "); 548 else 549 printf("label_state( "); 550 551 printf("label = %ld) \n", rchain->udesc.B4.label); 552 553 break; 554 555 556 case X1: 557 printf("\tX1:\n "); 558 break; 559 560 case X2: 561 printf("\tX2:\n"); 562 break; 563 564 case X3: 565 printf("\tX3:\n"); 566 break; 567 568 case X4: 569 printf("\tX4:\n"); 570 break; 571 default: 572 printf("\tunknow: \n"); 573 } 574 575} 576 577/* State record stuff..... based on section 11. and Appendix A. of the 578 *"Itanium Software Conventions and Runtime Architecture Guide" 579 */ 580 581 582/* Global variables: 583 * 1. Two arrays of staterecords: recordstack[], recordstackcopy[] 584 * XXX: Since we don't use malloc, we have two arbitrary sized arrays 585 * providing guaranteed memory from the BSS. See the TODO file 586 * for more details. 587 * 2. Two head variables to hold the member index: unwind_rsp,unwind_rscp 588 */ 589 590struct staterecord recordstack[MAXSTATERECS]; 591struct staterecord recordstackcopy[MAXSTATERECS]; 592struct staterecord current_state; 593struct staterecord *unwind_rsp, *unwind_rscp; 594 595 596uint64_t spill_base = 0; /* Base of spill area in memory stack frame as a psp relative offset */ 597 598/* Initialises a staterecord from a given template, 599 * with default values as described by the Runtime Spec. 600 */ 601 602void 603initrecord(struct staterecord *target) 604{ 605 target->bsp.where = UNSAVED; 606 target->bsp.when = 0; 607 target->bsp.offset = INVALID; 608 target->psp.where = UNSAVED; 609 target->psp.when = 0; 610 target->psp.offset = INVALID; 611 target->rp.where = UNSAVED; 612 target->rp.when = 0; 613 target->rp.offset = INVALID; 614 target->pfs.where = UNSAVED; 615 target->pfs.when = 0; 616 target->pfs.offset = INVALID; 617} 618 619 620/* Modifies a staterecord structure by parsing 621 * a single record chain structure. 622 * regionoffset is the offset within a (prologue) region 623 * where the stack unwinding began. 624 */ 625 626void modifyrecord(struct staterecord *srec, struct recordchain *rchain, 627 uint64_t regionoffset) 628{ 629 630 631 uint64_t grno = 32; /* Default start save GR for prologue_save 632 * GRs. 633 */ 634 635 636 637 switch (rchain->type) { 638 639 case R2: 640 /* R2, prologue_gr is the only region encoding 641 * with register save info. 642 */ 643 644 grno = rchain->udesc.R2.grsave; 645 646 if (rchain->udesc.R2.mask & R2MASKRP) { 647 srec->rp.when = 0; 648 srec->rp.where = GRREL; 649 srec->rp.offset = grno++; 650 } 651 652 if (rchain->udesc.R2.mask & R2MASKPFS) { 653 srec->pfs.when = 0; 654 srec->pfs.where = GRREL; 655 srec->pfs.offset = grno++; 656 } 657 658 if (rchain->udesc.R2.mask & R2MASKPSP) { 659 srec->psp.when = 0; 660 srec->psp.where = GRREL; 661 srec->psp.offset = grno++; 662 } 663 break; 664 665 case P3: 666 switch (rchain->udesc.P3.r) { 667 case 0: /* psp_gr */ 668 if (srec->psp.when < regionoffset) { 669 srec->psp.where = GRREL; 670 srec->psp.offset = rchain->udesc.P3.grbr; 671 } 672 break; 673 674 case 1: /* rp_gr */ 675 if (srec->rp.when < regionoffset) { 676 srec->rp.where = GRREL; 677 srec->rp.offset = rchain->udesc.P3.grbr; 678 } 679 break; 680 681 case 2: /* pfs_gr */ 682 if (srec->pfs.when < regionoffset) { 683 srec->pfs.where = GRREL; 684 srec->pfs.offset = rchain->udesc.P3.grbr; 685 } 686 break; 687 688 } 689 break; 690 691 692 /* XXX: P4 spill_mask and P7: spill_base are for GRs, FRs, and BRs. 693 * We're not particularly worried about those right now. 694 */ 695 696 case P7: 697 switch (rchain->udesc.P7.r) { 698 699 case 0: /* mem_stack_f */ 700 if (srec->psp.offset != INVALID) printf("!!!saw mem_stack_f more than once. \n"); 701 srec->psp.when = rchain->udesc.P7.t; 702 if (srec->psp.when < regionoffset) { 703 srec->psp.where = IMMED; 704 srec->psp.offset = rchain->udesc.P7.size; /* spsz.offset is "overloaded" */ 705 } 706 break; 707 708 case 1: /* mem_stack_v */ 709 srec->psp.when = rchain->udesc.P7.t; 710 break; 711 712 case 2: /* spill_base */ 713 spill_base = rchain->udesc.P7.t; 714 break; 715 716 case 3: /* psp_sprel */ 717 if (srec->psp.when < regionoffset) { 718 srec->psp.where = SPREL; 719 srec->psp.offset = rchain->udesc.P7.t; 720 } 721 break; 722 723 case 4: /* rp_when */ 724 srec->rp.when = rchain->udesc.P7.t; 725 /* XXX: Need to set to prologue_gr(grno) for the orphan case 726 * ie; _gr/_psprel/_sprel not set and therefore default 727 * to begin from the gr specified in prologue_gr. 728 */ 729 break; 730 731 case 5: /* rp_psprel */ 732 if (srec->rp.when < regionoffset) { 733 srec->rp.where = PSPREL; 734 srec->rp.offset = rchain->udesc.P7.t; 735 } 736 break; 737 738 case 6: /* pfs_when */ 739 srec->pfs.when = rchain->udesc.P7.t; 740 /* XXX: Need to set to prologue_gr(grno) for the orphan case 741 * ie; _gr/_psprel/_sprel not set and therefore default 742 * to begin from the gr specified in prologue_gr. 743 */ 744 break; 745 746 case 7: /* pfs_psprel */ 747 if (srec->pfs.when < regionoffset) { 748 srec->pfs.where = PSPREL; 749 srec->pfs.offset = rchain->udesc.P7.t; 750 } 751 break; 752 753 } 754 break; 755 756 case P8: 757 switch (rchain->udesc.P8.r) { 758 case 1: /* rp_sprel */ 759 if (srec->rp.when < regionoffset) { 760 srec->rp.where = SPREL; 761 srec->rp.offset = rchain->udesc.P8.t; 762 } 763 break; 764 case 2: /* pfs_sprel */ 765 if (srec->pfs.when < regionoffset) { 766 srec->pfs.where = SPREL; 767 srec->pfs.offset = rchain->udesc.P8.t; 768 769 } 770 break; 771 } 772 break; 773 774 case B1: 775 776 rchain->udesc.B1.r ? switchrecordstack(0) : 777 clonerecordstack(0); 778 break; 779 780 case B2: 781 if (regionoffset < rchain->udesc.B2.t) { 782 poprecord(¤t_state, rchain->udesc.B2.ecount); 783 } 784 break; 785 case B3: 786 if (regionoffset < rchain->udesc.B3.t) { 787 poprecord(¤t_state, rchain->udesc.B3.ecount); 788 } 789 break; 790 case B4: 791 rchain->udesc.B4.r ? switchrecordstack(0) : 792 clonerecordstack(0); 793 break; 794 795 case X1: 796 case X2: 797 case X3: 798 /* XXX: Todo */ 799 break; 800 801 802 case R1: 803 case R3: 804 case P1: 805 case P2: 806 case P4: 807 case P5: 808 case P6: 809 case P9: 810 case P10: 811 default: 812 /* Ignore. */ 813 printf("XXX: Ignored. \n"); 814 } 815 816 817} 818 819void dump_staterecord(struct staterecord *srec) 820{ 821 printf("rp.where: "); 822 switch(srec->rp.where) { 823 case UNSAVED: 824 printf("UNSAVED "); 825 break; 826 case BRREL: 827 printf("BRREL "); 828 break; 829 case GRREL: 830 printf("GRREL "); 831 break; 832 case SPREL: 833 printf("SPREL "); 834 break; 835 case PSPREL: 836 printf("PSPSREL "); 837 break; 838 default: 839 printf("unknown "); 840 } 841 842 printf(", rp.when = %lu, ", srec->rp.when); 843 printf("rp.offset = %lu \n", srec->rp.offset); 844 845 846 printf("pfs.where: "); 847 switch(srec->pfs.where) { 848 case UNSAVED: 849 printf("UNSAVED "); 850 break; 851 case BRREL: 852 printf("BRREL "); 853 break; 854 case GRREL: 855 printf("GRREL "); 856 break; 857 case SPREL: 858 printf("SPREL "); 859 break; 860 case PSPREL: 861 printf("PSPSREL "); 862 break; 863 default: 864 printf("unknown "); 865 } 866 867 printf(", pfs.when = %lu, ", srec->pfs.when); 868 printf("pfs.offset = %lu \n", srec->pfs.offset); 869 870 871} 872 873 874/* Push a state record on the record stack. */ 875 876void pushrecord(struct staterecord *srec) 877{ 878 if(unwind_rsp >= recordstack + MAXSTATERECS) { 879 printf("Push exceeded array size!!! \n"); 880 return; 881 } 882 883 memcpy(unwind_rsp, srec, sizeof(struct staterecord)); 884 unwind_rsp++; 885 886} 887 888/* Pop n state records off the record stack. */ 889 890void poprecord(struct staterecord *srec, int n) 891{ 892 if(unwind_rsp == recordstack) { 893 printf("Popped beyond end of Stack!!! \n"); 894 return; 895 } 896 unwind_rsp -= n; 897 memcpy(srec, unwind_rsp, sizeof(struct staterecord)); 898#ifdef DEBUG 899 memset(unwind_rsp, 0, sizeof(struct staterecord) * n); 900#endif 901 902} 903 904/* Clone the whole record stack upto this one. */ 905void clonerecordstack(u_int label) 906{ 907 memcpy(recordstackcopy, recordstack, 908 (unwind_rsp - recordstack) * sizeof(struct staterecord)); 909 unwind_rscp = unwind_rsp; 910} 911 912/* Discard the current stack, and adopt a clone. */ 913void switchrecordstack(u_int label) 914{ 915 memcpy((void *) recordstack, (void *) recordstackcopy, 916 (unwind_rscp - recordstackcopy) * sizeof(struct staterecord)); 917 unwind_rsp = unwind_rscp; 918 919} 920 921/* In the context of a procedure: 922 * Parses through a record chain, building, pushing and/or popping staterecords, 923 * or cloning/destroying stacks of staterecords as required. 924 * Parameters are: 925 * rchain: pointer to recordchain array. 926 * procoffset: offset of point of interest, in slots, within procedure starting from slot 0 927 * This routine obeys [1] 928 */ 929struct staterecord *buildrecordstack(struct recordchain *rchain, uint64_t procoffset) 930{ 931 932 uint64_t rlen = 0; /* Current region length, defaults to zero, if not specified */ 933 uint64_t roffset = 0; /* Accumulated region length */ 934 uint64_t rdepth = 0; /* Offset within current region */ 935 936 937 char *spill_mask = NULL; /* Specifies when preserved registers are spilled, as a bit mask */ 938 939 spill_mask = NULL; 940 bool rtype; 941 942 unwind_rsp = recordstack; /* Start with bottom of staterecord stack. */ 943 944 initrecord(¤t_state); 945 946 int i; 947 948 949 for (i = 0;i < rec_cnt;i++) { 950 951 switch (rchain[i].type) { 952 case R1: 953 rlen = rchain[i].udesc.R1.rlen; 954 rdepth = procoffset - roffset; 955 if (rdepth < 0) goto out; /* Overshot Region containing procoffset. Bailout. */ 956 roffset += rlen; 957 rtype = rchain[i].udesc.R1.r; 958 if (!rtype) { 959 pushrecord(¤t_state); 960 } 961 break; 962 963 case R3: 964 rlen = rchain[i].udesc.R3.rlen; 965 rdepth = procoffset - roffset; 966 if (rdepth < 0) goto out; /* Overshot Region containing procoffset. Bailout. */ 967 roffset += rlen; 968 rtype = rchain[i].udesc.R3.r; 969 if (!rtype) { 970 pushrecord(¤t_state); 971 } 972 break; 973 974 case R2: 975 rlen = rchain[i].udesc.R2.rlen; 976 rdepth = procoffset - roffset; 977 if (rdepth < 0) goto out; /* Overshot Region containing procoffset. Bailout. */ 978 roffset += rlen; 979 rtype = false; /* prologue region */ 980 pushrecord(¤t_state); 981 982 /* R2 has save info. Continue down. */ 983 984 case P1: 985 case P2: 986 case P3: 987 case P4: 988 case P5: 989 case P6: 990 case P7: 991 case P8: 992 case P9: 993 case P10: 994 modifyrecord(¤t_state, &rchain[i], rdepth); 995 break; 996 997 case B1: 998 case B2: 999 case B3: 1000 case B4: 1001 modifyrecord(¤t_state, &rchain[i], rlen - 1 - rdepth); 1002 break; 1003 1004 case X1: 1005 case X2: 1006 case X3: 1007 case X4: 1008 default: 1009 printf("Error: Unknown descriptor type!!! \n"); 1010 1011 } 1012 1013#if UNWIND_DIAGNOSTIC 1014 dump_staterecord(¤t_state); 1015#endif 1016 1017 1018 } 1019 1020out: 1021 1022 return ¤t_state; 1023} 1024 1025void updateregs(struct unwind_frame *uwf, struct staterecord *srec, uint64_t procoffset) 1026{ 1027 1028#ifdef UNWIND_DIAGNOSTIC 1029 printf("updateregs(): \n"); 1030 printf("procoffset (slots) = %lu \n", procoffset); 1031#endif 1032 /* XXX: Update uwf for regs other than rp and pfs*/ 1033 uint64_t roffset = 0; 1034 1035 1036 /* Uses shadow arrays to update uwf from srec in a loop. */ 1037 /* Count of number of regstate elements in struct staterecord */ 1038 int statecount = sizeof(struct staterecord)/sizeof(struct regstate); 1039 /* Pointer to current regstate. */ 1040 struct regstate *stptr = (void *) srec; 1041 /* Pointer to current unwind_frame element */ 1042 uint64_t *gr = (void *) uwf; 1043 1044 1045 int i; 1046 1047 for(i = 0; i < statecount; i++) { 1048 switch (stptr[i].where) { 1049 case IMMED: /* currently only mem_stack_f */ 1050 if (stptr[i].when >= procoffset) break; 1051 uwf->psp -= (stptr[i].offset << 4); 1052 break; 1053 1054 case GRREL: 1055 if (stptr[i].when >= procoffset) break; 1056 1057 roffset = stptr[i].offset; 1058 if (roffset == 0) { 1059 gr[i] = 0; 1060 break; 1061 } 1062 1063 1064 if (roffset < 32) { 1065 printf("GR%ld: static register save ??? \n", roffset); 1066 break; 1067 } 1068 1069 /* Fetch from bsp + offset - 32 + Adjust for RNAT. */ 1070 roffset -= 32; 1071 gr[i] = ia64_getrse_gr(uwf->bsp, roffset); 1072 break; 1073 1074 case SPREL: 1075 if (stptr[i].when >= procoffset) break; 1076 1077 /* Check if frame has been setup. */ 1078 if (srec->psp.offset == INVALID) { 1079 printf("sprel used without setting up stackframe!!! \n"); 1080 break; 1081 } 1082 1083 roffset = stptr[i].offset; 1084 1085 /* Fetch from sp + offset */ 1086 memcpy(&gr[i], (char *) uwf->sp + roffset * 4, sizeof(uint64_t)); 1087 break; 1088 1089 1090 case PSPREL: 1091 if (stptr[i].when >= procoffset) break; 1092 1093 /* Check if frame has been setup. */ 1094 if (srec->psp.offset == INVALID) { 1095 printf("psprel used without setting up stackframe!!! \n"); 1096 break; 1097 } 1098 1099 roffset = stptr[i].offset; 1100 1101 /* Fetch from sp + offset */ 1102 memcpy(&gr[i], (char *) uwf->psp + 16 - (roffset * 4), sizeof(uint64_t)); 1103 break; 1104 1105 case UNSAVED: 1106 case BRREL: 1107 default: 1108#ifdef UNWIND_DIAGNOSTIC 1109 printf ("updateregs: reg[%d] is UNSAVED \n", i); 1110#endif 1111 break; 1112 /* XXX: Not implemented yet. */ 1113 } 1114 1115 } 1116 1117} 1118 1119 1120/* Locates unwind table entry, given unwind table entry info. 1121 * Expects the variables ia64_unwindtab, and ia64_unwindtablen 1122 * to be set appropriately. 1123 */ 1124 1125struct uwtable_ent * 1126get_unwind_table_entry(uint64_t iprel) 1127{ 1128 1129 extern uint64_t ia64_unwindtab, ia64_unwindtablen; 1130 1131 struct uwtable_ent *uwt; 1132 1133 1134 int tabent; 1135 1136 for(uwt = (struct uwtable_ent *) ia64_unwindtab, tabent = 0; 1137 /* The Runtime spec tells me the table entries are sorted. */ 1138 uwt->end <= iprel && tabent < ia64_unwindtablen; 1139 uwt++, tabent += sizeof(struct uwtable_ent)); 1140 1141 1142 if (!(uwt->start <= iprel && iprel < uwt->end)) { 1143#ifdef UNWIND_DIAGNOSTIC 1144 printf("Entry not found \n"); 1145 printf("iprel = %lx \n", iprel); 1146 printf("uwt->start = %lx \nuwt->end = %lx \n", 1147 uwt->start, uwt->end); 1148 printf("tabent = %d \n", tabent); 1149 printf("ia64_unwindtablen = %ld \n", 1150 ia64_unwindtablen); 1151#endif 1152 return NULL; 1153 } 1154 1155#ifdef UNWIND_DIAGNOSTIC 1156 printf("uwt->start = %lx \nuwt->end = %lx \n" 1157 "uwt->infoptr = %p\n", uwt->start, uwt->end, uwt->infoptr); 1158#endif 1159 1160 return uwt; 1161} 1162 1163 1164/* 1165 * Reads unwind table info and updates register values. 1166 */ 1167 1168void 1169patchunwindframe(struct unwind_frame *uwf, uint64_t iprel, uint64_t relocoffset) 1170{ 1171 1172 extern struct recordchain strc[]; 1173 struct staterecord *srec; 1174 struct uwtable_ent *uwt; 1175 uint64_t infoptr, procoffset, slotoffset; 1176 1177 if (iprel < 0) { 1178 panic("unwind ip out of range!!! \n"); 1179 return; 1180 } 1181 1182 1183 uwt = get_unwind_table_entry(iprel); 1184 1185 if (uwt == NULL) return; 1186 1187 infoptr = (uint64_t) uwt->infoptr + relocoffset; 1188 1189 if (infoptr > relocoffset) { 1190 buildrecordchain(infoptr, NULL); 1191 } 1192 else return; 1193 1194 slotoffset = iprel & 3; 1195 1196 /* procoffset in Number of _slots_ , _not_ a byte offset. */ 1197 1198 procoffset = (((iprel - slotoffset) - (uwt->start)) / 0x10 * 3) + slotoffset; 1199 srec = buildrecordstack(strc, procoffset); 1200 1201 updateregs(uwf, srec, procoffset); 1202} 1203 1204