static void out_debug_line (segT line_seg) { expressionS exp; symbolS *prologue_end; symbolS *line_end; struct line_seg *s; int sizeof_offset; sizeof_offset = out_header (line_seg, &exp); line_end = exp.X_add_symbol; /* Version. */ out_two (DWARF2_VERSION); /* Length of the prologue following this length. */ prologue_end = symbol_temp_make (); exp.X_add_symbol = prologue_end; exp.X_add_number = - (4 + 2 + 4); emit_expr (&exp, sizeof_offset); /* Parameters of the state machine. */ out_byte (DWARF2_LINE_MIN_INSN_LENGTH); out_byte (DWARF2_LINE_DEFAULT_IS_STMT); out_byte (DWARF2_LINE_BASE); out_byte (DWARF2_LINE_RANGE); out_byte (DWARF2_LINE_OPCODE_BASE); /* Standard opcode lengths. */ out_byte (0); /* DW_LNS_copy */ out_byte (1); /* DW_LNS_advance_pc */ out_byte (1); /* DW_LNS_advance_line */ out_byte (1); /* DW_LNS_set_file */ out_byte (1); /* DW_LNS_set_column */ out_byte (0); /* DW_LNS_negate_stmt */ out_byte (0); /* DW_LNS_set_basic_block */ out_byte (0); /* DW_LNS_const_add_pc */ out_byte (1); /* DW_LNS_fixed_advance_pc */ out_byte (0); /* DW_LNS_set_prologue_end */ out_byte (0); /* DW_LNS_set_epilogue_begin */ out_byte (1); /* DW_LNS_set_isa */ out_file_list (); symbol_set_value_now (prologue_end); /* For each section, emit a statement program. */ for (s = all_segs; s; s = s->next) if (SEG_NORMAL (s->seg)) process_entries (s->seg, s->head->head); else as_warn ("dwarf line number information for %s ignored", segment_name (s->seg)); symbol_set_value_now (line_end); }
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_debug_aranges (segT aranges_seg, segT info_seg) { unsigned int addr_size = sizeof_address; struct line_seg *s; expressionS exp; symbolS *aranges_end; char *p; int sizeof_offset; sizeof_offset = out_header (aranges_seg, &exp); aranges_end = exp.X_add_symbol; /* Version. */ out_two (DWARF2_VERSION); /* Offset to .debug_info. */ TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), sizeof_offset); /* Size of an address (offset portion). */ out_byte (addr_size); /* Size of a segment descriptor. */ out_byte (0); /* Align the header. */ frag_align (ffs (2 * addr_size) - 1, 0, 0); for (s = all_segs; s; s = s->next) { fragS *frag; symbolS *beg, *end; frag = first_frag_for_seg (s->seg); beg = symbol_temp_new (s->seg, 0, frag); s->text_start = beg; frag = last_frag_for_seg (s->seg); end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag); s->text_end = end; exp.X_op = O_symbol; exp.X_add_symbol = beg; exp.X_add_number = 0; emit_expr (&exp, addr_size); exp.X_op = O_subtract; exp.X_add_symbol = end; exp.X_op_symbol = beg; exp.X_add_number = 0; emit_expr (&exp, addr_size); } p = frag_more (2 * addr_size); md_number_to_chars (p, 0, addr_size); md_number_to_chars (p + addr_size, 0, addr_size); symbol_set_value_now (aranges_end); }
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 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 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 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 out_debug_line (segT line_seg) { expressionS expr; symbolS *line_start; symbolS *prologue_end; symbolS *line_end; struct line_seg *s; enum dwarf2_format d2f; int sizeof_offset; subseg_set (line_seg, 0); line_start = symbol_temp_new_now (); prologue_end = symbol_temp_make (); line_end = symbol_temp_make (); /* Total length of the information for this compilation unit. */ expr.X_op = O_subtract; expr.X_add_symbol = line_end; expr.X_op_symbol = line_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")); } /* Version. */ out_two (2); /* Length of the prologue following this length. */ expr.X_op = O_subtract; expr.X_add_symbol = prologue_end; expr.X_op_symbol = line_start; expr.X_add_number = - (4 + 2 + 4); emit_expr (&expr, sizeof_offset); /* Parameters of the state machine. */ out_byte (DWARF2_LINE_MIN_INSN_LENGTH); out_byte (DWARF2_LINE_DEFAULT_IS_STMT); out_byte (DWARF2_LINE_BASE); out_byte (DWARF2_LINE_RANGE); out_byte (DWARF2_LINE_OPCODE_BASE); /* Standard opcode lengths. */ out_byte (0); /* DW_LNS_copy */ out_byte (1); /* DW_LNS_advance_pc */ out_byte (1); /* DW_LNS_advance_line */ out_byte (1); /* DW_LNS_set_file */ out_byte (1); /* DW_LNS_set_column */ out_byte (0); /* DW_LNS_negate_stmt */ out_byte (0); /* DW_LNS_set_basic_block */ out_byte (0); /* DW_LNS_const_add_pc */ out_byte (1); /* DW_LNS_fixed_advance_pc */ out_file_list (); symbol_set_value_now (prologue_end); /* For each section, emit a statement program. */ for (s = all_segs; s; s = s->next) process_entries (s->seg, s->head->head); symbol_set_value_now (line_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); }