Commit e1f9550a by Richard Henderson Committed by Richard Henderson

except.c (eh_data_format_name): Move to ...

	* except.c (eh_data_format_name): Move to ...
	* dwarf2asm.c: ... here.  Use designated initializers if available.
	(dw2_asm_output_encoded_addr_rtx): Accept varargs commentary.
	* dwarf2asm.h: Update declarations.
	* dwarf2out.c (output_cfi) [DW_CFA_set_loc]: If for_eh, mind
	ASM_PREFERRED_EH_DATA_FORMAT.
	(output_call_frame_info): Likewise.  Use 'L' augmentation for
	the LSDA encoding.

	* unwind-dw2-fde.h (struct fde_vector): New.
	(struct old_object): Rename from struct object.
	(struct object): New.
	(__register_frame_info_bases): Declare.
	(__register_frame_info_table_bases): Declare.
	(struct dwarf_fde): Remove explicit pc_begin/pc_range members.
	* unwind-dw2-fde.c (objects): Remove.
	(unseen_objects, seen_objects): New.
	(__register_frame_info_bases): New.
	(__register_frame_info): Use it.
	(__register_frame_info_table_bases): New.
	(__register_frame_info_table): Use it.
	(__deregister_frame_info): Rewrite for changed object struct.
	(base_from_object, get_cie_encoding, get_fde_encoding): New.
	(fde_unencoded_compare): Rename from fde_compare; uninline.
	(fde_single_encoding_compare, fde_mixed_encoding_compare): New.
	(start_fde_sort): Adjust for new definition of fde_vector.
	(fde_insert): Likewise.
	(end_fde_sort): Likewise.  Select comparison function based
	on properties of the object.
	(fde_split): Take object and fde_compare_t arguments.
	(frame_heapsort, fde_merge): Likewise.
	(classify_object_over_fdes): Rename from count_fdes.  Handle
	encoded pointers.  Collect encoding, mixed_encoding, and pc_begin
	for the object.
	(add_fdes): Handle encoded pointers.
	(init_object): Rename from frame_init.  Update for new struct object.
	(linear_search_fdes): Rename from search_fdes.  Handle encoded
	pointers.
	(binary_search_unencoded_fdes): Broken out from _Unwind_Find_FDE.
	(binary_search_single_encoding_fdes): New.
	(binary_search_mixed_encoding_fdes): New.
	(search_object): New.
	(_Unwind_Find_FDE): Update for new struct object.  Fill in
	the dwarf_eh_bases.
	* unwind-dw2.c: Include unwind-pe.h.  Constify all pointers
	iterating over EH data.
	(_Unwind_FrameState): Remove saw_lsda, addr_encoding.  Add
	fde_encoding, lsda_encoding.
	(read_uleb128, read_sleb128): Remove.
	(read_encoded_pointer): Remove.  All callers use read_encoded_value.
	(extract_cie_info): Set lsda_encoding from 'L' augmentation.
	(uw_frame_state_for): Don't set bases.func.  Handle encoded fde
	pointers.
	* unwind-pe.h: Add "struct" to _Unwind_Context references.

