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 */
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 _SUNW_Unwind_DeleteException = _Unwind_DeleteException
134 #pragma weak _SUNW_Unwind_ForcedUnwind = _Unwind_ForcedUnwind
135 #pragma weak _SUNW_Unwind_GetCFA = _Unwind_GetCFA
136 #pragma weak _SUNW_Unwind_GetGR = _Unwind_GetGR
137 #pragma weak _SUNW_Unwind_GetIP = _Unwind_GetIP
138 #pragma weak _SUNW_Unwind_GetLanguageSpecificData = \
139 _Unwind_GetLanguageSpecificData
140 #pragma weak _SUNW_Unwind_GetRegionStart = _Unwind_GetRegionStart
141 #pragma weak _SUNW_Unwind_RaiseException = _Unwind_RaiseException
142 #pragma weak _SUNW_Unwind_Resume = _Unwind_Resume
143 #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR
144 #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP
145 #endif
146
147 #include "lint.h"
148 #include <string.h>
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
copy_ctx(struct _Unwind_Context * ctx1,struct _Unwind_Context * ctx2)162 copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
163 {
164 if (ctx1 != ctx2) {
165 (void) memcpy(ctx2, ctx1, sizeof (*ctx2));
166 }
167 }
168
169 static _Unwind_Personality_Fn
ctx_who(struct _Unwind_Context * ctx)170 ctx_who(struct _Unwind_Context *ctx)
171 {
172 return (ctx->pfn);
173 }
174
175 /* ARGSUSED */
176 _Unwind_Reason_Code
_Unw_very_boring_personality(int version,int actions,uint64_t exclass,struct _Unwind_Exception * exception_object,struct _Unwind_Context * ctx)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
_SUNW_Unw_set_defaults(int use,uintptr_t def_per)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
complete_context(struct _Unwind_Context * ctx)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
finish_capture(struct _Unwind_Context * ctx,int from_landing_pad)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
down_one(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)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
jmp_ctx(struct _Unwind_Context * ctx)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
_Unwind_RaiseException_Body(struct _Unwind_Exception * exception_object,struct _Unwind_Context * entry_ctx,int phase)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
_Unwind_RaiseException(struct _Unwind_Exception * exception_object)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
_Unwind_ForcedUnwind_Body(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter,struct _Unwind_Context * ctx,int resume)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
_Unwind_ForcedUnwind(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter)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
_Unwind_Resume(struct _Unwind_Exception * exception_object)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
_Unwind_DeleteException(struct _Unwind_Exception * exception_object)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
_Unwind_GetGR(struct _Unwind_Context * context,int index)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
_Unwind_SetGR(struct _Unwind_Context * context,int index,uint64_t new_value)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
_Unwind_GetIP(struct _Unwind_Context * context)510 _Unwind_GetIP(struct _Unwind_Context *context)
511 {
512 return (context->pc);
513 }
514
515 void
_Unwind_SetIP(struct _Unwind_Context * context,uint64_t new_value)516 _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
517 {
518 context->pc = new_value;
519 }
520
521
522 void *
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)523 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
524 {
525 return (context->lsda);
526 }
527
528
529 uint64_t
_Unwind_GetRegionStart(struct _Unwind_Context * context)530 _Unwind_GetRegionStart(struct _Unwind_Context *context)
531 {
532 return (context->func);
533 }
534
535 uint64_t
_Unwind_GetCFA(struct _Unwind_Context * context)536 _Unwind_GetCFA(struct _Unwind_Context *context)
537 {
538 return (context->cfa);
539 }
540