static void out_debug_abbrev (segT abbrev_seg, segT info_seg ATTRIBUTE_UNUSED, segT line_seg ATTRIBUTE_UNUSED) { subseg_set (abbrev_seg, 0); out_uleb128 (1); out_uleb128 (DW_TAG_compile_unit); out_byte (DW_CHILDREN_no); if (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit) out_abbrev (DW_AT_stmt_list, DW_FORM_data4); else out_abbrev (DW_AT_stmt_list, DW_FORM_data8); if (all_segs->next == NULL) { out_abbrev (DW_AT_low_pc, DW_FORM_addr); out_abbrev (DW_AT_high_pc, DW_FORM_addr); } else { if (DWARF2_FORMAT (info_seg) == dwarf2_format_32bit) out_abbrev (DW_AT_ranges, DW_FORM_data4); else out_abbrev (DW_AT_ranges, DW_FORM_data8); } out_abbrev (DW_AT_name, DW_FORM_string); out_abbrev (DW_AT_comp_dir, DW_FORM_string); out_abbrev (DW_AT_producer, DW_FORM_string); out_abbrev (DW_AT_language, DW_FORM_data2); out_abbrev (0, 0); /* Terminate the abbreviations for this compilation unit. */ out_byte (0); }
static void out_file_list (void) { size_t size; const char *dir; char *cp; unsigned int i; /* Emit directory list. */ for (i = 1; i < dirs_in_use; ++i) { dir = remap_debug_filename (dirs[i]); size = strlen (dir) + 1; cp = frag_more (size); memcpy (cp, dir, size); } /* Terminate it. */ out_byte ('\0'); for (i = 1; i < files_in_use; ++i) { const char *fullfilename; if (files[i].filename == NULL) { as_bad (_("unassigned file number %ld"), (long) i); /* Prevent a crash later, particularly for file 1. */ files[i].filename = ""; continue; } fullfilename = DWARF2_FILE_NAME (files[i].filename, files[i].dir ? dirs [files [i].dir] : ""); size = strlen (fullfilename) + 1; cp = frag_more (size); memcpy (cp, fullfilename, size); out_uleb128 (files[i].dir); /* directory number */ /* Output the last modification timestamp. */ out_uleb128 (DWARF2_FILE_TIME_NAME (files[i].filename, files[i].dir ? dirs [files [i].dir] : "")); /* Output the filesize. */ out_uleb128 (DWARF2_FILE_SIZE_NAME (files[i].filename, files[i].dir ? dirs [files [i].dir] : "")); } /* Terminate filename list. */ out_byte (0); }
static void output_cie (struct cie_entry *cie) { symbolS *after_size_address, *end_address; expressionS exp; struct cfi_insn_data *i; cie->start_address = symbol_temp_new_now (); after_size_address = symbol_temp_make (); end_address = symbol_temp_make (); exp.X_op = O_subtract; exp.X_add_symbol = end_address; exp.X_op_symbol = after_size_address; exp.X_add_number = 0; emit_expr (&exp, 4); /* Length. */ symbol_set_value_now (after_size_address); out_four (0); /* CIE id. */ out_one (DW_CIE_VERSION); /* Version. */ out_one ('z'); /* Augmentation. */ 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. */ if (DW_CIE_VERSION == 1) /* Return column. */ out_one (cie->return_column); else out_uleb128 (cie->return_column); out_uleb128 (1); /* Augmentation size. */ #if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4); #else out_one (DW_EH_PE_sdata4); #endif if (cie->first) for (i = cie->first; i != cie->last; i = i->next) output_cfi_insn (i); frag_align (2, DW_CFA_nop, 0); symbol_set_value_now (end_address); }
static void out_file_list (void) { size_t size; char *cp; unsigned int i; /* Emit directory list. */ for (i = 1; i < dirs_in_use; ++i) { size = strlen (dirs[i]) + 1; cp = frag_more (size); memcpy (cp, dirs[i], size); } /* Terminate it. */ out_byte ('\0'); for (i = 1; i < files_in_use; ++i) { if (files[i].filename == NULL) { as_bad (_("unassigned file number %ld"), (long) i); /* Prevent a crash later, particularly for file 1. */ files[i].filename = ""; continue; } size = strlen (files[i].filename) + 1; cp = frag_more (size); memcpy (cp, files[i].filename, size); out_uleb128 (files[i].dir); /* directory number */ out_uleb128 (0); /* last modification timestamp */ out_uleb128 (0); /* filesize */ } /* Terminate filename list. */ out_byte (0); }
static void out_set_addr (symbolS *sym) { expressionS exp; out_opcode (DW_LNS_extended_op); out_uleb128 (sizeof_address + 1); out_opcode (DW_LNE_set_address); exp.X_op = O_symbol; exp.X_add_symbol = sym; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); }
static void out_debug_abbrev (segT abbrev_seg) { subseg_set (abbrev_seg, 0); out_uleb128 (1); out_uleb128 (DW_TAG_compile_unit); out_byte (DW_CHILDREN_no); out_abbrev (DW_AT_stmt_list, DW_FORM_data4); if (all_segs->next == NULL) { out_abbrev (DW_AT_low_pc, DW_FORM_addr); out_abbrev (DW_AT_high_pc, DW_FORM_addr); } out_abbrev (DW_AT_name, DW_FORM_string); out_abbrev (DW_AT_comp_dir, DW_FORM_string); out_abbrev (DW_AT_producer, DW_FORM_string); out_abbrev (DW_AT_language, DW_FORM_data2); out_abbrev (0, 0); /* Terminate the abbreviations for this compilation unit. */ out_byte (0); }
static void output_fde (struct fde_entry *fde, struct cie_entry *cie, struct cfi_insn_data *first, int align) { symbolS *after_size_address, *end_address; expressionS exp; after_size_address = symbol_temp_make (); end_address = symbol_temp_make (); exp.X_op = O_subtract; exp.X_add_symbol = end_address; exp.X_op_symbol = after_size_address; exp.X_add_number = 0; emit_expr (&exp, 4); /* 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. */ #ifdef DIFF_EXPR_OK exp.X_add_symbol = fde->start_address; exp.X_op_symbol = symbol_temp_new_now (); emit_expr (&exp, 4); /* Code offset. */ #else 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, 4); /* Code offset. */ #else emit_expr (&exp, 4); /* Code offset. */ #endif exp.X_op = O_subtract; #endif exp.X_add_symbol = fde->end_address; exp.X_op_symbol = fde->start_address; /* Code length. */ emit_expr (&exp, 4); out_uleb128 (0); /* Augmentation size. */ for (; first; first = first->next) output_cfi_insn (first); frag_align (align, DW_CFA_nop, 0); symbol_set_value_now (end_address); }
static void out_set_addr (segT seg, fragS *frag, addressT ofs) { expressionS expr; symbolS *sym; sym = symbol_temp_new (seg, ofs, frag); out_opcode (DW_LNS_extended_op); out_uleb128 (sizeof_address + 1); out_opcode (DW_LNE_set_address); expr.X_op = O_symbol; expr.X_add_symbol = sym; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); }
static inline void out_abbrev (int name, int form) { out_uleb128 (name); out_uleb128 (form); }
static void out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg) { char producer[128]; const char *comp_dir; const char *dirname; expressionS exp; symbolS *info_end; char *p; int len; int sizeof_offset; sizeof_offset = out_header (info_seg, &exp); info_end = exp.X_add_symbol; /* DWARF version. */ out_two (DWARF2_VERSION); /* .debug_abbrev offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); /* Target address size. */ out_byte (sizeof_address); /* DW_TAG_compile_unit DIE abbrev */ out_uleb128 (1); /* DW_AT_stmt_list */ TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit ? 4 : 8)); /* These two attributes are emitted if all of the code is contiguous. */ if (all_segs->next == NULL) { /* DW_AT_low_pc */ exp.X_op = O_symbol; exp.X_add_symbol = all_segs->text_start; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); /* DW_AT_high_pc */ exp.X_op = O_symbol; exp.X_add_symbol = all_segs->text_end; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); } else { /* This attribute is emitted if the code is disjoint. */ /* DW_AT_ranges. */ TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset); } /* DW_AT_name. We don't have the actual file name that was present on the command line, so assume files[1] is the main input file. We're not supposed to get called unless at least one line number entry was emitted, so this should always be defined. */ if (files_in_use == 0) abort (); if (files[1].dir) { dirname = remap_debug_filename (dirs[files[1].dir]); len = strlen (dirname); #ifdef TE_VMS /* Already has trailing slash. */ p = frag_more (len); memcpy (p, dirname, len); #else p = frag_more (len + 1); memcpy (p, dirname, len); INSERT_DIR_SEPARATOR (p, len); #endif } len = strlen (files[1].filename) + 1; p = frag_more (len); memcpy (p, files[1].filename, len); /* DW_AT_comp_dir */ comp_dir = remap_debug_filename (getpwd ()); len = strlen (comp_dir) + 1; p = frag_more (len); memcpy (p, comp_dir, len); /* DW_AT_producer */ sprintf (producer, "GNU AS %s", VERSION); len = strlen (producer) + 1; p = frag_more (len); memcpy (p, producer, len); /* DW_AT_language. Yes, this is probably not really MIPS, but the dwarf2 draft has no standard code for assembler. */ out_two (DW_LANG_Mips_Assembler); symbol_set_value_now (info_end); }
static void process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; unsigned column = 0; unsigned isa = 0; unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; fragS *last_frag = NULL, *frag; addressT last_frag_ofs = 0, frag_ofs; symbolS *last_lab = NULL, *lab; struct line_entry *next; do { int line_delta; if (filenum != e->loc.filenum) { filenum = e->loc.filenum; out_opcode (DW_LNS_set_file); out_uleb128 (filenum); } if (column != e->loc.column) { column = e->loc.column; out_opcode (DW_LNS_set_column); out_uleb128 (column); } if (e->loc.discriminator != 0) { out_opcode (DW_LNS_extended_op); out_leb128 (1 + sizeof_leb128 (e->loc.discriminator, 0)); out_opcode (DW_LNE_set_discriminator); out_uleb128 (e->loc.discriminator); } if (isa != e->loc.isa) { isa = e->loc.isa; out_opcode (DW_LNS_set_isa); out_uleb128 (isa); } if ((e->loc.flags ^ flags) & DWARF2_FLAG_IS_STMT) { flags = e->loc.flags; out_opcode (DW_LNS_negate_stmt); } if (e->loc.flags & DWARF2_FLAG_BASIC_BLOCK) out_opcode (DW_LNS_set_basic_block); if (e->loc.flags & DWARF2_FLAG_PROLOGUE_END) out_opcode (DW_LNS_set_prologue_end); if (e->loc.flags & DWARF2_FLAG_EPILOGUE_BEGIN) out_opcode (DW_LNS_set_epilogue_begin); /* Don't try to optimize away redundant entries; gdb wants two entries for a function where the code starts on the same line as the {, and there's no way to identify that case here. Trust gcc to optimize appropriately. */ line_delta = e->loc.line - line; lab = e->label; frag = symbol_get_frag (lab); frag_ofs = S_GET_VALUE (lab); if (last_frag == NULL) { out_set_addr (lab); out_inc_line_addr (line_delta, 0); } else if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs); else relax_inc_line_addr (line_delta, lab, last_lab); line = e->loc.line; last_lab = lab; last_frag = frag; last_frag_ofs = frag_ofs; next = e->next; free (e); e = next; } while (e); /* Emit a DW_LNE_end_sequence for the end of the section. */ frag = last_frag_for_seg (seg); frag_ofs = get_frag_fix (frag, seg); if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs); else { lab = symbol_temp_new (seg, frag_ofs, frag); relax_inc_line_addr (INT_MAX, lab, last_lab); } }
static void out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg) { char producer[128]; char *comp_dir; expressionS expr; symbolS *info_start; symbolS *info_end; char *p; int len; enum dwarf2_format d2f; int sizeof_offset; subseg_set (info_seg, 0); info_start = symbol_temp_new_now (); info_end = symbol_temp_make (); /* Compilation Unit length. */ expr.X_op = O_subtract; expr.X_add_symbol = info_end; expr.X_op_symbol = info_start; d2f = DWARF2_FORMAT (); if (d2f == dwarf2_format_32bit) { expr.X_add_number = -4; emit_expr (&expr, 4); sizeof_offset = 4; } else if (d2f == dwarf2_format_64bit) { expr.X_add_number = -12; out_four (-1); emit_expr (&expr, 8); sizeof_offset = 8; } else if (d2f == dwarf2_format_64bit_irix) { expr.X_add_number = -8; emit_expr (&expr, 8); sizeof_offset = 8; } else { as_fatal (_("internal error: unknown dwarf2 format")); } /* DWARF version. */ out_two (2); /* .debug_abbrev offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); /* Target address size. */ out_byte (sizeof_address); /* DW_TAG_compile_unit DIE abbrev */ out_uleb128 (1); /* DW_AT_stmt_list */ /* ??? sizeof_offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4); /* These two attributes may only be emitted if all of the code is contiguous. Multiple sections are not that. */ if (all_segs->next == NULL) { /* DW_AT_low_pc */ expr.X_op = O_symbol; expr.X_add_symbol = all_segs->text_start; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); /* DW_AT_high_pc */ expr.X_op = O_symbol; expr.X_add_symbol = all_segs->text_end; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); } /* DW_AT_name. We don't have the actual file name that was present on the command line, so assume files[1] is the main input file. We're not supposed to get called unless at least one line number entry was emitted, so this should always be defined. */ if (!files || files_in_use < 1) abort (); if (files[1].dir) { len = strlen (dirs[files[1].dir]); p = frag_more (len + 1); memcpy (p, dirs[files[1].dir], len); p[len] = '/'; } len = strlen (files[1].filename) + 1; p = frag_more (len); memcpy (p, files[1].filename, len); /* DW_AT_comp_dir */ comp_dir = getpwd (); len = strlen (comp_dir) + 1; p = frag_more (len); memcpy (p, comp_dir, len); /* DW_AT_producer */ sprintf (producer, "GNU AS %s", VERSION); len = strlen (producer) + 1; p = frag_more (len); memcpy (p, producer, len); /* DW_AT_language. Yes, this is probably not really MIPS, but the dwarf2 draft has no standard code for assembler. */ out_two (DW_LANG_Mips_Assembler); symbol_set_value_now (info_end); }
static void output_fde (struct fde_entry *fde, struct cie_entry *cie, 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_op = O_subtract; exp.X_add_symbol = end_address; exp.X_op_symbol = after_size_address; exp.X_add_number = 0; 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); if (eh_frame) { exp.X_op = O_subtract; exp.X_add_symbol = after_size_address; exp.X_op_symbol = cie->start_address; exp.X_add_number = 0; emit_expr (&exp, offset_size); /* CIE offset. */ } else { TC_DWARF2_EMIT_OFFSET (cie->start_address, offset_size); } if (eh_frame) { exp.X_op = O_subtract; exp.X_add_number = 0; #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. */ #else exp.X_op = O_symbol; exp.X_add_symbol = fde->start_address; #ifdef tc_cfi_emit_pcrel_expr tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ #else emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ #endif #endif addr_size = DWARF2_FDE_RELOC_SIZE; } else { exp.X_op = O_symbol; exp.X_add_symbol = fde->start_address; exp.X_add_number = 0; 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. */ exp.X_add_number = 0; emit_expr (&exp, addr_size); augmentation_size = encoding_size (fde->lsda_encoding); if (eh_frame) out_uleb128 (augmentation_size); /* Augmentation size. */ if (fde->lsda_encoding != DW_EH_PE_omit) { exp = fde->lsda; if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel) { #if CFI_DIFF_LSDA_OK exp.X_op = O_subtract; exp.X_op_symbol = symbol_temp_new_now (); emit_expr (&exp, augmentation_size); #elif defined (tc_cfi_emit_pcrel_expr) tc_cfi_emit_pcrel_expr (&exp, augmentation_size); #else abort (); #endif } else emit_expr (&exp, augmentation_size); } for (; first; first = first->next) if (CUR_SEG (first) == CUR_SEG (fde)) output_cfi_insn (first); frag_align (align, DW_CFA_nop, 0); symbol_set_value_now (end_address); }
static void 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 (); end_address = symbol_temp_make (); exp.X_op = O_subtract; exp.X_add_symbol = end_address; exp.X_op_symbol = after_size_address; exp.X_add_number = 0; 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); 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. */ 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. */ if (DW_CIE_VERSION == 1) /* Return column. */ out_one (cie->return_column); else out_uleb128 (cie->return_column); 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); out_one (cie->per_encoding); exp = cie->personality; if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel) { #if CFI_DIFF_EXPR_OK exp.X_op = O_subtract; exp.X_op_symbol = symbol_temp_new_now (); emit_expr (&exp, size); #elif defined (tc_cfi_emit_pcrel_expr) tc_cfi_emit_pcrel_expr (&exp, size); #else abort (); #endif } else emit_expr (&exp, size); } if (cie->lsda_encoding != DW_EH_PE_omit) out_one (cie->lsda_encoding); } switch (DWARF2_FDE_RELOC_SIZE) { case 2: enc = DW_EH_PE_sdata2; break; case 4: enc = DW_EH_PE_sdata4; break; case 8: enc = DW_EH_PE_sdata8; break; default: abort (); } #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr enc |= DW_EH_PE_pcrel; #endif if (eh_frame) out_one (enc); if (cie->first) { for (i = cie->first; i != cie->last; i = i->next) { if (CUR_SEG (i) != CUR_SEG (cie)) continue; output_cfi_insn (i); } } frag_align (align, DW_CFA_nop, 0); symbol_set_value_now (end_address); }
static void output_cfi_insn (struct cfi_insn_data *insn) { offsetT offset; unsigned int regno; switch (insn->insn) { case DW_CFA_advance_loc: { symbolS *from = insn->u.ll.lab1; symbolS *to = insn->u.ll.lab2; if (symbol_get_frag (to) == symbol_get_frag (from)) { addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; if (scaled <= 0x3F) out_one (DW_CFA_advance_loc + scaled); else if (scaled <= 0xFF) { out_one (DW_CFA_advance_loc1); out_one (scaled); } else if (scaled <= 0xFFFF) { out_one (DW_CFA_advance_loc2); out_two (scaled); } else { out_one (DW_CFA_advance_loc4); out_four (scaled); } } else { expressionS exp; exp.X_op = O_subtract; exp.X_add_symbol = to; exp.X_op_symbol = from; exp.X_add_number = 0; /* 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. */ *frag_more (1) = DW_CFA_advance_loc4; frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3, make_expr_symbol (&exp), frag_now_fix () - 1, (char *) frag_now); } } break; case DW_CFA_def_cfa: offset = insn->u.ri.offset; if (offset < 0) { out_one (DW_CFA_def_cfa_sf); out_uleb128 (insn->u.ri.reg); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa); out_uleb128 (insn->u.ri.reg); out_uleb128 (offset); } break; case DW_CFA_def_cfa_register: case DW_CFA_undefined: case DW_CFA_same_value: out_one (insn->insn); out_uleb128 (insn->u.r); break; case DW_CFA_def_cfa_offset: offset = insn->u.i; if (offset < 0) { out_one (DW_CFA_def_cfa_offset_sf); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa_offset); out_uleb128 (offset); } break; case DW_CFA_restore: regno = insn->u.r; if (regno <= 0x3F) { out_one (DW_CFA_restore + regno); } else { out_one (DW_CFA_restore_extended); out_uleb128 (regno); } break; case DW_CFA_offset: regno = insn->u.ri.reg; offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; if (offset < 0) { out_one (DW_CFA_offset_extended_sf); out_uleb128 (regno); out_sleb128 (offset); } else if (regno <= 0x3F) { out_one (DW_CFA_offset + regno); out_uleb128 (offset); } else { out_one (DW_CFA_offset_extended); out_uleb128 (regno); out_uleb128 (offset); } break; case DW_CFA_register: out_one (DW_CFA_register); out_uleb128 (insn->u.rr.reg1); out_uleb128 (insn->u.rr.reg2); break; case DW_CFA_remember_state: case DW_CFA_restore_state: out_one (insn->insn); break; case DW_CFA_GNU_window_save: out_one (DW_CFA_GNU_window_save); break; case CFI_escape: { struct cfi_escape_data *e; for (e = insn->u.esc; e ; e = e->next) emit_expr (&e->exp, 1); break; } case CFI_val_encoded_addr: { unsigned encoding = insn->u.ea.encoding; offsetT encoding_size; if (encoding == DW_EH_PE_omit) break; out_one (DW_CFA_val_expression); out_uleb128 (insn->u.ea.reg); switch (encoding & 0x7) { case DW_EH_PE_absptr: encoding_size = DWARF2_ADDR_SIZE (stdoutput); break; case DW_EH_PE_udata2: encoding_size = 2; break; case DW_EH_PE_udata4: encoding_size = 4; break; case DW_EH_PE_udata8: encoding_size = 8; break; default: abort (); } /* If the user has requested absolute encoding, then use the smaller DW_OP_addr encoding. */ if (insn->u.ea.encoding == DW_EH_PE_absptr) { out_uleb128 (1 + encoding_size); out_one (DW_OP_addr); } else { out_uleb128 (1 + 1 + encoding_size); out_one (DW_OP_GNU_encoded_addr); out_one (encoding); if ((encoding & 0x70) == DW_EH_PE_pcrel) { #if CFI_DIFF_EXPR_OK insn->u.ea.exp.X_op = O_subtract; insn->u.ea.exp.X_op_symbol = symbol_temp_new_now (); #elif defined (tc_cfi_emit_pcrel_expr) tc_cfi_emit_pcrel_expr (&insn->u.ea.exp, encoding_size); break; #else abort (); #endif } } emit_expr (&insn->u.ea.exp, encoding_size); } break; default: abort (); } }
static void output_fde (struct fde_entry *fde, struct cie_entry *cie, struct cfi_insn_data *first, int align) { symbolS *after_size_address, *end_address; expressionS exp; offsetT augmentation_size; after_size_address = symbol_temp_make (); end_address = symbol_temp_make (); exp.X_op = O_subtract; exp.X_add_symbol = end_address; exp.X_op_symbol = after_size_address; exp.X_add_number = 0; emit_expr (&exp, 4); /* 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. */ #ifdef DIFF_EXPR_OK exp.X_add_symbol = fde->start_address; exp.X_op_symbol = symbol_temp_new_now (); emit_expr (&exp, 4); /* Code offset. */ #else 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, 4); /* Code offset. */ #else emit_expr (&exp, 4); /* Code offset. */ #endif exp.X_op = O_subtract; #endif exp.X_add_symbol = fde->end_address; exp.X_op_symbol = fde->start_address; /* Code length. */ emit_expr (&exp, 4); augmentation_size = encoding_size (fde->lsda_encoding); out_uleb128 (augmentation_size); /* Augmentation size. */ if (fde->lsda_encoding != DW_EH_PE_omit) { exp = fde->lsda; if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel) { #ifdef DIFF_EXPR_OK exp.X_op = O_subtract; exp.X_op_symbol = symbol_temp_new_now (); emit_expr (&exp, augmentation_size); #elif defined (tc_cfi_emit_pcrel_expr) tc_cfi_emit_pcrel_expr (&exp, augmentation_size); #else abort (); #endif } else emit_expr (&exp, augmentation_size); } for (; first; first = first->next) output_cfi_insn (first); frag_align (align, DW_CFA_nop, 0); symbol_set_value_now (end_address); }
static void output_cfi_insn (struct cfi_insn_data *insn) { offsetT offset; unsigned int regno; switch (insn->insn) { case DW_CFA_advance_loc: { symbolS *from = insn->u.ll.lab1; symbolS *to = insn->u.ll.lab2; if (symbol_get_frag (to) == symbol_get_frag (from)) { addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; if (scaled <= 0x3F) out_one (DW_CFA_advance_loc + scaled); else if (delta <= 0xFF) { out_one (DW_CFA_advance_loc1); out_one (delta); } else if (delta <= 0xFFFF) { out_one (DW_CFA_advance_loc2); out_two (delta); } else { out_one (DW_CFA_advance_loc4); out_four (delta); } } else { expressionS exp; exp.X_op = O_subtract; exp.X_add_symbol = to; exp.X_op_symbol = from; exp.X_add_number = 0; /* 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. */ frag_more (1); frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3, make_expr_symbol (&exp), frag_now_fix () - 1, (char *) frag_now); } } break; case DW_CFA_def_cfa: offset = insn->u.ri.offset; if (offset < 0) { out_one (DW_CFA_def_cfa_sf); out_uleb128 (insn->u.ri.reg); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa); out_uleb128 (insn->u.ri.reg); out_uleb128 (offset); } break; case DW_CFA_def_cfa_register: case DW_CFA_undefined: case DW_CFA_same_value: out_one (insn->insn); out_uleb128 (insn->u.r); break; case DW_CFA_def_cfa_offset: offset = insn->u.i; if (offset < 0) { out_one (DW_CFA_def_cfa_offset_sf); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa_offset); out_uleb128 (offset); } break; case DW_CFA_restore: regno = insn->u.r; if (regno <= 0x3F) { out_one (DW_CFA_restore + regno); } else { out_one (DW_CFA_restore_extended); out_uleb128 (regno); } break; case DW_CFA_offset: regno = insn->u.ri.reg; offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; if (offset < 0) { out_one (DW_CFA_offset_extended_sf); out_uleb128 (regno); out_sleb128 (offset); } else if (regno <= 0x3F) { out_one (DW_CFA_offset + regno); out_uleb128 (offset); } else { out_one (DW_CFA_offset_extended); out_uleb128 (regno); out_uleb128 (offset); } break; case DW_CFA_register: out_one (DW_CFA_register); out_uleb128 (insn->u.rr.reg1); out_uleb128 (insn->u.rr.reg2); break; case DW_CFA_remember_state: case DW_CFA_restore_state: out_one (insn->insn); break; case DW_CFA_GNU_window_save: out_one (DW_CFA_GNU_window_save); break; case CFI_escape: { struct cfi_escape_data *e; for (e = insn->u.esc; e ; e = e->next) emit_expr (&e->exp, 1); break; } default: abort (); } }
static void process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; unsigned column = 0; unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_BEGIN_STMT : 0; fragS *frag = NULL; fragS *last_frag; addressT frag_ofs = 0; addressT last_frag_ofs; struct line_entry *next; while (e) { int changed = 0; if (filenum != e->loc.filenum) { filenum = e->loc.filenum; out_opcode (DW_LNS_set_file); out_uleb128 (filenum); changed = 1; } if (column != e->loc.column) { column = e->loc.column; out_opcode (DW_LNS_set_column); out_uleb128 (column); changed = 1; } if ((e->loc.flags ^ flags) & DWARF2_FLAG_BEGIN_STMT) { flags = e->loc.flags; out_opcode (DW_LNS_negate_stmt); changed = 1; } if (e->loc.flags & DWARF2_FLAG_BEGIN_BLOCK) { out_opcode (DW_LNS_set_basic_block); changed = 1; } /* Don't try to optimize away redundant entries; gdb wants two entries for a function where the code starts on the same line as the {, and there's no way to identify that case here. Trust gcc to optimize appropriately. */ if (1 /* line != e->loc.line || changed */) { int line_delta = e->loc.line - line; if (frag == NULL) { out_set_addr (seg, e->frag, e->frag_ofs); out_inc_line_addr (line_delta, 0); } else if (frag == e->frag) out_inc_line_addr (line_delta, e->frag_ofs - frag_ofs); else relax_inc_line_addr (line_delta, seg, e->frag, e->frag_ofs, frag, frag_ofs); frag = e->frag; frag_ofs = e->frag_ofs; line = e->loc.line; } else if (frag == NULL) { out_set_addr (seg, e->frag, e->frag_ofs); frag = e->frag; frag_ofs = e->frag_ofs; } next = e->next; free (e); e = next; } /* Emit a DW_LNE_end_sequence for the end of the section. */ last_frag = last_frag_for_seg (seg); last_frag_ofs = get_frag_fix (last_frag); if (frag == last_frag) out_inc_line_addr (INT_MAX, last_frag_ofs - frag_ofs); else relax_inc_line_addr (INT_MAX, seg, last_frag, last_frag_ofs, frag, frag_ofs); }