Message ID | 89584BF2-10CD-45DE-A4A5-4C2EE43396B3@sandoe-acoustics.co.uk |
---|---|
State | New |
Headers | show |
On 08/13/2010 12:50 PM, IainS wrote: > + DW_CFA_GNU_start_epilogue = 0x30 I'd rather not place this in dwarf2.h since we don't plan to emit this as an actual opcode. It only needs to be a marker in the dw_cfi_ref linked list for internal use of gcc. As such I think something like # define DW_CFA_INTERNAL_start_epilogue 0x100 would be appropriate. I believe you'll need to change typedef struct GTY(()) dw_cfi_struct { dw_cfi_ref dw_cfi_next; - enum dwarf_call_frame_info dw_cfi_opc; + unsigned int dw_cfi_opc; in order for this to be legal. Unfortunately that may require a host of other type changes or type casts in order to pass the C++ warning mode. > +/* True if start_epilogue should be emitted before following CFI directive. */ > +static bool emit_cfa_start_epilogue; I don't think this is needed... > if (i == NULL) > - return; > + { > + /* But we do mark the start of the epilogue to allow it to be skipped > + in _eh frames. */ > + emit_cfa_start_epilogue = true; > + return; > + } ... instead we want to add the cfi entry here, by hand. The reason being that we want to avoid the DW_CFA_advance_loc4 that would be added by actually inserting this opcode via add_fde_cfi. > +/* Targets might not need epilogue information in dwarf2 _eh frames. This > + hook should return true if the epilogue should be suppressed in such frames. > + Epilogues will still be emitted in _debug_frames. */ > +DEFHOOK_UNDOC > +(suppress_eh_epilogue_p, > + "", > + bool, (void), > + hook_bool_void_false) As discussed on IRC, I don't think we need a target hook for this. We should key this off of !flag_asynchronous_unwind_tables. That will allow all targets that only need unwind info for call sites omit this extra epilogue unwind info. At that point you can adjust Darwin's override_options hook(s) to make sure that this flag is appropriately off. It also seems like it would be a good idea to add a SPEC entry to disable compact unwind if the user explicitly uses -fasynchronous-unwind-info. > +/* Mark the start of each dwarf debug section to allow us to compute local > + offsets within the sections. We do this in darwin, rather than emitting > + relocs. */ > +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \ > + darwin_asm_output_dwarf_section_start_label Is this an unrelated change? I can't see how it relates to the rest. r~
On Fri, Aug 13, 2010 at 08:50:29PM +0100, IainS wrote: > As discussed off list and in IRC with Richard, > > =----= > > Some (if not most) targets do not require the function epilogue in their > _eh unwind frames. > In fact, it breaks the darwin unwinder (PR41991) my original motivation > for looking at this. > > However, as we went through the discussion it became apparent that this > might have wider application than fixing a darwin bug, in saving some > space in the eh. > > What this does is to use the existing DW_CFA_save/restore_state and a > new DW_CFA_GNU_start_epilogue marker to suppress the emitting of > function epilogues - when (a) we're emitting _eh and (b) the target > requests suppression via a hook. > The hook is a bool function to permit targets to choose whether to emit > this data or not at run time rather than config time (the default hook > does nothing). > > ---- > > The DW_CFA_GNU_start_epilogue marker is inserted under the circumstance > that an epilogue is detected at the end of a function. > The save/restore markers are not touched and deal with the case that we > are mid-function. > > There is a debug print of # DW_CFA_GNU_start_epilogue to show where we > are intercepting in the eh frames and not curtailing the debug_frames. > > I'd particularly welcome someone's eye over what's happening in the case > of section switches (it seems to me that the skipping of mid-function > save/restore is handled OK, but I'm not familiar with that code - and my > main target(s) don't use that facility). > > ==== > > This has only been lightly tested on i686/powerpc-darwin9 (regtested on > i686) - but it appears to restore Unwind functionality to the platform :) > [gcj works again, Yay!] > > ==== > > so we get this in the _eh frame: > > LECIE1: > .globl _main.eh > _main.eh: > LSFDE1: > .set L$set$1,LEFDE1-LASFDE1 > .long L$set$1 # FDE Length > LASFDE1: > .long LASFDE1-EH_frame1 # FDE CIE offset > .long LFB1-. # FDE initial location > .set L$set$2,LFE1-LFB1 > > <SNIP> > > .set L$set$5,LCFI4-LCFI1 > .long L$set$5 > .byte 0x83 # DW_CFA_offset, column 0x3 > .byte 0x3 # uleb128 0x3 > .byte 0x4 # DW_CFA_advance_loc4 > .set L$set$6,LCFI6-LCFI4 > .long L$set$6 > # # DW_CFA_GNU_start_epilogue > .align 2 > > and this in the _debug_frame: > .section __DWARF,__debug_frame,regular,debug > Lsection__debug_frame: > Lframe0: > .set L$set$7,LECIE0-LSCIE0 > .long L$set$7 # Length of Common Information Entry > LSCIE0: > > <SNIP> > > .byte 0x83 # DW_CFA_offset, column 0x3 > .byte 0x3 # uleb128 0x3 > .byte 0x4 # DW_CFA_advance_loc4 > .set L$set$14,LCFI6-LCFI4 > .long L$set$14 > # # DW_CFA_GNU_start_epilogue > .byte 0xc3 # DW_CFA_restore, column 0x3 > .byte 0x4 # DW_CFA_advance_loc4 > .set L$set$15,LCFI7-LCFI6 > .long L$set$15 > .byte 0xc # DW_CFA_def_cfa > .byte 0x4 # uleb128 0x4 > .byte 0x4 # uleb128 0x4 > .byte 0xc5 # DW_CFA_restore, column 0x5 > .align 2 > LEFDE2: > > ===== > thoughts? > Iain > Iain, So far the only failure I see with your patch under darwin10.4.0, using the compact unwinder (by eliminating the addition of -no_compact_unwind in darwin10.h), is... FAIL: g++.dg/eh/async-unwind2.C execution test at -m32. Interestingly, if I pass -Wl,-warn_compact_unwind when building that testcase, I get... [MacPro:~/async_unwind] howarth% /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../g++ -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../ /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/gcc/testsuite/g++.dg/eh/async-unwind2.C -nostdinc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include/x86_64-apple-darwin10.4.0 -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/libsupc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/include/backward -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/testsuite/util -fmessage-length=0 -Os -fasynchronous-unwind-tables -fpic -fno-inline -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libiberty -multiply_defined suppress -lm -m32 -g -Wl,-warn_compact_unwind -o ./async-unwind2.exe ld: warning: can't make compact unwind encoding from dwarf for S::sfn2(int) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size ld: warning: can't make compact unwind encoding from dwarf for S::sfn3(char const*) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size ld: warning: can't make compact unwind encoding from dwarf for baz1(S const&) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size These errors don't appear when I do the same to build the non-failing async-unwind1.exe testcase. Can we inhibit the emission of DW_CFA_GNU_args_size on darwin as well? Jack > > Change notes (not a proper changelog, at this juncture) > > include/dwarf2.h : DW_CFA_GNU_start_epilogue new enum. > > dwarf2out.c: dwarf_cfi_name() recognize DW_CFA_GNU_start_epilogue > static scope emit_cfa_start_epilogue new var. > add_fde_cfi() : emit a marker for the epilogue start; > dwarf2out_cfi_begin_epilogue (): note that we need to emit the epilogue > start marker when the epilogue is at the end. > dw_cfi_oprnd1_desc (): recognize DW_CFA_GNU_start_epilogue as a no-op. > output_cfi(): print debug message for DW_CFA_GNU_start_epilogue > emit_cfi_or_skip_epilogue (): New. > output_fde () : use emit_cfi_or_skip_epilogue (); > > target.def: suppress_eh_epilogue_p (): New ASM Hook. > > === the remainder are the implementation on the darwin side: > > gcc/config/darwin.h (TARGET_ASM_SUPPRESS_EH_EPILOGUE_P): New > gcc/config/darwin.c (darwin_asm_suppress_eh_epilogue_p): New. > gcc/config/darwin-protos.h: Declare darwin_asm_suppress_eh_epilogue_p. > > ========== - =========== > Index: include/dwarf2.h > =================================================================== > --- include/dwarf2.h (revision 163221) > +++ include/dwarf2.h (working copy) > @@ -854,7 +854,8 @@ enum dwarf_call_frame_info > /* GNU extensions. */ > DW_CFA_GNU_window_save = 0x2d, > DW_CFA_GNU_args_size = 0x2e, > - DW_CFA_GNU_negative_offset_extended = 0x2f > + DW_CFA_GNU_negative_offset_extended = 0x2f, > + DW_CFA_GNU_start_epilogue = 0x30 > }; > > #define DW_CIE_ID 0xffffffff > Index: gcc/dwarf2out.c > =================================================================== > --- gcc/dwarf2out.c (revision 163221) > +++ gcc/dwarf2out.c (working copy) > @@ -720,7 +724,9 @@ dwarf_cfi_name (unsigned int cfi_opc) > return "DW_CFA_GNU_args_size"; > case DW_CFA_GNU_negative_offset_extended: > return "DW_CFA_GNU_negative_offset_extended"; > - > + case DW_CFA_GNU_start_epilogue: > + return "DW_CFA_GNU_start_epilogue"; > + > default: > return "DW_CFA_<unknown>"; > } > @@ -801,6 +807,9 @@ dwarf2out_cfi_label (bool force) > /* True if remember_state should be emitted before following CFI directive. */ > static bool emit_cfa_remember; > > +/* True if start_epilogue should be emitted before following CFI directive. */ > +static bool emit_cfa_start_epilogue; > + > /* Add CFI to the current fde at the PC value indicated by LABEL if specified, > or to the CIE if LABEL is NULL. */ > > @@ -809,6 +818,17 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) > { > dw_cfi_ref *list_head; > > + if (emit_cfa_start_epilogue) > + { > + dw_cfi_ref cfi_epi_start; > + > + /* Emit the state save. */ > + emit_cfa_start_epilogue = false; > + cfi_epi_start = new_cfi (); > + cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue; > + add_fde_cfi (label, cfi_epi_start); > + } > + > if (emit_cfa_remember) > { > dw_cfi_ref cfi_remember; > @@ -2898,7 +2918,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn) > gcc_assert (i != NULL); > i = next_real_insn (i); > if (i == NULL) > - return; > + { > + /* But we do mark the start of the epilogue to allow it to be skipped > + in _eh frames. */ > + emit_cfa_start_epilogue = true; > + return; > + } > > /* Insert the restore before that next real insn in the stream, and before > a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be > @@ -2953,6 +2978,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi > case DW_CFA_GNU_window_save: > case DW_CFA_remember_state: > case DW_CFA_restore_state: > + case DW_CFA_GNU_start_epilogue: > return dw_cfi_oprnd_unused; > > case DW_CFA_set_loc: > @@ -3121,6 +3148,10 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo > dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)), > "DW_CFA_restore, column %#lx", r); > } > + else if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) > +/* DEBUG */ > + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START > + " DW_CFA_GNU_start_epilogue\n",asm_out_file); > else > { > dw2_asm_output_data (1, cfi->dw_cfi_opc, > @@ -3303,6 +3334,12 @@ output_cfi_directive (dw_cfi_ref cfi) > cfi->dw_cfi_oprnd1.dw_cfi_offset); > break; > > + case DW_CFA_GNU_start_epilogue: > +/*DEBUG */ > + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START > + " DW_CFA_GNU_start_epilogue\n",asm_out_file); > + break; > + > case DW_CFA_remember_state: > fprintf (asm_out_file, "\t.cfi_remember_state\n"); > break; > @@ -3498,6 +3535,41 @@ output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f > } > } > > +/* Output cfi skipping save/restore and epilogues in _eh frames > + for targets that do not want them. */ > + > +static dw_cfi_ref > +emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh) > +{ > + if (for_eh > + && targetm.asm_out.suppress_eh_epilogue_p()) > + { > + if (cfi->dw_cfi_opc == DW_CFA_remember_state) > + { > + /* Skip to the restore, unless there's an error and we fall off > + the end. */ > + while (cfi->dw_cfi_next > + && cfi->dw_cfi_opc != DW_CFA_restore_state) > + cfi = cfi->dw_cfi_next; > + return cfi; > + } > + if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) > + { > +/*DEBUG */ > + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START > + " DW_CFA_GNU_start_epilogue\n",asm_out_file); > + while (cfi->dw_cfi_next) > + /* Skip to the end. */ > + cfi = cfi->dw_cfi_next; > + return cfi; > + } > + } > + > + /* if it's not a special case, then just emit it. */ > + output_cfi (cfi, fde, for_eh); > + return cfi; > +} > + > /* Output one FDE. */ > > static void > @@ -3613,13 +3685,13 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco > fde->dw_fde_current_label = begin; > if (!fde->dw_fde_switched_sections) > for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) > - output_cfi (cfi, fde, for_eh); > + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); > else if (!second) > { > if (fde->dw_fde_switch_cfi) > for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) > { > - output_cfi (cfi, fde, for_eh); > + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); > if (cfi == fde->dw_fde_switch_cfi) > break; > } > @@ -3636,7 +3707,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco > fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next; > } > for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next) > - output_cfi (cfi, fde, for_eh); > + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); > } > > /* If we are to emit a ref/link from function bodies to their frame tables, > Index: gcc/target.def > =================================================================== > --- gcc/target.def (revision 163221) > +++ gcc/target.def (working copy) > @@ -390,6 +406,15 @@ DEFHOOK > void, (FILE *file, int size, rtx x), > NULL) > > +/* Targets might not need epilogue information in dwarf2 _eh frames. This > + hook should return true if the epilogue should be suppressed in such frames. > + Epilogues will still be emitted in _debug_frames. */ > +DEFHOOK_UNDOC > +(suppress_eh_epilogue_p, > + "", > + bool, (void), > + hook_bool_void_false) > + > /* Some target machines need to postscan each insn after it is output. */ > DEFHOOK > (final_postscan_insn, > Index: gcc/config/darwin-protos.h > =================================================================== > --- gcc/config/darwin-protos.h (revision 163221) > +++ gcc/config/darwin-protos.h (working copy) > @@ -83,10 +84,15 @@ extern tree darwin_handle_weak_import_attribute (t > extern void machopic_output_stub (FILE *, const char *, const char *); > extern void darwin_globalize_label (FILE *, const char *); > extern void darwin_assemble_visibility (tree, int); > + > +extern bool darwin_asm_suppress_eh_epilogue_p (void); > +extern void darwin_asm_output_dwarf_section_start_label (FILE *file, > + section *sect); > extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *, > const char *); > extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *, > section *); > + > extern void darwin_asm_declare_constant_name (FILE *, const char *, > const_tree, HOST_WIDE_INT); > extern bool darwin_binds_local_p (const_tree); > Index: gcc/config/darwin.h > =================================================================== > --- gcc/config/darwin.h (revision 163221) > +++ gcc/config/darwin.h (working copy) > @@ -669,7 +675,6 @@ extern GTY(()) int darwin_ms_struct; > Make Objective-C internal symbols local and in doing this, we need > to accommodate the name mangling done by c++ on file scope locals. */ > > - > int darwin_label_is_anonymous_local_objc_name (const char *name); > > #undef ASM_OUTPUT_LABELREF > @@ -927,6 +932,16 @@ enum machopic_addr_class { > ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \ > ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr) > > +/* Mark the start of each dwarf debug section to allow us to compute local > + offsets within the sections. We do this in darwin, rather than emitting > + relocs. */ > +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \ > + darwin_asm_output_dwarf_section_start_label > + > +/* For OSX compatibility we do not want to emit epilogues in _eh frames. */ > +#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \ > + darwin_asm_suppress_eh_epilogue_p > + > #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2) \ > darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2) > > Index: gcc/config/darwin.c > =================================================================== > --- gcc/config/darwin.c (revision 163221) > +++ gcc/config/darwin.c (working copy) > @@ -1666,6 +1666,36 @@ darwin_assemble_visibility (tree decl, int vis) > "not supported in this configuration; ignored"); > } > > +/* For compatibility with OSX versions that do not emit epilogues in _eh > + frames we suppress them. This is made a predicate function to permit > + us to add an OSX/FSF compatibility switch should that be required. */ > + > +bool > +darwin_asm_suppress_eh_epilogue_p (void) > +{ > + return true; > +} > + > +/* So that we can compute dwarf offsets within sections, we emit a known > + section marker at the begining of the section. This is distinct from > + the ones emitted by dwarf2out. The label is constructed by extracting > + sectname from __DWARF,__sectname,etc,etc. The hook should be invoked > + once, after the first switch to the section. */ > + > +void > +darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect) > +{ > + const char *dnam; > + int namelen; > + gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG))); > + dnam = ((struct named_section *)sect)->name; > + gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0); > + gcc_assert (strchr (dnam + 8, ',')); > + > + namelen = strchr (dnam + 8, ',') - (dnam + 8); > + fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8); > +} > + > /* Output a difference of two labels that will be an assembly time > constant if the two labels are local. (.long lab1-lab2 will be > very different if lab1 is at the boundary between two sections; it > > > > >
Thanks to Richard and Jakub for comments (on list and in irc) I've nearly finished re-working the patch (in testing now). On 14 Aug 2010, at 03:19, Jack Howarth wrote: > FAIL: g++.dg/eh/async-unwind2.C execution test if we say that darwin does not support -fasynchronous-unwind-tables, then we should simply skip this test. > ld: warning: can't make compact unwind encoding from dwarf for > S::sfn2(int) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-// > ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size This is interesting - is this a dwarf-2 opcode? It is enabled by -fasynchronous-unwind-tables (without any fall-back for non-gnu targets) Does this imply that -fasynchronous-unwind-tables is only usable by a gnu target? also I note that: -fnon-call-exceptions _unconditionally_ sets -fasynchronous-unwind- tables in toplev.c (and, of course, libjava does set -fnon-call-exceptions, so that builds with a bunch of warnings now - since I've added warnings for the two cases). So ... where do we stand? maybe toplev should do sth like; if ( flag_non_call_exceptions && flag_asynchronous_unwind_tables == 2) flag_asynchronous_unwind_tables = 1; Richard?, Jakub? any advice appreciated. thanks Iain
On Aug 14, 2010, at 6:49 AM, IainS wrote:
> if we say that darwin does not support -fasynchronous-unwind-tables, then we should simply skip this test.
darwin would like it... I don't know of anyone that is twisting in the wind on it however, so it could be xfailed for now, if one wants a cleaner run.
Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 163221) +++ include/dwarf2.h (working copy) @@ -854,7 +854,8 @@ enum dwarf_call_frame_info /* GNU extensions. */ DW_CFA_GNU_window_save = 0x2d, DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_GNU_start_epilogue = 0x30 }; #define DW_CIE_ID 0xffffffff Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 163221) +++ gcc/dwarf2out.c (working copy) @@ -720,7 +724,9 @@ dwarf_cfi_name (unsigned int cfi_opc) return "DW_CFA_GNU_args_size"; case DW_CFA_GNU_negative_offset_extended: return "DW_CFA_GNU_negative_offset_extended"; - + case DW_CFA_GNU_start_epilogue: + return "DW_CFA_GNU_start_epilogue"; + default: return "DW_CFA_<unknown>"; } @@ -801,6 +807,9 @@ dwarf2out_cfi_label (bool force) /* True if remember_state should be emitted before following CFI directive. */ static bool emit_cfa_remember; +/* True if start_epilogue should be emitted before following CFI directive. */ +static bool emit_cfa_start_epilogue; + /* Add CFI to the current fde at the PC value indicated by LABEL if specified, or to the CIE if LABEL is NULL. */ @@ -809,6 +818,17 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) { dw_cfi_ref *list_head; + if (emit_cfa_start_epilogue) + { + dw_cfi_ref cfi_epi_start; + + /* Emit the state save. */ + emit_cfa_start_epilogue = false; + cfi_epi_start = new_cfi (); + cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue; + add_fde_cfi (label, cfi_epi_start); + } + if (emit_cfa_remember) { dw_cfi_ref cfi_remember; @@ -2898,7 +2918,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn) gcc_assert (i != NULL); i = next_real_insn (i); if (i == NULL) - return; + { + /* But we do mark the start of the epilogue to allow it to be skipped + in _eh frames. */ + emit_cfa_start_epilogue = true; + return; + } /* Insert the restore before that next real insn in the stream, and before a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be @@ -2953,6 +2978,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi case DW_CFA_GNU_window_save: case DW_CFA_remember_state: case DW_CFA_restore_state: + case DW_CFA_GNU_start_epilogue: return dw_cfi_oprnd_unused; case DW_CFA_set_loc: @@ -3121,6 +3148,10 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)), "DW_CFA_restore, column %#lx", r); } + else if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) +/* DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); else { dw2_asm_output_data (1, cfi->dw_cfi_opc, @@ -3303,6 +3334,12 @@ output_cfi_directive (dw_cfi_ref cfi) cfi->dw_cfi_oprnd1.dw_cfi_offset); break; + case DW_CFA_GNU_start_epilogue: +/*DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); + break; + case DW_CFA_remember_state: fprintf (asm_out_file, "\t.cfi_remember_state\n"); break; @@ -3498,6 +3535,41 @@ output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f } } +/* Output cfi skipping save/restore and epilogues in _eh frames + for targets that do not want them. */ + +static dw_cfi_ref +emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh) +{ + if (for_eh + && targetm.asm_out.suppress_eh_epilogue_p()) + { + if (cfi->dw_cfi_opc == DW_CFA_remember_state) + { + /* Skip to the restore, unless there's an error and we fall off + the end. */ + while (cfi->dw_cfi_next + && cfi->dw_cfi_opc != DW_CFA_restore_state) + cfi = cfi->dw_cfi_next; + return cfi; + } + if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue) + { +/*DEBUG */ + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_GNU_start_epilogue\n",asm_out_file); + while (cfi->dw_cfi_next) + /* Skip to the end. */ + cfi = cfi->dw_cfi_next; + return cfi; + } + } + + /* if it's not a special case, then just emit it. */ + output_cfi (cfi, fde, for_eh); + return cfi; +} + /* Output one FDE. */ static void @@ -3613,13 +3685,13 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco fde->dw_fde_current_label = begin; if (!fde->dw_fde_switched_sections) for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); else if (!second) { if (fde->dw_fde_switch_cfi) for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) { - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); if (cfi == fde->dw_fde_switch_cfi) break; } @@ -3636,7 +3707,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next; } for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde, for_eh); + cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh); } /* If we are to emit a ref/link from function bodies to their frame tables, Index: gcc/target.def =================================================================== --- gcc/target.def (revision 163221) +++ gcc/target.def (working copy) @@ -390,6 +406,15 @@ DEFHOOK void, (FILE *file, int size, rtx x), NULL) +/* Targets might not need epilogue information in dwarf2 _eh frames. This + hook should return true if the epilogue should be suppressed in such frames. + Epilogues will still be emitted in _debug_frames. */ +DEFHOOK_UNDOC +(suppress_eh_epilogue_p, + "", + bool, (void), + hook_bool_void_false) + /* Some target machines need to postscan each insn after it is output. */ DEFHOOK (final_postscan_insn, Index: gcc/config/darwin-protos.h =================================================================== --- gcc/config/darwin-protos.h (revision 163221) +++ gcc/config/darwin-protos.h (working copy) @@ -83,10 +84,15 @@ extern tree darwin_handle_weak_import_attribute (t extern void machopic_output_stub (FILE *, const char *, const char *); extern void darwin_globalize_label (FILE *, const char *); extern void darwin_assemble_visibility (tree, int); + +extern bool darwin_asm_suppress_eh_epilogue_p (void); +extern void darwin_asm_output_dwarf_section_start_label (FILE *file, + section *sect); extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *, const char *); extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *, section *); + extern void darwin_asm_declare_constant_name (FILE *, const char *, const_tree, HOST_WIDE_INT); extern bool darwin_binds_local_p (const_tree); Index: gcc/config/darwin.h =================================================================== --- gcc/config/darwin.h (revision 163221) +++ gcc/config/darwin.h (working copy) @@ -669,7 +675,6 @@ extern GTY(()) int darwin_ms_struct; Make Objective-C internal symbols local and in doing this, we need to accommodate the name mangling done by c++ on file scope locals. */ - int darwin_label_is_anonymous_local_objc_name (const char *name); #undef ASM_OUTPUT_LABELREF @@ -927,6 +932,16 @@ enum machopic_addr_class { ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \ ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr) +/* Mark the start of each dwarf debug section to allow us to compute local + offsets within the sections. We do this in darwin, rather than emitting + relocs. */ +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \ + darwin_asm_output_dwarf_section_start_label + +/* For OSX compatibility we do not want to emit epilogues in _eh frames. */ +#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \ + darwin_asm_suppress_eh_epilogue_p + #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2) \ darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2) Index: gcc/config/darwin.c =================================================================== --- gcc/config/darwin.c (revision 163221) +++ gcc/config/darwin.c (working copy) @@ -1666,6 +1666,36 @@ darwin_assemble_visibility (tree decl, int vis) "not supported in this configuration; ignored"); } +/* For compatibility with OSX versions that do not emit epilogues in _eh + frames we suppress them. This is made a predicate function to permit + us to add an OSX/FSF compatibility switch should that be required. */ + +bool +darwin_asm_suppress_eh_epilogue_p (void) +{ + return true; +} + +/* So that we can compute dwarf offsets within sections, we emit a known + section marker at the begining of the section. This is distinct from + the ones emitted by dwarf2out. The label is constructed by extracting + sectname from __DWARF,__sectname,etc,etc. The hook should be invoked + once, after the first switch to the section. */ + +void +darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect) +{ + const char *dnam; + int namelen; + gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG))); + dnam = ((struct named_section *)sect)->name; + gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0); + gcc_assert (strchr (dnam + 8, ',')); + + namelen = strchr (dnam + 8, ',') - (dnam + 8); + fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8); +} + /* Output a difference of two labels that will be an assembly time constant if the two labels are local. (.long lab1-lab2 will be very different if lab1 is at the boundary between two sections; it