/* dwarf2dbg.c - DWARF2 debug support
- Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of GAS, the GNU Assembler.
#define DWARF2_ARANGES_VERSION 2
#endif
-/* This implementation output version 2 .debug_line information. */
+/* This implementation outputs version 3 .debug_line information. */
#ifndef DWARF2_LINE_VERSION
-#define DWARF2_LINE_VERSION 2
+#define DWARF2_LINE_VERSION 3
#endif
#include "subsegs.h"
{
expressionS exp;
+ memset (&exp, 0, sizeof exp);
exp.X_op = O_symbol;
exp.X_add_symbol = symbol;
exp.X_add_number = 0;
if (view_assert_failed)
{
expressionS chk;
+
memset (&chk, 0, sizeof (chk));
chk.X_unsigned = 1;
chk.X_op = O_add;
if (!S_IS_DEFINED (e->loc.view))
{
symbol_set_value_expression (e->loc.view, &viewx);
- S_SET_SEGMENT (e->loc.view, absolute_section);
+ S_SET_SEGMENT (e->loc.view, expr_section);
symbol_set_frag (e->loc.view, &zero_address_frag);
}
gas_assert (r == p);
/* Set or check views until we find a defined or absent view. */
do
- set_or_check_view (r, r->next, NULL);
+ {
+ /* Do not define the head of a (sub?)segment view while
+ handling others. It would be defined too early, without
+ regard to the last view of other subsegments.
+ set_or_check_view will be called for every head segment
+ that needs it. */
+ if (r == h)
+ break;
+ set_or_check_view (r, r->next, NULL);
+ }
while (r->next && r->next->loc.view && !S_IS_DEFINED (r->next->loc.view)
&& (r = r->next));
simplify the view expressions, until we do so to P. */
do
{
+ /* The head view of a subsegment may remain undefined while
+ handling other elements, before it is linked to the last
+ view of the previous subsegment. */
+ if (r == h)
+ continue;
gas_assert (S_IS_DEFINED (r->loc.view));
resolve_expression (symbol_get_value_expression (r->loc.view));
}
lss = get_line_subseg (now_seg, now_subseg, TRUE);
- if (loc->view)
+ /* Subseg heads are chained to previous subsegs in
+ dwarf2_finish. */
+ if (loc->view && lss->head)
set_or_check_view (e,
- !lss->head ? NULL : (struct line_entry *)lss->ptail,
+ (struct line_entry *)lss->ptail,
lss->head);
*lss->ptail = e;
dwarf2_where (&loc);
- dwarf2_gen_line_info (frag_now_fix () - size, &loc);
+ dwarf2_gen_line_info ((frag_now_fix_octets () - size) / OCTETS_PER_BYTE, &loc);
dwarf2_consume_line_info ();
}
| DWARF2_FLAG_PROLOGUE_END
| DWARF2_FLAG_EPILOGUE_BEGIN);
current.discriminator = 0;
+ current.view = NULL;
}
/* Called for each (preferably code) label. If dwarf2_loc_mark_labels
return;
if (S_GET_SEGMENT (label) != now_seg)
return;
- if (!(bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE))
+ if (!(bfd_section_flags (now_seg) & SEC_CODE))
return;
if (files_in_use == 0 && debug_type != DEBUG_DWARF2)
return;
unsigned int old = files_allocated;
files_allocated = i + 32;
- files = XRESIZEVEC (struct file_entry, files, files_allocated);
+ /* Catch wraparound. */
+ if (files_allocated <= old)
+ {
+ as_bad (_("file number %lu is too big"), (unsigned long) i);
+ return 0;
+ }
+ files = XRESIZEVEC (struct file_entry, files, files_allocated);
memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry));
}
- files[i].filename = num ? file : xstrdup (file);
+ files[i].filename = file;
files[i].dir = dir;
if (files_in_use < i + 1)
files_in_use = i + 1;
- Pass .file "source.c" to s_app_file
- Handle .file 1 "source.c" by adding an entry to the DWARF-2 file table
- If an entry is added to the file table, return a pointer to the filename. */
+ If an entry is added to the file table, return a pointer to the filename. */
char *
-dwarf2_directive_file (int dummy ATTRIBUTE_UNUSED)
+dwarf2_directive_filename (void)
{
- offsetT num;
+ valueT num;
char *filename;
int filename_len;
return NULL;
demand_empty_rest_of_line ();
- if (num < 1)
+ if ((offsetT) num < 1)
{
as_bad (_("file number less than one"));
return NULL;
being supplied. Turn off gas generated debug info. */
debug_type = DEBUG_NONE;
- if (num < (int) files_in_use && files[num].filename != 0)
+ if (num != (unsigned int) num
+ || num >= (size_t) -1 / sizeof (struct file_entry) - 32)
+ {
+ as_bad (_("file number %lu is too big"), (unsigned long) num);
+ return NULL;
+ }
+ if (num < files_in_use && files[num].filename != 0)
{
- as_bad (_("file number %ld already allocated"), (long) num);
+ as_bad (_("file number %u already allocated"), (unsigned int) num);
return NULL;
}
- get_filenum (filename, num);
+ get_filenum (filename, (unsigned int) num);
return filename;
}
+/* Calls dwarf2_directive_filename, but discards its result.
+ Used in pseudo-op tables where the function result is ignored. */
+
+void
+dwarf2_directive_file (int dummy ATTRIBUTE_UNUSED)
+{
+ (void) dwarf2_directive_filename ();
+}
+
void
dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
{
if (!name)
return;
sym = symbol_find_or_make (name);
- if (S_IS_DEFINED (sym))
+ if (S_IS_DEFINED (sym) || symbol_equated_p (sym))
{
- if (!S_CAN_BE_REDEFINED (sym))
- as_bad (_("symbol `%s' is already defined"), name);
- else
+ if (S_IS_VOLATILE (sym))
sym = symbol_clone (sym, 1);
- S_SET_SEGMENT (sym, undefined_section);
- S_SET_VALUE (sym, 0);
- symbol_set_frag (sym, &zero_address_frag);
+ else if (!S_CAN_BE_REDEFINED (sym))
+ {
+ as_bad (_("symbol `%s' is already defined"), name);
+ return;
+ }
}
+ S_SET_SEGMENT (sym, undefined_section);
+ S_SET_VALUE (sym, 0);
+ symbol_set_frag (sym, &zero_address_frag);
}
current.view = sym;
}
/* Set an absolute address (may result in a relocation entry). */
+static void
+out_inc_line_addr (int line_delta, addressT addr_delta);
+
static void
out_set_addr (symbolS *sym)
{
expressionS exp;
+ addressT expr_addr, expr_addr_aligned;
+
+ memset (&exp, 0, sizeof exp);
- out_opcode (DW_LNS_extended_op);
- out_uleb128 (sizeof_address + 1);
+ /* The expression at the bottom must be aligned to OCTETS_PER_BYTE. The
+ statements after the for loop will contribute 3 more octets. */
+ expr_addr = frag_now_fix_octets () + 3;
+ expr_addr_aligned = (expr_addr + OCTETS_PER_BYTE - 1) & -OCTETS_PER_BYTE;
+ for ( ; expr_addr != expr_addr_aligned; expr_addr++)
+ out_inc_line_addr (0, 0); /* NOP */
- out_opcode (DW_LNE_set_address);
+ out_opcode (DW_LNS_extended_op); /* 1 octet */
+ out_uleb128 (sizeof_address + 1); /* 1 octet */
+
+ out_opcode (DW_LNE_set_address); /* 1 octet */
exp.X_op = O_symbol;
exp.X_add_symbol = sym;
exp.X_add_number = 0;
if (DWARF2_LINE_MIN_INSN_LENGTH > 1)
{
if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0 && !printed_this)
- {
+ {
as_bad("unaligned opcodes detected in executable segment");
- printed_this = 1;
- }
+ printed_this = 1;
+ }
*addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
}
}
{
if (addr_delta == MAX_SPECIAL_ADDR_DELTA)
len = 1;
- else
+ else if (addr_delta)
len = 1 + sizeof_leb128 (addr_delta, 0);
return len + 3;
}
{
if (addr_delta == MAX_SPECIAL_ADDR_DELTA)
*p++ = DW_LNS_const_add_pc;
- else
+ else if (addr_delta)
{
*p++ = DW_LNS_advance_pc;
p += output_leb128 (p, addr_delta, 0);
symbolS *to_sym;
expressionS exp;
+ memset (&exp, 0, sizeof exp);
gas_assert (pexp->X_op == O_subtract);
to_sym = pexp->X_add_symbol;
expressionS exp;
int max_chars;
+ memset (&exp, 0, sizeof exp);
exp.X_op = O_subtract;
exp.X_add_symbol = to_sym;
exp.X_op_symbol = from_sym;
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);
+ sec_name = bfd_section_name (seg);
if (strcmp (sec_name, ".text") != 0)
{
name = concat (".debug_line", sec_name, (char *) NULL);
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] : ""));
+ 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] : ""));
+ files[i].dir ? dirs [files [i].dir] : ""));
}
/* Terminate filename list. */
}
else
{
- start_sym = symbol_temp_new_now ();
+ start_sym = symbol_temp_new_now_octets ();
end_sym = symbol_temp_make ();
}
symbolS *line_end;
struct line_seg *s;
int sizeof_offset;
+ addressT section_end, section_end_aligned;
+ memset (&exp, 0, sizeof exp);
sizeof_offset = out_header (line_seg, &exp);
line_end = exp.X_add_symbol;
exp.X_op_symbol = prologue_start;
exp.X_add_number = 0;
emit_expr (&exp, sizeof_offset);
- symbol_set_value_now (prologue_start);
+ symbol_set_value_now_octets (prologue_start);
/* Parameters of the state machine. */
out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
out_file_list ();
- symbol_set_value_now (prologue_end);
+ symbol_set_value_now_octets (prologue_end);
/* For each section, emit a statement program. */
for (s = all_segs; s; s = s->next)
in the DWARF Line Number header. */
subseg_set (subseg_get (".debug_line_end", FALSE), 0);
- symbol_set_value_now (line_end);
+ /* Pad size of .debug_line section to a multiple of OCTETS_PER_BYTE.
+ Simply sizing the section in md_section_align() is not sufficient,
+ also the size field in the .debug_line header must be a multiple
+ of OCTETS_PER_BYTE. Not doing so will introduce gaps within the
+ .debug_line sections after linking. */
+ section_end = frag_now_fix_octets ();
+ section_end_aligned = (section_end + OCTETS_PER_BYTE - 1) & -OCTETS_PER_BYTE;
+ for ( ; section_end != section_end_aligned; section_end++)
+ out_inc_line_addr (0, 0); /* NOP */
+
+ symbol_set_value_now_octets (line_end);
}
static void
expressionS exp;
unsigned int i;
+ memset (&exp, 0, sizeof exp);
subseg_set (ranges_seg, 0);
/* Base Address Entry. */
char *p;
int sizeof_offset;
+ memset (&exp, 0, sizeof exp);
sizeof_offset = out_header (aranges_seg, &exp);
aranges_end = exp.X_add_symbol;
size = -exp.X_add_number;
md_number_to_chars (p, 0, addr_size);
md_number_to_chars (p + addr_size, 0, addr_size);
- symbol_set_value_now (aranges_end);
+ symbol_set_value_now_octets (aranges_end);
}
/* Emit data for .debug_abbrev. Note that this must be kept in
symbolS *info_end;
int sizeof_offset;
+ memset (&exp, 0, sizeof exp);
sizeof_offset = out_header (info_seg, &exp);
info_end = exp.X_add_symbol;
dwarf2 draft has no standard code for assembler. */
out_two (DW_LANG_Mips_Assembler);
- symbol_set_value_now (info_end);
+ symbol_set_value_now_octets (info_end);
}
/* Emit the three debug strings needed in .debug_str and setup symbols
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. */
- *name_sym = symbol_temp_new_now ();
+ *name_sym = symbol_temp_new_now_octets ();
if (files_in_use == 0)
abort ();
if (files[1].dir)
memcpy (p, files[1].filename, len);
/* DW_AT_comp_dir */
- *comp_dir_sym = symbol_temp_new_now ();
+ *comp_dir_sym = symbol_temp_new_now_octets ();
comp_dir = remap_debug_filename (getpwd ());
len = strlen (comp_dir) + 1;
p = frag_more (len);
memcpy (p, comp_dir, len);
/* DW_AT_producer */
- *producer_sym = symbol_temp_new_now ();
+ *producer_sym = symbol_temp_new_now_octets ();
sprintf (producer, "GNU AS %s", VERSION);
len = strlen (producer) + 1;
p = frag_more (len);
/* Create and switch to the line number section. */
line_seg = subseg_new (".debug_line", 0);
- bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY | SEC_DEBUGGING);
+ bfd_set_section_flags (line_seg, SEC_READONLY | SEC_DEBUGGING);
/* For each subsection, chain the debug entries together. */
for (s = all_segs; s; s = s->next)
struct line_subseg *lss = s->head;
struct line_entry **ptail = lss->ptail;
+ /* Reset the initial view of the first subsection of the
+ section. */
+ if (lss->head && lss->head->loc.view)
+ set_or_check_view (lss->head, NULL, NULL);
+
while ((lss = lss->next) != NULL)
{
+ /* Link the first view of subsequent subsections to the
+ previous view. */
+ if (lss->head && lss->head->loc.view)
+ set_or_check_view (lss->head,
+ !s->head ? NULL : (struct line_entry *)ptail,
+ s->head ? s->head->head : NULL);
*ptail = lss->head;
ptail = lss->ptail;
}
aranges_seg = subseg_new (".debug_aranges", 0);
str_seg = subseg_new (".debug_str", 0);
- bfd_set_section_flags (stdoutput, info_seg,
- SEC_READONLY | SEC_DEBUGGING);
- bfd_set_section_flags (stdoutput, abbrev_seg,
- SEC_READONLY | SEC_DEBUGGING);
- bfd_set_section_flags (stdoutput, aranges_seg,
- SEC_READONLY | SEC_DEBUGGING);
- bfd_set_section_flags (stdoutput, str_seg,
- (SEC_READONLY | SEC_DEBUGGING
- | SEC_MERGE | SEC_STRINGS));
+ bfd_set_section_flags (info_seg, SEC_READONLY | SEC_DEBUGGING);
+ bfd_set_section_flags (abbrev_seg, SEC_READONLY | SEC_DEBUGGING);
+ bfd_set_section_flags (aranges_seg, SEC_READONLY | SEC_DEBUGGING);
+ bfd_set_section_flags (str_seg, (SEC_READONLY | SEC_DEBUGGING
+ | SEC_MERGE | SEC_STRINGS));
str_seg->entsize = 1;
record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1);
else
{
ranges_seg = subseg_new (".debug_ranges", 0);
- bfd_set_section_flags (stdoutput, ranges_seg,
- SEC_READONLY | SEC_DEBUGGING);
+ bfd_set_section_flags (ranges_seg, SEC_READONLY | SEC_DEBUGGING);
record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
out_debug_ranges (ranges_seg);
}