1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * interface used by unwind support to query frame descriptor info 31 */ 32 33 #ifndef _LIBCRUN_ 34 #include "lint.h" 35 #endif 36 #include <sys/types.h> 37 #include "stack_unwind.h" 38 #include "unwind_context.h" 39 #include "reg_num.h" 40 41 enum CFA_ops { 42 DW_CFA_nop = 0x00, 43 DW_CFA_set_loc = 0x01, 44 DW_CFA_advance_loc1 = 0x02, 45 DW_CFA_advance_loc2 = 0x03, 46 DW_CFA_advance_loc4 = 0x04, 47 DW_CFA_offset_extended = 0x05, 48 DW_CFA_restore_extended = 0x06, 49 DW_CFA_undefined = 0x07, 50 DW_CFA_same_value = 0x08, 51 DW_CFA_register = 0x09, 52 DW_CFA_remember_state = 0x0a, 53 DW_CFA_restore_state = 0x0b, 54 DW_CFA_def_cfa = 0x0c, 55 DW_CFA_def_cfa_register = 0x0d, 56 DW_CFA_def_cfa_offset = 0x0e, 57 DW_CFA_def_cfa_expression = 0x0f, 58 DW_CFA_expression = 0x10, 59 DW_CFA_offset_extended_sf = 0x11, 60 DW_CFA_def_cfa_sf = 0x12, 61 DW_CFA_def_cfa_offset_sf = 0x13, 62 /* skip 9 values */ 63 DW_CFA_SUNW_advance_loc = 0x1d, 64 DW_CFA_SUNW_offset = 0x1e, 65 DW_CFA_SUNW_restore = 0x1f, 66 DW_CFA_advance_loc = 0x40, 67 DW_CFA_offset = 0x80, 68 DW_CFA_restore = 0xc0 69 }; 70 71 struct operation_desc { 72 enum operand_desc op1; 73 enum operand_desc op2; 74 }; 75 76 struct operation_desc cfa_operations[] = { 77 {NO_OPR, NO_OPR}, /* DW_CFA_nop */ 78 {ADDR, NO_OPR}, /* DW_CFA_set_loc - address */ 79 {UNUM8, NO_OPR}, /* DW_CFA_advance_loc1 - delta */ 80 {UNUM16, NO_OPR}, /* DW_CFA_advance_loc2 - delta */ 81 {UNUM32, NO_OPR}, /* DW_CFA_advance_loc4 - delta */ 82 {ULEB128, ULEB128_FAC}, /* DW_CFA_offset_extended - reg, */ 83 /* data factored offset */ 84 {ULEB128, NO_OPR}, /* DW_CFA_restore_extended - register */ 85 {ULEB128, NO_OPR}, /* DW_CFA_undefined - register */ 86 {ULEB128, NO_OPR}, /* DW_CFA_same_value - register */ 87 {ULEB128, ULEB128_SREG}, /* DW_CFA_register - register, register */ 88 {NO_OPR, NO_OPR}, /* DW_CFA_remember_state */ 89 {NO_OPR, NO_OPR}, /* DW_CFA_restore_state */ 90 {ULEB128_SREG, ULEB128}, /* DW_CFA_def_cfa - register, offset */ 91 {ULEB128_SREG, NO_OPR}, /* DW_CFA_def_cfa_register - register */ 92 {ULEB128, NO_OPR}, /* DW_CFA_def_cfa_offset - offset */ 93 {BLOCK, NO_OPR}, /* DW_CFA_def_cfa_expression - expression */ 94 {ULEB128, BLOCK}, /* DW_CFA_expression - reg, expression */ 95 {ULEB128, SLEB128_FAC}, /* DW_CFA_offset_extended_sf - reg, */ 96 /* data factored offset */ 97 {ULEB128_SREG, SLEB128_FAC}, /* DW_CFA_def_cfa_sf - reg, */ 98 /* data factored offset */ 99 {SLEB128_FAC, NO_OPR}, /* DW_CFA_def_cfa_offset_sf - */ 100 /* data fctored offset */ 101 {NO_OPR, NO_OPR}, 102 {NO_OPR, NO_OPR}, 103 {NO_OPR, NO_OPR}, 104 {NO_OPR, NO_OPR}, 105 {NO_OPR, NO_OPR}, 106 {NO_OPR, NO_OPR}, 107 {NO_OPR, NO_OPR}, 108 {NO_OPR, NO_OPR}, 109 {NO_OPR, NO_OPR}, 110 {UNUM6_CFAC, NO_OPR}, /* DW_CFA_SUNW_advance_loc - */ 111 /* code factored delta */ 112 {UNUM6, ULEB128_FAC}, /* DW_CFA_SUNW_offset - reg */ 113 /* data factored offset */ 114 {UNUM6, NO_OPR} /* DW_CFA_SUNW_restore */ 115 }; 116 117 uint64_t interpret_ops(void *data, void *data_end, 118 ptrdiff_t reloc, uint64_t current_loc, uint64_t pc, 119 struct register_state f_state[], 120 struct register_state f_start_state[], 121 int daf, int caf, int enc); 122 123 /* 124 * The entry-point state of old_ctx defines the current 125 * suspended state of the caller (in new_ctx). If the old info 126 * will not be refered to again, old_ctx == new_ctx is OK 127 */ 128 void 129 _Unw_Propagate_Registers(struct _Unwind_Context *old_ctx, 130 struct _Unwind_Context *new_ctx) 131 { 132 new_ctx->current_regs[SP_RSP] = old_ctx->cfa; 133 new_ctx->pc = old_ctx->ra; 134 new_ctx->current_regs[FP_RBP] = old_ctx->entry_regs[FP_RBP]; 135 new_ctx->current_regs[GPR_RBX] = old_ctx->entry_regs[GPR_RBX]; 136 new_ctx->current_regs[EIR_R12] = old_ctx->entry_regs[EIR_R12]; 137 new_ctx->current_regs[EIR_R13] = old_ctx->entry_regs[EIR_R13]; 138 new_ctx->current_regs[EIR_R14] = old_ctx->entry_regs[EIR_R14]; 139 new_ctx->current_regs[EIR_R15] = old_ctx->entry_regs[EIR_R15]; 140 } 141 142 void 143 fix_cfa(struct _Unwind_Context *ctx, struct register_state *rs) 144 { 145 switch (rs[CF_ADDR].rule) { 146 default: 147 ctx->cfa = 0; 148 break; 149 case register_rule: /* CFA = offset + source_reg */ 150 ctx->cfa = (ctx->current_regs)[rs[CF_ADDR].source_reg] + 151 rs[CF_ADDR].offset; 152 break; 153 case constant_rule: /* CFA = offset */ 154 ctx->cfa = rs[CF_ADDR].offset; 155 break; 156 case indirect_rule: /* CFA = *(offset + source_reg) */ 157 ctx->cfa = *(uint64_t *) 158 (ctx->current_regs[rs[CF_ADDR].source_reg] + 159 rs[CF_ADDR].offset); 160 break; 161 } 162 ctx->entry_regs[SP_RSP] = ctx->cfa; 163 } 164 165 void 166 fix_ra(struct _Unwind_Context *ctx, struct register_state *rs) 167 { 168 switch (rs[RET_ADD].rule) { 169 case undefined_rule: 170 default: 171 ctx->ra = 0; 172 break; 173 case offset_rule: /* RA = *(offset + CFA) */ 174 ctx->ra = *(uint64_t *)(ctx->cfa + rs[RET_ADD].offset); 175 break; 176 case register_rule: /* RA = offset + source_reg */ 177 ctx->ra = ctx->current_regs[rs[RET_ADD].source_reg] + 178 rs[RET_ADD].offset; 179 break; 180 case indirect_rule: /* RA = *(offset + source_reg) */ 181 ctx->ra = *(uint64_t *) 182 (ctx->current_regs[rs[RET_ADD].source_reg] + 183 rs[RET_ADD].offset); 184 break; 185 } 186 } 187 188 void 189 fix_reg(struct _Unwind_Context *ctx, struct register_state *rs, int index) 190 { 191 switch (rs[index].rule) { 192 default: 193 ctx->entry_regs[index] = ctx->current_regs[index]; 194 break; 195 case offset_rule: /* target_reg = *(offset + CFA) */ 196 ctx->entry_regs[index] = *(uint64_t *) 197 (ctx->cfa + rs[index].offset); 198 break; 199 case is_offset_rule: /* target_reg = offset + CFA */ 200 ctx->entry_regs[index] = ctx->cfa + rs[index].offset; 201 break; 202 case register_rule: /* target_reg = offset + source_reg */ 203 ctx->entry_regs[index] = 204 ctx->current_regs[rs[index].source_reg] + 205 rs[index].offset; 206 break; 207 case constant_rule: /* target_reg = offset */ 208 ctx->entry_regs[index] = rs[index].offset; 209 break; 210 case indirect_rule: /* target_reg = *(offset + source_reg) */ 211 ctx->entry_regs[index] = *(uint64_t *) 212 (ctx->current_regs[rs[index].source_reg] + 213 rs[index].offset); 214 break; 215 } 216 } 217 218 219 /* 220 * Input: f->{cie_ops, cie_ops_end, fde_ops, fde_ops_end} 221 * + location of DWARF opcodes 222 * ctx->{current_regs, pc} 223 * + register values and pc at point of suspension 224 * Output: ctx->{entry_regs, cfa, ra} 225 * + register values when function was entered 226 * + Cannonical Frame Address 227 * + return address 228 */ 229 uint64_t 230 _Unw_Rollback_Registers(struct eh_frame_fields *f, 231 struct _Unwind_Context *ctx) 232 { 233 /* GPRs, RET_ADD, and CF_ADDR */ 234 struct register_state func_state[18]; 235 struct register_state func_start_state[18]; 236 struct register_state nop = { 0, undefined_rule, 0 }; 237 int i; 238 uint64_t first_pc; 239 240 if (f == 0) { 241 /* 242 * When no FDE we assume all routines have a frame pointer 243 * and pass back existing callee saves registers 244 */ 245 if (ctx->current_regs[FP_RBP] < ctx->current_regs[SP_RSP]) { 246 ctx->cfa = 0; 247 ctx->ra = 0; 248 ctx->pc = 0; 249 return (0); 250 } 251 ctx->entry_regs[FP_RBP] = ((uint64_t *) 252 (ctx->current_regs[FP_RBP]))[0]; 253 ctx->cfa = ctx->current_regs[FP_RBP] + 16; 254 ctx->entry_regs[SP_RSP] = ctx->cfa; 255 ctx->entry_regs[GPR_RBX] = ctx->current_regs[GPR_RBX]; 256 ctx->entry_regs[EIR_R12] = ctx->current_regs[EIR_R12]; 257 ctx->entry_regs[EIR_R13] = ctx->current_regs[EIR_R13]; 258 ctx->entry_regs[EIR_R14] = ctx->current_regs[EIR_R14]; 259 ctx->entry_regs[EIR_R15] = ctx->current_regs[EIR_R15]; 260 ctx->ra = ((uint64_t *)ctx->cfa)[-1]; 261 return (ctx->cfa); 262 } 263 264 for (i = 0; i < 18; i++) 265 func_start_state[i] = nop; 266 first_pc = interpret_ops(f->cie_ops, f->cie_ops_end, 267 f->cie_reloc, ctx->func, ctx->pc, func_start_state, 0, 268 f->data_align, f->code_align, f->code_enc); 269 for (i = 0; i < 18; i++) 270 func_state[i] = func_start_state[i]; 271 (void) interpret_ops(f->fde_ops, f->fde_ops_end, 272 f->fde_reloc, first_pc, ctx->pc, func_state, func_start_state, 273 f->data_align, f->code_align, f->code_enc); 274 275 fix_cfa(ctx, func_state); 276 if (ctx->cfa < ctx->current_regs[SP_RSP]) { 277 ctx->cfa = 0; 278 ctx->ra = 0; 279 ctx->pc = 0; 280 return (0); 281 } 282 fix_ra(ctx, func_state); 283 fix_reg(ctx, func_state, GPR_RBX); 284 fix_reg(ctx, func_state, FP_RBP); 285 fix_reg(ctx, func_state, EIR_R12); 286 fix_reg(ctx, func_state, EIR_R13); 287 fix_reg(ctx, func_state, EIR_R14); 288 fix_reg(ctx, func_state, EIR_R15); 289 290 return (ctx->cfa); 291 } 292 293 /* 294 * remap two-bit opcodes into a separate range or grab eight-bit opcode 295 * and advance pointer past it. 296 */ 297 static enum CFA_ops 298 separate_op(void **pp) 299 { 300 uint8_t c = **((uint8_t **)pp); 301 302 if (c & 0xc0) { 303 switch (c & 0xc0) { 304 case DW_CFA_advance_loc: 305 return (DW_CFA_SUNW_advance_loc); 306 case DW_CFA_offset: 307 return (DW_CFA_SUNW_offset); 308 case DW_CFA_restore: 309 return (DW_CFA_SUNW_restore); 310 } 311 } else { 312 *pp = (void *)((*(intptr_t *)pp) + 1); 313 } 314 return (c); 315 } 316 317 static uint64_t 318 extractuleb(void **datap) 319 { 320 uint8_t *data = *(uint8_t **)datap; 321 uint64_t res = 0; 322 int more = 1; 323 int shift = 0; 324 int val; 325 326 while (more) { 327 val = (*data) & 0x7f; 328 more = ((*data++) & 0x80) >> 7; 329 res = res | val << shift; 330 shift += 7; 331 } 332 *datap = (void *)data; 333 return (res); 334 } 335 336 static uint64_t 337 extractsleb(void** datap) 338 { 339 uint8_t *data = *datap; 340 int64_t res = 0; 341 int more = 1; 342 int shift = 0; 343 unsigned int val; 344 345 while (more) { 346 val = (*data) & 0x7f; 347 more = ((*data++) & 0x80) >> 7; 348 res = res | val<< shift; 349 shift += 7; 350 } 351 *datap = (void*) data; 352 res = (res << (64 - shift)) >> (64 - shift); 353 return (res); 354 } 355 356 static uint64_t get_encoded_val(void **datap, ptrdiff_t reloc, int enc); 357 358 /* 359 * do all field extractions needed for CFA operands and encoded FDE 360 * fields 361 */ 362 uint64_t 363 _Unw_get_val(void **datap, ptrdiff_t reloc, 364 enum operand_desc opr, int daf, int caf, int enc) 365 { 366 intptr_t data = (intptr_t)*datap; 367 uint64_t res; 368 char *dp, *rp; 369 370 switch (opr) { 371 case NO_OPR: 372 res = 0; 373 break; 374 case ULEB128_FAC: 375 return (daf * extractuleb(datap)); 376 break; 377 case ULEB128: 378 return (extractuleb(datap)); 379 break; 380 case ULEB128_SREG: 381 res = (uint64_t)(*((uint8_t *)data)); 382 data += 1; 383 switch (res) { 384 /* verify that register is one which is being tracked */ 385 case GPR_RBX: 386 case FP_RBP: 387 case SP_RSP: 388 case EIR_R12: 389 case EIR_R13: 390 case EIR_R14: 391 case EIR_R15: 392 break; 393 default: 394 res = BAD_REG; 395 break; 396 } 397 break; 398 case UNUM6: 399 res = (uint64_t)(0x3f & *((uint8_t *)data)); 400 data += 1; 401 break; 402 case UNUM8: 403 res = (uint64_t)(*((uint8_t *)data)); 404 data += 1; 405 break; 406 case UNUM16: 407 res = (uint64_t)(*((uint16_t *)data)); 408 data += 2; 409 break; 410 case UNUM32: 411 res = (uint64_t)(*((uint32_t *)data)); 412 data += 4; 413 break; 414 case UNUM6_CFAC: 415 res = caf * (uint64_t)(0x3f & *((uint8_t *)data)); 416 data += 1; 417 break; 418 case UNUM8_CFAC: 419 res = caf * (uint64_t)(*((uint8_t *)data)); 420 data += 1; 421 break; 422 case UNUM16_CFAC: 423 res = caf * (uint64_t)(*((uint16_t *)data)); 424 data += 2; 425 break; 426 case UNUM32_CFAC: 427 res = caf * (uint64_t)(*((uint32_t *)data)); 428 data += 4; 429 break; 430 case UNUM64: 431 res = (uint64_t)(*((uint64_t *)data)); 432 data += 8; 433 break; 434 case SNUM8: 435 res = (uint64_t)(int64_t)(*((int8_t *)data)); 436 data += 1; 437 break; 438 case SNUM16: 439 res = (uint64_t)(int64_t)(*((int16_t *)data)); 440 data += 2; 441 break; 442 case SNUM32: 443 res = (uint64_t)(int64_t)(*((int32_t *)data)); 444 data += 4; 445 break; 446 case SNUM64: 447 res = (uint64_t)(*((int64_t *)data)); 448 data += 8; 449 break; 450 case SLEB128_FAC: 451 return (daf * extractsleb(datap)); 452 break; 453 case SLEB128: 454 return (extractsleb(datap)); 455 break; 456 case ZTSTRING: 457 /* max length of augmentation string is 4 */ 458 rp = (char *)&res; 459 dp = (char *)data; 460 while (*rp++ = *dp++) 461 ; 462 data = (intptr_t)dp; 463 break; 464 case ADDR: 465 return (get_encoded_val(datap, reloc, enc)); 466 break; 467 case SIZE: 468 return (get_encoded_val(datap, reloc, enc & 0x7)); 469 case BLOCK: 470 res = 0; /* not implemented */ 471 break; 472 } 473 *datap = (void*)data; 474 return (res); 475 } 476 477 static uint64_t 478 get_encoded_val(void **datap, ptrdiff_t reloc, int enc) 479 { 480 int val = enc & 0xf; 481 int rel = (enc >> 4) & 0xf; 482 intptr_t loc = ((intptr_t)*datap) + reloc; 483 uint64_t res = 0; 484 485 switch (val) { 486 case 0x01: 487 res = _Unw_get_val(datap, reloc, ULEB128, 1, 1, 0); 488 break; 489 case 0x2: 490 res = _Unw_get_val(datap, reloc, UNUM16, 1, 1, 0); 491 break; 492 case 0x3: 493 res = _Unw_get_val(datap, reloc, UNUM32, 1, 1, 0); 494 break; 495 case 0x04: 496 res = _Unw_get_val(datap, reloc, UNUM64, 1, 1, 0); 497 break; 498 case 0x09: 499 res = _Unw_get_val(datap, reloc, SLEB128, 1, 1, 0); 500 break; 501 case 0x0a: 502 res = _Unw_get_val(datap, reloc, SNUM16, 1, 1, 0); 503 break; 504 case 0x0b: 505 res = _Unw_get_val(datap, reloc, SNUM32, 1, 1, 0); 506 break; 507 case 0x0c: 508 res = _Unw_get_val(datap, reloc, SNUM64, 1, 1, 0); 509 break; 510 } 511 512 switch (rel) { 513 case 0: 514 break; 515 case 1: 516 if (res != 0) 517 res += loc; 518 break; 519 default: 520 /* remainder not implemented */ 521 break; 522 } 523 return (res); 524 } 525 526 527 int interpret_op(void **datap, ptrdiff_t reloc, 528 uint64_t *reached_pc_p, uint64_t pc, 529 struct register_state f_state[], 530 struct register_state f_start_state[], 531 int daf, int caf, int enc); 532 533 uint64_t 534 interpret_ops(void *data, void *data_end, 535 ptrdiff_t reloc, 536 uint64_t start_pc, uint64_t pc, 537 struct register_state f_state[], 538 struct register_state f_start_state[], 539 int daf, int caf, int enc) 540 { 541 void *d = data; 542 uint64_t reached_pc = start_pc; 543 544 while (d < data_end) { 545 if (interpret_op(&d, reloc, &reached_pc, pc, 546 f_state, f_start_state, daf, caf, enc)) 547 break; 548 } 549 return (reached_pc); 550 } 551 552 int 553 interpret_op(void **datap, ptrdiff_t reloc, 554 uint64_t *reached_pc_p, uint64_t pc, 555 struct register_state f_state[], 556 struct register_state f_start_state[], 557 int daf, int caf, int enc) 558 { 559 enum CFA_ops op = separate_op(datap); 560 enum operand_desc opr1 = (cfa_operations[op]).op1; 561 enum operand_desc opr2 = (cfa_operations[op]).op2; 562 563 uint64_t val1 = _Unw_get_val(datap, reloc, opr1, daf, caf, enc); 564 uint64_t val2 = _Unw_get_val(datap, reloc, opr2, daf, caf, enc); 565 if ((opr1 == ULEB128_SREG && val1 == BAD_REG) || 566 (opr2 == ULEB128_SREG && val2 == BAD_REG)) 567 return (0); 568 switch (op) { 569 case DW_CFA_nop: 570 break; 571 case DW_CFA_set_loc: 572 if (val1 > pc) 573 return (1); 574 *reached_pc_p = val1; 575 break; 576 case DW_CFA_advance_loc1: 577 case DW_CFA_advance_loc2: 578 case DW_CFA_advance_loc4: 579 if (*reached_pc_p + val1 > pc) 580 return (1); 581 *reached_pc_p += val1; 582 break; 583 case DW_CFA_offset_extended: 584 f_state[val1].rule = offset_rule; 585 f_state[val1].source_reg = CF_ADDR; 586 f_state[val1].offset = val2; 587 break; 588 case DW_CFA_restore_extended: 589 if (f_start_state != 0) 590 f_state[val1] = f_start_state[val1]; 591 break; 592 case DW_CFA_undefined: 593 f_state[val1].rule = undefined_rule; 594 break; 595 case DW_CFA_same_value: 596 f_state[val1].rule = same_value_rule; 597 break; 598 case DW_CFA_register: 599 f_state[val1].rule = register_rule; 600 f_state[val1].source_reg = val2; 601 f_state[val1].offset = 0; 602 break; 603 case DW_CFA_remember_state: 604 break; 605 case DW_CFA_restore_state: 606 break; 607 case DW_CFA_def_cfa: 608 f_state[CF_ADDR].rule = register_rule; 609 f_state[CF_ADDR].source_reg = val1; 610 f_state[CF_ADDR].offset = val2; 611 break; 612 case DW_CFA_def_cfa_register: 613 f_state[CF_ADDR].source_reg = val1; 614 break; 615 case DW_CFA_def_cfa_offset: 616 f_state[CF_ADDR].offset = val1; 617 break; 618 case DW_CFA_def_cfa_expression: 619 break; 620 case DW_CFA_expression: 621 break; 622 case DW_CFA_offset_extended_sf: 623 f_state[val1].rule = offset_rule; 624 f_state[val1].source_reg = CF_ADDR; 625 f_state[val1].offset = val2; 626 break; 627 case DW_CFA_def_cfa_sf: 628 f_state[CF_ADDR].rule = register_rule; 629 f_state[CF_ADDR].source_reg = val1; 630 f_state[CF_ADDR].offset = val2; 631 break; 632 case DW_CFA_def_cfa_offset_sf: 633 f_state[CF_ADDR].offset = val1; 634 break; 635 case DW_CFA_SUNW_advance_loc: 636 if (*reached_pc_p + val1 > pc) 637 return (1); 638 *reached_pc_p += val1; 639 break; 640 case DW_CFA_SUNW_offset: 641 f_state[val1].rule = offset_rule; 642 f_state[val1].source_reg = CF_ADDR; 643 f_state[val1].offset = val2; 644 break; 645 case DW_CFA_SUNW_restore: 646 if (f_start_state != 0) 647 f_state[val1] = f_start_state[val1]; 648 break; 649 } 650 return (0); 651 } 652