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 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 27 */ 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_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_Resume = _Unwind_Resume 141 #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR 142 #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP 143 #endif 144 145 #include "lint.h" 146 #include <string.h> 147 #include "stack_unwind.h" 148 #include "reg_num.h" 149 #include "unwind_context.h" 150 151 const _Unwind_Action _UA_SEARCH_PHASE = 1; 152 const _Unwind_Action _UA_CLEANUP_PHASE = 2; 153 const _Unwind_Action _UA_HANDLER_FRAME = 4; 154 const _Unwind_Action _UA_FORCE_UNWIND = 8; 155 156 void _Unw_capture_regs(uint64_t *regs); 157 void _Unw_jmp(uint64_t pc, uint64_t *regs); 158 159 static void 160 copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2) 161 { 162 if (ctx1 != ctx2) { 163 (void) memcpy(ctx2, ctx1, sizeof (*ctx2)); 164 } 165 } 166 167 static _Unwind_Personality_Fn 168 ctx_who(struct _Unwind_Context *ctx) 169 { 170 return (ctx->pfn); 171 } 172 173 _Unwind_Reason_Code 174 _Unw_very_boring_personality(int version __unused, int actions __unused, 175 uint64_t exclass __unused, 176 struct _Unwind_Exception *exception_object __unused, 177 struct _Unwind_Context *ctx) 178 { 179 _Unwind_Reason_Code res = _URC_CONTINUE_UNWIND; 180 uint64_t fp; 181 182 fp = _Unwind_GetCFA(ctx); 183 if (fp == 0 || _Unwind_GetIP(ctx) == 0) { 184 return (_URC_END_OF_STACK); 185 } 186 return (res); 187 } 188 189 /* 190 * The only static variables in this code - changed by debugging hook below 191 */ 192 static int using_ehf = 1; 193 static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality; 194 195 void 196 _SUNW_Unw_set_defaults(int use, uintptr_t def_per) 197 { 198 using_ehf = use; 199 def_per_fcn = def_per; 200 } 201 202 static void 203 complete_context(struct _Unwind_Context *ctx) 204 { 205 struct eh_frame_fields sf; 206 struct eh_frame_fields *sfp = 0; 207 208 ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn; 209 ctx->lsda = 0; 210 ctx->func = 0; 211 ctx->range = 0; 212 ctx->fde = 0; 213 if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) { 214 sfp = _Unw_Decode_FDE(&sf, ctx); 215 } 216 (void) _Unw_Rollback_Registers(sfp, ctx); 217 } 218 219 /* 220 * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad)) 221 * 222 * FP2 = FP1[0]; 223 * BP3 = FP2[0]; 224 * PC3 = FP2[1]; 225 * SP3 = FP2 + 16; 226 * 227 * output: PC3, SP3, and BP3 228 * 229 * remaining callee saves registers are also captured in context 230 */ 231 static void 232 finish_capture(struct _Unwind_Context *ctx, int from_landing_pad) 233 { 234 uint64_t fp1 = ctx->current_regs[FP_RBP]; 235 uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0]; 236 237 ctx->pc = ((uint64_t *)fp2)[1]; 238 ctx->current_regs[SP_RSP] = fp2 + 16; 239 ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0]; 240 complete_context(ctx); 241 } 242 243 static int 244 down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx) 245 { 246 uint64_t old_cfa = old_ctx->cfa; 247 uint64_t old_pc = old_ctx->pc; 248 uint64_t new_cfa; 249 250 if (old_cfa == 0 || old_pc == 0) { 251 new_ctx->pc = 0; 252 new_ctx->cfa = 0; 253 new_ctx->ra = 0; 254 return (1); 255 } 256 if (old_ctx->ra == 0) { 257 new_ctx->pc = 0; 258 new_ctx->cfa = 0; 259 new_ctx->ra = 0; 260 return (0); 261 } 262 /* now shift ----------------------------- */ 263 _Unw_Propagate_Registers(old_ctx, new_ctx); 264 complete_context(new_ctx); 265 new_cfa = new_ctx->cfa; 266 if ((new_cfa < old_cfa) || (new_cfa & 7)) { 267 new_ctx->pc = 0; 268 new_ctx->cfa = 0; 269 new_ctx->ra = 0; 270 } 271 return (0); 272 } 273 274 static void 275 jmp_ctx(struct _Unwind_Context *ctx) 276 { 277 _Unw_jmp(ctx->pc, ctx->current_regs); 278 } 279 280 /* 281 * Here starts the real work - the entry points from either a language 282 * runtime or directly from user code. 283 * 284 * The two ..._Body functions are intended as private interfaces for 285 * Sun code as well so should remain accessible. 286 */ 287 _Unwind_Reason_Code 288 _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object, 289 struct _Unwind_Context *entry_ctx, int phase) 290 { 291 struct _Unwind_Context context; 292 struct _Unwind_Context *ctx = &context; 293 _Unwind_Reason_Code res; 294 295 if (phase & _UA_SEARCH_PHASE) { 296 finish_capture(entry_ctx, 0); 297 copy_ctx(entry_ctx, ctx); 298 299 for (;;) { 300 res = (*ctx_who(ctx))(1, phase, 301 exception_object->exception_class, 302 exception_object, ctx); 303 if (res != _URC_CONTINUE_UNWIND) 304 break; 305 if (down_one(ctx, ctx)) 306 return (_URC_FATAL_PHASE1_ERROR); 307 } 308 switch (res) { 309 case _URC_HANDLER_FOUND: 310 exception_object->private_2 = _Unwind_GetCFA(ctx); 311 break; 312 default: 313 return (res); 314 } 315 } else { 316 finish_capture(entry_ctx, 1); 317 if (down_one(entry_ctx, entry_ctx)) 318 return (_URC_FATAL_PHASE2_ERROR); 319 } 320 321 phase = _UA_CLEANUP_PHASE; 322 copy_ctx(entry_ctx, ctx); 323 324 for (;;) { 325 if (exception_object->private_2 == _Unwind_GetCFA(ctx)) { 326 phase |= _UA_HANDLER_FRAME; 327 } 328 res = (*ctx_who(ctx))(1, phase, 329 exception_object->exception_class, 330 exception_object, ctx); 331 if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT) 332 return (_URC_FATAL_PHASE2_ERROR); 333 if (res != _URC_CONTINUE_UNWIND) 334 break; 335 if (down_one(ctx, ctx)) 336 return (_URC_FATAL_PHASE2_ERROR); 337 } 338 switch (res) { 339 case _URC_INSTALL_CONTEXT: 340 exception_object->private_1 = 0; 341 jmp_ctx(ctx); /* does not return */ 342 break; 343 default: 344 break; 345 } 346 return (res); 347 } 348 349 /* 350 * Unfortunately, the closed source libCrun.so library calls into the 351 * _Unwind_RaiseException function without ensuring that the stack pointer 352 * is properly aligned. Some of the downstream functions use SSE instructions 353 * and raise GP when the stack is not aligned. 354 * To work around this, the entry point for _Unwind_RaiseException is 355 * implemented in assembler (in unwind_wrap.s) and it properly aligns the stack 356 * before calling the real function here. 357 */ 358 _Unwind_Reason_Code 359 __Unwind_RaiseException_Backend(struct _Unwind_Exception *exception_object) 360 { 361 struct _Unwind_Context entry_context; 362 struct _Unwind_Context *entry_ctx = &entry_context; 363 364 _Unw_capture_regs(entry_ctx->current_regs); 365 366 return (_Unwind_RaiseException_Body(exception_object, entry_ctx, 367 _UA_SEARCH_PHASE)); 368 } 369 370 _Unwind_Reason_Code 371 _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object, 372 _Unwind_Stop_Fn stop, void *stop_parameter, 373 struct _Unwind_Context *ctx, int resume) 374 { 375 _Unwind_Reason_Code res; 376 int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND; 377 378 int again; 379 int doper; 380 381 finish_capture(ctx, resume); 382 if (resume && down_one(ctx, ctx)) 383 return (_URC_FATAL_PHASE2_ERROR); 384 385 do { 386 again = 0; 387 doper = 0; 388 res = (*stop)(1, phase, 389 exception_object->exception_class, 390 exception_object, ctx, stop_parameter); 391 switch (res) { 392 case _URC_CONTINUE_UNWIND: 393 /* keep going - don't call personality */ 394 again = 1; 395 break; 396 case _URC_NO_REASON: 397 /* keep going - do call personality */ 398 again = 1; 399 doper = 1; 400 break; 401 case _URC_NORMAL_STOP: /* done */ 402 break; 403 case _URC_INSTALL_CONTEXT: /* resume execution */ 404 break; 405 default: /* failure */ 406 break; 407 } 408 if (doper) { 409 res = (*ctx_who(ctx))(1, phase, 410 exception_object->exception_class, 411 exception_object, ctx); 412 } 413 switch (res) { 414 case _URC_INSTALL_CONTEXT: 415 exception_object->private_1 = (uint64_t)stop; 416 exception_object->private_2 = (uint64_t)stop_parameter; 417 jmp_ctx(ctx); /* does not return */ 418 break; 419 case _URC_CONTINUE_UNWIND: 420 case _URC_NO_REASON: 421 break; 422 case _URC_END_OF_STACK: 423 ctx->cfa = ctx->ra = ctx->pc = 0; 424 res = (*stop)(1, phase, 425 exception_object->exception_class, 426 exception_object, ctx, stop_parameter); 427 return (_URC_END_OF_STACK); 428 default: 429 again = 0; 430 break; 431 } 432 if (again) { 433 if (down_one(ctx, ctx)) { 434 return (_URC_FATAL_PHASE2_ERROR); 435 } 436 } 437 } while (again); 438 439 return (res); 440 } 441 442 _Unwind_Reason_Code 443 _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, 444 _Unwind_Stop_Fn stop, void *stop_parameter) 445 { 446 struct _Unwind_Context context; 447 struct _Unwind_Context *ctx = &context; 448 449 _Unw_capture_regs(ctx->current_regs); 450 451 return (_Unwind_ForcedUnwind_Body(exception_object, stop, 452 stop_parameter, ctx, 0)); 453 } 454 455 void 456 _Unwind_Resume(struct _Unwind_Exception *exception_object) 457 { 458 struct _Unwind_Context context; 459 struct _Unwind_Context *ctx = &context; 460 461 _Unw_capture_regs(ctx->current_regs); 462 463 if (exception_object->private_1) 464 (void) _Unwind_ForcedUnwind_Body(exception_object, 465 (_Unwind_Stop_Fn)exception_object->private_1, 466 (void *)exception_object->private_2, 467 ctx, 1); 468 else 469 (void) _Unwind_RaiseException_Body(exception_object, ctx, 470 _UA_CLEANUP_PHASE); 471 } 472 473 /* Calls destructor function for exception object */ 474 void 475 _Unwind_DeleteException(struct _Unwind_Exception *exception_object) 476 { 477 if (exception_object->exception_cleanup != 0) 478 (*(exception_object->exception_cleanup))(_URC_NO_REASON, 479 exception_object); 480 } 481 482 483 /* 484 * stack frame context accessors defined in ABI 485 * (despite all the dire text in the ABI these are reliable Get/Set routines) 486 * Note: RA is handled as GR value 487 */ 488 uint64_t 489 _Unwind_GetGR(struct _Unwind_Context *context, int index) 490 { 491 uint64_t res = 0; 492 if (index <= EIR_R15) { 493 res = context->current_regs[index]; 494 } else if (index == RET_ADD) { 495 res = context->ra; 496 } 497 return (res); 498 } 499 500 501 void 502 _Unwind_SetGR(struct _Unwind_Context *context, int index, uint64_t new_value) 503 { 504 if (index <= EIR_R15) { 505 context->current_regs[index] = new_value; 506 } else if (index == RET_ADD) { 507 context->ra = new_value; 508 } 509 } 510 511 512 uint64_t 513 _Unwind_GetIP(struct _Unwind_Context *context) 514 { 515 return (context->pc); 516 } 517 518 void 519 _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value) 520 { 521 context->pc = new_value; 522 } 523 524 525 void * 526 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) 527 { 528 return (context->lsda); 529 } 530 531 532 uint64_t 533 _Unwind_GetRegionStart(struct _Unwind_Context *context) 534 { 535 return (context->func); 536 } 537 538 uint64_t 539 _Unwind_GetCFA(struct _Unwind_Context *context) 540 { 541 return (context->cfa); 542 } 543