#define DWARF2_FILE_SIZE_NAME(FILENAME,DIRNAME) 0
#endif
+#ifndef DWARF2_VERSION
+#define DWARF2_VERSION 2
+#endif
+
+/* The .debug_aranges version has been 2 in DWARF version 2, 3 and 4. */
+#ifndef DWARF2_ARANGES_VERSION
+#define DWARF2_ARANGES_VERSION 2
+#endif
+
+/* This implementation output version 2 .debug_line information. */
+#ifndef DWARF2_LINE_VERSION
+#define DWARF2_LINE_VERSION 2
+#endif
+
#include "subsegs.h"
#include "dwarf2.h"
opcodes and variable-length operands cannot be used. If this macro is
nonzero, use the DW_LNS_fixed_advance_pc opcode instead. */
#ifndef DWARF2_USE_FIXED_ADVANCE_PC
-# define DWARF2_USE_FIXED_ADVANCE_PC 0
+# define DWARF2_USE_FIXED_ADVANCE_PC linkrelax
#endif
/* First special line opcde - leave room for the standard opcodes.
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;
\f
return lss;
}
-/* Record an entry for LOC occurring at LABEL. */
+/* Push LOC onto the pending lines list. */
static void
-dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
+dwarf2_push_line (struct dwarf2_line_info *loc)
{
- struct line_subseg *lss;
struct line_entry *e;
e = (struct line_entry *) xmalloc (sizeof (*e));
e->next = NULL;
- e->label = label;
+ e->label = NULL;
e->loc = *loc;
- lss = get_line_subseg (now_seg, now_subseg);
- *lss->ptail = e;
- lss->ptail = &e->next;
+ *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;
+ }
}
/* Record an entry for LOC occurring at OFS within the current fragment. */
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;
line = loc->line;
filenum = loc->filenum;
- sym = symbol_temp_new (now_seg, ofs, frag_now);
- dwarf2_gen_line_info_1 (sym, loc);
+ dwarf2_push_line (loc);
+ if (linkrelax)
+ {
+ char name[120];
+
+ /* 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));
+ }
+ else
+ dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now));
}
/* Returns the current source information. If .file directives have
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;
loc.flags |= DWARF2_FLAG_BASIC_BLOCK;
- dwarf2_gen_line_info_1 (label, &loc);
+ dwarf2_push_line (&loc);
+ dwarf2_flush_pending_lines (label);
dwarf2_consume_line_info ();
}
/* If we see two .loc directives in a row, force the first one to be
output now. */
if (dwarf2_loc_directive_seen)
- dwarf2_emit_insn (0);
+ dwarf2_push_line (¤t);
filenum = get_absolute_expression ();
SKIP_WHITESPACE ();
emit_expr (&exp, sizeof_address);
}
-#if DWARF2_LINE_MIN_INSN_LENGTH > 1
static void scale_addr_delta (addressT *);
static void
scale_addr_delta (addressT *addr_delta)
{
static int printed_this = 0;
- if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0)
+ if (DWARF2_LINE_MIN_INSN_LENGTH > 1)
{
- if (!printed_this)
- as_bad("unaligned opcodes detected in executable segment");
- printed_this = 1;
+ if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0 && !printed_this)
+ {
+ as_bad("unaligned opcodes detected in executable segment");
+ printed_this = 1;
+ }
+ *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
}
- *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
}
-#else
-#define scale_addr_delta(A)
-#endif
/* Encode a pair of line and address skips as efficiently as possible.
Note that the line skip is signed, whereas the address skip is unsigned.
line and address information, but it is required if linker relaxation
could change the code offsets. The following two routines *must* be
kept in sync. */
+#define ADDR_DELTA_LIMIT 50000
static int
size_fixed_inc_line_addr (int line_delta, addressT addr_delta)
if (line_delta != INT_MAX)
len = 1 + sizeof_leb128 (line_delta, 1);
- if (addr_delta > 50000)
+ if (addr_delta > ADDR_DELTA_LIMIT)
{
/* DW_LNS_extended_op */
len += 1 + sizeof_leb128 (sizeof_address + 1, 0);
which this function would not be used) could change the operand by
an unknown amount. If the address increment is getting close to
the limit, just reset the address. */
- if (addr_delta > 50000)
+ if (addr_delta > ADDR_DELTA_LIMIT)
{
symbolS *to_sym;
expressionS exp;
{
offsetT addr_diff;
- addr_diff = resolve_symbol_value (frag->fr_symbol);
+ if (DWARF2_USE_FIXED_ADVANCE_PC)
+ {
+ /* If linker relaxation is enabled then the distance bewteen the two
+ symbols in the frag->fr_symbol expression might change. Hence we
+ cannot rely upon the value computed by resolve_symbol_value.
+ Instead we leave the expression unfinalized and allow
+ emit_fixed_inc_line_addr to create a fixup (which later becomes a
+ relocation) that will allow the linker to correctly compute the
+ actual address difference. We have to use a fixed line advance for
+ this as we cannot (easily) relocate leb128 encoded values. */
+ int saved_finalize_syms = finalize_syms;
+
+ finalize_syms = 0;
+ addr_diff = resolve_symbol_value (frag->fr_symbol);
+ finalize_syms = saved_finalize_syms;
+ }
+ else
+ addr_diff = resolve_symbol_value (frag->fr_symbol);
/* fr_var carries the max_chars that we created the fragment with.
fr_subtype carries the current expected length. We must, of
size = strlen (dir) + 1;
cp = frag_more (size);
memcpy (cp, dir, size);
- xfree ((char *) dir);
}
/* Terminate it. */
out_byte ('\0');
line_end = exp.X_add_symbol;
/* Version. */
- out_two (2);
+ out_two (DWARF2_LINE_VERSION);
/* Length of the prologue following this length. */
prologue_end = symbol_temp_make ();
/* For each section, emit a statement program. */
for (s = all_segs; s; s = s->next)
- process_entries (s->seg, s->head->head);
+ 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);
}
aranges_end = exp.X_add_symbol;
/* Version. */
- out_two (2);
+ out_two (DWARF2_ARANGES_VERSION);
/* Offset to .debug_info. */
TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), sizeof_offset);
if (all_segs->next == NULL)
{
out_abbrev (DW_AT_low_pc, DW_FORM_addr);
- out_abbrev (DW_AT_high_pc, DW_FORM_addr);
+ if (DWARF2_VERSION < 4)
+ out_abbrev (DW_AT_high_pc, DW_FORM_addr);
+ else
+ out_abbrev (DW_AT_high_pc, (sizeof_address == 4
+ ? DW_FORM_data4 : DW_FORM_data8));
}
else
{
info_end = exp.X_add_symbol;
/* DWARF version. */
- out_two (2);
+ out_two (DWARF2_VERSION);
/* .debug_abbrev offset */
TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
emit_expr (&exp, sizeof_address);
/* DW_AT_high_pc */
- exp.X_op = O_symbol;
+ if (DWARF2_VERSION < 4)
+ exp.X_op = O_symbol;
+ else
+ {
+ exp.X_op = O_subtract;
+ exp.X_op_symbol = all_segs->text_start;
+ }
exp.X_add_symbol = all_segs->text_end;
exp.X_add_number = 0;
emit_expr (&exp, sizeof_address);
memcpy (p, dirname, len);
INSERT_DIR_SEPARATOR (p, len);
#endif
- xfree ((char *) dirname);
}
len = strlen (files[1].filename) + 1;
p = frag_more (len);
len = strlen (comp_dir) + 1;
p = frag_more (len);
memcpy (p, comp_dir, len);
- xfree ((char *) comp_dir);
/* DW_AT_producer */
sprintf (producer, "GNU AS %s", VERSION);