diff options
author | Wez Furlong <wez@netevil.org> | 2011-04-03 16:00:01 -0400 |
---|---|---|
committer | Wez Furlong <wez@netevil.org> | 2011-04-03 16:00:01 -0400 |
commit | e9f8c2cd7be8f75fb1d6d9bdb7f3f418d5068e04 (patch) | |
tree | 98ef134b0997b71bc30b176d2752dab7eb3b2c1c | |
parent | ee2b74dbc88c21f3e6c53d6d4f09a69b271755e4 (diff) | |
download | ctf-e9f8c2cd7be8f75fb1d6d9bdb7f3f418d5068e04.tar.gz |
pull in the FreeBSD libdwarf, so that we can compile without an external
dependency.
-rw-r--r-- | Makefile.am | 19 | ||||
-rw-r--r-- | common/list.c | 1 | ||||
-rw-r--r-- | common/utils.c | 5 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | libctf/ctf_impl.h | 21 | ||||
-rw-r--r-- | libdwarf/_libdwarf.h | 164 | ||||
-rw-r--r-- | libdwarf/dwarf.h | 478 | ||||
-rw-r--r-- | libdwarf/dwarf_abbrev.c | 70 | ||||
-rw-r--r-- | libdwarf/dwarf_attr.c | 90 | ||||
-rw-r--r-- | libdwarf/dwarf_attrval.c | 267 | ||||
-rw-r--r-- | libdwarf/dwarf_cu.c | 68 | ||||
-rw-r--r-- | libdwarf/dwarf_dealloc.c | 41 | ||||
-rw-r--r-- | libdwarf/dwarf_die.c | 190 | ||||
-rw-r--r-- | libdwarf/dwarf_dump.c | 892 | ||||
-rw-r--r-- | libdwarf/dwarf_errmsg.c | 75 | ||||
-rw-r--r-- | libdwarf/dwarf_errno.c | 38 | ||||
-rw-r--r-- | libdwarf/dwarf_finish.c | 97 | ||||
-rw-r--r-- | libdwarf/dwarf_form.c | 47 | ||||
-rw-r--r-- | libdwarf/dwarf_init.c | 746 | ||||
-rw-r--r-- | libdwarf/dwarf_loc.c | 612 | ||||
-rw-r--r-- | libdwarf/libdwarf.h | 162 | ||||
-rw-r--r-- | libdwarf/queue.h | 636 | ||||
-rw-r--r-- | pctf/ctf_api.h | 1 |
23 files changed, 4711 insertions, 16 deletions
diff --git a/Makefile.am b/Makefile.am index e3c0bdd..f7f7a50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = ctfconvert ctfmerge ctfdump CFLAGS += -I$(top_srcdir) lib_LTLIBRARIES = libpctf.la -noinst_LTLIBRARIES = libpctfcommon.la libcvt.la +noinst_LTLIBRARIES = libpctfcommon.la libcvt.la libdwarf.la man1_MANS = man/ctfconvert.1 man/ctfmerge.1 man/ctfdump.1 include_HEADERS = pctf/libctf.h pctf/ctf_api.h pctf/ctf.h @@ -49,8 +49,23 @@ libcvt_la_SOURCES = \ cvt/traverse.c \ cvt/util.c +libdwarf_la_SOURCES = \ + libdwarf/dwarf_abbrev.c \ + libdwarf/dwarf_attr.c \ + libdwarf/dwarf_attrval.c \ + libdwarf/dwarf_cu.c \ + libdwarf/dwarf_dealloc.c \ + libdwarf/dwarf_die.c \ + libdwarf/dwarf_dump.c \ + libdwarf/dwarf_errmsg.c \ + libdwarf/dwarf_errno.c \ + libdwarf/dwarf_finish.c \ + libdwarf/dwarf_form.c \ + libdwarf/dwarf_init.c \ + libdwarf/dwarf_loc.c + ctfconvert_SOURCES = cvt/ctfconvert.c -ctfconvert_LDADD = libcvt.la libpctfcommon.la libpctf.la -ldwarf +ctfconvert_LDADD = libcvt.la libpctfcommon.la libpctf.la libdwarf.la ctfmerge_SOURCES = cvt/ctfmerge.c ctfmerge_LDADD = libcvt.la libpctfcommon.la libpctf.la diff --git a/common/list.c b/common/list.c index d5c796f..cc3b110 100644 --- a/common/list.c +++ b/common/list.c @@ -30,6 +30,7 @@ * Routines for manipulating linked lists */ +#include "libctf/ctf_impl.h" #include <stdio.h> #include <assert.h> #include <stdlib.h> diff --git a/common/utils.c b/common/utils.c index 49dc25e..f3443aa 100644 --- a/common/utils.c +++ b/common/utils.c @@ -46,6 +46,11 @@ getpname(void) p = getexecname(); #elif HAVE_GETPROGNAME p = getprogname(); +#elif defined(__linux__) + { + extern char *program_invocation_short_name; + p = program_invocation_short_name; + } #else # error dont know how to find my executable name #endif diff --git a/configure.ac b/configure.ac index 82ca2b1..0712796 100644 --- a/configure.ac +++ b/configure.ac @@ -23,12 +23,6 @@ getprogname \ AC_CHECK_LIB(z, uncompress) AC_CHECK_LIB(elf, gelf_getshdr) -AC_CHECK_LIB(dwarf, dwarf_elf_init, [ - AC_MSG_RESULT([you got dwarves]) -],[ - AC_ERROR([Need libdwarf for ctfconvert to operate]) -]) - AC_CHECK_LIB(pthread, pthread_create) AC_CHECK_HEADERS([ \ @@ -48,6 +42,7 @@ strings.h \ sys/elf.h \ sys/errno.h \ sys/mman.h \ +sys/param.h \ sys/stat.h \ sys/sysmacros.h \ unistd.h \ diff --git a/libctf/ctf_impl.h b/libctf/ctf_impl.h index f0f0d55..d7f0075 100644 --- a/libctf/ctf_impl.h +++ b/libctf/ctf_impl.h @@ -41,7 +41,7 @@ #if HAVE_SYS_ERRNO_H # include <sys/errno.h> #endif -#if HAVE_SYS_SYSMACROS_H +#ifdef sun # include <sys/sysmacros.h> #else # include "pctf/sysmacros.h" @@ -93,19 +93,26 @@ #if HAVE_SYS_ELF_H # include <sys/elf.h> #endif -#if HAVE_LIBDWARF_H -# include <libdwarf.h> -#endif #if HAVE_LIBGEN_H # include <libgen.h> #endif -#if HAVE_DWARF_H -# include <dwarf.h> -#endif +#include "libdwarf/dwarf.h" +#include "libdwarf/libdwarf.h" #if HAVE_STDINT_H # include <stdint.h> #endif #include <assert.h> +#if HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif +#include <signal.h> + +#ifndef NBBY +# define NBBY 8 +#endif +#ifndef __unused +# define __unused +#endif #ifdef __cplusplus extern "C" { diff --git a/libdwarf/_libdwarf.h b/libdwarf/_libdwarf.h new file mode 100644 index 0000000..0f55e49 --- /dev/null +++ b/libdwarf/_libdwarf.h @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/_libdwarf.h,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#ifndef __LIBDWARF_H_ +#define __LIBDWARF_H_ + +#include "libctf/ctf_impl.h" +#include "libdwarf/queue.h" + +#define DWARF_debug_abbrev 0 +#define DWARF_debug_aranges 1 +#define DWARF_debug_frame 2 +#define DWARF_debug_info 3 +#define DWARF_debug_line 4 +#define DWARF_debug_pubnames 5 +#define DWARF_eh_frame 6 +#define DWARF_debug_macinfo 7 +#define DWARF_debug_str 8 +#define DWARF_debug_loc 9 +#define DWARF_debug_pubtypes 10 +#define DWARF_debug_ranges 11 +#define DWARF_debug_static_func 12 +#define DWARF_debug_static_vars 13 +#define DWARF_debug_types 14 +#define DWARF_debug_weaknames 15 +#define DWARF_symtab 16 +#define DWARF_strtab 17 +#define DWARF_DEBUG_SNAMES 18 + +#define DWARF_DIE_HASH_SIZE 8191 + +#define DWARF_SET_ERROR(_e, _err) do { \ + _e->err_error = _err; \ + _e->elf_error = 0; \ + _e->err_func = __func__; \ + _e->err_line = __LINE__; \ + _e->err_msg[0] = '\0'; \ + } while (0) + +#define DWARF_SET_ELF_ERROR(_e, _err) do { \ + _e->err_error = DWARF_E_ELF; \ + _e->elf_error = _err; \ + _e->err_func = __func__; \ + _e->err_line = __LINE__; \ + _e->err_msg[0] = '\0'; \ + } while (0) + +struct _Dwarf_AttrValue { + uint64_t av_attrib; /* DW_AT_ */ + uint64_t av_form; /* DW_FORM_ */ + union { + uint64_t u64; + int64_t s64; + const char *s; + uint8_t *u8p; + } u[2]; /* Value. */ + STAILQ_ENTRY(_Dwarf_AttrValue) + av_next; /* Next attribute value. */ +}; + +struct _Dwarf_Die { + int die_level; /* Parent-child level. */ + uint64_t die_offset; /* DIE offset in section. */ + uint64_t die_abnum; /* Abbrev number. */ + Dwarf_Abbrev die_a; /* Abbrev pointer. */ + Dwarf_CU die_cu; /* Compilation unit pointer. */ + const char *die_name; /* Ptr to the name string. */ + STAILQ_HEAD(, _Dwarf_AttrValue) + die_attrval; /* List of attribute values. */ + STAILQ_ENTRY(_Dwarf_Die) + die_next; /* Next die in list. */ + STAILQ_ENTRY(_Dwarf_Die) + die_hash; /* Next die in hash table. */ +}; + +struct _Dwarf_Attribute { + uint64_t at_attrib; /* DW_AT_ */ + uint64_t at_form; /* DW_FORM_ */ + STAILQ_ENTRY(_Dwarf_Attribute) + at_next; /* Next attribute. */ +}; + +struct _Dwarf_Abbrev { + uint64_t a_entry; /* Abbrev entry. */ + uint64_t a_tag; /* Tag: DW_TAG_ */ + uint8_t a_children; /* DW_CHILDREN_no or DW_CHILDREN_yes */ + STAILQ_HEAD(, _Dwarf_Attribute) + a_attrib; /* List of attributes. */ + STAILQ_ENTRY(_Dwarf_Abbrev) + a_next; /* Next abbrev. */ +}; + +struct _Dwarf_CU { + uint64_t cu_offset; /* Offset to the this compilation unit. */ + uint32_t cu_length; /* Length of CU data. */ + uint32_t cu_header_length; + /* Length of the CU header. */ + uint16_t cu_version; /* DWARF version. */ + uint64_t cu_abbrev_offset; + /* Offset into .debug_abbrev. */ + uint8_t cu_pointer_size; + /* Number of bytes in pointer. */ + uint64_t cu_next_offset; + /* Offset to the next compilation unit. */ + STAILQ_HEAD(, _Dwarf_Abbrev) + cu_abbrev; /* List of abbrevs. */ + STAILQ_HEAD(, _Dwarf_Die) + cu_die; /* List of dies. */ + STAILQ_HEAD(, _Dwarf_Die) + cu_die_hash[DWARF_DIE_HASH_SIZE]; + /* Hash of dies. */ + STAILQ_ENTRY(_Dwarf_CU) + cu_next; /* Next compilation unit. */ +}; + +typedef struct _Dwarf_section { + Elf_Scn *s_scn; /* Section pointer. */ + GElf_Shdr s_shdr; /* Copy of the section header. */ + char *s_sname; /* Ptr to the section name. */ + uint32_t s_shnum; /* Section number. */ + Elf_Data *s_data; /* Section data. */ +} Dwarf_section; + +struct _Dwarf_Debug { + Elf *dbg_elf; /* Ptr to the ELF handle. */ + GElf_Ehdr dbg_ehdr; /* Copy of the ELF header. */ + int dbg_elf_close; /* True if elf_end() required. */ + int dbg_mode; /* Access mode. */ + size_t dbg_stnum; /* Section header string table section number. */ + int dbg_offsize; /* DWARF offset size. */ + Dwarf_section dbg_s[DWARF_DEBUG_SNAMES]; + /* Array of section information. */ + STAILQ_HEAD(, _Dwarf_CU) + dbg_cu; /* List of compilation units. */ + Dwarf_CU dbg_cu_current; + /* Ptr to the current compilation unit. */ +}; + +#endif /* !__LIBDWARF_H_ */ diff --git a/libdwarf/dwarf.h b/libdwarf/dwarf.h new file mode 100644 index 0000000..40e1229 --- /dev/null +++ b/libdwarf/dwarf.h @@ -0,0 +1,478 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf.h,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#ifndef _DWARF_H_ +#define _DWARF_H_ + +#define DW_TAG_array_type 0x01 +#define DW_TAG_class_type 0x02 +#define DW_TAG_entry_point 0x03 +#define DW_TAG_enumeration_type 0x04 +#define DW_TAG_formal_parameter 0x05 +#define DW_TAG_imported_declaration 0x08 +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +#define DW_TAG_member 0x0d +#define DW_TAG_pointer_type 0x0f +#define DW_TAG_reference_type 0x10 +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_string_type 0x12 +#define DW_TAG_structure_type 0x13 +#define DW_TAG_subroutine_type 0x15 +#define DW_TAG_typedef 0x16 +#define DW_TAG_union_type 0x17 +#define DW_TAG_unspecified_parameters 0x18 +#define DW_TAG_variant 0x19 +#define DW_TAG_common_block 0x1a +#define DW_TAG_common_inclusion 0x1b +#define DW_TAG_inheritance 0x1c +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_module 0x1e +#define DW_TAG_ptr_to_member_type 0x1f +#define DW_TAG_set_type 0x20 +#define DW_TAG_subrange_type 0x21 +#define DW_TAG_with_stmt 0x22 +#define DW_TAG_access_declaration 0x23 +#define DW_TAG_base_type 0x24 +#define DW_TAG_catch_block 0x25 +#define DW_TAG_const_type 0x26 +#define DW_TAG_constant 0x27 +#define DW_TAG_enumerator 0x28 +#define DW_TAG_friend 0x2a +#define DW_TAG_namelist 0x2b +#define DW_TAG_namelist_item 0x2c +#define DW_TAG_packed_type 0x2d +#define DW_TAG_subprogram 0x2e +#define DW_TAG_template_type_parameter 0x2f +#define DW_TAG_template_type_param 0x2f +#define DW_TAG_template_value_parameter 0x30 +#define DW_TAG_template_value_param 0x30 +#define DW_TAG_thrown_type 0x31 +#define DW_TAG_try_block 0x32 +#define DW_TAG_variant_part 0x33 +#define DW_TAG_variable 0x34 +#define DW_TAG_volatile_type 0x35 +#define DW_TAG_dwarf_procedure 0x36 +#define DW_TAG_restrict_type 0x37 +#define DW_TAG_interface_type 0x38 +#define DW_TAG_namespace 0x39 +#define DW_TAG_imported_module 0x3a +#define DW_TAG_unspecified_type 0x3b +#define DW_TAG_partial_unit 0x3c +#define DW_TAG_imported_unit 0x3d +#define DW_TAG_condition 0x3f +#define DW_TAG_shared_type 0x40 + +#define DW_TAG_lo_user 0x4080 + +#define DW_TAG_hi_user 0xffff + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +#define DW_AT_ordering 0x09 +#define DW_AT_subscr_data 0x0a +#define DW_AT_byte_size 0x0b +#define DW_AT_bit_offset 0x0c +#define DW_AT_bit_size 0x0d +#define DW_AT_element_list 0x0f +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_member 0x14 +#define DW_AT_discr 0x15 +#define DW_AT_discr_value 0x16 +#define DW_AT_visibility 0x17 +#define DW_AT_import 0x18 +#define DW_AT_string_length 0x19 +#define DW_AT_common_reference 0x1a +#define DW_AT_comp_dir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_default_value 0x1e +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_return_addr 0x2a +#define DW_AT_start_scope 0x2c +#define DW_AT_bit_stride 0x2e +#define DW_AT_stride_size 0x2e +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_address_class 0x33 +#define DW_AT_artificial 0x34 +#define DW_AT_base_types 0x35 +#define DW_AT_calling_convention 0x36 +#define DW_AT_count 0x37 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_column 0x39 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_discr_list 0x3d +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_friend 0x41 +#define DW_AT_identifier_case 0x42 +#define DW_AT_macro_info 0x43 +#define DW_AT_namelist_item 0x44 +#define DW_AT_priority 0x45 +#define DW_AT_segment 0x46 +#define DW_AT_specification 0x47 +#define DW_AT_static_link 0x48 +#define DW_AT_type 0x49 +#define DW_AT_use_location 0x4a +#define DW_AT_variable_parameter 0x4b +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d + +#define DW_AT_lo_user 0x2000 + +#define DW_AT_hi_user 0x3fff + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 + +#define DW_OP_addr 0x03 +#define DW_OP_deref 0x06 +#define DW_OP_const1u 0x08 +#define DW_OP_const1s 0x09 +#define DW_OP_const2u 0x0a +#define DW_OP_const2s 0x0b +#define DW_OP_const4u 0x0c +#define DW_OP_const4s 0x0d +#define DW_OP_const8u 0x0e +#define DW_OP_const8s 0x0f +#define DW_OP_constu 0x10 +#define DW_OP_consts 0x11 +#define DW_OP_dup 0x12 +#define DW_OP_drop 0x13 +#define DW_OP_over 0x14 +#define DW_OP_pick 0x15 +#define DW_OP_swap 0x16 +#define DW_OP_rot 0x17 +#define DW_OP_xderef 0x18 +#define DW_OP_abs 0x19 +#define DW_OP_and 0x1a +#define DW_OP_div 0x1b +#define DW_OP_minus 0x1c +#define DW_OP_mod 0x1d +#define DW_OP_mul 0x1e +#define DW_OP_neg 0x1f +#define DW_OP_not 0x20 +#define DW_OP_or 0x21 +#define DW_OP_plus 0x22 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_shl 0x24 +#define DW_OP_shr 0x25 +#define DW_OP_shra 0x26 +#define DW_OP_xor 0x27 +#define DW_OP_bra 0x28 +#define DW_OP_eq 0x29 +#define DW_OP_ge 0x2a +#define DW_OP_gt 0x2b +#define DW_OP_le 0x2c +#define DW_OP_lt 0x2d +#define DW_OP_ne 0x2e +#define DW_OP_skip 0x2f +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 +#define DW_OP_lit2 0x32 +#define DW_OP_lit3 0x33 +#define DW_OP_lit4 0x34 +#define DW_OP_lit5 0x35 +#define DW_OP_lit6 0x36 +#define DW_OP_lit7 0x37 +#define DW_OP_lit8 0x38 +#define DW_OP_lit9 0x39 +#define DW_OP_lit10 0x3a +#define DW_OP_lit11 0x3b +#define DW_OP_lit12 0x3c +#define DW_OP_lit13 0x3d +#define DW_OP_lit14 0x3e +#define DW_OP_lit15 0x3f +#define DW_OP_lit16 0x40 +#define DW_OP_lit17 0x41 +#define DW_OP_lit18 0x42 +#define DW_OP_lit19 0x43 +#define DW_OP_lit20 0x44 +#define DW_OP_lit21 0x45 +#define DW_OP_lit22 0x46 +#define DW_OP_lit23 0x47 +#define DW_OP_lit24 0x48 +#define DW_OP_lit25 0x49 +#define DW_OP_lit26 0x4a +#define DW_OP_lit27 0x4b +#define DW_OP_lit28 0x4c +#define DW_OP_lit29 0x4d +#define DW_OP_lit30 0x4e +#define DW_OP_lit31 0x4f +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_reg16 0x60 +#define DW_OP_reg17 0x61 +#define DW_OP_reg18 0x62 +#define DW_OP_reg19 0x63 +#define DW_OP_reg20 0x64 +#define DW_OP_reg21 0x65 +#define DW_OP_reg22 0x66 +#define DW_OP_reg23 0x67 +#define DW_OP_reg24 0x68 +#define DW_OP_reg25 0x69 +#define DW_OP_reg26 0x6a +#define DW_OP_reg27 0x6b +#define DW_OP_reg28 0x6c +#define DW_OP_reg29 0x6d +#define DW_OP_reg30 0x6e +#define DW_OP_reg31 0x6f +#define DW_OP_breg0 0x70 +#define DW_OP_breg1 0x71 +#define DW_OP_breg2 0x72 +#define DW_OP_breg3 0x73 +#define DW_OP_breg4 0x74 +#define DW_OP_breg5 0x75 +#define DW_OP_breg6 0x76 +#define DW_OP_breg7 0x77 +#define DW_OP_breg8 0x78 +#define DW_OP_breg9 0x79 +#define DW_OP_breg10 0x7a +#define DW_OP_breg11 0x7b +#define DW_OP_breg12 0x7c +#define DW_OP_breg13 0x7d +#define DW_OP_breg14 0x7e +#define DW_OP_breg15 0x7f +#define DW_OP_breg16 0x80 +#define DW_OP_breg17 0x81 +#define DW_OP_breg18 0x82 +#define DW_OP_breg19 0x83 +#define DW_OP_breg20 0x84 +#define DW_OP_breg21 0x85 +#define DW_OP_breg22 0x86 +#define DW_OP_breg23 0x87 +#define DW_OP_breg24 0x88 +#define DW_OP_breg25 0x89 +#define DW_OP_breg26 0x8a +#define DW_OP_breg27 0x8b +#define DW_OP_breg28 0x8c +#define DW_OP_breg29 0x8d +#define DW_OP_breg30 0x8e +#define DW_OP_breg31 0x8f +#define DW_OP_regx 0x90 +#define DW_OP_fbreg 0x91 +#define DW_OP_bregx 0x92 +#define DW_OP_piece 0x93 +#define DW_OP_deref_size 0x94 +#define DW_OP_xderef_size 0x95 +#define DW_OP_nop 0x96 + +#define DW_OP_lo_user 0xe0 + +#define DW_OP_hi_user 0xff + +#define DW_ATE_address 0x1 +#define DW_ATE_boolean 0x2 +#define DW_ATE_complex_float 0x3 +#define DW_ATE_float 0x4 +#define DW_ATE_signed 0x5 +#define DW_ATE_signed_char 0x6 +#define DW_ATE_unsigned 0x7 +#define DW_ATE_unsigned_char 0x8 +#define DW_ATE_imaginary_float 0x9 +#define DW_ATE_packed_decimal 0xa +#define DW_ATE_numeric_string 0xb +#define DW_ATE_edited 0xc +#define DW_ATE_signed_fixed 0xd +#define DW_ATE_unsigned_fixed 0xe +#define DW_ATE_decimal_float 0xf + +#define DW_ATE_lo_user 0x80 + +#define DW_ATE_hi_user 0xff + +#define DW_ACCESS_public 0x01 +#define DW_ACCESS_protected 0x02 +#define DW_ACCESS_private 0x03 + +#define DW_VIS_local 0x01 +#define DW_VIS_exported 0x02 +#define DW_VIS_qualified 0x03 + +#define DW_VIRTUALITY_none 0x00 +#define DW_VIRTUALITY_virtual 0x01 +#define DW_VIRTUALITY_pure_virtual 0x02 + +#define DW_LANG_C89 0x0001 +#define DW_LANG_C 0x0002 +#define DW_LANG_Ada83 0x0003 +#define DW_LANG_C_plus_plus 0x0004 +#define DW_LANG_Cobol74 0x0005 +#define DW_LANG_Cobol85 0x0006 +#define DW_LANG_Fortran77 0x0007 +#define DW_LANG_Fortran90 0x0008 +#define DW_LANG_Pascal83 0x0009 +#define DW_LANG_Modula2 0x000a +#define DW_LANG_Java 0x000b +#define DW_LANG_C99 0x000c +#define DW_LANG_Ada95 0x000d +#define DW_LANG_Fortran95 0x000e +#define DW_LANG_PLI 0x000f +#define DW_LANG_ObjC 0x0010 +#define DW_LANG_ObjC_plus_plus 0x0011 +#define DW_LANG_UPC 0x0012 +#define DW_LANG_D 0x0013 + +#define DW_LANG_lo_user 0x8000 + +#define DW_LANG_hi_user 0xffff + +#define DW_ID_case_sensitive 0x00 +#define DW_ID_up_case 0x01 +#define DW_ID_down_case 0x02 +#define DW_ID_case_insensitive 0x03 + +#define DW_CC_normal 0x01 +#define DW_CC_program 0x02 +#define DW_CC_nocall 0x03 + +#define DW_CC_lo_user 0x40 + +#define DW_CC_hi_user 0xff + +#define DW_INL_not_inlined 0x00 +#define DW_INL_inlined 0x01 +#define DW_INL_declared_not_inlined 0x02 +#define DW_INL_declared_inlined 0x03 + +#define DW_ORD_row_major 0x00 +#define DW_ORD_col_major 0x01 + +#define DW_DSC_label 0x00 +#define DW_DSC_range 0x01 + +#define DW_LNS_copy 0x01 +#define DW_LNS_advance_pc 0x02 +#define DW_LNS_advance_line 0x03 +#define DW_LNS_set_file 0x04 +#define DW_LNS_set_column 0x05 +#define DW_LNS_negate_stmt 0x06 +#define DW_LNS_set_basic_block 0x07 +#define DW_LNS_const_add_pc 0x08 +#define DW_LNS_fixed_advance_pc 0x09 +#define DW_LNS_set_prologue_end 0x0a +#define DW_LNS_set_epilogue_begin 0x0b +#define DW_LNS_set_isa 0x0c + +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_define_file 0x03 + +#define DW_LNE_lo_user 0x80 + +#define DW_LNE_hi_user 0xff + +#define DW_MACINFO_define 0x01 +#define DW_MACINFO_undef 0x02 +#define DW_MACINFO_start_file 0x03 +#define DW_MACINFO_end_file 0x04 +#define DW_MACINFO_vendor_ext 0xff + +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 +#define DW_CFA_extended 0 + +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_CFA_cfa_offset_extended_sf 0x11 +#define DW_CFA_def_cfa_sf 0x12 +#define DW_CFA_def_cfa_offset_sf 0x13 +#define DW_CFA_val_offset 0x14 +#define DW_CFA_val_offset_sf 0x15 +#define DW_CFA_val_expression 0x16 + +#define DW_CFA_lo_user 0x1c + +#define DW_CFA_high_user 0x3f + +#endif /* !_DWARF_H_ */ diff --git a/libdwarf/dwarf_abbrev.c b/libdwarf/dwarf_abbrev.c new file mode 100644 index 0000000..b3c863e --- /dev/null +++ b/libdwarf/dwarf_abbrev.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_abbrev.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_abbrev_add(Dwarf_CU cu, uint64_t entry, uint64_t tag, uint8_t children, Dwarf_Abbrev *ap, Dwarf_Error *error) +{ + Dwarf_Abbrev a; + int ret = DWARF_E_NONE; + + if ((a = malloc(sizeof(struct _Dwarf_Abbrev))) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MEMORY); + return DWARF_E_MEMORY; + } + + /* Initialise the abbrev structure. */ + a->a_entry = entry; + a->a_tag = tag; + a->a_children = children; + + /* Initialise the list of attributes. */ + STAILQ_INIT(&a->a_attrib); + + /* Add the abbrev to the list in the compilation unit. */ + STAILQ_INSERT_TAIL(&cu->cu_abbrev, a, a_next); + + if (ap != NULL) + *ap = a; + + return ret; +} + +Dwarf_Abbrev +dwarf_abbrev_find(Dwarf_CU cu, uint64_t entry) +{ + Dwarf_Abbrev a = NULL; + + STAILQ_FOREACH(a, &cu->cu_abbrev, a_next) { + if (a->a_entry == entry) + break; + } + + return a; +} diff --git a/libdwarf/dwarf_attr.c b/libdwarf/dwarf_attr.c new file mode 100644 index 0000000..600af2d --- /dev/null +++ b/libdwarf/dwarf_attr.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_attr.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_attr(Dwarf_Die die, Dwarf_Half attr, Dwarf_Attribute *atp, Dwarf_Error *err) +{ + Dwarf_Attribute at; + Dwarf_Abbrev a; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || atp == NULL || (a = die->die_a) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + STAILQ_FOREACH(at, &a->a_attrib, at_next) + if (at->at_attrib == attr) + break; + + *atp = at; + + if (at == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } + + return ret; +} + +int +dwarf_attr_add(Dwarf_Abbrev a, uint64_t attr, uint64_t form, Dwarf_Attribute *atp, Dwarf_Error *error) +{ + Dwarf_Attribute at; + int ret = DWARF_E_NONE; + + if (error == NULL) + return DWARF_E_ERROR; + + if (a == NULL) { + DWARF_SET_ERROR(error, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if ((at = malloc(sizeof(struct _Dwarf_Attribute))) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MEMORY); + return DWARF_E_MEMORY; + } + + /* Initialise the attribute structure. */ + at->at_attrib = attr; + at->at_form = form; + + /* Add the attribute to the list in the abbrev. */ + STAILQ_INSERT_TAIL(&a->a_attrib, at, at_next); + + if (atp != NULL) + *atp = at; + + return ret; +} diff --git a/libdwarf/dwarf_attrval.c b/libdwarf/dwarf_attrval.c new file mode 100644 index 0000000..a8689ae --- /dev/null +++ b/libdwarf/dwarf_attrval.c @@ -0,0 +1,267 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_attrval.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +Dwarf_AttrValue +dwarf_attrval_find(Dwarf_Die die, Dwarf_Half attr) +{ + Dwarf_AttrValue av; + + STAILQ_FOREACH(av, &die->die_attrval, av_next) { + if (av->av_attrib == attr) + break; + } + + return av; +} + +int +dwarf_attrval_add(Dwarf_Die die, Dwarf_AttrValue avref, Dwarf_AttrValue *avp, Dwarf_Error *error) +{ + Dwarf_AttrValue av; + int ret = DWARF_E_NONE; + + if ((av = malloc(sizeof(struct _Dwarf_AttrValue))) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MEMORY); + return DWARF_E_MEMORY; + } + + memcpy(av, avref, sizeof(struct _Dwarf_AttrValue)); + + /* Add the attribute value to the list in the die. */ + STAILQ_INSERT_TAIL(&die->die_attrval, av, av_next); + + /* Save a pointer to the attribute name if this is one. */ + if (av->av_attrib == DW_AT_name) + switch (av->av_form) { + case DW_FORM_strp: + die->die_name = av->u[1].s; + break; + case DW_FORM_string: + die->die_name = av->u[0].s; + break; + default: + break; + } + + if (avp != NULL) + *avp = av; + + return ret; +} + +int +dwarf_attrval_flag(Dwarf_Die die, uint64_t attr, Dwarf_Bool *valp, Dwarf_Error *err) +{ + Dwarf_AttrValue av; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || valp == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *valp = 0; + + if ((av = dwarf_attrval_find(die, attr)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else { + switch (av->av_form) { + case DW_FORM_flag: + *valp = (Dwarf_Bool) av->u[0].u64; + break; + default: + printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n", + __func__,__LINE__,get_form_desc(av->av_form), + (u_long) av->av_form); + DWARF_SET_ERROR(err, DWARF_E_BAD_FORM); + ret = DWARF_E_BAD_FORM; + } + } + + return ret; +} + +int +dwarf_attrval_string(Dwarf_Die die, uint64_t attr, const char **strp, Dwarf_Error *err) +{ + Dwarf_AttrValue av; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || strp == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *strp = NULL; + + if (attr == DW_AT_name) + *strp = die->die_name; + else if ((av = dwarf_attrval_find(die, attr)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else { + switch (av->av_form) { + case DW_FORM_strp: + *strp = av->u[1].s; + break; + case DW_FORM_string: + *strp = av->u[0].s; + break; + default: + printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n", + __func__,__LINE__,get_form_desc(av->av_form), + (u_long) av->av_form); + DWARF_SET_ERROR(err, DWARF_E_BAD_FORM); + ret = DWARF_E_BAD_FORM; + } + } + + return ret; +} + +int +dwarf_attrval_signed(Dwarf_Die die, uint64_t attr, Dwarf_Signed *valp, Dwarf_Error *err) +{ + Dwarf_AttrValue av; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || valp == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *valp = 0; + + if ((av = dwarf_attrval_find(die, attr)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else { + switch (av->av_form) { + case DW_FORM_data1: + case DW_FORM_sdata: + *valp = av->u[0].s64; + break; + default: + printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n", + __func__,__LINE__,get_form_desc(av->av_form), + (u_long) av->av_form); + DWARF_SET_ERROR(err, DWARF_E_BAD_FORM); + ret = DWARF_E_BAD_FORM; + } + } + + return ret; +} + +int +dwarf_attrval_unsigned(Dwarf_Die die, uint64_t attr, Dwarf_Unsigned *valp, Dwarf_Error *err) +{ + Dwarf_AttrValue av; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || valp == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *valp = 0; + + if ((av = dwarf_attrval_find(die, attr)) == NULL && attr != DW_AT_type) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else if (av == NULL && (av = dwarf_attrval_find(die, + DW_AT_abstract_origin)) != NULL) { + Dwarf_Die die1; + Dwarf_Unsigned val; + + switch (av->av_form) { + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + val = av->u[0].u64; + + if ((die1 = dwarf_die_find(die, val)) == NULL || + (av = dwarf_attrval_find(die1, attr)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } + break; + default: + printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n", + __func__,__LINE__,get_form_desc(av->av_form), + (u_long) av->av_form); + DWARF_SET_ERROR(err, DWARF_E_BAD_FORM); + ret = DWARF_E_BAD_FORM; + } + } + + if (ret == DWARF_E_NONE) { + switch (av->av_form) { + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + *valp = av->u[0].u64; + break; + default: + printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n", + __func__,__LINE__,get_form_desc(av->av_form), + (u_long) av->av_form); + DWARF_SET_ERROR(err, DWARF_E_BAD_FORM); + ret = DWARF_E_BAD_FORM; + } + } + + return ret; +} diff --git a/libdwarf/dwarf_cu.c b/libdwarf/dwarf_cu.c new file mode 100644 index 0000000..04b9557 --- /dev/null +++ b/libdwarf/dwarf_cu.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_cu.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_next_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned *cu_header_length, + Dwarf_Half *cu_version, Dwarf_Unsigned *cu_abbrev_offset, + Dwarf_Half *cu_pointer_size, Dwarf_Unsigned *cu_next_offset, Dwarf_Error *error) +{ + Dwarf_CU next; + + if (error == NULL) + return DWARF_E_ERROR; + + if (dbg == NULL || cu_header_length == NULL || cu_version == NULL || + cu_abbrev_offset == NULL || cu_pointer_size == NULL || + cu_next_offset == NULL) { + DWARF_SET_ERROR(error, DWARF_E_ARGUMENT); + return DWARF_E_ERROR; + } + + if (dbg->dbg_cu_current == NULL) + dbg->dbg_cu_current = STAILQ_FIRST(&dbg->dbg_cu); + else if ((next = STAILQ_NEXT(dbg->dbg_cu_current, cu_next)) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_NO_ENTRY); + return DWARF_E_NO_ENTRY; + } else + dbg->dbg_cu_current = next; + + if (dbg->dbg_cu_current == NULL) { + DWARF_SET_ERROR(error, DWARF_E_NO_ENTRY); + return DWARF_E_NO_ENTRY; + } + + *cu_header_length = dbg->dbg_cu_current->cu_header_length; + *cu_version = dbg->dbg_cu_current->cu_version; + *cu_abbrev_offset = dbg->dbg_cu_current->cu_abbrev_offset; + *cu_pointer_size = dbg->dbg_cu_current->cu_pointer_size; + *cu_next_offset = dbg->dbg_cu_current->cu_next_offset; + + return DWARF_E_NONE; +} diff --git a/libdwarf/dwarf_dealloc.c b/libdwarf/dwarf_dealloc.c new file mode 100644 index 0000000..0ccb7e7 --- /dev/null +++ b/libdwarf/dwarf_dealloc.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_dealloc.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +void +dwarf_dealloc(Dwarf_Debug dbg __unused, Dwarf_Ptr p __unused, Dwarf_Unsigned alloc_type __unused) +{ + /* + * This libdwarf implementation doesn't use this style + * of memory allocation. It doesn't copy things to return + * them to the client, so the client doesn't need to + * remember to free them. + */ + return; +} diff --git a/libdwarf/dwarf_die.c b/libdwarf/dwarf_die.c new file mode 100644 index 0000000..d0b4f62 --- /dev/null +++ b/libdwarf/dwarf_die.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_die.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +static const char *anon_name = "__anon__"; + +int +dwarf_die_add(Dwarf_CU cu, int level, uint64_t offset, uint64_t abnum, Dwarf_Abbrev a, Dwarf_Die *diep, Dwarf_Error *err) +{ + Dwarf_Die die; + uint64_t key; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (cu == NULL || a == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if ((die = malloc(sizeof(struct _Dwarf_Die))) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_MEMORY); + return DWARF_E_MEMORY; + } + + /* Initialise the abbrev structure. */ + die->die_level = level; + die->die_offset = offset; + die->die_abnum = abnum; + die->die_a = a; + die->die_cu = cu; + die->die_name = anon_name; + + /* Initialise the list of attribute values. */ + STAILQ_INIT(&die->die_attrval); + + /* Add the die to the list in the compilation unit. */ + STAILQ_INSERT_TAIL(&cu->cu_die, die, die_next); + + /* Add the die to the hash table in the compilation unit. */ + key = offset % DWARF_DIE_HASH_SIZE; + STAILQ_INSERT_TAIL(&cu->cu_die_hash[key], die, die_hash); + + if (diep != NULL) + *diep = die; + + return ret; +} + +int +dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *err __unused) +{ + *ret_offset = die->die_offset; + + return DWARF_E_NONE; +} + +int +dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *err) +{ + Dwarf_Die next; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || ret_die == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if ((next = STAILQ_NEXT(die, die_next)) == NULL || + next->die_level != die->die_level + 1) { + *ret_die = NULL; + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else + *ret_die = next; + + return ret; +} + +int +dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *err) +{ + Dwarf_Abbrev a; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || tag == NULL || (a = die->die_a) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *tag = a->a_tag; + + return DWARF_E_NONE; +} + +int +dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *caller_ret_die, Dwarf_Error *err) +{ + Dwarf_Die next; + Dwarf_CU cu; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (dbg == NULL || caller_ret_die == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if ((cu = dbg->dbg_cu_current) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_CU_CURRENT); + return DWARF_E_CU_CURRENT; + } + + if (die == NULL) { + *caller_ret_die = STAILQ_FIRST(&cu->cu_die); + + if (*caller_ret_die == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } + } else { + next = die; + while ((next = STAILQ_NEXT(next, die_next)) != NULL) { + if (next->die_level < die->die_level) { + next = NULL; + break; + } + if (next->die_level == die->die_level) { + *caller_ret_die = next; + break; + } + } + + if (next == NULL) { + *caller_ret_die = NULL; + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } + } + + return ret; +} + +Dwarf_Die +dwarf_die_find(Dwarf_Die die, Dwarf_Unsigned off) +{ + Dwarf_CU cu = die->die_cu; + Dwarf_Die die1; + + STAILQ_FOREACH(die1, &cu->cu_die, die_next) { + if (die1->die_offset == off) + return (die1); + } + + return (NULL); +} diff --git a/libdwarf/dwarf_dump.c b/libdwarf/dwarf_dump.c new file mode 100644 index 0000000..a6683a2 --- /dev/null +++ b/libdwarf/dwarf_dump.c @@ -0,0 +1,892 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_dump.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +const char * +get_sht_desc(uint32_t sh_type) +{ + switch (sh_type) { + case SHT_NULL: + return "inactive"; + case SHT_PROGBITS: + return "program defined information"; + case SHT_SYMTAB: + return "symbol table section"; + case SHT_STRTAB: + return "string table section"; + case SHT_RELA: + return "relocation section with addends"; + case SHT_HASH: + return "symbol hash table section"; + case SHT_DYNAMIC: + return "dynamic section"; + case SHT_NOTE: + return "note section"; + case SHT_NOBITS: + return "no space section"; + case SHT_REL: + return "relocation section - no addends"; + case SHT_SHLIB: + return "reserved - purpose unknown"; + case SHT_DYNSYM: + return "dynamic symbol table section"; + case SHT_INIT_ARRAY: + return "Initialization function pointers."; + case SHT_FINI_ARRAY: + return "Termination function pointers."; + case SHT_PREINIT_ARRAY: + return "Pre-initialization function ptrs."; + case SHT_GROUP: + return "Section group."; + case SHT_SYMTAB_SHNDX: + return "Section indexes (see SHN_XINDEX)."; + case SHT_GNU_verdef: + return "Symbol versions provided"; + case SHT_GNU_verneed: + return "Symbol versions required"; + case SHT_GNU_versym: + return "Symbol version table"; +#ifdef SHT_AMD64_UNWIND + case SHT_AMD64_UNWIND: + return "AMD64 unwind"; +#endif + default: + return "Unknown"; + } +} + +const char * +get_attr_desc(uint32_t attr) +{ + switch (attr) { + case DW_AT_abstract_origin: + return "DW_AT_abstract_origin"; + case DW_AT_accessibility: + return "DW_AT_accessibility"; + case DW_AT_address_class: + return "DW_AT_address_class"; + case DW_AT_artificial: + return "DW_AT_artificial"; + case DW_AT_base_types: + return "DW_AT_base_types"; + case DW_AT_bit_offset: + return "DW_AT_bit_offset"; + case DW_AT_bit_size: + return "DW_AT_bit_size"; + case DW_AT_byte_size: + return "DW_AT_byte_size"; + case DW_AT_calling_convention: + return "DW_AT_calling_convention"; + case DW_AT_common_reference: + return "DW_AT_common_reference"; + case DW_AT_comp_dir: + return "DW_AT_comp_dir"; + case DW_AT_const_value: + return "DW_AT_const_value"; + case DW_AT_containing_type: + return "DW_AT_containing_type"; + case DW_AT_count: + return "DW_AT_count"; + case DW_AT_data_member_location: + return "DW_AT_data_member_location"; + case DW_AT_decl_column: + return "DW_AT_decl_column"; + case DW_AT_decl_file: + return "DW_AT_decl_file"; + case DW_AT_decl_line: + return "DW_AT_decl_line"; + case DW_AT_declaration: + return "DW_AT_declaration"; + case DW_AT_default_value: + return "DW_AT_default_value"; + case DW_AT_discr: + return "DW_AT_discr"; + case DW_AT_discr_list: + return "DW_AT_discr_list"; + case DW_AT_discr_value: + return "DW_AT_discr_value"; + case DW_AT_element_list: + return "DW_AT_element_list"; + case DW_AT_encoding: + return "DW_AT_encoding"; + case DW_AT_external: + return "DW_AT_external"; + case DW_AT_frame_base: + return "DW_AT_frame_base"; + case DW_AT_friend: + return "DW_AT_friend"; + case DW_AT_high_pc: + return "DW_AT_high_pc"; + case DW_AT_identifier_case: + return "DW_AT_identifier_case"; + case DW_AT_import: + return "DW_AT_import"; + case DW_AT_inline: + return "DW_AT_inline"; + case DW_AT_is_optional: + return "DW_AT_is_optional"; + case DW_AT_language: + return "DW_AT_language"; + case DW_AT_location: + return "DW_AT_location"; + case DW_AT_low_pc: + return "DW_AT_low_pc"; + case DW_AT_lower_bound: + return "DW_AT_lower_bound"; + case DW_AT_macro_info: + return "DW_AT_macro_info"; + case DW_AT_member: + return "DW_AT_member"; + case DW_AT_name: + return "DW_AT_name"; + case DW_AT_namelist_item: + return "DW_AT_namelist_item"; + case DW_AT_ordering: + return "DW_AT_ordering"; + case DW_AT_priority: + return "DW_AT_priority"; + case DW_AT_producer: + return "DW_AT_producer"; + case DW_AT_prototyped: + return "DW_AT_prototyped"; + case DW_AT_return_addr: + return "DW_AT_return_addr"; + case DW_AT_segment: + return "DW_AT_segment"; + case DW_AT_sibling: + return "DW_AT_sibling"; + case DW_AT_specification: + return "DW_AT_specification"; + case DW_AT_start_scope: + return "DW_AT_start_scope"; + case DW_AT_static_link: + return "DW_AT_static_link"; + case DW_AT_stmt_list: + return "DW_AT_stmt_list"; + case DW_AT_stride_size: + return "DW_AT_stride_size"; + case DW_AT_string_length: + return "DW_AT_string_length"; + case DW_AT_subscr_data: + return "DW_AT_subscr_data"; + case DW_AT_type: + return "DW_AT_type"; + case DW_AT_upper_bound: + return "DW_AT_upper_bound"; + case DW_AT_use_location: + return "DW_AT_use_location"; + case DW_AT_variable_parameter: + return "DW_AT_variable_parameter"; + case DW_AT_virtuality: + return "DW_AT_virtuality"; + case DW_AT_visibility: + return "DW_AT_visibility"; + case DW_AT_vtable_elem_location: + return "DW_AT_vtable_elem_location"; + default: + break; + } + + return "Unknown attribute"; +} + +const char * +get_form_desc(uint32_t form) +{ + switch (form) { + case DW_FORM_addr: + return "DW_FORM_addr"; + case DW_FORM_block: + return "DW_FORM_block"; + case DW_FORM_block1: + return "DW_FORM_block1"; + case DW_FORM_block2: + return "DW_FORM_block2"; + case DW_FORM_block4: + return "DW_FORM_block4"; + case DW_FORM_data1: + return "DW_FORM_data1"; + case DW_FORM_data2: + return "DW_FORM_data2"; + case DW_FORM_data4: + return "DW_FORM_data4"; + case DW_FORM_data8: + return "DW_FORM_data8"; + case DW_FORM_flag: + return "DW_FORM_flag"; + case DW_FORM_indirect: + return "DW_FORM_indirect"; + case DW_FORM_ref1: + return "DW_FORM_ref1"; + case DW_FORM_ref2: + return "DW_FORM_ref2"; + case DW_FORM_ref4: + return "DW_FORM_ref4"; + case DW_FORM_ref8: + return "DW_FORM_ref8"; + case DW_FORM_ref_addr: + return "DW_FORM_ref_addr"; + case DW_FORM_ref_udata: + return "DW_FORM_ref_udata"; + case DW_FORM_sdata: + return "DW_FORM_sdata"; + case DW_FORM_string: + return "DW_FORM_string"; + case DW_FORM_strp: + return "DW_FORM_strp"; + case DW_FORM_udata: + return "DW_FORM_udata"; + default: + break; + } + + return "Unknown attribute"; +} + +const char * +get_tag_desc(uint32_t tag) +{ + switch (tag) { + case DW_TAG_access_declaration: + return "DW_TAG_access_declaration"; + case DW_TAG_array_type: + return "DW_TAG_array_type"; + case DW_TAG_base_type: + return "DW_TAG_base_type"; + case DW_TAG_catch_block: + return "DW_TAG_catch_block"; + case DW_TAG_class_type: + return "DW_TAG_class_type"; + case DW_TAG_common_block: + return "DW_TAG_common_block"; + case DW_TAG_common_inclusion: + return "DW_TAG_common_inclusion"; + case DW_TAG_compile_unit: + return "DW_TAG_compile_unit"; + case DW_TAG_condition: + return "DW_TAG_condition"; + case DW_TAG_const_type: + return "DW_TAG_const_type"; + case DW_TAG_constant: + return "DW_TAG_constant"; + case DW_TAG_dwarf_procedure: + return "DW_TAG_dwarf_procedure"; + case DW_TAG_entry_point: + return "DW_TAG_entry_point"; + case DW_TAG_enumeration_type: + return "DW_TAG_enumeration_type"; + case DW_TAG_enumerator: + return "DW_TAG_enumerator"; + case DW_TAG_formal_parameter: + return "DW_TAG_formal_parameter"; + case DW_TAG_friend: + return "DW_TAG_friend"; + case DW_TAG_imported_declaration: + return "DW_TAG_imported_declaration"; + case DW_TAG_imported_module: + return "DW_TAG_imported_module"; + case DW_TAG_imported_unit: + return "DW_TAG_imported_unit"; + case DW_TAG_inheritance: + return "DW_TAG_inheritance"; + case DW_TAG_inlined_subroutine: + return "DW_TAG_inlined_subroutine"; + case DW_TAG_interface_type: + return "DW_TAG_interface_type"; + case DW_TAG_label: + return "DW_TAG_label"; + case DW_TAG_lexical_block: + return "DW_TAG_lexical_block"; + case DW_TAG_member: + return "DW_TAG_member"; + case DW_TAG_module: + return "DW_TAG_module"; + case DW_TAG_namelist: + return "DW_TAG_namelist"; + case DW_TAG_namelist_item: + return "DW_TAG_namelist_item"; + case DW_TAG_namespace: + return "DW_TAG_namespace"; + case DW_TAG_packed_type: + return "DW_TAG_packed_type"; + case DW_TAG_partial_unit: + return "DW_TAG_partial_unit"; + case DW_TAG_pointer_type: + return "DW_TAG_pointer_type"; + case DW_TAG_ptr_to_member_type: + return "DW_TAG_ptr_to_member_type"; + case DW_TAG_reference_type: + return "DW_TAG_reference_type"; + case DW_TAG_restrict_type: + return "DW_TAG_restrict_type"; + case DW_TAG_set_type: + return "DW_TAG_set_type"; + case DW_TAG_shared_type: + return "DW_TAG_shared_type"; + case DW_TAG_string_type: + return "DW_TAG_string_type"; + case DW_TAG_structure_type: + return "DW_TAG_structure_type"; + case DW_TAG_subprogram: + return "DW_TAG_subprogram"; + case DW_TAG_subrange_type: + return "DW_TAG_subrange_type"; + case DW_TAG_subroutine_type: + return "DW_TAG_subroutine_type"; + case DW_TAG_template_type_parameter: + return "DW_TAG_template_type_parameter"; + case DW_TAG_template_value_parameter: + return "DW_TAG_template_value_parameter"; + case DW_TAG_thrown_type: + return "DW_TAG_thrown_type"; + case DW_TAG_try_block: + return "DW_TAG_try_block"; + case DW_TAG_typedef: + return "DW_TAG_typedef"; + case DW_TAG_union_type: + return "DW_TAG_union_type"; + case DW_TAG_unspecified_parameters: + return "DW_TAG_unspecified_parameters"; + case DW_TAG_unspecified_type: + return "DW_TAG_unspecified_type"; + case DW_TAG_variable: + return "DW_TAG_variable"; + case DW_TAG_variant: + return "DW_TAG_variant"; + case DW_TAG_variant_part: + return "DW_TAG_variant_part"; + case DW_TAG_volatile_type: + return "DW_TAG_volatile_type"; + case DW_TAG_with_stmt: + return "DW_TAG_with_stmt"; + default: + break; + } + + return "Unknown tag"; +} + +void +dwarf_dump_abbrev(Dwarf_Debug dbg) +{ + Dwarf_Abbrev a; + Dwarf_Attribute at; + Dwarf_CU cu; + + printf("Contents of the .debug_abbrev section:\n\nEntry Tag\n"); + + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + STAILQ_FOREACH(a, &cu->cu_abbrev, a_next) { + printf("%5lu %-30s [%s children]\n", + (u_long) a->a_entry, get_tag_desc(a->a_tag), + (a->a_children == DW_CHILDREN_yes) ? "has" : "no"); + + STAILQ_FOREACH(at, &a->a_attrib, at_next) + printf(" %-30s %s\n", get_attr_desc(at->at_attrib), + get_form_desc(at->at_form)); + } + } +} +#ifdef DOODAD + case DW_AT_inline: + switch (uvalue) + { + case DW_INL_not_inlined: + printf (_("(not inlined)")); + break; + case DW_INL_inlined: + printf (_("(inlined)")); + break; + case DW_INL_declared_not_inlined: + printf (_("(declared as inline but ignored)")); + break; + case DW_INL_declared_inlined: + printf (_("(declared as inline and inlined)")); + break; + default: + printf (_(" (Unknown inline attribute value: %lx)"), uvalue); + break; + } + break; + + case DW_AT_language: + switch (uvalue) + { + case DW_LANG_C: printf ("(non-ANSI C)"); break; + case DW_LANG_C89: printf ("(ANSI C)"); break; + case DW_LANG_C_plus_plus: printf ("(C++)"); break; + case DW_LANG_Fortran77: printf ("(FORTRAN 77)"); break; + case DW_LANG_Fortran90: printf ("(Fortran 90)"); break; + case DW_LANG_Modula2: printf ("(Modula 2)"); break; + case DW_LANG_Pascal83: printf ("(ANSI Pascal)"); break; + case DW_LANG_Ada83: printf ("(Ada)"); break; + case DW_LANG_Cobol74: printf ("(Cobol 74)"); break; + case DW_LANG_Cobol85: printf ("(Cobol 85)"); break; + /* DWARF 2.1 values. */ + case DW_LANG_C99: printf ("(ANSI C99)"); break; + case DW_LANG_Ada95: printf ("(ADA 95)"); break; + case DW_LANG_Fortran95: printf ("(Fortran 95)"); break; + /* MIPS extension. */ + case DW_LANG_Mips_Assembler: printf ("(MIPS assembler)"); break; + /* UPC extension. */ + case DW_LANG_Upc: printf ("(Unified Parallel C)"); break; + default: + printf ("(Unknown: %lx)", uvalue); + break; + } + break; + + case DW_AT_encoding: + switch (uvalue) + { + case DW_ATE_void: printf ("(void)"); break; + case DW_ATE_address: printf ("(machine address)"); break; + case DW_ATE_boolean: printf ("(boolean)"); break; + case DW_ATE_complex_float: printf ("(complex float)"); break; + case DW_ATE_float: printf ("(float)"); break; + case DW_ATE_signed: printf ("(signed)"); break; + case DW_ATE_signed_char: printf ("(signed char)"); break; + case DW_ATE_unsigned: printf ("(unsigned)"); break; + case DW_ATE_unsigned_char: printf ("(unsigned char)"); break; + /* DWARF 2.1 value. */ + case DW_ATE_imaginary_float: printf ("(imaginary float)"); break; + default: + if (uvalue >= DW_ATE_lo_user + && uvalue <= DW_ATE_hi_user) + printf ("(user defined type)"); + else + printf ("(unknown type)"); + break; + } + break; + + case DW_AT_accessibility: + switch (uvalue) + { + case DW_ACCESS_public: printf ("(public)"); break; + case DW_ACCESS_protected: printf ("(protected)"); break; + case DW_ACCESS_private: printf ("(private)"); break; + default: + printf ("(unknown accessibility)"); + break; + } + break; + + case DW_AT_visibility: + switch (uvalue) + { + case DW_VIS_local: printf ("(local)"); break; + case DW_VIS_exported: printf ("(exported)"); break; + case DW_VIS_qualified: printf ("(qualified)"); break; + default: printf ("(unknown visibility)"); break; + } + break; + + case DW_AT_virtuality: + switch (uvalue) + { + case DW_VIRTUALITY_none: printf ("(none)"); break; + case DW_VIRTUALITY_virtual: printf ("(virtual)"); break; + case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break; + default: printf ("(unknown virtuality)"); break; + } + break; + + case DW_AT_identifier_case: + switch (uvalue) + { + case DW_ID_case_sensitive: printf ("(case_sensitive)"); break; + case DW_ID_up_case: printf ("(up_case)"); break; + case DW_ID_down_case: printf ("(down_case)"); break; + case DW_ID_case_insensitive: printf ("(case_insensitive)"); break; + default: printf ("(unknown case)"); break; + } + break; + + case DW_AT_calling_convention: + switch (uvalue) + { + case DW_CC_normal: printf ("(normal)"); break; + case DW_CC_program: printf ("(program)"); break; + case DW_CC_nocall: printf ("(nocall)"); break; + default: + if (uvalue >= DW_CC_lo_user + && uvalue <= DW_CC_hi_user) + printf ("(user defined)"); + else + printf ("(unknown convention)"); + } + break; + + case DW_AT_ordering: + switch (uvalue) + { + case -1: printf ("(undefined)"); break; + case 0: printf ("(row major)"); break; + case 1: printf ("(column major)"); break; + } + break; + + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_stride: + case DW_AT_upper_bound: + case DW_AT_lower_bound: + if (block_start) + { + printf ("("); + decode_location_expression (block_start, pointer_size, uvalue); + printf (")"); + } + else if (form == DW_FORM_data4 || form == DW_FORM_data8) + { + printf ("("); + printf ("location list"); + printf (")"); + } + break; +#endif + +static void +dwarf_dump_av_attr(Dwarf_Die die __unused, Dwarf_AttrValue av) +{ + switch (av->av_attrib) { + case DW_AT_accessibility: + break; + + case DW_AT_calling_convention: + break; + + case DW_AT_encoding: + break; + + case DW_AT_identifier_case: + break; + + case DW_AT_inline: + break; + + case DW_AT_language: + break; + + case DW_AT_ordering: + break; + + case DW_AT_virtuality: + break; + + case DW_AT_visibility: + break; + + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_upper_bound: + case DW_AT_lower_bound: + break; + + default: + break; + } +} + +void +dwarf_dump_av(Dwarf_Die die, Dwarf_AttrValue av) +{ + uint64_t i; + + printf(" %-30s : %-16s ", + get_attr_desc(av->av_attrib), + get_form_desc(av->av_form)); + + switch (av->av_form) { + case DW_FORM_addr: + printf("0x%llx", (unsigned long long) av->u[0].u64); + break; + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + printf("%lu byte block:", (u_long) av->u[0].u64); + for (i = 0; i < av->u[0].u64; i++) + printf(" %02x", av->u[1].u8p[i]); + break; + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_flag: + printf("%llu", (unsigned long long) av->u[0].u64); + break; + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + printf("<%llx>", (unsigned long long) (av->u[0].u64 + + die->die_cu->cu_offset)); + break; + case DW_FORM_string: + printf("%s", av->u[0].s); + break; + case DW_FORM_strp: + printf("(indirect string, offset 0x%llx): %s", + (unsigned long long) av->u[0].u64, av->u[1].s); + break; + default: + printf("unknown form"); + break; + } + + /* Dump any extra attribute-specific information. */ + dwarf_dump_av_attr(die, av); + + printf("\n"); +} + +void +dwarf_dump_die_at_offset(Dwarf_Debug dbg, Dwarf_Off off) +{ + Dwarf_CU cu; + Dwarf_Die die; + + if (dbg == NULL) + return; + + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + STAILQ_FOREACH(die, &cu->cu_die, die_next) { + if ((off_t) die->die_offset == off) { + dwarf_dump_die(die); + return; + } + } + } +} + +void +dwarf_dump_die(Dwarf_Die die) +{ + Dwarf_AttrValue av; + + printf("<%d><%llx>: Abbrev number: %llu (%s)\n", + die->die_level, (unsigned long long) die->die_offset, + (unsigned long long) die->die_abnum, + get_tag_desc(die->die_a->a_tag)); + + STAILQ_FOREACH(av, &die->die_attrval, av_next) + dwarf_dump_av(die, av); +} + +void +dwarf_dump_raw(Dwarf_Debug dbg) +{ + Dwarf_CU cu; + char *p = (char *) dbg; + int i; + + printf("dbg %p\n",dbg); + + if (dbg == NULL) + return; + + for (i = 0; i < (int) sizeof(*dbg); i++) { + if (*p >= 0x20 && *p < 0x7f) { + printf(" %c",*p++ & 0xff); + } else { + printf(" %02x",*p++ & 0xff); + } + } + printf("\n"); + + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + p = (char *) cu; + printf("cu %p\n",cu); + for (i = 0; i < (int) sizeof(*cu); i++) { + if (*p >= 0x20 && *p < 0x7f) { + printf(" %c",*p++ & 0xff); + } else { + printf(" %02x",*p++ & 0xff); + } + } + printf("\n"); + } +} + +static void +dwarf_dump_tree_dies(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Error *error) +{ + Dwarf_Die child; + int ret; + + do { + dwarf_dump_die(die); + + if ((ret = dwarf_child(die, &child, error) == DWARF_E_NO_ENTRY)) { + /* No children. */ + } else if (ret != DWARF_E_NONE) { + printf("Error %s\n", dwarf_errmsg(error)); + return; + } else + dwarf_dump_tree_dies(dbg, child, error); + + if (dwarf_siblingof(dbg, die, &die, error) != DWARF_E_NONE) + die = NULL; + + } while (die != NULL); +} + +void +dwarf_dump_tree(Dwarf_Debug dbg) +{ + Dwarf_CU cu; + Dwarf_Die die; + Dwarf_Error error; + Dwarf_Half cu_pointer_size; + Dwarf_Half cu_version; + Dwarf_Unsigned cu_abbrev_offset; + Dwarf_Unsigned cu_header_length; + Dwarf_Unsigned cu_next_offset; + + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + printf ("\nCompilation Unit @ offset %llx:\n", + (unsigned long long) cu->cu_offset); + printf (" Length: %lu\n", (u_long) cu->cu_length); + printf (" Version: %hu\n", cu->cu_version); + printf (" Abbrev Offset: %lu\n", (u_long) cu->cu_abbrev_offset); + printf (" Pointer Size: %u\n", (u_int) cu->cu_pointer_size); + + if (dwarf_next_cu_header(dbg, &cu_header_length, + &cu_version, &cu_abbrev_offset, &cu_pointer_size, + &cu_next_offset, &error) != DWARF_E_NONE) { + printf("Error %s\n", dwarf_errmsg(&error)); + return; + } + + if (dwarf_siblingof(dbg, NULL, &die, &error) != DWARF_E_NONE) { + printf("Error %s\n", dwarf_errmsg(&error)); + return; + } + + dwarf_dump_tree_dies(dbg, die, &error); + + } +} + +void +dwarf_dump_info(Dwarf_Debug dbg) +{ + Dwarf_CU cu; + Dwarf_Die die; + + printf("Contents of the .debug_info section:\n"); + + STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { + printf ("\nCompilation Unit @ offset %llx:\n", + (unsigned long long) cu->cu_offset); + printf (" Length: %lu\n", (u_long) cu->cu_length); + printf (" Version: %hu\n", cu->cu_version); + printf (" Abbrev Offset: %lu\n", (u_long) cu->cu_abbrev_offset); + printf (" Pointer Size: %u\n", (u_int) cu->cu_pointer_size); + + STAILQ_FOREACH(die, &cu->cu_die, die_next) + dwarf_dump_die(die); + } +} + + +void +dwarf_dump_shstrtab(Dwarf_Debug dbg) +{ + char *name; + int indx = 0; + + printf("---------------------\nSection header string table contents:\n"); + while ((name = elf_strptr(dbg->dbg_elf, dbg->dbg_stnum, indx)) != NULL) { + printf("%5d '%s'\n",indx,name); + indx += strlen(name) + 1; + } +} + +void +dwarf_dump_strtab(Dwarf_Debug dbg) +{ + char *name; + int indx = 0; + + printf("---------------------\nString table contents:\n"); + while ((name = elf_strptr(dbg->dbg_elf, dbg->dbg_s[DWARF_strtab].s_shnum, indx)) != NULL) { + printf("%5d '%s'\n",indx,name); + indx += strlen(name) + 1; + } +} + +void +dwarf_dump_dbgstr(Dwarf_Debug dbg) +{ + char *name; + int indx = 0; + + printf("---------------------\nDebug string table contents:\n"); + while ((name = elf_strptr(dbg->dbg_elf, dbg->dbg_s[DWARF_debug_str].s_shnum, indx)) != NULL) { + printf("%5d '%s'\n",indx,name); + indx += strlen(name) + 1; + } +} + +void +dwarf_dump_symtab(Dwarf_Debug dbg) +{ + GElf_Sym sym; + char *name; + int indx = 0; + + printf("---------------------\nSymbol table contents:\n"); + while (gelf_getsym(dbg->dbg_s[DWARF_symtab].s_data, indx++, &sym) != NULL) { + if ((name = elf_strptr(dbg->dbg_elf, dbg->dbg_s[DWARF_strtab].s_shnum, sym.st_name)) == NULL) + printf("sym.st_name %u indx %d sym.st_size %lu\n",sym.st_name,indx,(u_long) sym.st_size); + else + printf("'%s' sym.st_name %u indx %d sym.st_size %lu\n",name,sym.st_name,indx,(u_long) sym.st_size); + } +} + +void +dwarf_dump(Dwarf_Debug dbg) +{ + dwarf_dump_strtab(dbg); + dwarf_dump_shstrtab(dbg); + dwarf_dump_dbgstr(dbg); + dwarf_dump_symtab(dbg); + dwarf_dump_info(dbg); +} diff --git a/libdwarf/dwarf_errmsg.c b/libdwarf/dwarf_errmsg.c new file mode 100644 index 0000000..29b7b34 --- /dev/null +++ b/libdwarf/dwarf_errmsg.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_errmsg.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +const char *_libdwarf_errors[] = { +#define DEFINE_ERROR(N,S) [DWARF_E_##N] = S + DEFINE_ERROR(NONE, "No Error"), + DEFINE_ERROR(ERROR, "An error"), + DEFINE_ERROR(NO_ENTRY, "No entry found"), + DEFINE_ERROR(ARGUMENT, "Invalid argument"), + DEFINE_ERROR(DEBUG_INFO, "Debug info NULL"), + DEFINE_ERROR(MEMORY, "Insufficient memory"), + DEFINE_ERROR(ELF, "ELF error"), + DEFINE_ERROR(INVALID_CU, "Invalid compilation unit data"), + DEFINE_ERROR(CU_VERSION, "Wrong CU version. Only 2 and 3 supported"), + DEFINE_ERROR(MISSING_ABBREV, "Abbrev not found"), + DEFINE_ERROR(NOT_IMPLEMENTED, "Unimplemented code at"), + DEFINE_ERROR(CU_CURRENT, "No current compilation unit"), + DEFINE_ERROR(BAD_FORM, "Wrong form type for attribute value"), + DEFINE_ERROR(INVALID_EXPR, "Invalid DWARF expression"), + DEFINE_ERROR(NUM, "Unknown DWARF error") +#undef DEFINE_ERROR +}; + +const char * +dwarf_errmsg(Dwarf_Error *error) +{ + const char *p; + + if (error == NULL) + return NULL; + + if (error->err_error < 0 || error->err_error >= DWARF_E_NUM) + return _libdwarf_errors[DWARF_E_NUM]; + else if (error->err_error == DWARF_E_NONE) + return _libdwarf_errors[DWARF_E_NONE]; + else + p = _libdwarf_errors[error->err_error]; + + if (error->err_error == DWARF_E_ELF) + snprintf(error->err_msg, sizeof(error->err_msg), + "ELF error : %s [%s(%d)]", elf_errmsg(error->elf_error), + error->err_func, error->err_line); + else + snprintf(error->err_msg, sizeof(error->err_msg), + "%s [%s(%d)]", p, error->err_func, error->err_line); + + return (const char *) error->err_msg; +} diff --git a/libdwarf/dwarf_errno.c b/libdwarf/dwarf_errno.c new file mode 100644 index 0000000..e50c387 --- /dev/null +++ b/libdwarf/dwarf_errno.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_errno.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_errno(Dwarf_Error *err) +{ + if (err == NULL) + return -1; + + return (err->err_error); +} diff --git a/libdwarf/dwarf_finish.c b/libdwarf/dwarf_finish.c new file mode 100644 index 0000000..f3f8687 --- /dev/null +++ b/libdwarf/dwarf_finish.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_finish.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_finish(Dwarf_Debug *dbgp, Dwarf_Error *error) +{ + Dwarf_Abbrev ab; + Dwarf_Abbrev tab; + Dwarf_Attribute at; + Dwarf_Attribute tat; + Dwarf_AttrValue av; + Dwarf_AttrValue tav; + Dwarf_CU cu; + Dwarf_CU tcu; + Dwarf_Debug dbg; + Dwarf_Die die; + Dwarf_Die tdie; + + if (error == NULL) + /* Can only return a generic error. */ + return DWARF_E_ERROR; + + if (dbgp == NULL) { + DWARF_SET_ERROR(error, DWARF_E_ARGUMENT); + return DWARF_E_ERROR; + } + + if ((dbg = *dbgp) == NULL) + return DWARF_E_NONE; + + /* Free entries in the compilation unit list. */ + STAILQ_FOREACH_SAFE(cu, &dbg->dbg_cu, cu_next, tcu) { + /* Free entries in the die list */ + STAILQ_FOREACH_SAFE(die, &cu->cu_die, die_next, tdie) { + /* Free entries in the attribute value list */ + STAILQ_FOREACH_SAFE(av, &die->die_attrval, av_next, tav) { + STAILQ_REMOVE(&die->die_attrval, av, _Dwarf_AttrValue, av_next); + free(av); + } + + STAILQ_REMOVE(&cu->cu_die, die, _Dwarf_Die, die_next); + free(die); + } + + /* Free entries in the abbrev list */ + STAILQ_FOREACH_SAFE(ab, &cu->cu_abbrev, a_next, tab) { + /* Free entries in the attribute list */ + STAILQ_FOREACH_SAFE(at, &ab->a_attrib, at_next, tat) { + STAILQ_REMOVE(&ab->a_attrib, at, _Dwarf_Attribute, at_next); + free(at); + } + + STAILQ_REMOVE(&cu->cu_abbrev, ab, _Dwarf_Abbrev, a_next); + free(ab); + } + + STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); + free(cu); + } + + if (dbg->dbg_elf_close) + /* Free resources associated with the ELF file. */ + elf_end(dbg->dbg_elf); + + free(dbg); + + *dbgp = NULL; + + return DWARF_E_NONE; +} diff --git a/libdwarf/dwarf_form.c b/libdwarf/dwarf_form.c new file mode 100644 index 0000000..64b97b1 --- /dev/null +++ b/libdwarf/dwarf_form.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_form.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +int +dwarf_whatform(Dwarf_Attribute at, Dwarf_Half *return_form, Dwarf_Error *err) +{ + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (at == NULL || return_form == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + *return_form = at->at_form; + + return ret; +} diff --git a/libdwarf/dwarf_init.c b/libdwarf/dwarf_init.c new file mode 100644 index 0000000..9128a76 --- /dev/null +++ b/libdwarf/dwarf_init.c @@ -0,0 +1,746 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_init.c,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +static const char *debug_snames[DWARF_DEBUG_SNAMES] = { + ".debug_abbrev", + ".debug_aranges", + ".debug_frame", + ".debug_info", + ".debug_line", + ".debug_pubnames", + ".eh_frame", + ".debug_macinfo", + ".debug_str", + ".debug_loc", + ".debug_pubtypes", + ".debug_ranges", + ".debug_static_func", + ".debug_static_vars", + ".debug_types", + ".debug_weaknames", + ".symtab", + ".strtab" +}; + +static uint64_t (*dwarf_read) (Elf_Data **, uint64_t *, int); +static void (*dwarf_write) (Elf_Data **, uint64_t *, uint64_t, int); + +static uint64_t +dwarf_read_lsb(Elf_Data **dp, uint64_t *offsetp, int bytes_to_read) +{ + uint64_t ret = 0; + + uint8_t *src = (uint8_t *) (*dp)->d_buf + *offsetp; + + switch (bytes_to_read) { + case 8: + ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40; + ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56; + case 4: + ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24; + case 2: + ret |= ((uint64_t) src[1]) << 8; + case 1: + ret |= src[0]; + break; + default: + return 0; + break; + } + + *offsetp += bytes_to_read; + + return ret; +} + +static uint64_t +dwarf_read_msb(Elf_Data **dp, uint64_t *offsetp, int bytes_to_read) +{ + uint64_t ret = 0; + + uint8_t *src = (uint8_t *) (*dp)->d_buf + *offsetp; + + switch (bytes_to_read) { + case 1: + ret = src[0]; + break; + case 2: + ret = src[1] | ((uint64_t) src[0]) << 8; + break; + case 4: + ret = src[3] | ((uint64_t) src[2]) << 8; + ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24; + break; + case 8: + ret = src[7] | ((uint64_t) src[6]) << 8; + ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24; + ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40; + ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56; + break; + default: + return 0; + break; + } + + *offsetp += bytes_to_read; + + return ret; +} + +static void +dwarf_write_lsb(Elf_Data **dp, uint64_t *offsetp, uint64_t value, int bytes_to_write) +{ + uint8_t *dst = (uint8_t *) (*dp)->d_buf + *offsetp; + + switch (bytes_to_write) { + case 8: + dst[7] = (value >> 56) & 0xff; + dst[6] = (value >> 48) & 0xff; + dst[5] = (value >> 40) & 0xff; + dst[4] = (value >> 32) & 0xff; + case 4: + dst[3] = (value >> 24) & 0xff; + dst[2] = (value >> 16) & 0xff; + case 2: + dst[1] = (value >> 8) & 0xff; + case 1: + dst[0] = value & 0xff; + break; + default: + return; + break; + } + + *offsetp += bytes_to_write; +} + +static void +dwarf_write_msb(Elf_Data **dp, uint64_t *offsetp, uint64_t value, int bytes_to_write) +{ + uint8_t *dst = (uint8_t *) (*dp)->d_buf + *offsetp; + + switch (bytes_to_write) { + case 8: + dst[7] = value & 0xff; + dst[6] = (value >> 8) & 0xff; + dst[5] = (value >> 16) & 0xff; + dst[4] = (value >> 24) & 0xff; + value >>= 32; + case 4: + dst[3] = value & 0xff; + dst[2] = (value >> 8) & 0xff; + value >>= 16; + case 2: + dst[1] = value & 0xff; + value >>= 8; + case 1: + dst[0] = value & 0xff; + break; + default: + return; + break; + } + + *offsetp += bytes_to_write; +} + +static int64_t +dwarf_read_sleb128(Elf_Data **dp, uint64_t *offsetp) +{ + int64_t ret = 0; + uint8_t b; + int shift = 0; + + uint8_t *src = (uint8_t *) (*dp)->d_buf + *offsetp; + + do { + b = *src++; + + ret |= ((b & 0x7f) << shift); + + (*offsetp)++; + + shift += 7; + } while ((b & 0x80) != 0); + + if (shift < 32 && (b & 0x40) != 0) + ret |= (-1 << shift); + + return ret; +} + +static uint64_t +dwarf_read_uleb128(Elf_Data **dp, uint64_t *offsetp) +{ + uint64_t ret = 0; + uint8_t b; + int shift = 0; + + uint8_t *src = (uint8_t *) (*dp)->d_buf + *offsetp; + + do { + b = *src++; + + ret |= ((b & 0x7f) << shift); + + (*offsetp)++; + + shift += 7; + } while ((b & 0x80) != 0); + + return ret; +} + +static const char * +dwarf_read_string(Elf_Data **dp, uint64_t *offsetp) +{ + char *ret; + + char *src = (char *) (*dp)->d_buf + *offsetp; + + ret = src; + + while (*src != '\0' && *offsetp < (*dp)->d_size) { + src++; + (*offsetp)++; + } + + if (*src == '\0' && *offsetp < (*dp)->d_size) + (*offsetp)++; + + return ret; +} + +static uint8_t * +dwarf_read_block(Elf_Data **dp, uint64_t *offsetp, uint64_t length) +{ + uint8_t *ret; + + uint8_t *src = (char *) (*dp)->d_buf + *offsetp; + + ret = src; + + (*offsetp) += length; + + return ret; +} + +static int +dwarf_apply_relocations(Dwarf_Debug dbg, Elf_Data *reld, int secindx) +{ + Elf_Data *d; + GElf_Rela rela; + int indx = 0; + int ret = DWARF_E_NONE; + uint64_t offset; + + /* Point to the data to be relocated: */ + d = dbg->dbg_s[secindx].s_data; + + /* Enter a loop to process each relocation addend: */ + while (gelf_getrela(reld, indx++, &rela) != NULL) { + GElf_Sym sym; + Elf64_Xword symindx = ELF64_R_SYM(rela.r_info); + + if (gelf_getsym(dbg->dbg_s[DWARF_symtab].s_data, symindx, &sym) == NULL) { + printf("Couldn't find symbol index %lu for relocation\n",(u_long) symindx); + continue; + } + + offset = rela.r_offset; + + dwarf_write(&d, &offset, rela.r_addend, dbg->dbg_offsize); + } + + return ret; +} + +static int +dwarf_relocate(Dwarf_Debug dbg, Dwarf_Error *error) +{ + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + int i; + int ret = DWARF_E_NONE; + + /* Look for sections which relocate the debug sections. */ + while ((scn = elf_nextscn(dbg->dbg_elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + if (shdr.sh_type != SHT_RELA || shdr.sh_size == 0) + continue; + + for (i = 0; i < DWARF_DEBUG_SNAMES; i++) { + if (dbg->dbg_s[i].s_shnum == shdr.sh_info && + dbg->dbg_s[DWARF_symtab].s_shnum == shdr.sh_link) { + Elf_Data *rd; + + /* Get the relocation data. */ + if ((rd = elf_getdata(scn, NULL)) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + /* Apply the relocations. */ + dwarf_apply_relocations(dbg, rd, i); + break; + } + } + } + + return ret; +} + +static int +dwarf_init_attr(Dwarf_Debug dbg, Elf_Data **dp, uint64_t *offsetp, + Dwarf_CU cu, Dwarf_Die die, Dwarf_Attribute at, uint64_t form, + Dwarf_Error *error) +{ + int ret = DWARF_E_NONE; + struct _Dwarf_AttrValue avref; + + memset(&avref, 0, sizeof(avref)); + avref.av_attrib = at->at_attrib; + avref.av_form = at->at_form; + + switch (form) { + case DW_FORM_addr: + avref.u[0].u64 = dwarf_read(dp, offsetp, cu->cu_pointer_size); + break; + case DW_FORM_block: + avref.u[0].u64 = dwarf_read_uleb128(dp, offsetp); + avref.u[1].u8p = dwarf_read_block(dp, offsetp, avref.u[0].u64); + break; + case DW_FORM_block1: + avref.u[0].u64 = dwarf_read(dp, offsetp, 1); + avref.u[1].u8p = dwarf_read_block(dp, offsetp, avref.u[0].u64); + break; + case DW_FORM_block2: + avref.u[0].u64 = dwarf_read(dp, offsetp, 2); + avref.u[1].u8p = dwarf_read_block(dp, offsetp, avref.u[0].u64); + break; + case DW_FORM_block4: + avref.u[0].u64 = dwarf_read(dp, offsetp, 4); + avref.u[1].u8p = dwarf_read_block(dp, offsetp, avref.u[0].u64); + break; + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + avref.u[0].u64 = dwarf_read(dp, offsetp, 1); + break; + case DW_FORM_data2: + case DW_FORM_ref2: + avref.u[0].u64 = dwarf_read(dp, offsetp, 2); + break; + case DW_FORM_data4: + case DW_FORM_ref4: + avref.u[0].u64 = dwarf_read(dp, offsetp, 4); + break; + case DW_FORM_data8: + case DW_FORM_ref8: + avref.u[0].u64 = dwarf_read(dp, offsetp, 8); + break; + case DW_FORM_indirect: + form = dwarf_read_uleb128(dp, offsetp); + return dwarf_init_attr(dbg, dp, offsetp, cu, die, at, form, error); + case DW_FORM_ref_addr: + if (cu->cu_version == 2) + avref.u[0].u64 = dwarf_read(dp, offsetp, cu->cu_pointer_size); + else if (cu->cu_version == 3) + avref.u[0].u64 = dwarf_read(dp, offsetp, dbg->dbg_offsize); + break; + case DW_FORM_ref_udata: + case DW_FORM_udata: + avref.u[0].u64 = dwarf_read_uleb128(dp, offsetp); + break; + case DW_FORM_sdata: + avref.u[0].s64 = dwarf_read_sleb128(dp, offsetp); + break; + case DW_FORM_string: + avref.u[0].s = dwarf_read_string(dp, offsetp); + break; + case DW_FORM_strp: + avref.u[0].u64 = dwarf_read(dp, offsetp, dbg->dbg_offsize); + avref.u[1].s = elf_strptr(dbg->dbg_elf, + dbg->dbg_s[DWARF_debug_str].s_shnum, avref.u[0].u64); + break; + default: + DWARF_SET_ERROR(error, DWARF_E_NOT_IMPLEMENTED); + ret = DWARF_E_NOT_IMPLEMENTED; + break; + } + + if (ret == DWARF_E_NONE) + ret = dwarf_attrval_add(die, &avref, NULL, error); + + return ret; +} + +static int +dwarf_init_abbrev(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Error *error) +{ + Dwarf_Abbrev a; + Elf_Data *d; + int ret = DWARF_E_NONE; + uint64_t attr; + uint64_t entry; + uint64_t form; + uint64_t offset; + uint64_t tag; + u_int8_t children; + + d = dbg->dbg_s[DWARF_debug_abbrev].s_data; + + offset = cu->cu_abbrev_offset; + + while (offset < d->d_size) { + + entry = dwarf_read_uleb128(&d, &offset); + + /* Check if this is the end of the data: */ + if (entry == 0) + break; + + tag = dwarf_read_uleb128(&d, &offset); + + children = dwarf_read(&d, &offset, 1); + + if ((ret = dwarf_abbrev_add(cu, entry, tag, children, &a, error)) != DWARF_E_NONE) + break; + + do { + attr = dwarf_read_uleb128(&d, &offset); + form = dwarf_read_uleb128(&d, &offset); + + if (attr != 0) + if ((ret = dwarf_attr_add(a, attr, form, NULL, error)) != DWARF_E_NONE) + return ret; + } while (attr != 0); + } + + return ret; +} + +static int +dwarf_init_info(Dwarf_Debug dbg, Dwarf_Error *error) +{ + Dwarf_CU cu; + Elf_Data *d = NULL; + Elf_Scn *scn; + int i; + int level = 0; + int relocated = 0; + int ret = DWARF_E_NONE; + uint64_t length; + uint64_t next_offset; + uint64_t offset = 0; + + scn = dbg->dbg_s[DWARF_debug_info].s_scn; + + d = dbg->dbg_s[DWARF_debug_info].s_data; + + while (offset < d->d_size) { + /* Allocate memory for the first compilation unit. */ + if ((cu = calloc(sizeof(struct _Dwarf_CU), 1)) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MEMORY); + return DWARF_E_MEMORY; + } + + /* Save the offet to this compilation unit: */ + cu->cu_offset = offset; + + length = dwarf_read(&d, &offset, 4); + if (length == 0xffffffff) { + length = dwarf_read(&d, &offset, 8); + dbg->dbg_offsize = 8; + } else + dbg->dbg_offsize = 4; + + /* + * Check if there is enough ELF data for this CU. + * This assumes that libelf gives us the entire + * section in one Elf_Data object. + */ + if (length > d->d_size - offset) { + free(cu); + DWARF_SET_ERROR(error, DWARF_E_INVALID_CU); + return DWARF_E_INVALID_CU; + } + + /* Relocate the DWARF sections if necessary: */ + if (!relocated) { + if ((ret = dwarf_relocate(dbg, error)) != DWARF_E_NONE) + return ret; + relocated = 1; + } + + /* Compute the offset to the next compilation unit: */ + next_offset = offset + length; + + /* Initialise the compilation unit. */ + cu->cu_length = length; + cu->cu_header_length = (dbg->dbg_offsize == 4) ? 4 : 12; + cu->cu_version = dwarf_read(&d, &offset, 2); + cu->cu_abbrev_offset = dwarf_read(&d, &offset, dbg->dbg_offsize); + cu->cu_pointer_size = dwarf_read(&d, &offset, 1); + cu->cu_next_offset = next_offset; + + /* Initialise the list of abbrevs. */ + STAILQ_INIT(&cu->cu_abbrev); + + /* Initialise the list of dies. */ + STAILQ_INIT(&cu->cu_die); + + /* Initialise the hash table of dies. */ + for (i = 0; i < DWARF_DIE_HASH_SIZE; i++) + STAILQ_INIT(&cu->cu_die_hash[i]); + + /* Add the compilation unit to the list. */ + STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); + + if (cu->cu_version != 2 && cu->cu_version != 3) { + DWARF_SET_ERROR(error, DWARF_E_CU_VERSION); + ret = DWARF_E_CU_VERSION; + break; + } + + /* Parse the .debug_abbrev info for this CU: */ + if ((ret = dwarf_init_abbrev(dbg, cu, error)) != DWARF_E_NONE) + break; + + level = 0; + + while (offset < next_offset && offset < d->d_size) { + Dwarf_Abbrev a; + Dwarf_Attribute at; + Dwarf_Die die; + uint64_t abnum; + uint64_t die_offset = offset;; + + abnum = dwarf_read_uleb128(&d, &offset); + + if (abnum == 0) { + level--; + continue; + } + + if ((a = dwarf_abbrev_find(cu, abnum)) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MISSING_ABBREV); + return DWARF_E_MISSING_ABBREV; + } + + if ((ret = dwarf_die_add(cu, level, die_offset, + abnum, a, &die, error)) != DWARF_E_NONE) + return ret; + + STAILQ_FOREACH(at, &a->a_attrib, at_next) { + if ((ret = dwarf_init_attr(dbg, &d, &offset, + cu, die, at, at->at_form, error)) != DWARF_E_NONE) + return ret; + } + + if (a->a_children == DW_CHILDREN_yes) + level++; + } + + offset = next_offset; + } + + return ret; +} + +static int +dwarf_elf_read(Dwarf_Debug dbg, Dwarf_Error *error) +{ + GElf_Shdr shdr; + Elf_Scn *scn = NULL; + char *sname; + int i; + int ret = DWARF_E_NONE; + + /* Get a copy of the ELF header. */ + if (gelf_getehdr(dbg->dbg_elf, &dbg->dbg_ehdr) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + /* Check the ELF data format: */ + switch (dbg->dbg_ehdr.e_ident[EI_DATA]) { + case ELFDATA2MSB: + dwarf_read = dwarf_read_msb; + dwarf_write = dwarf_write_msb; + break; + + case ELFDATA2LSB: + case ELFDATANONE: + default: + dwarf_read = dwarf_read_lsb; + dwarf_write = dwarf_write_lsb; + break; + } + + /* Get the section index to the string table. */ + if (elf_getshstrndx(dbg->dbg_elf, &dbg->dbg_stnum) == 0) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + /* Look for the debug sections. */ + while ((scn = elf_nextscn(dbg->dbg_elf, scn)) != NULL) { + /* Get a copy of the section header: */ + if (gelf_getshdr(scn, &shdr) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + /* Get a pointer to the section name: */ + if ((sname = elf_strptr(dbg->dbg_elf, dbg->dbg_stnum, shdr.sh_name)) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + + /* + * Look up the section name to check if it's + * one we need for DWARF. + */ + for (i = 0; i < DWARF_DEBUG_SNAMES; i++) { + if (strcmp(sname, debug_snames[i]) == 0) { + dbg->dbg_s[i].s_sname = sname; + dbg->dbg_s[i].s_shnum = elf_ndxscn(scn); + dbg->dbg_s[i].s_scn = scn; + memcpy(&dbg->dbg_s[i].s_shdr, &shdr, sizeof(shdr)); + if ((dbg->dbg_s[i].s_data = elf_getdata(scn, NULL)) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ELF; + } + break; + } + } + } + + /* Check if any of the required sections are missing: */ + if (dbg->dbg_s[DWARF_debug_abbrev].s_scn == NULL || + dbg->dbg_s[DWARF_debug_info].s_scn == NULL) { + /* Missing debug information. */ + DWARF_SET_ERROR(error, DWARF_E_DEBUG_INFO); + return DWARF_E_DEBUG_INFO; + } + + /* Initialise the compilation-units: */ + ret = dwarf_init_info(dbg, error); + + return ret; +} + +int +dwarf_elf_init(Elf *elf, int mode, Dwarf_Debug *ret_dbg, Dwarf_Error *error) +{ + Dwarf_Debug dbg; + int ret = DWARF_E_NONE; + + if (error == NULL) + /* Can only return a generic error. */ + return DWARF_E_ERROR; + + if (elf == NULL || ret_dbg == NULL) { + DWARF_SET_ERROR(error, DWARF_E_ARGUMENT); + ret = DWARF_E_ARGUMENT; + } else if ((dbg = calloc(sizeof(struct _Dwarf_Debug), 1)) == NULL) { + DWARF_SET_ERROR(error, DWARF_E_MEMORY); + ret = DWARF_E_MEMORY; + } else { + dbg->dbg_elf = elf; + dbg->dbg_elf_close = 0; + dbg->dbg_mode = mode; + + STAILQ_INIT(&dbg->dbg_cu); + + *ret_dbg = dbg; + + /* Read the ELF sections. */ + ret = dwarf_elf_read(dbg, error); + } + + return ret; +} + +int +dwarf_init(int fd, int mode, Dwarf_Debug *ret_dbg, Dwarf_Error *error) +{ + Dwarf_Error lerror; + Elf *elf; + Elf_Cmd c; + int ret; + + if (error == NULL) + /* Can only return a generic error. */ + return DWARF_E_ERROR; + + if (fd < 0 || ret_dbg == NULL) { + DWARF_SET_ERROR(error, DWARF_E_ARGUMENT); + return DWARF_E_ERROR; + } + + /* Translate the DWARF mode to ELF mode. */ + switch (mode) { + default: + case DW_DLC_READ: + c = ELF_C_READ; + break; + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ERROR; + } + + if ((elf = elf_begin(fd, c, NULL)) == NULL) { + DWARF_SET_ELF_ERROR(error, elf_errno()); + return DWARF_E_ERROR; + } + + ret = dwarf_elf_init(elf, mode, ret_dbg, error); + + if (*ret_dbg != NULL) + /* Remember to close the ELF file. */ + (*ret_dbg)->dbg_elf_close = 1; + + if (ret != DWARF_E_NONE) { + if (*ret_dbg != NULL) { + dwarf_finish(ret_dbg, &lerror); + } else + elf_end(elf); + } + + return ret; +} diff --git a/libdwarf/dwarf_loc.c b/libdwarf/dwarf_loc.c new file mode 100644 index 0000000..19b9e77 --- /dev/null +++ b/libdwarf/dwarf_loc.c @@ -0,0 +1,612 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/dwarf_loc.c,v 1.2.2.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#include "_libdwarf.h" + +static int64_t +dwarf_decode_sleb128(uint8_t **dp) +{ + int64_t ret = 0; + uint8_t b; + int shift = 0; + + uint8_t *src = *dp; + + do { + b = *src++; + + ret |= ((b & 0x7f) << shift); + + shift += 7; + } while ((b & 0x80) != 0); + + if (shift < 32 && (b & 0x40) != 0) + ret |= (-1 << shift); + + *dp = src; + + return ret; +} + +static uint64_t +dwarf_decode_uleb128(uint8_t **dp) +{ + uint64_t ret = 0; + uint8_t b; + int shift = 0; + + uint8_t *src = *dp; + + do { + b = *src++; + + ret |= ((b & 0x7f) << shift); + + shift += 7; + } while ((b & 0x80) != 0); + + *dp = src; + + return ret; +} + +/* + * Given an array of bytes of length 'len' representing a + * DWARF expression, compute the number of operations based + * on there being one byte describing the operation and + * zero or more bytes of operands as defined in the standard + * for each operation type. + */ +int +dwarf_op_num(uint8_t pointer_size, uint8_t *p, int len) +{ + int count = 0; + int64_t sval; + uint64_t uval; + uint8_t *last = p + len; + + /* + * Process each byte. If an error occurs, then the + * count will be set to -1. + */ + while (p < last && count >= 0) { + count++; + + switch (*p++) { + /* Operations with no operands. */ + case DW_OP_deref: + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + + case DW_OP_dup: + case DW_OP_drop: + + case DW_OP_over: + + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + + case DW_OP_nop: + break; + + /* Operations with 1-byte operands. */ + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + p++; + break; + + /* Operations with 2-byte operands. */ + case DW_OP_const2u: + case DW_OP_const2s: + case DW_OP_bra: + case DW_OP_skip: + p += 2; + break; + + /* Operations with 4-byte operands. */ + case DW_OP_const4u: + case DW_OP_const4s: + p += 4; + break; + + /* Operations with 8-byte operands. */ + case DW_OP_const8u: + case DW_OP_const8s: + p += 8; + break; + + /* Operations with an unsigned LEB128 operand. */ + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + uval = dwarf_decode_uleb128(&p); + break; + + /* Operations with a signed LEB128 operand. */ + case DW_OP_consts: + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + case DW_OP_fbreg: + sval = dwarf_decode_sleb128(&p); + break; + + /* + * Operations with an unsigned LEB128 operand + * followed by a signed LEB128 operand. + */ + case DW_OP_bregx: + uval = dwarf_decode_uleb128(&p); + sval = dwarf_decode_sleb128(&p); + break; + + /* Target address size operand. */ + case DW_OP_addr: + p += pointer_size; + break; + + /* All other operations cause an error. */ + default: + count = -1; + break; + } + } + + return count; +} + +static int +dwarf_loc_fill(Dwarf_Locdesc *lbuf, uint8_t pointer_size, uint8_t *p, int len) +{ + int count = 0; + int ret = DWARF_E_NONE; + uint64_t operand1; + uint64_t operand2; + uint8_t *last = p + len; + + /* + * Process each byte. If an error occurs, then the + * count will be set to -1. + */ + while (p < last && ret == DWARF_E_NONE) { + operand1 = 0; + operand2 = 0; + + lbuf->ld_s[count].lr_atom = *p; + + switch (*p++) { + /* Operations with no operands. */ + case DW_OP_deref: + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + + case DW_OP_dup: + case DW_OP_drop: + + case DW_OP_over: + + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + + case DW_OP_nop: + break; + + /* Operations with 1-byte operands. */ + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + operand1 = *p++; + break; + + /* Operations with 2-byte operands. */ + case DW_OP_const2u: + case DW_OP_const2s: + case DW_OP_bra: + case DW_OP_skip: + p += 2; + break; + + /* Operations with 4-byte operands. */ + case DW_OP_const4u: + case DW_OP_const4s: + p += 4; + break; + + /* Operations with 8-byte operands. */ + case DW_OP_const8u: + case DW_OP_const8s: + p += 8; + break; + + /* Operations with an unsigned LEB128 operand. */ + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + operand1 = dwarf_decode_uleb128(&p); + break; + + /* Operations with a signed LEB128 operand. */ + case DW_OP_consts: + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + case DW_OP_fbreg: + operand1 = dwarf_decode_sleb128(&p); + break; + + /* + * Operations with an unsigned LEB128 operand + * followed by a signed LEB128 operand. + */ + case DW_OP_bregx: + operand1 = dwarf_decode_uleb128(&p); + operand2 = dwarf_decode_sleb128(&p); + break; + + /* Target address size operand. */ + case DW_OP_addr: + p += pointer_size; + break; + + /* All other operations cause an error. */ + default: + break; + } + + lbuf->ld_s[count].lr_number = operand1; + lbuf->ld_s[count].lr_number2 = operand2; + + count++; + } + + return ret; +} + +int +dwarf_locdesc(Dwarf_Die die, uint64_t attr, Dwarf_Locdesc **llbuf, Dwarf_Signed *lenp, Dwarf_Error *err) +{ + Dwarf_AttrValue av; + Dwarf_Locdesc *lbuf; + int num; + int ret = DWARF_E_NONE; + + if (err == NULL) + return DWARF_E_ERROR; + + if (die == NULL || llbuf == NULL || lenp == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if ((av = dwarf_attrval_find(die, attr)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY); + ret = DWARF_E_NO_ENTRY; + } else if ((lbuf = calloc(sizeof(Dwarf_Locdesc), 1)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_MEMORY); + ret = DWARF_E_MEMORY; + } else { + *lenp = 0; + switch (av->av_form) { + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + /* Compute the number of locations: */ + if ((num = dwarf_op_num(die->die_cu->cu_pointer_size, + av->u[1].u8p, av->u[0].u64)) < 0) { + DWARF_SET_ERROR(err, DWARF_E_INVALID_EXPR); + ret = DWARF_E_INVALID_EXPR; + + /* Allocate an array of location structures. */ + } else if ((lbuf->ld_s = + calloc(sizeof(Dwarf_Loc), num)) == NULL) { + DWARF_SET_ERROR(err, DWARF_E_MEMORY); + ret = DWARF_E_MEMORY; + + /* Fill the array of location structures. */ + } else if ((ret = dwarf_loc_fill(lbuf, + die->die_cu->cu_pointer_size, + av->u[1].u8p, av->u[0].u64)) != DWARF_E_NONE) { + free(lbuf->ld_s); + } else + /* Only one descriptor is returned. */ + *lenp = 1; + break; + default: + printf("%s(%d): form %s not handled\n",__func__, + __LINE__,get_form_desc(av->av_form)); + DWARF_SET_ERROR(err, DWARF_E_NOT_IMPLEMENTED); + ret = DWARF_E_ERROR; + } + + if (ret == DWARF_E_NONE) { + *llbuf = lbuf; + } else + free(lbuf); + } + + return ret; +} + +int +dwarf_locdesc_free(Dwarf_Locdesc *lbuf, Dwarf_Error *err) +{ + if (err == NULL) + return DWARF_E_ERROR; + + if (lbuf == NULL) { + DWARF_SET_ERROR(err, DWARF_E_ARGUMENT); + return DWARF_E_ARGUMENT; + } + + if (lbuf->ld_s != NULL) + free(lbuf->ld_s); + + free(lbuf); + + return DWARF_E_NONE; +} diff --git a/libdwarf/libdwarf.h b/libdwarf/libdwarf.h new file mode 100644 index 0000000..d3b6905 --- /dev/null +++ b/libdwarf/libdwarf.h @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2007 John Birrell (jb@freebsd.org) + * 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libdwarf/libdwarf.h,v 1.1.4.1.6.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#ifndef _LIBDWARF_H_ +#define _LIBDWARF_H_ + +#include <libelf.h> + +typedef int Dwarf_Bool; +typedef off_t Dwarf_Off; +typedef uint64_t Dwarf_Unsigned; +typedef uint16_t Dwarf_Half; +typedef uint8_t Dwarf_Small; +typedef int64_t Dwarf_Signed; +typedef uint64_t Dwarf_Addr; +typedef void *Dwarf_Ptr; + +/* Forward definitions. */ +typedef struct _Dwarf_Abbrev *Dwarf_Abbrev; +typedef struct _Dwarf_Arange *Dwarf_Arange; +typedef struct _Dwarf_Attribute *Dwarf_Attribute; +typedef struct _Dwarf_AttrValue *Dwarf_AttrValue; +typedef struct _Dwarf_CU *Dwarf_CU; +typedef struct _Dwarf_Cie *Dwarf_Cie; +typedef struct _Dwarf_Debug *Dwarf_Debug; +typedef struct _Dwarf_Die *Dwarf_Die; +typedef struct _Dwarf_Fde *Dwarf_Fde; +typedef struct _Dwarf_Func *Dwarf_Func; +typedef struct _Dwarf_Global *Dwarf_Global; +typedef struct _Dwarf_Line *Dwarf_Line; +typedef struct _Dwarf_Type *Dwarf_Type; +typedef struct _Dwarf_Var *Dwarf_Var; +typedef struct _Dwarf_Weak *Dwarf_Weak; + +typedef struct { + Dwarf_Small lr_atom; + Dwarf_Unsigned lr_number; + Dwarf_Unsigned lr_number2; + Dwarf_Unsigned lr_offset; +} Dwarf_Loc; + +typedef struct { + Dwarf_Addr ld_lopc; + Dwarf_Addr ld_hipc; + Dwarf_Half ld_cents; + Dwarf_Loc *ld_s; +} Dwarf_Locdesc; + +/* + * Error numbers which are specific to this implementation. + */ +enum { + DWARF_E_NONE, /* No error. */ + DWARF_E_ERROR, /* An error! */ + DWARF_E_NO_ENTRY, /* No entry. */ + DWARF_E_ARGUMENT, /* Invalid argument. */ + DWARF_E_DEBUG_INFO, /* Debug info NULL. */ + DWARF_E_MEMORY, /* Insufficient memory. */ + DWARF_E_ELF, /* ELF error. */ + DWARF_E_INVALID_CU, /* Invalid compilation unit data. */ + DWARF_E_CU_VERSION, /* Wrong CU version. */ + DWARF_E_MISSING_ABBREV, /* Abbrev not found. */ + DWARF_E_NOT_IMPLEMENTED, /* Not implemented. */ + DWARF_E_CU_CURRENT, /* No current compilation unit. */ + DWARF_E_BAD_FORM, /* Wrong form type for attribute value. */ + DWARF_E_INVALID_EXPR, /* Invalid DWARF expression. */ + DWARF_E_NUM /* Max error number. */ +}; + +typedef struct _Dwarf_Error { + int err_error; /* DWARF error. */ + int elf_error; /* ELF error. */ + const char *err_func; /* Function name where error occurred. */ + int err_line; /* Line number where error occurred. */ + char err_msg[1024]; /* Formatted error message. */ +} Dwarf_Error; + +/* + * Return values which have to be compatible with other + * implementations of libdwarf. + */ +#define DW_DLV_NO_ENTRY DWARF_E_NO_ENTRY +#define DW_DLV_OK DWARF_E_NONE +#define DW_DLE_DEBUG_INFO_NULL DWARF_E_DEBUG_INFO + +#define DW_DLC_READ 0 /* read only access */ + +/* Function prototype definitions. */ +__BEGIN_DECLS +Dwarf_Abbrev dwarf_abbrev_find(Dwarf_CU, uint64_t); +Dwarf_AttrValue dwarf_attrval_find(Dwarf_Die, Dwarf_Half); +Dwarf_Die dwarf_die_find(Dwarf_Die, Dwarf_Unsigned); +const char *dwarf_errmsg(Dwarf_Error *); +const char *get_sht_desc(uint32_t); +const char *get_attr_desc(uint32_t); +const char *get_form_desc(uint32_t); +const char *get_tag_desc(uint32_t); +int dwarf_abbrev_add(Dwarf_CU, uint64_t, uint64_t, uint8_t, Dwarf_Abbrev *, Dwarf_Error *); +int dwarf_attr(Dwarf_Die, Dwarf_Half, Dwarf_Attribute *, Dwarf_Error *); +int dwarf_attr_add(Dwarf_Abbrev, uint64_t, uint64_t, Dwarf_Attribute *, Dwarf_Error *); +int dwarf_attrval(Dwarf_Die, Dwarf_Half, Dwarf_AttrValue *, Dwarf_Error *); +int dwarf_attrval_add(Dwarf_Die, Dwarf_AttrValue, Dwarf_AttrValue *, Dwarf_Error *); +int dwarf_attrval_flag(Dwarf_Die, uint64_t, Dwarf_Bool *, Dwarf_Error *); +int dwarf_attrval_signed(Dwarf_Die, uint64_t, Dwarf_Signed *, Dwarf_Error *); +int dwarf_attrval_string(Dwarf_Die, uint64_t, const char **, Dwarf_Error *); +int dwarf_attrval_unsigned(Dwarf_Die, uint64_t, Dwarf_Unsigned *, Dwarf_Error *); +int dwarf_child(Dwarf_Die, Dwarf_Die *, Dwarf_Error *); +int dwarf_die_add(Dwarf_CU, int, uint64_t, uint64_t, Dwarf_Abbrev, Dwarf_Die *, Dwarf_Error *); +int dwarf_dieoffset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *); +int dwarf_elf_init(Elf *, int, Dwarf_Debug *, Dwarf_Error *); +int dwarf_errno(Dwarf_Error *); +int dwarf_finish(Dwarf_Debug *, Dwarf_Error *); +int dwarf_locdesc(Dwarf_Die, uint64_t, Dwarf_Locdesc **, Dwarf_Signed *, Dwarf_Error *); +int dwarf_locdesc_free(Dwarf_Locdesc *, Dwarf_Error *); +int dwarf_init(int, int, Dwarf_Debug *, Dwarf_Error *); +int dwarf_next_cu_header(Dwarf_Debug, Dwarf_Unsigned *, Dwarf_Half *, + Dwarf_Unsigned *, Dwarf_Half *, Dwarf_Unsigned *, Dwarf_Error *); +int dwarf_op_num(uint8_t, uint8_t *, int); +int dwarf_siblingof(Dwarf_Debug, Dwarf_Die, Dwarf_Die *, Dwarf_Error *); +int dwarf_tag(Dwarf_Die, Dwarf_Half *, Dwarf_Error *); +int dwarf_whatform(Dwarf_Attribute, Dwarf_Half *, Dwarf_Error *); +void dwarf_dealloc(Dwarf_Debug, Dwarf_Ptr, Dwarf_Unsigned); +void dwarf_dump(Dwarf_Debug); +void dwarf_dump_abbrev(Dwarf_Debug); +void dwarf_dump_av(Dwarf_Die, Dwarf_AttrValue); +void dwarf_dump_dbgstr(Dwarf_Debug); +void dwarf_dump_die(Dwarf_Die); +void dwarf_dump_die_at_offset(Dwarf_Debug, Dwarf_Off); +void dwarf_dump_info(Dwarf_Debug); +void dwarf_dump_shstrtab(Dwarf_Debug); +void dwarf_dump_strtab(Dwarf_Debug); +void dwarf_dump_symtab(Dwarf_Debug); +void dwarf_dump_raw(Dwarf_Debug); +void dwarf_dump_tree(Dwarf_Debug); +__END_DECLS + +#endif /* !_LIBDWARF_H_ */ diff --git a/libdwarf/queue.h b/libdwarf/queue.h new file mode 100644 index 0000000..1fdfea3 --- /dev/null +++ b/libdwarf/queue.h @@ -0,0 +1,636 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.72.2.3.2.1 2010/12/21 17:09:25 kensmith Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include <sys/cdefs.h> + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/pctf/ctf_api.h b/pctf/ctf_api.h index a26a39e..9a7b91e 100644 --- a/pctf/ctf_api.h +++ b/pctf/ctf_api.h @@ -43,7 +43,6 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/types.h> -#include <sys/elf.h> #include <pctf/ctf.h> #ifdef __cplusplus |