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