#include "as.h"
#include "dw2gencfi.h"
#include "subsegs.h"
+#include "dwarf2dbg.h"
#ifdef TARGET_USE_CFIPOP
# define tc_cfi_frame_initial_instructions() ((void)0)
#endif
+#ifndef DWARF2_FORMAT
+# define DWARF2_FORMAT(SEC) dwarf2_format_32bit
+#endif
+
#ifndef DWARF2_ADDR_SIZE
# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
#endif
static void dot_cfi (int);
static void dot_cfi_escape (int);
+static void dot_cfi_sections (int);
static void dot_cfi_startproc (int);
static void dot_cfi_endproc (int);
static void dot_cfi_personality (int);
const pseudo_typeS cfi_pseudo_table[] =
{
+ { "cfi_sections", dot_cfi_sections, 0 },
{ "cfi_startproc", dot_cfi_startproc, 0 },
{ "cfi_endproc", dot_cfi_endproc, 0 },
{ "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa },
demand_empty_rest_of_line ();
}
+/* By default emit .eh_frame only, not .debug_frame. */
+#define CFI_EMIT_eh_frame (1 << 0)
+#define CFI_EMIT_debug_frame (1 << 1)
+static int cfi_sections = CFI_EMIT_eh_frame;
+
+static void
+dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
+{
+ int sections = 0;
+
+ SKIP_WHITESPACE ();
+ if (is_name_beginner (*input_line_pointer))
+ while (1)
+ {
+ char *name, c;
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+
+ if (strcmp (name, ".eh_frame") == 0)
+ sections |= CFI_EMIT_eh_frame;
+ else if (strcmp (name, ".debug_frame") == 0)
+ sections |= CFI_EMIT_debug_frame;
+ else
+ {
+ *input_line_pointer = c;
+ input_line_pointer = name;
+ break;
+ }
+
+ *input_line_pointer = c;
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ name = input_line_pointer++;
+ SKIP_WHITESPACE ();
+ if (!is_name_beginner (*input_line_pointer))
+ {
+ input_line_pointer = name;
+ break;
+ }
+ }
+ else if (is_name_beginner (*input_line_pointer))
+ break;
+ }
+
+ demand_empty_rest_of_line ();
+ cfi_sections = sections;
+}
+
static void
dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
{
}
static void
-output_cie (struct cie_entry *cie)
+output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align)
{
symbolS *after_size_address, *end_address;
expressionS exp;
struct cfi_insn_data *i;
offsetT augmentation_size;
int enc;
+ enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
cie->start_address = symbol_temp_new_now ();
after_size_address = symbol_temp_make ();
exp.X_op_symbol = after_size_address;
exp.X_add_number = 0;
- emit_expr (&exp, 4); /* Length. */
+ if (eh_frame || fmt == dwarf2_format_32bit)
+ emit_expr (&exp, 4); /* Length. */
+ else
+ {
+ if (fmt == dwarf2_format_64bit)
+ out_four (-1);
+ emit_expr (&exp, 8); /* Length. */
+ }
symbol_set_value_now (after_size_address);
- out_four (0); /* CIE id. */
+ if (eh_frame)
+ out_four (0); /* CIE id. */
+ else
+ {
+ out_four (-1); /* CIE id. */
+ if (fmt != dwarf2_format_32bit)
+ out_four (-1);
+ }
out_one (DW_CIE_VERSION); /* Version. */
- out_one ('z'); /* Augmentation. */
- if (cie->per_encoding != DW_EH_PE_omit)
- out_one ('P');
- if (cie->lsda_encoding != DW_EH_PE_omit)
- out_one ('L');
- out_one ('R');
- if (cie->signal_frame)
- out_one ('S');
+ if (eh_frame)
+ {
+ out_one ('z'); /* Augmentation. */
+ if (cie->per_encoding != DW_EH_PE_omit)
+ out_one ('P');
+ if (cie->lsda_encoding != DW_EH_PE_omit)
+ out_one ('L');
+ out_one ('R');
+ if (cie->signal_frame)
+ out_one ('S');
+ }
out_one (0);
out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH); /* Code alignment. */
out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment. */
out_one (cie->return_column);
else
out_uleb128 (cie->return_column);
- augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
- if (cie->per_encoding != DW_EH_PE_omit)
- augmentation_size += 1 + encoding_size (cie->per_encoding);
- out_uleb128 (augmentation_size); /* Augmentation size. */
+ if (eh_frame)
+ {
+ augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
+ if (cie->per_encoding != DW_EH_PE_omit)
+ augmentation_size += 1 + encoding_size (cie->per_encoding);
+ out_uleb128 (augmentation_size); /* Augmentation size. */
+ }
if (cie->per_encoding != DW_EH_PE_omit)
{
offsetT size = encoding_size (cie->per_encoding);
#if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
enc |= DW_EH_PE_pcrel;
#endif
- out_one (enc);
+ if (eh_frame)
+ out_one (enc);
if (cie->first)
for (i = cie->first; i != cie->last; i = i->next)
output_cfi_insn (i);
- frag_align (2, DW_CFA_nop, 0);
+ frag_align (align, DW_CFA_nop, 0);
symbol_set_value_now (end_address);
}
static void
output_fde (struct fde_entry *fde, struct cie_entry *cie,
- struct cfi_insn_data *first, int align)
+ bfd_boolean eh_frame, struct cfi_insn_data *first,
+ int align)
{
symbolS *after_size_address, *end_address;
expressionS exp;
offsetT augmentation_size;
+ enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
+ int offset_size;
+ int addr_size;
after_size_address = symbol_temp_make ();
end_address = symbol_temp_make ();
exp.X_add_symbol = end_address;
exp.X_op_symbol = after_size_address;
exp.X_add_number = 0;
- emit_expr (&exp, 4); /* Length. */
+ if (eh_frame || fmt == dwarf2_format_32bit)
+ offset_size = 4;
+ else
+ {
+ if (fmt == dwarf2_format_64bit)
+ out_four (-1);
+ offset_size = 8;
+ }
+ emit_expr (&exp, offset_size); /* Length. */
symbol_set_value_now (after_size_address);
- exp.X_add_symbol = after_size_address;
- exp.X_op_symbol = cie->start_address;
- emit_expr (&exp, 4); /* CIE offset. */
+ if (eh_frame)
+ {
+ exp.X_add_symbol = after_size_address;
+ exp.X_op_symbol = cie->start_address;
+ }
+ else
+ {
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = cie->start_address;
+ exp.X_op_symbol = NULL;
+ }
+ emit_expr (&exp, offset_size); /* CIE offset. */
+ if (eh_frame)
+ {
#if CFI_DIFF_EXPR_OK
- exp.X_add_symbol = fde->start_address;
- exp.X_op_symbol = symbol_temp_new_now ();
- emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
+ exp.X_add_symbol = fde->start_address;
+ exp.X_op_symbol = symbol_temp_new_now ();
+ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else
- exp.X_op = O_symbol;
- exp.X_add_symbol = fde->start_address;
- exp.X_op_symbol = NULL;
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = fde->start_address;
+ exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr
- tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
+ tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else
- emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
+ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#endif
- exp.X_op = O_subtract;
#endif
+ addr_size = DWARF2_FDE_RELOC_SIZE;
+ }
+ else
+ {
+ exp.X_add_symbol = fde->start_address;
+ addr_size = DWARF2_ADDR_SIZE (stdoutput);
+ emit_expr (&exp, addr_size);
+ }
+ exp.X_op = O_subtract;
exp.X_add_symbol = fde->end_address;
exp.X_op_symbol = fde->start_address; /* Code length. */
- emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);
+ emit_expr (&exp, addr_size);
augmentation_size = encoding_size (fde->lsda_encoding);
- out_uleb128 (augmentation_size); /* Augmentation size. */
+ if (eh_frame)
+ out_uleb128 (augmentation_size); /* Augmentation size. */
if (fde->lsda_encoding != DW_EH_PE_omit)
{
}
static struct cie_entry *
-select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
+select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
+ struct cfi_insn_data **pfirst, int align)
{
struct cfi_insn_data *i, *j;
struct cie_entry *cie;
cie->last = i;
*pfirst = i;
-
- output_cie (cie);
+
+ output_cie (cie, eh_frame, align);
return cie;
}
+#ifdef md_reg_eh_frame_to_debug_frame
+static void
+cfi_change_reg_numbers (struct cfi_insn_data *insn)
+{
+ for (; insn; insn = insn->next)
+ switch (insn->insn)
+ {
+ case DW_CFA_advance_loc:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ case CFI_escape:
+ break;
+
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset:
+ insn->u.ri.reg = md_reg_eh_frame_to_debug_frame (insn->u.ri.reg);
+ break;
+
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_restore:
+ insn->u.r = md_reg_eh_frame_to_debug_frame (insn->u.r);
+ break;
+
+ case DW_CFA_register:
+ insn->u.rr.reg1 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg1);
+ insn->u.rr.reg2 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg2);
+ break;
+
+ case CFI_val_encoded_addr:
+ insn->u.ea.reg = md_reg_eh_frame_to_debug_frame (insn->u.ea.reg);
+ break;
+
+ default:
+ abort ();
+ }
+}
+#else
+#define cfi_change_reg_numbers(insn) do { } while (0)
+#endif
+
void
cfi_finish (void)
{
if (all_fde_data == 0)
return;
- /* Open .eh_frame section. */
- cfi_seg = subseg_new (".eh_frame", 0);
- bfd_set_section_flags (stdoutput, cfi_seg,
- SEC_ALLOC | SEC_LOAD | SEC_DATA
- | DWARF2_EH_FRAME_READ_ONLY);
- subseg_set (cfi_seg, 0);
- record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
+ if ((cfi_sections & CFI_EMIT_eh_frame) != 0)
+ {
+ /* Open .eh_frame section. */
+ cfi_seg = subseg_new (".eh_frame", 0);
+ bfd_set_section_flags (stdoutput, cfi_seg,
+ SEC_ALLOC | SEC_LOAD | SEC_DATA
+ | DWARF2_EH_FRAME_READ_ONLY);
+ subseg_set (cfi_seg, 0);
+ record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
#ifdef md_fix_up_eh_frame
- md_fix_up_eh_frame (cfi_seg);
+ md_fix_up_eh_frame (cfi_seg);
#endif
- /* Make sure check_eh_frame doesn't do anything with our output. */
- save_flag_traditional_format = flag_traditional_format;
- flag_traditional_format = 1;
+ /* Make sure check_eh_frame doesn't do anything with our output. */
+ save_flag_traditional_format = flag_traditional_format;
+ flag_traditional_format = 1;
- for (fde = all_fde_data; fde ; fde = fde->next)
+ for (fde = all_fde_data; fde ; fde = fde->next)
+ {
+ struct cfi_insn_data *first;
+ struct cie_entry *cie;
+
+ if (fde->end_address == NULL)
+ {
+ as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
+ fde->end_address = fde->start_address;
+ }
+
+ cie = select_cie_for_fde (fde, TRUE, &first, 2);
+ output_fde (fde, cie, TRUE, first,
+ fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
+ }
+
+ flag_traditional_format = save_flag_traditional_format;
+ }
+
+ if ((cfi_sections & CFI_EMIT_debug_frame) != 0)
{
- struct cfi_insn_data *first;
- struct cie_entry *cie;
+ struct cie_entry *cie, *cie_next;
+ int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
- if (fde->end_address == NULL)
+ for (cie = cie_root; cie; cie = cie_next)
{
- as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
- fde->end_address = fde->start_address;
+ cie_next = cie->next;
+ free ((void *) cie);
}
+ cie_root = NULL;
- cie = select_cie_for_fde (fde, &first);
- output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
- }
+ /* Open .debug_frame section. */
+ cfi_seg = subseg_new (".debug_frame", 0);
+ bfd_set_section_flags (stdoutput, cfi_seg,
+ SEC_READONLY | SEC_DEBUGGING);
+ subseg_set (cfi_seg, 0);
+ record_alignment (cfi_seg, alignment);
+
+ for (fde = all_fde_data; fde ; fde = fde->next)
+ {
+ struct cfi_insn_data *first;
+ struct cie_entry *cie;
- flag_traditional_format = save_flag_traditional_format;
+ if (fde->end_address == NULL)
+ {
+ as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
+ fde->end_address = fde->start_address;
+ }
+
+ fde->per_encoding = DW_EH_PE_omit;
+ fde->lsda_encoding = DW_EH_PE_omit;
+ cfi_change_reg_numbers (fde->data);
+ cie = select_cie_for_fde (fde, FALSE, &first, alignment);
+ output_fde (fde, cie, FALSE, first, alignment);
+ }
+ }
}
#else /* TARGET_USE_CFIPOP */