aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@gcc.gnu.org>1997-09-10 14:00:28 -0400
committerJason Merrill <jason@gcc.gnu.org>1997-09-10 14:00:28 -0400
commit0021b564f4ce0b648a8d6ec49b29afe609370788 (patch)
tree0928096722cf7e87c6973bd7bb029f787ab959db
parent0680d170431a1a44f958ca97a9ce01ea12b676b6 (diff)
downloadgcc-0021b564f4ce0b648a8d6ec49b29afe609370788.zip
gcc-0021b564f4ce0b648a8d6ec49b29afe609370788.tar.gz
gcc-0021b564f4ce0b648a8d6ec49b29afe609370788.tar.bz2
dwarf2 EH support
From-SVN: r15255
-rw-r--r--gcc/c-decl.c37
-rw-r--r--gcc/collect2.c79
-rw-r--r--gcc/config/i386/i386.c35
-rw-r--r--gcc/config/mips/iris6.h6
-rw-r--r--gcc/config/mips/mips.c3
-rw-r--r--gcc/config/mips/mips.h9
-rw-r--r--gcc/config/sparc/sparc.c52
-rw-r--r--gcc/config/sparc/sunos4.h3
-rw-r--r--gcc/config/sparc/sysv4.h3
-rw-r--r--gcc/cp/decl2.c4
-rw-r--r--gcc/cp/except.c7
-rw-r--r--gcc/cp/gxxint.texi62
-rw-r--r--gcc/crtstuff.c66
-rw-r--r--gcc/defaults.h4
-rw-r--r--gcc/dwarf2.h3
-rw-r--r--gcc/dwarf2out.c271
-rw-r--r--gcc/except.h12
-rw-r--r--gcc/final.c31
-rw-r--r--gcc/frame.c607
-rw-r--r--gcc/tm.texi37
-rw-r--r--gcc/toplev.c12
-rw-r--r--gcc/tree.h10
-rw-r--r--gcc/varasm.c21
23 files changed, 1210 insertions, 164 deletions
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index b556d08..94dc196 100644
--- a/gcc/c-decl.c
+++ b/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,
diff --git a/gcc/collect2.c b/gcc/collect2.c
index 7c17824..576bc74 100644
--- a/gcc/collect2.c
+++ b/gcc/collect2.c
@@ -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;
}
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d8d9757..fafdabc 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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)
diff --git a/gcc/config/mips/iris6.h b/gcc/config/mips/iris6.h
index 3521fdd..86746d1 100644
--- a/gcc/config/mips/iris6.h
+++ b/gcc/config/mips/iris6.h
@@ -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}"
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 7ebb508..ffbea13 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -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);
}
}
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 58ed718..fba9d0a 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -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)
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 4235c93..f040aa7 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -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
}
}
diff --git a/gcc/config/sparc/sunos4.h b/gcc/config/sparc/sunos4.h
index 1b58a17..070f41a 100644
--- a/gcc/config/sparc/sunos4.h
+++ b/gcc/config/sparc/sunos4.h
@@ -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
diff --git a/gcc/config/sparc/sysv4.h b/gcc/config/sparc/sysv4.h
index 38ddd48..cdb7cd6 100644
--- a/gcc/config/sparc/sysv4.h
+++ b/gcc/config/sparc/sysv4.h
@@ -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
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 2de7fce..0f313f5 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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)
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 79d8e19..355485a 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -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)
diff --git a/gcc/cp/gxxint.texi b/gcc/cp/gxxint.texi
index 5fe34b0a..587f0a2 100644
--- a/gcc/cp/gxxint.texi
+++ b/gcc/cp/gxxint.texi
@@ -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
diff --git a/gcc/crtstuff.c b/gcc/crtstuff.c
index 2c68243..bcb5cc5 100644
--- a/gcc/crtstuff.c
+++ b/gcc/crtstuff.c
@@ -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) */
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 6511338..434d761 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -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
diff --git a/gcc/dwarf2.h b/gcc/dwarf2.h
index 2390e57..4340344 100644
--- a/gcc/dwarf2.h
+++ b/gcc/dwarf2.h
@@ -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
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index fac5135..6789f01 100644
--- a/gcc/dwarf2out.c
+++ b/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)
{
diff --git a/gcc/except.h b/gcc/except.h
index 14bb234..71c49c2 100644
--- a/gcc/except.h
+++ b/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
diff --git a/gcc/final.c b/gcc/final.c
index a7fe94d..48e1a08 100644
--- a/gcc/final.c
+++ b/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
diff --git a/gcc/frame.c b/gcc/frame.c
new file mode 100644
index 0000000..a9e5e23
--- /dev/null
+++ b/gcc/frame.c
@@ -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, &reg);
+ 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, &reg);
+ 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, &reg);
+ p = decode_uleb128 (p, &reg2);
+ state->s.saved[reg] = REG_SAVED_REG;
+ state->s.reg_or_offset[reg] = reg2;
+ }
+ break;
+
+ case DW_CFA_def_cfa:
+ p = decode_uleb128 (p, &reg);
+ 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, &reg);
+ 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 */
diff --git a/gcc/tm.texi b/gcc/tm.texi
index d5e4c9f..0b95dbf 100644
--- a/gcc/tm.texi
+++ b/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
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d1ddf20..2658e5b 100644
--- a/gcc/toplev.c
+++ b/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,
diff --git a/gcc/tree.h b/gcc/tree.h
index 5e5087f..d594bd9 100644
--- a/gcc/tree.h
+++ b/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,
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 9d24583..351524d 100644
--- a/gcc/varasm.c
+++ b/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