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 /* ARGSUSED */ 174 _Unwind_Reason_Code 175 _Unw_very_boring_personality(int version, int actions, uint64_t exclass, 176 struct _Unwind_Exception *exception_object, struct _Unwind_Context *ctx) 177 { 178 _Unwind_Reason_Code res = _URC_CONTINUE_UNWIND; 179 uint64_t fp; 180 181 fp = _Unwind_GetCFA(ctx); 182 if (fp == 0 || _Unwind_GetIP(ctx) == 0) { 183 return (_URC_END_OF_STACK); 184 } 185 return (res); 186 } 187 188 /* 189 * The only static variables in this code - changed by debugging hook below 190 */ 191 static int using_ehf = 1; 192 static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality; 193 194 void 195 _SUNW_Unw_set_defaults(int use, uintptr_t def_per) 196 { 197 using_ehf = use; 198 def_per_fcn = def_per; 199 } 200 201 static void 202 complete_context(struct _Unwind_Context *ctx) 203 { 204 struct eh_frame_fields sf; 205 struct eh_frame_fields *sfp = 0; 206 207 ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn; 208 ctx->lsda = 0; 209 ctx->func = 0; 210 ctx->range = 0; 211 ctx->fde = 0; 212 if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) { 213 sfp = _Unw_Decode_FDE(&sf, ctx); 214 } 215 (void) _Unw_Rollback_Registers(sfp, ctx); 216 } 217 218 /* 219 * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad)) 220 * 221 * FP2 = FP1[0]; 222 * BP3 = FP2[0]; 223 * PC3 = FP2[1]; 224 * SP3 = FP2 + 16; 225 * 226 * output: PC3, SP3, and BP3 227 * 228 * remaining callee saves registers are also captured in context 229 */ 230 static void 231 finish_capture(struct _Unwind_Context *ctx, int from_landing_pad) 232 { 233 uint64_t fp1 = ctx->current_regs[FP_RBP]; 234 uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0]; 235 236 ctx->pc = ((uint64_t *)fp2)[1]; 237 ctx->current_regs[SP_RSP] = fp2 + 16; 238 ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0]; 239 complete_context(ctx); 240 } 241 242 static int 243 down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx) 244 { 245 uint64_t old_cfa = old_ctx->cfa; 246 uint64_t old_pc = old_ctx->pc; 247 uint64_t new_cfa; 248 249 if (old_cfa == 0 || old_pc == 0) { 250 new_ctx->pc = 0; 251 new_ctx->cfa = 0; 252 new_ctx->ra = 0; 253 return (1); 254 } 255 if (old_ctx->ra == 0) { 256 new_ctx->pc = 0; 257 new_ctx->cfa = 0; 258 new_ctx->ra = 0; 259 return (0); 260 } 261 /* now shift ----------------------------- */ 262 _Unw_Propagate_Registers(old_ctx, new_ctx); 263 complete_context(new_ctx); 264 new_cfa = new_ctx->cfa; 265 if ((new_cfa < old_cfa) || (new_cfa & 7)) { 266 new_ctx->pc = 0; 267 new_ctx->cfa = 0; 268 new_ctx->ra = 0; 269 } 270 return (0); 271 } 272 273 static void 274 jmp_ctx(struct _Unwind_Context *ctx) 275 { 276 _Unw_jmp(ctx->pc, ctx->current_regs); 277 } 278 279 /* 280 * Here starts the real work - the entry points from either a language 281 * runtime or directly from user code. 282 * 283 * The two ..._Body functions are intended as private interfaces for 284 * Sun code as well so should remain accessible. 285 */ 286 _Unwind_Reason_Code 287 _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object, 288 struct _Unwind_Context *entry_ctx, int phase) 289 { 290 struct _Unwind_Context context; 291 struct _Unwind_Context *ctx = &context; 292 _Unwind_Reason_Code res; 293 294 if (phase & _UA_SEARCH_PHASE) { 295 finish_capture(entry_ctx, 0); 296 copy_ctx(entry_ctx, ctx); 297 298 for (;;) { 299 res = (*ctx_who(ctx))(1, phase, 300 exception_object->exception_class, 301 exception_object, ctx); 302 if (res != _URC_CONTINUE_UNWIND) 303 break; 304 if (down_one(ctx, ctx)) 305 return (_URC_FATAL_PHASE1_ERROR); 306 } 307 switch (res) { 308 case _URC_HANDLER_FOUND: 309 exception_object->private_2 = _Unwind_GetCFA(ctx); 310 break; 311 default: 312 return (res); 313 } 314 } else { 315 finish_capture(entry_ctx, 1); 316 if (down_one(entry_ctx, entry_ctx)) 317 return (_URC_FATAL_PHASE2_ERROR); 318 } 319 320 phase = _UA_CLEANUP_PHASE; 321 copy_ctx(entry_ctx, ctx); 322 323 for (;;) { 324 if (exception_object->private_2 == _Unwind_GetCFA(ctx)) { 325 phase |= _UA_HANDLER_FRAME; 326 } 327 res = (*ctx_who(ctx))(1, phase, 328 exception_object->exception_class, 329 exception_object, ctx); 330 if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT) 331 return (_URC_FATAL_PHASE2_ERROR); 332 if (res != _URC_CONTINUE_UNWIND) 333 break; 334 if (down_one(ctx, ctx)) 335 return (_URC_FATAL_PHASE2_ERROR); 336 } 337 switch (res) { 338 case _URC_INSTALL_CONTEXT: 339 exception_object->private_1 = 0; 340 jmp_ctx(ctx); /* does not return */ 341 break; 342 default: 343 break; 344 } 345 return (res); 346 } 347 348 /* 349 * Unfortunately, the closed source libCrun.so library calls into the 350 * _Unwind_RaiseException function without ensuring that the stack pointer 351 * is properly aligned. Some of the downstream functions use SSE instructions 352 * and raise GP when the stack is not aligned. 353 * To work around this, the entry point for _Unwind_RaiseException is 354 * implemented in assembler (in unwind_wrap.s) and it properly aligns the stack 355 * before calling the real function here. 356 */ 357 _Unwind_Reason_Code 358 __Unwind_RaiseException_Backend(struct _Unwind_Exception *exception_object) 359 { 360 struct _Unwind_Context entry_context; 361 struct _Unwind_Context *entry_ctx = &entry_context; 362 363 _Unw_capture_regs(entry_ctx->current_regs); 364 365 return (_Unwind_RaiseException_Body(exception_object, entry_ctx, 366 _UA_SEARCH_PHASE)); 367 } 368 369 _Unwind_Reason_Code 370 _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object, 371 _Unwind_Stop_Fn stop, void *stop_parameter, 372 struct _Unwind_Context *ctx, int resume) 373 { 374 _Unwind_Reason_Code res; 375 int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND; 376 377 int again; 378 int doper; 379 380 finish_capture(ctx, resume); 381 if (resume && down_one(ctx, ctx)) 382 return (_URC_FATAL_PHASE2_ERROR); 383 384 do { 385 again = 0; 386 doper = 0; 387 res = (*stop)(1, phase, 388 exception_object->exception_class, 389 exception_object, ctx, stop_parameter); 390 switch (res) { 391 case _URC_CONTINUE_UNWIND: 392 /* keep going - don't call personality */ 393 again = 1; 394 break; 395 case _URC_NO_REASON: 396 /* keep going - do call personality */ 397 again = 1; 398 doper = 1; 399 break; 400 case _URC_NORMAL_STOP: /* done */ 401 break; 402 case _URC_INSTALL_CONTEXT: /* resume execution */ 403 break; 404 default: /* failure */ 405 break; 406 } 407 if (doper) { 408 res = (*ctx_who(ctx))(1, phase, 409 exception_object->exception_class, 410 exception_object, ctx); 411 } 412 switch (res) { 413 case _URC_INSTALL_CONTEXT: 414 exception_object->private_1 = (uint64_t)stop; 415 exception_object->private_2 = (uint64_t)stop_parameter; 416 jmp_ctx(ctx); /* does not return */ 417 break; 418 case _URC_CONTINUE_UNWIND: 419 case _URC_NO_REASON: 420 break; 421 case _URC_END_OF_STACK: 422 ctx->cfa = ctx->ra = ctx->pc = 0; 423 res = (*stop)(1, phase, 424 exception_object->exception_class, 425 exception_object, ctx, stop_parameter); 426 return (_URC_END_OF_STACK); 427 default: 428 again = 0; 429 break; 430 } 431 if (again) { 432 if (down_one(ctx, ctx)) { 433 return (_URC_FATAL_PHASE2_ERROR); 434 } 435 } 436 } while (again); 437 438 return (res); 439 } 440 441 _Unwind_Reason_Code 442 _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, 443 _Unwind_Stop_Fn stop, void *stop_parameter) 444 { 445 struct _Unwind_Context context; 446 struct _Unwind_Context *ctx = &context; 447 448 _Unw_capture_regs(ctx->current_regs); 449 450 return (_Unwind_ForcedUnwind_Body(exception_object, stop, 451 stop_parameter, ctx, 0)); 452 } 453 454 void 455 _Unwind_Resume(struct _Unwind_Exception *exception_object) 456 { 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