X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fdw2gencfi.c;h=a4fe8ac9196099f8049e3b650b8ea9744e1f1bb7;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=fb3e302a43839e20704fbac07aecda73e2117b0b;hpb=add39d2344036db9334bdeb1ec20a90beaa3ca49;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index fb3e302a43..a4fe8ac919 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -1,5 +1,5 @@ /* dw2gencfi.c - Support for generating Dwarf2 CFI information. - Copyright (C) 2003-2016 Free Software Foundation, Inc. + Copyright (C) 2003-2020 Free Software Foundation, Inc. Contributed by Michal Ludvig This file is part of GAS, the GNU Assembler. @@ -157,7 +157,7 @@ out_sleb128 (offsetT value) output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1); } -static offsetT +static unsigned int encoding_size (unsigned char encoding) { if (encoding == DW_EH_PE_omit) @@ -183,7 +183,7 @@ encoding_size (unsigned char encoding) static void emit_expr_encoded (expressionS *exp, int encoding, bfd_boolean emit_encoding) { - offsetT size = encoding_size (encoding); + unsigned int size = encoding_size (encoding); bfd_reloc_code_real_type code; if (encoding == DW_EH_PE_omit) @@ -197,6 +197,7 @@ emit_expr_encoded (expressionS *exp, int encoding, bfd_boolean emit_encoding) { reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, code); char *p = frag_more (size); + gas_assert (size == (unsigned) howto->bitsize / 8); md_number_to_chars (p, 0, size); fix_new (frag_now, p - frag_now->fr_literal, size, exp->X_add_symbol, exp->X_add_number, howto->pc_relative, code); @@ -224,37 +225,37 @@ emit_expr_encoded (expressionS *exp, int encoding, bfd_boolean emit_encoding) static char * get_debugseg_name (segT seg, const char *base_name) { - const char *name; + const char * name; + const char * dollar; + const char * dot; if (!seg) - name = ""; - else - { - const char * dollar; - const char * dot; + return concat (base_name, NULL); - name = bfd_get_section_name (stdoutput, seg); + name = bfd_section_name (seg); - dollar = strchr (name, '$'); - dot = strchr (name + 1, '.'); + if (name == NULL || *name == 0) + return concat (base_name, NULL); + + dollar = strchr (name, '$'); + dot = strchr (name + 1, '.'); - if (!dollar && !dot) - { - if (!strcmp (base_name, ".eh_frame_entry") - && strcmp (name, ".text") != 0) - return concat (base_name, ".", name, NULL); + if (!dollar && !dot) + { + if (!strcmp (base_name, ".eh_frame_entry") + && strcmp (name, ".text") != 0) + return concat (base_name, ".", name, NULL); - name = ""; - } - else if (!dollar) - name = dot; - else if (!dot) - name = dollar; - else if (dot < dollar) - name = dot; - else - name = dollar; + name = ""; } + else if (!dollar) + name = dot; + else if (!dot) + name = dollar; + else if (dot < dollar) + name = dot; + else + name = dollar; return concat (base_name, name, NULL); } @@ -280,7 +281,7 @@ is_now_linkonce_segment (void) if (compact_eh) return now_seg; - if ((bfd_get_section_flags (stdoutput, now_seg) + if ((bfd_section_flags (now_seg) & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE | SEC_LINK_DUPLICATES_SAME_CONTENTS)) != 0) @@ -305,16 +306,16 @@ make_debug_seg (segT cseg, char *name, int sflags) if (!cseg) flags = 0; else - flags = bfd_get_section_flags (stdoutput, cseg) - & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD - | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE - | SEC_LINK_DUPLICATES_SAME_CONTENTS); + flags = (bfd_section_flags (cseg) + & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD + | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE + | SEC_LINK_DUPLICATES_SAME_CONTENTS)); /* Add standard section flags. */ flags |= sflags; /* Apply possibly linked once flags to new generated segment, too. */ - if (!bfd_set_section_flags (stdoutput, r, flags)) + if (!bfd_set_section_flags (r, flags)) as_bad (_("bfd_set_section_flags: %s"), bfd_errmsg (bfd_get_error ())); @@ -402,6 +403,9 @@ struct cie_entry unsigned char per_encoding; unsigned char lsda_encoding; expressionS personality; +#ifdef tc_cie_entry_extras + tc_cie_entry_extras +#endif struct cfi_insn_data *first, *last; }; @@ -413,22 +417,6 @@ static struct fde_entry **last_fde_data = &all_fde_data; /* List of CIEs so that they could be reused. */ static struct cie_entry *cie_root; -/* Stack of old CFI data, for save/restore. */ -struct cfa_save_data -{ - struct cfa_save_data *next; - offsetT cfa_offset; -}; - -/* Current open FDE entry. */ -struct frch_cfi_data -{ - struct fde_entry *cur_fde_data; - symbolS *last_address; - offsetT cur_cfa_offset; - struct cfa_save_data *cfa_save_stack; -}; - /* Construct a new FDE structure and add it to the end of the fde list. */ static struct fde_entry * @@ -447,6 +435,9 @@ alloc_fde_entry (void) fde->per_encoding = DW_EH_PE_omit; fde->lsda_encoding = DW_EH_PE_omit; fde->eh_header_type = EH_COMPACT_UNKNOWN; +#ifdef tc_fde_entry_init_extra + tc_fde_entry_init_extra (fde) +#endif return fde; } @@ -600,6 +591,22 @@ cfi_add_CFA_offset (unsigned regno, offsetT offset) as_bad (_("register save offset not a multiple of %u"), abs_data_align); } +/* Add a DW_CFA_val_offset record to the CFI data. */ + +void +cfi_add_CFA_val_offset (unsigned regno, offsetT offset) +{ + unsigned int abs_data_align; + + gas_assert (DWARF2_CIE_DATA_ALIGNMENT != 0); + cfi_add_CFA_insn_reg_offset (DW_CFA_val_offset, regno, offset); + + abs_data_align = (DWARF2_CIE_DATA_ALIGNMENT < 0 + ? -DWARF2_CIE_DATA_ALIGNMENT : DWARF2_CIE_DATA_ALIGNMENT); + if (offset % abs_data_align) + as_bad (_("register save offset not a multiple of %u"), abs_data_align); +} + /* Add a DW_CFA_def_cfa record to the CFI data. */ void @@ -719,6 +726,7 @@ const pseudo_typeS cfi_pseudo_table[] = { "cfi_remember_state", dot_cfi, DW_CFA_remember_state }, { "cfi_restore_state", dot_cfi, DW_CFA_restore_state }, { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save }, + { "cfi_negate_ra_state", dot_cfi, DW_CFA_AARCH64_negate_ra_state }, { "cfi_escape", dot_cfi_escape, 0 }, { "cfi_signal_frame", dot_cfi, CFI_signal_frame }, { "cfi_personality", dot_cfi_personality, 0 }, @@ -727,6 +735,7 @@ const pseudo_typeS cfi_pseudo_table[] = { "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 }, { "cfi_inline_lsda", dot_cfi_inline_lsda, 0 }, { "cfi_label", dot_cfi_label, 0 }, + { "cfi_val_offset", dot_cfi, DW_CFA_val_offset }, { NULL, NULL, 0 } }; @@ -814,8 +823,8 @@ dot_cfi (int arg) /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now - || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) - != frag_now_fix ()) + || (S_GET_VALUE (frchain_now->frch_cfi_data->last_address) + != frag_now_fix ())) cfi_add_advance_loc (symbol_temp_new_now ()); switch (arg) @@ -827,6 +836,13 @@ dot_cfi (int arg) cfi_add_CFA_offset (reg1, offset); break; + case DW_CFA_val_offset: + reg1 = cfi_parse_reg (); + cfi_parse_separator (); + offset = cfi_parse_const (); + cfi_add_CFA_val_offset (reg1, offset); + break; + case CFI_rel_offset: reg1 = cfi_parse_reg (); cfi_parse_separator (); @@ -937,8 +953,8 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED) /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now - || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) - != frag_now_fix ()) + || (S_GET_VALUE (frchain_now->frch_cfi_data->last_address) + != frag_now_fix ())) cfi_add_advance_loc (symbol_temp_new_now ()); tail = &head; @@ -985,13 +1001,13 @@ dot_cfi_personality (int ignored ATTRIBUTE_UNUSED) if ((encoding & 0xff) != encoding || ((((encoding & 0x70) != 0 #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr - && (encoding & 0x70) != DW_EH_PE_pcrel + && (encoding & 0x70) != DW_EH_PE_pcrel #endif - ) - /* leb128 can be handled, but does something actually need it? */ + ) + /* leb128 can be handled, but does something actually need it? */ || (encoding & 7) == DW_EH_PE_uleb128 || (encoding & 7) > DW_EH_PE_udata8) - && tc_cfi_reloc_for_encoding (encoding) == BFD_RELOC_NONE)) + && tc_cfi_reloc_for_encoding (encoding) == BFD_RELOC_NONE)) { as_bad (_("invalid or unsupported encoding in .cfi_personality")); ignore_rest_of_line (); @@ -1058,8 +1074,8 @@ dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED) #if CFI_DIFF_LSDA_OK || defined tc_cfi_emit_pcrel_expr && (encoding & 0x70) != DW_EH_PE_pcrel #endif - ) - /* leb128 can be handled, but does something actually need it? */ + ) + /* leb128 can be handled, but does something actually need it? */ || (encoding & 7) == DW_EH_PE_uleb128 || (encoding & 7) > DW_EH_PE_udata8) && tc_cfi_reloc_for_encoding (encoding) == BFD_RELOC_NONE)) @@ -1119,8 +1135,8 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED) /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now - || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) - != frag_now_fix ()) + || (S_GET_VALUE (frchain_now->frch_cfi_data->last_address) + != frag_now_fix ())) cfi_add_advance_loc (symbol_temp_new_now ()); insn_ptr = alloc_cfi_insn_data (); @@ -1136,7 +1152,7 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED) && (encoding & 0x70) != DW_EH_PE_pcrel #endif ) - /* leb128 can be handled, but does something actually need it? */ + /* leb128 can be handled, but does something actually need it? */ || (encoding & 7) == DW_EH_PE_uleb128 || (encoding & 7) > DW_EH_PE_udata8) { @@ -1153,6 +1169,7 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED) case O_constant: if ((encoding & 0x70) != DW_EH_PE_pcrel) break; + /* Fall through. */ default: encoding = DW_EH_PE_omit; break; @@ -1172,15 +1189,23 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED) static void dot_cfi_label (int ignored ATTRIBUTE_UNUSED) { - char *name = read_symbol_name (); + char *name; + if (frchain_now->frch_cfi_data == NULL) + { + as_bad (_("CFI instruction used without previous .cfi_startproc")); + ignore_rest_of_line (); + return; + } + + name = read_symbol_name (); if (name == NULL) return; /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now - || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) - != frag_now_fix ()) + || (S_GET_VALUE (frchain_now->frch_cfi_data->last_address) + != frag_now_fix ())) cfi_add_advance_loc (symbol_temp_new_now ()); cfi_add_label (name); @@ -1210,7 +1235,8 @@ dot_cfi_sections (int ignored ATTRIBUTE_UNUSED) else if (strncmp (name, ".debug_frame", sizeof ".debug_frame") == 0) sections |= CFI_EMIT_debug_frame; #if SUPPORT_COMPACT_EH - else if (strncmp (name, ".eh_frame_entry", sizeof ".eh_frame_entry") == 0) + else if (strncmp (name, ".eh_frame_entry", + sizeof ".eh_frame_entry") == 0) { compact_eh = TRUE; sections |= CFI_EMIT_eh_frame_compact; @@ -1233,18 +1259,23 @@ dot_cfi_sections (int ignored ATTRIBUTE_UNUSED) { name = input_line_pointer++; SKIP_WHITESPACE (); - if (!is_name_beginner (*input_line_pointer) && *input_line_pointer != '"') + if (!is_name_beginner (*input_line_pointer) + && *input_line_pointer != '"') { input_line_pointer = name; break; } } - else if (is_name_beginner (*input_line_pointer) || *input_line_pointer == '"') + else if (is_name_beginner (*input_line_pointer) + || *input_line_pointer == '"') break; } demand_empty_rest_of_line (); - if (cfi_sections_set && cfi_sections != sections) + if (cfi_sections_set + && (sections & (CFI_EMIT_eh_frame | CFI_EMIT_eh_frame_compact)) + && ((cfi_sections & (CFI_EMIT_eh_frame | CFI_EMIT_eh_frame_compact)) + != (sections & (CFI_EMIT_eh_frame | CFI_EMIT_eh_frame_compact)))) as_bad (_("inconsistent uses of .cfi_sections")); cfi_sections = sections; } @@ -1329,7 +1360,7 @@ get_cfi_seg (segT cseg, const char *base, flagword flags, int align) else { cseg = subseg_new (base, 0); - bfd_set_section_flags (stdoutput, cseg, flags); + bfd_set_section_flags (cseg, flags); } record_alignment (cseg, align); return cseg; @@ -1568,7 +1599,9 @@ output_cfi_insn (struct cfi_insn_data *insn) addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; - if (scaled <= 0x3F) + if (scaled == 0) + ; + else if (scaled <= 0x3F) out_one (DW_CFA_advance_loc + scaled); else if (scaled <= 0xFF) { @@ -1598,7 +1631,12 @@ output_cfi_insn (struct cfi_insn_data *insn) /* The code in ehopt.c expects that one byte of the encoding is already allocated to the frag. This comes from the way that it scans the .eh_frame section looking first for the - .byte DW_CFA_advance_loc4. */ + .byte DW_CFA_advance_loc4. Call frag_grow with the sum of + room needed by frag_more and frag_var to preallocate space + ensuring that the DW_CFA_advance_loc4 is in the fixed part + of the rs_cfa frag, so that the relax machinery can remove + the advance_loc should it advance by zero. */ + frag_grow (5); *frag_more (1) = DW_CFA_advance_loc4; frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3, @@ -1680,6 +1718,23 @@ output_cfi_insn (struct cfi_insn_data *insn) } break; + case DW_CFA_val_offset: + regno = insn->u.ri.reg; + offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; + if (offset < 0) + { + out_one (DW_CFA_val_offset_sf); + out_uleb128 (regno); + out_sleb128 (offset); + } + else + { + out_one (DW_CFA_val_offset); + out_uleb128 (regno); + out_uleb128 (offset); + } + break; + case DW_CFA_register: out_one (DW_CFA_register); out_uleb128 (insn->u.rr.reg1); @@ -1806,7 +1861,7 @@ output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align) if (fmt != dwarf2_format_32bit) out_four (-1); } - out_one (DW_CIE_VERSION); /* Version. */ + out_one (flag_dwarf_cie_version); /* Version. */ if (eh_frame) { out_one ('z'); /* Augmentation. */ @@ -1815,14 +1870,30 @@ output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align) if (cie->lsda_encoding != DW_EH_PE_omit) out_one ('L'); out_one ('R'); +#ifdef tc_output_cie_extra + tc_output_cie_extra (cie); +#endif } if (cie->signal_frame) out_one ('S'); out_one (0); + if (flag_dwarf_cie_version >= 4) + { + /* For now we are assuming a flat address space with 4 or 8 byte + addresses. */ + int address_size = dwarf2_format_32bit ? 4 : 8; + out_one (address_size); /* Address size. */ + out_one (0); /* Segment size. */ + } out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH); /* Code alignment. */ out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment. */ - if (DW_CIE_VERSION == 1) /* Return column. */ - out_one (cie->return_column); + if (flag_dwarf_cie_version == 1) /* Return column. */ + { + if ((cie->return_column & 0xff) != cie->return_column) + as_bad (_("return column number %d overflows in CIE version 1"), + cie->return_column); + out_one (cie->return_column); + } else out_uleb128 (cie->return_column); if (eh_frame) @@ -1886,8 +1957,8 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie, expressionS exp; offsetT augmentation_size; enum dwarf2_format fmt = DWARF2_FORMAT (now_seg); - int offset_size; - int addr_size; + unsigned int offset_size; + unsigned int addr_size; after_size_address = symbol_temp_make (); end_address = symbol_temp_make (); @@ -1925,13 +1996,15 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie, { bfd_reloc_code_real_type code = tc_cfi_reloc_for_encoding (cie->fde_encoding); + addr_size = DWARF2_FDE_RELOC_SIZE; if (code != BFD_RELOC_NONE) { reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, code); - char *p = frag_more (4); - md_number_to_chars (p, 0, 4); - fix_new (frag_now, p - frag_now->fr_literal, 4, fde->start_address, - 0, howto->pc_relative, code); + char *p = frag_more (addr_size); + gas_assert (addr_size == (unsigned) howto->bitsize / 8); + md_number_to_chars (p, 0, addr_size); + fix_new (frag_now, p - frag_now->fr_literal, addr_size, + fde->start_address, 0, howto->pc_relative, code); } else { @@ -1940,19 +2013,18 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie, #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. */ + emit_expr (&exp, addr_size); /* Code offset. */ #else exp.X_op = O_symbol; exp.X_add_symbol = fde->start_address; #if defined(tc_cfi_emit_pcrel_expr) - tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ + tc_cfi_emit_pcrel_expr (&exp, addr_size); /* Code offset. */ #else - emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ + emit_expr (&exp, addr_size); /* Code offset. */ #endif #endif } - addr_size = DWARF2_FDE_RELOC_SIZE; } else { @@ -1993,6 +2065,10 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame, { if (CUR_SEG (cie) != CUR_SEG (fde)) continue; +#ifdef tc_cie_fde_equivalent_extra + if (!tc_cie_fde_equivalent_extra (cie, fde)) + continue; +#endif if (cie->return_column != fde->return_column || cie->signal_frame != fde->signal_frame || cie->per_encoding != fde->per_encoding @@ -2001,8 +2077,8 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame, if (cie->per_encoding != DW_EH_PE_omit) { if (cie->personality.X_op != fde->personality.X_op - || cie->personality.X_add_number - != fde->personality.X_add_number) + || (cie->personality.X_add_number + != fde->personality.X_add_number)) continue; switch (cie->personality.X_op) { @@ -2100,6 +2176,9 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame, cie->lsda_encoding = fde->lsda_encoding; cie->personality = fde->personality; cie->first = fde->data; +#ifdef tc_cie_entry_init_extra + tc_cie_entry_init_extra (cie, fde) +#endif for (i = cie->first; i ; i = i->next) if (i->insn == DW_CFA_advance_loc @@ -2265,7 +2344,7 @@ cfi_finish (void) #if SUPPORT_COMPACT_EH /* Emit a LEGACY format header if we have processed all - of the .cfi directives without encountering either inline or + of the .cfi directives without encountering either inline or out-of-line compact unwinding opcodes. */ if (fde->eh_header_type == EH_COMPACT_HAS_LSDA || fde->eh_header_type == EH_COMPACT_UNKNOWN) @@ -2303,7 +2382,8 @@ cfi_finish (void) if (fde->end_address == NULL) { - as_bad (_("open CFI at the end of file; missing .cfi_endproc directive")); + as_bad (_("open CFI at the end of file; " + "missing .cfi_endproc directive")); fde->end_address = fde->start_address; } @@ -2458,7 +2538,8 @@ cfi_finish (void) } if (fde->end_address == NULL) { - as_bad (_("open CFI at the end of file; missing .cfi_endproc directive")); + as_bad (_("open CFI at the end of file; " + "missing .cfi_endproc directive")); fde->end_address = fde->start_address; } @@ -2516,6 +2597,7 @@ const pseudo_typeS cfi_pseudo_table[] = { "cfi_val_encoded_addr", dot_cfi_dummy, 0 }, { "cfi_label", dot_cfi_dummy, 0 }, { "cfi_inline_lsda", dot_cfi_dummy, 0 }, + { "cfi_val_offset", dot_cfi_dummy, 0 }, { NULL, NULL, 0 } };