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