summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@qt.io>2020-02-07 01:02:09 +0100
committerRobert Griebl <robert.griebl@qt.io>2020-02-10 14:39:11 +0100
commit47049dfb737bc404f909b1ed6e0d9e39cd89e2e6 (patch)
tree9761189c2408ecb14951f221b57a13a7c9348996
parentd4f063d48bee3b1b1e6a6df781c01694581e3afd (diff)
Update libbacktrace to latest upstream
Change-Id: Iac90c09b8a117bdd96d162cec96584b5b4cb5298 Reviewed-by: Dominik Holland <dominik.holland@qt.io>
-rw-r--r--3rdparty/libbacktrace/libbacktrace/atomic.c8
-rw-r--r--3rdparty/libbacktrace/libbacktrace/backtrace.c10
-rw-r--r--3rdparty/libbacktrace/libbacktrace/backtrace.h35
-rw-r--r--3rdparty/libbacktrace/libbacktrace/dwarf.c2302
-rw-r--r--3rdparty/libbacktrace/libbacktrace/elf.c2596
-rw-r--r--3rdparty/libbacktrace/libbacktrace/fileline.c23
-rw-r--r--3rdparty/libbacktrace/libbacktrace/internal.h76
-rw-r--r--3rdparty/libbacktrace/libbacktrace/mmap.c34
-rw-r--r--3rdparty/libbacktrace/libbacktrace/mmapio.c16
-rw-r--r--3rdparty/libbacktrace/libbacktrace/posix.c8
-rw-r--r--3rdparty/libbacktrace/libbacktrace/print.c10
-rw-r--r--3rdparty/libbacktrace/libbacktrace/simple.c10
-rw-r--r--3rdparty/libbacktrace/libbacktrace/sort.c8
-rw-r--r--3rdparty/libbacktrace/libbacktrace/state.c8
14 files changed, 4456 insertions, 688 deletions
diff --git a/3rdparty/libbacktrace/libbacktrace/atomic.c b/3rdparty/libbacktrace/libbacktrace/atomic.c
index cb0ad029..502ad358 100644
--- a/3rdparty/libbacktrace/libbacktrace/atomic.c
+++ b/3rdparty/libbacktrace/libbacktrace/atomic.c
@@ -1,5 +1,5 @@
/* atomic.c -- Support for atomic functions if not present.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
diff --git a/3rdparty/libbacktrace/libbacktrace/backtrace.c b/3rdparty/libbacktrace/libbacktrace/backtrace.c
index b89bf554..c579e803 100644
--- a/3rdparty/libbacktrace/libbacktrace/backtrace.c
+++ b/3rdparty/libbacktrace/libbacktrace/backtrace.c
@@ -1,5 +1,5 @@
/* backtrace.c -- Entry point for stack backtrace library.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -98,7 +98,7 @@ unwind (struct _Unwind_Context *context, void *vdata)
/* Get a stack backtrace. */
-int
+int __attribute__((noinline))
backtrace_full (struct backtrace_state *state, int skip,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data)
diff --git a/3rdparty/libbacktrace/libbacktrace/backtrace.h b/3rdparty/libbacktrace/libbacktrace/backtrace.h
index d209219d..0631f265 100644
--- a/3rdparty/libbacktrace/libbacktrace/backtrace.h
+++ b/3rdparty/libbacktrace/libbacktrace/backtrace.h
@@ -1,5 +1,5 @@
/* backtrace.h -- Public header file for stack backtrace library.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -34,25 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. */
#define BACKTRACE_H
#include <stddef.h>
-#include <stdio.h>
-
-/* We want to get a definition for uintptr_t, but we still care about
- systems that don't have <stdint.h>. */
-#if defined(__GLIBC__) && __GLIBC__ >= 2
-
-#include <stdint.h>
-
-#elif defined(HAVE_STDINT_H)
-
#include <stdint.h>
-
-#else
-
-/* Systems that don't have <stdint.h> must provide gstdint.h, e.g.,
- from GCC_HEADER_STDINT in configure.ac. */
-#include "gstdint.h"
-
-#endif
+#include <stdio.h>
#ifdef __cplusplus
extern "C" {
@@ -92,7 +75,13 @@ typedef void (*backtrace_error_callback) (void *data, const char *msg,
use appropriate atomic operations. If THREADED is zero the state
may only be accessed by one thread at a time. This returns a state
pointer on success, NULL on error. If an error occurs, this will
- call the ERROR_CALLBACK routine. */
+ call the ERROR_CALLBACK routine.
+
+ Calling this function allocates resources that cannot be freed.
+ There is no backtrace_free_state function. The state is used to
+ cache information that is expensive to recompute. Programs are
+ expected to call this function at most once and to save the return
+ value for all later calls to backtrace functions. */
extern struct backtrace_state *backtrace_create_state (
const char *filename, int threaded,
diff --git a/3rdparty/libbacktrace/libbacktrace/dwarf.c b/3rdparty/libbacktrace/libbacktrace/dwarf.c
index 55b8d7dc..af79dfe5 100644
--- a/3rdparty/libbacktrace/libbacktrace/dwarf.c
+++ b/3rdparty/libbacktrace/libbacktrace/dwarf.c
@@ -1,5 +1,5 @@
/* dwarf.c -- Get file/line information from DWARF for backtraces.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -37,12 +37,345 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <string.h>
#include <sys/types.h>
-#include "dwarf2.h"
#include "filenames.h"
#include "backtrace.h"
#include "internal.h"
+/* DWARF constants. */
+
+enum dwarf_tag {
+ DW_TAG_entry_point = 0x3,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_subprogram = 0x2e,
+};
+
+enum dwarf_form {
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16,
+ DW_FORM_sec_offset = 0x17,
+ DW_FORM_exprloc = 0x18,
+ DW_FORM_flag_present = 0x19,
+ DW_FORM_ref_sig8 = 0x20,
+ DW_FORM_strx = 0x1a,
+ DW_FORM_addrx = 0x1b,
+ DW_FORM_ref_sup4 = 0x1c,
+ DW_FORM_strp_sup = 0x1d,
+ DW_FORM_data16 = 0x1e,
+ DW_FORM_line_strp = 0x1f,
+ DW_FORM_implicit_const = 0x21,
+ DW_FORM_loclistx = 0x22,
+ DW_FORM_rnglistx = 0x23,
+ DW_FORM_ref_sup8 = 0x24,
+ DW_FORM_strx1 = 0x25,
+ DW_FORM_strx2 = 0x26,
+ DW_FORM_strx3 = 0x27,
+ DW_FORM_strx4 = 0x28,
+ DW_FORM_addrx1 = 0x29,
+ DW_FORM_addrx2 = 0x2a,
+ DW_FORM_addrx3 = 0x2b,
+ DW_FORM_addrx4 = 0x2c,
+ DW_FORM_GNU_addr_index = 0x1f01,
+ DW_FORM_GNU_str_index = 0x1f02,
+ DW_FORM_GNU_ref_alt = 0x1f20,
+ DW_FORM_GNU_strp_alt = 0x1f21
+};
+
+enum dwarf_attribute {
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_subscr_data = 0x0a,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_element_list = 0x0f,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_member = 0x14,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_bit_stride = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_items = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ DW_AT_allocated = 0x4e,
+ DW_AT_associated = 0x4f,
+ DW_AT_data_location = 0x50,
+ DW_AT_byte_stride = 0x51,
+ DW_AT_entry_pc = 0x52,
+ DW_AT_use_UTF8 = 0x53,
+ DW_AT_extension = 0x54,
+ DW_AT_ranges = 0x55,
+ DW_AT_trampoline = 0x56,
+ DW_AT_call_column = 0x57,
+ DW_AT_call_file = 0x58,
+ DW_AT_call_line = 0x59,
+ DW_AT_description = 0x5a,
+ DW_AT_binary_scale = 0x5b,
+ DW_AT_decimal_scale = 0x5c,
+ DW_AT_small = 0x5d,
+ DW_AT_decimal_sign = 0x5e,
+ DW_AT_digit_count = 0x5f,
+ DW_AT_picture_string = 0x60,
+ DW_AT_mutable = 0x61,
+ DW_AT_threads_scaled = 0x62,
+ DW_AT_explicit = 0x63,
+ DW_AT_object_pointer = 0x64,
+ DW_AT_endianity = 0x65,
+ DW_AT_elemental = 0x66,
+ DW_AT_pure = 0x67,
+ DW_AT_recursive = 0x68,
+ DW_AT_signature = 0x69,
+ DW_AT_main_subprogram = 0x6a,
+ DW_AT_data_bit_offset = 0x6b,
+ DW_AT_const_expr = 0x6c,
+ DW_AT_enum_class = 0x6d,
+ DW_AT_linkage_name = 0x6e,
+ DW_AT_string_length_bit_size = 0x6f,
+ DW_AT_string_length_byte_size = 0x70,
+ DW_AT_rank = 0x71,
+ DW_AT_str_offsets_base = 0x72,
+ DW_AT_addr_base = 0x73,
+ DW_AT_rnglists_base = 0x74,
+ DW_AT_dwo_name = 0x76,
+ DW_AT_reference = 0x77,
+ DW_AT_rvalue_reference = 0x78,
+ DW_AT_macros = 0x79,
+ DW_AT_call_all_calls = 0x7a,
+ DW_AT_call_all_source_calls = 0x7b,
+ DW_AT_call_all_tail_calls = 0x7c,
+ DW_AT_call_return_pc = 0x7d,
+ DW_AT_call_value = 0x7e,
+ DW_AT_call_origin = 0x7f,
+ DW_AT_call_parameter = 0x80,
+ DW_AT_call_pc = 0x81,
+ DW_AT_call_tail_call = 0x82,
+ DW_AT_call_target = 0x83,
+ DW_AT_call_target_clobbered = 0x84,
+ DW_AT_call_data_location = 0x85,
+ DW_AT_call_data_value = 0x86,
+ DW_AT_noreturn = 0x87,
+ DW_AT_alignment = 0x88,
+ DW_AT_export_symbols = 0x89,
+ DW_AT_deleted = 0x8a,
+ DW_AT_defaulted = 0x8b,
+ DW_AT_loclists_base = 0x8c,
+ DW_AT_lo_user = 0x2000,
+ DW_AT_hi_user = 0x3fff,
+ DW_AT_MIPS_fde = 0x2001,
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+ DW_AT_MIPS_epilog_begin = 0x2004,
+ DW_AT_MIPS_loop_unroll_factor = 0x2005,
+ DW_AT_MIPS_software_pipeline_depth = 0x2006,
+ DW_AT_MIPS_linkage_name = 0x2007,
+ DW_AT_MIPS_stride = 0x2008,
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
+ DW_AT_HP_block_index = 0x2000,
+ DW_AT_HP_unmodifiable = 0x2001,
+ DW_AT_HP_prologue = 0x2005,
+ DW_AT_HP_epilogue = 0x2008,
+ DW_AT_HP_actuals_stmt_list = 0x2010,
+ DW_AT_HP_proc_per_section = 0x2011,
+ DW_AT_HP_raw_data_ptr = 0x2012,
+ DW_AT_HP_pass_by_reference = 0x2013,
+ DW_AT_HP_opt_level = 0x2014,
+ DW_AT_HP_prof_version_id = 0x2015,
+ DW_AT_HP_opt_flags = 0x2016,
+ DW_AT_HP_cold_region_low_pc = 0x2017,
+ DW_AT_HP_cold_region_high_pc = 0x2018,
+ DW_AT_HP_all_variables_modifiable = 0x2019,
+ DW_AT_HP_linkage_name = 0x201a,
+ DW_AT_HP_prof_flags = 0x201b,
+ DW_AT_HP_unit_name = 0x201f,
+ DW_AT_HP_unit_size = 0x2020,
+ DW_AT_HP_widened_byte_size = 0x2021,
+ DW_AT_HP_definition_points = 0x2022,
+ DW_AT_HP_default_location = 0x2023,
+ DW_AT_HP_is_result_param = 0x2029,
+ DW_AT_sf_names = 0x2101,
+ DW_AT_src_info = 0x2102,
+ DW_AT_mac_info = 0x2103,
+ DW_AT_src_coords = 0x2104,
+ DW_AT_body_begin = 0x2105,
+ DW_AT_body_end = 0x2106,
+ DW_AT_GNU_vector = 0x2107,
+ DW_AT_GNU_guarded_by = 0x2108,
+ DW_AT_GNU_pt_guarded_by = 0x2109,
+ DW_AT_GNU_guarded = 0x210a,
+ DW_AT_GNU_pt_guarded = 0x210b,
+ DW_AT_GNU_locks_excluded = 0x210c,
+ DW_AT_GNU_exclusive_locks_required = 0x210d,
+ DW_AT_GNU_shared_locks_required = 0x210e,
+ DW_AT_GNU_odr_signature = 0x210f,
+ DW_AT_GNU_template_name = 0x2110,
+ DW_AT_GNU_call_site_value = 0x2111,
+ DW_AT_GNU_call_site_data_value = 0x2112,
+ DW_AT_GNU_call_site_target = 0x2113,
+ DW_AT_GNU_call_site_target_clobbered = 0x2114,
+ DW_AT_GNU_tail_call = 0x2115,
+ DW_AT_GNU_all_tail_call_sites = 0x2116,
+ DW_AT_GNU_all_call_sites = 0x2117,
+ DW_AT_GNU_all_source_call_sites = 0x2118,
+ DW_AT_GNU_macros = 0x2119,
+ DW_AT_GNU_deleted = 0x211a,
+ DW_AT_GNU_dwo_name = 0x2130,
+ DW_AT_GNU_dwo_id = 0x2131,
+ DW_AT_GNU_ranges_base = 0x2132,
+ DW_AT_GNU_addr_base = 0x2133,
+ DW_AT_GNU_pubnames = 0x2134,
+ DW_AT_GNU_pubtypes = 0x2135,
+ DW_AT_GNU_discriminator = 0x2136,
+ DW_AT_GNU_locviews = 0x2137,
+ DW_AT_GNU_entry_view = 0x2138,
+ DW_AT_VMS_rtnbeg_pd_address = 0x2201,
+ DW_AT_use_GNAT_descriptive_type = 0x2301,
+ DW_AT_GNAT_descriptive_type = 0x2302,
+ DW_AT_GNU_numerator = 0x2303,
+ DW_AT_GNU_denominator = 0x2304,
+ DW_AT_GNU_bias = 0x2305,
+ DW_AT_upc_threads_scaled = 0x3210,
+ DW_AT_PGI_lbase = 0x3a00,
+ DW_AT_PGI_soffset = 0x3a01,
+ DW_AT_PGI_lstride = 0x3a02,
+ DW_AT_APPLE_optimized = 0x3fe1,
+ DW_AT_APPLE_flags = 0x3fe2,
+ DW_AT_APPLE_isa = 0x3fe3,
+ DW_AT_APPLE_block = 0x3fe4,
+ DW_AT_APPLE_major_runtime_vers = 0x3fe5,
+ DW_AT_APPLE_runtime_class = 0x3fe6,
+ DW_AT_APPLE_omit_frame_ptr = 0x3fe7,
+ DW_AT_APPLE_property_name = 0x3fe8,
+ DW_AT_APPLE_property_getter = 0x3fe9,
+ DW_AT_APPLE_property_setter = 0x3fea,
+ DW_AT_APPLE_property_attribute = 0x3feb,
+ DW_AT_APPLE_objc_complete_type = 0x3fec,
+ DW_AT_APPLE_property = 0x3fed
+};
+
+enum dwarf_line_number_op {
+ DW_LNS_extended_op = 0x0,
+ DW_LNS_copy = 0x1,
+ DW_LNS_advance_pc = 0x2,
+ DW_LNS_advance_line = 0x3,
+ DW_LNS_set_file = 0x4,
+ DW_LNS_set_column = 0x5,
+ DW_LNS_negate_stmt = 0x6,
+ DW_LNS_set_basic_block = 0x7,
+ DW_LNS_const_add_pc = 0x8,
+ DW_LNS_fixed_advance_pc = 0x9,
+ DW_LNS_set_prologue_end = 0xa,
+ DW_LNS_set_epilogue_begin = 0xb,
+ DW_LNS_set_isa = 0xc,
+};
+
+enum dwarf_extended_line_number_op {
+ DW_LNE_end_sequence = 0x1,
+ DW_LNE_set_address = 0x2,
+ DW_LNE_define_file = 0x3,
+ DW_LNE_set_discriminator = 0x4,
+};
+
+enum dwarf_line_number_content_type {
+ DW_LNCT_path = 0x1,
+ DW_LNCT_directory_index = 0x2,
+ DW_LNCT_timestamp = 0x3,
+ DW_LNCT_size = 0x4,
+ DW_LNCT_MD5 = 0x5,
+ DW_LNCT_lo_user = 0x2000,
+ DW_LNCT_hi_user = 0x3fff
+};
+
+enum dwarf_range_list_entry {
+ DW_RLE_end_of_list = 0x00,
+ DW_RLE_base_addressx = 0x01,
+ DW_RLE_startx_endx = 0x02,
+ DW_RLE_startx_length = 0x03,
+ DW_RLE_offset_pair = 0x04,
+ DW_RLE_base_address = 0x05,
+ DW_RLE_start_end = 0x06,
+ DW_RLE_start_length = 0x07
+};
+
+enum dwarf_unit_type {
+ DW_UT_compile = 0x01,
+ DW_UT_type = 0x02,
+ DW_UT_partial = 0x03,
+ DW_UT_skeleton = 0x04,
+ DW_UT_split_compile = 0x05,
+ DW_UT_split_type = 0x06,
+ DW_UT_lo_user = 0x80,
+ DW_UT_hi_user = 0xff
+};
+
#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
/* If strnlen is not declared, provide our own version. */
@@ -92,6 +425,8 @@ struct attr
enum dwarf_attribute name;
/* The attribute form. */
enum dwarf_form form;
+ /* The attribute value, for DW_FORM_implicit_const. */
+ int64_t val;
};
/* A single DWARF abbreviation. */
@@ -129,22 +464,33 @@ struct abbrevs
enum attr_val_encoding
{
+ /* No attribute value. */
+ ATTR_VAL_NONE,
/* An address. */
ATTR_VAL_ADDRESS,
+ /* An index into the .debug_addr section, whose value is relative to
+ * the DW_AT_addr_base attribute of the compilation unit. */
+ ATTR_VAL_ADDRESS_INDEX,
/* A unsigned integer. */
ATTR_VAL_UINT,
/* A sigd integer. */
ATTR_VAL_SINT,
/* A string. */
ATTR_VAL_STRING,
+ /* An index into the .debug_str_offsets section. */
+ ATTR_VAL_STRING_INDEX,
/* An offset to other data in the containing unit. */
ATTR_VAL_REF_UNIT,
- /* An offset to other data within the .dwarf_info section. */
+ /* An offset to other data within the .debug_info section. */
ATTR_VAL_REF_INFO,
+ /* An offset to other data within the alt .debug_info section. */
+ ATTR_VAL_REF_ALT_INFO,
/* An offset to data in some other section. */
ATTR_VAL_REF_SECTION,
/* A type signature. */
ATTR_VAL_REF_TYPE,
+ /* An index into the .debug_rnglists section. */
+ ATTR_VAL_RNGLISTS_INDEX,
/* A block of data (not represented). */
ATTR_VAL_BLOCK,
/* An expression (not represented). */
@@ -159,7 +505,7 @@ struct attr_val
enum attr_val_encoding encoding;
union
{
- /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */
+ /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*. */
uint64_t uint;
/* ATTR_VAL_SINT. */
int64_t sint;
@@ -175,6 +521,8 @@ struct line_header
{
/* The version of the line number information. */
int version;
+ /* Address size. */
+ int addrsize;
/* The minimum instruction length. */
unsigned int min_insn_len;
/* The maximum number of ops per instruction. */
@@ -197,6 +545,14 @@ struct line_header
const char **filenames;
};
+/* A format description from a line header. */
+
+struct line_header_format
+{
+ int lnct; /* LNCT code. */
+ enum dwarf_form form; /* Form of entry data. */
+};
+
/* Map a single PC value to a file/line. We will keep a vector of
these sorted by PC value. Each file/line will be correct from the
PC up to the PC of the next entry if there is one. We allocate one
@@ -279,6 +635,12 @@ struct unit
/* The offset of UNIT_DATA from the start of the information for
this compilation unit. */
size_t unit_data_offset;
+ /* Offset of the start of the compilation unit from the start of the
+ .debug_info section. */
+ size_t low_offset;
+ /* Offset of the end of the compilation unit from the start of the
+ .debug_info section. */
+ size_t high_offset;
/* DWARF version. */
int version;
/* Whether unit is DWARF64. */
@@ -287,6 +649,12 @@ struct unit
int addrsize;
/* Offset into line number information. */
off_t lineoff;
+ /* Offset of compilation unit in .debug_str_offsets. */
+ uint64_t str_offsets_base;
+ /* Offset of compilation unit in .debug_addr. */
+ uint64_t addr_base;
+ /* Offset of compilation unit in .debug_rnglists. */
+ uint64_t rnglists_base;
/* Primary source file. */
const char *filename;
/* Compilation command working directory. */
@@ -337,30 +705,34 @@ struct unit_addrs_vector
size_t count;
};
+/* A growable vector of compilation unit pointer. */
+
+struct unit_vector
+{
+ struct backtrace_vector vec;
+ size_t count;
+};
+
/* The information we need to map a PC to a file and line. */
struct dwarf_data
{
/* The data for the next file we know about. */
struct dwarf_data *next;
+ /* The data for .gnu_debugaltlink. */
+ struct dwarf_data *altlink;
/* The base address for this file. */
uintptr_t base_address;
/* A sorted list of address ranges. */
struct unit_addrs *addrs;
/* Number of address ranges in list. */
size_t addrs_count;
- /* The unparsed .debug_info section. */
- const unsigned char *dwarf_info;
- size_t dwarf_info_size;
- /* The unparsed .debug_line section. */
- const unsigned char *dwarf_line;
- size_t dwarf_line_size;
- /* The unparsed .debug_ranges section. */
- const unsigned char *dwarf_ranges;
- size_t dwarf_ranges_size;
- /* The unparsed .debug_str section. */
- const unsigned char *dwarf_str;
- size_t dwarf_str_size;
+ /* A sorted list of units. */
+ struct unit **units;
+ /* Number of units in the list. */
+ size_t units_count;
+ /* The unparsed DWARF debug data. */
+ struct dwarf_sections dwarf_sections;
/* Whether the data is big-endian or not. */
int is_bigendian;
/* A vector used for function addresses. We keep this here so that
@@ -411,6 +783,25 @@ advance (struct dwarf_buf *buf, size_t count)
return 1;
}
+/* Read one zero-terminated string from BUF and advance past the string. */
+
+static const char *
+read_string (struct dwarf_buf *buf)
+{
+ const char *p = (const char *)buf->buf;
+ size_t len = strnlen (p, buf->left);
+
+ /* - If len == left, we ran out of buffer before finding the zero terminator.
+ Generate an error by advancing len + 1.
+ - If len < left, advance by len + 1 to skip past the zero terminator. */
+ size_t count = len + 1;
+
+ if (!advance (buf, count))
+ return NULL;
+
+ return p;
+}
+
/* Read one byte from BUF and advance 1 byte. */
static unsigned char
@@ -450,6 +841,23 @@ read_uint16 (struct dwarf_buf *buf)
return ((uint16_t) p[1] << 8) | (uint16_t) p[0];
}
+/* Read a 24 bit value from BUF and advance 3 bytes. */
+
+static uint32_t
+read_uint24 (struct dwarf_buf *buf)
+{
+ const unsigned char *p = buf->buf;
+
+ if (!advance (buf, 3))
+ return 0;
+ if (buf->is_bigendian)
+ return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8)
+ | (uint32_t) p[2]);
+ else
+ return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8)
+ | (uint32_t) p[0]);
+}
+
/* Read a uint32 from BUF and advance 4 bytes. */
static uint32_t
@@ -632,6 +1040,25 @@ leb128_len (const unsigned char *p)
return ret;
}
+/* Read initial_length from BUF and advance the appropriate number of bytes. */
+
+static uint64_t
+read_initial_length (struct dwarf_buf *buf, int *is_dwarf64)
+{
+ uint64_t len;
+
+ len = read_uint32 (buf);
+ if (len == 0xffffffff)
+ {
+ len = read_uint64 (buf);
+ *is_dwarf64 = 1;
+ }
+ else
+ *is_dwarf64 = 0;
+
+ return len;
+}
+
/* Free an abbreviations structure. */
static void
@@ -657,10 +1084,10 @@ free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,
forms, because we don't care about them. */
static int
-read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
- int is_dwarf64, int version, int addrsize,
- const unsigned char *dwarf_str, size_t dwarf_str_size,
- struct attr_val *val)
+read_attribute (enum dwarf_form form, uint64_t implicit_val,
+ struct dwarf_buf *buf, int is_dwarf64, int version,
+ int addrsize, const struct dwarf_sections *dwarf_sections,
+ struct dwarf_data *altlink, struct attr_val *val)
{
/* Avoid warnings about val.u.FIELD may be used uninitialized if
this function is inlined. The warnings aren't valid but can
@@ -692,10 +1119,13 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_UINT;
val->u.uint = read_uint64 (buf);
return 1;
+ case DW_FORM_data16:
+ val->encoding = ATTR_VAL_BLOCK;
+ return advance (buf, 16);
case DW_FORM_string:
val->encoding = ATTR_VAL_STRING;
- val->u.string = (const char *) buf->buf;
- return advance (buf, strnlen ((const char *) buf->buf, buf->left) + 1);
+ val->u.string = read_string (buf);
+ return val->u.string == NULL ? 0 : 1;
case DW_FORM_block:
val->encoding = ATTR_VAL_BLOCK;
return advance (buf, read_uleb128 (buf));
@@ -719,13 +1149,29 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t offset;
offset = read_offset (buf, is_dwarf64);
- if (offset >= dwarf_str_size)
+ if (offset >= dwarf_sections->size[DEBUG_STR])
{
dwarf_buf_error (buf, "DW_FORM_strp out of range");
return 0;
}
val->encoding = ATTR_VAL_STRING;
- val->u.string = (const char *) dwarf_str + offset;
+ val->u.string =
+ (const char *) dwarf_sections->data[DEBUG_STR] + offset;
+ return 1;
+ }
+ case DW_FORM_line_strp:
+ {
+ uint64_t offset;
+
+ offset = read_offset (buf, is_dwarf64);
+ if (offset >= dwarf_sections->size[DEBUG_LINE_STR])
+ {
+ dwarf_buf_error (buf, "DW_FORM_line_strp out of range");
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING;
+ val->u.string =
+ (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset;
return 1;
}
case DW_FORM_udata:
@@ -764,8 +1210,14 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
uint64_t form;
form = read_uleb128 (buf);
- return read_attribute ((enum dwarf_form) form, buf, is_dwarf64,
- version, addrsize, dwarf_str, dwarf_str_size,
+ if (form == DW_FORM_implicit_const)
+ {
+ dwarf_buf_error (buf,
+ "DW_FORM_indirect to DW_FORM_implicit_const");
+ return 0;
+ }
+ return read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64,
+ version, addrsize, dwarf_sections, altlink,
val);
}
case DW_FORM_sec_offset:
@@ -783,6 +1235,88 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->encoding = ATTR_VAL_REF_TYPE;
val->u.uint = read_uint64 (buf);
return 1;
+ case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2:
+ case DW_FORM_strx3: case DW_FORM_strx4:
+ {
+ uint64_t offset;
+
+ switch (form)
+ {
+ case DW_FORM_strx:
+ offset = read_uleb128 (buf);
+ break;
+ case DW_FORM_strx1:
+ offset = read_byte (buf);
+ break;
+ case DW_FORM_strx2:
+ offset = read_uint16 (buf);
+ break;
+ case DW_FORM_strx3:
+ offset = read_uint24 (buf);
+ break;
+ case DW_FORM_strx4:
+ offset = read_uint32 (buf);
+ break;
+ default:
+ /* This case can't happen. */
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING_INDEX;
+ val->u.uint = offset;
+ return 1;
+ }
+ case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2:
+ case DW_FORM_addrx3: case DW_FORM_addrx4:
+ {
+ uint64_t offset;
+
+ switch (form)
+ {
+ case DW_FORM_addrx:
+ offset = read_uleb128 (buf);
+ break;
+ case DW_FORM_addrx1:
+ offset = read_byte (buf);
+ break;
+ case DW_FORM_addrx2:
+ offset = read_uint16 (buf);
+ break;
+ case DW_FORM_addrx3:
+ offset = read_uint24 (buf);
+ break;
+ case DW_FORM_addrx4:
+ offset = read_uint32 (buf);
+ break;
+ default:
+ /* This case can't happen. */
+ return 0;
+ }
+ val->encoding = ATTR_VAL_ADDRESS_INDEX;
+ val->u.uint = offset;
+ return 1;
+ }
+ case DW_FORM_ref_sup4:
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uint32 (buf);
+ return 1;
+ case DW_FORM_ref_sup8:
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uint64 (buf);
+ return 1;
+ case DW_FORM_implicit_const:
+ val->encoding = ATTR_VAL_UINT;
+ val->u.uint = implicit_val;
+ return 1;
+ case DW_FORM_loclistx:
+ /* We don't distinguish this from DW_FORM_sec_offset. It
+ * shouldn't matter since we don't care about loclists. */
+ val->encoding = ATTR_VAL_REF_SECTION;
+ val->u.uint = read_uleb128 (buf);
+ return 1;
+ case DW_FORM_rnglistx:
+ val->encoding = ATTR_VAL_RNGLISTS_INDEX;
+ val->u.uint = read_uleb128 (buf);
+ return 1;
case DW_FORM_GNU_addr_index:
val->encoding = ATTR_VAL_REF_SECTION;
val->u.uint = read_uleb128 (buf);
@@ -792,19 +1326,157 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->u.uint = read_uleb128 (buf);
return 1;
case DW_FORM_GNU_ref_alt:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_offset (buf, is_dwarf64);
- return 1;
- case DW_FORM_GNU_strp_alt:
- val->encoding = ATTR_VAL_REF_SECTION;
val->u.uint = read_offset (buf, is_dwarf64);
+ if (altlink == NULL)
+ {
+ val->encoding = ATTR_VAL_NONE;
+ return 1;
+ }
+ val->encoding = ATTR_VAL_REF_ALT_INFO;
return 1;
+ case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt:
+ {
+ uint64_t offset;
+
+ offset = read_offset (buf, is_dwarf64);
+ if (altlink == NULL)
+ {
+ val->encoding = ATTR_VAL_NONE;
+ return 1;
+ }
+ if (offset >= altlink->dwarf_sections.size[DEBUG_STR])
+ {
+ dwarf_buf_error (buf, "DW_FORM_strp_sup out of range");
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING;
+ val->u.string =
+ (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset;
+ return 1;
+ }
default:
dwarf_buf_error (buf, "unrecognized DWARF form");
return 0;
}
}
+/* If we can determine the value of a string attribute, set *STRING to
+ point to the string. Return 1 on success, 0 on error. If we don't
+ know the value, we consider that a success, and we don't change
+ *STRING. An error is only reported for some sort of out of range
+ offset. */
+
+static int
+resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64,
+ int is_bigendian, uint64_t str_offsets_base,
+ const struct attr_val *val,
+ backtrace_error_callback error_callback, void *data,
+ const char **string)
+{
+ switch (val->encoding)
+ {
+ case ATTR_VAL_STRING:
+ *string = val->u.string;
+ return 1;
+
+ case ATTR_VAL_STRING_INDEX:
+ {
+ uint64_t offset;
+ struct dwarf_buf offset_buf;
+
+ offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base;
+ if (offset + (is_dwarf64 ? 8 : 4)
+ >= dwarf_sections->size[DEBUG_STR_OFFSETS])
+ {
+ error_callback (data, "DW_FORM_strx value out of range", 0);
+ return 0;
+ }
+
+ offset_buf.name = ".debug_str_offsets";
+ offset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS];
+ offset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset;
+ offset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset;
+ offset_buf.is_bigendian = is_bigendian;
+ offset_buf.error_callback = error_callback;
+ offset_buf.data = data;
+ offset_buf.reported_underflow = 0;
+
+ offset = read_offset (&offset_buf, is_dwarf64);
+ if (offset >= dwarf_sections->size[DEBUG_STR])
+ {
+ dwarf_buf_error (&offset_buf, "DW_FORM_strx offset out of range");
+ return 0;
+ }
+ *string = (const char *) dwarf_sections->data[DEBUG_STR] + offset;
+ return 1;
+ }
+
+ default:
+ return 1;
+ }
+}
+
+/* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX.
+ Return 1 on success, 0 on error. */
+
+static int
+resolve_addr_index (const struct dwarf_sections *dwarf_sections,
+ uint64_t addr_base, int addrsize, int is_bigendian,
+ uint64_t addr_index,
+ backtrace_error_callback error_callback, void *data,
+ uint64_t *address)
+{
+ uint64_t offset;
+ struct dwarf_buf addr_buf;
+
+ offset = addr_index * addrsize + addr_base;
+ if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR])
+ {
+ error_callback (data, "DW_FORM_addrx value out of range", 0);
+ return 0;
+ }
+
+ addr_buf.name = ".debug_addr";
+ addr_buf.start = dwarf_sections->data[DEBUG_ADDR];
+ addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset;
+ addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset;
+ addr_buf.is_bigendian = is_bigendian;
+ addr_buf.error_callback = error_callback;
+ addr_buf.data = data;
+ addr_buf.reported_underflow = 0;
+
+ *address = read_address (&addr_buf, addrsize);
+ return 1;
+}
+
+/* Compare a unit offset against a unit for bsearch. */
+
+static int
+units_search (const void *vkey, const void *ventry)
+{
+ const size_t *key = (const size_t *) vkey;
+ const struct unit *entry = *((const struct unit *const *) ventry);
+ size_t offset;
+
+ offset = *key;
+ if (offset < entry->low_offset)
+ return -1;
+ else if (offset >= entry->high_offset)
+ return 1;
+ else
+ return 0;
+}
+
+/* Find a unit in PU containing OFFSET. */
+
+static struct unit *
+find_unit (struct unit **pu, size_t units_count, size_t offset)
+{
+ struct unit **u;
+ u = bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search);
+ return u == NULL ? NULL : *u;
+}
+
/* Compare function_addrs for qsort. When ranges are nested, make the
smallest one sort last. */
@@ -845,31 +1517,28 @@ function_addrs_search (const void *vkey, const void *ventry)
return 0;
}
-/* Add a new compilation unit address range to a vector. Returns 1 on
- success, 0 on failure. */
+/* Add a new compilation unit address range to a vector. This is
+ called via add_ranges. Returns 1 on success, 0 on failure. */
static int
-add_unit_addr (struct backtrace_state *state, uintptr_t base_address,
- struct unit_addrs addrs,
+add_unit_addr (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
backtrace_error_callback error_callback, void *data,
- struct unit_addrs_vector *vec)
+ void *pvec)
{
+ struct unit *u = (struct unit *) rdata;
+ struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec;
struct unit_addrs *p;
- /* Add in the base address of the module here, so that we can look
- up the PC directly. */
- addrs.low += base_address;
- addrs.high += base_address;
-
/* Try to merge with the last entry. */
if (vec->count > 0)
{
p = (struct unit_addrs *) vec->vec.base + (vec->count - 1);
- if ((addrs.low == p->high || addrs.low == p->high + 1)
- && addrs.u == p->u)
+ if ((lowpc == p->high || lowpc == p->high + 1)
+ && u == p->u)
{
- if (addrs.high > p->high)
- p->high = addrs.high;
+ if (highpc > p->high)
+ p->high = highpc;
return 1;
}
}
@@ -880,24 +1549,13 @@ add_unit_addr (struct backtrace_state *state, uintptr_t base_address,
if (p == NULL)
return 0;
- *p = addrs;
- ++vec->count;
- return 1;
-}
-
-/* Free a unit address vector. */
+ p->low = lowpc;
+ p->high = highpc;
+ p->u = u;
-static void
-free_unit_addrs_vector (struct backtrace_state *state,
- struct unit_addrs_vector *vec,
- backtrace_error_callback error_callback, void *data)
-{
- struct unit_addrs *addrs;
- size_t i;
+ ++vec->count;
- addrs = (struct unit_addrs *) vec->vec.base;
- for (i = 0; i < vec->count; ++i)
- free_abbrevs (state, &addrs[i].u->abbrevs, error_callback, data);
+ return 1;
}
/* Compare unit_addrs for qsort. When ranges are nested, make the
@@ -1056,7 +1714,13 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
read_byte (&count_buf);
// Skip attributes.
while (read_uleb128 (&count_buf) != 0)
- read_uleb128 (&count_buf);
+ {
+ uint64_t form;
+
+ form = read_uleb128 (&count_buf);
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ read_sleb128 (&count_buf);
+ }
// Skip form of last attribute.
read_uleb128 (&count_buf);
}
@@ -1067,13 +1731,13 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
if (num_abbrevs == 0)
return 1;
- abbrevs->num_abbrevs = num_abbrevs;
abbrevs->abbrevs = ((struct abbrev *)
backtrace_alloc (state,
num_abbrevs * sizeof (struct abbrev),
error_callback, data));
if (abbrevs->abbrevs == NULL)
return 0;
+ abbrevs->num_abbrevs = num_abbrevs;
memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev));
num_abbrevs = 0;
@@ -1099,8 +1763,12 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
num_attrs = 0;
while (read_uleb128 (&count_buf) != 0)
{
+ uint64_t form;
+
++num_attrs;
- read_uleb128 (&count_buf);
+ form = read_uleb128 (&count_buf);
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ read_sleb128 (&count_buf);
}
if (num_attrs == 0)
@@ -1128,6 +1796,10 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
break;
attrs[num_attrs].name = (enum dwarf_attribute) name;
attrs[num_attrs].form = (enum dwarf_form) form;
+ if ((enum dwarf_form) form == DW_FORM_implicit_const)
+ attrs[num_attrs].val = read_sleb128 (&abbrev_buf);
+ else
+ attrs[num_attrs].val = 0;
++num_attrs;
}
}
@@ -1177,29 +1849,165 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code,
return (const struct abbrev *) p;
}
-/* Add non-contiguous address ranges for a compilation unit. Returns
- 1 on success, 0 on failure. */
+/* This struct is used to gather address range information while
+ reading attributes. We use this while building a mapping from
+ address ranges to compilation units and then again while mapping
+ from address ranges to function entries. Normally either
+ lowpc/highpc is set or ranges is set. */
+
+struct pcrange {
+ uint64_t lowpc; /* The low PC value. */
+ int have_lowpc; /* Whether a low PC value was found. */
+ int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */
+ uint64_t highpc; /* The high PC value. */
+ int have_highpc; /* Whether a high PC value was found. */
+ int highpc_is_relative; /* Whether highpc is relative to lowpc. */
+ int highpc_is_addr_index; /* Whether highpc is in .debug_addr. */
+ uint64_t ranges; /* Offset in ranges section. */
+ int have_ranges; /* Whether ranges is valid. */
+ int ranges_is_index; /* Whether ranges is DW_FORM_rnglistx. */
+};
+
+/* Update PCRANGE from an attribute value. */
+
+static void
+update_pcrange (const struct attr* attr, const struct attr_val* val,
+ struct pcrange *pcrange)
+{
+ switch (attr->name)
+ {
+ case DW_AT_low_pc:
+ if (val->encoding == ATTR_VAL_ADDRESS)
+ {
+ pcrange->lowpc = val->u.uint;
+ pcrange->have_lowpc = 1;
+ }
+ else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ pcrange->lowpc = val->u.uint;
+ pcrange->have_lowpc = 1;
+ pcrange->lowpc_is_addr_index = 1;
+ }
+ break;
+
+ case DW_AT_high_pc:
+ if (val->encoding == ATTR_VAL_ADDRESS)
+ {
+ pcrange->highpc = val->u.uint;
+ pcrange->have_highpc = 1;
+ }
+ else if (val->encoding == ATTR_VAL_UINT)
+ {
+ pcrange->highpc = val->u.uint;
+ pcrange->have_highpc = 1;
+ pcrange->highpc_is_relative = 1;
+ }
+ else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ pcrange->highpc = val->u.uint;
+ pcrange->have_highpc = 1;
+ pcrange->highpc_is_addr_index = 1;
+ }
+ break;
+
+ case DW_AT_ranges:
+ if (val->encoding == ATTR_VAL_UINT
+ || val->encoding == ATTR_VAL_REF_SECTION)
+ {
+ pcrange->ranges = val->u.uint;
+ pcrange->have_ranges = 1;
+ }
+ else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX)
+ {
+ pcrange->ranges = val->u.uint;
+ pcrange->have_ranges = 1;
+ pcrange->ranges_is_index = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Call ADD_RANGE for a low/high PC pair. Returns 1 on success, 0 on
+ error. */
static int
-add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
- struct unit *u, uint64_t ranges, uint64_t base,
- int is_bigendian, const unsigned char *dwarf_ranges,
- size_t dwarf_ranges_size,
- backtrace_error_callback error_callback, void *data,
- struct unit_addrs_vector *addrs)
+add_low_high_range (struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state,
+ void *rdata, uint64_t lowpc,
+ uint64_t highpc,
+ backtrace_error_callback error_callback,
+ void *data, void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ uint64_t lowpc;
+ uint64_t highpc;
+
+ lowpc = pcrange->lowpc;
+ if (pcrange->lowpc_is_addr_index)
+ {
+ if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
+ is_bigendian, lowpc, error_callback, data,
+ &lowpc))
+ return 0;
+ }
+
+ highpc = pcrange->highpc;
+ if (pcrange->highpc_is_addr_index)
+ {
+ if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,
+ is_bigendian, highpc, error_callback, data,
+ &highpc))
+ return 0;
+ }
+ if (pcrange->highpc_is_relative)
+ highpc += lowpc;
+
+ /* Add in the base address of the module when recording PC values,
+ so that we can look up the PC directly. */
+ lowpc += base_address;
+ highpc += base_address;
+
+ return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
+}
+
+/* Call ADD_RANGE for each range read from .debug_ranges, as used in
+ DWARF versions 2 through 4. */
+
+static int
+add_ranges_from_ranges (
+ struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base,
+ const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback, void *data,
+ void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
{
struct dwarf_buf ranges_buf;
- if (ranges >= dwarf_ranges_size)
+ if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES])
{
error_callback (data, "ranges offset out of range", 0);
return 0;
}
ranges_buf.name = ".debug_ranges";
- ranges_buf.start = dwarf_ranges;
- ranges_buf.buf = dwarf_ranges + ranges;
- ranges_buf.left = dwarf_ranges_size - ranges;
+ ranges_buf.start = dwarf_sections->data[DEBUG_RANGES];
+ ranges_buf.buf = dwarf_sections->data[DEBUG_RANGES] + pcrange->ranges;
+ ranges_buf.left = dwarf_sections->size[DEBUG_RANGES] - pcrange->ranges;
ranges_buf.is_bigendian = is_bigendian;
ranges_buf.error_callback = error_callback;
ranges_buf.data = data;
@@ -1223,13 +2031,10 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
base = high;
else
{
- struct unit_addrs a;
-
- a.low = low + base;
- a.high = high + base;
- a.u = u;
- if (!add_unit_addr (state, base_address, a, error_callback, data,
- addrs))
+ if (!add_range (state, rdata,
+ low + base + base_address,
+ high + base + base_address,
+ error_callback, data, vec))
return 0;
}
}
@@ -1240,31 +2045,242 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
return 1;
}
+/* Call ADD_RANGE for each range read from .debug_rnglists, as used in
+ DWARF version 5. */
+
+static int
+add_ranges_from_rnglists (
+ struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base,
+ const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback, void *data,
+ void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ uint64_t offset;
+ struct dwarf_buf rnglists_buf;
+
+ if (!pcrange->ranges_is_index)
+ offset = pcrange->ranges;
+ else
+ offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4);
+ if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
+ {
+ error_callback (data, "rnglists offset out of range", 0);
+ return 0;
+ }
+
+ rnglists_buf.name = ".debug_rnglists";
+ rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS];
+ rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
+ rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
+ rnglists_buf.is_bigendian = is_bigendian;
+ rnglists_buf.error_callback = error_callback;
+ rnglists_buf.data = data;
+ rnglists_buf.reported_underflow = 0;
+
+ if (pcrange->ranges_is_index)
+ {
+ offset = read_offset (&rnglists_buf, u->is_dwarf64);
+ offset += u->rnglists_base;
+ if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])
+ {
+ error_callback (data, "rnglists index offset out of range", 0);
+ return 0;
+ }
+ rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;
+ rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;
+ }
+
+ while (1)
+ {
+ unsigned char rle;
+
+ rle = read_byte (&rnglists_buf);
+ if (rle == DW_RLE_end_of_list)
+ break;
+ switch (rle)
+ {
+ case DW_RLE_base_addressx:
+ {
+ uint64_t index;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &base))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_startx_endx:
+ {
+ uint64_t index;
+ uint64_t low;
+ uint64_t high;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &low))
+ return 0;
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &high))
+ return 0;
+ if (!add_range (state, rdata, low + base_address,
+ high + base_address, error_callback, data,
+ vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_startx_length:
+ {
+ uint64_t index;
+ uint64_t low;
+ uint64_t length;
+
+ index = read_uleb128 (&rnglists_buf);
+ if (!resolve_addr_index (dwarf_sections, u->addr_base,
+ u->addrsize, is_bigendian, index,
+ error_callback, data, &low))
+ return 0;
+ length = read_uleb128 (&rnglists_buf);
+ low += base_address;
+ if (!add_range (state, rdata, low, low + length,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_offset_pair:
+ {
+ uint64_t low;
+ uint64_t high;
+
+ low = read_uleb128 (&rnglists_buf);
+ high = read_uleb128 (&rnglists_buf);
+ if (!add_range (state, rdata, low + base + base_address,
+ high + base + base_address,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_base_address:
+ base = read_address (&rnglists_buf, u->addrsize);
+ break;
+
+ case DW_RLE_start_end:
+ {
+ uint64_t low;
+ uint64_t high;
+
+ low = read_address (&rnglists_buf, u->addrsize);
+ high = read_address (&rnglists_buf, u->addrsize);
+ if (!add_range (state, rdata, low + base_address,
+ high + base_address, error_callback, data,
+ vec))
+ return 0;
+ }
+ break;
+
+ case DW_RLE_start_length:
+ {
+ uint64_t low;
+ uint64_t length;
+
+ low = read_address (&rnglists_buf, u->addrsize);
+ length = read_uleb128 (&rnglists_buf);
+ low += base_address;
+ if (!add_range (state, rdata, low, low + length,
+ error_callback, data, vec))
+ return 0;
+ }
+ break;
+
+ default:
+ dwarf_buf_error (&rnglists_buf, "unrecognized DW_RLE value");
+ return 0;
+ }
+ }
+
+ if (rnglists_buf.reported_underflow)
+ return 0;
+
+ return 1;
+}
+
+/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is
+ passed to ADD_RANGE, and is either a struct unit * or a struct
+ function *. VEC is the vector we are adding ranges to, and is
+ either a struct unit_addrs_vector * or a struct function_vector *.
+ Returns 1 on success, 0 on error. */
+
+static int
+add_ranges (struct backtrace_state *state,
+ const struct dwarf_sections *dwarf_sections,
+ uintptr_t base_address, int is_bigendian,
+ struct unit *u, uint64_t base, const struct pcrange *pcrange,
+ int (*add_range) (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback,
+ void *data, void *vec),
+ void *rdata,
+ backtrace_error_callback error_callback, void *data,
+ void *vec)
+{
+ if (pcrange->have_lowpc && pcrange->have_highpc)
+ return add_low_high_range (state, dwarf_sections, base_address,
+ is_bigendian, u, pcrange, add_range, rdata,
+ error_callback, data, vec);
+
+ if (!pcrange->have_ranges)
+ {
+ /* Did not find any address ranges to add. */
+ return 1;
+ }
+
+ if (u->version < 5)
+ return add_ranges_from_ranges (state, dwarf_sections, base_address,
+ is_bigendian, u, base, pcrange, add_range,
+ rdata, error_callback, data, vec);
+ else
+ return add_ranges_from_rnglists (state, dwarf_sections, base_address,
+ is_bigendian, u, base, pcrange, add_range,
+ rdata, error_callback, data, vec);
+}
+
/* Find the address range covered by a compilation unit, reading from
UNIT_BUF and adding values to U. Returns 1 if all data could be
read, 0 if there is some error. */
static int
find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
- struct dwarf_buf *unit_buf,
- const unsigned char *dwarf_str, size_t dwarf_str_size,
- const unsigned char *dwarf_ranges,
- size_t dwarf_ranges_size,
- int is_bigendian, backtrace_error_callback error_callback,
- void *data, struct unit *u,
- struct unit_addrs_vector *addrs)
+ struct dwarf_buf *unit_buf,
+ const struct dwarf_sections *dwarf_sections,
+ int is_bigendian, struct dwarf_data *altlink,
+ backtrace_error_callback error_callback, void *data,
+ struct unit *u, struct unit_addrs_vector *addrs,
+ enum dwarf_tag *unit_tag)
{
while (unit_buf->left > 0)
{
uint64_t code;
const struct abbrev *abbrev;
- uint64_t lowpc;
- int have_lowpc;
- uint64_t highpc;
- int have_highpc;
- int highpc_is_relative;
- uint64_t ranges;
- int have_ranges;
+ struct pcrange pcrange;
+ struct attr_val name_val;
+ int have_name_val;
+ struct attr_val comp_dir_val;
+ int have_comp_dir_val;
size_t i;
code = read_uleb128 (unit_buf);
@@ -1275,72 +2291,68 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
if (abbrev == NULL)
return 0;
- lowpc = 0;
- have_lowpc = 0;
- highpc = 0;
- have_highpc = 0;
- highpc_is_relative = 0;
- ranges = 0;
- have_ranges = 0;
+ if (unit_tag != NULL)
+ *unit_tag = abbrev->tag;
+
+ memset (&pcrange, 0, sizeof pcrange);
+ memset (&name_val, 0, sizeof name_val);
+ have_name_val = 0;
+ memset (&comp_dir_val, 0, sizeof comp_dir_val);
+ have_comp_dir_val = 0;
for (i = 0; i < abbrev->num_attrs; ++i)
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- dwarf_str, dwarf_str_size, &val))
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ unit_buf, u->is_dwarf64, u->version,
+ u->addrsize, dwarf_sections, altlink, &val))
return 0;
switch (abbrev->attrs[i].name)
{
- case DW_AT_low_pc:
- if (val.encoding == ATTR_VAL_ADDRESS)
- {
- lowpc = val.u.uint;
- have_lowpc = 1;
- }
+ case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
+ update_pcrange (&abbrev->attrs[i], &val, &pcrange);
break;
- case DW_AT_high_pc:
- if (val.encoding == ATTR_VAL_ADDRESS)
- {
- highpc = val.u.uint;
- have_highpc = 1;
- }
- else if (val.encoding == ATTR_VAL_UINT)
+ case DW_AT_stmt_list:
+ if (abbrev->tag == DW_TAG_compile_unit
+ && (val.encoding == ATTR_VAL_UINT
+ || val.encoding == ATTR_VAL_REF_SECTION))
+ u->lineoff = val.u.uint;
+ break;
+
+ case DW_AT_name:
+ if (abbrev->tag == DW_TAG_compile_unit)
{
- highpc = val.u.uint;
- have_highpc = 1;
- highpc_is_relative = 1;
+ name_val = val;
+ have_name_val = 1;
}
break;
- case DW_AT_ranges:
- if (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_SECTION)
+ case DW_AT_comp_dir:
+ if (abbrev->tag == DW_TAG_compile_unit)
{
- ranges = val.u.uint;
- have_ranges = 1;
+ comp_dir_val = val;
+ have_comp_dir_val = 1;
}
break;
- case DW_AT_stmt_list:
+ case DW_AT_str_offsets_base:
if (abbrev->tag == DW_TAG_compile_unit
- && (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_SECTION))
- u->lineoff = val.u.uint;
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->str_offsets_base = val.u.uint;
break;
- case DW_AT_name:
+ case DW_AT_addr_base:
if (abbrev->tag == DW_TAG_compile_unit
- && val.encoding == ATTR_VAL_STRING)
- u->filename = val.u.string;
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->addr_base = val.u.uint;
break;
- case DW_AT_comp_dir:
+ case DW_AT_rnglists_base:
if (abbrev->tag == DW_TAG_compile_unit
- && val.encoding == ATTR_VAL_STRING)
- u->comp_dir = val.u.string;
+ && val.encoding == ATTR_VAL_REF_SECTION)
+ u->rnglists_base = val.u.uint;
break;
default:
@@ -1348,46 +2360,45 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
}
}
+ // Resolve strings after we're sure that we have seen
+ // DW_AT_str_offsets_base.
+ if (have_name_val)
+ {
+ if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
+ u->str_offsets_base, &name_val,
+ error_callback, data, &u->filename))
+ return 0;
+ }
+ if (have_comp_dir_val)
+ {
+ if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,
+ u->str_offsets_base, &comp_dir_val,
+ error_callback, data, &u->comp_dir))
+ return 0;
+ }
+
if (abbrev->tag == DW_TAG_compile_unit
|| abbrev->tag == DW_TAG_subprogram)
{
- if (have_ranges)
- {
- if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
- is_bigendian, dwarf_ranges,
- dwarf_ranges_size, error_callback,
- data, addrs))
- return 0;
- }
- else if (have_lowpc && have_highpc)
- {
- struct unit_addrs a;
-
- if (highpc_is_relative)
- highpc += lowpc;
- a.low = lowpc;
- a.high = highpc;
- a.u = u;
-
- if (!add_unit_addr (state, base_address, a, error_callback, data,
- addrs))
- return 0;
- }
+ if (!add_ranges (state, dwarf_sections, base_address,
+ is_bigendian, u, pcrange.lowpc, &pcrange,
+ add_unit_addr, (void *) u, error_callback, data,
+ (void *) addrs))
+ return 0;
/* If we found the PC range in the DW_TAG_compile_unit, we
can stop now. */
if (abbrev->tag == DW_TAG_compile_unit
- && (have_ranges || (have_lowpc && have_highpc)))
+ && (pcrange.have_ranges
+ || (pcrange.have_lowpc && pcrange.have_highpc)))
return 1;
}
if (abbrev->has_children)
{
if (!find_address_ranges (state, base_address, unit_buf,
- dwarf_str, dwarf_str_size,
- dwarf_ranges, dwarf_ranges_size,
- is_bigendian, error_callback, data,
- u, addrs))
+ dwarf_sections, is_bigendian, altlink,
+ error_callback, data, u, addrs, NULL))
return 0;
}
}
@@ -1401,33 +2412,40 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
static int
build_address_map (struct backtrace_state *state, uintptr_t base_address,
- const unsigned char *dwarf_info, size_t dwarf_info_size,
- const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
- const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
- const unsigned char *dwarf_str, size_t dwarf_str_size,
- int is_bigendian, backtrace_error_callback error_callback,
- void *data, struct unit_addrs_vector *addrs)
+ const struct dwarf_sections *dwarf_sections,
+ int is_bigendian, struct dwarf_data *altlink,
+ backtrace_error_callback error_callback, void *data,
+ struct unit_addrs_vector *addrs,
+ struct unit_vector *unit_vec)
{
struct dwarf_buf info;
- struct abbrevs abbrevs;
+ struct backtrace_vector units;
+ size_t units_count;
+ size_t i;
+ struct unit **pu;
+ size_t unit_offset = 0;
memset (&addrs->vec, 0, sizeof addrs->vec);
+ memset (&unit_vec->vec, 0, sizeof unit_vec->vec);
addrs->count = 0;
+ unit_vec->count = 0;
/* Read through the .debug_info section. FIXME: Should we use the
.debug_aranges section? gdb and addr2line don't use it, but I'm
not sure why. */
info.name = ".debug_info";
- info.start = dwarf_info;
- info.buf = dwarf_info;
- info.left = dwarf_info_size;
+ info.start = dwarf_sections->data[DEBUG_INFO];
+ info.buf = info.start;
+ info.left = dwarf_sections->size[DEBUG_INFO];
info.is_bigendian = is_bigendian;
info.error_callback = error_callback;
info.data = data;
info.reported_underflow = 0;
- memset (&abbrevs, 0, sizeof abbrevs);
+ memset (&units, 0, sizeof units);
+ units_count = 0;
+
while (info.left > 0)
{
const unsigned char *unit_data_start;
@@ -1435,23 +2453,18 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
int is_dwarf64;
struct dwarf_buf unit_buf;
int version;
+ int unit_type;
uint64_t abbrev_offset;
int addrsize;
struct unit *u;
+ enum dwarf_tag unit_tag;
if (info.reported_underflow)
goto fail;
unit_data_start = info.buf;
- is_dwarf64 = 0;
- len = read_uint32 (&info);
- if (len == 0xffffffff)
- {
- len = read_uint64 (&info);
- is_dwarf64 = 1;
- }
-
+ len = read_initial_length (&info, &is_dwarf64);
unit_buf = info;
unit_buf.left = len;
@@ -1459,23 +2472,70 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
goto fail;
version = read_uint16 (&unit_buf);
- if (version < 2 || version > 4)
+ if (version < 2 || version > 5)
{
dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
goto fail;
}
- abbrev_offset = read_offset (&unit_buf, is_dwarf64);
- if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size,
- is_bigendian, error_callback, data, &abbrevs))
- goto fail;
+ if (version < 5)
+ unit_type = 0;
+ else
+ {
+ unit_type = read_byte (&unit_buf);
+ if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ {
+ /* This unit doesn't have anything we need. */
+ continue;
+ }
+ }
- addrsize = read_byte (&unit_buf);
+ pu = ((struct unit **)
+ backtrace_vector_grow (state, sizeof (struct unit *),
+ error_callback, data, &units));
+ if (pu == NULL)
+ goto fail;
u = ((struct unit *)
backtrace_alloc (state, sizeof *u, error_callback, data));
if (u == NULL)
goto fail;
+
+ *pu = u;
+ ++units_count;
+
+ if (version < 5)
+ addrsize = 0; /* Set below. */
+ else
+ addrsize = read_byte (&unit_buf);
+
+ memset (&u->abbrevs, 0, sizeof u->abbrevs);
+ abbrev_offset = read_offset (&unit_buf, is_dwarf64);
+ if (!read_abbrevs (state, abbrev_offset,
+ dwarf_sections->data[DEBUG_ABBREV],
+ dwarf_sections->size[DEBUG_ABBREV],
+ is_bigendian, error_callback, data, &u->abbrevs))
+ goto fail;
+
+ if (version < 5)
+ addrsize = read_byte (&unit_buf);
+
+ switch (unit_type)
+ {
+ case 0:
+ break;
+ case DW_UT_compile: case DW_UT_partial:
+ break;
+ case DW_UT_skeleton: case DW_UT_split_compile:
+ read_uint64 (&unit_buf); /* dwo_id */
+ break;
+ default:
+ break;
+ }
+
+ u->low_offset = unit_offset;
+ unit_offset += len + (is_dwarf64 ? 12 : 4);
+ u->high_offset = unit_offset;
u->unit_data = unit_buf.buf;
u->unit_data_len = unit_buf.left;
u->unit_data_offset = unit_buf.buf - unit_data_start;
@@ -1486,8 +2546,6 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
u->comp_dir = NULL;
u->abs_filename = NULL;
u->lineoff = 0;
- u->abbrevs = abbrevs;
- memset (&abbrevs, 0, sizeof abbrevs);
/* The actual line number mappings will be read as needed. */
u->lines = NULL;
@@ -1495,32 +2553,37 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
u->function_addrs = NULL;
u->function_addrs_count = 0;
- if (!find_address_ranges (state, base_address, &unit_buf,
- dwarf_str, dwarf_str_size,
- dwarf_ranges, dwarf_ranges_size,
- is_bigendian, error_callback, data,
- u, addrs))
- {
- free_abbrevs (state, &u->abbrevs, error_callback, data);
- backtrace_free (state, u, sizeof *u, error_callback, data);
- goto fail;
- }
+ if (!find_address_ranges (state, base_address, &unit_buf, dwarf_sections,
+ is_bigendian, altlink, error_callback, data,
+ u, addrs, &unit_tag))
+ goto fail;
if (unit_buf.reported_underflow)
- {
- free_abbrevs (state, &u->abbrevs, error_callback, data);
- backtrace_free (state, u, sizeof *u, error_callback, data);
- goto fail;
- }
+ goto fail;
}
if (info.reported_underflow)
goto fail;
+ unit_vec->vec = units;
+ unit_vec->count = units_count;
return 1;
fail:
- free_abbrevs (state, &abbrevs, error_callback, data);
- free_unit_addrs_vector (state, addrs, error_callback, data);
+ if (units_count > 0)
+ {
+ pu = (struct unit **) units.base;
+ for (i = 0; i < units_count; i++)
+ {
+ free_abbrevs (state, &pu[i]->abbrevs, error_callback, data);
+ backtrace_free (state, pu[i], sizeof **pu, error_callback, data);
+ }
+ backtrace_vector_free (state, &units, error_callback, data);
+ }
+ if (addrs->count > 0)
+ {
+ backtrace_vector_free (state, &addrs->vec, error_callback, data);
+ addrs->count = 0;
+ }
return 0;
}
@@ -1563,102 +2626,71 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata,
return 1;
}
-/* Free the line header information. If FREE_FILENAMES is true we
- free the file names themselves, otherwise we leave them, as there
- may be line structures pointing to them. */
+/* Free the line header information. */
static void
free_line_header (struct backtrace_state *state, struct line_header *hdr,
backtrace_error_callback error_callback, void *data)
{
- backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *),
- error_callback, data);
+ if (hdr->dirs_count != 0)
+ backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *),
+ error_callback, data);
backtrace_free (state, hdr->filenames,
hdr->filenames_count * sizeof (char *),
error_callback, data);
}
-/* Read the line header. Return 1 on success, 0 on failure. */
+/* Read the directories and file names for a line header for version
+ 2, setting fields in HDR. Return 1 on success, 0 on failure. */
static int
-read_line_header (struct backtrace_state *state, struct unit *u,
- int is_dwarf64, struct dwarf_buf *line_buf,
- struct line_header *hdr)
+read_v2_paths (struct backtrace_state *state, struct unit *u,
+ struct dwarf_buf *hdr_buf, struct line_header *hdr)
{
- uint64_t hdrlen;
- struct dwarf_buf hdr_buf;
const unsigned char *p;
const unsigned char *pend;
size_t i;
- hdr->version = read_uint16 (line_buf);
- if (hdr->version < 2 || hdr->version > 4)
- {
- dwarf_buf_error (line_buf, "unsupported line number version");
- return 0;
- }
-
- hdrlen = read_offset (line_buf, is_dwarf64);
-
- hdr_buf = *line_buf;
- hdr_buf.left = hdrlen;
-
- if (!advance (line_buf, hdrlen))
- return 0;
-
- hdr->min_insn_len = read_byte (&hdr_buf);
- if (hdr->version < 4)
- hdr->max_ops_per_insn = 1;
- else
- hdr->max_ops_per_insn = read_byte (&hdr_buf);
-
- /* We don't care about default_is_stmt. */
- read_byte (&hdr_buf);
-
- hdr->line_base = read_sbyte (&hdr_buf);
- hdr->line_range = read_byte (&hdr_buf);
-
- hdr->opcode_base = read_byte (&hdr_buf);
- hdr->opcode_lengths = hdr_buf.buf;
- if (!advance (&hdr_buf, hdr->opcode_base - 1))
- return 0;
-
/* Count the number of directory entries. */
hdr->dirs_count = 0;
- p = hdr_buf.buf;
- pend = p + hdr_buf.left;
+ p = hdr_buf->buf;
+ pend = p + hdr_buf->left;
while (p < pend && *p != '\0')
{
p += strnlen((const char *) p, pend - p) + 1;
++hdr->dirs_count;
}
- hdr->dirs = ((const char **)
- backtrace_alloc (state,
- hdr->dirs_count * sizeof (const char *),
- line_buf->error_callback, line_buf->data));
- if (hdr->dirs == NULL)
- return 0;
+ hdr->dirs = NULL;
+ if (hdr->dirs_count != 0)
+ {
+ hdr->dirs = ((const char **)
+ backtrace_alloc (state,
+ hdr->dirs_count * sizeof (const char *),
+ hdr_buf->error_callback,
+ hdr_buf->data));
+ if (hdr->dirs == NULL)
+ return 0;
+ }
i = 0;
- while (*hdr_buf.buf != '\0')
+ while (*hdr_buf->buf != '\0')
{
- if (hdr_buf.reported_underflow)
+ if (hdr_buf->reported_underflow)
return 0;
- hdr->dirs[i] = (const char *) hdr_buf.buf;
- ++i;
- if (!advance (&hdr_buf,
- strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1))
+ hdr->dirs[i] = read_string (hdr_buf);
+ if (hdr->dirs[i] == NULL)
return 0;
+ ++i;
}
- if (!advance (&hdr_buf, 1))
+ if (!advance (hdr_buf, 1))
return 0;
/* Count the number of file entries. */
hdr->filenames_count = 0;
- p = hdr_buf.buf;
- pend = p + hdr_buf.left;
+ p = hdr_buf->buf;
+ pend = p + hdr_buf->left;
while (p < pend && *p != '\0')
{
p += strnlen ((const char *) p, pend - p) + 1;
@@ -1671,24 +2703,23 @@ read_line_header (struct backtrace_state *state, struct unit *u,
hdr->filenames = ((const char **)
backtrace_alloc (state,
hdr->filenames_count * sizeof (char *),
- line_buf->error_callback,
- line_buf->data));
+ hdr_buf->error_callback,
+ hdr_buf->data));
if (hdr->filenames == NULL)
return 0;
i = 0;
- while (*hdr_buf.buf != '\0')
+ while (*hdr_buf->buf != '\0')
{
const char *filename;
uint64_t dir_index;
- if (hdr_buf.reported_underflow)
+ if (hdr_buf->reported_underflow)
return 0;
- filename = (const char *) hdr_buf.buf;
- if (!advance (&hdr_buf,
- strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1))
+ filename = read_string (hdr_buf);
+ if (filename == NULL)
return 0;
- dir_index = read_uleb128 (&hdr_buf);
+ dir_index = read_uleb128 (hdr_buf);
if (IS_ABSOLUTE_PATH (filename)
|| (dir_index == 0 && u->comp_dir == NULL))
hdr->filenames[i] = filename;
@@ -1705,16 +2736,16 @@ read_line_header (struct backtrace_state *state, struct unit *u,
dir = hdr->dirs[dir_index - 1];
else
{
- dwarf_buf_error (line_buf,
+ dwarf_buf_error (hdr_buf,
("invalid directory index in "
"line number program header"));
return 0;
}
dir_len = strlen (dir);
filename_len = strlen (filename);
- s = ((char *)
- backtrace_alloc (state, dir_len + filename_len + 2,
- line_buf->error_callback, line_buf->data));
+ s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2,
+ hdr_buf->error_callback,
+ hdr_buf->data));
if (s == NULL)
return 0;
memcpy (s, dir, dir_len);
@@ -1727,12 +2758,258 @@ read_line_header (struct backtrace_state *state, struct unit *u,
}
/* Ignore the modification time and size. */
- read_uleb128 (&hdr_buf);
- read_uleb128 (&hdr_buf);
+ read_uleb128 (hdr_buf);
+ read_uleb128 (hdr_buf);
++i;
}
+ return 1;
+}
+
+/* Read a single version 5 LNCT entry for a directory or file name in a
+ line header. Sets *STRING to the resulting name, ignoring other
+ data. Return 1 on success, 0 on failure. */
+
+static int
+read_lnct (struct backtrace_state *state, struct dwarf_data *ddata,
+ struct unit *u, struct dwarf_buf *hdr_buf,
+ const struct line_header *hdr, size_t formats_count,
+ const struct line_header_format *formats, const char **string)
+{
+ size_t i;
+ const char *dir;
+ const char *path;
+
+ dir = NULL;
+ path = NULL;
+ for (i = 0; i < formats_count; i++)
+ {
+ struct attr_val val;
+
+ if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64,
+ u->version, hdr->addrsize, &ddata->dwarf_sections,
+ ddata->altlink, &val))
+ return 0;
+ switch (formats[i].lnct)
+ {
+ case DW_LNCT_path:
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, hdr_buf->error_callback, hdr_buf->data,
+ &path))
+ return 0;
+ break;
+ case DW_LNCT_directory_index:
+ if (val.encoding == ATTR_VAL_UINT)
+ {
+ if (val.u.uint >= hdr->dirs_count)
+ {
+ dwarf_buf_error (hdr_buf,
+ ("invalid directory index in "
+ "line number program header"));
+ return 0;
+ }
+ dir = hdr->dirs[val.u.uint];
+ }
+ break;
+ default:
+ /* We don't care about timestamps or sizes or hashes. */
+ break;
+ }
+ }
+
+ if (path == NULL)
+ {
+ dwarf_buf_error (hdr_buf,
+ "missing file name in line number program header");
+ return 0;
+ }
+
+ if (dir == NULL)
+ *string = path;
+ else
+ {
+ size_t dir_len;
+ size_t path_len;
+ char *s;
+
+ dir_len = strlen (dir);
+ path_len = strlen (path);
+ s = (char *) backtrace_alloc (state, dir_len + path_len + 2,
+ hdr_buf->error_callback, hdr_buf->data);
+ if (s == NULL)
+ return 0;
+ memcpy (s, dir, dir_len);
+ /* FIXME: If we are on a DOS-based file system, and the
+ directory or the path name use backslashes, then we should
+ use a backslash here. */
+ s[dir_len] = '/';
+ memcpy (s + dir_len + 1, path, path_len + 1);
+ *string = s;
+ }
+
+ return 1;
+}
+
+/* Read a set of DWARF 5 line header format entries, setting *PCOUNT
+ and *PPATHS. Return 1 on success, 0 on failure. */
+
+static int
+read_line_header_format_entries (struct backtrace_state *state,
+ struct dwarf_data *ddata,
+ struct unit *u,
+ struct dwarf_buf *hdr_buf,
+ struct line_header *hdr,
+ size_t *pcount,
+ const char ***ppaths)
+{
+ size_t formats_count;
+ struct line_header_format *formats;
+ size_t paths_count;
+ const char **paths;
+ size_t i;
+ int ret;
+
+ formats_count = read_byte (hdr_buf);
+ if (formats_count == 0)
+ formats = NULL;
+ else
+ {
+ formats = ((struct line_header_format *)
+ backtrace_alloc (state,
+ (formats_count
+ * sizeof (struct line_header_format)),
+ hdr_buf->error_callback,
+ hdr_buf->data));
+ if (formats == NULL)
+ return 0;
+
+ for (i = 0; i < formats_count; i++)
+ {
+ formats[i].lnct = (int) read_uleb128(hdr_buf);
+ formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf);
+ }
+ }
+
+ paths_count = read_uleb128 (hdr_buf);
+ if (paths_count == 0)
+ {
+ *pcount = 0;
+ *ppaths = NULL;
+ ret = 1;
+ goto exit;
+ }
+
+ paths = ((const char **)
+ backtrace_alloc (state, paths_count * sizeof (const char *),
+ hdr_buf->error_callback, hdr_buf->data));
+ if (paths == NULL)
+ {
+ ret = 0;
+ goto exit;
+ }
+ for (i = 0; i < paths_count; i++)
+ {
+ if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count,
+ formats, &paths[i]))
+ {
+ backtrace_free (state, paths,
+ paths_count * sizeof (const char *),
+ hdr_buf->error_callback, hdr_buf->data);
+ ret = 0;
+ goto exit;
+ }
+ }
+
+ *pcount = paths_count;
+ *ppaths = paths;
+
+ ret = 1;
+
+ exit:
+ if (formats != NULL)
+ backtrace_free (state, formats,
+ formats_count * sizeof (struct line_header_format),
+ hdr_buf->error_callback, hdr_buf->data);
+
+ return ret;
+}
+
+/* Read the line header. Return 1 on success, 0 on failure. */
+
+static int
+read_line_header (struct backtrace_state *state, struct dwarf_data *ddata,
+ struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf,
+ struct line_header *hdr)
+{
+ uint64_t hdrlen;
+ struct dwarf_buf hdr_buf;
+
+ hdr->version = read_uint16 (line_buf);
+ if (hdr->version < 2 || hdr->version > 5)
+ {
+ dwarf_buf_error (line_buf, "unsupported line number version");
+ return 0;
+ }
+
+ if (hdr->version < 5)
+ hdr->addrsize = u->addrsize;
+ else
+ {
+ hdr->addrsize = read_byte (line_buf);
+ /* We could support a non-zero segment_selector_size but I doubt
+ we'll ever see it. */
+ if (read_byte (line_buf) != 0)
+ {
+ dwarf_buf_error (line_buf,
+ "non-zero segment_selector_size not supported");
+ return 0;
+ }
+ }
+
+ hdrlen = read_offset (line_buf, is_dwarf64);
+
+ hdr_buf = *line_buf;
+ hdr_buf.left = hdrlen;
+
+ if (!advance (line_buf, hdrlen))
+ return 0;
+
+ hdr->min_insn_len = read_byte (&hdr_buf);
+ if (hdr->version < 4)
+ hdr->max_ops_per_insn = 1;
+ else
+ hdr->max_ops_per_insn = read_byte (&hdr_buf);
+
+ /* We don't care about default_is_stmt. */
+ read_byte (&hdr_buf);
+
+ hdr->line_base = read_sbyte (&hdr_buf);
+ hdr->line_range = read_byte (&hdr_buf);
+
+ hdr->opcode_base = read_byte (&hdr_buf);
+ hdr->opcode_lengths = hdr_buf.buf;
+ if (!advance (&hdr_buf, hdr->opcode_base - 1))
+ return 0;
+
+ if (hdr->version < 5)
+ {
+ if (!read_v2_paths (state, u, &hdr_buf, hdr))
+ return 0;
+ }
+ else
+ {
+ if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
+ &hdr->dirs_count,
+ &hdr->dirs))
+ return 0;
+ if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,
+ &hdr->filenames_count,
+ &hdr->filenames))
+ return 0;
+ }
+
if (hdr_buf.reported_underflow)
return 0;
@@ -1798,15 +3075,15 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
lineno = 1;
break;
case DW_LNE_set_address:
- address = read_address (line_buf, u->addrsize);
+ address = read_address (line_buf, hdr->addrsize);
break;
case DW_LNE_define_file:
{
const char *f;
unsigned int dir_index;
- f = (const char *) line_buf->buf;
- if (!advance (line_buf, strnlen (f, line_buf->left) + 1))
+ f = read_string (line_buf);
+ if (f == NULL)
return 0;
dir_index = read_uleb128 (line_buf);
/* Ignore that time and length. */
@@ -1821,7 +3098,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
size_t f_len;
char *p;
- if (dir_index == 0)
+ if (dir_index == 0 && hdr->version < 5)
dir = u->comp_dir;
else if (dir_index - 1 < hdr->dirs_count)
dir = hdr->dirs[dir_index - 1];
@@ -1967,31 +3244,25 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
memset (hdr, 0, sizeof *hdr);
if (u->lineoff != (off_t) (size_t) u->lineoff
- || (size_t) u->lineoff >= ddata->dwarf_line_size)
+ || (size_t) u->lineoff >= ddata->dwarf_sections.size[DEBUG_LINE])
{
error_callback (data, "unit line offset out of range", 0);
goto fail;
}
line_buf.name = ".debug_line";
- line_buf.start = ddata->dwarf_line;
- line_buf.buf = ddata->dwarf_line + u->lineoff;
- line_buf.left = ddata->dwarf_line_size - u->lineoff;
+ line_buf.start = ddata->dwarf_sections.data[DEBUG_LINE];
+ line_buf.buf = ddata->dwarf_sections.data[DEBUG_LINE] + u->lineoff;
+ line_buf.left = ddata->dwarf_sections.size[DEBUG_LINE] - u->lineoff;
line_buf.is_bigendian = ddata->is_bigendian;
line_buf.error_callback = error_callback;
line_buf.data = data;
line_buf.reported_underflow = 0;
- is_dwarf64 = 0;
- len = read_uint32 (&line_buf);
- if (len == 0xffffffff)
- {
- len = read_uint64 (&line_buf);
- is_dwarf64 = 1;
- }
+ len = read_initial_length (&line_buf, &is_dwarf64);
line_buf.left = len;
- if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr))
+ if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))
goto fail;
if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec))
@@ -2031,15 +3302,69 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
return 1;
fail:
- vec.vec.alc += vec.vec.size;
- vec.vec.size = 0;
- backtrace_vector_release (state, &vec.vec, error_callback, data);
+ backtrace_vector_free (state, &vec.vec, error_callback, data);
free_line_header (state, hdr, error_callback, data);
*lines = (struct line *) (uintptr_t) -1;
*lines_count = 0;
return 0;
}
+static const char *read_referenced_name (struct dwarf_data *, struct unit *,
+ uint64_t, backtrace_error_callback,
+ void *);
+
+/* Read the name of a function from a DIE referenced by ATTR with VAL. */
+
+static const char *
+read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
+ struct attr *attr, struct attr_val *val,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ switch (attr->name)
+ {
+ case DW_AT_abstract_origin:
+ case DW_AT_specification:
+ break;
+ default:
+ return NULL;
+ }
+
+ if (attr->form == DW_FORM_ref_sig8)
+ return NULL;
+
+ if (val->encoding == ATTR_VAL_REF_INFO)
+ {
+ struct unit *unit
+ = find_unit (ddata->units, ddata->units_count,
+ val->u.uint);
+ if (unit == NULL)
+ return NULL;
+
+ uint64_t offset = val->u.uint - unit->low_offset;
+ return read_referenced_name (ddata, unit, offset, error_callback, data);
+ }
+
+ if (val->encoding == ATTR_VAL_UINT
+ || val->encoding == ATTR_VAL_REF_UNIT)
+ return read_referenced_name (ddata, u, val->u.uint, error_callback, data);
+
+ if (val->encoding == ATTR_VAL_REF_ALT_INFO)
+ {
+ struct unit *alt_unit
+ = find_unit (ddata->altlink->units, ddata->altlink->units_count,
+ val->u.uint);
+ if (alt_unit == NULL)
+ return NULL;
+
+ uint64_t offset = val->u.uint - alt_unit->low_offset;
+ return read_referenced_name (ddata->altlink, alt_unit, offset,
+ error_callback, data);
+ }
+
+ return NULL;
+}
+
/* Read the name of a function from a DIE referenced by a
DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within
the same compilation unit. */
@@ -2071,7 +3396,7 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
offset -= u->unit_data_offset;
unit_buf.name = ".debug_info";
- unit_buf.start = ddata->dwarf_info;
+ unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];
unit_buf.buf = u->unit_data + offset;
unit_buf.left = u->unit_data_len - offset;
unit_buf.is_bigendian = ddata->is_bigendian;
@@ -2095,45 +3420,52 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, &unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- ddata->dwarf_str, ddata->dwarf_str_size,
- &val))
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ &unit_buf, u->is_dwarf64, u->version, u->addrsize,
+ &ddata->dwarf_sections, ddata->altlink, &val))
return NULL;
switch (abbrev->attrs[i].name)
{
case DW_AT_name:
- /* We prefer the linkage name if get one. */
- if (val.encoding == ATTR_VAL_STRING)
- ret = val.u.string;
+ /* Third name preference: don't override. A name we found in some
+ other way, will normally be more useful -- e.g., this name is
+ normally not mangled. */
+ if (ret != NULL)
+ break;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, error_callback, data, &ret))
+ return NULL;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
- if (val.encoding == ATTR_VAL_STRING)
- return val.u.string;
+ /* First name preference: override all. */
+ {
+ const char *s;
+
+ s = NULL;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian, u->str_offsets_base,
+ &val, error_callback, data, &s))
+ return NULL;
+ if (s != NULL)
+ return s;
+ }
break;
case DW_AT_specification:
- if (abbrev->attrs[i].form == DW_FORM_ref_addr
- || abbrev->attrs[i].form == DW_FORM_ref_sig8)
- {
- /* This refers to a specification defined in some other
- compilation unit. We can handle this case if we
- must, but it's harder. */
- break;
- }
- if (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_UNIT)
- {
- const char *name;
+ /* Second name preference: override DW_AT_name, don't override
+ DW_AT_linkage_name. */
+ {
+ const char *name;
- name = read_referenced_name (ddata, u, val.u.uint,
- error_callback, data);
- if (name != NULL)
- ret = name;
- }
+ name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
+ &val, error_callback, data);
+ if (name != NULL)
+ ret = name;
+ }
break;
default:
@@ -2144,25 +3476,22 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
return ret;
}
-/* Add a single range to U that maps to function. Returns 1 on
- success, 0 on error. */
+/* Add a range to a unit that maps to a function. This is called via
+ add_ranges. Returns 1 on success, 0 on error. */
static int
-add_function_range (struct backtrace_state *state, struct dwarf_data *ddata,
- struct function *function, uint64_t lowpc, uint64_t highpc,
- backtrace_error_callback error_callback,
- void *data, struct function_vector *vec)
+add_function_range (struct backtrace_state *state, void *rdata,
+ uint64_t lowpc, uint64_t highpc,
+ backtrace_error_callback error_callback, void *data,
+ void *pvec)
{
+ struct function *function = (struct function *) rdata;
+ struct function_vector *vec = (struct function_vector *) pvec;
struct function_addrs *p;
- /* Add in the base address here, so that we can look up the PC
- directly. */
- lowpc += ddata->base_address;
- highpc += ddata->base_address;
-
if (vec->count > 0)
{
- p = (struct function_addrs *) vec->vec.base + vec->count - 1;
+ p = (struct function_addrs *) vec->vec.base + (vec->count - 1);
if ((lowpc == p->high || lowpc == p->high + 1)
&& function == p->function)
{
@@ -2181,63 +3510,8 @@ add_function_range (struct backtrace_state *state, struct dwarf_data *ddata,
p->low = lowpc;
p->high = highpc;
p->function = function;
- ++vec->count;
- return 1;
-}
-
-/* Add PC ranges to U that map to FUNCTION. Returns 1 on success, 0
- on error. */
-
-static int
-add_function_ranges (struct backtrace_state *state, struct dwarf_data *ddata,
- struct unit *u, struct function *function,
- uint64_t ranges, uint64_t base,
- backtrace_error_callback error_callback, void *data,
- struct function_vector *vec)
-{
- struct dwarf_buf ranges_buf;
-
- if (ranges >= ddata->dwarf_ranges_size)
- {
- error_callback (data, "function ranges offset out of range", 0);
- return 0;
- }
-
- ranges_buf.name = ".debug_ranges";
- ranges_buf.start = ddata->dwarf_ranges;
- ranges_buf.buf = ddata->dwarf_ranges + ranges;
- ranges_buf.left = ddata->dwarf_ranges_size - ranges;
- ranges_buf.is_bigendian = ddata->is_bigendian;
- ranges_buf.error_callback = error_callback;
- ranges_buf.data = data;
- ranges_buf.reported_underflow = 0;
-
- while (1)
- {
- uint64_t low;
- uint64_t high;
-
- if (ranges_buf.reported_underflow)
- return 0;
- low = read_address (&ranges_buf, u->addrsize);
- high = read_address (&ranges_buf, u->addrsize);
-
- if (low == 0 && high == 0)
- break;
-
- if (is_highest_address (low, u->addrsize))
- base = high;
- else
- {
- if (!add_function_range (state, ddata, function, low + base,
- high + base, error_callback, data, vec))
- return 0;
- }
- }
-
- if (ranges_buf.reported_underflow)
- return 0;
+ ++vec->count;
return 1;
}
@@ -2261,13 +3535,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
struct function *function;
struct function_vector *vec;
size_t i;
- uint64_t lowpc;
- int have_lowpc;
- uint64_t highpc;
- int have_highpc;
- int highpc_is_relative;
- uint64_t ranges;
- int have_ranges;
+ struct pcrange pcrange;
+ int have_linkage_name;
code = read_uleb128 (unit_buf);
if (code == 0)
@@ -2297,29 +3566,34 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
memset (function, 0, sizeof *function);
}
- lowpc = 0;
- have_lowpc = 0;
- highpc = 0;
- have_highpc = 0;
- highpc_is_relative = 0;
- ranges = 0;
- have_ranges = 0;
+ memset (&pcrange, 0, sizeof pcrange);
+ have_linkage_name = 0;
for (i = 0; i < abbrev->num_attrs; ++i)
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, unit_buf,
- u->is_dwarf64, u->version, u->addrsize,
- ddata->dwarf_str, ddata->dwarf_str_size,
- &val))
+ if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,
+ unit_buf, u->is_dwarf64, u->version,
+ u->addrsize, &ddata->dwarf_sections,
+ ddata->altlink, &val))
return 0;
/* The compile unit sets the base address for any address
ranges in the function entries. */
if (abbrev->tag == DW_TAG_compile_unit
- && abbrev->attrs[i].name == DW_AT_low_pc
- && val.encoding == ATTR_VAL_ADDRESS)
- base = val.u.uint;
+ && abbrev->attrs[i].name == DW_AT_low_pc)
+ {
+ if (val.encoding == ATTR_VAL_ADDRESS)
+ base = val.u.uint;
+ else if (val.encoding == ATTR_VAL_ADDRESS_INDEX)
+ {
+ if (!resolve_addr_index (&ddata->dwarf_sections,
+ u->addr_base, u->addrsize,
+ ddata->is_bigendian, val.u.uint,
+ error_callback, data, &base))
+ return 0;
+ }
+ }
if (is_function)
{
@@ -2352,73 +3626,55 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
case DW_AT_abstract_origin:
case DW_AT_specification:
- if (abbrev->attrs[i].form == DW_FORM_ref_addr
- || abbrev->attrs[i].form == DW_FORM_ref_sig8)
- {
- /* This refers to an abstract origin defined in
- some other compilation unit. We can handle
- this case if we must, but it's harder. */
- break;
- }
- if (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_UNIT)
- {
- const char *name;
-
- name = read_referenced_name (ddata, u, val.u.uint,
- error_callback, data);
- if (name != NULL)
- function->name = name;
- }
+ /* Second name preference: override DW_AT_name, don't override
+ DW_AT_linkage_name. */
+ if (have_linkage_name)
+ break;
+ {
+ const char *name;
+
+ name
+ = read_referenced_name_from_attr (ddata, u,
+ &abbrev->attrs[i], &val,
+ error_callback, data);
+ if (name != NULL)
+ function->name = name;
+ }
break;
case DW_AT_name:
- if (val.encoding == ATTR_VAL_STRING)
- {
- /* Don't override a name we found in some other
- way, as it will normally be more
- useful--e.g., this name is normally not
- mangled. */
- if (function->name == NULL)
- function->name = val.u.string;
- }
+ /* Third name preference: don't override. */
+ if (function->name != NULL)
+ break;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian,
+ u->str_offsets_base, &val,
+ error_callback, data, &function->name))
+ return 0;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
- if (val.encoding == ATTR_VAL_STRING)
- function->name = val.u.string;
- break;
-
- case DW_AT_low_pc:
- if (val.encoding == ATTR_VAL_ADDRESS)
- {
- lowpc = val.u.uint;
- have_lowpc = 1;
- }
- break;
+ /* First name preference: override all. */
+ {
+ const char *s;
- case DW_AT_high_pc:
- if (val.encoding == ATTR_VAL_ADDRESS)
- {
- highpc = val.u.uint;
- have_highpc = 1;
- }
- else if (val.encoding == ATTR_VAL_UINT)
- {
- highpc = val.u.uint;
- have_highpc = 1;
- highpc_is_relative = 1;
- }
+ s = NULL;
+ if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
+ ddata->is_bigendian,
+ u->str_offsets_base, &val,
+ error_callback, data, &s))
+ return 0;
+ if (s != NULL)
+ {
+ function->name = s;
+ have_linkage_name = 1;
+ }
+ }
break;
- case DW_AT_ranges:
- if (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_SECTION)
- {
- ranges = val.u.uint;
- have_ranges = 1;
- }
+ case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:
+ update_pcrange (&abbrev->attrs[i], &val, &pcrange);
break;
default:
@@ -2438,18 +3694,14 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
if (is_function)
{
- if (have_ranges)
+ if (pcrange.have_ranges
+ || (pcrange.have_lowpc && pcrange.have_highpc))
{
- if (!add_function_ranges (state, ddata, u, function, ranges,
- base, error_callback, data, vec))
- return 0;
- }
- else if (have_lowpc && have_highpc)
- {
- if (highpc_is_relative)
- highpc += lowpc;
- if (!add_function_range (state, ddata, function, lowpc, highpc,
- error_callback, data, vec))
+ if (!add_ranges (state, &ddata->dwarf_sections,
+ ddata->base_address, ddata->is_bigendian,
+ u, base, &pcrange, add_function_range,
+ (void *) function, error_callback, data,
+ (void *) vec))
return 0;
}
else
@@ -2533,7 +3785,7 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata,
}
unit_buf.name = ".debug_info";
- unit_buf.start = ddata->dwarf_info;
+ unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];
unit_buf.buf = u->unit_data;
unit_buf.left = u->unit_data_len;
unit_buf.is_bigendian = ddata->is_bigendian;
@@ -2656,8 +3908,10 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
*found = 1;
/* Find an address range that includes PC. */
- entry = bsearch (&pc, ddata->addrs, ddata->addrs_count,
- sizeof (struct unit_addrs), unit_addrs_search);
+ entry = (ddata->addrs_count == 0
+ ? NULL
+ : bsearch (&pc, ddata->addrs, ddata->addrs_count,
+ sizeof (struct unit_addrs), unit_addrs_search));
if (entry == NULL)
{
@@ -2910,37 +4164,36 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
static struct dwarf_data *
build_dwarf_data (struct backtrace_state *state,
uintptr_t base_address,
- const unsigned char *dwarf_info,
- size_t dwarf_info_size,
- const unsigned char *dwarf_line,
- size_t dwarf_line_size,
- const unsigned char *dwarf_abbrev,
- size_t dwarf_abbrev_size,
- const unsigned char *dwarf_ranges,
- size_t dwarf_ranges_size,
- const unsigned char *dwarf_str,
- size_t dwarf_str_size,
+ const struct dwarf_sections *dwarf_sections,
int is_bigendian,
+ struct dwarf_data *altlink,
backtrace_error_callback error_callback,
void *data)
{
struct unit_addrs_vector addrs_vec;
struct unit_addrs *addrs;
size_t addrs_count;
+ struct unit_vector units_vec;
+ struct unit **units;
+ size_t units_count;
struct dwarf_data *fdata;
- if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size,
- dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges,
- dwarf_ranges_size, dwarf_str, dwarf_str_size,
- is_bigendian, error_callback, data, &addrs_vec))
+ if (!build_address_map (state, base_address, dwarf_sections, is_bigendian,
+ altlink, error_callback, data, &addrs_vec,
+ &units_vec))
return NULL;
if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
return NULL;
+ if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data))
+ return NULL;
addrs = (struct unit_addrs *) addrs_vec.vec.base;
+ units = (struct unit **) units_vec.vec.base;
addrs_count = addrs_vec.count;
+ units_count = units_vec.count;
backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs),
unit_addrs_compare);
+ /* No qsort for units required, already sorted. */
fdata = ((struct dwarf_data *)
backtrace_alloc (state, sizeof (struct dwarf_data),
@@ -2949,17 +4202,13 @@ build_dwarf_data (struct backtrace_state *state,
return NULL;
fdata->next = NULL;
+ fdata->altlink = altlink;
fdata->base_address = base_address;
fdata->addrs = addrs;
fdata->addrs_count = addrs_count;
- fdata->dwarf_info = dwarf_info;
- fdata->dwarf_info_size = dwarf_info_size;
- fdata->dwarf_line = dwarf_line;
- fdata->dwarf_line_size = dwarf_line_size;
- fdata->dwarf_ranges = dwarf_ranges;
- fdata->dwarf_ranges_size = dwarf_ranges_size;
- fdata->dwarf_str = dwarf_str;
- fdata->dwarf_str_size = dwarf_str_size;
+ fdata->units = units;
+ fdata->units_count = units_count;
+ fdata->dwarf_sections = *dwarf_sections;
fdata->is_bigendian = is_bigendian;
memset (&fdata->fvec, 0, sizeof fdata->fvec);
@@ -2973,30 +4222,23 @@ build_dwarf_data (struct backtrace_state *state,
int
backtrace_dwarf_add (struct backtrace_state *state,
uintptr_t base_address,
- const unsigned char *dwarf_info,
- size_t dwarf_info_size,
- const unsigned char *dwarf_line,
- size_t dwarf_line_size,
- const unsigned char *dwarf_abbrev,
- size_t dwarf_abbrev_size,
- const unsigned char *dwarf_ranges,
- size_t dwarf_ranges_size,
- const unsigned char *dwarf_str,
- size_t dwarf_str_size,
+ const struct dwarf_sections *dwarf_sections,
int is_bigendian,
+ struct dwarf_data *fileline_altlink,
backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn)
+ void *data, fileline *fileline_fn,
+ struct dwarf_data **fileline_entry)
{
struct dwarf_data *fdata;
- fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size,
- dwarf_line, dwarf_line_size, dwarf_abbrev,
- dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
- dwarf_str, dwarf_str_size, is_bigendian,
- error_callback, data);
+ fdata = build_dwarf_data (state, base_address, dwarf_sections, is_bigendian,
+ fileline_altlink, error_callback, data);
if (fdata == NULL)
return 0;
+ if (fileline_entry != NULL)
+ *fileline_entry = fdata;
+
if (!state->threaded)
{
struct dwarf_data **pp;
diff --git a/3rdparty/libbacktrace/libbacktrace/elf.c b/3rdparty/libbacktrace/libbacktrace/elf.c
index 81ba3440..d1d257b1 100644
--- a/3rdparty/libbacktrace/libbacktrace/elf.c
+++ b/3rdparty/libbacktrace/libbacktrace/elf.c
@@ -1,5 +1,5 @@
/* elf.c -- Get debug data from an ELF file for backtraces.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -32,9 +32,12 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#ifdef HAVE_DL_ITERATE_PHDR
#include <link.h>
@@ -43,6 +46,71 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.h"
#include "internal.h"
+#ifndef S_ISLNK
+ #ifndef S_IFLNK
+ #define S_IFLNK 0120000
+ #endif
+ #ifndef S_IFMT
+ #define S_IFMT 0170000
+ #endif
+ #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+#ifndef __GNUC__
+#define __builtin_prefetch(p, r, l)
+#define unlikely(x) (x)
+#else
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+
+#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
+
+/* If strnlen is not declared, provide our own version. */
+
+static size_t
+xstrnlen (const char *s, size_t maxlen)
+{
+ size_t i;
+
+ for (i = 0; i < maxlen; ++i)
+ if (s[i] == '\0')
+ break;
+ return i;
+}
+
+#define strnlen xstrnlen
+
+#endif
+
+#ifndef HAVE_LSTAT
+
+/* Dummy version of lstat for systems that don't have it. */
+
+static int
+xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED)
+{
+ return -1;
+}
+
+#define lstat xlstat
+
+#endif
+
+#ifndef HAVE_READLINK
+
+/* Dummy version of readlink for systems that don't have it. */
+
+static ssize_t
+xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED,
+ size_t bufsz ATTRIBUTE_UNUSED)
+{
+ return -1;
+}
+
+#define readlink xreadlink
+
+#endif
+
#ifndef HAVE_DL_ITERATE_PHDR
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
@@ -70,7 +138,7 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
ELF. We could make this code test and support either possibility,
but there is no point. This code only works for the currently
running executable, which means that we know the ELF mode at
- configure mode. */
+ configure time. */
#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64
#error "Unknown BACKTRACE_ELF_SIZE"
@@ -97,14 +165,20 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
#undef ELFDATA2MSB
#undef EV_CURRENT
#undef ET_DYN
+#undef EM_PPC64
+#undef EF_PPC64_ABI
#undef SHN_LORESERVE
#undef SHN_XINDEX
#undef SHN_UNDEF
+#undef SHT_PROGBITS
#undef SHT_SYMTAB
#undef SHT_STRTAB
#undef SHT_DYNSYM
+#undef SHF_COMPRESSED
#undef STT_OBJECT
#undef STT_FUNC
+#undef NT_GNU_BUILD_ID
+#undef ELFCOMPRESS_ZLIB
/* Basic types. */
@@ -174,6 +248,9 @@ typedef struct {
#define ET_DYN 3
+#define EM_PPC64 21
+#define EF_PPC64_ABI 3
+
typedef struct {
b_elf_word sh_name; /* Section name, index in string tbl */
b_elf_word sh_type; /* Type of section */
@@ -191,10 +268,13 @@ typedef struct {
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
+#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_DYNSYM 11
+#define SHF_COMPRESSED 0x800
+
#if BACKTRACE_ELF_SIZE == 32
typedef struct
@@ -224,27 +304,52 @@ typedef struct
#define STT_OBJECT 1
#define STT_FUNC 2
-/* An index of ELF sections we care about. */
+typedef struct
+{
+ uint32_t namesz;
+ uint32_t descsz;
+ uint32_t type;
+ char name[1];
+} b_elf_note;
+
+#define NT_GNU_BUILD_ID 3
-enum debug_section
+#if BACKTRACE_ELF_SIZE == 32
+
+typedef struct
{
- DEBUG_INFO,
- DEBUG_LINE,
- DEBUG_ABBREV,
- DEBUG_RANGES,
- DEBUG_STR,
- DEBUG_MAX
-};
+ b_elf_word ch_type; /* Compresstion algorithm */
+ b_elf_word ch_size; /* Uncompressed size */
+ b_elf_word ch_addralign; /* Alignment for uncompressed data */
+} b_elf_chdr; /* Elf_Chdr */
-/* Names of sections, indexed by enum elf_section. */
+#else /* BACKTRACE_ELF_SIZE != 32 */
-static const char * const debug_section_names[DEBUG_MAX] =
+typedef struct
+{
+ b_elf_word ch_type; /* Compression algorithm */
+ b_elf_word ch_reserved; /* Reserved */
+ b_elf_xword ch_size; /* Uncompressed size */
+ b_elf_xword ch_addralign; /* Alignment for uncompressed data */
+} b_elf_chdr; /* Elf_Chdr */
+
+#endif /* BACKTRACE_ELF_SIZE != 32 */
+
+#define ELFCOMPRESS_ZLIB 1
+
+/* Names of sections, indexed by enum dwarf_section in internal.h. */
+
+static const char * const dwarf_section_names[DEBUG_MAX] =
{
".debug_info",
".debug_line",
".debug_abbrev",
".debug_ranges",
- ".debug_str"
+ ".debug_str",
+ ".debug_addr",
+ ".debug_str_offsets",
+ ".debug_line_str",
+ ".debug_rnglists"
};
/* Information we gather for the sections we care about. */
@@ -257,6 +362,8 @@ struct debug_section_info
size_t size;
/* Section contents, after read from file. */
const unsigned char *data;
+ /* Whether the SHF_COMPRESSED flag is set for the section. */
+ int compressed;
};
/* Information we keep for an ELF symbol. */
@@ -283,6 +390,116 @@ struct elf_syminfo_data
size_t count;
};
+/* Information about PowerPC64 ELFv1 .opd section. */
+
+struct elf_ppc64_opd_data
+{
+ /* Address of the .opd section. */
+ b_elf_addr addr;
+ /* Section data. */
+ const char *data;
+ /* Size of the .opd section. */
+ size_t size;
+ /* Corresponding section view. */
+ struct backtrace_view view;
+};
+
+/* Compute the CRC-32 of BUF/LEN. This uses the CRC used for
+ .gnu_debuglink files. */
+
+static uint32_t
+elf_crc32 (uint32_t crc, const unsigned char *buf, size_t len)
+{
+ static const uint32_t crc32_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+ const unsigned char *end;
+
+ crc = ~crc;
+ for (end = buf + len; buf < end; ++ buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc;
+}
+
+/* Return the CRC-32 of the entire file open at DESCRIPTOR. */
+
+static uint32_t
+elf_crc32_file (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data)
+{
+ struct stat st;
+ struct backtrace_view file_view;
+ uint32_t ret;
+
+ if (fstat (descriptor, &st) < 0)
+ {
+ error_callback (data, "fstat", errno);
+ return 0;
+ }
+
+ if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback,
+ data, &file_view))
+ return 0;
+
+ ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size);
+
+ backtrace_release_view (state, &file_view, error_callback, data);
+
+ return ret;
+}
+
/* A dummy callback function used when we can't find any debug info. */
static int
@@ -351,7 +568,8 @@ elf_initialize_syminfo (struct backtrace_state *state,
const unsigned char *symtab_data, size_t symtab_size,
const unsigned char *strtab, size_t strtab_size,
backtrace_error_callback error_callback,
- void *data, struct elf_syminfo_data *sdata)
+ void *data, struct elf_syminfo_data *sdata,
+ struct elf_ppc64_opd_data *opd)
{
size_t sym_count;
const b_elf_sym *sym;
@@ -402,7 +620,17 @@ elf_initialize_syminfo (struct backtrace_state *state,
return 0;
}
elf_symbols[j].name = (const char *) strtab + sym->st_name;
- elf_symbols[j].address = sym->st_value + base_address;
+ /* Special case PowerPC64 ELFv1 symbols in .opd section, if the symbol
+ is a function descriptor, read the actual code address from the
+ descriptor. */
+ if (opd
+ && sym->st_value >= opd->addr
+ && sym->st_value < opd->addr + opd->size)
+ elf_symbols[j].address
+ = *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr));
+ else
+ elf_symbols[j].address = sym->st_value;
+ elf_symbols[j].address += base_address;
elf_symbols[j].size = sym->st_size;
++j;
}
@@ -510,6 +738,1876 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
callback (data, addr, sym->name, sym->address, sym->size);
}
+/* Return whether FILENAME is a symlink. */
+
+static int
+elf_is_symlink (const char *filename)
+{
+ struct stat st;
+
+ if (lstat (filename, &st) < 0)
+ return 0;
+ return S_ISLNK (st.st_mode);
+}
+
+/* Return the results of reading the symlink FILENAME in a buffer
+ allocated by backtrace_alloc. Return the length of the buffer in
+ *LEN. */
+
+static char *
+elf_readlink (struct backtrace_state *state, const char *filename,
+ backtrace_error_callback error_callback, void *data,
+ size_t *plen)
+{
+ size_t len;
+ char *buf;
+
+ len = 128;
+ while (1)
+ {
+ ssize_t rl;
+
+ buf = backtrace_alloc (state, len, error_callback, data);
+ if (buf == NULL)
+ return NULL;
+ rl = readlink (filename, buf, len);
+ if (rl < 0)
+ {
+ backtrace_free (state, buf, len, error_callback, data);
+ return NULL;
+ }
+ if ((size_t) rl < len - 1)
+ {
+ buf[rl] = '\0';
+ *plen = len;
+ return buf;
+ }
+ backtrace_free (state, buf, len, error_callback, data);
+ len *= 2;
+ }
+}
+
+#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/"
+
+/* Open a separate debug info file, using the build ID to find it.
+ Returns an open file descriptor, or -1.
+
+ The GDB manual says that the only place gdb looks for a debug file
+ when the build ID is known is in /usr/lib/debug/.build-id. */
+
+static int
+elf_open_debugfile_by_buildid (struct backtrace_state *state,
+ const char *buildid_data, size_t buildid_size,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ const char * const prefix = SYSTEM_BUILD_ID_DIR;
+ const size_t prefix_len = strlen (prefix);
+ const char * const suffix = ".debug";
+ const size_t suffix_len = strlen (suffix);
+ size_t len;
+ char *bd_filename;
+ char *t;
+ size_t i;
+ int ret;
+ int does_not_exist;
+
+ len = prefix_len + buildid_size * 2 + suffix_len + 2;
+ bd_filename = backtrace_alloc (state, len, error_callback, data);
+ if (bd_filename == NULL)
+ return -1;
+
+ t = bd_filename;
+ memcpy (t, prefix, prefix_len);
+ t += prefix_len;
+ for (i = 0; i < buildid_size; i++)
+ {
+ unsigned char b;
+ unsigned char nib;
+
+ b = (unsigned char) buildid_data[i];
+ nib = (b & 0xf0) >> 4;
+ *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;
+ nib = b & 0x0f;
+ *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;
+ if (i == 0)
+ *t++ = '/';
+ }
+ memcpy (t, suffix, suffix_len);
+ t[suffix_len] = '\0';
+
+ ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist);
+
+ backtrace_free (state, bd_filename, len, error_callback, data);
+
+ /* gdb checks that the debuginfo file has the same build ID note.
+ That seems kind of pointless to me--why would it have the right
+ name but not the right build ID?--so skipping the check. */
+
+ return ret;
+}
+
+/* Try to open a file whose name is PREFIX (length PREFIX_LEN)
+ concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with
+ DEBUGLINK_NAME. Returns an open file descriptor, or -1. */
+
+static int
+elf_try_debugfile (struct backtrace_state *state, const char *prefix,
+ size_t prefix_len, const char *prefix2, size_t prefix2_len,
+ const char *debuglink_name,
+ backtrace_error_callback error_callback, void *data)
+{
+ size_t debuglink_len;
+ size_t try_len;
+ char *try;
+ int does_not_exist;
+ int ret;
+
+ debuglink_len = strlen (debuglink_name);
+ try_len = prefix_len + prefix2_len + debuglink_len + 1;
+ try = backtrace_alloc (state, try_len, error_callback, data);
+ if (try == NULL)
+ return -1;
+
+ memcpy (try, prefix, prefix_len);
+ memcpy (try + prefix_len, prefix2, prefix2_len);
+ memcpy (try + prefix_len + prefix2_len, debuglink_name, debuglink_len);
+ try[prefix_len + prefix2_len + debuglink_len] = '\0';
+
+ ret = backtrace_open (try, error_callback, data, &does_not_exist);
+
+ backtrace_free (state, try, try_len, error_callback, data);
+
+ return ret;
+}
+
+/* Find a separate debug info file, using the debuglink section data
+ to find it. Returns an open file descriptor, or -1. */
+
+static int
+elf_find_debugfile_by_debuglink (struct backtrace_state *state,
+ const char *filename,
+ const char *debuglink_name,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ int ret;
+ char *alc;
+ size_t alc_len;
+ const char *slash;
+ int ddescriptor;
+ const char *prefix;
+ size_t prefix_len;
+
+ /* Resolve symlinks in FILENAME. Since FILENAME is fairly likely to
+ be /proc/self/exe, symlinks are common. We don't try to resolve
+ the whole path name, just the base name. */
+ ret = -1;
+ alc = NULL;
+ alc_len = 0;
+ while (elf_is_symlink (filename))
+ {
+ char *new_buf;
+ size_t new_len;
+
+ new_buf = elf_readlink (state, filename, error_callback, data, &new_len);
+ if (new_buf == NULL)
+ break;
+
+ if (new_buf[0] == '/')
+ filename = new_buf;
+ else
+ {
+ slash = strrchr (filename, '/');
+ if (slash == NULL)
+ filename = new_buf;
+ else
+ {
+ size_t clen;
+ char *c;
+
+ slash++;
+ clen = slash - filename + strlen (new_buf) + 1;
+ c = backtrace_alloc (state, clen, error_callback, data);
+ if (c == NULL)
+ goto done;
+
+ memcpy (c, filename, slash - filename);
+ memcpy (c + (slash - filename), new_buf, strlen (new_buf));
+ c[slash - filename + strlen (new_buf)] = '\0';
+ backtrace_free (state, new_buf, new_len, error_callback, data);
+ filename = c;
+ new_buf = c;
+ new_len = clen;
+ }
+ }
+
+ if (alc != NULL)
+ backtrace_free (state, alc, alc_len, error_callback, data);
+ alc = new_buf;
+ alc_len = new_len;
+ }
+
+ /* Look for DEBUGLINK_NAME in the same directory as FILENAME. */
+
+ slash = strrchr (filename, '/');
+ if (slash == NULL)
+ {
+ prefix = "";
+ prefix_len = 0;
+ }
+ else
+ {
+ slash++;
+ prefix = filename;
+ prefix_len = slash - filename;
+ }
+
+ ddescriptor = elf_try_debugfile (state, prefix, prefix_len, "", 0,
+ debuglink_name, error_callback, data);
+ if (ddescriptor >= 0)
+ {
+ ret = ddescriptor;
+ goto done;
+ }
+
+ /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME. */
+
+ ddescriptor = elf_try_debugfile (state, prefix, prefix_len, ".debug/",
+ strlen (".debug/"), debuglink_name,
+ error_callback, data);
+ if (ddescriptor >= 0)
+ {
+ ret = ddescriptor;
+ goto done;
+ }
+
+ /* Look for DEBUGLINK_NAME in /usr/lib/debug. */
+
+ ddescriptor = elf_try_debugfile (state, "/usr/lib/debug/",
+ strlen ("/usr/lib/debug/"), prefix,
+ prefix_len, debuglink_name,
+ error_callback, data);
+ if (ddescriptor >= 0)
+ ret = ddescriptor;
+
+ done:
+ if (alc != NULL && alc_len > 0)
+ backtrace_free (state, alc, alc_len, error_callback, data);
+ return ret;
+}
+
+/* Open a separate debug info file, using the debuglink section data
+ to find it. Returns an open file descriptor, or -1. */
+
+static int
+elf_open_debugfile_by_debuglink (struct backtrace_state *state,
+ const char *filename,
+ const char *debuglink_name,
+ uint32_t debuglink_crc,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ int ddescriptor;
+
+ ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
+ debuglink_name,
+ error_callback, data);
+ if (ddescriptor < 0)
+ return -1;
+
+ if (debuglink_crc != 0)
+ {
+ uint32_t got_crc;
+
+ got_crc = elf_crc32_file (state, ddescriptor, error_callback, data);
+ if (got_crc != debuglink_crc)
+ {
+ backtrace_close (ddescriptor, error_callback, data);
+ return -1;
+ }
+ }
+
+ return ddescriptor;
+}
+
+/* A function useful for setting a breakpoint for an inflation failure
+ when this code is compiled with -g. */
+
+static void
+elf_zlib_failed(void)
+{
+}
+
+/* *PVAL is the current value being read from the stream, and *PBITS
+ is the number of valid bits. Ensure that *PVAL holds at least 15
+ bits by reading additional bits from *PPIN, up to PINEND, as
+ needed. Updates *PPIN, *PVAL and *PBITS. Returns 1 on success, 0
+ on error. */
+
+static int
+elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend,
+ uint64_t *pval, unsigned int *pbits)
+{
+ unsigned int bits;
+ const unsigned char *pin;
+ uint64_t val;
+ uint32_t next;
+
+ bits = *pbits;
+ if (bits >= 15)
+ return 1;
+ pin = *ppin;
+ val = *pval;
+
+ if (unlikely (pinend - pin < 4))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \
+ && defined(__ORDER_BIG_ENDIAN__) \
+ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ \
+ || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ /* We've ensured that PIN is aligned. */
+ next = *(const uint32_t *)pin;
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ next = __builtin_bswap32 (next);
+#endif
+#else
+ next = pin[0] | (pin[1] << 8) | (pin[2] << 16) | (pin[3] << 24);
+#endif
+
+ val |= (uint64_t)next << bits;
+ bits += 32;
+ pin += 4;
+
+ /* We will need the next four bytes soon. */
+ __builtin_prefetch (pin, 0, 0);
+
+ *ppin = pin;
+ *pval = val;
+ *pbits = bits;
+ return 1;
+}
+
+/* Huffman code tables, like the rest of the zlib format, are defined
+ by RFC 1951. We store a Huffman code table as a series of tables
+ stored sequentially in memory. Each entry in a table is 16 bits.
+ The first, main, table has 256 entries. It is followed by a set of
+ secondary tables of length 2 to 128 entries. The maximum length of
+ a code sequence in the deflate format is 15 bits, so that is all we
+ need. Each secondary table has an index, which is the offset of
+ the table in the overall memory storage.
+
+ The deflate format says that all codes of a given bit length are
+ lexicographically consecutive. Perhaps we could have 130 values
+ that require a 15-bit code, perhaps requiring three secondary
+ tables of size 128. I don't know if this is actually possible, but
+ it suggests that the maximum size required for secondary tables is
+ 3 * 128 + 3 * 64 ... == 768. The zlib enough program reports 660
+ as the maximum. We permit 768, since in addition to the 256 for
+ the primary table, with two bytes per entry, and with the two
+ tables we need, that gives us a page.
+
+ A single table entry needs to store a value or (for the main table
+ only) the index and size of a secondary table. Values range from 0
+ to 285, inclusive. Secondary table indexes, per above, range from
+ 0 to 510. For a value we need to store the number of bits we need
+ to determine that value (one value may appear multiple times in the
+ table), which is 1 to 8. For a secondary table we need to store
+ the number of bits used to index into the table, which is 1 to 7.
+ And of course we need 1 bit to decide whether we have a value or a
+ secondary table index. So each entry needs 9 bits for value/table
+ index, 3 bits for size, 1 bit what it is. For simplicity we use 16
+ bits per entry. */
+
+/* Number of entries we allocate to for one code table. We get a page
+ for the two code tables we need. */
+
+#define HUFFMAN_TABLE_SIZE (1024)
+
+/* Bit masks and shifts for the values in the table. */
+
+#define HUFFMAN_VALUE_MASK 0x01ff
+#define HUFFMAN_BITS_SHIFT 9
+#define HUFFMAN_BITS_MASK 0x7
+#define HUFFMAN_SECONDARY_SHIFT 12
+
+/* For working memory while inflating we need two code tables, we need
+ an array of code lengths (max value 15, so we use unsigned char),
+ and an array of unsigned shorts used while building a table. The
+ latter two arrays must be large enough to hold the maximum number
+ of code lengths, which RFC 1951 defines as 286 + 30. */
+
+#define ZDEBUG_TABLE_SIZE \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (unsigned char))
+
+#define ZDEBUG_TABLE_CODELEN_OFFSET \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (uint16_t))
+
+#define ZDEBUG_TABLE_WORK_OFFSET \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t))
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used by the main function that generates the fixed table to learn
+ the table size. */
+static size_t final_next_secondary;
+
+#endif
+
+/* Build a Huffman code table from an array of lengths in CODES of
+ length CODES_LEN. The table is stored into *TABLE. ZDEBUG_TABLE
+ is the same as for elf_zlib_inflate, used to find some work space.
+ Returns 1 on success, 0 on error. */
+
+static int
+elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
+ uint16_t *zdebug_table, uint16_t *table)
+{
+ uint16_t count[16];
+ uint16_t start[16];
+ uint16_t prev[16];
+ uint16_t firstcode[7];
+ uint16_t *next;
+ size_t i;
+ size_t j;
+ unsigned int code;
+ size_t next_secondary;
+
+ /* Count the number of code of each length. Set NEXT[val] to be the
+ next value after VAL with the same bit length. */
+
+ next = (uint16_t *) (((unsigned char *) zdebug_table)
+ + ZDEBUG_TABLE_WORK_OFFSET);
+
+ memset (&count[0], 0, 16 * sizeof (uint16_t));
+ for (i = 0; i < codes_len; ++i)
+ {
+ if (unlikely (codes[i] >= 16))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (count[codes[i]] == 0)
+ {
+ start[codes[i]] = i;
+ prev[codes[i]] = i;
+ }
+ else
+ {
+ next[prev[codes[i]]] = i;
+ prev[codes[i]] = i;
+ }
+
+ ++count[codes[i]];
+ }
+
+ /* For each length, fill in the table for the codes of that
+ length. */
+
+ memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t));
+
+ /* Handle the values that do not require a secondary table. */
+
+ code = 0;
+ for (j = 1; j <= 8; ++j)
+ {
+ unsigned int jcnt;
+ unsigned int val;
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ if (unlikely (jcnt > (1U << j)))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* There are JCNT values that have this length, the values
+ starting from START[j] continuing through NEXT[VAL]. Those
+ values are assigned consecutive values starting at CODE. */
+
+ val = start[j];
+ for (i = 0; i < jcnt; ++i)
+ {
+ uint16_t tval;
+ size_t ind;
+ unsigned int incr;
+
+ /* In the compressed bit stream, the value VAL is encoded as
+ J bits with the value C. */
+
+ if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT);
+
+ /* The table lookup uses 8 bits. If J is less than 8, we
+ don't know what the other bits will be. We need to fill
+ in all possibilities in the table. Since the Huffman
+ code is unambiguous, those entries can't be used for any
+ other code. */
+
+ for (ind = code; ind < 0x100; ind += 1 << j)
+ {
+ if (unlikely (table[ind] != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ table[ind] = tval;
+ }
+
+ /* Advance to the next value with this length. */
+ if (i + 1 < jcnt)
+ val = next[val];
+
+ /* The Huffman codes are stored in the bitstream with the
+ most significant bit first, as is required to make them
+ unambiguous. The effect is that when we read them from
+ the bitstream we see the bit sequence in reverse order:
+ the most significant bit of the Huffman code is the least
+ significant bit of the value we read from the bitstream.
+ That means that to make our table lookups work, we need
+ to reverse the bits of CODE. Since reversing bits is
+ tedious and in general requires using a table, we instead
+ increment CODE in reverse order. That is, if the number
+ of bits we are currently using, here named J, is 3, we
+ count as 000, 100, 010, 110, 001, 101, 011, 111, which is
+ to say the numbers from 0 to 7 but with the bits
+ reversed. Going to more bits, aka incrementing J,
+ effectively just adds more zero bits as the beginning,
+ and as such does not change the numeric value of CODE.
+
+ To increment CODE of length J in reverse order, find the
+ most significant zero bit and set it to one while
+ clearing all higher bits. In other words, add 1 modulo
+ 2^J, only reversed. */
+
+ incr = 1U << (j - 1);
+ while ((code & incr) != 0)
+ incr >>= 1;
+ if (incr == 0)
+ code = 0;
+ else
+ {
+ code &= incr - 1;
+ code += incr;
+ }
+ }
+ }
+
+ /* Handle the values that require a secondary table. */
+
+ /* Set FIRSTCODE, the number at which the codes start, for each
+ length. */
+
+ for (j = 9; j < 16; j++)
+ {
+ unsigned int jcnt;
+ unsigned int k;
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ /* There are JCNT values that have this length, the values
+ starting from START[j]. Those values are assigned
+ consecutive values starting at CODE. */
+
+ firstcode[j - 9] = code;
+
+ /* Reverse add JCNT to CODE modulo 2^J. */
+ for (k = 0; k < j; ++k)
+ {
+ if ((jcnt & (1U << k)) != 0)
+ {
+ unsigned int m;
+ unsigned int bit;
+
+ bit = 1U << (j - k - 1);
+ for (m = 0; m < j - k; ++m, bit >>= 1)
+ {
+ if ((code & bit) == 0)
+ {
+ code += bit;
+ break;
+ }
+ code &= ~bit;
+ }
+ jcnt &= ~(1U << k);
+ }
+ }
+ if (unlikely (jcnt != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+
+ /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive
+ values starting at START[J] with consecutive codes starting at
+ FIRSTCODE[J - 9]. In the primary table we need to point to the
+ secondary table, and the secondary table will be indexed by J - 9
+ bits. We count down from 15 so that we install the larger
+ secondary tables first, as the smaller ones may be embedded in
+ the larger ones. */
+
+ next_secondary = 0; /* Index of next secondary table (after primary). */
+ for (j = 15; j >= 9; j--)
+ {
+ unsigned int jcnt;
+ unsigned int val;
+ size_t primary; /* Current primary index. */
+ size_t secondary; /* Offset to current secondary table. */
+ size_t secondary_bits; /* Bit size of current secondary table. */
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ val = start[j];
+ code = firstcode[j - 9];
+ primary = 0x100;
+ secondary = 0;
+ secondary_bits = 0;
+ for (i = 0; i < jcnt; ++i)
+ {
+ uint16_t tval;
+ size_t ind;
+ unsigned int incr;
+
+ if ((code & 0xff) != primary)
+ {
+ uint16_t tprimary;
+
+ /* Fill in a new primary table entry. */
+
+ primary = code & 0xff;
+
+ tprimary = table[primary];
+ if (tprimary == 0)
+ {
+ /* Start a new secondary table. */
+
+ if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK)
+ != next_secondary))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ secondary = next_secondary;
+ secondary_bits = j - 8;
+ next_secondary += 1 << secondary_bits;
+ table[primary] = (secondary
+ + ((j - 8) << HUFFMAN_BITS_SHIFT)
+ + (1U << HUFFMAN_SECONDARY_SHIFT));
+ }
+ else
+ {
+ /* There is an existing entry. It had better be a
+ secondary table with enough bits. */
+ if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT))
+ == 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ secondary = tprimary & HUFFMAN_VALUE_MASK;
+ secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT)
+ & HUFFMAN_BITS_MASK);
+ if (unlikely (secondary_bits < j - 8))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+ }
+
+ /* Fill in secondary table entries. */
+
+ tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT);
+
+ for (ind = code >> 8;
+ ind < (1U << secondary_bits);
+ ind += 1U << (j - 8))
+ {
+ if (unlikely (table[secondary + 0x100 + ind] != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ table[secondary + 0x100 + ind] = tval;
+ }
+
+ if (i + 1 < jcnt)
+ val = next[val];
+
+ incr = 1U << (j - 1);
+ while ((code & incr) != 0)
+ incr >>= 1;
+ if (incr == 0)
+ code = 0;
+ else
+ {
+ code &= incr - 1;
+ code += incr;
+ }
+ }
+ }
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+ final_next_secondary = next_secondary;
+#endif
+
+ return 1;
+}
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used to generate the fixed Huffman table for block type 1. */
+
+#include <stdio.h>
+
+static uint16_t table[ZDEBUG_TABLE_SIZE];
+static unsigned char codes[288];
+
+int
+main ()
+{
+ size_t i;
+
+ for (i = 0; i <= 143; ++i)
+ codes[i] = 8;
+ for (i = 144; i <= 255; ++i)
+ codes[i] = 9;
+ for (i = 256; i <= 279; ++i)
+ codes[i] = 7;
+ for (i = 280; i <= 287; ++i)
+ codes[i] = 8;
+ if (!elf_zlib_inflate_table (&codes[0], 288, &table[0], &table[0]))
+ {
+ fprintf (stderr, "elf_zlib_inflate_table failed\n");
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n",
+ final_next_secondary + 0x100);
+ printf ("{\n");
+ for (i = 0; i < final_next_secondary + 0x100; i += 8)
+ {
+ size_t j;
+
+ printf (" ");
+ for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)
+ printf (" %#x,", table[j]);
+ printf ("\n");
+ }
+ printf ("};\n");
+ printf ("\n");
+
+ for (i = 0; i < 32; ++i)
+ codes[i] = 5;
+ if (!elf_zlib_inflate_table (&codes[0], 32, &table[0], &table[0]))
+ {
+ fprintf (stderr, "elf_zlib_inflate_table failed\n");
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("static const uint16_t elf_zlib_default_dist_table[%#zx] =\n",
+ final_next_secondary + 0x100);
+ printf ("{\n");
+ for (i = 0; i < final_next_secondary + 0x100; i += 8)
+ {
+ size_t j;
+
+ printf (" ");
+ for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)
+ printf (" %#x,", table[j]);
+ printf ("\n");
+ }
+ printf ("};\n");
+
+ return 0;
+}
+
+#endif
+
+/* The fixed tables generated by the #ifdef'ed out main function
+ above. */
+
+static const uint16_t elf_zlib_default_table[0x170] =
+{
+ 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230,
+ 0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250,
+ 0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240,
+ 0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260,
+ 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238,
+ 0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258,
+ 0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248,
+ 0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268,
+ 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234,
+ 0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254,
+ 0xd05, 0xe5a, 0xe1a, 0x1204, 0xd15, 0xe7a, 0xe3a, 0x1244,
+ 0xd0d, 0xe6a, 0xe2a, 0x1224, 0xe0a, 0xe8a, 0xe4a, 0x1264,
+ 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123c,
+ 0xd0b, 0xe66, 0xe26, 0x121c, 0xe06, 0xe86, 0xe46, 0x125c,
+ 0xd07, 0xe5e, 0xe1e, 0x120c, 0xd17, 0xe7e, 0xe3e, 0x124c,
+ 0xd0f, 0xe6e, 0xe2e, 0x122c, 0xe0e, 0xe8e, 0xe4e, 0x126c,
+ 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1232,
+ 0xd08, 0xe61, 0xe21, 0x1212, 0xe01, 0xe81, 0xe41, 0x1252,
+ 0xd04, 0xe59, 0xe19, 0x1202, 0xd14, 0xe79, 0xe39, 0x1242,
+ 0xd0c, 0xe69, 0xe29, 0x1222, 0xe09, 0xe89, 0xe49, 0x1262,
+ 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123a,
+ 0xd0a, 0xe65, 0xe25, 0x121a, 0xe05, 0xe85, 0xe45, 0x125a,
+ 0xd06, 0xe5d, 0xe1d, 0x120a, 0xd16, 0xe7d, 0xe3d, 0x124a,
+ 0xd0e, 0xe6d, 0xe2d, 0x122a, 0xe0d, 0xe8d, 0xe4d, 0x126a,
+ 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1236,
+ 0xd09, 0xe63, 0xe23, 0x1216, 0xe03, 0xe83, 0xe43, 0x1256,
+ 0xd05, 0xe5b, 0xe1b, 0x1206, 0xd15, 0xe7b, 0xe3b, 0x1246,
+ 0xd0d, 0xe6b, 0xe2b, 0x1226, 0xe0b, 0xe8b, 0xe4b, 0x1266,
+ 0xd03, 0xe57, 0xe17, 0xf1f, 0xd13, 0xe77, 0xe37, 0x123e,
+ 0xd0b, 0xe67, 0xe27, 0x121e, 0xe07, 0xe87, 0xe47, 0x125e,
+ 0xd07, 0xe5f, 0xe1f, 0x120e, 0xd17, 0xe7f, 0xe3f, 0x124e,
+ 0xd0f, 0xe6f, 0xe2f, 0x122e, 0xe0f, 0xe8f, 0xe4f, 0x126e,
+ 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297,
+ 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f,
+ 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7,
+ 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af,
+ 0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7,
+ 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf,
+ 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7,
+ 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf,
+ 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7,
+ 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df,
+ 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7,
+ 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef,
+ 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7,
+ 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff,
+};
+
+static const uint16_t elf_zlib_default_dist_table[0x100] =
+{
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+ 0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+ 0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+ 0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+ 0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+};
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT. Return 1 on
+ success, 0 on some error parsing the stream. */
+
+static int
+elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
+ unsigned char *pout, size_t sout)
+{
+ unsigned char *porigout;
+ const unsigned char *pinend;
+ unsigned char *poutend;
+
+ /* We can apparently see multiple zlib streams concatenated
+ together, so keep going as long as there is something to read.
+ The last 4 bytes are the checksum. */
+ porigout = pout;
+ pinend = pin + sin;
+ poutend = pout + sout;
+ while ((pinend - pin) > 4)
+ {
+ uint64_t val;
+ unsigned int bits;
+ int last;
+
+ /* Read the two byte zlib header. */
+
+ if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */
+ {
+ /* Unknown compression method. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely ((pin[0] >> 4) > 7))
+ {
+ /* Window size too large. Other than this check, we don't
+ care about the window size. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely ((pin[1] & 0x20) != 0))
+ {
+ /* Stream expects a predefined dictionary, but we have no
+ dictionary. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ val = (pin[0] << 8) | pin[1];
+ if (unlikely (val % 31 != 0))
+ {
+ /* Header check failure. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ pin += 2;
+
+ /* Align PIN to a 32-bit boundary. */
+
+ val = 0;
+ bits = 0;
+ while ((((uintptr_t) pin) & 3) != 0)
+ {
+ val |= (uint64_t)*pin << bits;
+ bits += 8;
+ ++pin;
+ }
+
+ /* Read blocks until one is marked last. */
+
+ last = 0;
+
+ while (!last)
+ {
+ unsigned int type;
+ const uint16_t *tlit;
+ const uint16_t *tdist;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ last = val & 1;
+ type = (val >> 1) & 3;
+ val >>= 3;
+ bits -= 3;
+
+ if (unlikely (type == 3))
+ {
+ /* Invalid block type. */
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (type == 0)
+ {
+ uint16_t len;
+ uint16_t lenc;
+
+ /* An uncompressed block. */
+
+ /* If we've read ahead more than a byte, back up. */
+ while (bits > 8)
+ {
+ --pin;
+ bits -= 8;
+ }
+
+ val = 0;
+ bits = 0;
+ if (unlikely ((pinend - pin) < 4))
+ {
+ /* Missing length. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ len = pin[0] | (pin[1] << 8);
+ lenc = pin[2] | (pin[3] << 8);
+ pin += 4;
+ lenc = ~lenc;
+ if (unlikely (len != lenc))
+ {
+ /* Corrupt data. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely (len > (unsigned int) (pinend - pin)
+ || len > (unsigned int) (poutend - pout)))
+ {
+ /* Not enough space in buffers. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ memcpy (pout, pin, len);
+ pout += len;
+ pin += len;
+
+ /* Align PIN. */
+ while ((((uintptr_t) pin) & 3) != 0)
+ {
+ val |= (uint64_t)*pin << bits;
+ bits += 8;
+ ++pin;
+ }
+
+ /* Go around to read the next block. */
+ continue;
+ }
+
+ if (type == 1)
+ {
+ tlit = elf_zlib_default_table;
+ tdist = elf_zlib_default_dist_table;
+ }
+ else
+ {
+ unsigned int nlit;
+ unsigned int ndist;
+ unsigned int nclen;
+ unsigned char codebits[19];
+ unsigned char *plenbase;
+ unsigned char *plen;
+ unsigned char *plenend;
+
+ /* Read a Huffman encoding table. The various magic
+ numbers here are from RFC 1951. */
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ nlit = (val & 0x1f) + 257;
+ val >>= 5;
+ ndist = (val & 0x1f) + 1;
+ val >>= 5;
+ nclen = (val & 0xf) + 4;
+ val >>= 4;
+ bits -= 14;
+ if (unlikely (nlit > 286 || ndist > 30))
+ {
+ /* Values out of range. */
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* Read and build the table used to compress the
+ literal, length, and distance codes. */
+
+ memset(&codebits[0], 0, 19);
+
+ /* There are always at least 4 elements in the
+ table. */
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[16] = val & 7;
+ codebits[17] = (val >> 3) & 7;
+ codebits[18] = (val >> 6) & 7;
+ codebits[0] = (val >> 9) & 7;
+ val >>= 12;
+ bits -= 12;
+
+ if (nclen == 4)
+ goto codebitsdone;
+
+ codebits[8] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 5)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[7] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 6)
+ goto codebitsdone;
+
+ codebits[9] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 7)
+ goto codebitsdone;
+
+ codebits[6] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 8)
+ goto codebitsdone;
+
+ codebits[10] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 9)
+ goto codebitsdone;
+
+ codebits[5] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 10)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[11] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 11)
+ goto codebitsdone;
+
+ codebits[4] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 12)
+ goto codebitsdone;
+
+ codebits[12] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 13)
+ goto codebitsdone;
+
+ codebits[3] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 14)
+ goto codebitsdone;
+
+ codebits[13] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 15)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[2] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 16)
+ goto codebitsdone;
+
+ codebits[14] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 17)
+ goto codebitsdone;
+
+ codebits[1] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 18)
+ goto codebitsdone;
+
+ codebits[15] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ codebitsdone:
+
+ if (!elf_zlib_inflate_table (codebits, 19, zdebug_table,
+ zdebug_table))
+ return 0;
+
+ /* Read the compressed bit lengths of the literal,
+ length, and distance codes. We have allocated space
+ at the end of zdebug_table to hold them. */
+
+ plenbase = (((unsigned char *) zdebug_table)
+ + ZDEBUG_TABLE_CODELEN_OFFSET);
+ plen = plenbase;
+ plenend = plen + nlit + ndist;
+ while (plen < plenend)
+ {
+ uint16_t t;
+ unsigned int b;
+ uint16_t v;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = zdebug_table[val & 0xff];
+
+ /* The compression here uses bit lengths up to 7, so
+ a secondary table is never necessary. */
+ if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ val >>= b + 1;
+ bits -= b + 1;
+
+ v = t & HUFFMAN_VALUE_MASK;
+ if (v < 16)
+ *plen++ = v;
+ else if (v == 16)
+ {
+ unsigned int c;
+ unsigned int prev;
+
+ /* Copy previous entry 3 to 6 times. */
+
+ if (unlikely (plen == plenbase))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 3 + (val & 0x3);
+ val >>= 2;
+ bits -= 2;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ prev = plen[-1];
+ switch (c)
+ {
+ case 6:
+ *plen++ = prev;
+ /* fallthrough */
+ case 5:
+ *plen++ = prev;
+ /* fallthrough */
+ case 4:
+ *plen++ = prev;
+ }
+ *plen++ = prev;
+ *plen++ = prev;
+ *plen++ = prev;
+ }
+ else if (v == 17)
+ {
+ unsigned int c;
+
+ /* Store zero 3 to 10 times. */
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 3 + (val & 0x7);
+ val >>= 3;
+ bits -= 3;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ switch (c)
+ {
+ case 10:
+ *plen++ = 0;
+ /* fallthrough */
+ case 9:
+ *plen++ = 0;
+ /* fallthrough */
+ case 8:
+ *plen++ = 0;
+ /* fallthrough */
+ case 7:
+ *plen++ = 0;
+ /* fallthrough */
+ case 6:
+ *plen++ = 0;
+ /* fallthrough */
+ case 5:
+ *plen++ = 0;
+ /* fallthrough */
+ case 4:
+ *plen++ = 0;
+ }
+ *plen++ = 0;
+ *plen++ = 0;
+ *plen++ = 0;
+ }
+ else if (v == 18)
+ {
+ unsigned int c;
+
+ /* Store zero 11 to 138 times. */
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 11 + (val & 0x7f);
+ val >>= 7;
+ bits -= 7;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ memset (plen, 0, c);
+ plen += c;
+ }
+ else
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+
+ /* Make sure that the stop code can appear. */
+
+ plen = plenbase;
+ if (unlikely (plen[256] == 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* Build the decompression tables. */
+
+ if (!elf_zlib_inflate_table (plen, nlit, zdebug_table,
+ zdebug_table))
+ return 0;
+ if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table,
+ zdebug_table + HUFFMAN_TABLE_SIZE))
+ return 0;
+ tlit = zdebug_table;
+ tdist = zdebug_table + HUFFMAN_TABLE_SIZE;
+ }
+
+ /* Inflate values until the end of the block. This is the
+ main loop of the inflation code. */
+
+ while (1)
+ {
+ uint16_t t;
+ unsigned int b;
+ uint16_t v;
+ unsigned int lit;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = tlit[val & 0xff];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ v = t & HUFFMAN_VALUE_MASK;
+
+ if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+ {
+ lit = v;
+ val >>= b + 1;
+ bits -= b + 1;
+ }
+ else
+ {
+ t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ lit = t & HUFFMAN_VALUE_MASK;
+ val >>= b + 8;
+ bits -= b + 8;
+ }
+
+ if (lit < 256)
+ {
+ if (unlikely (pout == poutend))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ *pout++ = lit;
+
+ /* We will need to write the next byte soon. We ask
+ for high temporal locality because we will write
+ to the whole cache line soon. */
+ __builtin_prefetch (pout, 1, 3);
+ }
+ else if (lit == 256)
+ {
+ /* The end of the block. */
+ break;
+ }
+ else
+ {
+ unsigned int dist;
+ unsigned int len;
+
+ /* Convert lit into a length. */
+
+ if (lit < 265)
+ len = lit - 257 + 3;
+ else if (lit == 285)
+ len = 258;
+ else if (unlikely (lit > 285))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ else
+ {
+ unsigned int extra;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ /* This is an expression for the table of length
+ codes in RFC 1951 3.2.5. */
+ lit -= 265;
+ extra = (lit >> 2) + 1;
+ len = (lit & 3) << extra;
+ len += 11;
+ len += ((1U << (extra - 1)) - 1) << 3;
+ len += val & ((1U << extra) - 1);
+ val >>= extra;
+ bits -= extra;
+ }
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = tdist[val & 0xff];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ v = t & HUFFMAN_VALUE_MASK;
+
+ if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+ {
+ dist = v;
+ val >>= b + 1;
+ bits -= b + 1;
+ }
+ else
+ {
+ t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ dist = t & HUFFMAN_VALUE_MASK;
+ val >>= b + 8;
+ bits -= b + 8;
+ }
+
+ /* Convert dist to a distance. */
+
+ if (dist == 0)
+ {
+ /* A distance of 1. A common case, meaning
+ repeat the last character LEN times. */
+
+ if (unlikely (pout == porigout))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (unlikely ((unsigned int) (poutend - pout) < len))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ memset (pout, pout[-1], len);
+ pout += len;
+ }
+ else if (unlikely (dist > 29))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ else
+ {
+ if (dist < 4)
+ dist = dist + 1;
+ else
+ {
+ unsigned int extra;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ /* This is an expression for the table of
+ distance codes in RFC 1951 3.2.5. */
+ dist -= 4;
+ extra = (dist >> 1) + 1;
+ dist = (dist & 1) << extra;
+ dist += 5;
+ dist += ((1U << (extra - 1)) - 1) << 2;
+ dist += val & ((1U << extra) - 1);
+ val >>= extra;
+ bits -= extra;
+ }
+
+ /* Go back dist bytes, and copy len bytes from
+ there. */
+
+ if (unlikely ((unsigned int) (pout - porigout) < dist))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (unlikely ((unsigned int) (poutend - pout) < len))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (dist >= len)
+ {
+ memcpy (pout, pout - dist, len);
+ pout += len;
+ }
+ else
+ {
+ while (len > 0)
+ {
+ unsigned int copy;
+
+ copy = len < dist ? len : dist;
+ memcpy (pout, pout - dist, copy);
+ len -= copy;
+ pout += copy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* We should have filled the output buffer. */
+ if (unlikely (pout != poutend))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Verify the zlib checksum. The checksum is in the 4 bytes at
+ CHECKBYTES, and the uncompressed data is at UNCOMPRESSED /
+ UNCOMPRESSED_SIZE. Returns 1 on success, 0 on failure. */
+
+static int
+elf_zlib_verify_checksum (const unsigned char *checkbytes,
+ const unsigned char *uncompressed,
+ size_t uncompressed_size)
+{
+ unsigned int i;
+ unsigned int cksum;
+ const unsigned char *p;
+ uint32_t s1;
+ uint32_t s2;
+ size_t hsz;
+
+ cksum = 0;
+ for (i = 0; i < 4; i++)
+ cksum = (cksum << 8) | checkbytes[i];
+
+ s1 = 1;
+ s2 = 0;
+
+ /* Minimize modulo operations. */
+
+ p = uncompressed;
+ hsz = uncompressed_size;
+ while (hsz >= 5552)
+ {
+ for (i = 0; i < 5552; i += 16)
+ {
+ /* Manually unroll loop 16 times. */
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ }
+ hsz -= 5552;
+ s1 %= 65521;
+ s2 %= 65521;
+ }
+
+ while (hsz >= 16)
+ {
+ /* Manually unroll loop 16 times. */
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+
+ hsz -= 16;
+ }
+
+ for (i = 0; i < hsz; ++i)
+ {
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ }
+
+ s1 %= 65521;
+ s2 %= 65521;
+
+ if (unlikely ((s2 << 16) + s1 != cksum))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the
+ checksum. Return 1 on success, 0 on error. */
+
+static int
+elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin,
+ uint16_t *zdebug_table, unsigned char *pout,
+ size_t sout)
+{
+ if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout))
+ return 0;
+ if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout))
+ return 0;
+ return 1;
+}
+
+/* Uncompress the old compressed debug format, the one emitted by
+ --compress-debug-sections=zlib-gnu. The compressed data is in
+ COMPRESSED / COMPRESSED_SIZE, and the function writes to
+ *UNCOMPRESSED / *UNCOMPRESSED_SIZE. ZDEBUG_TABLE is work space to
+ hold Huffman tables. Returns 0 on error, 1 on successful
+ decompression or if something goes wrong. In general we try to
+ carry on, by returning 1, even if we can't decompress. */
+
+static int
+elf_uncompress_zdebug (struct backtrace_state *state,
+ const unsigned char *compressed, size_t compressed_size,
+ uint16_t *zdebug_table,
+ backtrace_error_callback error_callback, void *data,
+ unsigned char **uncompressed, size_t *uncompressed_size)
+{
+ size_t sz;
+ size_t i;
+ unsigned char *po;
+
+ *uncompressed = NULL;
+ *uncompressed_size = 0;
+
+ /* The format starts with the four bytes ZLIB, followed by the 8
+ byte length of the uncompressed data in big-endian order,
+ followed by a zlib stream. */
+
+ if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0)
+ return 1;
+
+ sz = 0;
+ for (i = 0; i < 8; i++)
+ sz = (sz << 8) | compressed[i + 4];
+
+ if (*uncompressed != NULL && *uncompressed_size >= sz)
+ po = *uncompressed;
+ else
+ {
+ po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data);
+ if (po == NULL)
+ return 0;
+ }
+
+ if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12,
+ zdebug_table, po, sz))
+ return 1;
+
+ *uncompressed = po;
+ *uncompressed_size = sz;
+
+ return 1;
+}
+
+/* Uncompress the new compressed debug format, the official standard
+ ELF approach emitted by --compress-debug-sections=zlib-gabi. The
+ compressed data is in COMPRESSED / COMPRESSED_SIZE, and the
+ function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE.
+ ZDEBUG_TABLE is work space as for elf_uncompress_zdebug. Returns 0
+ on error, 1 on successful decompression or if something goes wrong.
+ In general we try to carry on, by returning 1, even if we can't
+ decompress. */
+
+static int
+elf_uncompress_chdr (struct backtrace_state *state,
+ const unsigned char *compressed, size_t compressed_size,
+ uint16_t *zdebug_table,
+ backtrace_error_callback error_callback, void *data,
+ unsigned char **uncompressed, size_t *uncompressed_size)
+{
+ const b_elf_chdr *chdr;
+ unsigned char *po;
+
+ *uncompressed = NULL;
+ *uncompressed_size = 0;
+
+ /* The format starts with an ELF compression header. */
+ if (compressed_size < sizeof (b_elf_chdr))
+ return 1;
+
+ chdr = (const b_elf_chdr *) compressed;
+
+ if (chdr->ch_type != ELFCOMPRESS_ZLIB)
+ {
+ /* Unsupported compression algorithm. */
+ return 1;
+ }
+
+ if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size)
+ po = *uncompressed;
+ else
+ {
+ po = (unsigned char *) backtrace_alloc (state, chdr->ch_size,
+ error_callback, data);
+ if (po == NULL)
+ return 0;
+ }
+
+ if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr),
+ compressed_size - sizeof (b_elf_chdr),
+ zdebug_table, po, chdr->ch_size))
+ return 1;
+
+ *uncompressed = po;
+ *uncompressed_size = chdr->ch_size;
+
+ return 1;
+}
+
+/* This function is a hook for testing the zlib support. It is only
+ used by tests. */
+
+int
+backtrace_uncompress_zdebug (struct backtrace_state *state,
+ const unsigned char *compressed,
+ size_t compressed_size,
+ backtrace_error_callback error_callback,
+ void *data, unsigned char **uncompressed,
+ size_t *uncompressed_size)
+{
+ uint16_t *zdebug_table;
+ int ret;
+
+ zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ return 0;
+ ret = elf_uncompress_zdebug (state, compressed, compressed_size,
+ zdebug_table, error_callback, data,
+ uncompressed, uncompressed_size);
+ backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+ error_callback, data);
+ return ret;
+}
+
/* Add the backtrace data for one ELF file. Returns 1 on success,
0 on failure (in both cases descriptor is closed) or -1 if exe
is non-zero and the ELF file is ET_DYN, which tells the caller that
@@ -517,9 +2615,11 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
base_address is determined. */
static int
-elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
- backtrace_error_callback error_callback, void *data,
- fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
+elf_add (struct backtrace_state *state, const char *filename, int descriptor,
+ uintptr_t base_address, backtrace_error_callback error_callback,
+ void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf,
+ struct dwarf_data **fileline_entry, int exe, int debuginfo,
+ const char *with_buildid_data, uint32_t with_buildid_size)
{
struct backtrace_view ehdr_view;
b_elf_ehdr ehdr;
@@ -539,23 +2639,55 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
unsigned int dynsym_shndx;
unsigned int i;
struct debug_section_info sections[DEBUG_MAX];
+ struct debug_section_info zsections[DEBUG_MAX];
struct backtrace_view symtab_view;
int symtab_view_valid;
struct backtrace_view strtab_view;
int strtab_view_valid;
+ struct backtrace_view buildid_view;
+ int buildid_view_valid;
+ const char *buildid_data;
+ uint32_t buildid_size;
+ struct backtrace_view debuglink_view;
+ int debuglink_view_valid;
+ const char *debuglink_name;
+ uint32_t debuglink_crc;
+ struct backtrace_view debugaltlink_view;
+ int debugaltlink_view_valid;
+ const char *debugaltlink_name;
+ const char *debugaltlink_buildid_data;
+ uint32_t debugaltlink_buildid_size;
off_t min_offset;
off_t max_offset;
struct backtrace_view debug_view;
int debug_view_valid;
+ unsigned int using_debug_view;
+ uint16_t *zdebug_table;
+ struct elf_ppc64_opd_data opd_data, *opd;
+ struct dwarf_sections dwarf_sections;
- *found_sym = 0;
- *found_dwarf = 0;
+ if (!debuginfo)
+ {
+ *found_sym = 0;
+ *found_dwarf = 0;
+ }
shdrs_view_valid = 0;
names_view_valid = 0;
symtab_view_valid = 0;
strtab_view_valid = 0;
+ buildid_view_valid = 0;
+ buildid_data = NULL;
+ buildid_size = 0;
+ debuglink_view_valid = 0;
+ debuglink_name = NULL;
+ debuglink_crc = 0;
+ debugaltlink_view_valid = 0;
+ debugaltlink_name = NULL;
+ debugaltlink_buildid_data = NULL;
+ debugaltlink_buildid_size = 0;
debug_view_valid = 0;
+ opd = NULL;
if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
data, &ehdr_view))
@@ -663,7 +2795,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
shstr_size = shstrhdr->sh_size;
shstr_off = shstrhdr->sh_offset;
- if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size,
+ if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size,
error_callback, data, &names_view))
goto fail;
names_view_valid = 1;
@@ -673,6 +2805,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
dynsym_shndx = 0;
memset (sections, 0, sizeof sections);
+ memset (zsections, 0, sizeof zsections);
/* Look for the symbol table. */
for (i = 1; i < shnum; ++i)
@@ -700,18 +2833,134 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
for (j = 0; j < (int) DEBUG_MAX; ++j)
{
- if (strcmp (name, debug_section_names[j]) == 0)
+ if (strcmp (name, dwarf_section_names[j]) == 0)
{
sections[j].offset = shdr->sh_offset;
sections[j].size = shdr->sh_size;
+ sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0;
break;
}
}
+
+ if (name[0] == '.' && name[1] == 'z')
+ {
+ for (j = 0; j < (int) DEBUG_MAX; ++j)
+ {
+ if (strcmp (name + 2, dwarf_section_names[j] + 1) == 0)
+ {
+ zsections[j].offset = shdr->sh_offset;
+ zsections[j].size = shdr->sh_size;
+ break;
+ }
+ }
+ }
+
+ /* Read the build ID if present. This could check for any
+ SHT_NOTE section with the right note name and type, but gdb
+ looks for a specific section name. */
+ if ((!debuginfo || with_buildid_data != NULL)
+ && !buildid_view_valid
+ && strcmp (name, ".note.gnu.build-id") == 0)
+ {
+ const b_elf_note *note;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &buildid_view))
+ goto fail;
+
+ buildid_view_valid = 1;
+ note = (const b_elf_note *) buildid_view.data;
+ if (note->type == NT_GNU_BUILD_ID
+ && note->namesz == 4
+ && strncmp (note->name, "GNU", 4) == 0
+ && shdr->sh_size <= 12 + ((note->namesz + 3) & ~ 3) + note->descsz)
+ {
+ buildid_data = &note->name[0] + ((note->namesz + 3) & ~ 3);
+ buildid_size = note->descsz;
+ }
+
+ if (with_buildid_size != 0)
+ {
+ if (buildid_size != with_buildid_size)
+ goto fail;
+
+ if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0)
+ goto fail;
+ }
+ }
+
+ /* Read the debuglink file if present. */
+ if (!debuginfo
+ && !debuglink_view_valid
+ && strcmp (name, ".gnu_debuglink") == 0)
+ {
+ const char *debuglink_data;
+ size_t crc_offset;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &debuglink_view))
+ goto fail;
+
+ debuglink_view_valid = 1;
+ debuglink_data = (const char *) debuglink_view.data;
+ crc_offset = strnlen (debuglink_data, shdr->sh_size);
+ crc_offset = (crc_offset + 3) & ~3;
+ if (crc_offset + 4 <= shdr->sh_size)
+ {
+ debuglink_name = debuglink_data;
+ debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset);
+ }
+ }
+
+ if (!debugaltlink_view_valid
+ && strcmp (name, ".gnu_debugaltlink") == 0)
+ {
+ const char *debugaltlink_data;
+ size_t debugaltlink_name_len;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &debugaltlink_view))
+ goto fail;
+
+ debugaltlink_view_valid = 1;
+ debugaltlink_data = (const char *) debugaltlink_view.data;
+ debugaltlink_name = debugaltlink_data;
+ debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size);
+ if (debugaltlink_name_len < shdr->sh_size)
+ {
+ /* Include terminating zero. */
+ debugaltlink_name_len += 1;
+
+ debugaltlink_buildid_data
+ = debugaltlink_data + debugaltlink_name_len;
+ debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len;
+ }
+ }
+
+ /* Read the .opd section on PowerPC64 ELFv1. */
+ if (ehdr.e_machine == EM_PPC64
+ && (ehdr.e_flags & EF_PPC64_ABI) < 2
+ && shdr->sh_type == SHT_PROGBITS
+ && strcmp (name, ".opd") == 0)
+ {
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &opd_data.view))
+ goto fail;
+
+ opd = &opd_data;
+ opd->addr = shdr->sh_addr;
+ opd->data = (const char *) opd_data.view.data;
+ opd->size = shdr->sh_size;
+ }
}
if (symtab_shndx == 0)
symtab_shndx = dynsym_shndx;
- if (symtab_shndx != 0)
+ if (symtab_shndx != 0 && !debuginfo)
{
const b_elf_shdr *symtab_shdr;
unsigned int strtab_shndx;
@@ -748,7 +2997,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
if (!elf_initialize_syminfo (state, base_address,
symtab_view.data, symtab_shdr->sh_size,
strtab_view.data, strtab_shdr->sh_size,
- error_callback, data, sdata))
+ error_callback, data, sdata, opd))
{
backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
goto fail;
@@ -757,21 +3006,128 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
/* We no longer need the symbol table, but we hold on to the
string table permanently. */
backtrace_release_view (state, &symtab_view, error_callback, data);
+ symtab_view_valid = 0;
*found_sym = 1;
elf_add_syminfo_data (state, sdata);
}
- /* FIXME: Need to handle compressed debug sections. */
-
backtrace_release_view (state, &shdrs_view, error_callback, data);
shdrs_view_valid = 0;
backtrace_release_view (state, &names_view, error_callback, data);
names_view_valid = 0;
+ /* If the debug info is in a separate file, read that one instead. */
+
+ if (buildid_data != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size,
+ error_callback, data);
+ if (d >= 0)
+ {
+ int ret;
+
+ backtrace_release_view (state, &buildid_view, error_callback, data);
+ if (debuglink_view_valid)
+ backtrace_release_view (state, &debuglink_view, error_callback,
+ data);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
+ ret = elf_add (state, "", d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
+ 0);
+ if (ret < 0)
+ backtrace_close (d, error_callback, data);
+ else
+ backtrace_close (descriptor, error_callback, data);
+ return ret;
+ }
+ }
+
+ if (buildid_view_valid)
+ {
+ backtrace_release_view (state, &buildid_view, error_callback, data);
+ buildid_view_valid = 0;
+ }
+
+ if (opd)
+ {
+ backtrace_release_view (state, &opd->view, error_callback, data);
+ opd = NULL;
+ }
+
+ if (debuglink_name != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name,
+ debuglink_crc, error_callback,
+ data);
+ if (d >= 0)
+ {
+ int ret;
+
+ backtrace_release_view (state, &debuglink_view, error_callback,
+ data);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
+ ret = elf_add (state, "", d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
+ 0);
+ if (ret < 0)
+ backtrace_close (d, error_callback, data);
+ else
+ backtrace_close(descriptor, error_callback, data);
+ return ret;
+ }
+ }
+
+ if (debuglink_view_valid)
+ {
+ backtrace_release_view (state, &debuglink_view, error_callback, data);
+ debuglink_view_valid = 0;
+ }
+
+ struct dwarf_data *fileline_altlink = NULL;
+ if (debugaltlink_name != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_debuglink (state, filename, debugaltlink_name,
+ 0, error_callback, data);
+ if (d >= 0)
+ {
+ int ret;
+
+ ret = elf_add (state, filename, d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, &fileline_altlink,
+ 0, 1, debugaltlink_buildid_data,
+ debugaltlink_buildid_size);
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
+ debugaltlink_view_valid = 0;
+ if (ret < 0)
+ {
+ backtrace_close (d, error_callback, data);
+ return ret;
+ }
+ }
+ }
+
+ if (debugaltlink_view_valid)
+ {
+ backtrace_release_view (state, &debugaltlink_view, error_callback, data);
+ debugaltlink_view_valid = 0;
+ }
+
/* Read all the debug sections in a single view, since they are
- probably adjacent in the file. We never release this view. */
+ probably adjacent in the file. If any of sections are
+ uncompressed, we never release this view. */
min_offset = 0;
max_offset = 0;
@@ -779,13 +3135,22 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
{
off_t end;
- if (sections[i].size == 0)
- continue;
- if (min_offset == 0 || sections[i].offset < min_offset)
- min_offset = sections[i].offset;
- end = sections[i].offset + sections[i].size;
- if (end > max_offset)
- max_offset = end;
+ if (sections[i].size != 0)
+ {
+ if (min_offset == 0 || sections[i].offset < min_offset)
+ min_offset = sections[i].offset;
+ end = sections[i].offset + sections[i].size;
+ if (end > max_offset)
+ max_offset = end;
+ }
+ if (zsections[i].size != 0)
+ {
+ if (min_offset == 0 || zsections[i].offset < min_offset)
+ min_offset = zsections[i].offset;
+ end = zsections[i].offset + zsections[i].size;
+ if (end > max_offset)
+ max_offset = end;
+ }
}
if (min_offset == 0 || max_offset == 0)
{
@@ -805,28 +3170,110 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
goto fail;
descriptor = -1;
+ using_debug_view = 0;
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
if (sections[i].size == 0)
sections[i].data = NULL;
else
- sections[i].data = ((const unsigned char *) debug_view.data
- + (sections[i].offset - min_offset));
- }
-
- if (!backtrace_dwarf_add (state, base_address,
- sections[DEBUG_INFO].data,
- sections[DEBUG_INFO].size,
- sections[DEBUG_LINE].data,
- sections[DEBUG_LINE].size,
- sections[DEBUG_ABBREV].data,
- sections[DEBUG_ABBREV].size,
- sections[DEBUG_RANGES].data,
- sections[DEBUG_RANGES].size,
- sections[DEBUG_STR].data,
- sections[DEBUG_STR].size,
+ {
+ sections[i].data = ((const unsigned char *) debug_view.data
+ + (sections[i].offset - min_offset));
+ ++using_debug_view;
+ }
+
+ if (zsections[i].size == 0)
+ zsections[i].data = NULL;
+ else
+ zsections[i].data = ((const unsigned char *) debug_view.data
+ + (zsections[i].offset - min_offset));
+ }
+
+ /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */
+
+ zdebug_table = NULL;
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
+ {
+ if (sections[i].size == 0 && zsections[i].size > 0)
+ {
+ unsigned char *uncompressed_data;
+ size_t uncompressed_size;
+
+ if (zdebug_table == NULL)
+ {
+ zdebug_table = ((uint16_t *)
+ backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ goto fail;
+ }
+
+ uncompressed_data = NULL;
+ uncompressed_size = 0;
+ if (!elf_uncompress_zdebug (state, zsections[i].data,
+ zsections[i].size, zdebug_table,
+ error_callback, data,
+ &uncompressed_data, &uncompressed_size))
+ goto fail;
+ sections[i].data = uncompressed_data;
+ sections[i].size = uncompressed_size;
+ sections[i].compressed = 0;
+ }
+ }
+
+ /* Uncompress the official ELF format
+ (--compress-debug-sections=zlib-gabi). */
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
+ {
+ unsigned char *uncompressed_data;
+ size_t uncompressed_size;
+
+ if (sections[i].size == 0 || !sections[i].compressed)
+ continue;
+
+ if (zdebug_table == NULL)
+ {
+ zdebug_table = ((uint16_t *)
+ backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ goto fail;
+ }
+
+ uncompressed_data = NULL;
+ uncompressed_size = 0;
+ if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size,
+ zdebug_table, error_callback, data,
+ &uncompressed_data, &uncompressed_size))
+ goto fail;
+ sections[i].data = uncompressed_data;
+ sections[i].size = uncompressed_size;
+ sections[i].compressed = 0;
+
+ --using_debug_view;
+ }
+
+ if (zdebug_table != NULL)
+ backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+ error_callback, data);
+
+ if (debug_view_valid && using_debug_view == 0)
+ {
+ backtrace_release_view (state, &debug_view, error_callback, data);
+ debug_view_valid = 0;
+ }
+
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
+ {
+ dwarf_sections.data[i] = sections[i].data;
+ dwarf_sections.size[i] = sections[i].size;
+ }
+
+ if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
- error_callback, data, fileline_fn))
+ fileline_altlink,
+ error_callback, data, fileline_fn,
+ fileline_entry))
goto fail;
*found_dwarf = 1;
@@ -842,8 +3289,16 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
backtrace_release_view (state, &symtab_view, error_callback, data);
if (strtab_view_valid)
backtrace_release_view (state, &strtab_view, error_callback, data);
+ if (debuglink_view_valid)
+ backtrace_release_view (state, &debuglink_view, error_callback, data);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback, data);
+ if (buildid_view_valid)
+ backtrace_release_view (state, &buildid_view, error_callback, data);
if (debug_view_valid)
backtrace_release_view (state, &debug_view, error_callback, data);
+ if (opd)
+ backtrace_release_view (state, &opd->view, error_callback, data);
if (descriptor != -1)
backtrace_close (descriptor, error_callback, data);
return 0;
@@ -859,6 +3314,7 @@ struct phdr_data
fileline *fileline_fn;
int *found_sym;
int *found_dwarf;
+ const char *exe_filename;
int exe_descriptor;
};
@@ -873,6 +3329,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
void *pdata)
{
struct phdr_data *pd = (struct phdr_data *) pdata;
+ const char *filename;
int descriptor;
int does_not_exist;
fileline elf_fileline_fn;
@@ -885,6 +3342,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
{
if (pd->exe_descriptor == -1)
return 0;
+ filename = pd->exe_filename;
descriptor = pd->exe_descriptor;
pd->exe_descriptor = -1;
}
@@ -896,14 +3354,16 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
pd->exe_descriptor = -1;
}
+ filename = info->dlpi_name;
descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
pd->data, &does_not_exist);
if (descriptor < 0)
return 0;
}
- if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
- pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
+ if (elf_add (pd->state, filename, descriptor, info->dlpi_addr,
+ pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
+ &found_dwarf, NULL, 0, 0, NULL, 0))
{
if (found_dwarf)
{
@@ -920,8 +3380,8 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
sections. */
int
-backtrace_initialize (struct backtrace_state *state, int descriptor,
- backtrace_error_callback error_callback,
+backtrace_initialize (struct backtrace_state *state, const char *filename,
+ int descriptor, backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
int ret;
@@ -930,8 +3390,9 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
fileline elf_fileline_fn = elf_nodebug;
struct phdr_data pd;
- ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
- &found_sym, &found_dwarf, 1);
+ ret = elf_add (state, filename, descriptor, 0, error_callback, data,
+ &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL,
+ 0);
if (!ret)
return 0;
@@ -941,6 +3402,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
pd.fileline_fn = &elf_fileline_fn;
pd.found_sym = &found_sym;
pd.found_dwarf = &found_dwarf;
+ pd.exe_filename = filename;
pd.exe_descriptor = ret < 0 ? descriptor : -1;
dl_iterate_phdr (phdr_callback, (void *) &pd);
@@ -962,18 +3424,12 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
}
if (!state->threaded)
- {
- if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
- *fileline_fn = elf_fileline_fn;
- }
+ *fileline_fn = state->fileline_fn;
else
- {
- fileline current_fn;
+ *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
- current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
- if (current_fn == NULL || current_fn == elf_nodebug)
- *fileline_fn = elf_fileline_fn;
- }
+ if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)
+ *fileline_fn = elf_fileline_fn;
return 1;
}
diff --git a/3rdparty/libbacktrace/libbacktrace/fileline.c b/3rdparty/libbacktrace/libbacktrace/fileline.c
index 27ebbedc..369c9dee 100644
--- a/3rdparty/libbacktrace/libbacktrace/fileline.c
+++ b/3rdparty/libbacktrace/libbacktrace/fileline.c
@@ -1,5 +1,5 @@
/* fileline.c -- Get file and line number information in a backtrace.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
+#include <unistd.h>
#include "backtrace.h"
#include "internal.h"
@@ -57,6 +58,8 @@ fileline_initialize (struct backtrace_state *state,
int pass;
int called_error_callback;
int descriptor;
+ const char *filename;
+ char buf[64];
if (!state->threaded)
failed = state->fileline_initialization_failed;
@@ -80,9 +83,8 @@ fileline_initialize (struct backtrace_state *state,
descriptor = -1;
called_error_callback = 0;
- for (pass = 0; pass < 4; ++pass)
+ for (pass = 0; pass < 5; ++pass)
{
- const char *filename;
int does_not_exist;
switch (pass)
@@ -99,6 +101,11 @@ fileline_initialize (struct backtrace_state *state,
case 3:
filename = "/proc/curproc/file";
break;
+ case 4:
+ snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
+ (long) getpid ());
+ filename = buf;
+ break;
default:
abort ();
}
@@ -133,8 +140,8 @@ fileline_initialize (struct backtrace_state *state,
if (!failed)
{
- if (!backtrace_initialize (state, descriptor, error_callback, data,
- &fileline_fn))
+ if (!backtrace_initialize (state, filename, descriptor, error_callback,
+ data, &fileline_fn))
failed = 1;
}
diff --git a/3rdparty/libbacktrace/libbacktrace/internal.h b/3rdparty/libbacktrace/libbacktrace/internal.h
index 73728da3..a9c66882 100644
--- a/3rdparty/libbacktrace/libbacktrace/internal.h
+++ b/3rdparty/libbacktrace/libbacktrace/internal.h
@@ -1,5 +1,5 @@
/* internal.h -- Internal header file for stack backtrace library.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -179,7 +179,7 @@ struct backtrace_view
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the
result in *VIEW. Returns 1 on success, 0 on error. */
extern int backtrace_get_view (struct backtrace_state *state, int descriptor,
- off_t offset, size_t size,
+ off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view);
@@ -257,6 +257,18 @@ extern int backtrace_vector_release (struct backtrace_state *state,
backtrace_error_callback error_callback,
void *data);
+/* Free the space managed by VEC. This will reset VEC. */
+
+static inline void
+backtrace_vector_free (struct backtrace_state *state,
+ struct backtrace_vector *vec,
+ backtrace_error_callback error_callback, void *data)
+{
+ vec->alc += vec->size;
+ vec->size = 0;
+ backtrace_vector_release (state, vec, error_callback, data);
+}
+
/* Read initial debug data from a descriptor, and set the
fileline_data, syminfo_fn, and syminfo_data fields of STATE.
Return the fileln_fn field in *FILELN_FN--this is done this way so
@@ -268,27 +280,59 @@ extern int backtrace_vector_release (struct backtrace_state *state,
appropriate one. */
extern int backtrace_initialize (struct backtrace_state *state,
+ const char *filename,
int descriptor,
backtrace_error_callback error_callback,
void *data,
fileline *fileline_fn);
+/* An enum for the DWARF sections we care about. */
+
+enum dwarf_section
+{
+ DEBUG_INFO,
+ DEBUG_LINE,
+ DEBUG_ABBREV,
+ DEBUG_RANGES,
+ DEBUG_STR,
+ DEBUG_ADDR,
+ DEBUG_STR_OFFSETS,
+ DEBUG_LINE_STR,
+ DEBUG_RNGLISTS,
+
+ DEBUG_MAX
+};
+
+/* Data for the DWARF sections we care about. */
+
+struct dwarf_sections
+{
+ const unsigned char *data[DEBUG_MAX];
+ size_t size[DEBUG_MAX];
+};
+
+/* DWARF data read from a file, used for .gnu_debugaltlink. */
+
+struct dwarf_data;
+
/* Add file/line information for a DWARF module. */
extern int backtrace_dwarf_add (struct backtrace_state *state,
uintptr_t base_address,
- const unsigned char* dwarf_info,
- size_t dwarf_info_size,
- const unsigned char *dwarf_line,
- size_t dwarf_line_size,
- const unsigned char *dwarf_abbrev,
- size_t dwarf_abbrev_size,
- const unsigned char *dwarf_ranges,
- size_t dwarf_range_size,
- const unsigned char *dwarf_str,
- size_t dwarf_str_size,
+ const struct dwarf_sections *dwarf_sections,
int is_bigendian,
+ struct dwarf_data *fileline_altlink,
backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn);
+ void *data, fileline *fileline_fn,
+ struct dwarf_data **fileline_entry);
+
+/* A test-only hook for elf_uncompress_zdebug. */
+
+extern int backtrace_uncompress_zdebug (struct backtrace_state *,
+ const unsigned char *compressed,
+ size_t compressed_size,
+ backtrace_error_callback, void *data,
+ unsigned char **uncompressed,
+ size_t *uncompressed_size);
#endif
diff --git a/3rdparty/libbacktrace/libbacktrace/mmap.c b/3rdparty/libbacktrace/libbacktrace/mmap.c
index 138ef707..1b636649 100644
--- a/3rdparty/libbacktrace/libbacktrace/mmap.c
+++ b/3rdparty/libbacktrace/libbacktrace/mmap.c
@@ -1,5 +1,5 @@
/* mmap.c -- Memory allocation with mmap.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -69,11 +69,33 @@ struct backtrace_freelist_struct
static void
backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size)
{
- /* Just leak small blocks. We don't have to be perfect. */
+ /* Just leak small blocks. We don't have to be perfect. Don't put
+ more than 16 entries on the free list, to avoid wasting time
+ searching when allocating a block. If we have more than 16
+ entries, leak the smallest entry. */
+
if (size >= sizeof (struct backtrace_freelist_struct))
{
+ size_t c;
+ struct backtrace_freelist_struct **ppsmall;
+ struct backtrace_freelist_struct **pp;
struct backtrace_freelist_struct *p;
+ c = 0;
+ ppsmall = NULL;
+ for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next)
+ {
+ if (ppsmall == NULL || (*pp)->size < (*ppsmall)->size)
+ ppsmall = pp;
+ ++c;
+ }
+ if (c >= 16)
+ {
+ if (size <= (*ppsmall)->size)
+ return;
+ *ppsmall = (*ppsmall)->next;
+ }
+
p = (struct backtrace_freelist_struct *) addr;
p->next = state->freelist;
p->size = size;
@@ -299,5 +321,7 @@ backtrace_vector_release (struct backtrace_state *state,
backtrace_free (state, (char *) vec->base + aligned, alc,
error_callback, data);
vec->alc = 0;
+ if (vec->size == 0)
+ vec->base = NULL;
return 1;
}
diff --git a/3rdparty/libbacktrace/libbacktrace/mmapio.c b/3rdparty/libbacktrace/libbacktrace/mmapio.c
index dfdaf6fa..b188a43a 100644
--- a/3rdparty/libbacktrace/libbacktrace/mmapio.c
+++ b/3rdparty/libbacktrace/libbacktrace/mmapio.c
@@ -1,5 +1,5 @@
/* mmapio.c -- File views using mmap.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -51,7 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. */
int
backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
- int descriptor, off_t offset, size_t size,
+ int descriptor, off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view)
{
@@ -60,6 +60,12 @@ backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
off_t pageoff;
void *map;
+ if ((uint64_t) (size_t) size != size)
+ {
+ error_callback (data, "file size too large", 0);
+ return 0;
+ }
+
pagesize = getpagesize ();
inpage = offset % pagesize;
pageoff = offset - inpage;
diff --git a/3rdparty/libbacktrace/libbacktrace/posix.c b/3rdparty/libbacktrace/libbacktrace/posix.c
index 09f5e95a..baffb85b 100644
--- a/3rdparty/libbacktrace/libbacktrace/posix.c
+++ b/3rdparty/libbacktrace/libbacktrace/posix.c
@@ -1,5 +1,5 @@
/* posix.c -- POSIX file I/O routines for the backtrace library.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
diff --git a/3rdparty/libbacktrace/libbacktrace/print.c b/3rdparty/libbacktrace/libbacktrace/print.c
index 74c8fcbe..0767face 100644
--- a/3rdparty/libbacktrace/libbacktrace/print.c
+++ b/3rdparty/libbacktrace/libbacktrace/print.c
@@ -1,5 +1,5 @@
/* print.c -- Print the current backtrace.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -80,7 +80,7 @@ error_callback (void *data, const char *msg, int errnum)
/* Print a backtrace. */
-void
+void __attribute__((noinline))
backtrace_print (struct backtrace_state *state, int skip, FILE *f)
{
struct print_data data;
diff --git a/3rdparty/libbacktrace/libbacktrace/simple.c b/3rdparty/libbacktrace/libbacktrace/simple.c
index 018773a7..11893639 100644
--- a/3rdparty/libbacktrace/libbacktrace/simple.c
+++ b/3rdparty/libbacktrace/libbacktrace/simple.c
@@ -1,5 +1,5 @@
/* simple.c -- The backtrace_simple function.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
@@ -90,7 +90,7 @@ simple_unwind (struct _Unwind_Context *context, void *vdata)
/* Get a simple stack backtrace. */
-int
+int __attribute__((noinline))
backtrace_simple (struct backtrace_state *state, int skip,
backtrace_simple_callback callback,
backtrace_error_callback error_callback, void *data)
diff --git a/3rdparty/libbacktrace/libbacktrace/sort.c b/3rdparty/libbacktrace/libbacktrace/sort.c
index 68a7df65..6fe5ba24 100644
--- a/3rdparty/libbacktrace/libbacktrace/sort.c
+++ b/3rdparty/libbacktrace/libbacktrace/sort.c
@@ -1,5 +1,5 @@
/* sort.c -- Sort without allocating memory
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
diff --git a/3rdparty/libbacktrace/libbacktrace/state.c b/3rdparty/libbacktrace/libbacktrace/state.c
index 93420d9c..6196c267 100644
--- a/3rdparty/libbacktrace/libbacktrace/state.c
+++ b/3rdparty/libbacktrace/libbacktrace/state.c
@@ -1,5 +1,5 @@
/* state.c -- Create the backtrace state.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.