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