dwarf2 EH support
From-SVN: r15255
This commit is contained in:
parent
0680d17043
commit
0021b564f4
23 changed files with 1210 additions and 164 deletions
37
gcc/c-decl.c
37
gcc/c-decl.c
|
@ -2849,7 +2849,7 @@ init_decl_processing ()
|
|||
tree traditional_ptr_type_node;
|
||||
/* Data types of memcpy and strlen. */
|
||||
tree memcpy_ftype, memset_ftype, strlen_ftype;
|
||||
tree void_ftype_any;
|
||||
tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr;
|
||||
int wchar_type_size;
|
||||
tree temp;
|
||||
tree array_domain_type;
|
||||
|
@ -3165,6 +3165,11 @@ init_decl_processing ()
|
|||
sizetype,
|
||||
endlink))));
|
||||
|
||||
ptr_ftype_void = build_function_type (ptr_type_node, endlink);
|
||||
ptr_ftype_ptr
|
||||
= build_function_type (ptr_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node, endlink));
|
||||
|
||||
builtin_function ("__builtin_constant_p", default_function_type,
|
||||
BUILT_IN_CONSTANT_P, NULL_PTR);
|
||||
|
||||
|
@ -3186,6 +3191,36 @@ init_decl_processing ()
|
|||
build_function_type (ptr_type_node, NULL_TREE),
|
||||
BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR);
|
||||
|
||||
/* Hooks for the DWARF 2 __throw routine. */
|
||||
builtin_function ("__builtin_unwind_init",
|
||||
build_function_type (void_type_node, endlink),
|
||||
BUILT_IN_UNWIND_INIT, NULL_PTR);
|
||||
builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
|
||||
builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
|
||||
builtin_function ("__builtin_dwarf_fp_regnum",
|
||||
build_function_type (unsigned_type_node, endlink),
|
||||
BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
|
||||
builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
|
||||
BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
|
||||
builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
|
||||
BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
|
||||
builtin_function ("__builtin_set_return_addr_reg",
|
||||
build_function_type (void_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
ptr_type_node,
|
||||
endlink)),
|
||||
BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
|
||||
builtin_function ("__builtin_eh_stub", ptr_ftype_void,
|
||||
BUILT_IN_EH_STUB, NULL_PTR);
|
||||
builtin_function
|
||||
("__builtin_set_eh_regs",
|
||||
build_function_type (void_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
type_for_mode (ptr_mode, 0),
|
||||
endlink))),
|
||||
BUILT_IN_SET_EH_REGS, NULL_PTR);
|
||||
|
||||
builtin_function ("__builtin_alloca",
|
||||
build_function_type (ptr_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
|
|
|
@ -239,6 +239,7 @@ static char *initname, *fininame; /* names of init and fini funcs */
|
|||
static struct head constructors; /* list of constructors found */
|
||||
static struct head destructors; /* list of destructors found */
|
||||
static struct head exports; /* list of exported symbols */
|
||||
static struct head frame_tables; /* list of frame unwind info tables */
|
||||
|
||||
struct obstack temporary_obstack;
|
||||
struct obstack permanent_obstack;
|
||||
|
@ -599,13 +600,16 @@ is_ctor_dtor (s)
|
|||
#ifdef NO_DOT_IN_LABEL
|
||||
{ "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 },
|
||||
{ "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
|
||||
{ "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
|
||||
#else
|
||||
{ "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
|
||||
{ "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
|
||||
{ "GLOBAL_.F.", sizeof ("GLOBAL_.F.")-1, 5, 0 },
|
||||
#endif
|
||||
#else
|
||||
{ "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
|
||||
{ "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 },
|
||||
{ "GLOBAL_$F$", sizeof ("GLOBAL_$F$")-1, 5, 0 },
|
||||
#endif
|
||||
{ "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
|
||||
{ "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
|
||||
|
@ -993,6 +997,7 @@ main (argc, argv)
|
|||
num_c_args++;
|
||||
}
|
||||
obstack_free (&temporary_obstack, temporary_firstobj);
|
||||
++num_c_args;
|
||||
|
||||
c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
|
||||
|
||||
|
@ -1288,6 +1293,7 @@ main (argc, argv)
|
|||
shared_obj = 1;
|
||||
}
|
||||
obstack_free (&temporary_obstack, temporary_firstobj);
|
||||
*c_ptr++ = "-fno-exceptions";
|
||||
|
||||
#ifdef COLLECT_EXPORT_LIST
|
||||
/* The AIX linker will discard static constructors in object files if
|
||||
|
@ -1396,7 +1402,8 @@ main (argc, argv)
|
|||
}
|
||||
|
||||
if (constructors.number == 0 && destructors.number == 0
|
||||
#ifdef LDD_SUFFIX
|
||||
&& frame_tables.number == 0
|
||||
#ifdef SCAN_LIBRARIES
|
||||
/* If we will be running these functions ourselves, we want to emit
|
||||
stubs into the shared library so that we don't have to relink
|
||||
dependent programs when we add static objects. */
|
||||
|
@ -1690,6 +1697,7 @@ write_c_file_stat (stream, name)
|
|||
char *name;
|
||||
{
|
||||
char *prefix, *p, *q;
|
||||
int frames = (frame_tables.number > 0);
|
||||
|
||||
/* Figure out name of output_file, stripping off .so version. */
|
||||
p = rindex (output_file, '/');
|
||||
|
@ -1743,15 +1751,38 @@ write_c_file_stat (stream, name)
|
|||
fprintf (stream, "static int count;\n");
|
||||
fprintf (stream, "typedef void entry_pt();\n");
|
||||
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
|
||||
|
||||
if (frames)
|
||||
{
|
||||
write_list_with_asm (stream, "extern void *", frame_tables.first);
|
||||
|
||||
fprintf (stream, "\tstatic void *frame_table[] = {\n");
|
||||
write_list (stream, "\t\t&", frame_tables.first);
|
||||
fprintf (stream, "\t0\n};\n");
|
||||
|
||||
fprintf (stream, "extern void __register_frame_table (void *);\n");
|
||||
fprintf (stream, "extern void __deregister_frame (void *);\n");
|
||||
|
||||
fprintf (stream, "static void reg_frame () {\n");
|
||||
fprintf (stream, "\t__register_frame_table (frame_table);\n");
|
||||
fprintf (stream, "\t}\n");
|
||||
|
||||
fprintf (stream, "static void dereg_frame () {\n");
|
||||
fprintf (stream, "\t__deregister_frame (frame_table);\n");
|
||||
fprintf (stream, "\t}\n");
|
||||
}
|
||||
|
||||
fprintf (stream, "void %s() {\n", initname);
|
||||
if (constructors.number > 0)
|
||||
if (constructors.number > 0 || frames)
|
||||
{
|
||||
fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
|
||||
write_list (stream, "\t\t", constructors.first);
|
||||
if (frames)
|
||||
fprintf (stream, "\treg_frame,\n");
|
||||
fprintf (stream, "\t};\n");
|
||||
fprintf (stream, "\tentry_pt **p;\n");
|
||||
fprintf (stream, "\tif (count++ != 0) return;\n");
|
||||
fprintf (stream, "\tp = ctors + %d;\n", constructors.number);
|
||||
fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
|
||||
fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
|
||||
}
|
||||
else
|
||||
|
@ -1759,16 +1790,18 @@ write_c_file_stat (stream, name)
|
|||
fprintf (stream, "}\n");
|
||||
write_list_with_asm (stream, "extern entry_pt ", destructors.first);
|
||||
fprintf (stream, "void %s() {\n", fininame);
|
||||
if (destructors.number > 0)
|
||||
if (destructors.number > 0 || frames)
|
||||
{
|
||||
fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
|
||||
write_list (stream, "\t\t", destructors.first);
|
||||
if (frames)
|
||||
fprintf (stream, "\tdereg_frame,\n");
|
||||
fprintf (stream, "\t};\n");
|
||||
fprintf (stream, "\tentry_pt **p;\n");
|
||||
fprintf (stream, "\tif (--count != 0) return;\n");
|
||||
fprintf (stream, "\tp = dtors;\n");
|
||||
fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
|
||||
destructors.number);
|
||||
destructors.number + frames);
|
||||
}
|
||||
fprintf (stream, "}\n");
|
||||
|
||||
|
@ -1788,20 +1821,46 @@ write_c_file_glob (stream, name)
|
|||
{
|
||||
/* Write the tables as C code */
|
||||
|
||||
int frames = (frame_tables.number > 0);
|
||||
|
||||
fprintf (stream, "typedef void entry_pt();\n\n");
|
||||
|
||||
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
|
||||
|
||||
|
||||
if (frames)
|
||||
{
|
||||
write_list_with_asm (stream, "extern void *", frame_tables.first);
|
||||
|
||||
fprintf (stream, "\tstatic void *frame_table[] = {\n");
|
||||
write_list (stream, "\t\t&", frame_tables.first);
|
||||
fprintf (stream, "\t0\n};\n");
|
||||
|
||||
fprintf (stream, "extern void __register_frame_table (void *);\n");
|
||||
fprintf (stream, "extern void __deregister_frame (void *);\n");
|
||||
|
||||
fprintf (stream, "static void reg_frame () {\n");
|
||||
fprintf (stream, "\t__register_frame_table (frame_table);\n");
|
||||
fprintf (stream, "\t}\n");
|
||||
|
||||
fprintf (stream, "static void dereg_frame () {\n");
|
||||
fprintf (stream, "\t__deregister_frame (frame_table);\n");
|
||||
fprintf (stream, "\t}\n");
|
||||
}
|
||||
|
||||
fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
|
||||
write_list (stream, "\t", constructors.first);
|
||||
if (frames)
|
||||
fprintf (stream, "\treg_frame,\n");
|
||||
fprintf (stream, "\t0\n};\n\n");
|
||||
|
||||
write_list_with_asm (stream, "extern entry_pt ", destructors.first);
|
||||
|
||||
fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
|
||||
write_list (stream, "\t", destructors.first);
|
||||
if (frames)
|
||||
fprintf (stream, "\tdereg_frame,\n");
|
||||
fprintf (stream, "\t0\n};\n\n");
|
||||
|
||||
fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
|
||||
|
@ -1985,6 +2044,10 @@ scan_prog_file (prog_name, which_pass)
|
|||
#endif
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (which_pass != PASS_LIB)
|
||||
add_to_list (&frame_tables, name);
|
||||
|
||||
default: /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1866,6 +1866,7 @@ function_prologue (file, size)
|
|||
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|
||||
|| current_function_uses_const_pool);
|
||||
long tsize = get_frame_size ();
|
||||
int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
|
||||
|
||||
/* pic references don't explicitly mention pic_offset_table_rtx */
|
||||
if (TARGET_SCHEDULE_PROLOGUE)
|
||||
|
@ -1881,13 +1882,34 @@ function_prologue (file, size)
|
|||
if (frame_pointer_needed)
|
||||
{
|
||||
output_asm_insn ("push%L1 %1", xops);
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
cfa_store_offset += 4;
|
||||
cfa_offset = cfa_store_offset;
|
||||
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
|
||||
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset);
|
||||
}
|
||||
output_asm_insn (AS2 (mov%L0,%0,%1), xops);
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
|
||||
}
|
||||
|
||||
if (tsize == 0)
|
||||
;
|
||||
else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
|
||||
output_asm_insn (AS2 (sub%L0,%2,%0), xops);
|
||||
{
|
||||
output_asm_insn (AS2 (sub%L0,%2,%0), xops);
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
cfa_store_offset += tsize;
|
||||
if (! frame_pointer_needed)
|
||||
{
|
||||
cfa_offset = cfa_store_offset;
|
||||
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xops[3] = gen_rtx (REG, SImode, 0);
|
||||
|
@ -1913,6 +1935,17 @@ function_prologue (file, size)
|
|||
{
|
||||
xops[0] = gen_rtx (REG, SImode, regno);
|
||||
output_asm_insn ("push%L0 %0", xops);
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
cfa_store_offset += 4;
|
||||
if (! frame_pointer_needed)
|
||||
{
|
||||
cfa_offset = cfa_store_offset;
|
||||
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
|
||||
}
|
||||
dwarf2out_reg_save (l, regno, -cfa_store_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
|
||||
|
|
|
@ -249,6 +249,10 @@ Boston, MA 02111-1307, USA. */
|
|||
(TARGET_LONG64 ? ".section\t.dtors,1,2,0,8" : ".section\t.dtors,1,2,0,4")
|
||||
#endif /* defined (CRT_BEGIN) || defined (CRT_END) */
|
||||
|
||||
/* dwarf2out will handle padding this data properly. We definitely don't
|
||||
want it 8-byte aligned on n32. */
|
||||
#define EH_FRAME_SECTION_ASM_OP ".section\t.eh_frame,1,2,0,1"
|
||||
|
||||
/* A default list of other sections which we might be "in" at any given
|
||||
time. For targets that use additional sections (e.g. .tdesc) you
|
||||
should override this definition in the target-specific file which
|
||||
|
@ -538,5 +542,5 @@ do { \
|
|||
%{!static: \
|
||||
%{!shared: %{!non_shared: %{!call_shared: -call_shared -no_unresolved}}}} \
|
||||
%{rpath} -init __do_global_ctors -fini __do_global_dtors \
|
||||
%{shared:-hidden_symbol __do_global_ctors,__do_global_dtors} \
|
||||
%{shared:-hidden_symbol __do_global_ctors,__do_global_dtors,__EH_FRAME_BEGIN__} \
|
||||
-_SYSTYPE_SVR4 %{mabi=32: -32}%{mabi=n32: -n32}%{mabi=64: -64} %{!mabi*: -n32}"
|
||||
|
|
|
@ -5241,6 +5241,9 @@ function_prologue (file, size)
|
|||
sp_str, sp_str, tsize);
|
||||
fprintf (file, "\t.cprestore %d\n", current_frame_info.args_size);
|
||||
}
|
||||
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -948,12 +948,11 @@ while (0)
|
|||
#define DBX_REGISTER_NUMBER(REGNO) mips_dbx_regno[ (REGNO) ]
|
||||
|
||||
/* The mapping from gcc register number to DWARF 2 CFA column number.
|
||||
This mapping does not allow for tracking DBX register 0, since column 0
|
||||
is used for the frame address, but since register 0 is fixed this is
|
||||
not really a problem. */
|
||||
This mapping does not allow for tracking register 0, since SGI's broken
|
||||
dwarf reader thinks column 0 is used for the frame address, but since
|
||||
register 0 is fixed this is not a problem. */
|
||||
#define DWARF_FRAME_REGNUM(REG) \
|
||||
(REG == GP_REG_FIRST + 31 ? DWARF_FRAME_RETURN_COLUMN \
|
||||
: DBX_REGISTER_NUMBER (REG))
|
||||
(REG == GP_REG_FIRST + 31 ? DWARF_FRAME_RETURN_COLUMN : REG)
|
||||
|
||||
/* The DWARF 2 CFA column which tracks the return address. */
|
||||
#define DWARF_FRAME_RETURN_COLUMN (FP_REG_LAST + 1)
|
||||
|
|
|
@ -2910,10 +2910,8 @@ save_regs (file, low, high, base, offset, n_regs, real_offset)
|
|||
{
|
||||
fprintf (file, "\tstx %s,[%s+%d]\n",
|
||||
reg_names[i], base, offset + 4 * n_regs);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
|
||||
#endif
|
||||
n_regs += 2;
|
||||
}
|
||||
}
|
||||
|
@ -2927,34 +2925,28 @@ save_regs (file, low, high, base, offset, n_regs, real_offset)
|
|||
{
|
||||
fprintf (file, "\tstd %s,[%s+%d]\n",
|
||||
reg_names[i], base, offset + 4 * n_regs);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
|
||||
dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
|
||||
}
|
||||
#endif
|
||||
n_regs += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (file, "\tst %s,[%s+%d]\n",
|
||||
reg_names[i], base, offset + 4 * n_regs);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
|
||||
#endif
|
||||
n_regs += 2;
|
||||
}
|
||||
else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
|
||||
{
|
||||
fprintf (file, "\tst %s,[%s+%d]\n",
|
||||
reg_names[i+1], base, offset + 4 * n_regs + 4);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
|
||||
#endif
|
||||
n_regs += 2;
|
||||
}
|
||||
}
|
||||
|
@ -3196,8 +3188,7 @@ output_function_prologue (file, size, leaf_function)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG && actual_fsize)
|
||||
if (dwarf2out_do_frame () && actual_fsize)
|
||||
{
|
||||
char *label = (char *) dwarf2out_cfi_label ();
|
||||
|
||||
|
@ -3217,7 +3208,6 @@ output_function_prologue (file, size, leaf_function)
|
|||
dwarf2out_return_reg (label, 31);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If doing anything with PIC, do it now. */
|
||||
if (! flag_pic)
|
||||
|
@ -4739,15 +4729,13 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
|
|||
fprintf (file, "\t%s %s,[%s+%d]\n",
|
||||
doubleword_op, reg_names[regno],
|
||||
base_reg, offset);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
dwarf2out_reg_save (l, regno, offset + base_offset);
|
||||
dwarf2out_reg_save
|
||||
(l, regno+1, offset+base_offset + UNITS_PER_WORD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
fprintf (file, "\t%s [%s+%d],%s\n",
|
||||
|
@ -4764,10 +4752,8 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
|
|||
fprintf (file, "\t%s %s,[%s+%d]\n",
|
||||
word_op, reg_names[regno],
|
||||
base_reg, offset);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_reg_save ("", regno, offset + base_offset);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
fprintf (file, "\t%s [%s+%d],%s\n",
|
||||
|
@ -4790,10 +4776,8 @@ sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, doublewo
|
|||
fprintf (file, "\t%s %s,[%s+%d]\n",
|
||||
word_op, reg_names[regno],
|
||||
base_reg, offset);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_reg_save ("", regno, offset + base_offset);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
fprintf (file, "\t%s [%s+%d],%s\n",
|
||||
|
@ -4891,8 +4875,7 @@ sparc_flat_output_function_prologue (file, size)
|
|||
reg_offset += 4;
|
||||
}
|
||||
}
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
if (gmask & FRAME_POINTER_MASK)
|
||||
|
@ -4904,15 +4887,12 @@ sparc_flat_output_function_prologue (file, size)
|
|||
else
|
||||
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
|
||||
}
|
||||
#endif
|
||||
if (gmask & RETURN_ADDR_MASK)
|
||||
{
|
||||
fprintf (file, "\tst %s,[%s+%d]\n",
|
||||
reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_return_save ("", reg_offset - size);
|
||||
#endif
|
||||
reg_offset += 4;
|
||||
}
|
||||
sparc_flat_save_restore (file, sp_str, reg_offset,
|
||||
|
@ -4951,8 +4931,7 @@ sparc_flat_output_function_prologue (file, size)
|
|||
offset += 4;
|
||||
}
|
||||
}
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
{
|
||||
char *l = (char *) dwarf2out_cfi_label ();
|
||||
if (gmask & FRAME_POINTER_MASK)
|
||||
|
@ -4964,17 +4943,14 @@ sparc_flat_output_function_prologue (file, size)
|
|||
else
|
||||
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
|
||||
}
|
||||
#endif
|
||||
if (gmask & RETURN_ADDR_MASK)
|
||||
{
|
||||
fprintf (file, "\tst %s,[%s+%d]\n",
|
||||
reg_names[RETURN_ADDR_REGNUM], sp_str, offset);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
/* offset - size1 == reg_offset - size
|
||||
if reg_offset were updated above like offset. */
|
||||
dwarf2out_return_save ("", offset - size1);
|
||||
#endif
|
||||
offset += 4;
|
||||
}
|
||||
sparc_flat_save_restore (file, sp_str, offset,
|
||||
|
@ -4983,11 +4959,9 @@ sparc_flat_output_function_prologue (file, size)
|
|||
"st", "std", -size1);
|
||||
fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n",
|
||||
size - size1, t1_str, sp_str, t1_str, sp_str);
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
if (! (gmask & FRAME_POINTER_MASK))
|
||||
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,3 +25,6 @@ Boston, MA 02111-1307, USA. */
|
|||
#define DBX_USE_BINCL
|
||||
|
||||
#include "sparc/sparc.h"
|
||||
|
||||
/* The Sun as doesn't like unaligned data. */
|
||||
#define DWARF2_UNWIND_INFO 0
|
||||
|
|
|
@ -91,6 +91,7 @@ Boston, MA 02111-1307, USA. */
|
|||
#define STRING_ASM_OP ".asciz"
|
||||
#define COMMON_ASM_OP ".common"
|
||||
#define SKIP_ASM_OP ".skip"
|
||||
#define UNALIGNED_DOUBLE_INT_ASM_OP ".uaxword"
|
||||
#define UNALIGNED_INT_ASM_OP ".uaword"
|
||||
#define UNALIGNED_SHORT_ASM_OP ".uahalf"
|
||||
#define PUSHSECTION_ASM_OP ".pushsection"
|
||||
|
@ -179,6 +180,8 @@ do { ASM_OUTPUT_ALIGN ((FILE), Pmode == SImode ? 2 : 3); \
|
|||
#define CTORS_SECTION_ASM_OP ".section\t\".ctors\",#alloc,#write"
|
||||
#undef DTORS_SECTION_ASM_OP
|
||||
#define DTORS_SECTION_ASM_OP ".section\t\".dtors\",#alloc,#write"
|
||||
#undef EH_FRAME_SECTION_ASM_OP
|
||||
#define EH_FRAME_SECTION_ASM_OP ".section\t\".eh_frame\",#alloc,#write"
|
||||
|
||||
/* A C statement to output something to the assembler file to switch to section
|
||||
NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or
|
||||
|
|
|
@ -2934,7 +2934,7 @@ finish_file ()
|
|||
rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1);
|
||||
vars = static_aggregates;
|
||||
|
||||
if (static_ctors || vars || exception_table_p ())
|
||||
if (static_ctors || vars || register_exception_table_p ())
|
||||
needs_messing_up = 1;
|
||||
if (static_dtors)
|
||||
needs_cleaning = 1;
|
||||
|
@ -3033,7 +3033,7 @@ finish_file ()
|
|||
push_momentary ();
|
||||
expand_start_bindings (0);
|
||||
|
||||
if (exception_table_p ())
|
||||
if (register_exception_table_p ())
|
||||
register_exception_table ();
|
||||
|
||||
while (vars)
|
||||
|
|
|
@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
|
|||
#include "output.h"
|
||||
#include "except.h"
|
||||
#include "function.h"
|
||||
#include "defaults.h"
|
||||
|
||||
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
|
||||
|
||||
|
@ -609,7 +610,8 @@ do_unwind (inner_throw_label)
|
|||
rtx inner_throw_label;
|
||||
{
|
||||
#if defined (SPARC_STACK_ALIGN) /* was sparc */
|
||||
/* This doesn't work for the flat model sparc, I bet. */
|
||||
/* This doesn't work for the flat model sparc, nor does it need to
|
||||
as the default unwinder is only used to unwind non-flat frames. */
|
||||
tree fcall;
|
||||
tree params;
|
||||
rtx next_pc;
|
||||
|
@ -704,6 +706,7 @@ do_unwind (inner_throw_label)
|
|||
void
|
||||
expand_builtin_throw ()
|
||||
{
|
||||
#ifndef DWARF2_UNWIND_INFO
|
||||
tree fcall;
|
||||
tree params;
|
||||
rtx handler;
|
||||
|
@ -897,6 +900,7 @@ expand_builtin_throw ()
|
|||
pop_momentary ();
|
||||
|
||||
finish_function (lineno, 0, 0);
|
||||
#endif /* DWARF2_UNWIND_INFO */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1149,7 +1153,6 @@ expand_throw (exp)
|
|||
expand_expr (object, const0_rtx, VOIDmode, 0);
|
||||
end_anon_func ();
|
||||
mark_addressable (cleanup);
|
||||
|
||||
}
|
||||
|
||||
if (cleanup == empty_fndecl)
|
||||
|
|
|
@ -1185,29 +1185,28 @@ arrays. Exception specifications are now handled. Thrown objects are
|
|||
now cleaned up all the time. We can now tell if we have an active
|
||||
exception being thrown or not (__eh_type != 0). We use this to call
|
||||
terminate if someone does a throw; without there being an active
|
||||
exception object. uncaught_exception () works.
|
||||
exception object. uncaught_exception () works. Exception handling
|
||||
should work right if you optimize. Exception handling should work with
|
||||
-fpic or -fPIC.
|
||||
|
||||
The below points out some flaws in g++'s exception handling, as it now
|
||||
stands.
|
||||
|
||||
Only exact type matching or reference matching of throw types works when
|
||||
-fno-rtti is used. Only works on a SPARC (like Suns), SPARClite, i386,
|
||||
arm, rs6000, PowerPC, Alpha, mips, VAX, m68k and z8k machines. Partial
|
||||
support is in for all other machines, but a stack unwinder called
|
||||
__unwind_function has to be written, and added to libgcc2 for them. The
|
||||
new EH code doesn't rely upon the __unwind_function for C++ code,
|
||||
instead it creates per function unwinders right inside the function,
|
||||
unfortunately, on many platforms the definition of RETURN_ADDR_RTX in
|
||||
the tm.h file for the machine port is wrong. The HPPA has a brain dead
|
||||
abi that prevents exception handling from just working. See below for
|
||||
details on __unwind_function. Don't expect exception handling to work
|
||||
right if you optimize, in fact the compiler will probably core dump.
|
||||
RTL_EXPRs for EH cond variables for && and || exprs should probably be
|
||||
wrapped in UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be
|
||||
unsaved, and the UNSAVE_EXPR code should be in the backend, or
|
||||
alternatively, UNSAVE_EXPR should be ripped out and exactly one
|
||||
finalization allowed to be expanded by the backend. I talked with
|
||||
kenner about this, and we have to allow multiple expansions.
|
||||
-fno-rtti is used. Only works on a SPARC (like Suns) (both -mflat and
|
||||
-mno-flat models work), SPARClite, Hitachi SH, i386, arm, rs6000,
|
||||
PowerPC, Alpha, mips, VAX, m68k and z8k machines. SPARC v9 may not
|
||||
work. HPPA is mostly done, but throwing between a shared library and
|
||||
user code doesn't yet work. Some targets have support for data-driven
|
||||
unwinding. Partial support is in for all other machines, but a stack
|
||||
unwinder called __unwind_function has to be written, and added to
|
||||
libgcc2 for them. The new EH code doesn't rely upon the
|
||||
__unwind_function for C++ code, instead it creates per function
|
||||
unwinders right inside the function, unfortunately, on many platforms
|
||||
the definition of RETURN_ADDR_RTX in the tm.h file for the machine port
|
||||
is wrong. See below for details on __unwind_function. RTL_EXPRs for EH
|
||||
cond variables for && and || exprs should probably be wrapped in
|
||||
UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be unsaved.
|
||||
|
||||
We only do pointer conversions on exception matching a la 15.3 p2 case
|
||||
3: `A handler with type T, const T, T&, or const T& is a match for a
|
||||
|
@ -1397,6 +1396,33 @@ things: first, a way to figure out where the frame pointer was stored,
|
|||
and second, a functional @code{__builtin_return_address} implementation
|
||||
for except.c to be able to use it.
|
||||
|
||||
Or just support DWARF 2 unwind info.
|
||||
|
||||
@subsection New Backend Exception Support
|
||||
|
||||
This subsection discusses various aspects of the design of the
|
||||
data-driven model being implemented for the exception handling backend.
|
||||
|
||||
The goal is to generate enough data during the compilation of user code,
|
||||
such that we can dynamically unwind through functions at run time with a
|
||||
single routine (@code{__throw}) that lives in libgcc.a, built by the
|
||||
compiler, and dispatch into associated exception handlers.
|
||||
|
||||
This information is generated by the DWARF 2 debugging backend, and
|
||||
includes all of the information __throw needs to unwind an arbitrary
|
||||
frame. It specifies where all of the saved registers and the return
|
||||
address can be found at any point in the function.
|
||||
|
||||
Major disadvantages when enabling exceptions are:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Code that uses caller saved registers, can't, when flow can be
|
||||
transfered into that code from an exception handler. In high performace
|
||||
code this should not usually be true, so the effects should be minimal.
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection Backend Exception Support
|
||||
|
||||
The backend must be extended to fully support exceptions. Right now
|
||||
|
|
|
@ -52,6 +52,7 @@ Boston, MA 02111-1307, USA. */
|
|||
do not apply. */
|
||||
|
||||
#include "tm.h"
|
||||
#include "defaults.h"
|
||||
|
||||
/* Provide default definitions for the pseudo-ops used to switch to the
|
||||
.ctors and .dtors sections.
|
||||
|
@ -75,6 +76,9 @@ Boston, MA 02111-1307, USA. */
|
|||
#ifndef DTORS_SECTION_ASM_OP
|
||||
#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
|
||||
#endif
|
||||
#if !defined (EH_FRAME_SECTION_ASM_OP) && defined (DWARF2_UNWIND_INFO) && defined(ASM_OUTPUT_SECTION_NAME)
|
||||
#define EH_FRAME_SECTION_ASM_OP ".section\t.eh_frame,\"aw\""
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_FORMAT_ELF
|
||||
|
||||
|
@ -118,6 +122,7 @@ typedef void (*func_ptr) (void);
|
|||
the list we left off processing, and we resume at that point,
|
||||
should we be re-invoked. */
|
||||
|
||||
static char __EH_FRAME_BEGIN__[];
|
||||
static func_ptr __DTOR_LIST__[];
|
||||
static void
|
||||
__do_global_dtors_aux ()
|
||||
|
@ -128,6 +133,10 @@ __do_global_dtors_aux ()
|
|||
p++;
|
||||
(*(p-1)) ();
|
||||
}
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
__deregister_frame (__EH_FRAME_BEGIN__);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Stick a call to __do_global_dtors_aux into the .fini section. */
|
||||
|
@ -143,6 +152,29 @@ fini_dummy ()
|
|||
asm (TEXT_SECTION_ASM_OP);
|
||||
}
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
/* Stick a call to __register_frame into the .init section. For some reason
|
||||
calls with no arguments work more reliably in .init, so stick the call
|
||||
in another function. */
|
||||
|
||||
static void
|
||||
frame_dummy ()
|
||||
{
|
||||
__register_frame (__EH_FRAME_BEGIN__);
|
||||
}
|
||||
|
||||
static void
|
||||
init_dummy ()
|
||||
{
|
||||
asm (INIT_SECTION_ASM_OP);
|
||||
frame_dummy ();
|
||||
#ifdef FORCE_INIT_SECTION_ALIGN
|
||||
FORCE_INIT_SECTION_ALIGN;
|
||||
#endif
|
||||
asm (TEXT_SECTION_ASM_OP);
|
||||
}
|
||||
#endif /* EH_FRAME_SECTION_ASM_OP */
|
||||
|
||||
#else /* OBJECT_FORMAT_ELF */
|
||||
|
||||
/* The function __do_global_ctors_aux is compiled twice (once in crtbegin.o
|
||||
|
@ -200,7 +232,9 @@ __do_global_ctors_aux () /* prologue goes in .init section */
|
|||
#ifdef HAS_INIT_SECTION
|
||||
/* This case is used by the Irix 6 port, which supports named sections but
|
||||
not an SVR4-style .fini section. __do_global_dtors can be non-static
|
||||
in this case because the -fini switch to ld binds strongly. */
|
||||
in this case because we protect it with -hidden_symbol. */
|
||||
|
||||
static char __EH_FRAME_BEGIN__[];
|
||||
static func_ptr __DTOR_LIST__[];
|
||||
void
|
||||
__do_global_dtors ()
|
||||
|
@ -208,6 +242,10 @@ __do_global_dtors ()
|
|||
func_ptr *p;
|
||||
for (p = __DTOR_LIST__ + 1; *p; p++)
|
||||
(*p) ();
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
__deregister_frame (__EH_FRAME_BEGIN__);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -244,6 +282,17 @@ asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
|
|||
STATIC func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) };
|
||||
#endif
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
/* Stick a label at the beginning of the frame unwind info so we can register
|
||||
and deregister it with the exception handling library code. */
|
||||
|
||||
asm (EH_FRAME_SECTION_ASM_OP);
|
||||
#ifdef INIT_SECTION_ASM_OP
|
||||
STATIC
|
||||
#endif
|
||||
char __EH_FRAME_BEGIN__[] = { };
|
||||
#endif /* EH_FRAME_SECTION_ASM_OP */
|
||||
|
||||
#endif /* defined(CRT_BEGIN) */
|
||||
|
||||
#ifdef CRT_END
|
||||
|
@ -327,12 +376,16 @@ __do_global_ctors_aux () /* prologue goes in .text section */
|
|||
#ifdef HAS_INIT_SECTION
|
||||
/* This case is used by the Irix 6 port, which supports named sections but
|
||||
not an SVR4-style .init section. __do_global_ctors can be non-static
|
||||
in this case because the -init switch to ld binds strongly. */
|
||||
in this case because we protect it with -hidden_symbol. */
|
||||
extern char __EH_FRAME_BEGIN__[];
|
||||
static func_ptr __CTOR_END__[];
|
||||
void
|
||||
__do_global_ctors ()
|
||||
{
|
||||
func_ptr *p;
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
__register_frame (__EH_FRAME_BEGIN__);
|
||||
#endif
|
||||
for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
|
||||
(*p) ();
|
||||
}
|
||||
|
@ -363,4 +416,13 @@ asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
|
|||
STATIC func_ptr __DTOR_END__[1] = { (func_ptr) 0 };
|
||||
#endif
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
/* Terminate the frame unwind info section with a 4byte 0 as a sentinel;
|
||||
this would be the 'length' field in a real FDE. */
|
||||
|
||||
typedef unsigned int ui32 __attribute__ ((mode (SI)));
|
||||
asm (EH_FRAME_SECTION_ASM_OP);
|
||||
STATIC ui32 __FRAME_END__[] = { 0 };
|
||||
#endif /* EH_FRAME_SECTION */
|
||||
|
||||
#endif /* defined(CRT_END) */
|
||||
|
|
|
@ -136,6 +136,6 @@ do { fprintf (FILE, "\t%s\t", ASM_LONG); \
|
|||
|
||||
/* If we have a definition of INCOMING_RETURN_ADDR_RTX, assume that
|
||||
the rest of the DWARF 2 frame unwind support is also provided. */
|
||||
#ifdef INCOMING_RETURN_ADDR_RTX
|
||||
#define DWARF2_UNWIND_INFO
|
||||
#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX)
|
||||
#define DWARF2_UNWIND_INFO 1
|
||||
#endif
|
||||
|
|
|
@ -496,7 +496,8 @@ enum dwarf_call_frame_info
|
|||
DW_CFA_MIPS_advance_loc8 = 0x1d,
|
||||
|
||||
/* GNU extensions */
|
||||
DW_CFA_GNU_window_save = 0x2d
|
||||
DW_CFA_GNU_window_save = 0x2d,
|
||||
DW_CFA_GNU_args_size = 0x2e
|
||||
};
|
||||
|
||||
#define DW_CIE_ID 0xffffffff
|
||||
|
|
271
gcc/dwarf2out.c
271
gcc/dwarf2out.c
|
@ -20,19 +20,15 @@ You should have received a copy of the GNU General Public License
|
|||
along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "defaults.h"
|
||||
|
||||
/* The first part of this file deals with the DWARF 2 frame unwind
|
||||
information, which is also used by the GCC efficient exception handling
|
||||
mechanism. The second part, controlled only by an #ifdef
|
||||
DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
|
||||
information. */
|
||||
|
||||
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
|
||||
|
||||
#include "config.h"
|
||||
#include "defaults.h"
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include "dwarf2.h"
|
||||
#include "tree.h"
|
||||
#include "flags.h"
|
||||
|
@ -48,6 +44,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
/* #define NDEBUG 1 */
|
||||
#include "assert.h"
|
||||
|
||||
/* Decide whether we want to emit frame unwind information for the current
|
||||
translation unit. */
|
||||
|
||||
int
|
||||
dwarf2out_do_frame ()
|
||||
{
|
||||
return (write_symbols == DWARF2_DEBUG
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
|| (flag_exceptions && ! exceptions_via_longjmp)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define inline
|
||||
#endif
|
||||
|
@ -191,6 +202,7 @@ static unsigned reg_number PROTO((rtx));
|
|||
Theses may be overridden in the tm.h file (if necessary) for a particular
|
||||
assembler. */
|
||||
|
||||
#ifdef OBJECT_FORMAT_ELF
|
||||
#ifndef UNALIGNED_SHORT_ASM_OP
|
||||
#define UNALIGNED_SHORT_ASM_OP ".2byte"
|
||||
#endif
|
||||
|
@ -200,20 +212,12 @@ static unsigned reg_number PROTO((rtx));
|
|||
#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
|
||||
#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte"
|
||||
#endif
|
||||
#endif /* OBJECT_FORMAT_ELF */
|
||||
|
||||
#ifndef ASM_BYTE_OP
|
||||
#define ASM_BYTE_OP ".byte"
|
||||
#endif
|
||||
|
||||
#ifndef UNALIGNED_OFFSET_ASM_OP
|
||||
#define UNALIGNED_OFFSET_ASM_OP \
|
||||
(DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
|
||||
#endif
|
||||
|
||||
#ifndef UNALIGNED_WORD_ASM_OP
|
||||
#define UNALIGNED_WORD_ASM_OP \
|
||||
(PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
|
||||
#endif
|
||||
|
||||
/* Data and reference forms for relocatable data. */
|
||||
#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
|
||||
#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
|
||||
|
@ -238,9 +242,6 @@ static unsigned reg_number PROTO((rtx));
|
|||
#ifndef FRAME_SECTION
|
||||
#define FRAME_SECTION ".debug_frame"
|
||||
#endif
|
||||
#if !defined (EH_FRAME_SECTION) && defined (ASM_OUTPUT_SECTION_NAME)
|
||||
#define EH_FRAME_SECTION ".eh_frame"
|
||||
#endif
|
||||
|
||||
#ifndef FUNC_BEGIN_LABEL
|
||||
#define FUNC_BEGIN_LABEL "LFB"
|
||||
|
@ -262,6 +263,23 @@ static unsigned reg_number PROTO((rtx));
|
|||
fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
|
||||
#endif
|
||||
|
||||
#ifndef ASM_OUTPUT_DWARF_DATA1
|
||||
#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
|
||||
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, VALUE)
|
||||
#endif
|
||||
|
||||
#ifdef UNALIGNED_INT_ASM_OP
|
||||
|
||||
#ifndef UNALIGNED_OFFSET_ASM_OP
|
||||
#define UNALIGNED_OFFSET_ASM_OP \
|
||||
(DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
|
||||
#endif
|
||||
|
||||
#ifndef UNALIGNED_WORD_ASM_OP
|
||||
#define UNALIGNED_WORD_ASM_OP \
|
||||
(PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
|
||||
#endif
|
||||
|
||||
#ifndef ASM_OUTPUT_DWARF_DELTA2
|
||||
#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
|
||||
do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \
|
||||
|
@ -317,11 +335,6 @@ static unsigned reg_number PROTO((rtx));
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef ASM_OUTPUT_DWARF_DATA1
|
||||
#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
|
||||
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, VALUE)
|
||||
#endif
|
||||
|
||||
#ifndef ASM_OUTPUT_DWARF_DATA2
|
||||
#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
|
||||
fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) VALUE)
|
||||
|
@ -360,6 +373,43 @@ static unsigned reg_number PROTO((rtx));
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
#else /* UNALIGNED_INT_ASM_OP */
|
||||
|
||||
/* We don't have unaligned support, let's hope the normal output works for
|
||||
.debug_frame. */
|
||||
|
||||
#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
|
||||
assemble_integer (gen_rtx (SYMBOL_REF, Pmode, LABEL), PTR_SIZE, 1)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
|
||||
assemble_integer (gen_rtx (SYMBOL_REF, SImode, LABEL), 4, 1)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
|
||||
assemble_integer (gen_rtx (MINUS, HImode, \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL1), \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL2)), \
|
||||
2, 1)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \
|
||||
assemble_integer (gen_rtx (MINUS, SImode, \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL1), \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL2)), \
|
||||
4, 1)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \
|
||||
assemble_integer (gen_rtx (MINUS, Pmode, \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL1), \
|
||||
gen_rtx (SYMBOL_REF, Pmode, LABEL2)), \
|
||||
PTR_SIZE, 1)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
|
||||
ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
|
||||
|
||||
#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
|
||||
assemble_integer (GEN_INT (VALUE), 4, 1)
|
||||
|
||||
#endif /* UNALIGNED_INT_ASM_OP */
|
||||
|
||||
/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
|
||||
newline is produced. When flag_verbose_asm is asserted, we add commnetary
|
||||
at the end of the line, so we must avoid output of a newline here. */
|
||||
|
@ -404,6 +454,14 @@ static unsigned reg_number PROTO((rtx));
|
|||
#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
|
||||
#endif
|
||||
|
||||
/* Hook used by __throw. */
|
||||
|
||||
rtx
|
||||
expand_builtin_dwarf_fp_regnum ()
|
||||
{
|
||||
return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
|
||||
}
|
||||
|
||||
/* The offset from the incoming value of %sp to the top of the stack frame
|
||||
for the current function. */
|
||||
#ifndef INCOMING_FRAME_SP_OFFSET
|
||||
|
@ -497,6 +555,8 @@ dwarf_cfi_name (cfi_opc)
|
|||
/* GNU extensions */
|
||||
case DW_CFA_GNU_window_save:
|
||||
return "DW_CFA_GNU_window_save";
|
||||
case DW_CFA_GNU_args_size:
|
||||
return "DW_CFA_GNU_args_size";
|
||||
|
||||
default:
|
||||
return "DW_CFA_<unknown>";
|
||||
|
@ -638,6 +698,9 @@ static long cfa_offset;
|
|||
static unsigned cfa_store_reg;
|
||||
static long cfa_store_offset;
|
||||
|
||||
/* The running total of the size of arguments pushed onto the stack. */
|
||||
static long args_size;
|
||||
|
||||
/* Entry point to update the canonical frame address (CFA).
|
||||
LABEL is passed to add_fde_cfi. The value of CFA is now to be
|
||||
calculated from REG+OFFSET. */
|
||||
|
@ -743,6 +806,20 @@ dwarf2out_window_save (label)
|
|||
add_fde_cfi (label, cfi);
|
||||
}
|
||||
|
||||
/* Add a CFI to update the running total of the size of arguments
|
||||
pushed onto the stack. */
|
||||
|
||||
void
|
||||
dwarf2out_args_size (label, size)
|
||||
char *label;
|
||||
long size;
|
||||
{
|
||||
register dw_cfi_ref cfi = new_cfi ();
|
||||
cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
|
||||
cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
|
||||
add_fde_cfi (label, cfi);
|
||||
}
|
||||
|
||||
/* Entry point for saving a register to the stack. REG is the GCC register
|
||||
number. LABEL and OFFSET are passed to reg_save. */
|
||||
|
||||
|
@ -828,6 +905,67 @@ initial_return_save (rtl)
|
|||
reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset);
|
||||
}
|
||||
|
||||
/* Check INSN to see if it looks like a push or a stack adjustment, and
|
||||
make a note of it if it does. EH uses this information to find out how
|
||||
much extra space it needs to pop off the stack. */
|
||||
|
||||
static void
|
||||
dwarf2out_stack_adjust (insn)
|
||||
rtx insn;
|
||||
{
|
||||
rtx src, dest;
|
||||
enum rtx_code code;
|
||||
long offset;
|
||||
char *label;
|
||||
|
||||
if (GET_CODE (insn) != SET)
|
||||
return;
|
||||
|
||||
src = SET_SRC (insn);
|
||||
dest = SET_DEST (insn);
|
||||
if (dest == stack_pointer_rtx)
|
||||
{
|
||||
/* (set (reg sp) (plus (reg sp) (const_int))) */
|
||||
code = GET_CODE (src);
|
||||
if (! (code == PLUS || code == MINUS)
|
||||
|| XEXP (src, 0) != stack_pointer_rtx
|
||||
|| GET_CODE (XEXP (src, 1)) != CONST_INT)
|
||||
return;
|
||||
|
||||
offset = INTVAL (XEXP (src, 1));
|
||||
}
|
||||
else if (GET_CODE (dest) == MEM)
|
||||
{
|
||||
/* (set (mem (pre_dec (reg sp))) (foo)) */
|
||||
src = XEXP (dest, 0);
|
||||
code = GET_CODE (src);
|
||||
|
||||
if (! (code == PRE_DEC || code == PRE_INC)
|
||||
|| XEXP (src, 0) != stack_pointer_rtx)
|
||||
return;
|
||||
|
||||
offset = GET_MODE_SIZE (GET_MODE (dest));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if (code == PLUS || code == PRE_INC)
|
||||
offset = -offset;
|
||||
if (cfa_reg == STACK_POINTER_REGNUM)
|
||||
cfa_offset += offset;
|
||||
|
||||
#ifndef STACK_GROWS_DOWNWARD
|
||||
offset = -offset;
|
||||
#endif
|
||||
args_size += offset;
|
||||
if (args_size < 0)
|
||||
args_size = 0;
|
||||
|
||||
label = dwarf2out_cfi_label ();
|
||||
dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
|
||||
dwarf2out_args_size (label, args_size);
|
||||
}
|
||||
|
||||
/* Record call frame debugging information for INSN, which either
|
||||
sets SP or FP (adjusting how we calculate the frame address) or saves a
|
||||
register to the stack. If INSN is NULL_RTX, initialize our state. */
|
||||
|
@ -857,6 +995,12 @@ dwarf2out_frame_debug (insn)
|
|||
return;
|
||||
}
|
||||
|
||||
if (! RTX_FRAME_RELATED_P (insn))
|
||||
{
|
||||
dwarf2out_stack_adjust (PATTERN (insn));
|
||||
return;
|
||||
}
|
||||
|
||||
label = dwarf2out_cfi_label ();
|
||||
|
||||
insn = PATTERN (insn);
|
||||
|
@ -903,13 +1047,21 @@ dwarf2out_frame_debug (insn)
|
|||
abort ();
|
||||
}
|
||||
|
||||
if (XEXP (src, 0) == hard_frame_pointer_rtx)
|
||||
{
|
||||
/* Restoring SP from FP in the epilogue. */
|
||||
assert (cfa_reg == HARD_FRAME_POINTER_REGNUM);
|
||||
cfa_reg = STACK_POINTER_REGNUM;
|
||||
}
|
||||
else
|
||||
assert (XEXP (src, 0) == stack_pointer_rtx);
|
||||
|
||||
if (GET_CODE (src) == PLUS)
|
||||
offset = -offset;
|
||||
if (cfa_reg == STACK_POINTER_REGNUM)
|
||||
cfa_offset += offset;
|
||||
if (cfa_store_reg == STACK_POINTER_REGNUM)
|
||||
cfa_store_offset += offset;
|
||||
assert (XEXP (src, 0) == stack_pointer_rtx);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -953,7 +1105,7 @@ dwarf2out_frame_debug (insn)
|
|||
case PRE_INC:
|
||||
case PRE_DEC:
|
||||
offset = GET_MODE_SIZE (GET_MODE (dest));
|
||||
if (GET_CODE (src) == PRE_INC)
|
||||
if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
|
||||
offset = -offset;
|
||||
|
||||
assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM);
|
||||
|
@ -1196,12 +1348,29 @@ output_cfi (cfi, fde)
|
|||
break;
|
||||
case DW_CFA_GNU_window_save:
|
||||
break;
|
||||
case DW_CFA_GNU_args_size:
|
||||
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
|
||||
fputc ('\n', asm_out_file);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined (EH_FRAME_SECTION)
|
||||
#if defined (EH_FRAME_SECTION_ASM_OP)
|
||||
#define EH_FRAME_SECTION() eh_frame_section();
|
||||
#else
|
||||
#if defined (ASM_OUTPUT_SECTION_NAME)
|
||||
#define EH_FRAME_SECTION() \
|
||||
do { \
|
||||
named_section (NULL_TREE, ".eh_frame", 0); \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Output the call frame information used to used to record information
|
||||
that relates to calculating the frame pointer, and records the
|
||||
location of saved registers. */
|
||||
|
@ -1231,9 +1400,13 @@ output_call_frame_info (for_eh)
|
|||
if (for_eh)
|
||||
{
|
||||
#ifdef EH_FRAME_SECTION
|
||||
ASM_OUTPUT_SECTION_NAME (asm_out_file, NULL_TREE, EH_FRAME_SECTION, 0);
|
||||
EH_FRAME_SECTION ();
|
||||
#else
|
||||
tree label = (tree) get_file_function_name ('F');
|
||||
|
||||
data_section ();
|
||||
ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
|
||||
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
|
||||
#endif
|
||||
assemble_label ("__FRAME_BEGIN__");
|
||||
}
|
||||
|
@ -1272,9 +1445,9 @@ output_call_frame_info (for_eh)
|
|||
fputc ('\n', asm_out_file);
|
||||
if (eh_ptr)
|
||||
{
|
||||
/* The "z" augmentation was defined by SGI; the FDE contains a pointer
|
||||
/* The FDE contains a pointer
|
||||
to the exception region info for the frame. */
|
||||
ASM_OUTPUT_DWARF_STRING (asm_out_file, "z");
|
||||
ASM_OUTPUT_DWARF_STRING (asm_out_file, "e");
|
||||
if (flag_verbose_asm)
|
||||
fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
|
||||
}
|
||||
|
@ -1302,14 +1475,6 @@ output_call_frame_info (for_eh)
|
|||
fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
|
||||
|
||||
fputc ('\n', asm_out_file);
|
||||
if (eh_ptr)
|
||||
{
|
||||
output_uleb128 (0);
|
||||
if (flag_verbose_asm)
|
||||
fprintf (asm_out_file, "\t%s CIE augmentation fields length",
|
||||
ASM_COMMENT_START);
|
||||
fputc ('\n', asm_out_file);
|
||||
}
|
||||
|
||||
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
|
||||
output_cfi (cfi, NULL);
|
||||
|
@ -1355,19 +1520,9 @@ output_call_frame_info (for_eh)
|
|||
fputc ('\n', asm_out_file);
|
||||
if (eh_ptr)
|
||||
{
|
||||
output_uleb128 (PTR_SIZE);
|
||||
if (flag_verbose_asm)
|
||||
fprintf (asm_out_file, "\t%s FDE augmentation fields length",
|
||||
ASM_COMMENT_START);
|
||||
fputc ('\n', asm_out_file);
|
||||
|
||||
/* For now, a pointer to the translation unit's info will do.
|
||||
??? Eventually this should point to the function's info. */
|
||||
if (exception_table_p ())
|
||||
ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
|
||||
else
|
||||
ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
|
||||
|
||||
ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
|
||||
if (flag_verbose_asm)
|
||||
fprintf (asm_out_file, "\t%s pointer to exception region info",
|
||||
ASM_COMMENT_START);
|
||||
|
@ -1399,16 +1554,6 @@ output_call_frame_info (for_eh)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Decide whether we want to emit frame unwind information for the current
|
||||
translation unit. */
|
||||
|
||||
int
|
||||
dwarf2out_do_frame ()
|
||||
{
|
||||
return (write_symbols == DWARF2_DEBUG
|
||||
|| (flag_exceptions && ! exceptions_via_longjmp));
|
||||
}
|
||||
|
||||
/* Output a marker (i.e. a label) for the beginning of a function, before
|
||||
the prologue. */
|
||||
|
||||
|
@ -1443,6 +1588,8 @@ dwarf2out_begin_prologue ()
|
|||
fde->dw_fde_current_label = NULL;
|
||||
fde->dw_fde_end = NULL;
|
||||
fde->dw_fde_cfi = NULL;
|
||||
|
||||
args_size = 0;
|
||||
}
|
||||
|
||||
/* Output a marker (i.e. a label) for the absolute end of the generated code
|
||||
|
@ -9142,10 +9289,6 @@ dwarf2out_init (asm_out_file, main_input_filename)
|
|||
gen_compile_unit_die (main_input_filename);
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
|
||||
|
||||
/* Initialize the frame unwind information. Eventually this should be
|
||||
called from compile_file instead. */
|
||||
dwarf2out_frame_init ();
|
||||
}
|
||||
|
||||
/* Output stuff that dwarf requires at the end of every file,
|
||||
|
@ -9202,10 +9345,6 @@ dwarf2out_finish ()
|
|||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
|
||||
#endif
|
||||
|
||||
/* Output the frame unwind information. Eventually this should be called
|
||||
from compile_file instead. */
|
||||
dwarf2out_frame_finish ();
|
||||
|
||||
/* Output the source line correspondence table. */
|
||||
if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
|
||||
{
|
||||
|
|
12
gcc/except.h
12
gcc/except.h
|
@ -281,3 +281,15 @@ extern int protect_cleanup_actions_with_terminate;
|
|||
#ifdef TREE_CODE
|
||||
extern tree protect_with_terminate PROTO((tree));
|
||||
#endif
|
||||
|
||||
/* Various hooks for the DWARF 2 __throw routine. */
|
||||
|
||||
void expand_builtin_unwind_init PROTO((void));
|
||||
rtx expand_builtin_dwarf_fp_regnum PROTO((void));
|
||||
rtx expand_builtin_eh_stub PROTO((void));
|
||||
#ifdef TREE_CODE
|
||||
rtx expand_builtin_frob_return_addr PROTO((tree));
|
||||
rtx expand_builtin_extract_return_addr PROTO((tree));
|
||||
void expand_builtin_set_return_addr_reg PROTO((tree));
|
||||
void expand_builtin_set_eh_regs PROTO((tree, tree));
|
||||
#endif
|
||||
|
|
31
gcc/final.c
31
gcc/final.c
|
@ -955,9 +955,9 @@ final_start_function (first, file, optimize)
|
|||
last_linenum = high_block_linenum = high_function_linenum
|
||||
= NOTE_LINE_NUMBER (first);
|
||||
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
#if defined (DWARF2_UNWIND_INFO)
|
||||
/* Output DWARF definition of the function. */
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_begin_prologue ();
|
||||
#endif
|
||||
|
||||
|
@ -992,6 +992,11 @@ final_start_function (first, file, optimize)
|
|||
profile_function (file);
|
||||
#endif /* PROFILE_BEFORE_PROLOGUE */
|
||||
|
||||
#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_frame_debug (NULL_RTX);
|
||||
#endif
|
||||
|
||||
#ifdef FUNCTION_PROLOGUE
|
||||
/* First output the function prologue: code to set up the stack frame. */
|
||||
FUNCTION_PROLOGUE (file, get_frame_size ());
|
||||
|
@ -1142,8 +1147,8 @@ final_end_function (first, file, optimize)
|
|||
dwarfout_end_epilogue ();
|
||||
#endif
|
||||
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
#if defined (DWARF2_UNWIND_INFO)
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_end_epilogue ();
|
||||
#endif
|
||||
|
||||
|
@ -1265,11 +1270,6 @@ final (first, file, optimize, prescan)
|
|||
last_ignored_compare = 0;
|
||||
new_block = 1;
|
||||
|
||||
#if defined (DWARF2_DEBUGGING_INFO) && defined (HAVE_prologue)
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
dwarf2out_frame_debug (NULL_RTX);
|
||||
#endif
|
||||
|
||||
check_exception_handler_labels ();
|
||||
|
||||
/* Make a map indicating which line numbers appear in this function.
|
||||
|
@ -2171,12 +2171,21 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
|||
|
||||
output_asm_insn (template, recog_operand);
|
||||
|
||||
#if defined (DWARF2_DEBUGGING_INFO) && defined (HAVE_prologue)
|
||||
#if defined (DWARF2_UNWIND_INFO)
|
||||
#if !defined (ACCUMULATE_OUTGOING_ARGS)
|
||||
/* If we push arguments, we need to check all insns for stack
|
||||
adjustments. */
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_frame_debug (insn);
|
||||
#else
|
||||
#if defined (HAVE_prologue)
|
||||
/* If this insn is part of the prologue, emit DWARF v2
|
||||
call frame info. */
|
||||
if (write_symbols == DWARF2_DEBUG && RTX_FRAME_RELATED_P (insn))
|
||||
if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
|
||||
dwarf2out_frame_debug (insn);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* It's not at all clear why we did this and doing so interferes
|
||||
|
|
607
gcc/frame.c
Normal file
607
gcc/frame.c
Normal file
|
@ -0,0 +1,607 @@
|
|||
/* Subroutines needed for unwinding stack frames for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
GNU CC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU CC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* As a special exception, if you link this library with other files,
|
||||
some of which are compiled with GCC, to produce an executable,
|
||||
this library does not by itself cause the resulting executable
|
||||
to be covered by the GNU General Public License.
|
||||
This exception does not however invalidate any other reasons why
|
||||
the executable file might be covered by the GNU General Public License. */
|
||||
|
||||
/* It is incorrect to include config.h here, because this file is being
|
||||
compiled for the target, and hence definitions concerning only the host
|
||||
do not apply. */
|
||||
|
||||
#include "tconfig.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
#include "dwarf2.h"
|
||||
#include "frame.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* Don't use `fancy_abort' here even if config.h says to use it. */
|
||||
#ifdef abort
|
||||
#undef abort
|
||||
#endif
|
||||
|
||||
/* Some types used by the DWARF 2 spec. */
|
||||
|
||||
typedef unsigned int uword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
|
||||
typedef int saddr __attribute__ ((mode (pointer)));
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
/* The first few fields of a CIE. The CIE_id field is 0xffffffff for a CIE,
|
||||
to distinguish it from a valid FDE. FDEs are aligned to an addressing
|
||||
unit boundary, but the fields within are unaligned. */
|
||||
|
||||
struct dwarf_cie {
|
||||
uword length;
|
||||
uaddr CIE_id;
|
||||
ubyte version;
|
||||
char augmentation[0];
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
/* The first few fields of an FDE. */
|
||||
|
||||
struct dwarf_fde {
|
||||
uword length;
|
||||
struct dwarf_cie* CIE_pointer;
|
||||
void* pc_begin;
|
||||
uaddr pc_range;
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
typedef struct dwarf_fde fde;
|
||||
|
||||
/* The representation for an "object" to be searched for frame unwind info.
|
||||
For targets with named sections, one object is an executable or shared
|
||||
library; for other targets, one object is one translation unit. */
|
||||
|
||||
struct object {
|
||||
void *pc_begin;
|
||||
void *pc_end;
|
||||
fde *fde_begin;
|
||||
fde ** fde_array;
|
||||
size_t count;
|
||||
struct object *next;
|
||||
};
|
||||
|
||||
static struct object *objects;
|
||||
|
||||
/* The information we care about from a CIE. */
|
||||
|
||||
struct cie_info {
|
||||
char *augmentation;
|
||||
int code_align;
|
||||
int data_align;
|
||||
unsigned ra_regno;
|
||||
};
|
||||
|
||||
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
|
||||
|
||||
struct frame_state_internal
|
||||
{
|
||||
struct frame_state s;
|
||||
struct frame_state_internal *saved_state;
|
||||
};
|
||||
|
||||
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_uleb128 (unsigned char *buf, unsigned *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned 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 void *
|
||||
decode_sleb128 (unsigned char *buf, int *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
unsigned 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. */
|
||||
|
||||
union unaligned {
|
||||
void *p;
|
||||
unsigned b2 __attribute__ ((mode (HI)));
|
||||
unsigned b4 __attribute__ ((mode (SI)));
|
||||
unsigned b8 __attribute__ ((mode (DI)));
|
||||
} __attribute__ ((packed));
|
||||
static inline void *
|
||||
read_pointer (void *p)
|
||||
{ union unaligned *up = p; return up->p; }
|
||||
static inline unsigned
|
||||
read_1byte (void *p)
|
||||
{ return *(unsigned char *)p; }
|
||||
static inline unsigned
|
||||
read_2byte (void *p)
|
||||
{ union unaligned *up = p; return up->b2; }
|
||||
static inline unsigned
|
||||
read_4byte (void *p)
|
||||
{ union unaligned *up = p; return up->b4; }
|
||||
static inline unsigned long
|
||||
read_8byte (void *p)
|
||||
{ union unaligned *up = p; return up->b8; }
|
||||
|
||||
/* Ordering function for FDEs. Functions can't overlap, so we just compare
|
||||
their starting addresses. */
|
||||
|
||||
static inline saddr
|
||||
fde_compare (fde *x, fde *y)
|
||||
{
|
||||
return (saddr)x->pc_begin - (saddr)y->pc_begin;
|
||||
}
|
||||
|
||||
/* Return the address of the FDE after P. */
|
||||
|
||||
static inline fde *
|
||||
next_fde (fde *p)
|
||||
{
|
||||
return (fde *)(((char *)p) + p->length + sizeof (p->length));
|
||||
}
|
||||
|
||||
/* One iteration of an insertion sort, for adding new FDEs to the array.
|
||||
Usually the new FDE will go in at the end, so we can expect close to
|
||||
O(n) performance. If this turns out to be overly optimistic, we can have
|
||||
the linker sort the FDEs so we don't have to do it at run time. */
|
||||
|
||||
static void
|
||||
fde_insert (fde **array, size_t i, fde *this_fde)
|
||||
{
|
||||
array[i] = this_fde;
|
||||
|
||||
for (; i > 0 && fde_compare (array[i], array[i-1]) < 0; --i)
|
||||
{
|
||||
this_fde = array[i];
|
||||
array[i] = array[i-1];
|
||||
array[i-1] = this_fde;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_fdes (fde *this_fde)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs. */
|
||||
if ((uaddr)(this_fde->CIE_pointer) == (uaddr)-1)
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
add_fdes (fde *this_fde, fde **array, size_t *i_ptr,
|
||||
void **beg_ptr, void **end_ptr)
|
||||
{
|
||||
size_t i = *i_ptr;
|
||||
void *pc_begin = *beg_ptr;
|
||||
void *pc_end = *end_ptr;
|
||||
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs. */
|
||||
if ((uaddr)(this_fde->CIE_pointer) == (uaddr)-1)
|
||||
continue;
|
||||
|
||||
fde_insert (array, i++, this_fde);
|
||||
|
||||
if (this_fde->pc_begin < pc_begin)
|
||||
pc_begin = this_fde->pc_begin;
|
||||
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
|
||||
pc_end = this_fde->pc_begin + this_fde->pc_range;
|
||||
}
|
||||
|
||||
*i_ptr = i;
|
||||
*beg_ptr = pc_begin;
|
||||
*end_ptr = pc_end;
|
||||
}
|
||||
|
||||
/* Set up a sorted array of pointers to FDEs for a loaded object. We
|
||||
count up the entries before allocating the array because it's likely to
|
||||
be faster. */
|
||||
|
||||
static void
|
||||
frame_init (struct object* ob)
|
||||
{
|
||||
fde *this_fde;
|
||||
size_t count;
|
||||
fde **array;
|
||||
void *pc_begin, *pc_end;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (count = 0; *p; ++p)
|
||||
count += count_fdes (*p);
|
||||
}
|
||||
else
|
||||
count = count_fdes (ob->fde_begin);
|
||||
|
||||
ob->count = count;
|
||||
array = (fde **) malloc (sizeof (fde *) * count);
|
||||
|
||||
pc_begin = (void*)(uaddr)-1;
|
||||
pc_end = 0;
|
||||
count = 0;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (; *p; ++p)
|
||||
add_fdes (*p, array, &count, &pc_begin, &pc_end);
|
||||
}
|
||||
else
|
||||
add_fdes (ob->fde_begin, array, &count, &pc_begin, &pc_end);
|
||||
|
||||
ob->fde_array = array;
|
||||
ob->pc_begin = pc_begin;
|
||||
ob->pc_end = pc_end;
|
||||
}
|
||||
|
||||
/* Return a pointer to the FDE for the function containing PC. */
|
||||
|
||||
static fde *
|
||||
find_fde (void *pc)
|
||||
{
|
||||
struct object *ob;
|
||||
size_t lo, hi;
|
||||
|
||||
for (ob = objects; ob; ob = ob->next)
|
||||
{
|
||||
if (ob->pc_begin == 0)
|
||||
frame_init (ob);
|
||||
if (pc >= ob->pc_begin && pc < ob->pc_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ob == 0)
|
||||
return 0;
|
||||
|
||||
/* 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)
|
||||
hi = i;
|
||||
else if (pc > f->pc_begin + f->pc_range)
|
||||
lo = i + 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Extract any interesting information from the CIE for the translation
|
||||
unit F belongs to. */
|
||||
|
||||
static void *
|
||||
extract_cie_info (fde *f, struct cie_info *c)
|
||||
{
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
c->augmentation = f->CIE_pointer->augmentation;
|
||||
|
||||
if (strcmp (c->augmentation, "") != 0
|
||||
&& strcmp (c->augmentation, "e") != 0
|
||||
&& c->augmentation[0] != 'z')
|
||||
return 0;
|
||||
|
||||
p = c->augmentation + strlen (c->augmentation) + 1;
|
||||
|
||||
p = decode_uleb128 (p, &c->code_align);
|
||||
p = decode_sleb128 (p, &c->data_align);
|
||||
c->ra_regno = *(unsigned char *)p++;
|
||||
|
||||
/* If the augmentation starts with 'z', we now see the length of the
|
||||
augmentation fields. */
|
||||
if (c->augmentation[0] == 'z')
|
||||
{
|
||||
p = decode_uleb128 (p, &i);
|
||||
p += i;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Decode one instruction's worth of of DWARF 2 call frame information.
|
||||
Used by __frame_state_for. Takes pointers P to the instruction to
|
||||
decode, STATE to the current register unwind information, INFO to the
|
||||
current CIE information, and PC to the current PC value. Returns a
|
||||
pointer to the next instruction. */
|
||||
|
||||
static void *
|
||||
execute_cfa_insn (void *p, struct frame_state_internal *state,
|
||||
struct cie_info *info, void **pc)
|
||||
{
|
||||
unsigned insn = *(unsigned char *)p++;
|
||||
unsigned reg;
|
||||
int offset;
|
||||
|
||||
if (insn & DW_CFA_advance_loc)
|
||||
*pc += ((insn & 0x3f) * info->code_align);
|
||||
else if (insn & DW_CFA_offset)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
else if (insn & DW_CFA_restore)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
}
|
||||
else switch (insn)
|
||||
{
|
||||
case DW_CFA_set_loc:
|
||||
*pc = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
*pc += read_1byte (p);
|
||||
p += 1;
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
*pc += read_2byte (p);
|
||||
p += 2;
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
*pc += read_4byte (p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
break;
|
||||
|
||||
case DW_CFA_undefined:
|
||||
case DW_CFA_same_value:
|
||||
case DW_CFA_nop:
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
{
|
||||
unsigned reg2;
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, ®2);
|
||||
state->s.saved[reg] = REG_SAVED_REG;
|
||||
state->s.reg_or_offset[reg] = reg2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_reg = reg;
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.cfa_reg = reg;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_remember_state:
|
||||
{
|
||||
struct frame_state_internal *save =
|
||||
(struct frame_state_internal *)
|
||||
malloc (sizeof (struct frame_state_internal));
|
||||
memcpy (save, state, sizeof (struct frame_state_internal));
|
||||
state->saved_state = save;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
{
|
||||
struct frame_state_internal *save = state->saved_state;
|
||||
memcpy (state, save, sizeof (struct frame_state_internal));
|
||||
free (save);
|
||||
}
|
||||
break;
|
||||
|
||||
/* FIXME: Hardcoded for SPARC register window configuration. */
|
||||
case DW_CFA_GNU_window_save:
|
||||
for (reg = 16; reg < 32; ++reg)
|
||||
{
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_args_size:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.args_size = offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
void
|
||||
__register_frame (void *begin)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
|
||||
ob->fde_begin = begin;
|
||||
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->fde_array = 0;
|
||||
ob->count = 0;
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
}
|
||||
|
||||
/* Similar, but BEGIN is actually a pointer to a table of unwind entries
|
||||
for different translation units. Called from the file generated by
|
||||
collect2. */
|
||||
|
||||
void
|
||||
__register_frame_table (void *begin)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
|
||||
ob->fde_begin = begin;
|
||||
ob->fde_array = begin;
|
||||
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->count = 0;
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
}
|
||||
|
||||
/* Called from crtend.o to deregister the unwind info for an object. */
|
||||
|
||||
void
|
||||
__deregister_frame (void *begin)
|
||||
{
|
||||
struct object **p = &objects;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if ((*p)->fde_begin == begin)
|
||||
{
|
||||
struct object *ob = *p;
|
||||
*p = (*p)->next;
|
||||
|
||||
if (ob->fde_array)
|
||||
free (ob->fde_array);
|
||||
free (ob);
|
||||
|
||||
return;
|
||||
}
|
||||
p = &((*p)->next);
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Called from __throw to find the registers to restore for a given
|
||||
PC_TARGET. The caller should allocate a local variable of `struct
|
||||
frame_state' (declared in frame.h) and pass its address to STATE_IN. */
|
||||
|
||||
struct frame_state *
|
||||
__frame_state_for (void *pc_target, struct frame_state *state_in)
|
||||
{
|
||||
fde *f;
|
||||
void *insn, *end, *pc;
|
||||
struct cie_info info;
|
||||
struct frame_state_internal state;
|
||||
|
||||
f = find_fde (pc_target);
|
||||
if (f == 0)
|
||||
return 0;
|
||||
|
||||
insn = extract_cie_info (f, &info);
|
||||
if (insn == 0)
|
||||
return 0;
|
||||
|
||||
memset (&state, 0, sizeof (state));
|
||||
state.s.retaddr_column = info.ra_regno;
|
||||
|
||||
/* First decode all the insns in the CIE. */
|
||||
end = next_fde ((fde*) f->CIE_pointer);
|
||||
while (insn < end)
|
||||
insn = execute_cfa_insn (insn, &state, &info, 0);
|
||||
|
||||
insn = ((fde *)f) + 1;
|
||||
|
||||
if (info.augmentation[0] == 'z')
|
||||
{
|
||||
int i;
|
||||
insn = decode_uleb128 (insn, &i);
|
||||
insn += i;
|
||||
}
|
||||
else if (strcmp (info.augmentation, "e") == 0)
|
||||
{
|
||||
state.s.eh_ptr = read_pointer (insn);
|
||||
insn += sizeof (void *);
|
||||
}
|
||||
|
||||
/* Then the insns in the FDE up to our target PC. */
|
||||
end = next_fde (f);
|
||||
pc = f->pc_begin;
|
||||
while (insn < end && pc < pc_target)
|
||||
insn = execute_cfa_insn (insn, &state, &info, &pc);
|
||||
|
||||
memcpy (state_in, &state.s, sizeof (state.s));
|
||||
return state_in;
|
||||
}
|
||||
#endif /* DWARF2_UNWIND_INFO */
|
37
gcc/tm.texi
37
gcc/tm.texi
|
@ -5987,6 +5987,26 @@ A C expression to output text to mark the end of an exception region.
|
|||
|
||||
This macro need not be defined on most platforms.
|
||||
|
||||
@findex EXCEPTION_SECTION
|
||||
@item EXCEPTION_SECTION ()
|
||||
A C expression to switch to the section in which the main
|
||||
exception table is to be placed (@pxref{Sections}). The default is a
|
||||
section named @code{.gcc_except_table} on machines that support named
|
||||
sections via @code{ASM_OUTPUT_SECTION_NAME}, otherwise if @samp{-fpic}
|
||||
or @samp{-fPIC} is in effect, the @code{data_section}, otherwise the
|
||||
@code{readonly_data_section}.
|
||||
|
||||
@findex EH_FRAME_SECTION_ASM_OP
|
||||
@item EH_FRAME_SECTION_ASM_OP
|
||||
If defined, a C string constant for the assembler operation to switch to
|
||||
the section for exception handling frame unwind information. If not
|
||||
defined, GNU CC will provide a default definition if the target supports
|
||||
named sections. @file{crtstuff.c} uses this macro to switch to the
|
||||
appropriate section.
|
||||
|
||||
You should define this symbol if your target supports DWARF 2 frame
|
||||
unwind information and the default definition does not work.
|
||||
|
||||
@findex OMIT_EH_TABLE
|
||||
@item OMIT_EH_TABLE ()
|
||||
A C expression that is nonzero if the normal exception table output
|
||||
|
@ -6011,6 +6031,23 @@ for details on when to define this, and how.
|
|||
@item MASK_RETURN_ADDR
|
||||
An rtx used to mask the return address found via RETURN_ADDR_RTX, so
|
||||
that it does not contain any extraneous set bits in it.
|
||||
|
||||
@findex DWARF2_UNWIND_INFO
|
||||
@item DWARF2_UNWIND_INFO
|
||||
Define this macro to 0 if your target supports DWARF 2 frame unwind
|
||||
information, but it does not yet work with exception handling.
|
||||
Otherwise, if your target supports this information (if it defines
|
||||
@samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
|
||||
or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of
|
||||
1.
|
||||
|
||||
If this macro is defined to 1, the DWARF 2 unwinder will be the default
|
||||
exception handling mechanism; otherwise, setjmp/longjmp will be used by
|
||||
default.
|
||||
|
||||
If this macro is defined to anything, the DWARF 2 unwinder will be used
|
||||
instead of inline unwinders and __unwind_function in the non-setjmp case.
|
||||
|
||||
@end table
|
||||
|
||||
@node Alignment Output
|
||||
|
|
12
gcc/toplev.c
12
gcc/toplev.c
|
@ -2463,6 +2463,10 @@ compile_file (name)
|
|||
if (write_symbols == DWARF_DEBUG)
|
||||
TIMEVAR (symout_time, dwarfout_init (asm_out_file, main_input_filename));
|
||||
#endif
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_frame_init ();
|
||||
#endif
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
TIMEVAR (symout_time, dwarf2out_init (asm_out_file, main_input_filename));
|
||||
|
@ -2597,8 +2601,7 @@ compile_file (name)
|
|||
/* Now that all possible functions have been output, we can dump
|
||||
the exception table. */
|
||||
|
||||
if (exception_table_p ())
|
||||
output_exception_table ();
|
||||
output_exception_table ();
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
|
@ -2713,6 +2716,11 @@ compile_file (name)
|
|||
});
|
||||
#endif
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_frame_finish ();
|
||||
#endif
|
||||
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
TIMEVAR (symout_time,
|
||||
|
|
10
gcc/tree.h
10
gcc/tree.h
|
@ -101,6 +101,16 @@ enum built_in_function
|
|||
BUILT_IN_SETJMP,
|
||||
BUILT_IN_LONGJMP,
|
||||
|
||||
/* Various hooks for the DWARF 2 __throw routine. */
|
||||
BUILT_IN_FP, BUILT_IN_SP,
|
||||
BUILT_IN_UNWIND_INIT,
|
||||
BUILT_IN_DWARF_FP_REGNUM,
|
||||
BUILT_IN_FROB_RETURN_ADDR,
|
||||
BUILT_IN_EXTRACT_RETURN_ADDR,
|
||||
BUILT_IN_SET_RETURN_ADDR_REG,
|
||||
BUILT_IN_EH_STUB,
|
||||
BUILT_IN_SET_EH_REGS,
|
||||
|
||||
/* C++ extensions */
|
||||
BUILT_IN_NEW,
|
||||
BUILT_IN_VEC_NEW,
|
||||
|
|
21
gcc/varasm.c
21
gcc/varasm.c
|
@ -170,6 +170,9 @@ static enum in_section { no_section, in_text, in_data, in_named
|
|||
#ifdef BSS_SECTION_ASM_OP
|
||||
, in_bss
|
||||
#endif
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
, in_eh_frame
|
||||
#endif
|
||||
#ifdef EXTRA_SECTIONS
|
||||
, EXTRA_SECTIONS
|
||||
#endif
|
||||
|
@ -401,6 +404,18 @@ asm_output_aligned_bss (file, decl, name, size, align)
|
|||
|
||||
#endif /* BSS_SECTION_ASM_OP */
|
||||
|
||||
#ifdef EH_FRAME_SECTION_ASM_OP
|
||||
void
|
||||
eh_frame_section ()
|
||||
{
|
||||
if (in_section != in_eh_frame)
|
||||
{
|
||||
fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
|
||||
in_section = in_eh_frame;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Switch to the section for function DECL.
|
||||
|
||||
If DECL is NULL_TREE, switch to the text section.
|
||||
|
@ -461,15 +476,15 @@ variable_section (decl, reloc)
|
|||
void
|
||||
exception_section ()
|
||||
{
|
||||
#if defined (EXCEPTION_SECTION)
|
||||
EXCEPTION_SECTION ();
|
||||
#else
|
||||
#ifdef ASM_OUTPUT_SECTION_NAME
|
||||
named_section (NULL_TREE, ".gcc_except_table", 0);
|
||||
#else
|
||||
if (flag_pic)
|
||||
data_section ();
|
||||
else
|
||||
#if defined (EXCEPTION_SECTION)
|
||||
EXCEPTION_SECTION ();
|
||||
#else
|
||||
readonly_data_section ();
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue