diff options
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/Makefile.in | 5 | ||||
-rw-r--r-- | gcc/c-cppbuiltin.c | 6 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/config.in | 6 | ||||
-rwxr-xr-x | gcc/configure | 44 | ||||
-rw-r--r-- | gcc/configure.ac | 14 | ||||
-rw-r--r-- | gcc/doc/cpp.texi | 4 | ||||
-rw-r--r-- | gcc/dwarf2asm.c | 74 | ||||
-rw-r--r-- | gcc/dwarf2asm.h | 7 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 342 |
11 files changed, 519 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7444d7e3c0f..7884fa833b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2008-08-05 Richard Henderson <rth@redhat.com> + + * Makefile.in (c-cppbuiltin.o): Depend on debug.h. + * c-cppbuiltin.c (c_cpp_builtins): Define __GCC_HAVE_DWARF2_CFI_ASM. + * doc/cpp.texi (__GCC_HAVE_DWARF2_CFI_ASM): Document it. + * common.opt (fdwarf2-cfi-asm): New. + * configure.ac (HAVE_GAS_CFI_DIRECTIVE): New. + * config.in, configure: Rebuild. + * dwarf2asm.c (dw2_asm_output_data_raw): New. + (dw2_asm_output_data_uleb128_raw, dw2_asm_output_data_sleb128_raw): New. + (dw2_force_const_mem): Externalize. + * dwarf2asm.h: Update. + * dwarf2out.c (dwarf2out_cfi_label): If flag_dwarf2_cfi_asm, don't + generate a real label. + (output_cfi_directive): New. + (add_fde_cfi): If flag_dwarf2_cfi_asm, use it. + (output_call_frame_info): Do nothing if flag_dwarf2_cfi_asm. + (dwarf2out_begin_prologue): Emit .cfi_startproc, .cfi_personality, + and .cfi_lsda. + (dwarf2out_end_epilogue): Emit .cfi_endproc. + (output_loc_operands_raw, output_loc_sequence_raw): New. + (output_cfa_loc_raw): New. + 2008-08-05 Paul Brook <paul@codesourcery.com> * doc/invoke.texi: Document new ARM -mfpu= and -mcpu= options. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 479277a567b..1c22966d9d9 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1870,8 +1870,9 @@ c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $< $(OUTPUT_OPTION) @TARGET_SYSTEM_ROOT_DEFINE@ c-cppbuiltin.o : c-cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) $(TOPLEV_H) \ - output.h except.h $(REAL_H) $(TARGET_H) $(TM_P_H) $(BASEVER) + $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) \ + $(TOPLEV_H) output.h except.h $(REAL_H) $(TARGET_H) $(TM_P_H) \ + $(BASEVER) debug.h $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) -DBASEVER=$(BASEVER_s) \ $< $(OUTPUT_OPTION) diff --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c index 2d951fe450c..01f92155fd6 100644 --- a/gcc/c-cppbuiltin.c +++ b/gcc/c-cppbuiltin.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "c-pragma.h" #include "output.h" #include "except.h" /* For USING_SJLJ_EXCEPTIONS. */ +#include "debug.h" /* For dwarf2out_do_frame. */ #include "toplev.h" #include "tm_p.h" /* Target prototypes. */ #include "target.h" @@ -691,6 +692,11 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); #endif +#ifdef DWARF2_UNWIND_INFO + if (flag_dwarf2_cfi_asm && dwarf2out_do_frame ()) + cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM"); +#endif + /* Make the choice of ObjC runtime visible to source code. */ if (c_dialect_objc () && flag_next_runtime) cpp_define (pfile, "__NEXT_RUNTIME__"); diff --git a/gcc/common.opt b/gcc/common.opt index 08f95c228e6..02bdef25588 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -459,6 +459,10 @@ fdump-unnumbered Common Report Var(flag_dump_unnumbered) VarExists Suppress output of instruction numbers, line number notes and addresses in debugging dumps +fdwarf2-cfi-asm +Common Report Var(flag_dwarf2_cfi_asm) Init(HAVE_GAS_CFI_DIRECTIVE) +Enable CFI tables via GAS assembler directives. + fearly-inlining Common Report Var(flag_early_inlining) Init(1) Optimization Perform early inlining diff --git a/gcc/config.in b/gcc/config.in index b4261d9d9e5..47ec2ab2fe2 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -821,6 +821,12 @@ #endif +/* Define 0/1 if your assembler supports CFI directives. */ +#ifndef USED_FOR_TARGET +#undef HAVE_GAS_CFI_DIRECTIVE +#endif + + /* Define if your assembler uses the new HImode fild and fist notation. */ #ifndef USED_FOR_TARGET #undef HAVE_GAS_FILDS_FISTS diff --git a/gcc/configure b/gcc/configure index a79664b708e..d1996bb7b4b 100755 --- a/gcc/configure +++ b/gcc/configure @@ -20832,6 +20832,50 @@ _ACEOF fi +# Check if we have assembler support for unwind directives. +echo "$as_me:$LINENO: checking assembler for cfi directives" >&5 +echo $ECHO_N "checking assembler for cfi directives... $ECHO_C" >&6 +if test "${gcc_cv_as_cfi_directive+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + gcc_cv_as_cfi_directive=no + if test $in_tree_gas = yes; then + if test $in_tree_gas_is_elf = yes \ + && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0` + then gcc_cv_as_cfi_directive=yes +fi + elif test x$gcc_cv_as != x; then + echo ' .text + .cfi_startproc + .cfi_offset 0, 0 + .cfi_same_value 1 + .cfi_def_cfa 1, 2 + .cfi_escape 1, 2, 3, 4, 5 + .cfi_endproc' > conftest.s + if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } + then + gcc_cv_as_cfi_directive=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +echo "$as_me:$LINENO: result: $gcc_cv_as_cfi_directive" >&5 +echo "${ECHO_T}$gcc_cv_as_cfi_directive" >&6 + + +cat >>confdefs.h <<_ACEOF +#define HAVE_GAS_CFI_DIRECTIVE `if test $gcc_cv_as_cfi_directive = yes; then echo 1; else echo 0; fi` +_ACEOF + + # GAS versions up to and including 2.11.0 may mis-optimize # .eh_frame data. echo "$as_me:$LINENO: checking assembler for eh_frame optimization" >&5 diff --git a/gcc/configure.ac b/gcc/configure.ac index ced1a7cd21b..4f7fc325330 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2180,6 +2180,20 @@ changequote([,])dnl [AC_DEFINE(HAVE_AS_LEB128, 1, [Define if your assembler supports .sleb128 and .uleb128.])]) +# Check if we have assembler support for unwind directives. +gcc_GAS_CHECK_FEATURE([cfi directives], gcc_cv_as_cfi_directive, + [elf,2,17,0],, +[ .text + .cfi_startproc + .cfi_offset 0, 0 + .cfi_same_value 1 + .cfi_def_cfa 1, 2 + .cfi_escape 1, 2, 3, 4, 5 + .cfi_endproc]) +AC_DEFINE_UNQUOTED(HAVE_GAS_CFI_DIRECTIVE, + [`if test $gcc_cv_as_cfi_directive = yes; then echo 1; else echo 0; fi`], +[Define 0/1 if your assembler supports CFI directives.]) + # GAS versions up to and including 2.11.0 may mis-optimize # .eh_frame data. gcc_GAS_CHECK_FEATURE(eh_frame optimization, gcc_cv_as_eh_frame, diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index aaf83f99774..0eaece14d45 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -2239,6 +2239,10 @@ If GCC cannot determine the current date, it will emit a warning message These macros are defined when the target processor supports atomic compare and swap operations on operands 1, 2, 4, 8 or 16 bytes in length, respectively. +@item __GCC_HAVE_DWARF2_CFI_ASM +This macro is defined when the compiler is emitting Dwarf2 CFI directives +to the assembler. When this is defined, it is possible to emit those same +directives in inline assembly. @end table @node System-specific Predefined Macros diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c index 43d57e9fa8f..9ae94200f18 100644 --- a/gcc/dwarf2asm.c +++ b/gcc/dwarf2asm.c @@ -62,6 +62,34 @@ dw2_assemble_integer (int size, rtx x) } +/* Output a value of a given size in target byte order. */ + +void +dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value) +{ + unsigned char bytes[8]; + int i; + + for (i = 0; i < 8; ++i) + { + bytes[i] = value & 0xff; + value >>= 8; + } + + if (BYTES_BIG_ENDIAN) + { + for (i = size - 1; i > 0; --i) + fprintf (asm_out_file, "0x%x,", bytes[i]); + fprintf (asm_out_file, "0x%x", bytes[0]); + } + else + { + for (i = 0; i < size - 1; ++i) + fprintf (asm_out_file, "0x%x,", bytes[i]); + fprintf (asm_out_file, "0x%x", bytes[i]); + } +} + /* Output an immediate constant in a given SIZE in bytes. */ void @@ -505,6 +533,26 @@ eh_data_format_name (int format) #endif } +/* Output an unsigned LEB128 quantity, but only the byte values. */ + +void +dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value) +{ + while (1) + { + int byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (value == 0) + break; + fputc (',', asm_out_file); + } +} + /* Output an unsigned LEB128 quantity. */ void @@ -566,6 +614,29 @@ dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value, va_end (ap); } +/* Output an signed LEB128 quantity, but only the byte values. */ + +void +dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value) +{ + int byte, more; + + while (1) + { + byte = (value & 0x7f); + value >>= 7; + more = !((value == 0 && (byte & 0x40) == 0) + || (value == -1 && (byte & 0x40) != 0)); + if (more) + byte |= 0x80; + + fprintf (asm_out_file, "0x%x", byte); + if (!more) + break; + fputc (',', asm_out_file); + } +} + /* Output a signed LEB128 quantity. */ void @@ -689,7 +760,6 @@ dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED, } #endif /* 0 */ -static rtx dw2_force_const_mem (rtx, bool); static int dw2_output_indirect_constant_1 (splay_tree_node, void *); static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool; @@ -733,7 +803,7 @@ splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2) "near" the function in any interesting sense. IS_PUBLIC controls whether the symbol can be shared across the entire application (or DSO). */ -static rtx +rtx dw2_force_const_mem (rtx x, bool is_public) { splay_tree_node node; diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h index 03fc0ca0e16..70fbd4c4400 100644 --- a/gcc/dwarf2asm.h +++ b/gcc/dwarf2asm.h @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see extern void dw2_assemble_integer (int, rtx); +extern void dw2_asm_output_data_raw (int, unsigned HOST_WIDE_INT); + extern void dw2_asm_output_data (int, unsigned HOST_WIDE_INT, const char *, ...) ATTRIBUTE_NULL_PRINTF_3; @@ -46,10 +48,14 @@ extern void dw2_asm_output_nstring (const char *, size_t, const char *, ...) ATTRIBUTE_NULL_PRINTF_3; +extern void dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT); + extern void dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT, const char *, ...) ATTRIBUTE_NULL_PRINTF_2; +extern void dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT); + extern void dw2_asm_output_data_sleb128 (HOST_WIDE_INT, const char *, ...) ATTRIBUTE_NULL_PRINTF_2; @@ -63,6 +69,7 @@ extern int size_of_sleb128 (HOST_WIDE_INT); extern int size_of_encoded_value (int); extern const char *eh_data_format_name (int); +extern rtx dw2_force_const_mem (rtx, bool); extern void dw2_output_indirect_constants (void); /* These are currently unused. */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index e5128d4886d..ad09949cc15 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -384,6 +384,7 @@ static void initial_return_save (rtx); #endif static HOST_WIDE_INT stack_adjust_offset (const_rtx); static void output_cfi (dw_cfi_ref, dw_fde_ref, int); +static void output_cfi_directive (dw_cfi_ref); static void output_call_frame_info (int); static void dwarf2out_note_section_used (void); static void dwarf2out_stack_adjust (rtx, bool); @@ -394,6 +395,7 @@ static void dwarf2out_frame_debug_expr (rtx, const char *); /* Support for complex CFA locations. */ static void output_cfa_loc (dw_cfi_ref); +static void output_cfa_loc_raw (dw_cfi_ref); static void get_cfa_from_loc_descr (dw_cfa_location *, struct dw_loc_descr_struct *); static struct dw_loc_descr_struct *build_cfa_loc @@ -665,8 +667,19 @@ dwarf2out_cfi_label (void) { static char label[20]; - ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++); - ASM_OUTPUT_LABEL (asm_out_file, label); + if (flag_dwarf2_cfi_asm) + { + /* In this case, we will be emitting the asm directive instead of + the label, so just return a placeholder to keep the rest of the + interfaces happy. */ + strcpy (label, "<do not output>"); + } + else + { + ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++); + ASM_OUTPUT_LABEL (asm_out_file, label); + } + return label; } @@ -676,7 +689,25 @@ dwarf2out_cfi_label (void) static void add_fde_cfi (const char *label, dw_cfi_ref cfi) { - if (label) + dw_cfi_ref *list_head = &cie_cfi_head; + + if (flag_dwarf2_cfi_asm) + { + if (label) + { + output_cfi_directive (cfi); + + /* We still have to add the cfi to the list so that + lookup_cfa works later on. */ + list_head = ¤t_fde ()->dw_fde_cfi; + } + /* ??? If this is a CFI for the CIE, we don't emit. This + assumes that the standard CIE contents that the assembler + uses matches the standard CIE contents that the compiler + uses. This is probably a bad assumption. I'm not quite + sure how to address this for now. */ + } + else if (label) { dw_fde_ref fde = current_fde (); @@ -705,11 +736,10 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) fde->dw_fde_current_label = label; } - add_cfi (&fde->dw_fde_cfi, cfi); + list_head = &fde->dw_fde_cfi; } - else - add_cfi (&cie_cfi_head, cfi); + add_cfi (list_head, cfi); } /* Subroutine of lookup_cfa. */ @@ -2619,6 +2649,100 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh) } } +/* Similar, but do it via assembler directives instead. */ + +static void +output_cfi_directive (dw_cfi_ref cfi) +{ + unsigned long r, r2; + + switch (cfi->dw_cfi_opc) + { + case DW_CFA_advance_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + case DW_CFA_MIPS_advance_loc8: + case DW_CFA_set_loc: + /* Should only be created by add_fde_cfi in a code path not + followed when emitting via directives. The assembler is + going to take care of this for us. */ + gcc_unreachable (); + + case DW_CFA_offset: + case DW_CFA_offset_extended: + case DW_CFA_offset_extended_sf: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n", + r, cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT); + break; + + case DW_CFA_restore: + case DW_CFA_restore_extended: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_restore %lu\n", r); + break; + + case DW_CFA_undefined: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r); + break; + + case DW_CFA_same_value: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r); + break; + + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n", + r, cfi->dw_cfi_oprnd2.dw_cfi_offset); + break; + + case DW_CFA_def_cfa_register: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r); + break; + + case DW_CFA_register: + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 0); + fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2); + break; + + case DW_CFA_def_cfa_offset: + case DW_CFA_def_cfa_offset_sf: + fprintf (asm_out_file, "\t.cfi_def_cfa_offset " + HOST_WIDE_INT_PRINT_DEC"\n", + cfi->dw_cfi_oprnd1.dw_cfi_offset); + break; + + case DW_CFA_GNU_args_size: + fprintf (asm_out_file, "\t.cfi_escape 0x%x,", DW_CFA_GNU_args_size); + dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset); + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC, + ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); + fputc ('\n', asm_out_file); + break; + + case DW_CFA_GNU_window_save: + fprintf (asm_out_file, "\t.cfi_window_save\n"); + break; + + case DW_CFA_def_cfa_expression: + case DW_CFA_expression: + fprintf (asm_out_file, "\t.cfi_escape 0x%x,", cfi->dw_cfi_opc); + output_cfa_loc_raw (cfi); + fputc ('\n', asm_out_file); + break; + + default: + gcc_unreachable (); + } +} + /* Output the call frame information used to record information that relates to calculating the frame pointer, and records the location of saved registers. */ @@ -2642,6 +2766,10 @@ output_call_frame_info (int for_eh) if (fde_table_in_use == 0) return; + /* Nothing to do if the assembler's doing it all. */ + if (flag_dwarf2_cfi_asm) + return; + /* If we make FDEs linkonce, we may have to emit an empty label for an FDE that wouldn't otherwise be emitted. We want to avoid having an FDE kept around when the function it refers to is @@ -3058,6 +3186,49 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, if (file) dwarf2out_source_line (line, file); #endif + + if (flag_dwarf2_cfi_asm) + { + int enc; + rtx ref; + + fprintf (asm_out_file, "\t.cfi_startproc\n"); + + if (eh_personality_libfunc) + { + enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); + ref = eh_personality_libfunc; + + /* ??? The GAS support isn't entirely consistent. We have to + handle indirect support ourselves, but PC-relative is done + in the assembler. Further, the assembler can't handle any + of the weirder relocation types. */ + if (enc & DW_EH_PE_indirect) + ref = dw2_force_const_mem (ref, true); + + fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc); + output_addr_const (asm_out_file, ref); + fputc ('\n', asm_out_file); + } + + if (crtl->uses_eh_lsda) + { + char lab[20]; + + enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0); + ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA", + current_function_funcdef_no); + ref = gen_rtx_SYMBOL_REF (Pmode, lab); + SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL; + + if (enc & DW_EH_PE_indirect) + ref = dw2_force_const_mem (ref, true); + + fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc); + output_addr_const (asm_out_file, ref); + fputc ('\n', asm_out_file); + } + } } /* Output a marker (i.e. a label) for the absolute end of the generated code @@ -3071,6 +3242,9 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, dw_fde_ref fde; char label[MAX_ARTIFICIAL_LABEL_BYTES]; + if (flag_dwarf2_cfi_asm) + fprintf (asm_out_file, "\t.cfi_endproc\n"); + /* Output a label to mark the endpoint of the code generated for this function. */ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, @@ -3931,6 +4105,141 @@ output_loc_sequence (dw_loc_descr_ref loc) } } +/* Output location description stack opcode's operands (if any). + The output is single bytes on a line, suitable for .cfi_escape. */ + +static void +output_loc_operands_raw (dw_loc_descr_ref loc) +{ + dw_val_ref val1 = &loc->dw_loc_oprnd1; + dw_val_ref val2 = &loc->dw_loc_oprnd2; + + switch (loc->dw_loc_opc) + { + case DW_OP_addr: + /* We cannot output addresses in .cfi_escape, only bytes. */ + gcc_unreachable (); + + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + fputc (',', asm_out_file); + dw2_asm_output_data_raw (1, val1->v.val_int); + break; + + case DW_OP_const2u: + case DW_OP_const2s: + fputc (',', asm_out_file); + dw2_asm_output_data_raw (2, val1->v.val_int); + break; + + case DW_OP_const4u: + case DW_OP_const4s: + fputc (',', asm_out_file); + dw2_asm_output_data_raw (4, val1->v.val_int); + break; + + case DW_OP_const8u: + case DW_OP_const8s: + gcc_assert (HOST_BITS_PER_LONG >= 64); + fputc (',', asm_out_file); + dw2_asm_output_data_raw (8, val1->v.val_int); + break; + + case DW_OP_skip: + case DW_OP_bra: + { + int offset; + + gcc_assert (val1->val_class == dw_val_class_loc); + offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3); + + fputc (',', asm_out_file); + dw2_asm_output_data_raw (2, offset); + } + break; + + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + fputc (',', asm_out_file); + dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned); + break; + + case DW_OP_consts: + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + case DW_OP_fbreg: + fputc (',', asm_out_file); + dw2_asm_output_data_sleb128_raw (val1->v.val_int); + break; + + case DW_OP_bregx: + fputc (',', asm_out_file); + dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned); + fputc (',', asm_out_file); + dw2_asm_output_data_sleb128_raw (val2->v.val_int); + break; + + case INTERNAL_DW_OP_tls_addr: + gcc_unreachable (); + + default: + /* Other codes have no operands. */ + break; + } +} + +static void +output_loc_sequence_raw (dw_loc_descr_ref loc) +{ + while (1) + { + /* Output the opcode. */ + fprintf (asm_out_file, "0x%x", loc->dw_loc_opc); + output_loc_operands_raw (loc); + + if (!loc->dw_loc_next) + break; + loc = loc->dw_loc_next; + + fputc (',', asm_out_file); + } +} + /* This routine will generate the correct assembly data for a location description based on a cfi entry with a complex address. */ @@ -3952,6 +4261,27 @@ output_cfa_loc (dw_cfi_ref cfi) output_loc_sequence (loc); } +/* Similar, but used for .cfi_escape. */ + +static void +output_cfa_loc_raw (dw_cfi_ref cfi) +{ + dw_loc_descr_ref loc; + unsigned long size; + + if (cfi->dw_cfi_opc == DW_CFA_expression) + fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd2.dw_cfi_reg_num); + + /* Output the size of the block. */ + loc = cfi->dw_cfi_oprnd1.dw_cfi_loc; + size = size_of_locs (loc); + dw2_asm_output_data_uleb128_raw (size); + fputc (',', asm_out_file); + + /* Now output the operations themselves. */ + output_loc_sequence_raw (loc); +} + /* This function builds a dwarf location descriptor sequence from a dw_cfa_location, adding the given OFFSET to the result of the expression. */ |