aboutsummaryrefslogtreecommitdiff
path: root/gcc/dwarf2out.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r--gcc/dwarf2out.c342
1 files changed, 336 insertions, 6 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index e5128d4..ad09949 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 = &current_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. */