Compare commits

...

27 Commits

Author SHA1 Message Date
Cary Coutant
83222732f1 Fix crash when section ends with a .lloc directive not followed by an insn.
gas/
	* dwarf2dbg.c (emit_logicals): Handle case where e->label is NULL.
2015-03-25 15:27:52 -07:00
Cary Coutant
c312754797 Improve ODR checking.
2015-02-09  Cary Coutant  <ccoutant@google.com>

gold/
	* dwarf_reader.cc (Sized_dwarf_line_info::read_lines): Fix debug
	output to print correct context.
	(Sized_dwarf_line_info::do_addr2line): Add debug output. Return
	up to 4 more locations at the beginning of the function.
	* symtab.cc (Symbol_table::detect_odr_violations): Get canonical
	result before sorting list of line numbers.
2015-02-22 23:44:29 -08:00
Cary Coutant
76b3c0a533 Support compressed debug in dyn objects.
2015-02-09  Cary Coutant  <ccoutant@google.com>

gold/
	* dwp.cc (Sized_relobj_dwo::do_decompressed_section_contents): Delete.
	(Sized_relobj_dwo::setup): Setup map of compressed sections.
	(print_version): Update copyright.
	* dynobj.cc (Sized_dynobj::base_read_symbols): Set up map of compressed
	sections.
	* object.cc (Sized_relobj_file::compressed_sections): Delete.
	(build_compressed_section_map): Add decompress_if_needed parameter.
	Adjust callers.
	(Sized_relobj_file::do_find_special_sections): Set compressed sections
	map in Object base class.
	(Sized_relobj_file::do_decompressed_section_contents): Rename to
	Object::decompressed_section_contents.
	(Sized_relobj_file::do_discard_decompressed_sections): Rename to
	Object::discard_decompressed_sections.
	* object.h (Object::compressed_sections_): New data member.
	(Object::section_is_compressed): Remove virtual, implement here.
	(Object::decompressed_section_contents): Remove virtual.
	(Object::do_section_is_compressed): Delete.
	(Object::do_decompressed_section_contents): Delete.
	(Object::set_compressed_sections): New method.
	(Object::compressed_sections): New method.
	(Sized_relobj_file::do_section_is_compressed): Delete.
	(Sized_relobj_file::do_decompressed_section_contents): Delete.
	(Sized_relobj_file::do_discard_decompressed_sections): Delete.
	(Sized_relobj_file::compressed_sections): Delete.
2015-02-22 23:44:23 -08:00
Cary Coutant
f0c3f9ad7b Add gold support for two-level line tables.
2015-01-30  Cary Coutant  <ccoutant@google.com>

elfcpp/
	* dwarf.h (enum DW_LNS): Add experimental two-level line table opcodes.
	(enum DW_LNCT): New enum for DWARF-5.

gold/
	* debug.h (DEBUG_LOCATION): New constant.
	(debug_string_to_enum): Add DEBUG_LOCATION.
	* dwarf_reader.cc (struct LineStateMachine): Add context field.
	(ResetLineStateMachine): Likewise.
	(Sized_dwarf_line_info::Sized_dwarf_line_info): Add support for
	two-level line tables.
	(Sized_dwarf_line_info::read_header_prolog): Likewise. Also add
	support for DWARF-3+ line tables.
	(Sized_dwarf_line_info::read_header_tables_v5): New method.
	(Sized_dwarf_line_info::process_one_opcode): Add support for two-level
	line tables.
	(Sized_dwarf_line_info::read_lines): Likewise.
	(Sized_dwarf_line_info::read_line_mappings): Likewise.
	(Sized_dwarf_line_info::do_addr2line): Add debug output.
	* dwarf_reader.h (Sized_dwarf_line_info::~Sized_dwarf_line_info):
	Delete str_buffer_start_.
	(DWARF5_EXPERIMENTAL_LINE_TABLE): New constant.
	(Sized_dwarf_line_info::read_header_tables_v5): New method.
	(Sized_dwarf_line_info::read_lines): Update prototype.
	(Sized_dwarf_line_info::process_one_opcode): Likewise.
	(Sized_dwarf_line_info::max_ops_per_insn): New data member.
	(Sized_dwarf_line_info::str_buffer_): New data member.
	(Sized_dwarf_line_info::str_buffer_end_): New data member.
	(Sized_dwarf_line_info::str_buffer_start_): New data member.
	(Sized_dwarf_line_info::end_of_header_length_): New data member.
	(Sized_dwarf_line_info::logicals_start_): New data member.
	(Sized_dwarf_line_info::actuals_start_): New data member.
	(Sized_dwarf_line_info::end_of_unit_): New data member.
2015-02-22 23:43:57 -08:00
Cary Coutant
589778e030 Fix formatting.
2015-02-06  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (display_debug_lines_raw): Fix formatting.
2015-02-22 23:43:48 -08:00
Cary Coutant
b3759731e0 For ODR checking, when we see two .lloc directives in a row, output them both.
2015-01-30  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (dwarf2_directive_loc): Always emit extra .lloc.
2015-01-30 04:16:46 -08:00
Cary Coutant
89442fc483 Reformat experimental header for compatibility with old DWARF consumers.
2015-01-28  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (read_debug_line_header): Adjust to reformatted header.
	(display_line_program): Add missing space in output.
	(display_debug_lines_raw): Adjust to reformatted header.
	* dwarf.h (DWARF2_Internal_LineInfo): Remove li_actuals_table_offset.
2015-01-28 22:05:06 -08:00
Cary Coutant
05305251ad Reformat experimental header for compatibility with old DWARF consumers.
Old consumers will now see a DWARF-4 header, with new fields added at the
end of the header. The new fields and the entire logicals and actuals
tables are wrapped in a single extended opcode so that old consumers
will see just the single opcode.

2015-01-28  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (line_base): New variable.
	(line_range): New variable.
	(DWARF2_EXPERIMENTAL_LINE_OPCODE_BASE): Rename.
	(DWARF2_LINE_BASE): Restore to original value.
	(DWARF2_LINE_RANGE): Likewise.
	(DWARF5_EXPERIMENTAL_LINE_BASE): New macro.
	(DWARF5_EXPERIMENTAL_LINE_RANGE): New macro.
	(SPECIAL_LINE): Use line_base, line_range.
	(size_inc_line_addr): Likewise.
	(emit_inc_line_addr): Likewise.
	(out_debug_line): Reformat header for compatibility with old DWARF
	consumers.
2015-01-28 22:01:38 -08:00
Cary Coutant
d4c40a8552 Some minor cleanups in two-level line table support.
2015-01-28  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (free_logicals): Set logicals_table to NULL.
	(fetch_indirect_string): Correct boundary check.
	(fetch_indirect_line_string): Likewise.
	(fetch_indexed_string): Likewise.
	(display_dir_file_table_v5): Print unsigned value.
2015-01-28 11:22:01 -08:00
Cary Coutant
f7318adf46 Fix to read signed LEB128 for operand to DW_LNS_set_address_from_logical.
2015-01-26  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (display_line_program): Operand to
	DW_LNS_set_address_from_logical is signed.
2015-01-26 15:02:54 -08:00
Cary Coutant
a38fe6acd2 Reset discriminator after each row.
2015-01-26  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (display_line_program): Reset discriminator after each row.
2015-01-26 12:21:11 -08:00
Cary Coutant
e82144ec93 Set entsize for .debug_line_str section.
2015-01-23  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (dwarf2_finish): Set entsize for .debug_line_str section.
2015-01-23 16:35:06 -08:00
Cary Coutant
b18ad49bab Emit address_size and segment_size for version 5 line number tables.
2015-01-23  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (out_debug_line): Emit address_size and segment_size
	for version 5 line number tables.
2015-01-23 16:35:06 -08:00
Cary Coutant
285d7b5c33 Add address_size and segment_size to line number program header version 5.
2015-01-23  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.h (struct DWARF2_Internal_LineInfo): Add li_address_size and
	li_segment_size.
	* dwarf.c (read_debug_line_header): Read li_address_size and
	li_segment_size.
	(display_debug_lines_raw): Print li_address_size and li_segment_size.
2015-01-23 16:34:56 -08:00
Cary Coutant
2031626eb7 Update DW_LNS_opcodes for two-level line tables.
2015-01-23  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (append_logical): Fix format string.
	(display_line_program): Replace DW_LNS_set_context with
	DW_LNS_inlined_call. Fix format strings.