From-SVN: r42176
parent f2cf5c14
2001-05-16 Richard Henderson <rth@redhat.com>
* except.c (eh_data_format_name): Move to ...
* dwarf2asm.c: ... here. Use designated initializers if available.
(dw2_asm_output_encoded_addr_rtx): Accept varargs commentary.
* dwarf2asm.h: Update declarations.
* dwarf2out.c (output_cfi) [DW_CFA_set_loc]: If for_eh, mind
ASM_PREFERRED_EH_DATA_FORMAT.
(output_call_frame_info): Likewise. Use 'L' augmentation for
the LSDA encoding.
* unwind-dw2-fde.h (struct fde_vector): New.
(struct old_object): Rename from struct object.
(struct object): New.
(__register_frame_info_bases): Declare.
(__register_frame_info_table_bases): Declare.
(struct dwarf_fde): Remove explicit pc_begin/pc_range members.
* unwind-dw2-fde.c (objects): Remove.
(unseen_objects, seen_objects): New.
(__register_frame_info_bases): New.
(__register_frame_info): Use it.
(__register_frame_info_table_bases): New.
(__register_frame_info_table): Use it.
(__deregister_frame_info): Rewrite for changed object struct.
(base_from_object, get_cie_encoding, get_fde_encoding): New.
(fde_unencoded_compare): Rename from fde_compare; uninline.
(fde_single_encoding_compare, fde_mixed_encoding_compare): New.
(start_fde_sort): Adjust for new definition of fde_vector.
(fde_insert): Likewise.
(end_fde_sort): Likewise. Select comparison function based
on properties of the object.
(fde_split): Take object and fde_compare_t arguments.
(frame_heapsort, fde_merge): Likewise.
(classify_object_over_fdes): Rename from count_fdes. Handle
encoded pointers. Collect encoding, mixed_encoding, and pc_begin
for the object.
(add_fdes): Handle encoded pointers.
(init_object): Rename from frame_init. Update for new struct object.
(linear_search_fdes): Rename from search_fdes. Handle encoded
pointers.
(binary_search_unencoded_fdes): Broken out from _Unwind_Find_FDE.
(binary_search_single_encoding_fdes): New.
(binary_search_mixed_encoding_fdes): New.
(search_object): New.
(_Unwind_Find_FDE): Update for new struct object. Fill in
the dwarf_eh_bases.
* unwind-dw2.c: Include unwind-pe.h. Constify all pointers
iterating over EH data.
(_Unwind_FrameState): Remove saw_lsda, addr_encoding. Add
fde_encoding, lsda_encoding.
(read_uleb128, read_sleb128): Remove.
(read_encoded_pointer): Remove. All callers use read_encoded_value.
(extract_cie_info): Set lsda_encoding from 'L' augmentation.
(uw_frame_state_for): Don't set bases.func. Handle encoded fde
pointers.
* unwind-pe.h: Add "struct" to _Unwind_Context references.
2001-05-16 Neil Booth <neil@cat.daikokuya.demon.co.uk> 2001-05-16 Neil Booth <neil@cat.daikokuya.demon.co.uk>
* cppexp.c (lex): Use NODE_NAME and NODE_LEN. * cppexp.c (lex): Use NODE_NAME and NODE_LEN.
......
...@@ -470,6 +470,152 @@ size_of_encoded_value (encoding) ...@@ -470,6 +470,152 @@ size_of_encoded_value (encoding)
abort (); abort ();
} }
/* Yield a name for a given pointer encoding. */
const char *
eh_data_format_name (format)
int format;
{
#if HAVE_DESIGNATED_INITIALIZERS
#define S(p, v) [p] = v,
#else
#define S(p, v) case p: return v;
#endif
#if HAVE_DESIGNATED_INITIALIZERS
__extension__ static const char * const format_names[256] = {
#else
switch (format) {
#endif
S(DW_EH_PE_absptr, "absolute")
S(DW_EH_PE_omit, "omit")
S(DW_EH_PE_uleb128, "uleb128")
S(DW_EH_PE_udata2, "udata2")
S(DW_EH_PE_udata4, "udata4")
S(DW_EH_PE_udata8, "udata8")
S(DW_EH_PE_sleb128, "sleb128")
S(DW_EH_PE_sdata2, "sdata2")
S(DW_EH_PE_sdata4, "sdata4")
S(DW_EH_PE_sdata8, "sdata8")
S(DW_EH_PE_uleb128 | DW_EH_PE_pcrel, "pcrel uleb128")
S(DW_EH_PE_udata2 | DW_EH_PE_pcrel, "pcrel udata2")
S(DW_EH_PE_udata4 | DW_EH_PE_pcrel, "pcrel udata4")
S(DW_EH_PE_udata8 | DW_EH_PE_pcrel, "pcrel udata8")
S(DW_EH_PE_sleb128 | DW_EH_PE_pcrel, "pcrel sleb128")
S(DW_EH_PE_sdata2 | DW_EH_PE_pcrel, "pcrel sdata2")
S(DW_EH_PE_sdata4 | DW_EH_PE_pcrel, "pcrel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_pcrel, "pcrel sdata8")
S(DW_EH_PE_uleb128 | DW_EH_PE_textrel, "textrel uleb128")
S(DW_EH_PE_udata2 | DW_EH_PE_textrel, "textrel udata2")
S(DW_EH_PE_udata4 | DW_EH_PE_textrel, "textrel udata4")
S(DW_EH_PE_udata8 | DW_EH_PE_textrel, "textrel udata8")
S(DW_EH_PE_sleb128 | DW_EH_PE_textrel, "textrel sleb128")
S(DW_EH_PE_sdata2 | DW_EH_PE_textrel, "textrel sdata2")
S(DW_EH_PE_sdata4 | DW_EH_PE_textrel, "textrel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_textrel, "textrel sdata8")
S(DW_EH_PE_uleb128 | DW_EH_PE_datarel, "datarel uleb128")
S(DW_EH_PE_udata2 | DW_EH_PE_datarel, "datarel udata2")
S(DW_EH_PE_udata4 | DW_EH_PE_datarel, "datarel udata4")
S(DW_EH_PE_udata8 | DW_EH_PE_datarel, "datarel udata8")
S(DW_EH_PE_sleb128 | DW_EH_PE_datarel, "datarel sleb128")
S(DW_EH_PE_sdata2 | DW_EH_PE_datarel, "datarel sdata2")
S(DW_EH_PE_sdata4 | DW_EH_PE_datarel, "datarel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_datarel, "datarel sdata8")
S(DW_EH_PE_uleb128 | DW_EH_PE_funcrel, "funcrel uleb128")
S(DW_EH_PE_udata2 | DW_EH_PE_funcrel, "funcrel udata2")
S(DW_EH_PE_udata4 | DW_EH_PE_funcrel, "funcrel udata4")
S(DW_EH_PE_udata8 | DW_EH_PE_funcrel, "funcrel udata8")
S(DW_EH_PE_sleb128 | DW_EH_PE_funcrel, "funcrel sleb128")
S(DW_EH_PE_sdata2 | DW_EH_PE_funcrel, "funcrel sdata2")
S(DW_EH_PE_sdata4 | DW_EH_PE_funcrel, "funcrel sdata4")
S(DW_EH_PE_sdata8 | DW_EH_PE_funcrel, "funcrel sdata8")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel,
"indirect pcrel uleb128")
S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel,
"indirect pcrel udata2")
S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel,
"indirect pcrel udata4")
S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel,
"indirect pcrel udata8")
S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel,
"indirect pcrel sleb128")
S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel,
"indirect pcrel sdata2")
S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel,
"indirect pcrel sdata4")
S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel,
"indirect pcrel sdata8")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel,
"indirect textrel uleb128")
S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel,
"indirect textrel udata2")
S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel,
"indirect textrel udata4")
S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel,
"indirect textrel udata8")
S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel,
"indirect textrel sleb128")
S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel,
"indirect textrel sdata2")
S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel,
"indirect textrel sdata4")
S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel,
"indirect textrel sdata8")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel,
"indirect datarel uleb128")
S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel,
"indirect datarel udata2")
S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel,
"indirect datarel udata4")
S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel,
"indirect datarel udata8")
S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel,
"indirect datarel sleb128")
S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel,
"indirect datarel sdata2")
S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel,
"indirect datarel sdata4")
S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel,
"indirect datarel sdata8")
S(DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel,
"indirect funcrel uleb128")
S(DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel,
"indirect funcrel udata2")
S(DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel,
"indirect funcrel udata4")
S(DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel,
"indirect funcrel udata8")
S(DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel,
"indirect funcrel sleb128")
S(DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel,
"indirect funcrel sdata2")
S(DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel,
"indirect funcrel sdata4")
S(DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel,
"indirect funcrel sdata8")
#if HAVE_DESIGNATED_INITIALIZERS
};
if (format < 0 || format > 0xff || format_names[format] == NULL)
abort ();
return format_names[format];
#else
}
abort ();
#endif
}
/* Output an unsigned LEB128 quantity. */ /* Output an unsigned LEB128 quantity. */
void void
...@@ -682,6 +828,11 @@ static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *)); ...@@ -682,6 +828,11 @@ static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *));
static splay_tree indirect_pool; static splay_tree indirect_pool;
/* Put X, a SYMBOL_REF, in memory. Return a SYMBOL_REF to the allocated
memory. Differs from force_const_mem in that a single pool is used for
the entire unit of translation, and the memory is not guaranteed to be
"near" the function in any interesting sense. */
static rtx static rtx
dw2_force_const_mem (x) dw2_force_const_mem (x)
rtx x; rtx x;
...@@ -718,6 +869,9 @@ dw2_force_const_mem (x) ...@@ -718,6 +869,9 @@ dw2_force_const_mem (x)
return gen_rtx_SYMBOL_REF (Pmode, const_sym); return gen_rtx_SYMBOL_REF (Pmode, const_sym);
} }
/* A helper function for dw2_output_indirect_constants called through
splay_tree_foreach. Emit one queued constant to memory. */
static int static int
dw2_output_indirect_constant_1 (node, data) dw2_output_indirect_constant_1 (node, data)
splay_tree_node node; splay_tree_node node;
...@@ -736,6 +890,8 @@ dw2_output_indirect_constant_1 (node, data) ...@@ -736,6 +890,8 @@ dw2_output_indirect_constant_1 (node, data)
return 0; return 0;
} }
/* Emit the constants queued through dw2_force_const_mem. */
void void
dw2_output_indirect_constants () dw2_output_indirect_constants ()
{ {
...@@ -754,97 +910,104 @@ dw2_output_indirect_constants () ...@@ -754,97 +910,104 @@ dw2_output_indirect_constants ()
splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL); splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
} }
/* Like dw2_asm_output_addr_rtx, but encode the pointer as directed. */
void void
dw2_asm_output_encoded_addr_rtx (encoding, addr) dw2_asm_output_encoded_addr_rtx VPARAMS ((int encoding,
int encoding; rtx addr,
rtx addr; const char *comment, ...))
{ {
#ifndef ANSI_PROTOTYPES
int encoding;
rtx addr;
const char *comment;
#endif
va_list ap;
int size; int size;
switch (encoding & 0x07) VA_START (ap, comment);
{
case DW_EH_PE_absptr: #ifndef ANSI_PROTOTYPES
size = POINTER_SIZE / BITS_PER_UNIT; encoding = va_arg (ap, int);
break; addr = va_arg (ap, rtx);
case DW_EH_PE_udata2: comment = va_arg (ap, const char *);
size = 2; #endif
break;
case DW_EH_PE_udata4: size = size_of_encoded_value (encoding);
size = 4;
break;
case DW_EH_PE_udata8:
size = 8;
break;
default:
abort ();
}
/* NULL is _always_ represented as a plain zero. */ /* NULL is _always_ represented as a plain zero. */
if (addr == const0_rtx) if (addr == const0_rtx)
assemble_integer (addr, size, 1);
else
{ {
assemble_integer (addr, size, 1); restart:
return; /* Allow the target first crack at emitting this. Some of the
} special relocations require special directives instead of
just ".4byte" or whatever. */
restart:
/* Allow the target first crack at emitting this. Some of the
special relocations require special directives instead of
just ".4byte" or whatever. */
#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(asm_out_file, encoding, size, addr, done); ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX (asm_out_file, encoding, size,
addr, done);
#endif #endif
/* Indirection is used to get dynamic relocations out of a read-only /* Indirection is used to get dynamic relocations out of a
section. */ read-only section. */
if (encoding & DW_EH_PE_indirect) if (encoding & DW_EH_PE_indirect)
{ {
/* It is very tempting to use force_const_mem so that we share data /* It is very tempting to use force_const_mem so that we share data
with the normal constant pool. However, we've already emitted with the normal constant pool. However, we've already emitted
the constant pool for this function. Moreover, we'd like to share the constant pool for this function. Moreover, we'd like to
these constants across the entire unit of translation, or better, share these constants across the entire unit of translation,
across the entire application (or DSO). */ or better, across the entire application (or DSO). */
addr = dw2_force_const_mem (addr); addr = dw2_force_const_mem (addr);
encoding &= ~DW_EH_PE_indirect; encoding &= ~DW_EH_PE_indirect;
goto restart; goto restart;
} }
switch (encoding & 0xF0) switch (encoding & 0xF0)
{ {
case DW_EH_PE_absptr: case DW_EH_PE_absptr:
#ifdef UNALIGNED_INT_ASM_OP #ifdef UNALIGNED_INT_ASM_OP
fputs (unaligned_integer_asm_op (size), asm_out_file); fputs (unaligned_integer_asm_op (size), asm_out_file);
output_addr_const (asm_out_file, addr); output_addr_const (asm_out_file, addr);
#else #else
assemble_integer (addr, size, 1); assemble_integer (addr, size, 1);
#endif #endif
break; break;
case DW_EH_PE_pcrel: case DW_EH_PE_pcrel:
if (GET_CODE (addr) != SYMBOL_REF) if (GET_CODE (addr) != SYMBOL_REF)
abort (); abort ();
#ifdef ASM_OUTPUT_DWARF_PCREL #ifdef ASM_OUTPUT_DWARF_PCREL
ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0)); ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
#else #else
#ifdef UNALIGNED_INT_ASM_OP #ifdef UNALIGNED_INT_ASM_OP
fputs (unaligned_integer_asm_op (size), asm_out_file); fputs (unaligned_integer_asm_op (size), asm_out_file);
assemble_name (asm_out_file, XSTR (addr, 0)); assemble_name (asm_out_file, XSTR (addr, 0));
fputc ('-', asm_out_file); fputc ('-', asm_out_file);
fputc ('.', asm_out_file); fputc ('.', asm_out_file);
#else #else
abort (); abort ();
#endif #endif
#endif #endif
break; break;
default: default:
/* Other encodings should have been handled by /* Other encodings should have been handled by
ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */ ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */
abort (); abort ();
} }
#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX #ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
done: done:;
#endif #endif
}
if (flag_debug_asm && comment)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
vfprintf (asm_out_file, comment, ap);
}
fputc ('\n', asm_out_file); fputc ('\n', asm_out_file);
va_end (ap);
} }
...@@ -48,7 +48,9 @@ extern void dw2_asm_output_addr_rtx PARAMS ((int, rtx, ...@@ -48,7 +48,9 @@ extern void dw2_asm_output_addr_rtx PARAMS ((int, rtx,
const char *, ...)) const char *, ...))
/* ATTRIBUTE_PRINTF_3 */; /* ATTRIBUTE_PRINTF_3 */;
extern void dw2_asm_output_encoded_addr_rtx PARAMS ((int, rtx)); extern void dw2_asm_output_encoded_addr_rtx PARAMS ((int, rtx,
const char *, ...))
/* ATTRIBUTE_PRINTF_3 */;
extern void dw2_asm_output_nstring PARAMS ((const char *, size_t, extern void dw2_asm_output_nstring PARAMS ((const char *, size_t,
const char *, ...)) const char *, ...))
...@@ -73,5 +75,6 @@ extern void dw2_asm_output_delta_sleb128 PARAMS ((const char *, const char *, ...@@ -73,5 +75,6 @@ extern void dw2_asm_output_delta_sleb128 PARAMS ((const char *, const char *,
extern int size_of_uleb128 PARAMS ((unsigned HOST_WIDE_INT)); extern int size_of_uleb128 PARAMS ((unsigned HOST_WIDE_INT));
extern int size_of_sleb128 PARAMS ((HOST_WIDE_INT)); extern int size_of_sleb128 PARAMS ((HOST_WIDE_INT));
extern int size_of_encoded_value PARAMS ((int)); extern int size_of_encoded_value PARAMS ((int));
extern const char *eh_data_format_name PARAMS ((int));
extern void dw2_output_indirect_constants PARAMS ((void)); extern void dw2_output_indirect_constants PARAMS ((void));
...@@ -1649,8 +1649,14 @@ output_cfi (cfi, fde, for_eh) ...@@ -1649,8 +1649,14 @@ output_cfi (cfi, fde, for_eh)
switch (cfi->dw_cfi_opc) switch (cfi->dw_cfi_opc)
{ {
case DW_CFA_set_loc: case DW_CFA_set_loc:
dw2_asm_output_addr ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), if (for_eh)
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL); dw2_asm_output_encoded_addr_rtx (
ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
NULL);
else
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
break; break;
case DW_CFA_advance_loc1: case DW_CFA_advance_loc1:
dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr, dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
...@@ -1717,6 +1723,10 @@ output_call_frame_info (for_eh) ...@@ -1717,6 +1723,10 @@ output_call_frame_info (for_eh)
char l1[20], l2[20]; char l1[20], l2[20];
int any_lsda_needed = 0; int any_lsda_needed = 0;
char augmentation[6]; char augmentation[6];
int augmentation_size;
int fde_encoding = DW_EH_PE_absptr;
int per_encoding = DW_EH_PE_absptr;
int lsda_encoding = DW_EH_PE_absptr;
/* If we don't have any functions we'll want to unwind out of, don't /* If we don't have any functions we'll want to unwind out of, don't
emit any EH unwind information. */ emit any EH unwind information. */
...@@ -1770,20 +1780,46 @@ output_call_frame_info (for_eh) ...@@ -1770,20 +1780,46 @@ output_call_frame_info (for_eh)
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version"); dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
augmentation[0] = 0; augmentation[0] = 0;
augmentation_size = 0;
if (for_eh) if (for_eh)
{ {
char *p;
/* Augmentation: /* Augmentation:
z Indicates that a uleb128 is present to size the z Indicates that a uleb128 is present to size the
augmentation section. augmentation section.
R Indicates a pointer encoding for CIE and FDE pointers. L Indicates the encoding (and thus presence) of
P Indicates the presence of a language personality an LSDA pointer in the FDE augmentation.
routine in the CIE augmentation and an LSDA in the R Indicates a non-default pointer encoding for
FDE augmentation. */ FDE code pointers.
P Indicates the presence of an encoding + language
/* ??? Handle pointer encodings. */ personality routine in the CIE augmentation. */
fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
p = augmentation + 1;
if (eh_personality_libfunc)
{
*p++ = 'P';
augmentation_size += 1 + size_of_encoded_value (per_encoding);
}
if (any_lsda_needed) if (any_lsda_needed)
strcpy (augmentation, "zP"); {
*p++ = 'L';
augmentation_size += 1;
}
if (fde_encoding != DW_EH_PE_absptr)
{
*p++ = 'R';
augmentation_size += 1;
}
if (p > augmentation + 1)
{
augmentation[0] = 'z';
*p = '\0';
}
} }
dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation"); dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
...@@ -1796,12 +1832,20 @@ output_call_frame_info (for_eh) ...@@ -1796,12 +1832,20 @@ output_call_frame_info (for_eh)
if (augmentation[0]) if (augmentation[0])
{ {
dw2_asm_output_data_uleb128 (PTR_SIZE, "Augmentation size"); dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
if (eh_personality_libfunc) if (eh_personality_libfunc)
dw2_asm_output_addr_rtx (PTR_SIZE, eh_personality_libfunc, {
"Personality"); dw2_asm_output_data (1, per_encoding, "Personality (%s)",
else eh_data_format_name (per_encoding));
dw2_asm_output_data (PTR_SIZE, 0, "Personality (none)"); dw2_asm_output_encoded_addr_rtx (per_encoding,
eh_personality_libfunc, NULL);
}
if (any_lsda_needed)
dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
eh_data_format_name (lsda_encoding));
if (fde_encoding != DW_EH_PE_absptr)
dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
eh_data_format_name (fde_encoding));
} }
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
...@@ -1843,29 +1887,45 @@ output_call_frame_info (for_eh) ...@@ -1843,29 +1887,45 @@ output_call_frame_info (for_eh)
stripattributes (FRAME_SECTION), stripattributes (FRAME_SECTION),
"FDE CIE offset"); "FDE CIE offset");
dw2_asm_output_addr ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), if (for_eh)
fde->dw_fde_begin, {
"FDE initial location"); dw2_asm_output_encoded_addr_rtx (fde_encoding,
gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin),
dw2_asm_output_delta ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), "FDE initial location");
fde->dw_fde_end, dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_begin, fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range"); "FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
}
if (augmentation[0]) if (augmentation[0])
{ {
dw2_asm_output_data_uleb128 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), if (any_lsda_needed)
"Augmentation size");
if (fde->uses_eh_lsda)
{ {
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA", fde->funcdef_number); dw2_asm_output_data_uleb128 (
dw2_asm_output_offset ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), size_of_encoded_value (lsda_encoding), "Augmentation size");
l1, "Language Specific Data Area");
if (fde->uses_eh_lsda)
{
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
fde->funcdef_number);
dw2_asm_output_encoded_addr_rtx (
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
"Language Specific Data Area");
}
else
dw2_asm_output_data (size_of_encoded_value (lsda_encoding),
0, "Language Specific Data Area (none)");
} }
else else
dw2_asm_output_data ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE), dw2_asm_output_data_uleb128 (0, "Augmentation size");
0, "Language Specific Data Area (none)");
} }
/* Loop through the Call Frame Instructions associated with /* Loop through the Call Frame Instructions associated with
...@@ -1876,7 +1936,7 @@ output_call_frame_info (for_eh) ...@@ -1876,7 +1936,7 @@ output_call_frame_info (for_eh)
/* Pad the FDE out to an address sized boundary. */ /* Pad the FDE out to an address sized boundary. */
ASM_OUTPUT_ALIGN (asm_out_file, ASM_OUTPUT_ALIGN (asm_out_file,
floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE))); floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
ASM_OUTPUT_LABEL (asm_out_file, l2); ASM_OUTPUT_LABEL (asm_out_file, l2);
} }
......
...@@ -330,7 +330,6 @@ static int add_call_site PARAMS ((rtx, int)); ...@@ -330,7 +330,6 @@ static int add_call_site PARAMS ((rtx, int));
static void push_uleb128 PARAMS ((varray_type *, static void push_uleb128 PARAMS ((varray_type *,
unsigned int)); unsigned int));
static void push_sleb128 PARAMS ((varray_type *, int)); static void push_sleb128 PARAMS ((varray_type *, int));
static const char *eh_data_format_name PARAMS ((int));
#ifndef HAVE_AS_LEB128 #ifndef HAVE_AS_LEB128
static int dw2_size_of_call_site_table PARAMS ((void)); static int dw2_size_of_call_site_table PARAMS ((void));
static int sjlj_size_of_call_site_table PARAMS ((void)); static int sjlj_size_of_call_site_table PARAMS ((void));
...@@ -3367,133 +3366,6 @@ push_sleb128 (data_area, value) ...@@ -3367,133 +3366,6 @@ push_sleb128 (data_area, value)
} }
static const char *
eh_data_format_name (format)
int format;
{
switch (format)
{
case DW_EH_PE_absptr: return "absolute";
case DW_EH_PE_omit: return "omit";
case DW_EH_PE_uleb128: return "uleb128";
case DW_EH_PE_udata2: return "udata2";
case DW_EH_PE_udata4: return "udata4";
case DW_EH_PE_udata8: return "udata8";
case DW_EH_PE_sleb128: return "sleb128";
case DW_EH_PE_sdata2: return "sdata2";
case DW_EH_PE_sdata4: return "sdata4";
case DW_EH_PE_sdata8: return "sdata8";
case DW_EH_PE_uleb128 | DW_EH_PE_pcrel: return "pcrel uleb128";
case DW_EH_PE_udata2 | DW_EH_PE_pcrel: return "pcrel udata2";
case DW_EH_PE_udata4 | DW_EH_PE_pcrel: return "pcrel udata4";
case DW_EH_PE_udata8 | DW_EH_PE_pcrel: return "pcrel udata8";
case DW_EH_PE_sleb128 | DW_EH_PE_pcrel: return "pcrel sleb128";
case DW_EH_PE_sdata2 | DW_EH_PE_pcrel: return "pcrel sdata2";
case DW_EH_PE_sdata4 | DW_EH_PE_pcrel: return "pcrel sdata4";
case DW_EH_PE_sdata8 | DW_EH_PE_pcrel: return "pcrel sdata8";
case DW_EH_PE_uleb128 | DW_EH_PE_textrel: return "textrel uleb128";
case DW_EH_PE_udata2 | DW_EH_PE_textrel: return "textrel udata2";
case DW_EH_PE_udata4 | DW_EH_PE_textrel: return "textrel udata4";
case DW_EH_PE_udata8 | DW_EH_PE_textrel: return "textrel udata8";
case DW_EH_PE_sleb128 | DW_EH_PE_textrel: return "textrel sleb128";
case DW_EH_PE_sdata2 | DW_EH_PE_textrel: return "textrel sdata2";
case DW_EH_PE_sdata4 | DW_EH_PE_textrel: return "textrel sdata4";
case DW_EH_PE_sdata8 | DW_EH_PE_textrel: return "textrel sdata8";
case DW_EH_PE_uleb128 | DW_EH_PE_datarel: return "datarel uleb128";
case DW_EH_PE_udata2 | DW_EH_PE_datarel: return "datarel udata2";
case DW_EH_PE_udata4 | DW_EH_PE_datarel: return "datarel udata4";
case DW_EH_PE_udata8 | DW_EH_PE_datarel: return "datarel udata8";
case DW_EH_PE_sleb128 | DW_EH_PE_datarel: return "datarel sleb128";
case DW_EH_PE_sdata2 | DW_EH_PE_datarel: return "datarel sdata2";
case DW_EH_PE_sdata4 | DW_EH_PE_datarel: return "datarel sdata4";
case DW_EH_PE_sdata8 | DW_EH_PE_datarel: return "datarel sdata8";
case DW_EH_PE_uleb128 | DW_EH_PE_funcrel: return "funcrel uleb128";
case DW_EH_PE_udata2 | DW_EH_PE_funcrel: return "funcrel udata2";
case DW_EH_PE_udata4 | DW_EH_PE_funcrel: return "funcrel udata4";
case DW_EH_PE_udata8 | DW_EH_PE_funcrel: return "funcrel udata8";
case DW_EH_PE_sleb128 | DW_EH_PE_funcrel: return "funcrel sleb128";
case DW_EH_PE_sdata2 | DW_EH_PE_funcrel: return "funcrel sdata2";
case DW_EH_PE_sdata4 | DW_EH_PE_funcrel: return "funcrel sdata4";
case DW_EH_PE_sdata8 | DW_EH_PE_funcrel: return "funcrel sdata8";
case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel:
return "indirect pcrel uleb128";
case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel:
return "indirect pcrel udata2";
case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel:
return "indirect pcrel udata4";
case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel:
return "indirect pcrel udata8";
case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel:
return "indirect pcrel sleb128";
case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel:
return "indirect pcrel sdata2";
case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel:
return "indirect pcrel sdata4";
case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel:
return "indirect pcrel sdata8";
case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel:
return "indirect textrel uleb128";
case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel:
return "indirect textrel udata2";
case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel:
return "indirect textrel udata4";
case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel:
return "indirect textrel udata8";
case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel:
return "indirect textrel sleb128";
case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel:
return "indirect textrel sdata2";
case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel:
return "indirect textrel sdata4";
case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel:
return "indirect textrel sdata8";
case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel:
return "indirect datarel uleb128";
case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel:
return "indirect datarel udata2";
case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel:
return "indirect datarel udata4";
case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel:
return "indirect datarel udata8";
case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel:
return "indirect datarel sleb128";
case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel:
return "indirect datarel sdata2";
case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel:
return "indirect datarel sdata4";
case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel:
return "indirect datarel sdata8";
case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel:
return "indirect funcrel uleb128";
case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel:
return "indirect funcrel udata2";
case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel:
return "indirect funcrel udata4";
case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel:
return "indirect funcrel udata8";
case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel:
return "indirect funcrel sleb128";
case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel:
return "indirect funcrel sdata2";
case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel:
return "indirect funcrel sdata4";
case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel:
return "indirect funcrel sdata8";
default:
abort ();
}
}
#ifndef HAVE_AS_LEB128 #ifndef HAVE_AS_LEB128
static int static int
dw2_size_of_call_site_table () dw2_size_of_call_site_table ()
...@@ -3767,7 +3639,8 @@ output_function_exception_table () ...@@ -3767,7 +3639,8 @@ output_function_exception_table ()
dw2_asm_output_encoded_addr_rtx (tt_format, dw2_asm_output_encoded_addr_rtx (tt_format,
expand_expr (type, NULL_RTX, VOIDmode, expand_expr (type, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER)); EXPAND_INITIALIZER),
NULL);
} }
#ifdef HAVE_AS_LEB128 #ifdef HAVE_AS_LEB128
......
...@@ -30,10 +30,18 @@ Boston, MA 02111-1307, USA. */ ...@@ -30,10 +30,18 @@ Boston, MA 02111-1307, USA. */
#include "tconfig.h" #include "tconfig.h"
#include "tsystem.h" #include "tsystem.h"
#include "dwarf2.h"
#include "unwind.h"
#include "unwind-pe.h"
#include "unwind-dw2-fde.h" #include "unwind-dw2-fde.h"
#include "gthr.h" #include "gthr.h"
static struct object *objects; /* The unseen_objects list contains objects that have been registered
but not yet categorized in any way. The seen_objects list has had
it's pc_begin and count fields initialized at minimum, and is sorted
by decreasing value of pc_begin. */
static struct object *unseen_objects;
static struct object *seen_objects;
#ifdef __GTHREAD_MUTEX_INIT #ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT; static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
...@@ -61,23 +69,32 @@ init_object_mutex_once (void) ...@@ -61,23 +69,32 @@ init_object_mutex_once (void)
/* Called from crtbegin.o to register the unwind info for an object. */ /* Called from crtbegin.o to register the unwind info for an object. */
void void
__register_frame_info (void *begin, struct object *ob) __register_frame_info_bases (void *begin, struct object *ob,
void *tbase, void *dbase)
{ {
ob->pc_begin = ob->pc_end = 0; ob->pc_begin = (void *)-1;
ob->fde_begin = begin; ob->tbase = tbase;
ob->fde_array = 0; ob->dbase = dbase;
ob->count = 0; ob->u.single = begin;
ob->s.i = 0;
ob->s.b.encoding = DW_EH_PE_omit;
init_object_mutex_once (); init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex); __gthread_mutex_lock (&object_mutex);
ob->next = objects; ob->next = unseen_objects;
objects = ob; unseen_objects = ob;
__gthread_mutex_unlock (&object_mutex); __gthread_mutex_unlock (&object_mutex);
} }
void void
__register_frame_info (void *begin, struct object *ob)
{
__register_frame_info_bases (begin, ob, 0, 0);
}
void
__register_frame (void *begin) __register_frame (void *begin)
{ {
struct object *ob = (struct object *) malloc (sizeof (struct object)); struct object *ob = (struct object *) malloc (sizeof (struct object));
...@@ -89,23 +106,33 @@ __register_frame (void *begin) ...@@ -89,23 +106,33 @@ __register_frame (void *begin)
collect2. */ collect2. */
void void
__register_frame_info_table (void *begin, struct object *ob) __register_frame_info_table_bases (void *begin, struct object *ob,
void *tbase, void *dbase)
{ {
ob->pc_begin = ob->pc_end = 0; ob->pc_begin = (void *)-1;
ob->fde_begin = begin; ob->tbase = tbase;
ob->fde_array = begin; ob->dbase = dbase;
ob->count = 0; ob->u.array = begin;
ob->s.i = 0;
ob->s.b.from_array = 1;
ob->s.b.encoding = DW_EH_PE_omit;
init_object_mutex_once (); init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex); __gthread_mutex_lock (&object_mutex);
ob->next = objects; ob->next = unseen_objects;
objects = ob; unseen_objects = ob;
__gthread_mutex_unlock (&object_mutex); __gthread_mutex_unlock (&object_mutex);
} }
void void
__register_frame_info_table (void *begin, struct object *ob)
{
__register_frame_info_table_bases (begin, ob, 0, 0);
}
void
__register_frame_table (void *begin) __register_frame_table (void *begin)
{ {
struct object *ob = (struct object *) malloc (sizeof (struct object)); struct object *ob = (struct object *) malloc (sizeof (struct object));
...@@ -118,30 +145,46 @@ void * ...@@ -118,30 +145,46 @@ void *
__deregister_frame_info (void *begin) __deregister_frame_info (void *begin)
{ {
struct object **p; struct object **p;
struct object *ob = 0;
init_object_mutex_once (); init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex); __gthread_mutex_lock (&object_mutex);
p = &objects; for (p = &unseen_objects; *p ; p = &(*p)->next)
while (*p) if ((*p)->u.single == begin)
{ {
if ((*p)->fde_begin == begin) ob = *p;
{ *p = ob->next;
struct object *ob = *p; goto out;
*p = (*p)->next; }
/* If we've run init_frame for this object, free the FDE array. */ for (p = &seen_objects; *p ; p = &(*p)->next)
if (ob->fde_array && ob->fde_array != begin) if ((*p)->s.b.sorted)
free (ob->fde_array); {
if ((*p)->u.sort->orig_data == begin)
__gthread_mutex_unlock (&object_mutex); {
return (void *) ob; ob = *p;
} *p = ob->next;
p = &((*p)->next); free (ob->u.sort);
} goto out;
}
}
else
{
if ((*p)->u.single == begin)
{
ob = *p;
*p = ob->next;
goto out;
}
}
__gthread_mutex_unlock (&object_mutex); __gthread_mutex_unlock (&object_mutex);
abort (); abort ();
out:
__gthread_mutex_unlock (&object_mutex);
return (void *) ob;
} }
void void
...@@ -151,10 +194,119 @@ __deregister_frame (void *begin) ...@@ -151,10 +194,119 @@ __deregister_frame (void *begin)
} }
/* Like base_of_encoded_value, but take the base from a struct object
instead of an _Unwind_Context. */
static _Unwind_Ptr
base_from_object (unsigned char encoding, struct object *ob)
{
if (encoding == DW_EH_PE_omit)
return 0;
switch (encoding & 0x70)
{
case DW_EH_PE_absptr:
case DW_EH_PE_pcrel:
return 0;
case DW_EH_PE_textrel:
return (_Unwind_Ptr) ob->tbase;
case DW_EH_PE_datarel:
return (_Unwind_Ptr) ob->dbase;
}
abort ();
}
/* Return the FDE pointer encoding from the CIE. */
/* ??? This is a subset of extract_cie_info from unwind-dw2.c. */
static int
get_cie_encoding (struct dwarf_cie *cie)
{
const unsigned char *aug, *p;
_Unwind_Ptr dummy;
aug = cie->augmentation;
if (aug[0] != 'z')
return DW_EH_PE_absptr;
p = aug + strlen (aug) + 1; /* Skip the augmentation string. */
p = read_uleb128 (p, &dummy); /* Skip code alignment. */
p = read_sleb128 (p, &dummy); /* Skip data alignment. */
p++; /* Skip return address column. */
aug++; /* Skip 'z' */
p = read_uleb128 (p, &dummy); /* Skip augmentation length. */
while (1)
{
/* This is what we're looking for. */
if (*aug == 'R')
return *p;
/* Personality encoding and pointer. */
else if (*aug == 'P')
p = read_encoded_value_with_base (*p & 0xF, 0, p + 1, &dummy);
/* LSDA encoding. */
else if (*aug == 'L')
p++;
/* Otherwise end of string, or unknown augmentation. */
else
return DW_EH_PE_absptr;
aug++;
}
}
static inline int
get_fde_encoding (struct dwarf_fde *f)
{
return get_cie_encoding (get_cie (f));
}
/* Sorting an array of FDEs by address. /* Sorting an array of FDEs by address.
(Ideally we would have the linker sort the FDEs so we don't have to do (Ideally we would have the linker sort the FDEs so we don't have to do
it at run time. But the linkers are not yet prepared for this.) */ it at run time. But the linkers are not yet prepared for this.) */
/* Comparison routines. Three variants of increasing complexity. */
static saddr
fde_unencoded_compare (struct object *ob __attribute__((unused)),
fde *x, fde *y)
{
return *(saddr *)x->pc_begin - *(saddr *)y->pc_begin;
}
static saddr
fde_single_encoding_compare (struct object *ob, fde *x, fde *y)
{
_Unwind_Ptr base, x_ptr, y_ptr;
base = base_from_object (ob->s.b.encoding, ob);
read_encoded_value_with_base (ob->s.b.encoding, base, x->pc_begin, &x_ptr);
read_encoded_value_with_base (ob->s.b.encoding, base, y->pc_begin, &y_ptr);
return x_ptr - y_ptr;
}
static saddr
fde_mixed_encoding_compare (struct object *ob, fde *x, fde *y)
{
int x_encoding, y_encoding;
_Unwind_Ptr x_ptr, y_ptr;
x_encoding = get_fde_encoding (x);
read_encoded_value_with_base (x_encoding, base_from_object (x_encoding, ob),
x->pc_begin, &x_ptr);
y_encoding = get_fde_encoding (y);
read_encoded_value_with_base (y_encoding, base_from_object (y_encoding, ob),
y->pc_begin, &y_ptr);
return x_ptr - y_ptr;
}
typedef saddr (*fde_compare_t) (struct object *, fde *, fde *);
/* This is a special mix of insertion sort and heap sort, optimized for /* This is a special mix of insertion sort and heap sort, optimized for
the data sets that actually occur. They look like the data sets that actually occur. They look like
101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130. 101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
...@@ -166,41 +318,36 @@ __deregister_frame (void *begin) ...@@ -166,41 +318,36 @@ __deregister_frame (void *begin)
The worst-case total run time is O(N) + O(n log (n)), where N is the The worst-case total run time is O(N) + O(n log (n)), where N is the
total number of FDEs and n is the number of erratic ones. */ total number of FDEs and n is the number of erratic ones. */
typedef struct fde_vector struct fde_accumulator
{
fde **array;
size_t count;
} fde_vector;
typedef struct fde_accumulator
{ {
fde_vector linear; struct fde_vector *linear;
fde_vector erratic; struct fde_vector *erratic;
} fde_accumulator; };
static inline saddr
fde_compare (fde *x, fde *y)
{
return (saddr)x->pc_begin - (saddr)y->pc_begin;
}
static inline int static inline int
start_fde_sort (fde_accumulator *accu, size_t count) start_fde_sort (struct fde_accumulator *accu, size_t count)
{ {
accu->linear.array = count ? (fde **) malloc (sizeof (fde *) * count) : NULL; size_t size;
accu->erratic.array = accu->linear.array ? if (! count)
(fde **) malloc (sizeof (fde *) * count) : NULL; return 0;
accu->linear.count = 0;
accu->erratic.count = 0; size = sizeof (struct fde_vector) + sizeof (fde *) * count;
if ((accu->linear = (struct fde_vector *) malloc (size)))
return accu->linear.array != NULL; {
accu->linear->count = 0;
if ((accu->erratic = (struct fde_vector *) malloc (size)))
accu->erratic->count = 0;
return 1;
}
else
return 0;
} }
static inline void static inline void
fde_insert (fde_accumulator *accu, fde *this_fde) fde_insert (struct fde_accumulator *accu, fde *this_fde)
{ {
if (accu->linear.array) if (accu->linear)
accu->linear.array[accu->linear.count++] = this_fde; accu->linear->array[accu->linear->count++] = this_fde;
} }
/* Split LINEAR into a linear sequence with low values and an erratic /* Split LINEAR into a linear sequence with low values and an erratic
...@@ -214,8 +361,10 @@ fde_insert (fde_accumulator *accu, fde *this_fde) ...@@ -214,8 +361,10 @@ fde_insert (fde_accumulator *accu, fde *this_fde)
the ERRATIC array during construction. A final pass iterates over the the ERRATIC array during construction. A final pass iterates over the
chain to determine what should be placed in the ERRATIC array, and chain to determine what should be placed in the ERRATIC array, and
what is the linear sequence. This overlay is safe from aliasing. */ what is the linear sequence. This overlay is safe from aliasing. */
static inline void static inline void
fde_split (fde_vector *linear, fde_vector *erratic) fde_split (struct object *ob, fde_compare_t fde_compare,
struct fde_vector *linear, struct fde_vector *erratic)
{ {
static fde *marker; static fde *marker;
size_t count = linear->count; size_t count = linear->count;
...@@ -233,7 +382,7 @@ fde_split (fde_vector *linear, fde_vector *erratic) ...@@ -233,7 +382,7 @@ fde_split (fde_vector *linear, fde_vector *erratic)
fde **probe; fde **probe;
for (probe = chain_end; for (probe = chain_end;
probe != &marker && fde_compare (linear->array[i], *probe) < 0; probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0;
probe = chain_end) probe = chain_end)
{ {
chain_end = (fde **)erratic->array[probe - linear->array]; chain_end = (fde **)erratic->array[probe - linear->array];
...@@ -257,8 +406,10 @@ fde_split (fde_vector *linear, fde_vector *erratic) ...@@ -257,8 +406,10 @@ fde_split (fde_vector *linear, fde_vector *erratic)
/* This is O(n log(n)). BSD/OS defines heapsort in stdlib.h, so we must /* This is O(n log(n)). BSD/OS defines heapsort in stdlib.h, so we must
use a name that does not conflict. */ use a name that does not conflict. */
static inline void
frame_heapsort (fde_vector *erratic) static void
frame_heapsort (struct object *ob, fde_compare_t fde_compare,
struct fde_vector *erratic)
{ {
/* For a description of this algorithm, see: /* For a description of this algorithm, see:
Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed., Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
...@@ -279,13 +430,13 @@ frame_heapsort (fde_vector *erratic) ...@@ -279,13 +430,13 @@ frame_heapsort (fde_vector *erratic)
for (i = m; 2*i+1 < n; ) for (i = m; 2*i+1 < n; )
{ {
if (2*i+2 < n if (2*i+2 < n
&& fde_compare (a[2*i+2], a[2*i+1]) > 0 && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
&& fde_compare (a[2*i+2], a[i]) > 0) && fde_compare (ob, a[2*i+2], a[i]) > 0)
{ {
SWAP (a[i], a[2*i+2]); SWAP (a[i], a[2*i+2]);
i = 2*i+2; i = 2*i+2;
} }
else if (fde_compare (a[2*i+1], a[i]) > 0) else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
{ {
SWAP (a[i], a[2*i+1]); SWAP (a[i], a[2*i+1]);
i = 2*i+1; i = 2*i+1;
...@@ -302,13 +453,13 @@ frame_heapsort (fde_vector *erratic) ...@@ -302,13 +453,13 @@ frame_heapsort (fde_vector *erratic)
for (i = 0; 2*i+1 < n; ) for (i = 0; 2*i+1 < n; )
{ {
if (2*i+2 < n if (2*i+2 < n
&& fde_compare (a[2*i+2], a[2*i+1]) > 0 && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
&& fde_compare (a[2*i+2], a[i]) > 0) && fde_compare (ob, a[2*i+2], a[i]) > 0)
{ {
SWAP (a[i], a[2*i+2]); SWAP (a[i], a[2*i+2]);
i = 2*i+2; i = 2*i+2;
} }
else if (fde_compare (a[2*i+1], a[i]) > 0) else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
{ {
SWAP (a[i], a[2*i+1]); SWAP (a[i], a[2*i+1]);
i = 2*i+1; i = 2*i+1;
...@@ -321,8 +472,9 @@ frame_heapsort (fde_vector *erratic) ...@@ -321,8 +472,9 @@ frame_heapsort (fde_vector *erratic)
} }
/* Merge V1 and V2, both sorted, and put the result into V1. */ /* Merge V1 and V2, both sorted, and put the result into V1. */
static void static inline void
fde_merge (fde_vector *v1, const fde_vector *v2) fde_merge (struct object *ob, fde_compare_t fde_compare,
struct fde_vector *v1, struct fde_vector *v2)
{ {
size_t i1, i2; size_t i1, i2;
fde * fde2; fde * fde2;
...@@ -334,7 +486,7 @@ fde_merge (fde_vector *v1, const fde_vector *v2) ...@@ -334,7 +486,7 @@ fde_merge (fde_vector *v1, const fde_vector *v2)
do { do {
i2--; i2--;
fde2 = v2->array[i2]; fde2 = v2->array[i2];
while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0) while (i1 > 0 && fde_compare (ob, v1->array[i1-1], fde2) > 0)
{ {
v1->array[i1+i2] = v1->array[i1-1]; v1->array[i1+i2] = v1->array[i1-1];
i1--; i1--;
...@@ -345,81 +497,154 @@ fde_merge (fde_vector *v1, const fde_vector *v2) ...@@ -345,81 +497,154 @@ fde_merge (fde_vector *v1, const fde_vector *v2)
} }
} }
static fde ** static inline void
end_fde_sort (fde_accumulator *accu, size_t count) end_fde_sort (struct object *ob, struct fde_accumulator *accu, size_t count)
{ {
if (accu->linear.array && accu->linear.count != count) fde_compare_t fde_compare;
if (accu->linear && accu->linear->count != count)
abort (); abort ();
if (accu->erratic.array) if (ob->s.b.mixed_encoding)
fde_compare = fde_mixed_encoding_compare;
else if (ob->s.b.encoding == DW_EH_PE_absptr)
fde_compare = fde_unencoded_compare;
else
fde_compare = fde_single_encoding_compare;
if (accu->erratic)
{ {
fde_split (&accu->linear, &accu->erratic); fde_split (ob, fde_compare, accu->linear, accu->erratic);
if (accu->linear.count + accu->erratic.count != count) if (accu->linear->count + accu->erratic->count != count)
abort (); abort ();
frame_heapsort (&accu->erratic); frame_heapsort (ob, fde_compare, accu->erratic);
fde_merge (&accu->linear, &accu->erratic); fde_merge (ob, fde_compare, accu->linear, accu->erratic);
free (accu->erratic.array); free (accu->erratic);
} }
else else
{ {
/* We've not managed to malloc an erratic array, so heap sort in the /* We've not managed to malloc an erratic array,
linear one. */ so heap sort in the linear one. */
frame_heapsort (&accu->linear); frame_heapsort (ob, fde_compare, accu->linear);
} }
return accu->linear.array;
} }
/* Update encoding, mixed_encoding, and pc_begin for OB for the
fde array beginning at THIS_FDE. Return the number of fdes
encountered along the way. */
static size_t static size_t
count_fdes (fde *this_fde) classify_object_over_fdes (struct object *ob, fde *this_fde)
{ {
size_t count; struct dwarf_cie *last_cie = 0;
size_t count = 0;
int encoding = DW_EH_PE_absptr;
_Unwind_Ptr base = 0;
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde)) for (; this_fde->length != 0; this_fde = next_fde (this_fde))
/* Skip CIEs and omitted link-once FDE entries. */ {
if (this_fde->CIE_delta != 0 && this_fde->pc_begin != 0) struct dwarf_cie *this_cie;
++count; _Unwind_Ptr mask, pc_begin;
return count; /* Skip CIEs. */
} if (this_fde->CIE_delta == 0)
continue;
static void /* Determine the encoding for this FDE. Note mixed encoded
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr) objects for later. */
{ this_cie = get_cie (this_fde);
void *pc_begin = *beg_ptr; if (this_cie != last_cie)
void *pc_end = *end_ptr; {
last_cie = this_cie;
encoding = get_cie_encoding (this_cie);
base = base_from_object (encoding, ob);
if (ob->s.b.encoding == DW_EH_PE_omit)
ob->s.b.encoding = encoding;
else if (ob->s.b.encoding != encoding)
ob->s.b.mixed_encoding = 1;
}
for (; this_fde->length != 0; this_fde = next_fde (this_fde)) read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
{ &pc_begin);
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
fde_insert (accu, this_fde); /* Take care to ignore link-once functions that were removed.
In these cases, the function address will be NULL, but if
the encoding is smaller than a pointer a true NULL may not
be representable. Assume 0 in the representable bits is NULL. */
mask = size_of_encoded_value (encoding);
if (mask < sizeof (void *))
mask = (1L << (mask << 3)) - 1;
else
mask = -1;
if ((pc_begin & mask) == 0)
continue;
if (this_fde->pc_begin < pc_begin) count += 1;
pc_begin = this_fde->pc_begin; if ((void *)pc_begin < ob->pc_begin)
if (this_fde->pc_begin + this_fde->pc_range > pc_end) ob->pc_begin = (void *)pc_begin;
pc_end = this_fde->pc_begin + this_fde->pc_range;
} }
*beg_ptr = pc_begin; return count;
*end_ptr = pc_end;
} }
static fde * static void
search_fdes (fde *this_fde, void *pc) add_fdes (struct object *ob, struct fde_accumulator *accu, fde *this_fde)
{ {
struct dwarf_cie *last_cie = 0;
int encoding = ob->s.b.encoding;
_Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
for (; this_fde->length != 0; this_fde = next_fde (this_fde)) for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{ {
/* Skip CIEs and linked once FDE entries. */ struct dwarf_cie *this_cie;
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range) /* Skip CIEs. */
return this_fde; if (this_fde->CIE_delta == 0)
continue;
if (ob->s.b.mixed_encoding)
{
/* Determine the encoding for this FDE. Note mixed encoded
objects for later. */
this_cie = get_cie (this_fde);
if (this_cie != last_cie)
{
last_cie = this_cie;
encoding = get_cie_encoding (this_cie);
base = base_from_object (encoding, ob);
}
}
if (encoding == DW_EH_PE_absptr)
{
if (*(_Unwind_Ptr *)this_fde->pc_begin == 0)
continue;
}
else
{
_Unwind_Ptr pc_begin, mask;
read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
&pc_begin);
/* Take care to ignore link-once functions that were removed.
In these cases, the function address will be NULL, but if
the encoding is smaller than a pointer a true NULL may not
be representable. Assume 0 in the representable bits is NULL. */
mask = size_of_encoded_value (encoding);
if (mask < sizeof (void *))
mask = (1L << (mask << 3)) - 1;
else
mask = -1;
if ((pc_begin & mask) == 0)
continue;
}
fde_insert (accu, this_fde);
} }
return NULL;
} }
/* Set up a sorted array of pointers to FDEs for a loaded object. We /* Set up a sorted array of pointers to FDEs for a loaded object. We
...@@ -427,116 +652,317 @@ search_fdes (fde *this_fde, void *pc) ...@@ -427,116 +652,317 @@ search_fdes (fde *this_fde, void *pc)
be faster. We can be called multiple times, should we have failed to be faster. We can be called multiple times, should we have failed to
allocate a sorted fde array on a previous occasion. */ allocate a sorted fde array on a previous occasion. */
static void static inline void
frame_init (struct object* ob) init_object (struct object* ob)
{ {
struct fde_accumulator accu;
size_t count; size_t count;
fde_accumulator accu;
void *pc_begin, *pc_end;
fde **array;
if (ob->pc_begin) count = ob->s.b.count;
count = ob->count; if (count == 0)
else if (ob->fde_array)
{ {
fde **p = ob->fde_array; if (ob->s.b.from_array)
for (count = 0; *p; ++p) {
count += count_fdes (*p); fde **p = ob->u.array;
for (count = 0; *p; ++p)
count += classify_object_over_fdes (ob, *p);
}
else
count = classify_object_over_fdes (ob, ob->u.single);
/* The count field we have in the main struct object is somewhat
limited, but should suffice for virtually all cases. If the
counted value doesn't fit, re-write a zero. The worst that
happens is that we re-count next time -- admittedly non-trivial
in that this implies some 2M fdes, but at least we function. */
ob->s.b.count = count;
if (ob->s.b.count != count)
ob->s.b.count = 0;
} }
else
count = count_fdes (ob->fde_begin);
ob->count = count;
if (!start_fde_sort (&accu, count) && ob->pc_begin) if (!start_fde_sort (&accu, count))
return; return;
pc_begin = (void*)(uaddr)-1; if (ob->s.b.from_array)
pc_end = 0;
if (ob->fde_array)
{ {
fde **p = ob->fde_array; fde **p;
for (; *p; ++p) for (p = ob->u.array; *p; ++p)
add_fdes (*p, &accu, &pc_begin, &pc_end); add_fdes (ob, &accu, *p);
} }
else else
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end); add_fdes (ob, &accu, ob->u.single);
array = end_fde_sort (&accu, count);
if (array) end_fde_sort (ob, &accu, count);
ob->fde_array = array;
ob->pc_begin = pc_begin; /* Save the original fde pointer, since this is the key by which the
ob->pc_end = pc_end; DSO will deregister the object. */
accu.linear->orig_data = ob->u.single;
ob->u.sort = accu.linear;
ob->s.b.sorted = 1;
} }
fde * /* A linear search through a set of FDEs for the given PC. This is
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases ATTRIBUTE_UNUSED) used when there was insufficient memory to allocate and sort an
array. */
static fde *
linear_search_fdes (struct object *ob, fde *this_fde, void *pc)
{ {
struct object *ob; struct dwarf_cie *last_cie = 0;
int encoding = ob->s.b.encoding;
_Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{
struct dwarf_cie *this_cie;
_Unwind_Ptr pc_begin, pc_range;
/* Skip CIEs. */
if (this_fde->CIE_delta == 0)
continue;
if (ob->s.b.mixed_encoding)
{
/* Determine the encoding for this FDE. Note mixed encoded
objects for later. */
this_cie = get_cie (this_fde);
if (this_cie != last_cie)
{
last_cie = this_cie;
encoding = get_cie_encoding (this_cie);
base = base_from_object (encoding, ob);
}
}
if (encoding == DW_EH_PE_absptr)
{
pc_begin = ((_Unwind_Ptr *)this_fde->pc_begin)[0];
pc_range = ((_Unwind_Ptr *)this_fde->pc_begin)[1];
if (pc_begin == 0)
continue;
}
else
{
_Unwind_Ptr mask;
const char *p;
p = read_encoded_value_with_base (encoding, base,
this_fde->pc_begin, &pc_begin);
read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
/* Take care to ignore link-once functions that were removed.
In these cases, the function address will be NULL, but if
the encoding is smaller than a pointer a true NULL may not
be representable. Assume 0 in the representable bits is NULL. */
mask = size_of_encoded_value (encoding);
if (mask < sizeof (void *))
mask = (1L << (mask << 3)) - 1;
else
mask = -1;
if ((pc_begin & mask) == 0)
continue;
}
if ((_Unwind_Ptr)pc - pc_begin < pc_range)
return this_fde;
}
return NULL;
}
/* Binary search for an FDE containing the given PC. Here are three
implementations of increasing complexity. */
static inline fde *
binary_search_unencoded_fdes (struct object *ob, void *pc)
{
struct fde_vector *vec = ob->u.sort;
size_t lo, hi; size_t lo, hi;
for (lo = 0, hi = vec->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = vec->array[i];
void *pc_begin;
uaddr pc_range;
pc_begin = ((void **)f->pc_begin)[0];
pc_range = ((uaddr *)f->pc_begin)[1];
if (pc < pc_begin)
hi = i;
else if (pc >= pc_begin + pc_range)
lo = i + 1;
else
return f;
}
init_object_mutex_once (); return NULL;
__gthread_mutex_lock (&object_mutex); }
/* Linear search through the objects, to find the one containing the pc. */ static inline fde *
for (ob = objects; ob; ob = ob->next) binary_search_single_encoding_fdes (struct object *ob, void *pc)
{
struct fde_vector *vec = ob->u.sort;
int encoding = ob->s.b.encoding;
_Unwind_Ptr base = base_from_object (encoding, ob);
size_t lo, hi;
for (lo = 0, hi = vec->count; lo < hi; )
{ {
if (ob->pc_begin == 0) size_t i = (lo + hi) / 2;
frame_init (ob); fde *f = vec->array[i];
if (pc >= ob->pc_begin && pc < ob->pc_end) _Unwind_Ptr pc_begin, pc_range;
break; const char *p;
p = read_encoded_value_with_base (encoding, base, f->pc_begin,
&pc_begin);
read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
if ((_Unwind_Ptr)pc < pc_begin)
hi = i;
else if ((_Unwind_Ptr)pc >= pc_begin + pc_range)
lo = i + 1;
else
return f;
} }
if (ob == 0) return NULL;
}
static inline fde *
binary_search_mixed_encoding_fdes (struct object *ob, void *pc)
{
struct fde_vector *vec = ob->u.sort;
size_t lo, hi;
for (lo = 0, hi = vec->count; lo < hi; )
{ {
__gthread_mutex_unlock (&object_mutex); size_t i = (lo + hi) / 2;
return 0; fde *f = vec->array[i];
_Unwind_Ptr pc_begin, pc_range;
const char *p;
int encoding;
encoding = get_fde_encoding (f);
p = read_encoded_value_with_base (encoding,
base_from_object (encoding, ob),
f->pc_begin, &pc_begin);
read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
if ((_Unwind_Ptr)pc < pc_begin)
hi = i;
else if ((_Unwind_Ptr)pc >= pc_begin + pc_range)
lo = i + 1;
else
return f;
} }
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin) return NULL;
frame_init (ob); }
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin) static fde *
search_object (struct object* ob, void *pc)
{
/* If the data hasn't been sorted, try to do this now. We may have
more memory available than last time we tried. */
if (! ob->s.b.sorted)
{ {
__gthread_mutex_unlock (&object_mutex); init_object (ob);
/* Standard binary search algorithm. */
for (lo = 0, hi = ob->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = ob->fde_array[i];
if (pc < f->pc_begin) /* Despite the above comment, the normal reason to get here is
hi = i; that we've not processed this object before. A quick range
else if (pc >= f->pc_begin + f->pc_range) check is in order. */
lo = i + 1; if (pc < ob->pc_begin)
else return NULL;
return f; }
}
if (ob->s.b.sorted)
{
if (ob->s.b.mixed_encoding)
return binary_search_mixed_encoding_fdes (ob, pc);
else if (ob->s.b.encoding == DW_EH_PE_absptr)
return binary_search_unencoded_fdes (ob, pc);
else
return binary_search_single_encoding_fdes (ob, pc);
} }
else else
{ {
/* Long slow labourious linear search, cos we've no memory. */ /* Long slow labourious linear search, cos we've no memory. */
fde *f; if (ob->s.b.from_array)
if (ob->fde_array)
{ {
fde **p = ob->fde_array; fde **p;
for (p = ob->u.array; *p ; p++)
do {
{ fde *f = linear_search_fdes (ob, *p, pc);
f = search_fdes (*p, pc);
if (f) if (f)
break; return f;
p++;
} }
while (*p); return NULL;
} }
else else
f = search_fdes (ob->fde_begin, pc); return linear_search_fdes (ob, ob->u.single, pc);
}
}
fde *
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
{
struct object *ob;
fde *f = NULL;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
/* Linear search through the classified objects, to find the one
containing the pc. Note that pc_begin is sorted decending, and
we expect objects to be non-overlapping. */
for (ob = seen_objects; ob; ob = ob->next)
if (pc >= ob->pc_begin)
{
f = search_object (ob, pc);
if (f)
goto fini;
break;
}
/* Classify and search the objects we've not yet processed. */
while ((ob = unseen_objects))
{
struct object **p;
unseen_objects = ob->next;
f = search_object (ob, pc);
/* Insert the object into the classified list. */
for (p = &seen_objects; *p ; p = &(*p)->next)
if ((*p)->pc_begin < ob->pc_begin)
break;
ob->next = *p;
*p = ob;
if (f)
goto fini;
}
fini:
__gthread_mutex_unlock (&object_mutex);
if (f)
{
int encoding;
bases->tbase = ob->tbase;
bases->dbase = ob->dbase;
__gthread_mutex_unlock (&object_mutex); encoding = ob->s.b.encoding;
return f; if (ob->s.b.mixed_encoding)
encoding = get_fde_encoding (f);
read_encoded_value_with_base (encoding, base_from_object (encoding, ob),
f->pc_begin, (_Unwind_Ptr *)&bases->func);
} }
return 0; return f;
} }
...@@ -29,15 +29,52 @@ the Free Software Foundation, 59 Temple Place - Suite 330, ...@@ -29,15 +29,52 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
/* Describes data used to hold onto one shared object or object file. */ struct fde_vector
{
void *orig_data;
size_t count;
struct dwarf_fde *array[];
};
struct object struct object
{ {
void *pc_begin; void *pc_begin;
void *tbase;
void *dbase;
union {
struct dwarf_fde *single;
struct dwarf_fde **array;
struct fde_vector *sort;
} u;
union {
struct {
unsigned long sorted : 1;
unsigned long from_array : 1;
unsigned long mixed_encoding : 1;
unsigned long encoding : 8;
/* ??? Wish there was an easy way to detect a 64-bit host here;
we've got 32 bits left to play with... */
unsigned long count : 21;
} b;
size_t i;
} s;
struct object *next;
};
/* This is the original definition of struct object. While the struct
itself was opaque to users, they did know how large it was, and
allocate one statically in crtbegin for each DSO. Keep this around
so that we're aware of the static size limitations for the new struct. */
struct old_object
{
void *pc_begin;
void *pc_end; void *pc_end;
struct dwarf_fde *fde_begin; struct dwarf_fde *fde_begin;
struct dwarf_fde **fde_array; struct dwarf_fde **fde_array;
size_t count; size_t count;
struct object *next; struct old_object *next;
}; };
struct dwarf_eh_bases struct dwarf_eh_bases
...@@ -48,8 +85,12 @@ struct dwarf_eh_bases ...@@ -48,8 +85,12 @@ struct dwarf_eh_bases
}; };
extern void __register_frame_info_bases (void *, struct object *,
void *, void *);
extern void __register_frame_info (void *, struct object *); extern void __register_frame_info (void *, struct object *);
extern void __register_frame (void *); extern void __register_frame (void *);
extern void __register_frame_info_table_bases (void *, struct object *,
void *, void *);
extern void __register_frame_info_table (void *, struct object *); extern void __register_frame_info_table (void *, struct object *);
extern void __register_frame_table (void *); extern void __register_frame_table (void *);
extern void *__deregister_frame_info (void *); extern void *__deregister_frame_info (void *);
...@@ -97,8 +138,7 @@ struct dwarf_fde ...@@ -97,8 +138,7 @@ struct dwarf_fde
{ {
uword length; uword length;
sword CIE_delta; sword CIE_delta;
void * pc_begin; unsigned char pc_begin[];
uaddr pc_range;
} __attribute__ ((packed, aligned (__alignof__ (void *)))); } __attribute__ ((packed, aligned (__alignof__ (void *))));
typedef struct dwarf_fde fde; typedef struct dwarf_fde fde;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "tsystem.h" #include "tsystem.h"
#include "dwarf2.h" #include "dwarf2.h"
#include "unwind.h" #include "unwind.h"
#include "unwind-pe.h"
#include "unwind-dw2-fde.h" #include "unwind-dw2-fde.h"
#include "gthr.h" #include "gthr.h"
...@@ -69,7 +70,7 @@ typedef struct ...@@ -69,7 +70,7 @@ typedef struct
union { union {
unsigned int reg; unsigned int reg;
_Unwind_Sword offset; _Unwind_Sword offset;
unsigned char *exp; const unsigned char *exp;
} loc; } loc;
enum { enum {
REG_UNSAVED, REG_UNSAVED,
...@@ -87,7 +88,7 @@ typedef struct ...@@ -87,7 +88,7 @@ typedef struct
location expression. */ location expression. */
_Unwind_Sword cfa_offset; _Unwind_Sword cfa_offset;
_Unwind_Word cfa_reg; _Unwind_Word cfa_reg;
unsigned char *cfa_exp; const unsigned char *cfa_exp;
enum { enum {
CFA_UNSET, CFA_UNSET,
CFA_REG_OFFSET, CFA_REG_OFFSET,
...@@ -102,57 +103,11 @@ typedef struct ...@@ -102,57 +103,11 @@ typedef struct
signed int data_align; signed int data_align;
unsigned int code_align; unsigned int code_align;
unsigned char retaddr_column; unsigned char retaddr_column;
unsigned char addr_encoding; unsigned char fde_encoding;
unsigned char lsda_encoding;
unsigned char saw_z; unsigned char saw_z;
unsigned char saw_lsda;
} _Unwind_FrameState; } _Unwind_FrameState;
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static unsigned char *
read_uleb128 (unsigned char *buf, _Unwind_Word *r)
{
unsigned shift = 0;
_Unwind_Word result = 0;
while (1)
{
unsigned char byte = *buf++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*r = result;
return buf;
}
/* Decode the signed LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static unsigned char *
read_sleb128 (unsigned char *buf, _Unwind_Sword *r)
{
unsigned shift = 0;
_Unwind_Sword result = 0;
unsigned char byte;
while (1)
{
byte = *buf++;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
}
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= - (1 << shift);
*r = result;
return buf;
}
/* Read unaligned data from the instruction buffer. */ /* Read unaligned data from the instruction buffer. */
union unaligned union unaligned
...@@ -167,107 +122,31 @@ union unaligned ...@@ -167,107 +122,31 @@ union unaligned
} __attribute__ ((packed)); } __attribute__ ((packed));
static inline void * static inline void *
read_pointer (void *p) { union unaligned *up = p; return up->p; } read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
static inline int static inline int
read_1u (void *p) { return *(unsigned char *)p; } read_1u (const void *p) { return *(const unsigned char *)p; }
static inline int static inline int
read_1s (void *p) { return *(signed char *)p; } read_1s (const void *p) { return *(const signed char *)p; }
static inline int static inline int
read_2u (void *p) { union unaligned *up = p; return up->u2; } read_2u (const void *p) { const union unaligned *up = p; return up->u2; }
static inline int static inline int
read_2s (void *p) { union unaligned *up = p; return up->s2; } read_2s (const void *p) { const union unaligned *up = p; return up->s2; }
static inline unsigned int static inline unsigned int
read_4u (void *p) { union unaligned *up = p; return up->u4; } read_4u (const void *p) { const union unaligned *up = p; return up->u4; }
static inline int static inline int
read_4s (void *p) { union unaligned *up = p; return up->s4; } read_4s (const void *p) { const union unaligned *up = p; return up->s4; }
static inline unsigned long static inline unsigned long
read_8u (void *p) { union unaligned *up = p; return up->u8; } read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
static inline unsigned long static inline unsigned long
read_8s (void *p) { union unaligned *up = p; return up->s8; } read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
static unsigned char *
read_encoded_pointer (unsigned char *p, unsigned char encoding,
struct dwarf_eh_bases *bases, void **pptr)
{
signed long val;
unsigned char *ret;
switch (encoding & 0x0f)
{
case DW_EH_PE_absptr:
val = (_Unwind_Ptr) read_pointer (p);
ret = p + sizeof (void *);
break;
case DW_EH_PE_uleb128:
ret = read_uleb128 (p, &val);
break;
case DW_EH_PE_sleb128:
ret = read_sleb128 (p, &val);
break;
case DW_EH_PE_udata2:
val = read_2u (p);
ret = p + 2;
break;
case DW_EH_PE_udata4:
val = read_4u (p);
ret = p + 4;
break;
case DW_EH_PE_udata8:
val = read_8u (p);
ret = p + 8;
break;
case DW_EH_PE_sdata2:
val = read_2s (p);
ret = p + 2;
break;
case DW_EH_PE_sdata4:
val = read_4s (p);
ret = p + 4;
break;
case DW_EH_PE_sdata8:
val = read_8s (p);
ret = p + 8;
break;
default:
abort ();
}
if (val != 0)
switch (encoding & 0xf0)
{
case DW_EH_PE_absptr:
break;
case DW_EH_PE_pcrel:
val += (_Unwind_Ptr) p;
break;
case DW_EH_PE_textrel:
val += (_Unwind_Ptr) bases->tbase;
break;
case DW_EH_PE_datarel:
val += (_Unwind_Ptr) bases->dbase;
break;
case DW_EH_PE_funcrel:
val += (_Unwind_Ptr) bases->func;
break;
default:
abort ();
}
*pptr = (void *) (_Unwind_Ptr) val;
return ret;
}
/* Get the value of register REG as saved in CONTEXT. */ /* Get the value of register REG as saved in CONTEXT. */
...@@ -332,13 +211,13 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context) ...@@ -332,13 +211,13 @@ _Unwind_GetTextRelBase (struct _Unwind_Context *context)
unit F belongs to. Return a pointer to the byte after the augmentation, unit F belongs to. Return a pointer to the byte after the augmentation,
or NULL if we encountered an undecipherable augmentation. */ or NULL if we encountered an undecipherable augmentation. */
static unsigned char * static const unsigned char *
extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
_Unwind_FrameState *fs) _Unwind_FrameState *fs)
{ {
unsigned char *aug = cie->augmentation; const unsigned char *aug = cie->augmentation;
unsigned char *p = aug + strlen (aug) + 1; const unsigned char *p = aug + strlen (aug) + 1;
unsigned char *ret = NULL; const unsigned char *ret = NULL;
_Unwind_Word code_align; _Unwind_Word code_align;
_Unwind_Sword data_align; _Unwind_Sword data_align;
...@@ -349,6 +228,7 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, ...@@ -349,6 +228,7 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
fs->code_align = code_align; fs->code_align = code_align;
fs->data_align = data_align; fs->data_align = data_align;
fs->retaddr_column = *p++; fs->retaddr_column = *p++;
fs->lsda_encoding = DW_EH_PE_omit;
/* If the augmentation starts with 'z', then a uleb128 immediately /* If the augmentation starts with 'z', then a uleb128 immediately
follows containing the length of the augmentation field following follows containing the length of the augmentation field following
...@@ -373,20 +253,25 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, ...@@ -373,20 +253,25 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
aug += 2; aug += 2;
} }
/* "R" indicates a byte indicating how addresses are encoded. */ /* "L" indicates a byte showing how the LSDA pointer is encoded. */
else if (aug[0] == 'L')
{
fs->lsda_encoding = *p++;
aug += 1;
}
/* "R" indicates a byte indicating how FDE addresses are encoded. */
else if (aug[0] == 'R') else if (aug[0] == 'R')
{ {
fs->addr_encoding = *p++; fs->fde_encoding = *p++;
aug += 1; aug += 1;
} }
/* "P" indicates a personality routine in the CIE augmentation /* "P" indicates a personality routine in the CIE augmentation. */
and an lsda pointer in the FDE augmentation. */
else if (aug[0] == 'P') else if (aug[0] == 'P')
{ {
p = read_encoded_pointer (p, fs->addr_encoding, &context->bases, p = read_encoded_value (context, *p, p + 1,
(void **) &fs->personality); (_Unwind_Ptr *) &fs->personality);
fs->saw_lsda = 1;
aug += 1; aug += 1;
} }
...@@ -404,7 +289,7 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context, ...@@ -404,7 +289,7 @@ extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
onto the stack to start. */ onto the stack to start. */
static _Unwind_Word static _Unwind_Word
execute_stack_op (unsigned char *op_ptr, unsigned char *op_end, execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
struct _Unwind_Context *context, _Unwind_Word initial) struct _Unwind_Context *context, _Unwind_Word initial)
{ {
_Unwind_Word stack[64]; /* ??? Assume this is enough. */ _Unwind_Word stack[64]; /* ??? Assume this is enough. */
...@@ -800,8 +685,10 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end, ...@@ -800,8 +685,10 @@ execute_stack_op (unsigned char *op_ptr, unsigned char *op_end,
CIE info, and the PC range to evaluate. */ CIE info, and the PC range to evaluate. */
static void static void
execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end, execute_cfa_program (const unsigned char *insn_ptr,
struct _Unwind_Context *context, _Unwind_FrameState *fs) const unsigned char *insn_end,
struct _Unwind_Context *context,
_Unwind_FrameState *fs)
{ {
struct frame_state_reg_info *unused_rs = NULL; struct frame_state_reg_info *unused_rs = NULL;
...@@ -832,8 +719,8 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end, ...@@ -832,8 +719,8 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
else switch (insn) else switch (insn)
{ {
case DW_CFA_set_loc: case DW_CFA_set_loc:
insn_ptr = read_encoded_pointer (insn_ptr, fs->addr_encoding, insn_ptr = read_encoded_value (context, fs->fde_encoding,
&context->bases, &fs->pc); insn_ptr, (_Unwind_Ptr *) &fs->pc);
break; break;
case DW_CFA_advance_loc1: case DW_CFA_advance_loc1:
...@@ -989,7 +876,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -989,7 +876,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
{ {
struct dwarf_fde *fde; struct dwarf_fde *fde;
struct dwarf_cie *cie; struct dwarf_cie *cie;
unsigned char *aug, *insn, *end; const unsigned char *aug, *insn, *end;
memset (fs, 0, sizeof (*fs)); memset (fs, 0, sizeof (*fs));
context->args_size = 0; context->args_size = 0;
...@@ -1011,8 +898,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -1011,8 +898,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
#endif #endif
} }
context->bases.func = fde->pc_begin; fs->pc = context->bases.func;
fs->pc = fde->pc_begin;
cie = get_cie (fde); cie = get_cie (fde);
insn = extract_cie_info (cie, context, fs); insn = extract_cie_info (cie, context, fs);
...@@ -1026,6 +912,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -1026,6 +912,7 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
/* Locate augmentation for the fde. */ /* Locate augmentation for the fde. */
aug = (unsigned char *)fde + sizeof (*fde); aug = (unsigned char *)fde + sizeof (*fde);
aug += 2 * size_of_encoded_value (fs->fde_encoding);
insn = NULL; insn = NULL;
if (fs->saw_z) if (fs->saw_z)
{ {
...@@ -1033,9 +920,9 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -1033,9 +920,9 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
aug = read_uleb128 (aug, &i); aug = read_uleb128 (aug, &i);
insn = aug + i; insn = aug + i;
} }
if (fs->saw_lsda) if (fs->lsda_encoding != DW_EH_PE_omit)
aug = read_encoded_pointer (aug, fs->addr_encoding, aug = read_encoded_value (context, fs->lsda_encoding, aug,
&context->bases, &context->lsda); (_Unwind_Ptr *) &context->lsda);
/* Then the insns in the FDE up to our target PC. */ /* Then the insns in the FDE up to our target PC. */
if (insn == NULL) if (insn == NULL)
...@@ -1076,7 +963,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -1076,7 +963,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
CFA calculation is so complicated as to require a stack program CFA calculation is so complicated as to require a stack program
that this will not be a problem. */ that this will not be a problem. */
{ {
unsigned char *exp = fs->cfa_exp; const unsigned char *exp = fs->cfa_exp;
_Unwind_Word len; _Unwind_Word len;
exp = read_uleb128 (exp, &len); exp = read_uleb128 (exp, &len);
...@@ -1104,7 +991,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) ...@@ -1104,7 +991,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
break; break;
case REG_SAVED_EXP: case REG_SAVED_EXP:
{ {
unsigned char *exp = fs->regs.reg[i].loc.exp; const unsigned char *exp = fs->regs.reg[i].loc.exp;
_Unwind_Word len; _Unwind_Word len;
_Unwind_Ptr val; _Unwind_Ptr val;
......
...@@ -74,7 +74,7 @@ size_of_encoded_value (unsigned char encoding) ...@@ -74,7 +74,7 @@ size_of_encoded_value (unsigned char encoding)
not available. */ not available. */
static _Unwind_Ptr static _Unwind_Ptr
base_of_encoded_value (unsigned char encoding, _Unwind_Context *context) base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
{ {
if (encoding == DW_EH_PE_omit) if (encoding == DW_EH_PE_omit)
return 0; return 0;
...@@ -204,7 +204,7 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, ...@@ -204,7 +204,7 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
rather than providing it directly. */ rather than providing it directly. */
static inline const unsigned char * static inline const unsigned char *
read_encoded_value (_Unwind_Context *context, unsigned char encoding, read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
const unsigned char *p, _Unwind_Ptr *val) const unsigned char *p, _Unwind_Ptr *val)
{ {
return read_encoded_value_with_base (encoding, return read_encoded_value_with_base (encoding,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment