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 * UNWIND - Unwind library 30 */ 31 32 /* 33 * ===================== stack walk ==================== 34 * 35 * Stack walk-back starts with the user code at the top of the stack 36 * calling a language specific support routine which calls the generic 37 * unwind code. The unwind code captures 38 * information which can be used to partially build an _Unwind_Context 39 * for the user code containing: 40 * 41 * callee saves registers <current values> 42 * PC 43 * %rbp 44 * %rsp 45 * 46 * Using that pc location the unwind info for the function is found. 47 * Then the CFA operations encoded in the unwind info are interepreted to get 48 * 49 * callee saves registers <values on entry> 50 * the return address 51 * cannonical frame address 52 * 53 * completing the context for the user function (See 54 * _Unw_Rollback_Registers()) . 55 * 56 * The values computed above are equivalent to the info which would have been 57 * captured from the caller and are used to initialize the callers context 58 * (see _Unw_Propagate_Registers()) which can be completed. 59 * 60 * Using the same two-step procedure 61 * context records for each frame down the stack may be constructed 62 * in turn. The ABI defined interface to _Unwind_Context provides 63 * access to 64 * 65 * callee saves registers <current values> 66 * current PC 67 * frame pointer 68 * 69 * and allows changing 70 * 71 * PC 72 * values of integer argument registers 73 * 74 * (changed values take effect if context is "installed" - think 75 * setcontext(2)) 76 * 77 */ 78 79 /* 80 * 81 * | | 82 * | local storage for start() | <FP == 0> 83 * | | 84 * --------------------------------. 85 * | | 86 * | .......... | 87 * | | <- CFA for bar() 88 * --------------------------------. 89 * | | 90 * | local storage for bar() | 91 * | | <- SP for bar(), CFA for foo() 92 * ................................ 93 * | pc for bar() | 94 * -------------------------------- 95 * | | 96 * | local storage for foo() | 97 * | | <- SP for foo(), CFA for ex_throw() 98 * ................................ 99 * | pc for foo() - PC3 | 100 * ................................ 101 * | saved RBP from foo() - BP3 | <- FP for ex_throw() == FP2 102 * -------------------------------- 103 * | | 104 * | local storage for ex_throw() | 105 * | | <- SP for ex_throw(), CFA for Unw() 106 * ................................ 107 * | pc for ex_throw() - PC2 | 108 * ................................ 109 * | saved RBP from ex_throw() | <- FP for Unw() == FP1 110 * -------------------------------- 111 * | | 112 * | local storage for Unw() | 113 * | | <- SP for Unw() == SP1 114 * 115 * We know that Unw() and ex_throw save and have an FP 116 * 117 */ 118 119 #ifdef _LIBCRUN_ 120 #define _Unwind_DeleteException _SUNW_Unwind_DeleteException 121 #define _Unwind_ForcedUnwind _SUNW_Unwind_ForcedUnwind 122 #define _Unwind_GetCFA _SUNW_Unwind_GetCFA 123 #define _Unwind_GetGR _SUNW_Unwind_GetGR 124 #define _Unwind_GetIP _SUNW_Unwind_GetIP 125 #define _Unwind_GetLanguageSpecificData _SUNW_Unwind_GetLanguageSpecificData 126 #define _Unwind_GetRegionStart _SUNW_Unwind_GetRegionStart 127 #define _Unwind_RaiseException _SUNW_Unwind_RaiseException 128 #define _Unwind_Resume _SUNW_Unwind_Resume 129 #define _Unwind_SetGR _SUNW_Unwind_SetGR 130 #define _Unwind_SetIP _SUNW_Unwind_SetIP 131 #else 132 #pragma weak _SUNW_Unwind_DeleteException = _Unwind_DeleteException 133 #pragma weak _SUNW_Unwind_ForcedUnwind = _Unwind_ForcedUnwind 134 #pragma weak _SUNW_Unwind_GetCFA = _Unwind_GetCFA 135 #pragma weak _SUNW_Unwind_GetGR = _Unwind_GetGR 136 #pragma weak _SUNW_Unwind_GetIP = _Unwind_GetIP 137 #pragma weak _SUNW_Unwind_GetLanguageSpecificData = \ 138 _Unwind_GetLanguageSpecificData 139 #pragma weak _SUNW_Unwind_GetRegionStart = _Unwind_GetRegionStart 140 #pragma weak _SUNW_Unwind_RaiseException = _Unwind_RaiseException 141 #pragma weak _SUNW_Unwind_Resume = _Unwind_Resume 142 #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR 143 #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP 144 #endif 145 146 #include "lint.h" 147 #include <string.h> 148 #include "stack_unwind.h" 149 #include "reg_num.h" 150 #include "unwind_context.h" 151 152 const _Unwind_Action _UA_SEARCH_PHASE = 1; 153 const _Unwind_Action _UA_CLEANUP_PHASE = 2; 154 const _Unwind_Action _UA_HANDLER_FRAME = 4; 155 const _Unwind_Action _UA_FORCE_UNWIND = 8; 156 157 void _Unw_capture_regs(uint64_t *regs); 158 void _Unw_jmp(uint64_t pc, uint64_t *regs); 159 160 static void 161 copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2) 162 { 163 if (ctx1 != ctx2) { 164 (void) memcpy(ctx2, ctx1, sizeof (*ctx2)); 165 } 166 } 167 168 static _Unwind_Personality_Fn 169 ctx_who(struct _Unwind_Context *ctx) 170 { 171 return (ctx->pfn); 172 } 173 174 /* ARGSUSED */ 175 _Unwind_Reason_Code 176 _Unw_very_boring_personality(int version, int actions, uint64_t exclass, 177 struct _Unwind_Exception *exception_object, 178 struct _Unwind_Context *ctx) 179 { 180 _Unwind_Reason_Code res = _URC_CONTINUE_UNWIND; 181 uint64_t fp; 182 183 fp = _Unwind_GetCFA(ctx); 184 if (fp == 0 || _Unwind_GetIP(ctx) == 0) { 185 return (_URC_END_OF_STACK); 186 } 187 return (res); 188 } 189 190 /* 191 * The only static variables in this code - changed by debugging hook below 192 */ 193 static int using_ehf = 1; 194 static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality; 195 196 void 197 _SUNW_Unw_set_defaults(int use, uintptr_t def_per) 198 { 199 using_ehf = use; 200 def_per_fcn = def_per; 201 } 202 203 static void 204 complete_context(struct _Unwind_Context *ctx) 205 { 206 struct eh_frame_fields sf; 207 struct eh_frame_fields *sfp = 0; 208 209 ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn; 210 ctx->lsda = 0; 211 ctx->func = 0; 212 ctx->range = 0; 213 ctx->fde = 0; 214 if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) { 215 sfp = _Unw_Decode_FDE(&sf, ctx); 216 } 217 (void) _Unw_Rollback_Registers(sfp, ctx); 218 } 219 220 /* 221 * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad)) 222 * 223 * FP2 = FP1[0]; 224 * BP3 = FP2[0]; 225 * PC3 = FP2[1]; 226 * SP3 = FP2 + 16; 227 * 228 * output: PC3, SP3, and BP3 229 * 230 * remaining callee saves registers are also captured in context 231 */ 232 static void 233 finish_capture(struct _Unwind_Context *ctx, int from_landing_pad) 234 { 235 uint64_t fp1 = ctx->current_regs[FP_RBP]; 236 uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0]; 237 238 ctx->pc = ((uint64_t *)fp2)[1]; 239 ctx->current_regs[SP_RSP] = fp2 + 16; 240 ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0]; 241 complete_context(ctx); 242 } 243 244 static int 245 down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx) 246 { 247 uint64_t old_cfa = old_ctx->cfa; 248 uint64_t old_pc = old_ctx->pc; 249 uint64_t new_cfa; 250 251 if (old_cfa == 0 || old_pc == 0) { 252 new_ctx->pc = 0; 253 new_ctx->cfa = 0; 254 new_ctx->ra = 0; 255 return (1); 256 } 257 if (old_ctx->ra == 0) { 258 new_ctx->pc = 0; 259 new_ctx->cfa = 0; 260 new_ctx->ra = 0; 261 return (0); 262 } 263 /* now shift ----------------------------- */ 264 _Unw_Propagate_Registers(old_ctx, new_ctx); 265 complete_context(new_ctx); 266 new_cfa = new_ctx->cfa; 267 if ((new_cfa < old_cfa) || (new_cfa & 7)) { 268 new_ctx->pc = 0; 269 new_ctx->cfa = 0; 270 new_ctx->ra = 0; 271 } 272 return (0); 273 } 274 275 static void 276 jmp_ctx(struct _Unwind_Context *ctx) 277 { 278 _Unw_jmp(ctx->pc, ctx->current_regs); 279 } 280 281 /* 282 * Here starts the real work - the entry points from either a language 283 * runtime or directly from user code. 284 * 285 * The two ..._Body functions are intended as private interfaces for 286 * Sun code as well so should remain accessible. 287 */ 288 _Unwind_Reason_Code 289 _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object, 290 struct _Unwind_Context *entry_ctx, int phase) 291 { 292 struct _Unwind_Context context; 293 struct _Unwind_Context *ctx = &context; 294 _Unwind_Reason_Code res; 295 296 if (phase & _UA_SEARCH_PHASE) { 297 finish_capture(entry_ctx, 0); 298 copy_ctx(entry_ctx, ctx); 299 300 for (;;) { 301 res = (*ctx_who(ctx))(1, phase, 302 exception_object->exception_class, 303 exception_object, ctx); 304 if (res != _URC_CONTINUE_UNWIND) 305 break; 306 if (down_one(ctx, ctx)) 307 return (_URC_FATAL_PHASE1_ERROR); 308 } 309 switch (res) { 310 case _URC_HANDLER_FOUND: 311 exception_object->private_2 = _Unwind_GetCFA(ctx); 312 break; 313 default: 314 return (res); 315 } 316 } else { 317 finish_capture(entry_ctx, 1); 318 if (down_one(entry_ctx, entry_ctx)) 319 return (_URC_FATAL_PHASE2_ERROR); 320 } 321 322 phase = _UA_CLEANUP_PHASE; 323 copy_ctx(entry_ctx, ctx); 324 325 for (;;) { 326 if (exception_object->private_2 == _Unwind_GetCFA(ctx)) { 327 phase |= _UA_HANDLER_FRAME; 328 } 329 res = (*ctx_who(ctx))(1, phase, 330 exception_object->exception_class, 331 exception_object, ctx); 332 if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT) 333 return (_URC_FATAL_PHASE2_ERROR); 334 if (res != _URC_CONTINUE_UNWIND) 335 break; 336 if (down_one(ctx, ctx)) 337 return (_URC_FATAL_PHASE2_ERROR); 338 } 339 switch (res) { 340 case _URC_INSTALL_CONTEXT: 341 exception_object->private_1 = 0; 342 jmp_ctx(ctx); /* does not return */ 343 break; 344 default: 345 break; 346 } 347 return (res); 348 } 349 350 _Unwind_Reason_Code 351 _Unwind_RaiseException(struct _Unwind_Exception *exception_object) 352 { 353 struct _Unwind_Context entry_context; 354 struct _Unwind_Context *entry_ctx = &entry_context; 355 356 _Unw_capture_regs(entry_ctx->current_regs); 357 358 return (_Unwind_RaiseException_Body(exception_object, entry_ctx, 359 _UA_SEARCH_PHASE)); 360 } 361 362 _Unwind_Reason_Code 363 _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object, 364 _Unwind_Stop_Fn stop, void *stop_parameter, 365 struct _Unwind_Context *ctx, int resume) 366 { 367 _Unwind_Reason_Code res; 368 int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND; 369 370 int again; 371 int doper; 372 373 finish_capture(ctx, resume); 374 if (resume && down_one(ctx, ctx)) 375 return (_URC_FATAL_PHASE2_ERROR); 376 377 do { 378 again = 0; 379 doper = 0; 380 res = (*stop)(1, phase, 381 exception_object->exception_class, 382 exception_object, ctx, stop_parameter); 383 switch (res) { 384 case _URC_CONTINUE_UNWIND: 385 /* keep going - don't call personality */ 386 again = 1; 387 break; 388 case _URC_NO_REASON: 389 /* keep going - do call personality */ 390 again = 1; 391 doper = 1; 392 break; 393 case _URC_NORMAL_STOP: /* done */ 394 break; 395 case _URC_INSTALL_CONTEXT: /* resume execution */ 396 break; 397 default: /* failure */ 398 break; 399 } 400 if (doper) { 401 res = (*ctx_who(ctx))(1, phase, 402 exception_object->exception_class, 403 exception_object, ctx); 404 } 405 switch (res) { 406 case _URC_INSTALL_CONTEXT: 407 exception_object->private_1 = (uint64_t)stop; 408 exception_object->private_2 = (uint64_t)stop_parameter; 409 jmp_ctx(ctx); /* does not return */ 410 break; 411 case _URC_CONTINUE_UNWIND: 412 case _URC_NO_REASON: 413 break; 414 case _URC_END_OF_STACK: 415 ctx->cfa = ctx->ra = ctx->pc = 0; 416 res = (*stop)(1, phase, 417 exception_object->exception_class, 418 exception_object, ctx, stop_parameter); 419 return (_URC_END_OF_STACK); 420 default: 421 again = 0; 422 break; 423 } 424 if (again) { 425 if (down_one(ctx, ctx)) { 426 return (_URC_FATAL_PHASE2_ERROR); 427 } 428 } 429 } while (again); 430 431 return (res); 432 } 433 434 _Unwind_Reason_Code 435 _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, 436 _Unwind_Stop_Fn stop, void *stop_parameter) 437 { 438 struct _Unwind_Context context; 439 struct _Unwind_Context *ctx = &context; 440 441 _Unw_capture_regs(ctx->current_regs); 442 443 return (_Unwind_ForcedUnwind_Body(exception_object, stop, 444 stop_parameter, ctx, 0)); 445 } 446 447 void 448 _Unwind_Resume(struct _Unwind_Exception *exception_object) 449 { 450 451 struct _Unwind_Context context; 452 struct _Unwind_Context *ctx = &context; 453 454 _Unw_capture_regs(ctx->current_regs); 455 456 if (exception_object->private_1) 457 (void) _Unwind_ForcedUnwind_Body(exception_object, 458 (_Unwind_Stop_Fn)exception_object->private_1, 459 (void *)exception_object->private_2, 460 ctx, 1); 461 else 462 (void) _Unwind_RaiseException_Body(exception_object, ctx, 463 _UA_CLEANUP_PHASE); 464 } 465 466 /* Calls destructor function for exception object */ 467 void 468 _Unwind_DeleteException(struct _Unwind_Exception *exception_object) 469 { 470 if (exception_object->exception_cleanup != 0) 471 (*(exception_object->exception_cleanup))(_URC_NO_REASON, 472 exception_object); 473 } 474 475 476 /* 477 * stack frame context accessors defined in ABI 478 * (despite all the dire text in the ABI these are reliable Get/Set routines) 479 * Note: RA is handled as GR value 480 */ 481 uint64_t 482 _Unwind_GetGR(struct _Unwind_Context *context, int index) 483 { 484 uint64_t res = 0; 485 if (index <= EIR_R15) { 486 res = context->current_regs[index]; 487 } else if (index == RET_ADD) { 488 res = context->ra; 489 } 490 return (res); 491 } 492 493 494 void 495 _Unwind_SetGR(struct _Unwind_Context *context, int index, 496 uint64_t new_value) 497 { 498 if (index <= EIR_R15) { 499 context->current_regs[index] = new_value; 500 } else if (index == RET_ADD) { 501 context->ra = new_value; 502 } 503 } 504 505 506 uint64_t 507 _Unwind_GetIP(struct _Unwind_Context *context) 508 { 509 return (context->pc); 510 } 511 512 void 513 _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value) 514 { 515 context->pc = new_value; 516 } 517 518 519 void * 520 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) 521 { 522 return (context->lsda); 523 } 524 525 526 uint64_t 527 _Unwind_GetRegionStart(struct _Unwind_Context *context) 528 { 529 return (context->func); 530 } 531 532 uint64_t 533 _Unwind_GetCFA(struct _Unwind_Context *context) 534 { 535 return (context->cfa); 536 } 537