2015-01-23 13:14:41 -08:00
Cary Coutant
dc87246eb9 Update DW_LNS opcodes for two-level line tables.
2015-01-23  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (emit_logicals): Increase max number of
	DW_LNS_pop_context opcodes. Change DW_LNS_set_context
	to DW_LNS_inlined_call.
	(out_debug_line): Adjust operand lengths array.
2015-01-23 13:12:29 -08:00
Cary Coutant
49e4ed79b8 Update DW_LNS opcodes.
2015-01-23  Cary Coutant  <ccoutant@google.com>

include/
	* dwarf2.h (enum dwarf_line_number_ops): Remove
	DW_LNS_set_context, add DW_LNS_inlined_call; renumber
	new opcodes.
2015-01-23 13:11:06 -08:00
Cary Coutant
c63bcc5d2d Track discriminator when processing line number table.
2015-01-21  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (process_extended_line_op): Track discriminator.
2015-01-21 16:01:18 -08:00
Cary Coutant
361595a3de Ignore line tables whose versions we don't support.
2015-01-21  Cary Coutant  <ccoutant@google.com>

gold/
	* dwarf_reader.cc (Sized_dwarf_line_info::read_header_prolog): Check
	line table version number.
	(Sized_dwarf_line_info::read_line_mappings): Likewise.
2015-01-21 15:45:55 -08:00
Cary Coutant
fc0d0b62cb Silence "may be uninitialized" warnings.
2015-01-21  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (display_debug_lines_raw): Silence "may be uninitialized"
	warnings.
2015-01-21 15:43:52 -08:00
Cary Coutant
6a8cf4ce11 Fix bugs displaying DW_LNS_set_context and DW_LNS_pop_context.
2015-01-15  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (append_logical): Print summary for each logical row.
	(display_line_program): Remove incorrect consumption of an LEB128
	when reading DW_LNS_set_context and DW_LNS_pop_context.
2015-01-15 13:58:58 -08:00
Cary Coutant
ab071889a9 Fix problems with DW_LNS_pop_context in logicals table.
2015-01-15  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (emit_logicals): Fix bug in generating
	DW_LNS_pop_context.
	(process_entries): Don't always emit DW_LNS_set_address_from_logical
	when crossing frag boundaries.
2015-01-15 13:58:47 -08:00
Cary Coutant
af9adba57a Add support for DWARF-5 and experimental two-level line number tables.
http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables

2015-01-06  Cary Coutant  <ccoutant@google.com>

binutils/
	* dwarf.c (struct State_Machine_Registers): Add discriminator,
	context, and subprogram.
	(reset_state_machine): Likewise.
	(logicals_table, logicals_allocated, logicals_count): New variables.
	(free_logicals): New function.
	(append_logical): New function.
	(process_extended_line_op): Add is_logical parameter.
	(fetch_indirect_line_string): New function.
	(DWARF2_LINE_EXPERIMENTAL_VERSION): New macro.
	(read_debug_line_header): Add pinitial_length_size, poffset_size
	parameters.  Update all callers.  Check for new line table versions.
	(display_directory_table_v4): New function, factored out from
	display_debug_lines_raw.
	(display_file_name_table_v4): Likewise.
	(display_dir_file_table_v5): New function.
	(display_line_program): New function, factored out from
	display_debug_lines_raw.
	(display_debug_lines_raw): Support new line table versions.
	(display_debug_lines_decoded): Add missing newline to warning.
	(display_debug_lines): Load .debug_line_str section.
	(debug_displays): Add .debug_line_str section.
	* dwarf.h (DWARF2_Internal_LineInfo): Add li_actuals_table_offset field.
	(dwarf_section_display_enum): Add line_str.
	* readelf.c (process_section_headers): Add .debug_line_str.
2015-01-06 16:56:43 -08:00
Cary Coutant
c85ff14427 Update support for DWARF-5 and experimental two-level line number tables.
2015-01-06  Cary Coutant  <ccoutant@google.com>

gas/
	* dwarf2dbg.c (emit_logicals): Replace DW_LNS_inlined_call with
	DW_LNS_set_context and DW_LNS_set_subprogram.
	Fix bug where we emit wrong value for line number.
	(process_entries): Don't emit DW_LNS_negate_stmt in actuals table.
	(out_dwarf5_file_list): Fix bug where dir list or file list is empty.
	(out_debug_line): Update table of opcode lengths.
2015-01-06 16:40:43 -08:00
Cary Coutant
e7ca0f8d7d Update experimental DWARF-5 values for two-level line number tables.
http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables

2015-01-06  Cary Coutant  <ccoutant@google.com>

include/
    * dwarf2.h (enum dwarf_line_number_ops): Replace DW_LNS_inlined_call
    with DW_LNS_set_context and DW_LNS_set_subprogram.  Renumber subsequent
    opcodes.
2015-01-06 16:23:59 -08:00
Cary Coutant
b274bee161 Add support for DWARF-5 and experimental two-level line number tables.
2014-12-23  Cary Coutant  <ccoutant@google.com>

gas/
	* config/obj-elf.c (elf_pseudo_table): Add .lloc and .subprog
	directives.
	* dwarf2dbg.h (struct dwarf2_line_info): Add logical field.
	(dwarf2_directive_subprog): New function.
	(dwarf2_directive_loc): Add is_lloc parameter.
	* dwarf2dbg.c: Include "hash.h".
	(DWARF2_LINE_EXPERIMENTAL_VERSION): New macro.
	(DWARF2_EXPERIMENTAL_LINE_OPCODE_BASE): New macro.
	(opcode_base): New static variable.
	(DWARF2_LINE_BASE, DWARF2_LINE_RANGE): Adjust parameters.
	(DWARF2_LINE_MAX_OPS_PER_INSN): New macro.
	(SPECIAL_LINE, SPECIAL_ADDR): Use opcode_base.
	(struct subprog_entry): New struct.
	(subprogs, subprogs_in_use, subprogs_allocated): New variables.
	(struct logicals_entry): New struct.
	(logicals, logicals_in_use, logicals_allocated, logicals_with_labels):
	New variables.
	(struct string_table): New struct.
	(debug_line_str_table): New variable.
	(current): Add logical field.
	(dwarf2_gen_line_info): Fill in symbol and segment for recent logicals.
	(dwarf2_where): Add logical field.
	(make_subprog_entry): New function.
	(make_logical): New function.
	(dwarf2_directive_subprog): New function.
	(dwarf2_directive_loc): Add is_lloc parameter; add support for .lloc
	directive.
	(out_set_addr_from_logical): New function.
	(size_inc_line_addr): Fix signed/unsigned warnings. Use opcode_base.
	(emit_inc_line_addr): Likewise.
	(emit_logicals): New function.
	(process_entries): Add support for two-level line tables.
	(add_to_string_table): New function.
	(out_string_table): New function.
	(out_dwarf5_file_list): New function.
	(out_subprog_list): New function.
	(out_debug_line): Add support for DWARF-5 line tables and for
	experimental two-level line number tables.
	(dwarf2_finish): Likewise.
2015-01-01 10:59:24 -08:00
Cary Coutant
244e0772d8 Add experimental DWARF-5 values for two-level line number tables.
http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables

2014-12-23  Cary Coutant  <ccoutant@google.com>

include/
	* dwarf2.def (DW_FORM_line_strp): New constant.
	* dwarf2.h (enum dwarf_line_number_ops): Add DW_LNS_inlined_call,
	DW_LNS_pop_context, DW_LNS_set_address_from_logical.
	(enum dwarf_line_number_content_type): Add new DW_LNCT_ codes.
