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