diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h index 1234567..abcdefg 100644 --- a/libdwarf/dwarf.h +++ b/libdwarf/dwarf.h @@ -45,6 +45,7 @@ #define DW_DWARF_VERS2 2 #define DW_DWARF_VERS3 3 #define DW_DWARF_VERS4 4 +#define DW_DWARF_VERS5 5 /* DWARF section names. */ #define DW_SEC_INFO ".debug_info" @@ -61,6 +62,10 @@ #define DW_SEC_TYPES ".debug_types" #define DW_SEC_GDB_INDEX ".gdb_index" +/* DWARF 5 section names. */ +#define DW_SEC_ADDR ".debug_addr" +#define DW_SEC_LINE_STR ".debug_line_str" +#define DW_SEC_STR_OFFSETS ".debug_str_offsets" +#define DW_SEC_RNGLISTS ".debug_rnglists" +#define DW_SEC_LOCLISTS ".debug_loclists" + /* DWARF access method. */ #define DW_ACCESS_DIRECT 0 #define DW_ACCESS_BUFFER 1 @@ -148,6 +153,19 @@ #define DW_TAG_GNU_call_site_parameter 0x4109 #define DW_TAG_GNU_template_parameter_pack 0x4107 +/* DWARF 5 tags. */ +#define DW_TAG_atomic_type 0x47 +#define DW_TAG_call_site 0x48 +#define DW_TAG_call_site_parameter 0x49 +#define DW_TAG_skeleton_unit 0x4a +#define DW_TAG_immutable_type 0x4b +#define DW_TAG_coarray_type 0x50 +#define DW_TAG_generic_subrange 0x51 +#define DW_TAG_dynamic_type 0x52 +#define DW_TAG_LLVM_annotation 0x6000 +#define DW_TAG_format_label 0x4101 +#define DW_TAG_function_template 0x4102 +#define DW_TAG_class_template 0x4103 + /* Children Determination Values. */ #define DW_CHILDREN_no 0x0 #define DW_CHILDREN_yes 0x1 @@ -285,6 +303,30 @@ #define DW_AT_GNU_dwo_name 0x2130 #define DW_AT_GNU_dwo_id 0x2131 +/* DWARF 5 attributes. */ +#define DW_AT_reference 0x77 +#define DW_AT_rvalue_reference 0x78 +#define DW_AT_macros 0x79 +#define DW_AT_call_all_calls 0x7a +#define DW_AT_call_all_source_calls 0x7b +#define DW_AT_call_all_tail_calls 0x7c +#define DW_AT_call_return_pc 0x7d +#define DW_AT_call_value 0x7e +#define DW_AT_call_origin 0x7f +#define DW_AT_call_parameter 0x80 +#define DW_AT_call_pc 0x81 +#define DW_AT_call_tail_call 0x82 +#define DW_AT_call_target 0x83 +#define DW_AT_call_target_clobbered 0x84 +#define DW_AT_call_data_location 0x85 +#define DW_AT_call_data_value 0x86 +#define DW_AT_noreturn 0x87 +#define DW_AT_alignment 0x88 +#define DW_AT_export_symbols 0x89 +#define DW_AT_deleted 0x8a +#define DW_AT_defaulted 0x8b +#define DW_AT_loclists_base 0x8c + /* DWARF Form Classes. */ #define DW_FORM_addr 0x01 #define DW_FORM_block2 0x03 @@ -315,6 +357,21 @@ #define DW_FORM_GNU_strp_alt 0x1f21 #define DW_FORM_GNU_ref_alt 0x1f20 +/* DWARF 5 forms. */ +#define DW_FORM_addrx 0x1b +#define DW_FORM_strx 0x1a +#define DW_FORM_data16 0x1e +#define DW_FORM_line_strp 0x1f +#define DW_FORM_implicit_const 0x21 +#define DW_FORM_loclistx 0x22 +#define DW_FORM_rnglistx 0x23 +#define DW_FORM_ref_sup4 0x24 +#define DW_FORM_strp_sup 0x25 +#define DW_FORM_strx1 0x25 +#define DW_FORM_strx2 0x26 +#define DW_FORM_strx3 0x27 +#define DW_FORM_strx4 0x28 +#define DW_FORM_addrx1 0x29 +#define DW_FORM_addrx2 0x2a +#define DW_FORM_addrx3 0x2b +#define DW_FORM_addrx4 0x2c + /* DWARF Expression Operations. */ #define DW_OP_addr 0x03 #define DW_OP_deref 0x06 @@ -435,6 +492,25 @@ #define DW_OP_GNU_regval_type 0xf5 #define DW_OP_GNU_deref_type 0xf6 +/* DWARF 5 expressions. */ +#define DW_OP_addrx 0xa1 +#define DW_OP_constx 0xa2 +#define DW_OP_entry_value 0xa3 +#define DW_OP_const_type 0xa4 +#define DW_OP_regval_type 0xa5 +#define DW_OP_deref_type 0xa6 +#define DW_OP_xderef_type 0xa7 +#define DW_OP_convert 0xa8 +#define DW_OP_reinterpret 0xa9 + /* DWARF Base Type Encodings. */ #define DW_ATE_address 0x1 #define DW_ATE_boolean 0x2 @@ -456,6 +532,10 @@ #define DW_ATE_edited 0x80 #define DW_ATE_signed_fixed 0x81 #define DW_ATE_unsigned_fixed 0x82 +/* DWARF 5 base type encodings. */ +#define DW_ATE_UTF 0x10 +#define DW_ATE_UCS 0x11 +#define DW_ATE_ASCII 0x12 /* DWARF Decimal Sign Codes. */ #define DW_DS_unsigned 0x01 @@ -520,6 +600,26 @@ #define DW_LNS_set_epilogue_begin 0x0b #define DW_LNS_set_isa 0x0c +/* DWARF 5 line number standard opcodes. */ +#define DW_LNS_set_file 0x0d +#define DW_LNS_set_discriminator 0x0e + +/* DWARF 5 line number header entry format codes. */ +#define DW_LNCT_path 0x1 +#define DW_LNCT_directory_index 0x2 +#define DW_LNCT_timestamp 0x3 +#define DW_LNCT_size 0x4 +#define DW_LNCT_MD5 0x5 + +/* DWARF 5 unit header types. */ +#define DW_UT_compile 0x01 +#define DW_UT_type 0x02 +#define DW_UT_partial 0x03 +#define DW_UT_skeleton 0x04 +#define DW_UT_split_compile 0x05 +#define DW_UT_split_type 0x06 + /* DWARF Line Number Extended Opcodes. */ #define DW_LNE_end_sequence 0x01 #define DW_LNE_set_address 0x02 @@ -529,6 +629,9 @@ #define DW_LNE_HP_source_file_correlation 0x80 #define DW_LNE_lo_user 0x80 #define DW_LNE_hi_user 0xff +/* DWARF 5 line number extended opcodes. */ +#define DW_LNE_set_discriminator 0x04 +#define DW_LNE_HP_SFC 0x80 /* DWARF Macinfo Type Encodings. */ #define DW_MACINFO_define 0x01 @@ -548,6 +651,16 @@ #define DW_MACRO_GNU_transparent_include 0x0b #define DW_MACRO_GNU_lo_user 0xe0 #define DW_MACRO_GNU_hi_user 0xff +/* DWARF 5 macro information entry types. */ +#define DW_MACRO_define 0x01 +#define DW_MACRO_undef 0x02 +#define DW_MACRO_start_file 0x03 +#define DW_MACRO_end_file 0x04 +#define DW_MACRO_define_strp 0x05 +#define DW_MACRO_undef_strp 0x06 +#define DW_MACRO_import 0x07 +#define DW_MACRO_define_strx 0x0b +#define DW_MACRO_undef_strx 0x0c /* DWARF Call Frame Instruction Encodings. */ #define DW_CFA_advance_loc 0x40 @@ -640,6 +753,16 @@ #define DW_EH_PE_indirect 0x80 #define DW_EH_PE_omit 0xff +/* DWARF 5 Range List Entry Codes. */ +#define DW_RLE_end_of_list 0x00 +#define DW_RLE_base_addressx 0x01 +#define DW_RLE_startx_endx 0x02 +#define DW_RLE_startx_length 0x03 +#define DW_RLE_offset_pair 0x04 +#define DW_RLE_base_address 0x05 +#define DW_RLE_start_end 0x06 +#define DW_RLE_start_length 0x07 + /* DWARF List Terminator. */ #define DW_DLV_BADADDR (~0ULL) #define DW_DLV_NOCOUNT (~0U) @@ -714,6 +837,15 @@ typedef struct _Dwarf_CU { Dwarf_Unsigned cu_abbrev_offset_size; Dwarf_Half cu_pointer_size; Dwarf_Half cu_dwarf_size; + /* DWARF 5 fields */ + Dwarf_Small cu_unit_type; + Dwarf_Unsigned cu_type_signature; + Dwarf_Unsigned cu_type_offset; + Dwarf_Unsigned cu_addr_base; + Dwarf_Unsigned cu_str_offsets_base; + Dwarf_Unsigned cu_rnglists_base; + Dwarf_Unsigned cu_loclists_base; + Dwarf_Unsigned cu_line_str_base; STAILQ_HEAD(, _Dwarf_Die) cu_die; STAILQ_HEAD(, _Dwarf_Die) cu_die_search; RB_HEAD(die_tree, _Dwarf_Die) cu_die_tree; diff --git a/libdwarf/dwarf_init.c b/libdwarf/dwarf_init.c index 2345678..bcdefgh 100644 --- a/libdwarf/dwarf_init.c +++ b/libdwarf/dwarf_init.c @@ -98,6 +98,11 @@ static const char *debug_snames[] = { ".debug_pubtypes", ".debug_ranges", ".debug_static_func", + /* DWARF 5 sections */ + ".debug_addr", + ".debug_line_str", + ".debug_str_offsets", + ".debug_rnglists", + ".debug_loclists", ".debug_static_vars", ".debug_str", ".debug_types", @@ -123,6 +128,11 @@ static enum Dwarf_Section debug_sections[] = { DS_PUBTYPES, DS_RANGES, DS_STATIC_FUNC, + /* DWARF 5 sections */ + DS_ADDR, + DS_LINE_STR, + DS_STR_OFFSETS, + DS_RNGLISTS, + DS_LOCLISTS, DS_STATIC_VARS, DS_STR, DS_TYPES, @@ -185,6 +195,11 @@ _dwarf_info_first_cu(Dwarf_Debug dbg, Dwarf_Error *error) cu->cu_abbrev_offset = dbg->read(ds, &offset, dwarf_size); cu->cu_pointer_size = dbg->read(ds, &offset, 1); cu->cu_dwarf_size = dwarf_size; + + /* DWARF 5 additions */ + if (cu->cu_version >= 5) { + cu->cu_unit_type = dbg->read(ds, &offset, 1); + } /* Lookup abbrev table. */ ret = _dwarf_abbrev_add(cu, cu->cu_abbrev_offset, @@ -250,6 +265,17 @@ _dwarf_info_next_cu(Dwarf_Debug dbg, Dwarf_CU *cu, Dwarf_Error *error) next_cu->cu_abbrev_offset = dbg->read(ds, &offset, dwarf_size); next_cu->cu_pointer_size = dbg->read(ds, &offset, 1); next_cu->cu_dwarf_size = dwarf_size; + + /* DWARF 5 additions */ + if (next_cu->cu_version >= 5) { + next_cu->cu_unit_type = dbg->read(ds, &offset, 1); + + /* Handle type units */ + if (next_cu->cu_unit_type == DW_UT_type || + next_cu->cu_unit_type == DW_UT_split_type) { + next_cu->cu_type_signature = dbg->read(ds, &offset, 8); + next_cu->cu_type_offset = dbg->read(ds, &offset, dwarf_size); + } + } /* Lookup abbrev table. */ ret = _dwarf_abbrev_add(next_cu, next_cu->cu_abbrev_offset, diff --git a/libdwarf/dwarf_pro_init.c b/libdwarf/dwarf_pro_init.c index 3456789..cdefghi 100644 --- a/libdwarf/dwarf_pro_init.c +++ b/libdwarf/dwarf_pro_init.c @@ -45,6 +45,7 @@ dwarf_producer_init(Dwarf_Unsigned flags, Dwarf_Callback_Func func, dbg->dbg_isa = (flags >> 16) & 0xffff; dbg->dbg_dwarf_version = 4; /* Default to DWARF4 */ dbg->dbg_offset_size = 4; + dbg->dbg_format = DW_FORMAT_32BIT; dbg->dbg_pointer_size = pointer_size; dbg->dbg_errhand = errhand; dbg->dbg_errarg = errarg; @@ -64,6 +65,19 @@ dwarf_producer_init_b(Dwarf_Unsigned flags, Dwarf_Callback_Func func, return (DW_DLV_OK); } +int +dwarf_producer_init_c(Dwarf_Unsigned flags, Dwarf_Callback_Func func, + Dwarf_Handler errhand, Dwarf_Ptr errarg, Dwarf_Ptr user_data, + const char *abi, Dwarf_P_Debug *ret_dbg, Dwarf_Error *error) +{ + int ret; + + ret = dwarf_producer_init_b(flags, func, errhand, errarg, user_data, + abi, ret_dbg, error); + if (ret == DW_DLV_OK && *ret_dbg) + (*ret_dbg)->dbg_dwarf_version = 5; /* Default to DWARF5 */ + return ret; +} + int dwarf_transform_to_disk_form(Dwarf_P_Debug dbg, Dwarf_Error *error) { diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h index 4567890..defghij 100644 --- a/libdwarf/libdwarf.h +++ b/libdwarf/libdwarf.h @@ -145,6 +145,11 @@ enum Dwarf_Section { DS_PUBTYPES, DS_RANGES, DS_STATIC_FUNC, + /* DWARF 5 sections */ + DS_ADDR, + DS_LINE_STR, + DS_STR_OFFSETS, + DS_RNGLISTS, + DS_LOCLISTS, DS_STATIC_VARS, DS_STR, DS_TYPES, @@ -377,6 +382,8 @@ int dwarf_producer_init_b(Dwarf_Unsigned, Dwarf_Callback_Func, Dwarf_Handler, Dwarf_Ptr, Dwarf_Ptr, const char *, Dwarf_P_Debug *, Dwarf_Error *); int dwarf_producer_finish(Dwarf_P_Debug, Dwarf_Error *); +int dwarf_producer_init_c(Dwarf_Unsigned, Dwarf_Callback_Func, + Dwarf_Handler, Dwarf_Ptr, Dwarf_Ptr, const char *, + Dwarf_P_Debug *, Dwarf_Error *); int dwarf_reset_section_bytes(Dwarf_P_Debug, Dwarf_Error *); Dwarf_Unsigned dwarf_transform_to_disk_form(Dwarf_P_Debug, Dwarf_Error *); @@ -430,6 +437,10 @@ int dwarf_get_die_infotypes_flag(Dwarf_Die, Dwarf_Error *); int dwarf_get_version_of_die(Dwarf_Die, Dwarf_Half *, Dwarf_Error *); int dwarf_dieoffset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *); int dwarf_die_CU_offset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *); +int dwarf_cu_header_basics(Dwarf_Die, Dwarf_Half *, Dwarf_Half *, + Dwarf_Half *, Dwarf_Half *, Dwarf_Half *, Dwarf_Unsigned *, + Dwarf_Error *); + int dwarf_diename(Dwarf_Die, char **, Dwarf_Error *); int dwarf_hasattr(Dwarf_Die, Dwarf_Half, Dwarf_Bool *, Dwarf_Error *); int dwarf_attr(Dwarf_Die, Dwarf_Half, Dwarf_Attribute *, Dwarf_Error *); @@ -530,6 +541,14 @@ int dwarf_expand_frame_instructions(Dwarf_Cie, Dwarf_Ptr, Dwarf_Unsigned, Dwarf_Frame_Op3 **, Dwarf_Signed *, Dwarf_Error *); +/* DWARF 5 Address table functions */ +int dwarf_get_debug_addr_index(Dwarf_Die, Dwarf_Half, Dwarf_Unsigned *, + Dwarf_Error *); +int dwarf_debug_addr_table(Dwarf_Debug, Dwarf_Unsigned, Dwarf_Unsigned *, + Dwarf_Addr **, Dwarf_Error *); +int dwarf_get_str_from_str_offsets_table(Dwarf_Debug, Dwarf_Unsigned, + char **, Dwarf_Error *); + /* SGI/IRIX libdwarf interfaces. */ #define DW_FRAME_SAME_VAL 1035 #define DW_FRAME_UNDEFINED_VAL 1034 diff --git a/libdwarf/dwarf_form.c b/libdwarf/dwarf_form.c index 5678901..efghijk 100644 --- a/libdwarf/dwarf_form.c +++ b/libdwarf/dwarf_form.c @@ -98,6 +98,14 @@ dwarf_hasform(Dwarf_Attribute at, Dwarf_Half form, Dwarf_Bool *return_hasform, case DW_FORM_flag_present: case DW_FORM_ref_sig8: case DW_FORM_exprloc: + /* DWARF 5 forms */ + case DW_FORM_addrx: + case DW_FORM_strx: + case DW_FORM_data16: + case DW_FORM_line_strp: + case DW_FORM_implicit_const: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: if (at->at_form == form) { *return_hasform = 1; return (DW_DLV_OK); @@ -166,6 +174,13 @@ dwarf_whatform(Dwarf_Attribute at, Dwarf_Half *return_form, Dwarf_Error *error) case DW_FORM_flag_present: case DW_FORM_ref_sig8: case DW_FORM_exprloc: + /* DWARF 5 forms */ + case DW_FORM_addrx: + case DW_FORM_strx: + case DW_FORM_data16: + case DW_FORM_line_strp: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: *return_form = at->at_form; return (DW_DLV_OK); default: @@ -246,6 +261,16 @@ dwarf_formaddr(Dwarf_Attribute at, Dwarf_Addr *return_addr, Dwarf_Error *error) case DW_FORM_addr: *return_addr = at->u[0].u64; break; + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + /* Look up address in .debug_addr section */ + ret = _dwarf_get_addr_from_index(at->at_die, at->u[0].u64, + return_addr, error); + if (ret != DW_DLV_OK) + return (ret); + break; default: DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); @@ -398,6 +423,28 @@ dwarf_formstring(Dwarf_Attribute at, char **return_string, Dwarf_Error *error) if (ret != DW_DLV_OK) return (ret); break; + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + /* Look up string in .debug_str_offsets section */ + ret = _dwarf_get_string_from_index(at->at_die, at->u[0].u64, + return_string, error); + if (ret != DW_DLV_OK) + return (ret); + break; + case DW_FORM_line_strp: + /* String from .debug_line_str section */ + ret = _dwarf_get_string_from_section(dbg, DS_LINE_STR, + at->u[0].u64, return_string, error); + if (ret != DW_DLV_OK) + return (ret); + break; + case DW_FORM_strp_sup: + /* String from supplementary object file - not implemented */ + DWARF_SET_ERROR(dbg, error, DW_DLE_FORM_NOT_SUPPORTED); + return (DW_DLV_ERROR); default: DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD); return (DW_DLV_ERROR); diff --git a/libdwarf/dwarf_addr.c b/libdwarf/dwarf_addr.c new file mode 100644 index 0000000..1234567 --- /dev/null +++ b/libdwarf/dwarf_addr.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2025 The ELF Tool Chain Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)