2015-01-01 10:59:24 -08:00
17 changed files with 2071 additions and 534 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,8 @@ typedef struct
{ {
dwarf_vma li_length; dwarf_vma li_length;
unsigned short li_version; unsigned short li_version;
unsigned char li_address_size;
unsigned char li_segment_size;
unsigned int li_prologue_length; unsigned int li_prologue_length;
unsigned char li_min_insn_length; unsigned char li_min_insn_length;
unsigned char li_max_ops_per_insn; unsigned char li_max_ops_per_insn;
@@ -123,6 +125,7 @@ enum dwarf_section_display_enum
macinfo, macinfo,
macro, macro,
str, str,
line_str,
loc, loc,
pubtypes, pubtypes,
gnu_pubtypes, gnu_pubtypes,

View File

@@ -5503,6 +5503,7 @@ process_section_headers (FILE * file)
|| (do_debug_macinfo && const_strneq (name, "macinfo")) || (do_debug_macinfo && const_strneq (name, "macinfo"))
|| (do_debug_macinfo && const_strneq (name, "macro")) || (do_debug_macinfo && const_strneq (name, "macro"))
|| (do_debug_str && const_strneq (name, "str")) || (do_debug_str && const_strneq (name, "str"))
|| (do_debug_str && const_strneq (name, "line_str"))
|| (do_debug_loc && const_strneq (name, "loc")) || (do_debug_loc && const_strneq (name, "loc"))
|| (do_debug_addr && const_strneq (name, "addr")) || (do_debug_addr && const_strneq (name, "addr"))
|| (do_debug_cu_index && const_strneq (name, "cu_index")) || (do_debug_cu_index && const_strneq (name, "cu_index"))

View File

@@ -147,7 +147,13 @@ enum DW_LINE_OPS
// DWARF 3. // DWARF 3.
DW_LNS_set_prologue_end = 10, DW_LNS_set_prologue_end = 10,
DW_LNS_set_epilogue_begin = 11, 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. // Line number extended opcodes.
@@ -235,6 +241,20 @@ enum DW_SECT
DW_SECT_MAX = DW_SECT_MACRO, DW_SECT_MAX = DW_SECT_MACRO,
}; };
enum DW_LNCT
{
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
};
} // End namespace elfcpp. } // End namespace elfcpp.
#endif // !defined(ELFCPP_DWARF_H) #endif // !defined(ELFCPP_DWARF_H)

View File

@@ -125,8 +125,10 @@ static const pseudo_typeS elf_pseudo_table[] =
{"8byte", cons, 8}, {"8byte", cons, 8},
/* These are used for dwarf2. */ /* These are used for dwarf2. */
{ "file", (void (*) (int)) dwarf2_directive_file, 0 }, { "file", (void (*) (int)) dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 }, { "loc", dwarf2_directive_loc, 0 },
{ "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 }, { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
{ "lloc", dwarf2_directive_loc, 1 },
{ "subprog", dwarf2_directive_subprog, 0 },
/* We need to trap the section changing calls to handle .previous. */ /* We need to trap the section changing calls to handle .previous. */
{"data", obj_elf_data, 0}, {"data", obj_elf_data, 0},

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@ struct dwarf2_line_info {
unsigned int isa; unsigned int isa;
unsigned int flags; unsigned int flags;
unsigned int discriminator; unsigned int discriminator;
unsigned int logical;
}; };
/* Implements the .file FILENO "FILENAME" directive. FILENO can be 0 /* Implements the .file FILENO "FILENAME" directive. FILENO can be 0
@@ -42,13 +43,29 @@ struct dwarf2_line_info {
number must be >0. */ number must be >0. */
extern char *dwarf2_directive_file (int dummy); extern char *dwarf2_directive_file (int dummy);
/* Experimental DWARF-5 extension:
Implements the .subprog SUBPNO ["SUBPROG" [FILENO LINENO]] directive.
FILENO is the file number, LINENO the line number and the
(optional) COLUMN the column of the source code that the following
instruction corresponds to. FILENO can be 0 to indicate that the
filename specified by the textually most recent .file directive
should be used. */
extern void dwarf2_directive_subprog (int dummy);
/* Implements the .loc FILENO LINENO [COLUMN] directive. FILENO is /* Implements the .loc FILENO LINENO [COLUMN] directive. FILENO is
the file number, LINENO the line number and the (optional) COLUMN the file number, LINENO the line number and the (optional) COLUMN
the column of the source code that the following instruction the column of the source code that the following instruction
corresponds to. FILENO can be 0 to indicate that the filename corresponds to. FILENO can be 0 to indicate that the filename
specified by the textually most recent .file directive should be specified by the textually most recent .file directive should be
used. */ used. */
extern void dwarf2_directive_loc (int dummy); /* Experimental DWARF-5 extension:
If IS_LLOC is true, implements the .lloc LOGICAL [FILENO LINENO [COLUMN]]
directive. FILENO is the file number, LINENO the line number and the
(optional) COLUMN the column of the source code that the following
instruction corresponds to. FILENO can be 0 to indicate that the
filename specified by the textually most recent .file directive
should be used. */
extern void dwarf2_directive_loc (int is_lloc);
/* Implements the .loc_mark_labels {0,1} directive. */ /* Implements the .loc_mark_labels {0,1} directive. */
extern void dwarf2_directive_loc_mark_labels (int dummy); extern void dwarf2_directive_loc_mark_labels (int dummy);

View File

@@ -38,9 +38,11 @@ const int DEBUG_SCRIPT = 0x2;
const int DEBUG_FILES = 0x4; const int DEBUG_FILES = 0x4;
const int DEBUG_RELAXATION = 0x8; const int DEBUG_RELAXATION = 0x8;
const int DEBUG_INCREMENTAL = 0x10; const int DEBUG_INCREMENTAL = 0x10;
const int DEBUG_LOCATION = 0x20;
const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES
| DEBUG_RELAXATION | DEBUG_INCREMENTAL); | DEBUG_RELAXATION | DEBUG_INCREMENTAL
| DEBUG_LOCATION);
// Convert a debug string to the appropriate enum. // Convert a debug string to the appropriate enum.
inline int inline int
@@ -54,6 +56,7 @@ debug_string_to_enum(const char* arg)
{ "files", DEBUG_FILES }, { "files", DEBUG_FILES },
{ "relaxation", DEBUG_RELAXATION }, { "relaxation", DEBUG_RELAXATION },
{ "incremental", DEBUG_INCREMENTAL }, { "incremental", DEBUG_INCREMENTAL },
{ "location", DEBUG_LOCATION },
{ "all", DEBUG_ALL } { "all", DEBUG_ALL }
}; };

View File

