X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fdwarf2dbg.c;h=27b264634bcee2353eb347855c275db562c98da0;hb=15afaa63f39a44563e49bb3b9fb38ed43e8b48ed;hp=76b5fe0fe7ba04dda65d894b492fc4a44d23b5a8;hpb=5bb3703f01dd574faebbd3a69f4c64dbfee6a701;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index 76b5fe0fe7..27b264634b 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -1,6 +1,5 @@ /* dwarf2dbg.c - DWARF2 debug support - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 1999-2016 Free Software Foundation, Inc. Contributed by David Mosberger-Tang This file is part of GAS, the GNU Assembler. @@ -159,6 +158,10 @@ /* The maximum address skip amount that can be encoded with a special op. */ #define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) +#ifndef TC_PARSE_CONS_RETURN_NONE +#define TC_PARSE_CONS_RETURN_NONE BFD_RELOC_NONE +#endif + struct line_entry { struct line_entry *next; symbolS *label; @@ -170,6 +173,7 @@ struct line_subseg { subsegT subseg; struct line_entry *head; struct line_entry **ptail; + struct line_entry **pmove_tail; }; struct line_seg { @@ -182,9 +186,6 @@ struct line_seg { /* Collects data for all line table entries during assembly. */ static struct line_seg *all_segs; -/* Hash used to quickly lookup a segment by name, avoiding the need to search - through the all_segs list. */ -static struct hash_control *all_segs_hash; static struct line_seg **last_seg_ptr; struct file_entry { @@ -217,10 +218,6 @@ static struct dwarf2_line_info current = { 0 }; -/* Lines that are at the same location as CURRENT, and which are waiting - for a label. */ -static struct line_entry *pending_lines, **pending_lines_tail = &pending_lines; - /* The size of an address on the target. */ static unsigned int sizeof_address; @@ -243,31 +240,26 @@ generic_dwarf2_emit_offset (symbolS *symbol, unsigned int size) } #endif -/* Find or create an entry for SEG+SUBSEG in ALL_SEGS. */ +/* Find or create (if CREATE_P) an entry for SEG+SUBSEG in ALL_SEGS. */ static struct line_subseg * -get_line_subseg (segT seg, subsegT subseg) +get_line_subseg (segT seg, subsegT subseg, bfd_boolean create_p) { - static segT last_seg; - static subsegT last_subseg; - static struct line_subseg *last_line_subseg; - - struct line_seg *s; + struct line_seg *s = seg_info (seg)->dwarf2_line_seg; struct line_subseg **pss, *lss; - if (seg == last_seg && subseg == last_subseg) - return last_line_subseg; - - s = (struct line_seg *) hash_find (all_segs_hash, seg->name); if (s == NULL) { - s = (struct line_seg *) xmalloc (sizeof (*s)); + if (!create_p) + return NULL; + + s = XNEW (struct line_seg); s->next = NULL; s->seg = seg; s->head = NULL; *last_seg_ptr = s; last_seg_ptr = &s->next; - hash_insert (all_segs_hash, seg->name, s); + seg_info (seg)->dwarf2_line_seg = s; } gas_assert (seg == s->seg); @@ -279,62 +271,34 @@ get_line_subseg (segT seg, subsegT subseg) break; } - lss = (struct line_subseg *) xmalloc (sizeof (*lss)); + lss = XNEW (struct line_subseg); lss->next = *pss; lss->subseg = subseg; lss->head = NULL; lss->ptail = &lss->head; + lss->pmove_tail = &lss->head; *pss = lss; found_subseg: - last_seg = seg; - last_subseg = subseg; - last_line_subseg = lss; - return lss; } -/* Push LOC onto the pending lines list. */ +/* Record an entry for LOC occurring at LABEL. */ static void -dwarf2_push_line (struct dwarf2_line_info *loc) +dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc) { + struct line_subseg *lss; struct line_entry *e; - e = (struct line_entry *) xmalloc (sizeof (*e)); + e = XNEW (struct line_entry); e->next = NULL; - e->label = NULL; + e->label = label; e->loc = *loc; - *pending_lines_tail = e; - pending_lines_tail = &(*pending_lines_tail)->next; -} - -/* Emit all pending line information. LABEL is the label with which the - lines should be associated, or null if they should be associated with - the current position. */ - -static void -dwarf2_flush_pending_lines (symbolS *label) -{ - if (pending_lines) - { - struct line_subseg *lss; - struct line_entry *e; - - if (!label) - label = symbol_temp_new_now (); - - for (e = pending_lines; e; e = e->next) - e->label = label; - - lss = get_line_subseg (now_seg, now_subseg); - *lss->ptail = pending_lines; - lss->ptail = pending_lines_tail; - - pending_lines = NULL; - pending_lines_tail = &pending_lines; - } + lss = get_line_subseg (now_seg, now_subseg, TRUE); + *lss->ptail = e; + lss->ptail = &e->next; } /* Record an entry for LOC occurring at OFS within the current fragment. */ @@ -345,6 +309,8 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) static unsigned int line = -1; static unsigned int filenum = -1; + symbolS *sym; + /* Early out for as-yet incomplete location information. */ if (loc->filenum == 0 || loc->line == 0) return; @@ -360,7 +326,6 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) line = loc->line; filenum = loc->filenum; - dwarf2_push_line (loc); if (linkrelax) { char name[120]; @@ -368,10 +333,11 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) /* Use a non-fake name for the line number location, so that it can be referred to by relocations. */ sprintf (name, ".Loc.%u.%u", line, filenum); - dwarf2_flush_pending_lines (symbol_new (name, now_seg, ofs, frag_now)); + sym = symbol_new (name, now_seg, ofs, frag_now); } else - dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now)); + sym = symbol_temp_new (now_seg, ofs, frag_now); + dwarf2_gen_line_info_1 (sym, loc); } /* Returns the current source information. If .file directives have @@ -384,8 +350,7 @@ dwarf2_where (struct dwarf2_line_info *line) { if (debug_type == DEBUG_DWARF2) { - char *filename; - as_where (&filename, &line->line); + const char *filename = as_where (&line->line); line->filenum = get_filenum (filename, 0); line->column = 0; line->flags = DWARF2_FLAG_IS_STMT; @@ -424,6 +389,33 @@ dwarf2_emit_insn (int size) dwarf2_consume_line_info (); } +/* Move all previously-emitted line entries for the current position by + DELTA bytes. This function cannot be used to move the same entries + twice. */ + +void +dwarf2_move_insn (int delta) +{ + struct line_subseg *lss; + struct line_entry *e; + valueT now; + + if (delta == 0) + return; + + lss = get_line_subseg (now_seg, now_subseg, FALSE); + if (!lss) + return; + + now = frag_now_fix (); + while ((e = *lss->pmove_tail)) + { + if (S_GET_VALUE (e->label) == now) + S_SET_VALUE (e->label, now + delta); + lss->pmove_tail = &e->next; + } +} + /* Called after the current line information has been either used with dwarf2_gen_line_info or saved with a machine instruction for later use. This resets the state of the line number information to reflect that @@ -432,11 +424,6 @@ dwarf2_emit_insn (int size) void dwarf2_consume_line_info (void) { - /* If the consumer has stashed the current location away for later use, - assume that any earlier location information should be associated - with ".". */ - dwarf2_flush_pending_lines (NULL); - /* Unless we generate DWARF2 debugging information for each assembler line, we only emit one line symbol for one LOC. */ dwarf2_loc_directive_seen = FALSE; @@ -468,8 +455,7 @@ dwarf2_emit_label (symbolS *label) loc.flags |= DWARF2_FLAG_BASIC_BLOCK; - dwarf2_push_line (&loc); - dwarf2_flush_pending_lines (label); + dwarf2_gen_line_info_1 (label, &loc); dwarf2_consume_line_info (); } @@ -526,8 +512,7 @@ get_filenum (const char *filename, unsigned int num) if (dir >= dirs_allocated) { dirs_allocated = dir + 32; - dirs = (char **) - xrealloc (dirs, (dir + 32) * sizeof (const char *)); + dirs = XRESIZEVEC (char *, dirs, dirs_allocated); } dirs[dir] = (char *) xmalloc (dir_len + 1); @@ -557,8 +542,7 @@ get_filenum (const char *filename, unsigned int num) unsigned int old = files_allocated; files_allocated = i + 32; - files = (struct file_entry *) - xrealloc (files, (i + 32) * sizeof (struct file_entry)); + files = XRESIZEVEC (struct file_entry, files, files_allocated); memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry)); } @@ -629,7 +613,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) /* If we see two .loc directives in a row, force the first one to be output now. */ if (dwarf2_loc_directive_seen) - dwarf2_push_line (¤t); + dwarf2_emit_insn (0); filenum = get_absolute_expression (); SKIP_WHITESPACE (); @@ -657,13 +641,14 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) { size_t dir_len = strlen (dirs[files[filenum].dir]); size_t file_len = strlen (files[filenum].filename); - char *cp = (char *) alloca (dir_len + 1 + file_len + 1); + char *cp = (char *) xmalloc (dir_len + 1 + file_len + 1); memcpy (cp, dirs[files[filenum].dir], dir_len); INSERT_DIR_SEPARATOR (cp, dir_len); memcpy (cp + dir_len + 1, files[filenum].filename, file_len); cp[dir_len + file_len + 1] = '\0'; listing_source_file (cp); + free (cp); } else listing_source_file (files[filenum].filename); @@ -683,8 +668,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) char *p, c; offsetT value; - p = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& p); if (strcmp (p, "basic_block") == 0) { @@ -703,7 +687,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) } else if (strcmp (p, "is_stmt") == 0) { - *input_line_pointer = c; + (void) restore_line_pointer (c); value = get_absolute_expression (); if (value == 0) current.flags &= ~DWARF2_FLAG_IS_STMT; @@ -717,7 +701,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) } else if (strcmp (p, "isa") == 0) { - *input_line_pointer = c; + (void) restore_line_pointer (c); value = get_absolute_expression (); if (value >= 0) current.isa = value; @@ -729,7 +713,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) } else if (strcmp (p, "discriminator") == 0) { - *input_line_pointer = c; + (void) restore_line_pointer (c); value = get_absolute_expression (); if (value >= 0) current.discriminator = value; @@ -742,11 +726,11 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) else { as_bad (_("unknown .loc sub-directive `%s'"), p); - *input_line_pointer = c; + (void) restore_line_pointer (c); return; } - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); } demand_empty_rest_of_line (); @@ -1109,13 +1093,15 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag, char *p, int len) { expressionS *pexp; - segT line_seg; char *end = p + len; /* Line number sequences cannot go backward in addresses. This means we've incorrectly ordered the statements in the sequence. */ gas_assert ((offsetT) addr_delta >= 0); + /* Verify that we have kept in sync with size_fixed_inc_line_addr. */ + gas_assert (len == size_fixed_inc_line_addr (line_delta, addr_delta)); + /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. */ if (line_delta != INT_MAX) { @@ -1124,7 +1110,6 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag, } pexp = symbol_get_value_expression (frag->fr_symbol); - line_seg = subseg_get (".debug_line", 0); /* The DW_LNS_fixed_advance_pc opcode has a 2-byte operand so it can advance the address by at most 64K. Linker relaxation (without @@ -1145,15 +1130,13 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag, exp.X_op = O_symbol; exp.X_add_symbol = to_sym; exp.X_add_number = 0; - subseg_change (line_seg, 0); - emit_expr_fix (&exp, sizeof_address, frag, p); + emit_expr_fix (&exp, sizeof_address, frag, p, TC_PARSE_CONS_RETURN_NONE); p += sizeof_address; } else { *p++ = DW_LNS_fixed_advance_pc; - subseg_change (line_seg, 0); - emit_expr_fix (pexp, 2, frag, p); + emit_expr_fix (pexp, 2, frag, p, TC_PARSE_CONS_RETURN_NONE); p += 2; } @@ -1294,6 +1277,40 @@ process_entries (segT seg, struct line_entry *e) symbolS *last_lab = NULL, *lab; struct line_entry *next; + if (flag_dwarf_sections) + { + char * name; + const char * sec_name; + + /* Switch to the relevent sub-section before we start to emit + the line number table. + + FIXME: These sub-sections do not have a normal Line Number + Program Header, thus strictly speaking they are not valid + DWARF sections. Unfortunately the DWARF standard assumes + a one-to-one relationship between compilation units and + line number tables. Thus we have to have a .debug_line + section, as well as our sub-sections, and we have to ensure + that all of the sub-sections are merged into a proper + .debug_line section before a debugger sees them. */ + + sec_name = bfd_get_section_name (stdoutput, seg); + if (strcmp (sec_name, ".text") != 0) + { + unsigned int len; + + len = strlen (sec_name); + name = xmalloc (len + 11 + 2); + sprintf (name, ".debug_line%s", sec_name); + subseg_set (subseg_get (name, FALSE), 0); + } + else + /* Don't create a .debug_line.text section - + that is redundant. Instead just switch back to the + normal .debug_line section. */ + subseg_set (subseg_get (".debug_line", FALSE), 0); + } + do { int line_delta; @@ -1438,7 +1455,8 @@ out_file_list (void) /* Switch to SEC and output a header length field. Return the size of offsets used in SEC. The caller must set EXPR->X_add_symbol value - to the end of the section. */ + to the end of the section. EXPR->X_add_number will be set to the + negative size of the header. */ static int out_header (asection *sec, expressionS *exp) @@ -1447,8 +1465,21 @@ out_header (asection *sec, expressionS *exp) symbolS *end_sym; subseg_set (sec, 0); - start_sym = symbol_temp_new_now (); - end_sym = symbol_temp_make (); + + if (flag_dwarf_sections) + { + /* If we are going to put the start and end symbols in different + sections, then we need real symbols, not just fake, local ones. */ + frag_now_fix (); + start_sym = symbol_make (".Ldebug_line_start"); + end_sym = symbol_make (".Ldebug_line_end"); + symbol_set_value_now (start_sym); + } + else + { + start_sym = symbol_temp_new_now (); + end_sym = symbol_temp_make (); + } /* Total length of the information. */ exp->X_op = O_subtract; @@ -1484,7 +1515,7 @@ static void out_debug_line (segT line_seg) { expressionS exp; - symbolS *prologue_end; + symbolS *prologue_start, *prologue_end; symbolS *line_end; struct line_seg *s; int sizeof_offset; @@ -1496,10 +1527,14 @@ out_debug_line (segT line_seg) out_two (DWARF2_LINE_VERSION); /* Length of the prologue following this length. */ + prologue_start = symbol_temp_make (); prologue_end = symbol_temp_make (); + exp.X_op = O_subtract; exp.X_add_symbol = prologue_end; - exp.X_add_number = - (4 + 2 + 4); + exp.X_op_symbol = prologue_start; + exp.X_add_number = 0; emit_expr (&exp, sizeof_offset); + symbol_set_value_now (prologue_start); /* Parameters of the state machine. */ out_byte (DWARF2_LINE_MIN_INSN_LENGTH); @@ -1534,6 +1569,16 @@ out_debug_line (segT line_seg) as_warn ("dwarf line number information for %s ignored", segment_name (s->seg)); + if (flag_dwarf_sections) + /* We have to switch to the special .debug_line_end section + before emitting the end-of-debug_line symbol. The linker + script arranges for this section to be placed after all the + (potentially garbage collected) .debug_line. sections. + This section contains the line_end symbol which is used to + compute the size of the linked .debug_line section, as seen + in the DWARF Line Number header. */ + subseg_set (subseg_get (".debug_line_end", FALSE), 0); + symbol_set_value_now (line_end); } @@ -1591,6 +1636,7 @@ static void out_debug_aranges (segT aranges_seg, segT info_seg) { unsigned int addr_size = sizeof_address; + offsetT size; struct line_seg *s; expressionS exp; symbolS *aranges_end; @@ -1599,21 +1645,27 @@ out_debug_aranges (segT aranges_seg, segT info_seg) sizeof_offset = out_header (aranges_seg, &exp); aranges_end = exp.X_add_symbol; + size = -exp.X_add_number; /* Version. */ out_two (DWARF2_ARANGES_VERSION); + size += 2; /* Offset to .debug_info. */ TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), sizeof_offset); + size += sizeof_offset; /* Size of an address (offset portion). */ out_byte (addr_size); + size++; /* Size of a segment descriptor. */ out_byte (0); + size++; /* Align the header. */ - frag_align (ffs (2 * addr_size) - 1, 0, 0); + while ((size++ % (2 * addr_size)) > 0) + out_byte (0); for (s = all_segs; s; s = s->next) { @@ -1798,7 +1850,6 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg) void dwarf2_init (void) { - all_segs_hash = hash_new (); last_seg_ptr = &all_segs; }