From: Jason Merrill Date: Wed, 10 Sep 1997 18:00:28 +0000 (-0400) Subject: dwarf2 EH support X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0021b564f4ce0b648a8d6ec49b29afe609370788;p=gcc.git dwarf2 EH support From-SVN: r15255 --- diff --git a/gcc/c-decl.c b/gcc/c-decl.c index b556d0825f1..94dc196a6a1 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 7c17824cc01..576bc74669f 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 d8d9757e759..fafdabc91b4 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 3521fdd3b3b..86746d11e84 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 7ebb5083648..ffbea137862 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 58ed718cad7..fba9d0a1ce8 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 4235c935802..f040aa7608e 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 1b58a17d282..070f41aa3b5 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 38ddd4815ca..cdb7cd6a2bb 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 2de7fcede6e..0f313f5e7ec 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 79d8e197da1..355485af399 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 5fe34b0a6df..587f0a293ac 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 2c682436069..bcb5cc50bf0 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 651133898d0..434d761afed 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 2390e573297..4340344c868 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 fac51352750..6789f01af84 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 -#include #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_"; @@ -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 14bb2349fb0..71c49c25a77 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 a7fe94d38cb..48e1a0878f7 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 00000000000..a9e5e231e7d --- /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 . + +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 + +/* 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 */ diff --git a/gcc/tm.texi b/gcc/tm.texi index d5e4c9fffa4..0b95dbf1850 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 d1ddf202fee..2658e5b5ee9 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 5e5087fa14e..d594bd92ccd 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 9d245830f44..351524dec55 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