@@ -26,6 +26,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "debug.h"
#include "elfcpp_swap.h" #include "elfcpp_swap.h"
#include "dwarf.h" #include "dwarf.h"
#include "object.h" #include "object.h"
@@ -1526,6 +1527,7 @@ struct LineStateMachine
bool is_stmt; // stmt means statement. bool is_stmt; // stmt means statement.
bool basic_block; bool basic_block;
bool end_sequence; bool end_sequence;
unsigned int context;
}; };
static void static void
@@ -1539,6 +1541,7 @@ ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt)
lsm->is_stmt = default_is_stmt; lsm->is_stmt = default_is_stmt;
lsm->basic_block = false; lsm->basic_block = false;
lsm->end_sequence = false; lsm->end_sequence = false;
lsm->context = 0;
} }
template<int size, bool big_endian> template<int size, bool big_endian>
@@ -1546,27 +1549,40 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(
Object* object, Object* object,
unsigned int read_shndx) unsigned int read_shndx)
: data_valid_(false), buffer_(NULL), buffer_start_(NULL), : data_valid_(false), buffer_(NULL), buffer_start_(NULL),
str_buffer_(NULL), str_buffer_start_(NULL),
reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(), reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(),
current_header_index_(-1) current_header_index_(-1), reloc_map_(), line_number_map_()
{ {
unsigned int debug_shndx; unsigned int debug_line_shndx = 0;
unsigned int debug_line_str_shndx = 0;
for (debug_shndx = 1; debug_shndx < object->shnum(); ++debug_shndx) for (unsigned int i = 1; i < object->shnum(); ++i)
{ {
section_size_type buffer_size;
bool is_new = false;
// FIXME: do this more efficiently: section_name() isn't super-fast // FIXME: do this more efficiently: section_name() isn't super-fast
std::string name = object->section_name(debug_shndx); std::string name = object->section_name(i);
if (name == ".debug_line" || name == ".zdebug_line") if (name == ".debug_line" || name == ".zdebug_line")
{ {
section_size_type buffer_size; this->buffer_ =
bool is_new = false; object->decompressed_section_contents(i, &buffer_size, &is_new);
this->buffer_ = object->decompressed_section_contents(debug_shndx,
&buffer_size,
&is_new);
if (is_new) if (is_new)
this->buffer_start_ = this->buffer_; this->buffer_start_ = this->buffer_;
this->buffer_end_ = this->buffer_ + buffer_size; this->buffer_end_ = this->buffer_ + buffer_size;
break; debug_line_shndx = i;
} }
else if (name == ".debug_line_str" || name == ".zdebug_line_str")
{
this->str_buffer_ =
object->decompressed_section_contents(i, &buffer_size, &is_new);
if (is_new)
this->str_buffer_start_ = this->str_buffer_;
this->str_buffer_end_ = this->str_buffer_ + buffer_size;
debug_line_str_shndx = i;
}
if (debug_line_shndx > 0 && debug_line_str_shndx > 0)
break;
} }
if (this->buffer_ == NULL) if (this->buffer_ == NULL)
return; return;
@@ -1579,7 +1595,7 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(
unsigned int reloc_sh_type = object->section_type(i); unsigned int reloc_sh_type = object->section_type(i);
if ((reloc_sh_type == elfcpp::SHT_REL if ((reloc_sh_type == elfcpp::SHT_REL
|| reloc_sh_type == elfcpp::SHT_RELA) || reloc_sh_type == elfcpp::SHT_RELA)
&& object->section_info(i) == debug_shndx) && object->section_info(i) == debug_line_shndx)
{ {
reloc_shndx = i; reloc_shndx = i;
this->track_relocs_type_ = reloc_sh_type; this->track_relocs_type_ = reloc_sh_type;
@@ -1612,6 +1628,8 @@ Sized_dwarf_line_info<size, big_endian>::Sized_dwarf_line_info(
// Now that we have successfully read all the data, parse the debug // Now that we have successfully read all the data, parse the debug
// info. // info.
this->data_valid_ = true; this->data_valid_ = true;
gold_debug(DEBUG_LOCATION, "read_line_mappings: %s shndx %u",
object->name().c_str(), read_shndx);
this->read_line_mappings(read_shndx); this->read_line_mappings(read_shndx);
} }
@@ -1638,20 +1656,39 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog(
header_.total_length = initial_length; header_.total_length = initial_length;
gold_assert(lineptr + header_.total_length <= buffer_end_); this->end_of_unit_ = lineptr + initial_length;
gold_assert(this->end_of_unit_ <= buffer_end_);
header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr);
lineptr += 2; lineptr += 2;
// We can only read versions 2 and 3 of the DWARF line number table.
// For other versions, just skip the entire line number table.
if ((header_.version < 2 || header_.version > 4)
&& header_.version != DWARF5_EXPERIMENTAL_LINE_TABLE)
return this->end_of_unit_;
if (header_.offset_size == 4) if (header_.offset_size == 4)
header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
else else
header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
lineptr += header_.offset_size; lineptr += header_.offset_size;
this->end_of_header_length_ = lineptr;
// If this is a two-level line table, we'll adjust these below.
this->logicals_start_ = lineptr + header_.prologue_length;
this->actuals_start_ = NULL;
header_.min_insn_length = *lineptr; header_.min_insn_length = *lineptr;
lineptr += 1; lineptr += 1;
if (header_.version >= 4)
{
header_.max_ops_per_insn = *lineptr;
lineptr += 1;
}
header_.default_is_stmt = *lineptr; header_.default_is_stmt = *lineptr;
lineptr += 1; lineptr += 1;
@@ -1672,6 +1709,32 @@ Sized_dwarf_line_info<size, big_endian>::read_header_prolog(
lineptr += 1; lineptr += 1;
} }
if (header_.version == DWARF5_EXPERIMENTAL_LINE_TABLE)
{
// Skip over fake empty directory and filename tables,
// and fake extended opcode that hides the rest of the
// section from old consumers.
lineptr += 7;
// Offsets to logicals and actuals tables.
off_t logicals_offset;
off_t actuals_offset;
if (header_.offset_size == 4)
logicals_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
else
logicals_offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
lineptr += header_.offset_size;
if (header_.offset_size == 4)
actuals_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
else
actuals_offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
lineptr += header_.offset_size;
this->logicals_start_ = this->end_of_header_length_ + logicals_offset;
if (actuals_offset > 0)
this->actuals_start_ = this->end_of_header_length_ + actuals_offset;
}
return lineptr; return lineptr;
} }
@@ -1745,12 +1808,180 @@ Sized_dwarf_line_info<size, big_endian>::read_header_tables(
return lineptr; return lineptr;
} }
template<int size, bool big_endian>
const unsigned char*
Sized_dwarf_line_info<size, big_endian>::read_header_tables_v5(
const unsigned char* lineptr)
{
size_t len;
++this->current_header_index_;
// Create a new directories_ entry and a new files_ entry for our new
// header. We initialize each with a single empty element, because
// dwarf indexes directory and filenames starting at 1.
gold_assert(static_cast<int>(this->directories_.size())
== this->current_header_index_);
gold_assert(static_cast<int>(this->files_.size())
== this->current_header_index_);
// Read the directory list.
uint64_t format_count = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
unsigned int *types = new unsigned int[format_count];
unsigned int *forms = new unsigned int[format_count];
for (unsigned int i = 0; i < format_count; i++)
{
types[i] = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
forms[i] = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
}
uint64_t entry_count = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
this->directories_.push_back(std::vector<std::string>(1));
std::vector<std::string>& dir_list = this->directories_.back();
for (unsigned int j = 0; j < entry_count; j++)
{
std::string dirname;
for (unsigned int i = 0; i < format_count; i++)
{
if (types[i] == elfcpp::DW_LNCT_path)
{
if (forms[i] == elfcpp::DW_FORM_string)
{
dirname = reinterpret_cast<const char*>(lineptr);
lineptr += dirname.size() + 1;
}
else if (forms[i] == elfcpp::DW_FORM_line_strp)
{
uint64_t offset;
if (header_.offset_size == 4)
offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
else
offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
typename Reloc_map::const_iterator it
= this->reloc_map_.find(lineptr - this->buffer_);
if (it != reloc_map_.end())
{
if (this->track_relocs_type_ == elfcpp::SHT_RELA)
offset = 0;
offset += it->second.second;
}
lineptr += header_.offset_size;
dirname = reinterpret_cast<const char*>(this->str_buffer_
+ offset);
}
else
return lineptr;
}
else
return lineptr;
}
dir_list.push_back(dirname);
}
delete[] types;
delete[] forms;
// Read the filenames list.
format_count = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
types = new unsigned int[format_count];
forms = new unsigned int[format_count];
for (unsigned int i = 0; i < format_count; i++)
{
types[i] = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
forms[i] = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
}
entry_count = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
this->files_.push_back(
std::vector<std::pair<int, std::string> >(1));
std::vector<std::pair<int, std::string> >& file_list = this->files_.back();
for (unsigned int j = 0; j < entry_count; j++)
{
const char* path = NULL;
int dirindex = 0;
for (unsigned int i = 0; i < format_count; i++)
{
if (types[i] == elfcpp::DW_LNCT_path)
{
if (forms[i] == elfcpp::DW_FORM_string)
{
path = reinterpret_cast<const char*>(lineptr);
lineptr += strlen(path) + 1;
}
else if (forms[i] == elfcpp::DW_FORM_line_strp)
{
uint64_t offset;
if (header_.offset_size == 4)
offset = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr);
else
offset = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr);
typename Reloc_map::const_iterator it
= this->reloc_map_.find(lineptr - this->buffer_);
if (it != reloc_map_.end())
{
if (this->track_relocs_type_ == elfcpp::SHT_RELA)
offset = 0;
offset += it->second.second;
}
lineptr += header_.offset_size;
path = reinterpret_cast<const char*>(this->str_buffer_
+ offset);
}
else
return lineptr;
}
else if (types[i] == elfcpp::DW_LNCT_directory_index)
{
if (forms[i] == elfcpp::DW_FORM_udata)
{
dirindex = read_unsigned_LEB_128(lineptr, &len);
lineptr += len;
}
else
return lineptr;
}
else
return lineptr;
}
gold_debug(DEBUG_LOCATION, "File %3d: %s",
static_cast<int>(file_list.size()), path);
file_list.push_back(std::make_pair<int, std::string>(dirindex, path));
}
delete[] types;
delete[] forms;
// Ignore the subprograms table; we don't need it for now.
// Because it's the last thing in the header, we don't need
// to figure out how long it is to skip over it.
return lineptr;
}
// Process a single opcode in the .debug.line structure. // Process a single opcode in the .debug.line structure.
template<int size, bool big_endian> template<int size, bool big_endian>
bool bool
Sized_dwarf_line_info<size, big_endian>::process_one_opcode( Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
const unsigned char* start, struct LineStateMachine* lsm, size_t* len) const unsigned char* start, struct LineStateMachine* lsm, size_t* len,
std::vector<LineStateMachine>* logicals,
bool is_logicals_table, bool is_actuals_table)
{ {
size_t oplen = 0; size_t oplen = 0;
size_t templen; size_t templen;
@@ -1794,7 +2025,7 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
case elfcpp::DW_LNS_advance_line: case elfcpp::DW_LNS_advance_line:
{ {
const uint64_t advance_line = read_signed_LEB_128(start, &templen); const int64_t advance_line = read_signed_LEB_128(start, &templen);
oplen += templen; oplen += templen;
lsm->line_num += advance_line; lsm->line_num += advance_line;
} }
@@ -1842,6 +2073,61 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
} }
break; break;
case elfcpp::DW_LNS_set_subprogram:
// aliased with elfcpp::DW_LNS_set_address_from_logical
if (is_actuals_table)
{
// elfcpp::DW_LNS_set_address_from_logical
const int64_t advance_line = read_signed_LEB_128(start, &templen);
oplen += templen;
lsm->line_num += advance_line;
if (lsm->line_num >= 1
&& lsm->line_num <= static_cast<int64_t>(logicals->size()))
{
const LineStateMachine& logical = (*logicals)[lsm->line_num - 1];
lsm->address = logical.address;
lsm->shndx = logical.shndx;
}
}
else if (is_logicals_table)
{
// elfcpp::DW_LNS_set_subprogram
// Ignore the subprogram number for now.
read_unsigned_LEB_128(start, &templen);
oplen += templen;
lsm->context = 0;
}
break;
case elfcpp::DW_LNS_inlined_call:
if (is_logicals_table)
{
const int64_t advance_line = read_signed_LEB_128(start, &templen);
oplen += templen;
start += templen;
// Ignore the subprogram number for now.
read_unsigned_LEB_128(start, &templen);
oplen += templen;
lsm->context = logicals->size() + advance_line;
}
break;
case elfcpp::DW_LNS_pop_context:
if (is_logicals_table)
{
const unsigned int context = lsm->context;
if (context >= 1 && context <= logicals->size())
{
const LineStateMachine& logical = (*logicals)[context - 1];
lsm->file_num = logical.file_num;
lsm->line_num = logical.line_num;
lsm->column_num = logical.column_num;
lsm->is_stmt = logical.is_stmt;
lsm->context = logical.context;
}
}
break;
case elfcpp::DW_LNS_extended_op: case elfcpp::DW_LNS_extended_op:
{ {
const uint64_t extended_op_len const uint64_t extended_op_len
@@ -1939,54 +2225,92 @@ Sized_dwarf_line_info<size, big_endian>::process_one_opcode(
template<int size, bool big_endian> template<int size, bool big_endian>
unsigned const char* unsigned const char*
Sized_dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr, Sized_dwarf_line_info<size, big_endian>::read_lines(
unsigned int shndx) unsigned const char* lineptr,
unsigned const char* endptr,
std::vector<LineStateMachine>* logicals,
bool is_logicals_table,
bool is_actuals_table,
unsigned int shndx)
{ {
struct LineStateMachine lsm; struct LineStateMachine lsm;
// LENGTHSTART is the place the length field is based on. It is the while (lineptr < endptr)
// point in the header after the initial length field.
const unsigned char* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
if (header_.offset_size == 8)
lengthstart += 12;
else
lengthstart += 4;
while (lineptr < lengthstart + header_.total_length)
{ {
ResetLineStateMachine(&lsm, header_.default_is_stmt); ResetLineStateMachine(&lsm, header_.default_is_stmt);
while (!lsm.end_sequence) while (!lsm.end_sequence)
{ {
size_t oplength; size_t oplength;
bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength); if (lineptr >= endptr)
if (add_line break;
&& (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx))
{ bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength,
Offset_to_lineno_entry entry logicals,
= { static_cast<off_t>(lsm.address), is_logicals_table,
this->current_header_index_, is_actuals_table);
static_cast<unsigned int>(lsm.file_num),
true, lsm.line_num };
std::vector<Offset_to_lineno_entry>&
map(this->line_number_map_[lsm.shndx]);
// If we see two consecutive entries with the same
// offset and a real line number, then mark the first
// one as non-canonical.
if (!map.empty()
&& (map.back().offset == static_cast<off_t>(lsm.address))
&& lsm.line_num != -1
&& map.back().line_num != -1)
map.back().last_line_for_offset = false;
map.push_back(entry);
}
lineptr += oplength; lineptr += oplength;
if (add_line)
{
if (is_logicals_table)
{
logicals->push_back(lsm);
gold_debug(DEBUG_LOCATION, "Logical %d [%3u:%08x]: "
"file %d line %d context %u",
static_cast<int>(logicals->size()),
lsm.shndx, static_cast<int>(lsm.address),
lsm.file_num, lsm.line_num, lsm.context);
}
else if (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx)
{
Offset_to_lineno_entry entry;
if (is_actuals_table && lsm.line_num != -1)
{
if (lsm.line_num < 1
|| lsm.line_num > static_cast<int64_t>(logicals->size()))
continue;
const LineStateMachine& logical =
(*logicals)[lsm.line_num - 1];
gold_debug(DEBUG_LOCATION, "Actual [%3u:%08x]: "
"logical %u file %d line %d context %u",
lsm.shndx, static_cast<int>(lsm.address),
lsm.line_num, logical.file_num,
logical.line_num, logical.context);
entry.offset = static_cast<off_t>(lsm.address);
entry.header_num = this->current_header_index_;
entry.file_num =
static_cast<unsigned int>(logical.file_num);
entry.last_line_for_offset = true;
entry.line_num = logical.line_num;
}
else
{
entry.offset = static_cast<off_t>(lsm.address);
entry.header_num = this->current_header_index_;
entry.file_num = static_cast<unsigned int>(lsm.file_num);
entry.last_line_for_offset = true;
entry.line_num = lsm.line_num;
}
std::vector<Offset_to_lineno_entry>&
map(this->line_number_map_[lsm.shndx]);
// If we see two consecutive entries with the same
// offset and a real line number, then mark the first
// one as non-canonical.
if (!map.empty()
&& (map.back().offset == static_cast<off_t>(lsm.address))
&& lsm.line_num != -1
&& map.back().line_num != -1)
map.back().last_line_for_offset = false;
map.push_back(entry);
}
}
} }
} }
return lengthstart + header_.total_length; return endptr;
} }
// Read the relocations into a Reloc_map. // Read the relocations into a Reloc_map.
@@ -2026,10 +2350,48 @@ Sized_dwarf_line_info<size, big_endian>::read_line_mappings(unsigned int shndx)
while (this->buffer_ < this->buffer_end_) while (this->buffer_ < this->buffer_end_)
{ {
const unsigned char* lineptr = this->buffer_; const unsigned char* lineptr = this->buffer_;
std::vector<LineStateMachine> logicals;
lineptr = this->read_header_prolog(lineptr); lineptr = this->read_header_prolog(lineptr);
lineptr = this->read_header_tables(lineptr); if (header_.version >= 2 && header_.version <= 4)
lineptr = this->read_lines(lineptr, shndx); {
this->buffer_ = lineptr; lineptr = this->read_header_tables(lineptr);
lineptr = this->read_lines(this->logicals_start_,
this->end_of_unit_,
NULL,
false,
false,
shndx);
}
else if (header_.version == DWARF5_EXPERIMENTAL_LINE_TABLE)
{
lineptr = this->read_header_tables_v5(lineptr);
if (this->actuals_start_ != NULL)
{
lineptr = this->read_lines(this->logicals_start_,
this->actuals_start_,
&logicals,
true,
false,
shndx);
lineptr = this->read_lines(this->actuals_start_,
this->end_of_unit_,
&logicals,
false,
true,
shndx);
}
else
{
lineptr = this->read_lines(this->logicals_start_,
this->end_of_unit_,
NULL,
false,
false,
shndx);
}
}
this->buffer_ = this->end_of_unit_;
} }
// Sort the lines numbers, so addr2line can use binary search. // Sort the lines numbers, so addr2line can use binary search.
@@ -2185,6 +2547,9 @@ Sized_dwarf_line_info<size, big_endian>::do_addr2line(
off_t offset, off_t offset,
std::vector<std::string>* other_lines) std::vector<std::string>* other_lines)
{ {
gold_debug(DEBUG_LOCATION, "do_addr2line: shndx %u offset %08x",
shndx, static_cast<int>(offset));
if (this->data_valid_ == false) if (this->data_valid_ == false)
return ""; return "";
@@ -2205,13 +2570,33 @@ Sized_dwarf_line_info<size, big_endian>::do_addr2line(
return ""; return "";
std::string result = this->format_file_lineno(*it); std::string result = this->format_file_lineno(*it);
gold_debug(DEBUG_LOCATION, "do_addr2line: canonical result: %s",
result.c_str());
if (other_lines != NULL) if (other_lines != NULL)
for (++it; it != offsets->end() && it->offset == offset; ++it) {
{ unsigned int last_file_num = it->file_num;
if (it->line_num == -1) int last_line_num = it->line_num;
continue; // The end of a previous function. // Return up to 4 more locations from the beginning of the function
other_lines->push_back(this->format_file_lineno(*it)); // for fuzzy matching.
} for (++it; it != offsets->end(); ++it)
{
if (it->offset == offset && it->line_num == -1)
continue; // The end of a previous function.
if (it->line_num == -1)
break; // The end of the current function.
if (it->file_num != last_file_num || it->line_num != last_line_num)
{
other_lines->push_back(this->format_file_lineno(*it));
gold_debug(DEBUG_LOCATION, "do_addr2line: other: %s",
other_lines->back().c_str());
last_file_num = it->file_num;
last_line_num = it->line_num;
}
if (it->offset > offset && other_lines->size() >= 4)
break;
}
}
return result; return result;
} }

View File

@@ -1001,9 +1001,13 @@ class Sized_dwarf_line_info : public Dwarf_line_info
{ {
if (this->buffer_start_ != NULL) if (this->buffer_start_ != NULL)
delete[] this->buffer_start_; delete[] this->buffer_start_;
if (this->str_buffer_start_ != NULL)
delete[] this->str_buffer_start_;
} }
private: private:
const static int DWARF5_EXPERIMENTAL_LINE_TABLE = 0xf006;
std::string std::string
do_addr2line(unsigned int shndx, off_t offset, do_addr2line(unsigned int shndx, off_t offset,
std::vector<std::string>* other_lines); std::vector<std::string>* other_lines);
@@ -1031,11 +1035,17 @@ class Sized_dwarf_line_info : public Dwarf_line_info
const unsigned char* const unsigned char*
read_header_tables(const unsigned char* lineptr); read_header_tables(const unsigned char* lineptr);
const unsigned char*
read_header_tables_v5(const unsigned char* lineptr);
// Reads the DWARF2/3 line information. If shndx is non-negative, // Reads the DWARF2/3 line information. If shndx is non-negative,
// discard all line information that doesn't pertain to the given // discard all line information that doesn't pertain to the given
// section. // section.
const unsigned char* const unsigned char*
read_lines(const unsigned char* lineptr, unsigned int shndx); read_lines(const unsigned char* lineptr, const unsigned char* endptr,
std::vector<LineStateMachine>* logicals,
bool is_logicals_table, bool is_actuals_table,
unsigned int shndx);
// Process a single line info opcode at START using the state // Process a single line info opcode at START using the state
// machine at LSM. Return true if we should define a line using the // machine at LSM. Return true if we should define a line using the
@@ -1043,7 +1053,9 @@ class Sized_dwarf_line_info : public Dwarf_line_info
// opcode in LEN. // opcode in LEN.
bool bool
process_one_opcode(const unsigned char* start, process_one_opcode(const unsigned char* start,
struct LineStateMachine* lsm, size_t* len); struct LineStateMachine* lsm, size_t* len,
std::vector<LineStateMachine>* logicals,
bool is_logicals_table, bool is_actuals_table);
// Some parts of processing differ depending on whether the input // Some parts of processing differ depending on whether the input
// was a .o file or not. // was a .o file or not.
@@ -1064,6 +1076,7 @@ class Sized_dwarf_line_info : public Dwarf_line_info
int version; int version;
off_t prologue_length; off_t prologue_length;
int min_insn_length; // insn stands for instructin int min_insn_length; // insn stands for instructin
int max_ops_per_insn;
bool default_is_stmt; // stmt stands for statement bool default_is_stmt; // stmt stands for statement
signed char line_base; signed char line_base;
int line_range; int line_range;
@@ -1081,6 +1094,26 @@ class Sized_dwarf_line_info : public Dwarf_line_info
// of the buffer. // of the buffer.
const unsigned char* buffer_start_; const unsigned char* buffer_start_;
// buffer is the buffer for our line info, starting at exactly where
// the line info to read is.
const unsigned char* str_buffer_;
const unsigned char* str_buffer_end_;
// If the buffer was allocated temporarily, and therefore must be
// deallocated in the dtor, this contains a pointer to the start
// of the buffer.
const unsigned char* str_buffer_start_;
// Pointer to the end of the header_length field (aka prologue_length).
// The offsets to the line number programs are relative to this point.
const unsigned char* end_of_header_length_;
// Pointers to the start of the line number programs.
const unsigned char* logicals_start_;
const unsigned char* actuals_start_;
// Pointer to the end of the current compilation unit.
const unsigned char* end_of_unit_;
// This has relocations that point into buffer. // This has relocations that point into buffer.
Sized_elf_reloc_mapper<size, big_endian>* reloc_mapper_; Sized_elf_reloc_mapper<size, big_endian>* reloc_mapper_;
// The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA. // The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA.

View File

@@ -284,14 +284,6 @@ class Sized_relobj_dwo : public Sized_relobj<size, big_endian>
const unsigned char* const unsigned char*
do_section_contents(unsigned int, section_size_type*, bool); do_section_contents(unsigned int, section_size_type*, bool);
// Return a view of the uncompressed contents of a section. Set *PLEN
// to the size. Set *IS_NEW to true if the contents need to be deleted
// by the caller.
const unsigned char*
do_decompressed_section_contents(unsigned int shndx,
section_size_type* plen,
bool* is_new);
// The following virtual functions are abstract in the base classes, // The following virtual functions are abstract in the base classes,
// but are not used here. // but are not used here.
@@ -781,9 +773,36 @@ template <int size, bool big_endian>
void void
Sized_relobj_dwo<size, big_endian>::setup() Sized_relobj_dwo<size, big_endian>::setup()
{ {
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
const off_t shoff = this->elf_file_.shoff();
const unsigned int shnum = this->elf_file_.shnum(); const unsigned int shnum = this->elf_file_.shnum();
this->set_shnum(shnum); this->set_shnum(shnum);
this->section_offsets().resize(shnum); this->section_offsets().resize(shnum);
// Read the section headers.
const unsigned char* const pshdrs = this->get_view(shoff, shnum * shdr_size,
true, false);
// Read the section names.
const unsigned char* pshdrnames =
pshdrs + this->elf_file_.shstrndx() * shdr_size;
typename elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
if (shdrnames.get_sh_type() != elfcpp::SHT_STRTAB)
this->error(_("section name section has wrong type: %u"),
static_cast<unsigned int>(shdrnames.get_sh_type()));
section_size_type section_names_size =
convert_to_section_size_type(shdrnames.get_sh_size());
const unsigned char* namesu = this->get_view(shdrnames.get_sh_offset(),
section_names_size, false,
false);
const char* names = reinterpret_cast<const char*>(namesu);
Compressed_section_map* compressed_sections =
build_compressed_section_map<size, big_endian>(
pshdrs, this->shnum(), names, section_names_size, this, true);
if (compressed_sections != NULL && !compressed_sections->empty())
this->set_compressed_sections(compressed_sections);
} }
// Return a view of the contents of a section. // Return a view of the contents of a section.
@@ -805,43 +824,6 @@ Sized_relobj_dwo<size, big_endian>::do_section_contents(
return this->get_view(loc.file_offset, *plen, true, cache); return this->get_view(loc.file_offset, *plen, true, cache);
} }
// Return a view of the uncompressed contents of a section. Set *PLEN
// to the size. Set *IS_NEW to true if the contents need to be deleted
// by the caller.
template <int size, bool big_endian>
const unsigned char*
Sized_relobj_dwo<size, big_endian>::do_decompressed_section_contents(
unsigned int shndx,
section_size_type* plen,
bool* is_new)
{
section_size_type buffer_size;
const unsigned char* buffer = this->do_section_contents(shndx, &buffer_size,
false);
std::string sect_name = this->do_section_name(shndx);
if (!is_prefix_of(".zdebug_", sect_name.c_str()))
{
*plen = buffer_size;
*is_new = false;
return buffer;
}
section_size_type uncompressed_size = get_uncompressed_size(buffer,
buffer_size);
unsigned char* uncompressed_data = new unsigned char[uncompressed_size];
if (!decompress_input_section(buffer,
buffer_size,
uncompressed_data,
uncompressed_size))
this->error(_("could not decompress section %s"),
this->section_name(shndx).c_str());
*plen = uncompressed_size;
*is_new = true;
return uncompressed_data;
}
// Class Dwo_file. // Class Dwo_file.
Dwo_file::~Dwo_file() Dwo_file::~Dwo_file()
@@ -2352,7 +2334,7 @@ print_version()
{ {
// This output is intended to follow the GNU standards. // This output is intended to follow the GNU standards.
printf("GNU dwp %s\n", BFD_VERSION_STRING); printf("GNU dwp %s\n", BFD_VERSION_STRING);
printf(_("Copyright (C) 2014-2015 Free Software Foundation, Inc.\n")); printf(_("Copyright (C) 2015 Free Software Foundation, Inc.\n"));
printf(_("\ printf(_("\
This program is free software; you may redistribute it under the terms of\n\ This program is free software; you may redistribute it under the terms of\n\
the GNU General Public License version 3 or (at your option) any later version.\n\ the GNU General Public License version 3 or (at your option) any later version.\n\

View File

@@ -374,6 +374,17 @@ Sized_dynobj<size, big_endian>::base_read_symbols(Read_symbols_data* sd)
sd->verneed_size = 0; sd->verneed_size = 0;
sd->verneed_info = 0; sd->verneed_info = 0;
const unsigned char* namesu = sd->section_names->data();
const char* names = reinterpret_cast<const char*>(namesu);
if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL)
{
Compressed_section_map* compressed_sections =
build_compressed_section_map<size, big_endian>(
pshdrs, this->shnum(), names, sd->section_names_size, this, true);
if (compressed_sections != NULL)
this->set_compressed_sections(compressed_sections);
}
if (this->dynsym_shndx_ != -1U) if (this->dynsym_shndx_ != -1U)
{ {
// Get the dynamic symbols. // Get the dynamic symbols.

View File

@@ -432,8 +432,7 @@ Sized_relobj_file<size, big_endian>::Sized_relobj_file(
discarded_eh_frame_shndx_(-1U), discarded_eh_frame_shndx_(-1U),
is_deferred_layout_(false), is_deferred_layout_(false),
deferred_layout_(), deferred_layout_(),
deferred_layout_relocs_(), deferred_layout_relocs_()
compressed_sections_()
{ {
this->e_type_ = ehdr.get_e_type(); this->e_type_ = ehdr.get_e_type();
} }
@@ -675,7 +674,8 @@ build_compressed_section_map(
unsigned int shnum, unsigned int shnum,
const char* names, const char* names,
section_size_type names_size, section_size_type names_size,
Sized_relobj_file<size, big_endian>* obj) Object* obj,
bool decompress_if_needed)
{ {
Compressed_section_map* uncompressed_map = new Compressed_section_map(); Compressed_section_map* uncompressed_map = new Compressed_section_map();
const unsigned int shdr_size = elfcpp::Elf_sizes<size>::shdr_size; const unsigned int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
@@ -707,7 +707,7 @@ build_compressed_section_map(
if (uncompressed_size != -1ULL) if (uncompressed_size != -1ULL)
{ {
unsigned char* uncompressed_data = NULL; unsigned char* uncompressed_data = NULL;
if (need_decompressed_section(name)) if (decompress_if_needed && need_decompressed_section(name))
{ {
uncompressed_data = new unsigned char[uncompressed_size]; uncompressed_data = new unsigned char[uncompressed_size];
if (decompress_input_section(contents, len, if (decompress_input_section(contents, len,
@@ -741,9 +741,14 @@ Sized_relobj_file<size, big_endian>::do_find_special_sections(
this->has_eh_frame_ = true; this->has_eh_frame_ = true;
if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL) if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL)
this->compressed_sections_ {
= build_compressed_section_map(pshdrs, this->shnum(), names, Compressed_section_map* compressed_sections =
sd->section_names_size, this); build_compressed_section_map<size, big_endian>(
pshdrs, this->shnum(), names, sd->section_names_size, this, true);
if (compressed_sections != NULL)
this->set_compressed_sections(compressed_sections);
}
return (this->has_eh_frame_ return (this->has_eh_frame_
|| (!parameters->options().relocatable() || (!parameters->options().relocatable()
&& parameters->options().gdb_index() && parameters->options().gdb_index()
@@ -2804,9 +2809,8 @@ Sized_relobj_file<size, big_endian>::do_get_global_symbol_counts(
// to the size. Set *IS_NEW to true if the contents need to be freed // to the size. Set *IS_NEW to true if the contents need to be freed
// by the caller. // by the caller.
template<int size, bool big_endian>
const unsigned char* const unsigned char*
Sized_relobj_file<size, big_endian>::do_decompressed_section_contents( Object::decompressed_section_contents(
unsigned int shndx, unsigned int shndx,
section_size_type* plen, section_size_type* plen,
bool* is_new) bool* is_new)
@@ -2860,9 +2864,8 @@ Sized_relobj_file<size, big_endian>::do_decompressed_section_contents(
// Discard any buffers of uncompressed sections. This is done // Discard any buffers of uncompressed sections. This is done
// at the end of the Add_symbols task. // at the end of the Add_symbols task.
template<int size, bool big_endian>
void void
Sized_relobj_file<size, big_endian>::do_discard_decompressed_sections() Object::discard_decompressed_sections()
{ {
if (this->compressed_sections_ == NULL) if (this->compressed_sections_ == NULL)
return; return;

View File

@@ -314,6 +314,21 @@ class Got_offset_list
Got_offset_list* got_next_; Got_offset_list* got_next_;
}; };
// Type for mapping section index to uncompressed size and contents.
struct Compressed_section_info
{
section_size_type size;
const unsigned char* contents;
};
typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
template<int size, bool big_endian>
Compressed_section_map*
build_compressed_section_map(const unsigned char* pshdrs, unsigned int shnum,
const char* names, section_size_type names_size,
Object* obj, bool decompress_if_needed);
// Object is an abstract base class which represents either a 32-bit // Object is an abstract base class which represents either a 32-bit
// or a 64-bit input object. This can be a regular object file // or a 64-bit input object. This can be a regular object file
// (ET_REL) or a shared object (ET_DYN). // (ET_REL) or a shared object (ET_DYN).
@@ -332,7 +347,8 @@ class Object
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U), : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false), is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false),
has_no_split_stack_(false), no_export_(false), has_no_split_stack_(false), no_export_(false),
is_in_system_directory_(false), as_needed_(false), xindex_(NULL) is_in_system_directory_(false), as_needed_(false), xindex_(NULL),
compressed_sections_(NULL)
{ {
if (input_file != NULL) if (input_file != NULL)
{ {
@@ -725,26 +741,34 @@ class Object
set_no_export(bool value) set_no_export(bool value)
{ this->no_export_ = value; } { this->no_export_ = value; }
// Return TRUE if the section is a compressed debug section, and set
// *UNCOMPRESSED_SIZE to the size of the uncompressed data.
bool bool
section_is_compressed(unsigned int shndx, section_is_compressed(unsigned int shndx,
section_size_type* uncompressed_size) const section_size_type* uncompressed_size) const
{ return this->do_section_is_compressed(shndx, uncompressed_size); } {
if (this->compressed_sections_ == NULL)
return false;
Compressed_section_map::const_iterator p =
this->compressed_sections_->find(shndx);
if (p != this->compressed_sections_->end())
{
if (uncompressed_size != NULL)
*uncompressed_size = p->second.size;
return true;
}
return false;
}
// Return a view of the decompressed contents of a section. Set *PLEN // Return a view of the decompressed contents of a section. Set *PLEN
// to the size. Set *IS_NEW to true if the contents need to be freed // to the size. Set *IS_NEW to true if the contents need to be freed
// by the caller. // by the caller.
const unsigned char* const unsigned char*
decompressed_section_contents(unsigned int shndx, section_size_type* plen, decompressed_section_contents(unsigned int shndx, section_size_type* plen,
bool* is_cached) bool* is_cached);
{ return this->do_decompressed_section_contents(shndx, plen, is_cached); }
// Discard any buffers of decompressed sections. This is done // Discard any buffers of decompressed sections. This is done
// at the end of the Add_symbols task. // at the end of the Add_symbols task.
void void
discard_decompressed_sections() discard_decompressed_sections();
{ this->do_discard_decompressed_sections(); }
// Return the index of the first incremental relocation for symbol SYMNDX. // Return the index of the first incremental relocation for symbol SYMNDX.
unsigned int unsigned int
@@ -923,27 +947,6 @@ class Object
bool bool
handle_split_stack_section(const char* name); handle_split_stack_section(const char* name);
// Return TRUE if the section is a compressed debug section, and set
// *UNCOMPRESSED_SIZE to the size of the uncompressed data.
virtual bool
do_section_is_compressed(unsigned int, section_size_type*) const
{ return false; }
// Return a view of the decompressed contents of a section. Set *PLEN
// to the size. This default implementation simply returns the
// raw section contents and sets *IS_NEW to false to indicate
// that the contents do not need to be freed by the caller.
// This function must be overridden for any types of object files
// that might contain compressed sections.
virtual const unsigned char*
do_decompressed_section_contents(unsigned int shndx,
section_size_type* plen,
bool* is_new)
{
*is_new = false;
return this->do_section_contents(shndx, plen, false);
}
// Discard any buffers of decompressed sections. This is done // Discard any buffers of decompressed sections. This is done
// at the end of the Add_symbols task. // at the end of the Add_symbols task.
virtual void virtual void
@@ -962,6 +965,14 @@ class Object
do_get_incremental_reloc_count(unsigned int) const do_get_incremental_reloc_count(unsigned int) const
{ gold_unreachable(); } { gold_unreachable(); }
void
set_compressed_sections(Compressed_section_map* compressed_sections)
{ this->compressed_sections_ = compressed_sections; }
Compressed_section_map*
compressed_sections()
{ return this->compressed_sections_; }
private: private:
// This class may not be copied. // This class may not be copied.
Object(const Object&); Object(const Object&);
@@ -996,6 +1007,9 @@ class Object
bool as_needed_ : 1; bool as_needed_ : 1;
// Many sections for objects with more than SHN_LORESERVE sections. // Many sections for objects with more than SHN_LORESERVE sections.
Xindex* xindex_; Xindex* xindex_;
// For compressed debug sections, map section index to uncompressed size
// and contents.
Compressed_section_map* compressed_sections_;
}; };
// A regular object (ET_REL). This is an abstract base class itself. // A regular object (ET_REL). This is an abstract base class itself.
@@ -1862,15 +1876,6 @@ class Reloc_symbol_changes
std::vector<Symbol*> vec_; std::vector<Symbol*> vec_;
}; };
// Type for mapping section index to uncompressed size and contents.
struct Compressed_section_info
{
section_size_type size;
const unsigned char* contents;
};
typedef std::map<unsigned int, Compressed_section_info> Compressed_section_map;
// Abstract base class for a regular object file, either a real object file // Abstract base class for a regular object file, either a real object file
// or an incremental (unchanged) object. This is size and endian specific. // or an incremental (unchanged) object. This is size and endian specific.
@@ -2453,38 +2458,6 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
set_output_local_symbol_count(unsigned int value) set_output_local_symbol_count(unsigned int value)
{ this->output_local_symbol_count_ = value; } { this->output_local_symbol_count_ = value; }
// Return TRUE if the section is a compressed debug section, and set
// *UNCOMPRESSED_SIZE to the size of the uncompressed data.
bool
do_section_is_compressed(unsigned int shndx,
section_size_type* uncompressed_size) const
{
if (this->compressed_sections_ == NULL)
return false;
Compressed_section_map::const_iterator p =
this->compressed_sections_->find(shndx);
if (p != this->compressed_sections_->end())
{
if (uncompressed_size != NULL)
*uncompressed_size = p->second.size;
return true;
}
return false;
}
// Return a view of the uncompressed contents of a section. Set *PLEN
// to the size. Set *IS_NEW to true if the contents need to be deleted
// by the caller.
const unsigned char*
do_decompressed_section_contents(unsigned int shndx,
section_size_type* plen,
bool* is_new);
// Discard any buffers of decompressed sections. This is done
// at the end of the Add_symbols task.
void
do_discard_decompressed_sections();
private: private:
// For convenience. // For convenience.
typedef Sized_relobj_file<size, big_endian> This; typedef Sized_relobj_file<size, big_endian> This;
@@ -2751,9 +2724,6 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
std::vector<Deferred_layout> deferred_layout_; std::vector<Deferred_layout> deferred_layout_;
// The list of relocation sections whose layout was deferred. // The list of relocation sections whose layout was deferred.
std::vector<Deferred_layout> deferred_layout_relocs_; std::vector<Deferred_layout> deferred_layout_relocs_;
// For compressed debug sections, map section index to uncompressed size
// and contents.
Compressed_section_map* compressed_sections_;
}; };
// A class to manage the list of all objects. // A class to manage the list of all objects.

View File

@@ -3336,8 +3336,11 @@ Symbol_table::detect_odr_violations(const Task* task,
first_object_name = locs->object->name(); first_object_name = locs->object->name();
first_object_linenos = this->linenos_from_loc(task, *locs); first_object_linenos = this->linenos_from_loc(task, *locs);
} }
if (first_object_linenos.empty())
continue;
// Sort by Odr_violation_compare to make std::set_intersection work. // Sort by Odr_violation_compare to make std::set_intersection work.
std::string first_object_canonical_result = first_object_linenos.back();
std::sort(first_object_linenos.begin(), first_object_linenos.end(), std::sort(first_object_linenos.begin(), first_object_linenos.end(),
Odr_violation_compare()); Odr_violation_compare());
@@ -3349,6 +3352,8 @@ Symbol_table::detect_odr_violations(const Task* task,
if (linenos.empty()) if (linenos.empty())
continue; continue;
// Sort by Odr_violation_compare to make std::set_intersection work. // Sort by Odr_violation_compare to make std::set_intersection work.
gold_assert(!linenos.empty());
std::string second_object_canonical_result = linenos.back();
std::sort(linenos.begin(), linenos.end(), Odr_violation_compare()); std::sort(linenos.begin(), linenos.end(), Odr_violation_compare());
Check_intersection intersection_result = Check_intersection intersection_result =
@@ -3367,13 +3372,11 @@ Symbol_table::detect_odr_violations(const Task* task,
// which may not be the location we expect to intersect // which may not be the location we expect to intersect
// with another definition. We could print the whole // with another definition. We could print the whole
// set of locations, but that seems too verbose. // set of locations, but that seems too verbose.
gold_assert(!first_object_linenos.empty());
gold_assert(!linenos.empty());
fprintf(stderr, _(" %s from %s\n"), fprintf(stderr, _(" %s from %s\n"),
first_object_linenos[0].c_str(), first_object_canonical_result.c_str(),
first_object_name.c_str()); first_object_name.c_str());
fprintf(stderr, _(" %s from %s\n"), fprintf(stderr, _(" %s from %s\n"),
linenos[0].c_str(), second_object_canonical_result.c_str(),
locs->object->name().c_str()); locs->object->name().c_str());
// Only print one broken pair, to avoid needing to // Only print one broken pair, to avoid needing to
// compare against a list of the disjoint definition // compare against a list of the disjoint definition

View File

@@ -200,6 +200,8 @@ DW_FORM (DW_FORM_sec_offset, 0x17)
DW_FORM (DW_FORM_exprloc, 0x18) DW_FORM (DW_FORM_exprloc, 0x18)
DW_FORM (DW_FORM_flag_present, 0x19) DW_FORM (DW_FORM_flag_present, 0x19)
DW_FORM (DW_FORM_ref_sig8, 0x20) 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. */ /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
DW_FORM (DW_FORM_GNU_addr_index, 0x1f01) DW_FORM (DW_FORM_GNU_addr_index, 0x1f01)
DW_FORM (DW_FORM_GNU_str_index, 0x1f02) DW_FORM (DW_FORM_GNU_str_index, 0x1f02)

View File

@@ -222,7 +222,13 @@ enum dwarf_line_number_ops
/* DWARF 3. */ /* DWARF 3. */
DW_LNS_set_prologue_end = 10, DW_LNS_set_prologue_end = 10,
DW_LNS_set_epilogue_begin = 11, 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. */ /* Line number extended opcodes. */
@@ -268,6 +274,22 @@ enum dwarf_location_list_entry_type
DW_LLE_GNU_start_length_entry = 3 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
};
#define DW_CIE_ID 0xffffffff #define DW_CIE_ID 0xffffffff
#define DW64_CIE_ID 0xffffffffffffffffULL #define DW64_CIE_ID 0xffffffffffffffffULL
#define DW_CIE_VERSION 1 #define DW_CIE_VERSION 1