From 2f2708a769dfe6ad98b445b89e616cd62f657380 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Thu, 5 May 2022 09:10:37 +0200 Subject: [PATCH] Add dwarf support The new gcc12 release does not support stabs any more. This was a good reason to add support for dwarf. The stabs code still works and is used if configure option --dwarf is not used. Tested on x86_64, i386, arm, arm64, riscv64 with dwarf-5. Some debuggers may not support dwarf-5. Try using older dwarf versions i that case. The tccmacho.c code probably need some support for dwarf. arm-gen.c, arm64-gen.c, i386-gen.c, riscv64-gen.c, x86_64-gen. - fix get_sym_ref symbol size arm-link.c, arm64-link.c, i386-link.c, riscv64-link.c, x86_64-link.c - add R_DATA_32U libtcc.c: - parse -gdwarf option tcc.c: - add dwarf option tcc.h: - add dwarf option and sections tccelf.c: - init dwarf sections - avoid adding sh_addr for dwarf sections - remove dwarf relocs for output dll - add dwarf sections for tccrun tccgen.c: - add dwarf defines + global data - add dwarf_* functions - mix dwarf code with stabs code - a trick is used to emit function name in .debug_line section so only this section has to be parsed instead of .debug_info and .debug_abbrev. - fix init debug_modes tccrun.c: - add dwarf sections in rt_context - init them in tcc_run - add new dwarf code rt_printline_dwarf to find file/function dwarf.h: - New file tcc-doc.texi: - document dwarf configure: - add dwarf option lib/Makefile - change -gstabs into -gdwarf lib/bt-exe.c, tests/tests2/Makefile, tests/tests2/126_bound_global: - Add __bound_init call - Add new testcase to test it --- .gitignore | 1 + arm-gen.c | 2 +- arm-link.c | 1 + arm64-gen.c | 2 +- arm64-link.c | 1 + c67-link.c | 1 + configure | 5 + dwarf.h | 1046 ++++++++++++++++++++ i386-gen.c | 2 +- i386-link.c | 1 + lib/Makefile | 2 +- lib/bt-exe.c | 4 + libtcc.c | 19 +- riscv64-gen.c | 2 +- riscv64-link.c | 1 + tcc-doc.texi | 7 +- tcc.c | 3 +- tcc.h | 14 + tccelf.c | 80 +- tccgen.c | 1316 +++++++++++++++++++++++--- tccrun.c | 363 ++++++- tests/tests2/126_bound_global.c | 13 + tests/tests2/126_bound_global.expect | 2 + tests/tests2/Makefile | 7 +- x86_64-gen.c | 2 +- x86_64-link.c | 1 + 26 files changed, 2754 insertions(+), 144 deletions(-) create mode 100644 dwarf.h create mode 100644 tests/tests2/126_bound_global.c create mode 100644 tests/tests2/126_bound_global.expect diff --git a/.gitignore b/.gitignore index 34804df4..d3e7928c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ config*.h config*.mak config.texi conftest* +c2str tags TAGS tcc.1 diff --git a/arm-gen.c b/arm-gen.c index 0d466d4f..e0d98d01 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -866,7 +866,7 @@ static void gen_bounds_epilog(void) *bounds_ptr = 0; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); + func_bound_offset, PTR_SIZE); /* generate bound local allocation */ if (offset_modified) { diff --git a/arm-link.c b/arm-link.c index 5d40f843..47f60c80 100644 --- a/arm-link.c +++ b/arm-link.c @@ -4,6 +4,7 @@ /* relocation type for 32 bit data relocation */ #define R_DATA_32 R_ARM_ABS32 +#define R_DATA_32U R_ARM_ABS32 #define R_DATA_PTR R_ARM_ABS32 #define R_JMP_SLOT R_ARM_JUMP_SLOT #define R_GLOB_DAT R_ARM_GLOB_DAT diff --git a/arm64-gen.c b/arm64-gen.c index 25b50fab..8232f2a9 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -710,7 +710,7 @@ static void gen_bounds_epilog(void) *bounds_ptr = 0; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); + func_bound_offset, PTR_SIZE); /* generate bound local allocation */ if (offset_modified) { diff --git a/arm64-link.c b/arm64-link.c index 99916693..2d1628ff 100644 --- a/arm64-link.c +++ b/arm64-link.c @@ -3,6 +3,7 @@ #define EM_TCC_TARGET EM_AARCH64 #define R_DATA_32 R_AARCH64_ABS32 +#define R_DATA_32U R_AARCH64_ABS32 #define R_DATA_PTR R_AARCH64_ABS64 #define R_JMP_SLOT R_AARCH64_JUMP_SLOT #define R_GLOB_DAT R_AARCH64_GLOB_DAT diff --git a/c67-link.c b/c67-link.c index 514689c5..ba017802 100644 --- a/c67-link.c +++ b/c67-link.c @@ -4,6 +4,7 @@ /* relocation type for 32 bit data relocation */ #define R_DATA_32 R_C60_32 +#define R_DATA_32U R_C60_32 #define R_DATA_PTR R_C60_32 #define R_JMP_SLOT R_C60_JMP_SLOT #define R_GLOB_DAT R_C60_GLOB_DAT diff --git a/configure b/configure index 4063ac72..4af3f433 100755 --- a/configure +++ b/configure @@ -51,6 +51,7 @@ ar_set= darwin= cpu= cpuver= +dwarf= # OS specific cpu_sys=`uname -m` @@ -136,6 +137,8 @@ for opt do ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2-` ;; + --dwarf=*) dwarf=`echo $opt | cut -d '=' -f 2-` + ;; --enable-cross) confvars="$confvars cross" ;; --disable-static) confvars="$confvars static=no" @@ -328,6 +331,7 @@ Advanced options (experts only): --config-backtrace=no disable stack backtraces (with -run or -bt) --config-bcheck=no disable bounds checker (-b) --config-predefs=no do not compile tccdefs.h, instead just include + --dwarf=x Use dwarf debug info instead of stabs (x=2..5) EOF exit 1 fi @@ -493,6 +497,7 @@ print_mak CONFIG_TCC_ELFINTERP "$tcc_elfinterp" print_mak CONFIG_LDDIR "$tcc_lddir" print_mak CONFIG_TRIPLET "$triplet" print_mak TCC_CPU_VERSION "$cpuver" num +print_mak CONFIG_DWARF "$dwarf" echo "ARCH=$cpu" >> config.mak echo "TARGETOS=$targetos" >> config.mak diff --git a/dwarf.h b/dwarf.h new file mode 100644 index 00000000..c961bc36 --- /dev/null +++ b/dwarf.h @@ -0,0 +1,1046 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000-2011, 2014, 2016, 2017, 2018 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see . */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF Unit Header Types. */ +enum + { + 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 + }; + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + /* 0x06 reserved. */ + /* 0x07 reserved. */ + DW_TAG_imported_declaration = 0x08, + /* 0x09 reserved. */ + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + /* 0x0c reserved. */ + DW_TAG_member = 0x0d, + /* 0x0e reserved. */ + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + /* 0x14 reserved. */ + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_parameter = 0x2f, + DW_TAG_template_value_parameter = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + /* 0x3e reserved. Was DW_TAG_mutable_type. */ + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + DW_TAG_template_alias = 0x43, + DW_TAG_coarray_type = 0x44, + DW_TAG_generic_subrange = 0x45, + DW_TAG_dynamic_type = 0x46, + DW_TAG_atomic_type = 0x47, + DW_TAG_call_site = 0x48, + DW_TAG_call_site_parameter = 0x49, + DW_TAG_skeleton_unit = 0x4a, + DW_TAG_immutable_type = 0x4b, + + DW_TAG_lo_user = 0x4080, + + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + + DW_TAG_GNU_template_template_param = 0x4106, + DW_TAG_GNU_template_parameter_pack = 0x4107, + DW_TAG_GNU_formal_parameter_pack = 0x4108, + DW_TAG_GNU_call_site = 0x4109, + DW_TAG_GNU_call_site_parameter = 0x410a, + + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + /* 0x04 reserved. */ + /* 0x05 reserved. */ + /* 0x06 reserved. */ + /* 0x07 reserved. */ + /* 0x08 reserved. */ + DW_AT_ordering = 0x09, + /* 0x0a reserved. */ + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, /* Deprecated in DWARF4. */ + DW_AT_bit_size = 0x0d, + /* 0x0e reserved. */ + /* 0x0f reserved. */ + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + /* 0x14 reserved. */ + 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, + /* 0x1f reserved. */ + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + /* 0x23 reserved. */ + /* 0x24 reserved. */ + DW_AT_producer = 0x25, + /* 0x26 reserved. */ + DW_AT_prototyped = 0x27, + /* 0x28 reserved. */ + /* 0x29 reserved. */ + DW_AT_return_addr = 0x2a, + /* 0x2b reserved. */ + DW_AT_start_scope = 0x2c, + /* 0x2d reserved. */ + DW_AT_bit_stride = 0x2e, + DW_AT_upper_bound = 0x2f, + /* 0x30 reserved. */ + 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, /* Deprecated in DWARF5. */ + DW_AT_namelist_item = 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, + /* 0x75 reserved. */ + 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_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_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + + /* GNU extensions. */ + 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_locviews = 0x2137, + DW_AT_GNU_entry_view = 0x2138, + DW_AT_GNU_macros = 0x2119, + DW_AT_GNU_deleted = 0x211a, + /* GNU Debug Fission extensions. */ + 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, + + /* https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator */ + DW_AT_GNU_numerator = 0x2303, + DW_AT_GNU_denominator = 0x2304, + /* https://gcc.gnu.org/wiki/DW_AT_GNU_bias */ + DW_AT_GNU_bias = 0x2305, + + DW_AT_hi_user = 0x3fff + }; + +/* Old unofficially attribute names. Should not be used. + Will not appear in known-dwarf.h */ + +/* DWARF1 array subscripts and element data types. */ +#define DW_AT_subscr_data 0x0a +/* DWARF1 enumeration literals. */ +#define DW_AT_element_list 0x0f +/* DWARF1 reference for variable to member structure, class or union. */ +#define DW_AT_member 0x14 + +/* DWARF form encodings. */ +enum + { + 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_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_ref_sig8 = 0x20, + 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, + + /* GNU Debug Fission extensions. */ + DW_FORM_GNU_addr_index = 0x1f01, + DW_FORM_GNU_str_index = 0x1f02, + + DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */ + DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */ + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 offset. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b,/* TLS offset to address in current thread */ + DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ + DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ + DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */ + DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */ + + DW_OP_implicit_pointer = 0xa0, + DW_OP_addrx = 0xa1, + DW_OP_constx = 0xa2, + DW_OP_entry_value = 0xa3, + DW_OP_const_type = 0xa4, + DW_OP_regval_type = 0xa5, + DW_OP_deref_type = 0xa6, + DW_OP_xderef_type = 0xa7, + DW_OP_convert = 0xa8, + DW_OP_reinterpret = 0xa9, + + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_GNU_encoded_addr = 0xf1, + DW_OP_GNU_implicit_pointer = 0xf2, + DW_OP_GNU_entry_value = 0xf3, + DW_OP_GNU_const_type = 0xf4, + DW_OP_GNU_regval_type = 0xf5, + DW_OP_GNU_deref_type = 0xf6, + DW_OP_GNU_convert = 0xf7, + DW_OP_GNU_reinterpret = 0xf9, + DW_OP_GNU_parameter_ref = 0xfa, + + /* GNU Debug Fission extensions. */ + DW_OP_GNU_addr_index = 0xfb, + DW_OP_GNU_const_index = 0xfc, + + DW_OP_GNU_variable_value = 0xfd, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + DW_ATE_imaginary_float = 0x9, + DW_ATE_packed_decimal = 0xa, + DW_ATE_numeric_string = 0xb, + DW_ATE_edited = 0xc, + DW_ATE_signed_fixed = 0xd, + DW_ATE_unsigned_fixed = 0xe, + DW_ATE_decimal_float = 0xf, + DW_ATE_UTF = 0x10, + DW_ATE_UCS = 0x11, + DW_ATE_ASCII = 0x12, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF decimal sign encodings. */ +enum + { + DW_DS_unsigned = 1, + DW_DS_leading_overpunch = 2, + DW_DS_trailing_overpunch = 3, + DW_DS_leading_separate = 4, + DW_DS_trailing_separate = 5, + }; + + +/* DWARF endianity encodings. */ +enum + { + DW_END_default = 0, + DW_END_big = 1, + DW_END_little = 2, + + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, /* ISO C:1989 */ + DW_LANG_C = 0x0002, /* C */ + DW_LANG_Ada83 = 0x0003, /* ISO Ada:1983 */ + DW_LANG_C_plus_plus = 0x0004, /* ISO C++:1998 */ + DW_LANG_Cobol74 = 0x0005, /* ISO Cobol:1974 */ + DW_LANG_Cobol85 = 0x0006, /* ISO Cobol:1985 */ + DW_LANG_Fortran77 = 0x0007, /* ISO FORTRAN 77 */ + DW_LANG_Fortran90 = 0x0008, /* ISO Fortran 90 */ + DW_LANG_Pascal83 = 0x0009, /* ISO Pascal:1983 */ + DW_LANG_Modula2 = 0x000a, /* ISO Modula-2:1996 */ + DW_LANG_Java = 0x000b, /* Java */ + DW_LANG_C99 = 0x000c, /* ISO C:1999 */ + DW_LANG_Ada95 = 0x000d, /* ISO Ada:1995 */ + DW_LANG_Fortran95 = 0x000e, /* ISO Fortran 95 */ + DW_LANG_PLI = 0x000f, /* ISO PL/1:1976 */ + DW_LANG_ObjC = 0x0010, /* Objective-C */ + DW_LANG_ObjC_plus_plus = 0x0011, /* Objective-C++ */ + DW_LANG_UPC = 0x0012, /* Unified Parallel C */ + DW_LANG_D = 0x0013, /* D */ + DW_LANG_Python = 0x0014, /* Python */ + DW_LANG_OpenCL = 0x0015, /* OpenCL */ + DW_LANG_Go = 0x0016, /* Go */ + DW_LANG_Modula3 = 0x0017, /* Modula-3 */ + DW_LANG_Haskell = 0x0018, /* Haskell */ + DW_LANG_C_plus_plus_03 = 0x0019, /* ISO C++:2003 */ + DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */ + DW_LANG_OCaml = 0x001b, /* OCaml */ + DW_LANG_Rust = 0x001c, /* Rust */ + DW_LANG_C11 = 0x001d, /* ISO C:2011 */ + DW_LANG_Swift = 0x001e, /* Swift */ + DW_LANG_Julia = 0x001f, /* Julia */ + DW_LANG_Dylan = 0x0020, /* Dylan */ + DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */ + DW_LANG_Fortran03 = 0x0022, /* ISO/IEC 1539-1:2004 */ + DW_LANG_Fortran08 = 0x0023, /* ISO/IEC 1539-1:2010 */ + DW_LANG_RenderScript = 0x0024, /* RenderScript Kernal Language */ + DW_LANG_BLISS = 0x0025, /* BLISS */ + + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, /* Assembler */ + DW_LANG_hi_user = 0xffff + }; + +/* Old (typo) '1' != 'I'. */ +#define DW_LANG_PL1 DW_LANG_PLI + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. + Used as values of DW_AT_calling_convention for subroutines + (normal, program or nocall) or structures, unions and class types + (normal, reference or value). */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_pass_by_reference = 0x4, + DW_CC_pass_by_value = 0x5, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* DWARF defaulted member function encodings. */ +enum + { + DW_DEFAULTED_no = 0, + DW_DEFAULTED_in_class = 1, + DW_DEFAULTED_out_of_class = 2 + }; + +/* DWARF line content descriptions. */ +enum + { + 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 + }; + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + + +/* DWARF extended opcode encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + DW_LNE_set_discriminator = 4, + + DW_LNE_lo_user = 128, + + DW_LNE_NVIDIA_inlined_call = 144, + DW_LNE_NVIDIA_set_function_name = 145, + + DW_LNE_hi_user = 255 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF debug_macro type encodings. */ +enum + { + DW_MACRO_define = 0x01, + DW_MACRO_undef = 0x02, + DW_MACRO_start_file = 0x03, + DW_MACRO_end_file = 0x04, + DW_MACRO_define_strp = 0x05, + DW_MACRO_undef_strp = 0x06, + DW_MACRO_import = 0x07, + DW_MACRO_define_sup = 0x08, + DW_MACRO_undef_sup = 0x09, + DW_MACRO_import_sup = 0x0a, + DW_MACRO_define_strx = 0x0b, + DW_MACRO_undef_strx = 0x0c, + DW_MACRO_lo_user = 0xe0, + DW_MACRO_hi_user = 0xff + }; + +/* Old GNU extension names for DWARF5 debug_macro type encodings. + There are no equivalents for the supplementary object file (sup) + and indirect string references (strx). */ +#define DW_MACRO_GNU_define DW_MACRO_define +#define DW_MACRO_GNU_undef DW_MACRO_undef +#define DW_MACRO_GNU_start_file DW_MACRO_start_file +#define DW_MACRO_GNU_end_file DW_MACRO_end_file +#define DW_MACRO_GNU_define_indirect DW_MACRO_define_strp +#define DW_MACRO_GNU_undef_indirect DW_MACRO_undef_strp +#define DW_MACRO_GNU_transparent_include DW_MACRO_import +#define DW_MACRO_GNU_lo_user DW_MACRO_lo_user +#define DW_MACRO_GNU_hi_user DW_MACRO_hi_user + + +/* Range list entry encoding. */ +enum + { + DW_RLE_end_of_list = 0x0, + DW_RLE_base_addressx = 0x1, + DW_RLE_startx_endx = 0x2, + DW_RLE_startx_length = 0x3, + DW_RLE_offset_pair = 0x4, + DW_RLE_base_address = 0x5, + DW_RLE_start_end = 0x6, + DW_RLE_start_length = 0x7 + }; + + +/* Location list entry encoding. */ +enum + { + DW_LLE_end_of_list = 0x0, + DW_LLE_base_addressx = 0x1, + DW_LLE_startx_endx = 0x2, + DW_LLE_startx_length = 0x3, + DW_LLE_offset_pair = 0x4, + DW_LLE_default_location = 0x5, + DW_LLE_base_address = 0x6, + DW_LLE_start_end = 0x7, + DW_LLE_start_length = 0x8 + }; + + +/* GNU DebugFission list entry encodings (.debug_loc.dwo). */ +enum + { + DW_LLE_GNU_end_of_list_entry = 0x0, + DW_LLE_GNU_base_address_selection_entry = 0x1, + DW_LLE_GNU_start_end_entry = 0x2, + DW_LLE_GNU_start_length_entry = 0x3 + }; + +/* DWARF5 package file section identifiers. */ +enum + { + DW_SECT_INFO = 1, + /* Reserved = 2, */ + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOCLISTS = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8, + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_AARCH64_negate_ra_state = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_high_user = 0x3f + }; + +/* ID indicating CIE as opposed to FDE in .debug_frame. */ +enum + { + DW_CIE_ID_32 = 0xffffffffU, /* In 32-bit format CIE header. */ + DW_CIE_ID_64 = 0xffffffffffffffffULL /* In 64-bit format CIE header. */ + }; + + +/* Information for GNU unwind information. */ +enum + { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_omit = 0xff, + + /* FDE data encoding. */ + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0a, + DW_EH_PE_sdata4 = 0x0b, + DW_EH_PE_sdata8 = 0x0c, + DW_EH_PE_signed = 0x08, + + /* FDE flags. */ + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80 + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +/* Section 7.2.2 of the DWARF3 specification defines a range of escape + codes that can appear in the length field of certain DWARF structures. + + These defines enumerate the minimum and maximum values of this range. + Currently only the maximum value is used (to indicate that 64-bit + values are going to be used in the dwarf data that accompanies the + structure). The other values are reserved. + + Note: There is a typo in DWARF3 spec (published Dec 20, 2005). In + sections 7.4, 7.5.1, 7.19, 7.20 the minimum escape code is referred to + as 0xffffff00 whereas in fact it should be 0xfffffff0. */ +#define DWARF3_LENGTH_MIN_ESCAPE_CODE 0xfffffff0u +#define DWARF3_LENGTH_MAX_ESCAPE_CODE 0xffffffffu +#define DWARF3_LENGTH_64_BIT DWARF3_LENGTH_MAX_ESCAPE_CODE + +#endif /* dwarf.h */ diff --git a/i386-gen.c b/i386-gen.c index 8c245ada..62bc2ad5 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -1071,7 +1071,7 @@ static void gen_bounds_epilog(void) *bounds_ptr = 0; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); + func_bound_offset, PTR_SIZE); /* generate bound local allocation */ if (offset_modified) { diff --git a/i386-link.c b/i386-link.c index a7969f07..72a0884b 100644 --- a/i386-link.c +++ b/i386-link.c @@ -4,6 +4,7 @@ /* relocation type for 32 bit data relocation */ #define R_DATA_32 R_386_32 +#define R_DATA_32U R_386_32 #define R_DATA_PTR R_386_32 #define R_JMP_SLOT R_386_JMP_SLOT #define R_GLOB_DAT R_386_GLOB_DAT diff --git a/lib/Makefile b/lib/Makefile index 43942fc6..74722b61 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,7 +27,7 @@ arm-libtcc1-usegcc ?= no ifeq "$($(T)-libtcc1-usegcc)" "yes" XCC = $(CC) XAR = $(AR) - XFLAGS = $(CFLAGS) -fPIC -gstabs -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable + XFLAGS = $(CFLAGS) -fPIC -gdwarf -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable endif ifneq ($(CONFIG_backtrace),no) diff --git a/lib/bt-exe.c b/lib/bt-exe.c index f0e494d4..3f9cc929 100644 --- a/lib/bt-exe.c +++ b/lib/bt-exe.c @@ -18,6 +18,10 @@ void __bt_init(rt_context *p, int num_callers) __attribute__((weak)) void __bound_init(void*, int); struct rt_context *rc = &g_rtctxt; //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr); + /* call __bound_init here due to redirection of sigaction */ + /* needed to add global symbols */ + if (__bound_init && p->bounds_start) + __bound_init(p->bounds_start, -1); if (num_callers) { memcpy(rc, p, offsetof(rt_context, next)); rc->num_callers = num_callers - 1; diff --git a/libtcc.c b/libtcc.c index 1feb7410..e7335922 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1722,6 +1722,12 @@ static void args_parser_listfile(TCCState *s, *pargc = s->argc = argc, *pargv = s->argv = argv; } +#ifdef CONFIG_DWARF +#define DWARF_VERSION atoi(CONFIG_DWARF) +#else +#define DWARF_VERSION 0 +#endif + PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind) { TCCState *s1 = s; @@ -1819,6 +1825,7 @@ reparse: s->rt_num_callers = atoi(optarg); s->do_backtrace = 1; s->do_debug = 1; + s->dwarf = DWARF_VERSION; break; #endif #ifdef CONFIG_TCC_BCHECK @@ -1826,16 +1833,22 @@ reparse: s->do_bounds_check = 1; s->do_backtrace = 1; s->do_debug = 1; + s->dwarf = DWARF_VERSION; break; #endif case TCC_OPTION_g: /* Use "-g" as alias for "-g1". Use "-g0" to disable debug */ /* Other common used values: "-g0", "-g1", "-g2" and "-g3" */ /* no failure with unsupported options */ - if (isnum(*optarg)) + s->do_debug = 1; + s->dwarf = DWARF_VERSION; + if (*optarg == 'd') { + s->dwarf = 5; + if (!strncmp(optarg,"dwarf-",6)) + s->dwarf = atoi(optarg + 6); + } + else if (isnum(*optarg)) s->do_debug = atoi(optarg); - else - s->do_debug = 1; break; case TCC_OPTION_c: x = TCC_OUTPUT_OBJ; diff --git a/riscv64-gen.c b/riscv64-gen.c index 9a521d5a..b728d59e 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -471,7 +471,7 @@ static void gen_bounds_epilog(void) *bounds_ptr = 0; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); + func_bound_offset, PTR_SIZE); label.type.t = VT_VOID | VT_STATIC; /* generate bound local allocation */ diff --git a/riscv64-link.c b/riscv64-link.c index 2aeefefb..cf00c67d 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -3,6 +3,7 @@ #define EM_TCC_TARGET EM_RISCV #define R_DATA_32 R_RISCV_32 +#define R_DATA_32U R_RISCV_32 #define R_DATA_PTR R_RISCV_64 #define R_JMP_SLOT R_RISCV_JUMP_SLOT #define R_GLOB_DAT R_RISCV_64 diff --git a/tcc-doc.texi b/tcc-doc.texi index fa223250..83f05166 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -349,12 +349,15 @@ Turn on/off linking of all objects in archives. Debugger options: @table @option -@item -g -Generate run time debug information so that you get clear run time +@item -g[x] +Generate run time stab debug information so that you get clear run time error messages: @code{ test.c:68: in function 'test5()': dereferencing invalid pointer} instead of the laconic @code{Segmentation fault}. +@item -gdwarf[-x] +Generate run time dwarf debug information instead of stab debug information. + @item -b Generate additional support code to check memory allocations and array/pointer bounds (@pxref{Bounds}). @option{-g} is implied. diff --git a/tcc.c b/tcc.c index ce1945a1..693eb216 100644 --- a/tcc.c +++ b/tcc.c @@ -58,7 +58,8 @@ static const char help[] = " -soname set name for shared library to be used at runtime\n" " -Wl,-opt[=val] set linker option (see tcc -hh)\n" "Debugger options:\n" - " -g generate runtime debug info\n" + " -g[x] generate stab runtime debug info\n" + " -gdwarf[-x] generate dwarf runtime debug info\n" #ifdef CONFIG_TCC_BCHECK " -b compile with built-in memory and bounds checker (implies -g)\n" #endif diff --git a/tcc.h b/tcc.h index d66baf78..03e83343 100644 --- a/tcc.h +++ b/tcc.h @@ -368,6 +368,7 @@ extern long double strtold (const char *__nptr, char **__endptr); #include "libtcc.h" #include "elf.h" #include "stab.h" +#include "dwarf.h" /* -------------------------------------------- */ @@ -792,6 +793,7 @@ struct TCCState { /* compile with debug symbol (and use them if error during execution) */ unsigned char do_debug; + unsigned char dwarf; unsigned char do_backtrace; #ifdef CONFIG_TCC_BCHECK /* compile with built-in memory and bounds checker */ @@ -922,6 +924,12 @@ struct TCCState { Section *symtab_section; /* debug sections */ Section *stab_section; + Section *dwarf_info_section; + Section *dwarf_abbrev_section; + Section *dwarf_line_section; + Section *dwarf_aranges_section; + Section *dwarf_str_section; + Section *dwarf_line_str_section; /* Is there a new undefined sym since last new_undef_sym() */ int new_undef_sym; @@ -1822,6 +1830,12 @@ ST_FUNC void post_sem(TCCSem *p); #define symtab_section TCC_STATE_VAR(symtab_section) #define stab_section TCC_STATE_VAR(stab_section) #define stabstr_section stab_section->link +#define dwarf_info_section TCC_STATE_VAR(dwarf_info_section) +#define dwarf_abbrev_section TCC_STATE_VAR(dwarf_abbrev_section) +#define dwarf_line_section TCC_STATE_VAR(dwarf_line_section) +#define dwarf_aranges_section TCC_STATE_VAR(dwarf_aranges_section) +#define dwarf_str_section TCC_STATE_VAR(dwarf_str_section) +#define dwarf_line_str_section TCC_STATE_VAR(dwarf_line_str_section) #define gnu_ext TCC_STATE_VAR(gnu_ext) #define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort) #define tcc_error TCC_SET_STATE(_tcc_error) diff --git a/tccelf.c b/tccelf.c index 9e860b59..d4823eb9 100644 --- a/tccelf.c +++ b/tccelf.c @@ -47,6 +47,8 @@ struct sym_version { /* section is dynsymtab_section */ #define SHF_DYNSYM 0x40000000 +#define DWARF_DEBUG(s) (!strncmp((s), ".debug_", sizeof(".debug_")-1)) + /* ------------------------------------------------------------------------- */ ST_FUNC void tccelf_new(TCCState *s) @@ -102,12 +104,39 @@ ST_FUNC void tccelf_stab_new(TCCState *s) if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY) shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX #endif - stab_section = new_section(s, ".stab", SHT_PROGBITS, shf); - stab_section->sh_entsize = sizeof(Stab_Sym); - stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value; - stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf); - /* put first entry */ - put_stabs(s, "", 0, 0, 0, 0); + if (s->dwarf) { + dwarf_info_section = + new_section(s, ".debug_info", SHT_PROGBITS, shf); + dwarf_abbrev_section = + new_section(s, ".debug_abbrev", SHT_PROGBITS, shf); + dwarf_line_section = + new_section(s, ".debug_line", SHT_PROGBITS, shf); + dwarf_aranges_section = + new_section(s, ".debug_aranges", SHT_PROGBITS, shf); + shf |= SHF_MERGE | SHF_STRINGS; + dwarf_str_section = + new_section(s, ".debug_str", SHT_PROGBITS, shf); + dwarf_str_section->sh_entsize = 1; + dwarf_info_section->sh_addralign = + dwarf_abbrev_section->sh_addralign = + dwarf_line_section->sh_addralign = + dwarf_aranges_section->sh_addralign = + dwarf_str_section->sh_addralign = 1; + if (s1->dwarf >= 5) { + dwarf_line_str_section = + new_section(s, ".debug_line_str", SHT_PROGBITS, shf); + dwarf_line_str_section->sh_entsize = 1; + dwarf_line_str_section->sh_addralign = 1; + } + } + else { + stab_section = new_section(s, ".stab", SHT_PROGBITS, shf); + stab_section->sh_entsize = sizeof(Stab_Sym); + stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value; + stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf); + /* put first entry */ + put_stabs(s, "", 0, 0, 0, 0); + } } static void free_section(Section *s) @@ -944,7 +973,10 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) sym->st_value = 0; else tcc_error_noabort("undefined symbol '%s'", name); - } else if (sh_num < SHN_LORESERVE) { + } else if (sh_num < SHN_LORESERVE && + /* Debug dwarf relocations must be relative to start section. + This only happens when backtrace is used. */ + (sym->st_name || !DWARF_DEBUG(s1->sections[sym->st_shndx]->name))) { /* add section base */ sym->st_value += s1->sections[sym->st_shndx]->sh_addr; } @@ -1330,7 +1362,7 @@ ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t if (sec && offs == -1) offs = sec->data_offset; return set_elf_sym(symtab_section, offs, 0, - ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); + ELFW(ST_INFO)(name && !strstr(name, "__dwarf") ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); } static void add_init_array_defines(TCCState *s1, const char *section_name) @@ -1395,10 +1427,10 @@ static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset } #ifdef CONFIG_TCC_BACKTRACE -static void put_ptr(TCCState *s1, Section *s, int offs) +static void put_ptr(TCCState *s1, Section *s, int offs, const char *name) { int c; - c = set_global_sym(s1, NULL, s, offs); + c = set_global_sym(s1, name, s, offs); s = data_section; put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); section_ptr_add(s, PTR_SIZE); @@ -1415,16 +1447,29 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1)); o = s->data_offset; /* create (part of) a struct rt_context (see tccrun.c) */ - put_ptr(s1, stab_section, 0); - put_ptr(s1, stab_section, -1); - put_ptr(s1, stab_section->link, 0); + if (s1->dwarf) { + put_ptr(s1, dwarf_line_section, 0, "__dwarf_line"); + put_ptr(s1, dwarf_line_section, -1, "__dwarf_line_end"); + if (s1->dwarf >= 5) + put_ptr(s1, dwarf_line_str_section, 0, "__dwarf_line_str"); + else + put_ptr(s1, dwarf_str_section, 0, "__dwarf_str"); + put_ptr(s1, text_section, 0, "__dwarf_text"); + } + else { + put_ptr(s1, stab_section, 0, NULL); + put_ptr(s1, stab_section, -1, NULL); + put_ptr(s1, stab_section->link, 0, NULL); + section_ptr_add(s, PTR_SIZE); + } + /* skip esym_start/esym_end/elf_str (not loaded) */ section_ptr_add(s, 3 * PTR_SIZE); /* prog_base : local nameless symbol with offset 0 at SHN_ABS */ - put_ptr(s1, NULL, 0); + put_ptr(s1, NULL, 0, NULL); n = 2 * PTR_SIZE; #ifdef CONFIG_TCC_BCHECK if (s1->do_bounds_check) { - put_ptr(s1, bounds_section, 0); + put_ptr(s1, bounds_section, 0, NULL); n -= PTR_SIZE; } #endif @@ -1849,6 +1894,8 @@ static int set_sec_sizes(TCCState *s1) /* when generating a DLL, we include relocations but we may patch them */ if (file_type == TCC_OUTPUT_DLL + /* Do not include dwarf relocatable sections. */ + && !DWARF_DEBUG(s1->sections[s->sh_info]->name) && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) { int count = prepare_dynamic_rel(s1, s); if (count) { @@ -2963,8 +3010,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, strcmp(strsec + sh->sh_name, ".stabstr") ) continue; - if (seencompressed - && !strncmp(strsec + sh->sh_name, ".debug_", sizeof(".debug_")-1)) + if (seencompressed && DWARF_DEBUG(strsec + sh->sh_name)) continue; sh = &shdr[i]; diff --git a/tccgen.c b/tccgen.c index d1e0823a..3754fc98 100644 --- a/tccgen.c +++ b/tccgen.c @@ -142,52 +142,56 @@ static void init_prec(void); static const struct { int type; + int size; + int encoding; const char *name; } default_debug[] = { - { VT_INT, "int:t1=r1;-2147483648;2147483647;" }, - { VT_BYTE, "char:t2=r2;0;127;" }, + { VT_INT, 4, DW_ATE_signed, "int:t1=r1;-2147483648;2147483647;" }, + { VT_BYTE, 1, DW_ATE_signed_char, "char:t2=r2;0;127;" }, #if LONG_SIZE == 4 - { VT_LONG | VT_INT, "long int:t3=r3;-2147483648;2147483647;" }, + { VT_LONG | VT_INT, 4, DW_ATE_signed, "long int:t3=r3;-2147483648;2147483647;" }, #else - { VT_LLONG | VT_LONG, "long int:t3=r3;-9223372036854775808;9223372036854775807;" }, + { VT_LLONG | VT_LONG, 8, DW_ATE_signed, "long int:t3=r3;-9223372036854775808;9223372036854775807;" }, #endif - { VT_INT | VT_UNSIGNED, "unsigned int:t4=r4;0;037777777777;" }, + { VT_INT | VT_UNSIGNED, 4, DW_ATE_unsigned, "unsigned int:t4=r4;0;037777777777;" }, #if LONG_SIZE == 4 - { VT_LONG | VT_INT | VT_UNSIGNED, "long unsigned int:t5=r5;0;037777777777;" }, + { VT_LONG | VT_INT | VT_UNSIGNED, 4, DW_ATE_unsigned, "long unsigned int:t5=r5;0;037777777777;" }, #else /* use octal instead of -1 so size_t works (-gstabs+ in gcc) */ - { VT_LLONG | VT_LONG | VT_UNSIGNED, "long unsigned int:t5=r5;0;01777777777777777777777;" }, + { VT_LLONG | VT_LONG | VT_UNSIGNED, 8, DW_ATE_unsigned, "long unsigned int:t5=r5;0;01777777777777777777777;" }, #endif - { VT_QLONG, "__int128:t6=r6;0;-1;" }, - { VT_QLONG | VT_UNSIGNED, "__int128 unsigned:t7=r7;0;-1;" }, - { VT_LLONG, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" }, - { VT_LLONG | VT_UNSIGNED, "long long unsigned int:t9=r9;0;01777777777777777777777;" }, - { VT_SHORT, "short int:t10=r10;-32768;32767;" }, - { VT_SHORT | VT_UNSIGNED, "short unsigned int:t11=r11;0;65535;" }, - { VT_BYTE | VT_DEFSIGN, "signed char:t12=r12;-128;127;" }, - { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, "unsigned char:t13=r13;0;255;" }, - { VT_FLOAT, "float:t14=r1;4;0;" }, - { VT_DOUBLE, "double:t15=r1;8;0;" }, + { VT_QLONG, 16, DW_ATE_signed, "__int128:t6=r6;0;-1;" }, + { VT_QLONG | VT_UNSIGNED, 16, DW_ATE_unsigned, "__int128 unsigned:t7=r7;0;-1;" }, + { VT_LLONG, 8, DW_ATE_signed, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" }, + { VT_LLONG | VT_UNSIGNED, 8, DW_ATE_unsigned, "long long unsigned int:t9=r9;0;01777777777777777777777;" }, + { VT_SHORT, 2, DW_ATE_signed, "short int:t10=r10;-32768;32767;" }, + { VT_SHORT | VT_UNSIGNED, 2, DW_ATE_unsigned, "short unsigned int:t11=r11;0;65535;" }, + { VT_BYTE | VT_DEFSIGN, 1, DW_ATE_signed_char, "signed char:t12=r12;-128;127;" }, + { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, 1, DW_ATE_unsigned_char, "unsigned char:t13=r13;0;255;" }, + { VT_FLOAT, 4, DW_ATE_float, "float:t14=r1;4;0;" }, + { VT_DOUBLE, 8, DW_ATE_float, "double:t15=r1;8;0;" }, #ifdef TCC_USING_DOUBLE_FOR_LDOUBLE - { VT_DOUBLE | VT_LONG, "long double:t16=r1;8;0;" }, + { VT_DOUBLE | VT_LONG, 8, DW_ATE_float, "long double:t16=r1;8;0;" }, #else - { VT_LDOUBLE, "long double:t16=r1;16;0;" }, + { VT_LDOUBLE, 16, DW_ATE_float, "long double:t16=r1;16;0;" }, #endif - { -1, "_Float32:t17=r1;4;0;" }, - { -1, "_Float64:t18=r1;8;0;" }, - { -1, "_Float128:t19=r1;16;0;" }, - { -1, "_Float32x:t20=r1;8;0;" }, - { -1, "_Float64x:t21=r1;16;0;" }, - { -1, "_Decimal32:t22=r1;4;0;" }, - { -1, "_Decimal64:t23=r1;8;0;" }, - { -1, "_Decimal128:t24=r1;16;0;" }, + { -1, -1, -1, "_Float32:t17=r1;4;0;" }, + { -1, -1, -1, "_Float64:t18=r1;8;0;" }, + { -1, -1, -1, "_Float128:t19=r1;16;0;" }, + { -1, -1, -1, "_Float32x:t20=r1;8;0;" }, + { -1, -1, -1, "_Float64x:t21=r1;16;0;" }, + { -1, -1, -1, "_Decimal32:t22=r1;4;0;" }, + { -1, -1, -1, "_Decimal64:t23=r1;8;0;" }, + { -1, -1, -1, "_Decimal128:t24=r1;16;0;" }, /* if default char is unsigned */ - { VT_BYTE | VT_UNSIGNED, "unsigned char:t25=r25;0;255;" }, + { VT_BYTE | VT_UNSIGNED, 1, DW_ATE_unsigned_char, "unsigned char:t25=r25;0;255;" }, /* boolean type */ - { VT_BOOL, "bool:t26=r26;0;255;" }, - { VT_VOID, "void:t27=27" }, + { VT_BOOL, 1, DW_ATE_unsigned_char, "bool:t26=r26;0;255;" }, + { VT_VOID, 1, DW_ATE_void, "void:t27=27" }, }; +#define N_DEFAULT_DEBUG (sizeof (default_debug) / sizeof (default_debug[0])) + static int debug_next_type; static struct debug_hash { @@ -207,10 +211,231 @@ static struct debug_info { char *str; Section *sec; int sym_index; + int info; + int file; + int line; } *sym; struct debug_info *child, *next, *last, *parent; } *debug_info, *debug_info_root; +/* dwarf debug */ + +#define DWARF_LINE_BASE -5 +#define DWARF_LINE_RANGE 14 +#define DWARF_OPCODE_BASE 13 + +#if defined TCC_TARGET_ARM64 +#define DWARF_MIN_INSTR_LEN 4 +#elif defined TCC_TARGET_ARM +#define DWARF_MIN_INSTR_LEN 2 +#else +#define DWARF_MIN_INSTR_LEN 1 +#endif + +#define DWARF_ABBREV_COMPILE_UNIT 1 +#define DWARF_ABBREV_BASE_TYPE 2 +#define DWARF_ABBREV_VARIABLE_EXTERNAL 3 +#define DWARF_ABBREV_VARIABLE_STATIC 4 +#define DWARF_ABBREV_VARIABLE_LOCAL 5 +#define DWARF_ABBREV_FORMAL_PARAMETER 6 +#define DWARF_ABBREV_POINTER 7 +#define DWARF_ABBREV_ARRAY_TYPE 8 +#define DWARF_ABBREV_SUBRANGE_TYPE 9 +#define DWARF_ABBREV_TYPEDEF 10 +#define DWARF_ABBREV_ENUMERATOR 11 +#define DWARF_ABBREV_ENUMERATION_TYPE 12 +#define DWARF_ABBREV_MEMBER 13 +#define DWARF_ABBREV_MEMBER_BF 14 +#define DWARF_ABBREV_STRUCTURE_TYPE 15 +#define DWARF_ABBREV_UNION_TYPE 16 +#define DWARF_ABBREV_SUBPROGRAM_EXTERNAL 17 +#define DWARF_ABBREV_SUBPROGRAM_STATIC 18 +#define DWARF_ABBREV_LEXICAL_BLOCK 19 + +static const unsigned char dwarf_abbrev_init[] = { + DWARF_ABBREV_COMPILE_UNIT, DW_TAG_compile_unit, 1, + DW_AT_producer, DW_FORM_strp, + DW_AT_language, DW_FORM_data1, + DW_AT_name, DW_FORM_line_strp, + DW_AT_comp_dir, DW_FORM_line_strp, + DW_AT_low_pc, DW_FORM_addr, +#if PTR_SIZE == 4 + DW_AT_high_pc, DW_FORM_data4, +#else + DW_AT_high_pc, DW_FORM_data8, +#endif + DW_AT_stmt_list, DW_FORM_data4, + 0, 0, + DWARF_ABBREV_BASE_TYPE, DW_TAG_base_type, 0, + DW_AT_byte_size, DW_FORM_udata, + DW_AT_encoding, DW_FORM_data1, + DW_AT_name, DW_FORM_strp, + 0, 0, + DWARF_ABBREV_VARIABLE_EXTERNAL, DW_TAG_variable, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_external, DW_FORM_flag, + DW_AT_location, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_VARIABLE_STATIC, DW_TAG_variable, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_location, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_VARIABLE_LOCAL, DW_TAG_variable, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_type, DW_FORM_ref4, + DW_AT_location, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_FORMAL_PARAMETER, DW_TAG_formal_parameter, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_type, DW_FORM_ref4, + DW_AT_location, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_POINTER, DW_TAG_pointer_type, 0, + DW_AT_byte_size, DW_FORM_data1, + DW_AT_byte_size, DW_FORM_implicit_const, 8, + DW_AT_type, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_ARRAY_TYPE, DW_TAG_array_type, 1, + DW_AT_type, DW_FORM_ref4, + DW_AT_sibling, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_SUBRANGE_TYPE, DW_TAG_subrange_type, 0, + DW_AT_type, DW_FORM_ref4, + DW_AT_upper_bound, DW_FORM_udata, + 0, 0, + DWARF_ABBREV_TYPEDEF, DW_TAG_typedef, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_ENUMERATOR, DW_TAG_enumerator, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_const_value, DW_FORM_data4, + 0, 0, + DWARF_ABBREV_ENUMERATION_TYPE, DW_TAG_enumeration_type, 1, + DW_AT_name, DW_FORM_strp, + DW_AT_encoding, DW_FORM_data1, + DW_AT_byte_size, DW_FORM_data1, + DW_AT_type, DW_FORM_ref4, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_sibling, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_MEMBER, DW_TAG_member, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_data_member_location, DW_FORM_udata, + 0, 0, + DWARF_ABBREV_MEMBER_BF, DW_TAG_member, 0, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_bit_size, DW_FORM_udata, + DW_AT_data_bit_offset, DW_FORM_udata, + 0, 0, + DWARF_ABBREV_STRUCTURE_TYPE, DW_TAG_structure_type, 1, + DW_AT_name, DW_FORM_strp, + DW_AT_byte_size, DW_FORM_udata, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_sibling, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_UNION_TYPE, DW_TAG_union_type, 1, + DW_AT_name, DW_FORM_strp, + DW_AT_byte_size, DW_FORM_udata, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_sibling, DW_FORM_ref4, + 0, 0, + DWARF_ABBREV_SUBPROGRAM_EXTERNAL, DW_TAG_subprogram, 1, + DW_AT_external, DW_FORM_flag, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_low_pc, DW_FORM_addr, +#if PTR_SIZE == 4 + DW_AT_high_pc, DW_FORM_data4, +#else + DW_AT_high_pc, DW_FORM_data8, +#endif + DW_AT_sibling, DW_FORM_ref4, + DW_AT_frame_base, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_SUBPROGRAM_STATIC, DW_TAG_subprogram, 1, + DW_AT_name, DW_FORM_strp, + DW_AT_decl_file, DW_FORM_udata, + DW_AT_decl_line, DW_FORM_udata, + DW_AT_type, DW_FORM_ref4, + DW_AT_low_pc, DW_FORM_addr, +#if PTR_SIZE == 4 + DW_AT_high_pc, DW_FORM_data4, +#else + DW_AT_high_pc, DW_FORM_data8, +#endif + DW_AT_sibling, DW_FORM_ref4, + DW_AT_frame_base, DW_FORM_block1, + 0, 0, + DWARF_ABBREV_LEXICAL_BLOCK, DW_TAG_lexical_block, 1, + DW_AT_low_pc, DW_FORM_addr, +#if PTR_SIZE == 4 + DW_AT_high_pc, DW_FORM_data4, +#else + DW_AT_high_pc, DW_FORM_data8, +#endif + 0, 0, + 0 +}; + +static const unsigned char dwarf_line_opcodes[] = { + 0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,1 +}; + +static struct { + int info; + int abbrev; + int line; + int str; + int line_str; +} dwarf_sym; + +static struct { + int start; + int dir_size; + char **dir_table; + int filename_size; + struct dwarf_filename_struct { + int dir_entry; + char *name; + } *filename_table; + int line_size; + int line_max_size; + unsigned char *line_data; + int cur_file; + int last_file; + int last_pc; + int last_line; +} dwarf_line; + +static struct { + int start; + Sym *func; + int line; + int base_type_used[N_DEFAULT_DEBUG]; +} dwarf_info; + +/* test coverage */ + static struct { unsigned long offset; unsigned long last_file_name; @@ -404,36 +629,323 @@ void pv (const char *lbl, int a, int b) #endif /* ------------------------------------------------------------------------- */ + +#define dwarf_data1(s,data) \ + { unsigned char *p = section_ptr_add((s), 1); *p = (data); } +#define dwarf_data2(s,data) \ + write16le(section_ptr_add((s), 2), (data)) +#define dwarf_data4(s,data) \ + write32le(section_ptr_add((s), 4), (data)) +#define dwarf_data8(s,data) \ + write64le(section_ptr_add((s), 8), (data)) + +static int dwarf_get_section_sym(Section *s) +{ + return put_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, + s->sh_num, NULL); +} + +static void dwarf_reloc(Section *s, int sym, int rel) +{ + put_elf_reloca(symtab_section, s, s->data_offset, rel, sym, 0); +} + +static void dwarf_string(Section *s, Section *dw, int sym, const char *str) +{ + int offset, len; + char *ptr; + + len = strlen(str) + 1; + offset = dw->data_offset; + ptr = section_ptr_add(dw, len); + memmove(ptr, str, len); + put_elf_reloca(symtab_section, s, s->data_offset, R_DATA_32U, sym, + PTR_SIZE == 4 ? 0 : offset); + dwarf_data4(s, PTR_SIZE == 4 ? offset : 0); +} + +static void dwarf_strp(Section *s, const char *str) +{ + dwarf_string(s, dwarf_str_section, dwarf_sym.str, str); +} + +static void dwarf_line_strp(Section *s, const char *str) +{ + dwarf_string(s, dwarf_line_str_section, dwarf_sym.line_str, str); +} + +static void dwarf_line_op(unsigned char op) +{ + if (dwarf_line.line_size >= dwarf_line.line_max_size) { + dwarf_line.line_max_size += 1024; + dwarf_line.line_data = + (unsigned char *)tcc_realloc(dwarf_line.line_data, + dwarf_line.line_max_size); + } + dwarf_line.line_data[dwarf_line.line_size++] = op; +} + +static void dwarf_file(TCCState *s1) +{ + int i; + char *filename; + + if (!s1->do_debug || !s1->dwarf) + return; + filename = strrchr(file->filename, '/'); + if (filename == NULL) { + for (i = 1; i < dwarf_line.filename_size; i++) + if (dwarf_line.filename_table[i].dir_entry == 0 && + strcmp(dwarf_line.filename_table[i].name, + file->filename) == 0) { + dwarf_line.cur_file = i; + return; + } + } + else { + int j; + char *undo = filename; + + *filename++ = '\0'; + for (i = 0; i < dwarf_line.dir_size; i++) + if (strcmp(dwarf_line.dir_table[i], file->filename) == 0) + for (j = 1; j < dwarf_line.filename_size; j++) + if (dwarf_line.filename_table[i].dir_entry == i && + strcmp(dwarf_line.filename_table[j].name, + filename) == 0) { + *undo = '/'; + dwarf_line.cur_file = j; + return; + } + *undo = '/'; + } + return; +} + +#if 0 +static int dwarf_uleb128_size (unsigned long long value) +{ + int size = 0; + + do { + value >>= 7; + size++; + } while (value != 0); + return size; +} +#endif + +static int dwarf_sleb128_size (long long value) +{ + int more; + int size = 0; + + do { + unsigned char byte = value & 0x7f; + + value = (value >> 7) | ~(-1 >> 7); + more =!((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + size++; + } while (more); + return size; +} + +static void dwarf_uleb128 (Section *s, unsigned long long value) +{ + do { + unsigned char byte = value & 0x7f; + + value >>= 7; + if (value) + byte |= 0x80; + dwarf_data1(s, byte); + } while (value != 0); +} + +static void dwarf_sleb128 (Section *s, long long value) +{ + int more; + + do { + unsigned char byte = value & 0x7f; + + value = (value >> 7) | ~(-1 >> 7); + more =!((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + dwarf_data1(s, byte); + } while (more); +} + +static void dwarf_uleb128_op (unsigned long long value) +{ + do { + unsigned char byte = value & 0x7f; + + value >>= 7; + if (value) + byte |= 0x80; + dwarf_line_op(byte); + } while (value != 0); +} + +static void dwarf_sleb128_op (long long value) +{ + int more; + + do { + unsigned char byte = value & 0x7f; + + value = (value >> 7) | ~(-1 >> 7); + more =!((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + dwarf_line_op(byte); + } while (more); +} + /* start of translation unit info */ ST_FUNC void tcc_debug_start(TCCState *s1) { if (s1->do_debug) { int i; + char *filename = file->prev ? file->prev->filename : file->filename; char buf[512]; - /* file info: full path + filename */ - section_sym = put_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, - text_section->sh_num, NULL); getcwd(buf, sizeof(buf)); #ifdef _WIN32 normalize_slashes(buf); #endif pstrcat(buf, sizeof(buf), "/"); - put_stabs_r(s1, buf, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - put_stabs_r(s1, file->prev ? file->prev->filename : file->filename, - N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); - for (i = 0; i < sizeof (default_debug) / sizeof (default_debug[0]); i++) - put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0); + if (s1->dwarf) { + int start_abbrev; + unsigned char *ptr; + + /* dwarf_abbrev */ + start_abbrev = dwarf_abbrev_section->data_offset; + ptr = section_ptr_add(dwarf_abbrev_section, sizeof(dwarf_abbrev_init)); + memcpy(ptr, dwarf_abbrev_init, sizeof(dwarf_abbrev_init)); + + if (s1->dwarf < 5) { + while (*ptr) { + ptr += 3; + while (*ptr) { + if (ptr[1] == DW_FORM_line_strp) + ptr[1] = DW_FORM_strp; + ptr += 2; + } + } + } + + dwarf_sym.info = dwarf_get_section_sym(dwarf_info_section); + dwarf_sym.abbrev = dwarf_get_section_sym(dwarf_abbrev_section); + dwarf_sym.line = dwarf_get_section_sym(dwarf_line_section); + dwarf_sym.str = dwarf_get_section_sym(dwarf_str_section); + if (tcc_state->dwarf >= 5) + dwarf_sym.line_str = dwarf_get_section_sym(dwarf_line_str_section); + else { + dwarf_line_str_section = dwarf_str_section; + dwarf_sym.line_str = dwarf_sym.str; + } + section_sym = dwarf_get_section_sym(text_section); + + /* dwarf_info */ + dwarf_info.start = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); // size + dwarf_data2(dwarf_info_section, s1->dwarf); // version + if (s1->dwarf >= 5) { + dwarf_data1(dwarf_info_section, DW_UT_compile); // unit type + dwarf_data1(dwarf_info_section, PTR_SIZE); + dwarf_reloc(dwarf_info_section, dwarf_sym.abbrev, R_DATA_32U); + dwarf_data4(dwarf_info_section, start_abbrev); + } + else { + dwarf_reloc(dwarf_info_section, dwarf_sym.abbrev, R_DATA_32U); + dwarf_data4(dwarf_info_section, start_abbrev); + dwarf_data1(dwarf_info_section, PTR_SIZE); + } + + dwarf_data1(dwarf_info_section, DWARF_ABBREV_COMPILE_UNIT); + dwarf_strp(dwarf_info_section, "tcc " TCC_VERSION); + dwarf_data1(dwarf_info_section, DW_LANG_C11); + dwarf_line_strp(dwarf_info_section, filename); + dwarf_line_strp(dwarf_info_section, buf); + dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_info_section, ind); // low pc + dwarf_data4(dwarf_info_section, 0); // high pc +#else + dwarf_data8(dwarf_info_section, ind); // low pc + dwarf_data8(dwarf_info_section, 0); // high pc +#endif + dwarf_reloc(dwarf_info_section, dwarf_sym.line, R_DATA_32U); + dwarf_data4(dwarf_info_section, dwarf_line_section->data_offset); // stmt_list + + /* dwarf_line */ + dwarf_line.start = dwarf_line_section->data_offset; + dwarf_data4(dwarf_line_section, 0); // length + dwarf_data2(dwarf_line_section, s1->dwarf); // version + if (s1->dwarf >= 5) { + dwarf_data1(dwarf_line_section, PTR_SIZE); // address size + dwarf_data1(dwarf_line_section, 0); // segment selector + } + dwarf_data4(dwarf_line_section, 0); // prologue Length + dwarf_data1(dwarf_line_section, DWARF_MIN_INSTR_LEN); + if (s1->dwarf >= 4) + dwarf_data1(dwarf_line_section, 1); // maximum ops per instruction + dwarf_data1(dwarf_line_section, 1); // Initial value of 'is_stmt' + dwarf_data1(dwarf_line_section, DWARF_LINE_BASE); + dwarf_data1(dwarf_line_section, DWARF_LINE_RANGE); + dwarf_data1(dwarf_line_section, DWARF_OPCODE_BASE); + ptr = section_ptr_add(dwarf_line_section, sizeof(dwarf_line_opcodes)); + memcpy(ptr, dwarf_line_opcodes, sizeof(dwarf_line_opcodes)); + dwarf_line.dir_size = 1; + dwarf_line.dir_table = (char **) tcc_malloc(sizeof (char *)); + dwarf_line.dir_table[0] = tcc_strdup(buf); + /* line state machine starts with file 1 instead of 0 */ + dwarf_line.filename_size = 2; + dwarf_line.filename_table = + (struct dwarf_filename_struct *) + tcc_malloc(2*sizeof (struct dwarf_filename_struct)); + dwarf_line.filename_table[0].dir_entry = 0; + dwarf_line.filename_table[0].name = tcc_strdup(filename); + dwarf_line.filename_table[1].dir_entry = 0; + dwarf_line.filename_table[1].name = tcc_strdup(filename); + dwarf_line.line_size = dwarf_line.line_max_size = 0; + dwarf_line.line_data = NULL; + dwarf_line.cur_file = 1; + dwarf_line.last_file = 0; + dwarf_line.last_pc = 0; + dwarf_line.last_line = 1; + dwarf_line_op(0); // extended + dwarf_uleb128_op(1 + PTR_SIZE); // extended size + dwarf_line_op(DW_LNE_set_address); + for (i = 0; i < PTR_SIZE; i++) + dwarf_line_op(0); + memset(&dwarf_info.base_type_used, 0, sizeof(dwarf_info.base_type_used)); + } + else { + /* file info: full path + filename */ + section_sym = put_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, + text_section->sh_num, NULL); + put_stabs_r(s1, buf, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + put_stabs_r(s1, filename, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); + for (i = 0; i < N_DEFAULT_DEBUG; i++) + put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0); + } new_file = last_line_num = 0; func_ind = -1; - debug_next_type = sizeof(default_debug) / sizeof(default_debug[0]); + debug_next_type = N_DEFAULT_DEBUG; debug_hash = NULL; n_debug_hash = 0; - /* we're currently 'including' the */ tcc_debug_bincl(s1); } @@ -450,8 +962,111 @@ ST_FUNC void tcc_debug_end(TCCState *s1) { if (!s1->do_debug) return; - put_stabs_r(s1, NULL, N_SO, 0, 0, - text_section->data_offset, text_section, section_sym); + if (s1->dwarf) { + int i; + int start_aranges; + unsigned char *ptr; + int text_size = text_section->data_offset; + + /* dwarf_info */ + dwarf_data1(dwarf_info_section, 0); + ptr = dwarf_info_section->data + dwarf_info.start; + write32le(ptr, dwarf_info_section->data_offset - dwarf_info.start - 4); + write32le(ptr + 25 + (s1->dwarf >= 5) + PTR_SIZE, text_size); + + /* dwarf_aranges */ + start_aranges = dwarf_aranges_section->data_offset; + dwarf_data4(dwarf_aranges_section, 0); // size + dwarf_data2(dwarf_aranges_section, 2); // version + dwarf_reloc(dwarf_aranges_section, dwarf_sym.info, R_DATA_32U); + dwarf_data4(dwarf_aranges_section, 0); // dwarf_info +#if PTR_SIZE == 4 + dwarf_data1(dwarf_aranges_section, 4); // address size +#else + dwarf_data1(dwarf_aranges_section, 8); // address size +#endif + dwarf_data1(dwarf_aranges_section, 0); // segment selector size + dwarf_data4(dwarf_aranges_section, 0); // padding + dwarf_reloc(dwarf_aranges_section, section_sym, R_DATA_PTR); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_aranges_section, 0); // Begin + dwarf_data4(dwarf_aranges_section, text_size); // End + dwarf_data4(dwarf_aranges_section, 0); // End list + dwarf_data4(dwarf_aranges_section, 0); // End list +#else + dwarf_data8(dwarf_aranges_section, 0); // Begin + dwarf_data8(dwarf_aranges_section, text_size); // End + dwarf_data8(dwarf_aranges_section, 0); // End list + dwarf_data8(dwarf_aranges_section, 0); // End list +#endif + ptr = dwarf_aranges_section->data + start_aranges; + write32le(ptr, dwarf_aranges_section->data_offset - start_aranges - 4); + + /* dwarf_line */ + if (s1->dwarf >= 5) { + dwarf_data1(dwarf_line_section, 1); /* col */ + dwarf_uleb128(dwarf_line_section, DW_LNCT_path); + dwarf_uleb128(dwarf_line_section, DW_FORM_line_strp); + dwarf_uleb128(dwarf_line_section, dwarf_line.dir_size); + for (i = 0; i < dwarf_line.dir_size; i++) + dwarf_line_strp(dwarf_line_section, dwarf_line.dir_table[i]); + dwarf_data1(dwarf_line_section, 2); /* col */ + dwarf_uleb128(dwarf_line_section, DW_LNCT_path); + dwarf_uleb128(dwarf_line_section, DW_FORM_line_strp); + dwarf_uleb128(dwarf_line_section, DW_LNCT_directory_index); + dwarf_uleb128(dwarf_line_section, DW_FORM_udata); + dwarf_uleb128(dwarf_line_section, dwarf_line.filename_size); + for (i = 0; i < dwarf_line.filename_size; i++) { + dwarf_line_strp(dwarf_line_section, + dwarf_line.filename_table[i].name); + dwarf_uleb128(dwarf_line_section, + dwarf_line.filename_table[i].dir_entry); + } + } + else { + int len; + + for (i = 0; i < dwarf_line.dir_size; i++) { + len = strlen(dwarf_line.dir_table[i]) + 1; + ptr = section_ptr_add(dwarf_line_section, len); + memmove(ptr, dwarf_line.dir_table[i], len); + } + dwarf_data1(dwarf_line_section, 0); /* end dir */ + for (i = 0; i < dwarf_line.filename_size; i++) { + len = strlen(dwarf_line.filename_table[i].name) + 1; + ptr = section_ptr_add(dwarf_line_section, len); + memmove(ptr, dwarf_line.filename_table[i].name, len); + dwarf_uleb128(dwarf_line_section, + dwarf_line.filename_table[i].dir_entry); + dwarf_uleb128(dwarf_line_section, 0); /* time */ + dwarf_uleb128(dwarf_line_section, 0); /* size */ + } + dwarf_data1(dwarf_line_section, 0); /* end file */ + } + for (i = 0; i < dwarf_line.dir_size; i++) + tcc_free(dwarf_line.dir_table[i]); + tcc_free(dwarf_line.dir_table); + for (i = 0; i < dwarf_line.filename_size; i++) + tcc_free(dwarf_line.filename_table[i].name); + tcc_free(dwarf_line.filename_table); + + dwarf_line_op(0); // extended + dwarf_uleb128_op(1); // extended size + dwarf_line_op(DW_LNE_end_sequence); + i = (s1->dwarf >= 5) * 2; + write32le(&dwarf_line_section->data[dwarf_line.start + 6 + i], + dwarf_line_section->data_offset - dwarf_line.start - (10 + i)); + section_ptr_add(dwarf_line_section, 3); + dwarf_reloc(dwarf_line_section, section_sym, R_DATA_PTR); + ptr = section_ptr_add(dwarf_line_section, dwarf_line.line_size - 3); + memmove(ptr - 3, dwarf_line.line_data, dwarf_line.line_size); + tcc_free(dwarf_line.line_data); + write32le(dwarf_line_section->data + dwarf_line.start, + dwarf_line_section->data_offset - dwarf_line.start - 4); + } + else + put_stabs_r(s1, NULL, N_SO, 0, 0, + text_section->data_offset, text_section, section_sym); tcc_free(debug_hash); } @@ -462,8 +1077,10 @@ static BufferedFile* put_new_file(TCCState *s1) if (f->filename[0] == ':') f = f->prev; if (f && new_file) { - put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym); + if (!s1->dwarf) + put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym); new_file = last_line_num = 0; + dwarf_file(s1); } return f; } @@ -475,6 +1092,7 @@ ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename) return; pstrcpy(file->filename, sizeof(file->filename), filename); new_file = 1; + dwarf_file(s1); } /* begin of #include */ @@ -482,8 +1100,53 @@ ST_FUNC void tcc_debug_bincl(TCCState *s1) { if (!s1->do_debug) return; - put_stabs(s1, file->filename, N_BINCL, 0, 0, 0); + if (s1->dwarf) { + int i, j; + char *filename = strrchr(file->filename, '/'); + char *dir; + + if (filename == NULL) { + filename = file->filename; + i = 0; + } + else { + char *undo = filename; + + *filename++ = '\0'; + dir = file->filename; + for (i = 0; i < dwarf_line.dir_size; i++) + if (strcmp (dwarf_line.dir_table[i], dir) == 0) + break; + if (i == dwarf_line.dir_size) { + dwarf_line.dir_size++; + dwarf_line.dir_table = + (char **) tcc_realloc(dwarf_line.dir_table, + dwarf_line.dir_size * + sizeof (char *)); + dwarf_line.dir_table[i] = tcc_strdup(dir); + } + *undo = '/'; + } + if (strcmp(filename, "")) { + for (j = 0; j < dwarf_line.filename_size; j++) + if (strcmp (dwarf_line.filename_table[j].name, filename) == 0) + break; + if (j == dwarf_line.filename_size) { + dwarf_line.filename_table = + (struct dwarf_filename_struct *) + tcc_realloc(dwarf_line.filename_table, + (dwarf_line.filename_size + 1) * + sizeof (struct dwarf_filename_struct)); + dwarf_line.filename_table[dwarf_line.filename_size].dir_entry = i; + dwarf_line.filename_table[dwarf_line.filename_size++].name = + tcc_strdup(filename); + } + } + } + else + put_stabs(s1, file->filename, N_BINCL, 0, 0, 0); new_file = 1; + dwarf_file(s1); } /* end of #include */ @@ -491,30 +1154,73 @@ ST_FUNC void tcc_debug_eincl(TCCState *s1) { if (!s1->do_debug) return; - put_stabn(s1, N_EINCL, 0, 0, 0); + if (!s1->dwarf) + put_stabn(s1, N_EINCL, 0, 0, 0); new_file = 1; + dwarf_file(s1); } /* generate line number info */ static void tcc_debug_line(TCCState *s1) { BufferedFile *f; + if (!s1->do_debug || cur_text_section != text_section || !(f = put_new_file(s1)) || last_line_num == f->line_num) return; - if (func_ind != -1) { - put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind); - } else { - /* from tcc_assemble */ - put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym); + if (s1->dwarf) { + int len_pc = (ind - dwarf_line.last_pc) / DWARF_MIN_INSTR_LEN; + int len_line = f->line_num - dwarf_line.last_line; + int n = len_pc * DWARF_LINE_RANGE + len_line + DWARF_OPCODE_BASE - DWARF_LINE_BASE; + + if (dwarf_line.cur_file != dwarf_line.last_file) { + dwarf_line.last_file = dwarf_line.cur_file; + dwarf_line_op(DW_LNS_set_file); + dwarf_uleb128_op(dwarf_line.cur_file); + } + if (len_pc && + len_line >= DWARF_LINE_BASE && len_line <= (DWARF_OPCODE_BASE + DWARF_LINE_BASE) && + n >= DWARF_OPCODE_BASE && n <= 255) + dwarf_line_op(n); + else { + if (len_pc) { + n = len_pc * DWARF_LINE_RANGE + 0 + DWARF_OPCODE_BASE - DWARF_LINE_BASE; + if (n >= DWARF_OPCODE_BASE && n <= 255) + dwarf_line_op(n); + else { + dwarf_line_op(DW_LNS_advance_pc); + dwarf_uleb128_op(len_pc); + } + } + if (len_line) { + n = 0 * DWARF_LINE_RANGE + len_line + DWARF_OPCODE_BASE - DWARF_LINE_BASE; + if (len_line >= DWARF_LINE_BASE && len_line <= (DWARF_OPCODE_BASE + DWARF_LINE_BASE) && + n >= DWARF_OPCODE_BASE && n <= 255) + dwarf_line_op(n); + else { + dwarf_line_op(DW_LNS_advance_line); + dwarf_sleb128_op(len_line); + } + } + } + dwarf_line.last_pc = ind; + dwarf_line.last_line = f->line_num; + } + else { + if (func_ind != -1) { + put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind); + } else { + /* from tcc_assemble */ + put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym); + } + last_line_num = f->line_num; } - last_line_num = f->line_num; } static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned long value, - Section *sec, int sym_index) + Section *sec, int sym_index, int info) { struct debug_sym *s; @@ -529,6 +1235,9 @@ static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned l s->str = tcc_strdup(str); s->sec = sec; s->sym_index = sym_index; + s->info = info; + s->file = dwarf_line.cur_file; + s->line = file->line_num; } else if (sec) put_stabs_r (s1, str, type, 0, 0, value, sec, sym_index); @@ -567,6 +1276,40 @@ static void tcc_debug_stabn(TCCState *s1, int type, int value) } } +static int tcc_debug_find(Sym *t) +{ + int i; + + for (i = 0; i < n_debug_hash; i++) + if (t == debug_hash[i].type) + return debug_hash[i].debug_type; + return -1; +} + +static int tcc_debug_add(Sym *t, int dwarf) +{ + int offset = dwarf ? dwarf_info_section->data_offset : ++debug_next_type; + + debug_hash = (struct debug_hash *) + tcc_realloc (debug_hash, + (n_debug_hash + 1) * sizeof(*debug_hash)); + debug_hash[n_debug_hash].debug_type = offset; + debug_hash[n_debug_hash++].type = t; + return offset; +} + +static void tcc_debug_remove(Sym *t) +{ + int i; + + for (i = 0; i < n_debug_hash; i++) + if (t == debug_hash[i].type) { + n_debug_hash--; + for (; i < n_debug_hash; i++) + debug_hash[i] = debug_hash[i+1]; + } +} + static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) { int type; @@ -585,22 +1328,12 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) break; } if ((type & VT_BTYPE) == VT_STRUCT) { - int i; + Sym *e = t; t = t->type.ref; - for (i = 0; i < n_debug_hash; i++) { - if (t == debug_hash[i].type) { - debug_type = debug_hash[i].debug_type; - break; - } - } + debug_type = tcc_debug_find(t); if (debug_type == -1) { - debug_type = ++debug_next_type; - debug_hash = (struct debug_hash *) - tcc_realloc (debug_hash, - (n_debug_hash + 1) * sizeof(*debug_hash)); - debug_hash[n_debug_hash].debug_type = debug_type; - debug_hash[n_debug_hash++].type = t; + debug_type = tcc_debug_add(t, 0); cstr_new (&str); cstr_printf (&str, "%s:T%d=%c%d", (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM @@ -627,39 +1360,44 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) cstr_printf (&str, ",%d,%d;", pos, size); } cstr_printf (&str, ";"); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); + tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); cstr_free (&str); + if (debug_info) + tcc_debug_remove(e); } } else if (IS_ENUM(type)) { Sym *e = t = t->type.ref; - debug_type = ++debug_next_type; - cstr_new (&str); - cstr_printf (&str, "%s:T%d=e", - (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), - debug_type); - while (t->next) { - t = t->next; - cstr_printf (&str, "%s:", - (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM - ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL)); - cstr_printf (&str, e->type.t & VT_UNSIGNED ? "%u," : "%d,", - (int)t->enum_val); - } - cstr_printf (&str, ";"); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); - cstr_free (&str); + debug_type = tcc_debug_find(t); + if (debug_type == -1) { + debug_type = tcc_debug_add(t, 0); + cstr_new (&str); + cstr_printf (&str, "%s:T%d=e", + (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM + ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), + debug_type); + while (t->next) { + t = t->next; + cstr_printf (&str, "%s:", + (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM + ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL)); + cstr_printf (&str, e->type.t & VT_UNSIGNED ? "%u," : "%d,", + (int)t->enum_val); + } + cstr_printf (&str, ";"); + tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); + cstr_free (&str); + if (debug_info) + tcc_debug_remove(e); + } } else if ((type & VT_BTYPE) != VT_FUNC) { type &= ~VT_STRUCT_MASK; - for (debug_type = 1; - debug_type <= sizeof(default_debug) / sizeof(default_debug[0]); - debug_type++) + for (debug_type = 1; debug_type <= N_DEFAULT_DEBUG; debug_type++) if (default_debug[debug_type - 1].type == type) break; - if (debug_type > sizeof(default_debug) / sizeof(default_debug[0])) + if (debug_type > N_DEFAULT_DEBUG) return; } if (n > 0) @@ -686,8 +1424,263 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) cstr_printf (result, "%d", debug_type); } +static int tcc_get_dwarf_info(TCCState *s1, Sym *s) +{ + int type; + int debug_type = -1; + Sym *e, *t = s; + int i; + + for (;;) { + type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); + if ((type & VT_BTYPE) != VT_BYTE) + type &= ~VT_DEFSIGN; + if (type == VT_PTR || type == (VT_PTR | VT_ARRAY)) + t = t->type.ref; + else + break; + } + if ((type & VT_BTYPE) == VT_STRUCT) { + t = t->type.ref; + debug_type = tcc_debug_find(t); + if (debug_type == -1) { + int pos_sib, i, *pos_type; + + debug_type = tcc_debug_add(t, 1); + e = t; + i = 0; + while (e->next) { + e = e->next; + i++; + } + pos_type = (int *) tcc_malloc(i * sizeof(int)); + dwarf_data1(dwarf_info_section, + IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_TYPE + : DWARF_ABBREV_STRUCTURE_TYPE); + dwarf_strp(dwarf_info_section, + (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM + ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); + dwarf_uleb128(dwarf_info_section, t->c); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + pos_sib = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + e = t; + i = 0; + while (e->next) { + e = e->next; + if (e->type.t & VT_BITFIELD) { + int pos = e->c * 8 + BIT_POS(e->type.t); + int size = BIT_SIZE(e->type.t); + + dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER_BF); + dwarf_strp(dwarf_info_section, + (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM + ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + pos_type[i++] = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + dwarf_uleb128(dwarf_info_section, size); + dwarf_uleb128(dwarf_info_section, pos); + } + else { + dwarf_data1(dwarf_info_section, DWARF_ABBREV_MEMBER); + dwarf_strp(dwarf_info_section, + (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM + ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + pos_type[i++] = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + dwarf_uleb128(dwarf_info_section, e->c); + } + } + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + pos_sib, + dwarf_info_section->data_offset - dwarf_info.start); + e = t; + i = 0; + while (e->next) { + e = e->next; + type = tcc_get_dwarf_info(s1, e); + write32le(dwarf_info_section->data + pos_type[i++], + type - dwarf_info.start); + } + tcc_free(pos_type); + if (debug_info) + tcc_debug_remove(t); + } + } + else if (IS_ENUM(type)) { + t = t->type.ref; + debug_type = tcc_debug_find(t); + if (debug_type == -1) { + int pos_sib, pos_type; + CType ct = { VT_INT | (type & VT_UNSIGNED) , NULL }; + Sym sym = { .type = ct }; + + pos_type = tcc_get_dwarf_info(s1, &sym); + debug_type = tcc_debug_add(t, 1); + dwarf_data1(dwarf_info_section, DWARF_ABBREV_ENUMERATION_TYPE); + dwarf_strp(dwarf_info_section, + (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM + ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL)); + dwarf_data1(dwarf_info_section, + type & VT_UNSIGNED ? DW_ATE_unsigned : DW_ATE_signed ); + dwarf_data1(dwarf_info_section, 4); + dwarf_data4(dwarf_info_section, pos_type - dwarf_info.start); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + pos_sib = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + e = t; + while (e->next) { + e = e->next; + dwarf_data1(dwarf_info_section, DWARF_ABBREV_ENUMERATOR); + dwarf_strp(dwarf_info_section, + (e->v & ~SYM_FIELD) >= SYM_FIRST_ANOM + ? "" : get_tok_str(e->v & ~SYM_FIELD, NULL)); + dwarf_data4(dwarf_info_section, e->enum_val); + } + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + pos_sib, + dwarf_info_section->data_offset - dwarf_info.start); + if (debug_info) + tcc_debug_remove(t); + } + } + else if ((type & VT_BTYPE) != VT_FUNC) { + type &= ~VT_STRUCT_MASK; + for (i = 1; i <= N_DEFAULT_DEBUG; i++) + if (default_debug[i - 1].type == type) + break; + if (i > N_DEFAULT_DEBUG) + return 0; + debug_type = dwarf_info.base_type_used[i - 1]; + if (debug_type == 0) { + char name[100]; + + debug_type = dwarf_info_section->data_offset; + dwarf_data1(dwarf_info_section, DWARF_ABBREV_BASE_TYPE); + dwarf_uleb128(dwarf_info_section, default_debug[i - 1].size); + dwarf_data1(dwarf_info_section, default_debug[i - 1].encoding); + strncpy(name, default_debug[i - 1].name, sizeof(name) -1); + *strchr(name, ':') = 0; + dwarf_strp(dwarf_info_section, name); + dwarf_info.base_type_used[i - 1] = debug_type; + } + } + t = s; + for (;;) { + type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); + if ((type & VT_BTYPE) != VT_BYTE) + type &= ~VT_DEFSIGN; + if (type == VT_PTR) { + i = dwarf_info_section->data_offset; + dwarf_data1(dwarf_info_section, DWARF_ABBREV_POINTER); + dwarf_data1(dwarf_info_section, PTR_SIZE); + dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); + debug_type = i; + } + else if (type == (VT_PTR | VT_ARRAY)) { + int sib_pos, sub_type; + CType ct = { VT_INT | VT_UNSIGNED , NULL }; + Sym sym = { .type = ct }; + + sub_type = tcc_get_dwarf_info(s1, &sym); + i = dwarf_info_section->data_offset; + dwarf_data1(dwarf_info_section, DWARF_ABBREV_ARRAY_TYPE); + dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); + sib_pos = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); + for (;;) { + dwarf_data1(dwarf_info_section, DWARF_ABBREV_SUBRANGE_TYPE); + dwarf_data4(dwarf_info_section, sub_type - dwarf_info.start); + dwarf_uleb128(dwarf_info_section, t->type.ref->c - 1); + s = t->type.ref; + type = s->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); + if (type != (VT_PTR | VT_ARRAY)) + break; + t = s; + } + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + sib_pos, + dwarf_info_section->data_offset - dwarf_info.start); + debug_type = i; + } + else if (type == VT_FUNC) { + return tcc_get_dwarf_info (s1, t->type.ref); + } + else + break; + t = t->type.ref; + } + return debug_type; +} + static void tcc_debug_finish (TCCState *s1, struct debug_info *cur) { + if (s1->dwarf) { + while (cur) { + int i; + struct debug_info *next = cur->next; + + for (i = cur->n_sym - 1; i >= 0; i--) { + struct debug_sym *s = &cur->sym[i]; + + dwarf_data1(dwarf_info_section, + s->type == N_PSYM + ? DWARF_ABBREV_FORMAL_PARAMETER + : s->type == N_GSYM + ? DWARF_ABBREV_VARIABLE_EXTERNAL + : s->type == N_STSYM + ? DWARF_ABBREV_VARIABLE_STATIC + : DWARF_ABBREV_VARIABLE_LOCAL); + dwarf_strp(dwarf_info_section, s->str); + if (s->type == N_GSYM || s->type == N_STSYM) { + dwarf_uleb128(dwarf_info_section, s->file); + dwarf_uleb128(dwarf_info_section, s->line); + } + dwarf_data4(dwarf_info_section, s->info - dwarf_info.start); + if (s->type == N_GSYM || s->type == N_STSYM) { + /* global/static */ + if (s->type == N_GSYM) + dwarf_data1(dwarf_info_section, 1); + dwarf_data1(dwarf_info_section, PTR_SIZE + 1); + dwarf_data1(dwarf_info_section, DW_OP_addr); + if (s->type == N_STSYM) + dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_info_section, s->value); +#else + dwarf_data8(dwarf_info_section, s->value); +#endif + } + else { + /* param/local */ + dwarf_data1(dwarf_info_section, dwarf_sleb128_size(s->value) + 1); + dwarf_data1(dwarf_info_section, DW_OP_fbreg); + dwarf_sleb128(dwarf_info_section, s->value); + } + tcc_free (s->str); + } + tcc_free (cur->sym); + dwarf_data1(dwarf_info_section, DWARF_ABBREV_LEXICAL_BLOCK); + dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_info_section, func_ind + cur->start); + dwarf_data4(dwarf_info_section, cur->end - cur->start); +#else + dwarf_data8(dwarf_info_section, func_ind + cur->start); + dwarf_data8(dwarf_info_section, cur->end - cur->start); +#endif + tcc_debug_finish (s1, cur->child); + dwarf_data1(dwarf_info_section, 0); + tcc_free (cur); + cur = next; + } + } while (cur) { int i; struct debug_info *next = cur->next; @@ -720,10 +1713,19 @@ static void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e) for (; s != e; s = s->prev) { if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL) continue; - cstr_reset (&debug_str); - cstr_printf (&debug_str, "%s:%s", get_tok_str(s->v, NULL), param ? "p" : ""); - tcc_get_debug_info(s1, s, &debug_str); - tcc_debug_stabs(s1, debug_str.data, param ? N_PSYM : N_LSYM, s->c, NULL, 0); + if (s1->dwarf) { + tcc_debug_stabs(s1, get_tok_str(s->v, NULL), + param ? N_PSYM : N_LSYM, s->c, NULL, 0, + tcc_get_dwarf_info(s1, s)); + } + else { + cstr_reset (&debug_str); + cstr_printf (&debug_str, "%s:%s", get_tok_str(s->v, NULL), + param ? "p" : ""); + tcc_get_debug_info(s1, s, &debug_str); + tcc_debug_stabs(s1, debug_str.data, param ? N_PSYM : N_LSYM, + s->c, NULL, 0, 0); + } } cstr_free (&debug_str); } @@ -739,23 +1741,83 @@ static void tcc_debug_funcstart(TCCState *s1, Sym *sym) debug_info = NULL; tcc_debug_stabn(s1, N_LBRAC, ind - func_ind); if (!(f = put_new_file(s1))) - return; - cstr_new (&debug_str); - cstr_printf(&debug_str, "%s:%c", funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); - tcc_get_debug_info(s1, sym->type.ref, &debug_str); - put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c); - cstr_free (&debug_str); - + return; tcc_debug_line(s1); + if (s1->dwarf) { + dwarf_info.func = sym; + dwarf_info.line = file->line_num; + if (s1->do_backtrace) { + int i; + + dwarf_line_op(0); // extended + dwarf_uleb128_op(strlen(funcname) + 2); + dwarf_line_op(DW_LNE_hi_user - 1); + for (i = 0; i < strlen(funcname) + 1; i++) + dwarf_line_op(funcname[i]); + } + } + else { + cstr_new (&debug_str); + cstr_printf(&debug_str, "%s:%c", funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); + tcc_get_debug_info(s1, sym->type.ref, &debug_str); + put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c); + cstr_free (&debug_str); + } } /* put function size */ static void tcc_debug_funcend(TCCState *s1, int size) { + int func_sib = 0; + if (!s1->do_debug) return; + tcc_debug_line(s1); tcc_debug_stabn(s1, N_RBRAC, size); + if (s1->dwarf) { + Sym *sym = dwarf_info.func; + int debug_info = tcc_get_dwarf_info(s1, sym->type.ref); + + dwarf_data1(dwarf_info_section, + sym->type.t & VT_STATIC ? DWARF_ABBREV_SUBPROGRAM_STATIC + : DWARF_ABBREV_SUBPROGRAM_EXTERNAL); + if ((sym->type.t & VT_STATIC) == 0) + dwarf_data1(dwarf_info_section, 1); + dwarf_strp(dwarf_info_section, funcname); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, dwarf_info.line); + dwarf_data4(dwarf_info_section, debug_info - dwarf_info.start); + dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_info_section, func_ind); // low_pc + dwarf_data4(dwarf_info_section, size); // high_pc +#else + dwarf_data8(dwarf_info_section, func_ind); // low_pc + dwarf_data8(dwarf_info_section, size); // high_pc +#endif + func_sib = dwarf_info_section->data_offset; + dwarf_data4(dwarf_info_section, 0); // sibling + dwarf_data1(dwarf_info_section, 1); +#if defined(TCC_TARGET_I386) + dwarf_data1(dwarf_info_section, DW_OP_reg5); // ebp +#elif defined(TCC_TARGET_X86_64) + dwarf_data1(dwarf_info_section, DW_OP_reg6); // rbp +#elif defined TCC_TARGET_ARM + dwarf_data1(dwarf_info_section, DW_OP_reg13); // sp +#elif defined TCC_TARGET_ARM64 + dwarf_data1(dwarf_info_section, DW_OP_reg29); // reg 29 +#elif defined TCC_TARGET_RISCV64 + dwarf_data1(dwarf_info_section, DW_OP_reg8); // r8(s0) +#else + dwarf_data1(dwarf_info_section, DW_OP_call_frame_cfa); +#endif + } tcc_debug_finish (s1, debug_info_root); + if (s1->dwarf) { + dwarf_data1(dwarf_info_section, 0); + write32le(dwarf_info_section->data + func_sib, + dwarf_info_section->data_offset - dwarf_info.start); + } } @@ -769,19 +1831,44 @@ static void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bin if (sym_type == STT_FUNC || sym->v >= SYM_FIRST_ANOM) return; s = s1->sections[sh_num]; + if (s1->dwarf) { + int debug_type; + + debug_type = tcc_get_dwarf_info(s1, sym); + dwarf_data1(dwarf_info_section, + sym_bind == STB_GLOBAL + ? DWARF_ABBREV_VARIABLE_EXTERNAL + : DWARF_ABBREV_VARIABLE_STATIC); + dwarf_strp(dwarf_info_section, get_tok_str(sym->v, NULL)); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); + if (sym_bind == STB_GLOBAL) + dwarf_data1(dwarf_info_section, 1); + dwarf_data1(dwarf_info_section, PTR_SIZE + 1); + dwarf_data1(dwarf_info_section, DW_OP_addr); + greloca(dwarf_info_section, sym, dwarf_info_section->data_offset, + R_DATA_PTR, 0); +#if PTR_SIZE == 4 + dwarf_data4(dwarf_info_section, 0); +#else + dwarf_data8(dwarf_info_section, 0); +#endif + return; + } cstr_new (&str); cstr_printf (&str, "%s:%c", - get_tok_str(sym->v, NULL), - sym_bind == STB_GLOBAL ? 'G' : local_scope ? 'V' : 'S' - ); + get_tok_str(sym->v, NULL), + sym_bind == STB_GLOBAL ? 'G' : local_scope ? 'V' : 'S' + ); tcc_get_debug_info(s1, sym, &str); if (sym_bind == STB_GLOBAL) - tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0); + tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0, 0); else tcc_debug_stabs(s1, str.data, (sym->type.t & VT_STATIC) && data_section == s - ? N_STSYM : N_LCSYM, 0, s, sym->c); + ? N_STSYM : N_LCSYM, 0, s, sym->c, 0); cstr_free (&str); } @@ -791,12 +1878,25 @@ static void tcc_debug_typedef(TCCState *s1, Sym *sym) if (!s1->do_debug) return; + if (s1->dwarf) { + int debug_type; + + debug_type = tcc_get_dwarf_info(s1, sym); + if (debug_type != -1) { + dwarf_data1(dwarf_info_section, DWARF_ABBREV_TYPEDEF); + dwarf_strp(dwarf_info_section, get_tok_str(sym->v & ~SYM_FIELD, NULL)); + dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file); + dwarf_uleb128(dwarf_info_section, file->line_num); + dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start); + } + return; + } cstr_new (&str); cstr_printf (&str, "%s:t", (sym->v & ~SYM_FIELD) >= SYM_FIRST_ANOM ? "" : get_tok_str(sym->v & ~SYM_FIELD, NULL)); tcc_get_debug_info(s1, sym, &str); - tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); + tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0); cstr_free (&str); } @@ -973,7 +2073,7 @@ ST_FUNC int tccgen_compile(TCCState *s1) const_wanted = 0; nocode_wanted = 0x80000000; local_scope = 0; - debug_modes = s1->do_debug | s1->test_coverage << 1; + debug_modes = (s1->do_debug ? 1 : 0) | s1->test_coverage << 1; tcc_debug_start(s1); tcc_tcov_start (); diff --git a/tccrun.c b/tccrun.c index 9c9f4e07..d79da200 100644 --- a/tccrun.c +++ b/tccrun.c @@ -27,8 +27,16 @@ typedef struct rt_context { /* --> tccelf.c:tcc_add_btstub wants those below in that order: */ - Stab_Sym *stab_sym, *stab_sym_end; - char *stab_str; + union { + struct { + Stab_Sym *stab_sym, *stab_sym_end; + char *stab_str; + }; + struct { + unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str; + addr_t dwarf_text; + }; + }; ElfW(Sym) *esym_start, *esym_end; char *elf_str; addr_t prog_base; @@ -169,9 +177,18 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) memset(rc, 0, sizeof *rc); if (s1->do_debug) { void *p; - rc->stab_sym = (Stab_Sym *)stab_section->data; - rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); - rc->stab_str = (char *)stab_section->link->data; + if (s1->dwarf) { + rc->dwarf_line = dwarf_line_section->data; + rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset; + rc->dwarf_line_str = dwarf_line_str_section->data; + rc->dwarf_text = text_section->sh_addr; + } + else { + rc->stab_sym = (Stab_Sym *)stab_section->data; + rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); + rc->stab_str = (char *)stab_section->link->data; + rc->dwarf_text = 0; + } rc->esym_start = (ElfW(Sym) *)(symtab_section->data); rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); rc->elf_str = (char *)symtab_section->link->data; @@ -571,6 +588,337 @@ found: return func_addr; } +#define MAX_128 ((8 * sizeof (long long) + 6) / 7) + +#define DW_GETC(s,e) ((s) < (e) ? *(s)++ : 0) + +#define DIR_TABLE_SIZE (64) +#define FILE_TABLE_SIZE (256) + +static unsigned long long +dwarf_read_uleb128(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + unsigned long long retval = 0; + int i; + + for (i = 0; i < MAX_128; i++) { + unsigned long long byte = DW_GETC(cp, end); + + retval |= (byte & 0x7f) << (i * 7); + if ((byte & 0x80) == 0) + break; + } + *ln = cp; + return retval; +} + +static long long +dwarf_read_sleb128(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + long long retval = 0; + int i; + + for (i = 0; i < MAX_128; i++) { + unsigned long long byte = DW_GETC(cp, end); + + retval |= (byte & 0x7f) << (i * 7); + if ((byte & 0x80) == 0) { + if ((byte & 0x40) && (i + 1) * 7 < 64) + retval |= -1LL << ((i + 1) * 7); + break; + } + } + *ln = cp; + return retval; +} + +static unsigned int dwarf_read_32(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + unsigned int retval = 0; + + if ((cp + 4) < end) { + retval = read32le(cp); + cp += 4; + } + *ln = cp; + return retval; +} + +#if PTR_SIZE == 8 +static unsigned long long dwarf_read_64(unsigned char **ln, unsigned char *end) +{ + unsigned char *cp = *ln; + unsigned long long retval = 0; + + if ((cp + 8) < end) { + retval = read64le(cp); + cp += 8; + } + *ln = cp; + return retval; +} +#endif + +static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, + const char *msg, const char *skip) +{ + unsigned char *ln; + unsigned char *cp; + unsigned char *end; + unsigned int size; + unsigned char version; + unsigned int min_insn_length; + unsigned int max_ops_per_insn; + int line_base; + unsigned int line_range; + unsigned int opcode_base; + unsigned int opindex; + unsigned int col; + unsigned int i; + unsigned int len; + unsigned int dir_size; +#if 0 + char *dirs[DIR_TABLE_SIZE]; +#endif + unsigned int filename_size; + struct dwarf_filename_struct { + unsigned int dir_entry; + char *name; + } filename_table[FILE_TABLE_SIZE]; + addr_t last_pc; + addr_t pc; + addr_t func_addr; + int line; + char *filename; + char *function; + ElfW(Sym) *esym; + +next: + ln = rc->dwarf_line; + while (ln < rc->dwarf_line_end) { + dir_size = 0; + filename_size = 0; + last_pc = 0; + pc = 0; + func_addr = -1; + line = 1; + filename = NULL; + function = NULL; + size = dwarf_read_32(&ln, rc->dwarf_line_end); + end = ln + size; + version = DW_GETC(ln, end); + version += DW_GETC(ln, end) << 8; + if (version >= 5) + ln += 6; // address size, segment selector, prologue Length + else + ln += 4; // prologue Length + min_insn_length = DW_GETC(ln, end); + if (version >= 4) + max_ops_per_insn = DW_GETC(ln, end); + else + max_ops_per_insn = 1; + ln++; // Initial value of 'is_stmt' + line_base = DW_GETC(ln, end); + line_base |= line_base >= 0x80 ? ~0xff : 0; + line_range = DW_GETC(ln, end); + opcode_base = DW_GETC(ln, end); + opindex = 0; + ln += 12; + if (version >= 5) { + col = DW_GETC(ln, end); + for (i = 0; i < col * 2; i++) + dwarf_read_uleb128(&ln, end); + dir_size = dwarf_read_uleb128(&ln, end); + for (i = 0; i < dir_size; i++) +#if 0 + if (i < DIR_TABLE_SIZE) + dirs[i] = (char *)rc->dwarf_line_str + dwarf_read_32(&ln, end); + else +#endif + dwarf_read_32(&ln, end); + col = DW_GETC(ln, end); + for (i = 0; i < col * 2; i++) + dwarf_read_uleb128(&ln, end); + filename_size = dwarf_read_uleb128(&ln, end); + for (i = 0; i < filename_size; i++) + if (i < FILE_TABLE_SIZE) { + filename_table[i].name = (char *)rc->dwarf_line_str + dwarf_read_32(&ln, end); + filename_table[i].dir_entry = dwarf_read_uleb128(&ln, end); + } + else { + dwarf_read_32(&ln, end); + dwarf_read_uleb128(&ln, end); + } + } + else { + while ((i = DW_GETC(ln, end))) { +#if 0 + if (++dir_size < DIR_TABLE_SIZE) + dirs[dir_size - 1] = (char *)ln - 1; +#endif + while (DW_GETC(ln, end)) {} + } + while ((i = DW_GETC(ln, end))) { + if (++filename_size < FILE_TABLE_SIZE) { + filename_table[filename_size - 1].name = (char *)ln - 1; + while (DW_GETC(ln, end)) {} + filename_table[filename_size - 1].dir_entry = + dwarf_read_uleb128(&ln, end); + } + else { + while (DW_GETC(ln, end)) {} + dwarf_read_uleb128(&ln, end); + } + dwarf_read_uleb128(&ln, end); // time + dwarf_read_uleb128(&ln, end); // size + } + } + while (ln < end) { + last_pc = pc; + switch (DW_GETC(ln, end)) { + case 0: + len = dwarf_read_uleb128(&ln, end); + cp = ln; + ln += len; + if (len == 0) + goto next_line; + switch (DW_GETC(cp, end)) { + case DW_LNE_end_sequence: + goto next_line; + case DW_LNE_set_address: +#if PTR_SIZE == 4 + dwarf_read_32(&cp, end); +#else + dwarf_read_64(&cp, end); +#endif + pc = rc->dwarf_text; + opindex = 0; + break; + case DW_LNE_define_file: /* deprecated */ + break; + case DW_LNE_set_discriminator: + dwarf_read_uleb128(&cp, end); + break; + case DW_LNE_hi_user - 1: + function = (char *)cp; + func_addr = pc; + break; + default: + break; + } + break; + case DW_LNS_copy: + break; + case DW_LNS_advance_pc: + if (max_ops_per_insn == 1) + pc += dwarf_read_uleb128(&ln, end) * min_insn_length; + else { + unsigned long long off = dwarf_read_uleb128(&ln, end); + + pc += (opindex + off) / max_ops_per_insn * + min_insn_length; + opindex = (opindex + off) % max_ops_per_insn; + } + i = 0; + goto check_pc; + case DW_LNS_advance_line: + line += dwarf_read_sleb128(&ln, end); + break; + case DW_LNS_set_file: + i = dwarf_read_uleb128(&ln, end); + if (i < FILE_TABLE_SIZE && i < filename_size) + filename = filename_table[i].name; + break; + case DW_LNS_set_column: + dwarf_read_uleb128(&ln, end); + break; + case DW_LNS_negate_stmt: + break; + case DW_LNS_set_basic_block: + break; + case DW_LNS_const_add_pc: + if (max_ops_per_insn == 1) + pc += ((255 - opcode_base) / line_range) * min_insn_length; + else { + unsigned int off = (255 - opcode_base) / line_range; + + pc += ((opindex + off) / max_ops_per_insn) * + min_insn_length; + opindex = (opindex + off) % max_ops_per_insn; + } + i = 0; + goto check_pc; + case DW_LNS_fixed_advance_pc: + i = DW_GETC(ln, end); + i += DW_GETC(ln, end) << 8; + pc += i; + opindex = 0; + i = 0; + goto check_pc; + case DW_LNS_set_prologue_end: + break; + case DW_LNS_set_epilogue_begin: + break; + case DW_LNS_set_isa: + dwarf_read_uleb128(&ln, end); + break; + default: + i = ln[-1]; + if (max_ops_per_insn == 1) + pc += ((i - opcode_base) / line_range) * min_insn_length; + else { + pc += (opindex + (i - opcode_base) / line_range) / + max_ops_per_insn * min_insn_length; + opindex = (opindex + (i - opcode_base) / line_range) % + max_ops_per_insn; + } + i = (int)((i - opcode_base) % line_range) + line_base; +check_pc: + if (pc >= wanted_pc && wanted_pc >= last_pc) + goto found; + line += i; + break; + } + } +next_line: + ln = end; + } + + filename = NULL; + function = NULL; + func_addr = -1; + + /* we try symtab symbols (no line number info) */ + for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) { + int type = ELFW(ST_TYPE)(esym->st_info); + if (type == STT_FUNC || type == STT_GNU_IFUNC) { + if (wanted_pc >= esym->st_value && + wanted_pc < esym->st_value + esym->st_size) { + function = rc->elf_str + esym->st_name; + func_addr = esym->st_value; + goto found; + } + } + } + + if ((rc = rc->next)) + goto next; + +found: + if (filename) { + if (skip[0] && strstr(filename, skip)) + return (addr_t)-1; + rt_printf("%s:%d: ", filename, line); + } + else + rt_printf("0x%08llx : ", (long long)wanted_pc); + rt_printf("%s %s", msg, function ? function : "???"); + return (addr_t)func_addr; +} + static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level); static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) @@ -603,7 +951,10 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) ret = rt_get_caller_pc(&pc, rc, i); a = "%s"; if (ret != -1) { - pc = rt_printline(rc, pc, level ? "by" : "at", skip); + if ((addr_t)rc->dwarf_text) + pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip); + else + pc = rt_printline(rc, pc, level ? "by" : "at", skip); if (pc == (addr_t)-1) continue; a = ": %s"; diff --git a/tests/tests2/126_bound_global.c b/tests/tests2/126_bound_global.c new file mode 100644 index 00000000..d3a5c3b4 --- /dev/null +++ b/tests/tests2/126_bound_global.c @@ -0,0 +1,13 @@ +/* test bound checking code without -run */ + +int arr[10]; + +int +main(int argc, char **argv) +{ + int i; + + for (i = 0; i <= sizeof(arr)/sizeof(arr[0]); i++) + arr[i] = 0; + return 0; +} diff --git a/tests/tests2/126_bound_global.expect b/tests/tests2/126_bound_global.expect new file mode 100644 index 00000000..fcdea900 --- /dev/null +++ b/tests/tests2/126_bound_global.expect @@ -0,0 +1,2 @@ +126_bound_global.c:11: at main: BCHECK: ........ is outside of the region +126_bound_global.c:11: at main: RUNTIME ERROR: invalid memory access diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index a75ea6b6..776c7276 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -58,6 +58,9 @@ ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS))) SKIP += 114_bound_signal.test # libc problem signal/fork SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c endif +ifneq (,$(filter Darwin,$(TARGETOS))) + SKIP += 126_bound_global.test # bt-exe.c problem on apple +endif # Some tests might need arguments ARGS = @@ -100,7 +103,7 @@ GEN-ALWAYS = 108_constructor.test: NORUN = true 112_backtrace.test: FLAGS += -dt -b -112_backtrace.test 113_btdll.test: FILTER += \ +112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \ -e 's;[0-9A-Fa-fx]\{5,\};........;g' \ -e 's;0x[0-9A-Fa-f]\{1,\};0x?;g' @@ -122,6 +125,8 @@ ifneq ($(CONFIG_bcheck),no) endif 125_atomic_misc.test: FLAGS += -dt 124_atomic_counter.test: FLAGS += -pthread +126_bound_global.test: FLAGS += -b +126_bound_global.test: NORUN = true # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' diff --git a/x86_64-gen.c b/x86_64-gen.c index 6641901f..29871d57 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -701,7 +701,7 @@ static void gen_bounds_epilog(void) *bounds_ptr = 0; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); + func_bound_offset, PTR_SIZE); /* generate bound local allocation */ if (offset_modified) { diff --git a/x86_64-link.c b/x86_64-link.c index 6bffb059..abd6ddb9 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -4,6 +4,7 @@ /* relocation type for 32 bit data relocation */ #define R_DATA_32 R_X86_64_32S +#define R_DATA_32U R_X86_64_32 #define R_DATA_PTR R_X86_64_64 #define R_JMP_SLOT R_X86_64_JUMP_SLOT #define R_GLOB_DAT R_X86_64_GLOB_DAT