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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * interface used by unwind support to query frame descriptor info
36 #include <sys/types.h>
38 #include "stack_unwind.h"
39 #include "unwind_context.h"
47 * ZTSTRING augmentation
48 * ULEB128 Code Align Factor
49 * SLEB128 Data Align Factor
52 * UNUM8 personality enc
67 struct eh_frame_fields
*
68 _Unw_Decode_FDE(struct eh_frame_fields
*f
, struct _Unwind_Context
*ctx
)
70 void *fde_data
; /* location in this process of fde */
75 void *cie_data
; /* location in this process of cie */
88 _Unwind_Personality_Fn pfn
= 0;
91 /* here is where data mapping would happen ??REMOTE?? */
94 fde_end
= (void *)(((intptr_t)fde_data
) + 4 +
95 _Unw_get_val(&data
, 0, UNUM32
, 1, 1, 0));
97 base
= ((intptr_t)data
) + reloc
;
98 cie_data
= (void *)(base
- _Unw_get_val(&data
, 0, UNUM32
, 1, 1, 0));
100 cie_end
= (void *)(((intptr_t)cie_data
) + 4 +
101 _Unw_get_val(&cdata
, 0, UNUM32
, 1, 1, 0));
103 /* data mapping has happened */
105 f
->cie_ops_end
= cie_end
;
106 f
->cie_reloc
= creloc
;
107 f
->fde_ops_end
= fde_end
;
108 f
->fde_reloc
= reloc
;
110 (void) _Unw_get_val(&cdata
, creloc
, UNUM32
, 1, 1, 0);
111 (void) _Unw_get_val(&cdata
, creloc
, UNUM8
, 1, 1, 0);
112 /* LINTED alignment */
113 (*((uint64_t *)(&(augment
[0])))) =
114 _Unw_get_val(&cdata
, creloc
, ZTSTRING
, 1, 1, 0);
115 f
->code_align
= _Unw_get_val(&cdata
, creloc
, ULEB128
, 1, 1, 0);
116 f
->data_align
= _Unw_get_val(&cdata
, creloc
, SLEB128
, 1, 1, 0);
117 (void) _Unw_get_val(&cdata
, creloc
, UNUM8
, 1, 1, 0);
118 if (augment
[0] == 'z' &&
119 (scratch
= _Unw_get_val(&cdata
, creloc
, ULEB128
, 1, 1, 0)) != 0) {
120 for (p
= &(augment
[1]); *p
!= 0; p
++) {
123 per_enc
= _Unw_get_val(&cdata
, creloc
,
127 pfn
= (_Unwind_Personality_Fn
)
128 _Unw_get_val(&cdata
, creloc
,
129 ADDR
, 1, 1, per_enc
);
132 code_enc
= _Unw_get_val(&cdata
, creloc
,
136 lsda_enc
= _Unw_get_val(&cdata
, creloc
,
145 func
= _Unw_get_val(&data
, reloc
, ADDR
, 1, 1, code_enc
);
146 range
= _Unw_get_val(&data
, reloc
, SIZE
, 1, 1, code_enc
);
147 if ((ctx
->pc
< func
) || (ctx
->pc
> (func
+range
)))
151 if (augment
[0] == 'z') {
152 scratch
= _Unw_get_val(&data
, reloc
, ULEB128
, 1, 1, 0);
153 if (scratch
== 4 && lsda_enc
) {
155 * without the two work-arounds test would be
156 * (scratch > 0 & lsda_enc)
158 lsda
= (void *)_Unw_get_val(&data
, reloc
,
159 ADDR
, 1, 1, lsda_enc
);
160 } else if (scratch
== 4) {
162 * 11/24/04 compiler is sometimes not outputing
165 lsda
= (void*)_Unw_get_val(&data
, reloc
,
167 } else if (scratch
== 8) {
169 * 11/12/04 - compiler is putting out relative
170 * encoding byte and absolute data - inconsistancy
173 lsda
= (void *)_Unw_get_val(&data
, reloc
,
183 f
->code_enc
= code_enc
;
188 table_ent_log_size(int enc
)
213 get_table_ent_val(unsigned char *data
, unsigned char *data_end
,
214 int enc
, ptrdiff_t reloc
, uintptr_t base
,
215 uint64_t *codep
, uint64_t *next_codep
, void **fdep
)
218 int rel
= (enc
>> 4) & 0xf;
219 unsigned char *second
= data
;
220 unsigned char *third
= data
;
227 /* LINTED alignment */
228 code
= (uint64_t)(*((uint32_t *)data
));
230 /* LINTED alignment */
231 fde
= (void *)(uint64_t)(*((uint32_t *)second
));
233 next_code
= (third
>= data_end
)? ULONG_MAX
:
234 /* LINTED alignment */
235 (uint64_t)(*((uint32_t *)third
));
238 /* LINTED alignment */
239 code
= (uint64_t)(*((uint64_t *)data
));
241 /* LINTED alignment */
242 fde
= (void *)(uint64_t)(*((uint64_t *)second
));
244 next_code
= (third
>= data_end
)? ULONG_MAX
:
245 /* LINTED alignment */
246 (uint64_t)(*((uint64_t *)third
));
249 /* LINTED alignment */
250 code
= (uint64_t)(int64_t)(*((int32_t *)data
));
252 /* LINTED alignment */
253 fde
= (void *)(uint64_t)(int64_t)(*((int32_t *)second
));
255 next_code
= (third
>= data_end
)? ULONG_MAX
:
256 /* LINTED alignment */
257 (uint64_t)(int64_t)(*((int32_t *)third
));
260 /* LINTED alignment */
261 code
= (uint64_t)(*((int64_t *)data
));
263 /* LINTED alignment */
264 fde
= (void *)(uint64_t)(*((int64_t *)second
));
266 next_code
= (third
>= data_end
)? ULONG_MAX
:
267 /* LINTED alignment */
268 (uint64_t)(*((int64_t *)third
));
276 code
+= (uint64_t)data
+ reloc
;
277 fde
= (void *)(((uint64_t)fde
) + (uint64_t)second
+ reloc
);
278 if (next_code
!= ULONG_MAX
)
279 next_code
+= (uint64_t)third
+ reloc
;
283 fde
= (void *)(((uint64_t)fde
) + base
);
284 if (next_code
!= ULONG_MAX
)
288 /* remainder not implemented */
293 *next_codep
= next_code
;
298 locate_fde_for_pc(uint64_t pc
, int enc
,
299 unsigned char *table
, unsigned char *table_end
,
300 ptrdiff_t reloc
, uintptr_t base
);
303 * Search the eh_frame info with a given pc. Return a pointer to a
304 * FDE. The search is performed in two stages.
305 * First rtld.so identifies the load module containing the target location.
306 * This returns the appropiate eh_frame_hdr, and a binary search is
307 * then performed on the eh_frame_hdr to locate the entry with
308 * a matching pc value.
311 _Unw_EhfhLookup(struct _Unwind_Context
*ctx
)
313 Dl_amd64_unwindinfo dlef
;
316 uint64_t pc
= ctx
->pc
;
317 int fp_enc
, fc_enc
, ft_enc
;
318 unsigned char *pi
, *pj
;
322 dlef
.dlui_version
= 1;
324 /* Locate the appropiate exception_range_entry table first */
325 if (0 == dlamd64getunwind((void*)pc
, &dlef
)) {
330 * you now know size and position of block of data needed for
331 * binary search ??REMOTE??
333 data
= dlef
.dlui_unwindstart
;
336 base
= (uintptr_t)data
;
337 data_end
= dlef
.dlui_unwindend
;
341 (void) _Unw_get_val(&data
, reloc
, UNUM8
, 1, 1, 0);
342 fp_enc
= _Unw_get_val(&data
, reloc
, UNUM8
, 1, 1, 0);
343 fc_enc
= _Unw_get_val(&data
, reloc
, UNUM8
, 1, 1, 0);
344 ft_enc
= _Unw_get_val(&data
, reloc
, UNUM8
, 1, 1, 0);
345 (void) _Unw_get_val(&data
, reloc
, ADDR
, 1, 1, fp_enc
);
346 (void) _Unw_get_val(&data
, reloc
, SIZE
, 1, 1, fc_enc
);
349 ctx
->fde
= locate_fde_for_pc(pc
, ft_enc
, pi
, pj
, reloc
, base
);
350 return ((void *)(ctx
->fde
));
354 locate_fde_for_pc(uint64_t pc
, int enc
,
355 unsigned char *table_bg
, unsigned char *table_end
,
356 ptrdiff_t reloc
, uintptr_t base
)
358 unsigned char *pi
= table_bg
;
359 unsigned char *pj
= table_end
;
360 uint64_t range_start
, range_end
;
362 int log_size
= table_ent_log_size(enc
);
365 * Invariant -- if there is a containing range,
366 * it must lie in the interval [pi,pj). That is,
367 * pi <= p < pj, if p exists.
371 pi
+ (((pj
- pi
) >> (log_size
+ 1)) << log_size
);
372 /* Don't use (pi+pj)>>1 */
373 get_table_ent_val(pr
, table_end
, enc
, reloc
, base
,
374 &range_start
, &range_end
, &fde
);
376 /* Return fde if tpc is in this range. */
378 if (range_start
<= pc
&& pc
< range_end
) {
379 return ((void*) fde
);
382 if (range_start
< pc
)
383 pi
= pr
+ (1 << log_size
);