diff options
author | Doug Evans <dje@google.com> | 2015-12-10 12:00:32 -0800 |
---|---|---|
committer | Doug Evans <dje@google.com> | 2015-12-10 12:00:32 -0800 |
commit | d1fab5832436b4090ca7dbaa2a9f1f31f019bd46 (patch) | |
tree | a5981308b004529a7c31f737de283a4b97591ba8 | |
parent | 55145bb5e6cf17ed47f0674b2ddbde2d92aad4dc (diff) | |
download | fsf-binutils-gdb-d1fab5832436b4090ca7dbaa2a9f1f31f019bd46.zip fsf-binutils-gdb-d1fab5832436b4090ca7dbaa2a9f1f31f019bd46.tar.gz fsf-binutils-gdb-d1fab5832436b4090ca7dbaa2a9f1f31f019bd46.tar.bz2 |
patch ../102431983.patch
-rw-r--r-- | README.google | 59 | ||||
-rw-r--r-- | gdb/NEWS | 7 | ||||
-rw-r--r-- | gdb/dwarf2read.c | 1174 | ||||
-rw-r--r-- | gdb/symfile.h | 1 | ||||
-rw-r--r-- | gdb/testsuite/boards/fission-tll.exp | 39 | ||||
-rw-r--r-- | gdb/xcoffread.c | 1 | ||||
-rw-r--r-- | include/dwarf2.def | 2 | ||||
-rw-r--r-- | include/dwarf2.h | 26 |
8 files changed, 1203 insertions, 106 deletions
diff --git a/README.google b/README.google index 8b089b8..5686d22 100644 --- a/README.google +++ b/README.google @@ -281,3 +281,62 @@ they are an ongoing maintenance burden. + + testsuite/ + * gdb.python/py-mi.exp: Add tests for gdb.top_interpreter_is_mi. +--- README.google 2015-09-05 18:59:16.000000000 -0700 ++++ README.google 2015-09-05 20:17:18.000000000 -0700 ++ ++2015-09-05 Doug Evans <dje@google.com> ++ ++ Two Level Line Tables support. ++ Submitted upstream, but not committed there yet. ++ ++ * NEWS: Mention DWARF 5 line tables. ++ * dwarf2read.c (DW_VERSION_EXPERIMENTAL_TLL): New macro. ++ (dwarf2_per_objfile): New member line_str. ++ (dwarf2_elf_names): Update. ++ (struct file_entry): Add comment. New member offset_size. ++ Rename member header_length to prologue_length, all uses updated. ++ New members address_size, segment_size. ++ (line_header) <actuals_program_start, actuals_program_end>: New ++ members. ++ (dwarf2_statement_list_fits_in_line_number_section_complaint): Delete. ++ (dwarf2_invalid_form_complaint): New function. ++ (dwarf2_locate_sections): Handle .debug_line_str. ++ (read_indirect_line_string): New function. ++ (read_unsigned_integer): New function. ++ (read_dwarf2_line_header_paths): New function. ++ (dwarf5_line_header_format): New struct. ++ (dwarf5_line_header_entry): New struct. ++ (read_dwarf5_line_header_entry): New function. ++ (read_dwarf5_line_header_subtable): New function. ++ (read_dwarf5_line_header_paths): New function. ++ (read_dwarf6_subprograms): New function. ++ (read_experimental_tll_header_and_tables): New function. ++ (dwarf_decode_line_header): Update to handle DWARF5 line tables. ++ Handle DW_VERSION_EXPERIMENTAL_TLL. ++ (logical_line): New typedef. ++ (DEF_VEC_O logical_line): Define vector. ++ (record_line_ftype): New typedef. ++ (lnp_state_machine) <context, subprogram>: New members. ++ (lnp_reader_state) <two_level_p, build_logicals_p>: New members. ++ (lnp_reader_state) <logical_line_table>: New member. ++ (dwarf_append_logical_line): New function. ++ (dwarf_record_line): Handle Two Level Line Tables. ++ (init_lnp_state_machine): Initialize context, subprogram. ++ (dwarf_decode_lines_1): New result type to int. All callers updated. ++ Add Two Level Line Tables support. ++ (dwarf_decode_lines): Add Two Level Line Tables support. ++ (dwarf_line_number_content_type_name): New function. ++ (skip_form_bytes): Mention DW_FORM_data16. Call ++ dwarf2_invalid_form_complaint. ++ * symfile.h (struct dwarf2_debug_sections): New member line_str. ++ * xcoffread.c (dwarf2_xcoff_names): Add entry for .debug_line_str. ++ ++ testsuite/ ++ * boards/fission-tll.exp: New file. ++ ++ include/ ++ * dwarf2.def (DW_FORM_line_strp): New form. ++ * dwarf2.h (dwarf_line_number_ops): New enum values ++ DW_LNS_set_address_from_logical, DW_LNS_set_subprogram, ++ DW_LNS_inlined_call, DW_LNS_pop_context. ++ (dwarf_line_number_content_type): New enum. @@ -88,6 +88,13 @@ "const_value" which return a reference to the value and a "const" version of the value respectively. +* DWARF + +GDB now supports DWARF 5 line tables and the new .debug_line_str section. + +GDB now supports the Two Level Line Tables extension proposed here: +http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables + * New commands maint print symbol-cache diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index df37151..2819647 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -76,6 +76,11 @@ typedef struct symbol *symbolp; DEF_VEC_P (symbolp); +/* DWARF version with Two Level Line Tables (TLLs). + http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables + http://www.dwarfstd.org/ShowIssue.php?issue=140906.1 */ +#define DW_VERSION_EXPERIMENTAL_TLL 0xf006 + /* When == 1, print basic high level tracing messages. When > 1, be more verbose. This is in contrast to the low level DIE reading of dwarf_die_debug. */ @@ -229,6 +234,7 @@ struct dwarf2_per_objfile struct dwarf2_section_info macro; struct dwarf2_section_info str; struct dwarf2_section_info str_offsets; /* GOOGLE LOCAL */ + struct dwarf2_section_info line_str; struct dwarf2_section_info ranges; struct dwarf2_section_info addr; struct dwarf2_section_info frame; @@ -341,6 +347,7 @@ static const struct dwarf2_debug_sections dwarf2_elf_names = { ".debug_macro", ".zdebug_macro" }, { ".debug_str", ".zdebug_str" }, { ".debug_str_offsets", ".zdebug_str_offsets" }, /* GOOGLE LOCAL */ + { ".debug_line_str", ".zdebug_line_str" }, { ".debug_ranges", ".zdebug_ranges" }, { ".debug_types", ".zdebug_types" }, { ".debug_addr", ".zdebug_addr" }, @@ -1052,6 +1059,10 @@ typedef void (die_reader_func_ftype) (const struct die_reader_specs *reader, struct file_entry { const char *name; + /* Note: In DWARF5, the current directory is defined to exist in the + directory table as the first entry and has number zero. To preserve + the meaning of "dir_index == 0 -> no directory", one is added to the + DWARF5 directory number. */ unsigned int dir_index; unsigned int mod_time; unsigned int length; @@ -1073,8 +1084,9 @@ struct line_header unsigned offset_in_dwz : 1; unsigned int total_length; + unsigned int offset_size; unsigned short version; - unsigned int header_length; + unsigned int prologue_length; unsigned char minimum_instruction_length; unsigned char maximum_ops_per_instruction; unsigned char default_is_stmt; @@ -1082,6 +1094,9 @@ struct line_header unsigned char line_range; unsigned char opcode_base; + /* The address and segment sizes. These were added in DWARF5. */ + unsigned char address_size, segment_size; + /* standard_opcode_lengths[i] is the number of operands for the standard opcode whose value is i. This means that standard_opcode_lengths[0] is unused, and the last meaningful @@ -1104,6 +1119,13 @@ struct line_header /* The start and end of the statement program following this header. These point into dwarf2_per_objfile->line_buffer. */ const gdb_byte *statement_program_start, *statement_program_end; + + /* The start and end of the actuals statement program following this + header. These point into dwarf2_per_objfile->line_buffer. + Only used by Two Level Line Tables. + They are NULL if the actuals program is not present. + http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables */ + const gdb_byte *actuals_program_start, *actuals_program_end; }; /* When we construct a partial symbol table entry we only @@ -1745,6 +1767,8 @@ static char *dwarf_bool_name (unsigned int); static const char *dwarf_type_encoding_name (unsigned int); +static const char *dwarf_line_number_content_type_name (unsigned int); + static struct die_info *sibling_die (struct die_info *); static void dump_die_shallow (struct ui_file *, int indent, struct die_info *); @@ -1815,6 +1839,12 @@ static const gdb_byte *skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr, struct abbrev_info *abbrev); +static const gdb_byte *skip_form_bytes (bfd *abfd, const gdb_byte *bytes, + const gdb_byte *buffer_end, + enum dwarf_form form, + unsigned int offset_size, + struct dwarf2_section_info *section); + static void free_stack_comp_unit (void *); static hashval_t partial_die_hash (const void *item); @@ -1925,13 +1955,6 @@ static void free_line_header_voidp (void *arg); /* Various complaints about symbol reading that don't abort the process. */ static void -dwarf2_statement_list_fits_in_line_number_section_complaint (void) -{ - complaint (&symfile_complaints, - _("statement list doesn't fit in .debug_line section")); -} - -static void dwarf2_debug_line_missing_file_complaint (void) { complaint (&symfile_complaints, @@ -1988,6 +2011,20 @@ dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2) arg1, arg2); } +/* Issue a complaint saying FORM is invalid in context CONTEXT + in section SECTION. */ + +static void +dwarf2_invalid_form_complaint (unsigned int form, const char *context, + unsigned int offset, + struct dwarf2_section_info *section) +{ + complaint (&symfile_complaints, + _("invalid form %s(0x%x) in %s at offset 0x%x of section %s [in module %s]"), + dwarf_form_name (form), form, context, offset, + get_section_name (section), get_section_file_name (section)); +} + /* Hash function for line_header_hash. */ static hashval_t @@ -2234,6 +2271,11 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->line.s.asection = sectp; dwarf2_per_objfile->line.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, &names->line_str)) + { + dwarf2_per_objfile->line_str.s.asection = sectp; + dwarf2_per_objfile->line_str.size = bfd_get_section_size (sectp); + } else if (section_is_p (sectp->name, &names->loc)) { dwarf2_per_objfile->loc.s.asection = sectp; @@ -16817,6 +16859,36 @@ read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset) return (const char *) (dwarf2_per_objfile->str.buffer + str_offset); } +/* Return the string in .debug_line_str at STR_OFFSET. + Returns NULL if there is no such section or if STR_OFFSET is invalid, + a complaint will have already been issued. + The caller is responsible for converting "" to NULL if desired. */ + +static const char * +read_indirect_line_string (bfd *abfd, LONGEST str_offset) +{ + dwarf2_read_section (dwarf2_per_objfile->objfile, + &dwarf2_per_objfile->line_str); + if (dwarf2_per_objfile->line_str.buffer == NULL) + { + complaint (&symfile_complaints, + _("DW_FORM_line_strp used without .debug_line_str section" + " [in module %s]"), + bfd_get_filename (abfd)); + return NULL; + } + if (str_offset >= dwarf2_per_objfile->line_str.size) + { + complaint (&symfile_complaints, + _("DW_FORM_line_strp pointing outside of" + " .debug_line_str section [in module %s]"), + bfd_get_filename (abfd)); + return NULL; + } + gdb_assert (HOST_CHAR_BIT == 8); + return (const char *) (dwarf2_per_objfile->line_str.buffer + str_offset); +} + /* Read a string at offset STR_OFFSET in the .debug_str section from the .dwz file DWZ. Throw an error if the offset is too large. If the string consists of a single NUL byte, return NULL; otherwise @@ -16910,6 +16982,53 @@ read_signed_leb128 (bfd *abfd, const gdb_byte *buf, return result; } +/* Read an unsigned integer of form FORM from SECTION at INFO_PTR. + INFO_PTR must point into SECTION's buffer. + The value is stored in *RESULT_PTR. + CONTEXT describes the context in which the value is being read and is + only used in complaints. + The result is the number of bytes read, unless there was an error + (e.g., bad form), in which case a complaint is issued and NULL + is returned. */ + +static const gdb_byte * +read_unsigned_integer (struct dwarf2_section_info *section, + const gdb_byte *buf, unsigned int form, + const char *context, ULONGEST *result_ptr) +{ + bfd *abfd = get_section_bfd_owner (section); + + gdb_assert (buf >= section->buffer + && buf < section->buffer + section->size); + + switch (form) + { + case DW_FORM_data1: + *result_ptr = read_1_byte (abfd, buf); + return buf + 1; + case DW_FORM_data2: + *result_ptr = read_2_bytes (abfd, buf); + return buf + 2; + case DW_FORM_data4: + *result_ptr = read_4_bytes (abfd, buf); + return buf + 4; + case DW_FORM_data8: + *result_ptr = read_8_bytes (abfd, buf); + return buf + 8; + case DW_FORM_udata: + { + unsigned int bytes_read; + + *result_ptr = read_unsigned_leb128 (abfd, buf, &bytes_read); + return buf + bytes_read; + } + default: + dwarf2_invalid_form_complaint (form, context, buf - section->buffer, + section); + return NULL; + } +} + /* Given index ADDR_INDEX in .debug_addr, fetch the value. ADDR_BASE is the DW_AT_GNU_addr_base attribute or zero. ADDR_SIZE is the size of addresses from the CU header. */ @@ -17450,22 +17569,425 @@ get_debug_line_section (struct dwarf2_cu *cu) return section; } +/* Subroutine of dwarf_decode_line_header to simplify it. + Read old style (pre-dwarf5) line header paths (directory and + file name entries). + The result is a pointer to the end of the read data, or NULL + if there was an error (a complaint has already been issued). */ + +static const gdb_byte * +read_dwarf2_line_header_paths (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr) +{ + bfd *abfd = get_section_bfd_owner (section); + const gdb_byte *end_ptr = section->buffer + section->size; + unsigned int bytes_read; + const char *cur_dir, *cur_file; + + /* Read directory table. */ + while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL) + { + line_ptr += bytes_read; + add_include_dir (lh, cur_dir); + } + line_ptr += bytes_read; + + /* Read file name table. */ + while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL) + { + unsigned int dir_index, mod_time, length; + + line_ptr += bytes_read; + dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + add_file_name (lh, cur_file, dir_index, mod_time, length); + } + line_ptr += bytes_read; + + if (line_ptr > end_ptr) + { + dwarf2_section_buffer_overflow_complaint (section); + return NULL; + } + + return line_ptr; +} + +struct dwarf5_line_header_format +{ + /* One of DW_LNCT_*. */ + unsigned int type; + /* One of DW_FORM_*. */ + unsigned int form; +}; + +struct dwarf5_line_header_entry +{ + /* DW_LNCT_path or DW_LNCT_subprogram_name. */ + const char *path_or_name; + /* DW_LNCT_directory_index. */ + unsigned int dir_index; + /* DW_LNCT_timestamp. */ + unsigned int timestamp; + /* DW_LNCT_size. */ + unsigned int size; + /* DW_LNCT_decl_file. */ + unsigned int decl_file; + /* DW_LNCT_decl_line. */ + unsigned int decl_line; +}; + +/* Subroutine of read_dwarf5_line_header_paths to simplify it. + Process TYPE,FORM for ENTRY. + The result is a pointer to the end of the read data, or NULL + if an error was found (complaint has already been issued). */ + +static const gdb_byte * +read_dwarf5_line_header_entry (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr, + unsigned int type, unsigned int form, + struct dwarf5_line_header_entry *entry) +{ + bfd *abfd = get_section_bfd_owner (section); + const gdb_byte *end_ptr = section->buffer + section->size; + unsigned int offset_size = lh->offset_size; + unsigned int bytes_read; + const char *context = dwarf_line_number_content_type_name (type); + const char *string = NULL; + ULONGEST value = 0; + + switch (type) + { + case DW_LNCT_path: + case DW_LNCT_subprogram_name: + switch (form) + { + case DW_FORM_string: + string = read_direct_string (abfd, line_ptr, &bytes_read); + break; + case DW_FORM_line_strp: + value = read_offset_1 (abfd, line_ptr, offset_size); + line_ptr += offset_size; + string = read_indirect_line_string (abfd, value); + if (string == NULL) + string = "<invalid-file>"; + break; + /*case DW_FORM_strx: - TODO(dje) */ + default: + goto complaint_bad_form; + } + break; + case DW_LNCT_directory_index: + case DW_LNCT_timestamp: + case DW_LNCT_size: + case DW_LNCT_decl_file: + case DW_LNCT_decl_line: + line_ptr = read_unsigned_integer (section, line_ptr, form, context, + &value); + if (line_ptr == NULL) + return NULL; + break; +#if 0 /* Disabled until DW_FORM_data16 appears in dwarf2.def. */ + case DW_LNCT_MD5: + if (form != DW_FORM_data16) + goto complaint_bad_form; + /* Ignore for now. */ + line_ptr += 16; + break; +#endif + default: + /* Ignore. */ + line_ptr = skip_form_bytes (abfd, line_ptr, end_ptr, form, + offset_size, section); + if (line_ptr == NULL) + return NULL; + if (line_ptr > end_ptr) + { + dwarf2_section_buffer_overflow_complaint (section); + return NULL; + } + return line_ptr; + } + + switch (type) + { + case DW_LNCT_path: + entry->path_or_name = string; + break; + case DW_LNCT_subprogram_name: + entry->path_or_name = string; + break; + case DW_LNCT_directory_index: + entry->dir_index = value; + break; + case DW_LNCT_timestamp: + entry->timestamp = value; + break; + case DW_LNCT_size: + entry->size = value; + break; + case DW_LNCT_decl_file: + entry->decl_file = value; + break; + case DW_LNCT_decl_line: + entry->decl_line = value; + break; + default: + gdb_assert_not_reached ("bad type handling"); + } + + if (line_ptr > end_ptr) + { + dwarf2_section_buffer_overflow_complaint (section); + return NULL; + } + + return line_ptr; + + complaint_bad_form: + dwarf2_invalid_form_complaint (form, context, line_ptr - section->buffer, + section); + return NULL; +} + +/* Utility to read the directory / file-names / subprogram-names entries. + They all have the same format, which is self-describing. + The processed table is stored in *ENTRIES_PTR, with its size stored in + *NR_ENTRIES_PTR. + The result is a pointer to the end of the read data, or NULL + if an error was found (complaint has already been issued). */ + +static const gdb_byte * +read_dwarf5_line_header_subtable (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr, + struct dwarf5_line_header_entry **entries_ptr, + unsigned int *nr_entries_ptr) +{ + bfd *abfd = get_section_bfd_owner (section); + const gdb_byte *end_ptr = section->buffer + section->size; + unsigned char entry_format_count; + struct dwarf5_line_header_format *format; + unsigned int entry_count; + struct dwarf5_line_header_entry *entries; + unsigned int bytes_read; + unsigned int i, j; + struct cleanup *cleanups; + + entry_format_count = read_1_byte (abfd, line_ptr); + ++line_ptr; + + format = (struct dwarf5_line_header_format *) + alloca (entry_format_count + * sizeof (struct dwarf5_line_header_format *)); + for (i = 0; i < entry_format_count; ++i) + { + format[i].type = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + format[i].form = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + } + + entry_count = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + entries = XCNEWVEC (struct dwarf5_line_header_entry, entry_count); + cleanups = make_cleanup (xfree, entries); + + for (i = 0; i < entry_count; ++i) + { + for (j = 0; j < entry_format_count; ++j) + { + line_ptr = read_dwarf5_line_header_entry (lh, section, line_ptr, + format[j].type, + format[j].form, + &entries[i]); + if (line_ptr == NULL) + { + do_cleanups (cleanups); + return NULL; + } + } + } + + gdb_assert (line_ptr != NULL); + discard_cleanups (cleanups); + *entries_ptr = entries; + *nr_entries_ptr = entry_count; + return line_ptr; +} + +/* Subroutine of dwarf_decode_line_header to simplify it. + Read new style (dwarf5) line header paths (directory and + file name entries). + The result is a pointer to the end of the read data, or NULL + if an error was found (complaint has already been issued). */ + +static const gdb_byte * +read_dwarf5_line_header_paths (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr) +{ + bfd *abfd = get_section_bfd_owner (section); + unsigned int i, dir_count, file_count; + struct dwarf5_line_header_entry *directories, *files; + struct cleanup *cleanups; + + cleanups = make_cleanup (null_cleanup, NULL); + + line_ptr = read_dwarf5_line_header_subtable (lh, section, line_ptr, + &directories, &dir_count); + if (line_ptr == NULL) + { + do_cleanups (cleanups); + return NULL; + } + + make_cleanup (xfree, directories); + + line_ptr = read_dwarf5_line_header_subtable (lh, section, line_ptr, + &files, &file_count); + if (line_ptr == NULL) + { + do_cleanups (cleanups); + return NULL; + } + + make_cleanup (xfree, files); + + for (i = 0; i < dir_count; ++i) + { + add_include_dir (lh, directories[i].path_or_name); + } + + for (i = 0; i < file_count; ++i) + { + add_file_name (lh, files[i].path_or_name, files[i].dir_index, + files[i].timestamp, files[i].size); + } + + gdb_assert (line_ptr != NULL); + do_cleanups (cleanups); + return line_ptr; +} + +/* Subroutine of dwarf_decode_line_header to simplify it. + Read dwarf6 two level line table entries in the header. + The result is a pointer to the end of the read data, or NULL + if an error was found (complaint has already been issued). */ + +static const gdb_byte * +read_dwarf6_subprograms (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr) +{ + bfd *abfd = get_section_bfd_owner (section); + unsigned int subprog_count; + struct dwarf5_line_header_entry *subprograms; + struct cleanup *cleanups; + + cleanups = make_cleanup (null_cleanup, NULL); + + line_ptr = read_dwarf5_line_header_subtable (lh, section, line_ptr, + &subprograms, &subprog_count); + if (line_ptr == NULL) + { + do_cleanups (cleanups); + return NULL; + } + + /* TODO(dje): We don't do anything with subprograms. */ + xfree (subprograms); + + gdb_assert (line_ptr != NULL); + do_cleanups (cleanups); + return line_ptr; +} + +/* Read the header and directory/file/subprogram tables part of experimental + TLL support. + The result is a pointer to the logicals line number program, which + is actually embedded in the faked line number program of the outer + version 2 shell. */ + +static const gdb_byte * +read_experimental_tll_header_and_tables (struct line_header *lh, + struct dwarf2_section_info *section, + const gdb_byte *line_ptr, + const gdb_byte *end_of_header_length, + const gdb_byte *program_end) +{ + bfd *abfd = get_section_bfd_owner (section); + unsigned int logicals_offset, actuals_offset; + + /* Skip the fake directory and filename table. */ + if (*line_ptr != 0) + complaint (&symfile_complaints, _("fake directory table not empty")); + ++line_ptr; + if (*line_ptr != 0) + complaint (&symfile_complaints, _("fake file table not empty")); + ++line_ptr; + + /* Skip the fake extended opcode that wraps the rest of the section. */ + line_ptr += 5; + + logicals_offset = read_offset_1 (abfd, line_ptr, lh->offset_size); + line_ptr += lh->offset_size; + actuals_offset = read_offset_1 (abfd, line_ptr, lh->offset_size); + line_ptr += lh->offset_size; + + lh->statement_program_start = end_of_header_length + logicals_offset; + if (actuals_offset != 0) + { + lh->statement_program_end = end_of_header_length + actuals_offset; + lh->actuals_program_start = lh->statement_program_end; + lh->actuals_program_end = program_end; + } + else + lh->statement_program_end = program_end; + + if (line_ptr >= program_end) + { + dwarf2_section_buffer_overflow_complaint (section); + return NULL; + } + + line_ptr = read_dwarf5_line_header_paths (lh, section, line_ptr); + if (line_ptr == NULL) + return NULL; + + line_ptr = read_dwarf6_subprograms (lh, section, line_ptr); + if (line_ptr == NULL) + return NULL; + + return line_ptr; +} + /* Read the statement program header starting at OFFSET in .debug_line, or .debug_line.dwo. Return a pointer to a struct line_header, allocated using xmalloc. - Returns NULL if there is a problem reading the header, e.g., if it - has a version we don't understand. + Returns NULL if there is a problem reading the header, e.g., if it has a + version we don't understand, a complaint will have already been issued. NOTE: the strings in the include directory and file name tables of the returned object point into the dwarf line section buffer, - and must not be freed. */ + and must not be freed. + + DWARF5 support follows the proposal here: + http://dwarfstd.org/ShowIssue.php?issue=140724.1 */ static struct line_header * dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) { struct cleanup *back_to; struct line_header *lh; - const gdb_byte *line_ptr; + const gdb_byte *line_ptr, *end_ptr, *program_end, *end_of_header_length; unsigned int bytes_read, offset_size; int i; const char *cur_dir, *cur_file; @@ -17480,7 +18002,7 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) complaint (&symfile_complaints, _("missing .debug_line.dwo section")); else complaint (&symfile_complaints, _("missing .debug_line section")); - return 0; + return NULL; } /* We can't do this until we know the section is non-empty. @@ -17491,8 +18013,8 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) That could be 12 bytes long, but we're just going to fudge that. */ if (offset + 4 >= section->size) { - dwarf2_statement_list_fits_in_line_number_section_complaint (); - return 0; + dwarf2_section_buffer_overflow_complaint (section); + return NULL; } lh = xmalloc (sizeof (*lh)); @@ -17504,22 +18026,25 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) lh->offset_in_dwz = cu->per_cu->is_dwz; line_ptr = section->buffer + offset; + end_ptr = section->buffer + section->size; /* Read in the header. */ + lh->total_length = read_checked_initial_length_and_offset (abfd, line_ptr, &cu->header, &bytes_read, &offset_size); line_ptr += bytes_read; - if (line_ptr + lh->total_length > (section->buffer + section->size)) + lh->offset_size = offset_size; + if (line_ptr + lh->total_length > end_ptr) { - dwarf2_statement_list_fits_in_line_number_section_complaint (); + dwarf2_section_buffer_overflow_complaint (section); do_cleanups (back_to); - return 0; + return NULL; } - lh->statement_program_end = line_ptr + lh->total_length; + program_end = line_ptr + lh->total_length; lh->version = read_2_bytes (abfd, line_ptr); line_ptr += 2; - if (lh->version > 4) + if (lh->version > 5 && lh->version != DW_VERSION_EXPERIMENTAL_TLL) { /* This is a version we don't understand. The format could have changed in ways we don't handle properly so just punt. */ @@ -17527,8 +18052,16 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) _("unsupported version in .debug_line section")); return NULL; } - lh->header_length = read_offset_1 (abfd, line_ptr, offset_size); + if (lh->version >= 5 && lh->version != DW_VERSION_EXPERIMENTAL_TLL) + { + lh->address_size = read_1_byte (abfd, line_ptr); + line_ptr += 1; + lh->segment_size = read_1_byte (abfd, line_ptr); + line_ptr += 1; + } + lh->prologue_length = read_offset_1 (abfd, line_ptr, offset_size); line_ptr += offset_size; + end_of_header_length = line_ptr; lh->minimum_instruction_length = read_1_byte (abfd, line_ptr); line_ptr += 1; if (lh->version >= 4) @@ -17565,36 +18098,61 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) line_ptr += 1; } - /* Read directory table. */ - while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL) + if (line_ptr >= program_end) { - line_ptr += bytes_read; - add_include_dir (lh, cur_dir); + dwarf2_section_buffer_overflow_complaint (section); + do_cleanups (back_to); + return NULL; } - line_ptr += bytes_read; - /* Read file name table. */ - while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL) - { - unsigned int dir_index, mod_time, length; + /* Read in the directory and file tables. */ - line_ptr += bytes_read; - dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; + if (lh->version <= 4) + line_ptr = read_dwarf2_line_header_paths (lh, section, line_ptr); + else if (lh->version == 5) + { + line_ptr = read_dwarf5_line_header_paths (lh, section, line_ptr); + if (line_ptr == NULL) + { + do_cleanups (back_to); + return NULL; + } + } + if (line_ptr == NULL) + { + do_cleanups (back_to); + return NULL; + } - add_file_name (lh, cur_file, dir_index, mod_time, length); + /* In order to not hang existing gdb's the experimental version of TLL + support uses a gross hack. The extension is embedded in a line header + that looks like a version 4 header, and in the line number program that + is a single entry that masks out both the real programs (logicals and + actuals), plus the version field is different. */ + if (lh->version == DW_VERSION_EXPERIMENTAL_TLL) + { + line_ptr + = read_experimental_tll_header_and_tables (lh, section, line_ptr, + end_of_header_length, + program_end); + if (line_ptr == NULL) + { + do_cleanups (back_to); + return NULL; + } + } + else + { + lh->statement_program_start = line_ptr; + lh->statement_program_end = program_end; } - line_ptr += bytes_read; - lh->statement_program_start = line_ptr; - if (line_ptr > (section->buffer + section->size)) - complaint (&symfile_complaints, - _("line number info header doesn't " - "fit in `.debug_line' section")); + if (line_ptr > program_end) + { + dwarf2_section_buffer_overflow_complaint (section); + do_cleanups (back_to); + return NULL; + } discard_cleanups (back_to); return lh; @@ -17686,6 +18244,28 @@ psymtab_include_file_name (const struct line_header *lh, int file_index, return include_name; } +/* An entry in the "logicals" linetable of the Two Level Line Tables + extension to dwarf5. */ + +typedef struct +{ + unsigned int op_index; + unsigned int file; + unsigned int line; + CORE_ADDR address; + unsigned int discriminator; + int is_stmt; + unsigned int context; + unsigned int subprogram; +} logical_line; + +DEF_VEC_O (logical_line); + +/* Function to record a line number. */ + +typedef void (record_line_ftype) (struct subfile *subfile, int line, + CORE_ADDR pc); + /* State machine to track the state of the line number program. */ typedef struct @@ -17699,6 +18279,12 @@ typedef struct int is_stmt; unsigned int discriminator; + /* Two Level Line Tables. + http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables + http://www.dwarfstd.org/ShowIssue.php?issue=140906.1 */ + unsigned int context; + unsigned int subprogram; + /* Additional bits of state we need to track. */ /* The last file that we called dwarf2_start_subfile for. @@ -17732,8 +18318,65 @@ typedef struct Otherwise we're building partial symtabs and are just interested in finding include files mentioned by the line number program. */ int record_lines_p; + + /* Non-zero if we're reading Two Level Line Tables (TLLs). */ + int two_level_p; + + /* Non-zero if we're building the logical line table. + Otherwise we're building the actual line table. + The distinction comes from the TLL feature. + An "actual" line is what gets recorded in GDB's own tables. + A logical line is used to help compute actual line entries. */ + int build_logicals_p; + + /* The logical line table. */ + VEC (logical_line) *logical_line_table; } lnp_reader_state; +/* Append a line to the logical line table. + Note: There are no heuristics involved in building this table. + The finite state machine must be followed to the letter because entries + in the actuals table will refer to entries in the logicals table assuming + the state machine has been precisely followed. + Assuming no bugs of course :-). */ + +static void +dwarf_append_logical_line (lnp_reader_state *reader, + const lnp_state_machine *state) +{ + logical_line entry; + + if (dwarf_line_debug) + { + unsigned int logical_line_nr + = VEC_length (logical_line, reader->logical_line_table) + 1; + const char *file_name = "???"; + + if (state->file != 0 + && state->file - 1 < reader->line_header->num_file_names) + file_name = reader->line_header->file_names[state->file - 1].name; + + fprintf_unfiltered (gdb_stdlog, + "Adding logical line %u: file %u(%s), line %u," + " address %s, is_stmt %u, discrim %u\n", + logical_line_nr, state->file, lbasename (file_name), + state->line, + paddress (reader->gdbarch, state->address), + state->is_stmt, state->discriminator); + } + + entry.op_index = state->op_index; + entry.file = state->file; + entry.line = state->line; + entry.address = state->address; + entry.is_stmt = state->is_stmt; + entry.discriminator = state->discriminator; + entry.context = state->context; + entry.subprogram = state->subprogram; + + VEC_safe_push (logical_line, reader->logical_line_table, &entry); +} + /* Ignore this record_line request. */ static void @@ -17833,66 +18476,128 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, dwarf_record_line_1 (gdbarch, subfile, 0, address, p_record_line); } -/* Record the line in STATE. +/* Record either a logical line or an actual line. END_SEQUENCE is non-zero if we're processing the end of a sequence. */ static void dwarf_record_line (lnp_reader_state *reader, lnp_state_machine *state, int end_sequence) { - const struct line_header *lh = reader->line_header; - unsigned int file, line, discriminator; - int is_stmt; - - file = state->file; - line = state->line; - is_stmt = state->is_stmt; - discriminator = state->discriminator; - - if (dwarf_line_debug) + if (reader->build_logicals_p) { - fprintf_unfiltered (gdb_stdlog, - "Processing actual line %u: file %u," - " address %s, is_stmt %u, discrim %u\n", - line, file, - paddress (reader->gdbarch, state->address), - is_stmt, discriminator); + /* If there's a problem with a value here we leave it + to processing the actuals table to flag it. */ + dwarf_append_logical_line (reader, state); } - - if (file == 0 || file - 1 >= lh->num_file_names) - dwarf2_debug_line_missing_file_complaint (); - /* For now we ignore lines not starting on an instruction boundary. - But not when processing end_sequence for compatibility with the - previous version of the code. */ - else if (state->op_index == 0 || end_sequence) + else { - lh->file_names[file - 1].included_p = 1; - if (reader->record_lines_p && is_stmt) + const struct line_header *lh = reader->line_header; + unsigned int file, line, discriminator; + int is_stmt; + + /* If we're reading the actuals table, a lot of the info + comes from the logicals table, so fetch it. */ + if (reader->two_level_p) { - if (state->last_subfile != current_subfile || end_sequence) + const logical_line *table + = VEC_address (logical_line, reader->logical_line_table); + + if (state->line == 0 + || (state->line - 1 + >= VEC_length (logical_line, reader->logical_line_table))) { - dwarf_finish_line (reader->gdbarch, state->last_subfile, - state->address, state->record_line); + complaint (&symfile_complaints, + _("logical line number is zero" + " or too large")); + return; } - if (!end_sequence) + /* The "line number" when processing the actual line table is + an origin-1 index into the logical line table. */ + file = table[state->line - 1].file; + line = table[state->line - 1].line; + is_stmt = table[state->line - 1].is_stmt; + discriminator = table[state->line - 1].discriminator; + } + else + { + file = state->file; + line = state->line; + is_stmt = state->is_stmt; + discriminator = state->discriminator; + } + + if (dwarf_line_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Processing actual line %u: file %u," + " address %s, is_stmt %u, discrim %u\n", + line, file, + paddress (reader->gdbarch, state->address), + is_stmt, discriminator); + } + + if (file == 0 || file - 1 >= lh->num_file_names) + dwarf2_debug_line_missing_file_complaint (); + /* For now we ignore lines not starting on an instruction boundary. + But not when processing end_sequence for compatibility with the + previous version of the code. */ + else if (state->op_index == 0 || end_sequence) + { + lh->file_names[file - 1].included_p = 1; + if (reader->record_lines_p && is_stmt) { - if (dwarf_record_line_p (line, state->last_line, - state->line_has_non_zero_discriminator, - state->last_subfile)) + /* If we're reading the actuals line number program, then we + have to create subfiles here as DW_LNS_set_file isn't + used. */ + if (reader->two_level_p + /* Only do this if we need to, start_subfile does a + linear search for existing files. */ + && file != state->last_file) { - dwarf_record_line_1 (reader->gdbarch, current_subfile, - line, state->address, - state->record_line); + struct file_entry *fe; + const char *dir = NULL; + + fe = &lh->file_names[file - 1]; + if (fe->dir_index) + dir = lh->include_dirs[fe->dir_index - 1]; + /* dwarf2_start_subfile sets current_subfile, so save this + now. */ + state->last_subfile = current_subfile; + state->line_has_non_zero_discriminator = discriminator != 0; + dwarf2_start_subfile (fe->name, dir); + /* This records what's in current_subfile in a way we can + compare with the file in the state machine. */ + state->last_file = file; + } + + if (state->last_subfile != current_subfile) + { + dwarf_finish_line (reader->gdbarch, state->last_subfile, + state->address, state->record_line); + } + + if (!end_sequence) + { + if (dwarf_record_line_p (line, state->last_line, + state->line_has_non_zero_discriminator, + state->last_subfile)) + { + dwarf_record_line_1 (reader->gdbarch, current_subfile, + line, state->address, + state->record_line); + } + state->last_subfile = current_subfile; + state->last_line = line; } - state->last_subfile = current_subfile; - state->last_line = line; } } } } -/* Initialize STATE for the start of a line number program. */ +/* Initialize STATE for the start of a line number program. + TODO(dje): Seems like this should be reset at the start of each sequence + but that's not what the previous code did. */ static void init_lnp_state_machine (lnp_state_machine *state, @@ -17920,6 +18625,8 @@ init_lnp_state_machine (lnp_state_machine *state, state->address = gdbarch_adjust_dwarf2_line (reader->gdbarch, 0, 0); state->is_stmt = reader->line_header->default_is_stmt; state->discriminator = 0; + state->context = 0; + state->subprogram = 0; } /* Check address and if invalid nop-out the rest of the lines in this @@ -17955,11 +18662,23 @@ check_line_address (struct dwarf2_cu *cu, lnp_state_machine *state, /* Subroutine of dwarf_decode_lines to simplify it. Process the line number information in LH. If DECODE_FOR_PST_P is non-zero, all we do is process the line number - program in order to set included_p for every referenced header. */ + program in order to set included_p for every referenced header. -static void + Two Level Line Tables extension: If LOGICALS_PTR is non-NULL then we are + processing TLLs. If PASS is 1 then we are reading the logicals table, + and on return the result is stored in *LOGICALS_PTR. + If PASS is 2 then we are reading the actuals table, and *LOGICALS_PTR is + the used as input. + If LOGICALS_PTR is NULL (dwarf5 and earlier), then PASS must be 1. + If DECODE_FOR_PST_P is non-zero, then LOGICALS_PTR must be NULL and + PASS must be 1. + + The result is zero for success, -1 for failure. */ + +static int dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, - const int decode_for_pst_p, CORE_ADDR lowpc) + const int decode_for_pst_p, CORE_ADDR lowpc, + VEC (logical_line) **logicals_ptr, int pass) { const gdb_byte *line_ptr, *extended_end; const gdb_byte *line_end; @@ -17969,20 +18688,78 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; struct gdbarch *gdbarch = get_objfile_arch (objfile); + int two_level_p = logicals_ptr != NULL; + /* Non-zero if we're building the logical line table. */ + int build_logicals_p = two_level_p && pass == 1; + /* Non-zero if we're reading the actuals table, otherwise we're reading + the logicals table. */ + int reading_actuals_p = pass == 2; /* Non-zero if we're recording line info (as opposed to building partial - symtabs). */ - int record_lines_p = !decode_for_pst_p; + symtabs or building the logical line table). */ + int record_lines_p = (!decode_for_pst_p + && (!two_level_p || (two_level_p && pass == 2))); + struct cleanup *cleanups, *logicals_cleanup; /* A collection of things we need to pass to dwarf_record_line. */ lnp_reader_state reader_state; + cleanups = make_cleanup (null_cleanup, NULL); + + /* Reading the line number program state machine involves a lot of bit-fiddly + code and we'd rather have only one copy of it. OTOH it is used for + multiple purposes. These asserts exist, besides to validate the + arguments, to add clarity to how this function can be used. */ + + /* If we're not using TLLs there's only one pass. */ + if (!two_level_p) + gdb_assert (pass == 1); + /* Both could be zero (building partial symtabs), but at most one can be + non-zero. */ + gdb_assert (!(build_logicals_p && record_lines_p)); + /* If we're building partial symtabs, we only need the file information. */ + if (decode_for_pst_p) + gdb_assert (logicals_ptr == NULL && pass == 1); + /* If we're reading the actuals table then we should be recording lines. */ + if (reading_actuals_p) + gdb_assert (record_lines_p); + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - line_ptr = lh->statement_program_start; - line_end = lh->statement_program_end; + if (reading_actuals_p) + { + line_ptr = lh->actuals_program_start; + line_end = lh->actuals_program_end; + } + else + { + line_ptr = lh->statement_program_start; + line_end = lh->statement_program_end; + } reader_state.gdbarch = gdbarch; reader_state.line_header = lh; reader_state.record_lines_p = record_lines_p; + reader_state.two_level_p = two_level_p; + reader_state.build_logicals_p = build_logicals_p; + reader_state.logical_line_table = NULL; + + logicals_cleanup = NULL; + if (two_level_p) + { + if (pass == 1) + { + *logicals_ptr = NULL; + logicals_cleanup = make_cleanup (VEC_cleanup (logical_line), + &reader_state.logical_line_table); + } + else + reader_state.logical_line_table = *logicals_ptr; + } + + /* Note: If we're building the logical line table then we need to protect it + with a cleanup, but we also need to discard that cleanup at the end. + Therefore be careful with adding new cleanups after this point: they + can't just be simply added and forgotten because they will be discarded + along with logicals_cleanup. */ /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) @@ -17994,6 +18771,23 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, /* Reset the state machine at the start of each sequence. */ init_lnp_state_machine (&state_machine, &reader_state); + /* Notes on Two Level Line Tables. + http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables + + When only a single line number table is used, the context/subprogram + registers are not used, and the logicals table "degrades gracefully + to the single table of dwarf4". + + When both a logical line table and an actual line table are + used, the basic_block, end_sequence, and isa registers are + not used in the logical line table. The file, column, + is_stmt, prologue_end, epilogue_begin, discriminator, + context, and subprogram registers are not used in the actual + line table. In the actual line table, the line register + represents a row in the logicals table rather than an actual + line number. Rows in the logical line table are numbered + starting at 1. */ + if (record_lines_p && lh->num_file_names >= state_machine.file) { /* Start a subfile for the current file of the state machine. */ @@ -18105,7 +18899,8 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, default: complaint (&symfile_complaints, _("mangled .debug_line section")); - return; + do_cleanups (cleanups); + return -1; } /* Make sure that we parsed the extended op correctly. If e.g. we expected a different address size than the producer used, @@ -18114,7 +18909,8 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, { complaint (&symfile_complaints, _("mangled .debug_line section")); - return; + do_cleanups (cleanups); + return -1; } break; case DW_LNS_copy: @@ -18217,6 +19013,107 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, line_ptr += 2; } break; + case DW_LNS_set_subprogram: /* Logicals table only. */ + /* case DW_LNS_set_address_from_logical: - Actuals table only, + same value as DW_LNS_set_subprogram. */ + if (reading_actuals_p) + { + /* DW_LNS_set_address_from_logical */ + int line_adj = read_signed_leb128 (abfd, line_ptr, + &bytes_read); + + line_ptr += bytes_read; + state_machine.line = (int) state_machine.line + line_adj; + if (state_machine.line == 0 + || (state_machine.line - 1 + >= VEC_length (logical_line, + reader_state.logical_line_table))) + { + complaint (&symfile_complaints, + _("logical line number is zero" + " or too large")); + } + else + { + const logical_line *table + = VEC_address (logical_line, + reader_state.logical_line_table); + CORE_ADDR address + = table[state_machine.line - 1].address; + + check_line_address (cu, &state_machine, line_ptr, + lowpc, address); + state_machine.address = address; + state_machine.op_index + = table[state_machine.line - 1].op_index; + } + } + else /* DW_LNS_set_subprogram */ + { + state_machine.subprogram + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + state_machine.context = 0; + } + break; + case DW_LNS_inlined_call: /* Logicals table only. */ + { + int context_adj = read_signed_leb128 (abfd, line_ptr, + &bytes_read); + + line_ptr += bytes_read; + if (build_logicals_p) + { + state_machine.context + = ((int) VEC_length (logical_line, + reader_state.logical_line_table) + + context_adj); + state_machine.subprogram + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + } + else + { + complaint (&symfile_complaints, + _("DW_LNS_inlined_call seen outside of" + " logicals table")); + } + } + break; + case DW_LNS_pop_context: /* Logicals table only. */ + if (build_logicals_p) + { + unsigned int logical = state_machine.context; + const logical_line *table + = VEC_address (logical_line, + reader_state.logical_line_table); + + if (logical > 0 + && (logical - 1 + < VEC_length (logical_line, + reader_state.logical_line_table))) + { + state_machine.file = table[logical - 1].file; + state_machine.line = table[logical - 1].line; + state_machine.discriminator + = table[logical - 1].discriminator; + state_machine.is_stmt = table[logical - 1].is_stmt; + state_machine.context = table[logical - 1].context; + state_machine.subprogram = table[logical - 1].subprogram; + } + else + { + complaint (&symfile_complaints, + _("invalid context to pop from")); + } + } + else + { + complaint (&symfile_complaints, + _("DW_LNS_pop_context seen outside of" + " logicals table")); + } + break; default: { /* Unknown standard opcode, ignore it. */ @@ -18231,13 +19128,28 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, } } - if (!end_sequence) - dwarf2_debug_line_missing_end_sequence_complaint (); + if (!build_logicals_p) + { + if (!end_sequence) + dwarf2_debug_line_missing_end_sequence_complaint (); + + /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, + in which case we still finish recording the last line). */ + dwarf_record_line (&reader_state, &state_machine, 1); + } + } - /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, - in which case we still finish recording the last line). */ - dwarf_record_line (&reader_state, &state_machine, 1); + /* Pass back the logicals table to the caller if we just built it. */ + if (two_level_p && pass == 1) + { + *logicals_ptr = reader_state.logical_line_table; + discard_cleanups (logicals_cleanup); } + else + gdb_assert (logicals_cleanup == NULL); + + do_cleanups (cleanups); + return 0; } /* Decode the Line Number Program (LNP) for the given line_header @@ -18277,7 +19189,35 @@ dwarf_decode_lines (struct line_header *lh, const char *comp_dir, const int decode_for_pst_p = (pst != NULL); if (decode_mapping) - dwarf_decode_lines_1 (lh, cu, decode_for_pst_p, lowpc); + { + /* If an "actuals" line number program is present, we need to process the + line number information in two passes: the first pass builds the + "logicals" line table, and then the second pass builds the "actuals" + table (the one we use). If we're building partial symtabs, then we + just want file information and therefore just need to read the + logicals table. */ + if (!decode_for_pst_p && lh->actuals_program_start != NULL) + { + VEC (logical_line) *logical_line_table = NULL; + struct cleanup *cleanups = NULL; + + if (dwarf_decode_lines_1 (lh, cu, decode_for_pst_p, lowpc, + &logical_line_table, 1) == 0) + { + cleanups = make_cleanup (VEC_cleanup (logical_line), + &logical_line_table); + dwarf_decode_lines_1 (lh, cu, decode_for_pst_p, lowpc, + &logical_line_table, 2); + } + if (cleanups != NULL) + do_cleanups (cleanups); + } + else + dwarf_decode_lines_1 (lh, cu, decode_for_pst_p, lowpc, NULL, 1); + } + + /* We ignore a failure when building the real or "actuals" line table, + as we can still build the symtabs. */ if (decode_for_pst_p) { @@ -19878,6 +20818,28 @@ dwarf_type_encoding_name (unsigned enc) return name; } +/* Return name of a line number table content type. */ + +static const char * +dwarf_line_number_content_type_name (unsigned int type) +{ + switch (type) + { + case DW_LNCT_path: + return "DW_LNCT_path"; + case DW_LNCT_directory_index: + return "DW_LNCT_directory_index"; + case DW_LNCT_timestamp: + return "DW_LNCT_timestamp"; + case DW_LNCT_size: + return "DW_LNCT_size"; + case DW_LNCT_MD5: + return "DW_LNCT_MD5"; + default: + return "DW_LNCT_<unknown>"; + } +} + static void dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) { @@ -21265,6 +22227,12 @@ skip_form_bytes (bfd *abfd, const gdb_byte *bytes, const gdb_byte *buffer_end, bytes += 8; break; +#if 0 /* Disabled until DW_FORM_data16 appears in dwarf2.def. */ + case DW_FORM_data16: + bytes += 16; + break; +#endif + case DW_FORM_string: read_direct_string (abfd, bytes, &bytes_read); bytes += bytes_read; @@ -21304,13 +22272,9 @@ skip_form_bytes (bfd *abfd, const gdb_byte *bytes, const gdb_byte *buffer_end, break; default: - { - complain: - complaint (&symfile_complaints, - _("invalid form 0x%x in `%s'"), - form, get_section_name (section)); - return NULL; - } + dwarf2_invalid_form_complaint (form, _("skipping"), + bytes - section->buffer, section); + return NULL; } return bytes; diff --git a/gdb/symfile.h b/gdb/symfile.h index 1e719dc..15cc146 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -615,6 +615,7 @@ struct dwarf2_debug_sections { struct dwarf2_section_names macro; struct dwarf2_section_names str; struct dwarf2_section_names str_offsets; /* GOOGLE LOCAL */ + struct dwarf2_section_names line_str; struct dwarf2_section_names ranges; struct dwarf2_section_names types; struct dwarf2_section_names addr; diff --git a/gdb/testsuite/boards/fission-tll.exp b/gdb/testsuite/boards/fission-tll.exp new file mode 100644 index 0000000..4c4a95a --- /dev/null +++ b/gdb/testsuite/boards/fission-tll.exp @@ -0,0 +1,39 @@ +# Copyright 2012-2015 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This file is a dejagnu "board file" and is used to run the testsuite +# with Fission and Two Level Line Tables support. +# http://gcc.gnu.org/wiki/DebugFission +# http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables +# +# Example usage: +# bash$ make check RUNTESTFLAGS='--target_board=fission-tll' + +# This is copied from baseboards/unix.exp. +# At the moment this only supports things that unix.exp supports. +load_generic_config "unix" +process_multilib_options "" +set_board_info compiler "[find_gcc]" + +# This requires a relatively recent version of gcc (>4.7) and gold +# for the linker. +# Note: -ggnu-pubnames is required for Gold to build .gdb_index, and while +# -gsplit-dwarf implies -ggnu-pubnames for gcc, it doesn't for clang. +set_board_info debug_flags "-gdwarf-4 -gsplit-dwarf -ggnu-pubnames -fdebug-types-section -Wl,--gdb-index -ftwo-level-line-tables" + +# This is needed otherwise dejagnu tries to rsh to host "fission-tll". Blech. +# Double blech: set_board_info only sets the value if not already set. +unset_board_info isremote +set_board_info isremote 0 diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index 9e9409b..a3eb2f6 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -163,6 +163,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = { { NULL, NULL }, /* debug_macro */ { ".dwstr", NULL }, { NULL, NULL }, /* debug_str_offsets */ /* GOOGLE LOCAL */ + { NULL, NULL }, /* debug_line_str */ { ".dwrnges", NULL }, { NULL, NULL }, /* debug_types */ { NULL, NULL }, /* debug_addr */ diff --git a/include/dwarf2.def b/include/dwarf2.def index e29c536..39c5904 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -202,6 +202,8 @@ DW_FORM (DW_FORM_sec_offset, 0x17) DW_FORM (DW_FORM_exprloc, 0x18) DW_FORM (DW_FORM_flag_present, 0x19) DW_FORM (DW_FORM_ref_sig8, 0x20) +/* DWARF 5. */ +DW_FORM (DW_FORM_line_strp, 0x1f) /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ DW_FORM (DW_FORM_GNU_addr_index, 0x1f01) DW_FORM (DW_FORM_GNU_str_index, 0x1f02) diff --git a/include/dwarf2.h b/include/dwarf2.h index 4ada871..048aa56 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -222,7 +222,13 @@ enum dwarf_line_number_ops /* DWARF 3. */ DW_LNS_set_prologue_end = 10, DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 + DW_LNS_set_isa = 12, + /* Experimental DWARF 5 extensions. + See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables. */ + DW_LNS_set_address_from_logical = 13, /* Actuals table only. */ + DW_LNS_set_subprogram = 13, /* Logicals table only. */ + DW_LNS_inlined_call = 14, /* Logicals table only. */ + DW_LNS_pop_context = 15 /* Logicals table only. */ }; /* Line number extended opcodes. */ @@ -268,6 +274,24 @@ enum dwarf_location_list_entry_type DW_LLE_GNU_start_length_entry = 3 }; +/* Type codes for line number program content descriptors (DWARF 5). */ + +enum dwarf_line_number_content_type + { + DW_LNCT_path = 1, + DW_LNCT_directory_index = 2, + DW_LNCT_timestamp = 3, + DW_LNCT_size = 4, + DW_LNCT_MD5 = 5, + /* Experimental DWARF 5 extensions. + See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables. */ + DW_LNCT_subprogram_name = 6, + DW_LNCT_decl_file = 7, + DW_LNCT_decl_line = 8, + DW_LNCT_lo_user = 0x2000, + DW_LNCT_hi_user = 0x3fff + }; + #define DW_CIE_ID 0xffffffff #define DW64_CIE_ID 0xffffffffffffffffULL #define DW_CIE_VERSION 1 |