#define DWARF2_LINE_VERSION (dwarf_level > 3 ? dwarf_level : 3)
#endif
+/* The .debug_rnglists has only been in DWARF version 5. */
+#ifndef DWARF2_RNGLISTS_VERSION
+#define DWARF2_RNGLISTS_VERSION 5
+#endif
+
#include "subsegs.h"
#include "dwarf2.h"
static unsigned int dirs_allocated = 0;
/* TRUE when we've seen a .loc directive recently. Used to avoid
- doing work when there's nothing to do. */
+ doing work when there's nothing to do. Will be reset by
+ dwarf2_consume_line_info. */
bfd_boolean dwarf2_loc_directive_seen;
+/* TRUE when we've seen any .loc directive at any time during parsing.
+ Indicates the user wants us to generate a .debug_line section.
+ Used in dwarf2_finish as sanity check. */
+static bfd_boolean dwarf2_any_loc_directive_seen;
+
/* TRUE when we're supposed to set the basic block mark whenever a
label is seen. */
bfd_boolean dwarf2_loc_mark_labels;
/* 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);
- sym = symbol_new (name, now_seg, ofs, frag_now);
+ sym = symbol_new (name, now_seg, frag_now, ofs);
}
else
- sym = symbol_temp_new (now_seg, ofs, frag_now);
+ sym = symbol_temp_new (now_seg, frag_now, ofs);
dwarf2_gen_line_info_1 (sym, loc);
}
char *
dwarf2_directive_filename (void)
{
- bfd_boolean with_md5 = TRUE;
+ bfd_boolean with_md5 = FALSE;
valueT num;
char *filename;
const char * dirname = NULL;
sym = force_reset_view;
else
{
- sym = symbol_temp_new (absolute_section, value,
- &zero_address_frag);
+ sym = symbol_temp_new (absolute_section, &zero_address_frag,
+ value);
if (force_reset)
force_reset_view = sym;
}
}
demand_empty_rest_of_line ();
- dwarf2_loc_directive_seen = TRUE;
+ dwarf2_any_loc_directive_seen = dwarf2_loc_directive_seen = TRUE;
debug_type = DEBUG_NONE;
/* If we were given a view id, emit the row right away. */
out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
else
{
- lab = symbol_temp_new (seg, frag_ofs, frag);
+ lab = symbol_temp_new (seg, frag, frag_ofs);
relax_inc_line_addr (INT_MAX, lab, last_lab);
}
}
+/* Switch to LINE_STR_SEG and output the given STR. Return the
+ symbol pointing to the new string in the section. */
+
+static symbolS *
+add_line_strp (segT line_str_seg, const char *str)
+{
+ char *cp;
+ size_t size;
+ symbolS *sym;
+
+ subseg_set (line_str_seg, 0);
+
+ sym = symbol_temp_new_now_octets ();
+
+ size = strlen (str) + 1;
+ cp = frag_more (size);
+ memcpy (cp, str, size);
+
+ return sym;
+}
+
+
/* Emit the directory and file tables for .debug_line. */
static void
-out_dir_and_file_list (void)
+out_dir_and_file_list (segT line_seg, int sizeof_offset)
{
size_t size;
const char *dir;
bfd_boolean emit_md5 = FALSE;
bfd_boolean emit_timestamps = TRUE;
bfd_boolean emit_filesize = TRUE;
+ segT line_str_seg = NULL;
+ symbolS *line_strp;
/* Output the Directory Table. */
-
if (DWARF2_LINE_VERSION >= 5)
{
+ /* We only have one column in the directory table. */
out_byte (1);
+
+ /* Describe the purpose and format of the column. */
out_uleb128 (DW_LNCT_path);
- /* FIXME: it would be better to store these strings in
- the .debug_line_str section and reference them here. */
- out_uleb128 (DW_FORM_string);
- out_uleb128 (dirs_in_use);
+ /* Store these strings in the .debug_line_str section so they
+ can be shared. */
+ out_uleb128 (DW_FORM_line_strp);
+
+ /* Now state how many rows there are in the table. We need at
+ least 1 if there is one or more file names to store the
+ "working directory". */
+ if (dirs_in_use == 0 && files_in_use > 0)
+ out_uleb128 (1);
+ else
+ out_uleb128 (dirs_in_use);
}
/* Emit directory list. */
- if (DWARF2_LINE_VERSION >= 5)
- {
- if (dirs[0] == NULL)
- dir = remap_debug_filename (".");
- else
+ if (DWARF2_LINE_VERSION >= 5 && (dirs_in_use > 0 || files_in_use > 0))
+ {
+ line_str_seg = subseg_new (".debug_line_str", 0);
+ bfd_set_section_flags (line_str_seg,
+ SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS
+ | SEC_MERGE | SEC_STRINGS);
+ line_str_seg->entsize = 1;
+
+ /* DWARF5 uses slot zero, but that is only set explicitly
+ using a .file 0 directive. If that isn't used, but dir
+ one is used, then use that as main file directory.
+ Otherwise use pwd as main file directory. */
+ if (dirs_in_use > 0 && dirs != NULL && dirs[0] != NULL)
dir = remap_debug_filename (dirs[0]);
-
- size = strlen (dir) + 1;
- cp = frag_more (size);
- memcpy (cp, dir, size);
+ else if (dirs_in_use > 1 && dirs != NULL && dirs[1] != NULL)
+ dir = remap_debug_filename (dirs[1]);
+ else
+ dir = remap_debug_filename (getpwd ());
+
+ line_strp = add_line_strp (line_str_seg, dir);
+ subseg_set (line_seg, 0);
+ TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
}
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);
+ if (DWARF2_LINE_VERSION < 5)
+ {
+ size = strlen (dir) + 1;
+ cp = frag_more (size);
+ memcpy (cp, dir, size);
+ }
+ else
+ {
+ line_strp = add_line_strp (line_str_seg, dir);
+ subseg_set (line_seg, 0);
+ TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
+ }
}
if (DWARF2_LINE_VERSION < 5)
out_byte ('\0');
/* Output the File Name Table. */
-
if (DWARF2_LINE_VERSION >= 5)
{
unsigned int columns = 4;
/* The number of format entries to follow. */
out_byte (columns);
-
/* The format of the file name. */
out_uleb128 (DW_LNCT_path);
- /* FIXME: it would be better to store these strings in
- the .debug_line_str section and reference them here. */
- out_uleb128 (DW_FORM_string);
+ /* Store these strings in the .debug_line_str section so they
+ can be shared. */
+ out_uleb128 (DW_FORM_line_strp);
/* The format of the directory index. */
out_uleb128 (DW_LNCT_directory_index);
if (files[i].filename == NULL)
{
- /* Prevent a crash later, particularly for file 1. */
- files[i].filename = "";
+ /* Prevent a crash later, particularly for file 1. DWARF5
+ uses slot zero, but that is only set explicitly using a
+ .file 0 directive. If that isn't used, but file 1 is,
+ then use that as main file name. */
+ if (DWARF2_LINE_VERSION >= 5 && i == 0 && files_in_use >= 1)
+ files[0].filename = files[1].filename;
+ else
+ files[i].filename = "";
if (DWARF2_LINE_VERSION < 5 || i != 0)
{
as_bad (_("unassigned file number %ld"), (long) i);
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);
+ if (DWARF2_LINE_VERSION < 5)
+ {
+ size = strlen (fullfilename) + 1;
+ cp = frag_more (size);
+ memcpy (cp, fullfilename, size);
+ }
+ else
+ {
+ line_strp = add_line_strp (line_str_seg, fullfilename);
+ subseg_set (line_seg, 0);
+ TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
+ }
/* Directory number. */
out_uleb128 (files[i].dir);
matches up to the opcode base value we have been using. */
gas_assert (DWARF2_LINE_OPCODE_BASE == 13);
- out_dir_and_file_list ();
+ out_dir_and_file_list (line_seg, sizeof_offset);
symbol_set_value_now (prologue_end);
}
static void
-out_debug_ranges (segT ranges_seg)
+out_debug_ranges (segT ranges_seg, symbolS **ranges_sym)
{
unsigned int addr_size = sizeof_address;
struct line_seg *s;
memset (&exp, 0, sizeof exp);
subseg_set (ranges_seg, 0);
+ /* For DW_AT_ranges to point at (there is no header, so really start
+ of section, but see out_debug_rnglists). */
+ *ranges_sym = symbol_temp_new_now_octets ();
+
/* Base Address Entry. */
for (i = 0; i < addr_size; i++)
out_byte (0xff);
symbolS *beg, *end;
frag = first_frag_for_seg (s->seg);
- beg = symbol_temp_new (s->seg, 0, frag);
+ beg = symbol_temp_new (s->seg, frag, 0);
s->text_start = beg;
frag = last_frag_for_seg (s->seg);
- end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
+ end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
s->text_end = end;
exp.X_op = O_symbol;
out_byte (0);
}
+static void
+out_debug_rnglists (segT ranges_seg, symbolS **ranges_sym)
+{
+ expressionS exp;
+ symbolS *ranges_end;
+ struct line_seg *s;
+
+ /* Unit length. */
+ memset (&exp, 0, sizeof exp);
+ out_header (ranges_seg, &exp);
+ ranges_end = exp.X_add_symbol;
+
+ out_two (DWARF2_RNGLISTS_VERSION);
+ out_byte (sizeof_address);
+ out_byte (0); /* Segment Selector size. */
+ out_four (0); /* Offset entry count. */
+
+ /* For DW_AT_ranges to point at (must be after the header). */
+ *ranges_sym = symbol_temp_new_now_octets ();
+
+ for (s = all_segs; s; s = s->next)
+ {
+ fragS *frag;
+ symbolS *beg, *end;
+
+ out_byte (DW_RLE_start_length);
+
+ frag = first_frag_for_seg (s->seg);
+ beg = symbol_temp_new (s->seg, frag, 0);
+ s->text_start = beg;
+
+ frag = last_frag_for_seg (s->seg);
+ end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
+ s->text_end = end;
+
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = beg;
+ exp.X_add_number = 0;
+ emit_expr (&exp, sizeof_address);
+
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = end;
+ exp.X_add_number = 0;
+ emit_leb128_expr (&exp, 0);
+ }
+
+ out_byte (DW_RLE_end_of_list);
+
+ symbol_set_value_now (ranges_end);
+}
+
/* Emit data for .debug_aranges. */
static void
symbolS *beg, *end;
frag = first_frag_for_seg (s->seg);
- beg = symbol_temp_new (s->seg, 0, frag);
+ beg = symbol_temp_new (s->seg, frag, 0);
s->text_start = beg;
frag = last_frag_for_seg (s->seg);
- end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
+ end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
s->text_end = end;
exp.X_op = O_symbol;
segT info_seg ATTRIBUTE_UNUSED,
segT line_seg ATTRIBUTE_UNUSED)
{
+ int secoff_form;
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);
+ if (DWARF2_VERSION < 4)
+ {
+ if (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit)
+ secoff_form = DW_FORM_data4;
+ else
+ secoff_form = DW_FORM_data8;
+ }
else
- out_abbrev (DW_AT_stmt_list, DW_FORM_data8);
+ secoff_form = DW_FORM_sec_offset;
+ out_abbrev (DW_AT_stmt_list, secoff_form);
if (all_segs->next == NULL)
{
out_abbrev (DW_AT_low_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));
+ out_abbrev (DW_AT_high_pc, DW_FORM_udata);
}
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_ranges, secoff_form);
out_abbrev (DW_AT_name, DW_FORM_strp);
out_abbrev (DW_AT_comp_dir, DW_FORM_strp);
out_abbrev (DW_AT_producer, DW_FORM_strp);
/* Emit a description of this compilation unit for .debug_info. */
static void
-out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg,
- symbolS *name_sym, symbolS *comp_dir_sym, symbolS *producer_sym)
+out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg,
+ symbolS *ranges_sym, symbolS *name_sym,
+ symbolS *comp_dir_sym, symbolS *producer_sym)
{
expressionS exp;
symbolS *info_end;
/* DWARF version. */
out_two (DWARF2_VERSION);
- /* .debug_abbrev offset */
- TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+ if (DWARF2_VERSION < 5)
+ {
+ /* .debug_abbrev offset */
+ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+ }
+ else
+ {
+ /* unit (header) type */
+ out_byte (DW_UT_compile);
+ }
/* Target address size. */
out_byte (sizeof_address);
+ if (DWARF2_VERSION >= 5)
+ {
+ /* .debug_abbrev offset */
+ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+ }
+
/* DW_TAG_compile_unit DIE abbrev */
out_uleb128 (1);
}
exp.X_add_symbol = all_segs->text_end;
exp.X_add_number = 0;
- emit_expr (&exp, sizeof_address);
+ if (DWARF2_VERSION < 4)
+ emit_expr (&exp, sizeof_address);
+ else
+ emit_leb128_expr (&exp, 0);
}
else
{
/* This attribute is emitted if the code is disjoint. */
/* DW_AT_ranges. */
- TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset);
+ TC_DWARF2_EMIT_OFFSET (ranges_sym, sizeof_offset);
}
/* DW_AT_name, DW_AT_comp_dir and DW_AT_producer. Symbols in .debug_str
/* Finish the dwarf2 debug sections. We emit .debug.line if there
- were any .file/.loc directives, or --gdwarf2 was given, or if the
+ were any .file/.loc directives, or --gdwarf2 was given, and if the
file has a non-empty .debug_info section and an empty .debug_line
section. If we emit .debug_line, and the .debug_info section is
empty, we also emit .debug_info, .debug_aranges and .debug_abbrev.
empty_debug_line = line_seg == NULL || !seg_not_empty_p (line_seg);
/* We can't construct a new debug_line section if we already have one.
- Give an error. */
- if (all_segs && !empty_debug_line)
+ Give an error if we have seen any .loc, otherwise trust the user
+ knows what they are doing and want to generate the .debug_line
+ (and all other debug sections) themselves. */
+ if (all_segs && !empty_debug_line && dwarf2_any_loc_directive_seen)
as_fatal ("duplicate .debug_line sections");
if ((!all_segs && emit_other_sections)
sizeof_address = DWARF2_ADDR_SIZE (stdoutput);
/* Create and switch to the line number section. */
- line_seg = subseg_new (".debug_line", 0);
- bfd_set_section_flags (line_seg, SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
+ if (empty_debug_line)
+ {
+ line_seg = subseg_new (".debug_line", 0);
+ bfd_set_section_flags (line_seg,
+ SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
+ }
/* For each subsection, chain the debug entries together. */
for (s = all_segs; s; s = s->next)
}
}
- out_debug_line (line_seg);
+ if (empty_debug_line)
+ out_debug_line (line_seg);
/* If this is assembler generated line info, and there is no
debug_info already, we need .debug_info, .debug_abbrev and
{
segT abbrev_seg;
segT aranges_seg;
- segT ranges_seg;
segT str_seg;
- symbolS *name_sym, *comp_dir_sym, *producer_sym;
+ symbolS *name_sym, *comp_dir_sym, *producer_sym, *ranges_sym;
gas_assert (all_segs);
record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1);
if (all_segs->next == NULL)
- ranges_seg = NULL;
+ ranges_sym = NULL;
else
{
- ranges_seg = subseg_new (".debug_ranges", 0);
- bfd_set_section_flags (ranges_seg,
- SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
- record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
- out_debug_ranges (ranges_seg);
+ if (DWARF2_VERSION < 5)
+ {
+ segT ranges_seg = subseg_new (".debug_ranges", 0);
+ bfd_set_section_flags (ranges_seg, (SEC_READONLY
+ | SEC_DEBUGGING
+ | SEC_OCTETS));
+ record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
+ out_debug_ranges (ranges_seg, &ranges_sym);
+ }
+ else
+ {
+ segT rnglists_seg = subseg_new (".debug_rnglists", 0);
+ bfd_set_section_flags (rnglists_seg, (SEC_READONLY
+ | SEC_DEBUGGING
+ | SEC_OCTETS));
+ out_debug_rnglists (rnglists_seg, &ranges_sym);
+ }
}
out_debug_aranges (aranges_seg, info_seg);
out_debug_abbrev (abbrev_seg, info_seg, line_seg);
out_debug_str (str_seg, &name_sym, &comp_dir_sym, &producer_sym);
- out_debug_info (info_seg, abbrev_seg, line_seg, ranges_seg,
+ out_debug_info (info_seg, abbrev_seg, line_seg, ranges_sym,
name_sym, comp_dir_sym, producer_sym);
}
}