From c78e984f3abbd20f6e01d6f51819e826b1691f65 Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:24:44 -0500 Subject: [PATCH] Create mirror of 6216e185863f41d6f19ab850caabfff7326020d7 --- .gitattributes | 3 + .gitignore | 2 + CMakeLists.txt | 366 + COPYING | 25 + README.md | 2 + cmake/FindZSTD.cmake | 63 + cmake/config.h.cmake | 120 + notes.txt | 5 + patches/CMakeLists.patch | 239 + pull.sh | 24 + src/lib/libdwarf/CMakeLists.txt | 167 + src/lib/libdwarf/COPYING | 32 + src/lib/libdwarf/LGPL.txt | 504 + src/lib/libdwarf/LIBDWARFCOPYRIGHT | 42 + src/lib/libdwarf/Makefile.am | 162 + src/lib/libdwarf/README | 238 + src/lib/libdwarf/cmake/libdwarf-config.cmake | 3 + src/lib/libdwarf/dw-linetableheader.txt | 44 + src/lib/libdwarf/dwarf.h | 1584 +++ src/lib/libdwarf/dwarf_abbrev.c | 451 + src/lib/libdwarf/dwarf_abbrev.h | 82 + src/lib/libdwarf/dwarf_alloc.c | 1201 +++ src/lib/libdwarf/dwarf_alloc.h | 58 + src/lib/libdwarf/dwarf_arange.c | 738 ++ src/lib/libdwarf/dwarf_arange.h | 60 + src/lib/libdwarf/dwarf_base_types.h | 137 + src/lib/libdwarf/dwarf_crc.c | 137 + src/lib/libdwarf/dwarf_crc32.c | 153 + src/lib/libdwarf/dwarf_debug_sup.c | 206 + src/lib/libdwarf/dwarf_debugaddr.c | 342 + src/lib/libdwarf/dwarf_debugaddr.h | 75 + src/lib/libdwarf/dwarf_debuglink.c | 1085 ++ src/lib/libdwarf/dwarf_debuglink.h | 60 + src/lib/libdwarf/dwarf_debugnames.c | 1915 ++++ src/lib/libdwarf/dwarf_debugnames.h | 121 + src/lib/libdwarf/dwarf_die_deliv.c | 3263 ++++++ src/lib/libdwarf/dwarf_die_deliv.h | 78 + src/lib/libdwarf/dwarf_dsc.c | 331 + src/lib/libdwarf/dwarf_dsc.h | 59 + src/lib/libdwarf/dwarf_elf_access.h | 47 + src/lib/libdwarf/dwarf_elf_defines.h | 1118 ++ src/lib/libdwarf/dwarf_elf_load_headers.c | 2230 ++++ src/lib/libdwarf/dwarf_elf_rel_detector.c | 368 + src/lib/libdwarf/dwarf_elf_rel_detector.h | 48 + src/lib/libdwarf/dwarf_elfread.c | 809 ++ src/lib/libdwarf/dwarf_elfread.h | 288 + src/lib/libdwarf/dwarf_elfstructs.h | 213 + src/lib/libdwarf/dwarf_errmsg_list.h | 691 ++ src/lib/libdwarf/dwarf_error.c | 230 + src/lib/libdwarf/dwarf_error.h | 71 + src/lib/libdwarf/dwarf_fill_in_attr_form.c | 195 + src/lib/libdwarf/dwarf_find_sigref.c | 222 + src/lib/libdwarf/dwarf_fission_to_cu.c | 367 + src/lib/libdwarf/dwarf_form.c | 2263 +++++ src/lib/libdwarf/dwarf_form_class_names.c | 110 + src/lib/libdwarf/dwarf_frame.c | 3503 +++++++ src/lib/libdwarf/dwarf_frame.h | 509 + src/lib/libdwarf/dwarf_frame2.c | 2049 ++++ src/lib/libdwarf/dwarf_gdbindex.c | 850 ++ src/lib/libdwarf/dwarf_gdbindex.h | 84 + src/lib/libdwarf/dwarf_generic_init.c | 557 + src/lib/libdwarf/dwarf_global.c | 1674 +++ src/lib/libdwarf/dwarf_global.h | 135 + src/lib/libdwarf/dwarf_gnu_index.c | 791 ++ src/lib/libdwarf/dwarf_gnu_index.h | 95 + src/lib/libdwarf/dwarf_groups.c | 396 + src/lib/libdwarf/dwarf_harmless.c | 240 + src/lib/libdwarf/dwarf_harmless.h | 31 + src/lib/libdwarf/dwarf_init_finish.c | 1745 ++++ src/lib/libdwarf/dwarf_leb.c | 430 + src/lib/libdwarf/dwarf_line.c | 2649 +++++ src/lib/libdwarf/dwarf_line.h | 491 + .../libdwarf/dwarf_line_table_reader_common.h | 2857 ++++++ src/lib/libdwarf/dwarf_loc.c | 1929 ++++ src/lib/libdwarf/dwarf_loc.h | 339 + src/lib/libdwarf/dwarf_locationop_read.c | 895 ++ src/lib/libdwarf/dwarf_loclists.c | 1360 +++ src/lib/libdwarf/dwarf_macho_loader.h | 1959 ++++ src/lib/libdwarf/dwarf_machoread.c | 1427 +++ src/lib/libdwarf/dwarf_machoread.h | 158 + src/lib/libdwarf/dwarf_macro.c | 517 + src/lib/libdwarf/dwarf_macro.h | 36 + src/lib/libdwarf/dwarf_macro5.c | 1666 +++ src/lib/libdwarf/dwarf_macro5.h | 151 + src/lib/libdwarf/dwarf_memcpy_swap.c | 74 + src/lib/libdwarf/dwarf_memcpy_swap.h | 46 + src/lib/libdwarf/dwarf_names.c | 3834 +++++++ src/lib/libdwarf/dwarf_object_detector.c | 1019 ++ src/lib/libdwarf/dwarf_object_detector.h | 91 + src/lib/libdwarf/dwarf_object_read_common.c | 96 + src/lib/libdwarf/dwarf_object_read_common.h | 47 + src/lib/libdwarf/dwarf_opaque.h | 1108 ++ src/lib/libdwarf/dwarf_pe_descr.h | 257 + src/lib/libdwarf/dwarf_peread.c | 1005 ++ src/lib/libdwarf/dwarf_peread.h | 155 + src/lib/libdwarf/dwarf_print_lines.c | 1030 ++ src/lib/libdwarf/dwarf_query.c | 2129 ++++ src/lib/libdwarf/dwarf_ranges.c | 356 + src/lib/libdwarf/dwarf_reading.h | 72 + src/lib/libdwarf/dwarf_rnglists.c | 1541 +++ src/lib/libdwarf/dwarf_rnglists.h | 157 + src/lib/libdwarf/dwarf_safe_arithmetic.c | 167 + src/lib/libdwarf/dwarf_safe_arithmetic.h | 53 + src/lib/libdwarf/dwarf_safe_strcpy.c | 100 + src/lib/libdwarf/dwarf_safe_strcpy.h | 47 + src/lib/libdwarf/dwarf_secname_ck.c | 118 + src/lib/libdwarf/dwarf_secname_ck.h | 36 + src/lib/libdwarf/dwarf_setup_sections.c | 521 + src/lib/libdwarf/dwarf_setup_sections.h | 42 + src/lib/libdwarf/dwarf_str_offsets.c | 684 ++ src/lib/libdwarf/dwarf_str_offsets.h | 104 + src/lib/libdwarf/dwarf_string.c | 863 ++ src/lib/libdwarf/dwarf_string.h | 93 + src/lib/libdwarf/dwarf_stringsection.c | 100 + src/lib/libdwarf/dwarf_tied.c | 271 + src/lib/libdwarf/dwarf_tied_decls.h | 50 + src/lib/libdwarf/dwarf_tsearch.h | 123 + src/lib/libdwarf/dwarf_tsearchhash.c | 708 ++ src/lib/libdwarf/dwarf_universal.h | 63 + src/lib/libdwarf/dwarf_util.c | 1606 +++ src/lib/libdwarf/dwarf_util.h | 516 + src/lib/libdwarf/dwarf_xu_index.c | 1009 ++ src/lib/libdwarf/dwarf_xu_index.h | 63 + src/lib/libdwarf/libdwarf.h | 8991 +++++++++++++++++ src/lib/libdwarf/libdwarf.pc.cmake | 12 + src/lib/libdwarf/libdwarf_private.h | 113 + src/lib/libdwarf/meson.build | 102 + 127 files changed, 82542 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 README.md create mode 100644 cmake/FindZSTD.cmake create mode 100644 cmake/config.h.cmake create mode 100644 notes.txt create mode 100644 patches/CMakeLists.patch create mode 100644 pull.sh create mode 100644 src/lib/libdwarf/CMakeLists.txt create mode 100644 src/lib/libdwarf/COPYING create mode 100644 src/lib/libdwarf/LGPL.txt create mode 100644 src/lib/libdwarf/LIBDWARFCOPYRIGHT create mode 100644 src/lib/libdwarf/Makefile.am create mode 100644 src/lib/libdwarf/README create mode 100644 src/lib/libdwarf/cmake/libdwarf-config.cmake create mode 100644 src/lib/libdwarf/dw-linetableheader.txt create mode 100644 src/lib/libdwarf/dwarf.h create mode 100644 src/lib/libdwarf/dwarf_abbrev.c create mode 100644 src/lib/libdwarf/dwarf_abbrev.h create mode 100644 src/lib/libdwarf/dwarf_alloc.c create mode 100644 src/lib/libdwarf/dwarf_alloc.h create mode 100644 src/lib/libdwarf/dwarf_arange.c create mode 100644 src/lib/libdwarf/dwarf_arange.h create mode 100644 src/lib/libdwarf/dwarf_base_types.h create mode 100644 src/lib/libdwarf/dwarf_crc.c create mode 100644 src/lib/libdwarf/dwarf_crc32.c create mode 100644 src/lib/libdwarf/dwarf_debug_sup.c create mode 100644 src/lib/libdwarf/dwarf_debugaddr.c create mode 100644 src/lib/libdwarf/dwarf_debugaddr.h create mode 100644 src/lib/libdwarf/dwarf_debuglink.c create mode 100644 src/lib/libdwarf/dwarf_debuglink.h create mode 100644 src/lib/libdwarf/dwarf_debugnames.c create mode 100644 src/lib/libdwarf/dwarf_debugnames.h create mode 100644 src/lib/libdwarf/dwarf_die_deliv.c create mode 100644 src/lib/libdwarf/dwarf_die_deliv.h create mode 100644 src/lib/libdwarf/dwarf_dsc.c create mode 100644 src/lib/libdwarf/dwarf_dsc.h create mode 100644 src/lib/libdwarf/dwarf_elf_access.h create mode 100644 src/lib/libdwarf/dwarf_elf_defines.h create mode 100644 src/lib/libdwarf/dwarf_elf_load_headers.c create mode 100644 src/lib/libdwarf/dwarf_elf_rel_detector.c create mode 100644 src/lib/libdwarf/dwarf_elf_rel_detector.h create mode 100644 src/lib/libdwarf/dwarf_elfread.c create mode 100644 src/lib/libdwarf/dwarf_elfread.h create mode 100644 src/lib/libdwarf/dwarf_elfstructs.h create mode 100644 src/lib/libdwarf/dwarf_errmsg_list.h create mode 100644 src/lib/libdwarf/dwarf_error.c create mode 100644 src/lib/libdwarf/dwarf_error.h create mode 100644 src/lib/libdwarf/dwarf_fill_in_attr_form.c create mode 100644 src/lib/libdwarf/dwarf_find_sigref.c create mode 100644 src/lib/libdwarf/dwarf_fission_to_cu.c create mode 100644 src/lib/libdwarf/dwarf_form.c create mode 100644 src/lib/libdwarf/dwarf_form_class_names.c create mode 100644 src/lib/libdwarf/dwarf_frame.c create mode 100644 src/lib/libdwarf/dwarf_frame.h create mode 100644 src/lib/libdwarf/dwarf_frame2.c create mode 100644 src/lib/libdwarf/dwarf_gdbindex.c create mode 100644 src/lib/libdwarf/dwarf_gdbindex.h create mode 100644 src/lib/libdwarf/dwarf_generic_init.c create mode 100644 src/lib/libdwarf/dwarf_global.c create mode 100644 src/lib/libdwarf/dwarf_global.h create mode 100644 src/lib/libdwarf/dwarf_gnu_index.c create mode 100644 src/lib/libdwarf/dwarf_gnu_index.h create mode 100644 src/lib/libdwarf/dwarf_groups.c create mode 100644 src/lib/libdwarf/dwarf_harmless.c create mode 100644 src/lib/libdwarf/dwarf_harmless.h create mode 100644 src/lib/libdwarf/dwarf_init_finish.c create mode 100644 src/lib/libdwarf/dwarf_leb.c create mode 100644 src/lib/libdwarf/dwarf_line.c create mode 100644 src/lib/libdwarf/dwarf_line.h create mode 100644 src/lib/libdwarf/dwarf_line_table_reader_common.h create mode 100644 src/lib/libdwarf/dwarf_loc.c create mode 100644 src/lib/libdwarf/dwarf_loc.h create mode 100644 src/lib/libdwarf/dwarf_locationop_read.c create mode 100644 src/lib/libdwarf/dwarf_loclists.c create mode 100644 src/lib/libdwarf/dwarf_macho_loader.h create mode 100644 src/lib/libdwarf/dwarf_machoread.c create mode 100644 src/lib/libdwarf/dwarf_machoread.h create mode 100644 src/lib/libdwarf/dwarf_macro.c create mode 100644 src/lib/libdwarf/dwarf_macro.h create mode 100644 src/lib/libdwarf/dwarf_macro5.c create mode 100644 src/lib/libdwarf/dwarf_macro5.h create mode 100644 src/lib/libdwarf/dwarf_memcpy_swap.c create mode 100644 src/lib/libdwarf/dwarf_memcpy_swap.h create mode 100644 src/lib/libdwarf/dwarf_names.c create mode 100644 src/lib/libdwarf/dwarf_object_detector.c create mode 100644 src/lib/libdwarf/dwarf_object_detector.h create mode 100644 src/lib/libdwarf/dwarf_object_read_common.c create mode 100644 src/lib/libdwarf/dwarf_object_read_common.h create mode 100644 src/lib/libdwarf/dwarf_opaque.h create mode 100644 src/lib/libdwarf/dwarf_pe_descr.h create mode 100644 src/lib/libdwarf/dwarf_peread.c create mode 100644 src/lib/libdwarf/dwarf_peread.h create mode 100644 src/lib/libdwarf/dwarf_print_lines.c create mode 100644 src/lib/libdwarf/dwarf_query.c create mode 100644 src/lib/libdwarf/dwarf_ranges.c create mode 100644 src/lib/libdwarf/dwarf_reading.h create mode 100644 src/lib/libdwarf/dwarf_rnglists.c create mode 100644 src/lib/libdwarf/dwarf_rnglists.h create mode 100644 src/lib/libdwarf/dwarf_safe_arithmetic.c create mode 100644 src/lib/libdwarf/dwarf_safe_arithmetic.h create mode 100644 src/lib/libdwarf/dwarf_safe_strcpy.c create mode 100644 src/lib/libdwarf/dwarf_safe_strcpy.h create mode 100644 src/lib/libdwarf/dwarf_secname_ck.c create mode 100644 src/lib/libdwarf/dwarf_secname_ck.h create mode 100644 src/lib/libdwarf/dwarf_setup_sections.c create mode 100644 src/lib/libdwarf/dwarf_setup_sections.h create mode 100644 src/lib/libdwarf/dwarf_str_offsets.c create mode 100644 src/lib/libdwarf/dwarf_str_offsets.h create mode 100644 src/lib/libdwarf/dwarf_string.c create mode 100644 src/lib/libdwarf/dwarf_string.h create mode 100644 src/lib/libdwarf/dwarf_stringsection.c create mode 100644 src/lib/libdwarf/dwarf_tied.c create mode 100644 src/lib/libdwarf/dwarf_tied_decls.h create mode 100644 src/lib/libdwarf/dwarf_tsearch.h create mode 100644 src/lib/libdwarf/dwarf_tsearchhash.c create mode 100644 src/lib/libdwarf/dwarf_universal.h create mode 100644 src/lib/libdwarf/dwarf_util.c create mode 100644 src/lib/libdwarf/dwarf_util.h create mode 100644 src/lib/libdwarf/dwarf_xu_index.c create mode 100644 src/lib/libdwarf/dwarf_xu_index.h create mode 100644 src/lib/libdwarf/libdwarf.h create mode 100644 src/lib/libdwarf/libdwarf.pc.cmake create mode 100644 src/lib/libdwarf/libdwarf_private.h create mode 100644 src/lib/libdwarf/meson.build diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bafb944 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +src/** linguist-vendored +cmake/** linguist-vendored +CMakeLists.txt linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f63cd1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +libdwarf-code diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..50ce24c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,366 @@ +cmake_minimum_required(VERSION 3.5) + +project(libdwarf C CXX) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +include_directories( ${PROJECT_BINARY_DIR} ) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +# used to compile on MSVC upto 2013 where snprintf is not available +macro(msvc_posix target) + if(MSVC AND ("${MSVC_VERSION}" LESS 1900)) + # under VS 2015 + target_compile_definitions(${target} PUBLIC + snprintf=_snprintf) + endif() +endmacro() + +set(LIBDWARF_CRT "MD" CACHE STRING "Either MT or MD, specifies whether to use the static or dynamic MSVCRT.") + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # Use CMAKE_MSVC_RUNTIME in versions 3.15 and up + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") + cmake_policy(SET CMP0091 NEW) + if (LIBDWARF_CRT STREQUAL "MT") + message(STATUS "Using MT runtime by CMAKE_MSVC_RUNTIME_LIBRARY") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + elseif(LIBDWARF_CRT STREQUAL "MD") + message(STATUS "Using MD runtime by CMAKE_MSVC_RUNTIME_LIBRARY") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + else() + message(FATAL_ERROR "LIBDWARF_CRT must be MT or MD") + endif() + # Use regexes in versions before 3.15 + else() + if (LIBDWARF_CRT STREQUAL "MT") + message(STATUS "Using MT runtime by compile flag replacement") + # taken from the CMake FAQ + foreach(flag_v + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (${flag_v} MATCHES "([\\/\\-]M)D") + string(REGEX REPLACE "([\\/\\-]M)D" "\\1T" + ${flag_v} "${${flag_v}}") + endif() + endforeach() + elseif(LIBDWARF_CRT STREQUAL "MD") + message(STATUS "Using MD runtime by cmake default") + else() + message(FATAL_ERROR "LIBDWARF_CRT must be MT or MD") + endif() + endif() +endif() + +# message("CMake flags are:") +# message(" CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") +# message(" CMAKE_C_FLAGS_DEBUG: ${CMAKE_C_FLAGS_DEBUG}") +# message(" CMAKE_C_FLAGS_RELEASE: ${CMAKE_C_FLAGS_RELEASE}") +# message(" CMAKE_C_FLAGS_MINSIZEREL: ${CMAKE_C_FLAGS_MINSIZEREL}") +# message(" CMAKE_C_FLAGS_RELWITHDEBINFO: ${CMAKE_C_FLAGS_RELWITHDEBINFO}") +# message(" CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") +# message(" CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}") +# message(" CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") +# message(" CMAKE_CXX_FLAGS_MINSIZEREL: ${CMAKE_CXX_FLAGS_MINSIZEREL}") +# message(" CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + + +# set target folder on IDE +macro(set_folder target folder) + set_target_properties(${target} PROPERTIES FOLDER ${folder}) +endmacro() + +# set source groups on IDE +macro(set_source_group list_name group_name) + set(${list_name} ${ARGN}) + source_group(${group_name} FILES ${ARGN}) +endmacro() + +# view folders on supported IDEs +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# tells cmake to look in 64bit first (cmake +# would probably do this anyway). +set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE) + +enable_testing() + +# always include project's folder to includes +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) + +### begin what was configure.cmake +# cmake macros +include(TestBigEndian) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +include(CheckCSourceRuns) +include(CheckSymbolExists) +### Version also appears in configure.ac +set(VERSION 0.9.0) +set(PACKAGE_VERSION "\"${VERSION}\"") +set(PACKAGE_NAME "libdwarf" ) +set(PACKAGE_STRING "\"${PACKAGE_NAME} ${VERSION}\"") +string(REGEX REPLACE "[\"]" "" tarname1 "${PACKAGE_STRING}" ) +string(REGEX REPLACE "[^a-zA-Z0-9_]" "-" tarname "${tarname1}" ) +set(PACKAGE_TARNAME "\"${tarname}\"" ) + +test_big_endian(isBigEndian) +if (${isBigEndian}) + set ( WORDS_BIGENDIAN 1 ) +endif() + +# check_include_file( "sys/types.h" HAVE_SYS_TYPES_H) // Only used by dwarfgen +# check_include_file( "sys/stat.h" HAVE_SYS_STAT_H ) // Only used by dwarfgen +# check_include_file( "inttypes.h" HAVE_INTTYPES_H ) // Unused +# check_include_file( "memory.h" HAVE_MEMORY_H ) // Unused +# check_include_file( "strings.h" HAVE_STRINGS_H ) // Unused +check_include_file( "stdint.h" HAVE_STDINT_H ) +check_include_file( "unistd.h" HAVE_UNISTD_H ) +# check_include_file( "sgidefs.h" HAVE_SGIDEFS_H ) // Unused +check_include_file( "stdafx.h" HAVE_STDAFX_H ) +check_include_file( "fcntl.h" HAVE_FCNTL_H ) + +### cmake provides no way to guarantee uint32_t present. +### configure does guarantee that. +# HAVE_UINTPTR_T: Unused +# uintptr_t: Unused +# HAVE_INTPTR_T: Unused +# if(HAVE_STDINT_H) +# check_c_source_compiles(" +# #include +# int main() +# { +# uintptr_t i; i = 12; +# return (int)i; +# }" HAVE_UINTPTR_T) +# check_c_source_compiles(" +# #include +# int main() +# { +# intptr_t i; i = 12; +# return (int)i; +# }" HAVE_INTPTR_T) +# endif() +# if (HAVE_UINTPTR_T) +# message(STATUS "HAVE_UINTPTR_T 1: uintptr_t defined in stdint.h... YES") +# else() +# message(STATUS "uintptr_t defined in stdint.h... NO") +# set(uintptr_t "unsigned long long int" ) +# message(STATUS "Setting #define uintptr_t " ${uintptr_t}) +# endif() +# if (uintptr_t) +# message(STATUS "uintptr_t value considered YES ") +# else() +# message(STATUS "uintptr_t value considered NO ") +# endif() +# if (HAVE_INTPTR_T) +# message(STATUS "HAVE_INTPTR_T 1: intptr_t defined in stdint.h... YES") +# else() +# message(STATUS "intptr_t defined in stdint.h... NO") +# set(uintptr_t "long long int" ) +# message(STATUS "Setting #define intptr_t " ${intptr_t}) +# endif() +# if (intptr_t) +# message(STATUS "intptr_t value considered YES ") +# else() +# message(STATUS "intptr_t value considered NO ") +# endif() + +# Unused +# check_c_source_compiles(" +# static unsigned foo( unsigned x, +# __attribute__ ((unused)) int y) +# { +# unsigned x2 = x + 1; +# return x2; +# } + +# int main(void) { +# unsigned y = 0; +# y = foo(12,y); +# return 0; +# }" HAVE_UNUSED_ATTRIBUTE) +# message(STATUS "Checking compiler supports __attribute__ unused... ${HAVE_UNUSED_ATTRIBUTE}") + +# Redundant +# check_c_source_compiles([=[ +# #include "stdafx.h" +# int main() +# { +# int p; p = 27; +# return 0; +# }]=] HAVE_STDAFX_H) +#message(STATUS "Checking have windows stdafx.h... ${HAVE_STDAFX_H}") + +set(CMAKE_REQUIRED_LIBRARIES z) +check_c_source_compiles( [=[ + #include "zlib.h" + int main() + { + Bytef dest[100]; + uLongf destlen = 100; + Bytef *src = 0; + uLong srclen = 3; + int res = uncompress(dest,&destlen,src,srclen); + if (res == Z_OK) { + /* ALL IS WELL */ + } + return 0; + } ]=] HAVE_ZLIB ) +check_c_source_compiles( [=[ + #include "zlib.h" + int main() + { + Bytef dest[100]; + uLongf destlen = 100; + Bytef *src = 0; + uLong srclen = 3; + int res = uncompress(dest,&destlen,src,srclen); + if (res == Z_OK) { + /* ALL IS WELL */ + } + return 0; + } ]=] HAVE_ZLIB_H ) +set(CMAKE_REQUIRED_LIBRARIES) +if (HAVE_ZLIB) + # For linking in libz + set(DW_FZLIB "z") +endif() + +set(CMAKE_REQUIRED_LIBRARIES zstd ) +check_c_source_compiles( [=[ + #include "zstd.h" + int main() + { + char * dest[100]; + size_t destlen = 100; + char *src = 0; + size_t srclen = 3; + size_t res = ZSTD_decompress(dest,destlen,src,srclen); + if (res == destlen) { + /* ALL IS WELL */ + } + return 0; + } ]=] HAVE_ZSTD ) +check_c_source_compiles( [=[ + #include "zstd.h" + int main() + { + char * dest[100]; + size_t destlen = 100; + char *src = 0; + size_t srclen = 3; + size_t res = ZSTD_decompress(dest,destlen,src,srclen); + if (res == destlen) { + /* ALL IS WELL */ + } + return 0; + } ]=] HAVE_ZSTD_H ) +set(CMAKE_REQUIRED_LIBRARIES) +if (HAVE_ZSTD) + # For linking in libzstd + set(DW_FZSTD "zstd") +endif() + + +# Unused +# check_c_source_compiles([=[ +# #include +# int main() +# { +# intptr_t p; +# p = 27; +# return 0; +# }]=] HAVE_INTPTR_T) + +message(STATUS "CMAKE_SIZEOF_VOID_P ... " ${CMAKE_SIZEOF_VOID_P} ) + +# libdwarf +option(BUILD_NON_SHARED "build archive library libdwarf[p].a" TRUE) +option(BUILD_SHARED + "build shared library libdwarf[p].so and use it" FALSE) + +# This adds compiler option -Wall (gcc compiler warnings) +option(WALL "Add -Wall" FALSE) +option(LIBDWARF_STATIC "add -DLIBDWARF_STATIC" FALSE) + +# DW_FWALLXX are gnu C++ options. +if (WALL) + set(DW_FWALLXX -Wall -Wextra -Wno-unused-private-field -Wpointer-arith -Wmissing-declarations -Wcomment -Wformat -Wpedantic -Wuninitialized -Wshadow -Wno-long-long -Werror) + set(DW_FWALL ${DW_FWALLXX} -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wdeclaration-after-statement -Wextra -Wcomment -Wformat -Wpedantic -Wuninitialized -Wno-long-long -Wshadow -Werror ) + message(STATUS "Compiler warning options... YES ${DW_FWALL}") +else() + unset(DW_FWALL ) + message(STATUS "Compiler warning options... NO") +endif() +#if (LIBDWARF_STATIC) +# set(DW_LIBDWARF_STATIC -DLIBDWARF_STATIC) +#else() +# unset(DW_LIBDWARF_STATIC) +#endif() + +option(BUILD_DWARFDUMP "Build dwarfdump (default is YES)" FALSE) + +option(BUILD_DWARFGEN "Build dwarfgen (default is NO)" FALSE) +message(STATUS "Building dwarfgen ... ${BUILD_DWARFGEN}") + +option(BUILD_DWARFEXAMPLE "Build dwarfexample (default is NO)" FALSE) +message(STATUS "Building dwarfexample... ${BUILD_DWARFEXAMPLE}") + +option(DO_TESTING "Do certain api tests (default is NO)" FALSE) +message(STATUS "Building api tests ... ${DOTESTS}") +### end what was configure.cmake + +option(PIC_ALWAYS "Build libdwarf with position-independent code for both static and shared (default is NO)" FALSE) + +configure_file(cmake/config.h.cmake config.h) + +if(BUILD_NON_SHARED) + set(DW_LIBDWARF_STATIC -DLIBDWARF_STATIC) + set(BUILD_SHARED_LIBS NO) + set(DWARF_TARGETS dwarf-static) + set(DWARF_TYPES STATIC) + set(dwarf-target dwarf-static) + set(DWARFP_TARGETS dwarfp-static) + set(DWARFP_TYPES STATIC) + set(dwarfp-target dwarfp-static) +else() + unset(DW_LIBDWARF_STATIC) + set(BUILD_SHARED_LIBS YES) + set(DWARF_TARGETS dwarf-shared) + set(DWARF_TYPES SHARED) + set(dwarf-target dwarf-shared) + set(DWARFP_TARGETS dwarfp-shared) + set(DWARFP_TYPES SHARED) + set(dwarfp-target dwarfp-shared) +endif() + +add_subdirectory(src/lib/libdwarf) + +if ( BUILD_DWARFDUMP ) + add_subdirectory(src/bin/dwarfdump) +endif() + +if ( BUILD_DWARFEXAMPLE ) + add_subdirectory(src/bin/dwarfexample) +endif() + +if ( BUILD_DWARFGEN ) + set(LIBDWARF_INCLUDE_DIR ../libdwarf) + add_subdirectory(src/lib/libdwarfp) + add_subdirectory(src/bin/dwarfgen) +endif() + +if (DO_TESTING) +add_subdirectory(test) +endif() + +message(STATUS "Install prefix ... ${CMAKE_INSTALL_PREFIX}" ) +# installation of libdwarf[p] has to be in +# src/lib/libdwarf[p]/CMakeLists.txt +# so that it works properly for cmake before cmake 3.13. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..664ae63 --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ + COPYING + August 6 2023 + +The source code in the libdwarf directory is LGPL version +2.1. See libdwarf/LIBDWARFCOPYRIGHT libdwarf/LGPL.txt A +few of files use the two-clause BSD copyright ("FreeBSD +License"). + +The source code in the dwarfdump directory is +generally GPL version 2. See dwarfdump/COPYING +dwarfdump/DWARFDUMPCOPYRIGHT dwarfdump/GPL.txt a + +A few files in some directories may have the 3-clause +BSD copyright. + +The source code in the dwarfgen directory generally has +the two-clause BSD copyright. See dwarfgen/COPYING + +Various files begin with a copyright and a notice +saying the file is PUBLIC DOMAIN (sometimes spelled +public domain). Such files can be copied, modified, +and used by anyone for any purpose without attribution +or restriction. Example source code is marked as public +domain as we expect many people will use such as a starting +point in their code. diff --git a/README.md b/README.md new file mode 100644 index 0000000..557c3fd --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +This is a minimal mirror of libdwarf from https://github.com/davea42/libdwarf-code. The purpose of this repository is +optimizing clone and configure time. diff --git a/cmake/FindZSTD.cmake b/cmake/FindZSTD.cmake new file mode 100644 index 0000000..8dd53bf --- /dev/null +++ b/cmake/FindZSTD.cmake @@ -0,0 +1,63 @@ +# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. +# All rights reserved. +# +# This is licensed as LGPL 2.1 by the authors. +# For the licensing terms see COPYING and +# libdwarf/LIBDWARFCOPYRIGHT +# or https://github.com/root-project/root/blob/master/LICENSE +# For the list of contributors in the project that +# created this cmake file see +# https://github.com/root-project/root/blob/master/README/CREDITS + +#.rst: +# FindZSTD +# ----------- +# +# Find the ZSTD library header and define variables. +# +# Imported Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines :prop_tgt:`IMPORTED` target ``ZSTD::ZSTD``, +# if ZSTD has been found +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module defines the following variables: +# +# :: +# +# ZSTD_FOUND - True if ZSTD is found. +# ZSTD_INCLUDE_DIRS - Where to find zstd.h +# +# Finds the Zstandard library. This module defines: +# - ZSTD_INCLUDE_DIR, directory containing headers +# - ZSTD_LIBRARIES, the Zstandard library path +# - ZSTD_FOUND, whether Zstandard has been found + +# Find header files +find_path(ZSTD_INCLUDE_DIR zstd.h) + +# Find a ZSTD version +if (ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h") + file(READ "${ZSTD_INCLUDE_DIR}/zstd.h" CONTENT) + string(REGEX MATCH ".*define ZSTD_VERSION_MAJOR *([0-9]+).*define ZSTD_VERSION_MINOR *([0-9]+).*define ZSTD_VERSION_RELEASE *([0-9]+)" VERSION_REGEX "${CONTENT}") + set(ZSTD_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(ZSTD_VERSION_MINOR ${CMAKE_MATCH_2}) + set(ZSTD_VERSION_RELEASE ${CMAKE_MATCH_3}) + set(ZSTD_VERSION "${ZSTD_VERSION_MAJOR}.${ZSTD_VERSION_MINOR}.${ZSTD_VERSION_RELEASE}") +endif () + +# Find library +find_library(ZSTD_LIBRARIES NAMES zstd) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ZSTD REQUIRED_VARS ZSTD_LIBRARIES ZSTD_INCLUDE_DIR ZSTD_VERSION VERSION_VAR ZSTD_VERSION) + +if (ZSTD_FOUND) + if (NOT TARGET ZSTD::ZSTD) + add_library(ZSTD::ZSTD UNKNOWN IMPORTED) + set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION "${ZSTD_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}") + endif () +endif () diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake new file mode 100644 index 0000000..c672c41 --- /dev/null +++ b/cmake/config.h.cmake @@ -0,0 +1,120 @@ + +/* Define if building universal (internal helper macro) */ +#cmakedefine AC_APPLE_UNIVERSAL_BUILD 1 + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#cmakedefine CRAY_STACKSEG_END 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Set to 1 if big endian . */ +#cmakedefine WORDS_BIGENDIAN 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SGIDEFS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to HAVE_UINTPTR_T 1 if the system has the type `uintptr_t'. */ +#cmakedefine HAVE_UINTPTR_T 1 +/* Define to 1 if the system has the type `intptr_t'. */ +#cmakedefine HAVE_INTPTR_T + + +/* Define to the uintptr_t to the type of an unsigned integer + type wide enough to hold a pointer + if the system does not define it. */ +#cmakedefine uintptr_t ${uintptr_t} +#cmakedefine intptr_t ${intptr_t} + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Set to 1 if __attribute__ ((unused)) is available. */ +#cmakedefine HAVE_UNUSED_ATTRIBUTE 1 + +/* Set to 1 if zlib decompression is available. */ +#cmakedefine HAVE_ZLIB 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ZLIB_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#cmakedefine LT_OBJDIR 1 + +/* Name of package */ +#cmakedefine PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME libdwarf + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING "${PACKAGE_NAME} ${VERSION}" + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#cmakedefine PACKAGE_URL "${tarname}" ) + + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#cmakedefine STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS 1 + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION} + +/* Version number of package */ +#cmakedefine VERSION ${VERSION} + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# cmakedefine WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t + diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..5fd5a7b --- /dev/null +++ b/notes.txt @@ -0,0 +1,5 @@ +Making patch: +diff -Naru CMakeLists.txt CMakeListsUpdated.txt > patches/CMakeLists.patch + +Applying: +patch < patches/CMakeLists.patch diff --git a/patches/CMakeLists.patch b/patches/CMakeLists.patch new file mode 100644 index 0000000..4941446 --- /dev/null +++ b/patches/CMakeLists.patch @@ -0,0 +1,239 @@ +--- CMakeLists.txt 2023-11-13 10:57:07.278246800 -0500 ++++ CMakeListsUpdated.txt 2023-11-13 11:11:35.551623300 -0500 +@@ -11,7 +11,7 @@ + macro(msvc_posix target) + if(MSVC AND ("${MSVC_VERSION}" LESS 1900)) + # under VS 2015 +- target_compile_definitions(${target} PUBLIC ++ target_compile_definitions(${target} PUBLIC + snprintf=_snprintf) + endif() + endmacro() +@@ -36,7 +36,7 @@ + if (LIBDWARF_CRT STREQUAL "MT") + message(STATUS "Using MT runtime by compile flag replacement") + # taken from the CMake FAQ +- foreach(flag_v ++ foreach(flag_v + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO +@@ -102,7 +102,7 @@ + include(CheckSymbolExists) + ### Version also appears in configure.ac + set(VERSION 0.9.0) +-set(PACKAGE_VERSION "\"${VERSION}\"") ++set(PACKAGE_VERSION "\"${VERSION}\"") + set(PACKAGE_NAME "libdwarf" ) + set(PACKAGE_STRING "\"${PACKAGE_NAME} ${VERSION}\"") + string(REGEX REPLACE "[\"]" "" tarname1 "${PACKAGE_STRING}" ) +@@ -114,83 +114,87 @@ + set ( WORDS_BIGENDIAN 1 ) + endif() + +-check_include_file( "sys/types.h" HAVE_SYS_TYPES_H) +-check_include_file( "sys/stat.h" HAVE_SYS_STAT_H ) +-check_include_file( "inttypes.h" HAVE_INTTYPES_H ) +-check_include_file( "memory.h" HAVE_MEMORY_H ) +-check_include_file( "strings.h" HAVE_STRINGS_H ) ++# check_include_file( "sys/types.h" HAVE_SYS_TYPES_H) // Only used by dwarfgen ++# check_include_file( "sys/stat.h" HAVE_SYS_STAT_H ) // Only used by dwarfgen ++# check_include_file( "inttypes.h" HAVE_INTTYPES_H ) // Unused ++# check_include_file( "memory.h" HAVE_MEMORY_H ) // Unused ++# check_include_file( "strings.h" HAVE_STRINGS_H ) // Unused + check_include_file( "stdint.h" HAVE_STDINT_H ) + check_include_file( "unistd.h" HAVE_UNISTD_H ) +-check_include_file( "sgidefs.h" HAVE_SGIDEFS_H ) ++# check_include_file( "sgidefs.h" HAVE_SGIDEFS_H ) // Unused + check_include_file( "stdafx.h" HAVE_STDAFX_H ) +-check_include_file( "fcntl.h" HAVE_FCNTL_H ) ++check_include_file( "fcntl.h" HAVE_FCNTL_H ) + + ### cmake provides no way to guarantee uint32_t present. + ### configure does guarantee that. +-if(HAVE_STDINT_H) +- check_c_source_compiles(" +- #include +- int main() +- { +- uintptr_t i; i = 12; +- return (int)i; +- }" HAVE_UINTPTR_T) +- check_c_source_compiles(" +- #include +- int main() +- { +- intptr_t i; i = 12; +- return (int)i; +- }" HAVE_INTPTR_T) +-endif() +-if (HAVE_UINTPTR_T) +- message(STATUS "HAVE_UINTPTR_T 1: uintptr_t defined in stdint.h... YES") +-else() +- message(STATUS "uintptr_t defined in stdint.h... NO") +- set(uintptr_t "unsigned long long int" ) +- message(STATUS "Setting #define uintptr_t " ${uintptr_t}) +-endif() +-if (uintptr_t) +- message(STATUS "uintptr_t value considered YES ") +-else() +- message(STATUS "uintptr_t value considered NO ") +-endif() +-if (HAVE_INTPTR_T) +- message(STATUS "HAVE_INTPTR_T 1: intptr_t defined in stdint.h... YES") +-else() +- message(STATUS "intptr_t defined in stdint.h... NO") +- set(uintptr_t "long long int" ) +- message(STATUS "Setting #define intptr_t " ${intptr_t}) +-endif() +-if (intptr_t) +- message(STATUS "intptr_t value considered YES ") +-else() +- message(STATUS "intptr_t value considered NO ") +-endif() +- +- +-check_c_source_compiles(" +- static unsigned foo( unsigned x, +- __attribute__ ((unused)) int y) +- { +- unsigned x2 = x + 1; +- return x2; +- } +- +- int main(void) { +- unsigned y = 0; +- y = foo(12,y); +- return 0; +- }" HAVE_UNUSED_ATTRIBUTE) +-message(STATUS "Checking compiler supports __attribute__ unused... ${HAVE_UNUSED_ATTRIBUTE}") +- +-check_c_source_compiles([=[ +- #include "stdafx.h" +- int main() +- { +- int p; p = 27; +- return 0; +- }]=] HAVE_STDAFX_H) ++# HAVE_UINTPTR_T: Unused ++# uintptr_t: Unused ++# HAVE_INTPTR_T: Unused ++# if(HAVE_STDINT_H) ++# check_c_source_compiles(" ++# #include ++# int main() ++# { ++# uintptr_t i; i = 12; ++# return (int)i; ++# }" HAVE_UINTPTR_T) ++# check_c_source_compiles(" ++# #include ++# int main() ++# { ++# intptr_t i; i = 12; ++# return (int)i; ++# }" HAVE_INTPTR_T) ++# endif() ++# if (HAVE_UINTPTR_T) ++# message(STATUS "HAVE_UINTPTR_T 1: uintptr_t defined in stdint.h... YES") ++# else() ++# message(STATUS "uintptr_t defined in stdint.h... NO") ++# set(uintptr_t "unsigned long long int" ) ++# message(STATUS "Setting #define uintptr_t " ${uintptr_t}) ++# endif() ++# if (uintptr_t) ++# message(STATUS "uintptr_t value considered YES ") ++# else() ++# message(STATUS "uintptr_t value considered NO ") ++# endif() ++# if (HAVE_INTPTR_T) ++# message(STATUS "HAVE_INTPTR_T 1: intptr_t defined in stdint.h... YES") ++# else() ++# message(STATUS "intptr_t defined in stdint.h... NO") ++# set(uintptr_t "long long int" ) ++# message(STATUS "Setting #define intptr_t " ${intptr_t}) ++# endif() ++# if (intptr_t) ++# message(STATUS "intptr_t value considered YES ") ++# else() ++# message(STATUS "intptr_t value considered NO ") ++# endif() ++ ++# Unused ++# check_c_source_compiles(" ++# static unsigned foo( unsigned x, ++# __attribute__ ((unused)) int y) ++# { ++# unsigned x2 = x + 1; ++# return x2; ++# } ++ ++# int main(void) { ++# unsigned y = 0; ++# y = foo(12,y); ++# return 0; ++# }" HAVE_UNUSED_ATTRIBUTE) ++# message(STATUS "Checking compiler supports __attribute__ unused... ${HAVE_UNUSED_ATTRIBUTE}") ++ ++# Redundant ++# check_c_source_compiles([=[ ++# #include "stdafx.h" ++# int main() ++# { ++# int p; p = 27; ++# return 0; ++# }]=] HAVE_STDAFX_H) + #message(STATUS "Checking have windows stdafx.h... ${HAVE_STDAFX_H}") + + set(CMAKE_REQUIRED_LIBRARIES z) +@@ -223,7 +227,7 @@ + return 0; + } ]=] HAVE_ZLIB_H ) + set(CMAKE_REQUIRED_LIBRARIES) +-if (HAVE_ZLIB) ++if (HAVE_ZLIB) + # For linking in libz + set(DW_FZLIB "z") + endif() +@@ -264,21 +268,21 @@ + endif() + + +- +-check_c_source_compiles([=[ +-#include +-int main() +-{ +- intptr_t p; +- p = 27; +- return 0; +-}]=] HAVE_INTPTR_T) ++# Unused ++# check_c_source_compiles([=[ ++# #include ++# int main() ++# { ++# intptr_t p; ++# p = 27; ++# return 0; ++# }]=] HAVE_INTPTR_T) + + message(STATUS "CMAKE_SIZEOF_VOID_P ... " ${CMAKE_SIZEOF_VOID_P} ) + +-# libdwarf ++# libdwarf + option(BUILD_NON_SHARED "build archive library libdwarf[p].a" TRUE) +-option(BUILD_SHARED ++option(BUILD_SHARED + "build shared library libdwarf[p].so and use it" FALSE) + + # This adds compiler option -Wall (gcc compiler warnings) +@@ -300,7 +304,7 @@ + # unset(DW_LIBDWARF_STATIC) + #endif() + +-option(BUILD_DWARFDUMP "Build dwarfdump (default is YES)" TRUE) ++option(BUILD_DWARFDUMP "Build dwarfdump (default is YES)" FALSE) + + option(BUILD_DWARFGEN "Build dwarfgen (default is NO)" FALSE) + message(STATUS "Building dwarfgen ... ${BUILD_DWARFGEN}") diff --git a/pull.sh b/pull.sh new file mode 100644 index 0000000..52f2f88 --- /dev/null +++ b/pull.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "Removing files" +rm -rfv cmake src CMakeLists.txt COPYING +echo "Fetching" +git clone https://github.com/davea42/libdwarf-code.git +cd libdwarf-code +git checkout "6216e185863f41d6f19ab850caabfff7326020d7" # v0.8.0 +cd .. +echo "Copying files" +mkdir -p src/lib +mv -v libdwarf-code/CMakeLists.txt . +mv -v libdwarf-code/COPYING . +mv -v libdwarf-code/cmake . +mv -v libdwarf-code/src/lib/libdwarf src/lib +echo "Deleting cloned repo" +rm -rf libdwarf-code +echo "Cleaning up src/lib/libdwarf" +cd src/lib/libdwarf +rm -rfv ChangeLog* CHANGES CODINGSTYLE NEWS +cd ../../.. +echo "Patching" +patch < patches/CMakeLists.patch +echo "Done" diff --git a/src/lib/libdwarf/CMakeLists.txt b/src/lib/libdwarf/CMakeLists.txt new file mode 100644 index 0000000..9d3eab0 --- /dev/null +++ b/src/lib/libdwarf/CMakeLists.txt @@ -0,0 +1,167 @@ +set_source_group(SOURCES "Source Files" dwarf_abbrev.c +dwarf_alloc.c dwarf_crc.c dwarf_crc32.c dwarf_arange.c +dwarf_debug_sup.c +dwarf_debugaddr.c +dwarf_debuglink.c dwarf_die_deliv.c +dwarf_debugnames.c dwarf_dsc.c +dwarf_elf_load_headers.c +dwarf_elfread.c +dwarf_elf_rel_detector.c +dwarf_error.c +dwarf_fill_in_attr_form.c +dwarf_find_sigref.c dwarf_fission_to_cu.c +dwarf_form.c dwarf_form_class_names.c +dwarf_frame.c dwarf_frame2.c +dwarf_gdbindex.c dwarf_global.c +dwarf_gnu_index.c dwarf_groups.c +dwarf_harmless.c dwarf_generic_init.c dwarf_init_finish.c +dwarf_leb.c +dwarf_line.c dwarf_loc.c +dwarf_loclists.c +dwarf_locationop_read.c +dwarf_machoread.c dwarf_macro.c dwarf_macro5.c +dwarf_memcpy_swap.c +dwarf_names.c +dwarf_object_read_common.c dwarf_object_detector.c +dwarf_peread.c +dwarf_query.c dwarf_ranges.c +dwarf_rnglists.c +dwarf_safe_arithmetic.c +dwarf_safe_strcpy.c +dwarf_secname_ck.c +dwarf_setup_sections.c +dwarf_string.h dwarf_string.c +dwarf_stringsection.c +dwarf_tied.c +dwarf_str_offsets.c +dwarf_tsearchhash.c dwarf_util.c +dwarf_xu_index.c +dwarf_print_lines.c ) + +set_source_group(HEADERS "Header Files" dwarf.h dwarf_abbrev.h +dwarf_alloc.h dwarf_arange.h dwarf_base_types.h +dwarf_debugaddr.h +dwarf_debuglink.h dwarf_die_deliv.h +dwarf_debugnames.h dwarf_dsc.h +dwarf_elf_access.h dwarf_elf_defines.h dwarf_elfread.h +dwarf_elf_rel_detector.h +dwarf_elfstructs.h +dwarf_error.h dwarf_frame.h +dwarf_gdbindex.h dwarf_global.h dwarf_harmless.h +dwarf_gnu_index.h +dwarf_line.h dwarf_loc.h +dwarf_machoread.h dwarf_macro.h dwarf_macro5.h +dwarf_object_detector.h dwarf_opaque.h +dwarf_pe_descr.h dwarf_peread.h +dwarf_reading.h +dwarf_rnglists.h +dwarf_safe_arithmetic.h +dwarf_safe_strcpy.h +dwarf_tied_decls.h +dwarf_tsearch.h +dwarf_setup_sections.h +dwarf_str_offsets.h +dwarf_universal.h +dwarf_util.h +dwarf_xu_index.h libdwarf_private.h +dwarf_macho_loader.h +dwarf_memcpy_swap.h) + +set_source_group(CONFIGURATION_FILES "Configuration Files" + ${PROJECT_SOURCE_DIR}/cmake/config.h.cmake + ${PROJECT_BINARY_DIR}/config.h) + +# The -DPIC is so we find the right DW_API value in libdwarf.h +# with cmake with Linux. +# Dwarfgen requires all symbols in .so to be visible, so +# do not say hidden on libdwarf in that case. +if (BUILD_SHARED) + if(NOT BUILD_DWARFGEN) + set(CMAKE_C_VISIBILITY_PRESET hidden) + endif() + set(DEFS LIBDWARF_BUILD PIC) +else() + set(DEFS LIBDWARF_STATIC) +endif() + +if (PIC_ALWAYS) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) + list(APPEND DEFS PIC) +endif() + +include(GNUInstallDirs) + +list(LENGTH DWARF_TARGETS targetCount) +math(EXPR targetCount "${targetCount} - 1") +list(APPEND DWARF_LIBS ${LIBELF_LIBRARIES}) +if (DW_FZLIB) + list(APPEND DWARF_LIBS z) +endif() +if (DW_FZSTD) + list(APPEND DWARF_LIBS zstd) +endif() +foreach(i RANGE ${targetCount}) + list(GET DWARF_TARGETS ${i} target) + list(GET DWARF_TYPES ${i} type) + add_library(${target} ${type} ${SOURCES} ${HEADERS} + ${GENNAMES_OUTPUT} ${CONFIGURATION_FILES}) + + add_library(libdwarf::${target} ALIAS ${target}) + + set_folder(${target} src/lib/libdwarf) + target_compile_options(${target} PRIVATE ${COMPILER_FLAGS} + ${DW_FWALL}) + msvc_posix(${target}) + + target_compile_definitions(${target} PUBLIC ${DEFS}) + + target_include_directories( + ${target} + PUBLIC + $ + $ + ) + + target_link_libraries(${target} PUBLIC ${DW_FZLIB} ${DW_FZSTD} ) + + set_target_properties(${target} PROPERTIES OUTPUT_NAME dwarf) + + set(SUFFIX $<$:64>) + set(LIBDIR lib${SUFFIX}) + set(BINDIR bin${SUFFIX}) + + install(TARGETS ${target} + RUNTIME DESTINATION ${BINDIR} + LIBRARY DESTINATION ${LIBDIR} + ARCHIVE DESTINATION ${LIBDIR}) +endforeach() + +configure_file(libdwarf.pc.cmake libdwarf.pc @ONLY ) + +# The install has to be here, not in +# another CMakeLists.txt to make install work properly +# for cmake before cmake 3.13. This also works +# for newer cmake. +add_custom_target(dd DEPENDS ${DWARF_TARGETS} dwarfdump) +install(TARGETS ${DWARF_TARGETS} EXPORT libdwarfTargets + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +install(EXPORT libdwarfTargets + FILE libdwarf-targets.cmake + NAMESPACE libdwarf:: + DESTINATION lib/cmake/libdwarf +) +install( + FILES cmake/libdwarf-config.cmake + DESTINATION lib/cmake/libdwarf +) +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/libdwarf.h + DESTINATION include/libdwarf) +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/dwarf.h + DESTINATION include/libdwarf) +install( FILES ${PROJECT_BINARY_DIR}/src/lib/libdwarf/libdwarf.pc + DESTINATION lib/pkgconfig +) diff --git a/src/lib/libdwarf/COPYING b/src/lib/libdwarf/COPYING new file mode 100644 index 0000000..144137b --- /dev/null +++ b/src/lib/libdwarf/COPYING @@ -0,0 +1,32 @@ +The files: + libdwarf.h + libdwarfp.h + dwarf.h + and most of the .h and .c files in this implementation of + libdwarf and libdwarfp are copyrighted according to the file + LIBDWARFCOPYRIGHT (which mentions the LGPL version 2.1). + Each file mentions the LGPL. + The full text of the LGPL 2.1 is provided in LGPL.txt + Another copyright used here in some files is the + two-clause BSD license, (FreeBSD license). + + +The libdwarf documentation: + libdwarf.mm + is based on material submitted to the UI PLSIG as proposed + interfaces for dwarf, but completely rewritten. + Copyright ownership is therefore SGI (but see the + document for details) and it seems clear that the + intent was there was to be free + copying with no fees. + + libdwarfp.mm + is documentation of a set of interfaces + (not part of the UI PLSIG proposals) + and the document was written from scratch at SGI. + Copyright ownership is therefore SGI (but see the + document for details) and it seems clear that + the intent was there was to be free + copying with no fees. + +13 June 2021 updated to match the new file structure. diff --git a/src/lib/libdwarf/LGPL.txt b/src/lib/libdwarf/LGPL.txt new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/src/lib/libdwarf/LGPL.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/lib/libdwarf/LIBDWARFCOPYRIGHT b/src/lib/libdwarf/LIBDWARFCOPYRIGHT new file mode 100644 index 0000000..842cafb --- /dev/null +++ b/src/lib/libdwarf/LIBDWARFCOPYRIGHT @@ -0,0 +1,42 @@ + +====== +Update January 31, 2015: +The SGI postal address and oss.sgi.com address +in the original copyright are no longer correct. +So the final 8 lines of the original copyright +have been deleted from the current copyright. + +====== original copyright example. + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + + Contact information: Silicon Graphics, Inc., 1500 Crittenden + Lane, Mountain View, CA 94043, or: + + http://www.sgi.com + + For further information regarding this notice, see: + + http://oss.sgi.com/projects/GenInfo/NoticeExplan diff --git a/src/lib/libdwarf/Makefile.am b/src/lib/libdwarf/Makefile.am new file mode 100644 index 0000000..ddc0684 --- /dev/null +++ b/src/lib/libdwarf/Makefile.am @@ -0,0 +1,162 @@ +###Copyright (C) 2018 Vincent Torri de_callback_func_c’ +discards ‘const’ qualifier from pointer target type +[enabled by default]" at compile time are to be expected in +some pro*.c source files. Fixing the public prototype could +cause some producer-library user's code to fail to compile +so we live with the warnings. + +When cross-compiling, gennames has to be built by the +native compiler. So try + make HOSTCC=cc gennames +as a first step before the normal make. + + +If your headers are not in the expected places, +use the make command line to add flags and include directories. +For example + ./configure + PREINCS="-I /usr/local/share/include" POSTINCS="-I /home/x/include" make +PREINCS content is inserted before CFLAGS as make(1) is running. +POSTINCS content is added after the CFLAGS value. + +To set LDFLAGS (which is used when building a .so and +in building gennames to create some source here), +do so at configure time, for example: + ./configure LDFLAGS="-L /var/tmp" +Or use PRELIBS and/or POSTLIBS at 'make' time similar to the use +of PREINCS and POSTINCS. + +Windows (February 2016): Those wishing to read DWARF2 or +later from Windows PE files (using Mingw) should take a look at + https://github.com/jrfonseca/drmingw/tree/master/src/mgwhelp +which shows simple LGPL code that implements the necessary object +reading interfaces for PE objects. dwarf_pe.cpp +fills out the Dwarf_Obj_Access_Methods +object interface and opens an object +(see dwarf_object_init()) +using the PE object access making the full libdwarf API +available. +To enable dection of Windows pathnames as full paths +add --enable-windowspath. Doing this does mean things like +A:foo and \anything are treated as full paths (these are +unlikely path names on a POSIX system but are legal +POSIX partial paths). + +Back to Linux/Unix: +It is possible to request a shared library (libdwarf.so) build with + --enable-shared +To turn off the build of the archive library (libdwarf.a) specify + --disable-nonshared +but in this case you must specify --enable-shared or nothing will +build! + +TARGET DEPENDENCIES of .debug_frame: +dwarf.h + These should be revised if you have more than the defined + 63 'normal' registers. It's not harmful to have these too large! + Too small will lead to errors reading .debug_frame and .eh_frame. + DW_FRAME_HIGHEST_NORMAL_REGISTER + DW_FRAME_LAST_REG_NUM + + These you might revise, but can safely ignore if simply + using dwarfdump. If using the producer code you will want + to get these exactly right for your architecture. + DW_FRAME_RA_COL + DW_FRAME_STATIC_LINK + DW_FRAME_CFA_COL + +libdwarf.h + The DW_FRAME_REG_INITIAL_VALUE #define should be set to + the value appropriate to your architecture. See libdwarf.h + for details. + + If DW_REG_TABLE_SIZE is not set large enough attempts to + fill in the .debug_frame tables will get an error. + Should be at least as large as DW_FRAME_LAST_REG_NUM. + If it's too large nothing is harmed (but some extra space taken + at run time). + +If your printf does not support C standard %llx etc, +(such as MSWindows with long long), configure +option --enable-nonstandardprintf +and defines like DW_PR_DUx etc in libdwarf.h +provide a way to configure for that relatively easily. + + +The .debug_frame is so very architecture dependent +and because the host (where libdwarf/dwarfdump are executed) +and target (the objects read) could be different. +It's currently not supported to have dwarfdump/libdwarf determine +the architecture on-the-fly and do-the-right-thing. +Just setting DW_FRAME_LAST_REG_NUM and DW_FRAME_HIGHEST_NORMAL_REGISTER +and DW_REG_TABLE_SIZE high enough will likely suffice for most +purposes and most compilers/architectures.. +See comments in dwarf.h/libdwarf.h. + +It's perfectly safe to ignore the above suggestions as long +as libdwarf does not get a DW_DLE_DF_REG_NUM_TOO_HIGH error. +(which would only happen on reading .debug_frame or .eh_frame data). + +If you intend to use the libdwarf dwarf-producer code +for .debug_frame information +you must do a thorough analysys and revise dwarf.h +substantially to match the output target architecture. + +In general, in the producer code, numbers are copied from and +to integers with memcpy(). In case of endianness problems, +constants set in dwarf_producer_init() can fix the problems. +If one wants to produce a *different-endian* output the best +solution is to change the integer memcpy calls to call thru a +new dbg-based function pointer and have it 'do the right thing' +to adjust endianness. Set the function pointer correctly in +dwarf_producer_init() and the rest of the code will just call +thru the function pointer. Tedious work to find and change the +memcpy calls to be dbg->de_memcpy(), but once done the code is +no longer endian dependent (right now there is no way to ask +for cross-endian: a new flag needed or ?). + +leb128 numbers are endian-independent, so nothing need be +done with those for cross-endian support (the storage +of leb128 on disk is always little-endian). + +The .ps files are postscript. So those who cannot deal with mm +format files but do have a postscript printer (or have +ghostscript) can print the documents. +This form was chosen before pdf format existed... + +libdwarf2.1.pdf documents a way for a debugger to read dwarf information. +libdwarf2p.1.pdf documents a way for a compiler to generate dwarf information. +mips_extensions.ps documents the mips/sgi extensions to dwarf. + +See the Makefile for the commands used to build pdf files +libdwarf.2.1.pdf and libdwarf1p.1.pdf. + +pic is a picture processing tool (ATT command). +tbl is a table-processing tool. +(part of Documentor's Work Bench on ATT-like systems). +tbl and pic are available on linux. + +psroff is a name for a troff-like processor, part of +Documentor's Work Bench on IRIX. Substitute a +troff-like or nroff-like processor (GNU groff works fine). + +To use dwarf or libdwarf, you may want to install dwarf.h and +libdwarf.h somewhere convenient. + +You will also need libelf (libelf.a and/or libelf.so) and +libelf.h installed. These are available from GNU repositories +and from the normal Linux repositories for Linux releases. +On Ubuntu Linux for example: + sudo apt-get install libelf-dev libelf1 + +Compiler warnings: +A few Warnings like: +dwarf_frame.c:715:29: warning: cast from pointer to integer of different size [- +Wpointer-to-int-cast] +dwarf_arange.c:113:13: warning: variable ‘local_extension_size’ set but not used + [-Wunused-but-set-variable] +are considered normal. + + +As of January 2013 the code compiles with gcc without +problems with -Wall and -Wsign-compare +aside from the warnings hinted at above. + +The following gcc/clang options +have not all been tried as of January 2013, +but will be as time permits. +-Wsystem-headers +-Wall -Wsign-compare +-Wno-format-y2k -W +-Wno-unused-parameter -Wstrict-prototypes +-Wmissing-prototypes -Wpointer-arith +-Wreturn-type -Wcast-qual -Wwrite-strings +-Wswitch -Wshadow -Wunused-parameter +-Wcast-align -Wchar-subscripts -Winline +-Wnested-externs -Wredundant-decls +-Wold-style-definition -Wno-pointer-sign diff --git a/src/lib/libdwarf/cmake/libdwarf-config.cmake b/src/lib/libdwarf/cmake/libdwarf-config.cmake new file mode 100644 index 0000000..604c563 --- /dev/null +++ b/src/lib/libdwarf/cmake/libdwarf-config.cmake @@ -0,0 +1,3 @@ +if (NOT TARGET libdwarf::libdwarf) + include(${CMAKE_CURRENT_LIST_DIR}/libdwarf-targets.cmake) +endif() diff --git a/src/lib/libdwarf/dw-linetableheader.txt b/src/lib/libdwarf/dw-linetableheader.txt new file mode 100644 index 0000000..76f2b57 --- /dev/null +++ b/src/lib/libdwarf/dw-linetableheader.txt @@ -0,0 +1,44 @@ +Copyright (C) 2021. David Anderson. +This simple file is hereby placed in the Public Domain. + +This file documents the arrangement of line table headers +across all Standard versions of DWARF and some special +experimental line tables. + +Line Table Header variations. +The experimental version has a distinct version +number of 0xf006 so cannot be confused with DWARF4 or 5. + +DWversion +2,3,4,5 meaning the DWARF standards +x meaning gcc's experimental two level line table. + +2345x 1. unit_length (4 or 12 bytes) +2345x 2. version (2 bytes, for x is 0xF006) +5 2.1 address_size +5 2.2 segment_selector_size +2345x 3. header_length (4 or 8 bytes) +2345x 4. minimum_instruction_length (1 byte) +45 x 5. maximum_operations_per_instruction (1 byte) +2345x 6. default_is_stmt (1 byte) +2345x 7. line_base (1 byte) +2345x 8. line_range (1 byte) +2345x 9. opcode_base (1 byte) +2345x 10. standard_opcode_lengths (array of length opcode_base - 1) +234 x 11. include directories (for x just one NUL byte(empty list)) +234 x 12. file_names (for x just one NUL byte(empty list)) +x 13. fake_extended_op (5 bytes: 00 FF FF 7F 7F) +x 14. logicals_table_offset (4 or 8 bytes) +x 15. actuals_table_offset (4 or 8 bytes) +x5 16. directory_entry_format_count (1 byte) +x5 17. directory_entry_format (sequence of unsigned LEB128 pairs) +x5 18. directories_count (unsigned LEB128) +x5 19. directories (sequence of directory entries) +x5 20. file_name_entry_format_count (1 byte) +x5 21. file_name_entry_format (sequence of unsigned LEB128 pairs) +x5 22. file_names_count (unsigned LEB128) +x5 23. file_names (sequence of directory entries) +x 24. subprogram_entry_format_count (1 byte) +x 25. subprogram_entry_format (sequence of unsigned LEB128 pairs) +x 26. subprograms_count (unsigned LEB128) +x 27. subprograms (sequence of directory entries) diff --git a/src/lib/libdwarf/dwarf.h b/src/lib/libdwarf/dwarf.h new file mode 100644 index 0000000..85a61c9 --- /dev/null +++ b/src/lib/libdwarf/dwarf.h @@ -0,0 +1,1584 @@ +/* +Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved. +Portions Copyright 2007-2023 David Anderson. All rights reserved. + +This program is free software; you can redistribute it +and/or modify it under the terms of version 2.1 of the +GNU Lesser General Public License as published by the Free +Software Foundation. + +This program is distributed in the hope that it would be +useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. + +Further, this software is distributed without any warranty +that it is free of the rightful claim of any third person +regarding infringement or the like. Any license provided +herein, whether implied or otherwise, applies only to this +software file. Patent licenses, if any, provided herein +do not apply to combinations of this program with other +software, or any other product whatsoever. + +You should have received a copy of the GNU Lesser General +Public License along with this program; if not, write the +Free Software Foundation, Inc., 51 Franklin Street - Fifth +Floor, Boston MA 02110-1301, USA. +*/ + +/*! @file */ +/*! @page dwarf.h + dwarf.h contains all the identifiers + such as DW_TAG_compile_unit etc from the + various versions of the DWARF Standard + beginning with DWARF2 and containing + all later Dwarf Standard identifiers. + + In addition, it contains all user-defined + identifiers that we have been able to find. + + All identifiers here are C defines with the prefix "DW_" . +*/ + +#ifndef __DWARF_H +#define __DWARF_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + dwarf.h DWARF debugging information values + $Revision: 1.41 $ $Date: 2006/04/17 00:09:56 $ + + The comment "DWARF3" appears where there are + new entries from DWARF3 as of 2004, "DWARF3f" + where there are new entries as of the November 2005 + public review document and other comments apply + where extension entries appear. + + Extensions part of DWARF4 are marked DWARF4. + + A few extension names have omitted the 'vendor id' + (See chapter 7, "Vendor Extensibility"). Please + always use a 'vendor id' string in extension names. + + Vendors should use a vendor string in names and + wherever possible avoid duplicating values used by + other vendor extensions + + The DWARF1 comments indicate values unused in + DWARF2 and later but used or reserved in DWARF1. +*/ + +#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 +/* TAG_global_subroutine 0x06 DWARF1 only */ +/* TAG_global_variable 0x07 DWARF1 only */ +#define DW_TAG_imported_declaration 0x08 +/* reserved by DWARF1 0x09 DWARF1 only */ +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +/* TAG_local_variable 0x0c DWARF1 only. */ +#define DW_TAG_member 0x0d +/* reserved by DWARF1 0x0e DWARF1 only */ +#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 +/* TAG_subroutine 0x14 DWARF1 only */ +#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_file_type 0x29 +#define DW_TAG_friend 0x2a +#define DW_TAG_namelist 0x2b + /* Early releases of this header had the following + misspelled with a trailing 's' */ +#define DW_TAG_namelist_item 0x2c /* DWARF2 spelling*/ +#define DW_TAG_namelist_items 0x2c /* SGI misspelling/typo*/ +#define DW_TAG_packed_type 0x2d +#define DW_TAG_subprogram 0x2e + /* The DWARF2 document had two spellings of the following + two TAGs, DWARF3 specifies the longer spelling. */ +#define DW_TAG_template_type_parameter 0x2f /* DWARF3-5 spelling*/ +#define DW_TAG_template_type_param 0x2f /* DWARF2 inconsistent*/ +#define DW_TAG_template_value_parameter 0x30 /* DWARF all versions*/ +#define DW_TAG_template_value_param 0x30 /* SGI misspelling/typo*/ +#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 /* DWARF3 */ +#define DW_TAG_restrict_type 0x37 /* DWARF3 */ +#define DW_TAG_interface_type 0x38 /* DWARF3 */ +#define DW_TAG_namespace 0x39 /* DWARF3 */ +#define DW_TAG_imported_module 0x3a /* DWARF3 */ +#define DW_TAG_unspecified_type 0x3b /* DWARF3 */ +#define DW_TAG_partial_unit 0x3c /* DWARF3 */ +#define DW_TAG_imported_unit 0x3d /* DWARF3 */ + /* Do not use DW_TAG_mutable_type */ +#define DW_TAG_mutable_type 0x3e /*Withdrawn from DWARF3 by DWARF3f*/ +#define DW_TAG_condition 0x3f /* DWARF3f */ +#define DW_TAG_shared_type 0x40 /* DWARF3f */ +#define DW_TAG_type_unit 0x41 /* DWARF4 */ +#define DW_TAG_rvalue_reference_type 0x42 /* DWARF4 */ +#define DW_TAG_template_alias 0x43 /* DWARF4 */ +#define DW_TAG_coarray_type 0x44 /* DWARF5 */ +#define DW_TAG_generic_subrange 0x45 /* DWARF5 */ +#define DW_TAG_dynamic_type 0x46 /* DWARF5 */ +#define DW_TAG_atomic_type 0x47 /* DWARF5 */ +#define DW_TAG_call_site 0x48 /* DWARF5 */ +#define DW_TAG_call_site_parameter 0x49 /* DWARF5 */ +#define DW_TAG_skeleton_unit 0x4a /* DWARF5 */ +#define DW_TAG_immutable_type 0x4b /* DWARF5 */ +#define DW_TAG_lo_user 0x4080 + +#define DW_TAG_MIPS_loop 0x4081 + +/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/\ + WDB/wdb-4.0.tar.gz */ +#define DW_TAG_HP_array_descriptor 0x4090 /* HP */ + +/* GNU extensions. The first 3 missing the GNU_. */ +#define DW_TAG_format_label 0x4101 /* GNU. Fortran. */ +#define DW_TAG_function_template 0x4102 /* GNU. For C++ */ +#define DW_TAG_class_template 0x4103 /* GNU. For C++ */ +#define DW_TAG_GNU_BINCL 0x4104 /* GNU */ +#define DW_TAG_GNU_EINCL 0x4105 /* GNU */ + +/* GNU extension. http://gcc.gnu.org/wiki/TemplateParmsDwarf */ +#define DW_TAG_GNU_template_template_parameter 0x4106 /* GNU */ +#define DW_TAG_GNU_template_template_param 0x4106 /* GNU */ +#define DW_TAG_GNU_template_parameter_pack 0x4107 /* GNU */ +#define DW_TAG_GNU_formal_parameter_pack 0x4108 /* GNU */ + +#define DW_TAG_GNU_call_site 0x4109 /* GNU */ +#define DW_TAG_GNU_call_site_parameter 0x410a /* GNU */ + +/* The following are SUN extensions */ +#define DW_TAG_SUN_function_template 0x4201 /* SUN */ +#define DW_TAG_SUN_class_template 0x4202 /* SUN */ +#define DW_TAG_SUN_struct_template 0x4203 /* SUN */ +#define DW_TAG_SUN_union_template 0x4204 /* SUN */ +#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */ +#define DW_TAG_SUN_codeflags 0x4206 /* SUN */ +#define DW_TAG_SUN_memop_info 0x4207 /* SUN */ +#define DW_TAG_SUN_omp_child_func 0x4208 /* SUN */ +#define DW_TAG_SUN_rtti_descriptor 0x4209 /* SUN */ +#define DW_TAG_SUN_dtor_info 0x420a /* SUN */ +#define DW_TAG_SUN_dtor 0x420b /* SUN */ +#define DW_TAG_SUN_f90_interface 0x420c /* SUN */ +#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */ +#define DW_TAG_SUN_hi 0x42ff /* SUN */ + +/* ALTIUM extensions */ + /* DSP-C/Starcore __circ qualifier */ +#define DW_TAG_ALTIUM_circ_type 0x5101 /* ALTIUM */ + /* Starcore __mwa_circ qualifier */ +#define DW_TAG_ALTIUM_mwa_circ_type 0x5102 /* ALTIUM */ + /* Starcore __rev_carry qualifier */ +#define DW_TAG_ALTIUM_rev_carry_type 0x5103 /* ALTIUM */ + /* M16 __rom qualifier */ +#define DW_TAG_ALTIUM_rom 0x5111 /* ALTIUM */ + +#define DW_TAG_LLVM_annotation 0x6000 /* September 2021*/ + +/* GHS C */ +#define DW_TAG_ghs_namespace 0x8004 +#define DW_TAG_ghs_using_namespace 0x8005 +#define DW_TAG_ghs_using_declaration 0x8006 +#define DW_TAG_ghs_template_templ_param 0x8007 + +/* The following 3 are extensions to support UPC */ +#define DW_TAG_upc_shared_type 0x8765 /* UPC */ +#define DW_TAG_upc_strict_type 0x8766 /* UPC */ +#define DW_TAG_upc_relaxed_type 0x8767 /* UPC */ + +/* PGI (STMicroelectronics) extensions. */ +#define DW_TAG_PGI_kanji_type 0xa000 /* PGI */ +#define DW_TAG_PGI_interface_block 0xa020 /* PGI */ + +#define DW_TAG_BORLAND_property 0xb000 +#define DW_TAG_BORLAND_Delphi_string 0xb001 +#define DW_TAG_BORLAND_Delphi_dynamic_array 0xb002 +#define DW_TAG_BORLAND_Delphi_set 0xb003 +#define DW_TAG_BORLAND_Delphi_variant 0xb004 + +#define DW_TAG_hi_user 0xffff + +/* The following two are non-standard. Use DW_CHILDREN_yes + and DW_CHILDREN_no instead. These could + probably be deleted, but someone might be using them, + so they remain. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +#define DW_FORM_addr 0x01 +/* FORM_REF 0x02 DWARF1 only */ +#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_FORM_sec_offset 0x17 /* DWARF4 */ +#define DW_FORM_exprloc 0x18 /* DWARF4 */ +#define DW_FORM_flag_present 0x19 /* DWARF4 */ +#define DW_FORM_strx 0x1a /* DWARF5 */ +#define DW_FORM_addrx 0x1b /* DWARF5 */ +#define DW_FORM_ref_sup4 0x1c /* DWARF5 */ +#define DW_FORM_strp_sup 0x1d /* DWARF5 */ +#define DW_FORM_data16 0x1e /* DWARF5 */ +#define DW_FORM_line_strp 0x1f /* DWARF5 */ +#define DW_FORM_ref_sig8 0x20 /* DWARF4 */ +#define DW_FORM_implicit_const 0x21 /* DWARF5 */ +#define DW_FORM_loclistx 0x22 /* DWARF5 */ +#define DW_FORM_rnglistx 0x23 /* DWARF5 */ +#define DW_FORM_ref_sup8 0x24 /* DWARF5 */ +#define DW_FORM_strx1 0x25 /* DWARF5 */ +#define DW_FORM_strx2 0x26 /* DWARF5 */ +#define DW_FORM_strx3 0x27 /* DWARF5 */ +#define DW_FORM_strx4 0x28 /* DWARF5 */ +#define DW_FORM_addrx1 0x29 /* DWARF5 */ +#define DW_FORM_addrx2 0x2a /* DWARF5 */ +#define DW_FORM_addrx3 0x2b /* DWARF5 */ +#define DW_FORM_addrx4 0x2c /* DWARF5 */ + +/* Extensions http://gcc.gnu.org/wiki/DebugFission. */ +#define DW_FORM_GNU_addr_index 0x1f01 /* GNU, debug_info.dwo.*/ + +/* GNU, somewhat like DW_FORM_strp */ +#define DW_FORM_GNU_str_index 0x1f02 + +#define DW_FORM_GNU_ref_alt 0x1f20 /* GNU, Offset in .debug_info. */ + +/* GNU extension. Offset in .debug_str of another object file. */ +#define DW_FORM_GNU_strp_alt 0x1f21 + +#define DW_FORM_LLVM_addrx_offset 0x2001 + +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +/* reserved DWARF1 0x04, DWARF1 only */ +/* AT_fund_type 0x05, DWARF1 only */ +/* AT_mod_fund_type 0x06, DWARF1 only */ +/* AT_user_def_type 0x07, DWARF1 only */ +/* AT_mod_u_d_type 0x08, DWARF1 only */ +#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 +/* reserved DWARF1 0x0d, DWARF1 only */ +#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 +/* reserved 0x1f */ +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +/* reserved 0x23 */ +/* reserved 0x24 */ +#define DW_AT_producer 0x25 +/* reserved 0x26 */ +#define DW_AT_prototyped 0x27 +/* reserved 0x28 */ +/* reserved 0x29 */ +#define DW_AT_return_addr 0x2a +/* reserved 0x2b */ +#define DW_AT_start_scope 0x2c +/* reserved 0x2d */ +#define DW_AT_bit_stride 0x2e /* DWARF3 name */ +#define DW_AT_stride_size 0x2e /* DWARF2 name */ +#define DW_AT_upper_bound 0x2f +/* AT_virtual 0x30, DWARF1 only */ +#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 /* DWARF2 */ +#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 /* DWARF{234} not DWARF5 */ +#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_allocated 0x4e /* DWARF3 */ +#define DW_AT_associated 0x4f /* DWARF3 */ +#define DW_AT_data_location 0x50 /* DWARF3 */ +#define DW_AT_byte_stride 0x51 /* DWARF3f */ +#define DW_AT_stride 0x51 /* DWARF3 (do not use) */ +#define DW_AT_entry_pc 0x52 /* DWARF3 */ +#define DW_AT_use_UTF8 0x53 /* DWARF3 */ +#define DW_AT_extension 0x54 /* DWARF3 */ +#define DW_AT_ranges 0x55 /* DWARF3 */ +#define DW_AT_trampoline 0x56 /* DWARF3 */ +#define DW_AT_call_column 0x57 /* DWARF3 */ +#define DW_AT_call_file 0x58 /* DWARF3 */ +#define DW_AT_call_line 0x59 /* DWARF3 */ +#define DW_AT_description 0x5a /* DWARF3 */ +#define DW_AT_binary_scale 0x5b /* DWARF3f */ +#define DW_AT_decimal_scale 0x5c /* DWARF3f */ +#define DW_AT_small 0x5d /* DWARF3f */ +#define DW_AT_decimal_sign 0x5e /* DWARF3f */ +#define DW_AT_digit_count 0x5f /* DWARF3f */ +#define DW_AT_picture_string 0x60 /* DWARF3f */ +#define DW_AT_mutable 0x61 /* DWARF3f */ +#define DW_AT_threads_scaled 0x62 /* DWARF3f */ +#define DW_AT_explicit 0x63 /* DWARF3f */ +#define DW_AT_object_pointer 0x64 /* DWARF3f */ +#define DW_AT_endianity 0x65 /* DWARF3f */ +#define DW_AT_elemental 0x66 /* DWARF3f */ +#define DW_AT_pure 0x67 /* DWARF3f */ +#define DW_AT_recursive 0x68 /* DWARF3f */ +#define DW_AT_signature 0x69 /* DWARF4 */ +#define DW_AT_main_subprogram 0x6a /* DWARF4 */ +#define DW_AT_data_bit_offset 0x6b /* DWARF4 */ +#define DW_AT_const_expr 0x6c /* DWARF4 */ +#define DW_AT_enum_class 0x6d /* DWARF4 */ +#define DW_AT_linkage_name 0x6e /* DWARF4 */ +#define DW_AT_string_length_bit_size 0x6f /* DWARF5 */ +#define DW_AT_string_length_byte_size 0x70 /* DWARF5 */ +#define DW_AT_rank 0x71 /* DWARF5 */ +#define DW_AT_str_offsets_base 0x72 /* DWARF5 */ +#define DW_AT_addr_base 0x73 /* DWARF5 */ +/* Use DW_AT_rnglists_base, DW_AT_ranges_base is obsolete as */ +/* it was only used in some DWARF5 drafts, not the final DWARF5. */ +#define DW_AT_rnglists_base 0x74 /* DWARF5 */ +/* DW_AT_dwo_id, an experiment in some DWARF4+. Not DWARF5! */ +#define DW_AT_dwo_id 0x75 /* DWARF4!*/ +#define DW_AT_dwo_name 0x76 /* DWARF5 */ +#define DW_AT_reference 0x77 /* DWARF5 */ +#define DW_AT_rvalue_reference 0x78 /* DWARF5 */ +#define DW_AT_macros 0x79 /* DWARF5 */ +#define DW_AT_call_all_calls 0x7a /* DWARF5 */ +#define DW_AT_call_all_source_calls 0x7b /* DWARF5 */ +#define DW_AT_call_all_tail_calls 0x7c /* DWARF5 */ +#define DW_AT_call_return_pc 0x7d /* DWARF5 */ +#define DW_AT_call_value 0x7e /* DWARF5 */ +#define DW_AT_call_origin 0x7f /* DWARF5 */ +#define DW_AT_call_parameter 0x80 /* DWARF5 */ +#define DW_AT_call_pc 0x81 /* DWARF5 */ +#define DW_AT_call_tail_call 0x82 /* DWARF5 */ +#define DW_AT_call_target 0x83 /* DWARF5 */ +#define DW_AT_call_target_clobbered 0x84 /* DWARF5 */ +#define DW_AT_call_data_location 0x85 /* DWARF5 */ +#define DW_AT_call_data_value 0x86 /* DWARF5 */ +#define DW_AT_noreturn 0x87 /* DWARF5 */ +#define DW_AT_alignment 0x88 /* DWARF5 */ +#define DW_AT_export_symbols 0x89 /* DWARF5 */ +#define DW_AT_deleted 0x8a /* DWARF5 */ +#define DW_AT_defaulted 0x8b /* DWARF5 */ +#define DW_AT_loclists_base 0x8c /* DWARF5 */ + +/* GreenHills, ghs.com GHS C */ +#define DW_AT_ghs_namespace_alias 0x806 +#define DW_AT_ghs_using_namespace 0x807 +#define DW_AT_ghs_using_declaration 0x808 + +/* In extensions, we attempt to include the vendor extension + in the name even when the vendor leaves it out. */ + +/* HP extensions. */ +#define DW_AT_HP_block_index 0x2000 /* HP */ + +/* 0x2000 Follows extension so dwarfdump prints the + most-likely-useful name. */ +#define DW_AT_lo_user 0x2000 + +#define DW_AT_MIPS_fde 0x2001 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_begin 0x2002 /* MIPS/SGI */ +#define DW_AT_MIPS_tail_loop_begin 0x2003 /* MIPS/SGI */ +#define DW_AT_MIPS_epilog_begin 0x2004 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_unroll_factor 0x2005 /* MIPS/SGI */ +#define DW_AT_MIPS_software_pipeline_depth 0x2006 /* MIPS/SGI */ +#define DW_AT_MIPS_linkage_name 0x2007 /* MIPS/SGI,GNU,and others.*/ +#define DW_AT_MIPS_stride 0x2008 /* MIPS/SGI */ +#define DW_AT_MIPS_abstract_name 0x2009 /* MIPS/SGI */ +#define DW_AT_MIPS_clone_origin 0x200a /* MIPS/SGI */ +#define DW_AT_MIPS_has_inlines 0x200b /* MIPS/SGI */ +#define DW_AT_MIPS_stride_byte 0x200c /* MIPS/SGI */ +#define DW_AT_MIPS_stride_elem 0x200d /* MIPS/SGI */ +#define DW_AT_MIPS_ptr_dopetype 0x200e /* MIPS/SGI */ +#define DW_AT_MIPS_allocatable_dopetype 0x200f /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_size 0x2011 /* MIPS/SGI */ + +/* HP extensions. */ +#define DW_AT_HP_unmodifiable 0x2001 /* conflict: MIPS */ +#define DW_AT_HP_prologue 0x2005 /* conflict: MIPS */ +#define DW_AT_HP_epilogue 0x2008 /* conflict: MIPS */ +#define DW_AT_HP_actuals_stmt_list 0x2010 /* conflict: MIPS */ +#define DW_AT_HP_proc_per_section 0x2011 /* conflict: MIPS */ +#define DW_AT_HP_raw_data_ptr 0x2012 /* HP */ +#define DW_AT_HP_pass_by_reference 0x2013 /* HP */ +#define DW_AT_HP_opt_level 0x2014 /* HP */ +#define DW_AT_HP_prof_version_id 0x2015 /* HP */ +#define DW_AT_HP_opt_flags 0x2016 /* HP */ +#define DW_AT_HP_cold_region_low_pc 0x2017 /* HP */ +#define DW_AT_HP_cold_region_high_pc 0x2018 /* HP */ +#define DW_AT_HP_all_variables_modifiable 0x2019 /* HP */ +#define DW_AT_HP_linkage_name 0x201a /* HP */ +#define DW_AT_HP_prof_flags 0x201b /* HP */ +#define DW_AT_HP_unit_name 0x201f /* HP */ +#define DW_AT_HP_unit_size 0x2020 /* HP */ +#define DW_AT_HP_widened_byte_size 0x2021 /* HP */ +#define DW_AT_HP_definition_points 0x2022 /* HP */ +#define DW_AT_HP_default_location 0x2023 /* HP */ +#define DW_AT_HP_is_result_param 0x2029 /* HP */ + +#define DW_AT_CPQ_discontig_ranges 0x2001 /* COMPAQ/HP */ +#define DW_AT_CPQ_semantic_events 0x2002 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_var 0x2003 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_rtn 0x2004 /* COMPAQ/HP */ +#define DW_AT_CPQ_prologue_length 0x2005 /* COMPAQ/HP */ + +/* From GHS C GreenHills ghs.com */ +#define DW_AT_ghs_mangled 0x2007 /* conflict MIPS */ +#define DW_AT_ghs_rsm 0x2083 +#define DW_AT_ghs_frsm 0x2085 +#define DW_AT_ghs_frames 0x2086 +#define DW_AT_ghs_rso 0x2087 +#define DW_AT_ghs_subcpu 0x2092 +#define DW_AT_ghs_lbrace_line 0x2093 + +#define DW_AT_INTEL_other_endian 0x2026 /* Intel, 1 if byte swapped.*/ + +/* GNU extensions. */ +#define DW_AT_sf_names 0x2101 /* GNU */ +#define DW_AT_src_info 0x2102 /* GNU */ +#define DW_AT_mac_info 0x2103 /* GNU */ +#define DW_AT_src_coords 0x2104 /* GNU */ +#define DW_AT_body_begin 0x2105 /* GNU */ +#define DW_AT_body_end 0x2106 /* GNU */ +#define DW_AT_GNU_vector 0x2107 /* GNU */ + +/* Thread safety, see + http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . */ +/* The values here are from gcc-4.6.2 include/dwarf2.h. The + values are not given on the web page at all, nor on web pages + it refers to. */ +#define DW_AT_GNU_guarded_by 0x2108 /* GNU */ +#define DW_AT_GNU_pt_guarded_by 0x2109 /* GNU */ +#define DW_AT_GNU_guarded 0x210a /* GNU */ +#define DW_AT_GNU_pt_guarded 0x210b /* GNU */ +#define DW_AT_GNU_locks_excluded 0x210c /* GNU */ +#define DW_AT_GNU_exclusive_locks_required 0x210d /* GNU */ +#define DW_AT_GNU_shared_locks_required 0x210e /* GNU */ + +/* See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo */ +#define DW_AT_GNU_odr_signature 0x210f /* GNU */ + +/* See See http://gcc.gnu.org/wiki/TemplateParmsDwarf */ +/* The value here is from gcc-4.6.2 include/dwarf2.h. The value is + not consistent with the web page as of December 2011. */ +#define DW_AT_GNU_template_name 0x2110 /* GNU */ +/* The GNU call site extension. + See http://www.dwarfstd.org/ShowIssue.php?\ + issue=100909.2&type=open . */ +#define DW_AT_GNU_call_site_value 0x2111 /* GNU */ +#define DW_AT_GNU_call_site_data_value 0x2112 /* GNU */ +#define DW_AT_GNU_call_site_target 0x2113 /* GNU */ +#define DW_AT_GNU_call_site_target_clobbered 0x2114 /* GNU */ +#define DW_AT_GNU_tail_call 0x2115 /* GNU */ +#define DW_AT_GNU_all_tail_call_sites 0x2116 /* GNU */ +#define DW_AT_GNU_all_call_sites 0x2117 /* GNU */ +#define DW_AT_GNU_all_source_call_sites 0x2118 /* GNU */ +/* Section offset to .debug_macro section. */ +#define DW_AT_GNU_macros 0x2119 /* GNU */ +#define DW_AT_GNU_deleted 0x211a /* GNU */ +/* The GNU DebugFission project: + http://gcc.gnu.org/wiki/DebugFission */ +#define DW_AT_GNU_dwo_name 0x2130 /* GNU */ +#define DW_AT_GNU_dwo_id 0x2131 /* GNU */ + +#define DW_AT_GNU_ranges_base 0x2132 /* GNU */ +#define DW_AT_GNU_addr_base 0x2133 /* GNU */ +#define DW_AT_GNU_pubnames 0x2134 /* GNU */ +#define DW_AT_GNU_pubtypes 0x2135 /* GNU */ + +/* To distinguish distinct basic blocks in a single source line. */ +#define DW_AT_GNU_discriminator 0x2136 /* GNU */ +#define DW_AT_GNU_locviews 0x2137 /* GNU */ +#define DW_AT_GNU_entry_view 0x2138 /* GNU */ + +/* Sun extensions */ +#define DW_AT_SUN_template 0x2201 /* SUN */ +#define DW_AT_VMS_rtnbeg_pd_address 0x2201 /* VMS */ +#define DW_AT_SUN_alignment 0x2202 /* SUN */ +#define DW_AT_SUN_vtable 0x2203 /* SUN */ +#define DW_AT_SUN_count_guarantee 0x2204 /* SUN */ +#define DW_AT_SUN_command_line 0x2205 /* SUN */ +#define DW_AT_SUN_vbase 0x2206 /* SUN */ +#define DW_AT_SUN_compile_options 0x2207 /* SUN */ +#define DW_AT_SUN_language 0x2208 /* SUN */ +#define DW_AT_SUN_browser_file 0x2209 /* SUN */ +#define DW_AT_SUN_vtable_abi 0x2210 /* SUN */ +#define DW_AT_SUN_func_offsets 0x2211 /* SUN */ +#define DW_AT_SUN_cf_kind 0x2212 /* SUN */ +#define DW_AT_SUN_vtable_index 0x2213 /* SUN */ +#define DW_AT_SUN_omp_tpriv_addr 0x2214 /* SUN */ +#define DW_AT_SUN_omp_child_func 0x2215 /* SUN */ +#define DW_AT_SUN_func_offset 0x2216 /* SUN */ +#define DW_AT_SUN_memop_type_ref 0x2217 /* SUN */ +#define DW_AT_SUN_profile_id 0x2218 /* SUN */ +#define DW_AT_SUN_memop_signature 0x2219 /* SUN */ +#define DW_AT_SUN_obj_dir 0x2220 /* SUN */ +#define DW_AT_SUN_obj_file 0x2221 /* SUN */ +#define DW_AT_SUN_original_name 0x2222 /* SUN */ +#define DW_AT_SUN_hwcprof_signature 0x2223 /* SUN */ +#define DW_AT_SUN_amd64_parmdump 0x2224 /* SUN */ +#define DW_AT_SUN_part_link_name 0x2225 /* SUN */ +#define DW_AT_SUN_link_name 0x2226 /* SUN */ +#define DW_AT_SUN_pass_with_const 0x2227 /* SUN */ +#define DW_AT_SUN_return_with_const 0x2228 /* SUN */ +#define DW_AT_SUN_import_by_name 0x2229 /* SUN */ +#define DW_AT_SUN_f90_pointer 0x222a /* SUN */ +#define DW_AT_SUN_pass_by_ref 0x222b /* SUN */ +#define DW_AT_SUN_f90_allocatable 0x222c /* SUN */ +#define DW_AT_SUN_f90_assumed_shape_array 0x222d /* SUN */ +#define DW_AT_SUN_c_vla 0x222e /* SUN */ +#define DW_AT_SUN_return_value_ptr 0x2230 /* SUN */ +#define DW_AT_SUN_dtor_start 0x2231 /* SUN */ +#define DW_AT_SUN_dtor_length 0x2232 /* SUN */ +#define DW_AT_SUN_dtor_state_initial 0x2233 /* SUN */ +#define DW_AT_SUN_dtor_state_final 0x2234 /* SUN */ +#define DW_AT_SUN_dtor_state_deltas 0x2235 /* SUN */ +#define DW_AT_SUN_import_by_lname 0x2236 /* SUN */ +#define DW_AT_SUN_f90_use_only 0x2237 /* SUN */ +#define DW_AT_SUN_namelist_spec 0x2238 /* SUN */ +#define DW_AT_SUN_is_omp_child_func 0x2239 /* SUN */ +#define DW_AT_SUN_fortran_main_alias 0x223a /* SUN */ +#define DW_AT_SUN_fortran_based 0x223b /* SUN */ + +/* ALTIUM extension: ALTIUM Compliant location lists (flag) */ +#define DW_AT_ALTIUM_loclist 0x2300 /* ALTIUM */ +/* Ada GNAT gcc attributes. constant integer forms. */ +/* See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type . */ +#define DW_AT_use_GNAT_descriptive_type 0x2301 +#define DW_AT_GNAT_descriptive_type 0x2302 +#define DW_AT_GNU_numerator 0x2303 /* GNU */ +#define DW_AT_GNU_denominator 0x2304 /* GNU */ +/* See https://gcc.gnu.org/wiki/DW_AT_GNU_bias */ +#define DW_AT_GNU_bias 0x2305 /* GNU */ + +/* Go-specific type attributes + Naming as lower-case go instead of GO is a small mistake + by the Go language folks, it seems. This is the + common spelling for these. */ +#define DW_AT_go_kind 0x2900 +#define DW_AT_go_key 0x2901 +#define DW_AT_go_elem 0x2902 + +/* Attribute for DW_TAG_member of a struct type. + Nonzero value indicates the struct field is an embedded field.*/ +#define DW_AT_go_embedded_field 0x2903 + +#define DW_AT_go_runtime_type 0x2904 + +/* UPC extension. */ +#define DW_AT_upc_threads_scaled 0x3210 /* UPC */ + +#define DW_AT_IBM_wsa_addr 0x393e +#define DW_AT_IBM_home_location 0x393f +#define DW_AT_IBM_alt_srcview 0x3940 + +/* PGI (STMicroelectronics) extensions. */ +/* PGI. Block, constant, reference. This attribute is an ASTPLAB + extension used to describe the array local base. */ +#define DW_AT_PGI_lbase 0x3a00 + +/* PGI. Block, constant, reference. ASTPLAB adds this attribute + to describe the section offset, or the offset to the + first element in the dimension. */ +#define DW_AT_PGI_soffset 0x3a01 + +/* PGI. Block, constant, reference. ASTPLAB adds this + attribute to describe the linear stride or the distance + between elements in the dimension. */ +#define DW_AT_PGI_lstride 0x3a02 + +#define DW_AT_BORLAND_property_read 0x3b11 +#define DW_AT_BORLAND_property_write 0x3b12 +#define DW_AT_BORLAND_property_implements 0x3b13 +#define DW_AT_BORLAND_property_index 0x3b14 +#define DW_AT_BORLAND_property_default 0x3b15 +#define DW_AT_BORLAND_Delphi_unit 0x3b20 +#define DW_AT_BORLAND_Delphi_class 0x3b21 +#define DW_AT_BORLAND_Delphi_record 0x3b22 +#define DW_AT_BORLAND_Delphi_metaclass 0x3b23 +#define DW_AT_BORLAND_Delphi_constructor 0x3b24 +#define DW_AT_BORLAND_Delphi_destructor 0x3b25 +#define DW_AT_BORLAND_Delphi_anonymous_method 0x3b26 +#define DW_AT_BORLAND_Delphi_interface 0x3b27 +#define DW_AT_BORLAND_Delphi_ABI 0x3b28 +#define DW_AT_BORLAND_Delphi_frameptr 0x3b30 +#define DW_AT_BORLAND_closure 0x3b31 + +#define DW_AT_LLVM_include_path 0x3e00 +#define DW_AT_LLVM_config_macros 0x3e01 +#define DW_AT_LLVM_sysroot 0x3e02 +#define DW_AT_LLVM_tag_offset 0x3e03 +/* LLVM intends to use 0x3e04 - 0x3e06 */ +#define DW_AT_LLVM_apinotes 0x3e07 +/* Next 6 are for Heterogeneous debugging */ +#define DW_AT_LLVM_active_lane 0x3e08 +#define DW_AT_LLVM_augmentation 0x3e09 +#define DW_AT_LLVM_lanes 0x3e0a +#define DW_AT_LLVM_lane_pc 0x3e0b +#define DW_AT_LLVM_vector_size 0x3e0c + +#define DW_AT_APPLE_optimized 0x3fe1 +#define DW_AT_APPLE_flags 0x3fe2 +#define DW_AT_APPLE_isa 0x3fe3 +/* 0x3fe4 Also known as DW_AT_APPLE_closure, block preferred. */ +#define DW_AT_APPLE_block 0x3fe4 +/* The rest of APPLE here are in support of Objective C */ +#define DW_AT_APPLE_major_runtime_vers 0x3fe5 +#define DW_AT_APPLE_runtime_class 0x3fe6 +#define DW_AT_APPLE_omit_frame_ptr 0x3fe7 +#define DW_AT_APPLE_property_name 0x3fe8 +#define DW_AT_APPLE_property_getter 0x3fe9 +#define DW_AT_APPLE_property_setter 0x3fea +#define DW_AT_APPLE_property_attribute 0x3feb +#define DW_AT_APPLE_objc_complete_type 0x3fec +#define DW_AT_APPLE_property 0x3fed +#define DW_AT_APPLE_objc_direct 0x3fee +#define DW_AT_APPLE_sdk 0x3fef + +#define DW_AT_hi_user 0x3fff + +/* OP values 0x01,0x02,0x04,0x05,0x07 are DWARF1 only */ +#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_push_object_address 0x97 /* DWARF3 */ +#define DW_OP_call2 0x98 /* DWARF3 */ +#define DW_OP_call4 0x99 /* DWARF3 */ +#define DW_OP_call_ref 0x9a /* DWARF3 */ +#define DW_OP_form_tls_address 0x9b /* DWARF3f */ +#define DW_OP_call_frame_cfa 0x9c /* DWARF3f */ +#define DW_OP_bit_piece 0x9d /* DWARF3f */ +#define DW_OP_implicit_value 0x9e /* DWARF4 */ +#define DW_OP_stack_value 0x9f /* DWARF4 */ +#define DW_OP_implicit_pointer 0xa0 /* DWARF5 */ +#define DW_OP_addrx 0xa1 /* DWARF5 */ +#define DW_OP_constx 0xa2 /* DWARF5 */ +#define DW_OP_entry_value 0xa3 /* DWARF5 */ +#define DW_OP_const_type 0xa4 /* DWARF5 */ +#define DW_OP_regval_type 0xa5 /* DWARF5 */ +#define DW_OP_deref_type 0xa6 /* DWARF5 */ +#define DW_OP_xderef_type 0xa7 /* DWARF5 */ +#define DW_OP_convert 0xa8 /* DWARF5 */ +#define DW_OP_reinterpret 0xa9 /* DWARF5 */ + +#define DW_OP_GNU_push_tls_address 0xe0 /* GNU */ +#define DW_OP_WASM_location 0xed +#define DW_OP_WASM_location_int 0xee + +/* Follows extension so dwarfdump prints the +most-likely-useful name. */ +#define DW_OP_lo_user 0xe0 + + /* LLVM extensions. */ +#define DW_OP_LLVM_form_aspace_address 0xe1 +#define DW_OP_LLVM_push_lane 0xe2 +#define DW_OP_LLVM_offset 0xe3 +#define DW_OP_LLVM_offset_uconst 0xe4 +#define DW_OP_LLVM_bit_offset 0xe5 +#define DW_OP_LLVM_call_frame_entry_reg 0xe6 +#define DW_OP_LLVM_undefined 0xe7 +#define DW_OP_LLVM_aspace_bregx 0xe8 +#define DW_OP_LLVM_aspace_implicit_pointer 0xe9 +#define DW_OP_LLVM_piece_end 0xea +#define DW_OP_LLVM_extend 0xeb +#define DW_OP_LLVM_select_bit_piece 0xec + /* HP extensions. */ +#define DW_OP_HP_unknown 0xe0 /* HP conflict: GNU */ +#define DW_OP_HP_is_value 0xe1 /* HP */ +#define DW_OP_HP_fltconst4 0xe2 /* HP */ +#define DW_OP_HP_fltconst8 0xe3 /* HP */ +#define DW_OP_HP_mod_range 0xe4 /* HP */ +#define DW_OP_HP_unmod_range 0xe5 /* HP */ +#define DW_OP_HP_tls 0xe6 /* HP */ + +/* Intel: made obsolete by DW_OP_bit_piece above. */ +#define DW_OP_INTEL_bit_piece 0xe8 + +/* Apple extension. */ +#define DW_OP_GNU_uninit 0xf0 /* GNU */ +#define DW_OP_APPLE_uninit 0xf0 /* Apple */ +#define DW_OP_GNU_encoded_addr 0xf1 /* GNU */ +#define DW_OP_GNU_implicit_pointer 0xf2 /* GNU */ +#define DW_OP_GNU_entry_value 0xf3 /* GNU */ +#define DW_OP_GNU_const_type 0xf4 /* GNU */ +#define DW_OP_GNU_regval_type 0xf5 /* GNU */ +#define DW_OP_GNU_deref_type 0xf6 /* GNU */ +#define DW_OP_GNU_convert 0xf7 /* GNU */ +#define DW_OP_GNU_reinterpret 0xf9 /* GNU */ +#define DW_OP_GNU_parameter_ref 0xfa /* GNU */ +#define DW_OP_GNU_addr_index 0xfb /* GNU Fission */ +#define DW_OP_GNU_const_index 0xfc /* GNU Fission */ +#define DW_OP_GNU_variable_value 0xfd /* GNU 2017 */ +#define DW_OP_PGI_omp_thread_num 0xf8 /* PGI (STMicroelectronics) */ + +#define DW_OP_hi_user 0xff + +#define DW_ATE_address 0x01 +#define DW_ATE_boolean 0x02 +#define DW_ATE_complex_float 0x03 +#define DW_ATE_float 0x04 +#define DW_ATE_signed 0x05 +#define DW_ATE_signed_char 0x06 +#define DW_ATE_unsigned 0x07 +#define DW_ATE_unsigned_char 0x08 +#define DW_ATE_imaginary_float 0x09 /* DWARF3 */ +#define DW_ATE_packed_decimal 0x0a /* DWARF3f */ +#define DW_ATE_numeric_string 0x0b /* DWARF3f */ +#define DW_ATE_edited 0x0c /* DWARF3f */ +#define DW_ATE_signed_fixed 0x0d /* DWARF3f */ +#define DW_ATE_unsigned_fixed 0x0e /* DWARF3f */ +#define DW_ATE_decimal_float 0x0f /* DWARF3f */ +#define DW_ATE_UTF 0x10 /* DWARF4 */ +#define DW_ATE_UCS 0x11 /* DWARF5 */ +#define DW_ATE_ASCII 0x12 /* DWARF5 */ + +/* ALTIUM extensions. x80, x81 */ +#define DW_ATE_ALTIUM_fract 0x80 /* ALTIUM __fract type */ + +/* Follows extension so dwarfdump prints + the most-likely-useful name. */ +#define DW_ATE_lo_user 0x80 + +/* Shown here to help dwarfdump build script. */ +#define DW_ATE_ALTIUM_accum 0x81 /* ALTIUM __accum type */ + +/* HP extensions. */ +#define DW_ATE_HP_float80 0x80 /* (80 bit). HP */ +#define DW_ATE_HP_complex_float80 0x81 /* Complex (80 bit). HP */ +#define DW_ATE_HP_float128 0x82 /* (128 bit). HP */ +#define DW_ATE_HP_complex_float128 0x83 /* Complex (128 bit). HP */ +#define DW_ATE_HP_floathpintel 0x84 /* (82 bit IA64). HP */ +#define DW_ATE_HP_imaginary_float80 0x85 /* HP */ +#define DW_ATE_HP_imaginary_float128 0x86 /* HP */ +#define DW_ATE_HP_VAX_float 0x88 /* F or G floating. */ +#define DW_ATE_HP_VAX_float_d 0x89 /* D floating. */ +#define DW_ATE_HP_packed_decimal 0x8a /* Cobol. */ +#define DW_ATE_HP_zoned_decimal 0x8b /* Cobol. */ +#define DW_ATE_HP_edited 0x8c /* Cobol. */ +#define DW_ATE_HP_signed_fixed 0x8d /* Cobol. */ +#define DW_ATE_HP_unsigned_fixed 0x8e /* Cobol. */ +#define DW_ATE_HP_VAX_complex_float 0x8f /* ForG floating complex.*/ +#define DW_ATE_HP_VAX_complex_float_d 0x90 /* D floating complex. */ + +/* Sun extensions */ +#define DW_ATE_SUN_interval_float 0x91 + +/* Obsolete: See DW_ATE_imaginary_float */ +#define DW_ATE_SUN_imaginary_float 0x92 /* Really SUN 0x86 ? */ + +#define DW_ATE_hi_user 0xff + +/* DWARF5 Defaulted Member Encodings. */ +#define DW_DEFAULTED_no 0x0 /* DWARF5 */ +#define DW_DEFAULTED_in_class 0x1 /* DWARF5 */ +#define DW_DEFAULTED_out_of_class 0x2 /* DWARF5 */ + +#define DW_IDX_compile_unit 0x1 /* DWARF5 */ +#define DW_IDX_type_unit 0x2 /* DWARF5 */ +#define DW_IDX_die_offset 0x3 /* DWARF5 */ +#define DW_IDX_parent 0x4 /* DWARF5 */ +#define DW_IDX_type_hash 0x5 /* DWARF5 */ +#define DW_IDX_GNU_internal 0x2000 +#define DW_IDX_lo_user 0x2000 /* DWARF5 */ +#define DW_IDX_GNU_external 0x2001 +#define DW_IDX_hi_user 0x3fff /* DWARF5 */ + +/* These with not-quite-the-same-names were used in DWARF4 + We call then DW_LLEX. + Never official and should not be used by anyone.*/ +#define DW_LLEX_end_of_list_entry 0x0 +#define DW_LLEX_base_address_selection_entry 0x01 +#define DW_LLEX_start_end_entry 0x02 +#define DW_LLEX_start_length_entry 0x03 +#define DW_LLEX_offset_pair_entry 0x04 + +/* DWARF5 Location List Entries in Split Objects */ +#define DW_LLE_end_of_list 0x0 /* DWARF5 */ +#define DW_LLE_base_addressx 0x01 /* DWARF5 */ +#define DW_LLE_startx_endx 0x02 /* DWARF5 */ +#define DW_LLE_startx_length 0x03 /* DWARF5 */ +#define DW_LLE_offset_pair 0x04 /* DWARF5 */ +#define DW_LLE_default_location 0x05 /* DWARF5 */ +#define DW_LLE_base_address 0x06 /* DWARF5 */ +#define DW_LLE_start_end 0x07 /* DWARF5 */ +#define DW_LLE_start_length 0x08 /* DWARF5 */ + +/* DWARF5 Range List Entries */ +#define DW_RLE_end_of_list 0x00 /* DWARF5 */ +#define DW_RLE_base_addressx 0x01 /* DWARF5 */ +#define DW_RLE_startx_endx 0x02 /* DWARF5 */ +#define DW_RLE_startx_length 0x03 /* DWARF5 */ +#define DW_RLE_offset_pair 0x04 /* DWARF5 */ +#define DW_RLE_base_address 0x05 /* DWARF5 */ +#define DW_RLE_start_end 0x06 /* DWARF5 */ +#define DW_RLE_start_length 0x07 /* DWARF5 */ + +/* GNUIndex encodings non-standard. New in 2020, + used in .debug_gnu_pubnames .debug_gnu_pubtypes + but no spellings provided in documentation. */ +#define DW_GNUIVIS_global 0 +#define DW_GNUIVIS_static 1 + +/* GNUIndex encodings non-standard. New in 2020, + used in .debug_gnu_pubnames .debug_gnu_pubtypes + but no spellings provided in documentation. */ +#define DW_GNUIKIND_none 0 +#define DW_GNUIKIND_type 1 +#define DW_GNUIKIND_variable 2 +#define DW_GNUIKIND_function 3 +#define DW_GNUIKIND_other 4 + +/* DWARF5 Unit header unit type encodings */ +#define DW_UT_compile 0x01 /* DWARF5 */ +#define DW_UT_type 0x02 /* DWARF5 */ +#define DW_UT_partial 0x03 /* DWARF5 */ +#define DW_UT_skeleton 0x04 /* DWARF5 */ +#define DW_UT_split_compile 0x05 /* DWARF5 */ +#define DW_UT_split_type 0x06 /* DWARF5 */ +#define DW_UT_lo_user 0x80 /* DWARF5 */ +#define DW_UT_hi_user 0xff /* DWARF5 */ + +/* DWARF5 DebugFission object section id values + for .dwp object section offsets hash table. + 0 is reserved, not used. + 2 is actually reserved, not used in DWARF5. + But 2 may be seen in some DWARF4 objects. +*/ +#define DW_SECT_INFO 1 /* .debug_info.dwo DWARF5 */ +#define DW_SECT_TYPES 2 /* .debug_types.dwo pre-DWARF5 */ +#define DW_SECT_ABBREV 3 /* .debug_abbrev.dwo DWARF5 */ +#define DW_SECT_LINE 4 /* .debug_line.dwo DWARF5 */ +#define DW_SECT_LOCLISTS 5 /* .debug_loclists.dwo DWARF5 */ +#define DW_SECT_STR_OFFSETS 6 /* .debug_str_offsets.dwo DWARF5 */ +#define DW_SECT_MACRO 7 /* .debug_macro.dwo DWARF5 */ +#define DW_SECT_RNGLISTS 8 /* .debug_rnglists.dwo DWARF5 */ + +/* Decimal Sign codes. */ +#define DW_DS_unsigned 0x01 /* DWARF3f */ +#define DW_DS_leading_overpunch 0x02 /* DWARF3f */ +#define DW_DS_trailing_overpunch 0x03 /* DWARF3f */ +#define DW_DS_leading_separate 0x04 /* DWARF3f */ +#define DW_DS_trailing_separate 0x05 /* DWARF3f */ + +/* Endian code name. */ +#define DW_END_default 0x00 /* DWARF3f */ +#define DW_END_big 0x01 /* DWARF3f */ +#define DW_END_little 0x02 /* DWARF3f */ + +#define DW_END_lo_user 0x40 /* DWARF3f */ +#define DW_END_hi_user 0xff /* DWARF3f */ + +/* For use with DW_TAG_SUN_codeflags + If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then + standard dwarf ATCF entries start at 0x01 */ +#define DW_ATCF_lo_user 0x40 /* SUN */ +#define DW_ATCF_SUN_mop_bitfield 0x41 /* SUN */ +#define DW_ATCF_SUN_mop_spill 0x42 /* SUN */ +#define DW_ATCF_SUN_mop_scopy 0x43 /* SUN */ +#define DW_ATCF_SUN_func_start 0x44 /* SUN */ +#define DW_ATCF_SUN_end_ctors 0x45 /* SUN */ +#define DW_ATCF_SUN_branch_target 0x46 /* SUN */ +#define DW_ATCF_SUN_mop_stack_probe 0x47 /* SUN */ +#define DW_ATCF_SUN_func_epilog 0x48 /* SUN */ +#define DW_ATCF_hi_user 0xff /* SUN */ + +/* Accessibility code name. */ +#define DW_ACCESS_public 0x01 +#define DW_ACCESS_protected 0x02 +#define DW_ACCESS_private 0x03 + +/* Visibility code name. */ +#define DW_VIS_local 0x01 +#define DW_VIS_exported 0x02 +#define DW_VIS_qualified 0x03 + +/* Virtuality code name. */ +#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 /* DWARF3 */ +#define DW_LANG_C99 0x000c /* DWARF3 */ +#define DW_LANG_Ada95 0x000d /* DWARF3 */ +#define DW_LANG_Fortran95 0x000e /* DWARF3 */ +#define DW_LANG_PLI 0x000f /* DWARF3 */ +#define DW_LANG_ObjC 0x0010 /* DWARF3f */ +#define DW_LANG_ObjC_plus_plus 0x0011 /* DWARF3f */ +#define DW_LANG_UPC 0x0012 /* DWARF3f */ +#define DW_LANG_D 0x0013 /* DWARF3f */ +#define DW_LANG_Python 0x0014 /* DWARF4 */ +/* The following 2 are not yet formally approved October 2010, but + it seems extremely likely they will be approved as the committee + chair agrees these should be ok and no one on the committee + has objected. */ +#define DW_LANG_OpenCL 0x0015 /* DWARF5 */ +#define DW_LANG_Go 0x0016 /* DWARF5 */ +#define DW_LANG_Modula3 0x0017 /* DWARF5 */ +#define DW_LANG_Haskel 0x0018 /* DWARF5 */ +#define DW_LANG_C_plus_plus_03 0x0019 /* DWARF5 */ +#define DW_LANG_C_plus_plus_11 0x001a /* DWARF5 */ +#define DW_LANG_OCaml 0x001b /* DWARF5 */ +#define DW_LANG_Rust 0x001c /* DWARF5 */ +#define DW_LANG_C11 0x001d /* DWARF5 */ +#define DW_LANG_Swift 0x001e /* DWARF5 */ +#define DW_LANG_Julia 0x001f /* DWARF5 */ +#define DW_LANG_Dylan 0x0020 /* DWARF5 */ +#define DW_LANG_C_plus_plus_14 0x0021 /* DWARF5 */ +#define DW_LANG_Fortran03 0x0022 /* DWARF5 */ +#define DW_LANG_Fortran08 0x0023 /* DWARF5 */ +#define DW_LANG_RenderScript 0x0024 /* DWARF5 */ +#define DW_LANG_BLISS 0x0025 /* DWARF5 */ +#define DW_LANG_Kotlin 0x0026 /* DWARF6 */ +#define DW_LANG_Zig 0x0027 /* DWARF6 */ +#define DW_LANG_Crystal 0x0028 /* DWARF6 */ +#define DW_LANG_C_plus_plus_17 0x002a /* DWARF6 */ +#define DW_LANG_C_plus_plus_20 0x002b /* DWARF6 */ +#define DW_LANG_C17 0x002c /* DWARF6 */ +#define DW_LANG_Fortran18 0x002d /* DWARF6 */ +#define DW_LANG_Ada2005 0x002e /* DWARF6 */ +#define DW_LANG_Ada2012 0x002f /* DWARF6 */ +#define DW_LANG_HIP 0x0030 /* DWARF6 */ +#define DW_LANG_Assembly 0x0031 /* DWARF6 */ +#define DW_LANG_C_sharp 0x0032 /* DWARF6 */ +#define DW_LANG_Mojo 0x0033 /* DWARF6 */ + +#define DW_LANG_lo_user 0x8000 +#define DW_LANG_Mips_Assembler 0x8001 /* MIPS */ +#define DW_LANG_Upc 0x8765 /* UPC, use + DW_LANG_UPC instead. */ +#define DW_LANG_GOOGLE_RenderScript 0x8e57 +/* ALTIUM extension */ +#define DW_LANG_ALTIUM_Assembler 0x9101 /* ALTIUM */ +#define DW_LANG_BORLAND_Delphi 0xb000 + +/* Sun extensions */ +#define DW_LANG_SUN_Assembler 0x9001 /* SUN */ + +#define DW_LANG_hi_user 0xffff + +/* Identifier case name. */ +#define DW_ID_case_sensitive 0x00 +#define DW_ID_up_case 0x01 +#define DW_ID_down_case 0x02 +#define DW_ID_case_insensitive 0x03 + +/* Calling Convention Name. */ +#define DW_CC_normal 0x01 +#define DW_CC_program 0x02 +#define DW_CC_nocall 0x03 +#define DW_CC_pass_by_reference 0x04 /* DWARF5 */ +#define DW_CC_pass_by_value 0x05 /* DWARF5 */ +#define DW_CC_lo_user 0x40 + +#define DW_CC_GNU_renesas_sh 0x40 /* GNU */ +#define DW_CC_GNU_borland_fastcall_i386 0x41 /* GNU */ + +/* ALTIUM extensions. */ +/* Function is an interrupt handler, + return address on system stack. */ +#define DW_CC_ALTIUM_interrupt 0x65 /* ALTIUM*/ + +/* Near function model, return address on system stack. */ +#define DW_CC_ALTIUM_near_system_stack 0x66 /*ALTIUM */ + +/* Near function model, return address on user stack. */ +#define DW_CC_ALTIUM_near_user_stack 0x67 /* ALTIUM */ + +/* Huge function model, return address on user stack. */ +#define DW_CC_ALTIUM_huge_user_stack 0x68 /* ALTIUM */ + +#define DW_CC_GNU_BORLAND_safecall 0xb0 +#define DW_CC_GNU_BORLAND_stdcall 0xb1 +#define DW_CC_GNU_BORLAND_pascal 0xb2 +#define DW_CC_GNU_BORLAND_msfastcall 0xb3 +#define DW_CC_GNU_BORLAND_msreturn 0xb4 +#define DW_CC_GNU_BORLAND_thiscall 0xb5 +#define DW_CC_GNU_BORLAND_fastcall 0xb6 + +#define DW_CC_LLVM_vectorcall 0xc0 +#define DW_CC_LLVM_Win64 0xc1 +#define DW_CC_LLVM_X86_64SysV 0xc2 +#define DW_CC_LLVM_AAPCS 0xc3 +#define DW_CC_LLVM_AAPCS_VFP 0xc4 +#define DW_CC_LLVM_IntelOclBicc 0xc5 +#define DW_CC_LLVM_SpirFunction 0xc6 +#define DW_CC_LLVM_OpenCLKernel 0xc7 +#define DW_CC_LLVM_Swift 0xc8 +#define DW_CC_LLVM_PreserveMost 0xc9 +#define DW_CC_LLVM_PreserveAll 0xca +#define DW_CC_LLVM_X86RegCall 0xcb +#define DW_CC_GDB_IBM_OpenCL 0xff + +#define DW_CC_hi_user 0xff + +/* Inline Code Name. */ +#define DW_INL_not_inlined 0x00 +#define DW_INL_inlined 0x01 +#define DW_INL_declared_not_inlined 0x02 +#define DW_INL_declared_inlined 0x03 + +/* Ordering Name. */ +#define DW_ORD_row_major 0x00 +#define DW_ORD_col_major 0x01 + +/* Discriminant Descriptor Name. */ +#define DW_DSC_label 0x00 +#define DW_DSC_range 0x01 + +/* Line number header entry format encodings. DWARF5 */ +#define DW_LNCT_path 0x1 /* DWARF5 */ +#define DW_LNCT_directory_index 0x2 /* DWARF5 */ +#define DW_LNCT_timestamp 0x3 /* DWARF5 */ +#define DW_LNCT_size 0x4 /* DWARF5 */ +#define DW_LNCT_MD5 0x5 /* DWARF5 */ +/* Experimental two-level line tables. Non standard */ +#define DW_LNCT_GNU_subprogram_name 0x6 +#define DW_LNCT_GNU_decl_file 0x7 +#define DW_LNCT_GNU_decl_line 0x8 +#define DW_LNCT_lo_user 0x2000 /* DWARF5 */ +#define DW_LNCT_LLVM_source 0x2001 +#define DW_LNCT_LLVM_is_MD5 0x2002 +#define DW_LNCT_hi_user 0x3fff /* DWARF5 */ + +/* Line number standard opcode name. */ +#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 /* DWARF3 */ +#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */ +#define DW_LNS_set_isa 0x0c /* DWARF3 */ + +/* Experimental two-level line tables. NOT STD DWARF5 */ +/* Not saying GNU or anything. There are no + DW_LNS_lo_user or DW_LNS_hi_user values though. + DW_LNS_set_address_from_logical and + DW_LNS_set_subprogram being both 0xd + to avoid using up more space in the special opcode table. + EXPERIMENTAL DW_LNS follow. +*/ +#define DW_LNS_set_address_from_logical 0x0d /* Actuals table only */ +#define DW_LNS_set_subprogram 0x0d /* Logicals table only */ +#define DW_LNS_inlined_call 0x0e /* Logicals table only */ +#define DW_LNS_pop_context 0x0f /* Logicals table only */ + +/* Line number extended opcode name. */ +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_define_file 0x03 /* DWARF4 and earlier only */ +#define DW_LNE_set_discriminator 0x04 /* DWARF4 */ + +/* HP extensions. */ +#define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */ +#define DW_LNE_HP_push_context 0x12 /* 18 HP */ +#define DW_LNE_HP_pop_context 0x13 /* 19 HP */ +#define DW_LNE_HP_set_file_line_column 0x14 /* 20 HP */ +#define DW_LNE_HP_set_routine_name 0x15 /* 21 HP */ +#define DW_LNE_HP_set_sequence 0x16 /* 22 HP */ +#define DW_LNE_HP_negate_post_semantics 0x17 /* 23 HP */ +#define DW_LNE_HP_negate_function_exit 0x18 /* 24 HP */ +#define DW_LNE_HP_negate_front_end_logical 0x19 /* 25 HP */ +#define DW_LNE_HP_define_proc 0x20 /* 32 HP */ + +#define DW_LNE_HP_source_file_correlation 0x80 /* HP */ +#define DW_LNE_lo_user 0x80 /* DWARF3 */ +#define DW_LNE_hi_user 0xff /* DWARF3 */ + +/* These are known values for DW_LNS_set_isa. */ +/* These identifiers are not defined by any DWARFn standard. */ +#define DW_ISA_UNKNOWN 0 +/* The following two are ARM specific. */ +#define DW_ISA_ARM_thumb 1 /* ARM ISA */ +#define DW_ISA_ARM_arm 2 /* ARM ISA */ + +/* Macro information, DWARF5 */ +#define DW_MACRO_define 0x01 /* DWARF5 */ +#define DW_MACRO_undef 0x02 /* DWARF5 */ +#define DW_MACRO_start_file 0x03 /* DWARF5 */ +#define DW_MACRO_end_file 0x04 /* DWARF5 */ +#define DW_MACRO_define_strp 0x05 /* DWARF5 */ +#define DW_MACRO_undef_strp 0x06 /* DWARF5 */ +#define DW_MACRO_import 0x07 /* DWARF5 */ +#define DW_MACRO_define_sup 0x08 /* DWARF5 */ +#define DW_MACRO_undef_sup 0x09 /* DWARF5 */ +#define DW_MACRO_import_sup 0x0a /* DWARF5 */ +#define DW_MACRO_define_strx 0x0b /* DWARF5 */ +#define DW_MACRO_undef_strx 0x0c /* DWARF5 */ +#define DW_MACRO_lo_user 0xe0 +#define DW_MACRO_hi_user 0xff + +/* Macro information, DWARF2-DWARF4. */ +#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 + +/* CFA operator compaction (a space saving measure, see + the DWARF standard) means DW_CFA_extended and DW_CFA_nop + have the same value here. */ +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 +#define DW_CFA_nop 0x00 +#define DW_CFA_extended 0 +#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 /* DWARF3 */ +#define DW_CFA_expression 0x10 /* DWARF3 */ +#define DW_CFA_offset_extended_sf 0x11 /* DWARF3 */ +#define DW_CFA_def_cfa_sf 0x12 /* DWARF3 */ +#define DW_CFA_def_cfa_offset_sf 0x13 /* DWARF3 */ +#define DW_CFA_val_offset 0x14 /* DWARF3f */ +#define DW_CFA_val_offset_sf 0x15 /* DWARF3f */ +#define DW_CFA_val_expression 0x16 /* DWARF3f */ +#define DW_CFA_lo_user 0x1c +#define DW_CFA_low_user 0x1c /* Incorrect spelling, do not use. */ + +/* SGI/MIPS extension. */ +#define DW_CFA_MIPS_advance_loc8 0x1d /* MIPS */ + +/* GNU extensions. */ +#define DW_CFA_GNU_window_save 0x2d /* GNU */ +#define DW_CFA_AARCH64_negate_ra_state 0x2d +#define DW_CFA_GNU_args_size 0x2e /* GNU */ +#define DW_CFA_GNU_negative_offset_extended 0x2f /* GNU */ +#define DW_CFA_LLVM_def_aspace_cfa 0x30 +#define DW_CFA_LLVM_def_aspace_cfa_sf 0x31 + +/* Metaware if HC is augmentation, apparently meaning High C + and the op has a single uleb operand. + See http://sourceforge.net/p/elftoolchain/tickets/397/ */ +#define DW_CFA_METAWARE_info 0x34 + +#define DW_CFA_high_user 0x3f + +/* GNU exception header encoding. See the Generic + Elf Specification of the Linux Standard Base (LSB). + http://refspecs.freestandards.org/LSB_3.0.0/\ + LSB-Core-generic/LSB-Core-generic/dwarfext.html + The upper 4 bits indicate how the value is to be applied. + The lower 4 bits indicate the format of the data. + These identifiers are not defined by any DWARFn standard. +*/ +#define DW_EH_PE_absptr 0x00 /* GNU */ +#define DW_EH_PE_uleb128 0x01 /* GNU */ +#define DW_EH_PE_udata2 0x02 /* GNU */ +#define DW_EH_PE_udata4 0x03 /* GNU */ +#define DW_EH_PE_udata8 0x04 /* GNU */ +#define DW_EH_PE_sleb128 0x09 /* GNU */ +#define DW_EH_PE_sdata2 0x0A /* GNU */ +#define DW_EH_PE_sdata4 0x0B /* GNU */ +#define DW_EH_PE_sdata8 0x0C /* GNU */ + +#define DW_EH_PE_pcrel 0x10 /* GNU */ +#define DW_EH_PE_textrel 0x20 /* GNU */ +#define DW_EH_PE_datarel 0x30 /* GNU */ +#define DW_EH_PE_funcrel 0x40 /* GNU */ +#define DW_EH_PE_aligned 0x50 /* GNU */ + +#define DW_EH_PE_omit 0xff /* GNU. Means no value present. */ + +/* Mapping from machine registers and pseudo-regs into the + .debug_frame table. DW_FRAME entries are machine specific. + These describe MIPS/SGI R3000, R4K, R4400 and all later + MIPS/SGI IRIX machines. They describe a mapping from + hardware register number to the number used in the table + to identify that register. + + The CFA (Canonical Frame Address) described in DWARF is + called the Virtual Frame Pointer on MIPS/SGI machines. + + The DW_FRAME* names here are MIPS/SGI specific. + Libdwarf interfaces defined in 2008 make the + frame definitions here (and the fixed table sizes + they imply) obsolete. They are left here for compatibility. +*/ +/* These identifiers are not defined by any DWARFn standard. */ + +#define DW_FRAME_REG1 1 /* integer reg 1 */ +#define DW_FRAME_REG2 2 /* integer reg 2 */ +#define DW_FRAME_REG3 3 /* integer reg 3 */ +#define DW_FRAME_REG4 4 /* integer reg 4 */ +#define DW_FRAME_REG5 5 /* integer reg 5 */ +#define DW_FRAME_REG6 6 /* integer reg 6 */ +#define DW_FRAME_REG7 7 /* integer reg 7 */ +#define DW_FRAME_REG8 8 /* integer reg 8 */ +#define DW_FRAME_REG9 9 /* integer reg 9 */ +#define DW_FRAME_REG10 10 /* integer reg 10 */ +#define DW_FRAME_REG11 11 /* integer reg 11 */ +#define DW_FRAME_REG12 12 /* integer reg 12 */ +#define DW_FRAME_REG13 13 /* integer reg 13 */ +#define DW_FRAME_REG14 14 /* integer reg 14 */ +#define DW_FRAME_REG15 15 /* integer reg 15 */ +#define DW_FRAME_REG16 16 /* integer reg 16 */ +#define DW_FRAME_REG17 17 /* integer reg 17 */ +#define DW_FRAME_REG18 18 /* integer reg 18 */ +#define DW_FRAME_REG19 19 /* integer reg 19 */ +#define DW_FRAME_REG20 20 /* integer reg 20 */ +#define DW_FRAME_REG21 21 /* integer reg 21 */ +#define DW_FRAME_REG22 22 /* integer reg 22 */ +#define DW_FRAME_REG23 23 /* integer reg 23 */ +#define DW_FRAME_REG24 24 /* integer reg 24 */ +#define DW_FRAME_REG25 25 /* integer reg 25 */ +#define DW_FRAME_REG26 26 /* integer reg 26 */ +#define DW_FRAME_REG27 27 /* integer reg 27 */ +#define DW_FRAME_REG28 28 /* integer reg 28 */ +#define DW_FRAME_REG29 29 /* integer reg 29 */ +#define DW_FRAME_REG30 30 /* integer reg 30 */ +#define DW_FRAME_REG31 31 /* integer reg 31, aka ra */ + + /* MIPS1,2 have only some of these 64-bit registers. + ** MIPS1 save/restore takes 2 instructions per 64-bit reg, and + ** in that case, the register is considered stored after + ** the second swc1. */ +#define DW_FRAME_FREG0 32 /* 64-bit floating point reg 0 */ +#define DW_FRAME_FREG1 33 /* 64-bit floating point reg 1 */ +#define DW_FRAME_FREG2 34 /* 64-bit floating point reg 2 */ +#define DW_FRAME_FREG3 35 /* 64-bit floating point reg 3 */ +#define DW_FRAME_FREG4 36 /* 64-bit floating point reg 4 */ +#define DW_FRAME_FREG5 37 /* 64-bit floating point reg 5 */ +#define DW_FRAME_FREG6 38 /* 64-bit floating point reg 6 */ +#define DW_FRAME_FREG7 39 /* 64-bit floating point reg 7 */ +#define DW_FRAME_FREG8 40 /* 64-bit floating point reg 8 */ +#define DW_FRAME_FREG9 41 /* 64-bit floating point reg 9 */ +#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */ +#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */ +#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */ +#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */ +#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */ +#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */ +#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */ +#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */ +#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */ +#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */ +#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */ +#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */ +#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */ + +#define DW_FRAME_FREG32 64 /* 64-bit floating point reg 32 */ +#define DW_FRAME_FREG33 65 /* 64-bit floating point reg 33 */ +#define DW_FRAME_FREG34 66 /* 64-bit floating point reg 34 */ +#define DW_FRAME_FREG35 67 /* 64-bit floating point reg 35 */ +#define DW_FRAME_FREG36 68 /* 64-bit floating point reg 36 */ +#define DW_FRAME_FREG37 69 /* 64-bit floating point reg 37 */ +#define DW_FRAME_FREG38 70 /* 64-bit floating point reg 38 */ +#define DW_FRAME_FREG39 71 /* 64-bit floating point reg 39 */ +#define DW_FRAME_FREG40 72 /* 64-bit floating point reg 40 */ +#define DW_FRAME_FREG41 73 /* 64-bit floating point reg 41 */ +#define DW_FRAME_FREG42 74 /* 64-bit floating point reg 42 */ +#define DW_FRAME_FREG43 75 /* 64-bit floating point reg 43 */ +#define DW_FRAME_FREG44 76 /* 64-bit floating point reg 44 */ +#define DW_FRAME_FREG45 77 /* 64-bit floating point reg 45 */ +#define DW_FRAME_FREG46 78 /* 64-bit floating point reg 46 */ +#define DW_FRAME_FREG47 79 /* 64-bit floating point reg 47 */ +#define DW_FRAME_FREG48 80 /* 64-bit floating point reg 48 */ +#define DW_FRAME_FREG49 81 /* 64-bit floating point reg 49 */ +#define DW_FRAME_FREG50 82 /* 64-bit floating point reg 50 */ +#define DW_FRAME_FREG51 83 /* 64-bit floating point reg 51 */ +#define DW_FRAME_FREG52 84 /* 64-bit floating point reg 52 */ +#define DW_FRAME_FREG53 85 /* 64-bit floating point reg 53 */ +#define DW_FRAME_FREG54 86 /* 64-bit floating point reg 54 */ +#define DW_FRAME_FREG55 87 /* 64-bit floating point reg 55 */ +#define DW_FRAME_FREG56 88 /* 64-bit floating point reg 56 */ +#define DW_FRAME_FREG57 89 /* 64-bit floating point reg 57 */ +#define DW_FRAME_FREG58 90 /* 64-bit floating point reg 58 */ +#define DW_FRAME_FREG59 91 /* 64-bit floating point reg 59 */ +#define DW_FRAME_FREG60 92 /* 64-bit floating point reg 60 */ +#define DW_FRAME_FREG61 93 /* 64-bit floating point reg 61 */ +#define DW_FRAME_FREG62 94 /* 64-bit floating point reg 62 */ +#define DW_FRAME_FREG63 95 /* 64-bit floating point reg 63 */ +#define DW_FRAME_FREG64 96 /* 64-bit floating point reg 64 */ +#define DW_FRAME_FREG65 97 /* 64-bit floating point reg 65 */ +#define DW_FRAME_FREG66 98 /* 64-bit floating point reg 66 */ +#define DW_FRAME_FREG67 99 /* 64-bit floating point reg 67 */ +#define DW_FRAME_FREG68 100 /* 64-bit floating point reg 68 */ +#define DW_FRAME_FREG69 101 /* 64-bit floating point reg 69 */ +#define DW_FRAME_FREG70 102 /* 64-bit floating point reg 70 */ +#define DW_FRAME_FREG71 103 /* 64-bit floating point reg 71 */ +#define DW_FRAME_FREG72 104 /* 64-bit floating point reg 72 */ +#define DW_FRAME_FREG73 105 /* 64-bit floating point reg 73 */ +#define DW_FRAME_FREG74 106 /* 64-bit floating point reg 74 */ +#define DW_FRAME_FREG75 107 /* 64-bit floating point reg 75 */ +#define DW_FRAME_FREG76 108 /* 64-bit floating point reg 76 */ + +/* Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than + is strictly needed ... is safe. + These values can be changed at runtime by libdwarf. +*/ +#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER +#define DW_FRAME_HIGHEST_NORMAL_REGISTER 188 +#endif +/* This is the number of columns in the Frame Table. +*/ +#ifndef DW_FRAME_LAST_REG_NUM +#define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1) +#endif + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +#ifdef __cplusplus +} +#endif +#endif /* __DWARF_H */ diff --git a/src/lib/libdwarf/dwarf_abbrev.c b/src/lib/libdwarf/dwarf_abbrev.c new file mode 100644 index 0000000..360db8b --- /dev/null +++ b/src/lib/libdwarf/dwarf_abbrev.c @@ -0,0 +1,451 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. +*/ + +#include + +#include /* NULL size_t */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_abbrev.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" + +/* For abbrevs we first count the entries. + Actually recording the attr/form/implicit const + values happens later. */ +int +_dwarf_count_abbrev_entries(Dwarf_Debug dbg, + Dwarf_Byte_Ptr abbrev_ptr, + Dwarf_Byte_Ptr abbrev_section_end, + Dwarf_Unsigned *abbrev_count_out, + Dwarf_Unsigned *abbrev_implicit_const_count_out, + Dwarf_Byte_Ptr *abbrev_ptr_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned abbrev_count = 0; + Dwarf_Unsigned abbrev_implicit_const_count = 0; + Dwarf_Unsigned attr_name = 0; + Dwarf_Unsigned attr_form = 0; + + /* The abbreviations table ends with an entry with a single + byte of zero for the abbreviation code. + Padding bytes following that zero are allowed, but + here we simply stop looking past that zero abbrev. + + We also stop looking if the block/section ends, + though the DWARF2 and later standards do not specifically + allow section/block end to terminate an abbreviations + list. */ + + do { + DECODE_LEB128_UWORD_CK(abbrev_ptr, attr_name, + dbg,error,abbrev_section_end); + if (attr_name > DW_AT_hi_user) { + _dwarf_error(dbg, error,DW_DLE_ATTR_CORRUPT); + return DW_DLV_ERROR; + } + DECODE_LEB128_UWORD_CK(abbrev_ptr, attr_form, + dbg,error,abbrev_section_end); + /* If we have attr, form as 0,0, fall through to end */ + if (!_dwarf_valid_form_we_know(attr_form,attr_name)) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_UNKNOWN_FORM: Abbrev form 0x%" + DW_PR_DUx, + attr_form); + if (attr_name) { + dwarfstring_append_printf_u(&m, + " DW_DLE_UNKNOWN_FORM: Abbrev form 0x%" + DW_PR_DUx, + attr_form); + dwarfstring_append_printf_u(&m, + " with attribute 0x%" DW_PR_DUx, + attr_name); + } else { + dwarfstring_append_printf_u(&m, + " DW_DLE_UNKNOWN_FORM(really unknown attr)" + ": Abbrev form 0x%" + DW_PR_DUx, + attr_form); + dwarfstring_append_printf_u(&m, + " with attribute 0x%" DW_PR_DUx, + attr_name); + } + dwarfstring_append(&m," so abbreviations unusable. "); + _dwarf_error_string(dbg, error, DW_DLE_UNKNOWN_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (attr_form == DW_FORM_implicit_const) { + /* The value is here, not in a DIE. We do + nothing with it, but must read past it. */ + abbrev_implicit_const_count++; + SKIP_LEB128_CK(abbrev_ptr, + dbg,error,abbrev_section_end); + } + abbrev_count++; + } while ((abbrev_ptr < abbrev_section_end) && + (attr_name != 0 || attr_form != 0)); + /* We counted one too high,we included the 0,0 */ + *abbrev_count_out = abbrev_count-1; + *abbrev_implicit_const_count_out = abbrev_implicit_const_count; + *abbrev_ptr_out = abbrev_ptr; + return DW_DLV_OK; +} + +/* dwarf_get_abbrev() is used to print + a .debug_abbrev section without + knowing about the DIEs that use the abbrevs. + + When we have a simple .o + there is at least a hope of iterating through + the abbrevs meaningfully without knowing + a CU context. + + This often fails or gets incorrect info + because there is no guarantee the .debug_abbrev + section is free of garbage bytes. + + In an object with multiple CU/TUs the + output is difficult/impossible to usefully interpret. + + In a dwp (Package File) it is really impossible + to associate abbrevs with a CU. + +*/ + +int +dwarf_get_abbrev(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Abbrev * returned_abbrev, + Dwarf_Unsigned * length, + Dwarf_Unsigned * abbr_count, Dwarf_Error * error) +{ + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr abbrev_ptr_out = 0; + Dwarf_Byte_Ptr abbrev_section_end = 0; + Dwarf_Abbrev ret_abbrev = 0; + Dwarf_Unsigned labbr_count = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Unsigned abbrev_implicit_const_count_out = 0; + int res = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "calling dwarf_get_abbrev " + "either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + + if (dbg->de_debug_abbrev.dss_data == 0) { + /* Loads abbrev section (and .debug_info as we do those + together). */ + res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + + if (offset >= dbg->de_debug_abbrev.dss_size) { + return DW_DLV_NO_ENTRY; + } + ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, + DW_DLA_ABBREV, 1); + if (ret_abbrev == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + ret_abbrev->dab_dbg = dbg; + if (returned_abbrev == 0 || abbr_count == 0) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + _dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + + *abbr_count = 0; + if (length) { + *length = 1; + } + + abbrev_ptr = dbg->de_debug_abbrev.dss_data + offset; + abbrev_section_end = + dbg->de_debug_abbrev.dss_data + dbg->de_debug_abbrev.dss_size; + res = _dwarf_leb128_uword_wrapper(dbg,&abbrev_ptr, + abbrev_section_end,&utmp,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + return res; + } + ret_abbrev->dab_code = utmp; + if (ret_abbrev->dab_code == 0) { + *returned_abbrev = ret_abbrev; + *abbr_count = 0; + if (length) { + *length = 1; + } + return DW_DLV_OK; + } + + res = _dwarf_leb128_uword_wrapper(dbg,&abbrev_ptr, + abbrev_section_end,&utmp,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + return res; + } + if (utmp > DW_TAG_hi_user) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + return _dwarf_format_TAG_err_msg(dbg, + utmp,"DW_DLE_TAG_CORRUPT", + error); + } + ret_abbrev->dab_tag = utmp; + if (abbrev_ptr >= abbrev_section_end) { + dwarfstring m; + + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ABBREV_DECODE_ERROR: Ran off the end " + "of the abbrev section reading tag, starting at" + " abbrev section offset 0x%x",offset); + _dwarf_error_string(dbg, error, + DW_DLE_ABBREV_DECODE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + ret_abbrev->dab_has_child = *(abbrev_ptr++); + ret_abbrev->dab_abbrev_ptr = abbrev_ptr; + ret_abbrev->dab_next_ptr = abbrev_ptr; + ret_abbrev->dab_next_index = 0; + res = _dwarf_count_abbrev_entries(dbg,abbrev_ptr, + abbrev_section_end,&labbr_count, + &abbrev_implicit_const_count_out, + &abbrev_ptr_out,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + return res; + } + abbrev_ptr = abbrev_ptr_out; + + /* Global section offset. */ + ret_abbrev->dab_goffset = offset; + ret_abbrev->dab_count = labbr_count; + ret_abbrev->dab_implicit_count = abbrev_implicit_const_count_out; + if (abbrev_ptr > abbrev_section_end) { + dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); + _dwarf_error_string(dbg, error, + DW_DLE_ABBREV_DECODE_ERROR, + "DW_DLE_ABBREV_DECODE_ERROR: Ran off the end " + "of the abbrev section reading abbrev_entries."); + _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); + return DW_DLV_ERROR; + } + if (length) { + *length = abbrev_ptr - dbg->de_debug_abbrev.dss_data - offset; + } + *returned_abbrev = ret_abbrev; + *abbr_count = labbr_count; + return DW_DLV_OK; +} + +int +dwarf_get_abbrev_code(Dwarf_Abbrev abbrev, + Dwarf_Unsigned * returned_code, + Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + *returned_code = abbrev->dab_code; + return DW_DLV_OK; +} + +/* DWARF defines DW_TAG_hi_user as 0xffff so no tag should be + over 16 bits. */ +int +dwarf_get_abbrev_tag(Dwarf_Abbrev abbrev, + Dwarf_Half * returned_tag, Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + + *returned_tag = (Dwarf_Half)abbrev->dab_tag; + return DW_DLV_OK; +} + +int +dwarf_get_abbrev_children_flag(Dwarf_Abbrev abbrev, + Dwarf_Signed * returned_flag, + Dwarf_Error * error) +{ + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + + *returned_flag = abbrev->dab_has_child; + return DW_DLV_OK; +} + +/* If filter_outliers is non-zero then + the routine will return DW_DLV_ERROR + if the leb reading generates a number that + is so large it cannot be correct. + + If filter_outliers is 0 the uleb/sleb + values read are returned, even if + the values are unreasonable. This is + a useful option if one wishes to + have callers examine the return values + in greater detail than the checking here + provides. +*/ +int +dwarf_get_abbrev_entry_b(Dwarf_Abbrev abbrev, + Dwarf_Unsigned indx, + Dwarf_Bool filter_outliers, + Dwarf_Unsigned * returned_attr_num, + Dwarf_Unsigned * returned_form, + Dwarf_Signed * returned_implicitconst, + Dwarf_Off * offset, + Dwarf_Error * error) +{ + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr abbrev_end = 0; + Dwarf_Byte_Ptr mark_abbrev_ptr = 0; + Dwarf_Unsigned attr = 0; + Dwarf_Unsigned form = 0; + Dwarf_Unsigned implicitconst = 0; + Dwarf_Debug dbg = 0; + Dwarf_Signed local_indx = (Dwarf_Signed)indx; + + if (abbrev == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + if (abbrev->dab_code == 0) { + return DW_DLV_NO_ENTRY; + } + + dbg = abbrev->dab_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "calling dwarf_get_abbrev_entry_b() " + "either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + + abbrev_ptr = abbrev->dab_abbrev_ptr; + abbrev_end = dbg->de_debug_abbrev.dss_data + + dbg->de_debug_abbrev.dss_size; + if ((Dwarf_Unsigned)local_indx >= abbrev->dab_next_index) { + /* We want a part not yet scanned , + so we can start closer to the desired value. */ + abbrev_ptr = abbrev->dab_next_ptr; + local_indx -= abbrev->dab_next_index; + } + + for (attr = 1, form = 1; + local_indx >= 0 && abbrev_ptr < abbrev_end && + (attr != 0 || form != 0); + local_indx--) { + + mark_abbrev_ptr = abbrev_ptr; + DECODE_LEB128_UWORD_CK(abbrev_ptr, attr,dbg, + error,abbrev_end); + if (filter_outliers && attr > DW_AT_hi_user) { + _dwarf_error(dbg, error,DW_DLE_ATTR_CORRUPT); + return DW_DLV_ERROR; + } + DECODE_LEB128_UWORD_CK(abbrev_ptr, form,dbg, + error,abbrev_end); + if (filter_outliers && + !_dwarf_valid_form_we_know(form,attr)) { + _dwarf_error(dbg, error, DW_DLE_UNKNOWN_FORM); + return DW_DLV_ERROR; + } + if (form == DW_FORM_implicit_const) { + /* The value is here, not in a DIE. */ + DECODE_LEB128_SWORD_CK( abbrev_ptr, implicitconst, + dbg,error,abbrev_end); + } else { + implicitconst = 0; + } + } + + if (abbrev_ptr >= abbrev_end) { + _dwarf_error_string(dbg, error, + DW_DLE_ABBREV_DECODE_ERROR, + "DW_DLE_ABBREV_DECODE_ERROR: Ran off the end " + "of the abbrev section reading abbrev entries.."); + return DW_DLV_ERROR; + } + + if (local_indx >= 0) { + return DW_DLV_NO_ENTRY; + } + + if (returned_form != NULL) { + *returned_form = form; + } + if (offset != NULL) { + *offset = mark_abbrev_ptr - dbg->de_debug_abbrev.dss_data; + } + if (returned_attr_num) { + *returned_attr_num = attr; + } + if (returned_implicitconst) { + /* Callers should only examine implicit const value + if the form is DW_FORM_implicit_const. */ + *returned_implicitconst = implicitconst; + } + abbrev->dab_next_ptr = abbrev_ptr; + abbrev->dab_next_index = (Dwarf_Unsigned)local_indx ; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_abbrev.h b/src/lib/libdwarf/dwarf_abbrev.h new file mode 100644 index 0000000..20af595 --- /dev/null +++ b/src/lib/libdwarf/dwarf_abbrev.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. + +*/ + +#ifndef DWARF_ABBREV_H +#define DWARF_ABBREV_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* In a given CU, one of these is (eventually) set up + for every abbreviation we need to find (and for all + those earlier in the abbreviations for that CU). + So we don't want elements needlessly big. +*/ +struct Dwarf_Abbrev_s { + /* No TAG should exceed DW_TAG_hi_user, 0xffff, but + we do allow a larger value here. */ + Dwarf_Unsigned dab_tag; + /* Abbreviations are numbered (normally sequentially from + 1 and so 16 bits is not enough! */ + Dwarf_Unsigned dab_code; + Dwarf_Small dab_has_child; + /* dab_abbrev_ptr points to the abbreviations + themselves in memory, the list of attr/form + integers terminated by 0,0. */ + Dwarf_Byte_Ptr dab_abbrev_ptr; + Dwarf_Debug dab_dbg; + + /* Section global offset of the abbrev. */ + Dwarf_Off dab_goffset; + /* dab_count is the number of attr/form uleb pairs */ + Dwarf_Off dab_count; + /* The number of DW_FORM_implicit_const in the uleb pairs*/ + Dwarf_Unsigned dab_implicit_count; + + /* When the caller cycles through attr/form pairs + by index from zero this lets the code read just one + pair to work. */ + Dwarf_Byte_Ptr dab_next_ptr; + Dwarf_Unsigned dab_next_index; +}; + +int _dwarf_count_abbrev_entries(Dwarf_Debug dbg, + Dwarf_Byte_Ptr abbrev_ptr, + Dwarf_Byte_Ptr abbrev_section_end, + Dwarf_Unsigned *abbrev_count_out, + Dwarf_Unsigned *abbrev_implicit_const_count_out, + Dwarf_Byte_Ptr *abbrev_ptr_out, + Dwarf_Error *error); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_ABBREV_H */ diff --git a/src/lib/libdwarf/dwarf_alloc.c b/src/lib/libdwarf/dwarf_alloc.c new file mode 100644 index 0000000..cb5642f --- /dev/null +++ b/src/lib/libdwarf/dwarf_alloc.c @@ -0,0 +1,1201 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2022 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ +/* To see the full set of DW_DLA types and nothing + else try: + grep DW_DLA dwarf_alloc.c | grep 0x +*/ + +#include + +#include /* fclose() */ +#include /* malloc() free() */ +#include /* memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" +#include "dwarf_alloc.h" +/* These files are included to get the sizes + of structs for malloc. +*/ +#include "dwarf_util.h" +#include "dwarf_line.h" +#include "dwarf_global.h" +#include "dwarf_arange.h" +#include "dwarf_abbrev.h" +#include "dwarf_debugaddr.h" +#include "dwarf_die_deliv.h" +#include "dwarf_frame.h" +#include "dwarf_loc.h" +#include "dwarf_harmless.h" +#include "dwarf_tsearch.h" +#include "dwarf_gdbindex.h" +#include "dwarf_gnu_index.h" +#include "dwarf_xu_index.h" +#include "dwarf_macro5.h" +#include "dwarf_debugnames.h" +#include "dwarf_rnglists.h" +#include "dwarf_dsc.h" +#include "dwarf_string.h" +#include "dwarf_str_offsets.h" + +/* if DEBUG_ALLOC is defined a lot of stdout is generated here. */ +#undef DEBUG_ALLOC +/* Some allocations are simple some not. These reduce + the issue of determining which sort of thing to a simple + test. See ia_multiply_count + Usually when MULTIPLY_NO is set the count + is 1, so MULTIPY_CT would work as well. */ +#define MULTIPLY_NO 0 +#define MULTIPLY_CT 1 +#define MULTIPLY_SP 2 +/* This translates into de_alloc_hdr into a per-instance size + and allows room for a constructor/destructor pointer. + Rearranging the DW_DLA values would break binary compatibility + so that is not an option. +*/ +struct ial_s { + /* In bytes, one struct instance. */ + short ia_struct_size; + + /* Not a count, but a MULTIPLY{_NO,_CT,_SP} value. */ + short ia_multiply_count; + + /* When we really need a constructor/destructor + these make applying such quite simple. */ + int (*specialconstructor) (Dwarf_Debug, void *); + void (*specialdestructor) (void *); +}; + +/* Used as a way to return meaningful errors when + the malloc arena is exhausted (when malloc returns NULL). + Not normally used. + New in December 2014.*/ +struct Dwarf_Error_s _dwarf_failsafe_error = { + DW_DLE_FAILSAFE_ERRVAL, + 0, + 1 +}; + +/* If non-zero (the default) de_alloc_tree (see dwarf_alloc.c) + is used normally. If zero then dwarf allocations + are not tracked by libdwarf and dwarf_finish() cannot + clean up any per-Dwarf_Debug allocations the + caller forgot to dealloc. */ +static signed char global_de_alloc_tree_on = 1; + +/* Defined March 7 2020. Allows a caller to + avoid most tracking by the de_alloc_tree hash + table if called with v of zero. + Returns the value the flag was before this call. */ +int dwarf_set_de_alloc_flag(int v) +{ + int ov = global_de_alloc_tree_on; + global_de_alloc_tree_on = (char)v; + return ov; +} + +void +_dwarf_error_destructor(void *m) +{ + Dwarf_Error er = (Dwarf_Error)m; + dwarfstring *erm = (dwarfstring *)er->er_msg; + if (! erm) { + return; + } +#if DEBUG_ALLOC + printf("libdwarfdetector DEALLOC Now destruct error " + "string %s\n",dwarfstring_string(erm)); +#endif /* DEBUG_ALLOC */ + dwarfstring_destructor(erm); + free(erm); + er->er_msg = 0; + return; +} + +/* To do destructors we need some extra data in every + _dwarf_get_alloc situation. */ +/* Here is the extra we malloc for a prefix. */ +struct reserve_size_s { + void *dummy_rsv1; + void *dummy_rsv2; +}; +/* Here is how we use the extra prefix area. */ +struct reserve_data_s { + void *rd_dbg; + /* rd_length can only record correctly for short + allocations, but that's not a problem im practice + as the value is only for debugging and to + ensure this struct length is correct. */ + unsigned short rd_length; + unsigned short rd_type; +}; +#define DW_RESERVE sizeof(struct reserve_size_s) + +/* In rare cases (bad object files) an error is created + via malloc with no dbg to attach it to. + We do not expect this except on corrupt objects. + + In all cases the user is *supposed* to dealloc + the returned Dwarf_Error, and if it is in case + of a NULL Dwarf_Debug the code were will find it + in this special array and free and zero it. + Hence no leak. +*/ + +#define STATIC_ALLOWED 10 /* arbitrary, must be > 2, see below*/ +static unsigned static_used = 0; +static Dwarf_Error staticerrlist[STATIC_ALLOWED]; + +/* Clean this out if found */ +static void +dw_empty_errlist_item(Dwarf_Error e_in) +{ + unsigned i = 0; + if (!e_in) { + return; + } + for ( ; i er_static_alloc == DE_MALLOC) { + /* e is the returned address, not + the base. Free by the base. */ + void *mallocaddr = 0; + + if ( (uintptr_t)e > DW_RESERVE) { + mallocaddr = (char*)e - DW_RESERVE; + } else { + /* Impossible */ + continue; + } + _dwarf_error_destructor(e); + free(mallocaddr); + } + staticerrlist[i] = 0; + } +} + +/* If the userr calls dwarf_dealloc on an error + out of a dwarf_init*() call, this will find + it in the static err list. Here dbg is NULL + so not mentioned. */ +void +_dwarf_add_to_static_err_list(Dwarf_Error error) +{ + unsigned i = 0; + if (!error) { + return; + } + for ( ; i DW_RESERVE) { + malloc_addr = m - DW_RESERVE; + } else { + /* impossible */ + return; + } + reserve = (struct reserve_data_s *)malloc_addr; + type = reserve->rd_type; + if (type >= ALLOC_AREA_INDEX_TABLE_MAX) { + /* Internal error, corrupted data. */ + return; + } + if (!reserve->rd_dbg) { + /* Unused (corrupted?) node in the tree. + Should never happen. */ + return; + } + if (!reserve->rd_type) { + /* Unused (corrupted?) node in the tree. + Should never happen. */ + return; + } + if (alloc_instance_basics[type].specialdestructor) { + alloc_instance_basics[type].specialdestructor(m); + } + free(malloc_addr); +} + +/* The sort of hash table entries result in very simple + helper functions. */ +static int +simple_compare_function(const void *l, const void *r) +{ + DW_TSHASHTYPE lp = (DW_TSHASHTYPE)(uintptr_t)l; + DW_TSHASHTYPE rp = (DW_TSHASHTYPE)(uintptr_t)r; + if (lp < rp) { + return -1; + } + if (lp > rp) { + return 1; + } + return 0; +} + +/* This function returns a pointer to a region + of memory. For alloc_types that are not + strings or lists of pointers, only 1 struct + can be requested at a time. This is indicated + by an input count of 1. For strings, count + equals the length of the string it will + contain, i.e it the length of the string + plus 1 for the terminating null. For lists + of pointers, count is equal to the number of + pointers. For DW_DLA_FRAME_BLOCK, DW_DLA_RANGES, and + DW_DLA_LOC_BLOCK allocation types also, count + is the count of the number of structs needed. + + This function cannot be used to allocate a + Dwarf_Debug_s struct. */ +/* coverity[+alloc] */ +char * +_dwarf_get_alloc(Dwarf_Debug dbg, + Dwarf_Small alloc_type, Dwarf_Unsigned count) +{ + char * alloc_mem = 0; + Dwarf_Unsigned basesize = 0; + Dwarf_Unsigned size = 0; + unsigned int type = alloc_type; + short action = 0; + + if (dbg == NULL) { +#if DEBUG_ALLOC + printf("libdwarfdetector ALLOC dbg null " + "ret NULL type 0x%x size %lu line %d %s\n", + (unsigned)alloc_type,(unsigned long)size, + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return NULL; + } + if (type >= ALLOC_AREA_INDEX_TABLE_MAX) { + /* internal error */ +#if DEBUG_ALLOC + printf("libdwarfdetector ALLOC type bad ret null " + "ret NULL type 0x%x size %lu line %d %s\n", + (unsigned)alloc_type,(unsigned long)size, + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return NULL; + } + basesize = alloc_instance_basics[alloc_type].ia_struct_size; + action = alloc_instance_basics[alloc_type].ia_multiply_count; + if (action == MULTIPLY_NO) { + /* Usually count is 1, but do not assume it. */ + size = basesize; + } else if (action == MULTIPLY_CT) { + size = basesize * count; + } else { + /* MULTIPLY_SP */ + /* DW_DLA_ADDR.. count * largest size */ + size = count * + (sizeof(Dwarf_Addr) > sizeof(Dwarf_Off) ? + sizeof(Dwarf_Addr) : sizeof(Dwarf_Off)); + } + size += DW_RESERVE; + alloc_mem = malloc(size); + if (!alloc_mem) { + return NULL; + } + { + char * ret_mem = alloc_mem + DW_RESERVE; + void *key = ret_mem; + struct reserve_data_s *r = (struct reserve_data_s*)alloc_mem; + void *result = 0; + + memset(alloc_mem, 0, size); + /* We are not actually using rd_dbg, we are using rd_type. */ + r->rd_dbg = dbg; + r->rd_type = (unsigned short)alloc_type; + /* The following is wrong for large records, but + it's not important, so let it be truncated.*/ + r->rd_length = (unsigned short)size; + if (alloc_instance_basics[type].specialconstructor) { + int res = alloc_instance_basics[type]. + specialconstructor(dbg, ret_mem); + if (res != DW_DLV_OK) { + /* We leak what we allocated in + _dwarf_find_memory when + constructor fails. */ +#if DEBUG_ALLOC + printf("libdwarfdetector ALLOC constructor fails ret NULL " + "type 0x%x size %lu line %d %s\n", + (unsigned)alloc_type,(unsigned long)size,__LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return NULL; + } + } + /* See global flag. + If zero then caller chooses not + to track allocations, so dwarf_finish() + is unable to free anything the caller + omitted to dealloc. Normally + the global flag is non-zero */ + /* As of March 14, 2020 it's + not necessary to test for alloc type, but instead + only call tsearch if de_alloc_tree_on. */ + if (global_de_alloc_tree_on) { + result = dwarf_tsearch((void *)key, + &dbg->de_alloc_tree,simple_compare_function); + if (!result) { + /* Something badly wrong. Out of memory. + pretend all is well. */ + } + } +#if DEBUG_ALLOC + printf("libdwarfdetector ALLOC ret 0x%lx type 0x%x " + "size %lu line %d %s\n", + (unsigned long)ret_mem,(unsigned)alloc_type, + (unsigned long)size,__LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return (ret_mem); + } +} + +/* This was once a long list of tests using dss_data + and dss_size to see if 'space' was inside a debug section. + This tfind approach removes that maintenance headache. */ +static int +string_is_in_debug_section(Dwarf_Debug dbg,void * space) +{ + /* See dwarf_line.c dwarf_srcfiles() + for one way we can wind up with + a DW_DLA_STRING string that may or may not be malloc-ed + by _dwarf_get_alloc(). + + dwarf_formstring(), for example, returns strings + which point into .debug_info or .debug_types but + dwarf_dealloc is never supposed to be applied + to strings dwarf_formstring() returns! + + Lots of calls returning strings + have always been documented as requiring + dwarf_dealloc(...DW_DLA_STRING) when the code + just returns a pointer to a portion of a loaded section! + It is too late to change the documentation. */ + + void *result = 0; + result = dwarf_tfind((void *)space, + &dbg->de_alloc_tree,simple_compare_function); + if (!result) { + /* Not in the tree, so not malloc-ed + Nothing to delete. */ + return TRUE; + } + /* We found the address in the tree, so it is NOT + part of .debug_info or any other dwarf section, + but is space malloc-d in _dwarf_get_alloc(). */ + return FALSE; +} + +/* These wrappers for dwarf_dealloc enable type-checking + at call points. */ +void +dwarf_dealloc_error(Dwarf_Debug dbg, Dwarf_Error err) +{ + dwarf_dealloc(dbg,err,DW_DLA_ERROR); +} +void +dwarf_dealloc_die( Dwarf_Die die) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context context = 0; + + if (!die) { +#ifdef DEBUG_ALLOC + printf("DEALLOC die does nothing, die NULL line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return; + } + context = die->di_cu_context; + if (!context) { +#ifdef DEBUG_ALLOC + printf("DEALLOC die does nothing, context NULL line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return; + } + dbg = context->cc_dbg; + if (!dbg ||dbg->de_magic != DBG_IS_VALID) { + return; + } + dwarf_dealloc(dbg,die,DW_DLA_DIE); +} + +void +dwarf_dealloc_attribute(Dwarf_Attribute attr) +{ + Dwarf_Debug dbg = 0; + + if (!attr) { +#ifdef DEBUG_ALLOC + printf("DEALLOC does nothing, attr is NULL line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC */ + return; + } + dbg = attr->ar_dbg; + dwarf_dealloc(dbg,attr,DW_DLA_ATTR); +} +/* + This function is used to deallocate a region of memory + that was obtained by a call to _dwarf_get_alloc. Note + that though dwarf_dealloc() is a public function, + _dwarf_get_alloc() isn't. + + For lists, typically arrays of pointers, it is assumed + that the space was allocated by a direct call to malloc, + and so a straight free() is done. This is also the case + for variable length blocks such as DW_DLA_FRAME_BLOCK + and DW_DLA_LOC_BLOCK and DW_DLA_RANGES. + + For strings, the pointer might point to a string in + .debug_info or .debug_string. After this is checked, + and if found not to be the case, a free() is done, + again on the assumption that a malloc was used to + obtain the space. + + This function does not return anything. + The _dwarf_error_destructor() will be called + to free the er_msg string + (if this is a Dwarf_Error) just before the + Dwarf_Error is freed here. See...specialdestructor() + below. + +*/ +/* coverity[+free : arg-1] */ +void +dwarf_dealloc(Dwarf_Debug dbg, + Dwarf_Ptr space, Dwarf_Unsigned alloc_type) +{ + unsigned int type = 0; + char * malloc_addr = 0; + struct reserve_data_s * r = 0; + + if (!space) { +#ifdef DEBUG_ALLOC + printf("DEALLOC does nothing, space NULL line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + if (!dbg) { + /* App error, or an app that failed in a + dwarf_init*() or dwarf_elf_init*() call. + + */ + dw_empty_errlist_item(space); +#ifdef DEBUG_ALLOC + printf( "DEALLOC dbg NULL line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + if (space == (Dwarf_Ptr)&_dwarf_failsafe_error) { +#ifdef DEBUG_ALLOC + printf("DEALLOC failsafe requested at 0x%lx. " + "ignore. line %d %s\n", + (unsigned long)space, + __LINE__,__FILE__); + fflush(stdout); + return; +#endif /* DEBUG_ALLOC*/ + } + if (dbg && dbg->de_alloc_tree) { + /* If it's a string in debug_info etc doing + (char *)space - DW_RESERVE is totally bogus. */ + if (alloc_type == DW_DLA_STRING && + string_is_in_debug_section(dbg,space)) { + /* A string pointer may point into .debug_info or + .debug_string etc. + So must not be freed. And strings have + no need of a specialdestructor(). + Mostly a historical mistake here. + Corrected in libdwarf March 14,2020. */ +#ifdef DEBUG_ALLOC + printf( "DEALLOC string in section, no dealloc " + "line %d %s\n", __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + } + /* Otherwise it might be allocated string so it is ok + do the (char *)space - DW_RESERVE */ + + /* If it's a DW_DLA_STRING case and erroneous + the following pointer operations might + result in a coredump if the pointer + is to the beginning of a string section. + If not DW_DLA_STRING + no correctly written caller could coredump + here. */ + if ((uintptr_t)space > DW_RESERVE) { + malloc_addr = (char *)space - DW_RESERVE; + } else { + /* Impossible */ + return; + } + r =(struct reserve_data_s *)malloc_addr; + if (dbg && dbg != r->rd_dbg) { + /* Mixed up or originally a no_dbg alloc */ +#ifdef DEBUG_ALLOC + printf("DEALLOC find was NULL dbg 0x%lx " + "rd_dbg 0x%lx space 0x%lx line %d %s\n", + (unsigned long)dbg, + (unsigned long)r->rd_dbg, + (unsigned long)space, + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + } + if (dbg && alloc_type != r->rd_type) { + /* Something is mixed up. */ +#ifdef DEBUG_ALLOC + printf("DEALLOC does nothing, type 0x%lx rd_type 0x%lx" + " space 0x%lx line %d %s\n", + (unsigned long)alloc_type, + (unsigned long)r->rd_type, + (unsigned long)space, + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + if (alloc_type == DW_DLA_ERROR) { + Dwarf_Error ep = (Dwarf_Error)space; + + if (ep->er_static_alloc == DE_STATIC) { + /* This is special, malloc arena + was exhausted or a NULL dbg + was used for the error because the real + dbg was unavailable. + There is nothing to delete, really. + Set er_errval to signal that the + space was dealloc'd. */ + _dwarf_failsafe_error.er_errval = + DW_DLE_FAILSAFE_ERRVAL; + _dwarf_error_destructor(ep); +#ifdef DEBUG_ALLOC + printf("DEALLOC does nothing, DE_STATIC line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + if (ep->er_static_alloc == DE_MALLOC) { + /* This is special, we had no arena + but have a full special area as normal. */ +#ifdef DEBUG_ALLOC + printf("DEALLOC does free, DE_MALLOC line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + } + /* Was normal alloc, use normal dealloc. */ + /* DW_DLA_ERROR has a specialdestructor */ + } + /* alloc types are a defined library-private + set of integers. Less than 256 of them. */ + type = (unsigned int)alloc_type; +#if DEBUG_ALLOC + if (dbg != r->rd_dbg) { + printf("DEALLOC dbg != rd_dbg" + " going ahead line %d %s\n", + __LINE__,__FILE__); + fflush(stdout); + } + printf("libdwarfdetector DEALLOC ret 0x%lx type 0x%x " + "size %lu line %d %s\n", + (unsigned long)space,(unsigned)type, + (unsigned long)r->rd_length,__LINE__,__FILE__); +#endif /* DEBUG_ALLOC*/ + if (type >= ALLOC_AREA_INDEX_TABLE_MAX) { + /* internal or user app error */ +#ifdef DEBUG_ALLOC + printf("DEALLOC does nothing, type too big %lu line %d %s\n", + (unsigned long)type, + __LINE__,__FILE__); + fflush(stdout); +#endif /* DEBUG_ALLOC*/ + return; + } + if (alloc_instance_basics[type].specialdestructor) { + alloc_instance_basics[type].specialdestructor(space); + } + if (dbg && dbg->de_alloc_tree) { + /* The 'space' pointer we get points after the + reserve space. The key is 'space' + and address to free + is just a few bytes before 'space'. */ + void *key = space; + + dwarf_tdelete(key,&dbg->de_alloc_tree, + simple_compare_function); + /* If dwarf_tdelete returns NULL it might mean + a) tree is empty. + b) If hashsearch, then a single chain might + now be empty, + so we do not know of a 'parent node'. + c) We did not find that key, we did nothing. + + In any case, we simply don't worry about it. + Not Supposed To Happen. */ + } + r->rd_dbg = (void *)(uintptr_t)0xfeadbeef; + r->rd_length = 0; + r->rd_type = 0; + free(malloc_addr); + return; +} + +/* + Allocates space for a Dwarf_Debug_s struct, + since one does not exist. +*/ +Dwarf_Debug +_dwarf_get_debug(Dwarf_Unsigned filesize) +{ + Dwarf_Debug dbg; + + dbg = (Dwarf_Debug) malloc(sizeof(struct Dwarf_Debug_s)); + if (dbg == NULL) { + return NULL; + } + memset(dbg, 0, sizeof(struct Dwarf_Debug_s)); + /* Set up for a dwarf_tsearch hash table */ + dbg->de_magic = DBG_IS_VALID; + + if (global_de_alloc_tree_on) { + /* The type of the dwarf_initialize_search_hash + initial-size argument */ + unsigned long size_est = (unsigned long)(filesize/30); + +#ifdef TESTINGHASHTAB + printf("debugging: src filesize %lu hashtab init %lu\n", + (unsigned long)filesize,size_est); +#endif + dwarf_initialize_search_hash(&dbg->de_alloc_tree, + simple_value_hashfunc,size_est); + } + return dbg; +} + +/* In the 'rela' relocation case or in case + of compressed sections we might have malloc'd + space (to ensure it is read-write or to decompress it + respectively, or both). In that case, free the space. */ +static void +malloc_section_free(struct Dwarf_Section_s * sec) +{ + if (sec->dss_data_was_malloc) { + free(sec->dss_data); + } + sec->dss_data = 0; + sec->dss_data_was_malloc = 0; +} + +static void +freecontextlist(Dwarf_Debug dbg, Dwarf_Debug_InfoTypes dis) +{ + Dwarf_CU_Context context = 0; + Dwarf_CU_Context nextcontext = 0; + for (context = dis->de_cu_context_list; + context; context = nextcontext) { + Dwarf_Hash_Table hash_table = 0; + + hash_table = context->cc_abbrev_hash_table; + + _dwarf_free_abbrev_hash_table_contents(hash_table, + FALSE); + hash_table->tb_entries = 0; + nextcontext = context->cc_next; + context->cc_next = 0; + /* See also local_dealloc_cu_context() in + dwarf_die_deliv.c */ + free(hash_table); + context->cc_abbrev_hash_table = 0; + dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT); + } + dis->de_cu_context_list = 0; +} + +/* + Used to free all space allocated for this Dwarf_Debug. + The caller should assume that the Dwarf_Debug pointer + itself is no longer valid upon return from this function. + + NEVER returns DW_DLV_ERROR. + + In case of difficulty, this function simply returns quietly. +*/ +int +_dwarf_free_all_of_one_debug(Dwarf_Debug dbg) +{ + unsigned g = 0; + + if (dbg == NULL) { + _dwarf_free_static_errlist(); + return DW_DLV_NO_ENTRY; + } + if (dbg->de_magic != DBG_IS_VALID) { + _dwarf_free_static_errlist(); + return DW_DLV_NO_ENTRY; + } + /* To do complete validation that we have no surprising + missing or erroneous deallocs it is advisable to do + the dwarf_deallocs here + that are not things the user can otherwise request. + Housecleaning. */ + if (dbg->de_cu_hashindex_data) { + dwarf_dealloc_xu_header(dbg->de_cu_hashindex_data); + dbg->de_cu_hashindex_data = 0; + } + if (dbg->de_tu_hashindex_data) { + dwarf_dealloc_xu_header(dbg->de_tu_hashindex_data); + dbg->de_tu_hashindex_data = 0; + } + if (dbg->de_printf_callback_null_device_handle) { + fclose(dbg->de_printf_callback_null_device_handle); + dbg->de_printf_callback_null_device_handle = 0; + } + freecontextlist(dbg,&dbg->de_info_reading); + freecontextlist(dbg,&dbg->de_types_reading); + /* Housecleaning done. Now really free all the space. */ + malloc_section_free(&dbg->de_debug_info); + malloc_section_free(&dbg->de_debug_types); + malloc_section_free(&dbg->de_debug_abbrev); + malloc_section_free(&dbg->de_debug_line); + malloc_section_free(&dbg->de_debug_line_str); + malloc_section_free(&dbg->de_debug_loc); + malloc_section_free(&dbg->de_debug_aranges); + malloc_section_free(&dbg->de_debug_macinfo); + malloc_section_free(&dbg->de_debug_macro); + malloc_section_free(&dbg->de_debug_names); + malloc_section_free(&dbg->de_debug_pubnames); + malloc_section_free(&dbg->de_debug_str); + malloc_section_free(&dbg->de_debug_sup); + malloc_section_free(&dbg->de_debug_frame); + malloc_section_free(&dbg->de_debug_frame_eh_gnu); + malloc_section_free(&dbg->de_debug_pubtypes); + malloc_section_free(&dbg->de_debug_funcnames); + malloc_section_free(&dbg->de_debug_typenames); + malloc_section_free(&dbg->de_debug_varnames); + malloc_section_free(&dbg->de_debug_weaknames); + malloc_section_free(&dbg->de_debug_ranges); + malloc_section_free(&dbg->de_debug_str_offsets); + malloc_section_free(&dbg->de_debug_addr); + malloc_section_free(&dbg->de_debug_gdbindex); + malloc_section_free(&dbg->de_debug_cu_index); + malloc_section_free(&dbg->de_debug_tu_index); + malloc_section_free(&dbg->de_debug_loclists); + malloc_section_free(&dbg->de_debug_rnglists); + malloc_section_free(&dbg->de_gnu_debuglink); + malloc_section_free(&dbg->de_note_gnu_buildid); + _dwarf_harmless_cleanout(&dbg->de_harmless_errors); + + _dwarf_dealloc_rnglists_context(dbg); + _dwarf_dealloc_loclists_context(dbg); + if (dbg->de_printf_callback.dp_buffer && + !dbg->de_printf_callback.dp_buffer_user_provided ) { + free(dbg->de_printf_callback.dp_buffer); + } + + _dwarf_destroy_group_map(dbg); + /* de_alloc_tree might be NULL if + global_de_alloc_tree_on is zero. */ + if (dbg->de_alloc_tree) { + dbg->de_in_tdestroy = TRUE; + dwarf_tdestroy(dbg->de_alloc_tree,tdestroy_free_node); + dbg->de_in_tdestroy = FALSE; + dbg->de_alloc_tree = 0; + } + _dwarf_free_static_errlist(); + /* first, walk the search and free() + contents. */ + /* Now do the search tree itself */ + if (dbg->de_tied_data.td_tied_search) { + dwarf_tdestroy(dbg->de_tied_data.td_tied_search, + _dwarf_tied_destroy_free_node); + dbg->de_tied_data.td_tied_search = 0; + } + free((void *)dbg->de_path); + dbg->de_path = 0; + for (g = 0; g < dbg->de_gnu_global_path_count; ++g) { + free((char *)dbg->de_gnu_global_paths[g]); + dbg->de_gnu_global_paths[g] = 0; + } + free((void*)dbg->de_gnu_global_paths); + dbg->de_gnu_global_paths = 0; + dbg->de_gnu_global_path_count = 0; + memset(dbg, 0, sizeof(*dbg)); /* Prevent accidental use later. */ + free(dbg); + return DW_DLV_OK; +} +/* A special case: we have no dbg, no alloc header etc. + So create something out of thin air that we can recognize + in dwarf_dealloc. + Something with the prefix (prefix space hidden from caller). + + Only applies to DW_DLA_ERROR, and making up an error record. + + dwarf_error.c calls this and it adds to the staticerrlist + all of which is freed by free_static_errlist(); +*/ +struct Dwarf_Error_s * +_dwarf_special_no_dbg_error_malloc(void) +{ + Dwarf_Error e = 0; + Dwarf_Unsigned len = 0; + struct reserve_data_s *base = 0; + char *mem = 0; + + len = sizeof(struct Dwarf_Error_s) + DW_RESERVE; + mem = (char *)malloc((size_t)len); + if (!mem) { + return 0; + } + memset(mem, 0, len); + base = (struct reserve_data_s *)mem; + base->rd_dbg = 0; + base->rd_length = (unsigned short)sizeof(struct Dwarf_Error_s); + base->rd_type = DW_DLA_ERROR; + e = (Dwarf_Error)(mem+DW_RESERVE); + e->er_static_alloc = DE_MALLOC; + return e; +} diff --git a/src/lib/libdwarf/dwarf_alloc.h b/src/lib/libdwarf/dwarf_alloc.h new file mode 100644 index 0000000..ac22cf5 --- /dev/null +++ b/src/lib/libdwarf/dwarf_alloc.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. +*/ + +#ifndef DWARF_ALLOC_H +#define DWARF_ALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* #define DWARF_SIMPLE_MALLOC 1 */ + +char * _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned); +Dwarf_Debug _dwarf_get_debug(Dwarf_Unsigned filesize); +int _dwarf_free_all_of_one_debug(Dwarf_Debug); +struct Dwarf_Error_s * _dwarf_special_no_dbg_error_malloc(void); + +void _dwarf_error_destructor(void *); + +/* ALLOC_AREA_INDEX_TABLE_MAX is the size of the + struct ial_s index_into_allocated array in dwarf_alloc.c +*/ +#define ALLOC_AREA_INDEX_TABLE_MAX 66 + +void _dwarf_add_to_static_err_list(Dwarf_Error err); +void _dwarf_flush_static_error_list(void); +void _dwarf_free_static_errlist(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_ALLOC_H */ diff --git a/src/lib/libdwarf/dwarf_arange.c b/src/lib/libdwarf/dwarf_arange.c new file mode 100644 index 0000000..5e49ba5 --- /dev/null +++ b/src/lib/libdwarf/dwarf_arange.c @@ -0,0 +1,738 @@ +/* + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* NULL size_t */ +#include /* debug printf */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_arange.h" +#include "dwarf_global.h" /* for _dwarf_fixup_* */ +#include "dwarf_string.h" + +static void +free_aranges_chain(Dwarf_Debug dbg, Dwarf_Chain head) +{ + Dwarf_Chain cur = head; + Dwarf_Chain next = 0; + + if (!head) { + return; + } + next = head->ch_next; + for ( ;cur; cur = next) { + void *item = cur->ch_item; + int type = cur->ch_itemtype; + + next = cur->ch_next; + if (item && type) { + dwarf_dealloc(dbg,item,type); + cur->ch_item = 0; + dwarf_dealloc(dbg,cur,DW_DLA_CHAIN); + } + } +} + +/* Common code for two user-visible routines to share. + Errors here result in memory leaks, but errors here + are serious (making aranges unusable) so we assume + callers will not repeat the error often or mind the leaks. +*/ +static int +_dwarf_get_aranges_list(Dwarf_Debug dbg, + Dwarf_Chain * chain_out, + Dwarf_Signed * chain_count_out, + Dwarf_Error * error) +{ + /* Sweeps through the arange. */ + Dwarf_Small *arange_ptr = 0; + Dwarf_Small *arange_ptr_start = 0; + + /* Start of arange header. + Used for rounding offset of arange_ptr + to twice the tuple size. Libdwarf requirement. */ + Dwarf_Small *header_ptr = 0; + + /* Version of .debug_aranges header. */ + Dwarf_Unsigned version = 0; + + /* Offset of current set of aranges into .debug_info. */ + Dwarf_Off info_offset = 0; + /* Size in bytes of addresses in target. */ + Dwarf_Small address_size = 0; + /* Size in bytes of segment offsets in target. */ + Dwarf_Small segment_sel_size = 0; + /* Count of total number of aranges. */ + Dwarf_Signed arange_count = 0; + Dwarf_Arange arange = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Byte_Ptr arange_end_section = 0; + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Chain *plast = &head_chain; + + if (!dbg->de_debug_aranges.dss_size) { + return DW_DLV_NO_ENTRY; + } + arange_ptr = dbg->de_debug_aranges.dss_data; + arange_ptr_start = arange_ptr; + section_size = dbg->de_debug_aranges.dss_size; + arange_end_section = arange_ptr + section_size; + + do { + /* Length of current set of aranges. + This is local length, which begins just + after the length field itself. */ + Dwarf_Unsigned area_length = 0; + Dwarf_Unsigned remainder = 0; + Dwarf_Unsigned range_entry_size = 0; + int local_length_size; + int local_extension_size = 0; + Dwarf_Small *end_this_arange = 0; + int res = 0; + + header_ptr = arange_ptr; + if (header_ptr >= arange_end_section) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + res = _dwarf_read_area_length_ck_wrapper(dbg,&area_length, + &arange_ptr,&local_length_size,&local_extension_size, + section_size,arange_end_section,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + /* arange_ptr has been incremented appropriately past + the length field by READ_AREA_LENGTH. */ + + if (area_length > dbg->de_debug_aranges.dss_size || + (area_length +local_length_size+local_extension_size) + > dbg->de_debug_aranges.dss_size ) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + if ((area_length + local_length_size + local_extension_size) > + dbg->de_debug_aranges.dss_size) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + + end_this_arange = arange_ptr + area_length; + if (end_this_arange > arange_end_section) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error,DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (!area_length) { + /* We read 4 bytes of zero, so area-length zero. + Keep scanning. First seen Nov 27, 2018 + in GNU-cc in windows dll. */ + continue; + } + + res = _dwarf_read_unaligned_ck_wrapper(dbg,&version, + arange_ptr,DWARF_HALF_SIZE,end_this_arange,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + arange_ptr += DWARF_HALF_SIZE; + if (arange_ptr >= end_this_arange) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (version != DW_ARANGES_VERSION2) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return DW_DLV_ERROR; + } + res = _dwarf_read_unaligned_ck_wrapper(dbg,&info_offset, + arange_ptr,local_length_size,end_this_arange,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + + arange_ptr += local_length_size; + if (arange_ptr >= end_this_arange) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGES_HEADER_ERROR); + return DW_DLV_ERROR; + } + /* This applies to debug_info only, not to debug_types. */ + if (info_offset >= dbg->de_debug_info.dss_size) { + FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset, + "arange info offset.a"); + if (info_offset >= dbg->de_debug_info.dss_size) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); + return DW_DLV_ERROR; + } + } + + address_size = *(Dwarf_Small *) arange_ptr; + if (address_size > sizeof(Dwarf_Addr)) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); + return DW_DLV_ERROR; + } + if (address_size == 0) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ZERO); + return DW_DLV_ERROR; + } + /* It is not an error if the sizes differ. + Unusual, but not an error. */ + arange_ptr = arange_ptr + sizeof(Dwarf_Small); + + /* The following deref means we better + check the pointer for off-end. */ + if (arange_ptr >= end_this_arange) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); + return DW_DLV_ERROR; + } + + /* Even DWARF2 had a segment_sel_size field here, + meaning + size in bytes of a segment selector/descriptor + on the target system. + In reality it is unlikely any non-zero + value will work sensibly for the user. */ + segment_sel_size = *(Dwarf_Small *) arange_ptr; + if (segment_sel_size > 0) { + free_aranges_chain(dbg,head_chain); + _dwarf_error_string(dbg, error, + DW_DLE_SEGMENT_SIZE_BAD, + "DW_DLE_SEGMENT_SIZE_BAD: " + "segment selector size > 0 is not supported"); + return DW_DLV_ERROR; + } + arange_ptr = arange_ptr + sizeof(Dwarf_Small); + /* Code below will check for == end_this_arange + as appropriate. */ + if (arange_ptr > end_this_arange) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); + return DW_DLV_ERROR; + } + range_entry_size = 2*address_size + segment_sel_size; + /* Round arange_ptr offset to next multiple of + address_size. */ + remainder = (Dwarf_Unsigned) ((arange_ptr - header_ptr) % + (range_entry_size)); + if (remainder != 0) { + arange_ptr = arange_ptr + (2 * address_size) - remainder; + } + + do { + Dwarf_Addr range_address = 0; + Dwarf_Unsigned segment_selector = 0; + Dwarf_Unsigned range_length = 0; + /* For segmented address spaces, the first field to + read is a segment selector (new in DWARF4). + The version number DID NOT CHANGE from 2, which + is quite surprising. + Also surprising since the segment_sel_size + was always there + in the table header! */ + /* We want to test cu_version here + and segment_sel_size, but + currently with no way segment_sel_size + can be other than zero. + We just hope no one using + segment_selectors, really. FIXME */ + res = _dwarf_read_unaligned_ck_wrapper(dbg,&range_address, + arange_ptr,address_size,end_this_arange,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + arange_ptr += address_size; + + res = _dwarf_read_unaligned_ck_wrapper(dbg,&range_length, + arange_ptr,address_size,end_this_arange,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + + arange_ptr += address_size; + + { + /* We used to suppress all-zero entries, but + now we return all aranges entries so we show + the entire content. March 31, 2010. */ + + arange = (Dwarf_Arange) + _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); + if (arange == NULL) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + arange->ar_segment_selector = segment_selector; + arange->ar_segment_selector_size = + segment_sel_size; + arange->ar_address = range_address; + arange->ar_length = range_length; + arange->ar_info_offset = info_offset; + arange->ar_dbg = dbg; + arange_count++; + + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + dwarf_dealloc(dbg,arange,DW_DLA_ARANGE); + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + curr_chain->ch_item = arange; + curr_chain->ch_itemtype = DW_DLA_ARANGE; + (*plast) = curr_chain; + plast = &(curr_chain->ch_next); + } + /* The current set of ranges is terminated by + range_address 0 and range_length 0, but that + does not necessarily terminate the ranges for this CU! + There can be multiple sets in that DWARF + does not explicitly forbid multiple sets. + DWARF2,3,4 section 7.20 + We stop short to avoid overrun of the + end of the CU. */ + } while (end_this_arange >= (arange_ptr + range_entry_size)); + + /* A compiler could emit some padding bytes here. dwarf2/3 + (dwarf4 sec 7.20) does not clearly make extra padding + bytes illegal. */ + if (end_this_arange < arange_ptr) { + Dwarf_Unsigned pad_count = arange_ptr - end_this_arange; + Dwarf_Unsigned offset = arange_ptr - arange_ptr_start; + dwarfstring aramsg; + + dwarfstring_constructor(&aramsg); + /* Safe. Length strictly limited. */ + dwarfstring_append_printf_u(&aramsg, + "DW_DLE_ARANGE_LENGTH_BAD." + " 0x%" DW_PR_XZEROS DW_PR_DUx, + pad_count); + dwarfstring_append_printf_u(&aramsg, + " pad bytes at offset 0x%" DW_PR_XZEROS DW_PR_DUx + " in .debug_aranges", + offset); + dwarf_insert_harmless_error(dbg, + dwarfstring_string(&aramsg)); + dwarfstring_destructor(&aramsg); + } + /* For most compilers, arange_ptr == end_this_arange at + this point. But not if there were padding bytes */ + arange_ptr = end_this_arange; + } while (arange_ptr < arange_end_section); + + if (arange_ptr != arange_end_section) { + free_aranges_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR); + return DW_DLV_ERROR; + } + *chain_out = head_chain; + *chain_count_out = arange_count; + return DW_DLV_OK; +} + +/* + This function returns the count of the number of + aranges in the .debug_aranges section. It sets + aranges to point to a block of Dwarf_Arange's + describing the arange's. It returns DW_DLV_ERROR + on error. + + Must be identical in most aspects to + dwarf_get_aranges_addr_offsets! + +*/ +int +dwarf_get_aranges(Dwarf_Debug dbg, + Dwarf_Arange ** aranges, + Dwarf_Signed * returned_count, Dwarf_Error * error) +{ + /* Count of total number of aranges. */ + Dwarf_Signed arange_count = 0; + + Dwarf_Arange *arange_block = 0; + + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Signed i = 0; + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error); + if (res != DW_DLV_OK) { + return res; + } + /* aranges points in to info, so if info needs expanding + we have to load it. */ + res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + + res = _dwarf_get_aranges_list(dbg,&head_chain, + &arange_count,error); + if (res != DW_DLV_OK) { + free_aranges_chain(dbg,head_chain); + return res; + } + + arange_block = (Dwarf_Arange *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count); + if (arange_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + free_aranges_chain(dbg,head_chain); + return DW_DLV_ERROR; + } + + /* See also free_aranges_chain() above */ + curr_chain = head_chain; + for (i = 0; i < arange_count; i++) { + Dwarf_Chain prev = 0; + + /* Copies pointers. No dealloc of ch_item, */ + *(arange_block + i) = curr_chain->ch_item; + curr_chain->ch_item = 0; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + *aranges = arange_block; + *returned_count = (arange_count); + return DW_DLV_OK; +} + +#if 0 +/* + This function returns DW_DLV_OK if it succeeds + and DW_DLV_ERR or DW_DLV_OK otherwise. + count is set to the number of addresses in the + .debug_aranges section. + For each address, the corresponding element in + an array is set to the address itself(aranges) and + the section offset (offsets). + Must be identical in most aspects to + dwarf_get_aranges! +*/ +int +_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg, + Dwarf_Addr ** addrs, + Dwarf_Off ** offsets, + Dwarf_Signed * count, + Dwarf_Error * error) +{ + Dwarf_Signed i = 0; + + /* Used to chain Dwarf_Aranges structs. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain head_chain = NULL; + + Dwarf_Signed arange_count = 0; + Dwarf_Addr *arange_addrs = 0; + Dwarf_Off *arange_offsets = 0; + + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + + if (error != NULL) + *error = NULL; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error); + if (res != DW_DLV_OK) { + return res; + } + /* aranges points in to info, so if info needs expanding + we have to load it. */ + res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_get_aranges_list(dbg,&head_chain, + &arange_count,error); + if (res != DW_DLV_OK) { + return res; + } + arange_addrs = (Dwarf_Addr *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_addrs == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + arange_offsets = (Dwarf_Off *) + _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); + if (arange_offsets == NULL) { + free_aranges_chain(dbg,head_chain); + dwarf_dealloc(dbg,arange_addrs,DW_DLA_ADDR); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + curr_chain = head_chain; + for (i = 0; i < arange_count; i++) { + Dwarf_Arange ar = curr_chain->ch_item; + int itemtype = curr_chain->ch_itemtype; + Dwarf_Chain prev = 0; + + if (!ar) { + arange_addrs[i] = 0; + arange_offsets[i] = 0; + continue; + } + curr_chain->ch_item = 0; + arange_addrs[i] = ar->ar_address; + arange_offsets[i] = ar->ar_info_offset; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + if (itemtype) { + dwarf_dealloc(dbg, ar, itemtype); + } + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + *count = arange_count; + *offsets = arange_offsets; + *addrs = arange_addrs; + return DW_DLV_OK; +} +#endif /* 0 */ + +/* + This function takes a pointer to a block + of Dwarf_Arange's, and a count of the + length of the block. It checks if the + given address is within the range of an + address range in the block. If yes, it + returns the appropriate Dwarf_Arange. + If no, it returns DW_DLV_NO_ENTRY; + On error it returns DW_DLV_ERROR. +*/ +int +dwarf_get_arange(Dwarf_Arange * aranges, + Dwarf_Unsigned arange_count, + Dwarf_Addr address, + Dwarf_Arange * returned_arange, Dwarf_Error * error) +{ + Dwarf_Arange curr_arange = 0; + Dwarf_Unsigned i = 0; + + if (!aranges) { + _dwarf_error(NULL, error, DW_DLE_ARANGES_NULL); + return DW_DLV_ERROR; + } + for (i = 0; i < arange_count; i++) { + curr_arange = *(aranges + i); + if (address >= curr_arange->ar_address && + address < + curr_arange->ar_address + curr_arange->ar_length) { + *returned_arange = curr_arange; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +/* + This function takes an Dwarf_Arange, + and returns the offset of the first + die in the compilation-unit that the + arange belongs to. Returns DW_DLV_ERROR + on error. + + For an arange, the cu_die can only be from debug_info, + not debug_types, it seems. +*/ +int +dwarf_get_cu_die_offset(Dwarf_Arange arange, + Dwarf_Off * returned_offset, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Off offset = 0; + Dwarf_Unsigned headerlen = 0; + int cres = 0; + + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return DW_DLV_ERROR; + } + dbg = arange->ar_dbg; + offset = arange->ar_info_offset; + /* This applies to debug_info only, not to debug_types. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + } + cres = _dwarf_length_of_cu_header(dbg, offset, + true, &headerlen,error); + if (cres != DW_DLV_OK) { + return cres; + } + *returned_offset = headerlen + offset; + return DW_DLV_OK; +} + +/* This function takes an Dwarf_Arange, + and returns the offset of the CU header + in the compilation-unit that the + arange belongs to. Returns DW_DLV_ERROR + on error. + Ensures .debug_info loaded so + the cu_offset is meaningful. */ +int +dwarf_get_arange_cu_header_offset(Dwarf_Arange arange, + Dwarf_Off * cu_header_offset_returned, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return DW_DLV_ERROR; + } + dbg = arange->ar_dbg; + /* This applies to debug_info only, not to debug_types. */ + /* Like dwarf_get_arange_info_b() this ensures debug_info loaded: + the cu_header is in debug_info and will be used else + we would not call dwarf_get_arange_cu_header_offset. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + *cu_header_offset_returned = arange->ar_info_offset; + return DW_DLV_OK; +} + +/* + This function takes a Dwarf_Arange, and returns + true if it is not NULL. It also stores the start + address of the range in *start, the length of the + range in *length, and the offset of the first die + in the compilation-unit in *cu_die_offset. It + returns false on error. + If cu_die_offset returned ensures .debug_info loaded so + the cu_die_offset is meaningful. + + New for DWARF4, entries may have segment information. + *segment is only meaningful + if *segment_entry_size is non-zero. + But segment_selectors are not fully defined so + a non-zero segment_entry_size is not actually + usable. */ +int +dwarf_get_arange_info_b(Dwarf_Arange arange, + Dwarf_Unsigned* segment, + Dwarf_Unsigned* segment_entry_size, + Dwarf_Addr * start, + Dwarf_Unsigned* length, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) +{ + if (arange == NULL) { + _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); + return DW_DLV_ERROR; + } + + if (segment != NULL) { + *segment = arange->ar_segment_selector; + } + if (segment_entry_size != NULL) { + *segment_entry_size = arange->ar_segment_selector_size; + } + if (start != NULL) + *start = arange->ar_address; + if (length != NULL) + *length = arange->ar_length; + if (cu_die_offset != NULL) { + Dwarf_Debug dbg = arange->ar_dbg; + Dwarf_Off offset = arange->ar_info_offset; + Dwarf_Unsigned headerlen = 0; + int cres = 0; + + /* This applies to debug_info only, not to debug_types. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + if (res != DW_DLV_OK) { + return res; + } + } + cres = _dwarf_length_of_cu_header(dbg, offset, + true, &headerlen,error); + if (cres != DW_DLV_OK) { + return cres; + } + *cu_die_offset = offset + headerlen; + + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_arange.h b/src/lib/libdwarf/dwarf_arange.h new file mode 100644 index 0000000..1ca7579 --- /dev/null +++ b/src/lib/libdwarf/dwarf_arange.h @@ -0,0 +1,60 @@ +/* + +Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2011-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* This structure is used to read an arange into. */ +struct Dwarf_Arange_s { + + /* The segment selector. Only non-zero if Dwarf4, only + meaningful if ar_segment_selector_size non-zero */ + Dwarf_Unsigned ar_segment_selector; + + /* Starting address of the arange, ie low-pc. */ + Dwarf_Addr ar_address; + + /* Length of the arange. */ + Dwarf_Unsigned ar_length; + + /* Offset into .debug_info of the start of the compilation-unit + containing this set of aranges. + Applies only to .debug_info, not .debug_types. */ + Dwarf_Off ar_info_offset; + + /* Corresponding Dwarf_Debug. */ + Dwarf_Debug ar_dbg; + + Dwarf_Half ar_segment_selector_size; +}; + +int +_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg, + Dwarf_Addr ** addrs, + Dwarf_Off ** offsets, + Dwarf_Signed * count, + Dwarf_Error * error); diff --git a/src/lib/libdwarf/dwarf_base_types.h b/src/lib/libdwarf/dwarf_base_types.h new file mode 100644 index 0000000..89a38eb --- /dev/null +++ b/src/lib/libdwarf/dwarf_base_types.h @@ -0,0 +1,137 @@ +/* + +Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2008-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#ifndef DWARF_BASE_TYPES_H +#define DWARF_BASE_TYPES_H + +#define true 1 +#define false 0 + +/* .debug_addr new in DWARF5 */ +#define DW_ADDR_VERSION5 5 + +/* To identify a cie. That is, for .debug_frame */ +#define DW_CIE_ID ~(0x0) +#define DW_CIE_VERSION 1 /* DWARF2 */ +#define DW_CIE_VERSION3 3 /* DWARF3 */ +#define DW_CIE_VERSION4 4 /* DWARF4 */ +#define DW_CIE_VERSION5 5 /* DWARF5 */ + +/* For .debug_info DWARF2,3,4,5. + .debug_types in DWARF4 only, and gets DW_CU_VERSION4. */ +#define DW_CU_VERSION2 2 +#define DW_CU_VERSION3 3 +#define DW_CU_VERSION4 4 +#define DW_CU_VERSION5 5 + +/* For .debug_macro: DWARF 4 (extension) or DWARF5 */ +#define DW_MACRO_VERSION4 4 +#define DW_MACRO_VERSION5 5 + +/* DWARF2,3, 4 and 5.*/ +#define DW_ARANGES_VERSION2 2 + +#define DW_LINE_VERSION2 2 +#define DW_LINE_VERSION3 3 +#define DW_LINE_VERSION4 4 +#define DW_LINE_VERSION5 5 + +/* .debug_line_str (and .dwo) new in DWARF5. */ +#define DW_LINE_STR_VERSION5 5 + +/* Experimental two-level line tables */ +#define EXPERIMENTAL_LINE_TABLES_VERSION 0xf006 + +/* .debug_loc (and .dwo) First header version number is DWARF5. */ +#define DW_LOC_VERSION5 5 + +/* .debug_names new in DWARF5. */ +#define DW_NAMES_VERSION5 5 + +/* .debug_pubnames in DWARF2,3,4. */ +#define DW_PUBNAMES_VERSION2 2 +/* .debug_pubnames in DWARF3,4. */ +#define DW_PUBTYPES_VERSION2 2 + +/* .debug_ranges gets a version number in header in DWARF5. */ +#define DW_RANGES_VERSION5 5 + +/* .debug_str_offsets (and .dwo) new in DWARF5. */ +#define DW_STR_OFFSETS_VERSION5 5 +#define DW_STR_OFFSETS_VERSION4 4 /* GNU extension in DW4 */ + +/* .debug_sup new in DWARF5. */ +#define DW_SUP_VERSION5 5 + +/* .debug_cu_index new in DWARF5. */ +#define DW_CU_INDEX_VERSION5 5 +/* .debug_tu_index new in DWARF5. */ +#define DW_TU_INDEX_VERSION5 5 + +/* These are allocation type codes for structs that + are internal to the Libdwarf Consumer library. */ +#define DW_DLA_ABBREV_LIST 0x1e +#define DW_DLA_CHAIN 0x1f +#define DW_DLA_CU_CONTEXT 0x20 +#define DW_DLA_FRAME 0x21 +#define DW_DLA_GLOBAL_CONTEXT 0x22 +#define DW_DLA_FILE_ENTRY 0x23 +#define DW_DLA_LINE_CONTEXT 0x24 +#define DW_DLA_LOC_CHAIN 0x25 +#define DW_DLA_HASH_TABLE 0x26 +#define DW_DLA_FUNC_CONTEXT 0x27 +#define DW_DLA_TYPENAME_CONTEXT 0x28 +#define DW_DLA_VAR_CONTEXT 0x29 +#define DW_DLA_WEAK_CONTEXT 0x2a +#define DW_DLA_PUBTYPES_CONTEXT 0x2b /* DWARF3 */ +#define DW_DLA_HASH_TABLE_ENTRY 0x2c +#define DW_DLA_FISSION_PERCU 0x2d +#define DW_DLA_CHAIN_2 0x3d +/* Thru 0x36 reserved for internal future use. */ + +/* Maximum number of allocation types for allocation routines. + Only used with malloc_check.c and that is basically obsolete. */ +#define MAX_DW_DLA 0x3a + +typedef signed char Dwarf_Sbyte; +typedef unsigned char Dwarf_Ubyte; +typedef signed short Dwarf_Shalf; +typedef Dwarf_Small *Dwarf_Byte_Ptr; + +#define DWARF_HALF_SIZE 2 +#define DWARF_32BIT_SIZE 4 +#define DWARF_64BIT_SIZE 8 + +typedef struct Dwarf_Abbrev_List_s *Dwarf_Abbrev_List; +typedef struct Dwarf_File_Entry_s *Dwarf_File_Entry; +typedef struct Dwarf_CU_Context_s *Dwarf_CU_Context; +typedef struct Dwarf_Hash_Table_s *Dwarf_Hash_Table; +typedef struct Dwarf_Alloc_Hdr_s *Dwarf_Alloc_Hdr; +#endif /* DWARF_BASE_TYPES_H */ diff --git a/src/lib/libdwarf/dwarf_crc.c b/src/lib/libdwarf/dwarf_crc.c new file mode 100644 index 0000000..537f7ed --- /dev/null +++ b/src/lib/libdwarf/dwarf_crc.c @@ -0,0 +1,137 @@ +/* + Copyright 2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. +*/ + +#include + +#include /* size_t */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" /* For the function prototype */ + +#define uint32_t unsigned int + +/* Table computed by David Anderson + with Mark Adler's table builder + logic on October 20,2020 + with pattern from polynomial (0xedb88320) */ +static const uint32_t crc32_table[256] = +{ +0x00000000,0x77073096,0xee0e612c,0x990951ba, +0x076dc419,0x706af48f,0xe963a535,0x9e6495a3, +0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988, +0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91, +0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de, +0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7, +0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec, +0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5, +0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172, +0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b, +0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940, +0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59, +0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116, +0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f, +0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924, +0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d, +0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a, +0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433, +0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818, +0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01, +0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e, +0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457, +0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c, +0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65, +0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2, +0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb, +0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0, +0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9, +0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086, +0x5768b525,0x206f85b3,0xb966d409,0xce61e49f, +0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4, +0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad, +0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a, +0xead54739,0x9dd277af,0x04db2615,0x73dc1683, +0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8, +0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1, +0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe, +0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7, +0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc, +0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5, +0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252, +0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b, +0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60, +0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79, +0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236, +0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f, +0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04, +0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d, +0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a, +0x9c0906a9,0xeb0e363f,0x72076785,0x05005713, +0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38, +0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21, +0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e, +0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777, +0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c, +0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45, +0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2, +0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db, +0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0, +0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9, +0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6, +0xbad03605,0xcdd70693,0x54de5729,0x23d967bf, +0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94, +0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d +}; + +/* The following is essentially identical + to every crc32 anyone uses up to trivial + differences in starting conditions. + The algorithm appears on + https://en.wikipedia.org/wiki/Cyclic_redundancy_check + in a simple logic loop (written in no actual + language but English) and the following is a translation + into C. Just like every other crc calculation. + + The unsigned int return will not get the same CRC as + Linux/Macos if int/unsigned-int is 16 bits (Windows), + but there the crc does not matter in practice. + The results on big-endian are not the same + as little-endian machines.*/ +unsigned int +dwarf_basic_crc32 (const unsigned char *buf, + unsigned long len, + unsigned int crc) +{ + const unsigned char *end = 0; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/src/lib/libdwarf/dwarf_crc32.c b/src/lib/libdwarf/dwarf_crc32.c new file mode 100644 index 0000000..9aea05a --- /dev/null +++ b/src/lib/libdwarf/dwarf_crc32.c @@ -0,0 +1,153 @@ +/* + Copyright (C) 2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. +*/ + +#include + +#include /* size_t */ +#include /* SEEK_END SEEK_SET */ +#include /* free() malloc() */ +#include /* memcpy() */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* lseek() off_t ssize_t */ +#elif defined HAVE_UNISTD_H +#include /* lseek() off_t */ +#endif /* _WIN32 */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" + +/* Returns DW_DLV_OK DW_DLV_NO_ENTRY or DW_DLV_ERROR + crc32 used for debuglink crc calculation. + Caller passes pointer to an + uninitialized array of 4 unsigned char + and if this returns DW_DLV_OK that is filled in. + The crc is calculated based on reading + the entire current open + Dwarf_Debug dbg object file and all bytes in + the file are read to create the crc. */ +int +dwarf_crc32 (Dwarf_Debug dbg,unsigned char *crcbuf, + Dwarf_Error *error) +{ + /* off_t is signed, defined by POSIX */ + /* ssize_t is signed, defined in POSIX */ + /* size_t is unsigned, defined in C89. */ + off_t size_left = 0; + off_t fsize = 0; + off_t lsval = 0; + /* Named with u to remind the reader that this is + an unsigned value. */ + size_t readlenu = 1000; + unsigned char *readbuf = 0; + unsigned int tcrc = 0; + unsigned int init = 0; + int fd = -1; + + if (!dbg) { + _dwarf_error_string(dbg,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: Bad call to dwarf_crc32"); + return DW_DLV_ERROR; + } + if (!crcbuf) { + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_owns_fd) { + return DW_DLV_NO_ENTRY; + } + fd = dbg->de_fd; + if (fd < 0) { + return DW_DLV_NO_ENTRY; + } + fd = dbg->de_fd; + if (dbg->de_filesize) { + fsize = size_left = (off_t)dbg->de_filesize; + } else { + fsize = size_left = lseek(fd,0L,SEEK_END); + if (fsize == (off_t)-1) { + _dwarf_error_string(dbg,error,DW_DLE_SEEK_ERROR, + "DW_DLE_SEEK_ERROR: dwarf_crc32 seek " + "to end fails"); + return DW_DLV_ERROR; + } + } + if (fsize <= (off_t)500) { + /* Not a real object file. + A random length check. */ + return DW_DLV_NO_ENTRY; + } + lsval = lseek(fd,0L,SEEK_SET); + if (lsval < 0) { + _dwarf_error_string(dbg,error,DW_DLE_SEEK_ERROR, + "DW_DLE_SEEK_ERROR: dwarf_crc32 seek " + "to start fails"); + return DW_DLV_ERROR; + } + readbuf = (unsigned char *)malloc(readlenu); + if (!readbuf) { + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: dwarf_crc32 read buffer" + " alloc fails"); + return DW_DLV_ERROR; + } + while (size_left > 0) { + ssize_t readreturnv = 0; + + if (size_left < (off_t)readlenu) { + readlenu = (size_t)size_left; + } + /* Fix warning on Windows: read()'s + 3rd parameter is a unsigned const */ +#ifdef _WIN32 + readreturnv = read(fd,readbuf,(unsigned const)readlenu); +#else + readreturnv = read(fd,readbuf,readlenu); +#endif + if (readreturnv != (ssize_t)readlenu) { + _dwarf_error_string(dbg,error,DW_DLE_READ_ERROR, + "DW_DLE_READ_ERROR: dwarf_crc32 read fails "); + free(readbuf); + return DW_DLV_ERROR; + } + /* Call the public API function so it gets tested too. */ + tcrc = dwarf_basic_crc32(readbuf,readlenu, + (unsigned long)init); + init = tcrc; + size_left -= (off_t)readlenu; + } + /* endianness issues? */ + free(readbuf); + memcpy(crcbuf,(void *)&tcrc,4); + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_debug_sup.c b/src/lib/libdwarf/dwarf_debug_sup.c new file mode 100644 index 0000000..18086f1 --- /dev/null +++ b/src/lib/libdwarf/dwarf_debug_sup.c @@ -0,0 +1,206 @@ +/* +Copyright (c) 2020, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ + +/* This provides access to the DWARF5 .debug_sup section. */ + +#include + +#include /* strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_global.h" +#include "dwarf_string.h" + +static void +get_sup_fields(Dwarf_Debug dbg, + struct Dwarf_Section_s **sec_out) +{ + if (!dbg) { + return; + } + *sec_out = &dbg->de_debug_sup; +} + +static int +load_sup(Dwarf_Debug dbg, + Dwarf_Error *error) +{ + struct Dwarf_Section_s * sec = 0; + int res; + + get_sup_fields(dbg,&sec); + if (!sec) { + return DW_DLV_NO_ENTRY; + } + res = _dwarf_load_section(dbg,sec,error); + return res; +} + +/* New for DWARF5 in July 2020. */ +int +dwarf_get_debug_sup(Dwarf_Debug dbg, + Dwarf_Half * version_out, + Dwarf_Small * is_supplementary_out, + char ** filename_out, + Dwarf_Unsigned * checksum_len_out, + Dwarf_Small ** checksum_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned version = 0; + Dwarf_Small is_supp = 0; + char *filename = 0; + Dwarf_Unsigned checksum_len = 0; + Dwarf_Small *checksum_ptr = 0; + int res = 0; + Dwarf_Small *data = 0; + Dwarf_Small *enddata = 0; + Dwarf_Unsigned size = 0; + + res = load_sup(dbg,error); + if (res != DW_DLV_OK) { + return res; + } + data = dbg->de_debug_sup.dss_data; + size = dbg->de_debug_sup.dss_size; + if (dbg->de_filesize && size > dbg->de_filesize) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, "DW_DLE_DEBUG_SUP_ERROR: " + ".debug_sup section size 0x%x bigger than file " + "size! Corrupt", + size); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_SUP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + enddata = data + size; + res = _dwarf_read_unaligned_ck_wrapper(dbg, + &version, + data,DWARF_HALF_SIZE, + enddata,error); + if (res != DW_DLV_OK) { + return res; + } + data+= DWARF_HALF_SIZE; + if ((data+4) > enddata) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, "DW_DLE_DEBUG_SUP_ERROR: " + " .debug_sup section size 0x%x" + " too small to be correct! Corrupt", + size); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_SUP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + is_supp = (Dwarf_Small)*data; + ++data; + res = _dwarf_check_string_valid(dbg,data,data,enddata, + DW_DLE_DEBUG_SUP_STRING_ERROR,error); + if (res != DW_DLV_OK) { + return res; + } + filename = (char *)data; + + data += strlen((char *)data) +1; + + res = _dwarf_leb128_uword_wrapper(dbg, &data,enddata, + &checksum_len,error); + if (res != DW_DLV_OK) { + return res; + } + + if (checksum_len >= size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, "DW_DLE_DEBUG_SUP_ERROR: " + " .debug_sup checksum length 0x%x" + " too large to be correct! Corrupt", + checksum_len); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_SUP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if ((data +checksum_len) > enddata) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, "DW_DLE_DEBUG_SUP_ERROR: " + " .debug_sup checksum (length 0x%x) " + " runs off the end of the section, Corrupt data", + checksum_len); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_SUP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + checksum_ptr = data; + if (version_out) { + *version_out = (Dwarf_Half)version; + } + if (is_supp) { + *is_supplementary_out = is_supp; + } + if (filename_out) { + *filename_out = filename; + } + if (checksum_len_out) { + *checksum_len_out = checksum_len; + } + if (checksum_out) { + *checksum_out = checksum_ptr; + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_debugaddr.c b/src/lib/libdwarf/dwarf_debugaddr.c new file mode 100644 index 0000000..0f4c46a --- /dev/null +++ b/src/lib/libdwarf/dwarf_debugaddr.c @@ -0,0 +1,342 @@ +/* +Copyright (C) 2022 David Anderson. All Rights Reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ + +#include + +#include /* NULL size_t */ +#include /* debug printf */ +#include /* memset() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_debugaddr.h" +#include "dwarf_string.h" + +#if 0 +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + int linelim=16; + int lineb = 0; + + printf("dump_bytes: %s %ld starting %p \n",msg,len, + (void *)start); + fflush(stdout); + for (; cur < end; cur++, ++lineb) { + if (lineb == linelim) { + printf("\n"); + lineb = 0; + } + printf("%02x",*cur); + } + printf("\n"); + fflush(stdout); +} +#endif /* 0 */ + +int +dwarf_debug_addr_table(Dwarf_Debug dbg, + Dwarf_Unsigned dw_section_offset, + Dwarf_Debug_Addr_Table *dw_table_header, + Dwarf_Unsigned *dw_length, + Dwarf_Half *dw_version, + Dwarf_Small *dw_address_size, + Dwarf_Unsigned *dw_at_addr_base, + Dwarf_Unsigned *dw_entry_count, + Dwarf_Unsigned *dw_next_table_offset, + Dwarf_Error *error) +{ + int res = 0; + struct Dwarf_Debug_Addr_Table_s tab; + Dwarf_Unsigned section_size = 0; + Dwarf_Small *end_data = 0; + Dwarf_Small *data = 0; + Dwarf_Small *section_start = 0; + Dwarf_Unsigned arealen = 0; + Dwarf_Unsigned tablelen = 0; + int offset_size = 0; + int exten_size = 0; + Dwarf_Small address_size = 0; + Dwarf_Small segment_selector_size = 0; + Dwarf_Half version = 0; + Dwarf_Unsigned curlocaloffset = 0; + Dwarf_Unsigned offset_one_past_end = 0; + /* we will instantiate this below */ + Dwarf_Debug_Addr_Table newad = 0; + + res = _dwarf_load_section(dbg, &dbg->de_debug_addr,error); + if (res == DW_DLV_NO_ENTRY) { + return res; + } + if (res == DW_DLV_ERROR) { + if (error) { + Dwarf_Error e = *error; + + /* Lets append info to the error string! */ + if (e->er_static_alloc != DE_STATIC) { + dwarfstring *em = (dwarfstring*)(e->er_msg); + dwarfstring_append(em, "Unable to open " + ".debug_addr section, serious error"); + } + } + return DW_DLV_ERROR; + } + memset(&tab,0,sizeof(tab)); + tab.da_magic = DW_ADDR_TABLE_MAGIC; + section_size = dbg->de_debug_addr.dss_size; + section_start = dbg->de_debug_addr.dss_data; + end_data = section_start + section_size; + tab.da_section_size = section_size; + if (dw_section_offset >= section_size) { + return DW_DLV_NO_ENTRY; + } + curlocaloffset = 0; + data = section_start + dw_section_offset; + READ_AREA_LENGTH_CK(dbg,arealen,Dwarf_Unsigned, + data,offset_size,exten_size, + error, + section_size,end_data); + if (arealen > section_size || + (arealen + offset_size +exten_size) > section_size) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_SECTION_SIZE_ERROR: A .debug_addr " + "area size of 0x%x ",arealen); + dwarfstring_append_printf_u(&m, + "at offset 0x%x ",dw_section_offset); + dwarfstring_append_printf_u(&m, + "is larger than the entire section size of " + "0x%x. Corrupt DWARF.",section_size); + _dwarf_error_string(dbg,error, + DW_DLE_SECTION_SIZE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + tab.da_dbg = dbg; + tablelen = arealen - 4; /* 4: the rest of the header */ + tab.da_length = tablelen; + curlocaloffset = offset_size + exten_size; + offset_one_past_end = dw_section_offset + + curlocaloffset + 4 /*rest of header */ + + tablelen; + end_data = section_start + offset_one_past_end; + tab.da_end_table = end_data; + READ_UNALIGNED_CK(dbg,version,Dwarf_Half,data, + SIZEOFT16,error,end_data); + if (version != DW_CU_VERSION5) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_VERSION_STAMP_ERROR: " + "The .debug_addr version should be 5 " + "but we find %u instead.",version); + _dwarf_error_string(dbg,error, + DW_DLE_VERSION_STAMP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + tab.da_version = version; + data += SIZEOFT16; + curlocaloffset += SIZEOFT16; + READ_UNALIGNED_CK(dbg,address_size,Dwarf_Small,data, + 1,error,end_data); + if (address_size != 4 && address_size != 8 && + address_size != 2) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_ADDRESS_SIZE_ERROR: The " + " .debug_addr address size " + "of %u is not supported.",address_size); + _dwarf_error_string(dbg,error,DW_DLE_ADDRESS_SIZE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + tab.da_address_size = address_size; + data++; + curlocaloffset++; + + READ_UNALIGNED_CK(dbg,segment_selector_size,Dwarf_Small,data, + 1,error,end_data); + if (segment_selector_size != 0) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append(&m, + " DW_DLE_DEBUG_ADDR_ERROR: The " + " .debug_addr segment selector size " + "of non-zero is not supported."); + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_ADDR_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + /* We do not record segment selector size, + as it is not supported. */ + curlocaloffset++; + data++; + tab.da_data_entries = data; + /* Now we are at the beginning of the actual table */ + { + Dwarf_Unsigned entry_count = 0; + /* Two byte version and two byte flags preceed the + actual table */ + Dwarf_Unsigned table_len_bytes = tab.da_length; + + if (table_len_bytes%(Dwarf_Unsigned)address_size) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_DEBUG_ADDR_ERROR: The " + " .debug_addr address array " + "length of %u not a multiple of " + "address_size.",table_len_bytes); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_ADDR_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + entry_count = table_len_bytes/address_size; + tab.da_entry_count = entry_count; + } + tab.da_table_section_offset = dw_section_offset; + tab.da_addr_base = dw_section_offset + curlocaloffset; + /* Do alloc as late as possible to avoid + any concern about missing a dealloc in + case of error. */ + newad = (Dwarf_Debug_Addr_Table) + _dwarf_get_alloc(dbg,DW_DLA_DEBUG_ADDR,1); + if (!newad) { + _dwarf_error_string(dbg, error, + DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: " + "allocating a Dwarf_Debug_Addr_Table " + "record."); + return DW_DLV_ERROR; + } + /* Copy structure itself */ + *newad = tab; + *dw_table_header = newad; + if (dw_length) { + *dw_length = newad->da_length; + } + if (dw_version) { + *dw_version = newad->da_version; + } + if (dw_address_size) { + *dw_address_size = newad->da_address_size; + } + if (dw_at_addr_base) { + *dw_at_addr_base = newad->da_addr_base; + } + if (dw_entry_count) { + *dw_entry_count = newad->da_entry_count; + } + if (dw_next_table_offset) { + *dw_next_table_offset = offset_one_past_end; + } + return DW_DLV_OK; +} + +int +dwarf_debug_addr_by_index(Dwarf_Debug_Addr_Table dw_dat, + Dwarf_Unsigned dw_entry_index, + Dwarf_Unsigned *dw_address, + Dwarf_Error *dw_error) +{ + Dwarf_Small *data = 0; + Dwarf_Unsigned addr = 0; + + if (!dw_dat) { + _dwarf_error_string(NULL,dw_error, + DW_DLE_DEBUG_ADDR_ERROR, + "DW_DLE_DEBUG_ADDR_ERROR: " + "NULL dw_dat passed in."); + return DW_DLV_ERROR; + } + if (dw_dat->da_magic != DW_ADDR_TABLE_MAGIC) { + _dwarf_error_string(NULL,dw_error, + DW_DLE_DEBUG_ADDR_ERROR, + "DW_DLE_DEBUG_ADDR_ERROR: " + "Bad debug addr table magic number. "); + return DW_DLV_ERROR; + } + if (dw_entry_index >= dw_dat->da_entry_count) { + return DW_DLV_NO_ENTRY; + } + data = dw_dat->da_data_entries+ + dw_dat->da_address_size * dw_entry_index; + if ((data+ dw_dat->da_address_size) > dw_dat->da_end_table) { + _dwarf_error_string(NULL,dw_error, + DW_DLE_DEBUG_ADDR_ERROR, + "DW_DLE_DEBUG_ADDR_ERROR: " + "Bad debug addr table: miscount, too short. "); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dw_dat->da_dbg, + addr,Dwarf_Unsigned, data, + dw_dat->da_address_size,dw_error, + dw_dat->da_end_table); + *dw_address = addr; + return DW_DLV_OK; +} + +void +dwarf_dealloc_debug_addr_table(Dwarf_Debug_Addr_Table dw_dat) +{ + Dwarf_Debug dbg = 0; + if (!dw_dat) { + return; + } + if (dw_dat->da_magic != DW_ADDR_TABLE_MAGIC) { + return; + } + dbg = dw_dat->da_dbg; + dw_dat->da_magic = 0; + dwarf_dealloc(dbg,dw_dat,DW_DLA_DEBUG_ADDR); +} diff --git a/src/lib/libdwarf/dwarf_debugaddr.h b/src/lib/libdwarf/dwarf_debugaddr.h new file mode 100644 index 0000000..3ade4b8 --- /dev/null +++ b/src/lib/libdwarf/dwarf_debugaddr.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 2022-2023 David Anderson. All Rights Reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#ifndef DWARF_DEBUGADDR_H +#define DWARF_DEBUGADDR_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DW_ADDR_TABLE_MAGIC 0xfade + +struct Dwarf_Debug_Addr_Table_s { + Dwarf_Unsigned da_magic; + Dwarf_Debug da_dbg; + /* Length includes the table header and + the length-field of the header and + the array of addresses. */ + Dwarf_Unsigned da_length; + Dwarf_Small da_length_size; /* 4 or 8 */ + Dwarf_Small da_extension_size; /* 4 or 0 */ + Dwarf_Unsigned da_table_section_offset; + + /* Whole section size. >= this table length */ + Dwarf_Unsigned da_section_size ; + + /* pointer to entry[0] */ + Dwarf_Small *da_data_entries; + Dwarf_Unsigned da_entry_count; + /* One past end of this Debug Addr Table */ + Dwarf_Small *da_end_table; + + /* The value appearing in some DW_AT_addr_base: + da_table_section_offset+da_local_offset_entry0. */ + Dwarf_Unsigned da_addr_base; + Dwarf_Half da_version; + Dwarf_Small da_address_size; +#if 0 + /* this is not really handled anywhere by any compiler + so we do not remember it. Must be zero. */ + Dwarf_Small da_segment_selector_size; +#endif +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_DEBUGADDR_H */ diff --git a/src/lib/libdwarf/dwarf_debuglink.c b/src/lib/libdwarf/dwarf_debuglink.c new file mode 100644 index 0000000..708cd7c --- /dev/null +++ b/src/lib/libdwarf/dwarf_debuglink.c @@ -0,0 +1,1085 @@ +/* +Copyright (c) 2019-2021, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ + +#include + +#include /* printf() */ +#include /* free() malloc() */ +#include /* memcpy() memset() strcmp() strdup() strlen() */ +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#if defined _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* getcwd */ +#elif defined HAVE_UNISTD_H +#include /* getcwd */ +#endif /* _WIN32 */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_global.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_debuglink.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ + +#define MINBUFLEN 1000 + +static char joinchar = '/'; +static char* joinstr = "/"; +static char joincharw = '\\'; +/* Large enough it is unlikely dwarfstring will ever + do a malloc here, Windows paths usually < 256 characters. */ +#if defined (_WIN32) +static char winbuf[256]; +#endif /* _WIN32 */ + +static int +is_full_path(char *path) +{ + unsigned char c = path[0]; + unsigned char c1 = 0; + int okdriveletter = FALSE; + + if (!c) { + /* empty string. */ + return FALSE; + } + if (c == joinchar) { + return TRUE; + } + if (c >= 'c' && c <= 'z') { + okdriveletter = TRUE; + } else if (c >= 'C' && c <= 'Z') { + okdriveletter = TRUE; + } + if (!okdriveletter) { + return FALSE; + } + + c1 = path[1]; + if (!c1) { + /* No second character */ + return FALSE; + } + if (c1 == ':') { + /* Windows full path, we assume + We just assume nobody would be silly enough + to name a linux/posix directory starting with "C:" */ + return TRUE; + } + /* No kind of full path name */ + return FALSE; +} + +static int +_dwarf_extract_buildid(Dwarf_Debug dbg, + struct Dwarf_Section_s * pbuildid, + unsigned *type_returned, + char **owner_name_returned, + unsigned char **build_id_returned, + unsigned *build_id_length_returned, + Dwarf_Error *error); + +struct joins_s { + dwarfstring js_dirname; + dwarfstring js_basenamesimple; + dwarfstring js_basesimpledebug; + dwarfstring js_binname; + dwarfstring js_cwd; + dwarfstring js_originalfullpath; + dwarfstring js_linkstring; + dwarfstring js_tmp2; + dwarfstring js_tmp3; + dwarfstring js_buildid; + dwarfstring js_buildid_filename; +}; + +static void +construct_js(struct joins_s * js) +{ + memset(js,0,sizeof(struct joins_s)); + dwarfstring_constructor(&js->js_dirname); + dwarfstring_constructor(&js->js_basenamesimple); + dwarfstring_constructor(&js->js_basesimpledebug); + dwarfstring_constructor(&js->js_cwd); + dwarfstring_constructor(&js->js_originalfullpath); + dwarfstring_constructor(&js->js_linkstring); + dwarfstring_constructor(&js->js_tmp2); + dwarfstring_constructor(&js->js_tmp3); + dwarfstring_constructor(&js->js_buildid); + dwarfstring_constructor(&js->js_buildid_filename); +} +static void +destruct_js(struct joins_s * js) +{ + dwarfstring_destructor(&js->js_dirname); + dwarfstring_destructor(&js->js_basenamesimple); + dwarfstring_destructor(&js->js_basesimpledebug); + dwarfstring_destructor(&js->js_cwd); + dwarfstring_destructor(&js->js_originalfullpath); + dwarfstring_destructor(&js->js_linkstring); + dwarfstring_destructor(&js->js_tmp2); + dwarfstring_destructor(&js->js_tmp3); + dwarfstring_destructor(&js->js_buildid); + dwarfstring_destructor(&js->js_buildid_filename); +} + +/* Altering Windows \ to posix / + which is sort of useful in mingw64 msys2. + Simply assuming no one would use \ in + a file/directory name in posix. */ +static void +transform_to_posix_slash(dwarfstring * out, char *in) +{ + char *cp = in; + int c = 0; + + for (c = *cp ; c ; ++cp,c = *cp) { + if ( *cp == joincharw ) { + dwarfstring_append_length(out,joinstr,1); + } else { + dwarfstring_append_length(out,cp,1); + } + } +} + +/* We change c: or C: to /c for example */ +static void +transform_leading_windowsletter(dwarfstring *out, + char *in) +{ + char *cp = in; + char c = 0; + int isupper = FALSE; + int islower = FALSE; + + if (!cp) { + /* Nothing to do here. */ + return; + } + c = *cp++; + /* Unsure if a, b are normal Windows drive letters. */ + if (c && (c >= 'C') && (c <= 'Z')) { + isupper = TRUE; + } else if (c && (c >= 'c') && (c <= 'z')) { + islower = TRUE; + } + if (isupper || islower) { + int c2 = 0; + + /* ++ here to move past the colon in the input */ + c2 = *cp++; + if (c2 && (c2 == ':')) { + /* Example: Turn uppercase C to c */ + char newstr[4]; + char newletter = c; + + if (isupper) { + char distance = 'a' - 'A'; + newletter = c + distance; + } + newstr[0] = '/'; + newstr[1] = newletter; + newstr[2] = 0; + dwarfstring_append(out,newstr); + } else { + cp = in; + } + } else { + cp = in; + } + transform_to_posix_slash(out,cp); +} + +int +_dwarf_pathjoinl(dwarfstring *target,dwarfstring * input) +{ + char *inputs = dwarfstring_string(input); + char *targ = dwarfstring_string(target); + size_t targlenszt = 0; +#if defined (_WIN32) + /* Assuming we are in mingw msys2 or equivalent. + If we are reading a Windows object file but + running non-Windows this won't happen + but debuglink won't be useful anyway. */ + dwarfstring winput; + + dwarfstring_constructor_static(&winput,winbuf,sizeof(winbuf)); + transform_to_posix_slash(&winput,inputs); + targlenszt = dwarfstring_strlen(target); + inputs = dwarfstring_string(&winput); + if (!targlenszt) { + dwarfstring_append(target,inputs); + return DW_DLV_OK; + } +#else /* !_Windows */ + targlenszt = dwarfstring_strlen(target); +#endif /* _WIN32 */ + + if (!targlenszt) { + dwarfstring_append(target,inputs); + return DW_DLV_OK; + } + targ = dwarfstring_string(target); + if (!is_full_path(targ+targlenszt-1)) { + if (!is_full_path(inputs)) { + dwarfstring_append(target,joinstr); + dwarfstring_append(target,inputs); + } else { + dwarfstring_append(target,inputs); + } + } else { + if (!is_full_path(inputs)) { + dwarfstring_append(target,inputs); + } else { + dwarfstring_append(target,inputs+1); + } + } +#if defined (_WIN32) + dwarfstring_destructor(&winput); +#endif /* _WIN32 */ + return DW_DLV_OK; +} +/* Find the length of the prefix before the final part of the path. + ASSERT: the last character in s is not a / */ +static size_t +mydirlen(char *s) +{ + char *cp = 0; + char *lastjoinchar = 0; + size_t count =0; + + for (cp = s ; *cp ; ++cp,++count) { + if (*cp == joinchar) { + lastjoinchar = cp; + } + } + if (lastjoinchar) { + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned sizetoendjoin = + (lastjoinchar >= s)? + (Dwarf_Unsigned)(uintptr_t)lastjoinchar - + (Dwarf_Unsigned)(uintptr_t)s + :(Dwarf_Unsigned)0xffffffff; + /* count the last join as mydirlen. */ + if (sizetoendjoin == 0xffffffff) { + /* impossible. */ + return 0; + } + return sizetoendjoin; + } + return 0; +} + +struct dwarfstring_list_s { + dwarfstring dl_string; + struct dwarfstring_list_s *dl_next; +}; + +static void +dwarfstring_list_constructor(struct dwarfstring_list_s *l) +{ + dwarfstring_constructor(&l->dl_string); + l->dl_next = 0; +} + +static int +dwarfstring_list_add_new(struct dwarfstring_list_s * base_entry, + struct dwarfstring_list_s *prev, + dwarfstring * input, + struct dwarfstring_list_s ** new_out, + int *errcode) +{ + struct dwarfstring_list_s *next = 0; + + if (prev) { + next = ( struct dwarfstring_list_s *) + malloc(sizeof(struct dwarfstring_list_s)); + if (!next) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + dwarfstring_list_constructor(next); + } else { + next = base_entry; + } + dwarfstring_append(&next->dl_string, + dwarfstring_string(input)); + if (prev) { + prev->dl_next = next; + } + *new_out = next; + return DW_DLV_OK; +} + +/* destructs passed in entry (does not free it) and all + those on the dl_next list (those are freed). */ +static void +dwarfstring_list_destructor(struct dwarfstring_list_s *l) +{ + struct dwarfstring_list_s *curl = l; + struct dwarfstring_list_s *nextl = l; + + nextl = curl->dl_next; + dwarfstring_destructor(&curl->dl_string); + curl->dl_next = 0; + curl = nextl; + for ( ; curl ; curl = nextl) { + nextl = curl->dl_next; + dwarfstring_destructor(&curl->dl_string); + curl->dl_next = 0; + free(curl); + } +} + +static void +prepare_linked_name(dwarfstring *out, + dwarfstring *dirname, + dwarfstring *extradir, + dwarfstring *linkname) +{ + dwarfstring_append(out, dwarfstring_string(dirname)); + if (extradir) { + _dwarf_pathjoinl(out,extradir); + } + _dwarf_pathjoinl(out,linkname); +} + +static void +build_buildid_filename(dwarfstring *target, + unsigned buildid_length, + unsigned char *buildid) +{ + dwarfstring tmp; + unsigned bu = 0; + unsigned char *cp = 0; + + dwarfstring_constructor(&tmp); + dwarfstring_append(&tmp,".build-id"); + dwarfstring_append(&tmp,joinstr); + cp = buildid; + for (bu = 0; bu < buildid_length; ++bu ,++cp) { + dwarfstring_append_printf_u(&tmp, "%02x",*cp); + if (bu == 0) { + dwarfstring_append(&tmp,"/"); + } + } + _dwarf_pathjoinl(target,&tmp); + dwarfstring_append(target,".debug"); + dwarfstring_destructor(&tmp); + return; +} + +#if 0 +static void +dump_bytes(const char *msg,unsigned char * start, unsigned len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* If the compiler or the builder of the object file + being read has made a mistake it is possible + for a constructed name to match the original + file path, yet we do not want to add that to + the search path. */ +static int +duplicatedpath(dwarfstring* l, + dwarfstring*r) +{ + if (strcmp(dwarfstring_string(l), + dwarfstring_string(r))) { + return FALSE; + } + /* Oops. somebody made a mistake */ + return TRUE; +} + +static int +_dwarf_do_debuglink_setup(char *link_string_in, + dwarfstring * link_string_fullpath_out, + char ** global_prefixes_in, + unsigned length_global_prefixes_in, + struct dwarfstring_list_s **last_entry, + struct joins_s *joind, + struct dwarfstring_list_s* base_dwlist, + int *errcode) +{ + int res = 0; + + if (!link_string_in) { + return DW_DLV_OK; + } + { + /* First try dir of executable */ + struct dwarfstring_list_s *now_last = 0; + unsigned global_prefix_number = 0; + + dwarfstring_append(&joind->js_linkstring, + link_string_in); + dwarfstring_reset(&joind->js_tmp3); + dwarfstring_reset(&joind->js_tmp2); + prepare_linked_name(&joind->js_tmp3, + &joind->js_dirname, + 0,&joind->js_linkstring); + dwarfstring_append( + link_string_fullpath_out, + dwarfstring_string(&joind->js_tmp3)); + if (!duplicatedpath(&joind->js_originalfullpath, + &joind->js_tmp3)) { + res = dwarfstring_list_add_new( + base_dwlist, + *last_entry,&joind->js_tmp3, + &now_last,errcode); + if (res != DW_DLV_OK) { + return res; + } + *last_entry = now_last; + } + dwarfstring_reset(&joind->js_tmp2); + dwarfstring_reset(&joind->js_tmp3); + dwarfstring_append(&joind->js_tmp3,".debug"); + prepare_linked_name(&joind->js_tmp2, + &joind->js_dirname, + &joind->js_tmp3,&joind->js_linkstring); + if (! duplicatedpath(&joind->js_originalfullpath, + &joind->js_tmp2)) { + res = dwarfstring_list_add_new( + base_dwlist, + *last_entry,&joind->js_tmp2, + &now_last,errcode); + if (res != DW_DLV_OK) { + return res; + } + *last_entry = now_last; + } else { + } + /* Now look in the global locations. */ + for (global_prefix_number = 0; + global_prefix_number < length_global_prefixes_in; + ++global_prefix_number) { + char * prefix = + global_prefixes_in[global_prefix_number]; + + dwarfstring_reset(&joind->js_tmp2); + dwarfstring_reset(&joind->js_tmp3); + dwarfstring_append(&joind->js_tmp2, prefix); + prepare_linked_name(&joind->js_tmp3, + &joind->js_tmp2, + &joind->js_dirname, + &joind->js_linkstring); + if (!duplicatedpath(&joind->js_originalfullpath, + &joind->js_tmp3)) { + res = dwarfstring_list_add_new( + base_dwlist, + *last_entry,&joind->js_tmp3, + &now_last,errcode); + if (res != DW_DLV_OK) { + return res; + } + *last_entry = now_last; + } else { + } + } + } + return DW_DLV_OK; +} + +static int +_dwarf_do_buildid_setup(unsigned buildid_length, + char ** global_prefixes_in, + unsigned length_global_prefixes_in, + struct dwarfstring_list_s **last_entry, + struct joins_s *joind, + struct dwarfstring_list_s* base_dwlist, + int *errcode) +{ + unsigned global_prefix_number = 0; + int res = 0; + + if (!buildid_length) { + return DW_DLV_OK; + } + for (global_prefix_number = 0; + buildid_length && + (global_prefix_number < length_global_prefixes_in); + ++global_prefix_number) { + char * prefix = 0; + struct dwarfstring_list_s *now_last = 0; + + prefix = global_prefixes_in[global_prefix_number]; + dwarfstring_reset(&joind->js_buildid); + dwarfstring_append(&joind->js_buildid,prefix); + _dwarf_pathjoinl(&joind->js_buildid, + &joind->js_buildid_filename); + res = dwarfstring_list_add_new( + base_dwlist, + *last_entry,&joind->js_buildid, + &now_last,errcode); + if (res != DW_DLV_OK) { + return res; + } + *last_entry = now_last; + } + return DW_DLV_OK; +} + +/* New September 2019. Access to the GNU section named + .gnu_debuglink + See + https://sourceware.org/gdb/onlinedocs/ + gdb/Separate-Debug-Files.html + The default global path was set + to /usr/lib/debug + by set_global_paths_init() + called at libdwarf object init time. + So there is always the default + global path present. + From the above web page: + For the “debug link” method, GDB looks up the named + file in the directory of the executable file, then + in a subdirectory of that directory named .debug, and + finally under each one of the global debug directories, + in a subdirectory whose name is identical to the leading + directories of the executable’s absolute file name. (On + MS-Windows/MS-DOS, the drive letter of the executable’s + leading directories is converted to a one-letter + subdirectory, i.e. d:/usr/bin/ is converted to /d/usr/bin/, + because Windows filesystems disallow colons in file names.) + + For the “build ID” method, GDB looks in the .build-id + subdirectory of each one of the global debug directories + for a file named nn/nnnnnnnn.debug, where nn are the + first 2 hex characters of the build ID bit string, and + nnnnnnnn are the rest of the bit string. (Real build ID + strings are 32 or more hex characters, not 10.) GDB can + automatically query debuginfod servers using build IDs + in order to download separate debug files that cannot be + found locally. +*/ +int +_dwarf_construct_linkedto_path( + char **global_prefixes_in, + unsigned length_global_prefixes_in, + char *pathname_in, + char *link_string_in, /* from debug link */ + dwarfstring *link_string_fullpath_out, + unsigned char *buildid, /* from gnu buildid */ + unsigned buildid_length, /* from gnu buildid */ + char ***paths_out, + unsigned *paths_out_length, + int *errcode) +{ + char * pathname = pathname_in; + int res = 0; + struct joins_s joind; + size_t dirnamelen = 0; + struct dwarfstring_list_s base_dwlist; + struct dwarfstring_list_s *last_entry = 0; + + dwarfstring_list_constructor(&base_dwlist); + construct_js(&joind); + dirnamelen = mydirlen(pathname); + if (dirnamelen) { + /* Original dirname, before cwd (if needed) */ + dwarfstring_append_length(&joind.js_tmp2, + pathname,dirnamelen); + } + if (!is_full_path(pathname)) { + /* Meaning a/b or b, not /a/b or /b , + so we apply cwd */ + char buffer[2000]; + unsigned buflen= sizeof(buffer); + char *wdret = 0; + + buffer[0] = 0; + wdret = getcwd(buffer,buflen); + if (!wdret) { + /* printf("getcwd() issue. Do nothing. " + " line %d %s\n",__LINE__,__FILE__); */ + dwarfstring_list_destructor(&base_dwlist); + destruct_js(&joind); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + dwarfstring_append(&joind.js_cwd,buffer); + } + /* Applies to the leading chars in the named file */ + if (dwarfstring_strlen(&joind.js_tmp2) > 0) { + transform_leading_windowsletter(&joind.js_dirname, + dwarfstring_string(&joind.js_tmp2)); + } + dwarfstring_reset(&joind.js_tmp2); + + /* Creating a real basename. No slashes. */ + dwarfstring_append(&joind.js_basenamesimple, + pathname+dirnamelen); + dwarfstring_append(&joind.js_basesimpledebug, + dwarfstring_string(&joind.js_basenamesimple)); + dwarfstring_append(&joind.js_basesimpledebug,".debug"); + + /* Now js_dirname / js_basenamesimple + are reflecting a full path */ + + /* saves the full path to the original + executable */ + dwarfstring_append(&joind.js_originalfullpath, + dwarfstring_string(&joind.js_dirname)); + _dwarf_pathjoinl(&joind.js_originalfullpath, + &joind.js_basenamesimple); + + build_buildid_filename(&joind.js_buildid_filename, + buildid_length, buildid); + /* The GNU buildid method of finding debug files. + No crc calculation required ever. */ + res = _dwarf_do_buildid_setup(buildid_length, + global_prefixes_in, + length_global_prefixes_in, + &last_entry, + &joind, + &base_dwlist,errcode); + if (res == DW_DLV_ERROR) { + dwarfstring_list_destructor(&base_dwlist); + destruct_js(&joind); + return res; + } + + /* The debug link method of finding debug files. + A crc calculation is required for full + checking. Which can be slow if an object file is large. */ + res = _dwarf_do_debuglink_setup(link_string_in, + link_string_fullpath_out, + global_prefixes_in, + length_global_prefixes_in, + &last_entry, + &joind,&base_dwlist,errcode); + if (res == DW_DLV_ERROR) { + dwarfstring_list_destructor(&base_dwlist); + destruct_js(&joind); + return res; + } + + /* Now malloc space for the pointer array + and the strings they point at so a simple + free by our caller will clean up + everything. Copy the data from + base_dwlist to the new area. */ + { + struct dwarfstring_list_s *cur = 0; + char **resultfullstring = 0; + unsigned long count = 0; + size_t pointerarraysize = 0; + size_t sumstringlengths = 0; + size_t totalareasize = 0; + size_t setptrindex = 0; + size_t setstrindex = 0; + + cur = &base_dwlist; + for ( ; cur ; cur = cur->dl_next) { + ++count; + pointerarraysize += sizeof(void *); + sumstringlengths += + dwarfstring_strlen(&cur->dl_string) +1; + } + /* Make a final null pointer in the pointer array. */ + pointerarraysize += sizeof(void *); + totalareasize = pointerarraysize + sumstringlengths +8; + resultfullstring = (char **)malloc(totalareasize); + setstrindex = pointerarraysize; + if (!resultfullstring) { + dwarfstring_list_destructor(&base_dwlist); + destruct_js(&joind); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + memset(resultfullstring,0,totalareasize); + cur = &base_dwlist; + + for ( ; cur ; cur = cur->dl_next,++setptrindex) { + char **iptr = (char **)((char *)resultfullstring + + setptrindex*sizeof(void *)); + char *sptr = (char*)resultfullstring + setstrindex; + char *msg = dwarfstring_string(&cur->dl_string); + size_t slen = dwarfstring_strlen(&cur->dl_string); + + _dwarf_safe_strcpy(sptr,totalareasize - setstrindex, + msg,slen); + setstrindex += slen +1; + *iptr = sptr; + } + *paths_out = resultfullstring; + *paths_out_length = count; + } + dwarfstring_list_destructor(&base_dwlist); + destruct_js(&joind); + return DW_DLV_OK; +} + +static int +_dwarf_extract_debuglink(Dwarf_Debug dbg, + struct Dwarf_Section_s * pdebuglink, + char ** name_returned, /* static storage, do not free */ + unsigned char ** crc_returned, /* 32bit crc , do not free */ + Dwarf_Error *error) +{ + Dwarf_Small *ptr = 0; + Dwarf_Small *endptr = 0; + size_t namelenszt = 0; + unsigned m = 0; + unsigned incr = 0; + Dwarf_Small *crcptr = 0; + int res = DW_DLV_ERROR; + Dwarf_Unsigned secsize = 0; + + if (!pdebuglink->dss_data) { + return DW_DLV_NO_ENTRY; + } + secsize = pdebuglink->dss_size; + ptr = pdebuglink->dss_data; + endptr = ptr + secsize; + + res = _dwarf_check_string_valid(dbg,ptr, + ptr, endptr, DW_DLE_FORM_STRING_BAD_STRING, + error); + if ( res != DW_DLV_OK) { + return res; + } + namelenszt = strlen((const char*)ptr); + m = (namelenszt+1) %4; + if (m) { + incr = 4 - m; + } + crcptr = (unsigned char *)ptr +namelenszt +1 +incr; + if ((crcptr +4) != (unsigned char*)endptr) { + _dwarf_error(dbg,error,DW_DLE_CORRUPT_GNU_DEBUGLINK); + return DW_DLV_ERROR; + } + *name_returned = (char *)ptr; + *crc_returned = crcptr; + return DW_DLV_OK; +} + +/* The definition of .note.gnu.buildid contents (also + used for other GNU .note.gnu. sections too. */ +struct buildid_s { + char bu_ownernamesize[4]; + char bu_buildidsize[4]; + char bu_type[4]; + char bu_owner[1]; +}; + +static int +_dwarf_extract_buildid(Dwarf_Debug dbg, + struct Dwarf_Section_s * pbuildid, + unsigned * type_returned, + char **owner_name_returned, + unsigned char **build_id_returned, + unsigned * build_id_length_returned, + Dwarf_Error *error) +{ + Dwarf_Small * ptr = 0; + Dwarf_Small * endptr = 0; + int res = DW_DLV_ERROR; + struct buildid_s *bu = 0; + Dwarf_Unsigned namesize = 0; + Dwarf_Unsigned descrsize = 0; + Dwarf_Unsigned type = 0; + Dwarf_Unsigned finalsize; + Dwarf_Unsigned secsize = 0; + + if (!pbuildid->dss_data) { + return DW_DLV_NO_ENTRY; + } + secsize = pbuildid->dss_size; + ptr = pbuildid->dss_data; + if (secsize < sizeof(struct buildid_s)) { + _dwarf_error(dbg,error,DW_DLE_CORRUPT_NOTE_GNU_DEBUGID); + return DW_DLV_ERROR; + } + endptr = ptr + secsize; + /* We hold gh_content till all is closed + as we return pointers into it + if all goes well. */ + bu = (struct buildid_s *)ptr; + ASNAR(dbg->de_copy_word,namesize, bu->bu_ownernamesize); + ASNAR(dbg->de_copy_word,descrsize,bu->bu_buildidsize); + if (descrsize >= secsize) { + _dwarf_error_string(dbg,error, + DW_DLE_BUILD_ID_DESCRIPTION_SIZE, + "DW_DLE_BUILD_ID_DESCRIPTION_SIZE Size is much too " + "large to be correct. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + if ((descrsize+8) >= secsize) { + _dwarf_error_string(dbg,error, + DW_DLE_BUILD_ID_DESCRIPTION_SIZE, + "DW_DLE_BUILD_ID_DESCRIPTION_SIZE Size is too " + "large to be correct. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + if (descrsize >= DW_BUILDID_SANE_SIZE) { + _dwarf_error_string(dbg,error, + DW_DLE_BUILD_ID_DESCRIPTION_SIZE, + "DW_DLE_BUILD_ID_DESCRIPTION_SIZE Size is too " + "large to be sane. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + + ASNAR(dbg->de_copy_word,type, bu->bu_type); + /* descrsize test is no longer appropriate, other lengths + than 20 may exist. --Wl,--build-id= can have + at least one of 'fast', 'md5', 'sha1', 'uuid' or + possibly others so we should not check the length. */ + res = _dwarf_check_string_valid(dbg, + (Dwarf_Small *)&bu->bu_owner[0], + (Dwarf_Small *)&bu->bu_owner[0], + endptr, + DW_DLE_CORRUPT_GNU_DEBUGID_STRING, + error); + if ( res != DW_DLV_OK) { + return res; + } + if ((strlen(bu->bu_owner) +1) != namesize) { + _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_STRING); + return DW_DLV_ERROR; + } + + finalsize = sizeof(struct buildid_s)-1 + namesize + descrsize; + if (finalsize > secsize) { + _dwarf_error(dbg,error, DW_DLE_CORRUPT_GNU_DEBUGID_SIZE); + return DW_DLV_ERROR; + } + *type_returned = (unsigned)type; + *owner_name_returned = &bu->bu_owner[0]; + if (descrsize >= secsize) { /* In case value insanely large */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_CORRUPT_NOTE_GNU_DEBUGID buildid description" + "length %u larger than the section size. " + "Corrupt object section",descrsize); + _dwarf_error_string(dbg,error, + DW_DLE_CORRUPT_GNU_DEBUGID_SIZE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if ((descrsize+8) >= secsize) { /* In case a bit too large */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_CORRUPT_NOTE_GNU_DEBUGID buildid description" + "length %u larger than is appropriate. " + "Corrupt object section",descrsize); + _dwarf_error_string(dbg,error, + DW_DLE_CORRUPT_GNU_DEBUGID_SIZE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *build_id_length_returned = (unsigned)descrsize; + *build_id_returned = (unsigned char *)ptr + + sizeof(struct buildid_s)-1 + namesize; + return DW_DLV_OK; +} + +/* Caller frees space returned by debuglink_fillpath_returned and + The following return pointers into the dbg itself + and are only valid while that dbg is open. + debuglink_path_returned. + crc_returned, buildid_owner_name_returned, + buildid_returned, */ +int +dwarf_gnu_debuglink(Dwarf_Debug dbg, + char ** debuglink_path_returned, /* do not free*/ + unsigned char ** crc_returned, + char ** debuglink_fullpath_returned, /* caller frees */ + unsigned * debuglink_fullpath_length_returned, + + unsigned * buildid_type_returned , + char ** buildid_owner_name_returned, + unsigned char ** buildid_returned, + unsigned * buildid_length_returned, + char *** paths_returned, + unsigned * paths_count_returned, + Dwarf_Error* error) +{ + dwarfstring debuglink_fullpath; + int res = DW_DLV_ERROR; + char * pathname = 0; + int errcode = 0; + struct Dwarf_Section_s * pdebuglink = 0; + struct Dwarf_Section_s * pbuildid = 0; + + if (dbg->de_gnu_debuglink.dss_size) { + pdebuglink = &dbg->de_gnu_debuglink; + res = _dwarf_load_section(dbg, pdebuglink,error); + if (res == DW_DLV_ERROR) { + return res; + } + } + if (dbg->de_note_gnu_buildid.dss_size) { + pbuildid = &dbg->de_note_gnu_buildid; + res = _dwarf_load_section(dbg, pbuildid,error); + if (res == DW_DLV_ERROR) { + return res; + } + } + + if (!pdebuglink && !pbuildid) { + *debuglink_fullpath_returned = strdup(dbg->de_path); + *debuglink_fullpath_length_returned = + (unsigned)strlen(dbg->de_path); + return DW_DLV_OK; + } + + if (pbuildid) { + /* buildid does not involve calculating a crc at any point */ + int buildidres = 0; + buildidres = _dwarf_extract_buildid(dbg, + pbuildid, + buildid_type_returned, + buildid_owner_name_returned, + buildid_returned, + buildid_length_returned, + error); + if (buildidres == DW_DLV_ERROR) { + return buildidres; + } + } + if (pdebuglink) { + int linkres = 0; + + linkres = _dwarf_extract_debuglink(dbg, + pdebuglink, + debuglink_path_returned, + crc_returned, + error); + if (linkres == DW_DLV_ERROR) { + return linkres; + } + } + dwarfstring_constructor(&debuglink_fullpath); + pathname = (char *)dbg->de_path; + if (pathname && paths_returned) { + /* Caller wants paths created and returned. */ + res = _dwarf_construct_linkedto_path( + (char **)dbg->de_gnu_global_paths, + dbg->de_gnu_global_path_count, + pathname, + *debuglink_path_returned, + &debuglink_fullpath, + *buildid_returned, + *buildid_length_returned, + paths_returned, + paths_count_returned, + &errcode); + if (res == DW_DLV_ERROR) { + dwarfstring_destructor(&debuglink_fullpath); + return res; + } + if (dwarfstring_strlen(&debuglink_fullpath)) { + *debuglink_fullpath_returned = + strdup(dwarfstring_string(&debuglink_fullpath)); + *debuglink_fullpath_length_returned = + (unsigned)dwarfstring_strlen(&debuglink_fullpath); + } + } else if (paths_count_returned) { + *paths_count_returned = 0; + } else { + /* nothing special to do */ + } + dwarfstring_destructor(&debuglink_fullpath); + return DW_DLV_OK; +} + +/* This should be rarely called and most likely + only once (at dbg init time from dwarf_generic_init.c, + see set_global_paths_init()). + Maybe once or twice later. +*/ +int +dwarf_add_debuglink_global_path(Dwarf_Debug dbg, + const char *pathname, + Dwarf_Error *error) +{ + unsigned glpath_count_in = 0; + unsigned glpath_count_out = 0; + char **glpaths = 0; + char *path1 = 0; + + glpath_count_in = dbg->de_gnu_global_path_count; + glpath_count_out = glpath_count_in+1; + glpaths = (char **)malloc(sizeof(char *)* + glpath_count_out); + if (!glpaths) { + _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + if (glpath_count_in) { + memcpy(glpaths, dbg->de_gnu_global_paths, + sizeof(char *)*glpath_count_in); + } + path1 = strdup(pathname); + if (!path1) { + free(glpaths); + _dwarf_error(dbg,error,DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + free(dbg->de_gnu_global_paths); + glpaths[glpath_count_in] = path1; + dbg->de_gnu_global_paths = (const char **)glpaths; + dbg->de_gnu_global_path_count = glpath_count_out; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_debuglink.h b/src/lib/libdwarf/dwarf_debuglink.h new file mode 100644 index 0000000..cf71d32 --- /dev/null +++ b/src/lib/libdwarf/dwarf_debuglink.h @@ -0,0 +1,60 @@ +/* +Copyright (c) 2019-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ + +#ifndef DWARF_DEBUGLINK_H +#define DWARF_DEBUGLINK_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define DW_BUILDID_SANE_SIZE (8*1024) + +int _dwarf_pathjoinl(dwarfstring *target,dwarfstring * input); + +int _dwarf_construct_linkedto_path( + char **global_prefixes_in, + unsigned length_global_prefixes_in, + char *pathname_in, + char *link_string_in, /* from debug link */ + dwarfstring *link_string_fullpath, +#if 0 + unsigned char *crc_in, /* from debug_link, 4 bytes */ +#endif + + unsigned char *buildid, /* from gnu buildid */ + unsigned buildid_length, /* from gnu buildid */ + char ***paths_out, + unsigned *paths_out_length, + int *errcode); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_DEBUGLINK_H */ diff --git a/src/lib/libdwarf/dwarf_debugnames.c b/src/lib/libdwarf/dwarf_debugnames.c new file mode 100644 index 0000000..081d3d1 --- /dev/null +++ b/src/lib/libdwarf/dwarf_debugnames.c @@ -0,0 +1,1915 @@ +/* + Portions Copyright (C) 2017-2021 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. +*/ + +/* This provides access to the DWARF5 .debug_names section. */ + +#include + +#include /* calloc() free() */ +#include +#include /* memcpy */ +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_global.h" +#include "dwarf_debugnames.h" +#include "dwarf_string.h" + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s(%ld bytes):",msg,len); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ +#if 0 +static void +dump_abbrev_record(const char *msg, + Dwarf_Unsigned abcode, + struct Dwarf_D_Abbrev_s *abb, + int line) +{ + unsigned long i = 0; + + printf("%s: code %lu abpairs %lu line %d \n", + msg,(unsigned long)abcode, + (unsigned long)abb->da_pairs_count,line); + for (i=0; i < abb->da_pairs_count ; ++i) { + printf(" [%lu] 0x%02lx 0x%02lx\n", + i, + (unsigned long)abb->da_idxattr[i], + (unsigned long)abb->da_form[i]); + } +} +#endif + +/* Encapsulates DECODE_LEB128_UWORD_LEN_CK + so the caller can free resources + in case of problems. + This updates *lp to point to next byte +*/ +static int +_dwarf_read_uleb_ck(Dwarf_Small **lp, + Dwarf_Unsigned *out_p, + Dwarf_Debug dbg, + Dwarf_Error *err, + Dwarf_Small *lpend) +{ + Dwarf_Small *inptr = *lp; + Dwarf_Unsigned abcode = 0; + + /* The macro updates inptr */ + DECODE_LEB128_UWORD_CK(inptr, + abcode,dbg,err,lpend); + *lp = inptr; + *out_p = abcode; + return DW_DLV_OK; +} + +/* Encapsulates DECODE_LEB128_UWORD_CK + so the caller can free resources + in case of problems. */ +static int +read_uword_ab(Dwarf_Small **lp, + Dwarf_Unsigned *out_p, + Dwarf_Debug dbg, + Dwarf_Error *err, + Dwarf_Small *lpend) + +{ + Dwarf_Small *inptr = *lp; + Dwarf_Unsigned out = 0; + + /* The macro updates inptr */ + DECODE_LEB128_UWORD_CK(inptr, + out, dbg,err,lpend); + *lp = inptr; + *out_p = out; + return DW_DLV_OK; +} + +static void +free_temp_abbrevs( struct Dwarf_D_Abbrev_s * firstab) +{ + struct Dwarf_D_Abbrev_s *curab = firstab; + + while (curab) { + struct Dwarf_D_Abbrev_s *nxtab = 0; + + nxtab = curab->da_next; + curab->da_next = 0; + free(curab); + curab = nxtab; + } +} + +static int +fill_in_abbrevs_table(Dwarf_Dnames_Head dn, + Dwarf_Error * error) +{ + Dwarf_Unsigned ablen = dn->dn_abbrev_table_size; + Dwarf_Small *abdata = dn->dn_abbrevs; + Dwarf_Small *tabend = abdata + ablen; + Dwarf_Small *abcur = 0; + Dwarf_Unsigned code = 0; + Dwarf_Unsigned tag = 0; + int foundabend = FALSE; + Dwarf_Unsigned abcount = 0; + struct Dwarf_D_Abbrev_s *curdab = 0; + struct Dwarf_D_Abbrev_s *firstdab = 0; + struct Dwarf_D_Abbrev_s **lastabp = &firstdab; + Dwarf_Debug dbg = dn->dn_dbg; + + for (abcur = abdata; abcur < tabend; ) { + Dwarf_Unsigned attr = 0; + Dwarf_Unsigned form = 0; + Dwarf_Small *inner = 0; + Dwarf_Unsigned inroffset = 0; + int res = 0; + + inroffset = abcur - abdata; + res = read_uword_ab(&abcur,&code,dbg,error,tabend); + if (res != DW_DLV_OK) { + free_temp_abbrevs(firstdab); + return res; + } + if (code == 0) { + foundabend = TRUE; + break; + } + + res = read_uword_ab(&abcur,&tag,dbg,error,tabend); + if (res != DW_DLV_OK) { + free_temp_abbrevs(firstdab); + return res; + } + inner = abcur; + curdab = (struct Dwarf_D_Abbrev_s *)calloc(1, + sizeof(struct Dwarf_D_Abbrev_s)); + if (!curdab) { + free_temp_abbrevs(firstdab); + firstdab = 0; + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + curdab->da_abbrev_offset = inroffset; + curdab->da_abbrev_code = code; + curdab->da_tag = tag; + abcount++; + for (;;) { + res = read_uword_ab(&inner,&attr,dbg,error,tabend); + if (res != DW_DLV_OK) { + free_temp_abbrevs(curdab); + free_temp_abbrevs(firstdab); + firstdab = 0; + return res; + } + res = read_uword_ab(&inner,&form,dbg,error,tabend); + if (res != DW_DLV_OK) { + free_temp_abbrevs(curdab); + free_temp_abbrevs(firstdab); + firstdab = 0; + return res; + } + if ( curdab->da_pairs_count == + ABB_PAIRS_MAX) { + free_temp_abbrevs(curdab); + free_temp_abbrevs(firstdab); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION, + "DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: " + "Impossible: too many idxattr/form pairs" + "corrupt abbrevs"); + return DW_DLV_ERROR; + } + curdab->da_idxattr[curdab->da_pairs_count] = + (Dwarf_Half)attr; + curdab->da_form[curdab->da_pairs_count] = + (Dwarf_Half)form; + curdab->da_pairs_count++; + if (!attr && !form) { + /* We put the terminator into the pairs list. + done for this pair set */ + break; + } + } + + /* Building singly linked list. without if stmt. */ + abcur = inner; + *lastabp = curdab; + lastabp = &curdab->da_next; + } + if (!foundabend) { + free_temp_abbrevs(firstdab); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION, + "DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: Never found" + "abbrev final NUL byte"); + return DW_DLV_ERROR; + } + if ( abcur < tabend) { + unsigned padcount = 0; + + for (; abcur < tabend; ++abcur) { + ++padcount; + if (*abcur) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "WARNING NON NULL debug_names " + "abbreviation pad. " + "padcount %u at ",padcount); + dwarfstring_append_printf_u(&m, + ".debug_names sec_offset 0x%lx", + (uintptr_t)(abcur - dn->dn_section_data)); + dwarf_insert_harmless_error(dbg, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + } + } + { + Dwarf_Unsigned ct = 0; + struct Dwarf_D_Abbrev_s *tmpa = 0; + + dn->dn_abbrev_instances = + (struct Dwarf_D_Abbrev_s *)calloc( + abcount,sizeof(struct Dwarf_D_Abbrev_s)); + if (!dn->dn_abbrev_instances) { + free_temp_abbrevs(firstdab); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + dn->dn_abbrev_instance_count = abcount; + tmpa = firstdab; + for (ct = 0; ct < abcount; ++ct) { + struct Dwarf_D_Abbrev_s *tmpb =tmpa->da_next; + /* da_next no longer means anything */ + dn->dn_abbrev_instances[ct] = *tmpa; + dn->dn_abbrev_instances[ct].da_next = 0; + free(tmpa); + tmpa = tmpb; + } + tmpa = 0; + firstdab = 0; + /* Now the list has turned into an + array. We can ignore + the list aspect. */ + } + return DW_DLV_OK; +} +static int +read_uword_val(Dwarf_Debug dbg, + Dwarf_Small **ptr_in, + Dwarf_Small *endptr, + int errcode, + Dwarf_Unsigned *val_out, + Dwarf_Unsigned area_length, + Dwarf_Error *error) +{ + Dwarf_Unsigned val = 0; + Dwarf_Small *ptr = *ptr_in; + + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + ptr, DWARF_32BIT_SIZE, + error,endptr); + ptr += DWARF_32BIT_SIZE; + if (ptr >= endptr) { + _dwarf_error(dbg, error,errcode); + return DW_DLV_ERROR; + } + /* Some of the fields are not length fields, but + if non-zero the size will be longer than + the value, so we do the following + overall sanity check to avoid overflows. */ + if (val > area_length) { + _dwarf_error(dbg, error,errcode); + return DW_DLV_ERROR; + } + *val_out = val; + *ptr_in = ptr; + return DW_DLV_OK; +} + +/* For now, check using global offset, not pointer */ +#define VALIDATEOFFSET(dnm,used,m) \ + do { \ + if ((used) >= (dnm)->dn_next_set_offset) { \ + _dwarf_error_string(dbg, error, \ + DW_DLE_DEBUG_NAMES_HEADER_ERROR, \ + "DW_DLE_DEBUG_NAMES_HEADER_ERROR: " \ + m); \ + return DW_DLV_ERROR; \ + } \ + } while(0) + +/* Reading a .debug_names Name Index header */ +static int +read_a_name_table_header(Dwarf_Dnames_Head dn, + Dwarf_Unsigned starting_offset, + Dwarf_Unsigned remaining_space, + Dwarf_Small *curptr_in, + Dwarf_Unsigned *usedspace_out, + Dwarf_Unsigned *next_offset, + Dwarf_Small *end_section, + Dwarf_Error *error) +{ + Dwarf_Unsigned area_length = 0; + Dwarf_Unsigned area_max_offset = 0; + unsigned initial_length = 0; /*offset_size+local_ext */ + int offset_size = 0; + int local_extension_size = 0; + Dwarf_Small *end_dnames = 0; /* 1 past local table */ + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + Dwarf_Unsigned comp_unit_count = 0; + Dwarf_Unsigned local_type_unit_count = 0; + Dwarf_Unsigned foreign_type_unit_count = 0; + Dwarf_Unsigned bucket_count = 0; + Dwarf_Unsigned name_count = 0; + Dwarf_Unsigned abbrev_table_size = 0; /* bytes */ + Dwarf_Unsigned entry_pool_size = 0; /* bytes */ + Dwarf_Unsigned augmentation_string_size = 0; /* bytes */ + Dwarf_Unsigned usedspace = 0; + Dwarf_Unsigned totaloffset = 0; + int res = 0; + const char *str_utf8 = 0; /* Augmentation string */ + Dwarf_Small *curptr = 0; + Dwarf_Debug dbg = dn->dn_dbg; + + curptr = curptr_in; + usedspace = 0; + totaloffset = starting_offset; + /* 1 */ + READ_AREA_LENGTH_CK(dbg, area_length, Dwarf_Unsigned, + curptr, offset_size, + local_extension_size,error, + remaining_space,end_section); + initial_length = offset_size+local_extension_size; + + /* curptr now points past the length field */ + area_max_offset = area_length + initial_length; + usedspace = initial_length; + totaloffset += initial_length; + dn->dn_offset_size = (Dwarf_Half)offset_size; + /* Two stage length test so overflow is caught. */ + if (area_length > remaining_space || + (area_length +offset_size +local_extension_size) > + remaining_space) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_HEADER_ERROR, + "DW_DLE_DEBUG_NAMES_HEADER_ERROR: " + "The index table runs off the end of the .debug_names " + "section. Corrupt data."); + return DW_DLV_ERROR; + } + if (area_max_offset > remaining_space) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_HEADER_ERROR, + "DW_DLE_DEBUG_NAMES_HEADER_ERROR: " + "The index table runs off the end of the .debug_names " + "section... Corrupt data."); + return DW_DLV_ERROR; + } + end_dnames = curptr + area_length; + dn->dn_unit_length = area_length + local_extension_size; + dn->dn_indextable_data_end = end_dnames; + dn->dn_next_set_offset = area_length + + initial_length + + + starting_offset; + + /* 2 */ + READ_UNALIGNED_CK(dbg, version, Dwarf_Half, + curptr, DWARF_HALF_SIZE, + error,end_dnames); + curptr += DWARF_HALF_SIZE; + usedspace += DWARF_HALF_SIZE; + totaloffset += DWARF_HALF_SIZE; + if (curptr >= end_dnames) { + _dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (version != DWARF_DNAMES_VERSION5) { + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return DW_DLV_ERROR; + } + /* 3 */ + READ_UNALIGNED_CK(dbg, padding, Dwarf_Half, + curptr, DWARF_HALF_SIZE, + error,end_dnames); + curptr += DWARF_HALF_SIZE; + usedspace += DWARF_HALF_SIZE; + totaloffset += DWARF_HALF_SIZE; + if (curptr >= end_dnames) { + _dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (padding) { + _dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR); + return DW_DLV_ERROR; + } + /* 4 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &comp_unit_count,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (comp_unit_count > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR comp_unit_count too large"); + return DW_DLV_ERROR; + } + dn->dn_comp_unit_count = comp_unit_count; + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + /* 5 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &local_type_unit_count,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (local_type_unit_count > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR local_type_unit_count large"); + return DW_DLV_ERROR; + } + dn->dn_local_type_unit_count = local_type_unit_count; + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + + /* 6 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &foreign_type_unit_count,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (foreign_type_unit_count > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "foreign_type_unit_count large"); + return DW_DLV_ERROR; + } + dn->dn_foreign_type_unit_count = foreign_type_unit_count; + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + /* 7 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &bucket_count,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (bucket_count > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR bucketcount too large"); + return DW_DLV_ERROR; + } + dn->dn_bucket_count = bucket_count; + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + /* name_count gives the size of + the string-offsets and entry-offsets arrays, + and if hashes present, the size of the hashes + array. */ + /* 8 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &name_count,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + dn->dn_name_count = name_count; + if (name_count > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR name_count too large"); + return DW_DLV_ERROR; + } + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + + /* abbrev_table */ + /* 9 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &abbrev_table_size,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (abbrev_table_size > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR abbrev_table_size too large"); + return DW_DLV_ERROR; + } + dn->dn_abbrev_table_size = abbrev_table_size; + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + + /* 10 */ + res = read_uword_val(dbg, &curptr, + end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR, + &augmentation_string_size,area_max_offset,error); + if (res != DW_DLV_OK) { + return res; + } + if (augmentation_string_size > dn->dn_section_size) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR augmentation string too long"); + return DW_DLV_ERROR; + } + usedspace += SIZEOFT32; + totaloffset += SIZEOFT32; + + str_utf8 = (const char *) curptr; + totaloffset += augmentation_string_size; + usedspace += augmentation_string_size; + curptr += augmentation_string_size; + dn->dn_augmentation_string_size = augmentation_string_size; + if (curptr >= end_dnames) { + _dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR); + return DW_DLV_ERROR; + } + + dn->dn_version = version; + dn->dn_abbrev_table_size = abbrev_table_size; + if (augmentation_string_size) { + /* 11. len: The string size includes zero or + more NUL bytes to be a multiple of + four bytes long. */ + Dwarf_Unsigned len = augmentation_string_size; + const char *cp = 0; + const char *cpend = 0; + Dwarf_Unsigned finallen = 0; + + dn->dn_augmentation_string = calloc(1, + augmentation_string_size + 1); + /* Ensures a final NUL byte */ + _dwarf_safe_strcpy(dn->dn_augmentation_string, + len +1,str_utf8, len); + /* This validates a zero length string too. */ + /* in LLVM0700 there is no NUL terminator there: + See DWARF5 page 144 and also ISSUE + 200505.4 */ + cp = dn->dn_augmentation_string; + cpend = cp + len; + /* It's null terminated now, so find the true length */ + for ( ; cpdn_cu_list = curptr; + dn->dn_cu_list_offset = usedspace; + curptr += dn->dn_offset_size * comp_unit_count; + usedspace += dn->dn_offset_size * comp_unit_count ; + totaloffset += dn->dn_offset_size * comp_unit_count ; + VALIDATEOFFSET(dn,totaloffset,"comp_unit array error"); + + dn->dn_local_tu_list = curptr; + dn->dn_local_tu_list_offset = usedspace; + curptr += dn->dn_offset_size *local_type_unit_count; + usedspace += dn->dn_offset_size* local_type_unit_count; + totaloffset += dn->dn_offset_size* local_type_unit_count; + VALIDATEOFFSET(dn,totaloffset,"local_type__unit array error"); + + dn->dn_foreign_tu_list = curptr; + dn->dn_foreign_tu_list_offset = usedspace; + curptr += sizeof(Dwarf_Sig8) * foreign_type_unit_count; + usedspace += sizeof(Dwarf_Sig8) * foreign_type_unit_count; + totaloffset += sizeof(Dwarf_Sig8)* foreign_type_unit_count; + VALIDATEOFFSET(dn,totaloffset,"foreign_type__unit array error"); + + dn->dn_buckets_offset = usedspace; + dn->dn_buckets = curptr; + curptr += SIZEOFT32 * bucket_count ; + usedspace += SIZEOFT32 * bucket_count; + totaloffset += SIZEOFT32 * bucket_count; + VALIDATEOFFSET(dn,totaloffset," bucket array error"); + + if (comp_unit_count == 1) { + Dwarf_Small *ptrx = dn->dn_cu_list; + Dwarf_Small *endptr = dn->dn_foreign_tu_list; + Dwarf_Unsigned unit_entry_size = dn->dn_offset_size; + Dwarf_Unsigned offsetval = 0; + + READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned, + ptrx,(unsigned long) unit_entry_size, + error,endptr); + dn->dn_single_cu = TRUE; + dn->dn_single_cu_offset = offsetval; + } + dn->dn_hash_table = curptr; + dn->dn_hash_table_offset = usedspace; + if (bucket_count) { + curptr += SIZEOFT32 * name_count; + usedspace += SIZEOFT32 * name_count; + totaloffset += SIZEOFT32 * name_count; + } + VALIDATEOFFSET(dn,totaloffset,"hashes array error"); + + dn->dn_string_offsets = curptr; + dn->dn_string_offsets_offset = usedspace; + curptr += dn->dn_offset_size * name_count; + usedspace += dn->dn_offset_size * name_count; + totaloffset += dn->dn_offset_size * name_count; + VALIDATEOFFSET(dn,totaloffset,"string offsets array error"); + + dn->dn_entry_offsets = curptr; + dn->dn_entry_offsets_offset = usedspace; + curptr += dn->dn_offset_size * name_count; + usedspace += dn->dn_offset_size * name_count; + totaloffset += dn->dn_offset_size * name_count; + VALIDATEOFFSET(dn,totaloffset,"entry offsets array error"); + + dn->dn_abbrevs = curptr; + dn->dn_abbrevs_offset = totaloffset; + VALIDATEOFFSET(dn,totaloffset,"abbrev table error"); + curptr += dn->dn_abbrev_table_size; + usedspace += dn->dn_abbrev_table_size; + totaloffset += dn->dn_abbrev_table_size; + VALIDATEOFFSET(dn,totaloffset,"abbrev table error"); + + dn->dn_entry_pool = curptr; + dn->dn_entry_pool_offset = totaloffset; + if (dn->dn_next_set_offset < totaloffset) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_HEADER_ERROR, + "DW_DLE_DEBUG_NAMES_HEADER_ERROR: " + "Abbrev total wrong, exceeds " + "the room available."); + return DW_DLV_ERROR; + } + + entry_pool_size = dn->dn_next_set_offset - totaloffset; + dn->dn_entry_pool_size = entry_pool_size; + curptr += entry_pool_size; + usedspace += entry_pool_size; + totaloffset += entry_pool_size; + + if (totaloffset != dn->dn_next_set_offset) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_HEADER_ERROR, + "DW_DLE_DEBUG_NAMES_HEADER_ERROR: " + "Final total offset does not match base " + "calculation. Logic error."); + return DW_DLV_ERROR; + } + + *usedspace_out = usedspace; + *next_offset = dn->dn_next_set_offset; + res = fill_in_abbrevs_table(dn,error); + if (res != DW_DLV_OK) { + free(dn->dn_augmentation_string); + dn->dn_augmentation_string = 0; + return res; + } + return DW_DLV_OK; +} + +#define FAKE_LAST_USED 0xffffffff + +/* There may be one debug index for an entire object file, + for multiple CUs or there can be individual indexes + for some CUs. + see DWARF5 6.1.1.3 Per_CU versus Per-Module Indexes. + The initial of these tables starts at offset 0. + If the starting-offset is too high for the section + return DW_DLV_NO_ENTRY */ +int +dwarf_dnames_header(Dwarf_Debug dbg, + Dwarf_Off starting_offset, + Dwarf_Dnames_Head * dn_out, + Dwarf_Off * offset_of_next_table, + Dwarf_Error * error) +{ + Dwarf_Unsigned remaining = 0; + Dwarf_Dnames_Head dn = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Unsigned usedspace = 0; + Dwarf_Unsigned next_offset = 0; + Dwarf_Small *start_section= 0; + Dwarf_Small *end_section = 0; + Dwarf_Small *curptr = 0; + int res = 0; + + if (!dbg) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: Dwarf_Debug argument in " + "dwarf_dnames_header() " + "call is NULL"); + return DW_DLV_ERROR; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_names, error); + if (res != DW_DLV_OK) { + return res; + } + section_size = dbg->de_debug_names.dss_size; + if (!section_size){ + return DW_DLV_NO_ENTRY; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (starting_offset >= section_size) { + return DW_DLV_NO_ENTRY; + } + start_section = dbg->de_debug_names.dss_data; + curptr = start_section += starting_offset; + end_section = start_section + section_size; + dn = (Dwarf_Dnames_Head)_dwarf_get_alloc(dbg, + DW_DLA_DNAMES_HEAD, 1); + if (!dn) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: dwarf_get_alloc of " + "a Dwarf_Dnames_Head record failed."); + return DW_DLV_ERROR; + } + dn->dn_magic = DWARF_DNAMES_MAGIC; + dn->dn_section_data = start_section; + dn->dn_section_size = section_size; + dn->dn_section_end = start_section + section_size; + dn->dn_dbg = dbg; + dn->dn_section_offset = starting_offset; + dn->dn_indextable_data = starting_offset + start_section;; + remaining = dn->dn_section_size - starting_offset; + res = read_a_name_table_header(dn, + starting_offset, + remaining, + curptr, + &usedspace, + &next_offset, + dn->dn_section_end, + error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc_dnames(dn); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* Impossible. A bug. Or possibly + a bunch of zero pad? */ + dwarf_dealloc_dnames(dn); + return res; + } + if (usedspace > section_size) { + dwarf_dealloc_dnames(dn); + _dwarf_error_string(dbg, error,DW_DLE_DEBUG_NAMES_OFF_END, + "DW_DLE_DEBUG_NAMES_OFF_END: " + " used space > section size"); + return DW_DLV_ERROR; + } + remaining -= usedspace; + if (remaining && remaining < 15) { + /* No more content in here, just padding. Check for zero + in padding. */ + curptr += usedspace; + for ( ; curptr < end_section; ++curptr) { + if (*curptr) { + /* One could argue this is a harmless error, + but for now assume it is real corruption. */ + dwarf_dealloc(dbg,dn,DW_DLA_DNAMES_HEAD); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_NAMES_PAD_NON_ZERO, + "DW_DLE_DEBUG_NAMES_PAD_NON_ZERO: " + "space at end of valid tables not zeros"); + return DW_DLV_ERROR; + } + } + } + *dn_out = dn; + *offset_of_next_table = next_offset; + return DW_DLV_OK; +} + +/* Frees all the space in dn. It's up to you + to to "dn = 0;" after the call. */ +static void +_dwarf_internal_dwarf_dealloc_dnames(Dwarf_Dnames_Head dn) +{ + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + return; + } + free(dn->dn_augmentation_string); + dn->dn_augmentation_string = 0; + free(dn->dn_bucket_array); + dn->dn_bucket_array = 0; + free(dn->dn_abbrev_instances); + dn->dn_abbrev_instances = 0; + dn->dn_abbrev_instance_count = 0; + dn->dn_magic = 0; +} + +void +dwarf_dealloc_dnames(Dwarf_Dnames_Head dn) +{ + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + return; + } + _dwarf_internal_dwarf_dealloc_dnames(dn); + /* Now dn_magic 0 so the dwarf_dealloc + will just do the base record free. */ + dwarf_dealloc(dn->dn_dbg,dn,DW_DLA_DNAMES_HEAD); +} +/* Frees any Dwarf_Dnames_Head_s data content that is directly + mallocd, unless such is already done. */ +void +_dwarf_dnames_destructor(void *m) +{ + Dwarf_Dnames_Head dn = (Dwarf_Dnames_Head)m; + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + return; + } + _dwarf_internal_dwarf_dealloc_dnames(dn); +} + +/* These are the sizes/counts applicable a particular + names table (most likely the only one) in the + .debug_names section, numbers from the section + Dwarf_Dnames header. + DWARF5 section 6.1.1.2 Structure of the Name Header. */ +int dwarf_dnames_sizes(Dwarf_Dnames_Head dn, + /* The counts are entry counts, not byte sizes. */ + Dwarf_Unsigned * comp_unit_count, + Dwarf_Unsigned * local_type_unit_count, + Dwarf_Unsigned * foreign_type_unit_count, + Dwarf_Unsigned * bucket_count, + Dwarf_Unsigned * name_count, + + /* The following are counted in bytes */ + Dwarf_Unsigned * abbrev_table_size, + Dwarf_Unsigned * entry_pool_size, + Dwarf_Unsigned * augmentation_string_size, + char ** augmentation_string, + Dwarf_Unsigned * section_size, + Dwarf_Half * table_version, + Dwarf_Half * offset_size, + Dwarf_Error * error) +{ + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: A call to dwarf_dnames_sizes() " + "has a NULL Dwarf_Dnames_Head or an improper one."); + return DW_DLV_ERROR; + } + if (comp_unit_count) { + *comp_unit_count = dn->dn_comp_unit_count; + } + if (local_type_unit_count) { + *local_type_unit_count = dn->dn_local_type_unit_count; + } + if (foreign_type_unit_count) { + *foreign_type_unit_count = dn->dn_foreign_type_unit_count; + } + if (bucket_count) { + *bucket_count = dn->dn_bucket_count; + } + if (name_count) { + *name_count = dn->dn_name_count; + } + if (abbrev_table_size) { + *abbrev_table_size = dn->dn_abbrev_table_size; + } + if (entry_pool_size) { + *entry_pool_size = dn->dn_entry_pool_size; + } + if (augmentation_string_size) { + *augmentation_string_size = dn->dn_augmentation_string_size; + } + if (augmentation_string) { + *augmentation_string = dn->dn_augmentation_string; + } + if (section_size) { + *section_size = dn->dn_section_size; + } + if (table_version) { + *table_version = dn->dn_version; + } + if (offset_size) { + *offset_size = dn->dn_offset_size; + } + return DW_DLV_OK; +} + +/* Useful for investigating errors in libdwarf or the + .debug_names section. */ +int +dwarf_dnames_offsets(Dwarf_Dnames_Head dn, + Dwarf_Unsigned * header_offset, + Dwarf_Unsigned * cu_table_offset, + Dwarf_Unsigned * tu_local_offset, + Dwarf_Unsigned * foreign_tu_offset, + Dwarf_Unsigned * bucket_offset, + Dwarf_Unsigned * hashes_offset, + Dwarf_Unsigned * stringoffsets_offset, + Dwarf_Unsigned * entryoffsets_offset, + Dwarf_Unsigned * abbrev_table_offset, + Dwarf_Unsigned * entry_pool_offset, + Dwarf_Error * error) +{ + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: A call to dwarf_dnames_offsets() " + "has a NULL Dwarf_Dnames_Head or an improper one."); + return DW_DLV_ERROR; + } + if (header_offset) { + *header_offset = dn->dn_section_offset; + } + if (cu_table_offset) { + *cu_table_offset = dn->dn_cu_list_offset; + } + if (tu_local_offset) { + *tu_local_offset = dn->dn_local_tu_list_offset; + } + if (foreign_tu_offset) { + *foreign_tu_offset = dn->dn_foreign_tu_list_offset; + } + if (bucket_offset) { + *bucket_offset = dn->dn_buckets_offset; + } + if (hashes_offset) { + *hashes_offset = dn->dn_hash_table_offset; + } + if (stringoffsets_offset) { + *stringoffsets_offset = dn->dn_string_offsets_offset; + } + if (entryoffsets_offset) { + *entryoffsets_offset = dn->dn_entry_offsets_offset; + } + if (abbrev_table_offset) { + *abbrev_table_offset = dn->dn_abbrevs_offset; + } + if (entry_pool_offset) { + *entry_pool_offset = dn->dn_entry_pool_offset; + } + return DW_DLV_OK; +} + +/* The "tu" case covers both local type units + and foreign type units. + This table is indexed starting at 0. +*/ +int +dwarf_dnames_cu_table(Dwarf_Dnames_Head dn, + const char * type /* "cu", "tu" */, + Dwarf_Unsigned index_number, + Dwarf_Unsigned * offset, + Dwarf_Sig8 * sig, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned unit_count = 0; + Dwarf_Unsigned total_count = 0; + Dwarf_Unsigned unit_entry_size = 0; + Dwarf_Small * unit_ptr = 0; + Dwarf_Unsigned foreign_count = 0; + Dwarf_Bool offset_case = TRUE; + + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + " Dwarf_Dnames_Head is NULL or invalid pointer" + "calling dwarf_dnames_cu_table()"); + return DW_DLV_ERROR; + } + + dbg = dn->dn_dbg; + if (type[0] == 'c') { + unit_ptr = dn->dn_cu_list; + unit_entry_size = dn->dn_offset_size; + unit_count = dn->dn_comp_unit_count; + total_count = unit_count; + offset_case = TRUE; + } else if (type[0] == 't') { + unit_count = dn->dn_local_type_unit_count; + foreign_count = dn->dn_foreign_type_unit_count; + total_count = unit_count + foreign_count; + if (index_number < dn->dn_local_type_unit_count) { + unit_ptr = dn->dn_local_tu_list; + unit_entry_size = dn->dn_offset_size; + offset_case = TRUE; + } else { + unit_ptr = dn->dn_foreign_tu_list; + unit_entry_size = sizeof(Dwarf_Sig8); + offset_case = FALSE; + } + } else { + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "type string is not start with cu or tu" + "so invalid call to dwarf_dnames_cu_table()"); + return DW_DLV_ERROR; + } + if (index_number >= total_count) { + return DW_DLV_NO_ENTRY; + } + if (offset_case) { + /* CU or TU ref */ + Dwarf_Unsigned offsetval = 0; + Dwarf_Small *ptr = unit_ptr + + (index_number) *unit_entry_size; + Dwarf_Small *endptr = dn->dn_indextable_data_end; + + READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned, + ptr, (unsigned long)unit_entry_size, + error,endptr); + if (offset) { + *offset = offsetval; + } + return DW_DLV_OK; + } + { + Dwarf_Small *ptr = unit_ptr + + (index_number -unit_count) *unit_entry_size; + if (sig) { + memcpy(sig,ptr,sizeof(*sig)); + } + } + return DW_DLV_OK; +} + +/* Each bucket gives the index of the first of + the name entries for the bucket + index_of_entry returns the name table entry. + indexcount returns the number of name table entries + (representing name collisions) for this bucket. */ +static int +_dwarf_initialize_bucket_details(Dwarf_Dnames_Head dn, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned i = 0; + struct Dwarf_DN_Bucket_s *curbucket = 0; + + dbg = dn->dn_dbg; + if (dn->dn_bucket_array) { + return DW_DLV_OK; + } + if (!dn->dn_bucket_count) { + return DW_DLV_NO_ENTRY; + } + dn->dn_bucket_array = (struct Dwarf_DN_Bucket_s*) + calloc(dn->dn_bucket_count,sizeof(struct Dwarf_DN_Bucket_s)); + if (!dn->dn_bucket_array) { + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: " + ".debug_names bucket array could not be allocated"); + return DW_DLV_ERROR; + } + + curbucket = dn->dn_bucket_array ; + for (i = 0 ; i < dn->dn_bucket_count; ++i) { + Dwarf_Unsigned offsetval = 0; + Dwarf_Small *ptr = dn->dn_buckets + + i * DWARF_32BIT_SIZE; + Dwarf_Small *endptr = dn->dn_buckets+ + dn->dn_bucket_count*DWARF_32BIT_SIZE; + + READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned, + ptr, DWARF_32BIT_SIZE, + error,endptr); + curbucket = dn->dn_bucket_array +i; + curbucket->db_nameindex = offsetval; + } + for (i = 0; i < dn->dn_bucket_count; ) { + Dwarf_Unsigned j = 0; + + curbucket = dn->dn_bucket_array+i; + if (!curbucket->db_nameindex) { + ++i; + continue; + } + for (j = i+1; j < dn->dn_bucket_count; ++j) { + struct Dwarf_DN_Bucket_s *partial = + dn->dn_bucket_array+j; + + if (partial->db_nameindex) { + curbucket->db_collisioncount = + partial->db_nameindex - curbucket->db_nameindex; + i = j; + break; + } + } + if (j >= dn->dn_bucket_count) { + /* Ran off end */ + curbucket->db_collisioncount = + dn->dn_name_count - curbucket->db_nameindex; + if (!curbucket->db_collisioncount) { + curbucket->db_collisioncount = 1; + } + break; + } + } + return DW_DLV_OK; +} + +int +dwarf_dnames_bucket(Dwarf_Dnames_Head dn, + Dwarf_Unsigned bucket_number, + Dwarf_Unsigned * name_index, + Dwarf_Unsigned * collision_count, + Dwarf_Error * error) +{ + struct Dwarf_DN_Bucket_s *cur = 0; + int res = 0; + + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: bad Head argument to " + "dwarf_dnames_bucket"); + return DW_DLV_ERROR; + } + if (bucket_number >= dn->dn_bucket_count) { + return DW_DLV_NO_ENTRY; + } + res = _dwarf_initialize_bucket_details(dn,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (!dn->dn_bucket_array) { + return DW_DLV_NO_ENTRY; + } + cur = dn->dn_bucket_array + bucket_number; + *name_index = cur->db_nameindex; + *collision_count = cur->db_collisioncount; + return DW_DLV_OK; +} +static int +get_hash_value_number(Dwarf_Dnames_Head dn, + Dwarf_Unsigned name_index, + Dwarf_Unsigned *hash_value, + Dwarf_Error *error) +{ + Dwarf_Unsigned hash_val = 0; + int res = 0; + Dwarf_Small * hashesentry = 0; + Dwarf_Small *end = 0; + + if (!dn->dn_bucket_count) { + return DW_DLV_NO_ENTRY; + } + hashesentry = dn->dn_hash_table + (name_index-1)*DWARF_32BIT_SIZE; + end = dn->dn_hash_table + DWARF_32BIT_SIZE*(dn->dn_name_count+1); + res = read_uword_val(dn->dn_dbg, + &hashesentry, + end, + DW_DLE_DEBUG_NAMES_OFF_END, + &hash_val, + 0xffffffff, /* hashes fit in 32 bits */ + error); + if (res != DW_DLV_OK) { + return res; + } + *hash_value = hash_val; + return DW_DLV_OK; +} + +static int +get_bucket_number(Dwarf_Dnames_Head dn, + Dwarf_Unsigned name_index, + Dwarf_Unsigned *bucket_num) +{ + Dwarf_Unsigned i = 0; + + if (!dn->dn_bucket_count) { + return DW_DLV_NO_ENTRY; + } + if (!dn->dn_bucket_array) { + return DW_DLV_NO_ENTRY; + } + /* Binary search would be better FIXME */ + for (i = 0; i < dn->dn_bucket_count; ++i) { + Dwarf_Unsigned bindx = 0; + Dwarf_Unsigned ccount = 0; + Dwarf_Unsigned lastbindx = 0; + struct Dwarf_DN_Bucket_s *cur = dn->dn_bucket_array +i; + + bindx = cur->db_nameindex; + ccount = cur->db_collisioncount; + lastbindx = ccount + bindx -1; + if (name_index > lastbindx) { + continue; + } + if (!bindx ) { + /* empty bucket */ + continue; + } + if (bindx == name_index) { + *bucket_num = i; + return DW_DLV_OK; + } + if (name_index <= lastbindx) { + *bucket_num = i; + return DW_DLV_OK; + } + } + /* ? is it an error? */ + return DW_DLV_NO_ENTRY; +} + +/* We try to protect against bogus arguments, + but all we can do is check for null. */ +int +dwarf_dnames_abbrevtable(Dwarf_Dnames_Head dn, + Dwarf_Unsigned index, + Dwarf_Unsigned *abbrev_offset, + Dwarf_Unsigned *abbrev_code, + Dwarf_Unsigned *abbrev_tag, + Dwarf_Unsigned array_size, + Dwarf_Half * idxattr_array, + Dwarf_Half * form_array, + Dwarf_Unsigned * attr_count) +{ + struct Dwarf_D_Abbrev_s *ab = 0; + Dwarf_Unsigned abnumber = 0; + Dwarf_Unsigned abmax = 0; + + if (!dn) { + return DW_DLV_NO_ENTRY; + } + if (!idxattr_array || !form_array) { + return DW_DLV_NO_ENTRY; + } + if (index >= dn->dn_abbrev_instance_count) { + return DW_DLV_NO_ENTRY; + } + ab = dn->dn_abbrev_instances + index; + if (abbrev_offset) { + *abbrev_offset = ab->da_abbrev_offset; + } + if (abbrev_code) { + *abbrev_code = ab->da_abbrev_code; + } + if (abbrev_tag) { + *abbrev_tag = ab->da_tag; + } + abmax = ab->da_pairs_count; + if (attr_count) { + *attr_count = abmax; + } + if (array_size < abmax) { + abmax = array_size; + } + for ( ; abnumber < abmax; ++abnumber) { + idxattr_array[abnumber] = ab->da_idxattr[abnumber]; + form_array[abnumber] = ab->da_form[abnumber]; + } + return DW_DLV_OK; +} + +static int +_dwarf_read_abbrev_code_from_pool(Dwarf_Dnames_Head dn, + Dwarf_Unsigned entrypooloffset, + Dwarf_Unsigned *code, + Dwarf_Error *error) +{ + Dwarf_Small *epool = 0; + Dwarf_Small *end = 0; + Dwarf_Debug dbg = 0; + int res = 0; + + epool = dn->dn_entry_pool; + end = epool + dn->dn_entry_pool_size; + if (entrypooloffset >= dn->dn_entry_pool_size) { + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "The entry pool offset from the names table " + " is out of bounds."); + return DW_DLV_ERROR; + } + epool += entrypooloffset; + dbg = dn->dn_dbg; + res = _dwarf_read_uleb_ck(&epool, + code,dbg,error,end); + if (res == DW_DLV_ERROR) { + return res; + } + return DW_DLV_OK; +} + +/* Starting out with a simple linear search. + Better to use a dwarf_tsearch function. */ +static int +_dwarf_find_abbrev_for_code(Dwarf_Dnames_Head dn, + Dwarf_Unsigned code, + struct Dwarf_D_Abbrev_s **abbrevdata, + Dwarf_Error *error) +{ + Dwarf_Unsigned i = 0; + struct Dwarf_D_Abbrev_s *ap =0; + + ap = dn->dn_abbrev_instances; + for (i = 0; i < dn->dn_abbrev_instance_count; ++i,++ap) { + if (ap->da_abbrev_code == code) { + *abbrevdata = ap; + return DW_DLV_OK; + } + } + { + Dwarf_Debug dbg = 0; + dwarfstring m; + + dbg = dn->dn_dbg; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_NAMES_ERROR: " + "The abbrev code %u",code); + dwarfstring_append_printf_u(&m, + "(0x%x) ",code); + dwarfstring_append(&m, + "from the entry pool " + "is absent from the abbrev table."); + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; +} + +static int +_dwarf_fill_in_attr_form(Dwarf_Dnames_Head dn, + struct Dwarf_D_Abbrev_s *abbrevdata, + Dwarf_Half *idxattr_array, + Dwarf_Half *form_array, + Dwarf_Unsigned array_size, + Dwarf_Error *error) +{ + Dwarf_Unsigned limit = abbrevdata->da_pairs_count; + Dwarf_Unsigned i = 0; + Dwarf_Debug dbg = 0; + + if (limit > array_size) { + limit = array_size; + } + for ( ; i < limit ; ++i) { + idxattr_array[i] = abbrevdata->da_idxattr[i]; + form_array[i] = abbrevdata->da_form[i]; + } + if (i < limit) { + dwarfstring m; + + dbg= dn->dn_dbg; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_NAMES_ERROR: " + "At attr-form pair ",i); + dwarfstring_append_printf_u(&m, + ", with attr-form max of %u", + abbrevdata->da_pairs_count); + dwarfstring_append_printf_u(&m, + ", and limit of of %u", + limit); + dwarfstring_append(&m, + " something is very wrong. " + "a pairs pointer is null"); + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_OK; + +} + +/* Each Name Table entry, one at a time. + It is not an error if array_size is zero or + small. Check the returned attr_count to + know now much of array filled in and + if the array you provided is + large enough. Possibly 40 is + sufficient. + name indexes start at 1. */ +int +dwarf_dnames_name(Dwarf_Dnames_Head dn, + Dwarf_Unsigned name_index, + Dwarf_Unsigned * bucket_number, + Dwarf_Unsigned * hash_value, + Dwarf_Unsigned * offset_to_debug_str, + char * * ptrtostr , + Dwarf_Unsigned * offset_in_entrypool, + Dwarf_Unsigned * abbrev_code, + Dwarf_Half * abbrev_tag, + Dwarf_Unsigned array_size, + Dwarf_Half * idxattr_array, + Dwarf_Half * form_array, + Dwarf_Unsigned * attr_count, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + int res = 0; + Dwarf_Unsigned entrypooloffset = 0; + Dwarf_Unsigned debugstroffset = 0; + Dwarf_Small * strpointer = 0; + struct Dwarf_D_Abbrev_s *abbrevdata = 0; + Dwarf_Unsigned code = 0; + + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "a call to dwarf_dnames_name() " + "Passes in a NULL or uninitialized pointer"); + return DW_DLV_ERROR; + } + dbg = dn->dn_dbg; + if (!dbg) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "a call to dwarf_dnames_name() " + "finds a NULL Dwarf_Debug in a Dwarf_Dnames_Head"); + return DW_DLV_ERROR; + } + if (!name_index || name_index > dn->dn_name_count) { + return DW_DLV_NO_ENTRY; + } + res = get_bucket_number(dn,name_index,bucket_number); + if (res == DW_DLV_OK) { + res = get_hash_value_number(dn,name_index,hash_value,error); + if (res == DW_DLV_ERROR) { + return res; + } + } + { + Dwarf_Small *ptr = dn->dn_string_offsets + + (name_index-1) * dn->dn_offset_size; + Dwarf_Small *endptr = dn->dn_abbrevs; + + READ_UNALIGNED_CK(dbg, debugstroffset, Dwarf_Unsigned, + ptr, dn->dn_offset_size, + error,endptr); + if (offset_to_debug_str) { + *offset_to_debug_str = debugstroffset; + } + } + /* Get str ptr from .debug_str */ + { + Dwarf_Small *secdataptr = 0; + Dwarf_Unsigned secdatalen = 0; + Dwarf_Small *secend = 0; + int res_s = 0; + + secdataptr = (Dwarf_Small *)dbg->de_debug_str.dss_data; + secdatalen = dbg->de_debug_str.dss_size; + secend = secdataptr+secdatalen; + strpointer = secdataptr +debugstroffset; + res_s = _dwarf_check_string_valid(dbg, + secdataptr,strpointer,secend, + DW_DLE_FORM_STRING_BAD_STRING,error); + if (res_s != DW_DLV_OK) { + return res_s; + } + if (ptrtostr) { + *ptrtostr = (char *)strpointer; + } + } + + { + Dwarf_Small *ptr = dn->dn_entry_offsets + + (name_index-1) * dn->dn_offset_size; + Dwarf_Small *endptr = dn->dn_abbrevs; + /* offsets relative to the start of the + entry_pool */ + + READ_UNALIGNED_CK(dbg, entrypooloffset, Dwarf_Unsigned, + ptr, dn->dn_offset_size, + error,endptr); + if (entrypooloffset >= dn->dn_entry_pool_size) { + _dwarf_error_string(dbg, error,DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "The entrypool offset read is larger than" + "the entrypool size"); + return DW_DLV_ERROR; + } + if (offset_in_entrypool) { + *offset_in_entrypool = entrypooloffset; + } + } + /* Find abbrev code at the given entry offset */ + res = _dwarf_read_abbrev_code_from_pool(dn, + entrypooloffset, &code,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_find_abbrev_for_code(dn,code,&abbrevdata,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + + if (abbrev_code) { + *abbrev_code = code; + } + if (code && abbrev_tag) { + *abbrev_tag = (Dwarf_Half)abbrevdata->da_tag; + } + if (code) { + if (attr_count) { + *attr_count = abbrevdata->da_pairs_count; + } + res = _dwarf_fill_in_attr_form(dn,abbrevdata,idxattr_array, + form_array, array_size,error); + if (res == DW_DLV_ERROR) { + return res; + } + } + return DW_DLV_OK; +} + +/* If abbrev_code returned is zero there is no tag returned + and we are at the end of the entry pool set for this name + entry. + abbrev code, tag + attr,form + ... + 0,0 + ... repeat like the above + 0 +*/ + +static int +_dwarf_internal_abbrev_by_code(Dwarf_Dnames_Head dn, + Dwarf_Unsigned abbrev_code, + Dwarf_Half *tag, + Dwarf_Unsigned *index_of_abbrev, + Dwarf_Unsigned *number_of_attr_form_entries) +{ + Dwarf_Unsigned n = 0; + struct Dwarf_D_Abbrev_s * abbrev = 0; + + abbrev = dn->dn_abbrev_instances; + for (n = 0; n < dn->dn_abbrev_instance_count; ++n,++abbrev) { + if (abbrev_code == abbrev->da_abbrev_code) { + if (tag) { + *tag = (Dwarf_Half)abbrev->da_tag; + } + if (index_of_abbrev) { + *index_of_abbrev = n; + } + if (number_of_attr_form_entries) { + *number_of_attr_form_entries = abbrev->da_pairs_count; + } + return DW_DLV_OK; + } + } + /* Something is wrong, not found! */ + return DW_DLV_NO_ENTRY; +} + +/* This, combined with dwarf_dnames_entrypool_values(), + lets one examine as much or as little of an entrypool + as one wants to by alternately calling these two + functions. +*/ + +int dwarf_dnames_entrypool(Dwarf_Dnames_Head dn, + Dwarf_Unsigned offset_in_entrypool, + Dwarf_Unsigned *abbrev_code, + Dwarf_Half *tag, + Dwarf_Unsigned *value_count, + Dwarf_Unsigned *index_of_abbrev, + Dwarf_Unsigned *offset_of_initial_value, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + int res = 0; + Dwarf_Small *entrypool = 0; + Dwarf_Small *endentrypool = 0; + Dwarf_Unsigned abcode = 0; + Dwarf_Unsigned leblen = 0; + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error(NULL, error,DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + + dbg = dn->dn_dbg; + if (offset_in_entrypool >= dn->dn_entry_pool_size) { + _dwarf_error(NULL, error,DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET); + return DW_DLV_ERROR; + } + endentrypool = dn->dn_entry_pool +dn->dn_entry_pool_size; + entrypool = dn->dn_entry_pool + offset_in_entrypool; + + DECODE_LEB128_UWORD_LEN_CK(entrypool,abcode,leblen, + dbg,error,endentrypool); + + res = _dwarf_internal_abbrev_by_code(dn, + abcode, + tag, index_of_abbrev, + value_count); + if (res != DW_DLV_OK) { + /* Never DW_DLV_ERROR (so far) */ + return res; + } + *offset_of_initial_value = offset_in_entrypool + leblen; + *abbrev_code = abcode; + return DW_DLV_OK; +} + +static int +isformrefval(Dwarf_Debug dbg,Dwarf_Half form, + Dwarf_Small *poolptr, + Dwarf_Small *endpool, + Dwarf_Unsigned *val, + Dwarf_Unsigned *bytesread, + Dwarf_Error *error) +{ + Dwarf_Unsigned localval =0; + + switch(form) { + case DW_FORM_ref1: + *val = *poolptr; + *bytesread = 1; + break; + case DW_FORM_ref2: + READ_UNALIGNED_CK(dbg, localval, Dwarf_Unsigned, + poolptr, DWARF_HALF_SIZE, + error,endpool); + *bytesread = DWARF_HALF_SIZE; + *val = localval; + break; + case DW_FORM_ref4: + READ_UNALIGNED_CK(dbg, localval, Dwarf_Unsigned, + poolptr, DWARF_32BIT_SIZE, + error,endpool); + *bytesread = DWARF_32BIT_SIZE; + *val = localval; + break; + case DW_FORM_ref8: + default: + return DW_DLV_NO_ENTRY; + } + return DW_DLV_OK; +} +/* Caller, knowing array size needed, passes in arrays + it allocates of for idx, form, offset-size-values, + and signature values. Caller must examine idx-number + and form to decide, for each array element, whether + the offset or the signature contains the value. + So this returns all the values for the abbrev code. + And points via offset_of_next to the next abbrev code. + + While an array of structs would be easier for the caller + to allocate than parallel arrays, public structs have + turned out to be difficult to work with as interfaces + (as formats change over time). + */ +int dwarf_dnames_entrypool_values(Dwarf_Dnames_Head dn, + Dwarf_Unsigned index_of_abbrev, + Dwarf_Unsigned offset_in_entrypool_of_values, + Dwarf_Unsigned array_sizes, + Dwarf_Half * array_dw_idx_number, + Dwarf_Half * array_form, + Dwarf_Unsigned * array_of_offsets, + Dwarf_Sig8 * array_of_signatures, + Dwarf_Bool * single_cu, + Dwarf_Unsigned * single_cu_offset, + /* offset of the next entrypool entry. */ + Dwarf_Unsigned * offset_of_next_entrypool, + Dwarf_Error * error) +{ + struct Dwarf_D_Abbrev_s * abbrev = 0; + Dwarf_Debug dbg = 0; + unsigned n = 0; + int res = 0; + Dwarf_Unsigned abcount = 0; + Dwarf_Unsigned pooloffset = + offset_in_entrypool_of_values; + Dwarf_Small * endpool = 0; + Dwarf_Small * poolptr = 0; + Dwarf_Unsigned bytesread = 0; + + if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: bad Head argument to " + "dwarf_dnames_entrypool_values"); + return DW_DLV_ERROR; + } + dbg = dn->dn_dbg; + endpool = dn->dn_entry_pool + dn->dn_entry_pool_size; + if (pooloffset >= dn->dn_entry_pool_size) { + /* make error or harmless error? */ + return DW_DLV_NO_ENTRY; + } + if (index_of_abbrev >= dn->dn_abbrev_instance_count) { + /* make error or harmless error? */ + return DW_DLV_NO_ENTRY; + } + + poolptr = dn->dn_entry_pool + pooloffset; + abbrev = dn->dn_abbrev_instances + index_of_abbrev; + abcount = abbrev->da_pairs_count; + if (!abcount) { + return DW_DLV_NO_ENTRY; + } + if (abcount > array_sizes) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_NAMES_OFF_END: " + "The size of the pair of arrays " + "passed to dwarf_dnames_entrypool_values " + "is %u", + array_sizes); + dwarfstring_append_printf_u(&m, + " but the entry requires %u entries.", + abcount); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_OFF_END, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (abcount > dn->dn_entry_pool_size) { + /* Just looking for a horrible giant value */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: " + "The abbrev count for this entry pool entry" + " is %u, impossibly large. Corrupt data", + abcount); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + for (n = 0; n < abcount ; ++n) { + Dwarf_Half idxtype = 0; + Dwarf_Half form = 0; + + idxtype = abbrev->da_idxattr[n]; + form = abbrev->da_form[n]; + array_dw_idx_number[n] = idxtype; + array_form[n] = form; + + if (!idxtype && !form) { + break; + } + + if (form == DW_FORM_data8 && idxtype == DW_IDX_type_hash) { + if ((poolptr + sizeof(Dwarf_Sig8)) > endpool){ + _dwarf_error(dbg,error, + DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET); + return DW_DLV_ERROR; + } + bytesread = sizeof(Dwarf_Sig8); + memcpy(array_of_signatures+n, + poolptr,bytesread); + poolptr += bytesread; + pooloffset += bytesread; + continue; + } else if (_dwarf_allow_formudata(form)) { + Dwarf_Unsigned val = 0; + res = _dwarf_formudata_internal(dbg,0,form,poolptr, + endpool,&val,&bytesread,error); + if (res != DW_DLV_OK) { + return res; + } + poolptr += bytesread; + pooloffset += bytesread; + + array_of_offsets[n] = val; + continue; + } else { + Dwarf_Unsigned val = 0; + res =isformrefval(dbg,form,poolptr, + endpool,&val,&bytesread,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_OK) { + poolptr += bytesread; + if (poolptr > endpool) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET, + "DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET:" + " a DW_FORM_ref* would read past end" + " of the entrypool"); + return DW_DLV_ERROR; + } + poolptr += bytesread; + pooloffset += bytesread; + array_of_offsets[n] = val; + continue; + } + } + /* There is some mistake/omission in our code here or in + the data. */ + { + dwarfstring m; + const char *name = ""; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_NAMES_UNHANDLED_FORM: Form 0x%x", + form); + dwarf_get_FORM_name(form,&name); + dwarfstring_append_printf_s(&m, + " %s is not currently supported for .debug_names ", + (char *)name); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_UNHANDLED_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; + } + if ( dn->dn_single_cu) { + if (single_cu && single_cu_offset) { + *single_cu = dn->dn_single_cu; + *single_cu_offset = dn->dn_single_cu_offset; + } + } + *offset_of_next_entrypool = pooloffset; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_debugnames.h b/src/lib/libdwarf/dwarf_debugnames.h new file mode 100644 index 0000000..ad717e0 --- /dev/null +++ b/src/lib/libdwarf/dwarf_debugnames.h @@ -0,0 +1,121 @@ +/* + Copyright (C) 2017-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* Adjust this number to hope for best space and time efficiency. */ +#define ABB_PAIRS_MAX 10 + +/* The unused attr/form entries are zero. */ +struct Dwarf_D_Abbrev_s { + struct Dwarf_D_Abbrev_s * da_next; + Dwarf_Unsigned da_abbrev_offset; + Dwarf_Unsigned da_abbrev_code; + Dwarf_Unsigned da_tag; + Dwarf_Unsigned da_pairs_count; + Dwarf_Half da_idxattr[ABB_PAIRS_MAX]; + Dwarf_Half da_form[ABB_PAIRS_MAX]; +}; + +struct Dwarf_DN_Bucket_s { + Dwarf_Unsigned db_nameindex; + Dwarf_Unsigned db_collisioncount; +}; + +#define DWARF_DNAMES_VERSION5 5 +#define DWARF_DNAMES_MAGIC 0xabcd + +/* All offsets section global */ +struct Dwarf_Dnames_Head_s { + Dwarf_Unsigned dn_magic; + Dwarf_Debug dn_dbg; + /* For entire section */ + Dwarf_Small * dn_section_data; + Dwarf_Small * dn_section_end; + Dwarf_Unsigned dn_section_size; + + /* For this names table set of data */ + Dwarf_Unsigned dn_section_offset; /* unit length offset*/ + Dwarf_Small * dn_indextable_data; /* unit length ptr */ + Dwarf_Unsigned dn_unit_length; + Dwarf_Small * dn_indextable_data_end; + Dwarf_Unsigned dn_next_set_offset; + Dwarf_Half dn_offset_size; + Dwarf_Half dn_version; + + Dwarf_Unsigned dn_comp_unit_count; + Dwarf_Unsigned dn_local_type_unit_count; + Dwarf_Unsigned dn_foreign_type_unit_count; + Dwarf_Unsigned dn_bucket_count; + + /* Once set, this is a single array of entries. */ + struct Dwarf_DN_Bucket_s * dn_bucket_array; + + /* dn_name_count gives the size of + the dn_string_offsets and dn_entry_offsets arrays, + and if hashes present, the size of the + dn_hash_table array. */ + Dwarf_Unsigned dn_name_count; + Dwarf_Unsigned dn_abbrev_table_size; /* bytes */ + Dwarf_Unsigned dn_entry_pool_size; /* bytes */ + Dwarf_Unsigned dn_augmentation_string_size; + char * dn_augmentation_string; /* local copy */ + /*Offsets are non-decreasing (even empty tables */ + Dwarf_Unsigned dn_cu_list_offset; + Dwarf_Unsigned dn_local_tu_list_offset; + Dwarf_Unsigned dn_foreign_tu_list_offset; + Dwarf_Unsigned dn_buckets_offset; + Dwarf_Unsigned dn_hash_table_offset; + Dwarf_Unsigned dn_string_offsets_offset; + Dwarf_Unsigned dn_entry_offsets_offset; + Dwarf_Unsigned dn_abbrevs_offset; + Dwarf_Unsigned dn_entry_pool_offset; + /* pointers non-decreasing (even empty tables) */ + Dwarf_Small * dn_cu_list; + Dwarf_Small * dn_local_tu_list; + Dwarf_Small * dn_foreign_tu_list; + Dwarf_Small * dn_buckets; + Dwarf_Small * dn_hash_table; + Dwarf_Small * dn_string_offsets; + Dwarf_Small * dn_entry_offsets; + Dwarf_Small * dn_abbrevs; + Dwarf_Small * dn_entry_pool; + + /* Array of structs*/ + struct Dwarf_D_Abbrev_s *dn_abbrev_instances; + Dwarf_Unsigned dn_abbrev_instance_count; + + /* If this is a single-CU entry the next two are set + for later return. */ + Dwarf_Bool dn_single_cu; + Dwarf_Unsigned dn_single_cu_offset; + + Dwarf_Unsigned b_value; + Dwarf_Unsigned b_orig_bucket_index; + Dwarf_Unsigned b_sorted_bucket_index; +}; + +void _dwarf_dnames_destructor(void *m); diff --git a/src/lib/libdwarf/dwarf_die_deliv.c b/src/lib/libdwarf/dwarf_die_deliv.c new file mode 100644 index 0000000..cba0ae6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_die_deliv.c @@ -0,0 +1,3263 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2022 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include +#include /* debugging */ + +#include /* memcmp() memcpy() memset() strcmp() strlen() */ +#include /* calloc() free() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_str_offsets.h" +#include "dwarf_string.h" +#include "dwarf_die_deliv.h" + +/* These are sanity checks, not 'rules'. */ +#define MINIMUM_ADDRESS_SIZE 2 +#define MAXIMUM_ADDRESS_SIZE 8 + +static void assign_correct_unit_type(Dwarf_CU_Context cu_context); +static int find_cu_die_base_fields(Dwarf_Debug dbg, + Dwarf_CU_Context cucon, + Dwarf_Die cudie, + Dwarf_Error *error); + +static int _dwarf_siblingof_internal(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_CU_Context context, + Dwarf_Bool is_info, + Dwarf_Die * caller_ret_die, Dwarf_Error * error); + +/* see cuandunit.txt for an overview of the + DWARF5 split dwarf sections and values + and the DWARF4 GNU cc version of a draft + version of DWARF5 (quite different from + the final DWARF5). +*/ + +static struct Dwarf_Sig8_s dwarfsig8zero; + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s ",msg); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* New October 2011. Enables client code to know if + it is a debug_info or debug_types context. */ +Dwarf_Bool +dwarf_get_die_infotypes_flag(Dwarf_Die die) +{ + return die->di_is_info; +} + +/* + For a given Dwarf_Debug dbg, this function checks + if a CU that includes the given offset has been read + or not. If yes, it returns the Dwarf_CU_Context + for the CU. Otherwise it returns NULL. Being an + internal routine, it is assumed that a valid dbg + is passed. + + **This is a sequential search. May be too slow. + + If debug_info and debug_abbrev not loaded, this will + wind up returning NULL. So no need to load before calling + this. +*/ +static Dwarf_CU_Context +_dwarf_find_CU_Context(Dwarf_Debug dbg, + Dwarf_Off offset, + Dwarf_Bool is_info) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + + if (offset >= dis->de_last_offset){ + return NULL; + } + if (dis->de_cu_context != NULL && + dis->de_cu_context->cc_next != NULL && + dis->de_cu_context->cc_next->cc_debug_offset == offset) { + return dis->de_cu_context->cc_next; + } + if (dis->de_cu_context != NULL && + dis->de_cu_context->cc_debug_offset <= offset) { + for (cu_context = dis->de_cu_context; + cu_context != NULL; + cu_context = cu_context->cc_next) { + if (offset >= cu_context->cc_debug_offset && + offset < cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + return cu_context; + } + } + } + for (cu_context = dis->de_cu_context_list; + cu_context != NULL; + cu_context = cu_context->cc_next) { + if (offset >= cu_context->cc_debug_offset && + offset < cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + return cu_context; + } + } + return NULL; +} + +int +dwarf_get_debugfission_for_die(Dwarf_Die die, + struct Dwarf_Debug_Fission_Per_CU_s *fission_out, + Dwarf_Error *error) +{ + Dwarf_CU_Context context = 0; + Dwarf_Debug dbg = 0; + struct Dwarf_Debug_Fission_Per_CU_s * percu = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + if (!_dwarf_file_has_debug_fission_index(dbg)) { + return DW_DLV_NO_ENTRY; + } + + /* Logic should work for DW4 and DW5. */ + if (context->cc_unit_type == DW_UT_type|| + context->cc_unit_type == DW_UT_split_type ) { + if (!_dwarf_file_has_debug_fission_tu_index(dbg)) { + return DW_DLV_NO_ENTRY; + } + } else if (context->cc_unit_type == DW_UT_split_compile) { + if (!_dwarf_file_has_debug_fission_cu_index(dbg)) { + return DW_DLV_NO_ENTRY; + } + } else { /* Fall through*/ } + percu = &context->cc_dwp_offsets; + if (!percu->pcu_type) { + return DW_DLV_NO_ENTRY; + } + *fission_out = *percu; + return DW_DLV_OK; +} + +static Dwarf_Bool +is_unknown_UT_value(int ut) +{ + switch(ut) { + case DW_UT_compile: + case DW_UT_type: + case DW_UT_partial: + return FALSE; + case DW_UT_skeleton: + case DW_UT_split_compile: + case DW_UT_split_type: + return FALSE; + default: + break; + } + return TRUE; +} + +/* ASSERT: whichone is a DW_SECT* macro value. */ +Dwarf_Unsigned +_dwarf_get_dwp_extra_offset(struct Dwarf_Debug_Fission_Per_CU_s* dwp, + unsigned whichone, Dwarf_Unsigned * size) +{ + Dwarf_Unsigned sectoff = 0; + if (!dwp->pcu_type) { + return 0; + } + sectoff = dwp->pcu_offset[whichone]; + *size = dwp->pcu_size[whichone]; + return sectoff; +} + +/* _dwarf_get_fission_addition_die returns DW_DLV_OK etc. +*/ +int +_dwarf_get_fission_addition_die(Dwarf_Die die, int dw_sect_index, + Dwarf_Unsigned *offset, + Dwarf_Unsigned *size, + Dwarf_Error *error) +{ + /* We do not yet know the DIE hash, so we cannot use it + to identify the offset. */ + Dwarf_CU_Context context = 0; + Dwarf_Unsigned dwpadd = 0; + Dwarf_Unsigned dwpsize = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dwpadd = _dwarf_get_dwp_extra_offset( + &context->cc_dwp_offsets, + dw_sect_index,&dwpsize); + *offset = dwpadd; + *size = dwpsize; + return DW_DLV_OK; +} + +/* Not sure if this is the only way to be sure early on in + reading a compile unit. */ +static int +section_name_ends_with_dwo(const char *name) +{ + size_t lenstr = 0; + size_t dotpos = 0; + if (!name) { + return FALSE; + } + lenstr = strlen(name); + if (lenstr < 5) { + return FALSE; + } + dotpos = lenstr - 4; + if (strcmp(name+dotpos,".dwo")) { + return FALSE; + } + return TRUE; +} + +void +_dwarf_create_address_size_dwarf_error(Dwarf_Debug dbg, + Dwarf_Error *error, + Dwarf_Unsigned addrsize, + int errcode,const char *errname) +{ + dwarfstring m; + const char *bites = "bytes"; + if (addrsize == 1) { + bites = "byte"; + } + + dwarfstring_constructor(&m); + dwarfstring_append(&m,(char *)errname); + dwarfstring_append_printf_u(&m, + ": Address size of %u ", + addrsize); + dwarfstring_append_printf_s(&m, + "%s is not supported. Corrupt DWARF.", + (char *)bites); + _dwarf_error_string(dbg,error,errcode, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* New January 2017 */ +static int +_dwarf_read_cu_version_and_abbrev_offset(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Bool is_info, + unsigned offset_size, /* 4 or 8 */ + Dwarf_CU_Context cu_context, + /* end_data used for sanity checking */ + Dwarf_Small * end_data, + Dwarf_Unsigned * bytes_read_out, + Dwarf_Error * error) +{ + Dwarf_Small * data_start = data; + Dwarf_Small * dataptr = data; + Dwarf_Ubyte unit_type = 0; + Dwarf_Ubyte addrsize = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half version = 0; + + READ_UNALIGNED_CK(dbg, version, Dwarf_Half, + dataptr,DWARF_HALF_SIZE,error,end_data); + dataptr += DWARF_HALF_SIZE; + if (version == DW_CU_VERSION5) { + Dwarf_Ubyte unit_typeb = 0; + Dwarf_Unsigned herelen = sizeof(unit_typeb) + + sizeof(addrsize) + offset_size; + + if ((dataptr+herelen) > end_data) { + _dwarf_error_string(dbg, error, + DW_DLE_CU_UT_TYPE_ERROR, + "DW_DLE_UT_TYPE_ERROR: " + " Reading the unit type, address size, " + "and abbrev_offset of the DWARF5 header" + " will run off the end of the section. " + "Corrupt DWARF"); + } + READ_UNALIGNED_CK(dbg, unit_typeb, Dwarf_Ubyte, + dataptr, sizeof(unit_typeb),error,end_data); + dataptr += sizeof(unit_typeb); + + unit_type = unit_typeb; + /* We do not need is_info flag in DWARF5 */ + if (is_unknown_UT_value(unit_type)) { + /* DWARF5 object file is corrupt. Invalid value */ + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_CU_UT_TYPE_ERROR: we do not know " + " the CU header unit_type 0x%x",unit_type); + dwarfstring_append_printf_u(&m," (%u) so cannot" + "process this compilation_unit. A valid type ", + unit_type); + dwarfstring_append(&m,"would be DW_UT_compile" + ", for example"); + _dwarf_error_string(dbg, error, + DW_DLE_CU_UT_TYPE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, addrsize, unsigned char, + dataptr, sizeof(addrsize),error,end_data); + dataptr += sizeof(char); + + READ_UNALIGNED_CK(dbg, abbrev_offset, Dwarf_Unsigned, + dataptr, offset_size,error,end_data); + dataptr += offset_size; + + } else if (version == DW_CU_VERSION2 || + version == DW_CU_VERSION3 || + version == DW_CU_VERSION4) { + Dwarf_Unsigned herelen = sizeof(addrsize) + offset_size; + + if ((dataptr+herelen) > end_data) { + _dwarf_error_string(dbg, error, + DW_DLE_CU_UT_TYPE_ERROR, + "DW_DLE_UT_TYPE_ERROR: " + " Reading the address size, " + "and abbrev_offset of the DWARF header" + " will run off the end of the section. " + "Corrupt DWARF"); + } + /* DWARF2,3,4 */ + READ_UNALIGNED_CK(dbg, abbrev_offset, Dwarf_Unsigned, + dataptr, offset_size,error,end_data); + dataptr += offset_size; + + READ_UNALIGNED_CK(dbg, addrsize, Dwarf_Ubyte, + dataptr, sizeof(addrsize),error,end_data); + dataptr += sizeof(addrsize); + + /* This is an initial approximation of unit_type. + For DW4 we will refine this after we + have built the CU header (by reading + CU_die) + */ + unit_type = is_info?DW_UT_compile:DW_UT_type; + } else { + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return DW_DLV_ERROR; + } + cu_context->cc_version_stamp = version; + cu_context->cc_unit_type = unit_type; + cu_context->cc_address_size = addrsize; + cu_context->cc_abbrev_offset = abbrev_offset; + if (!addrsize) { + _dwarf_error(dbg,error,DW_DLE_ADDRESS_SIZE_ZERO); + return DW_DLV_ERROR; + } + if (addrsize < MINIMUM_ADDRESS_SIZE || + addrsize > MAXIMUM_ADDRESS_SIZE ) { + _dwarf_create_address_size_dwarf_error(dbg,error,addrsize, + DW_DLE_ADDRESS_SIZE_ERROR, + "DW_DLE_ADDRESS_SIZE_ERROR::"); + return DW_DLV_ERROR; + } + if (addrsize > sizeof(Dwarf_Addr)) { + _dwarf_create_address_size_dwarf_error(dbg,error,addrsize, + DW_DLE_ADDRESS_SIZE_ERROR, + "DW_DLE_ADDRESS_SIZE_ERROR: not representable" + " in Dwarf_Addr field."); + return DW_DLV_ERROR; + } + + /* We are ignoring this. Can get it from DWARF5. */ + cu_context->cc_segment_selector_size = 0; + *bytes_read_out = (dataptr - data_start); + return DW_DLV_OK; +} + +/* .debug_info[.dwo] .debug_types[.dwo] + the latter only DWARF4. */ +static int +read_info_area_length_and_check(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Unsigned offset, + Dwarf_Byte_Ptr *cu_ptr_io, + Dwarf_Unsigned section_size, + Dwarf_Byte_Ptr section_end_ptr, + Dwarf_Unsigned *max_cu_global_offset_out, + Dwarf_Error *error) +{ + Dwarf_Byte_Ptr cu_ptr = 0; + /* The following two will be either 0,4, or 8. */ + Dwarf_Unsigned local_length_size = 0; + Dwarf_Unsigned local_extension_size = 0; + + Dwarf_Unsigned max_cu_global_offset = 0; + Dwarf_Unsigned length = 0; + + cu_ptr = *cu_ptr_io; + /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */ + READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned, + cu_ptr, local_length_size, local_extension_size, + error,section_size,section_end_ptr); + if (!length) { + return DW_DLV_NO_ENTRY; + } + + /* ASSERT: The following is either 4 or 8. */ + cu_context->cc_length_size = (Dwarf_Small)local_length_size; + /* ASSERT: The following is either 0 or 4. */ + cu_context->cc_extension_size = (Dwarf_Small)local_extension_size; + cu_context->cc_length = length; + + /* This is a bare minimum, not the real max offset. + A preliminary sanity check. */ + max_cu_global_offset = offset + length + + local_extension_size + local_length_size; + if (length > section_size || + (length+local_length_size + local_extension_size)> + section_size) { + _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR); + return DW_DLV_ERROR; + } + if (max_cu_global_offset > section_size) { + _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR); + return DW_DLV_ERROR; + } + *cu_ptr_io = cu_ptr; + *max_cu_global_offset_out = max_cu_global_offset; + return DW_DLV_OK; +} + +/* In DWARF4 GNU dwp there is a problem. + We cannot read the CU die and it's + DW_AT_GNU_dwo_id until we know the + section offsets from the index files. + Hence we do not know how to search the + index files by key. So search by offset. + + There is no such problem in DWARF5. + + We have not yet corrected the unit_type so, for DWARF4, + we check for simpler unit types. +*/ + +static int +fill_in_dwp_offsets_if_present(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Sig8 * signaturedata, + Dwarf_Off offset, + Dwarf_Error *error) +{ + Dwarf_Half unit_type = cu_context->cc_unit_type; + const char * typename = 0; + Dwarf_Half ver = cu_context->cc_version_stamp; + + if (unit_type == DW_UT_split_type || + (ver == DW_CU_VERSION4 && unit_type == DW_UT_type)){ + typename = "tu"; + if (!_dwarf_file_has_debug_fission_tu_index(dbg) ){ + /* nothing to do. */ + return DW_DLV_OK; + } + } else if (unit_type == DW_UT_split_compile || + (ver == DW_CU_VERSION4 && + unit_type == DW_UT_compile)){ + typename = "cu"; + if (!_dwarf_file_has_debug_fission_cu_index(dbg) ){ + /* nothing to do. */ + return DW_DLV_OK; + } + } else { + /* nothing to do. */ + return DW_DLV_OK; + } + + if (cu_context->cc_signature_present) { + int resdf = 0; + + resdf = dwarf_get_debugfission_for_key(dbg, + signaturedata, + typename, + &cu_context->cc_dwp_offsets, + error); + if (resdf == DW_DLV_ERROR) { + return resdf; + } + if (resdf == DW_DLV_NO_ENTRY) { + _dwarf_error_string(dbg, error, + DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH, + "DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH: " + " dwarf_get_debugfission_for_key returned" + " DW_DLV_NO_ENTRY, something is wrong"); + return DW_DLV_ERROR; + } + } else { + int resdf = 0; + + resdf = _dwarf_get_debugfission_for_offset(dbg, + offset, + typename, + &cu_context->cc_dwp_offsets, + error); + if (resdf == DW_DLV_ERROR) { + return resdf; + } + if (resdf == DW_DLV_NO_ENTRY) { + _dwarf_error_string(dbg, error, + DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH, + "DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH: " + " dwarf_get_debugfission_for_offset returned" + " DW_DLV_NO_ENTRY, something is wrong"); + return DW_DLV_ERROR; + } + cu_context->cc_signature = + cu_context->cc_dwp_offsets.pcu_hash; + cu_context->cc_signature_present = TRUE; + } + return DW_DLV_OK; +} + +static int +finish_cu_context_via_cudie_inner( + Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Error *error) +{ + /* DW4: Look for DW_AT_dwo_id and + DW_AT_low_pc and more. + if there is one pick up the hash + DW5: hash in skeleton CU die + Also pick up cc_str_offset_base and + any other base values. */ + Dwarf_Die cudie = 0; + int resdwo = 0; + + /* Must call the internal siblingof so + we do not depend on the dbg...de_cu_context + used by and for dwarf_cu_header_* calls. */ + resdwo = _dwarf_siblingof_internal(dbg,NULL, + cu_context, + cu_context->cc_is_info, + &cudie, error); + if (resdwo == DW_DLV_OK) { + Dwarf_Half cutag = 0; + int resdwob = 0; + resdwob = find_cu_die_base_fields(dbg, + cu_context, + cudie, + error); + if (resdwob == DW_DLV_NO_ENTRY) { + /* The CU die has no children */ + dwarf_dealloc_die(cudie); + cudie = 0; + cu_context->cc_cu_die_has_children = FALSE; + return DW_DLV_OK; + } + if (resdwob == DW_DLV_ERROR) { + /* Not applicable or an error */ + dwarf_dealloc_die(cudie); + cudie = 0; + return resdwob; + } + resdwob = dwarf_tag(cudie,&cutag,error); + if (resdwob == DW_DLV_OK) { + cu_context->cc_cu_die_tag = cutag; + } + dwarf_dealloc_die(cudie); + return resdwob; + } + if (resdwo == DW_DLV_NO_ENTRY) { + /* no cudie. Empty CU. */ + return DW_DLV_OK; + } + /* no cudie. DW_DLV_ERROR.*/ + return resdwo; +} + +static void +local_dealloc_cu_context(Dwarf_Debug dbg, + Dwarf_CU_Context context) +{ + Dwarf_Hash_Table hash_table = 0; + + if (!context) { + return; + } + hash_table = context->cc_abbrev_hash_table; + if (hash_table) { + _dwarf_free_abbrev_hash_table_contents(hash_table, + FALSE); + hash_table->tb_entries = 0; + free(hash_table); + context->cc_abbrev_hash_table = 0; + } + dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT); +} + +static void +report_local_unit_type_error(Dwarf_Debug dbg, + int unit_type, + const char *msg, + Dwarf_Error *error) +{ + dwarfstring m; + + if (!error) { + return; + } + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_CU_UT_TYPE_VALUE: %s ",(char *)msg); + dwarfstring_append_printf_u(&m, + "the compilation unit unit_type is 0x%x," + " which is unknown to libdwarf. Corrupt DWARF.", + unit_type); + _dwarf_error_string(dbg,error,DW_DLE_CU_UT_TYPE_VALUE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* This function is used to create a CU Context for + a compilation-unit that begins at offset in + .debug_info. The CU Context is attached to the + list of CU Contexts for this dbg. It is assumed + that the CU at offset has not been read before, + and so do not call this routine before making + sure of this with _dwarf_find_CU_Context(). + Returns NULL on error. As always, being an + internal routine, assumes a good dbg. + + The offset argument is global offset, the offset + in the section, irrespective of CUs. + The offset has the DWP Package File offset built in + as it comes from the actual section. + + max_cu_local_offset is a local offset in this CU. + So zero of this field is immediately following the length + field of the CU header. so max_cu_local_offset is + identical to the CU length field. + max_cu_global_offset is the offset one-past the end + of this entire CU. */ +static int +_dwarf_make_CU_Context(Dwarf_Debug dbg, + Dwarf_Off offset,Dwarf_Bool is_info, + Dwarf_CU_Context * context_out,Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned typeoffset = 0; + Dwarf_Sig8 signaturedata; + Dwarf_Unsigned types_extra_len = 0; + Dwarf_Unsigned max_cu_local_offset = 0; + Dwarf_Unsigned max_cu_global_offset = 0; + Dwarf_Byte_Ptr cu_ptr = 0; + Dwarf_Byte_Ptr section_end_ptr = 0; + int local_length_size = 0; + Dwarf_Unsigned bytes_read = 0; + const char * secname = 0; + Dwarf_Debug_InfoTypes dis = 0; + struct Dwarf_Section_s * secdp = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Half unit_type = 0; + Dwarf_Unsigned version = 0; + Dwarf_Small * dataptr = 0; + int res = 0; + if (is_info) { + secname = dbg->de_debug_info.dss_name; + dis = &dbg->de_info_reading; + secdp = &dbg->de_debug_info; + } else { + secname = dbg->de_debug_types.dss_name; + dis = &dbg->de_types_reading; + secdp = &dbg->de_debug_types; + } + section_size = secdp->dss_size; + + signaturedata = dwarfsig8zero; + cu_context = + (Dwarf_CU_Context)_dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1); + if (!cu_context) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + cu_context->cc_dbg = dbg; + cu_context->cc_is_info = is_info; + + dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + /* Preliminary sanity checking. */ + if (!dataptr) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, DW_DLE_INFO_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (offset >= section_size) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, DW_DLE_INFO_HEADER_ERROR); + return DW_DLV_ERROR; + } + if ((offset+4) > section_size) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, DW_DLE_INFO_HEADER_ERROR); + return DW_DLV_ERROR; + } + section_end_ptr = dataptr+section_size; + cu_ptr = (Dwarf_Byte_Ptr) (dataptr+offset); + + if (section_name_ends_with_dwo(secname)) { + cu_context->cc_is_dwo = TRUE; + } + res = read_info_area_length_and_check(dbg, + cu_context, + offset, + &cu_ptr, + section_size, + section_end_ptr, + &max_cu_global_offset, + error); + if (res != DW_DLV_OK) { + local_dealloc_cu_context(dbg,cu_context); + return res; + } + local_length_size = cu_context->cc_length_size; + length = cu_context->cc_length; + max_cu_local_offset = length; + res = _dwarf_read_cu_version_and_abbrev_offset(dbg, + cu_ptr, + is_info, + local_length_size, + cu_context, + section_end_ptr, + &bytes_read,error); + if (res != DW_DLV_OK) { + local_dealloc_cu_context(dbg,cu_context); + return res; + } + version = cu_context->cc_version_stamp; + cu_ptr += bytes_read; + unit_type = cu_context->cc_unit_type; + if (cu_ptr > section_end_ptr) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, DW_DLE_INFO_HEADER_ERROR); + return DW_DLV_ERROR; + } + + /* In a dwp context, the abbrev_offset is + still incomplete. + We need to add in the base from the .debug_cu_index + or .debug_tu_index . Done below */ + + /* At this point, for DW4, the unit_type is not fully + correct as we don't know if it is a skeleton or + a split_compile or split_type */ + if (version == DW_CU_VERSION5 || + version == DW_CU_VERSION4) { + /* DW4/DW5 header fields, depending on UT type. + See DW5 section 7.5.1.x, DW4 + data is a GNU extension of DW4. */ + switch(unit_type) { + case DW_UT_split_type: + case DW_UT_type: { + types_extra_len = sizeof(Dwarf_Sig8) /* 8 */ + + local_length_size /*type_offset size*/; + break; + } + case DW_UT_skeleton: + case DW_UT_split_compile: { + types_extra_len = sizeof(Dwarf_Sig8) /* 8 */; + break; + } + case DW_UT_compile: /* No additional fields */ + case DW_UT_partial: /* No additional fields */ + break; + default: + /* Data corruption in libdwarf? */ + report_local_unit_type_error(dbg, unit_type, + "(DW4 or DW5)",error); + local_dealloc_cu_context(dbg,cu_context); + return DW_DLV_ERROR; + } + } + + /* Compare the space following the length field + to the bytes in the CU header. */ + if (length < + (CU_VERSION_STAMP_SIZE /* is 2 */ + + local_length_size /*for debug_abbrev offset */ + + CU_ADDRESS_SIZE_SIZE /* is 1 */ + + /* and finally size of the rest of the header: */ + types_extra_len)) { + + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error_string(dbg, error, DW_DLE_CU_LENGTH_ERROR, + "DW_DLE_CU_LENGTH_ERROR: reading version " + "stamp and address size fields"); + return DW_DLV_ERROR; + } + /* Now we can read the fields with some confidence, + we know the fields of the header are inside + the section. */ + + cu_context->cc_unit_type = unit_type; + switch(unit_type) { + case DW_UT_split_type: + case DW_UT_type: { + int tres = 0; + /* ASSERT: DW_CU_VERSION4 or DW_CU_VERSION5, + determined by logic above. + Now read the debug_types extra header fields of + the signature (8 bytes) and the typeoffset. + This can be in executable, ordinary object + (as in Type Unit), + there was no dwo in DWARF4 + */ + if ((cu_ptr + sizeof(signaturedata)) > section_end_ptr) { + _dwarf_error_string(dbg, error, DW_DLE_CU_LENGTH_ERROR, + "DW_DLE_CU_LENGTH_ERROR: reading " + "Dwarf_Sig8 signature field"); + local_dealloc_cu_context(dbg,cu_context); + return DW_DLV_ERROR; + } + memcpy(&signaturedata,cu_ptr,sizeof(signaturedata)); + cu_ptr += sizeof(signaturedata); + tres = _dwarf_read_unaligned_ck_wrapper(dbg, + &typeoffset,cu_ptr,local_length_size, + section_end_ptr,error); + if (tres != DW_DLV_OK ) { + local_dealloc_cu_context(dbg,cu_context); + return tres; + } + cu_context->cc_signature = signaturedata; + cu_context->cc_signature_present = TRUE; + cu_context->cc_signature_offset = typeoffset; + if (typeoffset >= max_cu_local_offset) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_TYPEOFFSET_BAD); + return DW_DLV_ERROR; + } + } + break; + case DW_UT_skeleton: + case DW_UT_split_compile: { + if ((cu_ptr + sizeof(signaturedata)) > section_end_ptr) { + _dwarf_error_string(dbg, error, DW_DLE_CU_LENGTH_ERROR, + "DW_DLE_CU_LENGTH_ERROR: reading " + "Dwarf_Sig8 signature field"); + local_dealloc_cu_context(dbg,cu_context); + return DW_DLV_ERROR; + } + /* These unit types make a pair and + paired units have identical signature.*/ + memcpy(&signaturedata,cu_ptr,sizeof(signaturedata)); + cu_context->cc_signature = signaturedata; + cu_context->cc_signature_present = TRUE; + + break; + } + /* The following with no additional fields */ + case DW_UT_compile: + case DW_UT_partial: + break; + default: { + /* Data corruption in libdwarf? */ + report_local_unit_type_error(dbg, unit_type, + "",error); + local_dealloc_cu_context(dbg,cu_context); + return DW_DLV_ERROR; + } + } + cu_context->cc_abbrev_hash_table = + (Dwarf_Hash_Table) calloc(1, + sizeof(struct Dwarf_Hash_Table_s)); + if (!cu_context->cc_abbrev_hash_table) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + cu_context->cc_debug_offset = offset; + + /* This is recording an overall section value for later + sanity checking. */ + dis->de_last_offset = max_cu_global_offset; + *context_out = cu_context; + return DW_DLV_OK; +} + +static int +reloc_incomplete(int res,Dwarf_Error err) +{ + Dwarf_Unsigned e = 0; + + if (res == DW_DLV_OK) { + return FALSE; + } + if (res == DW_DLV_NO_ENTRY) { + return FALSE; + } + e = dwarf_errno(err); + switch(e) { + case DW_DLE_RELOC_MISMATCH_INDEX: + case DW_DLE_RELOC_MISMATCH_RELOC_INDEX: + case DW_DLE_RELOC_MISMATCH_STRTAB_INDEX: + case DW_DLE_RELOC_SECTION_MISMATCH: + case DW_DLE_RELOC_SECTION_MISSING_INDEX: + case DW_DLE_RELOC_SECTION_LENGTH_ODD: + case DW_DLE_RELOC_SECTION_PTR_NULL: + case DW_DLE_RELOC_SECTION_MALLOC_FAIL: + case DW_DLE_SEEK_OFF_END: + case DW_DLE_RELOC_INVALID: + case DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD: + case DW_DLE_ELF_RELOC_SECTION_ERROR: + case DW_DLE_RELOCATION_SECTION_SIZE_ERROR: + return TRUE; + default: break; + } + return FALSE; +} + +/* Returns offset of next compilation-unit thru next_cu_offset + pointer. + It sequentially moves from one + cu to the next. The current cu is recorded + internally by libdwarf. */ +int +dwarf_next_cu_header_d(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature, + Dwarf_Unsigned * typeoffset, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Half * header_cu_type, + Dwarf_Error * error) +{ + Dwarf_Bool has_signature = FALSE; + int res = 0; + + res = _dwarf_next_cu_header_internal(dbg, + is_info, + cu_header_length, + version_stamp, + abbrev_offset, + address_size, + offset_size, + extension_size, + signature, + &has_signature, + typeoffset, + next_cu_offset, + header_cu_type, + error); + return res; +} + +static void +local_attrlist_dealloc(Dwarf_Debug dbg, + Dwarf_Signed atcount, + Dwarf_Attribute *alist) +{ + Dwarf_Signed i = 0; + + for ( ; i < atcount; ++i) { + dwarf_dealloc(dbg,alist[i],DW_DLA_ATTR); + } + dwarf_dealloc(dbg,alist,DW_DLA_LIST); +} + +static int +_dwarf_setup_base_address(Dwarf_Debug dbg, + const char *attrname, + Dwarf_Attribute attr, + Dwarf_Signed at_addr_base_attrnum, + Dwarf_CU_Context cucon, + Dwarf_Error *error) +{ + int lres = 0; + Dwarf_Half form = 0; + + /* If the form is indexed, we better have + seen DW_AT_addr_base.! */ + lres = dwarf_whatform(attr,&form,error); + if (lres != DW_DLV_OK) { + return lres; + } + if (dwarf_addr_form_is_indexed(form)) { + if (at_addr_base_attrnum < 0) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_ATTR_NO_CU_CONTEXT: The "); + dwarfstring_append(&m,(char *)attrname); + dwarfstring_append(&m," CU_DIE uses " + "an indexed attribute yet " + "DW_AT_addr_base is not in the CU DIE."); + _dwarf_error_string(dbg,error, + DW_DLE_ATTR_NO_CU_CONTEXT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + lres = dwarf_formaddr(attr, + &cucon->cc_low_pc,error); + if (lres == DW_DLV_OK) { + /* Pretending low_pc (ie cu base address for loclists) + if it was DW_AT_entry_pc with no DW_AT_low_pc + Allowing DW_AT_entry_pc */ + cucon->cc_low_pc_present = TRUE; + } else { + /* Something is badly wrong. */ + return lres; + } + return lres; +} + +/* + For a DWP/DWO the base fields + of a CU are inherited from the skeleton. + DWARF5 section 3.1.3 + "Split Full Compilation Unit Entries". +*/ +static int +find_cu_die_base_fields(Dwarf_Debug dbg, + Dwarf_CU_Context cucon, + Dwarf_Die cudie, + Dwarf_Error* error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Attribute * alist = 0; + Dwarf_Signed atcount = 0; + unsigned version_stamp = 2; + int alres = 0; + Dwarf_Signed i = 0; + Dwarf_Signed low_pc_attrnum = -1; + Dwarf_Signed entry_pc_attrnum = -1; + Dwarf_Signed at_addr_base_attrnum = -1; + + cu_context = cudie->di_cu_context; + version_stamp = cu_context->cc_version_stamp; + + alres = dwarf_attrlist(cudie, &alist, + &atcount,error); + if (alres != DW_DLV_OK) { + /* Something is badly wrong. No attrlist! */ + return alres; + } + /* DW_AT_dwo_id and/or DW_AT_GNU_dwo_id + are only found in some + experimental DWARF4. + Even DWARF3,4 use DW_AT_low_pc as base address + DWARF5 changed CU header contents + to make this attribute unnecessary. + DW_AT_GNU_odr_signature is the same format, + but is in a different namespace so not + appropriate here.. + */ + for (i = 0; i < atcount; ++i) { + Dwarf_Half attrnum = 0; + Dwarf_Half form = 0; + int ares = 0; + int ares2 = 0; + Dwarf_Attribute attr = alist[i]; + + ares = dwarf_whatattr(attr,&attrnum,error); + if (ares == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + ares2 = dwarf_whatform(attr,&form,error); + if (ares2 == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + /* We are not returning on DW_DLV_NO_ENTRY + or DW_DLV_ERROR here. Such will be + caught later. Lets finish a CU die + scan and finish the cu_context */ + if (ares == DW_DLV_OK && ares2 == DW_DLV_OK) { + switch(form) { + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + cucon->cc_at_strx_present = TRUE; + default: + break; + } + switch(attrnum) { + case DW_AT_dwo_id: + case DW_AT_GNU_dwo_id: { + Dwarf_Sig8 signature; + /* This is for DWARF4 with an early + non-standard version + of split dwarf. Not DWARF5. */ + int sres = 0; + if (version_stamp != DW_CU_VERSION4 ) { + /* Not supposed to happen. */ + local_attrlist_dealloc(dbg,atcount,alist); + _dwarf_error(dbg,error, + DW_DLE_IMPROPER_DWO_ID); + return DW_DLV_ERROR; + } + signature = dwarfsig8zero; + sres = dwarf_formsig8_const(attr, + &signature,error); + if (sres == DW_DLV_OK) { + if (!cucon->cc_signature_present) { + cucon->cc_signature = signature; + cucon->cc_signature_present = TRUE; + } else { + /* Something wrong. Two styles of sig? + Can happen with DWARF4 + debug-fission extension DWO_id. + */ + if (memcmp(&signature,&cucon->cc_signature, + sizeof(signature))) { + /* The two sigs do not match! */ + const char *m="DW_DLE_SIGNATURE_MISMATCH" + "DWARF4 extension fission signature" + " and DW_AT_GNU_dwo_id do not match" + " ignoring DW_AT[_GNU]_dwo_id"; + dwarf_insert_harmless_error(dbg, + (char*)m); + } + } + } else { + /* Something is badly wrong. */ + local_attrlist_dealloc(dbg,atcount,alist); + return sres; + } + /* Something is badly wrong. */ + break; + } + /* If, in .debug_rnglists for a CU the + applicable range has no base address + this attribute provides a base address. + If this is indexed doing this now would + lead to an infinite recursion. + So wait till all the other fields seen. + */ + case DW_AT_low_pc: { + low_pc_attrnum = i; + break; + } + /* DW_AT_producer 4.2.1 (Based on Apple Inc. build 5658) + (LLVM build 2336.1.00) uses DW_AT_entry_pc as the + base address (DW_AT_entry_pc + first appears in DWARF3). + So we allow that as an extension, + as a 'low_pc' if there is DW_AT_entry_pc with + no DW_AT_low_pc. 19 May 2022. + */ + case DW_AT_entry_pc: { + entry_pc_attrnum = i; + break; + } + + /* The offset is of the first offset in + .debug_str_offsets that is the string table + offset array for this CU. */ + case DW_AT_str_offsets_base:{ + int udres = 0; + Dwarf_Bool is_info = cucon->cc_is_info; + + udres = _dwarf_internal_global_formref_b(attr, + /* avoid recurse creating context */ 1, + &cucon->cc_str_offsets_array_offset, + &is_info, + error); + if (udres == DW_DLV_OK) { + cucon->cc_str_offsets_array_offset_present = TRUE; + } else { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong. */ + return udres; + } + break; + } + /* offset in .debug_loclists of the offsets table + applicable to this CU. */ + case DW_AT_loclists_base: { + int udres = 0; + Dwarf_Bool is_info = cucon->cc_is_info; + + udres = _dwarf_internal_global_formref_b(attr, + /* avoid recurse creating context */ 1, + &cucon->cc_loclists_base, + &is_info, + error); + if (udres == DW_DLV_OK) { + cucon->cc_loclists_base_present = TRUE; + } else { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong. */ + return udres; + } + break; + } + /* Base offset in .debug_addr of the addr table + for this CU. DWARF5 (and possibly GNU DWARF4) + So we really want to look in only + this section, not an offset referring + to another (DWARF5 debug_info vs debug_types) */ + case DW_AT_addr_base: + case DW_AT_GNU_addr_base: { + int udres = 0; + Dwarf_Bool is_info = cucon->cc_is_info; + + at_addr_base_attrnum = i; + + udres = _dwarf_internal_global_formref_b(attr, + /* avoid recurse creating context */ 1, + &cucon->cc_addr_base, + &is_info, + error); + if (udres == DW_DLV_OK) { + if (is_info == cucon->cc_is_info) { + /* Only accept if same .debug section, + which is relevant for DWARF4 */ + cucon->cc_addr_base_present = TRUE; + } + } else { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong. */ + return udres; + } + break; + } + case DW_AT_GNU_ranges_base: { + /* The DW4 ranges base was never used in GNU + but did get emitted in skeletons. + http://llvm.1065342.n5.nabble.com/ + DebugInfo-DW-AT-GNU-ranges-base-in- + non-fission-td64194.html + But we accept it anyway. */ + /* offset in .debug_rnglists of the offsets table + applicable to this CU. + Note that this base applies when + referencing from the dwp, but NOT + when referencing from the a.out */ + int udres = 0; + Dwarf_Bool is_info = cucon->cc_is_info; + + udres = _dwarf_internal_global_formref_b(attr, + /* avoid recurse creating context */ 1, + &cucon->cc_ranges_base, + &is_info, + error); + if (udres == DW_DLV_OK) { + cucon->cc_ranges_base_present = TRUE; + } else { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong. */ + return udres; + } + break; + } + case DW_AT_rnglists_base: { + int udres = 0; + Dwarf_Bool is_info = cucon->cc_is_info; + + udres = _dwarf_internal_global_formref_b(attr, + /* avoid recurse creating context */ 1, + &cucon->cc_rnglists_base, + &is_info, + error); + if (udres == DW_DLV_OK) { + cucon->cc_rnglists_base_present = TRUE; + } else { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong. */ + return udres; + } + break; + } + /* A signature, found in a DWARF5 skeleton + compilation unit. */ + case DW_AT_GNU_dwo_name: + case DW_AT_dwo_name: { + int dnres = 0; + + dnres = dwarf_formstring(attr, + &cucon->cc_dwo_name,error); + if (dnres != DW_DLV_OK) { + local_attrlist_dealloc(dbg,atcount,alist); + return dnres; + } + cucon->cc_dwo_name_present = TRUE; + break; + } + default: /* do nothing, not an attribute + we need to deal with here. */ + break; + } + } + } + if (low_pc_attrnum >= 0 ){ + int battr = 0; + + /* Prefer DW_AT_low_pc */ + Dwarf_Attribute attr = alist[low_pc_attrnum]; + battr = _dwarf_setup_base_address(dbg,"DW_AT_low_pc", + attr,at_addr_base_attrnum, cucon,error); + if (battr != DW_DLV_OK) { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong */ + return battr; + } + } else if (entry_pc_attrnum >= 0) { + int battr = 0; + + /* Pretending that DW_AT_entry_pc with no + DW_AT_low_pc is a valid base address for + loccation lists. + DW_AT_producer 4.2.1 (Based on Apple Inc. build 5658) + (LLVM build 2336.1.00) uses DW_AT_entry_pc as the + base address (DW_AT_entry_pc first appears in DWARF3). + So we allow that as an extension, + as a 'low_pc' if there is DW_AT_entry_pc with + no DW_AT_low_pc. 19 May 2022. */ + Dwarf_Attribute attr = alist[entry_pc_attrnum]; + battr = _dwarf_setup_base_address(dbg,"DW_AT_entry_pc", + attr,at_addr_base_attrnum, cucon,error); + if (battr != DW_DLV_OK) { + local_attrlist_dealloc(dbg,atcount,alist); + /* Something is badly wrong */ + return battr; + } + } + local_attrlist_dealloc(dbg,atcount,alist); + alist = 0; + atcount = 0; + { + int chres = 0; + Dwarf_Half flag = 0; + + /* always winds up with cc_cu_die_has_children + set intentionally...to something. */ + cucon->cc_cu_die_has_children = TRUE; + chres = dwarf_die_abbrev_children_flag(cudie,&flag); + /* If chres is not DW_DLV_OK the assumption + of children remains true. */ + if (chres == DW_DLV_OK) { + cucon->cc_cu_die_has_children = flag; + } + } + return DW_DLV_OK; +} + +/* Called only for DWARF4 */ +static void +assign_correct_unit_type(Dwarf_CU_Context cu_context) +{ + Dwarf_Half tag = cu_context->cc_cu_die_tag; + if (!cu_context->cc_cu_die_has_children) { + if (cu_context->cc_signature_present) { + if (tag == DW_TAG_compile_unit || + tag == DW_TAG_type_unit ) { + cu_context->cc_unit_type = DW_UT_skeleton; + } + } + } else { + if (cu_context->cc_signature_present) { + if (tag == DW_TAG_compile_unit) { + cu_context->cc_unit_type = DW_UT_split_compile; + } else if (tag == DW_TAG_type_unit) { + cu_context->cc_unit_type = DW_UT_split_type; + } + } + } +} + +static int +finish_up_cu_context_from_cudie(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_CU_Context cu_context, + Dwarf_Error *error) +{ + int version = cu_context->cc_version_stamp; + Dwarf_Sig8 signaturedata = cu_context->cc_signature; + int res = 0; + + /* Loads and initializes the dwarf .debug_cu_index + and .debug_tu_index split dwarf package + file sections */ + res = fill_in_dwp_offsets_if_present(dbg, + cu_context, + &signaturedata, + offset, + error); + if (res != DW_DLV_OK) { + return res; + } + if (cu_context->cc_dwp_offsets.pcu_type) { + Dwarf_Unsigned absize = 0; + Dwarf_Unsigned aboff = 0; + + aboff = _dwarf_get_dwp_extra_offset( + &cu_context->cc_dwp_offsets, + DW_SECT_ABBREV, &absize); + cu_context->cc_abbrev_offset += aboff; + } + + if (cu_context->cc_abbrev_offset >= + dbg->de_debug_abbrev.dss_size) { + _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR); + return DW_DLV_ERROR; + } + /* Now we can read the CU die and determine + the correct DW_UT_ type for DWARF4 and some + offset base fields for DW4-fission and DW5, + and even DW3 and DW4 and some non-std DW2 */ + { + res = finish_cu_context_via_cudie_inner(dbg, + cu_context, + error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res != DW_DLV_OK) { + return res; + } + if (version == DW_CU_VERSION4) { + assign_correct_unit_type(cu_context); + } + if (cu_context->cc_signature_present) { + /* Initially just for DW_SECT_STR_OFFSETS, + finds the section offset of the + contribution which is not the same + as the table offset. */ + res = _dwarf_find_all_offsets_via_fission(dbg, + cu_context,error); + if (res == DW_DLV_ERROR) { + /* something seriously wrong. */ + return res; + } + } + } + return DW_DLV_OK; +} +/* + CU_Contexts do not overlap. + cu_context we see here is not in the list we + are updating. See _dwarf_find_CU_Context() + + Invariant: cc_debug_offset in strictly + ascending order in the list. +*/ +static int +insert_into_cu_context_list(Dwarf_Debug_InfoTypes dis, + Dwarf_CU_Context icu_context) +{ + Dwarf_Unsigned ioffset = icu_context->cc_debug_offset; + Dwarf_Unsigned eoffset = 0; + Dwarf_Unsigned hoffset = 0; + Dwarf_Unsigned coffset = 0; + Dwarf_CU_Context next = 0; + Dwarf_CU_Context past = 0; + Dwarf_CU_Context cur = 0; + + /* Add the context into the section context list. + This is the one and only place where it is + saved for re-use and eventual dealloc. */ + if (!dis->de_cu_context_list) { + /* First cu encountered. */ + dis->de_cu_context_list = icu_context; + dis->de_cu_context_list_end = icu_context; + return DW_DLV_OK; + } + if (!dis->de_cu_context_list_end) { + return DW_DLV_ERROR; + } + eoffset = dis->de_cu_context_list_end->cc_debug_offset; + if (eoffset < ioffset) { + /* Normal case, add at end. */ + dis->de_cu_context_list_end->cc_next = icu_context; + dis->de_cu_context_list_end = icu_context; + return DW_DLV_OK; + } + hoffset = dis->de_cu_context_list->cc_debug_offset; + if (hoffset > ioffset) { + /* insert as new head. Unusual. */ + next = dis->de_cu_context_list; + dis->de_cu_context_list = icu_context; + dis->de_cu_context_list->cc_next = next; + /* No need to touch de_cu_context_list_end */ + return DW_DLV_OK; + } + cur = dis->de_cu_context_list; + past = 0; + /* Insert in middle somewhere. Neither at + start nor end. + ASSERT: cur non-null + ASSERT: past non-null */ + past = cur; + cur = cur->cc_next; + for ( ; cur ; cur = next) { + next = cur->cc_next; + coffset = cur->cc_debug_offset; + if (coffset > ioffset) { + /* Insert before cur, using past. + ASSERT: past non-null */ + past->cc_next = icu_context; + icu_context->cc_next = cur; + return DW_DLV_OK; + } + past = cur; + } + /* Impossible, for end, coffset (ie, eoffset) > ioffset */ + /* NOTREACHED */ + return DW_DLV_ERROR; +} + +Dwarf_Unsigned +_dwarf_calculate_next_cu_context_offset(Dwarf_CU_Context cu_context) +{ + Dwarf_Unsigned next_cu_offset = 0; + + next_cu_offset = cu_context->cc_debug_offset + + cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size; + return next_cu_offset; +} + +int +_dwarf_create_a_new_cu_context_record_on_list( + Dwarf_Debug dbg, + Dwarf_Debug_InfoTypes dis, + Dwarf_Bool is_info, + Dwarf_Unsigned section_size, + Dwarf_Unsigned new_cu_offset, + Dwarf_CU_Context *context_out, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_CU_Context cu_context = 0; + int icres = 0; + + if ((new_cu_offset + + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= + section_size) { + _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD); + return DW_DLV_ERROR; + } + res = _dwarf_make_CU_Context(dbg, new_cu_offset,is_info, + &cu_context,error); + if (res != DW_DLV_OK) { + return res; + } + /* The called func does not dealloc cu_context + in case of error, so we do it here. */ + res = finish_up_cu_context_from_cudie(dbg,new_cu_offset, + cu_context,error); + if (res == DW_DLV_ERROR) { + local_dealloc_cu_context(dbg,cu_context); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + local_dealloc_cu_context(dbg,cu_context); + return res; + } + /* Add the new cu_context to a list of contexts */ + icres = insert_into_cu_context_list(dis,cu_context); + if (icres == DW_DLV_ERROR) { + local_dealloc_cu_context(dbg,cu_context); + _dwarf_error_string(dbg,error,DW_DLE_DIE_NO_CU_CONTEXT, + "DW_DLE_DIE_NO_CU_CONTEXT" + "Impossible error inserting into internal context list"); + return icres; + } + *context_out = cu_context; + return DW_DLV_OK; +} + +int +_dwarf_load_die_containing_section(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Error *error) +{ + Dwarf_Error err2 = 0; + + int resd = is_info? + _dwarf_load_debug_info(dbg, &err2): + _dwarf_load_debug_types(dbg,&err2); + if (resd == DW_DLV_ERROR) { + if (reloc_incomplete(resd,err2)) { + /* We will assume all is ok, though it is not. + Relocation errors need not be fatal. */ + char msg_buf[300]; + char *dwerrmsg = 0; + char *msgprefix = + "Relocations did not complete successfully, " + "but we are " " ignoring error: "; + size_t totallen = 0; + size_t prefixlen = 0; + + dwerrmsg = dwarf_errmsg(err2); + prefixlen = strlen(msgprefix); + totallen = prefixlen + strlen(dwerrmsg); + if ( totallen >= sizeof(msg_buf)) { + const char *m= "Error:corrupted dwarf message table!"; + /* Impossible unless something corrupted. + Provide a shorter dwerrmsg*/ + _dwarf_safe_strcpy(msg_buf,sizeof(msg_buf), + m,strlen(m)); + } else { + _dwarf_safe_strcpy(msg_buf,sizeof(msg_buf), + msgprefix,prefixlen); + _dwarf_safe_strcpy(msg_buf +prefixlen, + sizeof(msg_buf)-prefixlen, + dwerrmsg,strlen(dwerrmsg)); + } + dwarf_insert_harmless_error(dbg,msg_buf); + /* Fall thru to use the newly loaded section. + even though it might not be adequately + relocated. */ + dwarf_dealloc_error(dbg,err2); + if (error) { + *error = 0; + } + return DW_DLV_OK; + } + if (error) { + *error = err2; + } else { + dwarf_dealloc_error(dbg,err2); + } + return DW_DLV_ERROR; + } + return resd; +} + +int +_dwarf_next_cu_header_internal(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature_out, + Dwarf_Bool * has_signature, + Dwarf_Unsigned *typeoffset, + Dwarf_Unsigned * next_cu_offset, + + /* header_type: DW_UT_compile, DW_UT_partial, + DW_UT_type, returned through the pointer. + A new item in DWARF5, synthesized for earlier DWARF + CUs (& TUs). */ + Dwarf_Half * header_type, + Dwarf_Error * error) +{ + /* Offset for current and new CU. */ + Dwarf_Unsigned new_offset = 0; + + /* CU Context for current CU. */ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug_InfoTypes dis = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Small *dataptr = 0; + struct Dwarf_Section_s *secdp = 0; + int res = 0; + + /* ***** BEGIN CODE ***** */ + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: calling dwarf_next_cuheader_d() " + "Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (is_info) { + dis =&dbg->de_info_reading; + dataptr = dbg->de_debug_info.dss_data; + secdp = &dbg->de_debug_info; + } else { + dis =&dbg->de_types_reading; + dataptr = dbg->de_debug_types.dss_data; + secdp = &dbg->de_debug_types; + } + + if (!dataptr) { + res = _dwarf_load_die_containing_section(dbg, + is_info, error); + if (res != DW_DLV_OK) { + return res; + } + } +#if 0 + /* Get offset into .debug_info of next CU. + If dbg has no context, + this has to be the first one. */ + if (!dis->de_cu_context) { + Dwarf_Small *dataptr = is_info? + dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + new_offset = 0; + if (!dataptr) { + Dwarf_Error err2= 0; + int resd = is_info? + _dwarf_load_debug_info(dbg, &err2): + _dwarf_load_debug_types(dbg,&err2); + + if (resd != DW_DLV_OK) { + if (reloc_incomplete(resd,err2)) { + /* We will assume all is ok, though it is not. + Relocation errors need not be fatal. */ + char msg_buf[300]; + char *dwerrmsg = 0; + char *msgprefix = + "Relocations did not complete successfully, " + "but we are " " ignoring error: "; + size_t totallen = 0; + size_t prefixlen = 0; + + dwerrmsg = dwarf_errmsg(err2); + prefixlen = strlen(msgprefix); + totallen = prefixlen + strlen(dwerrmsg); + if ( totallen >= sizeof(msg_buf)) { + /* Impossible unless something corrupted. + Provide a shorter dwerrmsg*/ + const char * m= + "Error:corrupted dwarf message table!"); + _dwarf_safe_strcpy(msg_buf, + sizeof(msg_buf), + m,strlen(m)); + } else { + _dwarf_safe_strcpy,strcpy(msg_buf, + sizeof(msg_buf),msgprefix, + prefixlen); + _dwarf_safe_strcpy(msg_buf+prefixlen, + sizeof(msg_buf)-prefixlen, + dwerrmsg,strlen(dwerrmsg)); + } + dwarf_insert_harmless_error(dbg,msg_buf); + /* Fall thru to use the newly loaded section. + even though it might not be adequately + relocated. */ + if (resd == DW_DLV_ERROR) { + dwarf_dealloc_error(dbg,err2); + err2 = 0; + } + } else { + if (error) { + *error = err2; + err2 = 0; + } + /* There is nothing here, or + what is here is damaged. */ + return resd; + } + } + } + } +#endif /*0*/ + if (!dis->de_cu_context) { + /* We are leaving new_offset zero. We are at the + start of a section. */ + new_offset = 0; + } else { + new_offset = _dwarf_calculate_next_cu_context_offset( + dis->de_cu_context); + } + + /* Check that there is room in .debug_info beyond + the new offset for at least a new cu header. + If not, return DW_DLV_NO_ENTRY to indicate end + of debug_info section, and reset + de_cu_debug_info_offset to + enable looping back through the cu's. */ + section_size = secdp->dss_size; + if ((new_offset + + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= + section_size) { + /* We must reset as we will not create a proper + de_cu_context here, see comment just above. */ + dis->de_cu_context = NULL; + return DW_DLV_NO_ENTRY; + } + + /* Check if this CU has been read before. */ + cu_context = _dwarf_find_CU_Context(dbg, new_offset,is_info); + + /* If not, make CU Context for it. */ + if (!cu_context) { + res = _dwarf_create_a_new_cu_context_record_on_list( + dbg,dis,is_info,section_size,new_offset, + &cu_context,error); + if (res != DW_DLV_OK) { + return res; + } + } + /* Next assignment is what makes + _dwarf_next_cu_header*() + with no offset presented work to march + through all the CUs in order. Other places + creating a cu_context do not set de_cu_context. */ + dis->de_cu_context = cu_context; + if (cu_header_length) { + *cu_header_length = cu_context->cc_length; + } + if (version_stamp) { + *version_stamp = cu_context->cc_version_stamp; + } + if (abbrev_offset) { + *abbrev_offset = cu_context->cc_abbrev_offset; + } + if (address_size) { + *address_size = cu_context->cc_address_size; + } + if (offset_size) { + *offset_size = cu_context->cc_length_size; + } + if (extension_size) { + *extension_size = cu_context->cc_extension_size; + } + if (header_type) { + *header_type = cu_context->cc_unit_type; + } + if (typeoffset) { + *typeoffset = cu_context->cc_signature_offset; + } + if (signature_out) { + *signature_out = cu_context->cc_signature; + } + if (has_signature) { + *has_signature = cu_context->cc_signature_present; + } + /* Determine the offset of the next CU. */ + new_offset = new_offset + cu_context->cc_length + + cu_context->cc_length_size + cu_context->cc_extension_size; + /* Allowing null argument starting 22 April 2019. */ + if (next_cu_offset) { + *next_cu_offset = new_offset; + } + { + Dwarf_Debug tieddbg = 0; + int tres = 0; + tieddbg = dbg->de_tied_data.td_tied_object; + if (tieddbg) { + tres = _dwarf_merge_all_base_attrs_of_cu_die( + dbg, cu_context, + tieddbg, 0, + error); + } + if (tres == DW_DLV_ERROR && error) { + /* We'll assume any errors will be + discovered later. Lets get our CU_context + finished. + if error NULL it's a caller issue + and there is nothing we can do here */ + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + } + return DW_DLV_OK; +} + +/* This involves data in a split dwarf or package file. + + Given hash signature, return the CU_die of the applicable CU. + The hash is assumed to be from 'somewhere'. + For DWARF 4: + From a skeleton DIE DW_AT_GNU_dwo_id ("cu" case) or + From a DW_FORM_ref_sig8 ("tu" case). + For DWARF5: + From dwo_id in a skeleton CU header (DW_UT_skeleton). + From a DW_FORM_ref_sig8 ("tu" case). + + If "tu" request, the CU_die + of of the type unit. + Works on either a dwp package file or a dwo object. + + If "cu" request, the CU_die + of the compilation unit. + Works on either a dwp package file or a dwo object. + + If the hash passed is not present, returns DW_DLV_NO_ENTRY + (but read the next two paragraphs for more detail). + + If a dwp package file with the hash signature + is present in the applicable index but no matching + compilation unit can be found, it returns DW_DLV_ERROR. + + If a .dwo object there is no index and we look at the + compilation units (possibly all of them). If not present + then we return DW_DLV_NO_ENTRY. + + The returned_die is a CU DIE if the sig_type is "cu". + The returned_die is a type DIE if the sig_type is "tu". + Perhaps both should return CU die. + + New 27 April, 2015 +*/ +int +dwarf_die_from_hash_signature(Dwarf_Debug dbg, + Dwarf_Sig8 * hash_sig, + const char * sig_type /* "tu" or "cu"*/, + Dwarf_Die * returned_die, + Dwarf_Error* error) +{ + Dwarf_Bool is_type_unit = FALSE; + int sres = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: calling dwarf_die_from_hash_signature()" + "Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + + sres = _dwarf_load_debug_info(dbg,error); + if (sres == DW_DLV_ERROR) { + return sres; + } + sres = _dwarf_load_debug_types(dbg,error); + if (sres == DW_DLV_ERROR) { + return sres; + } + + if (!strcmp(sig_type,"tu")) { + is_type_unit = TRUE; + } else if (!strcmp(sig_type,"cu")) { + is_type_unit = FALSE; + } else { + _dwarf_error(dbg,error,DW_DLE_SIG_TYPE_WRONG_STRING); + return DW_DLV_ERROR; + } + + if (_dwarf_file_has_debug_fission_index(dbg)) { + /* This is a dwp package file. */ + int fisres = 0; + Dwarf_Bool is_info2 = TRUE; + Dwarf_Off cu_header_off = 0; + Dwarf_Off cu_size = 0; + Dwarf_Off cu_die_off = 0; + Dwarf_Off typeoffset = 0; + Dwarf_Die cudie = 0; + Dwarf_Die typedie = 0; + Dwarf_CU_Context context = 0; + Dwarf_Debug_Fission_Per_CU fiss; + + memset(&fiss,0,sizeof(fiss)); + fisres = dwarf_get_debugfission_for_key(dbg,hash_sig, + sig_type,&fiss,error); + if (fisres != DW_DLV_OK) { + return fisres; + } + /* Found it */ + if (is_type_unit) { + /* DW4 has debug_types, so look in .debug_types + Else look in .debug_info. */ + is_info2 = dbg->de_debug_types.dss_size?FALSE:TRUE; + } else { + is_info2 = TRUE; + } + + cu_header_off = _dwarf_get_dwp_extra_offset(&fiss, + is_info2?DW_SECT_INFO:DW_SECT_TYPES, + &cu_size); + + fisres = dwarf_get_cu_die_offset_given_cu_header_offset_b( + dbg,cu_header_off, + is_info2, + &cu_die_off,error); + if (fisres != DW_DLV_OK) { + return fisres; + } + fisres = dwarf_offdie_b(dbg,cu_die_off,is_info2, + &cudie,error); + if (fisres != DW_DLV_OK) { + return fisres; + } + if (!is_type_unit) { + *returned_die = cudie; + return DW_DLV_OK; + } + context = cudie->di_cu_context; + typeoffset = context->cc_signature_offset; + typeoffset += cu_header_off; + fisres = dwarf_offdie_b(dbg,typeoffset,is_info2, + &typedie,error); + if (fisres != DW_DLV_OK) { + dwarf_dealloc(dbg,cudie,DW_DLA_DIE); + return fisres; + } + *returned_die = typedie; + dwarf_dealloc(dbg,cudie,DW_DLA_DIE); + return DW_DLV_OK; + } + /* Look thru all the CUs, there is no DWP tu/cu index. + There will be COMDAT sections for the type TUs + (DW_UT_type). + A single non-comdat for the DW_UT_compile. */ + /* FIXME: DW_DLE_DEBUG_FISSION_INCOMPLETE */ + _dwarf_error(dbg,error,DW_DLE_DEBUG_FISSION_INCOMPLETE); + return DW_DLV_ERROR; +} + +static int +_dwarf_ptr_CU_offset(Dwarf_CU_Context cu_context, + Dwarf_Byte_Ptr di_ptr, + Dwarf_Bool is_info, + Dwarf_Off * cu_off) +{ + Dwarf_Debug dbg = cu_context->cc_dbg; + Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + *cu_off = (di_ptr - dataptr); + return DW_DLV_OK; +} +#if 0 /* FOR DEBUGGING */ +/* Just for debug purposes */ +void print_sib_offset(Dwarf_Die sibling) +{ + Dwarf_Off sib_off; + Dwarf_Error error; + dwarf_dieoffset(sibling,&sib_off,&error); + fprintf(stderr," SIB OFF = 0x%" DW_PR_XZEROS DW_PR_DUx,sib_off); +} +void print_ptr_offset(Dwarf_CU_Context cu_context, + Dwarf_Byte_Ptr di_ptr) +{ + Dwarf_Off ptr_off; + _dwarf_ptr_CU_offset(cu_context,di_ptr, + di_ptr->di_is_info,&ptr_off); + fprintf(stderr," PTR OFF = 0x%" DW_PR_XZEROS DW_PR_DUx,ptr_off); +} +#endif /*0*/ + +/* Validate the sibling DIE. This only makes sense to call + if the sibling's DIEs have been travsersed and + dwarf_child() called on each, + so that the last DIE dwarf_child saw was the last. + Essentially ensuring that (after such traversal) that we + are in the same place a sibling attribute would identify. + In case we return DW_DLV_ERROR, the global offset of the last + DIE traversed by dwarf_child is returned through *offset + + It is essentially guaranteed that dbg->de_last_die + is a stale DIE pointer of a deallocated DIE when we get here. + It must not be used as a DIE pointer here, + just as a sort of anonymous pointer that we just check against + NULL. + + There is a (subtle?) dependence on the fact that when we + call this the last dwarf_child() call would have been for + this sibling. + Meaning that this works in a depth-first + traversal even though there + is no stack of 'de_last_die' values. + + The check for dbg->de_last_die just ensures sanity. + + If one is switching between normal debug_frame and eh_frame + (traversing them in tandem, let us say) in a single + Dwarf_Debug this validator makes no sense. + It works if one processes a .debug_frame (entirely) and + then an eh_frame (or vice versa) though. + Use caution. +*/ +int +dwarf_validate_die_sibling(Dwarf_Die sibling,Dwarf_Off *offset) +{ + Dwarf_Debug dbg = 0; + Dwarf_Error *error = 0; + Dwarf_Debug_InfoTypes dis = 0; + + CHECK_DIE(sibling, DW_DLV_ERROR); + dbg = sibling->di_cu_context->cc_dbg; + dis = sibling->di_is_info? + &dbg->de_info_reading: &dbg->de_types_reading; + *offset = 0; + if (dis->de_last_die && dis->de_last_di_ptr) { + if (sibling->di_debug_ptr == dis->de_last_di_ptr) { + return DW_DLV_OK; + } + } + /* Calculate global offset used for error reporting */ + _dwarf_ptr_CU_offset(sibling->di_cu_context, + dis->de_last_di_ptr,sibling->di_is_info,offset); + return DW_DLV_ERROR; +} + +/* This function does two slightly different things + depending on the input flag want_AT_sibling. If + this flag is true, it checks if the input die has + a DW_AT_sibling attribute. If it does it returns + a pointer to the start of the sibling die in the + .debug_info section. Otherwise it behaves the + same as the want_AT_sibling false case. + + If the want_AT_sibling flag is false, it returns + a pointer to the immediately adjacent die in the + .debug_info section. + + Die_info_end points to the end of the .debug_info + portion for the cu the die belongs to. It is used + to check that the search for the next die does not + cross the end of the current cu. Cu_info_start points + to the start of the .debug_info portion for the + current cu, and is used to add to the offset for + DW_AT_sibling attributes. Finally, has_die_child + is a pointer to a Dwarf_Bool that is set true if + the present die has children, false otherwise. + However, in case want_AT_child is true and the die + has a DW_AT_sibling attribute *has_die_child is set + false to indicate that the children are being skipped. + + die_info_end points to the last byte+1 of the cu. */ +static int +_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr, + Dwarf_CU_Context cu_context, + Dwarf_Byte_Ptr die_info_end, + Dwarf_Byte_Ptr cu_info_start, + Dwarf_Bool want_AT_sibling, + Dwarf_Bool * has_die_child, + Dwarf_Byte_Ptr *next_die_ptr_out, + Dwarf_Error *error) +{ + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Abbrev_List abbrev_list = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr abbrev_end = 0; + int lres = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned highest_code = 0; + + dbg = cu_context->cc_dbg; + info_ptr = die_info_ptr; + DECODE_LEB128_UWORD_CK(info_ptr, utmp,dbg,error,die_info_end); + abbrev_code = (Dwarf_Unsigned) utmp; + if (abbrev_code == 0) { + /* Should never happen. Tested before we got here. */ + _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); + return DW_DLV_ERROR; + } + lres = _dwarf_get_abbrev_for_code(cu_context, abbrev_code, + &abbrev_list,&highest_code,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_NEXT_DIE_NO_ABBREV_LIST " + "There is no abbrev present for code %u" + " in this compilation unit. ", + abbrev_code); + dwarfstring_append_printf_u(&m, + "The highest known code in any " + "compilation unit is %u.", + highest_code); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_NO_ABBREV_LIST, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + *has_die_child = abbrev_list->abl_has_child; + abbrev_ptr = abbrev_list->abl_abbrev_ptr; + abbrev_end = _dwarf_calculate_abbrev_section_end_ptr(cu_context); + + if (!abbrev_list->abl_attr) { + int bres = 0; + + bres = _dwarf_fill_in_attr_form_abtable(cu_context, + abbrev_ptr, abbrev_end, abbrev_list, + error); + if (bres != DW_DLV_OK) { + return bres; + } + } + /* ASSERT list->abl_addr and list->abl_form + are non-null and if list->abl_implicit_const_count > 0 + list->abl_implicit_const is non-null. */ + + for ( i = 0; i abl_abbrev_count; ++i) { + /* Dwarf_Signed implicit_const = 0; */ + Dwarf_Half attr = 0; + Dwarf_Half attr_form = 0; + int res = 0; + Dwarf_Byte_Ptr next_die_ptr = 0; + + attr = abbrev_list->abl_attr[i]; + attr_form = abbrev_list->abl_form[i]; + if (attr_form == DW_FORM_implicit_const) { + /* implicit_const = abbrev_list->abl_implicit_const[i];*/ + } else if (attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6; + /* DECODE_LEB128_UWORD updates info_ptr */ + DECODE_LEB128_UWORD_CK(info_ptr, utmp6,dbg,error, + die_info_end); + attr_form = (Dwarf_Half) utmp6; + if (attr_form == DW_FORM_implicit_const || + attr_form == DW_FORM_indirect) { + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_WRONG_FORM, + "DW_DLE_NEXT_DIE_WRONG_FORM: " + " Reading Attriutes: an indirect " + " or implicit_const form " + "leads to one of the same. " + "Which is not handled. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + } + if (attr_form == DW_FORM_implicit_const) { + SKIP_LEB128_CK(abbrev_ptr,dbg,error, abbrev_end); + } + + if (want_AT_sibling && attr == DW_AT_sibling) { + switch (attr_form) { + case DW_FORM_ref1: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Small), + error,die_info_end); + break; + case DW_FORM_ref2: + /* READ_UNALIGNED does not update info_ptr */ + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + info_ptr,DWARF_HALF_SIZE, + error,die_info_end); + break; + case DW_FORM_ref4: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + info_ptr, DWARF_32BIT_SIZE, + error,die_info_end); + break; + case DW_FORM_ref8: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + info_ptr, DWARF_64BIT_SIZE, + error,die_info_end); + break; + case DW_FORM_ref_udata: + DECODE_LEB128_UWORD_CK(info_ptr, offset, + dbg,error,die_info_end); + break; + case DW_FORM_ref_addr: + /* Very unusual. The FORM is intended to refer to + a different CU, but a different CU cannot + be a sibling, can it? + We could ignore this and treat as if no + DW_AT_sibling + present. Or derive the offset from it and if + it is in the same CU use it directly. + The offset here is *supposed* to be a + global offset, + so adding cu_info_start is wrong to any offset + we find here unless cu_info_start + is zero! Lets pretend there is no DW_AT_sibling + attribute. */ + goto no_sibling_attr; + default: + _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_WRONG_FORM); + return DW_DLV_ERROR; + } + + /* Reset *has_die_child to indicate children skipped. */ + *has_die_child = false; + + /* A value beyond die_info_end indicates an error. + Exactly at die_info_end means 1-past-cu-end + and simply means we + are at the end, do not return error. Higher level + will detect that we are at the end. */ + { /* Care required here. Offset can be garbage. */ + Dwarf_Unsigned plen = 0; + + /* ptrdiff_t is generated but not named */ + plen = (die_info_end >= cu_info_start)? + (die_info_end - cu_info_start):0; + if (offset > plen) { + /* Error case, bad DWARF. */ + _dwarf_error_string(dbg, error, + DW_DLE_SIBLING_OFFSET_WRONG, + "DW_DLE_SIBLING_OFFSET_WRONG " + "the offset makes the new die ptr " + "off the end of the section. Corrupt dwarf"); + return DW_DLV_ERROR; + } + } + /* At or before end-of-cu */ + next_die_ptr = cu_info_start + offset; + if (next_die_ptr <= die_info_ptr) { + /* This is a fix for ossfuzz 57562 */ + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_SIBLING_OFFSET_WRONG " + "the DW_AT_sibling offset (%u) puts " + "the sibling DIE ptr " + "equal to or less then the current DIE ptr. " + "Corrupt dwarf",offset); + _dwarf_error_string(dbg, error, + DW_DLE_SIBLING_OFFSET_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *next_die_ptr_out = next_die_ptr; + return DW_DLV_OK; + } + + no_sibling_attr: + if (attr_form != 0 && attr_form != DW_FORM_implicit_const) { + Dwarf_Unsigned sizeofval = 0; + Dwarf_Unsigned ssize = 0; + + res = _dwarf_get_size_of_val(cu_context->cc_dbg, + attr_form, + cu_context->cc_version_stamp, + cu_context->cc_address_size, + info_ptr, + cu_context->cc_length_size, + &sizeofval, + die_info_end, + error); + if (res != DW_DLV_OK) { + return res; + } + /* It is ok for info_ptr == die_info_end, as we + will test later before using a too-large info_ptr */ + /* ptrdiff_t is generated but not named */ + ssize = (die_info_end >= info_ptr)? + (die_info_end - info_ptr): 0; + if (sizeofval > ssize) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_NEXT_DIE_PAST_END:" + " the DIE value just checked is %u" + " bytes long, and that would extend" + " past the end of the section.", + sizeofval); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_PAST_END, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + info_ptr += sizeofval; + if (info_ptr > die_info_end) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_NEXT_DIE_PAST_END:" + " the DIE value just checked is %u" + " bytes long, and puts us past" + " the end of the section", + sizeofval); + dwarfstring_append_printf_u(&m, + " which is 0x%x", + (Dwarf_Unsigned)(uintptr_t)die_info_end); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_PAST_END, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + /* More than one-past-end indicates a bug somewhere, + likely bad dwarf generation. */ + return DW_DLV_ERROR; + } + } + } + *next_die_ptr_out = info_ptr; + return DW_DLV_OK; +} + +/* Multiple TAGs are in fact compile units. + Allow them all. + Return non-zero if a CU tag. + Else return 0. +*/ +static int +is_cu_tag(int t) +{ + if (t == DW_TAG_compile_unit || + t == DW_TAG_partial_unit || + t == DW_TAG_skeleton_unit || + t == DW_TAG_type_unit) { + return 1; + } + return 0; +} + +/* Given a Dwarf_Debug dbg, and a Dwarf_Die die, it returns + a Dwarf_Die for the sibling of die. In case die is NULL, + it returns (thru ptr) a Dwarf_Die for the first die in the current + cu in dbg. Returns DW_DLV_ERROR on error. + + It is assumed that every sibling chain including those with + only one element is terminated with a NULL die, except a + chain with only a NULL die. + + The algorithm moves from one die to the adjacent one. It + returns when the depth of children it sees equals the number + of sibling chain terminations. A single count, child_depth + is used to track the depth of children and sibling terminations + encountered. Child_depth is incremented when a die has the + Has-Child flag set unless the child happens to be a NULL die. + Child_depth is decremented when a die has Has-Child false, + and the adjacent die is NULL. Algorithm returns when + child_depth is 0. + + **NOTE: Do not modify input die, since it is used at the end. + + * This is the correct form. On calling with 'die' NULL, + we cannot tell if this is debug_info or debug_types, so + we must be informed!. */ +int +dwarf_siblingof_b(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Bool is_info, + Dwarf_Die * caller_ret_die, Dwarf_Error * error) +{ + int res = 0; + Dwarf_Debug_InfoTypes dis = 0; + + dis = is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + + res = _dwarf_siblingof_internal(dbg,die, + die?die->di_cu_context:dis->de_cu_context, + is_info,caller_ret_die,error); + return res; +} + +static int +_dwarf_siblingof_internal(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_CU_Context context, + Dwarf_Bool is_info, + Dwarf_Die * caller_ret_die, Dwarf_Error * error) +{ + Dwarf_Die ret_die = 0; + Dwarf_Byte_Ptr die_info_ptr = 0; + Dwarf_Byte_Ptr cu_info_start = 0; + + /* die_info_end points 1-past end of die (once set) */ + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Unsigned highest_code = 0; + int lres = 0; + int dieres = 0; + /* Since die may be NULL, we rely on the input argument. */ + Dwarf_Small *dataptr = 0; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + dataptr = is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + if (!dataptr) { + return DW_DLV_NO_ENTRY; + } + if (die == NULL) { + /* Find root die of cu */ + /* die_info_end is untouched here, need not be set in this + branch. */ + Dwarf_Off off2 = 0; + Dwarf_Unsigned headerlen = 0; + int cres = 0; + + /* If we've not loaded debug_info + context will be NULL. */ + if (!context) { + local_dealloc_cu_context(dbg,context); + return DW_DLV_ERROR; + } + off2 = context->cc_debug_offset; + cu_info_start = dataptr + off2; + cres = _dwarf_length_of_cu_header(dbg, off2,is_info, + &headerlen,error); + if (cres != DW_DLV_OK) { + return cres; + } + die_info_ptr = cu_info_start + headerlen; + die_info_end = _dwarf_calculate_info_section_end_ptr(context); + + /* Recording the CU die pointer so we can later access + for special FORMs relating to .debug_str_offsets + and .debug_addr */ + context->cc_cu_die_offset_present = TRUE; + context->cc_cu_die_global_sec_offset = off2 + headerlen; + } else { + /* Find sibling die. */ + Dwarf_Bool has_child = false; + Dwarf_Signed child_depth = 0; + + /* We cannot have a legal die unless debug_info + was loaded, so + no need to load debug_info here. */ + CHECK_DIE(die, DW_DLV_ERROR); + + die_info_ptr = die->di_debug_ptr; + if (*die_info_ptr == 0) { + return DW_DLV_NO_ENTRY; + } + context = die->di_cu_context; + cu_info_start = dataptr+ context->cc_debug_offset; + die_info_end = _dwarf_calculate_info_section_end_ptr(context); + + if ((*die_info_ptr) == 0) { + return DW_DLV_NO_ENTRY; + } + child_depth = 0; + do { + int res2 = 0; + Dwarf_Byte_Ptr die_info_ptr2 = 0; + + res2 = _dwarf_next_die_info_ptr(die_info_ptr, + context, die_info_end, + cu_info_start, true, &has_child, + &die_info_ptr2, + error); + if (res2 != DW_DLV_OK) { + return res2; + } + if (die_info_ptr2 == die_info_ptr) { + /* There is something very wrong, our die value + unchanged. Bad DWARF. */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_NEXT_DIE_LOW_ERROR: " + "Somehow the next die pointer 0x%x", + (Dwarf_Unsigned)(uintptr_t)die_info_ptr2); + dwarfstring_append_printf_u(&m, + " points before the current die " + "pointer 0x%x so an " + "overflow of some sort happened", + (Dwarf_Unsigned)(uintptr_t)die_info_ptr); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_LOW_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (die_info_ptr2 < die_info_ptr) { + /* There is something very wrong, our die value + decreased. Bad DWARF. */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_NEXT_DIE_LOW_ERROR: " + "Somehow the next die pointer 0x%x", + (Dwarf_Unsigned)(uintptr_t)die_info_ptr2); + dwarfstring_append_printf_u(&m, + " points before the current die " + "pointer 0x%x so an " + "overflow of some sort happened", + (Dwarf_Unsigned)(uintptr_t)die_info_ptr); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_LOW_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (die_info_ptr2 > die_info_end) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_NEXT_DIE_PAST_END: " + "the next DIE at 0x%x", + (Dwarf_Unsigned)(uintptr_t)die_info_ptr2); + dwarfstring_append_printf_u(&m, + " would be past " + " the end of the section (0x%x)," + " which is an error.", + (Dwarf_Unsigned)(uintptr_t)die_info_end); + _dwarf_error_string(dbg, error, + DW_DLE_NEXT_DIE_PAST_END, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + die_info_ptr = die_info_ptr2; + + /* die_info_end is one past end. Do not read it! + A test for '!= die_info_end' would work as well, + but perhaps < reads more like the meaning. */ + if (die_info_ptr < die_info_end) { + if ((*die_info_ptr) == 0 && has_child) { + die_info_ptr++; + has_child = false; + } + } + + /* die_info_ptr can be one-past-end. */ + if ((die_info_ptr == die_info_end) || + ((*die_info_ptr) == 0)) { + /* We are at the end of a sibling list. + get back to the next containing + sibling list (looking for a libling + list with more on it). + */ + for (;;) { + if (child_depth == 0) { + /* Meaning there is no outer list, + so stop. */ + break; + } + if (die_info_ptr == die_info_end) { + /* September 2016: do not deref + if we are past end. + If we are at end at this point + it means the sibling list + inside this CU is not properly + terminated. + August 2019: + We used to declare an error, + DW_DLE_SIBLING_LIST_IMPROPER but + now we just silently + declare this is the end of the list. + Each level of a sibling nest should + have a single NUL byte, but here + things are wrong, the DWARF + is corrupt. */ + return DW_DLV_NO_ENTRY; + } + if (*die_info_ptr) { + /* We have a real sibling. */ + break; + } + /* Move out one DIE level. + Move past NUL byte marking end of + this sibling list. */ + child_depth--; + die_info_ptr++; + } + } else { + child_depth = has_child ? + child_depth + 1 : child_depth; + } + } while (child_depth != 0); + } + /* die_info_ptr > die_info_end is really a bug (possibly in dwarf + generation)(but we are past end, no more DIEs here), whereas + die_info_ptr == die_info_end means 'one past end, no more DIEs + here'. */ + if (die_info_ptr >= die_info_end) { + return DW_DLV_NO_ENTRY; + } + if ((*die_info_ptr) == 0) { + return DW_DLV_NO_ENTRY; + } + ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (!ret_die) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + ret_die->di_is_info = is_info; + ret_die->di_debug_ptr = die_info_ptr; + ret_die->di_cu_context = + die == NULL ? context : die->di_cu_context; + + dieres = _dwarf_leb128_uword_wrapper(dbg, + &die_info_ptr,die_info_end,&utmp,error); + if (dieres == DW_DLV_ERROR) { + dwarf_dealloc_die(ret_die); + return dieres; + } + if (die_info_ptr > die_info_end) { + /* We managed to go past the end of the CU!. + Something is badly wrong. */ + dwarf_dealloc_die(ret_die); + _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); + return DW_DLV_ERROR; + } + abbrev_code = utmp; + if (abbrev_code == 0) { + /* Zero means a null DIE */ + dwarf_dealloc_die(ret_die); + return DW_DLV_NO_ENTRY; + } + ret_die->di_abbrev_code = abbrev_code; + lres = _dwarf_get_abbrev_for_code(ret_die->di_cu_context, + abbrev_code, + &ret_die->di_abbrev_list, + &highest_code,error); + if (lres == DW_DLV_ERROR) { + dwarf_dealloc_die(ret_die); + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + char buf[130]; + + buf[0] = 0; + dwarfstring_constructor_static(&m,buf,sizeof(buf)); + dwarf_dealloc_die(ret_die); + dwarfstring_append_printf_u(&m, + "DW_DLE_DIE_ABBREV_LIST_NULL: " + "There is no abbrev present for code %u" + " in this compilation unit. ", + abbrev_code); + dwarfstring_append_printf_u(&m, + "The highest known code" + " in any compilation unit is %u .", + highest_code); + _dwarf_error_string(dbg, error, + DW_DLE_DIE_ABBREV_LIST_NULL,dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (!ret_die->di_abbrev_list->abl_attr) { + int bres = 0; + Dwarf_Byte_Ptr abbrev_ptr = + ret_die->di_abbrev_list->abl_abbrev_ptr; + Dwarf_Byte_Ptr abbrev_end = + _dwarf_calculate_abbrev_section_end_ptr( + ret_die->di_cu_context); + bres = _dwarf_fill_in_attr_form_abtable( + ret_die->di_cu_context, + abbrev_ptr, + abbrev_end, + ret_die->di_abbrev_list, + error); + if (bres != DW_DLV_OK) { + dwarf_dealloc_die(ret_die); + return bres; + } + } + + if (die == NULL && !is_cu_tag(ret_die->di_abbrev_list->abl_tag)) { + dwarf_dealloc_die(ret_die); + _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU); + return DW_DLV_ERROR; + } + *caller_ret_die = ret_die; + return DW_DLV_OK; +} + +int +dwarf_child(Dwarf_Die die, + Dwarf_Die * caller_ret_die, + Dwarf_Error * error) +{ + Dwarf_Byte_Ptr die_info_ptr = 0; + Dwarf_Byte_Ptr die_info_ptr2 = 0; + + /* die_info_end points one-past-end of die area. */ + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Die ret_die = 0; + Dwarf_Bool has_die_child = 0; + Dwarf_Debug dbg; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + Dwarf_Debug_InfoTypes dis = 0; + int res = 0; + Dwarf_CU_Context context = 0; + int lres = 0; + Dwarf_Unsigned highest_code = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dis = die->di_is_info? &dbg->de_info_reading: + &dbg->de_types_reading; + die_info_ptr = die->di_debug_ptr; + + /* We are saving a DIE pointer here, but the pointer + will not be presumed live later, when it is tested. */ + dis->de_last_die = die; + dis->de_last_di_ptr = die_info_ptr; + + /* NULL die has no child. */ + if ((*die_info_ptr) == 0) { + return DW_DLV_NO_ENTRY; + } + context = die->di_cu_context; + die_info_end = _dwarf_calculate_info_section_end_ptr(context); + + res = _dwarf_next_die_info_ptr(die_info_ptr, + die->di_cu_context, + die_info_end, + NULL, false, + &has_die_child, + &die_info_ptr2, + error); + if (res != DW_DLV_OK) { + return res; + } + if (die_info_ptr == die_info_end) { + return DW_DLV_NO_ENTRY; + } + die_info_ptr = die_info_ptr2; + + dis->de_last_di_ptr = die_info_ptr; + + if (!has_die_child) { + /* Look for end of sibling chain. */ + while (dis->de_last_di_ptr < die_info_end) { + if (*dis->de_last_di_ptr) { + break; + } + ++dis->de_last_di_ptr; + } + return DW_DLV_NO_ENTRY; + } + + ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (!ret_die) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + ret_die->di_debug_ptr = die_info_ptr; + ret_die->di_cu_context = die->di_cu_context; + ret_die->di_is_info = die->di_is_info; + + res = _dwarf_leb128_uword_wrapper(dbg,&die_info_ptr, + die_info_end, &utmp,error); + if (res != DW_DLV_OK) { + dwarf_dealloc_die(ret_die); + return res; + } + abbrev_code = (Dwarf_Unsigned) utmp; + + dis->de_last_di_ptr = die_info_ptr; + + if (abbrev_code == 0) { + /* Look for end of sibling chain */ + while (dis->de_last_di_ptr < die_info_end) { + if (*dis->de_last_di_ptr) { + break; + } + ++dis->de_last_di_ptr; + } + + /* We have arrived at a null DIE, + at the end of a CU or the end + of a list of siblings. */ + *caller_ret_die = 0; + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + ret_die = 0; + return DW_DLV_NO_ENTRY; + } + ret_die->di_abbrev_code = abbrev_code; + lres = _dwarf_get_abbrev_for_code(ret_die->di_cu_context, + abbrev_code, + &ret_die->di_abbrev_list, + &highest_code,error); + if (lres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); + ret_die = 0; + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarf_dealloc_die(ret_die); + ret_die = 0; + dwarfstring_append_printf_u(&m, + "DW_DLE_ABBREV_MISSING: the abbrev code not found " + " in dwarf_child() is %u. ",abbrev_code); + dwarfstring_append_printf_u(&m, + "The highest known code" + " in any compilation unit is %u.", + highest_code); + _dwarf_error_string(dbg, error, DW_DLE_ABBREV_MISSING, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (!ret_die->di_abbrev_list->abl_attr) { + int bres = 0; + Dwarf_Byte_Ptr abbrev_ptr = + ret_die->di_abbrev_list->abl_abbrev_ptr; + Dwarf_Byte_Ptr abbrev_end = + _dwarf_calculate_abbrev_section_end_ptr( + ret_die->di_cu_context); + bres = _dwarf_fill_in_attr_form_abtable( + ret_die->di_cu_context, + abbrev_ptr, + abbrev_end, + ret_die->di_abbrev_list, + error); + if (bres != DW_DLV_OK) { + dwarf_dealloc_die(ret_die); + return bres; + } + } + *caller_ret_die = ret_die; + return DW_DLV_OK; +} + +/* Given a (global, not cu_relative) die offset, this returns + a pointer to a DIE thru *new_die. + It is up to the caller to do a + dwarf_dealloc(dbg,*new_die,DW_DLE_DIE); + The old form only works with debug_info. + The new _b form works with debug_info or debug_types. + + */ +int +dwarf_offdie_b(Dwarf_Debug dbg, + Dwarf_Off offset, Dwarf_Bool is_info, + Dwarf_Die * new_die, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Off new_cu_offset = 0; + Dwarf_Die die = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned utmp = 0; + int lres = 0; + Dwarf_Debug_InfoTypes dis = 0; + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Unsigned highest_code = 0; + struct Dwarf_Section_s * secdp = 0; + + if (dbg == NULL) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "in call to dwarf_offdie_b()"); + return DW_DLV_ERROR; + } + if (is_info) { + dis =&dbg->de_info_reading; + secdp = &dbg->de_debug_info; + dataptr = dbg->de_debug_info.dss_data; + } else { + dis =&dbg->de_types_reading; + secdp = &dbg->de_debug_types; + dataptr = dbg->de_debug_types.dss_data; + } + + if (!dataptr) { + lres = _dwarf_load_die_containing_section(dbg, + is_info, error); + if (lres != DW_DLV_OK) { + return lres; + } + } + cu_context = _dwarf_find_CU_Context(dbg, offset,is_info); + if (cu_context == NULL) { + Dwarf_Unsigned section_size = 0; + + if (dis->de_cu_context_list_end != NULL) { + new_cu_offset = _dwarf_calculate_next_cu_context_offset( + dis->de_cu_context_list_end); + }/* Else new_cu_offset remains 0, no CUs on list, + a fresh section setup. */ + section_size = secdp->dss_size; + do { + lres = _dwarf_create_a_new_cu_context_record_on_list( + dbg, dis,is_info,section_size,new_cu_offset, + &cu_context,error); + if (lres != DW_DLV_OK) { + return lres; + } + new_cu_offset = _dwarf_calculate_next_cu_context_offset( + cu_context); + /* Not setting dis->de_cu_context, leave + that unchanged. */ + } while (offset >= new_cu_offset); + } + /* We have a cu_context for this offset. */ + die_info_end = _dwarf_calculate_info_section_end_ptr(cu_context); + die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); + if (!die) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + die->di_cu_context = cu_context; + die->di_is_info = is_info; + /* dataptr above might be stale if we loaded a section + above. So access dss_data here. */ + if (is_info) { + info_ptr = offset + dbg->de_debug_info.dss_data; + } else { + info_ptr = offset + dbg->de_debug_types.dss_data; + } + die->di_debug_ptr = info_ptr; + lres = _dwarf_leb128_uword_wrapper(dbg,&info_ptr,die_info_end, + &utmp,error); + if (lres != DW_DLV_OK) { + dwarf_dealloc_die(die); + return lres; + } + abbrev_code = utmp; + if (abbrev_code == 0) { + /* we are at a null DIE (or there is a bug). */ + dwarf_dealloc_die(die); + die = 0; + return DW_DLV_NO_ENTRY; + } + die->di_abbrev_code = abbrev_code; + lres = _dwarf_get_abbrev_for_code(cu_context, abbrev_code, + &die->di_abbrev_list, + &highest_code,error); + if (lres == DW_DLV_ERROR) { + dwarf_dealloc_die(die); + die = 0; + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + + dwarf_dealloc_die(die); + die = 0; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DIE_ABBREV_LIST_NULL: " + "There is no abbrev present for code %u" + " in this compilation unit" + " when calling dwarf_offdie_b(). ", + abbrev_code); + dwarfstring_append_printf_u(&m, + "The highest known code " + "in any compilation unit is %u .", + highest_code); + _dwarf_error_string(dbg, error, + DW_DLE_DIE_ABBREV_LIST_NULL, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (!die->di_abbrev_list->abl_attr) { + int bres = 0; + Dwarf_Byte_Ptr abbrev_ptr = + die->di_abbrev_list->abl_abbrev_ptr; + Dwarf_Byte_Ptr abbrev_end = + _dwarf_calculate_abbrev_section_end_ptr( + die->di_cu_context); + bres = _dwarf_fill_in_attr_form_abtable( + die->di_cu_context, + abbrev_ptr, + abbrev_end, + die->di_abbrev_list, + error); + if (bres != DW_DLV_OK) { + dwarf_dealloc_die(die); + return bres; + } + } + *new_die = die; + return DW_DLV_OK; +} + +/* New March 2016. + Lets one cross check the abbreviations section and + the DIE information presented by dwarfdump -i -G -v. */ +int +dwarf_die_abbrev_global_offset(Dwarf_Die die, + Dwarf_Off * abbrev_goffset, + Dwarf_Unsigned * abbrev_count, + Dwarf_Error* error) +{ + Dwarf_Abbrev_List dal = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dal = die->di_abbrev_list; + if (!dal) { + _dwarf_error(dbg,error,DW_DLE_DWARF_ABBREV_NULL); + return DW_DLV_ERROR; + } + *abbrev_goffset = dal->abl_goffset; + *abbrev_count = dal->abl_abbrev_count; + return DW_DLV_OK; +} + +/* New August 2018. + Because some real compressed sections + have .zdebug instead + of .debug as the leading characters. + actual_sec_name_out points to a static + string so so not free it. */ +int +dwarf_get_real_section_name(Dwarf_Debug dbg, + const char *std_section_name, + const char **actual_sec_name_out, + Dwarf_Small *marked_zcompressed, /* zdebug */ + Dwarf_Small *marked_zlib_compressed, /* ZLIB string */ + Dwarf_Small *marked_shf_compressed, /* SHF_COMPRESSED */ + Dwarf_Unsigned *compressed_length, + Dwarf_Unsigned *uncompressed_length, + Dwarf_Error *error) +{ + unsigned i = 0; + char tbuf[100]; + size_t std_sec_name_len = strlen(std_section_name); + + tbuf[0] = 0; + /* std_section_name never has the .dwo on the end, + so allow for that and allow one (arbitrarily) more. */ + if ((std_sec_name_len + 5) < sizeof(tbuf)) { + _dwarf_safe_strcpy(tbuf,sizeof(tbuf), + std_section_name,std_sec_name_len); + _dwarf_safe_strcpy(tbuf+std_sec_name_len, + sizeof(tbuf)-std_sec_name_len, + ".dwo",4); + } + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + for (i=0; i < dbg->de_debug_sections_total_entries; i++) { + struct Dwarf_dbg_sect_s *sdata = &dbg->de_debug_sections[i]; + struct Dwarf_Section_s *section = sdata->ds_secdata; + const char *std = section->dss_standard_name; + + if (!strcmp(std,std_section_name) || + !strcmp(std,tbuf)) { + const char *used = section->dss_name; + *actual_sec_name_out = used; + if (sdata->ds_have_zdebug) { + *marked_zcompressed = TRUE; + } + if (section->dss_ZLIB_compressed) { + *marked_zlib_compressed = TRUE; + if (uncompressed_length) { + *uncompressed_length = + section->dss_uncompressed_length; + } + if (compressed_length) { + *compressed_length = + section->dss_compressed_length; + } + } + if (section->dss_shf_compressed) { + *marked_shf_compressed = TRUE; + if (uncompressed_length) { + *uncompressed_length = + section->dss_uncompressed_length; + } + if (compressed_length) { + *compressed_length = + section->dss_compressed_length; + } + } + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} +/* This is useful when printing DIE data. + The string pointer returned must not be freed. + With non-elf objects it is possible the + string returned might be empty or NULL, + so callers should be prepared for that kind + of return. */ +int +dwarf_get_die_section_name(Dwarf_Debug dbg, + Dwarf_Bool is_info, + const char ** sec_name, + Dwarf_Error * error) +{ + struct Dwarf_Section_s *sec = 0; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + if (is_info) { + sec = &dbg->de_debug_info; + } else { + sec = &dbg->de_debug_types; + } + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *sec_name = sec->dss_name; + return DW_DLV_OK; +} + +/* This one assumes is_info not known to caller but a DIE is known. */ +int +dwarf_get_die_section_name_b(Dwarf_Die die, + const char ** sec_name, + Dwarf_Error * error) +{ + Dwarf_CU_Context context = 0; + Dwarf_Bool is_info = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + is_info = context->cc_is_info; + return dwarf_get_die_section_name(dbg,is_info,sec_name,error); +} diff --git a/src/lib/libdwarf/dwarf_die_deliv.h b/src/lib/libdwarf/dwarf_die_deliv.h new file mode 100644 index 0000000..537714c --- /dev/null +++ b/src/lib/libdwarf/dwarf_die_deliv.h @@ -0,0 +1,78 @@ +/* + +Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2008-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* + This struct holds information about an abbreviation. + It is put in the hash table for abbreviations for + a compile-unit. Typically the list contains + exactly one item (except with somewhat + pathological abbrev codes, and that likely + never happens). + It is dealloced by dwarf_finish(). +*/ +struct Dwarf_Abbrev_List_s { + Dwarf_Unsigned abl_code; + Dwarf_Half abl_tag; + Dwarf_Half abl_has_child; + /* This reference count is just for + analysis, does not affect size + or correctness. */ + Dwarf_Unsigned abl_reference_count; + /* Section global offset of this abbrev entry. */ + Dwarf_Off abl_goffset; + + /* Singly linked synonym list in case of duplicate + hash. */ + Dwarf_Abbrev_List abl_next; + + /* Points to start of attribute/form pairs in + the .debug_abbrev section for the abbrev. */ + Dwarf_Byte_Ptr abl_abbrev_ptr; + /* The number of at/form[/implicitvalue] pairs + in this abbrev. */ + Dwarf_Unsigned abl_abbrev_count; + Dwarf_Unsigned abl_implicit_const_count; + + /* For indirect can only be completed at a real + point in the program, not just on the + .debug_abbrev content, and we want to know + of it at the first encounter. */ + Dwarf_Bool abl_has_form_indirect; + /* The following are the decoded attribte and + FORM pairs, abl_abbrev_count of them. */ + Dwarf_Half *abl_attr; + Dwarf_Half *abl_form; + /* If there are any DW_FORM_implicit_const + in *abl_form array the following is + an array of abl_abbrev_count slots + for an implicit const value. */ + Dwarf_Signed *abl_implicit_const; + +}; diff --git a/src/lib/libdwarf/dwarf_dsc.c b/src/lib/libdwarf/dwarf_dsc.c new file mode 100644 index 0000000..286c77b --- /dev/null +++ b/src/lib/libdwarf/dwarf_dsc.c @@ -0,0 +1,331 @@ +/* + Copyright (C) 2016-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ +#include /* memcpy() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_dsc.h" + +/* When called with ary and *arraycount 0 + this just counts the elements found. + Otherwise it records the values in ary and + recounts. The arraycount pointer must be + passed-in non-null always. */ +static int +get_dsc_leb_entries(Dwarf_Debug dbg, + Dwarf_Small * blockpointer, + Dwarf_Unsigned blocklen, + int dounsigned, + struct Dwarf_Dsc_Entry_s *ary, + size_t * arraycount, + Dwarf_Error * error) +{ + Dwarf_Small *p = blockpointer; + Dwarf_Small *endp = blockpointer + blocklen; + size_t larraycount = 0; + size_t iarraycount = *arraycount; + + if (!ary) { + if (iarraycount) { + /* Internal botch calling this static function. */ + _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } else {} + } else { + if (!iarraycount) { + /* Internal botch calling this static function. */ + _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } else {} + } + if (dounsigned) { + while (p < endp) { + Dwarf_Unsigned dsc = 0; + Dwarf_Unsigned low = 0; + Dwarf_Unsigned high = 0; + + if (ary && (larraycount >= iarraycount)) { + _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } + DECODE_LEB128_UWORD_CK(p,dsc, + dbg,error,endp); + if (!dsc) { + DECODE_LEB128_UWORD_CK(p,low, + dbg,error,endp); + } else { + DECODE_LEB128_UWORD_CK(p,low, + dbg,error,endp); + DECODE_LEB128_UWORD_CK(p,high, + dbg,error,endp); + } + if (ary) { + struct Dwarf_Dsc_Entry_s *arye = + ary+larraycount; + + /* type reads the same as uleb and leb because + it is only zero or one. */ + arye->dsc_type = (Dwarf_Half)dsc; + arye->dsc_low_u = low; + arye->dsc_high_u = high; + } + larraycount++; + } + } else { + while (p < endp) { + Dwarf_Signed dsc = 0; + Dwarf_Signed low = 0; + Dwarf_Signed high = 0; + Dwarf_Unsigned leblen = 0; + + (void)leblen; + if (ary && (larraycount >= iarraycount)) { + _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } + DECODE_LEB128_SWORD_LEN_CK(p,dsc, + leblen,dbg,error,endp); + if (!dsc) { + DECODE_LEB128_SWORD_LEN_CK(p,low, + leblen,dbg,error,endp); + } else { + DECODE_LEB128_SWORD_LEN_CK(p,low, + leblen,dbg,error,endp); + DECODE_LEB128_SWORD_LEN_CK(p,high, + leblen,dbg,error,endp); + } + if (ary) { + struct Dwarf_Dsc_Entry_s *arye = + ary+larraycount; + + /* type reads the same as uleb and leb because + it is only zero or one. */ + arye->dsc_type = (Dwarf_Half)dsc; + arye->dsc_low_s = low; + arye->dsc_high_s = high; + } + larraycount++; + } + } + if (ary) { + /* Just verify this recount matches original */ + if (iarraycount != larraycount) { + _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } + } else { + /* This matters for first call with + ary 0 and iarraycount 0 as we are generating the + count. */ + *arraycount = larraycount; + } + return DW_DLV_OK; +} + +int dwarf_discr_list(Dwarf_Debug dbg, + Dwarf_Small * blockpointer, + Dwarf_Unsigned blocklen, + Dwarf_Dsc_Head * dsc_head_out, + Dwarf_Unsigned * dsc_array_length_out, + Dwarf_Error * error) +{ + Dwarf_Dsc_Head h = 0; + int res = 0; + size_t arraycount = 0; + struct Dwarf_Dsc_Entry_s *ary = 0; + Dwarf_Small * dscblockp = 0; + Dwarf_Unsigned dscblocklen = 0; + + if (!dbg){ + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); \ + return DW_DLV_ERROR; + } + if (blocklen == 0) { + return DW_DLV_NO_ENTRY; + } + dscblockp = (Dwarf_Small *)calloc(blocklen,sizeof(Dwarf_Small)); + if (!dscblockp) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + dscblocklen = blocklen; + memcpy(dscblockp,blockpointer,blocklen); + + res = get_dsc_leb_entries(dbg,dscblockp,dscblocklen, + /* TRUE or FALSE here is not important, the arraycount + returned to us will be identical either way. */ + FALSE, 0, &arraycount,error); + if (res != DW_DLV_OK) { + free(dscblockp); + return res; + } + + h = (Dwarf_Dsc_Head)_dwarf_get_alloc(dbg,DW_DLA_DSC_HEAD,1); + if (!h) { + free(dscblockp); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + h->dsh_block = dscblockp; + h->dsh_block_len = dscblocklen; + h->dsh_debug = dbg; + /* Now the destructor for h will deal with block malloc space. */ + + ary = (struct Dwarf_Dsc_Entry_s *)calloc(arraycount, + sizeof(struct Dwarf_Dsc_Entry_s)); + if (!ary) { + dwarf_dealloc(dbg,h,DW_DLA_DSC_HEAD); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + h->dsh_count = arraycount; + h->dsh_array = ary; + h->dsh_set_unsigned = 0; + h->dsh_set_signed = 0; + + *dsc_head_out = h; + *dsc_array_length_out = arraycount; + return DW_DLV_OK; +} + +/* NEW September 2016. Allows easy access to DW_AT_discr_list + entry. Callers must know which is the appropriate + one of the following two interfaces, though both + will work. */ +int +dwarf_discr_entry_u(Dwarf_Dsc_Head dsh , + Dwarf_Unsigned entrynum, + Dwarf_Half * out_type, + Dwarf_Unsigned * out_discr_low, + Dwarf_Unsigned * out_discr_high, + Dwarf_Error * error) +{ + struct Dwarf_Dsc_Entry_s *dse = 0; + + (void)error; + if (entrynum >= dsh->dsh_count) { + return DW_DLV_NO_ENTRY; + } + if (!dsh->dsh_set_unsigned) { + int res =0; + int dounsigned = 1; + size_t count = dsh->dsh_count; + + res = get_dsc_leb_entries(dsh->dsh_debug, + dsh->dsh_block, + dsh->dsh_block_len, + dounsigned, + dsh->dsh_array, + &count, + error); + if (res != DW_DLV_OK) { + return res; + } + dsh->dsh_set_unsigned = TRUE; + } + if (!dsh->dsh_array) { + _dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } + dse = dsh->dsh_array + entrynum; + *out_type = dse->dsc_type; + *out_discr_low = dse->dsc_low_u; + *out_discr_high = dse->dsc_high_u; + return DW_DLV_OK; +} + +/* NEW September 2016. Allows easy access to DW_AT_discr_list + entry. */ +int +dwarf_discr_entry_s(Dwarf_Dsc_Head dsh, + Dwarf_Unsigned entrynum, + Dwarf_Half * out_type, + Dwarf_Signed * out_discr_low, + Dwarf_Signed * out_discr_high, + Dwarf_Error * error) +{ + struct Dwarf_Dsc_Entry_s *dse = 0; + + (void)error; + if (entrynum >= dsh->dsh_count) { + return DW_DLV_NO_ENTRY; + } + if (!dsh->dsh_set_signed) { + int res =0; + int dounsigned = 0; + size_t count = dsh->dsh_count; + + res = get_dsc_leb_entries(dsh->dsh_debug, + dsh->dsh_block, + dsh->dsh_block_len, + dounsigned, + dsh->dsh_array, + &count, + error); + if (res != DW_DLV_OK) { + return res; + } + dsh->dsh_set_signed = TRUE; + } + if (!dsh->dsh_array) { + _dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR); + return DW_DLV_ERROR; + } + dse = dsh->dsh_array + entrynum; + *out_type = dse->dsc_type; + *out_discr_low = dse->dsc_low_s; + *out_discr_high = dse->dsc_high_s; + return DW_DLV_OK; +} + +void +_dwarf_dsc_destructor(void *m) +{ + Dwarf_Dsc_Head h = (Dwarf_Dsc_Head) m; + + free(h->dsh_array); + h->dsh_array = 0; + free(h->dsh_block); + h->dsh_block = 0; + h->dsh_count = 0; +} diff --git a/src/lib/libdwarf/dwarf_dsc.h b/src/lib/libdwarf/dwarf_dsc.h new file mode 100644 index 0000000..7c4c771 --- /dev/null +++ b/src/lib/libdwarf/dwarf_dsc.h @@ -0,0 +1,59 @@ +/* +Copyright (C) 2016-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* dsc_type: if 0, then dsc_low is a single discriminant value + and dsc_high is zero.. + If 1, then dsc_low, dsc_high are a discriminant range + + All the messy complexity here is so we can have both + a set of values read as uleb and as sleb. + We make our own copy of the block for the same reason. +*/ +struct Dwarf_Dsc_Entry_s { + /* Type is a 1 byte leb that reads the same as sleb or uleb + because its value can only be zero or one. */ + Dwarf_Half dsc_type; + Dwarf_Unsigned dsc_low_u; + Dwarf_Unsigned dsc_high_u; + Dwarf_Signed dsc_low_s; + Dwarf_Signed dsc_high_s; +}; +struct Dwarf_Dsc_Head_s { + Dwarf_Debug dsh_debug; + Dwarf_Unsigned dsh_count; + Dwarf_Small *dsh_block; + Dwarf_Unsigned dsh_block_len; + /* Following two are flags to tell us whether + lebs already read in a given signedness. */ + Dwarf_Bool dsh_set_unsigned; + Dwarf_Bool dsh_set_signed; + + struct Dwarf_Dsc_Entry_s *dsh_array; +}; + +void _dwarf_dsc_destructor(void *m); diff --git a/src/lib/libdwarf/dwarf_elf_access.h b/src/lib/libdwarf/dwarf_elf_access.h new file mode 100644 index 0000000..4357dae --- /dev/null +++ b/src/lib/libdwarf/dwarf_elf_access.h @@ -0,0 +1,47 @@ +#ifndef _DWARF_ELF_PORT_H +#define _DWARF_ELF_PORT_H +/* + +Copyright (C) 2008-2023 David Anderson. All rights reserved. +Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* libelf) object access for the generic + object file interface */ + +int +dwarf_elf_object_access_init(void * elf , + int libdwarf_owns_elf, + Dwarf_Obj_Access_Interface** ret_obj, + int *err ); + +void +dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj ); + +/* End ELF object access for the generic object file interface */ + +#endif diff --git a/src/lib/libdwarf/dwarf_elf_defines.h b/src/lib/libdwarf/dwarf_elf_defines.h new file mode 100644 index 0000000..03000c7 --- /dev/null +++ b/src/lib/libdwarf/dwarf_elf_defines.h @@ -0,0 +1,1118 @@ +/* Copyright (c) 2019-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#ifndef DWARF_ELF_DEFINES_H +#define DWARF_ELF_DEFINES_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Standard Elf section types. */ +#ifndef SHT_NULL +#define SHT_NULL 0 +#endif +#ifndef SHT_PROGBITS +#define SHT_PROGBITS 1 +#endif +#ifndef SHT_SYMTAB +#define SHT_SYMTAB 2 +#endif +#ifndef SHT_STRTAB +#define SHT_STRTAB 3 +#endif +#ifndef SHT_RELA +#define SHT_RELA 4 +#endif +#ifndef SHT_REL +#define SHT_REL 9 +#endif + +#ifndef DW_GROUPNUMBER_BASE +#define DW_GROUPNUMBER_BASE 1 +#endif +#ifndef DW_GROUPNUMBER_DWO +#define DW_GROUPNUMBER_DWO 2 +#endif + +#ifndef SHF_GROUP +#define SHF_GROUP (1 << 9) +#endif /* SHF_GROUP */ + +#ifndef STN_UNDEF +#define STN_UNDEF 0 +#endif /* STN_UNDEF */ + +#ifndef SHT_HASH +#define SHT_HASH 5 +#endif +#ifndef SHT_DYNAMIC +#define SHT_DYNAMIC 6 +#endif +#ifndef SHT_NOTE +#define SHT_NOTE 7 +#endif +#ifndef SHT_NOBITS +#define SHT_NOBITS 8 +#endif +#ifndef SHT_REL +#define SHT_REL 9 +#endif +#ifndef SHT_SHLIB +#define SHT_SHLIB 10 +#endif +#ifndef SHT_DYNSYM +#define SHT_DYNSYM 11 +#endif +#ifndef SHT_GROUP +#define SHT_GROUP 17 +#endif /* SHT_GROUP */ + +/* Symbol Types, Elf standard. */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#ifndef PT_NULL +#define PT_NULL 0 +#endif +#ifndef PT_LOAD +#define PT_LOAD 1 +#endif +#ifndef PT_DYNAMIC +#define PT_DYNAMIC 2 +#endif +#ifndef PT_INTERP +#define PT_INTERP 3 +#endif +#ifndef PT_NOTE +#define PT_NOTE 4 +#endif +#ifndef PT_SHLIB +#define PT_SHLIB 5 +#endif +#ifndef PT_PHDR +#define PT_PHDR 6 +#endif +#ifndef PT_LOPROC +#define PT_LOPROC 0x70000000 +#endif +#ifndef PT_HIPROC +#define PT_HIPROC 0x7fffffff +#endif + +#ifndef PF_X +#define PF_X (1 << 0) +#endif +#ifndef PF_W +#define PF_W (1 << 1) +#endif +#ifndef PF_R +#define PF_R (1 << 2) +#endif +#ifndef PF_MASKOS +#define PF_MASKOS 0x0ff00000 +#endif +#ifndef PF_MASKPROC +#define PF_MASKPROC 0xf0000000 +#endif + +#ifndef ET_NONE +#define ET_NONE 0 +#endif +#ifndef ET_REL +#define ET_REL 1 +#endif +#ifndef ET_EXEC +#define ET_EXEC 2 +#endif +#ifndef ET_DYN +#define ET_DYN 3 +#endif +#ifndef ET_CORE +#define ET_CORE 4 +#endif +#ifndef ET_NUM +#define ET_NUM 5 +#endif +#ifndef ET_LOOS +#define ET_LOOS 0xfe00 +#endif +#ifndef ET_HIOS +#define ET_HIOS 0xfeff +#endif +#ifndef ET_LOPROC +#define ET_LOPROC 0xff00 +#endif +#ifndef ET_HIPROC +#define ET_HIPROC 0xffff +#endif + +#ifndef EM_NONE +#define EM_NONE 0 +#endif +#ifndef EM_M32 +#define EM_M32 1 +#endif +#ifndef EM_SPARC +#define EM_SPARC 2 +#endif +#ifndef EM_386 +#define EM_386 3 +#endif +#ifndef EM_68K +#define EM_68K 4 +#endif +#ifndef EM_88K +#define EM_88K 5 +#endif +#ifndef EM_IAMCU +#define EM_IAMCU 6 +#endif +#ifndef EM_860 +#define EM_860 7 +#endif +#ifndef EM_MIPS +#define EM_MIPS 8 +#endif +#ifndef EM_S370 +#define EM_S370 9 +#endif +#ifndef EM_MIPS_RS3_LE +#define EM_MIPS_RS3_LE 10 +#endif +#ifndef EM_PARISC +#define EM_PARISC 15 +#endif +#ifndef EM_VPP500 +#define EM_VPP500 17 +#endif +#ifndef EM_SPARC32PLUS +#define EM_SPARC32PLUS 18 +#endif +#ifndef EM_960 +#define EM_960 19 +#endif +#ifndef EM_PPC +#define EM_PPC 20 +#endif +#ifndef EM_PPC64 +#define EM_PPC64 21 +#endif +#ifndef EM_S390 +#define EM_S390 22 +#endif +#ifndef EM_SPU +#define EM_SPU 23 +#endif +#ifndef EM_V800 +#define EM_V800 36 +#endif +#ifndef EM_FR20 +#define EM_FR20 37 +#endif +#ifndef EM_RH32 +#define EM_RH32 38 +#endif +#ifndef EM_RCE +#define EM_RCE 39 +#endif +#ifndef EM_ARM +#define EM_ARM 40 +#endif +#ifndef EM_FAKE_ALPHA +#define EM_FAKE_ALPHA 41 +#endif +#ifndef EM_SH +#define EM_SH 42 +#endif +#ifndef EM_SPARCV9 +#define EM_SPARCV9 43 +#endif +#ifndef EM_TRICORE +#define EM_TRICORE 44 +#endif +#ifndef EM_ARC +#define EM_ARC 45 +#endif +#ifndef EM_H8_300 +#define EM_H8_300 46 +#endif +#ifndef EM_H8_300H +#define EM_H8_300H 47 +#endif +#ifndef EM_H8S +#define EM_H8S 48 +#endif +#ifndef EM_H8_500 +#define EM_H8_500 49 +#endif +#ifndef EM_IA_64 +#define EM_IA_64 50 +#endif +#ifndef EM_MIPS_X +#define EM_MIPS_X 51 +#endif +#ifndef EM_COLDFIRE +#define EM_COLDFIRE 52 +#endif +#ifndef EM_68HC12 +#define EM_68HC12 53 +#endif +#ifndef EM_MMA +#define EM_MMA 54 +#endif +#ifndef EM_PCP +#define EM_PCP 55 +#endif +#ifndef EM_NCPU +#define EM_NCPU 56 +#endif +#ifndef EM_NDR1 +#define EM_NDR1 57 +#endif +#ifndef EM_STARCORE +#define EM_STARCORE 58 +#endif +#ifndef EM_ME16 +#define EM_ME16 59 +#endif +#ifndef EM_ST100 +#define EM_ST100 60 +#endif +#ifndef EM_TINYJ +#define EM_TINYJ 61 +#endif +#ifndef EM_X86_64 +#define EM_X86_64 62 +#endif +#ifndef EM_PDSP +#define EM_PDSP 63 +#endif +#ifndef EM_PDP10 +#define EM_PDP10 64 +#endif +#ifndef EM_PDP11 +#define EM_PDP11 65 +#endif +#ifndef EM_FX66 +#define EM_FX66 66 +#endif +#ifndef EM_ST9PLUS +#define EM_ST9PLUS 67 +#endif +#ifndef EM_ST7 +#define EM_ST7 68 +#endif +#ifndef EM_68HC16 +#define EM_68HC16 69 +#endif +#ifndef EM_68HC11 +#define EM_68HC11 70 +#endif +#ifndef EM_68HC08 +#define EM_68HC08 71 +#endif +#ifndef EM_68HC05 +#define EM_68HC05 72 +#endif +#ifndef EM_SVX +#define EM_SVX 73 +#endif +#ifndef EM_ST19 +#define EM_ST19 74 +#endif +#ifndef EM_VAX +#define EM_VAX 75 +#endif +#ifndef EM_CRIS +#define EM_CRIS 76 +#endif +#ifndef EM_JAVELIN +#define EM_JAVELIN 77 +#endif +#ifndef EM_FIREPATH +#define EM_FIREPATH 78 +#endif +#ifndef EM_ZSP +#define EM_ZSP 79 +#endif +#ifndef EM_MMIX +#define EM_MMIX 80 +#endif +#ifndef EM_HUANY +#define EM_HUANY 81 +#endif +#ifndef EM_PRISM +#define EM_PRISM 82 +#endif +#ifndef EM_AVR +#define EM_AVR 83 +#endif +#ifndef EM_FR30 +#define EM_FR30 84 +#endif +#ifndef EM_D10V +#define EM_D10V 85 +#endif +#ifndef EM_D30V +#define EM_D30V 86 +#endif +#ifndef EM_V850 +#define EM_V850 87 +#endif +#ifndef EM_M32R +#define EM_M32R 88 +#endif +#ifndef EM_MN10300 +#define EM_MN10300 89 +#endif +#ifndef EM_MN10200 +#define EM_MN10200 90 +#endif +#ifndef EM_PJ +#define EM_PJ 91 +#endif +#ifndef EM_OPENRISC +#define EM_OPENRISC 92 +#endif +#ifndef EM_ARC_COMPACT +#define EM_ARC_COMPACT 93 +#endif +#ifndef EM_XTENSA +#define EM_XTENSA 94 +#endif +#ifndef EM_VIDEOCORE +#define EM_VIDEOCORE 95 +#endif +#ifndef EM_TMM_GPP +#define EM_TMM_GPP 96 +#endif +#ifndef EM_NS32K +#define EM_NS32K 97 +#endif +#ifndef EM_TPC +#define EM_TPC 98 +#endif +#ifndef EM_SNP1K +#define EM_SNP1K 99 +#endif +#ifndef EM_ST200 +#define EM_ST200 100 +#endif +#ifndef EM_IP2K +#define EM_IP2K 101 +#endif +#ifndef EM_MAX +#define EM_MAX 102 +#endif +#ifndef EM_CR +#define EM_CR 103 +#endif +#ifndef EM_F2MC16 +#define EM_F2MC16 104 +#endif +#ifndef EM_MSP430 +#define EM_MSP430 105 +#endif +#ifndef EM_BLACKFIN +#define EM_BLACKFIN 106 +#endif +#ifndef EM_SE_C33 +#define EM_SE_C33 107 +#endif +#ifndef EM_SEP +#define EM_SEP 108 +#endif +#ifndef EM_ARCA +#define EM_ARCA 109 +#endif +#ifndef EM_UNICORE +#define EM_UNICORE 110 +#endif +#ifndef EM_EXCESS +#define EM_EXCESS 111 +#endif +#ifndef EM_DXP +#define EM_DXP 112 +#endif +#ifndef EM_ALTERA_NIOS2 +#define EM_ALTERA_NIOS2 113 +#endif +#ifndef EM_CRX +#define EM_CRX 114 +#endif +#ifndef EM_XGATE +#define EM_XGATE 115 +#endif +#ifndef EM_C166 +#define EM_C166 116 +#endif +#ifndef EM_M16C +#define EM_M16C 117 +#endif +#ifndef EM_DSPIC30F +#define EM_DSPIC30F 118 +#endif +#ifndef EM_CE +#define EM_CE 119 +#endif +#ifndef EM_M32C +#define EM_M32C 120 +#endif +#ifndef EM_TSK3000 +#define EM_TSK3000 131 +#endif +#ifndef EM_RS08 +#define EM_RS08 132 +#endif +#ifndef EM_SHARC +#define EM_SHARC 133 +#endif +#ifndef EM_ECOG2 +#define EM_ECOG2 134 +#endif +#ifndef EM_SCORE7 +#define EM_SCORE7 135 +#endif +#ifndef EM_DSP24 +#define EM_DSP24 136 +#endif +#ifndef EM_VIDEOCORE3 +#define EM_VIDEOCORE3 137 +#endif +#ifndef EM_LATTICEMICO32 +#define EM_LATTICEMICO32 138 +#endif +#ifndef EM_SE_C17 +#define EM_SE_C17 139 +#endif +#ifndef EM_TI_C6000 +#define EM_TI_C6000 140 +#endif +#ifndef EM_TI_C2000 +#define EM_TI_C2000 141 +#endif +#ifndef EM_TI_C5500 +#define EM_TI_C5500 142 +#endif +#ifndef EM_TI_ARP32 +#define EM_TI_ARP32 143 +#endif +#ifndef EM_TI_PRU +#define EM_TI_PRU 144 +#endif +#ifndef EM_MMDSP_PLUS +#define EM_MMDSP_PLUS 160 +#endif +#ifndef EM_CYPRESS_M8C +#define EM_CYPRESS_M8C 161 +#endif +#ifndef EM_R32C +#define EM_R32C 162 +#endif +#ifndef EM_TRIMEDIA +#define EM_TRIMEDIA 163 +#endif +#ifndef EM_QDSP6 +#define EM_QDSP6 164 +#endif +#ifndef EM_QUALCOMM_DSP6 +#define EM_QUALCOMM_DSP6 164 +#endif +#ifndef EM_8051 +#define EM_8051 165 +#endif +#ifndef EM_STXP7X +#define EM_STXP7X 166 +#endif +#ifndef EM_NDS32 +#define EM_NDS32 167 +#endif +#ifndef EM_ECOG1X +#define EM_ECOG1X 168 +#endif +#ifndef EM_MAXQ30 +#define EM_MAXQ30 169 +#endif +#ifndef EM_XIMO16 +#define EM_XIMO16 170 +#endif +#ifndef EM_MANIK +#define EM_MANIK 171 +#endif +#ifndef EM_CRAYNV2 +#define EM_CRAYNV2 172 +#endif +#ifndef EM_RX +#define EM_RX 173 +#endif +#ifndef EM_METAG +#define EM_METAG 174 +#endif +#ifndef EM_MCST_ELBRUS +#define EM_MCST_ELBRUS 175 +#endif +#ifndef EM_ECOG16 +#define EM_ECOG16 176 +#endif +#ifndef EM_CR16 +#define EM_CR16 177 +#endif +#ifndef EM_ETPU +#define EM_ETPU 178 +#endif +#ifndef EM_SLE9X +#define EM_SLE9X 179 +#endif +#ifndef EM_L10M +#define EM_L10M 180 +#endif +#ifndef EM_K10M +#define EM_K10M 181 +#endif +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif +#ifndef EM_AVR32 +#define EM_AVR32 185 +#endif +#ifndef EM_STM8 +#define EM_STM8 186 +#endif +#ifndef EM_TILE64 +#define EM_TILE64 187 +#endif +#ifndef EM_TILEPRO +#define EM_TILEPRO 188 +#endif +#ifndef EM_MICROBLAZE +#define EM_MICROBLAZE 189 +#endif +#ifndef EM_CUDA +#define EM_CUDA 190 +#endif +#ifndef EM_TILEGX +#define EM_TILEGX 191 +#endif +#ifndef EM_CLOUDSHIELD +#define EM_CLOUDSHIELD 192 +#endif +#ifndef EM_COREA_1ST +#define EM_COREA_1ST 193 +#endif +#ifndef EM_COREA_2ND +#define EM_COREA_2ND 194 +#endif +#ifndef EM_ARC_COMPACT2 +#define EM_ARC_COMPACT2 195 +#endif +#ifndef EM_OPEN8 +#define EM_OPEN8 196 +#endif +#ifndef EM_RL78 +#define EM_RL78 197 +#endif +#ifndef EM_VIDEOCORE5 +#define EM_VIDEOCORE5 198 +#endif +#ifndef EM_78KOR +#define EM_78KOR 199 +#endif +#ifndef EM_56800EX +#define EM_56800EX 200 +#endif +#ifndef EM_BA1 +#define EM_BA1 201 +#endif +#ifndef EM_BA2 +#define EM_BA2 202 +#endif +#ifndef EM_XCORE +#define EM_XCORE 203 +#endif +#ifndef EM_MCHP_PIC +#define EM_MCHP_PIC 204 +#endif +#ifndef EM_KM32 +#define EM_KM32 210 +#endif +#ifndef EM_KMX32 +#define EM_KMX32 211 +#endif +#ifndef EM_EMX16 +#define EM_EMX16 212 +#endif +#ifndef EM_EMX8 +#define EM_EMX8 213 +#endif +#ifndef EM_KVARC +#define EM_KVARC 214 +#endif +#ifndef EM_CDP +#define EM_CDP 215 +#endif +#ifndef EM_COGE +#define EM_COGE 216 +#endif +#ifndef EM_COOL +#define EM_COOL 217 +#endif +#ifndef EM_NORC +#define EM_NORC 218 +#endif +#ifndef EM_CSR_KALIMBA +#define EM_CSR_KALIMBA 219 +#endif +#ifndef EM_Z80 +#define EM_Z80 220 +#endif +#ifndef EM_VISIUM +#define EM_VISIUM 221 +#endif +#ifndef EM_FT32 +#define EM_FT32 222 +#endif +#ifndef EM_MOXIE +#define EM_MOXIE 223 +#endif +#ifndef EM_AMDGPU +#define EM_AMDGPU 224 +#endif +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif +#ifndef EM_BPF +#define EM_BPF 247 +#endif + +/* Standard Elf dynamic tags. */ +#ifndef DT_NULL +#define DT_NULL 0 +#endif +#ifndef DT_NEEDED +#define DT_NEEDED 1 +#endif +#ifndef DT_PLTRELSZ +#define DT_PLTRELSZ 2 +#endif +#ifndef DT_PLTGOT +#define DT_PLTGOT 3 +#endif +#ifndef DT_HASH +#define DT_HASH 4 +#endif +#ifndef DT_STRTAB +#define DT_STRTAB 5 +#endif +#ifndef DT_SYMTAB +#define DT_SYMTAB 6 +#endif +#ifndef DT_RELA +#define DT_RELA 7 +#endif +#ifndef DT_REL +#define DT_REL 17 +#endif +#ifndef DT_RELASZ +#define DT_RELASZ 8 +#endif +#ifndef DT_RELAENT +#define DT_RELAENT 9 +#endif +#ifndef DT_STRSZ +#define DT_STRSZ 10 +#endif + +#ifndef DT_SYMENT +#define DT_SYMENT 11 +#endif + +#ifndef DT_INIT +#define DT_INIT 12 +#endif + +#ifndef DT_FINI +#define DT_FINI 13 +#endif + +#ifndef DT_SONAME +#define DT_SONAME 14 +#endif + +#ifndef DT_RPATH +#define DT_RPATH 15 +#endif + +#ifndef DT_SYMBOLIC +#define DT_SYMBOLIC 16 +#endif + +#ifndef DT_REL +#define DT_REL 17 +#endif +#ifndef DT_RELSZ +#define DT_RELSZ 18 +#endif + +#ifndef DT_RELENT +#define DT_RELENT 19 +#endif + +#ifndef DT_PLTREL +#define DT_PLTREL 20 +#endif + +#ifndef DT_DEBUG +#define DT_DEBUG 21 +#endif + +#ifndef DT_TEXTREL +#define DT_TEXTREL 22 +#endif + +#ifndef DT_JMPREL +#define DT_JMPREL 23 +#endif + +#ifndef SHN_UNDEF +#define SHN_UNDEF 0 +#endif +#ifndef SHN_LORESERVE +#define SHN_LORESERVE 0xff00 +#endif +#ifndef SHN_LOPROC +#define SHN_LOPROC 0xff00 +#endif +#ifndef SHN_HIPROC +#define SHN_HIPROC 0xff1f +#endif +#ifndef SHN_ABS +#define SHN_ABS 0xfff1 +#endif +#ifndef SHN_COMMON +#define SHN_COMMON 0xfff2 +#endif +#ifndef SHN_HIRESERVE +#define SHN_HIRESERVE 0xffff +#endif + +#ifndef EV_CURRENT +#define EV_CURRENT 1 +#endif +#ifndef EV_NONE +#define EV_NONE 0 +#endif + +#ifndef EI_MAG0 +#define EI_MAG0 0 +#endif +#ifndef EI_MAG1 +#define EI_MAG1 1 +#endif +#ifndef EI_MAG2 +#define EI_MAG2 2 +#endif +#ifndef EI_MAG3 +#define EI_MAG3 3 +#endif +#ifndef EI_CLASS +#define EI_CLASS 4 +#endif +#ifndef EI_DATA +#define EI_DATA 5 +#endif +#ifndef EI_VERSION +#define EI_VERSION 6 +#endif +#ifndef EI_PAD +#define EI_PAD 7 +#endif +#ifndef EI_OSABI +#define EI_OSABI 7 +#endif +#ifndef EI_NIDENT +#define EI_NIDENT 16 +#endif +#ifndef EI_ABIVERSION +#define EI_ABIVERSION 8 +#endif + +#ifndef ELFMAG0 +#define ELFMAG0 0x7f +#endif +#ifndef ELFMAG1 +#define ELFMAG1 'E' +#endif +#ifndef ELFMAG2 +#define ELFMAG2 'L' +#endif +#ifndef ELFMAG3 +#define ELFMAG3 'F' +#endif +#ifndef ELFCLASSNONE +#define ELFCLASSNONE 0 +#endif +#ifndef ELFCLASS32 +#define ELFCLASS32 1 +#endif +#ifndef ELFCLASS64 +#define ELFCLASS64 2 +#endif +#ifndef ELFDATANONE +#define ELFDATANONE 0 +#endif +#ifndef ELFDATA2LSB +#define ELFDATA2LSB 1 +#endif +#ifndef ELFDATA2MSB +#define ELFDATA2MSB 2 +#endif + +#ifndef ELFOSABI_NONE +#define ELFOSABI_NONE 0 +#endif +#ifndef ELFOSABI_SYSV +#define ELFOSABI_SYSV 0 +#endif +#ifndef ELFOSABI_HPUX +#define ELFOSABI_HPUX 1 +#endif +#ifndef ELFOSABI_NETBSD +#define ELFOSABI_NETBSD 2 +#endif +#ifndef ELFOSABI_GNU +#define ELFOSABI_GNU 3 +#endif +#ifndef ELFOSABI_LINUX +#define ELFOSABI_LINUX ELFOSABI_GNU +#endif +#ifndef ELFOSABI_SOLARIS +#define ELFOSABI_SOLARIS 6 +#endif +#ifndef ELFOSABI_AIX +#define ELFOSABI_AIX 7 +#endif +#ifndef ELFOSABI_IRIX +#define ELFOSABI_IRIX 8 +#endif +#ifndef ELFOSABI_FREEBSD +#define ELFOSABI_FREEBSD 9 +#endif +#ifndef ELFOSABI_TRU64 +#define ELFOSABI_TRU64 10 +#endif +#ifndef ELFOSABI_MODESTO +#define ELFOSABI_MODESTO 11 +#endif +#ifndef ELFOSABI_OPENBSD +#define ELFOSABI_OPENBSD 12 +#endif +#ifndef ELFOSABI_ARM_AEABI +#define ELFOSABI_ARM_AEABI 64 +#endif +#ifndef ELFOSABI_ARM +#define ELFOSABI_ARM 97 +#endif +#ifndef ELFOSABI_STANDALONE +#define ELFOSABI_STANDALONE 255 +#endif + +/* for the producer code. */ +#ifndef R_MIPS_NONE +#define R_MIPS_NONE 0 +#endif +#ifndef R_QUALCOMM_REL32 +#define R_QUALCOMM_REL32 6 +#endif +/* For Freebsd: */ +#ifndef R_PPC64_ADDR32 +#define R_PPC64_ADDR32 1 +#endif +#ifndef R_PPC64_DTPREL32 +#define R_PPC64_DTPREL32 110 +#endif +#ifndef R_PPC64_DTPREL64 +#define R_PPC64_DTPREL64 78 +#endif +#ifndef R_PPC_DTPREL32 +#define R_PPC_DTPREL32 78 +#endif +/* The following two probably useless. */ +#ifndef R_X86_64_PC32_BND +#define R_X86_64_PC32_BND 39 +#endif +#ifndef R_X86_64_PLT32_BND +#define R_X86_64_PLT32_BND 40 +#endif + +/* Seen in a Linux Kernel. Means 'nothing to do' */ +#ifndef R_X86_64_NONE +#define R_X86_64_NONE 0 +#endif /* R_X86_64_NONE */ + +#ifndef R_386_32 +#define R_386_32 1 +#endif /* R_386_32 */ +#ifndef R_386_GOTPC +#define R_386_GOTPC 10 +#endif /* R_386_GOTPC */ +#ifndef R_386_PC32 +#define R_386_PC32 2 +#endif /* R_386_PC32 */ +#ifndef R_386_TLS_DTPOFF32 +#define R_386_TLS_DTPOFF32 36 +#endif /* R_386_TLS_DTPOFF32 */ +#ifndef R_386_TLS_LDO_32 +#define R_386_TLS_LDO_32 32 +#endif /* R_386_TLS_LDO_32 */ +#ifndef R_390_32 +#define R_390_32 4 +#endif /* R_390_32 */ +#ifndef R_390_64 +#define R_390_64 22 +#endif /* R_390_64 */ +#ifndef R_390_TLS_LDO32 +#define R_390_TLS_LDO32 52 +#endif /* R_390_TLS_LDO32 */ +#ifndef R_390_TLS_LDO64 +#define R_390_TLS_LDO64 53 +#endif /* R_390_TLS_LDO64 */ +#ifndef R_AARCH64_NONE +#define R_AARCH64_NONE 0 +#endif /* R_AARCH64_NONE */ +#ifndef R_AARCH64_ABS32 +#define R_AARCH64_ABS32 258 +#endif /* R_AARCH64_ABS32 */ +#ifndef R_AARCH64_ABS64 +#define R_AARCH64_ABS64 257 +#endif /* R_AARCH64_ABS64 */ +#ifndef R_ARM_ABS32 +#define R_ARM_ABS32 2 +#endif /* R_ARM_ABS32 */ +#ifndef R_ARM_TLS_LDO32 +#define R_ARM_TLS_LDO32 106 +#endif /* R_ARM_TLS_LDO32 */ +#ifndef R_IA64_DIR32LSB +#define R_IA64_DIR32LSB 0x25 +#endif /* R_IA64_DIR32LSB */ +#ifndef R_IA64_DIR64LSB +#define R_IA64_DIR64LSB 0x27 +#endif /* R_IA64_DIR64LSB */ +#ifndef R_IA64_DTPREL32LSB +#define R_IA64_DTPREL32LSB 0xb5 +#endif /* R_IA64_DTPREL32LSB */ +#ifndef R_IA64_DTPREL64LSB +#define R_IA64_DTPREL64LSB 0xb7 +#endif /* R_IA64_DTPREL64LSB */ +#ifndef R_IA64_REL32LSB +#define R_IA64_REL32LSB 0x6d +#endif /* R_IA64_REL32LSB */ +#ifndef R_IA64_SECREL32LSB +#define R_IA64_SECREL32LSB 0x65 +#endif /* R_IA64_SECREL32LSB */ +#ifndef R_IA64_SECREL64LSB +#define R_IA64_SECREL64LSB 0x67 +#endif /* R_IA64_SECREL64LSB */ +#ifndef R_MIPS_32 +#define R_MIPS_32 2 +#endif /* R_MIPS_32 */ +#ifndef R_MIPS_64 +#define R_MIPS_64 18 +#endif /* R_MIPS_64 */ +#ifndef R_MIPS_TLS_DTPREL32 +#define R_MIPS_TLS_DTPREL32 39 +#endif /* R_MIPS_TLS_DTPREL32 */ +#ifndef R_MIPS_TLS_DTPREL64 +#define R_MIPS_TLS_DTPREL64 41 +#endif /* R_MIPS_TLS_DTPREL64 */ +#ifndef R_PPC64_ADDR64 +#define R_PPC64_ADDR64 38 +#endif /* R_PPC64_ADDR64 */ +#ifndef R_PPC64_DTPREL32 +#define R_PPC64_DTPREL32 110 +#endif /* R_PPC64_DTPREL32 */ +#ifndef R_PPC64_DTPREL64 +#define R_PPC64_DTPREL64 78 +#endif /* R_PPC64_DTPREL64 */ +#ifndef R_PPC_ADDR32 +#define R_PPC_ADDR32 1 +#endif /* R_PPC_ADDR32 */ +#ifndef R_PPC_DTPREL32 +#define R_PPC_DTPREL32 78 +#endif /* R_PPC_DTPREL32 */ +#ifndef R_QUALCOMM_REL32 +#define R_QUALCOMM_REL32 6 +#endif /* R_QUALCOMM_REL32 */ +#ifndef R_SH_DIR32 +#define R_SH_DIR32 1 +#endif /* R_SH_DIR32 */ +#ifndef R_SH_TLS_DTPOFF32 +#define R_SH_TLS_DTPOFF32 150 +#endif /* R_SH_TLS_DTPOFF32 */ +#ifndef R_SPARC_TLS_DTPOFF32 +#define R_SPARC_TLS_DTPOFF32 76 +#endif /* R_SPARC_TLS_DTPOFF32 */ +#ifndef R_SPARC_TLS_DTPOFF64 +#define R_SPARC_TLS_DTPOFF64 77 +#endif /* R_SPARC_TLS_DTPOFF64 */ +#ifndef R_SPARC_UA32 +#define R_SPARC_UA32 23 +#endif /* R_SPARC_UA32 */ +#ifndef R_SPARC_UA64 +#define R_SPARC_UA64 54 +#endif /* R_SPARC_UA64 */ +#ifndef R_X86_64_32 +#define R_X86_64_32 10 +#endif /* R_X86_64_32 */ +#ifndef R_X86_64_64 +#define R_X86_64_64 1 +#endif /* R_X86_64_64 */ +#ifndef R_X86_64_PC64 +#define R_X86_64_PC64 24 +#endif /* R_X86_64_PC64 */ +#ifndef R_X86_64_DTPOFF32 +#define R_X86_64_DTPOFF32 21 +#endif /* R_X86_64_DTPOFF32 */ +#ifndef R_X86_64_DTPOFF64 +#define R_X86_64_DTPOFF64 17 +#endif /* R_X86_64_DTPOFF64 */ +#ifndef R_X86_64_PC32 +#define R_X86_64_PC32 2 +#endif /* R_X86_64_PC32 */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_ELF_DEFINES_H */ diff --git a/src/lib/libdwarf/dwarf_elf_load_headers.c b/src/lib/libdwarf/dwarf_elf_load_headers.c new file mode 100644 index 0000000..6c1cdfe --- /dev/null +++ b/src/lib/libdwarf/dwarf_elf_load_headers.c @@ -0,0 +1,2230 @@ +/* Copyright 2018 David Anderson. All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* +This reads elf headers and creates generic-elf +structures containing the Elf headers. + +These two enums used for type safety in passing +values. See dwarf_elfread.h + +enum RelocRela +enum RelocOffsetSize + +dwarf_elfread.c +calls + _dwarf_load_elf_relx(intfc,i,...,enum RelocRela,errcode) + calls _dwarf_elf_load_a_relx_batch(ep,...enum RelocRela, + enum RelocOffsetSize,errcode) + which calls generic_rel_from_rela32(ep,gsh,relp,grel + or calls generic_rel_from_rela64(ep,gsh,relp,grel + or calls generic_rel_from_rel32(ep,gsh,relp,grel... + or calls generic_rel_from_rel64(ep,gsh,relp,grel... +*/ + +#include + +#include /* size_t */ +#include /* calloc() free() malloc() */ +#include /* memcpy() strcmp() strdup() + strlen() strncmp() */ + +/* Windows specific header files */ +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* close() off_t */ +#elif defined HAVE_UNISTD_H +#include /* close() */ +#endif /* _WIN32 */ +#ifdef HAVE_FCNTL_H +#include /* open() O_RDONLY */ +#endif /* HAVE_FCNTL_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_reading.h" +#include "dwarf_elf_defines.h" +#include "dwarf_elfstructs.h" +#include "dwarf_elfread.h" +#include "dwarf_object_detector.h" +#include "dwarf_object_read_common.h" +#include "dwarf_util.h" +#include "dwarf_secname_ck.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif /* O_CLOEXEC */ + +#if 0 +/* One example of calling this. + place just before DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE + dumpsizes(__LINE__,strsectlength,strpsh->gh_offset, + ep->f_filesize); +*/ +static void +dumpsizes(int line,Dwarf_Unsigned s, + Dwarf_Unsigned o, + Dwarf_Unsigned fsz) +{ + Dwarf_Unsigned tlen = s + o; + printf("Size Error DEBUGONLY sz 0x%llx off 0x%llx fsx 0x%llx " + "sum 0x%llx line %d \n", + s,o,fsz,tlen,line); +} +#endif /*0*/ + +int nibblecounts[16] = { +0,1,1,2, +1,2,2,3, +2,2,2,3, +2,3,3,4 +}; + +static int +getbitsoncount(Dwarf_Unsigned v_in) +{ + int bitscount = 0; + Dwarf_Unsigned v = v_in; + + while (v) { + unsigned int nibble = v & 0xf; + bitscount += nibblecounts[nibble]; + v >>= 4; + } + return bitscount; +} + +static int +_dwarf_load_elf_section_is_dwarf(const char *sname, + int *is_rela,int *is_rel) +{ + *is_rel = FALSE; + *is_rela = FALSE; + if (_dwarf_ignorethissection(sname)) { + return FALSE; + } + if (!strncmp(sname,".rel",4)) { + if (!strncmp(sname,".rela.",6)) { + *is_rela = TRUE; + return TRUE; + } + if (!strncmp(sname,".rel.",5)) { + *is_rela = TRUE; + return TRUE; + } + /* Else something is goofy/Impossible */ + return FALSE; + } + if (!strncmp(sname,".debug_",7)) { + return TRUE; + } + if (!strncmp(sname,".zdebug_",8)) { + return TRUE; + } + if (!strcmp(sname,".eh_frame")) { + return TRUE; + } + if (!strncmp(sname,".gdb_index",10)) { + return TRUE; + } + return FALSE; +} + +static int +is_empty_section(Dwarf_Unsigned type) +{ + if (type == SHT_NOBITS) { + return TRUE; + } + if (type == SHT_NULL) { + return TRUE; + } + return FALSE; +} + +static int +generic_ehdr_from_32(dwarf_elf_object_access_internals_t *ep, + struct generic_ehdr *ehdr, dw_elf32_ehdr *e, + int *errcode) +{ + int i = 0; + + for (i = 0; i < EI_NIDENT; ++i) { + ehdr->ge_ident[i] = e->e_ident[i]; + } + ASNAR(ep->f_copy_word,ehdr->ge_type,e->e_type); + ASNAR(ep->f_copy_word,ehdr->ge_machine,e->e_machine); + ASNAR(ep->f_copy_word,ehdr->ge_version,e->e_version); + ASNAR(ep->f_copy_word,ehdr->ge_entry,e->e_entry); + ASNAR(ep->f_copy_word,ehdr->ge_phoff,e->e_phoff); + ASNAR(ep->f_copy_word,ehdr->ge_shoff,e->e_shoff); + ASNAR(ep->f_copy_word,ehdr->ge_flags,e->e_flags); + ASNAR(ep->f_copy_word,ehdr->ge_ehsize,e->e_ehsize); + ASNAR(ep->f_copy_word,ehdr->ge_phentsize,e->e_phentsize); + ASNAR(ep->f_copy_word,ehdr->ge_phnum,e->e_phnum); + ASNAR(ep->f_copy_word,ehdr->ge_shentsize,e->e_shentsize); + ASNAR(ep->f_copy_word,ehdr->ge_shnum,e->e_shnum); + ASNAR(ep->f_copy_word,ehdr->ge_shstrndx,e->e_shstrndx); + if (ehdr->ge_shoff < sizeof(dw_elf32_ehdr)) { + /* zero or offset is inside the header! */ + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + if (ehdr->ge_shstrndx == SHN_XINDEX) { + ehdr->ge_strndx_extended = TRUE; + } else { + ehdr->ge_strndx_in_strndx = TRUE; + if (ehdr->ge_shstrndx < 1) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + } + /* If !ge_strndx_extended && !ehdr->ge_shnum + this is a very unusual case. */ + if (!ehdr->ge_shnum) { + ehdr->ge_shnum_extended = TRUE; + } else { + ehdr->ge_shnum_in_shnum = TRUE; + if (ehdr->ge_shnum < 3) { + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + } + if (ehdr->ge_shnum_in_shnum && + ehdr->ge_strndx_in_strndx && + (ehdr->ge_shstrndx >= ehdr->ge_shnum)) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + + ep->f_machine = (unsigned int)ehdr->ge_machine; + ep->f_ehdr = ehdr; + ep->f_loc_ehdr.g_name = "Elf File Header"; + ep->f_loc_ehdr.g_offset = 0; + ep->f_loc_ehdr.g_count = 1; + ep->f_loc_ehdr.g_entrysize = sizeof(dw_elf32_ehdr); + ep->f_loc_ehdr.g_totalsize = sizeof(dw_elf32_ehdr); + return DW_DLV_OK; +} + +static int +generic_ehdr_from_64(dwarf_elf_object_access_internals_t* ep, + struct generic_ehdr *ehdr, dw_elf64_ehdr *e, + int *errcode) +{ + int i = 0; + + for (i = 0; i < EI_NIDENT; ++i) { + ehdr->ge_ident[i] = e->e_ident[i]; + } + ASNAR(ep->f_copy_word,ehdr->ge_type,e->e_type); + ASNAR(ep->f_copy_word,ehdr->ge_machine,e->e_machine); + ASNAR(ep->f_copy_word,ehdr->ge_version,e->e_version); + ASNAR(ep->f_copy_word,ehdr->ge_entry,e->e_entry); + ASNAR(ep->f_copy_word,ehdr->ge_phoff,e->e_phoff); + ASNAR(ep->f_copy_word,ehdr->ge_shoff,e->e_shoff); + ASNAR(ep->f_copy_word,ehdr->ge_flags,e->e_flags); + ASNAR(ep->f_copy_word,ehdr->ge_ehsize,e->e_ehsize); + ASNAR(ep->f_copy_word,ehdr->ge_phentsize,e->e_phentsize); + ASNAR(ep->f_copy_word,ehdr->ge_phnum,e->e_phnum); + ASNAR(ep->f_copy_word,ehdr->ge_shentsize,e->e_shentsize); + ASNAR(ep->f_copy_word,ehdr->ge_shnum,e->e_shnum); + ASNAR(ep->f_copy_word,ehdr->ge_shstrndx,e->e_shstrndx); + if (ehdr->ge_shoff < sizeof(dw_elf64_ehdr)) { + /* zero or offset is inside the header! */ + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + if (ehdr->ge_shstrndx == SHN_XINDEX) { + ehdr->ge_strndx_extended = TRUE; + } else { + ehdr->ge_strndx_in_strndx = TRUE; + if (ehdr->ge_shstrndx < 1) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + } + if (!ehdr->ge_shnum) { + ehdr->ge_shnum_extended = TRUE; + } else { + ehdr->ge_shnum_in_shnum = TRUE; + if (ehdr->ge_shnum < 3) { + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + } + if (ehdr->ge_shnum_in_shnum && + ehdr->ge_strndx_in_strndx && + (ehdr->ge_shstrndx >= ehdr->ge_shnum)) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + ep->f_machine = (unsigned int)ehdr->ge_machine; + ep->f_ehdr = ehdr; + ep->f_loc_ehdr.g_name = "Elf File Header"; + ep->f_loc_ehdr.g_offset = 0; + ep->f_loc_ehdr.g_count = 1; + ep->f_loc_ehdr.g_entrysize = sizeof(dw_elf64_ehdr); + ep->f_loc_ehdr.g_totalsize = sizeof(dw_elf64_ehdr); + return DW_DLV_OK; +} + +#if 0 /* not used */ +static int +generic_phdr_from_phdr32(dwarf_elf_object_access_internals_t* ep, + struct generic_phdr **phdr_out, + Dwarf_Unsigned * count_out, + Dwarf_Unsigned offset, + Dwarf_Unsigned entsize, + Dwarf_Unsigned count, + int *errcode) +{ + dw_elf32_phdr *pph =0; + dw_elf32_phdr *orig_pph =0; + struct generic_phdr *gphdr =0; + struct generic_phdr *orig_gphdr =0; + Dwarf_Unsigned i = 0; + int res = 0; + + *count_out = 0; + pph = (dw_elf32_phdr *)calloc(count , entsize); + if (pph == 0) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gphdr = (struct generic_phdr *)calloc(count,sizeof(*gphdr)); + if (gphdr == 0) { + free(pph); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + + orig_pph = pph; + orig_gphdr = gphdr; + res = RRMOA(ep->f_fd,pph,offset,count*entsize, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(pph); + free(gphdr); + return res; + } + for ( i = 0; i < count; + ++i, pph++,gphdr++) { + ASNAR(ep->f_copy_word,gphdr->gp_type,pph->p_type); + ASNAR(ep->f_copy_word,gphdr->gp_offset,pph->p_offset); + ASNAR(ep->f_copy_word,gphdr->gp_vaddr,pph->p_vaddr); + ASNAR(ep->f_copy_word,gphdr->gp_paddr,pph->p_paddr); + ASNAR(ep->f_copy_word,gphdr->gp_filesz,pph->p_filesz); + ASNAR(ep->f_copy_word,gphdr->gp_memsz,pph->p_memsz); + ASNAR(ep->f_copy_word,gphdr->gp_flags,pph->p_flags); + ASNAR(ep->f_copy_word,gphdr->gp_align,pph->p_align); + } + free(orig_pph); + *phdr_out = orig_gphdr; + *count_out = count; + ep->f_phdr = orig_gphdr; + ep->f_loc_phdr.g_name = "Program Header"; + ep->f_loc_phdr.g_offset = offset; + ep->f_loc_phdr.g_count = count; + ep->f_loc_phdr.g_entrysize = sizeof(dw_elf32_phdr); + ep->f_loc_phdr.g_totalsize = sizeof(dw_elf32_phdr)*count; + return DW_DLV_OK; +} + +static int +generic_phdr_from_phdr64(dwarf_elf_object_access_internals_t* ep, + struct generic_phdr **phdr_out, + Dwarf_Unsigned * count_out, + Dwarf_Unsigned offset, + Dwarf_Unsigned entsize, + Dwarf_Unsigned count, + int *errcode) +{ + dw_elf64_phdr *pph =0; + dw_elf64_phdr *orig_pph =0; + struct generic_phdr *gphdr =0; + struct generic_phdr *orig_gphdr =0; + int res = 0; + Dwarf_Unsigned i = 0; + + *count_out = 0; + pph = (dw_elf64_phdr *)calloc(count , entsize); + if (pph == 0) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gphdr = (struct generic_phdr *)calloc(count,sizeof(*gphdr)); + if (gphdr == 0) { + free(pph); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + + orig_pph = pph; + orig_gphdr = gphdr; + res = RRMOA(ep->f_fd,pph,offset,count*entsize, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(pph); + free(gphdr); + return res; + } + for ( i = 0; i < count; + ++i, pph++,gphdr++) { + ASNAR(ep->f_copy_word,gphdr->gp_type,pph->p_type); + ASNAR(ep->f_copy_word,gphdr->gp_offset,pph->p_offset); + ASNAR(ep->f_copy_word,gphdr->gp_vaddr,pph->p_vaddr); + ASNAR(ep->f_copy_word,gphdr->gp_paddr,pph->p_paddr); + ASNAR(ep->f_copy_word,gphdr->gp_filesz,pph->p_filesz); + ASNAR(ep->f_copy_word,gphdr->gp_memsz,pph->p_memsz); + ASNAR(ep->f_copy_word,gphdr->gp_flags,pph->p_flags); + ASNAR(ep->f_copy_word,gphdr->gp_align,pph->p_align); + } + free(orig_pph); + *phdr_out = orig_gphdr; + *count_out = count; + ep->f_phdr = orig_gphdr; + ep->f_loc_phdr.g_name = "Program Header"; + ep->f_loc_phdr.g_offset = offset; + ep->f_loc_phdr.g_count = count; + ep->f_loc_phdr.g_entrysize = sizeof(dw_elf64_phdr); + ep->f_loc_phdr.g_totalsize = sizeof(dw_elf64_phdr)*count; + return DW_DLV_OK; +} +#endif /*0*/ + +static void +copysection32( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr *gshdr, + dw_elf32_shdr *psh) +{ + ASNAR(ep->f_copy_word,gshdr->gh_name,psh->sh_name); + ASNAR(ep->f_copy_word,gshdr->gh_type,psh->sh_type); + ASNAR(ep->f_copy_word,gshdr->gh_flags,psh->sh_flags); + ASNAR(ep->f_copy_word,gshdr->gh_addr,psh->sh_addr); + ASNAR(ep->f_copy_word,gshdr->gh_offset,psh->sh_offset); + ASNAR(ep->f_copy_word,gshdr->gh_size,psh->sh_size); + ASNAR(ep->f_copy_word,gshdr->gh_link,psh->sh_link); + ASNAR(ep->f_copy_word,gshdr->gh_info,psh->sh_info); + ASNAR(ep->f_copy_word,gshdr->gh_addralign,psh->sh_addralign); + ASNAR(ep->f_copy_word,gshdr->gh_entsize,psh->sh_entsize); +} + +static int +generic_shdr_from_shdr32(dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned * count_out, + Dwarf_Unsigned offset, + Dwarf_Unsigned entsize, + Dwarf_Unsigned count, + int *errcode) +{ + dw_elf32_shdr *psh =0; + dw_elf32_shdr *orig_psh =0; + struct generic_ehdr *ehdr = ep->f_ehdr; + struct generic_shdr *gshdr =0; + struct generic_shdr *orig_gshdr =0; + Dwarf_Unsigned i = 0; + int res = 0; + + *count_out = 0; + psh = (dw_elf32_shdr *)calloc(count , entsize); + if (!psh) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gshdr = (struct generic_shdr *)calloc(count,sizeof(*gshdr)); + if (!gshdr) { + free(psh); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + + orig_psh = psh; + orig_gshdr = gshdr; + res = RRMOA(ep->f_fd,psh,offset,count*entsize, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(orig_psh); + free(orig_gshdr); + return res; + } + for (i = 0; i < count; + ++i, psh++,gshdr++) { + int isempty = FALSE; + int bitsoncount = 0; + + gshdr->gh_secnum = i; + copysection32(ep,gshdr,psh); +#if 1 + if (gshdr->gh_size >= ep->f_filesize && + gshdr->gh_type != SHT_NOBITS) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } +#endif /* 0 */ + isempty = is_empty_section(gshdr->gh_type); + if (i == 0) { + Dwarf_Unsigned shnum = 0; + Dwarf_Unsigned shstrx = 0; + + /* Catch errors asap */ + if (!ehdr->ge_shnum_extended) { + shnum = gshdr->gh_size; + } + if (!ehdr->ge_strndx_extended) { + shstrx = gshdr->gh_link; + } + /* We require that section zero be 'empty' + per the Elf ABI. + gh_link and gh_size are sometimes used + with the elf header, so we do not check + them here. */ + if (!isempty || gshdr->gh_name || gshdr->gh_flags || + shnum || shstrx || + gshdr->gh_addr || + gshdr->gh_info) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_IMPROPER_SECTION_ZERO; + return DW_DLV_ERROR; + } + } + bitsoncount = getbitsoncount(gshdr->gh_flags); + if (bitsoncount > 8) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_BAD_SECTION_FLAGS; + return DW_DLV_ERROR; + } + + if (gshdr->gh_type == SHT_REL || gshdr->gh_type == SHT_RELA){ + gshdr->gh_reloc_target_secnum = gshdr->gh_info; + } + } + free(orig_psh); + *count_out = count; + ep->f_shdr = orig_gshdr; + ep->f_loc_shdr.g_name = "Section Header"; + ep->f_loc_shdr.g_count = count; + ep->f_loc_shdr.g_offset = offset; + ep->f_loc_shdr.g_entrysize = sizeof(dw_elf32_shdr); + ep->f_loc_shdr.g_totalsize = sizeof(dw_elf32_shdr)*count; + return DW_DLV_OK; +} + +static void +copysection64( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr *gshdr, + dw_elf64_shdr *psh) +{ + ASNAR(ep->f_copy_word,gshdr->gh_name,psh->sh_name); + ASNAR(ep->f_copy_word,gshdr->gh_type,psh->sh_type); + ASNAR(ep->f_copy_word,gshdr->gh_flags,psh->sh_flags); + ASNAR(ep->f_copy_word,gshdr->gh_addr,psh->sh_addr); + ASNAR(ep->f_copy_word,gshdr->gh_offset,psh->sh_offset); + ASNAR(ep->f_copy_word,gshdr->gh_size,psh->sh_size); + ASNAR(ep->f_copy_word,gshdr->gh_link,psh->sh_link); + ASNAR(ep->f_copy_word,gshdr->gh_info,psh->sh_info); + ASNAR(ep->f_copy_word,gshdr->gh_addralign,psh->sh_addralign); + ASNAR(ep->f_copy_word,gshdr->gh_entsize,psh->sh_entsize); +} + +static int +generic_shdr_from_shdr64(dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned * count_out, + Dwarf_Unsigned offset, + Dwarf_Unsigned entsize, + Dwarf_Unsigned count, + int *errcode) +{ + dw_elf64_shdr *psh =0; + dw_elf64_shdr *orig_psh =0; + struct generic_shdr *gshdr =0; + struct generic_shdr *orig_gshdr =0; + struct generic_ehdr *ehdr = ep->f_ehdr; + Dwarf_Unsigned i = 0; + int res = 0; + + *count_out = 0; + psh = (dw_elf64_shdr *)calloc(count , entsize); + if (!psh) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gshdr = (struct generic_shdr *)calloc(count,sizeof(*gshdr)); + if (gshdr == 0) { + free(psh); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + orig_psh = psh; + orig_gshdr = gshdr; + res = RRMOA(ep->f_fd,psh,offset,count*entsize, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(orig_psh); + free(orig_gshdr); + return res; + } + for ( i = 0; i < count; + ++i, psh++,gshdr++) { + int bitsoncount = 0; + int isempty = FALSE; + + gshdr->gh_secnum = i; + copysection64(ep,gshdr,psh); + if (gshdr->gh_size >= ep->f_filesize && + gshdr->gh_type != SHT_NOBITS) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + isempty = is_empty_section(gshdr->gh_type); + if (i == 0) { + Dwarf_Unsigned shnum = 0; + Dwarf_Unsigned shstrx = 0; + + /* Catch errors asap */ + if (!ehdr->ge_shnum_extended) { + shnum = gshdr->gh_size; + } + if (!ehdr->ge_strndx_extended) { + shstrx = gshdr->gh_link; + } + /* We require that section zero be 'empty' + per the Elf ABI. + But gh_link and gh_size might be used for + ge_shstrndx and ge_shnum, respectively*/ + if (!isempty || gshdr->gh_name || gshdr->gh_flags || + shnum || shstrx || + gshdr->gh_addr || + gshdr->gh_info) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_IMPROPER_SECTION_ZERO; + return DW_DLV_ERROR; + } + } + bitsoncount = getbitsoncount(gshdr->gh_flags); + if (bitsoncount > 8) { + free(orig_psh); + free(orig_gshdr); + *errcode = DW_DLE_BAD_SECTION_FLAGS; + return DW_DLV_ERROR; + } + + if (gshdr->gh_type == SHT_REL || + gshdr->gh_type == SHT_RELA){ + gshdr->gh_reloc_target_secnum = gshdr->gh_info; + } + } + free(orig_psh); + *count_out = count; + ep->f_shdr = orig_gshdr; + ep->f_loc_shdr.g_name = "Section Header"; + ep->f_loc_shdr.g_count = count; + ep->f_loc_shdr.g_offset = offset; + ep->f_loc_shdr.g_entrysize = sizeof(dw_elf64_shdr); + ep->f_loc_shdr.g_totalsize = sizeof(dw_elf64_shdr)*count; + return DW_DLV_OK; +} + +static int +_dwarf_generic_elf_load_symbols32( + dwarf_elf_object_access_internals_t *ep, + struct generic_symentry **gsym_out, + Dwarf_Unsigned offset,Dwarf_Unsigned size, + Dwarf_Unsigned *count_out,int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + dw_elf32_sym *psym = 0; + dw_elf32_sym *orig_psym = 0; + struct generic_symentry * gsym = 0; + struct generic_symentry * orig_gsym = 0; + int res = 0; + + ecount = (long)(size/sizeof(dw_elf32_sym)); + size2 = ecount * sizeof(dw_elf32_sym); + if (size != size2) { + *errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size >= ep->f_filesize ) { + *errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + psym = calloc(ecount,sizeof(dw_elf32_sym)); + if (!psym) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gsym = calloc(ecount,sizeof(struct generic_symentry)); + if (!gsym) { + free(psym); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,psym,offset,size, + ep->f_filesize,errcode); + if (res!= DW_DLV_OK) { + free(psym); + free(gsym); + return res; + } + orig_psym = psym; + orig_gsym = gsym; + for ( i = 0; i < ecount; ++i,++psym,++gsym) { + Dwarf_Unsigned bind = 0; + Dwarf_Unsigned type = 0; + + ASNAR(ep->f_copy_word,gsym->gs_name,psym->st_name); + ASNAR(ep->f_copy_word,gsym->gs_value,psym->st_value); + ASNAR(ep->f_copy_word,gsym->gs_size,psym->st_size); + ASNAR(ep->f_copy_word,gsym->gs_info,psym->st_info); + ASNAR(ep->f_copy_word,gsym->gs_other,psym->st_other); + ASNAR(ep->f_copy_word,gsym->gs_shndx,psym->st_shndx); + bind = gsym->gs_info >> 4; + type = gsym->gs_info & 0xf; + gsym->gs_bind = bind; + gsym->gs_type = type; + } + *count_out = ecount; + *gsym_out = orig_gsym; + free(orig_psym); + return DW_DLV_OK; +} + +static int +_dwarf_generic_elf_load_symbols64( + dwarf_elf_object_access_internals_t *ep, + struct generic_symentry **gsym_out, + Dwarf_Unsigned offset,Dwarf_Unsigned size, + Dwarf_Unsigned *count_out,int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + dw_elf64_sym *psym = 0; + dw_elf64_sym *orig_psym = 0; + struct generic_symentry * gsym = 0; + struct generic_symentry * orig_gsym = 0; + int res = 0; + + ecount = (long)(size/sizeof(dw_elf64_sym)); + size2 = ecount * sizeof(dw_elf64_sym); + if (size != size2) { + *errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size >= ep->f_filesize ) { + *errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + psym = calloc(ecount,sizeof(dw_elf64_sym)); + if (!psym) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + gsym = calloc(ecount,sizeof(struct generic_symentry)); + if (!gsym) { + free(psym); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,psym,offset,size, + ep->f_filesize,errcode); + if (res!= DW_DLV_OK) { + free(psym); + free(gsym); + *errcode = DW_DLE_ALLOC_FAIL; + return res; + } + orig_psym = psym; + orig_gsym = gsym; + for ( i = 0; i < ecount; ++i,++psym,++gsym) { + Dwarf_Unsigned bind = 0; + Dwarf_Unsigned type = 0; + + ASNAR(ep->f_copy_word,gsym->gs_name,psym->st_name); + ASNAR(ep->f_copy_word,gsym->gs_value,psym->st_value); + ASNAR(ep->f_copy_word,gsym->gs_size,psym->st_size); + ASNAR(ep->f_copy_word,gsym->gs_info,psym->st_info); + ASNAR(ep->f_copy_word,gsym->gs_other,psym->st_other); + ASNAR(ep->f_copy_word,gsym->gs_shndx,psym->st_shndx); + bind = gsym->gs_info >> 4; + type = gsym->gs_info & 0xf; + gsym->gs_bind = bind; + gsym->gs_type = type; + } + *count_out = ecount; + *gsym_out = orig_gsym; + free(orig_psym); + return DW_DLV_OK; +} + +static int +_dwarf_generic_elf_load_symbols( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned secnum, + struct generic_shdr *psh, + struct generic_symentry **gsym_out, + Dwarf_Unsigned *count_out,int *errcode) +{ + int res = 0; + struct generic_symentry *gsym = 0; + Dwarf_Unsigned count = 0; + + if (!secnum) { + return DW_DLV_NO_ENTRY; + } + if (psh->gh_size > ep->f_filesize) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (ep->f_offsetsize == 32) { + res = _dwarf_generic_elf_load_symbols32(ep, + &gsym, + psh->gh_offset,psh->gh_size, + &count,errcode); + } else if (ep->f_offsetsize == 64) { + res = _dwarf_generic_elf_load_symbols64(ep, + &gsym, + psh->gh_offset,psh->gh_size, + &count,errcode); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + if (res == DW_DLV_OK) { + *gsym_out = gsym; + *count_out = count; + } + return res; +} +#if 0 /* not needed */ +int +dwarf_load_elf_dynsym_symbols( + dwarf_elf_object_access_internals_t *ep, int*errcode) +{ + int res = 0; + struct generic_symentry *gsym = 0; + Dwarf_Unsigned count = 0; + Dwarf_Unsigned secnum = ep->f_dynsym_sect_index; + struct generic_shdr * psh = 0; + + if (!secnum) { + return DW_DLV_NO_ENTRY; + } + psh = ep->f_shdr + secnum; + if we ever use this... gh_size big? + res = _dwarf_generic_elf_load_symbols(ep, + secnum, + psh, + &gsym, + &count,errcode); + if (res == DW_DLV_OK) { + ep->f_dynsym = gsym; + ep->f_loc_dynsym.g_count = count; + } + return res; +} +#endif /*0*/ + +int +_dwarf_load_elf_symtab_symbols( + dwarf_elf_object_access_internals_t *ep, int*errcode) +{ + int res = 0; + struct generic_symentry *gsym = 0; + Dwarf_Unsigned count = 0; + Dwarf_Unsigned secnum = ep->f_symtab_sect_index; + struct generic_shdr * psh = 0; + + if (!secnum) { + return DW_DLV_NO_ENTRY; + } + psh = ep->f_shdr + secnum; + if (psh->gh_size > ep->f_filesize) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + res = _dwarf_generic_elf_load_symbols(ep, + secnum, + psh, + &gsym, + &count,errcode); + if (res == DW_DLV_OK) { + ep->f_symtab = gsym; + ep->f_loc_symtab.g_count = count; + } + return res; +} + +static int +generic_rel_from_rela32( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr * gsh, + dw_elf32_rela *relp, + struct generic_rela *grel, + int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size = gsh->gh_size; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + + ecount = size/sizeof(dw_elf32_rela); + size2 = ecount * sizeof(dw_elf32_rela); + if (size >= ep->f_filesize) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size != size2) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + for ( i = 0; i < ecount; ++i,++relp,++grel) { + ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset); + ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info); + /* addend signed */ + ASNAR(ep->f_copy_word,grel->gr_addend,relp->r_addend); + SIGN_EXTEND(grel->gr_addend,sizeof(relp->r_addend)); + grel->gr_sym = grel->gr_info>>8; /* ELF32_R_SYM */ + grel->gr_type = grel->gr_info & 0xff; + grel->gr_is_rela = TRUE; + } + return DW_DLV_OK; +} + +static int +generic_rel_from_rela64( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr * gsh, + dw_elf64_rela *relp, + struct generic_rela *grel, int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size = gsh->gh_size; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + int objlittleendian = (ep->f_endian == DW_END_little); + int ismips64 = (ep->f_machine == EM_MIPS); + int issparcv9 = (ep->f_machine == EM_SPARCV9); + + ecount = size/sizeof(dw_elf64_rela); + size2 = ecount * sizeof(dw_elf64_rela); + if (size >= ep->f_filesize) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size != size2) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + for ( i = 0; i < ecount; ++i,++relp,++grel) { + ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset); + ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info); + ASNAR(ep->f_copy_word,grel->gr_addend,relp->r_addend); + SIGN_EXTEND(grel->gr_addend,sizeof(relp->r_addend)); + if (ismips64 && objlittleendian ) { + char realsym[4]; + + memcpy(realsym,&relp->r_info,sizeof(realsym)); + ASNAR(ep->f_copy_word,grel->gr_sym,realsym); + grel->gr_type = relp->r_info[7]; + grel->gr_type2 = relp->r_info[6]; + grel->gr_type3 = relp->r_info[5]; + } else if (issparcv9) { + /* Always Big Endian? */ + char realsym[4]; + + memcpy(realsym,&relp->r_info,sizeof(realsym)); + ASNAR(ep->f_copy_word,grel->gr_sym,realsym); + grel->gr_type = relp->r_info[7]; + } else { + grel->gr_sym = grel->gr_info >> 32; + grel->gr_type = grel->gr_info & 0xffffffff; + } + grel->gr_is_rela = TRUE; + } + return DW_DLV_OK; +} + +static int +generic_rel_from_rel32( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr * gsh, + dw_elf32_rel *relp, + struct generic_rela *grel,int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size = gsh->gh_size; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + + ecount = size/sizeof(dw_elf32_rel); + size2 = ecount * sizeof(dw_elf32_rel); + if (size >= ep->f_filesize) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size != size2) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + for ( i = 0; i < ecount; ++i,++relp,++grel) { + ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset); + ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info); + grel->gr_addend = 0; /* Unused for plain .rel */ + grel->gr_sym = grel->gr_info >>8; /* ELF32_R_SYM */ + grel->gr_is_rela = FALSE; + grel->gr_type = grel->gr_info & 0xff; + } + return DW_DLV_OK; +} + +static int +generic_rel_from_rel64( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr * gsh, + dw_elf64_rel *relp, + struct generic_rela *grel,int *errcode) +{ + Dwarf_Unsigned ecount = 0; + Dwarf_Unsigned size = gsh->gh_size; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned i = 0; + int objlittleendian = (ep->f_endian == DW_END_little); + int ismips64 = (ep->f_machine == EM_MIPS); + int issparcv9 = (ep->f_machine == EM_SPARCV9); + + ecount = size/sizeof(dw_elf64_rel); + size2 = ecount * sizeof(dw_elf64_rel); + if (size >= ep->f_filesize) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (size != size2) { + *errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + for ( i = 0; i < ecount; ++i,++relp,++grel) { + ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset); + ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info); + grel->gr_addend = 0; /* Unused for plain .rel */ + if (ismips64 && objlittleendian ) { + char realsym[4]; + + memcpy(realsym,&relp->r_info,sizeof(realsym)); + ASNAR(ep->f_copy_word,grel->gr_sym,realsym); + grel->gr_type = relp->r_info[7]; + grel->gr_type2 = relp->r_info[6]; + grel->gr_type3 = relp->r_info[5]; + } else if (issparcv9) { + /* Always Big Endian? */ + char realsym[4]; + + memcpy(realsym,&relp->r_info,sizeof(realsym)); + ASNAR(ep->f_copy_word,grel->gr_sym,realsym); + grel->gr_type = relp->r_info[7]; + } else { + grel->gr_sym = grel->gr_info >>32; + grel->gr_type = grel->gr_info & 0xffffffff; + } + grel->gr_is_rela = FALSE; + } + return DW_DLV_OK; +} + +#if 0 /* not needed */ +int +dwarf_load_elf_dynstr( + dwarf_elf_object_access_internals_t *ep, int *errcode) +{ + struct generic_shdr *strpsh = 0; + int res = 0; + Dwarf_Unsigned strsectindex =0; + Dwarf_Unsigned strsectlength = 0; + + if (!ep->f_dynsym_sect_strings_sect_index) { + return DW_DLV_NO_ENTRY; + } + strsectindex = ep->f_dynsym_sect_strings_sect_index; + strsectlength = ep->f_dynsym_sect_strings_max; + strpsh = ep->f_shdr + strsectindex; + /* Alloc an extra byte as a guaranteed NUL byte + at the end of the strings in case the section + is corrupted and lacks a NUL at end. */ + ep->f_dynsym_sect_strings = calloc(1,strsectlength+1); + if (!ep->f_dynsym_sect_strings) { + ep->f_dynsym_sect_strings = 0; + ep->f_dynsym_sect_strings_max = 0; + ep->f_dynsym_sect_strings_sect_index = 0; + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,ep->f_dynsym_sect_strings, + strpsh->gh_offset, + strsectlength, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + ep->f_dynsym_sect_strings = 0; + ep->f_dynsym_sect_strings_max = 0; + ep->f_dynsym_sect_strings_sect_index = 0; + return res; + } + return DW_DLV_OK; +} +#endif /*0*/ + +int +_dwarf_load_elf_symstr( + dwarf_elf_object_access_internals_t *ep, int *errcode) +{ + struct generic_shdr *strpsh = 0; + int res = 0; + Dwarf_Unsigned strsectindex =0; + Dwarf_Unsigned strsectlength = 0; + + if (!ep->f_symtab_sect_strings_sect_index) { + return DW_DLV_NO_ENTRY; + } + strsectindex = ep->f_symtab_sect_strings_sect_index; + strsectlength = ep->f_symtab_sect_strings_max; + strpsh = ep->f_shdr + strsectindex; + /* Alloc an extra byte as a guaranteed NUL byte + at the end of the strings in case the section + is corrupted and lacks a NUL at end. */ + if (strsectlength > ep->f_filesize || + strpsh->gh_offset >ep->f_filesize || + (strsectlength + strpsh->gh_offset) > + ep->f_filesize) { + *errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE; + return DW_DLV_ERROR; + } + ep->f_symtab_sect_strings = calloc(1,strsectlength+1); + if (!ep->f_symtab_sect_strings) { + ep->f_symtab_sect_strings = 0; + ep->f_symtab_sect_strings_max = 0; + ep->f_symtab_sect_strings_sect_index = 0; + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,ep->f_symtab_sect_strings, + strpsh->gh_offset, + strsectlength, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(ep->f_symtab_sect_strings); + ep->f_symtab_sect_strings = 0; + ep->f_symtab_sect_strings_max = 0; + ep->f_symtab_sect_strings_sect_index = 0; + return res; + } + return DW_DLV_OK; +} + +static int +_dwarf_elf_load_sectstrings( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned stringsection, + int *errcode) +{ + int res = 0; + struct generic_shdr *psh = 0; + Dwarf_Unsigned secoffset = 0; + + ep->f_elf_shstrings_length = 0; + if (stringsection >= ep->f_ehdr->ge_shnum) { + *errcode = DW_DLE_SECTION_INDEX_BAD; + return DW_DLV_ERROR; + } + psh = ep->f_shdr + stringsection; + secoffset = psh->gh_offset; + if (is_empty_section(psh->gh_type)) { + *errcode = DW_DLE_ELF_STRING_SECTION_MISSING; + return DW_DLV_ERROR; + } + if (secoffset >= ep->f_filesize || + psh->gh_size > ep->f_filesize || + (secoffset + psh->gh_size) > + ep->f_filesize) { + *errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE; + return DW_DLV_ERROR; + } + if (psh->gh_size > ep->f_elf_shstrings_max) { + free(ep->f_elf_shstrings_data); + ep->f_elf_shstrings_data = (char *)malloc(psh->gh_size); + ep->f_elf_shstrings_max = psh->gh_size; + if (!ep->f_elf_shstrings_data) { + ep->f_elf_shstrings_max = 0; + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + } + ep->f_elf_shstrings_length = psh->gh_size; + res = RRMOA(ep->f_fd,ep->f_elf_shstrings_data,secoffset, + psh->gh_size, + ep->f_filesize,errcode); + return res; +} + +static const dw_elf32_shdr shd32zero; +static const struct generic_shdr shdgzero; + +/* Has a side effect of setting count, number + in the ehdr ep points to. */ +static int +get_counts_from_sec32_zero( + dwarf_elf_object_access_internals_t * ep, + Dwarf_Unsigned offset, + Dwarf_Bool *have_shdr_count, + Dwarf_Unsigned *shdr_count, + Dwarf_Bool *have_shstrndx_number, + Dwarf_Unsigned *shstrndx_number, + int *errcode) +{ + dw_elf32_shdr shd32; + struct generic_shdr shdg; + int res = 0; + Dwarf_Unsigned size = sizeof(shd32); + struct generic_ehdr * geh = ep->f_ehdr; + + shd32 = shd32zero; + shdg = shdgzero; + res = RRMOA(ep->f_fd,&shd32,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + copysection32(ep,&shdg,&shd32); + if (geh->ge_shnum_extended) { + geh->ge_shnum = shdg.gh_size; + geh->ge_shnum_in_shnum = TRUE; + if (geh->ge_shnum < 3) { + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + } + *have_shdr_count = TRUE; + *shdr_count = geh->ge_shnum; + if (geh->ge_strndx_extended) { + geh->ge_shstrndx = shdg.gh_link; + geh->ge_strndx_in_strndx = TRUE; + } + if (geh->ge_shnum_in_shnum && + geh->ge_strndx_in_strndx&& + (geh->ge_shstrndx >= geh->ge_shnum)) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + *have_shstrndx_number = TRUE; + *shstrndx_number = geh->ge_shstrndx; + return DW_DLV_OK; +} + +static int +elf_load_sectheaders32( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned offset, + Dwarf_Unsigned entsize, + Dwarf_Unsigned count, + int *errcode) +{ + Dwarf_Unsigned generic_count = 0; + Dwarf_Unsigned shdr_count = 0; + Dwarf_Bool have_shdr_count = FALSE; + Dwarf_Unsigned shstrndx_number = 0; + Dwarf_Bool have_shstrndx_number = FALSE; + struct generic_ehdr *ehp = 0; + int res = 0; + + if (entsize < sizeof(dw_elf32_shdr)) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + ehp = ep->f_ehdr; + if (!ehp->ge_shnum_in_shnum || !ehp->ge_strndx_in_strndx) { + res = get_counts_from_sec32_zero(ep,offset, + &have_shdr_count,&shdr_count, + &have_shstrndx_number,&shstrndx_number, + errcode); + if (res != DW_DLV_OK) { + return res; + } + if (have_shdr_count) { + count = shdr_count; + } + } + if (count == 0) { + return DW_DLV_NO_ENTRY; + } + if ((offset > ep->f_filesize)|| + (entsize > 200)|| + (count > ep->f_filesize) || + ((count *entsize +offset) > ep->f_filesize)) { + *errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE; + return DW_DLV_ERROR; + } + res = generic_shdr_from_shdr32(ep,&generic_count, + offset,entsize,count,errcode); + if (res != DW_DLV_OK) { + return res; + } + if (generic_count != count) { + *errcode = DW_DLE_ELF_SECTION_COUNT_MISMATCH; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} +static const dw_elf64_shdr shd64zero; +/* Has a side effect of setting count, number + in the ehdr ep points to. */ +static int +get_counts_from_sec64_zero( + dwarf_elf_object_access_internals_t * ep, + Dwarf_Unsigned offset, + Dwarf_Bool *have_shdr_count, + Dwarf_Unsigned *shdr_count, + Dwarf_Bool *have_shstrndx_number, + Dwarf_Unsigned *shstrndx_number, + int *errcode) +{ + dw_elf64_shdr shd64; + struct generic_shdr shdg; + int res = 0; + Dwarf_Unsigned size = sizeof(shd64); + struct generic_ehdr * geh = ep->f_ehdr; + + shd64 = shd64zero; + shdg = shdgzero; + res = RRMOA(ep->f_fd,&shd64,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + copysection64(ep,&shdg,&shd64); + if (geh->ge_shnum_extended) { + geh->ge_shnum = shdg.gh_size; + geh->ge_shnum_in_shnum = TRUE; + if (geh->ge_shnum < 3) { + *errcode = DW_DLE_TOO_FEW_SECTIONS; + return DW_DLV_ERROR; + } + } + *have_shdr_count = TRUE; + *shdr_count = geh->ge_shnum; + if (geh->ge_strndx_extended) { + geh->ge_shstrndx = shdg.gh_link; + geh->ge_strndx_in_strndx = TRUE; + } + if (geh->ge_shnum_in_shnum && + geh->ge_strndx_in_strndx && + (geh->ge_shstrndx >= geh->ge_shnum)) { + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } + + *have_shstrndx_number = TRUE; + *shstrndx_number = geh->ge_shstrndx; + return DW_DLV_OK; +} + +static int +elf_load_sectheaders64( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned offset,Dwarf_Unsigned entsize, + Dwarf_Unsigned count,int*errcode) +{ + Dwarf_Unsigned generic_count = 0; + Dwarf_Unsigned shdr_count = 0; + Dwarf_Bool have_shdr_count = FALSE; + Dwarf_Unsigned shstrndx_number = 0; + Dwarf_Bool have_shstrndx_number = FALSE; + struct generic_ehdr *ehp = 0; + int res = 0; + + ehp = ep->f_ehdr; + if (!ehp->ge_shnum_in_shnum || !ehp->ge_strndx_in_strndx ) { + res = get_counts_from_sec64_zero(ep,offset, + &have_shdr_count,&shdr_count, + &have_shstrndx_number,&shstrndx_number, + errcode); + if (res != DW_DLV_OK) { + return res; + } + if (have_shdr_count) { + count = shdr_count; + } + } + if (count == 0) { + return DW_DLV_NO_ENTRY; + } + if (entsize < sizeof(dw_elf64_shdr)) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if ((offset > ep->f_filesize)|| + (entsize > 200)|| + (count > ep->f_filesize) || + ((count *entsize +offset) > ep->f_filesize)) { + *errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE; + return DW_DLV_ERROR; + } + + res = generic_shdr_from_shdr64(ep,&generic_count, + offset,entsize,count,errcode); + if (res != DW_DLV_OK) { + return res; + } + if (generic_count != count) { + *errcode = DW_DLE_ELF_SECTION_COUNT_MISMATCH; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} + +static int +_dwarf_elf_load_a_relx_batch( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr * gsh, + struct generic_rela ** grel_out, + Dwarf_Unsigned *count_out, + enum RelocRela localrela, + enum RelocOffsetSize localoffsize, + int *errcode) +{ + Dwarf_Unsigned count = 0; + Dwarf_Unsigned size = 0; + Dwarf_Unsigned size2 = 0; + Dwarf_Unsigned sizeg = 0; + Dwarf_Unsigned offset = 0; + int res = 0; + Dwarf_Unsigned object_reclen = 0; + struct generic_rela *grel = 0; + + /* ASSERT: Caller guarantees localoffsetsize + is a valid 4 or 8. */ + /* ASSERT: Caller guarantees localrela is one + of the 2 valid values 1 or 2 */ + + offset = gsh->gh_offset; + size = gsh->gh_size; + if (size == 0) { + return DW_DLV_NO_ENTRY; + } + if ((offset > ep->f_filesize)|| + (size > ep->f_filesize) || + ((size +offset) > ep->f_filesize)) { + *errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE; + return DW_DLV_ERROR; + } + if (localoffsize == RelocOffset32) { + if (localrela == RelocIsRela) { + object_reclen = sizeof(dw_elf32_rela); + count = (long)(size/object_reclen); + size2 = count * object_reclen; + if (size != size2) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + } else { + object_reclen = sizeof(dw_elf32_rel); + count = (long)(size/object_reclen); + size2 = count * object_reclen; + if (size != size2) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + } + } else { + if (localrela == RelocIsRela) { + object_reclen = sizeof(dw_elf64_rela); + count = (long)(size/object_reclen); + size2 = count * object_reclen; + if (size != size2) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + } else { + object_reclen = sizeof(dw_elf64_rel); + count = (long)(size/object_reclen); + size2 = count * object_reclen; + if (size != size2) { + *errcode = DW_DLE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + } + } + sizeg = count*sizeof(struct generic_rela); + grel = (struct generic_rela *)malloc(sizeg); + if (!grel) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + if (localoffsize == RelocOffset32) { + if (localrela == RelocIsRela) { + dw_elf32_rela *relp = 0; + relp = (dw_elf32_rela *)malloc(size); + if (!relp) { + free(grel); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,relp,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(relp); + free(grel); + return res; + } + res = generic_rel_from_rela32(ep,gsh,relp,grel,errcode); + free(relp); + } else { + dw_elf32_rel *relp = 0; + relp = (dw_elf32_rel *)malloc(size); + if (!relp) { + free(grel); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,relp,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(relp); + free(grel); + return res; + } + res = generic_rel_from_rel32(ep,gsh,relp,grel,errcode); + free(relp); + } + } else { + if (localrela == RelocIsRela) { + dw_elf64_rela *relp = 0; + relp = (dw_elf64_rela *)malloc(size); + if (!relp) { + free(grel); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,relp,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(relp); + free(grel); + return res; + } + res = generic_rel_from_rela64(ep,gsh,relp,grel,errcode); + free(relp); + } else { + dw_elf64_rel *relp = 0; + relp = (dw_elf64_rel *)malloc(size); + if (!relp) { + free(grel); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,relp,offset,size, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(relp); + free(grel); + return res; + } + res = generic_rel_from_rel64(ep,gsh,relp,grel,errcode); + free(relp); + } + } + if (res == DW_DLV_OK) { + gsh->gh_relcount = count; + gsh->gh_rels = grel; + *count_out = count; + *grel_out = grel; + return res; + } + /* Some sort of issue */ + count_out = 0; + free(grel); + return res; +} + +/* Is this rel/rela section related to dwarf at all? + set oksecnum zero if not. Else set targ secnum. + Never returns DW_DLV_NO_ENTRY. */ +static int +this_rel_is_a_section_dwarf_related( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr *gshdr, + unsigned *oksecnum_out, + int *errcode) +{ + Dwarf_Unsigned oksecnum = 0; + struct generic_shdr *gstarg = 0; + + if (gshdr->gh_type != SHT_RELA && + gshdr->gh_type != SHT_REL) { + *oksecnum_out = 0; + return DW_DLV_OK; + } + oksecnum = gshdr->gh_reloc_target_secnum; + if (oksecnum >= ep->f_loc_shdr.g_count) { + *oksecnum_out = 0; + *errcode = DW_DLE_ELF_SECTION_ERROR; + return DW_DLV_ERROR; + } + gstarg = ep->f_shdr+oksecnum; + if (!gstarg->gh_is_dwarf) { + *oksecnum_out = 0; /* no reloc needed. */ + return DW_DLV_OK; + } + *oksecnum_out = (unsigned)oksecnum; + return DW_DLV_OK; +} +/* Secnum here is the secnum of rela. Not + the target of the relocations. + This also loads .rel. */ +int +_dwarf_load_elf_relx( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned secnum, + enum RelocRela localr, + int *errcode) +{ + struct generic_shdr *gshdr = 0; + Dwarf_Unsigned seccount = 0; + unsigned offsetsize = 0; + struct generic_rela *grp = 0; + Dwarf_Unsigned count_read = 0; + int res = 0; + unsigned oksec = 0; + enum RelocOffsetSize localoffsize = RelocOffset32; + + /* ASSERT: Caller guarantees localr is + a valid RelocRela */ + if (!ep) { + *errcode = DW_DLE_INTERNAL_NULL_POINTER; + return DW_DLV_ERROR; + } + offsetsize = ep->f_offsetsize; + seccount = ep->f_loc_shdr.g_count; + if (secnum >= seccount) { + *errcode = DW_DLE_ELF_SECTION_ERROR; + return DW_DLV_ERROR; + } + gshdr = ep->f_shdr +secnum; + if (is_empty_section(gshdr->gh_type)) { + + return DW_DLV_NO_ENTRY; + } + + res = this_rel_is_a_section_dwarf_related(ep,gshdr, + &oksec,errcode); + if (res == DW_DLV_ERROR) { + return res; + } + if (!oksec) { + return DW_DLV_OK; + } + /* We will actually read these relocations. */ + if (offsetsize == 64) { + localoffsize = RelocOffset64; + } else if (offsetsize == 32) { + localoffsize = RelocOffset32; + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + /* ASSERT: localoffsize is now a valid enum value, + one of the two defined. */ + res = _dwarf_elf_load_a_relx_batch(ep, + gshdr,&grp,&count_read,localr,localoffsize,errcode); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + gshdr->gh_rels = grp; + gshdr->gh_relcount = count_read; + return DW_DLV_OK; +} + +static int +validate_section_name_string(Dwarf_Unsigned section_length, + Dwarf_Unsigned string_loc_index, + const char * strings_start, + int * errcode) +{ + const char *endpoint = strings_start + section_length; + const char *cur = 0; + + if (section_length <= string_loc_index) { + *errcode = DW_DLE_SECTION_STRING_OFFSET_BAD; + return DW_DLV_ERROR; + } + cur = string_loc_index+strings_start; + for ( ; cur < endpoint;++cur) { + if (!*cur) { + return DW_DLV_OK; + } + } + *errcode = DW_DLE_SECTION_STRING_OFFSET_BAD; + return DW_DLV_ERROR; +} + +/* Without proper section names in place nothing + is going to work in reading DWARF sections. */ +static int +_dwarf_elf_load_sect_namestring( + dwarf_elf_object_access_internals_t *ep, + int *errcode) +{ + struct generic_shdr *gshdr = 0; + Dwarf_Unsigned generic_count = 0; + Dwarf_Unsigned i = 1; + const char *stringsecbase = 0; + + stringsecbase = ep->f_elf_shstrings_data; + gshdr = ep->f_shdr; + generic_count = ep->f_loc_shdr.g_count; + for (i = 0; i < generic_count; i++, ++gshdr) { + const char *namestr = + ""; + int res = 0; + + if (!ep->f_ehdr->ge_shstrndx || !stringsecbase) { + gshdr->gh_namestring = namestr; + continue; + } + namestr = ""; + res = validate_section_name_string(ep->f_elf_shstrings_length, + gshdr->gh_name, stringsecbase, + errcode); + if (res != DW_DLV_OK) { + gshdr->gh_namestring = namestr; + if (res == DW_DLV_ERROR) { + return res; + } + /* no entry, missing strings. */ + *errcode = DW_DLE_NO_SECT_STRINGS; + return DW_DLV_ERROR; + } else { + gshdr->gh_namestring = stringsecbase + gshdr->gh_name; + } + } + return DW_DLV_OK; +} + +/* The C standard ensures these are all appropriate + zero bits. */ +static const dw_elf32_ehdr eh32_zero; +static const dw_elf64_ehdr eh64_zero; + +static int +elf_load_elf_header32( + dwarf_elf_object_access_internals_t *ep,int *errcode) +{ + int res = 0; + dw_elf32_ehdr ehdr32; + struct generic_ehdr *ehdr = 0; + + ehdr32 = eh32_zero; + res = RRMOA(ep->f_fd,&ehdr32,0,sizeof(ehdr32), + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + ehdr = (struct generic_ehdr *)calloc(1, + sizeof(struct generic_ehdr)); + if (!ehdr) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = generic_ehdr_from_32(ep,ehdr,&ehdr32,errcode); + if (res != DW_DLV_OK) { + free(ehdr); + } + return res; +} +static int +elf_load_elf_header64( + dwarf_elf_object_access_internals_t *ep,int *errcode) +{ + int res = 0; + dw_elf64_ehdr ehdr64; + struct generic_ehdr *ehdr = 0; + + ehdr64 = eh64_zero; + res = RRMOA(ep->f_fd,&ehdr64,0,sizeof(ehdr64), + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + ehdr = (struct generic_ehdr *)calloc(1, + sizeof(struct generic_ehdr)); + if (!ehdr) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = generic_ehdr_from_64(ep,ehdr,&ehdr64,errcode); + if (res != DW_DLV_OK) { + free(ehdr); + } + return res; +} + +int +_dwarf_load_elf_header( + dwarf_elf_object_access_internals_t *ep,int*errcode) +{ + unsigned offsetsize = ep->f_offsetsize; + int res = 0; + + if (offsetsize == 32) { + res = elf_load_elf_header32(ep,errcode); + } else if (offsetsize == 64) { + if (sizeof(Dwarf_Unsigned) < 8) { + *errcode = DW_DLE_INTEGER_TOO_SMALL; + return DW_DLV_ERROR; + } + res = elf_load_elf_header64(ep,errcode); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + return res; +} + +static int +validate_links( + dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned knownsect, + Dwarf_Unsigned string_sect, + int *errcode) +{ + struct generic_shdr* pshk = 0; + + if (!knownsect) { + return DW_DLV_OK; + } + if (!string_sect) { + *errcode = DW_DLE_ELF_STRING_SECTION_ERROR; + return DW_DLV_ERROR; + } + pshk = ep->f_shdr + knownsect; + if (string_sect != pshk->gh_link) { + *errcode = DW_DLE_ELF_SECTION_LINK_ERROR; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} + +static int +string_endswith(const char *n,const char *q) +{ + size_t len = strlen(n); + size_t qlen = strlen(q); + const char *startpt = 0; + + if ( len < qlen) { + return FALSE; + } + startpt = n + (len-qlen); + if (strcmp(startpt,q)) { + return FALSE; + } + return TRUE; +} + +/* We are allowing either SHT_GROUP or .group to indicate + a group section, but really one should have both + or neither! */ +static int +elf_sht_groupsec(Dwarf_Unsigned type, const char *sname) +{ + /* ARM compilers name SHT group "__ARM_grp" + not .group */ + if ((type == SHT_GROUP) || (!strcmp(sname,".group"))){ + return TRUE; + } + return FALSE; +} + +static int +elf_flagmatches(Dwarf_Unsigned flagsword,Dwarf_Unsigned flag) +{ + if ((flagsword&flag) == flag) { + return TRUE; + } + return FALSE; +} + +/* For SHT_GROUP sections. + A group section starts with a 32bit flag + word with value 1. + 32bit section numbers of the sections + in the group follow the flag field. */ +static int +read_gs_section_group( + dwarf_elf_object_access_internals_t *ep, + struct generic_shdr* psh, + int *errcode) +{ + Dwarf_Unsigned i = 0; + int res = 0; + + if (!psh->gh_sht_group_array) { + Dwarf_Unsigned seclen = psh->gh_size; + char *data = 0; + char *dp = 0; + Dwarf_Unsigned* grouparray = 0; + char dblock[4]; + Dwarf_Unsigned va = 0; + Dwarf_Unsigned count = 0; + Dwarf_Unsigned groupmallocsize = 0; + int foundone = 0; + + if (seclen >= ep->f_filesize) { + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + if (seclen < DWARF_32BIT_SIZE) { + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + data = malloc(seclen); + if (!data) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + dp = data; + if (psh->gh_entsize != DWARF_32BIT_SIZE) { + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + free(data); + return DW_DLV_ERROR; + } + if (!psh->gh_entsize) { + free(data); + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + count = seclen/psh->gh_entsize; + if (count >= ep->f_loc_shdr.g_count) { + /* Impossible */ + free(data); + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + res = RRMOA(ep->f_fd,data,psh->gh_offset,seclen, + ep->f_filesize,errcode); + if (res != DW_DLV_OK) { + free(data); + return res; + } + groupmallocsize = count * sizeof(Dwarf_Unsigned); + if (groupmallocsize >= ep->f_filesize) { + free(data); + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + grouparray = malloc(groupmallocsize); + if (!grouparray) { + free(data); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + + memcpy(dblock,dp,DWARF_32BIT_SIZE); + ASNAR(memcpy,va,dblock); + /* There is ambiguity on the endianness of this stuff. */ + if (va != 1 && va != 0x1000000) { + /* Could be corrupted elf object. */ + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + free(data); + free(grouparray); + return DW_DLV_ERROR; + } + grouparray[0] = 1; + /* A .group section will have 0 to G sections + listed */ + dp = dp + DWARF_32BIT_SIZE; + for ( i = 1; i < count; ++i,dp += DWARF_32BIT_SIZE) { + Dwarf_Unsigned gseca = 0; + Dwarf_Unsigned gsecb = 0; + struct generic_shdr* targpsh = 0; + + memcpy(dblock,dp,DWARF_32BIT_SIZE); + ASNAR(memcpy,gseca,dblock); + ASNAR(_dwarf_memcpy_swap_bytes,gsecb,dblock); + if (!gseca) { + free(data); + free(grouparray); + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + grouparray[i] = gseca; + if (gseca >= ep->f_loc_shdr.g_count) { + /* Might be confused endianness by + the compiler generating the SHT_GROUP. + This is pretty horrible. */ + + if (gsecb >= ep->f_loc_shdr.g_count) { + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + free(data); + free(grouparray); + return DW_DLV_ERROR; + } + /* Ok. Yes, ugly. */ + gseca = gsecb; + grouparray[i] = gseca; + } + targpsh = ep->f_shdr + gseca; + if (_dwarf_ignorethissection(targpsh->gh_namestring)){ + continue; + } + if (targpsh->gh_section_group_number) { + /* multi-assignment to groups. Oops. */ + free(data); + free(grouparray); + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + targpsh->gh_section_group_number = + ep->f_sg_next_group_number; + foundone = 1; + } + if (foundone) { + ++ep->f_sg_next_group_number; + ++ep->f_sht_group_type_section_count; + } + free(data); + psh->gh_sht_group_array = grouparray; + psh->gh_sht_group_array_count = count; + } + return DW_DLV_OK; +} +/* Does related things. + A) Counts the number of SHT_GROUP + and for each builds an array of the sections in the group + (which we expect are all DWARF-related) + and sets the group number in each mentioned section. + B) Counts the number of SHF_GROUP flags. + C) If gnu groups: + ensure all the DWARF sections marked with right group + based on A(we will mark unmarked as group 1, + DW_GROUPNUMBER_BASE). + D) If arm groups (SHT_GROUP zero, SHF_GROUP non-zero): + Check the relocations of all SHF_GROUP section + FIXME: algorithm needed. + + If SHT_GROUP and SHF_GROUP this is GNU groups. + If no SHT_GROUP and have SHF_GROUP this is + arm cc groups and we must use relocation information + to identify the group members. + + It seems(?) impossible for an object to have both + dwo sections and (SHF_GROUP or SHT_GROUP), but + we do not rule that out here. */ +static int +_dwarf_elf_setup_all_section_groups( + dwarf_elf_object_access_internals_t *ep, + int *errcode) +{ + struct generic_shdr* psh = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned count = 0; + int res = 0; + + count = ep->f_loc_shdr.g_count; + psh = ep->f_shdr; + + /* Does step A and step B */ + for (i = 0; i < count; ++psh,++i) { + const char *name = psh->gh_namestring; + + if (is_empty_section(psh->gh_type)) { + /* No data here. */ + continue; + } + if (!elf_sht_groupsec(psh->gh_type,name)) { + /* Step B */ + if (elf_flagmatches(psh->gh_flags,SHF_GROUP)) { + ep->f_shf_group_flag_section_count++; + } + continue; + } + /* Looks like a section group. Do Step A. */ + res =read_gs_section_group(ep,psh,errcode); + if (res != DW_DLV_OK) { + return res; + } + } + /* Any sections not marked above or here are in + grep DW_GROUPNUMBER_BASE (1). + Section C. */ + psh = ep->f_shdr; + for (i = 0; i < count; ++psh,++i) { + const char *name = psh->gh_namestring; + int is_rel = FALSE; + int is_rela = FALSE; + + if (is_empty_section(psh->gh_type)) { + /* No data here. */ + continue; + } + if (elf_sht_groupsec(psh->gh_type,name)) { + continue; + } + /* Not a section group */ + if (string_endswith(name,".dwo")) { + if (psh->gh_section_group_number) { + /* multi-assignment to groups. Oops. */ + *errcode = DW_DLE_ELF_SECTION_GROUP_ERROR; + return DW_DLV_ERROR; + } + psh->gh_is_dwarf = TRUE; + psh->gh_section_group_number = DW_GROUPNUMBER_DWO; + ep->f_dwo_group_section_count++; + } else if (_dwarf_load_elf_section_is_dwarf(name, + &is_rela,&is_rel)) { + if (!psh->gh_section_group_number) { + psh->gh_section_group_number = DW_GROUPNUMBER_BASE; + } + psh->gh_is_dwarf = TRUE; + } else { + /* Do nothing. */ + } + } + if (ep->f_sht_group_type_section_count) { + /* Not ARM. Done. */ + } + if (!ep->f_shf_group_flag_section_count) { + /* Nothing more to do. */ + return DW_DLV_OK; + } + return DW_DLV_OK; +} + +static int +_dwarf_elf_find_sym_sections( + dwarf_elf_object_access_internals_t *ep, + int *errcode) +{ + struct generic_shdr* psh = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned count = 0; + int res = 0; + + count = ep->f_loc_shdr.g_count; + psh = ep->f_shdr; + for (i = 0; i < count; ++psh,++i) { + const char *name = psh->gh_namestring; + if (is_empty_section(psh->gh_type)) { + /* No data here. */ + continue; + } + if (!strcmp(name,".dynsym")) { + ep->f_dynsym_sect_index = i; + ep->f_loc_dynsym.g_offset = psh->gh_offset; + } else if (!strcmp(name,".dynstr")) { + ep->f_dynsym_sect_strings_sect_index = i; + ep->f_dynsym_sect_strings_max = psh->gh_size; + } else if (!strcmp(name,".symtab")) { + ep->f_symtab_sect_index = i; + ep->f_loc_symtab.g_offset = psh->gh_offset; + } else if (!strcmp(name,".strtab")) { + ep->f_symtab_sect_strings_sect_index = i; + ep->f_symtab_sect_strings_max = psh->gh_size; + } else if (!strcmp(name,".dynamic")) { + ep->f_dynamic_sect_index = i; + ep->f_loc_dynamic.g_offset = psh->gh_offset; + } + } + res = validate_links(ep,ep->f_symtab_sect_index, + ep->f_symtab_sect_strings_sect_index,errcode); + if (res!= DW_DLV_OK) { + return res; + } + return DW_DLV_OK; +} + +int +_dwarf_load_elf_sectheaders( + dwarf_elf_object_access_internals_t *ep,int*errcode) +{ + int res = 0; + + if (ep->f_offsetsize == 32) { + res = elf_load_sectheaders32(ep,ep->f_ehdr->ge_shoff, + ep->f_ehdr->ge_shentsize, + ep->f_ehdr->ge_shnum,errcode); + } else if (ep->f_offsetsize == 64) { + res = elf_load_sectheaders64(ep,ep->f_ehdr->ge_shoff, + ep->f_ehdr->ge_shentsize, + ep->f_ehdr->ge_shnum,errcode); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_elf_load_sectstrings(ep, + ep->f_ehdr->ge_shstrndx,errcode); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_elf_load_sect_namestring(ep,errcode); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_elf_find_sym_sections(ep,errcode); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_elf_setup_all_section_groups(ep,errcode); + return res; +} diff --git a/src/lib/libdwarf/dwarf_elf_rel_detector.c b/src/lib/libdwarf/dwarf_elf_rel_detector.c new file mode 100644 index 0000000..1cfb60d --- /dev/null +++ b/src/lib/libdwarf/dwarf_elf_rel_detector.c @@ -0,0 +1,368 @@ +/* +Copyright (c) 2019, David Anderson +All rights reserved. +cc +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include "dwarf_elf_defines.h" +#include "dwarf_elf_rel_detector.h" + +unsigned +_dwarf_is_32bit_abs_reloc(unsigned int type, unsigned machine) +{ + unsigned r = 0; + + switch (machine) { +#if defined(EM_MIPS) && defined (R_MIPS_32) + case EM_MIPS: + r = (0 +#if defined (R_MIPS_32) + | (type == R_MIPS_32) +#endif +#if defined (R_MIPS_TLS_DTPREL32) + | (type == R_MIPS_TLS_DTPREL32) +#endif /* DTPREL32 */ + ); + break; +#endif /* MIPS case */ +#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA32) + case EM_SPARC32PLUS: + r = (0 +#if defined(R_SPARC_UA32) + | (type == R_SPARC_UA32) +#endif +#if defined(R_SPARC_TLS_DTPOFF32) + | (type == R_SPARC_TLS_DTPOFF32) +#endif + ); + break; +#endif +#if defined(EM_SPARCV9) && defined (R_SPARC_UA32) + case EM_SPARCV9: + r = (type == R_SPARC_UA32); + break; +#endif +#if defined(EM_SPARC) && defined (R_SPARC_UA32) + case EM_SPARC: + r = (0 +#if defined(R_SPARC_UA32) + | (type == R_SPARC_UA32) +#endif +#if (R_SPARC_TLS_DTPOFF32) + | (type == R_SPARC_TLS_DTPOFF32) +#endif + ); + break; +#endif /* EM_SPARC */ +#if defined(EM_386) && defined (R_386_32) && defined (R_386_PC32) + case EM_386: + r = (0 +#if defined (R_386_32) + | (type == R_386_32) +#endif +#if defined (R_386_GOTPC) + | (type == R_386_GOTPC) +#endif +#if defined (R_386_PC32) + | (type == R_386_PC32) +#endif +#if defined (R_386_TLS_LDO_32) + | (type == R_386_TLS_LDO_32) +#endif +#if defined (R_386_TLS_DTPOFF32) + | (type == R_386_TLS_DTPOFF32) +#endif + ); + break; +#endif /* EM_386 */ + +#if defined (EM_SH) && defined (R_SH_DIR32) + case EM_SH: + r = (0 +#if defined (R_SH_DIR32) + | (type == R_SH_DIR32) +#endif +#if defined (R_SH_DTPOFF32) + | (type == R_SH_TLS_DTPOFF32) +#endif + ); + break; +#endif /* SH */ + +#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB) + case EM_IA_64: /* 32bit? ! */ + r = (0 +#if defined (R_IA64_SECREL32LSB) + | (type == R_IA64_SECREL32LSB) +#endif +#if defined (R_IA64_DIR32LSB) + | (type == R_IA64_DIR32LSB) +#endif +#if defined (R_IA64_DTPREL32LSB) + | (type == R_IA64_DTPREL32LSB) +#endif + ); + break; +#endif /* EM_IA_64 */ + +#if defined(EM_ARM) && defined (R_ARM_ABS32) + case EM_ARM: + case EM_AARCH64: + r = (0 +#if defined (R_ARM_ABS32) + | ( type == R_ARM_ABS32) +#endif +#if defined (R_AARCH64_ABS32) + | ( type == R_AARCH64_ABS32) +#endif +#if defined (R_ARM_TLS_LDO32) + | ( type == R_ARM_TLS_LDO32) +#endif + ); + break; +#endif /* EM_ARM */ + +/* On FreeBSD xR_PPC64_ADDR32 not defined + so we use the xR_PPC_ names which + have the proper value. + Our headers have: + xR_PPC64_ADDR64 38 + xR_PPC_ADDR32 1 so we use this one + xR_PPC64_ADDR32 R_PPC_ADDR32 + + xR_PPC64_DTPREL32 110 which may be wrong/unavailable + xR_PPC64_DTPREL64 78 + xR_PPC_DTPREL32 78 + */ +#if defined(EM_PPC64) && defined (R_PPC_ADDR32) + case EM_PPC64: + r = (0 +#if defined(R_PPC_ADDR32) + | (type == R_PPC_ADDR32) +#endif +#if defined(R_PPC64_DTPREL32) + | (type == R_PPC64_DTPREL32) +#endif + ); + break; +#endif /* EM_PPC64 */ + +#if defined(EM_PPC) && defined (R_PPC_ADDR32) + case EM_PPC: + r = (0 +#if defined (R_PPC_ADDR32) + | (type == R_PPC_ADDR32) +#endif +#if defined (R_PPC_DTPREL32) + | (type == R_PPC_DTPREL32) +#endif + ); + break; +#endif /* EM_PPC */ + +#if defined(EM_S390) && defined (R_390_32) + case EM_S390: + r = (0 +#if defined (R_390_32) + | (type == R_390_32) +#endif +#if defined (R_390_TLS_LDO32) + | (type == R_390_TLS_LDO32) +#endif + ); + break; +#endif /* EM_S390 */ + +#if defined(EM_X86_64) && \ + ( defined(R_X86_64_32) || defined(R_X86_64_PC32) ||\ + defined(R_X86_64_DTPOFF32) ) +#if defined(EM_K10M) + case EM_K10M: +#endif +#if defined(EM_L10M) + case EM_L10M: +#endif + case EM_X86_64: + r = (0 +#if defined (R_X86_64_PC32) + | (type == R_X86_64_PC32) +#endif +#if defined (R_X86_64_32) + | (type == R_X86_64_32) +#endif +#if defined (R_X86_64_DTPOFF32) + | (type == R_X86_64_DTPOFF32) +#endif + ); + break; +#endif /* EM_X86_64 */ + + case EM_QUALCOMM_DSP6: + r = (type == R_QUALCOMM_REL32); + break; + default: break; + } + return r; +} + +unsigned +_dwarf_is_64bit_abs_reloc(unsigned int type, unsigned machine) +{ + unsigned r = 0; + + switch (machine) { +#if defined(EM_MIPS) && defined (R_MIPS_64) + case EM_MIPS: + r = (0 +#if defined (R_MIPS_64) + | (type == R_MIPS_64) +#endif +#if defined (R_MIPS_32) + | (type == R_MIPS_32) +#endif +#if defined(R_MIPS_TLS_DTPREL64) + | (type == R_MIPS_TLS_DTPREL64) +#endif + ); + break; +#endif /* EM_MIPS */ +#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA64) + case EM_SPARC32PLUS: + r = (type == R_SPARC_UA64); + break; +#endif +#if defined(EM_SPARCV9) && defined (R_SPARC_UA64) + case EM_SPARCV9: + r = (0 +#if defined (R_SPARC_UA64) + | (type == R_SPARC_UA64) +#endif +#if defined (R_SPARC_TLS_DTPOFF64) + | (type == R_SPARC_TLS_DTPOFF64) +#endif + ); + break; +#endif +#if defined(EM_SPARC) && defined (R_SPARC_UA64) + case EM_SPARC: + r = (0 +#if defined(R_SPARC_UA64) + | (type == R_SPARC_UA64) +#endif +#if defined (R_SPARC_TLS_DTPOFF64) + | (type == R_SPARC_TLS_DTPOFF64) +#endif + ); + break; +#endif /* EM_SPARC */ + +#if defined(EM_IA_64) && defined (R_IA64_SECREL64LSB) + case EM_IA_64: /* 64bit */ + r = (0 +#if defined (R_IA64_SECREL64LSB) + | (type == R_IA64_SECREL64LSB) +#endif +#if defined (R_IA64_SECREL32LSB) + | (type == R_IA64_SECREL32LSB) +#endif +#if defined (R_IA64_DIR64LSB) + | (type == R_IA64_DIR64LSB) +#endif +#if defined (R_IA64_DTPREL64LSB) + | (type == R_IA64_DTPREL64LSB) +#endif +#if defined (R_IA64_REL32LSB) + | (type == R_IA64_REL32LSB) +#endif + ); + break; +#endif /* EM_IA_64 */ + +#if defined(EM_PPC64) && defined (R_PPC64_ADDR64) + case EM_PPC64: + r = (0 +#if defined(R_PPC64_ADDR64) + | (type == R_PPC64_ADDR64) +#endif +#if defined(R_PPC64_DTPREL64) + | (type == R_PPC64_DTPREL64) +#endif + ); + break; +#endif /* EM_PPC64 */ + +#if defined(EM_S390) && defined (R_390_64) + case EM_S390: + r = (0 +#if defined(R_390_64) + | (type == R_390_64) +#endif +#if defined(R_390_TLS_LDO64) + | (type == R_390_TLS_LDO64) +#endif + ); + break; +#endif /* EM_390 */ + +#if defined(EM_X86_64) && defined (R_X86_64_64) +#if defined(EM_K10M) + case EM_K10M: +#endif +#if defined(EM_L10M) + case EM_L10M: +#endif + case EM_X86_64: + r = (0 +#if defined (R_X86_64_64) + | (type == R_X86_64_64) +#endif +#if defined (R_X86_64_PC64) + | (type == R_X86_64_PC64) +#endif +#if defined (R_X86_64_DTPOFF32) + | (type == R_X86_64_DTPOFF64) +#endif + ); + break; +#endif /* EM_X86_64 */ +#if defined(EM_AARCH64) && defined (R_AARCH64_ABS64) + case EM_AARCH64: + r = (0 +#if defined (R_AARCH64_ABS64) + | ( type == R_AARCH64_ABS64) +#endif + ); + break; +#endif /* EM_AARCH64 */ + default: break; + } + return r; +} diff --git a/src/lib/libdwarf/dwarf_elf_rel_detector.h b/src/lib/libdwarf/dwarf_elf_rel_detector.h new file mode 100644 index 0000000..b450b89 --- /dev/null +++ b/src/lib/libdwarf/dwarf_elf_rel_detector.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2019-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#ifndef DWARF_ELF_REL_DETECTOR_H +#define DWARF_ELF_REL_DETECTOR_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +unsigned _dwarf_is_32bit_abs_reloc(unsigned int type, + unsigned machine); +unsigned _dwarf_is_64bit_abs_reloc(unsigned int type, + unsigned machine); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_ELF_REL_DETECTOR_H */ diff --git a/src/lib/libdwarf/dwarf_elfread.c b/src/lib/libdwarf/dwarf_elfread.c new file mode 100644 index 0000000..a5c3101 --- /dev/null +++ b/src/lib/libdwarf/dwarf_elfread.c @@ -0,0 +1,809 @@ +/* +Copyright (c) 2019, David Anderson +All rights reserved. +cc +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* This file reads the parts of an Elf + file appropriate to reading DWARF debugging data. + Overview: + _dwarf_elf_nlsetup() Does all elf setup. + calls _dwarf_elf_access_init() + calls _dwarf_elf_object_access_internals_init() + Creates internals record 'M', + dwarf_elf_object_access_internals_t + Sets flags/data in internals record + Loads elf object data needed later. + Sets methods struct to access elf object. + calls _dwarf_object_init_b() Creates Dwarf_Debug, independent + of any elf code. + Sets internals record into dbg. + ---------------------- + _dwarf_destruct_elf_nlaccess(). This frees + the elf internals record created in + _dwarf_elf_object_access_internals_init() + in case of errors during setup or when + dwarf_finish() is called. Works safely for + partially or fully set-up elf internals record. + + Other than in _dwarf_elf_nlsetup() the elf code + knows nothing about Dwarf_Debug, and the rest of + libdwarf knows nothing about the content of the + object-type-specific (for Elf here) + internals record. +*/ + +#include + +#include /* size_t */ +#include /* free() malloc() */ +#include /* debug printf */ +#include /* memset() strdup() strncmp() */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* close() off_t */ +#elif defined HAVE_UNISTD_H +#include /* close() off_t */ +#endif /* _WIN32*/ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" /* for _dwarf_error() declaration */ +#include "dwarf_reading.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_object_read_common.h" +#include "dwarf_object_detector.h" +#include "dwarf_elfstructs.h" +#include "dwarf_elf_defines.h" +#include "dwarf_elf_rel_detector.h" +#include "dwarf_elfread.h" + +#ifndef TYP +#define TYP(n,l) char (n)[(l)] +#endif /* TYPE */ + +#ifdef WORDS_BIGENDIAN +#define READ_UNALIGNED_SAFE(dbg,dest, source, length) \ + do { \ + Dwarf_Unsigned _ltmp = 0; \ + (dbg)->de_copy_word( (((char *)(&_ltmp)) + \ + sizeof(_ltmp) - length),(source),(length)); \ + dest = _ltmp; \ + } while (0) + +#define WRITE_UNALIGNED_LOCAL(dbg,dest,source, srclength,len_out) \ + { \ + (dbg)->de_copy_word((dest), \ + ((char *)(source)) +(srclength)-(len_out), \ + (len_out)) ; \ + } +#else /* LITTLE ENDIAN */ +#define READ_UNALIGNED_SAFE(dbg,dest, source, srclength) \ + do { \ + Dwarf_Unsigned _ltmp = 0; \ + dbg->de_copy_word( (char *)(&_ltmp), \ + (source), (srclength)) ; \ + dest = _ltmp; \ + } while (0) + +#define WRITE_UNALIGNED_LOCAL(dbg,dest,source, srclength,len_out) \ + { \ + dbg->de_copy_word( (dest) , \ + ((char *)(source)) , \ + (len_out)) ; \ + } +#endif /* *-ENDIAN */ + +static int +_dwarf_elf_object_access_init( + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum); + +static Dwarf_Small elf_get_nolibelf_byte_order (void *obj) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + return (Dwarf_Small)elf->f_endian; +} + +static Dwarf_Small elf_get_nolibelf_length_size (void *obj) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + return elf->f_offsetsize/8; +} + +static Dwarf_Small elf_get_nolibelf_pointer_size (void *obj) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + return elf->f_pointersize/8; +} + +static Dwarf_Unsigned elf_get_nolibelf_file_size(void *obj) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + return elf->f_filesize; +} + +static Dwarf_Unsigned elf_get_nolibelf_section_count (void *obj) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + return elf->f_loc_shdr.g_count; +} + +static int elf_get_nolibelf_section_info(void *obj, + Dwarf_Unsigned section_index, + Dwarf_Obj_Access_Section_a *return_section, + int *error) +{ + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + + (void)error; + if (section_index < elf->f_loc_shdr.g_count) { + struct generic_shdr *sp = 0; + + sp = elf->f_shdr + section_index; + return_section->as_addr = sp->gh_addr; + return_section->as_type = sp->gh_type; + return_section->as_size = sp->gh_size; + return_section->as_name = sp->gh_namestring; + return_section->as_link = sp->gh_link; + return_section->as_info = sp->gh_info; + return_section->as_flags = sp->gh_flags; + return_section->as_entrysize = sp->gh_entsize; + return_section->as_offset = sp->gh_offset; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static int +elf_load_nolibelf_section (void *obj, Dwarf_Unsigned section_index, + Dwarf_Small **return_data, int *error) +{ + /* Linux kernel read size limit 0x7ffff000, + Without any good reason, limit our reads + to a bit less. */ + const Dwarf_Unsigned read_size_limit = 0x7ff00000; + Dwarf_Unsigned read_offset = 0; + Dwarf_Unsigned read_size = 0; + Dwarf_Unsigned remaining_bytes = 0; + Dwarf_Small * read_target = 0; + dwarf_elf_object_access_internals_t *elf = + (dwarf_elf_object_access_internals_t*)(obj); + + if (0 < section_index && + section_index < elf->f_loc_shdr.g_count) { + int res = 0; + + struct generic_shdr *sp = + elf->f_shdr + section_index; + if (sp->gh_content) { + *return_data = (Dwarf_Small *)sp->gh_content; + return DW_DLV_OK; + } + if (!sp->gh_size) { + return DW_DLV_NO_ENTRY; + } + /* Guarding against bad values and + against overflow */ + if (sp->gh_size > elf->f_filesize || + sp->gh_offset > elf->f_filesize || + (sp->gh_size + sp->gh_offset) > + elf->f_filesize) { + *error = DW_DLE_ELF_SECTION_ERROR; + return DW_DLV_ERROR; + } + + sp->gh_content = malloc((size_t)sp->gh_size); + if (!sp->gh_content) { + *error = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + /* Linux has a 2GB limit on read size. + So break this into 2gb pieces. */ + remaining_bytes = sp->gh_size; + read_size = remaining_bytes; + read_offset = sp->gh_offset; + read_target = (Dwarf_Small*)sp->gh_content; + for ( ; remaining_bytes > 0; read_size = remaining_bytes ) { + if (read_size > read_size_limit) { + read_size = read_size_limit; + } + res = RRMOA(elf->f_fd, + (void *)read_target, (off_t)read_offset, + (size_t)read_size, + (off_t)elf->f_filesize, error); + if (res != DW_DLV_OK) { + free(sp->gh_content); + sp->gh_content = 0; + return res; + } + remaining_bytes -= read_size; + read_offset += read_size; + read_target += read_size; + } + *return_data = (Dwarf_Small *)sp->gh_content; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +#define MATCH_REL_SEC(i_,s_,r_) \ +if ((i_) == (s_).dss_index) { \ + *(r_) = &(s_); \ + return DW_DLV_OK; \ +} + +static int +find_section_to_relocate(Dwarf_Debug dbg,Dwarf_Unsigned section_index, + struct Dwarf_Section_s **relocatablesec, int *error) +{ + MATCH_REL_SEC(section_index,dbg->de_debug_info,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_abbrev,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_line,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_loc,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_aranges,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_macinfo,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_pubnames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_names, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_ranges,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_frame, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_frame_eh_gnu, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_pubtypes, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_funcnames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_typenames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_varnames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_weaknames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_types,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_macro,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_rnglists, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_loclists, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_aranges, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_sup, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_str_offsets, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_addr,relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_gnu_pubnames, + relocatablesec); + MATCH_REL_SEC(section_index,dbg->de_debug_gnu_pubtypes, + relocatablesec); + /* dbg-> de_debug_tu_index,reloctablesec); */ + /* dbg-> de_debug_cu_index,reloctablesec); */ + /* dbg-> de_debug_gdbindex,reloctablesec); */ + /* dbg-> de_debug_str,syms); */ + /* de_elf_symtab,syms); */ + /* de_elf_strtab,syms); */ + *error = DW_DLE_RELOC_SECTION_MISMATCH; + return DW_DLV_ERROR; +} + +/* Returns DW_DLV_OK if it works, else DW_DLV_ERROR. + The caller may decide to ignore the errors or report them. */ +static int +update_entry(Dwarf_Debug dbg, + dwarf_elf_object_access_internals_t*obj, + struct generic_rela *rela, + Dwarf_Small *target_section, + Dwarf_Unsigned target_section_size, + int *error) +{ + unsigned int type = 0; + unsigned int sym_idx = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Signed addend = 0; + Dwarf_Half reloc_size = 0; + Dwarf_Half machine = (Dwarf_Half)obj->f_machine; + struct generic_symentry *symp = 0; + int is_rela = rela->gr_is_rela; + + offset = rela->gr_offset; + addend = rela->gr_addend; + type = (unsigned int)rela->gr_type; + sym_idx = (unsigned int)rela->gr_sym; + if (sym_idx >= obj->f_loc_symtab.g_count) { + *error = DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD; + return DW_DLV_ERROR; + } + symp = obj->f_symtab + sym_idx; + if (offset >= target_section_size) { + /* If offset really big, any add will overflow. + So lets stop early if offset is corrupt. */ + *error = DW_DLE_RELOC_INVALID; + return DW_DLV_ERROR; + } + /* Determine relocation size */ + if (_dwarf_is_32bit_abs_reloc(type, machine)) { + reloc_size = 4; + } else if (_dwarf_is_64bit_abs_reloc(type, machine)) { + reloc_size = 8; + } else if (!type) { + /* There is nothing to do. , this is the case such as + R_AARCH64_NONE and R_X86_64_NONE and the other machine + cases have it too. Most object files do not have + any relocation records of type R__NONE. */ + return DW_DLV_OK; + } else { + *error = DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN; + return DW_DLV_ERROR; + } + if ( (offset + reloc_size) < offset) { + /* Another check for overflow. */ + *error = DW_DLE_RELOC_INVALID; + return DW_DLV_ERROR; + } + if ( (offset + reloc_size) > target_section_size) { + *error = DW_DLE_RELOC_INVALID; + return DW_DLV_ERROR; + } + /* Assuming we do not need to do a READ_UNALIGNED here + at target_section + offset and add its value to + outval. Some ABIs say no read (for example MIPS), + but if some do then which ones? */ + { /* .rel. (addend is 0), or .rela. */ + Dwarf_Small *targ = target_section+offset; + Dwarf_Unsigned presentval = 0; + Dwarf_Unsigned outval = 0; + + if (!is_rela) { + READ_UNALIGNED_SAFE(dbg,presentval, + targ,(unsigned long)reloc_size); + } + /* There is no addend in .rel. + Normally presentval is correct + and st_value will be zero. + But a few compilers have + presentval zero and st_value set. */ + outval = presentval + symp->gs_value + addend; + WRITE_UNALIGNED_LOCAL(dbg,targ, + &outval,sizeof(outval),(unsigned long)reloc_size); + } + return DW_DLV_OK; +} + +/* Somewhat arbitrarily, we attempt to apply all the + relocations we can + and still notify the caller of at least one error if we found + any errors. */ + +static int +apply_rela_entries( + Dwarf_Debug dbg, + /* Section_index of the relocation section, .rela entries */ + Dwarf_Unsigned r_section_index, + dwarf_elf_object_access_internals_t*obj, + /* relocatablesec is the .debug_info(etc) in Dwarf_Debug */ + struct Dwarf_Section_s * relocatablesec, + int *error) +{ + int return_res = DW_DLV_OK; + struct generic_shdr * rels_shp = 0; + Dwarf_Unsigned relcount; + Dwarf_Unsigned i = 0; + + if (r_section_index >= obj->f_loc_shdr.g_count) { + *error = DW_DLE_SECTION_INDEX_BAD; + return DW_DLV_ERROR; + } + rels_shp = obj->f_shdr + r_section_index; + relcount = rels_shp->gh_relcount; + if (obj->f_ehdr->ge_type != ET_REL) { + /* No relocations to do */ + return DW_DLV_OK; + } + if (!relcount) { + /* Nothing to do. */ + return DW_DLV_OK; + } + if (!rels_shp->gh_rels) { + /* something wrong. */ + *error = DW_DLE_RELOCS_ERROR; + return DW_DLV_ERROR; + } + for (i = 0; i < relcount; i++) { + int res = update_entry(dbg,obj, + rels_shp->gh_rels+i, + relocatablesec->dss_data, + relocatablesec->dss_size, + error); + if (res != DW_DLV_OK) { + /* We try to keep going, not stop. */ + return_res = res; + } + } + return return_res; +} + +/* Find the section data in dbg and find all the relevant + sections. Then do relocations. + + section_index is the index of a .debug_info (for example) + so we have to find the section(s) with relocations + targeting section_index. + Normally there is exactly one such, though. +*/ +static int +elf_relocations_nolibelf(void* obj_in, + Dwarf_Unsigned section_index, + Dwarf_Debug dbg, + int* error) +{ + int res = DW_DLV_ERROR; + dwarf_elf_object_access_internals_t*obj = 0; + struct Dwarf_Section_s * relocatablesec = 0; + Dwarf_Unsigned section_with_reloc_records = 0; + + if (section_index == 0) { + return DW_DLV_NO_ENTRY; + } + obj = (dwarf_elf_object_access_internals_t*)obj_in; + + /* The section to relocate must already be loaded into memory. + This just turns section_index into a pointer + to a de_debug_info or other section record in + Dwarf_Debug. */ + res = find_section_to_relocate(dbg, section_index, + &relocatablesec, error); + if (res != DW_DLV_OK) { + return res; + } + /* Now we know the Dwarf_Section_s section + we need to relocate. + So lets find the rela section(s) targeting this. + */ + + /* Sun and possibly others do not always set + sh_link in .debug_* sections. + So we cannot do full consistency checks. + FIXME: This approach assumes there is only one + relocation section applying to section section_index! */ + section_with_reloc_records = relocatablesec->dss_reloc_index; + if (!section_with_reloc_records) { + /* Something is wrong. */ + *error = DW_DLE_RELOC_SECTION_MISSING_INDEX; + return DW_DLV_ERROR; + } + /* The relocations, if they exist, have been loaded. */ + /* The symtab was already loaded. */ + if (!obj->f_symtab || !obj->f_symtab_sect_strings) { + *error = DW_DLE_DEBUG_SYMTAB_ERR; + return DW_DLV_ERROR; + } + if (obj->f_symtab_sect_index != relocatablesec->dss_reloc_link) { + /* Something is wrong. */ + *error = DW_DLE_RELOC_MISMATCH_RELOC_INDEX; + return DW_DLV_ERROR; + } + /* We have all the data we need in memory. */ + /* Now we apply the relocs in section_with_reloc_records to the + target, relocablesec */ + res = apply_rela_entries(dbg, + section_with_reloc_records, + obj, relocatablesec,error); + return res; +} + +void +_dwarf_destruct_elf_nlaccess( + struct Dwarf_Obj_Access_Interface_a_s *aip) +{ + dwarf_elf_object_access_internals_t *ep = 0; + struct generic_shdr *shp = 0; + Dwarf_Unsigned shcount = 0; + Dwarf_Unsigned i = 0; + + ep = (dwarf_elf_object_access_internals_t *)aip->ai_object; + free(ep->f_ehdr); + shp = ep->f_shdr; + shcount = ep->f_loc_shdr.g_count; + for (i = 0; i < shcount; ++i,++shp) { + free(shp->gh_rels); + shp->gh_rels = 0; + free(shp->gh_content); + shp->gh_content = 0; + free(shp->gh_sht_group_array); + shp->gh_sht_group_array = 0; + shp->gh_sht_group_array_count = 0; + } + free(ep->f_shdr); + ep->f_loc_shdr.g_count = 0; + free(ep->f_phdr); + free(ep->f_elf_shstrings_data); + free(ep->f_dynamic); + free(ep->f_symtab_sect_strings); + free(ep->f_dynsym_sect_strings); + free(ep->f_symtab); + free(ep->f_dynsym); + + /* if TRUE close f_fd on destruct.*/ + if (ep->f_destruct_close_fd) { + close(ep->f_fd); + } + ep->f_ident[0] = 'X'; + free(ep->f_path); + free(ep); + free(aip); +} + +int +_dwarf_elf_nlsetup(int fd, + char *true_path, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error) +{ + Dwarf_Obj_Access_Interface_a *binary_interface = 0; + dwarf_elf_object_access_internals_t *intfc = 0; + int res = DW_DLV_OK; + int localerrnum = 0; + + res = _dwarf_elf_object_access_init( + fd, + ftype,endian,offsetsize,filesize, + &binary_interface, + &localerrnum); + if (res != DW_DLV_OK) { + if (res == DW_DLV_NO_ENTRY) { + return res; + } + _dwarf_error(NULL, error, localerrnum); + return DW_DLV_ERROR; + } + /* allocates and initializes Dwarf_Debug, + generic code */ + res = dwarf_object_init_b(binary_interface, errhand, errarg, + groupnumber, dbg, error); + if (res != DW_DLV_OK){ + _dwarf_destruct_elf_nlaccess(binary_interface); + return res; + } + intfc = binary_interface->ai_object; + intfc->f_path = strdup(true_path); + return res; +} + +/* dwarf_elf_access method table for use with non-libelf. + See also the methods table in dwarf_elf_access.c for libelf. +*/ +static Dwarf_Obj_Access_Methods_a const elf_nlmethods = { + elf_get_nolibelf_section_info, + elf_get_nolibelf_byte_order, + elf_get_nolibelf_length_size, + elf_get_nolibelf_pointer_size, + elf_get_nolibelf_file_size, + elf_get_nolibelf_section_count, + elf_load_nolibelf_section, + elf_relocations_nolibelf +}; + +/* On any error this frees internals argument. */ +static int +_dwarf_elf_object_access_internals_init( + dwarf_elf_object_access_internals_t * internals, + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + int *errcode) +{ + dwarf_elf_object_access_internals_t * intfc = internals; + Dwarf_Unsigned i = 0; + struct Dwarf_Obj_Access_Interface_a_s *localdoas; + int res = 0; + + /* Must malloc as _dwarf_destruct_elf_access() + forces that due to other uses. */ + localdoas = (struct Dwarf_Obj_Access_Interface_a_s *) + malloc(sizeof(struct Dwarf_Obj_Access_Interface_a_s)); + if (!localdoas) { + free(internals); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_a_s)); + /* E is used with libelf. F with this elf reader. */ + intfc->f_ident[0] = 'F'; + intfc->f_ident[1] = '1'; + intfc->f_fd = fd; + intfc->f_is_64bit = ((offsetsize==64)?TRUE:FALSE); + intfc->f_offsetsize = (Dwarf_Small)offsetsize; + intfc->f_pointersize = (Dwarf_Small)offsetsize; + intfc->f_filesize = filesize; + intfc->f_ftype = ftype; + intfc->f_destruct_close_fd = FALSE; + +#ifdef WORDS_BIGENDIAN + if (endian == DW_END_little ) { + intfc->f_copy_word = _dwarf_memcpy_swap_bytes; + intfc->f_endian = DW_END_little; + } else { + intfc->f_copy_word = _dwarf_memcpy_noswap_bytes; + intfc->f_endian = DW_END_big; + } +#else /* LITTLE ENDIAN */ + if (endian == DW_END_little ) { + intfc->f_copy_word = _dwarf_memcpy_noswap_bytes; + intfc->f_endian = DW_END_little; + } else { + intfc->f_copy_word = _dwarf_memcpy_swap_bytes; + intfc->f_endian = DW_END_big; + } +#endif /* LITTLE- BIG-ENDIAN */ + /* The following sets f_machine. */ + res = _dwarf_load_elf_header(intfc,errcode); + if (res != DW_DLV_OK) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_elf_nlaccess(localdoas); + localdoas = 0; + return res; + } + /* Not loading progheaders */ + res = _dwarf_load_elf_sectheaders(intfc,errcode); + if (res != DW_DLV_OK) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_elf_nlaccess(localdoas); + localdoas = 0; + return res; + } + /* We are not looking at symbol strings for now. */ + res = _dwarf_load_elf_symstr(intfc,errcode); + if (res == DW_DLV_ERROR) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_elf_nlaccess(localdoas); + localdoas = 0; + return res; + } + res = _dwarf_load_elf_symtab_symbols(intfc,errcode); + if (res == DW_DLV_ERROR) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_elf_nlaccess(localdoas); + localdoas = 0; + return res; + } + for ( i = 1; i < intfc->f_loc_shdr.g_count; ++i) { + struct generic_shdr *shp = 0; + Dwarf_Unsigned section_type = 0; + enum RelocRela localrel = RelocIsRela; + + shp = intfc->f_shdr +i; + section_type = shp->gh_type; + if (!shp->gh_namestring) { + /* A serious error which we ignore here + as it will be caught elsewhere + if necessary. */ + continue; + } else if (section_type == SHT_REL || + (!strncmp(".rel.",shp->gh_namestring,5))) { + localrel = RelocIsRel; + } else if (section_type == SHT_RELA || + (!strncmp(".rela.",shp->gh_namestring,6))) { + localrel = RelocIsRela; + } else { + continue; + } + /* ASSERT: local rel is either RelocIsRel or + RelocIsRela. Never any other value. */ + /* Possibly we should check if the target section + is one we care about before loading rela + FIXME */ + res = _dwarf_load_elf_relx(intfc,i,localrel,errcode); + if (res == DW_DLV_ERROR) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_elf_nlaccess(localdoas); + localdoas = 0; + return res; + } + } + free(localdoas); + localdoas = 0; + return DW_DLV_OK; +} + +static int +_dwarf_elf_object_access_init( + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum) +{ + + int res = 0; + dwarf_elf_object_access_internals_t *internals = 0; + Dwarf_Obj_Access_Interface_a *intfc = 0; + + internals = malloc(sizeof(dwarf_elf_object_access_internals_t)); + if (!internals) { + *localerrnum = DW_DLE_ALLOC_FAIL; + /* Impossible case, we hope. Give up. */ + return DW_DLV_ERROR; + } + memset(internals,0,sizeof(*internals)); + res = _dwarf_elf_object_access_internals_init(internals, + fd, + ftype, endian, offsetsize, filesize, + localerrnum); + if (res != DW_DLV_OK){ + return res; + } + + intfc = malloc(sizeof(Dwarf_Obj_Access_Interface_a)); + if (!intfc) { + /* Impossible case, we hope. Give up. */ + free(internals); + *localerrnum = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + /* Initialize the interface struct */ + intfc->ai_object = internals; + intfc->ai_methods = &elf_nlmethods; + *binary_interface = intfc; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_elfread.h b/src/lib/libdwarf/dwarf_elfread.h new file mode 100644 index 0000000..fa25d56 --- /dev/null +++ b/src/lib/libdwarf/dwarf_elfread.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2013-2023, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#ifndef READELFOBJ_H +#define READELFOBJ_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Use this for .rel. too. */ +struct generic_rela { + Dwarf_Unsigned gr_offset; + Dwarf_Unsigned gr_info; + Dwarf_Unsigned gr_sym; /* From info */ + Dwarf_Unsigned gr_type; /* From info */ + Dwarf_Signed gr_addend; + unsigned char gr_type2; /*MIPS64*/ + unsigned char gr_type3; /*MIPS64*/ + /* The following TRUE if .rela. and FALSE if .rel. + if FALSE, gr_addend will be zero. */ + int gr_is_rela; +}; + +/* The following are generic to simplify handling + Elf32 and Elf64. Some fields added where + the two sizes have different extraction code. */ +struct generic_ehdr { + unsigned char ge_ident[EI_NIDENT]; + Dwarf_Unsigned ge_type; + Dwarf_Unsigned ge_machine; + Dwarf_Unsigned ge_version; + Dwarf_Unsigned ge_entry; + Dwarf_Unsigned ge_phoff; + Dwarf_Unsigned ge_shoff; + Dwarf_Unsigned ge_flags; + Dwarf_Unsigned ge_ehsize; + Dwarf_Unsigned ge_phentsize; + Dwarf_Unsigned ge_phnum; + Dwarf_Unsigned ge_shentsize; + Dwarf_Unsigned ge_shnum; + /* if ge_shnum >= 0xff00 SHN_LORESERVE + Once section zero is read we put the sh_size + member as the true count and set ge_shnum_in_shnum TRUE. + ge_shnum_extended is TRUE if the object used the extension + mechanism */ + Dwarf_Bool ge_shnum_in_shnum; + Dwarf_Bool ge_shnum_extended; + + /* if section num of sec strings >= 0xff SHN_LORESERVE + this member holds SHN_XINDEX (0xffff) and the real + section string index is the sh_link value of section + 0. ge_sstrndx_extended is TRUE if the object used + the extension mechanism */ + Dwarf_Unsigned ge_shstrndx; + Dwarf_Bool ge_strndx_in_strndx; + Dwarf_Bool ge_strndx_extended; +}; +struct generic_phdr { + Dwarf_Unsigned gp_type; + Dwarf_Unsigned gp_flags; + Dwarf_Unsigned gp_offset; + Dwarf_Unsigned gp_vaddr; + Dwarf_Unsigned gp_paddr; + Dwarf_Unsigned gp_filesz; + Dwarf_Unsigned gp_memsz; + Dwarf_Unsigned gp_align; +}; +struct generic_shdr { + Dwarf_Unsigned gh_secnum; + Dwarf_Unsigned gh_name; + const char * gh_namestring; + Dwarf_Unsigned gh_type; + Dwarf_Unsigned gh_flags; + Dwarf_Unsigned gh_addr; + Dwarf_Unsigned gh_offset; + Dwarf_Unsigned gh_size; + Dwarf_Unsigned gh_link; + /* Section index (in an SHT_REL or SHT_RELA section) + of the target section from gh_link. Otherwise 0. */ + Dwarf_Unsigned gh_reloc_target_secnum; + Dwarf_Unsigned gh_info; + Dwarf_Unsigned gh_addralign; + Dwarf_Unsigned gh_entsize; + + /* Zero unless content read in. Malloc space + of size gh_size, in bytes. For dwarf + and strings mainly. free() this if not null*/ + char * gh_content; + + /* If a .rel or .rela section this will point + to generic relocation records if such + have been loaded. + free() this if not null. */ + Dwarf_Unsigned gh_relcount; + struct generic_rela * gh_rels; + + /* For SHT_GROUP based grouping, which + group is this section in. 0 unknown, + 1 DW_GROUP_NUMBER_BASE base DWARF, + 2 DW_GROUPNUMBER_DWO dwo sections, 3+ + are in an SHT_GROUP. GNU uses this. + set with group number (3+) from SHT_GROUP + and the flags should have SHF_GROUP set + if in SHT_GROUP. Must only be in one group? */ + Dwarf_Unsigned gh_section_group_number; + + /* Content of an SHT_GROUP section as an array + of integers. [0] is the version, which + can only be one(1) . */ + Dwarf_Unsigned * gh_sht_group_array; + /* Number of elements in the gh_sht_group_array. */ + Dwarf_Unsigned gh_sht_group_array_count; + + /* TRUE if .debug_info .eh_frame etc. */ + char gh_is_dwarf; +}; + +struct generic_dynentry { + Dwarf_Unsigned gd_tag; + /* gd_val stands in for d_ptr and d_val union, + the union adds nothing in practice since + we expect ptrsize <= ulongest. */ + Dwarf_Unsigned gd_val; + Dwarf_Unsigned gd_dyn_file_offset; +}; + +struct generic_symentry { + Dwarf_Unsigned gs_name; + Dwarf_Unsigned gs_value; + Dwarf_Unsigned gs_size; + Dwarf_Unsigned gs_info; + Dwarf_Unsigned gs_other; + Dwarf_Unsigned gs_shndx; + /* derived */ + Dwarf_Unsigned gs_bind; + Dwarf_Unsigned gs_type; +}; + +struct location { + const char *g_name; + Dwarf_Unsigned g_offset; + Dwarf_Unsigned g_count; + Dwarf_Unsigned g_entrysize; + Dwarf_Unsigned g_totalsize; +}; + +typedef struct elf_filedata_s { + /* f_ident[0] == 'E' means it is elf and + elf_filedata_s is the struct involved. + Other means error/corruption of some kind. + f_ident[1] is a version number. + Only version 1 is defined. */ + char f_ident[8]; + char * f_path; /* non-null if known. Must be freed */ + int f_fd; + unsigned f_machine; /* EM_* */ + int f_destruct_close_fd; + int f_is_64bit; + unsigned f_endian; + Dwarf_Unsigned f_filesize; + /* Elf size, not DWARF. 32 or 64 */ + Dwarf_Small f_offsetsize; + Dwarf_Small f_pointersize; + int f_ftype; + + Dwarf_Unsigned f_max_secdata_offset; + Dwarf_Unsigned f_max_progdata_offset; + + void (*f_copy_word) (void *, const void *, unsigned long); + + struct location f_loc_ehdr; + struct generic_ehdr* f_ehdr; + + struct location f_loc_shdr; + struct generic_shdr* f_shdr; + + struct location f_loc_phdr; + struct generic_phdr* f_phdr; + + char *f_elf_shstrings_data; /* section name strings */ + /* length of currentsection. Might be zero..*/ + Dwarf_Unsigned f_elf_shstrings_length; + /* size of malloc-d space */ + Dwarf_Unsigned f_elf_shstrings_max; + + /* This is the .dynamic section */ + struct location f_loc_dynamic; + struct generic_dynentry * f_dynamic; + Dwarf_Unsigned f_dynamic_sect_index; + + /* .dynsym, .dynstr */ + struct location f_loc_dynsym; + struct generic_symentry* f_dynsym; + char *f_dynsym_sect_strings; + Dwarf_Unsigned f_dynsym_sect_strings_max; + Dwarf_Unsigned f_dynsym_sect_strings_sect_index; + Dwarf_Unsigned f_dynsym_sect_index; + + /* .symtab .strtab */ + struct location f_loc_symtab; + struct generic_symentry* f_symtab; + char * f_symtab_sect_strings; + Dwarf_Unsigned f_symtab_sect_strings_max; + Dwarf_Unsigned f_symtab_sect_strings_sect_index; + Dwarf_Unsigned f_symtab_sect_index; + + /* Starts at 3. 0,1,2 used specially. */ + Dwarf_Unsigned f_sg_next_group_number; + /* Both the following will be zero unless there + are explicit Elf groups. */ + Dwarf_Unsigned f_sht_group_type_section_count; + Dwarf_Unsigned f_shf_group_flag_section_count; + Dwarf_Unsigned f_dwo_group_section_count; +} dwarf_elf_object_access_internals_t; + +int dwarf_construct_elf_access(int fd, + const char *path, + dwarf_elf_object_access_internals_t **ep,int *errcode); +int dwarf_destruct_elf_access( + dwarf_elf_object_access_internals_t *ep,int *errcode); +int _dwarf_load_elf_header( + dwarf_elf_object_access_internals_t *ep,int *errcode); +int _dwarf_load_elf_sectheaders( + dwarf_elf_object_access_internals_t* ep,int *errcode); +int _dwarf_load_elf_symtab_symbols( + dwarf_elf_object_access_internals_t *ep,int *errcode); +int _dwarf_load_elf_symstr( + dwarf_elf_object_access_internals_t *ep, int *errcode); + +/* These two enums used for type safety in passing + values. */ +enum RelocRela { + RelocIsRela = 1, + RelocIsRel = 2 +}; +enum RelocOffsetSize { + RelocOffset32 = 4, + RelocOffset64 = 8 +}; + +int _dwarf_load_elf_relx(dwarf_elf_object_access_internals_t *ep, + Dwarf_Unsigned secnum,enum RelocRela,int *errcode); + +#ifndef EI_NIDENT +#define EI_NIDENT 16 +#endif /* EI_NIDENT */ + +#ifndef SHN_XINDEX +#define SHN_XINDEX 0xffff +#endif /* SHN_XINDEX */ + +#ifndef SHN_lORESERVE +#define SHN_LORESERVE 0xff00 +#endif /* SHN_lORESERVE */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* READELFOBJ_H */ diff --git a/src/lib/libdwarf/dwarf_elfstructs.h b/src/lib/libdwarf/dwarf_elfstructs.h new file mode 100644 index 0000000..b53c85c --- /dev/null +++ b/src/lib/libdwarf/dwarf_elfstructs.h @@ -0,0 +1,213 @@ +/* +Copyright (c) 2021-2023, David Anderson +All rights reserved. +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* Typed in from the SystemV Application Binary Interface + but using char arrays instead of variables as + for reading we don't need the struct members to be + variables. This simplifies configure. + + https://www.uclibc.org/docs/elf-64-gen.pdf used as source + of Elf64 fields. + + It is expected code including this will have included + an official (for various definitions needed) + before including this. But that is not strictly necessary + given other headers. + + The structs were all officially defined so files + could be mapped in. Fields are arranged so + there will not be gaps and we need not deal with + alignment-gaps. +*/ + +#ifndef DW_ELFSTRUCTS_H +#define DW_ELFSTRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef EI_NIDENT +#define EI_NIDENT 16 +#endif + +#ifndef TYP +#define TYP(n,l) char (n)[(l)] +#endif + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; + TYP(e_type,2); + TYP(e_machine,2); + TYP(e_version,4); + TYP(e_entry,4); + TYP(e_phoff,4); + TYP(e_shoff,4); + TYP(e_flags,4); + TYP(e_ehsize,2); + TYP(e_phentsize,2); + TYP(e_phnum,2); + TYP(e_shentsize,2); + TYP(e_shnum,2); + TYP(e_shstrndx,2); +} dw_elf32_ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; + TYP(e_type,2); + TYP(e_machine,2); + TYP(e_version,4); + TYP(e_entry,8); + TYP(e_phoff,8); + TYP(e_shoff,8); + TYP(e_flags,4); + TYP(e_ehsize,2); + TYP(e_phentsize,2); + TYP(e_phnum,2); + TYP(e_shentsize,2); + TYP(e_shnum,2); + TYP(e_shstrndx,2); +} dw_elf64_ehdr; + +typedef struct +{ + TYP(p_type,4); + TYP(p_offset,4); + TYP(p_vaddr,4); + TYP(p_paddr,4); + TYP(p_filesz,4); + TYP(p_memsz,4); + TYP(p_flags,4); + TYP(p_align,4); +} dw_elf32_phdr; + +typedef struct +{ + TYP(p_type,4); + TYP(p_flags,4); + TYP(p_offset,8); + TYP(p_vaddr,8); + TYP(p_paddr,8); + TYP(p_filesz,8); + TYP(p_memsz,8); + TYP(p_align,8); +} dw_elf64_phdr; + +typedef struct +{ + TYP(sh_name,4); + TYP(sh_type,4); + TYP(sh_flags,4); + TYP(sh_addr,4); + TYP(sh_offset,4); + TYP(sh_size,4); + TYP(sh_link,4); + TYP(sh_info,4); + TYP(sh_addralign,4); + TYP(sh_entsize,4); +} dw_elf32_shdr; + +typedef struct +{ + TYP(sh_name,4); + TYP(sh_type,4); + TYP(sh_flags,8); + TYP(sh_addr,8); + TYP(sh_offset,8); + TYP(sh_size,8); + TYP(sh_link,4); + TYP(sh_info,4); + TYP(sh_addralign,8); + TYP(sh_entsize,8); +} dw_elf64_shdr; + +typedef struct +{ + TYP(r_offset,4); + TYP(r_info,4); +} dw_elf32_rel; + +typedef struct +{ + TYP(r_offset,8); + TYP(r_info,8); +} dw_elf64_rel; + +typedef struct +{ + TYP(r_offset,4); + TYP(r_info,4); + TYP(r_addend,4); /* signed */ +} dw_elf32_rela; + +typedef struct +{ + TYP(r_offset,8); + TYP(r_info,8); + TYP(r_addend,8); /* signed */ +} dw_elf64_rela; + +typedef struct { + TYP(st_name,4); + TYP(st_value,4); + TYP(st_size,4); + unsigned char st_info[1]; + unsigned char st_other[1]; + TYP(st_shndx,2); +} dw_elf32_sym; + +typedef struct { + TYP(st_name,4); + unsigned char st_info[1]; + unsigned char st_other[1]; + TYP(st_shndx,2); + TYP(st_value,8); + TYP(st_size,8); +} dw_elf64_sym; + +typedef struct +{ + TYP(d_tag,4); /* signed */ + TYP(d_val,4); /* Union in original */ +} dw_elf32_dyn; + +typedef struct +{ + TYP(d_tag,8); /* signed */ + TYP(d_val,8); /* Union in original */ +} dw_elf64_dyn; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DW_ELFSTRUCTS_H */ diff --git a/src/lib/libdwarf/dwarf_errmsg_list.h b/src/lib/libdwarf/dwarf_errmsg_list.h new file mode 100644 index 0000000..4a7a8a6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_errmsg_list.h @@ -0,0 +1,691 @@ +/* +Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2008-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ +#ifndef DWARF_ERRMSG_LIST_H +#define DWARF_ERRMSG_LIST_H + +/* Array to hold string representation of errors. Any time a + define is added to the list in libdwarf.h, a string should be + added to this Array + + Errors in the list (missing a comma, for example) + happen too often. Making this a separate little file + simplifies testing for missing-commas/extra-strings. + + Using an array table instead of + pointers saves DW_DLE_LAST+1 relocations at runtime + for libdwarf as DSO (libdwarf.so). +*/ +#define DW_MAX_MSG_LEN 111 +static const char _dwarf_errmsgs[DW_DLE_LAST+1][DW_MAX_MSG_LEN] = { +{"DW_DLE_No error (0)\n"}, +{"DW_DLE_VMM (1) dwarf format/library version mismatch"}, +{"DW_DLE_MAP (2) memory map failure"}, +{"DW_DLE_LEE (3) libelf error"}, +{"DW_DLE_NDS (4) no debug section"}, +{"DW_DLE_NLS (5) no line section "}, +{"DW_DLE_ID (6) invalid descriptor for query "}, +{"DW_DLE_IOF (7) I/O failure "}, +{"DW_DLE_MAF (8) memory allocation failure "}, +{"DW_DLE_IA (9) invalid argument "}, +{"DW_DLE_MDE (10) mangled debugging entry:libelf detected error"}, +{"DW_DLE_MLE (11) mangled line number entry "}, +{"DW_DLE_FNO (12) file not open "}, +{"DW_DLE_FNR (13) file not a regular file "}, +{"DW_DLE_FWA (14) file open with wrong access "}, +{"DW_DLE_NOB (15) not an object file "}, +{"DW_DLE_MOF (16) mangled object file header "}, +{"DW_DLE_EOLL (17) end of location list entries "}, +{"DW_DLE_NOLL (18) no location list section "}, +{"DW_DLE_BADOFF (19) Invalid offset "}, +{"DW_DLE_EOS (20) end of section "}, +{"DW_DLE_ATRUNC (21) abbreviations section appears truncated"}, +{"DW_DLE_BADBITC (22) Address size passed to dwarf bad"}, + +{"DW_DLE_DBG_ALLOC (23) Unable to malloc a Dwarf_Debug structure"}, +{"DW_DLE_FSTAT_ERROR (24) The file fd passed to dwarf_init " + "cannot be fstat()ed"}, +{"DW_DLE_FSTAT_MODE_ERROR (25) The file mode bits say not " + "a normal file"}, +{"DW_DLE_INIT_ACCESS_WRONG (26) A call to dwarf_init failed," + " this error impossible as of July 2021"}, +{"DW_DLE_ELF_BEGIN_ERROR (27) a call to " + "elf_begin(... ELF_C_READ_MMAP... ) failed"}, +{"DW_DLE_ELF_GETEHDR_ERROR (28) a call to " + "elf32_getehdr() or elf64_getehdr() failed"}, +{"DW_DLE_ELF_GETSHDR_ERROR (29) a call to " + "elf32_getshdr() or elf64_getshdr() failed"}, +{"DW_DLE_ELF_STRPTR_ERROR (30) a call to " + "elf_strptr() failed trying to get a section name"}, +{"DW_DLE_DEBUG_INFO_DUPLICATE (31) Only one .debug_info " + "section is allowed"}, +{"DW_DLE_DEBUG_INFO_NULL (32) .debug_info section present but " + "elf_getdata() failed"}, +{"DW_DLE_DEBUG_ABBREV_DUPLICATE (33) Only one .debug_abbrev " + "section is allowed"}, +{"DW_DLE_DEBUG_ABBREV_NULL (34) .debug_abbrev section present but " + "elf_getdata() failed"}, +{"DW_DLE_DEBUG_ARANGES_DUPLICATE (35) Only one .debug_aranges " + "section is allowed"}, +{"DW_DLE_DEBUG_ARANGES_NULL (36) .debug_aranges section present but " + "elf_getdata() failed"}, +{"DW_DLE_DEBUG_LINE_DUPLICATE (37) Only one .debug_line " + "section is allowed"}, +{"DW_DLE_DEBUG_LINE_NULL (38) .debug_line section 0-size. Corrupt."}, +{"DW_DLE_DEBUG_LOC_DUPLICATE (39) Only one .debug_loc " + "section is allowed"}, +{"DW_DLE_DEBUG_LOC_NULL (40) .debug_loc section present but " + "elf_getdata() failed"}, +{"DW_DLE_DEBUG_MACINFO_DUPLICATE (41) Only one .debug_macinfo " + "section is allowed"}, +{"DW_DLE_DEBUG_MACINFO_NULL (42) .debug_macinfo section present but " + "elf_getdata() failed"}, +{"DW_DLE_DEBUG_PUBNAMES_DUPLICATE (43) Only one .debug_pubnames " + "section is allowed"}, +{"DW_DLE_DEBUG_PUBNAMES_NULL (44) .debug_pubnames section " + "present but elf_getdata() failed"}, +{"DW_DLE_DEBUG_STR_DUPLICATE (45) Only one .debug_str " + "section is allowed"}, +{"DW_DLE_DEBUG_STR_NULL (46) .debug_str section present but " + "elf_getdata() failed"}, +{"DW_DLE_CU_LENGTH_ERROR (47) Corrupted DWARF or corrupted object"}, +{"DW_DLE_VERSION_STAMP_ERROR (48) Corrupted DWARF " + "or corrupted object"}, +{"DW_DLE_ABBREV_OFFSET_ERROR (49) Corrupted DWARF or " + "corrupted object"}, +{"DW_DLE_ADDRESS_SIZE_ERROR (50) size too large"}, +{"DW_DLE_DEBUG_INFO_PTR_NULL (51)"}, +{"DW_DLE_DIE_NULL (52)"}, +{"DW_DLE_STRING_OFFSET_BAD (53) Corrupted DWARF or corrupted object"}, +{"DW_DLE_DEBUG_LINE_LENGTH_BAD (54)"}, +{"DW_DLE_LINE_PROLOG_LENGTH_BAD (55)"}, +{"DW_DLE_LINE_NUM_OPERANDS_BAD (56)"}, +{"DW_DLE_LINE_SET_ADDR_ERROR (57)"}, +{"DW_DLE_LINE_EXT_OPCODE_BAD (58)"}, +{"DW_DLE_DWARF_LINE_NULL (59)"}, +{"DW_DLE_INCL_DIR_NUM_BAD (60)"}, +{"DW_DLE_LINE_FILE_NUM_BAD (61)"}, +{"DW_DLE_ALLOC_FAIL (62) Out of memory or corrupted object"}, +{"DW_DLE_NO_CALLBACK_FUNC (63)"}, +{"DW_DLE_SECT_ALLOC (64)"}, +{"DW_DLE_FILE_ENTRY_ALLOC (65)"}, +{"DW_DLE_LINE_ALLOC (66)"}, +{"DW_DLE_FPGM_ALLOC (67)"}, +{"DW_DLE_INCDIR_ALLOC (68)"}, +{"DW_DLE_STRING_ALLOC (69)"}, +{"DW_DLE_CHUNK_ALLOC (70)"}, +{"DW_DLE_BYTEOFF_ERR (71)"}, +{"DW_DLE_CIE_ALLOC (72)"}, +{"DW_DLE_FDE_ALLOC (73)"}, +{"DW_DLE_REGNO_OVFL (74)"}, +{"DW_DLE_CIE_OFFS_ALLOC (75)"}, +{"DW_DLE_WRONG_ADDRESS (76)"}, +{"DW_DLE_EXTRA_NEIGHBORS (77)"}, +{"DW_DLE_WRONG_TAG (78)"}, +{"DW_DLE_DIE_ALLOC (79)"}, +{"DW_DLE_PARENT_EXISTS (80)"}, +{"DW_DLE_DBG_NULL (81)"}, +{"DW_DLE_DEBUGLINE_ERROR (82)"}, +{"DW_DLE_DEBUGFRAME_ERROR (83)"}, +{"DW_DLE_DEBUGINFO_ERROR (84)"}, +{"DW_DLE_ATTR_ALLOC (85)"}, +{"DW_DLE_ABBREV_ALLOC (86)"}, +{"DW_DLE_OFFSET_UFLW (87)"}, +{"DW_DLE_ELF_SECT_ERR (88)"}, +{"DW_DLE_DEBUG_FRAME_LENGTH_BAD (89)"}, +{"DW_DLE_FRAME_VERSION_BAD (90)"}, +{"DW_DLE_CIE_RET_ADDR_REG_ERROR (91)"}, +{"DW_DLE_FDE_NULL (92)"}, +{"DW_DLE_FDE_DBG_NULL (93)"}, +{"DW_DLE_CIE_NULL (94)"}, +{"DW_DLE_CIE_DBG_NULL (95)"}, +{"DW_DLE_FRAME_TABLE_COL_BAD (96)"}, +{"DW_DLE_PC_NOT_IN_FDE_RANGE (97)"}, +{"DW_DLE_CIE_INSTR_EXEC_ERROR (98)"}, +{"DW_DLE_FRAME_INSTR_EXEC_ERROR (99)"}, +{"DW_DLE_FDE_PTR_NULL (100)"}, +{"DW_DLE_RET_OP_LIST_NULL (101)"}, +{"DW_DLE_LINE_CONTEXT_NULL (102)"}, +{"DW_DLE_DBG_NO_CU_CONTEXT (103)"}, +{"DW_DLE_DIE_NO_CU_CONTEXT (104)"}, +{"DW_DLE_FIRST_DIE_NOT_CU (105)"}, +{"DW_DLE_NEXT_DIE_PTR_NULL (106)"}, +{"DW_DLE_DEBUG_FRAME_DUPLICATE (107) Only one .debug_frame " + "section is allowed"}, +{"DW_DLE_DEBUG_FRAME_NULL (108) .debug_frame section present but " + "elf_getdata() failed"}, +{"DW_DLE_ABBREV_DECODE_ERROR (109)"}, +{"DW_DLE_DWARF_ABBREV_NULL (110)"}, +{"DW_DLE_ATTR_NULL (111)"}, +{"DW_DLE_DIE_BAD (112)"}, +{"DW_DLE_DIE_ABBREV_BAD (113)"}, +{"DW_DLE_ATTR_FORM_BAD (114)"}, +{"DW_DLE_ATTR_NO_CU_CONTEXT (115)"}, +{"DW_DLE_ATTR_FORM_SIZE_BAD (116)"}, +{"DW_DLE_ATTR_DBG_NULL (117)"}, +{"DW_DLE_BAD_REF_FORM (118)"}, +{"DW_DLE_ATTR_FORM_OFFSET_BAD (119)"}, +{"DW_DLE_LINE_OFFSET_BAD (120)"}, +{"DW_DLE_DEBUG_STR_OFFSET_BAD (121)"}, +{"DW_DLE_STRING_PTR_NULL (122)"}, +{"DW_DLE_PUBNAMES_VERSION_ERROR (123)"}, +{"DW_DLE_PUBNAMES_LENGTH_BAD (124)"}, +{"DW_DLE_GLOBAL_NULL (125)"}, +{"DW_DLE_GLOBAL_CONTEXT_NULL (126)"}, +{"DW_DLE_DIR_INDEX_BAD (127)"}, +{"DW_DLE_LOC_EXPR_BAD (128)"}, +{"DW_DLE_DIE_LOC_EXPR_BAD (129)"}, +{"DW_DLE_ADDR_ALLOC (130)"}, +{"DW_DLE_OFFSET_BAD (131)"}, +{"DW_DLE_MAKE_CU_CONTEXT_FAIL (132)"}, +{"DW_DLE_REL_ALLOC (133)"}, +{"DW_DLE_ARANGE_OFFSET_BAD (134)"}, +{"DW_DLE_SEGMENT_SIZE_BAD (135) Size of a segment selector " + "should usually be less than 8 (bytes)."}, +{"DW_DLE_ARANGE_LENGTH_BAD (136)"}, +{"DW_DLE_ARANGE_DECODE_ERROR (137)"}, +{"DW_DLE_ARANGES_NULL (138)"}, +{"DW_DLE_ARANGE_NULL (139)"}, +{"DW_DLE_NO_FILE_NAME (140)"}, +{"DW_DLE_NO_COMP_DIR (141)"}, +{"DW_DLE_CU_ADDRESS_SIZE_BAD (142)"}, +{"DW_DLE_INPUT_ATTR_BAD (143)"}, +{"DW_DLE_EXPR_NULL (144)"}, +{"DW_DLE_BAD_EXPR_OPCODE (145)"}, +{"DW_DLE_EXPR_LENGTH_BAD (146)"}, +{"DW_DLE_MULTIPLE_RELOC_IN_EXPR (147)"}, +{"DW_DLE_ELF_GETIDENT_ERROR (148)"}, +{"DW_DLE_NO_AT_MIPS_FDE (149)"}, +{"DW_DLE_NO_CIE_FOR_FDE (150)"}, +{"DW_DLE_DIE_ABBREV_LIST_NULL (151) No abbrev exists for " + "the requested abbrev code"}, +{"DW_DLE_DEBUG_FUNCNAMES_DUPLICATE (152)"}, +{"DW_DLE_DEBUG_FUNCNAMES_NULL (153) .debug_funcnames section " + "present but elf_getdata() bad"}, +{"DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR (154)"}, +{"DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD (155)"}, +{"DW_DLE_FUNC_NULL (156)"}, +{"DW_DLE_FUNC_CONTEXT_NULL (157)"}, +{"DW_DLE_DEBUG_TYPENAMES_DUPLICATE (158)"}, +{"DW_DLE_DEBUG_TYPENAMES_NULL (159) .debug_typenames section " + "present but elf_getdata() failed"}, +{"DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR (160)"}, +{"DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD (161)"}, +{"DW_DLE_TYPE_NULL (162)"}, +{"DW_DLE_TYPE_CONTEXT_NULL (163)"}, +{"DW_DLE_DEBUG_VARNAMES_DUPLICATE (164)"}, +{"DW_DLE_DEBUG_VARNAMES_NULL (165) .debug_varnames section present " + "but elf_getdata() failed"}, +{"DW_DLE_DEBUG_VARNAMES_VERSION_ERROR (166)"}, +{"DW_DLE_DEBUG_VARNAMES_LENGTH_BAD (167)"}, +{"DW_DLE_VAR_NULL (168)"}, +{"DW_DLE_VAR_CONTEXT_NULL (169)"}, +{"DW_DLE_DEBUG_WEAKNAMES_DUPLICATE (170)"}, +{"DW_DLE_DEBUG_WEAKNAMES_NULL (171) .debug_weaknames section " + "present but elf_getdata() failed"}, + +{"DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR (172)"}, +{"DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD (173)"}, +{"DW_DLE_WEAK_NULL (174)"}, +{"DW_DLE_WEAK_CONTEXT_NULL (175)"}, +{"DW_DLE_LOCDESC_COUNT_WRONG (176)"}, +{"DW_DLE_MACINFO_STRING_NULL (177)"}, +{"DW_DLE_MACINFO_STRING_EMPTY (178)"}, +{"DW_DLE_MACINFO_INTERNAL_ERROR_SPACE (179)"}, +{"DW_DLE_MACINFO_MALLOC_FAIL (180)"}, +{"DW_DLE_DEBUGMACINFO_ERROR (181)"}, +{"DW_DLE_DEBUG_MACRO_LENGTH_BAD (182) in .debug_macinfo"}, +{"DW_DLE_DEBUG_MACRO_MAX_BAD (183) in .debug_macinfo"}, +{"DW_DLE_DEBUG_MACRO_INTERNAL_ERR (184) in .debug_macinfo"}, +{"DW_DLE_DEBUG_MACRO_MALLOC_SPACE (185) in .debug_macinfo"}, +{"DW_DLE_DEBUG_MACRO_INCONSISTENT (186) in .debug_macinfo"}, +{"DW_DLE_DF_NO_CIE_AUGMENTATION(187)"}, +{"DW_DLE_DF_REG_NUM_TOO_HIGH(188)"}, +{"DW_DLE_DF_MAKE_INSTR_NO_INIT(189)"}, +{"DW_DLE_DF_NEW_LOC_LESS_OLD_LOC(190)"}, +{"DW_DLE_DF_POP_EMPTY_STACK(191)"}, +{"DW_DLE_DF_ALLOC_FAIL(192)"}, +{"DW_DLE_DF_FRAME_DECODING_ERROR(193)"}, +{"DW_DLE_DEBUG_LOC_SECTION_SHORT(194)"}, +{"DW_DLE_FRAME_AUGMENTATION_UNKNOWN(195)"}, +{"DW_DLE_PUBTYPE_CONTEXT(196)"}, +{"DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD(197)"}, +{"DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR(198)"}, +{"DW_DLE_DEBUG_PUBTYPES_DUPLICATE(199)"}, +{"DW_DLE_FRAME_CIE_DECODE_ERROR(200)"}, +{"DW_DLE_FRAME_REGISTER_UNREPRESENTABLE(201)"}, +{"DW_DLE_FRAME_REGISTER_COUNT_MISMATCH(202)"}, +{"DW_DLE_LINK_LOOP(203)"}, +{"DW_DLE_STRP_OFFSET_BAD(204)"}, +{"DW_DLE_DEBUG_RANGES_DUPLICATE(205)"}, +{"DW_DLE_DEBUG_RANGES_OFFSET_BAD(206)"}, +{"DW_DLE_DEBUG_RANGES_MISSING_END(207)"}, +{"DW_DLE_DEBUG_RANGES_OUT_OF_MEM(208)"}, +{"DW_DLE_DEBUG_SYMTAB_ERR(209)"}, +{"DW_DLE_DEBUG_STRTAB_ERR(210)"}, +{"DW_DLE_RELOC_MISMATCH_INDEX(211)"}, +{"DW_DLE_RELOC_MISMATCH_RELOC_INDEX(212)"}, +{"DW_DLE_RELOC_MISMATCH_STRTAB_INDEX(213)"}, +{"DW_DLE_RELOC_SECTION_MISMATCH(214)"}, +{"DW_DLE_RELOC_SECTION_MISSING_INDEX(215)"}, +{"DW_DLE_RELOC_SECTION_LENGTH_ODD(216)"}, +{"DW_DLE_RELOC_SECTION_PTR_NULL(217)"}, +{"DW_DLE_RELOC_SECTION_MALLOC_FAIL(218)"}, +{"DW_DLE_NO_ELF64_SUPPORT(219)"}, +{"DW_DLE_MISSING_ELF64_SUPPORT(220)"}, +{"DW_DLE_ORPHAN_FDE(221)"}, +{"DW_DLE_DUPLICATE_INST_BLOCK(222)"}, +{"DW_DLE_BAD_REF_SIG8_FORM(223)"}, +{"DW_DLE_ATTR_EXPRLOC_FORM_BAD(224)"}, +{"DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD(225)"}, +{"DW_DLE_NOT_REF_FORM(226)"}, +{"DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE(227)"}, +{"DW_DLE_REF_SIG8_NOT_HANDLED (228)"}, +{"DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH (229)"}, +{"DW_DLE_LOC_BAD_TERMINATION (230) location operator " + "in expression missing data"}, +{"DW_DLE_SYMTAB_SECTION_LENGTH_ODD (231) so doing " + "relocations seems unsafe"}, +{"DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD (232) so doing a " + "relocation seems unsafe"}, +{"DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN (233) so " + "doing a relocation is unsafe"}, +{"DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO(234)"}, +{"DW_DLE_LINE_NUMBER_HEADER_ERROR (235), a line number " + "program header seems incomplete"}, +{"DW_DLE_DEBUG_TYPES_NULL (236)"}, +{"DW_DLE_DEBUG_TYPES_DUPLICATE (237)"}, +{"DW_DLE_DEBUG_TYPES_ONLY_DWARF4 (238) DW4 and DW5 have types CUs"}, +{"DW_DLE_DEBUG_TYPEOFFSET_BAD (239)"}, +{"DW_DLE_GNU_OPCODE_ERROR (240)"}, +{"DW_DLE_DEBUGPUBTYPES_ERROR (241), could not create " + "pubtypes section"}, +{"DW_DLE_AT_FIXUP_NULL (242)"}, +{"DW_DLE_AT_FIXUP_DUP (243)"}, +{"DW_DLE_BAD_ABINAME (244)"}, +{"DW_DLE_TOO_MANY_DEBUG(245), too many .debug_* sections " + "present somehow"}, +{"DW_DLE_DEBUG_STR_OFFSETS_DUPLICATE(246)"}, +{"DW_DLE_SECTION_DUPLICATION(247)"}, +{"DW_DLE_SECTION_ERROR(248)"}, +{"DW_DLE_DEBUG_ADDR_DUPLICATE(249)"}, +{"DW_DLE_DEBUG_CU_UNAVAILABLE_FOR_FORM(250)"}, +{"DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE(251)"}, +{"DW_DLE_NEXT_DIE_PAST_END(252)"}, +{"DW_DLE_NEXT_DIE_WRONG_FORM(253)"}, +{"DW_DLE_NEXT_DIE_NO_ABBREV_LIST(254)"}, +{"DW_DLE_NESTED_FORM_INDIRECT_ERROR(255)"}, +{"DW_DLE_CU_DIE_NO_ABBREV_LIST(256)"}, +{"DW_DLE_MISSING_NEEDED_DEBUG_ADDR_SECTION(257)"}, +{"DW_DLE_ATTR_FORM_NOT_ADDR_INDEX(258)"}, +{"DW_DLE_ATTR_FORM_NOT_STR_INDEX(259)"}, +{"DW_DLE_DUPLICATE_GDB_INDEX(260)"}, +{"DW_DLE_ERRONEOUS_GDB_INDEX_SECTION(261) The section is too small"}, +{"DW_DLE_GDB_INDEX_COUNT_ERROR(262)"}, +{"DW_DLE_GDB_INDEX_COUNT_ADDR_ERROR(263)"}, +{"DW_DLE_GDB_INDEX_CUVEC_ERROR(264)"}, +{"DW_DLE_GDB_INDEX_INDEX_ERROR(265)"}, +{"DW_DLE_DUPLICATE_CU_INDEX(266)"}, +{"DW_DLE_DUPLICATE_TU_INDEX(267)"}, +{"DW_DLE_XU_TYPE_ARG_ERROR(268) XU means dwarf_cu_ or " + "tu_ index section"}, +{"DW_DLE_XU_IMPOSSIBLE_ERROR(269) XU means dwarf_cu_ or " + "tu_ index section"}, +{"DW_DLE_XU_NAME_COL_ERROR(270) XU means dwarf_cu_ or " + "tu_ index section"}, +{"DW_DLE_XU_HASH_ROW_ERROR(271) XU means dwarf_cu_ or " + "tu_ index section"}, +{"DW_DLE_XU_HASH_INDEX_ERROR(272) XU means dwarf_cu_ or " + "tu_ index section"}, +{"DW_DLE_FAILSAFE_ERRVAL(273)"}, +{"DW_DLE_ARANGE_ERROR(274) producer problem in object generation"}, +{"DW_DLE_PUBNAMES_ERROR(275) producer problem in object generation"}, +{"DW_DLE_FUNCNAMES_ERROR(276) producer problem in object generation"}, +{"DW_DLE_TYPENAMES_ERROR(277) producer problem in object generation"}, +{"DW_DLE_VARNAMES_ERROR(278) producer problem in object generation"}, +{"DW_DLE_WEAKNAMES_ERROR(279) producer problem in object generation"}, +{"DW_DLE_RELOCS_ERROR(280) producer problem in object generation"}, +{"DW_DLE_DW_DLE_ATTR_OUTSIDE_SECTION(281)"}, +{"DW_DLE_FISSION_INDEX_WRONG(282)"}, +{"DW_DLE_FISSION_VERSION_ERROR(283)"}, +{"DW_DLE_NEXT_DIE_LOW_ERROR(284) corrupted DIE tree"}, +{"DW_DLE_CU_UT_TYPE_ERROR(285) bad DW_UT_* value, corrupt DWARF5"}, +{"DW_DLE_NO_SUCH_SIGNATURE_FOUND(286) CU signature not in the index"}, +{"DW_DLE_SIGNATURE_SECTION_NUMBER_WRONG(287) " + "libdwarf software error"}, +{"DW_DLE_ATTR_FORM_NOT_DATA8(288) wanted an 8 byte signature"}, +{"DW_DLE_SIG_TYPE_WRONG_STRING (289) expected tu or cu"}, +{"DW_DLE_MISSING_REQUIRED_TU_OFFSET_HASH(290) is a " + "broken dwp package file"}, +{"DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH(291) is a " + "broken dwp package file"}, +{"DW_DLE_DWP_MISSING_DWO_ID(292)"}, +{"DW_DLE_DWP_SIBLING_ERROR(293)"}, +{"DW_DLE_DEBUG_FISSION_INCOMPLETE(294)"}, +{"DW_DLE_FISSION_SECNUM_ERR(295) internal libdwarf error"}, +{"DW_DLE_DEBUG_MACRO_DUPLICATE(296)"}, +{"DW_DLE_DEBUG_NAMES_DUPLICATE(297)"}, +{"DW_DLE_DEBUG_LINE_STR_DUPLICATE(298)"}, +{"DW_DLE_DEBUG_SUP_DUPLICATE(299)"}, +{"DW_DLE_NO_SIGNATURE_TO_LOOKUP(300)"}, +{"DW_DLE_NO_TIED_ADDR_AVAILABLE(301)"}, +{"DW_DLE_NO_TIED_SIG_AVAILABLE(302)"}, +{"DW_DLE_STRING_NOT_TERMINATED(303) section data may be corrupted"}, +{"DW_DLE_BAD_LINE_TABLE_OPERATION(304) two-level line table botch"}, +{"DW_DLE_LINE_CONTEXT_BOTCH(305) call is wrong or memory corruption"}, +{"DW_DLE_LINE_CONTEXT_INDEX_WRONG(306)"}, +{"DW_DLE_NO_TIED_STRING_AVAILABLE(307) tied file does not " + "have the string"}, +{"DW_DLE_NO_TIED_FILE_AVAILABLE(308) see dwarf_set_tied_dbg()"}, +{"DW_DLE_CU_TYPE_MISSING(309) libdwarf bug or data corruption"}, +{"DW_DLE_LLE_CODE_UNKNOWN (310) libdwarf bug or data corruption"}, +{"DW_DLE_LOCLIST_INTERFACE_ERROR (311) interface cannot do " + "location or DW_OP*"}, +{"DW_DLE_LOCLIST_INDEX_ERROR (312)"}, +{"DW_DLE_INTERFACE_NOT_SUPPORTED (313)"}, +{"DW_DLE_ZDEBUG_REQUIRES_ZLIB (314) Unable to decompress .zdebug " + "as zlib missing"}, +{"DW_DLE_ZDEBUG_INPUT_FORMAT_ODD(315)"}, +{"DW_DLE_ZLIB_BUF_ERROR (316) Z_BUF_ERROR buffer size small"}, +{"DW_DLE_ZLIB_DATA_ERROR (317) Z_DATA_ERROR compressed " + "data corrupted"}, +{"DW_DLE_MACRO_OFFSET_BAD (318)"}, +{"DW_DLE_MACRO_OPCODE_BAD (319)"}, +{"DW_DLE_MACRO_OPCODE_FORM_BAD (320)"}, +{"DW_DLE_UNKNOWN_FORM (321) Possibly corrupt DWARF data"}, +{"DW_DLE_BAD_MACRO_HEADER_POINTER(322)"}, +{"DW_DLE_BAD_MACRO_INDEX(323)"}, +{"DW_DLE_MACRO_OP_UNHANDLED(324) Possibly an implementation " + "extension"}, +{"DW_DLE_MACRO_PAST_END(325)"}, +{"DW_DLE_LINE_STRP_OFFSET_BAD(326)"}, +{"DW_DLE_STRING_FORM_IMPROPER(327) An internal libdwarf logic error"}, +{"DW_DLE_ELF_FLAGS_NOT_AVAILABLE(328) elf/non-elf object confusion?"}, +{"DW_DLE_LEB_IMPROPER (329) Runs off end of section or CU"}, +{"DW_DLE_DEBUG_LINE_RANGE_ZERO (330) Corrupted line section"}, +{"DW_DLE_READ_LITTLEENDIAN_ERROR (331) Corrupted dwarfdata " + "littleendian host"}, +{"DW_DLE_READ_BIGENDIAN_ERROR (332) Corrupted dwarf data " + "bigendian host"}, +{"DW_DLE_RELOC_INVALID (333) relocation corruption"}, +{"DW_DLE_INFO_HEADER_ERROR(334) Corrupt dwarf"}, +{"DW_DLE_ARANGES_HEADER_ERROR(335) Corrupt dwarf"}, +{"DW_DLE_LINE_OFFSET_WRONG_FORM(336) Corrupt dwarf"}, +{"DW_DLE_FORM_BLOCK_LENGTH_ERROR(337) Corrupt dwarf"}, +{"DW_DLE_ZLIB_SECTION_SHORT (338) Corrupt dwarf"}, +{"DW_DLE_CIE_INSTR_PTR_ERROR (339)"}, +{"DW_DLE_FDE_INSTR_PTR_ERROR (340)"}, +{"DW_DLE_FISSION_ADDITION_ERROR (341) Corrupt dwarf"}, +{"DW_DLE_HEADER_LEN_BIGGER_THAN_SECSIZE (342) Corrupt dwarf"}, +{"DW_DLE_LOCEXPR_OFF_SECTION_END (343) Corrupt dwarf"}, +{"DW_DLE_POINTER_SECTION_UNKNOWN (344)"}, +{"DW_DLE_ERRONEOUS_XU_INDEX_SECTION(345) XU means cu_ or tu_ index"}, +{"DW_DLE_DIRECTORY_FORMAT_COUNT_VS_DIRECTORIES_MISMATCH(346) " + "Inconsistent line table, corrupted."}, +{"DW_DLE_COMPRESSED_EMPTY_SECTION(347) corrupt section data"}, +{"DW_DLE_SIZE_WRAPAROUND(348) Impossible string length"}, +{"DW_DLE_ILLOGICAL_TSEARCH(349) Impossible situation. " + "Corrupted data?"}, +{"DW_DLE_BAD_STRING_FORM(350) Not a currently allowed form"}, +{"DW_DLE_DEBUGSTR_ERROR(351) problem generating .debug_str section"}, +{"DW_DLE_DEBUGSTR_UNEXPECTED_REL(352) string relocation " + "will be wrong."}, +{"DW_DLE_DISCR_ARRAY_ERROR(353) Internal error in " + "dwarf_discr_list()"}, +{"DW_DLE_LEB_OUT_ERROR(354) Insufficient buffer to turn " + "integer to leb"}, +{"DW_DLE_SIBLING_LIST_IMPROPER(355) Runs off end of section. " + "Corrupt dwarf"}, +{"DW_DLE_LOCLIST_OFFSET_BAD(356) Corrupt dwarf"}, +{"DW_DLE_LINE_TABLE_BAD(357) Corrupt line table"}, +{"DW_DLE_DEBUG_LOClISTS_DUPLICATE(358)"}, +{"DW_DLE_DEBUG_RNGLISTS_DUPLICATE(359)"}, +{"DW_DLE_ABBREV_OFF_END(360)"}, +{"DW_DLE_FORM_STRING_BAD_STRING(361) string runs off end of data"}, +{"DW_DLE_AUGMENTATION_STRING_OFF_END(362) augmentation runs off " + "of its section"}, +{"DW_DLE_STRING_OFF_END_PUBNAMES_LIKE(363) one of the global " + "sections, string bad"}, +{"DW_DLE_LINE_STRING_BAD(364) runs off end of line data"}, +{"DW_DLE_DEFINE_FILE_STRING_BAD(365) runs off end of section"}, +{"DW_DLE_MACRO_STRING_BAD(366) DWARF5 macro def/undef string " + "runs off section data"}, +{"DW_DLE_MACINFO_STRING_BAD(367) DWARF2..4 macro def/undef " + "string runs off section data"}, +{"DW_DLE_ZLIB_UNCOMPRESS_ERROR(368) Surely an invalid " + "uncompress length"}, +{"DW_DLE_IMPROPER_DWO_ID(369)"}, +{"DW_DLE_GROUPNUMBER_ERROR(370) An error determining default " + "target group number"}, +{"DW_DLE_ADDRESS_SIZE_ZERO(371)"}, +{"DW_DLE_DEBUG_NAMES_HEADER_ERROR(372)"}, +{"DW_DLE_DEBUG_NAMES_AUG_STRING_ERROR(373) corrupt dwarf"}, +{"DW_DLE_DEBUG_NAMES_PAD_NON_ZERO(374) corrupt dwarf"}, +{"DW_DLE_DEBUG_NAMES_OFF_END(375) corrupt dwarf"}, +{"DW_DLE_DEBUG_NAMES_ABBREV_OVERFLOW(376) Surprising " + "overrun of fixed size array"}, +{"DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION(377)"}, +{"DW_DLE_DEBUG_NAMES_NULL_POINTER(378) null argument"}, +{"DW_DLE_DEBUG_NAMES_BAD_INDEX_ARG(379) index outside valid range"}, +{"DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET(380) offset outside entrypool"}, +{"DW_DLE_DEBUG_NAMES_UNHANDLED_FORM(381) Might be corrupt " + "dwarf or incomplete DWARF support"}, +{"DW_DLE_LNCT_CODE_UNKNOWN(382)"}, +{"DW_DLE_LNCT_FORM_CODE_NOT_HANDLED(383) Might be bad form " + "or just not implemented"}, +{"DW_DLE_LINE_HEADER_LENGTH_BOTCH(384) Internal libdwarf error"}, +{"DW_DLE_STRING_HASHTAB_IDENTITY_ERROR(385) Internal libdwarf error"}, +{"DW_DLE_UNIT_TYPE_NOT_HANDLED(386) Possibly incomplete " + "dwarf5 support"}, +{"DW_DLE_GROUP_MAP_ALLOC(387) Out of malloc space"}, +{"DW_DLE_GROUP_MAP_DUPLICATE(388) Each section # should appear once"}, +{"DW_DLE_GROUP_COUNT_ERROR(389) An inconsistency in map entry count"}, +{"DW_DLE_GROUP_INTERNAL_ERROR(390) libdwarf data corruption"}, +{"DW_DLE_GROUP_LOAD_ERROR(391) corrupt data?"}, +{"DW_DLE_GROUP_LOAD_READ_ERROR(392)"}, +{"DW_DLE_AUG_DATA_LENGTH_BAD(393) Data does not fit in section"}, +{"DW_DLE_ABBREV_MISSING(394) Unable to find abbrev for DIE"}, +{"DW_DLE_NO_TAG_FOR_DIE(395)"}, +{"DW_DLE_LOWPC_WRONG_CLASS(396) found in dwarf_lowpc()"}, +{"DW_DLE_HIGHPC_WRONG_FORM(397) found in dwarf_highpc()"}, +{"DW_DLE_STR_OFFSETS_BASE_WRONG_FORM(398)"}, +{"DW_DLE_DATA16_OUTSIDE_SECTION(399)"}, +{"DW_DLE_LNCT_MD5_WRONG_FORM(400)"}, +{"DW_DLE_LINE_HEADER_CORRUPT(401) possible data corruption"}, +{"DW_DLE_STR_OFFSETS_NULLARGUMENT(402) improper call"}, +{"DW_DLE_STR_OFFSETS_NULL_DBG(403) improper call"}, +{"DW_DLE_STR_OFFSETS_NO_MAGIC(404) improper call"}, +{"DLE_STR_OFFSETS_ARRAY_SIZE(405) Not a multiple of entry size"}, +{"DW_DLE_STR_OFFSETS_VERSION_WRONG(406) Must be 5 "}, +{"DW_DLE_STR_OFFSETS_ARRAY_INDEX_WRONG(407) Requested outside bound"}, +{"DW_DLE_STR_OFFSETS_EXTRA_BYTES(408) .debug_str_offsets " + "section problem"}, +{"DW_DLE_DUP_ATTR_ON_DIE(409) Compiler error, object improper DWARF"}, +{"DW_DLE_SECTION_NAME_BIG(410) Caller provided insufficient " + "room for section name"}, +{"DW_DLE_FILE_UNAVAILABLE(411). Unable find/read object file"}, +{"DW_DLE_FILE_WRONG_TYPE(412). Not an object type we recognize."}, +{"DW_DLE_SIBLING_OFFSET_WRONG(413). Corrupt dwarf."}, +{"DW_DLE_OPEN_FAIL(414) Unable to open, possibly a bad filename"}, +{"DW_DLE_OFFSET_SIZE(415) Offset size is neither 32 nor 64"}, +{"DW_DLE_MACH_O_SEGOFFSET_BAD(416) corrupt object"}, +{"DW_DLE_FILE_OFFSET_BAD(417) corrupt object"}, +{"DW_DLE_SEEK_ERROR(418). Seek failed, corrupt object"}, +{"DW_DLE_READ_ERROR(419). Read failed, corrupt object"}, +{"DW_DLE_ELF_CLASS_BAD(420) Corrupt object."}, +{"DW_DLE_ELF_ENDIAN_BAD(421) Corrupt object."}, +{"DW_DLE_ELF_VERSION_BAD(422) Corrupt object."}, +{"DW_DLE_FILE_TOO_SMALL(423) File is too small to be an " + "object file."}, +{"DW_DLE_PATH_SIZE_TOO_SMALL(424) buffer passed to " + "dwarf_object_detector_path is too small."}, +{"DW_DLE_BAD_TYPE_SIZE(425) At compile time the build " + "configured itself improperly."}, +{"DW_DLE_PE_SIZE_SMALL(426) File too small to be valid PE object."}, +{"DW_DLE_PE_OFFSET_BAD(427) Calculated offset too large. " + "Corrupt object."}, +{"DW_DLE_PE_STRING_TOO_LONG(428) Increase size for call."}, +{"DW_DLE_IMAGE_FILE_UNKNOWN_TYPE(429) a PE object has an " + "unknown machine type, not 0x14c, 0x200 or 0x8664"}, +{"DLE_LINE_TABLE_LINENO_ERROR(430) Negative line number " + "impossible. Corrupted line table."}, +{"DW_DLE_PRODUCER_CODE_NOT_AVAILABLE(431) Without elf.h " + "the producer code is not available."}, +{"DW_DLE_NO_ELF_SUPPORT(432) libdwarf was compiled without " + "Elf object support."}, +{"DW_DLE_NO_STREAM_RELOC_SUPPORT(433) no elf.h so cannot " + "generate STREAM relocations"}, +{"DW_DLE_RETURN_EMPTY_PUBNAMES_ERROR(434) Flag value passed " + "in not allowed."}, +{"DW_DLE_SECTION_SIZE_ERROR(435) Corrupt Elf. Section size: " + "> file size or not a multiple of entry size"}, +{"DW_DLE_INTERNAL_NULL_POINTER(436) Internal libdwarf " + "call:null pointer"}, +{"DW_DLE_SECTION_STRING_OFFSET_BAD(437) Corrupt Elf, an " + "offset to section name is invalid"}, +{"DW_DLE_SECTION_INDEX_BAD(438) Corrupt Elf, a section " + "index is incorrect"}, +{"DW_DLE_INTEGER_TOO_SMALL(439) Build does not allow reading Elf64"}, +{"DW_DLE_ELF_SECTION_LINK_ERROR(440) Corrupt Elf, section " + "links in error"}, +{"DW_DLE_ELF_SECTION_GROUP_ERROR(441) Corrupt Elf, section " + "group information problem"}, +{"DW_DLE_ELF_SECTION_COUNT_MISMATCH(442) Corrupt Elf or " + "libdwarf bug."}, +{"DW_DLE_ELF_STRING_SECTION_MISSING(443) Corrupt Elf, " + "string section wrong type"}, +{"DW_DLE_SEEK_OFF_END(444) Corrupt Elf. Seek past the end " + "not allowed"}, +{"DW_DLE_READ_OFF_END(445) Corrupt Elf. A read would read past " + "end of object"}, +{"DW_DLE_ELF_SECTION_ERROR(446) Section offset or size is too large. " + "Corrupt elf object."}, +{"DW_DLE_ELF_STRING_SECTION_ERROR(447) String section missing. " + "Corrupt Elf"}, +{"DW_DLE_MIXING_SPLIT_DWARF_VERSIONS(448) DWARF5 header " + "signature and DWARF4 DW_AT_[GNU]_dwo_id both present"}, +{"DW_DLE_TAG_CORRUPT(449) DW_TAG outside allowed range. " + "Corrupt DWARF."}, +{"DW_DLE_FORM_CORRUPT(450) DW_FORM unknown, too large a value. " + "Corrupt DWARF?"}, +{"DW_DLE_ATTR_CORRUPT(451) DW_AT outside allowed range. " + "Corrupt DWARF."}, +{"DW_DLE_ABBREV_ATTR_DUPLICATION(452) Abbreviation list corruption."}, +{"DW_DLE_DWP_SIGNATURE_MISMATCH(453) Impossible signature " + "mismatch. Corrupted Dwarf?"}, +{"DW_DLE_CU_UT_TYPE_VALUE(454) Internal libdwarf data corruption"}, +{"DW_DLE_DUPLICATE_GNU_DEBUGLINK(455) Duplicated section " + ".gnu_debuglink"}, +{"DW_DLE_CORRUPT_GNU_DEBUGLINK(456) Section length wrong"}, +{"DW_DLE_CORRUPT_NOTE_GNU_DEBUGID(457) Data corruption in " + ".note.gnu.debugid section"}, +{"DW_DLE_CORRUPT_GNU_DEBUGID_SIZE(458) Section .note.gnu.debugid " + "size incorrect"}, +{"DW_DLE_CORRUPT_GNU_DEBUGID_STRING(459) Section .note.gnu.debugid " + "owner string not terminated properly"}, +{"DW_DLE_HEX_STRING_ERROR(460). dwarf_producer_init() " + "extras string has a bad hex string"}, +{"DW_DLE_DECIMAL_STRING_ERROR(461) dwarf_producer_init() extras " + "string has a bad decimal string"}, +{"DW_DLE_PRO_INIT_EXTRAS_UNKNOWN(462) dwarf_producer_init() extras " + "string has an unknown string"}, +{"DW_DLE_PRO_INIT_EXTRAS_ERR(463) dwarf_producer_init() extras " + "string has an unexpected space character"}, +{"DW_DLE_NULL_ARGS_DWARF_ADD_PATH(464) obsolete error code"}, +{"DW_DLE_DWARF_INIT_DBG_NULL(465) a dwarf_init*() call " + "the return-dbg argument is null"}, +{"DW_DLE_ELF_RELOC_SECTION_ERROR(466) A relocation section header " + "link field is incorrect."}, +{"DW_DLE_USER_DECLARED_ERROR(467) library user created this."}, +{"DW_DLE_RNGLISTS_ERROR(468) Corrupt dwarf. Bad .debug_rnglists " + "data."}, +{"DW_DLE_LOCLISTS_ERROR(469) Corrupt dwarf. Bad .debug_loclists " + "data."}, +{"DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE(470) corrupt section header."}, +{"DW_DLE_GDBINDEX_STRING_ERROR(471) .gdb_index section string error"}, +{"DW_DLE_GNU_PUBNAMES_ERROR(472) A problem with .debug_gnu_pubnames"}, +{"DW_DLE_GNU_PUBTYPES_ERROR(473) A problem with .debug_gnu_pubtypes"}, +{"DW_DLE_DUPLICATE_GNU_DEBUG_PUBNAMES(474) Duplicated section " + ".debug_gnu_pubnames"}, +{"DW_DLE_DUPLICATE_GNU_DEBUG_PUBTYPES(475) Duplicated section " + ".debug_gnu_pubtypes"}, +{"DW_DLE_DEBUG_SUP_STRING_ERROR(476) String in .debug_sup head " + "runs off the end of the section."}, +{"DW_DLE_DEBUG_SUP_ERROR(477). .debug_sup data corruption"}, +{"DW_DLE_LOCATION_ERROR(478). A location processing libdwarf error"}, +{"DW_DLE_DEBUGLINK_PATH_SHORT(479) Buffer provided for GNU " + "debuglink is too small"}, +{"DW_DLE_SIGNATURE_MISMATCH(480) DWARF4 extension dwo_id and " + "dwarf5signature present but they do not match!"}, +{"DW_DLE_MACRO_VERSION_ERROR(481) Unknown DWARF5 macro version." + " Corrupt data."}, +{"DW_DLE_NEGATIVE_SIZE(482) A size < 0 " + "(from DW_FORM_implicit_const) is not appropriate"}, +{"DW_DLE_UDATA_VALUE_NEGATIVE(483) Reading a negative value from " + "dwarf_formudata() is not allowed."}, +{"DW_DLE_DEBUG_NAMES_ERROR(484) Error reading .debug_names"}, +{"DW_DLE_CFA_INSTRUCTION_ERROR(485) Error accessing " + "frame instructions"}, +{"DW_DLE_MACHO_CORRUPT_HEADER(486) Incorrect header content." + " Corrupt DWARF"}, +{"DW_DLE_MACHO_CORRUPT_COMMAND(487) Incorrect Macho Command " + "data. Corrupt DWARF"}, +{"DW_DLE_MACHO_CORRUPT_SECTIONDETAILS(488) Incorrect Macho " + "section data. Corrupt DWARF"}, +{"DW_DLE_RELOCATION_SECTION_SIZE_ERROR(489) Corrupt Elf. " + "Reloc section size impossible."}, +{"DW_DLE_SYMBOL_SECTION_SIZE_ERROR(490) Corrupt Elf. " + "Symbols section size bad"}, +{"DW_DLE_PE_SECTION_SIZE_ERROR(491) Corrupt PE object. " + "Section size too large."}, +{"DW_DLE_DEBUG_ADDR_ERROR(492) Problem reading .debug_addr"}, +{"DW_DLE_NO_SECT_STRINGS(493) Section strings section " + "number from header " + "is incorrect. Unusable object"}, +{"DW_DLE_TOO_FEW_SECTIONS(494) Sections incomplete, corrupted. " + "Unusable object"}, +{"DW_DLE_BUILD_ID_DESCRIPTION_SIZE(495) .note.gnu.build-id section" + " corrupt. Unusable object"}, +{"DW_DLE_BAD_SECTION_FLAGS(496) Some section flags are incorrect." + " Unusable object"}, +{"DW_DLE_IMPROPER_SECTION_ZERO(497) Section zero header contents " + "incorrect. See Elf ABI. Unsafe object."}, +{"DW_DLE_INVALID_NULL_ARGUMENT(498) Argument must be a valid " + "pointer and non-null"}, +{"DW_DLE_LINE_INDEX_WRONG(499) An index into a line table is " + "not valid. Corrupt data."}, +{"DW_DLE_LINE_COUNT_WRONG(500) A count in a line table is " + "not valid. Corrupt data."}, +{"DW_DLE_ARITHMETIC_OVERFLOW(501) Arithmetic overflow. " + " Corrupt Dwarf." }, +{"DW_DLE_UNIVERSAL_BINARY_ERROR(502) Error reading Mach-O " + "uninversal binary head. Corrupt Mach-O object." }, +{"DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR(503) Offset/size from " + "a Mach-O universal binary has an impossible value"} +}; +#endif /* DWARF_ERRMSG_LIST_H */ diff --git a/src/lib/libdwarf/dwarf_error.c b/src/lib/libdwarf/dwarf_error.c new file mode 100644 index 0000000..c961de6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_error.c @@ -0,0 +1,230 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* stderr fflush() fprintf() */ +#include /* calloc() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_string.h" +#include "dwarf_error.h" + +#undef DEBUG + +/* Array to hold string representation of errors. Any time a + define is added to the list in libdwarf.h, a string should be + added to this Array +*/ +#include "dwarf_errmsg_list.h" + +/* This function performs error handling as described in the + libdwarf consumer document section 3. Dbg is the Dwarf_debug + structure being processed. Error is a pointer to the pointer + to the error descriptor that will be returned. Errval is an + error code listed in dwarf_error.h. + + If the malloc arena is exhausted we return a pointer to + a special static error record. This special singleton + is mostly ignored by dwarf_dealloc(). + Users should not be storing Dwarf_Error pointers + for long so this singleton is only going to cause + confusion when callers try to save an out-of-memory + Dwarf_Error pointer. + If the call provides no way to handle the error + the function simply returns, whereas it used + (before July 2021) to abort in that case. +*/ + +/* The user provides an explanatory string, the error + number itself explains little. + This prepends DW_DLE_USER_DECLARED_ERROR to the + caller-provided string. + New in April, 2020 . Used by dwarfdump in a few + circumstances. */ +void +dwarf_error_creation(Dwarf_Debug dbg, + Dwarf_Error *err, + char *errmsg) +{ + dwarfstring m; + if (!dbg) { + return; + } + dwarfstring_constructor(&m); + dwarfstring_append(&m,"DW_DLE_USER_DECLARED_ERROR: "); + dwarfstring_append(&m,errmsg); + _dwarf_error_string(dbg,err, + DW_DLE_USER_DECLARED_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* In rare cases (bad object files) an error is created + via malloc with no dbg to attach it to. + We record a few of those and dealloc and flush + on any dwarf_finish() + We do not expect this except on corrupt objects. */ + +void +_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, + Dwarf_Signed errval) +{ + _dwarf_error_string(dbg,error,errval,0); +} +void +_dwarf_error_string(Dwarf_Debug dbg, Dwarf_Error * error, + Dwarf_Signed errval,char *msg) +{ + Dwarf_Error errptr = 0; + + /* Allow NULL dbg on entry, since sometimes that + can happen and we want to report the upper-level + error, not the null dbg error. */ + if (error) { + /* If dbg is NULL, use the alternate error struct. However, + this will overwrite the earlier error. */ + if (dbg) { + errptr = + (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1); + if (!errptr) { + errptr = &_dwarf_failsafe_error; + errptr->er_static_alloc = DE_STATIC; + } else { + errptr->er_static_alloc = DE_STANDARD; + } + } else { + /* We have no dbg to work with. dwarf_init + failed. We hack + up a special area. */ + errptr = _dwarf_special_no_dbg_error_malloc(); + if (!errptr) { + errptr = &_dwarf_failsafe_error; + errptr->er_static_alloc = DE_STATIC; +#ifdef DEBUG + printf("libdwarf no dbg, fullystatic, " + "using DE_STATIC alloc, addr" + " 0x%lx line %d %s\n", + (unsigned long)errptr, + __LINE__,__FILE__); +#endif /* DEBUG */ + } else { + errptr->er_static_alloc = DE_MALLOC; + +#ifdef DEBUG + printf("libdwarf no dbg,leaks, " + "static DE_MALLOC alloc, addr" + " 0x%lx line %d %s\n", + (unsigned long)errptr, + __LINE__,__FILE__); +#endif /* DEBUG */ + _dwarf_add_to_static_err_list(errptr); + } + } + + errptr->er_errval = errval; + if (msg && errptr->er_static_alloc != DE_STATIC) { + dwarfstring *em = 0; + +#ifdef DEBUG + printf("libdwarf ALLOC creating error string" + " %s errval %ld errptr 0x%lx \n", + msg,(long)errval,(unsigned long)errptr); +#endif /* DEBUG */ + em = (dwarfstring *)calloc(1,sizeof(dwarfstring)); + if (em) { + dwarfstring_constructor(em); + dwarfstring_append(em,msg); + errptr->er_msg = (void*)em; + } + } + *error = errptr; + return; + } + + if (dbg && dbg->de_errhand != NULL) { + errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1); + if (errptr == NULL) { + errptr = &_dwarf_failsafe_error; + errptr->er_static_alloc = DE_STATIC; + } + errptr->er_errval = errval; + dbg->de_errhand(errptr, dbg->de_errarg); + return; + } + fflush(stderr); + fprintf(stderr, + "\nlibdwarf is unable to record error %s " + "No error argument or handler available\n", + dwarf_errmsg_by_number(errval)); + fflush(stderr); + return; +} + +Dwarf_Unsigned +dwarf_errno(Dwarf_Error error) +{ + if (!error) { + return (0); + } + return (error->er_errval); +} + +char* +dwarf_errmsg_by_number(Dwarf_Unsigned errornum ) +{ + if (errornum > DW_DLE_LAST) { + return "Dwarf_Error value out of range"; + } + return ((char *) &_dwarf_errmsgs[errornum][0]); +} + +/* +*/ +char * +dwarf_errmsg(Dwarf_Error error) +{ + if (!error) { + return "Dwarf_Error is NULL"; + } + if (error->er_msg) { + return dwarfstring_string(error->er_msg); + } + return dwarf_errmsg_by_number(error->er_errval); +} diff --git a/src/lib/libdwarf/dwarf_error.h b/src/lib/libdwarf/dwarf_error.h new file mode 100644 index 0000000..6855e98 --- /dev/null +++ b/src/lib/libdwarf/dwarf_error.h @@ -0,0 +1,71 @@ +/* + +Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2011-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#ifndef DWARF_ERROR_H +#define DWARF_ERROR_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void _dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, + Dwarf_Signed errval); +void _dwarf_error_string(Dwarf_Debug dbg, Dwarf_Error * error, + Dwarf_Signed errval, char *msg); + +#define DWARF_DBG_ERROR(dbg,errval,retval) \ + _dwarf_error((dbg), error, (errval)); return(retval); + +#define DE_STANDARD 0 /* Normal alloc attached to dbg. */ +#define DE_STATIC 1 /* Using global static var */ +#define DE_MALLOC 2 /* Using malloc space */ +struct Dwarf_Error_s { + Dwarf_Signed er_errval; + void * er_msg; + + /* If non-zero the Dwarf_Error_s struct is not malloc'd. + To aid when malloc returns NULL. + If zero a normal dwarf_dealloc will work. + er_static_alloc only accessed by dwarf_alloc.c. + + If er_static_alloc is 1 in a Dwarf_Error_s + struct (set by libdwarf) and client code accidentally + turns that 0 to zero through a wild + pointer reference (the field is hidden + from clients...) then chaos will + eventually follow. + */ + int er_static_alloc; +}; +extern struct Dwarf_Error_s _dwarf_failsafe_error; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_ERROR_H */ diff --git a/src/lib/libdwarf/dwarf_fill_in_attr_form.c b/src/lib/libdwarf/dwarf_fill_in_attr_form.c new file mode 100644 index 0000000..c6b3a2a --- /dev/null +++ b/src/lib/libdwarf/dwarf_fill_in_attr_form.c @@ -0,0 +1,195 @@ +/* +Copyright (C) 2022 David Anderson. All Rights Reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include "config.h" +#include /* NULL size_t */ +#include /* calloc() free() malloc() */ +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_die_deliv.h" +#include "dwarf_abbrev.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" + +/* + This is a pre-scan of the abbrev/form list. + We will not handle DW_FORM_indirect here as that + accesses data outside of the abbrev section. +*/ +int +_dwarf_fill_in_attr_form_abtable(Dwarf_CU_Context context, + Dwarf_Byte_Ptr abbrev_ptr, + Dwarf_Byte_Ptr abbrev_end, + Dwarf_Abbrev_List abbrev_list, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned i = 0; + + dbg = context->cc_dbg; + abbrev_list->abl_attr = (Dwarf_Half*) + calloc(abbrev_list->abl_abbrev_count, + SIZEOFT16); + abbrev_list->abl_form = (Dwarf_Half *) + calloc(abbrev_list->abl_abbrev_count, + SIZEOFT16); + if (abbrev_list->abl_implicit_const_count > 0) { + abbrev_list->abl_implicit_const = (Dwarf_Signed *) + calloc(abbrev_list->abl_abbrev_count, + sizeof(Dwarf_Signed)); + if (!abbrev_list->abl_implicit_const) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ALLOC_FAIL :" + " Attempt to malloc space for " + "abbrev_list->abl_implicit_const " + "with %u entries failed.", + abbrev_list->abl_abbrev_count); + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + if (!abbrev_list->abl_attr || !abbrev_list->abl_form ) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ALLOC_FAIL :" + " Attempt to malloc space for " + "abbrev_list->abl_attr or abl_form " + "with %u entries failed.", + abbrev_list->abl_abbrev_count); + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + for (i = 0; i < abbrev_list->abl_abbrev_count; ++i) { + Dwarf_Unsigned attr = 0; + Dwarf_Unsigned attr_form = 0; + Dwarf_Signed implicit_const = 0; + int res = 0; + + res = _dwarf_leb128_uword_wrapper(dbg, + &abbrev_ptr,abbrev_end,&attr,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (attr > 0xffff) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_ATTR_FORM_SIZE_BAD :" + " reading Attribute number "); + dwarfstring_append(&m," for abbrev list entry" + " the ULEB number is too large. Corrupt Dwarf."); + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_SIZE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + abbrev_list->abl_attr[i] = (Dwarf_Half)attr; + if (attr > DW_AT_hi_user) { + _dwarf_error(dbg, error,DW_DLE_ATTR_CORRUPT); + return DW_DLV_ERROR; + } + res = _dwarf_leb128_uword_wrapper(dbg, + &abbrev_ptr,abbrev_end,&attr_form,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (attr_form > 0xffff) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_ATTR_FORM_SIZE_BAD :" + " reading attr_form"); + dwarfstring_append(&m,"an abbrev list entry " + "the ULEB form number is too large. " + "to be valid. Corrupt Dwarf."); + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_SIZE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (!_dwarf_valid_form_we_know(attr_form,attr)) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m,"Reading an abbreviation list " + " we find the attribute form pair to be " + " impossible or unknown."); + dwarfstring_append_printf_u(&m," attr 0x%x ",attr); + dwarfstring_append_printf_u(&m," attrform 0x%x ", + attr_form); + _dwarf_error_string(dbg, error, DW_DLE_UNKNOWN_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + abbrev_list->abl_attr[i] = (Dwarf_Half)attr; + abbrev_list->abl_form[i] = (Dwarf_Half)attr_form; + if (attr_form == DW_FORM_implicit_const) { + res = _dwarf_leb128_sword_wrapper(dbg, + &abbrev_ptr,abbrev_end,&implicit_const,error); + if (res == DW_DLV_ERROR) { + return res; + } + abbrev_list->abl_implicit_const_count++; + abbrev_list->abl_implicit_const[i] = implicit_const; + } +#if 0 + if (attr_form == DW_FORM_indirect) { + /* Do nothing special here. Do not read + from the DIE till reading for + a specific DIE, which we are not + intending here, we do not know + where the DIE is. */ + } +#endif + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_find_sigref.c b/src/lib/libdwarf/dwarf_find_sigref.c new file mode 100644 index 0000000..45e5739 --- /dev/null +++ b/src/lib/libdwarf/dwarf_find_sigref.c @@ -0,0 +1,222 @@ +/* +Copyright (C) 2021 David Anderson. All Rights Reserved. + +This program is free software; you can redistribute it +and/or modify it under the terms of version 2.1 of the +GNU Lesser General Public License as published by the Free +Software Foundation. + +This program is distributed in the hope that it would be +useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. + +Further, this software is distributed without any warranty +that it is free of the rightful claim of any third person +regarding infringement or the like. Any license provided +herein, whether implied or otherwise, applies only to this +software file. Patent licenses, if any, provided herein +do not apply to combinations of this program with other +software, or any other product whatsoever. + +You should have received a copy of the GNU Lesser General +Public License along with this program; if not, write the +Free Software Foundation, Inc., 51 Franklin Street - Fifth +Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* memcmp() */ +#include /* printf() debugging */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#if 0 +static void +dump_bytes(const char *msg,int line, + Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) line %d\n ",msg,(unsigned long)start,line); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ + +static int +_dwarf_find_CU_Context_given_sig(Dwarf_Debug dbg, + int context_level, + Dwarf_Sig8 *sig_in, + Dwarf_CU_Context *cu_context_out, + Dwarf_Bool *is_info_out, + Dwarf_Error *error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Bool is_info = FALSE; + int loopcount = 0; + int lres = 0; + Dwarf_Debug_InfoTypes dis = 0; + struct Dwarf_Section_s *secdp = 0; + + /* Loop once with is_info, once with !is_info. + Then stop. */ + for ( ; loopcount < 2; ++loopcount) { + Dwarf_CU_Context prev_cu_context = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Unsigned new_cu_offset = 0; + + is_info = !is_info; + + if (is_info) { + dis = &dbg->de_info_reading; + secdp = &dbg->de_debug_info; + } else { + dis = &dbg->de_types_reading; + secdp = &dbg->de_debug_types; + } + lres = _dwarf_load_die_containing_section(dbg,is_info,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY ) { + continue; + } + /* Lets see if we already have the CU we need. */ + for (cu_context = dis->de_cu_context_list; + cu_context; cu_context = cu_context->cc_next) { + prev_cu_context = cu_context; + + if (memcmp(sig_in,&cu_context->cc_signature, + sizeof(Dwarf_Sig8))) { + continue; + } + if (cu_context->cc_unit_type == DW_UT_split_type|| + cu_context->cc_unit_type == DW_UT_type) { + *cu_context_out = cu_context; + *is_info_out = cu_context->cc_is_info; + return DW_DLV_OK; + } + } + if (context_level > 0) { + /* Make no attempt to create new context, + we are finishing cu die base fields + on one already. + Just look for the other context, + DWARF4 debug_types */ + continue; + } + if (prev_cu_context) { + Dwarf_CU_Context lcu_context = prev_cu_context; + new_cu_offset = + _dwarf_calculate_next_cu_context_offset( + lcu_context); + } else { + new_cu_offset = 0; + } + section_size = secdp->dss_size; + for ( ; new_cu_offset < section_size; + new_cu_offset = + _dwarf_calculate_next_cu_context_offset( + cu_context)) { +#if 0 + lres = _dwarf_load_die_containing_section(dbg, + is_info,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + continue; + } +#endif /*0*/ + lres = _dwarf_create_a_new_cu_context_record_on_list( + dbg, dis,is_info,section_size,new_cu_offset, + &cu_context,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + break; + } + if (memcmp(sig_in,&cu_context->cc_signature, + sizeof(Dwarf_Sig8))) { + continue; + } + if (cu_context->cc_unit_type == DW_UT_split_type|| + cu_context->cc_unit_type == DW_UT_type) { + *cu_context_out = cu_context; + *is_info_out = cu_context->cc_is_info; + return DW_DLV_OK; + } + } + } /* Loop-end. */ + /* Not found */ + return DW_DLV_NO_ENTRY; +} + +/* We will search to find a CU with the indicated signature + The attribute leading us here is often + We are looking for a DW_UT_split_type or DW_UT_type + CU. + DW_AT_type and if DWARF4 that means our first look is + to !is_info */ +int +dwarf_find_die_given_sig8(Dwarf_Debug dbg, + Dwarf_Sig8 *ref, + Dwarf_Die *die_out, + Dwarf_Bool *is_info, + Dwarf_Error *error) +{ + int res = 0; + res = _dwarf_internal_find_die_given_sig8( + dbg,0,ref,die_out,is_info,error); + return res; +} + +/* If context level > 0 restrict what we will do + to avoid recursion creating CU Contexts */ +int +_dwarf_internal_find_die_given_sig8(Dwarf_Debug dbg, + int context_level, + Dwarf_Sig8 *ref, + Dwarf_Die *die_out, + Dwarf_Bool *is_info, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Die ndi = 0; + Dwarf_CU_Context context = 0; + Dwarf_Bool result_is_info = FALSE; + Dwarf_Unsigned dieoffset = 0; + + res =_dwarf_find_CU_Context_given_sig(dbg, + context_level, + ref, &context, &result_is_info,error); + if (res != DW_DLV_OK) { + return res; + } + dieoffset = context->cc_debug_offset + + context->cc_signature_offset; + res = dwarf_offdie_b(dbg,dieoffset,result_is_info, + &ndi,error); + if (res == DW_DLV_OK) { + *die_out = ndi; + *is_info = result_is_info; + } + return res; +} diff --git a/src/lib/libdwarf/dwarf_fission_to_cu.c b/src/lib/libdwarf/dwarf_fission_to_cu.c new file mode 100644 index 0000000..9404ad2 --- /dev/null +++ b/src/lib/libdwarf/dwarf_fission_to_cu.c @@ -0,0 +1,367 @@ +/* + Copyright (C) 2018-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the + Free Software Foundation. + + This program is distributed in the hope that it would + be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to + this software file. Patent licenses, if any, provided + herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. +*/ + +#include + +#include /* memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_str_offsets.h" +#include "dwarf_loc.h" +#include "dwarf_rnglists.h" + +/* ASSERT: dbg,cu_context, and fsd are non-NULL + as the caller ensured that. */ +const struct Dwarf_Loclists_Context_s localcontxt_zero; +static int +load_xu_loclists_into_cucontext(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + struct Dwarf_Debug_Fission_Per_CU_s*fsd, + int fsd_index, + Dwarf_Error *error) +{ + Dwarf_Unsigned size = 0; + Dwarf_Unsigned soff_hdroffset = 0; + Dwarf_Unsigned soff_size = 0; + struct Dwarf_Loclists_Context_s localcontxt; + Dwarf_Loclists_Context buildhere = &localcontxt; + Dwarf_Unsigned nextset = 0; + int res = 0; + + if (!fsd) { + _dwarf_error_string(dbg, error, DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: a required argument to" + "load_xu_loclists_into_cucontext() is NULL"); + return DW_DLV_ERROR; + } + localcontxt = localcontxt_zero; + size = fsd->pcu_size[fsd_index]; + soff_hdroffset = fsd->pcu_offset[fsd_index]; + soff_size = dbg->de_debug_loclists.dss_size; + if (!soff_size) { + return DW_DLV_NO_ENTRY; + } + if (soff_hdroffset >= soff_size) { + /* Something is badly wrong. Ignore it here. */ + return DW_DLV_NO_ENTRY; + } + memset(buildhere,0,sizeof(localcontxt)); + res = _dwarf_internal_read_loclists_header(dbg, + 0,soff_size, + dbg->de_debug_loclists.dss_data, + dbg->de_debug_loclists.dss_data +soff_size, + soff_hdroffset, + buildhere, + &nextset,error); + if (res != DW_DLV_OK) { + return res; + } + cu_context->cc_loclists_base_present = TRUE; + cu_context->cc_loclists_base_contr_size = size; + cu_context->cc_loclists_base = + buildhere->lc_offsets_off_in_sect; + return DW_DLV_OK; +} + +/* + + ASSERT: dbg,cu_context, and fsd are non-NULL + as the caller ensured that. + If .debug_cu_index or + .debug_tu_index is present it might help us find + the offset for this CU's .debug_str_offsets. +*/ +static int +load_xu_str_offsets_into_cucontext(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + struct Dwarf_Debug_Fission_Per_CU_s*fsd, + int fsd_index, + Dwarf_Error *error ) +{ + Dwarf_Small *soff_secptr = 0; + Dwarf_Unsigned soff_hdroffset = 0; + Dwarf_Unsigned soff_size = 0; + Dwarf_Small *soff_eptr = 0; + int res = 0; + + res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets, + error); + if (res != DW_DLV_OK) { + return res; + } + soff_hdroffset = fsd->pcu_offset[fsd_index]; + soff_secptr = dbg->de_debug_str_offsets.dss_data; + soff_size = dbg->de_debug_str_offsets.dss_size; + if (soff_hdroffset >= soff_size) { + /* Something is badly wrong. Ignore it here. */ + return DW_DLV_NO_ENTRY; + } + + { + Dwarf_Unsigned length = 0; + Dwarf_Half offset_size = 0; + Dwarf_Half extension_size = 0; + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + Dwarf_Unsigned local_offset_to_array=0; + Dwarf_Unsigned total_table_length =0; + struct Dwarf_Str_Offsets_Table_s sotstr; + + memset(&sotstr,0,sizeof(sotstr)); + sotstr.so_dbg = dbg; + sotstr.so_section_start_ptr = soff_secptr; + sotstr.so_section_end_ptr = soff_eptr; + sotstr.so_section_size = soff_size; + sotstr.so_next_table_offset = soff_hdroffset; + res = _dwarf_read_str_offsets_header(&sotstr, + cu_context, + &length,&offset_size, + &extension_size,&version,&padding, + &local_offset_to_array, + &total_table_length, + error); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + return DW_DLV_NO_ENTRY; + } + /* See dwarf_opaque.h for comments. */ + cu_context->cc_str_offsets_tab_present = TRUE; + cu_context->cc_str_offsets_header_offset = soff_hdroffset; + cu_context->cc_str_offsets_tab_to_array = + local_offset_to_array; + cu_context->cc_str_offsets_table_size = total_table_length; + cu_context->cc_str_offsets_version = version; + cu_context->cc_str_offsets_offset_size = offset_size; + } + return DW_DLV_OK; +} + +/* ASSERT: dbg,cu_context, and fsd are non-NULL + as the caller ensured that. */ +static int +load_xu_debug_macro_into_cucontext(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + struct Dwarf_Debug_Fission_Per_CU_s*fsd, + int fsd_index, + Dwarf_Error *error ) +{ + Dwarf_Unsigned size = 0; + Dwarf_Unsigned soff_hdroffset = 0; + Dwarf_Unsigned soff_size = 0; + int res = 0; + + res = _dwarf_load_section(dbg, &dbg->de_debug_macro, + error); + if (res != DW_DLV_OK) { + return res; + } + size = fsd->pcu_size[fsd_index]; + soff_hdroffset = fsd->pcu_offset[fsd_index]; + soff_size = dbg->de_debug_macro.dss_size; + if (!soff_size) { + return DW_DLV_NO_ENTRY; + } + if (soff_hdroffset >= soff_size) { + /* Something is badly wrong. Ignore it here. */ + return DW_DLV_NO_ENTRY; + } + /* Presently assuming that DW_AT_macros + and the fission entry both + indicate the beginning + of a .debug_macro sectiom macro header. + (not true for str_offsets or for loclists!) + */ + cu_context->cc_macro_base_present = TRUE; + cu_context->cc_macro_base_contr_size = size; + cu_context->cc_macro_base = soff_hdroffset; + /* FIXME cc_macro_header_length_present? */ + return DW_DLV_OK; +} + +/* ASSERT: dbg,cu_context, and fsd are non-NULL + as the caller ensured that. */ +const struct Dwarf_Rnglists_Context_s builddata_zero; +static int +load_xu_rnglists_into_cucontext(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + struct Dwarf_Debug_Fission_Per_CU_s*fsd, + int fsd_index, + Dwarf_Error *error ) +{ + Dwarf_Unsigned size = 0; + Dwarf_Unsigned soff_hdroffset = 0; + Dwarf_Unsigned soff_size = 0; + struct Dwarf_Rnglists_Context_s builddata; + Dwarf_Rnglists_Context buildhere = &builddata; + Dwarf_Unsigned nextoffset = 0; + int res = 0; + + builddata = builddata_zero; + res = _dwarf_load_section(dbg, &dbg->de_debug_rnglists, + error); + if (res != DW_DLV_OK) { + return res; + } + size = fsd->pcu_size[fsd_index]; + soff_hdroffset = fsd->pcu_offset[fsd_index]; + soff_size = dbg->de_debug_rnglists.dss_size; + if (!soff_size) { + return DW_DLV_NO_ENTRY; + } + if (soff_hdroffset >= soff_size) { + /* Something is badly wrong. Ignore it here. */ + return DW_DLV_NO_ENTRY; + } + memset(buildhere,0,sizeof(builddata)); + res = _dwarf_internal_read_rnglists_header(dbg, + 0,soff_size, + dbg->de_debug_rnglists.dss_data, + dbg->de_debug_rnglists.dss_data+soff_size, + soff_hdroffset,buildhere, + &nextoffset,error); + if (res != DW_DLV_OK) { + return res; + } + cu_context->cc_rnglists_base = + buildhere->rc_offsets_off_in_sect; + cu_context->cc_rnglists_base_present = TRUE; + cu_context->cc_rnglists_base_contr_size = size; + /* FIXME cc_rnglists_header_length_present? */ + return DW_DLV_OK; +} + +static const char *keylist[2] = { +"cu", +"tu" +}; +/* ASSERT: The context has a signature. + + ASSERT: dbg and cu_context are non-NULL + as the caller tested them. + + _dwarf_make_CU_Context() calls + finish_up_cu_context_from_cudie() which calls + us here. + Then, _dwarf_make_CU_Context() calls + _dwarf_merge_all_base_attrs_of_cu_die() if there + is a tied (executable) object known. + + Called by dwarf_die_deliv.c +*/ +const struct Dwarf_Debug_Fission_Per_CU_s fission_data_zero; +int +_dwarf_find_all_offsets_via_fission(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Error *error) +{ + struct Dwarf_Debug_Fission_Per_CU_s fission_data; + struct Dwarf_Debug_Fission_Per_CU_s*fsd = 0; + int si = 0; + int smax = 2; + int fdres = 0; + int res = 0; + + fission_data = fission_data_zero; + fsd = &fission_data; + for (si = 0; si < smax ; ++si) { + int sec_index = 0; + + memset(&fission_data,0,sizeof(fission_data)); + fdres = dwarf_get_debugfission_for_key(dbg, + &cu_context->cc_signature, + keylist[si], + fsd,error); + if (fdres == DW_DLV_NO_ENTRY) { + continue; + } + if (fdres == DW_DLV_ERROR) { + if (error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + continue; + } + for (sec_index = 1; sec_index < DW_FISSION_SECT_COUNT; + ++sec_index) { + if (!fsd->pcu_size[sec_index]) { + continue; + } + res = DW_DLV_OK; + switch(sec_index) { + /* these handled elsewhere, such + as by _dwarf_get_dwp_extra_offset() + _dwarf_get_fission_addition_die() + case DW_SECT_INFO: + case DW_SECT_ABBREV: + case DW_SECT_LINE: + */ + case DW_SECT_LOCLISTS: + res = load_xu_loclists_into_cucontext(dbg, + cu_context, + fsd,sec_index,error); + break; + case DW_SECT_STR_OFFSETS: + res = load_xu_str_offsets_into_cucontext(dbg, + cu_context, + fsd,sec_index,error); + break; + case DW_SECT_MACRO: + res = load_xu_debug_macro_into_cucontext(dbg, + cu_context, + fsd,sec_index,error); + break; + case DW_SECT_RNGLISTS: + res = load_xu_rnglists_into_cucontext(dbg, + cu_context, + fsd,sec_index,error); + break; + default: + res = DW_DLV_OK; + break; + } + if (res == DW_DLV_ERROR) { + return res; + } + } + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_form.c b/src/lib/libdwarf/dwarf_form.c new file mode 100644 index 0000000..6093147 --- /dev/null +++ b/src/lib/libdwarf/dwarf_form.c @@ -0,0 +1,2263 @@ +/* + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2021 David Anderson. All rights reserved. + Portions Copyright 2010-2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* memcpy() memset() */ +#include /* printf() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_string.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_die_deliv.h" +#include "dwarf_str_offsets.h" +#include "dwarf_string.h" +#if 0 +static void +dump_bytes(const char *msg,int line, + Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) line %d\n ",msg,(unsigned long)start,line); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* It is necessary at times to cause errors of this sort + in determining what we really have. So best to avoid + too much malloc and free, hence the static constructor + dwarfstring will use malloc if we guess too-small + for the size of mbuf. */ +static void +generate_form_error(Dwarf_Debug dbg, + Dwarf_Error *error, + unsigned form, + int err_code, + const char *errname, + const char *funcname) +{ + dwarfstring m; /* constructor_static ok */ + char mbuf[DWARFSTRING_ALLOC_SIZE]; + const char * defaultname = ""; + + dwarfstring_constructor_static(&m,mbuf, + sizeof(mbuf)); + dwarfstring_append(&m,(char *)errname); + dwarfstring_append(&m,": In function "); + dwarfstring_append(&m,(char *)funcname); + dwarfstring_append_printf_u(&m, + " on seeing form 0x%x ",form); + dwarf_get_FORM_name(form,&defaultname); + dwarfstring_append_printf_s(&m, + " (%s)",(char *)defaultname); + _dwarf_error_string(dbg,error,err_code, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* This code was repeated many times, now it + is all in one place. + Never returns DW_DLV_NO_ENTRY */ +static int +get_attr_dbg(Dwarf_Debug *dbg_out, + Dwarf_CU_Context * cu_context_out, + Dwarf_Attribute attr, + Dwarf_Error *error) +{ + Dwarf_CU_Context cup = 0; + Dwarf_Debug dbg = 0; + + if (!attr) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return DW_DLV_ERROR; + } + cup = attr->ar_cu_context; + if (!cup) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + dbg = cup->cc_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, + "DW_DLE_ATTR_DBG_NULL: Stale or null Dwarf_Debug" + "in a Dwarf_CU_Context" ); + return DW_DLV_ERROR; + } + if (dbg != attr->ar_dbg) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, + "DW_DLE_ATTR_DBG_NULL: an attribute and its " + "cu_context do not have the same Dwarf_Debug" ); + return DW_DLV_ERROR; + } + *cu_context_out = cup; + *dbg_out = dbg; + return DW_DLV_OK; + +} + +/* This checks the final-form (after any DW_FORM_indirect + converted to final form). */ +int +dwarf_hasform(Dwarf_Attribute attr, + Dwarf_Half dw_form, + Dwarf_Bool * dw_return_bool, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + int res = 0; + + res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dw_return_bool) { + _dwarf_error_string(dbg,error, + DW_DLE_INVALID_NULL_ARGUMENT, + " DW_DLE_INVALID_NULL_ARGUMENT " + "calling dwarf_hasform: " + "dw_return_bool must be passed" + " as a non-NULL valid pointer"); + return DW_DLV_ERROR; + } + *dw_return_bool = (attr->ar_attribute_form == dw_form); + return DW_DLV_OK; +} + +/* Not often called, we do not worry about efficiency here. + The dwarf_whatform() call does the sanity checks for us. + The form returned is the original form, which could + be DW_FORM_indirect. +*/ +int +dwarf_whatform_direct(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + int res = dwarf_whatform(attr, return_form, error); + + if (res != DW_DLV_OK) { + return res; + } + + *return_form = attr->ar_attribute_form_direct; + return DW_DLV_OK; +} + +/* This code was contributed around 2007. + As of 2021 it is not clear that Sun Sparc + compilers are in current use, nor whether + there is a reason to make reads of + this data format safe from corrupted object files. + + Pass in the content of a block and the length of that + content. On success return DW_DLV_OK and set *value_count + to the size of the array returned through value_array. */ +int +dwarf_uncompress_integer_block_a(Dwarf_Debug dbg, + Dwarf_Unsigned input_length_in_bytes, + void * input_block, + Dwarf_Unsigned * value_count, + Dwarf_Signed ** value_array, + Dwarf_Error * error) +{ + Dwarf_Unsigned output_length_in_units = 0; + Dwarf_Signed *output_block = 0; + unsigned i = 0; + char *ptr = 0; + Dwarf_Signed remain = 0; + Dwarf_Signed *array = 0; + Dwarf_Byte_Ptr endptr = (Dwarf_Byte_Ptr)input_block+ + input_length_in_bytes; + + output_length_in_units = 0; + remain = (Dwarf_Signed)input_length_in_bytes; + ptr = input_block; + while (remain > 0) { + Dwarf_Unsigned len = 0; + Dwarf_Signed value = 0; + int rres = 0; + + rres = dwarf_decode_signed_leb128((char *)ptr, + &len, &value,(char *)endptr); + if (rres != DW_DLV_OK) { + _dwarf_error(NULL, error, DW_DLE_LEB_IMPROPER); + return DW_DLV_ERROR; + } + ptr += len; + remain -= (Dwarf_Signed)len; + output_length_in_units++; + } + if (remain != 0) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + output_block = (Dwarf_Signed*) + _dwarf_get_alloc(dbg, + DW_DLA_STRING, + output_length_in_units * sizeof(Dwarf_Signed)); + if (!output_block) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + array = output_block; + remain = input_length_in_bytes; + ptr = input_block; + for (i=0; i0; i++) { + Dwarf_Signed num; + Dwarf_Unsigned len; + int sres = 0; + + sres = dwarf_decode_signed_leb128((char *)ptr, + &len, &num,(char *)endptr); + if (sres != DW_DLV_OK) { + dwarf_dealloc(dbg,output_block,DW_DLA_STRING); + _dwarf_error(NULL, error, DW_DLE_LEB_IMPROPER); + return DW_DLV_ERROR; + } + ptr += len; + remain -= (Dwarf_Signed)len; + array[i] = num; + } + + if (remain != 0) { + dwarf_dealloc(dbg, (unsigned char *)output_block, + DW_DLA_STRING); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + *value_count = output_length_in_units; + *value_array = output_block; + return DW_DLV_OK; +} + +/* This code was contributed around 2007 + and the return value is in the wrong form. + See dwarf_uncompress_integer_block_a() above. + + As of 2019 it is not clear that Sun Sparc + compilers are in current use, nor whether + there is a reason to make reads of + this data format safe from corrupted object files. +*/ + +void +dwarf_dealloc_uncompressed_block(Dwarf_Debug dbg, void * space) +{ + dwarf_dealloc(dbg, space, DW_DLA_STRING); +} + +/* Never returns DW_DLV_NO_ENTRY + Returns the final form after any DW_FORM_indirect + resolved to final form. */ +int +dwarf_whatform(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_form = attr->ar_attribute_form; + return DW_DLV_OK; +} + +/* + This function is analogous to dwarf_whatform. + It returns the attribute in attr instead of + the form. +*/ +int +dwarf_whatattr(Dwarf_Attribute attr, + Dwarf_Half * return_attr, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_attr = (attr->ar_attribute); + return DW_DLV_OK; +} + +/* Convert an offset within the local CU into a section-relative + debug_info (or debug_types) offset. + See dwarf_global_formref() and dwarf_formref() + for additional information on conversion rules. +*/ +int +dwarf_convert_to_global_offset(Dwarf_Attribute attr, + Dwarf_Off offset, + Dwarf_Off * ret_offset, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + int res = 0; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + /* It is a cu-local offset. Convert to section-global. */ + /* It would be nice to put some code to check + legality of the offset */ + /* cc_debug_offset always has any DWP Package File + offset included (when the cu_context created) + so there is no extra work for DWP. + Globalize the offset */ + offset += cu_context->cc_debug_offset; + + break; + + case DW_FORM_ref_addr: + /* This offset is defined to be debug_info global already, so + use this value unaltered. + + Since a DWP package file is not relocated there + is no way that this reference offset to an address in + any other CU can be correct for a DWP Package File offset + */ + break; + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_BAD_REF_FORM. The form " + "code is 0x%x which cannot be converted to a global " + " offset by " + "dwarf_convert_to_global_offset()", + attr->ar_attribute_form); + _dwarf_error_string(dbg, error, DW_DLE_BAD_REF_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + + *ret_offset = (offset); + return DW_DLV_OK; +} + +/* A global offset cannot be returned by this interface: + see dwarf_global_formref(). + + DW_FORM_ref_addr is considered an incorrect form + for this call because DW_FORM_ref_addr is a global-offset into + the debug_info section. + + For the same reason DW_FORM_data4/data8 are not returned + from this function. + + For the same reason DW_FORM_sec_offset is not returned + from this function, DW_FORM_sec_offset is a global offset + (to various sections, not a CU relative offset. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + The dwarfstd.org FAQ "How big is a DW_FORM_ref_addr?" + suggested all should use offset-size, but that suggestion + seems to have been ignored in favor of doing what the + DWARF2 and 3 standards actually say. + + November, 2010: *ret_offset is always set now. + Even in case of error. + Set to zero for most errors, but for + DW_DLE_ATTR_FORM_OFFSET_BAD + *ret_offset is set to the bad offset. + + DW_FORM_addrx + DW_FORM_strx + DW_FORM_LLVM_addrx_offset + DW_FORM_rnglistx + DW_FORM_GNU_addr_index + DW_FORM_GNU_str_index + are not references to .debug_info/.debug_types, + so they are not allowed here. */ + +int +dwarf_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, + Dwarf_Bool * ret_is_info, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned maximumoffset = 0; + int res = DW_DLV_ERROR; + Dwarf_Byte_Ptr section_end = 0; + Dwarf_Bool is_info = TRUE; + + *ret_offset = 0; + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + is_info = cu_context->cc_is_info; + + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + break; + + case DW_FORM_ref2: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_HALF_SIZE, + error,section_end); + break; + + case DW_FORM_ref4: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error,section_end); + break; + + case DW_FORM_ref8: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_64BIT_SIZE, + error,section_end); + break; + + case DW_FORM_ref_udata: { + Dwarf_Byte_Ptr ptr = attr->ar_debug_ptr; + Dwarf_Unsigned localoffset = 0; + + DECODE_LEB128_UWORD_CK(ptr,localoffset, + dbg,error,section_end); + offset = localoffset; + break; + } + case DW_FORM_ref_sig8: { + /* We need to look for a local reference here. + The function we are in is only CU_local + offsets returned. */ +#if 0 + Dwarf_Sig8 sig8; + memcpy(&sig8,ptr,sizeof(Dwarf_Sig8)); + res = dwarf_find_die_given_sig8(dbg, + &sig8, ... + We could look, then determine if + resulting offset is actually local. +#endif /*0*/ + + /* We cannot handle this here. + The reference could be to .debug_types + or another CU! + not a .debug_info CU local offset. */ + _dwarf_error(dbg, error, DW_DLE_REF_SIG8_NOT_HANDLED); + return DW_DLV_ERROR; + } + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_BAD_REF_FORM. The form " + "code is 0x%x which does not have an offset " + " for " + "dwarf_formref() to return.", + attr->ar_attribute_form); + _dwarf_error_string(dbg, error, DW_DLE_BAD_REF_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + + /* Check that offset is within current + cu portion of .debug_info. */ + + maximumoffset = cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size; + if (offset >= maximumoffset) { + /* For the DW_TAG_compile_unit is legal to have the + DW_AT_sibling attribute outside the current cu portion of + .debug_info. + In other words, sibling points to the end of the CU. + It is used for precompiled headers. + The valid condition will be: 'offset == maximumoffset'. */ + Dwarf_Half tag = 0; + int tres = dwarf_tag(attr->ar_die,&tag,error); + if (tres != DW_DLV_OK) { + if (tres == DW_DLV_NO_ENTRY) { + _dwarf_error(dbg, error, DW_DLE_NO_TAG_FOR_DIE); + return DW_DLV_ERROR; + } + return DW_DLV_ERROR; + } + + if (DW_TAG_compile_unit != tag && + DW_AT_sibling != attr->ar_attribute && + offset > maximumoffset) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + /* Return the incorrect offset for better + error reporting */ + *ret_offset = (offset); + return DW_DLV_ERROR; + } + } + *ret_is_info = is_info; + *ret_offset = (offset); + return DW_DLV_OK; +} + +static int +_dwarf_formsig8_internal(Dwarf_Attribute attr, + int formexpected, + Dwarf_Sig8 * returned_sig_bytes, + Dwarf_Error* error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Byte_Ptr field_end = 0; + Dwarf_Byte_Ptr section_end = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + + if (attr->ar_attribute_form != formexpected) { + return DW_DLV_NO_ENTRY; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + field_end = attr->ar_debug_ptr + sizeof(Dwarf_Sig8); + if (field_end > section_end) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return DW_DLV_ERROR; + } + + memcpy(returned_sig_bytes, attr->ar_debug_ptr, + sizeof(*returned_sig_bytes)); + return DW_DLV_OK; +} + +int +dwarf_formsig8_const(Dwarf_Attribute attr, + Dwarf_Sig8 * returned_sig_bytes, + Dwarf_Error* error) +{ + int res =_dwarf_formsig8_internal(attr, DW_FORM_data8, + returned_sig_bytes,error); + return res; +} + +/* dwarf_formsig8 returns in the caller-provided 8 byte area + the 8 bytes of a DW_FORM_ref_sig8 (copying the bytes + directly to the caller). Not a string, an 8 byte + MD5 hash or a signature. + This function is new in DWARF4 libdwarf and used in + more places in DWARF5. +*/ +int +dwarf_formsig8(Dwarf_Attribute attr, + Dwarf_Sig8 * returned_sig_bytes, + Dwarf_Error* error) +{ + int res = _dwarf_formsig8_internal(attr, DW_FORM_ref_sig8, + returned_sig_bytes,error); + return res; +} + +/* This finds a target via a sig8 and if + DWARF4 is likely finding a reference from .debug_info + to .debug_types. So the offset may or may not be + in the same section if DWARF4. + context_level prevents infinite loop + during CU_Context creation */ +static int +find_sig8_target_as_global_offset(Dwarf_Attribute attr, + int context_level, + Dwarf_Sig8 *sig8, + Dwarf_Bool *is_info, + Dwarf_Off *targoffset, + Dwarf_Error *error) +{ + Dwarf_Die targdie = 0; + Dwarf_Bool targ_is_info = 0; + Dwarf_Off localoff = 0; + int res = 0; + int resb = 0; + + targ_is_info = attr->ar_cu_context->cc_is_info; + memcpy(sig8,attr->ar_debug_ptr,sizeof(*sig8)); + res = _dwarf_internal_find_die_given_sig8(attr->ar_dbg, + context_level, + sig8,&targdie,&targ_is_info,error); + if (res != DW_DLV_OK) { + return res; + } + resb = dwarf_die_offsets(targdie,targoffset,&localoff,error); + if (resb != DW_DLV_OK) { + dwarf_dealloc_die(targdie); + return resb; + } + *is_info = targdie->di_cu_context->cc_is_info; + dwarf_dealloc_die(targdie); + return DW_DLV_OK; +} + +/* Since this returns section-relative debug_info offsets, + this can represent all REFERENCE forms correctly + and allows all applicable forms. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + gcc and Go and libdwarf producer code + define the length of the value of DW_FORM_ref_addr + per the version. So for V2 it is address-size and V3 and later + it is offset-size. + + See the DWARF4 document for the 3 cases fitting + reference forms. The caller must determine which section the + reference 'points' to. The function added in November 2009, + dwarf_get_form_class(), helps in this regard. + + unlike dwarf_formref(), this allows references to + sections other than just .debug_info/.debug_types. + See case DW_FORM_sec_offset: + case DW_FORM_GNU_ref_alt: 2013 GNU extension + case DW_FORM_GNU_strp_alt: 2013 GNU extension + case DW_FORM_strp_sup: DWARF5, sup string section + case DW_FORM_line_strp: DWARF5, .debug_line_str section +*/ + +/* This follows DW_FORM_ref_sig8 so could got + to any CU and from debug_info to debug_types + (or vice versa?) + dwarf_global_formref_b is aimed at for DIE references. + Only the DW_FORM_ref_sig8 form can change + from a cu_context in .debug_info + to one in .debug_types (DWARF4 only). + For references to other sections it is simpler + to call the original: dwarf_global_formref. +*/ +int +dwarf_global_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, + Dwarf_Error * error) +{ + Dwarf_Bool is_info = 0; + int res = 0; + + res = dwarf_global_formref_b(attr,ret_offset, + &is_info,error); + return res; +} + +/* If context_level is 0, normal call + But if non-zero will avoid creating CU Context. */ +int +dwarf_global_formref_b(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, + Dwarf_Bool * offset_is_info, + Dwarf_Error * error) +{ + int res = 0; + res = _dwarf_internal_global_formref_b( attr, + 0, + ret_offset, + offset_is_info, + error); + return res; +} +int +_dwarf_internal_global_formref_b(Dwarf_Attribute attr, + int context_level, + Dwarf_Off * ret_offset, + Dwarf_Bool * offset_is_info, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Half context_version = 0; + Dwarf_Byte_Ptr section_end = 0; + Dwarf_Bool is_info = TRUE; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + context_version = cu_context->cc_version_stamp; + is_info = cu_context->cc_is_info; + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + goto fixoffset; + + case DW_FORM_ref2: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_HALF_SIZE, + error,section_end); + goto fixoffset; + + case DW_FORM_ref4: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error,section_end); + goto fixoffset; + + case DW_FORM_ref8: + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_64BIT_SIZE, + error,section_end); + goto fixoffset; + + case DW_FORM_ref_udata: + { + Dwarf_Byte_Ptr ptr = attr->ar_debug_ptr; + Dwarf_Unsigned localoffset = 0; + + DECODE_LEB128_UWORD_CK(ptr,localoffset, + dbg,error,section_end); + offset = localoffset; + + fixoffset: /* we have a local offset, make it global */ + + /* check legality of offset */ + if (offset >= cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return DW_DLV_ERROR; + } + + /* globalize the offset */ + offset += cu_context->cc_debug_offset; + } + break; + + /* The DWARF2 document did not make clear that + DW_FORM_data4( and 8) were references with + global offsets to some section. + That was first clearly documented in DWARF3. + In DWARF4 these two forms are no longer references. */ + case DW_FORM_data4: + if (context_version >= DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error, section_end); + /* The offset is global. */ + break; + case DW_FORM_data8: + if (context_version >= DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_64BIT_SIZE, + error,section_end); + /* The offset is global. */ + break; + case DW_FORM_ref_addr: + { + /* In Dwarf V2 DW_FORM_ref_addr was defined + as address-size even though it is a .debug_info + offset. Fixed in Dwarf V3 to be offset-size. + */ + unsigned length_size = 0; + if (context_version == 2) { + length_size = cu_context->cc_address_size; + } else { + length_size = cu_context->cc_length_size; + } + if (length_size == 4) { + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error,section_end); + } else if (length_size == 8) { + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_64BIT_SIZE, + error,section_end); + } else { + _dwarf_error(dbg, error, + DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD); + return DW_DLV_ERROR; + } + } + break; + /* Index into .debug_rnglists/.debug_loclists section. + Return the index itself. */ + case DW_FORM_loclistx: + case DW_FORM_rnglistx: { + unsigned length_size = cu_context->cc_length_size; + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, length_size, + error,section_end); + } + break; + case DW_FORM_sec_offset: + case DW_FORM_GNU_ref_alt: /* 2013 GNU extension */ + case DW_FORM_GNU_strp_alt: /* 2013 GNU extension */ + case DW_FORM_strp_sup: /* DWARF5, sup string section */ + case DW_FORM_line_strp: /* DWARF5, .debug_line_str section */ + { + /* DW_FORM_sec_offset first exists in DWARF4.*/ + /* It is up to the caller to know what the offset + of DW_FORM_sec_offset, DW_FORM_strp_sup + or DW_FORM_GNU_strp_alt etc refer to, + the offset is not going to refer to .debug_info! */ + unsigned length_size = cu_context->cc_length_size; + if (length_size == 4) { + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error,section_end); + } else if (length_size == 8) { + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_64BIT_SIZE, + error,section_end); + } else { + _dwarf_error(dbg, error, + DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD); + return DW_DLV_ERROR; + } + } + break; + case DW_FORM_ref_sig8: { + /* This, in DWARF4, is how + .debug_info refers to .debug_types. */ + Dwarf_Sig8 sig8; + Dwarf_Bool t_is_info = TRUE; + Dwarf_Unsigned t_offset = 0; + + if ((attr->ar_debug_ptr + sizeof(Dwarf_Sig8)) > section_end) { + _dwarf_error_string(dbg, error, + DW_DLE_REF_SIG8_NOT_HANDLED, + "DW_DLE_REF_SIG8_NOT_HANDLED: " + " Dwarf_Sig8 content runs off the end of " + "its section"); + return DW_DLV_ERROR; + } + memcpy(&sig8,attr->ar_debug_ptr,sizeof(Dwarf_Sig8)); + res = find_sig8_target_as_global_offset(attr, + context_level, + &sig8,&t_is_info,&t_offset,error); + if (res == DW_DLV_ERROR) { + + /* Lets construct an easily usable error number. + Avoiding resizing strings and avoiding + using the stack for strings possibly + a few hundred bytes long */ + if (error) { + dwarfstring m; + dwarfstring k; + + dwarfstring_constructor_fixed(&m,400); + dwarfstring_constructor_fixed(&k,200); + /* *error non null */ + dwarfstring_append(&k,dwarf_errmsg(*error)); + dwarfstring_append(&m, + "DW_DLE_REF_SIG8_NOT_HANDLED: " + " problem finding target. "); + dwarf_dealloc_error(dbg,*error);/* *error nonnull*/ + *error = 0; /*error nonnull*/ + dwarfstring_append(&m,dwarfstring_string(&k)); + dwarfstring_destructor(&k); + _dwarf_error_string(dbg, error, + DW_DLE_REF_SIG8_NOT_HANDLED, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + is_info = t_is_info; + offset = t_offset; + break; + } + default: { + dwarfstring m; + int formcode = attr->ar_attribute_form; + int fcres = 0; + const char *name = 0; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_BAD_REF_FORM: The form code is 0x%x ", + formcode); + fcres = dwarf_get_FORM_name (formcode,&name); + if (fcres != DW_DLV_OK) { + name=""; + } + dwarfstring_append_printf_s(&m, + " %s.",(char *)name); + _dwarf_error_string(dbg, error, DW_DLE_BAD_REF_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + + *offset_is_info = is_info; + *ret_offset = offset; + return DW_DLV_OK; +} + +/* Part of DebugFission. So a consumer can get the index when + the object with the actual debug_addr is + elsewhere. New May 2014*/ + +int +_dwarf_get_addr_index_itself(int theform, + Dwarf_Small *info_ptr, + Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Unsigned *val_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned index = 0; + Dwarf_Byte_Ptr section_end = 0; + + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + switch(theform){ + case DW_FORM_LLVM_addrx_offset: { + Dwarf_Unsigned tmp = 0; + Dwarf_Unsigned tmp2 = 0; + DECODE_LEB128_UWORD_CK(info_ptr,tmp, + dbg,error,section_end); + READ_UNALIGNED_CK(dbg, tmp2, Dwarf_Unsigned, + info_ptr, SIZEOFT32, + error,section_end); + index = (tmp<<32) | tmp2; + break; + } + case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: + DECODE_LEB128_UWORD_CK(info_ptr,index, + dbg,error,section_end); + break; + case DW_FORM_addrx1: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 1, + error,section_end); + break; + case DW_FORM_addrx2: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 2, + error,section_end); + break; + case DW_FORM_addrx3: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 3, + error,section_end); + break; + case DW_FORM_addrx4: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 4, + error,section_end); + break; + default: + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_NOT_ADDR_INDEX); + return DW_DLV_ERROR; + } + /* At this point we do not know for sure + if the index refers + to a local .debug_addr or a tied file .debug_addr + so lets be cautious. */ +#if 0 + if (!dbg->de_tied_data.td_tied_object && + index > dbg->de_filesize) { + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_OFFSET_BAD, + "DW_DLE_ATTR_FORM_OFFSET_BAD " + "reading an indexed form addr the index " + "read is impossibly large (no tied file " + "available). Corrupt Dwarf."); + return DW_DLV_ERROR; + } +#endif + *val_out = index; + return DW_DLV_OK; +} + +int +dwarf_get_debug_addr_index(Dwarf_Attribute attr, + Dwarf_Unsigned * return_index, + Dwarf_Error * error) +{ + int theform = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + theform = attr->ar_attribute_form; + if (dwarf_addr_form_is_indexed(theform)) { + Dwarf_Unsigned index = 0; + + res = _dwarf_get_addr_index_itself(theform, + attr->ar_debug_ptr,dbg,cu_context,&index,error); + *return_index = index; + return res; + } + + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_NOT_ADDR_INDEX); + return DW_DLV_ERROR; +} + +/* The index value here is the value of the + attribute with this form. + FORMs passed in are always strx forms. */ +static int +dw_read_str_index_val_itself(Dwarf_Debug dbg, + unsigned theform, + Dwarf_Small *info_ptr, + Dwarf_Small *section_end, + Dwarf_Unsigned *return_index, + Dwarf_Error *error) +{ + Dwarf_Unsigned index = 0; + + switch(theform) { + case DW_FORM_strx: + case DW_FORM_GNU_str_index: + DECODE_LEB128_UWORD_CK(info_ptr,index, + dbg,error,section_end); + break; + case DW_FORM_strx1: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 1, + error,section_end); + break; + case DW_FORM_strx2: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 2, + error,section_end); + break; + case DW_FORM_strx3: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 3, + error,section_end); + break; + case DW_FORM_strx4: + READ_UNALIGNED_CK(dbg, index, Dwarf_Unsigned, + info_ptr, 4, + error,section_end); + break; + default: + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_NOT_STR_INDEX); + return DW_DLV_ERROR; + } + *return_index = index; + return DW_DLV_OK; +} + +/* Part of DebugFission. So a dwarf dumper application + can get the index and print it for the user. + A convenience function. New May 2014 + Also used with DWARF5 forms. */ +int +dwarf_get_debug_str_index(Dwarf_Attribute attr, + Dwarf_Unsigned *return_index, + Dwarf_Error *error) +{ + int theform = attr->ar_attribute_form; + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + int res = 0; + Dwarf_Byte_Ptr section_end = 0; + Dwarf_Unsigned index = 0; + Dwarf_Small *info_ptr = 0; + int indxres = 0; + Dwarf_Unsigned length_size = 0; + Dwarf_Unsigned sectionlen = 0; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + info_ptr = attr->ar_debug_ptr; + + indxres = dw_read_str_index_val_itself(dbg, theform, info_ptr, + section_end, &index,error); + if (indxres == DW_DLV_OK) { + *return_index = index; + return indxres; + } + length_size = cu_context->cc_length_size; + sectionlen = dbg->de_debug_str_offsets.dss_size; + if (index > sectionlen || + (index *length_size) > sectionlen) { + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_FORM_SIZE_BAD, + "DW_DLE_ATTR_FORM_SIZE_BAD: " + "An Attribute Value (index into " + ".debug_str_offsets) is Impossibly " + "large. Corrupt Dwarf."); + return DW_DLV_ERROR; + } + return indxres; +} + +int +_dwarf_extract_data16(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Small *section_start, + Dwarf_Small *section_end, + Dwarf_Form_Data16 * returned_val, + Dwarf_Error *error) +{ + Dwarf_Small *data16end = 0; + + data16end = data + sizeof(Dwarf_Form_Data16); + if (data < section_start || + section_end < data16end) { + _dwarf_error(dbg, error,DW_DLE_DATA16_OUTSIDE_SECTION); + return DW_DLV_ERROR; + } + memcpy(returned_val, data, sizeof(*returned_val)); + return DW_DLV_OK; + +} + +int +dwarf_formdata16(Dwarf_Attribute attr, + Dwarf_Form_Data16 * returned_val, + Dwarf_Error* error) +{ + Dwarf_Half attrform = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + int res = 0; + Dwarf_Small *section_end = 0; + Dwarf_Unsigned section_length = 0; + Dwarf_Small *section_start = 0; + + if (!attr) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return DW_DLV_ERROR; + } + if (!returned_val ) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return DW_DLV_ERROR; + } + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + attrform = attr->ar_attribute_form; + if (attrform != DW_FORM_data16) { + generate_form_error(dbg,error,attrform, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "dwarf_formdata16"); + return DW_DLV_ERROR; + } + section_start = _dwarf_calculate_info_section_start_ptr( + cu_context,§ion_length); + section_end = section_start + section_length; + + res = _dwarf_extract_data16(dbg, attr->ar_debug_ptr, + section_start, section_end, + returned_val, error); + return res; +} + +/* The *addrx are DWARF5 standard. + The GNU form is non-standard gcc DWARF4 + The LLVM form is the newest. */ +Dwarf_Bool +dwarf_addr_form_is_indexed(int form) +{ + switch(form) { + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + case DW_FORM_GNU_addr_index: + case DW_FORM_LLVM_addrx_offset: + return TRUE; + default: break; + } + return FALSE; +} + +int +dwarf_formaddr(Dwarf_Attribute attr, + Dwarf_Addr * return_addr, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Addr ret_addr = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Half attrform = 0; + int res = 0; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + attrform = attr->ar_attribute_form; + if (dwarf_addr_form_is_indexed(attrform)) { + res = _dwarf_look_in_local_and_tied( + attrform, + cu_context, + attr->ar_debug_ptr, + return_addr, + error); + return res; + } + if (attrform == DW_FORM_addr + /* || attrform == DW_FORM_ref_addr Allowance of + DW_FORM_ref_addr was a mistake. The value returned in that + case is NOT an address it is a global debug_info + offset (ie, not CU-relative offset within the CU + in debug_info). + The DWARF2 document refers to it as an address + (misleadingly) in sec 6.5.4 where it describes + the reference form. It is + address-sized so that the linker can easily update it, but + it is a reference inside the debug_info section. No longer + allowed. */ + ) { + Dwarf_Small *section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + + READ_UNALIGNED_CK(dbg, ret_addr, Dwarf_Addr, + attr->ar_debug_ptr, + cu_context->cc_address_size, + error,section_end); + *return_addr = ret_addr; + return DW_DLV_OK; + } + generate_form_error(dbg,error,attrform, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "dwarf_formaddr"); + return DW_DLV_ERROR; +} + +int +dwarf_formflag(Dwarf_Attribute attr, + Dwarf_Bool * ret_bool, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + if (!attr) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return DW_DLV_ERROR; + } + cu_context = attr->ar_cu_context; + if (!cu_context) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + dbg = cu_context->cc_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, + "DW_DLE_ATTR_DBG_NULL: dwarf_formflag() attribute" + " passed in has NULL or stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (dbg != attr->ar_dbg) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, + "DW_DLE_ATTR_DBG_NULL: an attribute and its " + "cu_context do not have the same Dwarf_Debug" ); + return DW_DLV_ERROR; + } + if (attr->ar_attribute_form == DW_FORM_flag_present) { + /* Implicit means we don't read any data at all. Just + the existence of the Form does it. DWARF4. */ + *ret_bool = 1; + return DW_DLV_OK; + } + + if (attr->ar_attribute_form == DW_FORM_flag) { + *ret_bool = *(Dwarf_Small *)(attr->ar_debug_ptr); + return DW_DLV_OK; + } + generate_form_error(dbg,error,attr->ar_attribute_form, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "dwarf_formflat"); + return DW_DLV_ERROR; +} + +Dwarf_Bool +_dwarf_allow_formudata(unsigned form) +{ + switch(form) { + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_udata: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + return TRUE; + default: + break; + } + return FALSE; +} +/* If the form is DW_FORM_constx and the .debug_addr section + is missing, this returns DW_DLV_ERROR and the error number + in the Dwarf_Error is DW_DLE_MISSING_NEEDED_DEBUG_ADDR_SECTION. + When that arises, a consumer should call + dwarf_get_debug_addr_index() and use that on the appropriate + .debug_addr section in the executable or another object. + + Since this accept some signed values, callers + must not assume a DW_DLV_OK means + the value is unsigned. The form is the first clue here. + If DW_FORM_sdata, then signed. Else unknown sign or + is unsigned. +*/ + +int +_dwarf_formudata_internal(Dwarf_Debug dbg, + Dwarf_Attribute attr, + unsigned form, + Dwarf_Byte_Ptr data, + Dwarf_Byte_Ptr section_end, + Dwarf_Unsigned *return_uval, + Dwarf_Unsigned *bytes_read, + Dwarf_Error *error) +{ + Dwarf_Unsigned ret_value = 0; + + switch (form) { + case DW_FORM_data1: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + data, sizeof(Dwarf_Small), + error,section_end); + *return_uval = ret_value; + *bytes_read = 1; + return DW_DLV_OK; + + /* READ_UNALIGNED does the right thing as it reads + the right number bits and generates host order. + So we can just assign to *return_uval. */ + case DW_FORM_data2:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + data, DWARF_HALF_SIZE, + error,section_end); + *return_uval = ret_value; + *bytes_read = DWARF_HALF_SIZE; + return DW_DLV_OK; + } + + case DW_FORM_data4:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + data, + DWARF_32BIT_SIZE, + error,section_end); + *return_uval = ret_value; + *bytes_read = DWARF_32BIT_SIZE;; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + data, + DWARF_64BIT_SIZE, + error,section_end); + *return_uval = ret_value; + *bytes_read = DWARF_64BIT_SIZE; + return DW_DLV_OK; + } + break; + /* real udata */ + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_udata: { + Dwarf_Unsigned leblen = 0; + DECODE_LEB128_UWORD_LEN_CK(data, ret_value,leblen, + dbg,error,section_end); + *return_uval = ret_value; + *bytes_read = leblen; + return DW_DLV_OK; + } + /* IRIX bug 583450. We do not allow reading + sdata from a udata + value. Caller can retry, calling sdata */ + default: + break; + } + if (attr) { + int res = 0; + Dwarf_Signed s = 0; + res = dwarf_formsdata(attr,&s,error); + if (res != DW_DLV_OK) { + return res; + } + if (s < 0 ) { + _dwarf_error(dbg, error, DW_DLE_UDATA_VALUE_NEGATIVE); + return DW_DLV_ERROR; + } + *return_uval = (Dwarf_Unsigned)s; + *bytes_read = 0; + return DW_DLV_OK; + } + generate_form_error(dbg,error,form, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "formudata (internal function)"); + return DW_DLV_ERROR; +} + +int +dwarf_formudata(Dwarf_Attribute attr, + Dwarf_Unsigned * return_uval, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Byte_Ptr section_end = 0; + Dwarf_Unsigned bytes_read = 0; + Dwarf_Byte_Ptr data = attr->ar_debug_ptr; + unsigned form = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + form = attr->ar_attribute_form; + + res = _dwarf_formudata_internal(dbg, + attr, + form, data, section_end, return_uval, + &bytes_read, error); + return res; +} + +int +dwarf_formsdata(Dwarf_Attribute attr, + Dwarf_Signed * return_sval, Dwarf_Error * error) +{ + Dwarf_Signed ret_value = 0; + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Byte_Ptr section_end = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + switch (attr->ar_attribute_form) { + + case DW_FORM_data1: + if ( attr->ar_debug_ptr >= section_end) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return DW_DLV_ERROR; + } + *return_sval = (*(Dwarf_Sbyte *) attr->ar_debug_ptr); + return DW_DLV_OK; + + /* READ_UNALIGNED does not sign extend. + So we have to use a cast to get the + value sign extended in the right way for each case. */ + case DW_FORM_data2:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + DWARF_HALF_SIZE, + error,section_end); + *return_sval = (Dwarf_Shalf) ret_value; + return DW_DLV_OK; + + } + + case DW_FORM_data4:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + DWARF_32BIT_SIZE, + error,section_end); + SIGN_EXTEND(ret_value,DWARF_32BIT_SIZE); + *return_sval = (Dwarf_Signed) ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + DWARF_64BIT_SIZE, + error,section_end); + /* No SIGN_EXTEND needed, we are filling all bytes already.*/ + *return_sval = (Dwarf_Signed) ret_value; + return DW_DLV_OK; + } + + /* DW_FORM_implicit_const is a value in the + abbreviations, not in the DIEs. */ + case DW_FORM_implicit_const: + *return_sval = attr->ar_implicit_const; + return DW_DLV_OK; + + case DW_FORM_sdata: { + Dwarf_Byte_Ptr tmp = attr->ar_debug_ptr; + + DECODE_LEB128_SWORD_CK(tmp, ret_value, + dbg,error,section_end); + *return_sval = ret_value; + return DW_DLV_OK; + + } + + /* IRIX bug 583450. We do not allow reading sdata from a udata + value. Caller can retry, calling udata */ + + default: + break; + } + generate_form_error(dbg,error,attr->ar_attribute_form, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "dwarf_formsdata"); + return DW_DLV_ERROR; +} + +int +_dwarf_formblock_internal(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_CU_Context cu_context, + Dwarf_Block * return_block, + Dwarf_Error * error) +{ + Dwarf_Small *section_start = 0; + Dwarf_Small *section_end = 0; + Dwarf_Unsigned section_length = 0; + Dwarf_Unsigned length = 0; + Dwarf_Small *data = 0; + + section_end = + _dwarf_calculate_info_section_end_ptr(cu_context); + section_start = + _dwarf_calculate_info_section_start_ptr(cu_context, + §ion_length); + + switch (attr->ar_attribute_form) { + + case DW_FORM_block1: + length = *(Dwarf_Small *) attr->ar_debug_ptr; + data = attr->ar_debug_ptr + sizeof(Dwarf_Small); + break; + + case DW_FORM_block2: + READ_UNALIGNED_CK(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_HALF_SIZE, + error,section_end); + data = attr->ar_debug_ptr + DWARF_HALF_SIZE; + break; + + case DW_FORM_block4: + READ_UNALIGNED_CK(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, DWARF_32BIT_SIZE, + error,section_end); + data = attr->ar_debug_ptr + DWARF_32BIT_SIZE; + break; + + case DW_FORM_exprloc: + case DW_FORM_block: { + Dwarf_Byte_Ptr tmp = attr->ar_debug_ptr; + Dwarf_Unsigned leblen = 0; + + DECODE_LEB128_UWORD_LEN_CK(tmp, length, leblen, + dbg,error,section_end); + data = attr->ar_debug_ptr + leblen; + break; + } + default: + generate_form_error(dbg,error,attr->ar_attribute_form, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "dwarf_formblock"); + return DW_DLV_ERROR; + } + /* We have the data. Check for errors. */ + if (length >= section_length) { + /* Sanity test looking for wraparound: + when length actually added in + it would not be caught. + Test could be just >, but >= ok here too.*/ + _dwarf_error_string(dbg, error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: " + "The length of the block is greater " + "than the section length! Corrupt Dwarf."); + return DW_DLV_ERROR; + } + if ((attr->ar_debug_ptr + length) > section_end) { + _dwarf_error_string(dbg, error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: " + "The block length means the block " + "runs off the end of the section length!" + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + if (data > section_end) { + _dwarf_error_string(dbg, error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: " + "The block content is " + "past the end of the section!" + " Corrupt Dwarf."); + _dwarf_error(dbg, error, DW_DLE_FORM_BLOCK_LENGTH_ERROR); + return DW_DLV_ERROR; + } + if ((data + length) > section_end) { + _dwarf_error_string(dbg, error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: " + "The end of the block content is " + "past the end of the section!" + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + return_block->bl_len = length; + return_block->bl_data = data; + /* This struct is public so use the old name instead + of what we now would call it: bl_kind */ + return_block->bl_from_loclist = DW_LKIND_expression; + return_block->bl_section_offset = data - section_start; + return DW_DLV_OK; +} + +int +dwarf_formblock(Dwarf_Attribute attr, + Dwarf_Block ** return_block, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Block local_block; + Dwarf_Block *out_block = 0; + int res = 0; + + memset(&local_block,0,sizeof(local_block)); + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_formblock_internal(dbg,attr, + cu_context, &local_block, error); + if (res != DW_DLV_OK) { + return res; + } + out_block = (Dwarf_Block *) + _dwarf_get_alloc(dbg, DW_DLA_BLOCK, 1); + if (!out_block) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + *out_block = local_block; + *return_block = out_block; + return DW_DLV_OK; +} + +/* This is called for attribute with strx form + or macro5 with strx form. + No relation to the Name Table or + to FIXME */ +int +_dwarf_extract_string_offset_via_str_offsets(Dwarf_Debug dbg, + Dwarf_Small *data_ptr, + Dwarf_Small *end_data_ptr, + Dwarf_Half attrform, + Dwarf_CU_Context cu_context, + Dwarf_Unsigned *str_sect_offset_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned index_to_offset_entry = 0; + Dwarf_Unsigned offsettotable = 0; + Dwarf_Unsigned end_offsettotable = 0; + Dwarf_Unsigned indexoffset = 0; + Dwarf_Unsigned baseoffset = 0; + Dwarf_Unsigned table_offset_to_array = 0; + int res = 0; + int idxres = 0; + Dwarf_Small *sectionptr = 0; + Dwarf_Unsigned sectionlen = 0; + Dwarf_Small *sof_start = 0; + Dwarf_Small *sof_end = 0; + Dwarf_Unsigned str_sect_offset = 0; + Dwarf_Unsigned length_size = 0; + Dwarf_Bool have_array_offset = FALSE; + + res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets,error); + if (res != DW_DLV_OK) { + return res; + } + sectionptr = dbg->de_debug_str_offsets.dss_data; + sectionlen = dbg->de_debug_str_offsets.dss_size; + length_size = cu_context->cc_length_size; + /* If this is a dwp we look there, but I suppose + we could also look for the section in the tied + executable object file it is not here. FIXME */ + idxres = dw_read_str_index_val_itself(dbg, + attrform,data_ptr,end_data_ptr,&index_to_offset_entry,error); + if ( idxres != DW_DLV_OK) { + return idxres; + } + if (cu_context->cc_str_offsets_array_offset_present) { + baseoffset = cu_context->cc_str_offsets_array_offset; + have_array_offset = TRUE; + } else if (cu_context->cc_str_offsets_tab_present) { + baseoffset = cu_context->cc_str_offsets_header_offset; + baseoffset += cu_context->cc_str_offsets_tab_to_array; + have_array_offset = TRUE; + } else { /* do nothing */} + if (baseoffset > sectionlen || + (baseoffset+length_size) > sectionlen || + (baseoffset+(index_to_offset_entry *length_size)) > + sectionlen) { + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_FORM_SIZE_BAD, + "DW_DLE_ATTR_FORM_SIZE_BAD: " + "An Attribute value (offset into " + ".debug_str_offsets) is impossibly " + "large. Corrupt Dwarf."); + return DW_DLV_ERROR; + } + indexoffset = index_to_offset_entry* length_size; + if (!have_array_offset) { + /* missing any connection to a specific + str_offsets table this guesses at table zero. + When the compiler/linker have + combined str offsets into a + single table this works. */ + Dwarf_Unsigned headeroffset = 0; + if (cu_context->cc_version_stamp == DW_CU_VERSION5 ) { + /* A base offset of 0 is ok for either + DWARF5. but some early GNU compilers emitted + DWARF4 .debug_str_offsets, so lets check + the first table. */ + Dwarf_Unsigned stsize = + dbg->de_debug_str_offsets.dss_size; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned table_length = 0; + Dwarf_Half local_offset_size = 0; + Dwarf_Half local_extension_size = 0; + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + + res = _dwarf_trial_read_dwarf_five_hdr(dbg, + headeroffset,stsize, + &table_offset_to_array, + &table_length, + &length, &local_offset_size, + &local_extension_size, + &version, + &padding, + error); + if (res == DW_DLV_OK) { + baseoffset = table_offset_to_array+ + headeroffset; + } else { + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } else {} + } + } + } + offsettotable = indexoffset+ baseoffset; + end_offsettotable = offsettotable + length_size; + /* The offsets table is a series of offset-size entries. + The == case in the test applies when we are at the last table + entry, so == is not an error, hence only test > + */ + if (offsettotable > sectionlen || + end_offsettotable > sectionlen) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ATTR_FORM_SIZE_BAD: The end offset of " + "a .debug_str_offsets table is 0x%x ", + end_offsettotable); + dwarfstring_append_printf_u(&m, + "but the object section is just 0x%x " + "bytes long", + sectionlen); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_FORM_SIZE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + sof_start = sectionptr+ offsettotable; + sof_end = sectionptr + end_offsettotable; + /* Now read the string offset from the offset table. */ + READ_UNALIGNED_CK(dbg,str_sect_offset,Dwarf_Unsigned, + sof_start, + length_size,error,sof_end); + *str_sect_offset_out = str_sect_offset; + return DW_DLV_OK; +} + +int +_dwarf_extract_local_debug_str_string_given_offset(Dwarf_Debug dbg, + unsigned attrform, + Dwarf_Unsigned offset, + char ** return_str, + Dwarf_Error * error) +{ + if (attrform == DW_FORM_strp || + attrform == DW_FORM_line_strp || + attrform == DW_FORM_GNU_str_index || + attrform == DW_FORM_strx1 || + attrform == DW_FORM_strx2 || + attrform == DW_FORM_strx3 || + attrform == DW_FORM_strx4 || + attrform == DW_FORM_strx) { + /* The 'offset' into .debug_str or .debug_line_str is given, + here we turn that into a pointer. */ + Dwarf_Small *secend = 0; + Dwarf_Small *secbegin = 0; + Dwarf_Small *strbegin = 0; + Dwarf_Unsigned secsize = 0; + int errcode = 0; + const char *errname = 0; + int res = 0; + + if (attrform == DW_FORM_line_strp) { + res = _dwarf_load_section(dbg, + &dbg->de_debug_line_str,error); + if (res != DW_DLV_OK) { + return res; + } + errcode = DW_DLE_STRP_OFFSET_BAD; + errname = "DW_DLE_STRP_OFFSET_BAD"; + secsize = dbg->de_debug_line_str.dss_size; + secbegin = dbg->de_debug_line_str.dss_data; + strbegin= dbg->de_debug_line_str.dss_data + offset; + secend = dbg->de_debug_line_str.dss_data + secsize; + } else { + /* DW_FORM_strp etc */ + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + errcode = DW_DLE_STRING_OFFSET_BAD; + errname = "DW_DLE_STRING_OFFSET_BAD"; + secsize = dbg->de_debug_str.dss_size; + secbegin = dbg->de_debug_str.dss_data; + strbegin= dbg->de_debug_str.dss_data + offset; + secend = dbg->de_debug_str.dss_data + secsize; + } + if (offset >= secsize) { + dwarfstring m; + const char *name = ""; + + dwarf_get_FORM_name(attrform,&name); + + dwarfstring_constructor(&m); + dwarfstring_append(&m,(char *)errname); + dwarfstring_append_printf_s(&m, + " Form %s ",(char *)name); + dwarfstring_append_printf_u(&m, + "string offset of 0x%" DW_PR_DUx " ", + offset); + dwarfstring_append_printf_u(&m, + "is larger than the string section " + "size of 0x%" DW_PR_DUx, + secsize); + _dwarf_error_string(dbg, error, errcode, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + /* Badly damaged DWARF here. */ + return DW_DLV_ERROR; + } + res= _dwarf_check_string_valid(dbg,secbegin,strbegin, secend, + errcode,error); + if (res != DW_DLV_OK) { + return res; + } + + *return_str = (char *)strbegin; + return DW_DLV_OK; + } + generate_form_error(dbg,error,attrform, + DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD", + "extract debug_str string"); + return DW_DLV_ERROR; +} + +/* Contrary to pre-2005 documentation, + The string pointer returned thru return_str must + never have dwarf_dealloc() applied to it. + Documentation fixed July 2005. +*/ +int +dwarf_formstring(Dwarf_Attribute attr, + char **return_str, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + int res = DW_DLV_ERROR; + Dwarf_Small *secdataptr = 0; + Dwarf_Small *secend = 0; + Dwarf_Unsigned secdatalen = 0; + Dwarf_Small *infoptr = attr->ar_debug_ptr; + Dwarf_Small *contextend = 0; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + if (cu_context->cc_is_info) { + secdataptr = (Dwarf_Small *)dbg->de_debug_info.dss_data; + secdatalen = dbg->de_debug_info.dss_size; + } else { + secdataptr = (Dwarf_Small *)dbg->de_debug_types.dss_data; + secdatalen = dbg->de_debug_types.dss_size; + } + contextend = secdataptr + + cu_context->cc_debug_offset + + cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size; + secend = secdataptr + secdatalen; + if (contextend < secend) { + secend = contextend; + } + switch(attr->ar_attribute_form) { + case DW_FORM_string: { + Dwarf_Small *begin = attr->ar_debug_ptr; + + res= _dwarf_check_string_valid(dbg,secdataptr,begin, secend, + DW_DLE_FORM_STRING_BAD_STRING,error); + if (res != DW_DLV_OK) { + return res; + } + *return_str = (char *) (begin); + return DW_DLV_OK; + } + case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: { + Dwarf_Error alterr = 0; + Dwarf_Bool is_info = TRUE; + /* See dwarfstd.org issue 120604.1 + This is the offset in the .debug_str section + of another object file. + The 'tied' file notion should apply. + It is not clear whether both a supplementary + and a split object might be needed at the same time + (hence two 'tied' files simultaneously). */ + Dwarf_Off soffset = 0; + + res = dwarf_global_formref_b(attr, &soffset, + &is_info,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_get_string_from_tied(dbg, soffset, + return_str, &alterr); + if (res == DW_DLV_ERROR) { + if (dwarf_errno(alterr) == + DW_DLE_NO_TIED_FILE_AVAILABLE) { + dwarf_dealloc(dbg,alterr,DW_DLA_ERROR); + if ( attr->ar_attribute_form == + DW_FORM_GNU_strp_alt) { + *return_str = + (char *)""; + } else { + *return_str = + (char *)""; + } + return DW_DLV_OK; + } + if (error) { + *error = alterr; + } else { + dwarf_dealloc_error(dbg,alterr); + alterr = 0; + } + return res; + } + if (res == DW_DLV_NO_ENTRY) { + if ( attr->ar_attribute_form == DW_FORM_GNU_strp_alt) { + *return_str = + (char *)""; + }else { + *return_str = + (char *)""; + } + } + return res; + } + case DW_FORM_GNU_str_index: + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: { + Dwarf_Unsigned offsettostr= 0; + + res = _dwarf_extract_string_offset_via_str_offsets(dbg, + infoptr, + secend, + attr->ar_attribute_form, + cu_context, + &offsettostr, + error); + if (res != DW_DLV_OK) { + return res; + } + offset = offsettostr; + break; + } + case DW_FORM_strp: + case DW_FORM_line_strp:{ + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + infoptr, + cu_context->cc_length_size,error,secend); + break; + } + default: + _dwarf_error(dbg, error, DW_DLE_STRING_FORM_IMPROPER); + return DW_DLV_ERROR; + } + /* Now we have offset so read the string from + debug_str or debug_line_str. */ + res = _dwarf_extract_local_debug_str_string_given_offset(dbg, + attr->ar_attribute_form, + offset, + return_str, + error); + return res; +} + +int +_dwarf_get_string_from_tied(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + char **return_str, + Dwarf_Error*error) +{ + Dwarf_Debug tieddbg = 0; + Dwarf_Small *secend = 0; + Dwarf_Small *secbegin = 0; + Dwarf_Small *strbegin = 0; + int res = DW_DLV_ERROR; + Dwarf_Error localerror = 0; + + /* Attach errors to dbg, not tieddbg. */ + tieddbg = dbg->de_tied_data.td_tied_object; + if (!tieddbg) { + _dwarf_error(dbg, error, DW_DLE_NO_TIED_FILE_AVAILABLE); + return DW_DLV_ERROR; + } + /* The 'offset' into .debug_str is set. */ + res = _dwarf_load_section(tieddbg, &tieddbg->de_debug_str, + &localerror); + if (res == DW_DLV_ERROR) { + Dwarf_Unsigned lerrno = dwarf_errno(localerror); + dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR); + _dwarf_error(dbg,error,lerrno); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + if (offset >= tieddbg->de_debug_str.dss_size) { + /* Badly damaged DWARF here. */ + _dwarf_error(dbg, error, DW_DLE_NO_TIED_STRING_AVAILABLE); + return DW_DLV_ERROR; + } + secbegin = tieddbg->de_debug_str.dss_data; + strbegin= tieddbg->de_debug_str.dss_data + offset; + secend = tieddbg->de_debug_str.dss_data + + tieddbg->de_debug_str.dss_size; + + /* Ensure the offset lies within the .debug_str */ + if (offset >= tieddbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_NO_TIED_STRING_AVAILABLE); + return DW_DLV_ERROR; + } + res= _dwarf_check_string_valid(tieddbg,secbegin,strbegin, secend, + DW_DLE_NO_TIED_STRING_AVAILABLE, + &localerror); + if (res == DW_DLV_ERROR) { + Dwarf_Unsigned lerrno = dwarf_errno(localerror); + dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR); + _dwarf_error(dbg,error,lerrno); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + *return_str = (char *) (tieddbg->de_debug_str.dss_data + offset); + return DW_DLV_OK; +} + +int +dwarf_formexprloc(Dwarf_Attribute attr, + Dwarf_Unsigned * return_exprlen, + Dwarf_Ptr * block_ptr, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if (res != DW_DLV_OK) { + return res; + } + if (attr->ar_attribute_form == DW_FORM_exprloc ) { + Dwarf_Die die = 0; + Dwarf_Unsigned leb_len = 0; + Dwarf_Byte_Ptr section_start = 0; + Dwarf_Unsigned section_len = 0; + Dwarf_Byte_Ptr section_end = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Unsigned exprlen = 0; + Dwarf_Small * addr = attr->ar_debug_ptr; + + info_ptr = addr; + section_start = + _dwarf_calculate_info_section_start_ptr(cu_context, + §ion_len); + section_end = section_start + section_len; + + DECODE_LEB128_UWORD_LEN_CK(info_ptr, exprlen, leb_len, + dbg,error,section_end); + if (exprlen > section_len) { + /* Corrupted dwarf! */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + "The expression length is %u,",exprlen); + dwarfstring_append_printf_u(&m, + " but the section length is just %u. " + "Corrupt Dwarf.",section_len); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + die = attr->ar_die; + /* Is the block entirely in the section, or is + there bug somewhere? + Here the final addr may be 1 past end of section. */ + if (_dwarf_reference_outside_section(die, + (Dwarf_Small *)addr, + ((Dwarf_Small *)addr)+exprlen +leb_len)) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + "The expression length %u,",exprlen); + dwarfstring_append_printf_u(&m, + " plus the leb value length of " + "%u ",leb_len); + dwarfstring_append(&m, + " runs past the end of the section. " + "Corrupt Dwarf."); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *return_exprlen = exprlen; + *block_ptr = addr + leb_len; + return DW_DLV_OK; + + } + { + dwarfstring m; + const char *name = ""; + unsigned mform = attr->ar_attribute_form; + + dwarfstring_constructor(&m); + + dwarf_get_FORM_name (mform,&name); + dwarfstring_append_printf_u(&m, + "DW_DLE_ATTR_EXPRLOC_FORM_BAD: " + "The form is 0x%x ", mform); + dwarfstring_append_printf_s(&m, + "(%s) but should be DW_FORM_exprloc. " + "Corrupt Dwarf.",(char *)name); + _dwarf_error_string(dbg, error, DW_DLE_ATTR_EXPRLOC_FORM_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; +} diff --git a/src/lib/libdwarf/dwarf_form_class_names.c b/src/lib/libdwarf/dwarf_form_class_names.c new file mode 100644 index 0000000..d8f035d --- /dev/null +++ b/src/lib/libdwarf/dwarf_form_class_names.c @@ -0,0 +1,110 @@ +/* +Copyright (c) 2021, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include "libdwarf.h" + +/* FORM_CLASS is created by libdwarf, it is + not a part of Standard Dwarf. Dwarf_Form_Class attempts + to allow convenient processing of FORMs + across DWARF2,3,4, and 5 for libdwarf, + dwarfdump, and other clients and ensures + type-safe referencing. */ +int +dwarf_get_FORM_CLASS_name (enum Dwarf_Form_Class fc, + const char ** s_out) +{ + switch (fc) { + case DW_FORM_CLASS_UNKNOWN: + *s_out = "DW_FORM_CLASS_UNKNOWN"; + return DW_DLV_OK; + case DW_FORM_CLASS_ADDRESS: + *s_out = "DW_FORM_CLASS_ADDRESS"; + return DW_DLV_OK; + case DW_FORM_CLASS_BLOCK: + *s_out = "DW_FORM_CLASS_BLOCK"; + return DW_DLV_OK; + case DW_FORM_CLASS_CONSTANT: + *s_out = "DW_FORM_CLASS_CONSTANT"; + return DW_DLV_OK; + case DW_FORM_CLASS_EXPRLOC: + *s_out = "DW_FORM_CLASS_EXPRLOC"; + return DW_DLV_OK; + case DW_FORM_CLASS_FLAG: + *s_out = "DW_FORM_CLASS_FLAG"; + return DW_DLV_OK; + case DW_FORM_CLASS_LINEPTR: + *s_out = "DW_FORM_CLASS_LINEPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_LOCLISTPTR: + *s_out = "DW_FORM_CLASS_LOCLISTPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_MACPTR: + *s_out = "DW_FORM_CLASS_MACPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_RANGELISTPTR: + *s_out = "DW_FORM_CLASS_RANGELISTPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_REFERENCE: + *s_out = "DW_FORM_CLASS_REFERENCE"; + return DW_DLV_OK; + case DW_FORM_CLASS_STRING: + *s_out = "DW_FORM_CLASS_STRING"; + return DW_DLV_OK; + case DW_FORM_CLASS_FRAMEPTR: + *s_out = "DW_FORM_CLASS_FRAMEPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_MACROPTR: + *s_out = "DW_FORM_CLASS_MAXCROPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_ADDRPTR: + *s_out = "DW_FORM_CLASS_ADDRPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_LOCLIST: + *s_out = "DW_FORM_CLASS_LOCLIST"; + return DW_DLV_OK; + case DW_FORM_CLASS_LOCLISTSPTR: + *s_out = "DW_FORM_CLASS_LOCLISTSPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_RNGLIST: + *s_out = "DW_FORM_CLASS_RNGLIST"; + return DW_DLV_OK; + case DW_FORM_CLASS_RNGLISTSPTR: + *s_out = "DW_FORM_CLASS_RNGLISTSPTR"; + return DW_DLV_OK; + case DW_FORM_CLASS_STROFFSETSPTR: + *s_out = "DW_FORM_CLASS_STROFFSETSPTR"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} diff --git a/src/lib/libdwarf/dwarf_frame.c b/src/lib/libdwarf/dwarf_frame.c new file mode 100644 index 0000000..042b498 --- /dev/null +++ b/src/lib/libdwarf/dwarf_frame.c @@ -0,0 +1,3503 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2022 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ +#include /* memset() */ +#include /* memset() */ +#include /* MAX/MIN() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* Using Arange as a way to build a list */ +#include "dwarf_string.h" +#include "dwarf_safe_arithmetic.h" + +/* Dwarf_Unsigned is always 64 bits */ +#define INVALIDUNSIGNED(x) ((x) & (((Dwarf_Unsigned)1) << 63)) + +#define FDE_NULL_CHECKS_AND_SET_DBG(fde,dbg ) \ + do { \ + if ((fde) == NULL) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_NULL);\ + return DW_DLV_ERROR; \ + } \ + (dbg)= (fde)->fd_dbg; \ + if ((dbg) == NULL) { \ + _dwarf_error_string(NULL, error, DW_DLE_FDE_DBG_NULL,\ + "DW_DLE_FDE_DBG_NULL: An fde contains a stale "\ + "Dwarf_Debug "); \ + return DW_DLV_ERROR; \ + } \ + if ((dbg)->de_magic != DBG_IS_VALID) { \ + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);\ + return DW_DLV_ERROR; \ + } } while (0) + +#define MIN(a,b) (((a) < (b))? (a):(b)) + +#if 0 /* FOR DEBUGGING */ +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +/* Only used for debugging libdwarf. */ +static void dump_frame_rule(char *msg, + struct Dwarf_Reg_Rule_s *reg_rule); +#endif /*0*/ + +static int _dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error); +static void _dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table); +static void _dwarf_init_reg_rules_ru( + struct Dwarf_Reg_Rule_s *base, + Dwarf_Unsigned first, Dwarf_Unsigned last, + Dwarf_Unsigned initial_value); +static void _dwarf_init_reg_rules_dw3( + Dwarf_Regtable_Entry3_i *base, + Dwarf_Unsigned, Dwarf_Unsigned last, + Dwarf_Unsigned initial_value); + +/* The rules for register settings are described + in libdwarf.pdf and the html version. + (see Special Frame Registers). +*/ +static int +regerror(Dwarf_Debug dbg,Dwarf_Error *error, + int enumber, + const char *msg) +{ + _dwarf_error_string(dbg,error,enumber,(char *)msg); + return DW_DLV_ERROR; +} + +int +_dwarf_validate_register_numbers( + Dwarf_Debug dbg, + Dwarf_Error *error) +{ + if (dbg->de_frame_same_value_number == + dbg->de_frame_undefined_value_number) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "same_value == undefined_value"); + } + if (dbg->de_frame_cfa_col_number == + dbg->de_frame_same_value_number) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "same_value == cfa_column_number "); + } + if (dbg->de_frame_cfa_col_number == + dbg->de_frame_undefined_value_number) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "undefined_value == cfa_column_number "); + } + if ((dbg->de_frame_rule_initial_value != + dbg->de_frame_same_value_number) && + (dbg->de_frame_rule_initial_value != + dbg->de_frame_undefined_value_number)) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "initial_value not set to " + " same_value or undefined_value"); + } + if (dbg->de_frame_undefined_value_number <= + dbg->de_frame_reg_rules_entry_count) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "undefined_value less than number of registers"); + } + if (dbg->de_frame_same_value_number <= + dbg->de_frame_reg_rules_entry_count) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "same_value <= number of registers"); + } + if (dbg->de_frame_cfa_col_number <= + dbg->de_frame_reg_rules_entry_count) { + return regerror(dbg,error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR " + "cfa_column <= number of registers"); + } + return DW_DLV_OK; +} + +int +dwarf_get_frame_section_name(Dwarf_Debug dbg, + const char **sec_name, + Dwarf_Error *error) +{ + struct Dwarf_Section_s *sec = 0; + if (error != NULL) { + *error = NULL; + } + sec = &dbg->de_debug_frame; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *sec_name = sec->dss_name; + return DW_DLV_OK; +} + +int +dwarf_get_frame_section_name_eh_gnu(Dwarf_Debug dbg, + const char **sec_name, + Dwarf_Error *error) +{ + struct Dwarf_Section_s *sec = 0; + if (error != NULL) { + *error = NULL; + } + sec = &dbg->de_debug_frame_eh_gnu; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *sec_name = sec->dss_name; + return DW_DLV_OK; +} + +/* + This function is the heart of the debug_frame stuff. Don't even + think of reading this without reading both the Libdwarf and + consumer API carefully first. This function executes + frame instructions contained in a Cie or an Fde, but does in a + number of different ways depending on the information sought. + Start_instr_ptr points to the first byte of the frame instruction + stream, and final_instr_ptr one past the last byte. + + The offsets returned in the frame instructions are factored. That + is they need to be multiplied by either the code_alignment_factor + or the data_alignment_factor, as appropriate to obtain the actual + offset. This makes it possible to expand an instruction stream + without the corresponding Cie. However, when an Fde frame instr + sequence is being expanded there must be a valid Cie + with a pointer to an initial table row. + + If successful, returns DW_DLV_OK + And sets returned_count thru the pointer + if make_instr is true. + If make_instr is false returned_count + should NOT be used by the caller (returned_count + is set to 0 thru the pointer by this routine...) + If unsuccessful, returns DW_DLV_ERROR + and sets returned_error to the error code + + It does not do a whole lot of input validation being a private + function. Please make sure inputs are valid. + + (1) If make_instr is true, it makes a list of pointers to + Dwarf_Frame_Op structures containing the frame instructions + executed. A pointer to this list is returned in ret_frame_instr. + Make_instr is true only when a list of frame instructions is to be + returned. In this case since we are not interested + in the contents + of the table, the input Cie can be NULL. This is the only case + where the input Cie can be NULL. + + (2) If search_pc is true, frame instructions are executed till + either a location is reached that is greater than the + search_pc_val + provided, or all instructions are executed. At this point the + last row of the table generated is returned in a structure. + A pointer to this structure is supplied in table. + + (3) This function is also used to create the initial table row + defined by a Cie. In this case, the Dwarf_Cie pointer cie, is + NULL. For an FDE, however, cie points to the associated Cie. + + (4) If search_pc is true and (has_more_rows and subsequent_pc + are non-null) then: + has_more_rows is set true if there are instruction + bytes following the detection of search_over. + If all the instruction bytes have been seen + then *has_more_rows is set false. + + If *has_more_rows is true then *subsequent_pc + is set to the pc value that is the following + row in the table. + + make_instr - make list of frame instr? 0/1 + ret_frame_instr - Ptr to list of ptrs to frame instrs + search_pc - Search for a pc value? 0/1 + search_pc_val - Search for this pc value + initial_loc - Initial code location value. + start_instr_ptr - Ptr to start of frame instrs. + final_instr_ptr - Ptr just past frame instrs. + table - Ptr to struct with last row. + cie - Ptr to Cie used by the Fde. + + Different cies may have distinct address-sizes, so the cie + is used, not de_pointer_size. + +*/ + +/* Cleans up the in-process linked list of these + in case of early exit in + _dwarf_exec_frame_instr. */ +static void +_dwarf_free_dfi_list(Dwarf_Frame_Instr fr) +{ + Dwarf_Frame_Instr cur = fr; + Dwarf_Frame_Instr next = 0; + for ( ; cur ; cur = next) { + next = cur->fi_next; + free(cur); + } +} +#if 0 +static void +printlist(Dwarf_Frame_Instr x) +{ + int i = 0; + Dwarf_Frame_Instr nxt = 0; + + printf("=========== print cur list of ptrs\n"); + for ( ; x ; x = nxt,++i) { + printf("%d inst 0x%lx nxt 0x%lx\n", + i,(unsigned long)x, + (unsigned long)x->fi_next); + nxt = x->fi_next; + } + printf("=========== done cur list of ptrs\n"); +} +#endif /*0*/ + +int +_dwarf_exec_frame_instr(Dwarf_Bool make_instr, + Dwarf_Bool search_pc, + Dwarf_Addr search_pc_val, + Dwarf_Addr initial_loc, + Dwarf_Small * start_instr_ptr, + Dwarf_Small * final_instr_ptr, + Dwarf_Frame table, + Dwarf_Cie cie, + Dwarf_Debug dbg, + Dwarf_Unsigned reg_num_of_cfa, + Dwarf_Bool * has_more_rows, + Dwarf_Addr * subsequent_pc, + Dwarf_Frame_Instr_Head *ret_frame_instr_head, + Dwarf_Unsigned * returned_frame_instr_count, + Dwarf_Error *error) +{ +/* The following macro depends on macreg and + machigh_reg both being unsigned to avoid + unintended behavior and to avoid compiler warnings when + high warning levels are turned on. To avoid + truncation turning a bogus large value into a smaller + sensible-seeming value we use Dwarf_Unsigned for register + numbers. */ +#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \ + do { \ + if ((macreg) >= (machigh_reg)) { \ + SER(DW_DLE_DF_REG_NUM_TOO_HIGH); \ + } \ + } /*CONSTCOND */ while (0) +#define FREELOCALMALLOC \ + _dwarf_free_dfi_list(ilisthead); \ + ilisthead =0; \ + free(dfi); dfi = 0; \ + free(localregtab); localregtab = 0; +/* SER === SIMPLE_ERROR_RETURN */ +#define SER(code) \ + FREELOCALMALLOC; \ + _dwarf_error(dbg,error,(code)); \ + return DW_DLV_ERROR +#define SERSTRING(code,m) \ + FREELOCALMALLOC; \ + _dwarf_error_string(dbg,error,(code),m); \ + return DW_DLV_ERROR +/* m must be a quoted string */ +#define SERINST(m) \ + FREELOCALMALLOC; \ + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, \ + "DW_DLE_ALLOC_FAIL: " m); \ + return DW_DLV_ERROR + + /* Sweeps the frame instructions. */ + Dwarf_Small *instr_ptr = 0; + Dwarf_Frame_Instr dfi = 0; + + /* Register numbers not limited to just 255, + thus not using Dwarf_Small. */ + typedef Dwarf_Unsigned reg_num_type; + + Dwarf_Unsigned factored_N_value = 0; + Dwarf_Signed signed_factored_N_value = 0; + Dwarf_Addr current_loc = initial_loc; /* code location/ + pc-value corresponding to the frame instructions. + Starts at zero when the caller has no value to pass in. */ + + /* Must be min de_pointer_size bytes and must be at least 4 */ + Dwarf_Unsigned adv_loc = 0; + + Dwarf_Unsigned reg_count = dbg->de_frame_reg_rules_entry_count; + struct Dwarf_Reg_Rule_s *localregtab = calloc(reg_count, + sizeof(struct Dwarf_Reg_Rule_s)); + + struct Dwarf_Reg_Rule_s cfa_reg; + + /* This is used to end executing frame instructions. */ + /* Becomes true when search_pc is true and current_loc */ + /* is greater than search_pc_val. */ + Dwarf_Bool search_over = false; + + Dwarf_Addr possible_subsequent_pc = 0; + + Dwarf_Half address_size = (cie)? cie->ci_address_size: + dbg->de_pointer_size; + + /* Stack_table points to the row (Dwarf_Frame ie) being + pushed or popped by a remember or restore instruction. + Top_stack points to + the top of the stack of rows. */ + Dwarf_Frame stack_table = NULL; + Dwarf_Frame top_stack = NULL; + + /* These are used only when make_instr is true. Curr_instr is a + pointer to the current frame instruction executed. + Curr_instr_ptr, head_instr_list, and curr_instr_list are + used to form a chain of Dwarf_Frame_Op structs. + Dealloc_instr_ptr is + used to deallocate the structs used to form the chain. + Head_instr_block points to a contiguous list of + pointers to the + Dwarf_Frame_Op structs executed. */ + /* Build single linked list of instrs, and + at end turn into array. */ + Dwarf_Frame_Instr ilisthead = 0; + Dwarf_Frame_Instr *ilistlastptr = &ilisthead; + /* Counts the number of frame instructions + in the returned instrs if instruction + details are asked for. Else 0. */ + Dwarf_Unsigned instr_count = 0; + + /* These are the alignment_factors taken from the Cie provided. + When no input Cie is provided they are set to 1, because only + factored offsets are required. */ + Dwarf_Signed code_alignment_factor = 1; + Dwarf_Signed data_alignment_factor = 1; + + /* This flag indicates when an actual alignment factor + is needed. + So if a frame instruction that computes an offset + using an alignment factor is encountered when this + flag is set, an error is returned because the Cie + did not have a valid augmentation. */ + Dwarf_Bool need_augmentation = false; + Dwarf_Unsigned instr_area_length = 0; + + Dwarf_Unsigned i = 0; + + /* Initialize first row from associated Cie. + Using temp regs explicitly */ + + if (!localregtab) { + SER(DW_DLE_ALLOC_FAIL); + } + { + struct Dwarf_Reg_Rule_s *t1reg = localregtab; + if (cie != NULL && cie->ci_initial_table != NULL) { + unsigned minregcount = 0; + unsigned curreg = 0; + struct Dwarf_Reg_Rule_s *t2reg = + cie->ci_initial_table->fr_reg; + + if (reg_count != cie->ci_initial_table->fr_reg_count) { + /* Should never happen, + it makes no sense to have the + table sizes change. There + is no real allowance for + the set of registers + to change dynamically + in a single Dwarf_Debug + (except the size can be set + near initial Dwarf_Debug + creation time). */ + SER(DW_DLE_FRAME_REGISTER_COUNT_MISMATCH); + } + minregcount = + MIN(reg_count,cie->ci_initial_table->fr_reg_count); + for ( ; curreg < minregcount ; + curreg++, t1reg++, t2reg++) { + *t1reg = *t2reg; + } cfa_reg = + cie->ci_initial_table->fr_cfa_rule; + } else { + _dwarf_init_reg_rules_ru(localregtab,0,reg_count, + dbg->de_frame_rule_initial_value); + _dwarf_init_reg_rules_ru(&cfa_reg,0, 1, + dbg->de_frame_rule_initial_value); + } + } + /* The idea here is that the code_alignment_factor and + data_alignment_factor which are needed for certain + instructions are valid only when the Cie has a proper + augmentation string. So if the augmentation is not + right, only Frame instruction can be read. */ + if (cie != NULL && cie->ci_augmentation != NULL) { + code_alignment_factor = cie->ci_code_alignment_factor; + data_alignment_factor = cie->ci_data_alignment_factor; + } else { + need_augmentation = !make_instr; + } + instr_ptr = start_instr_ptr; + instr_area_length = (uintptr_t) + (final_instr_ptr - start_instr_ptr); + while ((instr_ptr < final_instr_ptr) && (!search_over)) { + Dwarf_Small instr = 0; + Dwarf_Small opcode = 0; + reg_num_type reg_no = 0; + Dwarf_Unsigned adv_pc = 0; + Dwarf_Off fp_instr_offset = 0; + Dwarf_Small * base_instr_ptr = 0; + + if (instr_ptr < start_instr_ptr) { + SERINST("DW_DLE_DF_NEW_LOC_LESS_OLD_LOC: " + "Following instruction bytes we find impossible " + "decrease in a pointer"); + } + fp_instr_offset = instr_ptr - start_instr_ptr; + if (instr_ptr >= final_instr_ptr) { + _dwarf_error(NULL, error, DW_DLE_DF_FRAME_DECODING_ERROR); + return DW_DLV_ERROR; + } + instr = *(Dwarf_Small *) instr_ptr; + instr_ptr += sizeof(Dwarf_Small); + base_instr_ptr = instr_ptr; + if ((instr & 0xc0) == 0x00) { + opcode = instr; /* is really extended op */ + } else { + opcode = instr & 0xc0; /* is base op */ + } + if (make_instr) { + dfi = calloc(1,sizeof(*dfi)); + if (!dfi) { + SERINST("DW_CFA_advance_loc out of memory"); + } + dfi->fi_op = opcode; + dfi->fi_instr_offset = fp_instr_offset; + dfi->fi_fields = ""; + } + switch (opcode) { + case DW_CFA_lo_user: { + if (make_instr) { + dfi->fi_fields = ""; + } + } + break; + case DW_CFA_advance_loc: { + Dwarf_Unsigned adv_pc_val = 0; + int alres = 0; + + /* base op */ + adv_pc_val = instr &DW_FRAME_INSTR_OFFSET_MASK; + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + + /* CHECK OVERFLOW */ + alres = _dwarf_uint64_mult(adv_pc_val, + code_alignment_factor,&adv_pc,dbg,error); + if (alres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return DW_DLV_ERROR; + } + if (INVALIDUNSIGNED(adv_pc)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "negative new location"); + } + + possible_subsequent_pc = current_loc + + (Dwarf_Unsigned)adv_pc; + if (possible_subsequent_pc < current_loc && + possible_subsequent_pc < adv_pc) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "add overflowed"); + } + + search_over = search_pc && + (possible_subsequent_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "uc"; + dfi->fi_u0 = adv_pc_val; + dfi->fi_code_align_factor = code_alignment_factor; + } + } + break; + case DW_CFA_offset: { /* base op */ + int adres = 0; + Dwarf_Signed result = 0; + reg_no = (reg_num_type) (instr & + DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER( DW_DLE_DF_NO_CIE_AUGMENTATION); + } + if (INVALIDUNSIGNED(factored_N_value)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "negative factored_N_value location"); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult( + (Dwarf_Signed)factored_N_value, + data_alignment_factor, + &result,dbg, error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return DW_DLV_ERROR; + } + localregtab[reg_no].ru_offset = result; + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + if (make_instr) { + dfi->fi_fields = "rud"; + dfi->fi_u0 = reg_no; + dfi->fi_u1 = factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + case DW_CFA_restore: { /* base op */ + reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK); + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + if (cie != NULL && cie->ci_initial_table != NULL) { + localregtab[reg_no] = + cie->ci_initial_table->fr_reg[reg_no]; + } else if (!make_instr) { + SER(DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + if (make_instr) { + dfi->fi_fields = "r"; + dfi->fi_u0 = reg_no; + } + } + break; + case DW_CFA_set_loc: { + Dwarf_Addr new_loc = 0; + int adres = 0; + adres=_dwarf_read_unaligned_ck_wrapper(dbg, + &new_loc, + instr_ptr, address_size, + final_instr_ptr,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + instr_ptr += address_size; + if (new_loc != 0 && current_loc != 0) { + /* Pre-relocation or before current_loc + is set the test comparing new_loc + and current_loc makes no + sense. Testing for non-zero (above) is a way + (fallible) to check that current_loc, new_loc + are already relocated. */ + if (new_loc <= current_loc) { + /* Within a frame, address must increase. + Seemingly it has not. + Seems to be an error. */ + SER(DW_DLE_DF_NEW_LOC_LESS_OLD_LOC); + } + } + search_over = search_pc && (new_loc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + possible_subsequent_pc = new_loc; + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "u"; + dfi->fi_u0 = new_loc; + } + } + break; + case DW_CFA_advance_loc1: + { + int adres = 0; + Dwarf_Unsigned advloc_val = 0; + adres=_dwarf_read_unaligned_ck_wrapper(dbg, + &advloc_val, + instr_ptr, sizeof(Dwarf_Small), + final_instr_ptr,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + instr_ptr += sizeof(Dwarf_Small); + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_uint64_mult( + advloc_val, + code_alignment_factor, + &adv_loc,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + + /* CHECK OVERFLOW add */ + possible_subsequent_pc = current_loc + adv_loc; + if (possible_subsequent_pc < current_loc && + possible_subsequent_pc < adv_loc) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "add overflowed calcating subsequent pc"); + } + search_over = search_pc && + (possible_subsequent_pc > search_pc_val); + + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "uc"; + dfi->fi_u0 = advloc_val; + dfi->fi_code_align_factor = + code_alignment_factor; + } + break; + } + + case DW_CFA_advance_loc2: + { + int adres = 0; + Dwarf_Unsigned advloc_val = 0; + adres=_dwarf_read_unaligned_ck_wrapper(dbg, &advloc_val, + instr_ptr, DWARF_HALF_SIZE, + final_instr_ptr,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + instr_ptr += DWARF_HALF_SIZE; + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_uint64_mult( + advloc_val, + code_alignment_factor, + &adv_loc,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + /* CHECK OVERFLOW add */ + if (INVALIDUNSIGNED(adv_loc)) { + SERSTRING( DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "negative new location"); + } + + /* CHECK OVERFLOW add */ + possible_subsequent_pc = current_loc + adv_loc; + if (possible_subsequent_pc < current_loc && + possible_subsequent_pc < adv_loc) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "add overflowed"); + } + search_over = search_pc && + (possible_subsequent_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "uc"; + dfi->fi_u0 = advloc_val; + dfi->fi_code_align_factor = + code_alignment_factor; + } + break; + } + + case DW_CFA_advance_loc4: + { + int adres = 0; + Dwarf_Unsigned advloc_val = 0; + + adres=_dwarf_read_unaligned_ck_wrapper(dbg, &advloc_val, + instr_ptr, DWARF_32BIT_SIZE, + final_instr_ptr,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + instr_ptr += DWARF_32BIT_SIZE; + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_uint64_mult( + advloc_val, + code_alignment_factor, + &adv_loc,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + /* CHECK OVERFLOW add */ + possible_subsequent_pc = current_loc + adv_loc; + if (possible_subsequent_pc < current_loc && + possible_subsequent_pc < adv_loc) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "unsigned add overflowed"); + } + + search_over = search_pc && + (possible_subsequent_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "uc"; + dfi->fi_u0 = advloc_val; + dfi->fi_code_align_factor = + code_alignment_factor; + } + break; + } + case DW_CFA_MIPS_advance_loc8: + { + int adres = 0; + Dwarf_Unsigned advloc_val = 0; + adres=_dwarf_read_unaligned_ck_wrapper(dbg, &advloc_val, + instr_ptr, DWARF_64BIT_SIZE, + final_instr_ptr,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + instr_ptr += DWARF_64BIT_SIZE; + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_uint64_mult(advloc_val, + code_alignment_factor,&adv_loc, + dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + /* CHECK OVERFLOW add */ + possible_subsequent_pc = current_loc + adv_loc; + if (possible_subsequent_pc < current_loc && + possible_subsequent_pc < adv_loc) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "unsigned add overflowed"); + } + search_over = search_pc && + (possible_subsequent_pc > search_pc_val); + /* If gone past pc needed, retain old pc. */ + if (!search_over) { + current_loc = possible_subsequent_pc; + } + if (make_instr) { + dfi->fi_fields = "u"; + dfi->fi_u0 = advloc_val; + dfi->fi_code_align_factor = + code_alignment_factor; + } + break; + } + + case DW_CFA_offset_extended: + { + Dwarf_Unsigned lreg = 0; + Dwarf_Signed result = 0; + int adres = 0; + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + if (INVALIDUNSIGNED(factored_N_value)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "negative new location"); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult((Dwarf_Signed)factored_N_value, + data_alignment_factor, &result, + dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rud"; + dfi->fi_u0 = lreg; + dfi->fi_u1 = factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + break; + } + + case DW_CFA_restore_extended: + { + Dwarf_Unsigned lreg = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + if (cie != NULL && cie->ci_initial_table != NULL) { + localregtab[reg_no] = + cie->ci_initial_table->fr_reg[reg_no]; + } else { + if (!make_instr) { + SER(DW_DLE_DF_MAKE_INSTR_NO_INIT); + } + } + if (make_instr) { + dfi->fi_fields = "r"; + dfi->fi_u0 = lreg; + } + break; + } + + case DW_CFA_undefined: + { + Dwarf_Unsigned lreg = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + localregtab[reg_no].ru_is_offset = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = + dbg->de_frame_undefined_value_number; + localregtab[reg_no].ru_offset = 0; + if (make_instr) { + dfi->fi_fields = "r"; + dfi->fi_u0 = lreg; + } + break; + } + + case DW_CFA_same_value: + { + Dwarf_Unsigned lreg = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + localregtab[reg_no].ru_is_offset = 0; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = + dbg->de_frame_same_value_number; + localregtab[reg_no].ru_offset = 0; + if (make_instr) { + dfi->fi_fields = "r"; + dfi->fi_u0 = lreg; + } + break; + } + + case DW_CFA_register: + { + Dwarf_Unsigned lreg; + reg_num_type reg_noA = 0; + reg_num_type reg_noB = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_noA = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_noB = (reg_num_type) lreg; + if (reg_noB > reg_count) { + SER(DW_DLE_DF_REG_NUM_TOO_HIGH); + } + localregtab[reg_noA].ru_is_offset = 0; + localregtab[reg_noA].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_noA].ru_register = reg_noB; + localregtab[reg_noA].ru_offset = 0; + if (make_instr) { + dfi->fi_fields = "rr"; + dfi->fi_u0 = reg_noA; + dfi->fi_u1 = reg_noB; + } + break; + } + + case DW_CFA_remember_state: + { + stack_table = (Dwarf_Frame) + _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1); + if (stack_table == NULL) { + SER(DW_DLE_DF_ALLOC_FAIL); + } + for (i = 0; i < reg_count; i++) { + stack_table->fr_reg[i] = localregtab[i]; + } + stack_table->fr_cfa_rule = cfa_reg; + if (top_stack != NULL) { + stack_table->fr_next = top_stack; + } + top_stack = stack_table; + if (make_instr) { + dfi->fi_fields = ""; + } + } + break; + case DW_CFA_restore_state: + { + if (top_stack == NULL) { + SER(DW_DLE_DF_POP_EMPTY_STACK); + } + stack_table = top_stack; + top_stack = stack_table->fr_next; + for (i = 0; i < reg_count; i++) { + localregtab[i] = stack_table->fr_reg[i]; + } + cfa_reg = stack_table->fr_cfa_rule; + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + if (make_instr) { + dfi->fi_fields = ""; + } + break; + } + + case DW_CFA_def_cfa: + { + Dwarf_Unsigned lreg = 0; + int adres = 0; + Dwarf_Off nonfactoredoffset = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &nonfactoredoffset,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + cfa_reg.ru_is_offset = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + if (INVALIDUNSIGNED(nonfactoredoffset)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "DW_CFA_def_cfa offset unrepresantable " + "as signed"); + } + cfa_reg.ru_offset = (Dwarf_Signed)nonfactoredoffset; + if (make_instr) { + dfi->fi_fields = "ru"; + dfi->fi_u0 = lreg; + dfi->fi_u1 = nonfactoredoffset; + } + break; + } + + case DW_CFA_def_cfa_register: + { + Dwarf_Unsigned lreg = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + cfa_reg.ru_register = (Dwarf_Half)reg_no; + /* Do NOT set ru_offset_or_block_len or + ru_is_off here. + See dwarf2/3 spec. */ + if (make_instr) { + dfi->fi_fields = "r"; + dfi->fi_u0 = lreg; + } + break; + } + + case DW_CFA_def_cfa_offset: + { + int adres = 0; + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_offset = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + if (INVALIDUNSIGNED(factored_N_value)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "DW_CFA_def_cfa_offset unrepresantable " + "as signed"); + } + cfa_reg.ru_offset = (Dwarf_Signed)factored_N_value; + if (make_instr) { + dfi->fi_fields = "u"; + dfi->fi_u0 = factored_N_value; + } + break; + } + /* This is for Metaware with augmentation string HC + We do not really know what to do with it. */ + case DW_CFA_METAWARE_info: + { + int adres = 0; + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + /* Not really known what the value means or is. */ + cfa_reg.ru_is_offset = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + if (INVALIDUNSIGNED(factored_N_value)) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "DW_CFA_METAWARE_info unrepresantable as signed"); + } + cfa_reg.ru_offset = (Dwarf_Signed)factored_N_value; + if (make_instr) { + dfi->fi_fields = "u"; + dfi->fi_u0 = factored_N_value; + } + break; + } + case DW_CFA_nop: + { + if (make_instr) { + dfi->fi_fields = ""; + } + break; + } + /* DWARF3 ops begin here. */ + case DW_CFA_def_cfa_expression: { + /* A single DW_FORM_block representing a dwarf + expression. The form block establishes the way to + compute the CFA. */ + Dwarf_Unsigned block_len = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &block_len,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + cfa_reg.ru_is_offset = 0; /* arbitrary */ + cfa_reg.ru_value_type = DW_EXPR_EXPRESSION; + cfa_reg.ru_block.bl_len = block_len; + cfa_reg.ru_block.bl_data = instr_ptr; + if (make_instr) { + dfi->fi_fields = "b"; + dfi->fi_expr.bl_len = block_len; + dfi->fi_expr.bl_data = instr_ptr; + } + if (block_len >= instr_area_length) { + SERSTRING(DW_DLE_DF_FRAME_DECODING_ERROR, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "DW_CFA_def_cfa_expression " + "block len overflows instructions " + "available range."); + } + instr_ptr += block_len; + if (instr_area_length < block_len || + instr_ptr < base_instr_ptr) { + SERSTRING(DW_DLE_DF_FRAME_DECODING_ERROR, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "DW_CFA_def_cfa_expression " + "block len overflows instructions " + "available range."); + } + } + break; + case DW_CFA_expression: { + /* An unsigned leb128 value is the first operand (a + register number). The second operand is single + DW_FORM_block representing a dwarf expression. The + evaluator pushes the CFA on the evaluation stack + then evaluates the expression to compute the value + of the register contents. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &block_len,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + localregtab[lreg].ru_is_offset = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = DW_EXPR_EXPRESSION; + localregtab[lreg].ru_block.bl_data = instr_ptr; + localregtab[lreg].ru_block.bl_len = block_len; + if (make_instr) { + dfi->fi_fields = "rb"; + dfi->fi_u0 = lreg; + dfi->fi_expr.bl_len = block_len; + dfi->fi_expr.bl_data = instr_ptr; + } + instr_ptr += block_len; + if (instr_area_length < block_len || + instr_ptr < base_instr_ptr) { + SERSTRING(DW_DLE_DF_FRAME_DECODING_ERROR, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "DW_CFA_expression " + "block len overflows instructions " + "available range."); + } + } + break; + case DW_CFA_offset_extended_sf: { + /* The first operand is an unsigned leb128 register + number. The second is a signed factored offset. + Identical to DW_CFA_offset_extended except the + second operand is signed */ + Dwarf_Unsigned lreg = 0; + int adres = 0; + Dwarf_Signed result = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_sword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &signed_factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult(signed_factored_N_value, + data_alignment_factor, + &result,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rsd"; + dfi->fi_u0 = lreg; + dfi->fi_s1 = signed_factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + case DW_CFA_def_cfa_sf: { + /* The first operand is an unsigned leb128 register + number. The second is a signed leb128 factored + offset. Identical to DW_CFA_def_cfa except + that the second operand is signed + and factored. */ + Dwarf_Unsigned lreg = 0; + int adres = 0; + Dwarf_Signed result =0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_sword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &signed_factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult(signed_factored_N_value, + data_alignment_factor, + &result,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + cfa_reg.ru_is_offset = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_register = reg_no; + cfa_reg.ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rsd"; + dfi->fi_u0 = lreg; + dfi->fi_s1 = signed_factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + case DW_CFA_def_cfa_offset_sf: { + /* The operand is a signed leb128 operand + representing a factored offset. Identical to + DW_CFA_def_cfa_offset except the operand is + signed and factored. */ + int adres = 0; + Dwarf_Signed result = 0; + + adres = _dwarf_leb128_sword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &signed_factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult(signed_factored_N_value, + data_alignment_factor, + &result,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + cfa_reg.ru_is_offset = 1; + cfa_reg.ru_value_type = DW_EXPR_OFFSET; + cfa_reg.ru_offset = result; + if (make_instr) { + dfi->fi_fields = "sd"; + dfi->fi_s0 = signed_factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + case DW_CFA_val_offset: { + /* The first operand is an unsigned leb128 register + number. The second is a factored unsigned offset. + Makes the register be a val_offset(N) + rule with N = + factored_offset*data_alignment_factor. */ + Dwarf_Unsigned lreg = 0; + int adres = 0; + Dwarf_Signed result = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (INVALIDUNSIGNED(factored_N_value) ) { + SERSTRING(DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "in DW_CFA_val_offset factored value"); + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult( + (Dwarf_Signed)factored_N_value, + data_alignment_factor, + &result,dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_value_type = + DW_EXPR_VAL_OFFSET; + /* CHECK OVERFLOW */ + localregtab[reg_no].ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rud"; + dfi->fi_u0 = lreg; + dfi->fi_u1 = factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + break; + } + case DW_CFA_val_offset_sf: { + /* The first operand is an unsigned leb128 register + number. The second is a factored signed offset. + Makes the register be a val_offset(N) rule + with + N = factored_offset*data_alignment_factor. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Signed result = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_sword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &signed_factored_N_value,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (need_augmentation) { + SER(DW_DLE_DF_NO_CIE_AUGMENTATION); + } + adres = _dwarf_int64_mult(signed_factored_N_value, + data_alignment_factor,&result, + dbg,error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return adres; + } + /* Do set ru_is_off here, as here factored_N_value + counts. */ + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_value_type = + DW_EXPR_VAL_OFFSET; + /* CHECK OVERFLOW */ + localregtab[reg_no].ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rsd"; + dfi->fi_u0 = lreg; + dfi->fi_s1 = signed_factored_N_value; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + case DW_CFA_val_expression: { + /* The first operand is an unsigned leb128 register + number. The second is a DW_FORM_block + representing a + DWARF expression. The rule for the register + number becomes a val_expression(E) rule. */ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned block_len = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + reg_no = (reg_num_type) lreg; + ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &block_len,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + localregtab[lreg].ru_is_offset = 0; /* arbitrary */ + localregtab[lreg].ru_value_type = + DW_EXPR_VAL_EXPRESSION; + localregtab[lreg].ru_offset = 0; + localregtab[lreg].ru_block.bl_data = instr_ptr; + localregtab[lreg].ru_block.bl_len = block_len; + if (make_instr) { + dfi->fi_fields = "rb"; + dfi->fi_u0 = lreg; + dfi->fi_expr.bl_len = block_len; + dfi->fi_expr.bl_data = instr_ptr; + } + instr_ptr += block_len; + if (instr_area_length < block_len || + instr_ptr < base_instr_ptr) { + SERSTRING(DW_DLE_DF_FRAME_DECODING_ERROR, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "DW_CFA_val_expression " + "block len overflows instructions " + "available range."); + } + } + break; + /* END DWARF3 new ops. */ + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save: { + /* No information: this just tells + unwinder to restore + the window registers from the previous frame's + window save area */ + if (make_instr) { + dfi->fi_fields = ""; + } + } + break; +#endif +#ifdef DW_CFA_GNU_args_size + /* Single uleb128 is the current arg area + size in bytes. No + register exists yet to save this in. + the value of must be added to + an x86 register to get the correct + stack pointer. + https://lists.nongnu.org/archive/html/ + libunwind-devel/2016-12/msg00004.html + https://refspecs.linuxfoundation.org/ + LSB_3.0.0/LSB-PDA/LSB-PDA.junk/dwarfext.html + */ + case DW_CFA_GNU_args_size: { + Dwarf_Unsigned asize = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &asize,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + /* Currently not put into ru_* reg rules, not + sure what to do with it. */ + /* This is the total size of arguments + pushed on the stack. */ + if (make_instr) { + dfi->fi_fields = "u"; + dfi->fi_u0 = asize; + } + } + break; +#endif + case DW_CFA_LLVM_def_aspace_cfa: { + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned addrspace = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + ERROR_IF_REG_NUM_TOO_HIGH(lreg, reg_count); + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &offset,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &addrspace,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + if (make_instr) { + dfi->fi_fields = "rua"; + dfi->fi_u0 = lreg; + dfi->fi_u1 = offset; + dfi->fi_u2 = addrspace; + } + } + break; + case DW_CFA_LLVM_def_aspace_cfa_sf: { + Dwarf_Unsigned lreg = 0; + Dwarf_Signed offset = 0; + Dwarf_Signed result = 0; + Dwarf_Unsigned addrspace = 0; + int adres = 0; + + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &lreg,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + ERROR_IF_REG_NUM_TOO_HIGH(lreg, reg_count); + adres = _dwarf_leb128_sword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &offset,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + adres = _dwarf_leb128_uword_wrapper(dbg, + &instr_ptr,final_instr_ptr, + &addrspace,error); + if (adres != DW_DLV_OK) { + FREELOCALMALLOC; + return adres; + } + /* CHECK OVERFLOW */ + adres = _dwarf_int64_mult( + (Dwarf_Signed)offset, + data_alignment_factor, + &result,dbg, error); + if (adres == DW_DLV_ERROR) { + FREELOCALMALLOC; + return DW_DLV_ERROR; + } + localregtab[reg_no].ru_is_offset = 1; + localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET; + localregtab[reg_no].ru_register = reg_num_of_cfa; + localregtab[reg_no].ru_offset = result; + if (make_instr) { + dfi->fi_fields = "rsda"; + dfi->fi_u0 = lreg; + dfi->fi_s1 = offset; + dfi->fi_u2 = addrspace; + dfi->fi_data_align_factor = + data_alignment_factor; + } + } + break; + default: { + /* ERROR, we have an opcode we know nothing + about. Memory leak here, but an error + like this is not supposed to + happen so we ignore the leak. + These used to be ignored, + now we notice and report. */ + dwarfstring ms; + + dwarfstring_constructor(&ms); + dwarfstring_append_printf_u(&ms, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "instr opcode 0x%x unknown",opcode); + _dwarf_error_string(dbg,error, + DW_DLE_DF_FRAME_DECODING_ERROR, + dwarfstring_string(&ms)); + dwarfstring_destructor(&ms); + FREELOCALMALLOC; + return DW_DLV_ERROR; + } + } + if (make_instr) { + /* add dfi to end of singly-linked list */ + instr_count++; + (*ilistlastptr) = dfi; + ilistlastptr = &dfi->fi_next; + /* dfi itself is stale, the pointer is on the list */ + dfi = 0; + } + } /* end for-loop on ops */ + + /* If frame instruction decoding was right we would + stop exactly at + final_instr_ptr. */ + if (instr_ptr > final_instr_ptr) { + SER(DW_DLE_DF_FRAME_DECODING_ERROR); + } + /* If search_over is set the last instr was an advance_loc + so we are not done with rows. */ + if ((instr_ptr == final_instr_ptr) && !search_over) { + if (has_more_rows) { + *has_more_rows = false; + } + if (subsequent_pc) { + *subsequent_pc = 0; + } + } else { + if (has_more_rows) { + *has_more_rows = true; + } + if (subsequent_pc) { + *subsequent_pc = possible_subsequent_pc; + } + } + + /* Fill in the actual output table, the space the + caller passed in. */ + if (table) { + + struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg; + struct Dwarf_Reg_Rule_s *t3reg = localregtab; + unsigned minregcount = MIN(table->fr_reg_count,reg_count); + unsigned curreg = 0; + + table->fr_loc = current_loc; + for (; curreg < minregcount ; curreg++, t3reg++, t2reg++) { + *t2reg = *t3reg; + } + + /* CONSTCOND */ + /* Do not update the main table with the cfa_reg. + Just leave cfa_reg as cfa_reg. */ + table->fr_cfa_rule = cfa_reg; + } + /* Dealloc anything remaining on stack. */ + for (; top_stack != NULL;) { + stack_table = top_stack; + top_stack = top_stack->fr_next; + dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME); + } + if (make_instr) { + Dwarf_Frame_Instr_Head head = 0; + Dwarf_Frame_Instr *instrptrs = 0; + Dwarf_Frame_Instr *curinstrptr = 0; + Dwarf_Frame_Instr cur = 0; + Dwarf_Frame_Instr next = 0; + Dwarf_Unsigned ic = 0; + + head= (Dwarf_Frame_Instr_Head) + _dwarf_get_alloc(dbg, DW_DLA_FRAME_INSTR_HEAD,1); + if (!head) { + SER(DW_DLE_DF_ALLOC_FAIL); + } + instrptrs= (Dwarf_Frame_Instr *) + _dwarf_get_alloc(dbg, DW_DLA_LIST,instr_count); + if (!instrptrs) { + dwarf_dealloc(dbg,head,DW_DLA_FRAME_INSTR_HEAD); + SER(DW_DLE_DF_ALLOC_FAIL); + } + head->fh_array = instrptrs; + head->fh_array_count = instr_count; + head->fh_dbg = dbg; + head->fh_cie = cie; + cur = ilisthead; + curinstrptr = instrptrs; + for ( ; cur ; ic++,cur = next,++curinstrptr) { + *curinstrptr = cur; + next = cur->fi_next; + cur->fi_next = 0; + } + ilisthead = 0; + if (ic != instr_count) { + dwarfstring m; + + FREELOCALMALLOC; + dwarf_dealloc(dbg,head,DW_DLA_FRAME_INSTR_HEAD); + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DF_FRAME_DECODING_ERROR: " + "Instruction array build, instr count %u", + instr_count); + dwarfstring_append_printf_u(&m, + " index i %u. Impossible error.",ic); + _dwarf_error_string(dbg,error, + DW_DLE_DF_FRAME_DECODING_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *ret_frame_instr_head = head; + *returned_frame_instr_count = instr_count; + } else { + if (ret_frame_instr_head) { + *ret_frame_instr_head = 0; + } + if (returned_frame_instr_count) { + *returned_frame_instr_count = 0; + } + } + FREELOCALMALLOC; + return DW_DLV_OK; +#undef ERROR_IF_REG_NUM_TOO_HIGH +#undef FREELOCALMALLOC +#undef SER +} + +/* Depending on version, either read the return address register + as a ubyte or as an leb number. + The form of this value changed for DWARF3. +*/ +int +_dwarf_get_return_address_reg(Dwarf_Small *frame_ptr, + int version, + Dwarf_Debug dbg, + Dwarf_Byte_Ptr section_end, + unsigned long *size, + Dwarf_Unsigned *return_address_register, + Dwarf_Error *error) +{ + Dwarf_Unsigned uvalue = 0; + Dwarf_Unsigned leb128_length = 0; + + if (version == 1) { + if (frame_ptr >= section_end) { + _dwarf_error(NULL, error, DW_DLE_DF_FRAME_DECODING_ERROR); + return DW_DLV_ERROR; + } + *size = 1; + uvalue = *(unsigned char *) frame_ptr; + *return_address_register = uvalue; + return DW_DLV_OK; + } + DECODE_LEB128_UWORD_LEN_CK(frame_ptr,uvalue,leb128_length, + dbg,error,section_end); + *size = (unsigned long)leb128_length; + *return_address_register = uvalue; + return DW_DLV_OK; +} + +/* Trivial consumer function. +*/ +int +dwarf_get_cie_of_fde(Dwarf_Fde fde, + Dwarf_Cie * cie_returned, Dwarf_Error * error) +{ + if (!fde) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + + *cie_returned = fde->fd_cie; + return DW_DLV_OK; + +} + +int +dwarf_get_cie_index( + Dwarf_Cie cie, + Dwarf_Signed* indx, + Dwarf_Error* error ) +{ + if (cie == NULL) + { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return DW_DLV_ERROR; + } + + *indx = cie->ci_index; + return DW_DLV_OK; +} + +/* For g++ .eh_frame fde and cie. + the cie id is different as the + definition of the cie_id in an fde + is the distance back from the address of the + value to the cie. + Or 0 if this is a true cie. + Non standard dwarf, designed this way to be + convenient at run time for an allocated + (mapped into memory as part of the running image) section. +*/ +int +dwarf_get_fde_list_eh(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res = 0; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + res = _dwarf_load_section(dbg, + &dbg->de_debug_frame_eh_gnu,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_get_fde_list_internal(dbg, + cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame_eh_gnu.dss_data, + dbg->de_debug_frame_eh_gnu.dss_index, + dbg->de_debug_frame_eh_gnu.dss_size, + /* cie_id_value */ 0, + /* use_gnu_cie_calc= */ 1, + error); + return res; +} + +/* For standard dwarf .debug_frame + cie_id is -1 in a cie, and + is the section offset in the .debug_frame section + of the cie otherwise. Standard dwarf +*/ +int +dwarf_get_fde_list(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Error * error) +{ + int res = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: dwarf_get_fde_list: " + "Either null Dwarf_Debug or it is" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_get_fde_list_internal(dbg, cie_data, + cie_element_count, + fde_data, + fde_element_count, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + (Dwarf_Unsigned)DW_CIE_ID, + /* use_gnu_cie_calc= */ 0, + error); + + return res; +} + +/* Only works on dwarf sections, not eh_frame + because based on DW_AT_MIPS_fde. + Given a Dwarf_Die, see if it has a + DW_AT_MIPS_fde attribute and if so use that + to get an fde offset. + Then create a Dwarf_Fde to return thru the ret_fde pointer. + Also creates a cie (pointed at from the Dwarf_Fde). */ +int +dwarf_get_fde_for_die(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Fde * ret_fde, Dwarf_Error * error) +{ + Dwarf_Attribute attr; + Dwarf_Unsigned fde_offset = 0; + Dwarf_Signed signdval = 0; + Dwarf_Fde new_fde = 0; + unsigned char *fde_ptr = 0; + unsigned char *fde_start_ptr = 0; + unsigned char *fde_end_ptr = 0; + unsigned char *cie_ptr = 0; + Dwarf_Unsigned cie_id = 0; + Dwarf_Half address_size = 0; + + /* Fields for the current Cie being read. */ + int res = 0; + int resattr = 0; + int sdatares = 0; + + struct cie_fde_prefix_s prefix; + struct cie_fde_prefix_s prefix_c; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: in dwarf_get_fde_for_die(): " + "Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (!die ) { + _dwarf_error_string(NULL, error, DW_DLE_DIE_NULL, + "DW_DLE_DIE_NUL: in dwarf_get_fde_for_die(): " + "Called with Dwarf_Die argument null"); + return DW_DLV_ERROR; + } + resattr = dwarf_attr(die, DW_AT_MIPS_fde, &attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + /* why is this formsdata? FIX */ + sdatares = dwarf_formsdata(attr, &signdval, error); + if (sdatares != DW_DLV_OK) { + dwarf_dealloc_attribute(attr); + return sdatares; + } + res = dwarf_get_die_address_size(die,&address_size,error); + if (res != DW_DLV_OK) { + dwarf_dealloc_attribute(attr); + return res; + } + dwarf_dealloc_attribute(attr); + res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error); + if (res != DW_DLV_OK) { + return res; + } + fde_offset = signdval; + fde_start_ptr = dbg->de_debug_frame.dss_data; + fde_ptr = fde_start_ptr + fde_offset; + fde_end_ptr = fde_start_ptr + dbg->de_debug_frame.dss_size; + res = _dwarf_validate_register_numbers(dbg,error); + if (res == DW_DLV_ERROR) { + return res; + } + + /* First read in the 'common prefix' to figure out + what we are to do with this entry. */ + memset(&prefix_c, 0, sizeof(prefix_c)); + memset(&prefix, 0, sizeof(prefix)); + res = _dwarf_read_cie_fde_prefix(dbg, fde_ptr, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + &prefix, + error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + fde_ptr = prefix.cf_addr_after_prefix; + cie_id = prefix.cf_cie_id; + if (cie_id >= dbg->de_debug_frame.dss_size ) { + _dwarf_error_string(dbg, error, DW_DLE_NO_CIE_FOR_FDE, + "DW_DLE_NO_CIE_FOR_FDE: " + "dwarf_get_fde_for_die fails as the CIE id " + "offset is impossibly large"); + return DW_DLV_ERROR; + } + /* Pass NULL, not section pointer, for 3rd argument. + de_debug_frame.dss_data has no eh_frame relevance. */ + res = _dwarf_create_fde_from_after_start(dbg, &prefix, + fde_start_ptr, + dbg->de_debug_frame.dss_size, + fde_ptr, + fde_end_ptr, + /* use_gnu_cie_calc= */ 0, + /* Dwarf_Cie = */ 0, + address_size, + &new_fde, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + /* DW_DLV_OK */ + + /* This is the only situation this is set. + and is really dangerous. as fde and cie + are set for dealloc by dwarf_finish(). */ + new_fde->fd_fde_owns_cie = TRUE; + /* Now read the cie corresponding to the fde, + _dwarf_read_cie_fde_prefix checks + cie_ptr for being within the section. */ + if (cie_id >= dbg->de_debug_frame.dss_size ) { + _dwarf_error_string(dbg, error, DW_DLE_NO_CIE_FOR_FDE, + "DW_DLE_NO_CIE_FOR_FDE: " + "dwarf_get_fde_for_die fails as the CIE id " + "offset is impossibly large"); + return DW_DLV_ERROR; + } + cie_ptr = new_fde->fd_section_ptr + cie_id; + if ((Dwarf_Unsigned)cie_ptr < + (Dwarf_Unsigned) new_fde->fd_section_ptr || + (Dwarf_Unsigned)cie_ptr < cie_id) { + dwarf_dealloc(dbg,new_fde,DW_DLA_FDE); + new_fde = 0; + _dwarf_error_string(dbg, error, DW_DLE_NO_CIE_FOR_FDE, + "DW_DLE_NO_CIE_FOR_FDE: " + "dwarf_get_fde_for_die fails as the CIE id " + "offset is impossibly large"); + return DW_DLV_ERROR; + } + res = _dwarf_read_cie_fde_prefix(dbg, cie_ptr, + dbg->de_debug_frame.dss_data, + dbg->de_debug_frame.dss_index, + dbg->de_debug_frame.dss_size, + &prefix_c, error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,new_fde,DW_DLA_FDE); + new_fde = 0; + return res; + } + if (res == DW_DLV_NO_ENTRY) { + dwarf_dealloc(dbg,new_fde,DW_DLA_FDE); + new_fde = 0; + return res; + } + + cie_ptr = prefix_c.cf_addr_after_prefix; + cie_id = prefix_c.cf_cie_id; + + if (cie_id == (Dwarf_Unsigned)DW_CIE_ID) { + int res2 = 0; + Dwarf_Cie new_cie = 0; + + /* Pass NULL, not section pointer, for 3rd argument. + de_debug_frame.dss_data has no eh_frame relevance. */ + res2 = _dwarf_create_cie_from_after_start(dbg, + &prefix_c, + fde_start_ptr, + cie_ptr, + fde_end_ptr, + /* cie_count= */ 0, + /* use_gnu_cie_calc= */ + 0, &new_cie, error); + if (res2 != DW_DLV_OK) { + dwarf_dealloc(dbg, new_fde, DW_DLA_FDE); + return res; + } + new_fde->fd_cie = new_cie; + } else { + dwarf_dealloc(dbg,new_fde,DW_DLA_FDE); + new_fde = 0; + _dwarf_error_string(dbg, error, DW_DLE_NO_CIE_FOR_FDE, + "DW_DLE_NO_CIE_FOR_FDE: " + "The CIE id is not a true cid id. Corrupt DWARF."); + return DW_DLV_ERROR; + } + *ret_fde = new_fde; + return DW_DLV_OK; +} + +int +dwarf_get_fde_range(Dwarf_Fde fde, + Dwarf_Addr * low_pc, + Dwarf_Unsigned * func_length, + Dwarf_Byte_Ptr * fde_bytes, + Dwarf_Unsigned * fde_byte_length, + Dwarf_Off * cie_offset, + Dwarf_Signed * cie_index, + Dwarf_Off * fde_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return DW_DLV_ERROR; + } + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_FDE_DBG_NULL, + "DW_DLE_FDE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + /* We have always already done the section load here, + so no need to load the section. We did the section + load in order to create the + Dwarf_Fde pointer passed in here. */ + if (low_pc != NULL) + *low_pc = fde->fd_initial_location; + if (func_length != NULL) + *func_length = fde->fd_address_range; + if (fde_bytes != NULL) + *fde_bytes = fde->fd_fde_start; + if (fde_byte_length != NULL) + *fde_byte_length = fde->fd_length; + if (cie_offset != NULL) + *cie_offset = fde->fd_cie_offset; + if (cie_index != NULL) + *cie_index = fde->fd_cie_index; + if (fde_offset != NULL) + *fde_offset = fde->fd_fde_start - fde->fd_section_ptr; + + return DW_DLV_OK; +} + +/* IRIX specific function. The exception tables + have C++ destructor information and are + at present undocumented. */ +int +dwarf_get_fde_exception_info(Dwarf_Fde fde, + Dwarf_Signed * + offset_into_exception_tables, + Dwarf_Error * error) +{ + Dwarf_Debug dbg; + + dbg = fde->fd_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_FDE_DBG_NULL, + "DW_DLE_FDE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + + *offset_into_exception_tables = + fde->fd_offset_into_exception_tables; + return DW_DLV_OK; +} + +/* A consumer code function. + Given a CIE pointer, return the normal CIE data thru + pointers. + Special augmentation data is not returned here. +*/ +int +dwarf_get_cie_info_b(Dwarf_Cie cie, + Dwarf_Unsigned *bytes_in_cie, + Dwarf_Small *ptr_to_version, + char **augmenter, + Dwarf_Unsigned *code_alignment_factor, + Dwarf_Signed *data_alignment_factor, + Dwarf_Half *return_address_register, + Dwarf_Byte_Ptr *initial_instructions, + Dwarf_Unsigned *initial_instructions_length, + Dwarf_Half *offset_size, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + + if (!cie) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return DW_DLV_ERROR; + } + dbg = cie->ci_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_CIE_DBG_NULL, + "DW_DLE_CIE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (ptr_to_version != NULL) + *ptr_to_version = + (Dwarf_Small)cie->ci_cie_version_number; + if (augmenter != NULL) + *augmenter = cie->ci_augmentation; + if (code_alignment_factor != NULL) + *code_alignment_factor = cie->ci_code_alignment_factor; + if (data_alignment_factor != NULL) + *data_alignment_factor = cie->ci_data_alignment_factor; + if (return_address_register != NULL) + *return_address_register = cie->ci_return_address_register; + if (initial_instructions != NULL) + *initial_instructions = cie->ci_cie_instr_start; + if (initial_instructions_length != NULL) { + *initial_instructions_length = cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - cie->ci_cie_start); + } + if (offset_size) { + *offset_size = cie->ci_length_size; + } + *bytes_in_cie = (cie->ci_length); + return DW_DLV_OK; +} + +/* Return the register rules for all registers at a given pc. +*/ +static int +_dwarf_get_fde_info_for_a_pc_row(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Frame table, + Dwarf_Unsigned cfa_reg_col_num, + Dwarf_Bool * has_more_rows, + Dwarf_Addr * subsequent_pc, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Cie cie = 0; + int res = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + + dbg = fde->fd_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL); + return DW_DLV_ERROR; + } + + if (pc_requested < fde->fd_initial_location || + pc_requested >= + fde->fd_initial_location + fde->fd_address_range) { + _dwarf_error(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE); + return DW_DLV_ERROR; + } + + cie = fde->fd_cie; + if (cie->ci_initial_table == NULL) { + Dwarf_Small *instrstart = cie->ci_cie_instr_start; + Dwarf_Small *instrend = instrstart +cie->ci_length + + cie->ci_length_size + + cie->ci_extension_size - + (cie->ci_cie_instr_start - + cie->ci_cie_start); + if (instrend > cie->ci_cie_end) { + _dwarf_error(dbg, error,DW_DLE_CIE_INSTR_PTR_ERROR); + return DW_DLV_ERROR; + } + cie->ci_initial_table = (Dwarf_Frame)_dwarf_get_alloc(dbg, + DW_DLA_FRAME, 1); + + if (cie->ci_initial_table == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + _dwarf_init_reg_rules_ru(cie->ci_initial_table->fr_reg, + 0, cie->ci_initial_table->fr_reg_count, + dbg->de_frame_rule_initial_value); + _dwarf_init_reg_rules_ru(&cie->ci_initial_table->fr_cfa_rule, + 0,1,dbg->de_frame_rule_initial_value); + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + instrstart, + instrend, + cie->ci_initial_table, + cie, dbg, + cfa_reg_col_num, + has_more_rows, + subsequent_pc, + NULL,NULL, + error); + if (res != DW_DLV_OK) { + return res; + } + } + + { + Dwarf_Small *instr_end = fde->fd_length + + fde->fd_length_size + + fde->fd_extension_size + fde->fd_fde_start; + if (instr_end > fde->fd_fde_end) { + _dwarf_error(dbg, error,DW_DLE_FDE_INSTR_PTR_ERROR); + return DW_DLV_ERROR; + } + res = _dwarf_exec_frame_instr( /* make_instr= */ false, + /* search_pc */ true, + /* search_pc_val */ pc_requested, + fde->fd_initial_location, + fde->fd_fde_instr_start, + instr_end, + table, + cie,dbg, + cfa_reg_col_num, + has_more_rows, + subsequent_pc, + NULL,NULL, + error); + } + if (res != DW_DLV_OK) { + return res; + } + + return DW_DLV_OK; +} + +int +dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Regtable3 * reg_table, + Dwarf_Addr * row_pc, + Dwarf_Error * error) +{ + + struct Dwarf_Frame_s fde_table; + Dwarf_Unsigned i = 0; + int res = 0; + struct Dwarf_Reg_Rule_s *rule = NULL; + + /* Internal-only struct. */ + Dwarf_Regtable_Entry3_i *rule_i = NULL; + + Dwarf_Debug dbg = 0; + Dwarf_Unsigned output_table_real_data_size = 0; + Dwarf_Regtable3_i reg_table_i; + + memset(®_table_i,0,sizeof(reg_table_i)); + memset(&fde_table,0,sizeof(fde_table)); + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + output_table_real_data_size = reg_table->rt3_reg_table_size; + reg_table_i.rt3_reg_table_size = output_table_real_data_size; + output_table_real_data_size = + MIN(output_table_real_data_size, + dbg->de_frame_reg_rules_entry_count); + res = _dwarf_initialize_fde_table(dbg, &fde_table, + output_table_real_data_size, + error); + if (res != DW_DLV_OK) { + return res; + } + /* Allocate array of internal structs to match, + in count, what was passed in. */ + reg_table_i.rt3_rules = calloc(reg_table->rt3_reg_table_size, + sizeof(Dwarf_Regtable_Entry3_i)); + if (!reg_table_i.rt3_rules) { + _dwarf_free_fde_table(&fde_table); + _dwarf_error_string(dbg,error, + DW_DLE_ALLOC_FAIL, + "Failure allocating Dwarf_Regtable_Entry3_i " + "in dwarf_get_fde_info_for_all_regs3()"); + return DW_DLV_ERROR; + } + /* _dwarf_get_fde_info_for_a_pc_row will perform + more sanity checks */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, + dbg->de_frame_cfa_col_number, + NULL,NULL, + error); + if (res != DW_DLV_OK) { + free(reg_table_i.rt3_rules); + reg_table_i.rt3_rules = 0; + _dwarf_free_fde_table(&fde_table); + return res; + } + + rule_i = ®_table_i.rt3_rules[0]; + rule = &fde_table.fr_reg[0]; + /* Initialize known rules */ + for (i = 0; i < output_table_real_data_size; + i++, ++rule_i, ++rule) { + rule_i->dw_offset_relevant = rule->ru_is_offset; + rule_i->dw_args_size = rule->ru_args_size; + rule_i->dw_value_type = rule->ru_value_type; + rule_i->dw_regnum = rule->ru_register; + rule_i->dw_offset = (Dwarf_Unsigned)rule->ru_offset; + rule_i->dw_block = rule->ru_block; + } + /* If i < reg_table_i.rt3_reg_table_size finish + initializing register rules */ + _dwarf_init_reg_rules_dw3(®_table_i.rt3_rules[0], + i, reg_table_i.rt3_reg_table_size, + dbg->de_frame_undefined_value_number); + { + /* Now get this into the real output. + Truncating rule numbers, and offset set + unsigned. */ + Dwarf_Unsigned j = 0; + Dwarf_Regtable_Entry3 *targ = ®_table->rt3_rules[0]; + Dwarf_Regtable_Entry3_i *src = ®_table_i.rt3_rules[0]; + for ( ; j < reg_table->rt3_reg_table_size; + ++j, targ++,src++) { + targ->dw_offset_relevant = src->dw_offset_relevant; + targ->dw_args_size = src->dw_args_size; + targ->dw_value_type = src->dw_value_type; + targ->dw_regnum = (Dwarf_Half)src->dw_regnum; + targ->dw_offset= (Dwarf_Unsigned)src->dw_offset; + targ->dw_block = src->dw_block; + } + } + reg_table->rt3_cfa_rule.dw_offset_relevant = + fde_table.fr_cfa_rule.ru_is_offset; + reg_table->rt3_cfa_rule.dw_value_type = + fde_table.fr_cfa_rule.ru_value_type; + reg_table->rt3_cfa_rule.dw_regnum = + fde_table.fr_cfa_rule.ru_register; + reg_table->rt3_cfa_rule.dw_offset = + (Dwarf_Unsigned)fde_table.fr_cfa_rule.ru_offset; + reg_table->rt3_cfa_rule.dw_block = + fde_table.fr_cfa_rule.ru_block; + reg_table->rt3_cfa_rule.dw_args_size = + fde_table.fr_cfa_rule.ru_args_size; + if (row_pc != NULL) { + *row_pc = fde_table.fr_loc; + } + free(reg_table_i.rt3_rules); + reg_table_i.rt3_rules = 0; + reg_table_i.rt3_reg_table_size = 0; + _dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* Table_column DW_FRAME_CFA_COL is not meaningful. + Use dwarf_get_fde_info_for_cfa_reg3_b() to get the CFA. + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init() + (DW_FRAME_CFA_COL3 is a sensible column to use). +*/ +/* New May 2018. + If one is tracking the value of a single table + column through a function, this lets us + skip to the next pc value easily. + + if pc_requested is a change from the last + pc_requested on this pc, this function + returns *has_more_rows and *subsequent_pc + (null pointers passed are acceptable, the + assignment through the pointer is skipped + if the pointer is null). + Otherwise *has_more_rows and *subsequent_pc + are not set. + + The offset returned is Unsigned, which was + always wrong. Cast to Dwarf_Signed to use it. +*/ +int +dwarf_get_fde_info_for_reg3_b(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr requested, + Dwarf_Small *value_type, + Dwarf_Unsigned *offset_relevant, + Dwarf_Unsigned *register_num, + Dwarf_Unsigned *offset, + Dwarf_Block *block, + Dwarf_Addr *row_pc_out, + Dwarf_Bool *has_more_rows, + Dwarf_Addr *subsequent_pc, + Dwarf_Error *error) +{ + Dwarf_Signed soff = 0; + int res = 0; + + res = dwarf_get_fde_info_for_reg3_c( + fde,table_column,requested, + value_type,offset_relevant, + register_num,&soff, + block,row_pc_out,has_more_rows, + subsequent_pc,error); + if (offset) { + *offset = (Dwarf_Unsigned)soff; + } + return res; +} +/* New September 2023. + The same as dwarf_get_fde_info_for_reg3_b() but here +*/ +int +dwarf_get_fde_info_for_reg3_c(Dwarf_Fde fde, + Dwarf_Half table_column, + Dwarf_Addr pc_requested, + Dwarf_Small *value_type, + Dwarf_Unsigned *offset_relevant, + Dwarf_Unsigned *register_num, + Dwarf_Signed *offset, + Dwarf_Block *block, + Dwarf_Addr *row_pc_out, + Dwarf_Bool *has_more_rows, + Dwarf_Addr *subsequent_pc, + Dwarf_Error *error) +{ + struct Dwarf_Frame_s * fde_table = &(fde->fd_fde_table); + int res = DW_DLV_ERROR; + + Dwarf_Debug dbg = 0; + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + if (!fde->fd_have_fde_tab || + /* The test is just in case it's not inside the table. + For non-MIPS + it could be outside the table and that is just fine, it was + really a mistake to put it in the table in 1993. */ + fde->fd_fde_pc_requested != pc_requested) { + if (fde->fd_have_fde_tab) { + _dwarf_free_fde_table(fde_table); + fde->fd_have_fde_tab = false; + } + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = _dwarf_initialize_fde_table(dbg, fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) { + return res; + } + if (table_column >= table_real_data_size) { + _dwarf_free_fde_table(fde_table); + fde->fd_have_fde_tab = false; + _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD); + return DW_DLV_ERROR; + } + + /* _dwarf_get_fde_info_for_a_pc_row will perform + more sanity checks */ + res = _dwarf_get_fde_info_for_a_pc_row(fde, + pc_requested, fde_table, + dbg->de_frame_cfa_col_number, + has_more_rows,subsequent_pc, + error); + if (res != DW_DLV_OK) { + _dwarf_free_fde_table(fde_table); + fde->fd_have_fde_tab = false; + return res; + } + } + + if (register_num) { + *register_num = fde_table->fr_reg[table_column].ru_register; + } + if (offset) { + *offset = fde_table->fr_reg[table_column].ru_offset; + } + if (row_pc_out != NULL) { + *row_pc_out = fde_table->fr_loc; + } + if (block) { + *block = fde_table->fr_reg[table_column].ru_block; + } + + /* Without value_type the data cannot be understood, + so we insist on it being present, we don't test it. */ + *value_type = fde_table->fr_reg[table_column].ru_value_type; + *offset_relevant = (fde_table->fr_reg[table_column].ru_is_offset); + fde->fd_have_fde_tab = true; + fde->fd_fde_pc_requested = pc_requested; + return DW_DLV_OK; + +} + +/* + This deals with the CFA by not + making the CFA a column number, which means + DW_FRAME_CFA_COL3 is, like DW_CFA_SAME_VALUE, + a special value, not something one uses as an index. + + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init(). + DW_FRAME_CFA_COL3 is a sensible column to use. +*/ +int +dwarf_get_fde_info_for_cfa_reg3_b(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Small *value_type, + Dwarf_Unsigned *offset_relevant, + Dwarf_Unsigned *register_num, + Dwarf_Unsigned *offset, + Dwarf_Block *block, + Dwarf_Addr *row_pc_out, + Dwarf_Bool *has_more_rows, + Dwarf_Addr *subsequent_pc, + Dwarf_Error *error) +{ + Dwarf_Signed soff = 0; + int res = 0; + + res = dwarf_get_fde_info_for_cfa_reg3_c(fde, + pc_requested, value_type,offset_relevant, + register_num,&soff,block, row_pc_out, + has_more_rows,subsequent_pc,error); + if (offset) { + *offset = (Dwarf_Unsigned)soff; + } + return res; +} +/* + New September 2023. With the offset argument + a signed value. This is more correct, so + convert from dwarf_get_fde_info_for_cfa_reg3_b + when convenient. +*/ +int +dwarf_get_fde_info_for_cfa_reg3_c(Dwarf_Fde fde, + Dwarf_Addr pc_requested, + Dwarf_Small *value_type, + Dwarf_Unsigned *offset_relevant, + Dwarf_Unsigned *register_num, + Dwarf_Signed *offset, + Dwarf_Block *block, + Dwarf_Addr *row_pc_out, + Dwarf_Bool *has_more_rows, + Dwarf_Addr *subsequent_pc, + Dwarf_Error *error) +{ + struct Dwarf_Frame_s fde_table; + int res = DW_DLV_ERROR; + Dwarf_Debug dbg = 0; + + int table_real_data_size = 0; + + FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg); + + table_real_data_size = dbg->de_frame_reg_rules_entry_count; + res = _dwarf_initialize_fde_table(dbg, &fde_table, + table_real_data_size, error); + if (res != DW_DLV_OK) + return res; + res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, + &fde_table, + dbg->de_frame_cfa_col_number,has_more_rows, + subsequent_pc,error); + if (res != DW_DLV_OK) { + _dwarf_free_fde_table(&fde_table); + return res; + } + if (register_num) { + *register_num = fde_table.fr_cfa_rule.ru_register; + } + if (offset) { + *offset = fde_table.fr_cfa_rule.ru_offset; + } + if (row_pc_out != NULL) { + *row_pc_out = fde_table.fr_loc; + } + if (block) { + *block = fde_table.fr_cfa_rule.ru_block; + } + /* Without value_type the data cannot be + understood, so we insist + on it being present, we don't test it. */ + *value_type = fde_table.fr_cfa_rule.ru_value_type; + *offset_relevant = fde_table.fr_cfa_rule.ru_is_offset; + _dwarf_free_fde_table(&fde_table); + return DW_DLV_OK; +} + +/* Return pointer to the instructions in the dwarf fde. */ +int +dwarf_get_fde_instr_bytes(Dwarf_Fde inFde, + Dwarf_Small ** outinstrs, + Dwarf_Unsigned * outinstrslen, + Dwarf_Error * error) +{ + Dwarf_Unsigned len = 0; + Dwarf_Small *instrs = 0; + Dwarf_Debug dbg = 0; + + if (!inFde) { + _dwarf_error(dbg, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + dbg = inFde->fd_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_FDE_DBG_NULL, + "DW_DLE_FDE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + instrs = inFde->fd_fde_instr_start; + len = inFde->fd_fde_end - inFde->fd_fde_instr_start; + *outinstrs = instrs; + *outinstrslen = len; + return DW_DLV_OK; +} + +/* Allows getting an fde from its table via an index. + With more error checking than simply indexing oneself. */ +int +dwarf_get_fde_n(Dwarf_Fde * fde_data, + Dwarf_Unsigned fde_index, + Dwarf_Fde * returned_fde, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned fdecount = 0; + + if (fde_data == NULL) { + _dwarf_error(dbg, error, DW_DLE_FDE_PTR_NULL); + return DW_DLV_ERROR; + } + + FDE_NULL_CHECKS_AND_SET_DBG(*fde_data, dbg); + /* Assumes fde_data table has at least one entry. */ + fdecount = fde_data[0]->fd_is_eh? + dbg->de_fde_count_eh:dbg->de_fde_count; + if (fde_index >= fdecount) { + return DW_DLV_NO_ENTRY; + } + *returned_fde = (*(fde_data + fde_index)); + return DW_DLV_OK; +} + +/* Lopc and hipc are extensions to the interface to + return the range of addresses that are described + by the returned fde. */ +int +dwarf_get_fde_at_pc(Dwarf_Fde * fde_data, + Dwarf_Addr pc_of_interest, + Dwarf_Fde * returned_fde, + Dwarf_Addr * lopc, + Dwarf_Addr * hipc, Dwarf_Error * error) +{ + Dwarf_Debug dbg = NULL; + Dwarf_Fde fde = NULL; + Dwarf_Fde entryfde = NULL; + Dwarf_Signed fdecount = 0; + + if (fde_data == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL); + return DW_DLV_ERROR; + } + + /* Assumes fde_data table has at least one entry. */ + entryfde = *fde_data; + FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg); + fdecount = entryfde->fd_is_eh? + dbg->de_fde_count_eh:dbg->de_fde_count; + { + /* The fdes are sorted by their addresses. Binary search to + find correct fde. */ + Dwarf_Signed low = 0; + Dwarf_Signed high = fdecount - 1L; + Dwarf_Signed middle = 0; + Dwarf_Fde cur_fde; + + while (low <= high) { + middle = (low + high) / 2; + cur_fde = fde_data[middle]; + if (pc_of_interest < cur_fde->fd_initial_location) { + high = middle - 1; + } else if (pc_of_interest >= + (cur_fde->fd_initial_location + + cur_fde->fd_address_range)) { + low = middle + 1; + } else { + fde = fde_data[middle]; + break; + } + } + } + + if (fde) { + if (lopc != NULL) + *lopc = fde->fd_initial_location; + if (hipc != NULL) + *hipc = + fde->fd_initial_location + fde->fd_address_range - 1; + *returned_fde = fde; + return DW_DLV_OK; + } + + return DW_DLV_NO_ENTRY; +} + +/* Expands a single frame instruction block + from a specific cie or fde into a + Dwarf_Frame_Instr_Head. + + Call dwarf_set_frame_cfa_value() to set the correct column + after calling dwarf_init(). + DW_FRAME_CFA_COL3 is a sensible column to use. +*/ +int +dwarf_expand_frame_instructions(Dwarf_Cie cie, + Dwarf_Small *instruction, + Dwarf_Unsigned i_length, + Dwarf_Frame_Instr_Head * returned_instr_head, + Dwarf_Unsigned * returned_instr_count, + Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + Dwarf_Debug dbg = 0; + Dwarf_Small * instr_start = instruction; + Dwarf_Small * instr_end = (Dwarf_Small *)instruction + i_length;; + + if (cie == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + dbg = cie->ci_dbg; + + if (!returned_instr_head || !returned_instr_count) { + _dwarf_error_string(dbg, error, DW_DLE_RET_OP_LIST_NULL, + "DW_DLE_RET_OP_LIST_NULL: " + "Calling dwarf_expand_frame_instructions without " + "a non-NULL Dwarf_Frame_Instr_Head pointer and " + "count pointer seems wrong."); + return DW_DLV_ERROR; + } + if ( instr_end < instr_start) { + /* Impossible unless there was wraparond somewhere and + we missed it. */ + _dwarf_error(dbg, error,DW_DLE_FDE_INSTR_PTR_ERROR); + return DW_DLV_ERROR; + } + res = _dwarf_exec_frame_instr( /* make_instr= */ true, + /* search_pc */ false, + /* search_pc_val */ 0, + /* location */ 0, + instr_start, + instr_end, + /* Dwarf_Frame */ NULL, + cie, + dbg, + dbg->de_frame_cfa_col_number, + /* has more rows */0, + /* subsequent_pc */0, + returned_instr_head, + returned_instr_count, + error); + if (res != DW_DLV_OK) { + return res; + } + return DW_DLV_OK; +} + +/* Call to access a single CFA frame instruction. + The 2021 DW_CFA_LLVM addition for hetrogenous + debugging has a third field, an address space + value. */ +int +dwarf_get_frame_instruction(Dwarf_Frame_Instr_Head head, + Dwarf_Unsigned instr_index, + Dwarf_Unsigned * instr_offset_in_instrs, + Dwarf_Small * cfa_operation, + const char ** fields_description, + Dwarf_Unsigned * u0, + Dwarf_Unsigned * u1, + Dwarf_Signed * s0, + Dwarf_Signed * s1, + Dwarf_Unsigned * code_alignment_factor, + Dwarf_Signed * data_alignment_factor, + Dwarf_Block * expression_block, + Dwarf_Error * error) +{ + Dwarf_Unsigned aspace = 0; + return dwarf_get_frame_instruction_a(head, + instr_index, + instr_offset_in_instrs, + cfa_operation, + fields_description, + u0, + u1, + & aspace, + s0, + s1, + code_alignment_factor, + data_alignment_factor, + expression_block, + error); +} +int +dwarf_get_frame_instruction_a(Dwarf_Frame_Instr_Head head, + Dwarf_Unsigned instr_index, + Dwarf_Unsigned * instr_offset_in_instrs, + Dwarf_Small * cfa_operation, + const char ** fields_description, + Dwarf_Unsigned * u0, + Dwarf_Unsigned * u1, + Dwarf_Unsigned * u2, + Dwarf_Signed * s0, + Dwarf_Signed * s1, + Dwarf_Unsigned * code_alignment_factor, + Dwarf_Signed * data_alignment_factor, + Dwarf_Block * expression_block, + Dwarf_Error * error) +{ + Dwarf_Frame_Instr ip = 0; + Dwarf_Debug dbg = 0; + if (!head) { + _dwarf_error_string(dbg, error,DW_DLE_CFA_INSTRUCTION_ERROR, + "DW_DLE_CFA_INSTRUCTION_ERROR: Head argument NULL " + " calling dwarf_get_frame_instruction"); + return DW_DLV_ERROR; + } + if (!head->fh_dbg) { + _dwarf_error_string(dbg, error,DW_DLE_CFA_INSTRUCTION_ERROR, + "DW_DLE_CFA_INSTRUCTION_ERROR: Head missing " + "Dwarf_Debug field " + " calling dwarf_get_frame_instruction"); + return DW_DLV_ERROR; + } + dbg = head->fh_dbg; + if (instr_index >= head->fh_array_count) { + return DW_DLV_NO_ENTRY; + } + ip = head->fh_array[instr_index]; + if (!ip) { + _dwarf_error_string(dbg, error,DW_DLE_CFA_INSTRUCTION_ERROR, + "DW_DLE_CFA_INSTRUCTION_ERROR: instr array missing " + "calling dwarf_get_frame_instruction"); + return DW_DLV_ERROR; + } + *instr_offset_in_instrs = ip->fi_instr_offset; + *cfa_operation = ip->fi_op; + *fields_description = ip->fi_fields; + *u0 = ip->fi_u0; + *u1 = ip->fi_u1; + *u2 = ip->fi_u2; + *s0 = ip->fi_s0; + *s1 = ip->fi_s1; + /* These next two might be known to caller already, + so let caller not pass useless pointers. */ + if (code_alignment_factor) { + *code_alignment_factor = ip->fi_code_align_factor; + } + if (data_alignment_factor) { + *data_alignment_factor = ip->fi_data_align_factor; + } + *expression_block = ip->fi_expr; + return DW_DLV_OK; +} + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * error) +{ + return dwarf_fde_section_offset(dbg,in_fde,fde_off, + cie_off,error); +} +/* ARGSUSED 4 */ +int +dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde, + Dwarf_Off * fde_off, Dwarf_Off * cie_off, + Dwarf_Error * error) +{ + char *start = 0; + char *loc = 0; + + if (!in_fde) { + _dwarf_error(dbg, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + start = (char *) in_fde->fd_section_ptr; + loc = (char *) in_fde->fd_fde_start; + + *fde_off = (loc - start); + *cie_off = in_fde->fd_cie_offset; + return DW_DLV_OK; +} + +/* Used by dwarfdump -v to print offsets, for debugging + dwarf info. + The dwarf_ version is preferred over the obsolete _dwarf version. + _dwarf version kept for compatibility. +*/ +/* ARGSUSED 4 */ +int +_dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * error) +{ + return dwarf_cie_section_offset(dbg,in_cie,cie_off,error); +} +/* ARGSUSED 4 */ +int +dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie, + Dwarf_Off * cie_off, Dwarf_Error * error) +{ + char *start = 0; + char *loc = 0; + + if (!in_cie) { + _dwarf_error(dbg, error, DW_DLE_CIE_NULL); + return DW_DLV_ERROR; + } + start = (char *) in_cie->ci_section_ptr; + loc = (char *) in_cie->ci_cie_start; + + *cie_off = (loc - start); + return DW_DLV_OK; +} + +/* Returns a pointer to target-specific augmentation data + thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Cie, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. */ +int +dwarf_get_cie_augmentation_data(Dwarf_Cie cie, + Dwarf_Small ** augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return DW_DLV_ERROR; + } + if (cie->ci_gnu_eh_augmentation_len == 0) { + return DW_DLV_NO_ENTRY; + } + *augdata = (Dwarf_Small *) (cie->ci_gnu_eh_augmentation_bytes); + *augdata_len = cie->ci_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + +/* Returns a pointer to target-specific augmentation data + thru augdata + and returns the length of the data thru augdata_len. + + It's up to the consumer code to know how to interpret the bytes + of target-specific data (endian issues apply too, these + are just raw bytes pointed to). + See Linux Standard Base Core Specification version 3.0 for + the details on .eh_frame info. + + Returns DW_DLV_ERROR if fde is NULL or some other serious + error. + Returns DW_DLV_NO_ENTRY if there is no target-specific + augmentation data. + + The bytes pointed to are in the Dwarf_Fde, and as long as that + is valid the bytes are there. No 'dealloc' call is needed + for the bytes. */ +int +dwarf_get_fde_augmentation_data(Dwarf_Fde fde, + Dwarf_Small * *augdata, + Dwarf_Unsigned * augdata_len, + Dwarf_Error * error) +{ + Dwarf_Cie cie = 0; + + if (fde == NULL) { + _dwarf_error(NULL, error, DW_DLE_FDE_NULL); + return DW_DLV_ERROR; + } + if (!fde->fd_gnu_eh_aug_present) { + return DW_DLV_NO_ENTRY; + } + cie = fde->fd_cie; + if (cie == NULL) { + _dwarf_error(NULL, error, DW_DLE_CIE_NULL); + return DW_DLV_ERROR; + } + *augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes; + *augdata_len = fde->fd_gnu_eh_augmentation_len; + return DW_DLV_OK; +} + +#if 0 /* FOR DEBUGGING */ +/* Used solely for debugging libdwarf. */ +static void +dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule) +{ + printf + ("%s type %s (0x%" DW_PR_XZEROS DW_PR_DUx + "), is_off %" DW_PR_DUu + " reg %" DW_PR_DUu " offset 0x%" DW_PR_XZEROS DW_PR_DUx + " blockp 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + msg, + (reg_rule->ru_value_type == DW_EXPR_OFFSET) ? + "DW_EXPR_OFFSET" : + (reg_rule->ru_value_type == DW_EXPR_VAL_OFFSET) ? + "DW_EXPR_VAL_OFFSET" : + (reg_rule->ru_value_type == DW_EXPR_VAL_EXPRESSION) ? + "DW_EXPR_VAL_EXPRESSION" : + (reg_rule->ru_value_type == DW_EXPR_EXPRESSION) ? + "DW_EXPR_EXPRESSION" : "Unknown", + (Dwarf_Unsigned) reg_rule->ru_value_type, + (Dwarf_Unsigned) reg_rule->ru_is_off, + (Dwarf_Unsigned) reg_rule->ru_register, + (Dwarf_Unsigned) reg_rule->ru_offset_or_block_len, + (Dwarf_Unsigned) reg_rule->ru_block); + return; +} +#endif /*0*/ + +/* This allows consumers to set the 'initial value' so that + an ISA/ABI specific default can be used, dynamically, + at run time. Useful for dwarfdump and non-MIPS architectures.. + The value defaults to one of + DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE + but dwarfdump can dump multiple ISA/ABI objects so + we may want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. */ +Dwarf_Half +dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Unsigned orig = dbg->de_frame_rule_initial_value; + dbg->de_frame_rule_initial_value = value; + return orig; +} + +/* This allows consumers to set the array size of the reg rules + table so that + an ISA/ABI specific value can be used, dynamically, + at run time. Useful for non-MIPS architectures. + The value defaults to DW_FRAME_LAST_REG_NUM. + but dwarfdump can dump multiple ISA/ABI objects so + consumers want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. +*/ + +Dwarf_Half +dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_reg_rules_entry_count; + dbg->de_frame_reg_rules_entry_count = value; + + /* Take the caller-specified value, but do not + let the value be too small. Keep it at least to + DW_FRAME_LAST_REG_NUM. + This helps prevent libdwarf (mistakenly) indexing outside + of of a register array when the ABI reg count + is really small. */ + if (value < DW_FRAME_LAST_REG_NUM) { + dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM; + } + return orig; +} +/* This allows consumers to set the CFA register value + so that an ISA/ABI specific value can be used, dynamically, + at run time. Useful for non-MIPS architectures. + The value defaults to DW_FRAME_CFA_COL3 and should be + higher than any real register in the ABI. + Dwarfdump can dump multiple ISA/ABI objects so + consumers want to get this set to what the ABI says is correct. + + Returns the value that was present before we changed it here. */ + +Dwarf_Half +dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_cfa_col_number; + dbg->de_frame_cfa_col_number = value; + return orig; +} +/* Similar to above, but for the other crucial fields for frames. */ +Dwarf_Half +dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_same_value_number; + dbg->de_frame_same_value_number = value; + return orig; +} +Dwarf_Half +dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value) +{ + Dwarf_Half orig = dbg->de_frame_same_value_number; + dbg->de_frame_undefined_value_number = value; + return orig; +} + +/* Does something only if value passed in is greater than 0 and + a size than we can handle (in number of bytes). */ +Dwarf_Small +dwarf_set_default_address_size(Dwarf_Debug dbg, + Dwarf_Small value ) +{ + Dwarf_Small orig = dbg->de_pointer_size; + if (value > 0 && value <= sizeof(Dwarf_Addr)) { + dbg->de_pointer_size = value; + } + return orig; +} + +static int +init_reg_rules_alloc(Dwarf_Debug dbg,struct Dwarf_Frame_s *f, + unsigned count, Dwarf_Error * error) +{ + f->fr_reg_count = count; + f->fr_reg = (struct Dwarf_Reg_Rule_s *) + calloc(sizeof(struct Dwarf_Reg_Rule_s), count); + if (f->fr_reg == 0) { + if (error) { + _dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL); + } + return DW_DLV_ERROR; + } + _dwarf_init_reg_rules_ru(f->fr_reg,0, count, + dbg->de_frame_rule_initial_value); + return DW_DLV_OK; +} +static int +_dwarf_initialize_fde_table(Dwarf_Debug dbg, + struct Dwarf_Frame_s *fde_table, + unsigned table_real_data_size, + Dwarf_Error * error) +{ + unsigned entry_size = sizeof(struct Dwarf_Frame_s); + memset(fde_table,0,entry_size); + fde_table->fr_loc = 0; + fde_table->fr_next = 0; + + return init_reg_rules_alloc(dbg,fde_table, + table_real_data_size,error); +} +static void +_dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table) +{ + free(fde_table->fr_reg); + fde_table->fr_reg_count = 0; + fde_table->fr_reg = 0; +} + +/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR. +*/ +int +_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + + if (!dbg) { + return DW_DLV_ERROR; + } + return init_reg_rules_alloc(dbg,fp, + dbg->de_frame_reg_rules_entry_count, 0); +} + +void +_dwarf_frame_destructor(void *frame) +{ + struct Dwarf_Frame_s *fp = frame; + _dwarf_free_fde_table(fp); +} + +void +_dwarf_fde_destructor(void *f) +{ + struct Dwarf_Fde_s *fde = f; + + if (fde->fd_fde_owns_cie) { + Dwarf_Debug dbg = fde->fd_dbg; + + if (!dbg->de_in_tdestroy) { + /* This is just for dwarf_get_fde_for_die() and + must not be applied in alloc tree destruction. */ + dwarf_dealloc(fde->fd_dbg,fde->fd_cie,DW_DLA_CIE); + fde->fd_cie = 0; + } + } + if (fde->fd_have_fde_tab) { + _dwarf_free_fde_table(&fde->fd_fde_table); + fde->fd_have_fde_tab = false; + } +} +void +_dwarf_frame_instr_destructor(void *f) +{ + Dwarf_Frame_Instr_Head head = f; + Dwarf_Debug dbg = head->fh_dbg; + Dwarf_Unsigned count = head->fh_array_count; + Dwarf_Unsigned i = 0; + + for ( ; i < count ; ++i) { + free(head->fh_array[i]); + head->fh_array[i] = 0; + } + dwarf_dealloc(dbg,head->fh_array,DW_DLA_LIST); + head->fh_array = 0; + head->fh_array_count = 0; +} +void +dwarf_dealloc_frame_instr_head(Dwarf_Frame_Instr_Head h) +{ + if (!h) { + return; + } + dwarf_dealloc(h->fh_dbg,h,DW_DLA_FRAME_INSTR_HEAD); +} + +static void +_dwarf_init_reg_rules_ru(struct Dwarf_Reg_Rule_s *base, + Dwarf_Unsigned first, Dwarf_Unsigned last, + Dwarf_Unsigned initial_value) +{ + struct Dwarf_Reg_Rule_s *r = base+first; + unsigned i = first; + for (; i < last; ++i,++r) { + r->ru_is_offset = 0; + r->ru_value_type = DW_EXPR_OFFSET; + r->ru_register = (Dwarf_Unsigned)initial_value; + r->ru_offset = 0; + r->ru_args_size = 0; + r->ru_block.bl_data = 0; + r->ru_block.bl_len = 0; + } +} + +/* For any remaining columns after what fde has. */ +static void +_dwarf_init_reg_rules_dw3( + Dwarf_Regtable_Entry3_i *base, + Dwarf_Unsigned first, Dwarf_Unsigned last, + Dwarf_Unsigned initial_value) +{ + Dwarf_Regtable_Entry3_i *r = base+first; + Dwarf_Unsigned i = first; + for (; i < last; ++i,++r) { + r->dw_offset_relevant = 0; + r->dw_value_type = DW_EXPR_OFFSET; + r->dw_regnum = initial_value; + r->dw_offset = 0; + r->dw_args_size = 0; + r->dw_block.bl_data = 0; + r->dw_block.bl_len = 0; + } +} diff --git a/src/lib/libdwarf/dwarf_frame.h b/src/lib/libdwarf/dwarf_frame.h new file mode 100644 index 0000000..070ddb6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_frame.h @@ -0,0 +1,509 @@ +/* +Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2021-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* The dwarf 2.0 standard dictates that only the following + fields can be read when an unexpected augmentation string + (in the cie) is encountered: CIE length, CIE_id, version and + augmentation; FDE: length, CIE pointer, initial location and + address range. Unfortunately, with the above restrictions, it + is impossible to read the instruction table from a CIE or a FDE + when a new augmentation string is encountered. + To fix this problem, the following layout is used, if the + augmentation string starts with the string "z". + CIE FDE + length length + CIE_id CIE_pointer + version initial_location + augmentation address_range + + - length_of_augmented_fields (*NEW*) + code_alignment_factor Any new fields as necessary + data_alignment_factor instruction_table + return_address + length_of_augmented fields + Any new fields as necessary + initial_instructions + + The type of all the old data items are the same as what is + described in dwarf 2.0 standard. The length_of_augmented_fields + is an LEB128 data item that denotes the size (in bytes) of + the augmented fields (not including the size of + "length_of_augmented_fields" itself). + + Handling of cie augmentation strings is necessarily a heuristic. + See dwarf_frame.c for the currently known augmentation strings. + + ---START SGI-ONLY COMMENT: + SGI-IRIX versions of cie or fde were intended + to use "z1", "z2" as the + augmenter strings if required for new augmentation. + However, that never happened (as of March 2005). + + The fde's augmented by the string "z" have a new field + (signed constant, 4 byte field) + called offset_into_exception_tables, following the + length_of_augmented field. This field contains an offset + into the "_MIPS_eh_region", which describes + the IRIX CC exception handling tables. + ---END SGI-ONLY COMMENT + + GNU .eh_frame has an augmentation string of z[RLP]* (gcc 3.4) + The similarity to IRIX 'z' (and proposed but never + implemented IRIX z1, z2 etc) was confusing things. + If the section is .eh_frame then 'z' means GNU exception + information 'Augmentation Data' not IRIX 'z'. + See The Linux Standard Base Core Specification version 3.0 +*/ + +#define DW_DEBUG_FRAME_VERSION 1 /* DWARF2 */ +#define DW_DEBUG_FRAME_VERSION3 3 /* DWARF3 */ +#define DW_DEBUG_FRAME_VERSION4 4 /* DWARF4 */ +/* The following is SGI/IRIX specific, and probably no longer + in use anywhere. */ +#define DW_DEBUG_FRAME_AUGMENTER_STRING "mti v1" + +/* The value of the offset field for Cie's. */ +#define DW_CIE_OFFSET ~(0x0) + +/* The augmentation string may be NULL. */ +#define DW_EMPTY_STRING "" + +#define DW_FRAME_INSTR_OPCODE_SHIFT 6 +#define DW_FRAME_INSTR_OFFSET_MASK 0x3f + +/* Frame description instructions expanded. + Accessed via a function. +*/ +struct Dwarf_Frame_Instr_s { + /* fp_op, if a base op, has the low 6 bits set zero here */ + Dwarf_Small fi_op; + /* fp_instr_offset is within instructions */ + Dwarf_Unsigned fi_instr_offset; + Dwarf_Unsigned fi_offset; /* frame offset */ + /* A string like "u","r", or "rsd" denoting the field + meanings. See the entire list of possibilities. + Never free. */ + const char *fi_fields; + + /* letter r and u both use u struct elements. */ + Dwarf_Unsigned fi_u0; + Dwarf_Unsigned fi_u1; + Dwarf_Unsigned fi_u2; /* LLVM extension */ + Dwarf_Signed fi_s0; + Dwarf_Signed fi_s1; + Dwarf_Unsigned fi_code_align_factor; + Dwarf_Signed fi_data_align_factor; + + Dwarf_Block fi_expr; + /* Used to prepare a list, which + is then turned into array and this zeroed. */ + struct Dwarf_Frame_Instr_s *fi_next; +}; +typedef struct Dwarf_Frame_Instr_s * Dwarf_Frame_Instr; + +struct Dwarf_Frame_Instr_Head_s { + /* fp_op, if a base op, has the low 6 bits set zero here */ + Dwarf_Debug fh_dbg; + Dwarf_Cie fh_cie; + + /* array of pointers to Dwarf_Frame_Instr_s */ + Dwarf_Frame_Instr *fh_array; + Dwarf_Unsigned fh_array_count; +}; + +/* + This struct denotes the rule for a register in a row of + the frame table. In other words, it is one element of + the table. +*/ +struct Dwarf_Reg_Rule_s { + + /* Is a flag indicating whether the rule includes the offset + field, ie whether the ru_soffset field is valid or not. + Applies only if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET. + It is important, since reg+offset (offset of 0) + is different from + just 'register' since the former means 'read memory at address + given by the sum of register contents plus offset to get the + value'. whereas the latter + means 'the value is in the register'. + */ + Dwarf_Sbyte ru_is_offset; + + /* This has to do with evaluating register + instructions, not with printing frame instruction. + DW_EXPR_OFFSET 0 ( DWARF2) + DW_EXPR_VAL_OFFSET 1 (dwarf2/3) + DW_EXPR_EXPRESSION 2 (dwarf2/3) + DW_EXPR_VAL_EXPRESSION 3 (dwarf2/3) + DW_EXPR_ARGS_SIZE 4 (GNU) + */ + Dwarf_Sbyte ru_value_type; + + /* Register involved in this rule, real or non-real-register. + ru_value_type is DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET. + */ + Dwarf_Unsigned ru_register; + + /* Offset to add to register, if indicated by ru_is_offset. + ru_value_type is DW_EXPR_OFFSET */ + Dwarf_Signed ru_offset; + Dwarf_Unsigned ru_args_size; /* DW_CFA_GNU_args_size */ + /* If ru_value_type is DW_EXPR_EXPRESSION + or DW_EXPR_VAL_EXPRESSION this is filled in. */ + Dwarf_Block ru_block; + +}; +/* Internal use only */ +typedef struct Dwarf_Regtable_Entry3_s_i { + Dwarf_Small dw_offset_relevant; + Dwarf_Small dw_value_type; + Dwarf_Unsigned dw_regnum; + Dwarf_Unsigned dw_offset; + Dwarf_Unsigned dw_args_size; /* Not dealt with. */ + Dwarf_Block dw_block; +} Dwarf_Regtable_Entry3_i; +/* Internal use only */ +typedef struct Dwarf_Regtable3_s_i { + Dwarf_Regtable_Entry3_i rt3_cfa_rule; + Dwarf_Unsigned rt3_reg_table_size; + Dwarf_Regtable_Entry3_i *rt3_rules; +} Dwarf_Regtable3_i; + +typedef struct Dwarf_Frame_s *Dwarf_Frame; + +/* + This structure represents a row of the frame table. + Fr_loc is the pc value for this row, and Fr_reg + contains the rule for each column. + + Entry DW_FRAME_CFA_COL of fr_reg was the traditional MIPS + way of setting CFA. cfa_rule is the new one. +*/ +struct Dwarf_Frame_s { + + /* Pc value corresponding to this row of the frame table. */ + Dwarf_Addr fr_loc; + + /* Rules for all the registers in this row. */ + struct Dwarf_Reg_Rule_s fr_cfa_rule; + + /* fr_reg_count is the the number of + entries of the fr_reg array. */ + Dwarf_Unsigned fr_reg_count; + struct Dwarf_Reg_Rule_s *fr_reg; + + Dwarf_Frame fr_next; +}; + +/* See dwarf_frame.c for the heuristics used to set the + Dwarf_Cie ci_augmentation_type. + + This succinctly helps interpret the size and + meaning of .debug_frame + and (for gcc) .eh_frame. + + In the case of gcc .eh_frame (gcc 3.3, 3.4) + z may be followed by one or more of + L R P. + +*/ +enum Dwarf_augmentation_type { + aug_empty_string, /* Default empty augmentation string. */ + aug_irix_exception_table, /* IRIX plain "z", + for exception handling, IRIX CC compiler. + Proposed z1 z2 ... never implemented. */ + aug_gcc_eh_z, /* gcc z augmentation, (including + L R P variations). gcc 3.3 3.4 exception + handling in eh_frame. */ + aug_irix_mti_v1, /* IRIX "mti v1" augmentation string. Probably + never in any released SGI-IRIX compiler. */ + aug_eh, /* For gcc .eh_frame, "eh" is the string., + gcc 1,2, egcs. Older values. */ + aug_armcc, /* "armcc+" meaning the cfa calculation + is corrected to be standard (output by + Arm C RVCT 3.0 SP1 and later). See + http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html + for details. */ + aug_unknown, /* Unknown augmentation, we cannot do much. */ + + /* HC, From http://sourceforge.net/p/elftoolchain/tickets/397/ */ + aug_metaware, + + aug_past_last +}; + +/* + This structure contains all the pertinent info for a Cie. Most + of the fields are taken straight from the definition of a Cie. + Ci_cie_start points to the address (in .debug_frame) where this + Cie begins. Ci_cie_instr_start points to the first byte of the + frame instructions for this Cie. Ci_dbg points to the associated + Dwarf_Debug structure. Ci_initial_table is a pointer to the table + row generated by the instructions for this Cie. +*/ +struct Dwarf_Cie_s { + Dwarf_Unsigned ci_length; + char *ci_augmentation; + Dwarf_Unsigned ci_code_alignment_factor; + Dwarf_Signed ci_data_alignment_factor; + Dwarf_Small ci_return_address_register; + Dwarf_Small *ci_cie_start; + Dwarf_Small *ci_cie_instr_start; + Dwarf_Small *ci_cie_end; + Dwarf_Debug ci_dbg; + Dwarf_Frame ci_initial_table; + Dwarf_Cie ci_next; + Dwarf_Small ci_length_size; + Dwarf_Small ci_extension_size; + Dwarf_Half ci_cie_version_number; + enum Dwarf_augmentation_type ci_augmentation_type; + + /* The following 2 for GNU .eh_frame exception handling + Augmentation Data. Set if ci_augmentation_type + is aug_gcc_eh_z. Zero if unused. */ + Dwarf_Unsigned ci_gnu_eh_augmentation_len; + Dwarf_Ptr ci_gnu_eh_augmentation_bytes; + + /* These are extracted from the gnu eh_frame + augmentation if the + augmentation begins with 'z'. See Linux LSB documents. + Otherwize these are zero. */ + unsigned char ci_gnu_personality_handler_encoding; + unsigned char ci_gnu_lsda_encoding; + unsigned char ci_gnu_fde_begin_encoding; + + /* If 'P' augmentation present, is handler addr. Else + is zero. */ + Dwarf_Addr ci_gnu_personality_handler_addr; + + /* In creating list of cie's (which will become an array) + record the position so fde can get it on fde creation. */ + Dwarf_Unsigned ci_index; + Dwarf_Small * ci_section_ptr; + Dwarf_Unsigned ci_section_length; + Dwarf_Small * ci_section_end; + /* DWARF4 adds address size and segment size to the CIE: + the .debug_info + section may not always be present to allow libdwarf to + find address_size from the compilation-unit. */ + Dwarf_Half ci_address_size; + Dwarf_Half ci_segment_size; + +}; + +/* + This structure contains all the pertinent info for a Fde. + Most of the fields are taken straight from the definition. + fd_cie_index is the index of the Cie associated with this + Fde in the list of Cie's for this debug_frame. Fd_cie + points to the corresponding Dwarf_Cie structure. Fd_fde_start + points to the start address of the Fde. Fd_fde_instr_start + points to the start of the instructions for this Fde. Fd_dbg + points to the associated Dwarf_Debug structure. +*/ +struct Dwarf_Fde_s { + Dwarf_Unsigned fd_length; + Dwarf_Addr fd_cie_offset; + Dwarf_Unsigned fd_cie_index; + Dwarf_Cie fd_cie; + Dwarf_Addr fd_initial_location; + Dwarf_Small *fd_initial_loc_pos; + Dwarf_Addr fd_address_range; + Dwarf_Small *fd_fde_start; + Dwarf_Small *fd_fde_instr_start; + Dwarf_Small *fd_fde_end; + Dwarf_Debug fd_dbg; + + /* fd_offset_into_exception_tables is SGI/IRIX exception table + offset. Unused and zero if not IRIX .debug_frame. */ + Dwarf_Signed fd_offset_into_exception_tables; + + Dwarf_Fde fd_next; + Dwarf_Small fd_length_size; + Dwarf_Small fd_extension_size; + /* So we know from an fde which 'count' of fde-s in + Dwarf_Debug applies: eh or standard. */ + Dwarf_Small fd_is_eh; + /* The following 2 for GNU .eh_frame exception handling + Augmentation Data. Set if CIE ci_augmentation_type + is aug_gcc_eh_z. Zero if unused. */ + Dwarf_Unsigned fd_gnu_eh_augmentation_len; + Dwarf_Bool fd_gnu_eh_aug_present; + Dwarf_Ptr fd_gnu_eh_augmentation_bytes; + Dwarf_Addr fd_gnu_eh_lsda; /* If 'L' augmentation letter + present: is address of the + Language Specific Data Area (LSDA). If not 'L" is zero. */ + + /* The following 3 are about the Elf section the FDEs come from.*/ + Dwarf_Small *fd_section_ptr; + Dwarf_Unsigned fd_section_length; + Dwarf_Unsigned fd_section_index; + Dwarf_Small *fd_section_end; + + /* If fd_eh_table_value_set is true, then fd_eh_table_value is + meaningful. Never meaningful for .debug_frame, is + part of .eh_frame. */ + Dwarf_Unsigned fd_eh_table_value; + Dwarf_Bool fd_eh_table_value_set; + + /* The following are memoization to save recalculation. */ + struct Dwarf_Frame_s fd_fde_table; + Dwarf_Addr fd_fde_pc_requested; + Dwarf_Bool fd_have_fde_tab; + + /* Set by dwarf_get_fde_for_die() */ + Dwarf_Bool fd_fde_owns_cie; + +}; + +int +_dwarf_validate_register_numbers(Dwarf_Debug dbg,Dwarf_Error *error); + +int +_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist, + Dwarf_Off ** offsetlist, + Dwarf_Signed * returncount, + Dwarf_Error * err); + +int +_dwarf_get_fde_list_internal(Dwarf_Debug dbg, + Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, /* If non-zero, + this is gcc eh_frame. */ + Dwarf_Error * error); + +enum Dwarf_augmentation_type +_dwarf_get_augmentation_type(Dwarf_Debug dbg, + Dwarf_Small *augmentation_string, + int is_gcc_eh_frame); +int _dwarf_fde_section_offset(Dwarf_Debug /*dbg*/, + Dwarf_Fde /*in_fde*/, + Dwarf_Off * /*fde_off*/, + Dwarf_Off * /*cie_off*/, + Dwarf_Error * /*err*/); +int _dwarf_cie_section_offset(Dwarf_Debug /*dbg*/, + Dwarf_Cie /*in_cie*/, + Dwarf_Off * /*cie_off */, + Dwarf_Error * /*err*/); + +int _dwarf_get_return_address_reg(Dwarf_Small *frame_ptr, + int version, + Dwarf_Debug dbg, + Dwarf_Byte_Ptr section_end, + unsigned long *size, + Dwarf_Unsigned *return_address_register, + Dwarf_Error *error); + +/* Temporary recording of crucial cie/fde prefix data. + Vastly simplifies some argument lists. */ +struct cie_fde_prefix_s { + /* cf_start_addr is a pointer to the first byte + of this fde/cie (meaning the length field itself) */ + Dwarf_Small * cf_start_addr; + /* cf_addr_after_prefix is a pointer + to the first byte of this fde/cie + we are reading now, immediately following + the length field read by READ_AREA_LENGTH. */ + Dwarf_Small * cf_addr_after_prefix; + /* cf_length is the length field value from the cie/fde + header. */ + Dwarf_Unsigned cf_length; + int cf_local_length_size; + int cf_local_extension_size; + Dwarf_Unsigned cf_cie_id; + Dwarf_Small * cf_cie_id_addr; /*used for eh_frame calculations.*/ + + /* Simplifies passing around these values to create fde having + these here. */ + /* cf_section_ptr is a pointer to the first byte + of the object section the prefix is read from. */ + Dwarf_Small * cf_section_ptr; + Dwarf_Unsigned cf_section_index; + Dwarf_Unsigned cf_section_length; +}; + +int +_dwarf_exec_frame_instr(Dwarf_Bool make_instr, + Dwarf_Bool search_pc, + Dwarf_Addr search_pc_val, + Dwarf_Addr initial_loc, + Dwarf_Small * start_instr_ptr, + Dwarf_Small * final_instr_ptr, + Dwarf_Frame table, + Dwarf_Cie cie, + Dwarf_Debug dbg, + Dwarf_Unsigned reg_num_of_cfa, + Dwarf_Bool * has_more_rows, + Dwarf_Addr * subsequent_pc, + Dwarf_Frame_Instr_Head *ret_frame_instr_head, + Dwarf_Unsigned * returned_frame_instr_count, + Dwarf_Error *error); + +int _dwarf_read_cie_fde_prefix(Dwarf_Debug dbg, + Dwarf_Small *frame_ptr_in, + Dwarf_Small *section_ptr_in, + Dwarf_Unsigned section_index_in, + Dwarf_Unsigned section_length_in, + struct cie_fde_prefix_s *prefix_out, + Dwarf_Error *error); + +int _dwarf_create_fde_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s * prefix, + Dwarf_Small *section_pointer, + Dwarf_Unsigned section_length, + Dwarf_Small *frame_ptr, + Dwarf_Small *section_ptr_end, + int use_gnu_cie_calc, + Dwarf_Cie cie_ptr_in, + Dwarf_Small address_size_in, + Dwarf_Fde *fde_ptr_out, + Dwarf_Error *error); + +int _dwarf_create_cie_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small* section_pointer, + Dwarf_Small* frame_ptr, + Dwarf_Small *section_ptr_end, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie *cie_ptr_out, + Dwarf_Error *error); + +int _dwarf_frame_constructor(Dwarf_Debug dbg,void * ); +void _dwarf_frame_destructor (void *); +void _dwarf_fde_destructor (void *); +void _dwarf_frame_instr_destructor(void *); diff --git a/src/lib/libdwarf/dwarf_frame2.c b/src/lib/libdwarf/dwarf_frame2.c new file mode 100644 index 0000000..df598b2 --- /dev/null +++ b/src/lib/libdwarf/dwarf_frame2.c @@ -0,0 +1,2049 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* This implements _dwarf_get_fde_list_internal() + and related helper functions for reading cie/fde data. */ + +#include + +#include /* qsort() */ +#include /* printf() */ +#include /* memcpy() memset() strcmp() + strncmp() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_frame.h" +#include "dwarf_arange.h" /* using Arange as a way to build a list */ +#include "dwarf_string.h" + +/* For a little information about .eh_frame see + https://stackoverflow.com/questions/14091231/ + what-do-the-eh-frame-and-eh-frame-hdr-sections-store-exactly + http://refspecs.linuxfoundation.org/LSB_3.0.0/ + LSB-Core-generic/LSB-Core-generic/ehframechpt.html + The above give information about fields and sizes but + very very little about content. + + .eh_frame_hdr contains data for C++ unwinding. Namely + tables for fast access into .eh_frame. +*/ + +#if 0 /* FOR DEBUGGING */ +/* For debugging only. */ +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} + +#endif + +static int _dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr, + Dwarf_Cie cur_cie_ptr, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Cie head_cie_ptr); +static void _dwarf_dealloc_fde_cie_list_internal( + Dwarf_Fde head_fde_ptr, + Dwarf_Cie head_cie_ptr); +static int _dwarf_create_cie_from_start(Dwarf_Debug dbg, + Dwarf_Small * cie_ptr_val, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Small * section_ptr_end, + Dwarf_Unsigned cie_id_value, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Error * error); + +static int _dwarf_get_gcc_eh_augmentation(Dwarf_Debug dbg, + Dwarf_Small * frame_ptr, + unsigned long + *size_of_augmentation_data, + enum Dwarf_augmentation_type augtype, + Dwarf_Small * section_end_pointer, + char *augmentation, + Dwarf_Error *error); + +static int +_dwarf_gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation, + Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len, + Dwarf_Half address_size, + unsigned char *pers_hand_enc_out, + unsigned char *lsda_enc_out, + unsigned char *fde_begin_enc_out, + Dwarf_Addr * gnu_pers_addr_out, + Dwarf_Error *error); + +static int _dwarf_read_encoded_ptr(Dwarf_Debug dbg, + Dwarf_Small * section_pointer, + Dwarf_Small * input_field, + int gnu_encoding, + Dwarf_Small * section_ptr_end, + Dwarf_Half address_size, + Dwarf_Unsigned * addr, + Dwarf_Small ** input_field_out, + Dwarf_Error *error); + +/* Called by qsort to compare FDE entries. + Consumer code expects the array of FDE pointers to be + in address order. +*/ +static int +qsort_compare(const void *elem1, const void *elem2) +{ + const Dwarf_Fde fde1 = *(const Dwarf_Fde *) elem1; + const Dwarf_Fde fde2 = *(const Dwarf_Fde *) elem2; + Dwarf_Addr addr1 = fde1->fd_initial_location; + Dwarf_Addr addr2 = fde2->fd_initial_location; + + if (addr1 < addr2) { + return -1; + } else if (addr1 > addr2) { + return 1; + } + return 0; +} + +/* Adds 'newone' to the end of the list starting at 'head' + and makes the new one current. */ +static void +chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur) +{ + if (*head == NULL) + *head = newone; + else { + (*cur)->fd_next = newone; + } + *cur = newone; + +} + +/* Adds 'newone' to the end of the list starting at 'head' + and makes the new one current. */ +static void +chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur) +{ + if (*head == NULL) { + *head = newone; + } else { + (*cur)->ci_next = newone; + } + *cur = newone; +} + +/* The size of the length field plus the + value of length must be an integral + multiple of the address size. Dwarf4 standard. + + A constant that gives the number of bytes of the CIE + structure, not including the length field itself + (where length mod == 0) + (see Section 7.2.2). Dwarf3 standard. + + A uword constant that gives the number of bytes of + the CIE structure, not including the + length field, itself (length mod == 0). + Dwarf2 standard.*/ +static void +validate_length(Dwarf_Debug dbg, + Dwarf_Cie cieptr, Dwarf_Unsigned length, + Dwarf_Unsigned length_size, + Dwarf_Unsigned extension_size, + Dwarf_Small * section_ptr, + Dwarf_Small * ciefde_start, + const char * cieorfde) +{ + Dwarf_Unsigned address_size = 0; + Dwarf_Unsigned length_field_summed = length_size + extension_size; + Dwarf_Unsigned total_len = length + length_field_summed; + Dwarf_Unsigned mod = 0; + + if (cieptr) { + address_size = cieptr->ci_address_size; + } else { + address_size = dbg->de_pointer_size; + } + mod = total_len % address_size; + if (mod != 0) { + dwarfstring harm; + Dwarf_Unsigned sectionoffset = ciefde_start - section_ptr; + + dwarfstring_constructor(&harm); + if (!cieorfde || (strlen(cieorfde) > 3)) { + /* Coding error or memory corruption? */ + cieorfde = "ERROR!"; + } + dwarfstring_append_printf_u(&harm, + "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE" + " len=0x%" DW_PR_XZEROS DW_PR_DUx, + length); + dwarfstring_append_printf_u(&harm, + ", len size=0x%" DW_PR_XZEROS DW_PR_DUx, + length_size); + dwarfstring_append_printf_u(&harm, + ", extn size=0x%" DW_PR_XZEROS DW_PR_DUx, + extension_size); + dwarfstring_append_printf_u(&harm, + ", totl length=0x%" DW_PR_XZEROS DW_PR_DUx, + total_len); + dwarfstring_append_printf_u(&harm, + ", addr size=0x%" DW_PR_XZEROS DW_PR_DUx, + address_size); + dwarfstring_append_printf_u(&harm, + ", mod=0x%" DW_PR_XZEROS DW_PR_DUx " must be zero", + mod); + dwarfstring_append_printf_s(&harm, + " in %s",(char *)cieorfde); + dwarfstring_append_printf_u(&harm, + ", offset 0x%" DW_PR_XZEROS DW_PR_DUx ".", + sectionoffset); + dwarf_insert_harmless_error(dbg, + dwarfstring_string(&harm)); + dwarfstring_destructor(&harm); + } + return; +} + +#if 0 /* FOR DEBUGGING */ +/* For debugging only. */ +static void +print_prefix(struct cie_fde_prefix_s *prefix, int line) +{ + printf("prefix-print, prefix at 0x%lx, line %d\n", + (unsigned long) prefix, line); + printf(" start addr 0x%lx after prefix 0x%lx\n", + (unsigned long) prefix->cf_start_addr, + (unsigned long) prefix->cf_addr_after_prefix); + printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n", + (Dwarf_Unsigned) prefix->cf_length, + prefix->cf_local_length_size, + prefix->cf_local_extension_size); + printf(" cie_id 0x%" DW_PR_DUx " cie_id cie_id_addr 0x%lx\n", + (Dwarf_Unsigned) prefix->cf_cie_id, + (long) prefix->cf_cie_id_addr); + printf + (" sec ptr 0x%lx sec index %" DW_PR_DSd + " sec len 0x%" DW_PR_DUx " sec past end 0x%lx\n", + (unsigned long) prefix->cf_section_ptr, + (Dwarf_Signed) prefix->cf_section_index, + (Dwarf_Unsigned) prefix->cf_section_length, + (unsigned long) prefix->cf_section_ptr + + (unsigned long)prefix->cf_section_length); +} +#endif + +/* Make the 'cieptr' consistent across .debug_frame and .eh_frame. + Calculate a pointer into section bytes given a cie_id in + an FDE header. + + In .debug_frame, the CIE_pointer is an offset in .debug_frame. + + In .eh_frame, the CIE Pointer is, when + cie_id_value subtracted from the + cie_id_addr, the address in memory of + a CIE length field. + Since cie_id_addr is the address of an FDE CIE_Pointer + field, cie_id_value for .eh_frame + has to account for the length-prefix. + so that the returned cieptr really points to + a CIE length field. Whew! + Available documentation on this is just a bit + ambiguous, but this calculation is correct. +*/ + +static int +get_cieptr_given_offset(Dwarf_Debug dbg, + Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_length, + Dwarf_Small * cie_id_addr, + Dwarf_Small ** ret_cieptr, + Dwarf_Error *error) +{ + if (cie_id_value >= section_length) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: in eh_frame " + " cie_id value makes no sense. Corrupt DWARF"); + return DW_DLV_ERROR; + } + if (use_gnu_cie_calc) { + /* cie_id value is offset, in section, of the + cie_id itself, to + use vm ptr of the value, + less the value, to get to the cie header. */ + if ((Dwarf_Unsigned)cie_id_addr <= cie_id_value) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: in eh_frame " + " cie_id makes no sense. Corrupt DWARF"); + return DW_DLV_ERROR; + } + *ret_cieptr = cie_id_addr - cie_id_value; + } else { + /* Traditional dwarf section offset is in cie_id */ + *ret_cieptr = section_ptr + cie_id_value; + } + return DW_DLV_OK; +} + +/* Internal function called from various places to create + lists of CIEs and FDEs. Not directly called + by consumer code */ +int +_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data, + Dwarf_Signed * cie_element_count, + Dwarf_Fde ** fde_data, + Dwarf_Signed * fde_element_count, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Unsigned cie_id_value, + int use_gnu_cie_calc, Dwarf_Error * error) +{ + /* Scans the debug_frame section. */ + Dwarf_Small *frame_ptr = section_ptr; + Dwarf_Small *section_ptr_end = section_ptr + section_length; + + /* New_cie points to the Cie being read, and head_cie_ptr and + cur_cie_ptr are used for chaining them up in sequence. + In case cie's are reused aggressively we need tail_cie_ptr + to add to the chain. If we re-use an early cie + later on, that does not mean we chain a + new cie to the early one, + we always chain it to the tail. */ + Dwarf_Cie head_cie_ptr = NULL; + Dwarf_Cie cur_cie_ptr = NULL; + Dwarf_Cie tail_cie_ptr = NULL; + Dwarf_Unsigned cie_count = 0; + + /* Points to a list of contiguous pointers to + Dwarf_Cie structures. + */ + Dwarf_Cie *cie_list_ptr = 0; + + /* New_fde points to the Fde being created, and head_fde_ptr and + cur_fde_ptr are used to chain them up. */ + Dwarf_Fde head_fde_ptr = NULL; + Dwarf_Fde cur_fde_ptr = NULL; + Dwarf_Unsigned fde_count = 0; + + /* Points to a list of contiguous pointers to + Dwarf_Fde structures. + */ + Dwarf_Fde *fde_list_ptr = NULL; + + Dwarf_Unsigned i = 0; + int res = DW_DLV_ERROR; + + if (frame_ptr == 0) { + return DW_DLV_NO_ENTRY; + } + res = _dwarf_validate_register_numbers(dbg,error); + if (res == DW_DLV_ERROR) { + return res; + } + + /* We create the fde and cie arrays. + Processing each CIE as we come + to it or as an FDE refers to it. + We cannot process 'late' CIEs + late as GNU .eh_frame complexities + mean we need the whole CIE + before we can process the FDE correctly. */ + while (frame_ptr < section_ptr_end) { + + struct cie_fde_prefix_s prefix; + + /* First read in the 'common prefix' to + figure out what we are + to do with this entry. */ + memset(&prefix, 0, sizeof(prefix)); + res = _dwarf_read_cie_fde_prefix(dbg, + frame_ptr, section_ptr, + section_index, + section_length, &prefix, error); + if (res == DW_DLV_ERROR) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + break; + } + frame_ptr = prefix.cf_addr_after_prefix; + if (frame_ptr >= section_ptr_end) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); +#if 0 + _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); +#endif + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: following " + "a the start of a cie/fde we have run off" + " the end of the section. Corrupt Dwarf"); + + return DW_DLV_ERROR; + } + + if (prefix.cf_cie_id == cie_id_value) { + /* This is a CIE. */ + Dwarf_Cie cie_ptr_to_use = 0; + int resc = 0; + + resc = _dwarf_find_existing_cie_ptr(prefix.cf_start_addr, + cur_cie_ptr, + &cie_ptr_to_use, + head_cie_ptr); + if (resc == DW_DLV_OK) { + cur_cie_ptr = cie_ptr_to_use; + /* Ok. Seen already. */ + } else if (resc == DW_DLV_NO_ENTRY) { + /* CIE before its FDE in this case. */ + resc = _dwarf_create_cie_from_after_start(dbg, + &prefix, + section_ptr, + frame_ptr, + section_ptr_end, + cie_count, + use_gnu_cie_calc, + &cie_ptr_to_use, + error); + if (resc != DW_DLV_OK) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return resc; + } + cie_count++; + chain_up_cie(cie_ptr_to_use, &head_cie_ptr, + &tail_cie_ptr); + cur_cie_ptr = tail_cie_ptr; + } else { /* res == DW_DLV_ERROR */ + + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return resc; + } + frame_ptr = cie_ptr_to_use->ci_cie_start + + cie_ptr_to_use->ci_length + + cie_ptr_to_use->ci_length_size + + cie_ptr_to_use->ci_extension_size; + continue; + } else { + /* This is an FDE, Frame Description Entry, see the Dwarf + Spec, (section 6.4.1 in DWARF2, DWARF3, DWARF4, ...) + Or see the .eh_frame specification, + from the Linux Foundation (or other source). */ + int resf = DW_DLV_ERROR; + Dwarf_Cie cie_ptr_to_use = 0; + Dwarf_Fde fde_ptr_to_use = 0; + Dwarf_Small *cieptr_val = 0; + + resf = get_cieptr_given_offset(dbg, + prefix.cf_cie_id, + use_gnu_cie_calc, + section_ptr, + section_length, + prefix.cf_cie_id_addr,&cieptr_val,error); + if (resf != DW_DLV_OK) { + return resf; + } + resf = _dwarf_find_existing_cie_ptr(cieptr_val, + cur_cie_ptr, + &cie_ptr_to_use, + head_cie_ptr); + if (resf == DW_DLV_OK) { + cur_cie_ptr = cie_ptr_to_use; + /* Ok. Seen CIE already. */ + } else if (resf == DW_DLV_NO_ENTRY) { + resf = _dwarf_create_cie_from_start(dbg, + cieptr_val, + section_ptr, + section_index, + section_length, + section_ptr_end, + cie_id_value, + cie_count, + use_gnu_cie_calc, + &cie_ptr_to_use, + error); + if (resf == DW_DLV_ERROR) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return resf; + } else if (resf == DW_DLV_NO_ENTRY) { + return resf; + } + ++cie_count; + chain_up_cie(cie_ptr_to_use, &head_cie_ptr, + &tail_cie_ptr); + cur_cie_ptr = tail_cie_ptr; + + } else { + /* DW_DLV_ERROR */ + return resf; + } + + resf = _dwarf_create_fde_from_after_start(dbg, + &prefix, + section_ptr, + section_length, + frame_ptr, + section_ptr_end, + use_gnu_cie_calc, + cie_ptr_to_use, + cie_ptr_to_use->ci_address_size, + &fde_ptr_to_use, + error); + if (resf == DW_DLV_ERROR) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return resf; + } + if (resf == DW_DLV_NO_ENTRY) { + /* impossible. */ + return resf; + } + chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr); + fde_count++; + /* ASSERT: DW_DLV_OK. */ + frame_ptr = cur_fde_ptr->fd_fde_start + + cur_fde_ptr->fd_length + + cur_fde_ptr->fd_length_size + + cur_fde_ptr->fd_extension_size; + if (frame_ptr < fde_ptr_to_use->fd_fde_instr_start) { + /* Sanity check. With a really short fde instruction + set and address_size we think is 8 + as it is ELF64 (but is + really 4, as in DWARF{2,3} where we have + no FDE address_size) we emit an error. + This error means things will not go well. */ + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + _dwarf_error(dbg,error, + DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH); + return DW_DLV_ERROR; + } + continue; + } + } + /* Now build list of CIEs from the list. If there are no CIEs + there should be no FDEs. */ + if (cie_count > 0) { + cie_list_ptr = (Dwarf_Cie *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count); + } else { + if (fde_count > 0) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + _dwarf_error(dbg, error, DW_DLE_ORPHAN_FDE); + return DW_DLV_ERROR; + } + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + return DW_DLV_NO_ENTRY; + } + if (cie_list_ptr == NULL) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + if (!head_cie_ptr) { + /* Should be impossible. */ + _dwarf_error_string(dbg, error,DW_DLE_DEBUGFRAME_ERROR, + "DW_DLE_DEBUGFRAME_ERROR" + "Impossible no head_cie_ptr"); + return DW_DLV_ERROR; + } + cur_cie_ptr = head_cie_ptr; + for (i = 0; i < cie_count; i++) { + *(cie_list_ptr + i) = cur_cie_ptr; + cur_cie_ptr = cur_cie_ptr->ci_next; + } + + /* Now build array of FDEs from the list. + With orphan CIEs (meaning no FDEs) + lets not return DW_DLV_NO_ENTRY */ + if (fde_count > 0) { + fde_list_ptr = (Dwarf_Fde *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count); + if (!fde_list_ptr) { + _dwarf_dealloc_fde_cie_list_internal(head_fde_ptr, + head_cie_ptr); + _dwarf_error_string(dbg, error,DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL" + "getting DW_DLA_LIST given fde_count"); + return DW_DLV_ERROR; + } + } + + /* It is ok if fde_list_ptr is NULL, we just have no fdes. */ + cur_fde_ptr = head_fde_ptr; + for (i = 0; i < fde_count; i++) { + *(fde_list_ptr + i) = cur_fde_ptr; + cur_fde_ptr = cur_fde_ptr->fd_next; + } + + /* Return arguments. */ + *cie_data = cie_list_ptr; + *cie_element_count = cie_count; + + *fde_data = fde_list_ptr; + *fde_element_count = fde_count; + if (use_gnu_cie_calc) { + dbg->de_fde_data_eh = fde_list_ptr; + dbg->de_fde_count_eh = fde_count; + dbg->de_cie_data_eh = cie_list_ptr; + dbg->de_cie_count_eh = cie_count; + } else { + dbg->de_fde_data = fde_list_ptr; + dbg->de_fde_count = fde_count; + dbg->de_cie_data = cie_list_ptr; + dbg->de_cie_count = cie_count; + } + + /* Sort the list by the address so that + dwarf_get_fde_at_pc() can + binary search this list. */ + if (fde_count > 0) { + qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr), + qsort_compare); + } + + return DW_DLV_OK; +} + +/* Internal function, not called by consumer code. + 'prefix' has accumulated the info up thru the cie-id + and now we consume the rest and build a Dwarf_Cie_s structure. +*/ +int +_dwarf_create_cie_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small * section_pointer, + Dwarf_Small * frame_ptr, + Dwarf_Small * section_ptr_end, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie * cie_ptr_out, + Dwarf_Error * error) +{ + Dwarf_Cie new_cie = 0; + + /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing + id. sgi uses + -1 (in .debug_frame). .eh_frame not quite identical to + .debug_frame */ + /* We here default the address size as it is not present + in DWARF2 or DWARF3 cie data, below we set it right if + it is present. */ + Dwarf_Half address_size = dbg->de_pointer_size; + Dwarf_Small *augmentation = 0; + Dwarf_Half segment_size = 0; + Dwarf_Signed data_alignment_factor = -1; + Dwarf_Unsigned code_alignment_factor = 4; + Dwarf_Unsigned return_address_register = 31; + int local_length_size = 0; + Dwarf_Unsigned leb128_length = 0; + Dwarf_Unsigned cie_aug_data_len = 0; + Dwarf_Small *cie_aug_data = 0; + Dwarf_Addr gnu_personality_handler_addr = 0; + unsigned char gnu_personality_handler_encoding = 0; + unsigned char gnu_lsda_encoding = 0; + unsigned char gnu_fde_begin_encoding = 0; + int res = 0; + Dwarf_Small version = 0; + + enum Dwarf_augmentation_type augt = aug_unknown; + + /* This is a CIE, Common Information Entry: See the dwarf spec, + section 6.4.1 */ + if (frame_ptr >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: reading a cie" + " version byte we have run off" + " the end of the section. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + version = *(Dwarf_Small *) frame_ptr; + + if ((frame_ptr+2) >= section_ptr_end) { + _dwarf_error_string(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: reading an augmentation" + " would run off" + " the end of the section. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 && + version != DW_CIE_VERSION4 && version != DW_CIE_VERSION5) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_FRAME_VERSION_BAD: cie version %u unknown", + version); + _dwarf_error_string(dbg, error, + DW_DLE_FRAME_VERSION_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + frame_ptr++; + augmentation = frame_ptr; + res = _dwarf_check_string_valid(dbg,section_pointer, + frame_ptr,section_ptr_end, + DW_DLE_AUGMENTATION_STRING_OFF_END,error); + if (res != DW_DLV_OK) { + return res; + } + frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1; + if (frame_ptr >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: following any " + "augmentation field we have run off " + "the end of the section " + "with the CIE incomplete. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + augt = _dwarf_get_augmentation_type(dbg, + augmentation, use_gnu_cie_calc); + if (augt == aug_eh) { + if ((frame_ptr+local_length_size) >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: following " + "type field we have run off the end of the section " + "with the CIE incomplete. Corrupt Dwarf"); + return DW_DLV_ERROR; + } +#if 0 + /* REFERENCED *//* Not used in this instance */ + Dwarf_Unsigned exception_table_addr = 0; + /* this is per egcs-1.1.2 as on RH 6.0 */ + READ_UNALIGNED_CK(dbg, exception_table_addr, + Dwarf_Unsigned, frame_ptr, local_length_size, + error,section_ptr_end); +#endif + frame_ptr += local_length_size; + } + { + Dwarf_Unsigned lreg = 0; + unsigned long size = 0; + + if (version == DW_CIE_VERSION4) { + if ((frame_ptr+2) >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "We would run off the end of the section " + "in a DWARF4 cie header. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + address_size = *((unsigned char *)frame_ptr); + if (address_size < 1) { + _dwarf_error_string(dbg, error, + DW_DLE_ADDRESS_SIZE_ZERO, + "DW_DLE_ADDRESS_SIZE_ZERO: bad address size " + "for a DWARF4 cie header"); + return DW_DLV_ERROR; + } + if (address_size > sizeof(Dwarf_Addr)) { + _dwarf_create_address_size_dwarf_error(dbg, + error,address_size, + DW_DLE_ADDRESS_SIZE_ERROR, + "DW_DLE_ADDRESS_SIZE_ERROR..:"); + return DW_DLV_ERROR; + } + if ((frame_ptr+2) >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "Running off the end " + " of a CIE header. Corrupt DWARF4"); + return DW_DLV_ERROR; + } + ++frame_ptr; + segment_size = *((unsigned char *)frame_ptr); + ++frame_ptr; + if (segment_size > sizeof(Dwarf_Addr)) { + _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); + return DW_DLV_ERROR; + } + } + + /* Not a great test. But the DECODE* do checking so ok. */ + if ((frame_ptr+2) >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Running off the end " + " of a CIE header before the code alignment value " + "read. Corrupt DWARF"); + return DW_DLV_ERROR; + } + DECODE_LEB128_UWORD_CK(frame_ptr, lreg,dbg,error, + section_ptr_end); + code_alignment_factor = (Dwarf_Unsigned) lreg; + res = dwarf_decode_signed_leb128( + (char *)frame_ptr, + &leb128_length,&data_alignment_factor, + (char *)section_ptr_end); + if (res != DW_DLV_OK) { + return res; + } + frame_ptr = frame_ptr + leb128_length; + if ((frame_ptr+1) >= section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Running off the end " + "of a CIE header before the return address register " + "number read. Corrupt DWARF"); + + return DW_DLV_ERROR; + } + res = _dwarf_get_return_address_reg(frame_ptr, version, + dbg,section_ptr_end, &size, + &return_address_register,error); + if (res != DW_DLV_OK) { + return res; + } + if (return_address_register > + dbg->de_frame_reg_rules_entry_count) { + _dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR); + return DW_DLV_ERROR; + } + frame_ptr += size; + if ((frame_ptr) > section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: Past the end " + "of a CIE header before reading " + "the augmentation string." + " Corrupt DWARF"); + return DW_DLV_ERROR; + } + } + switch (augt) { + case aug_empty_string: + break; + case aug_irix_mti_v1: + break; + case aug_irix_exception_table:{ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned length_of_augmented_fields; + + /* Decode the length of augmented fields. */ + DECODE_LEB128_UWORD_CK(frame_ptr, lreg, + dbg,error,section_ptr_end); + length_of_augmented_fields = (Dwarf_Unsigned) lreg; + if (length_of_augmented_fields >= dbg->de_filesize) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "The irix exception table length is too large " + "to be real"); + return DW_DLV_ERROR; + } + /* set the frame_ptr to point at the instruction start. */ + frame_ptr += length_of_augmented_fields; + } + break; + + case aug_eh:{ + int err = 0; + unsigned long increment = 0; + + if (!use_gnu_cie_calc) { + /* This should be impossible. */ + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + + err = _dwarf_get_gcc_eh_augmentation(dbg, frame_ptr, + &increment, + augt, + section_ptr_end, + (char *) augmentation,error); + if (err == DW_DLV_ERROR) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + frame_ptr += increment; + } + break; + case aug_gcc_eh_z:{ + /* Here we have Augmentation Data Length (uleb128) followed + by Augmentation Data bytes (not a string). */ + int resz = DW_DLV_ERROR; + Dwarf_Unsigned adlen = 0; + + if ((frame_ptr+1) > section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "gcc .eh_frame augmentation data " + "cannot be read. Out of room in the section." + " Corrupt DWARF."); + return DW_DLV_ERROR; + } + DECODE_LEB128_UWORD_CK(frame_ptr, adlen, + dbg,error,section_ptr_end); + cie_aug_data_len = adlen; + cie_aug_data = frame_ptr; + if (adlen) { + Dwarf_Small *cie_aug_data_end = cie_aug_data+adlen; + if (cie_aug_data_end < cie_aug_data || + cie_aug_data_end > section_ptr_end) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "gcc .eh_frame augmentation data " + "length of %" DW_PR_DUu " is too long to" + " fit in the section.",adlen); + _dwarf_error_string(dbg, error, + DW_DLE_AUG_DATA_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + resz = _dwarf_gnu_aug_encodings(dbg, + (char *) augmentation, + cie_aug_data, + cie_aug_data_len, + address_size, + &gnu_personality_handler_encoding, + &gnu_lsda_encoding, + &gnu_fde_begin_encoding, + &gnu_personality_handler_addr, + error); + if (resz != DW_DLV_OK) { + if (resz == DW_DLV_ERROR) { + _dwarf_error_string(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN, + "DW_DLE_FRAME_AUGMENTATION_UNKNOWN " + " Reading gnu aug encodings failed"); + } /* DW_DLV_NO_ENTRY seems impossible. */ + return resz; + } + frame_ptr += adlen; + } + break; + case aug_armcc: + break; + default:{ + /* We do not understand the augmentation string. No + assumption can be made about any fields other than what + we have already read. */ + frame_ptr = prefix->cf_start_addr + + prefix->cf_length + prefix->cf_local_length_size + + prefix->cf_local_extension_size; + /* FIX -- What are the values of data_alignment_factor, + code_alignment_factor, return_address_register and + instruction start? They were clearly uninitialized in the + previous version and I am leaving them the same way. */ + } + if ((frame_ptr) > section_ptr_end) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "Reading an unknown type of augmentation string " + "run off the end of the section. Corrupt DWARF."); + return DW_DLV_ERROR; + } + break; + } /* End switch on augmentation type. */ + + new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1); + if (new_cie == NULL) { + _dwarf_error_string(dbg, error, + DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL " + "attempting to allocate a Dwarf_Cie"); + return DW_DLV_ERROR; + } + + new_cie->ci_cie_version_number = version; + new_cie->ci_initial_table = NULL; + new_cie->ci_length = (Dwarf_Unsigned) prefix->cf_length; + new_cie->ci_length_size = + (Dwarf_Small)prefix->cf_local_length_size; + new_cie->ci_extension_size = + (Dwarf_Small)prefix->cf_local_extension_size; + new_cie->ci_augmentation = (char *) augmentation; + + new_cie->ci_data_alignment_factor = + (Dwarf_Sbyte) data_alignment_factor; + new_cie->ci_code_alignment_factor = + (Dwarf_Small) code_alignment_factor; + new_cie->ci_return_address_register = return_address_register; + new_cie->ci_cie_start = prefix->cf_start_addr; + + if ( frame_ptr > section_ptr_end) { + _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR); + return DW_DLV_ERROR; + } + new_cie->ci_cie_instr_start = frame_ptr; + new_cie->ci_dbg = dbg; + new_cie->ci_augmentation_type = augt; + new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len; + new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data; + new_cie->ci_gnu_personality_handler_encoding = + gnu_personality_handler_encoding; + new_cie->ci_gnu_personality_handler_addr = + gnu_personality_handler_addr; + new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding; + new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding; + + new_cie->ci_index = cie_count; + new_cie->ci_section_ptr = prefix->cf_section_ptr; + new_cie->ci_section_end = section_ptr_end; + new_cie->ci_cie_end = new_cie->ci_cie_start + new_cie->ci_length + + new_cie->ci_length_size+ new_cie->ci_extension_size; + if ( new_cie->ci_cie_end > section_ptr_end) { + dwarf_dealloc(dbg,new_cie,DW_DLA_CIE); + _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR); + return DW_DLV_ERROR; + } + + /* The Following new in DWARF4 */ + new_cie->ci_address_size = address_size; + new_cie->ci_segment_size = segment_size; + validate_length(dbg,new_cie,new_cie->ci_length, + new_cie->ci_length_size, new_cie->ci_extension_size, + new_cie->ci_section_ptr, + new_cie->ci_cie_start,"cie"); + *cie_ptr_out = new_cie; + return DW_DLV_OK; +} + +/* Internal function, not called by consumer code. + 'prefix' has accumulated the info up thru the cie-id + and now we consume the rest and build a Dwarf_Fde_s structure. + Can be called with cie_ptr_in NULL from dwarf_frame.c */ + +int +_dwarf_create_fde_from_after_start(Dwarf_Debug dbg, + struct cie_fde_prefix_s *prefix, + Dwarf_Small *section_pointer, + Dwarf_Unsigned section_length, + Dwarf_Small *frame_ptr, + Dwarf_Small *section_ptr_end, + int use_gnu_cie_calc, + Dwarf_Cie cie_ptr_in, + Dwarf_Small address_size, + Dwarf_Fde *fde_ptr_out, + Dwarf_Error *error) +{ + Dwarf_Fde new_fde = 0; + Dwarf_Cie cieptr = 0; + Dwarf_Small *saved_frame_ptr = 0; + + Dwarf_Small *initloc = frame_ptr; + Dwarf_Signed offset_into_exception_tables + = (Dwarf_Signed) DW_DLX_NO_EH_OFFSET; + Dwarf_Small *fde_aug_data = 0; + Dwarf_Unsigned fde_aug_data_len = 0; + Dwarf_Addr cie_base_offset = prefix->cf_cie_id; + Dwarf_Addr initial_location = 0; /* must be min de_pointer_size + bytes in size */ + Dwarf_Addr address_range = 0; /* must be min de_pointer_size + bytes in size */ + Dwarf_Unsigned eh_table_value = 0; + Dwarf_Bool eh_table_value_set = FALSE; + /* Temporary assumption. */ + enum Dwarf_augmentation_type augt = aug_empty_string; + + if (cie_ptr_in) { + cieptr = cie_ptr_in; + augt = cieptr->ci_augmentation_type; + } + if (augt == aug_gcc_eh_z) { + /* If z augmentation this is eh_frame, + and initial_location and + address_range in the FDE are read according to the CIE + augmentation string instructions. */ + + if (cieptr) { + Dwarf_Small *fp_updated = 0; + int res = _dwarf_read_encoded_ptr(dbg, + section_pointer, + frame_ptr, + cieptr-> ci_gnu_fde_begin_encoding, + section_ptr_end, + address_size, + &initial_location, + &fp_updated,error); + if (res != DW_DLV_OK) { + return res; + } + frame_ptr = fp_updated; + /* For the address-range it makes no sense to be + pc-relative, so we turn it off + with a section_pointer of + NULL. Masking off DW_EH_PE_pcrel from the + ci_gnu_fde_begin_encoding in this + call would also work + to turn off DW_EH_PE_pcrel. */ + res = _dwarf_read_encoded_ptr(dbg, (Dwarf_Small *) NULL, + frame_ptr, + cieptr->ci_gnu_fde_begin_encoding, + section_ptr_end, + address_size, + &address_range, &fp_updated,error); + if (res != DW_DLV_OK) { + return res; + } + frame_ptr = fp_updated; + } /* We know cieptr was set as was augt, no else needed + converity scan CID 323429 */ + { + Dwarf_Unsigned adlen = 0; + + DECODE_LEB128_UWORD_CK(frame_ptr, adlen, + dbg,error,section_ptr_end); + fde_aug_data_len = adlen; + fde_aug_data = frame_ptr; + if (frame_ptr < section_ptr_end) { + Dwarf_Unsigned remaininglen = 0; + remaininglen = (Dwarf_Unsigned) + (section_ptr_end - frame_ptr); + if (remaininglen <= adlen) { + _dwarf_error_string(dbg, error, + DW_DLE_AUG_DATA_LENGTH_BAD, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "augmentation length is too large for " + "the frame section, corrupt DWARF"); + return DW_DLV_ERROR; + } + } else { + _dwarf_error_string(dbg, error, + DW_DLE_AUG_DATA_LENGTH_BAD, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "frame pointer has stepped off the end " + "of the frame section on reading augmentation " + "length. Corrupt DWARF"); + return DW_DLV_ERROR; + } + if ( adlen >= section_length) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "gcc .eh_frame augmentation data " + "length of %" DW_PR_DUu " is too long to" + " fit in the section.",adlen); + _dwarf_error_string(dbg, error, + DW_DLE_AUG_DATA_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + frame_ptr += adlen; + if (adlen) { + if (frame_ptr < fde_aug_data || + frame_ptr >= section_ptr_end ) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_AUG_DATA_LENGTH_BAD: The " + "gcc .eh_frame augmentation data " + "length of %" DW_PR_DUu " is too long to" + " fit in the section.",adlen); + _dwarf_error_string(dbg, error, + DW_DLE_AUG_DATA_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + } + } else { + if ((frame_ptr + 2*address_size) > section_ptr_end) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, initial_location, Dwarf_Addr, + frame_ptr, address_size, + error,section_ptr_end); + frame_ptr += address_size; + READ_UNALIGNED_CK(dbg, address_range, Dwarf_Addr, + frame_ptr, address_size, + error,section_ptr_end); + frame_ptr += address_size; + } + switch (augt) { + case aug_irix_mti_v1: + case aug_empty_string: + break; + case aug_irix_exception_table:{ + Dwarf_Unsigned lreg = 0; + Dwarf_Unsigned length_of_augmented_fields = 0; + + DECODE_LEB128_UWORD_CK(frame_ptr, lreg, + dbg,error,section_ptr_end); + length_of_augmented_fields = (Dwarf_Unsigned) lreg; + + if (length_of_augmented_fields >= dbg->de_filesize) { + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD " + "in irix exception table length of augmented " + "fields is too large to be real"); + return DW_DLV_ERROR; + } + saved_frame_ptr = frame_ptr; + /* The first word is an offset into exception tables. + Defined as a 32bit offset even for CC -64. */ + if ((frame_ptr + DWARF_32BIT_SIZE) > section_ptr_end) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD " + "irix:frame does not fit in the DWARF section"); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, offset_into_exception_tables, + Dwarf_Addr, frame_ptr, DWARF_32BIT_SIZE, + error,section_ptr_end); + SIGN_EXTEND(offset_into_exception_tables, + DWARF_32BIT_SIZE); + if (offset_into_exception_tables > 0) { + if ((Dwarf_Unsigned)offset_into_exception_tables >= + dbg->de_filesize) { + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD " + "Irix offset into exception tables"); + return DW_DLV_ERROR; + } + } /* nobody uses irix anyway now */ + frame_ptr = saved_frame_ptr + length_of_augmented_fields; + } + break; + case aug_eh:{ + + if (!use_gnu_cie_calc) { + /* This should be impossible. */ + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + + /* gnu eh fde case. we do not need to do anything */ + /*REFERENCED*/ /* Not used in this instance of the macro */ + if ((frame_ptr + address_size) > section_ptr_end) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, eh_table_value, + Dwarf_Unsigned, frame_ptr, + address_size, + error,section_ptr_end); + eh_table_value_set = TRUE; + frame_ptr += address_size; + } + break; + + case aug_gcc_eh_z:{ + /* The Augmentation Data Length is here, followed by the + Augmentation Data bytes themselves. */ + } + break; + case aug_armcc: + break; + case aug_past_last: + break; + + case aug_metaware: /* No special fields. See dwarf_util.h */ + break; + + case aug_unknown: + _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + default: break; + } /* End switch on augmentation type */ + if ( frame_ptr > section_ptr_end) { + _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR); + return DW_DLV_ERROR; + } + if ( frame_ptr < initloc) { + _dwarf_error_string(dbg, error, + DW_DLE_DF_FRAME_DECODING_ERROR, + "DW_DLE_DF_FRAME_DECODING_ERROR " + "frame pointer decreased.Impossible. " + "arithmetic overflow"); + return DW_DLV_ERROR; + } + + new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1); + if (new_fde == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + new_fde->fd_length = prefix->cf_length; + new_fde->fd_length_size = + (Dwarf_Small)prefix->cf_local_length_size; + new_fde->fd_extension_size = + (Dwarf_Small)prefix->cf_local_extension_size; + new_fde->fd_is_eh = (Dwarf_Small)use_gnu_cie_calc; + new_fde->fd_cie_offset = cie_base_offset; + if (cieptr) { + new_fde->fd_cie_index = cieptr->ci_index; + } + new_fde->fd_cie = cieptr; + new_fde->fd_initial_location = initial_location; + new_fde->fd_initial_loc_pos = initloc; + new_fde->fd_address_range = address_range; + new_fde->fd_fde_start = prefix->cf_start_addr; + + new_fde->fd_fde_instr_start = frame_ptr; + new_fde->fd_fde_end = prefix->cf_start_addr + + prefix->cf_length + prefix->cf_local_length_size + + prefix->cf_local_extension_size; + if ( new_fde->fd_fde_end > section_ptr_end) { + _dwarf_error(dbg, error, DW_DLE_DF_FRAME_DECODING_ERROR); + dwarf_dealloc(dbg,new_fde,DW_DLA_FDE); + return DW_DLV_ERROR; + } + + new_fde->fd_dbg = dbg; + new_fde->fd_offset_into_exception_tables = + offset_into_exception_tables; + new_fde->fd_eh_table_value = eh_table_value; + new_fde->fd_eh_table_value_set = eh_table_value_set; + + new_fde->fd_section_ptr = prefix->cf_section_ptr; + new_fde->fd_section_index = prefix->cf_section_index; + new_fde->fd_section_length = prefix->cf_section_length; + new_fde->fd_section_end = section_ptr_end; + + if (augt == aug_gcc_eh_z) { + new_fde->fd_gnu_eh_aug_present = TRUE; + } + new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data; + new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len; + validate_length(dbg,cieptr,new_fde->fd_length, + new_fde->fd_length_size, new_fde->fd_extension_size, + new_fde->fd_section_ptr,new_fde->fd_fde_start,"fde"); + *fde_ptr_out = new_fde; + return DW_DLV_OK; +} + +/* Read in the common cie/fde prefix, including reading + the cie-value which shows which this is: cie or fde. */ +int +_dwarf_read_cie_fde_prefix(Dwarf_Debug dbg, + Dwarf_Small * frame_ptr_in, + Dwarf_Small * section_ptr_in, + Dwarf_Unsigned section_index_in, + Dwarf_Unsigned section_length_in, + struct cie_fde_prefix_s *data_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned length = 0; + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Small *frame_ptr = frame_ptr_in; + Dwarf_Small *cie_ptr_addr = 0; + Dwarf_Unsigned cie_id = 0; + Dwarf_Small *section_end = section_ptr_in + section_length_in; + + if (frame_ptr_in < section_ptr_in || + frame_ptr_in >= section_end) { + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "The frame point given _dwarf_read_cie_fde_prefix() " + "is invalid"); + return DW_DLV_ERROR; + } + if (section_end < (frame_ptr +4)) { + dwarfstring m; + Dwarf_Unsigned u = + (Dwarf_Unsigned)(uintptr_t)(frame_ptr+4) - + (Dwarf_Unsigned)(uintptr_t)section_end; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_FRAME_LENGTH_BAD: " + "Reading the cie/fde prefix would " + "put us %u bytes past the end of the " + "frame section. Corrupt Dwarf.",u); + _dwarf_error_string(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */ + READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned, + frame_ptr, local_length_size, + local_extension_size,error, + section_length_in,section_end); + if (length == 0) { + /* nul bytes at end of section, seen at end of egcs eh_frame + sections (in a.out). Take this as meaning no more CIE/FDE + data. We should be very close to end of section. */ + return DW_DLV_NO_ENTRY; + } + if (length >= dbg->de_filesize) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + if (length > section_length_in || + (length +local_length_size + local_extension_size) > + section_length_in) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + if ((frame_ptr + local_length_size) >= section_end) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + + cie_ptr_addr = frame_ptr; + READ_UNALIGNED_CK(dbg, cie_id, Dwarf_Unsigned, + frame_ptr, local_length_size,error,section_end); + SIGN_EXTEND(cie_id, local_length_size); + frame_ptr += local_length_size; + + data_out->cf_start_addr = frame_ptr_in; + data_out->cf_addr_after_prefix = frame_ptr; + + data_out->cf_length = length; + if (length > section_length_in) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + if (cie_ptr_addr+length > section_end) { + _dwarf_error(dbg,error,DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + data_out->cf_local_length_size = local_length_size; + data_out->cf_local_extension_size = local_extension_size; + + /* We do not know if it is a CIE or FDE id yet. + How we check and what it means + depends whether it is .debug_frame + or .eh_frame. */ + data_out->cf_cie_id = cie_id; + + /* The address of the CIE_id or FDE_id value in memory. */ + data_out->cf_cie_id_addr = cie_ptr_addr; + + data_out->cf_section_ptr = section_ptr_in; + data_out->cf_section_index = section_index_in; + data_out->cf_section_length = section_length_in; + return DW_DLV_OK; +} + +/* On various errors previously-allocated CIEs and FDEs + must be cleaned up. + This helps avoid leaks in case of errors. +*/ +static void +_dwarf_dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr, + Dwarf_Cie head_cie_ptr) +{ + Dwarf_Fde curfde = 0; + Dwarf_Cie curcie = 0; + Dwarf_Fde nextfde = 0; + Dwarf_Cie nextcie = 0; + + for (curfde = head_fde_ptr; curfde; curfde = nextfde) { + nextfde = curfde->fd_next; + dwarf_dealloc(curfde->fd_dbg, curfde, DW_DLA_FDE); + } + for (curcie = head_cie_ptr; curcie; curcie = nextcie) { + Dwarf_Frame frame = curcie->ci_initial_table; + + nextcie = curcie->ci_next; + if (frame) + dwarf_dealloc(curcie->ci_dbg, frame, DW_DLA_FRAME); + dwarf_dealloc(curcie->ci_dbg, curcie, DW_DLA_CIE); + } +} + +/* Find the cie whose id value is given: the id + value is, per DWARF2/3, an offset in the section. + For .debug_frame, zero is a legal offset. For + GNU .eh_frame it is not a legal offset. + 'cie_ptr' is a pointer into our section, not an offset. */ +static int +_dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr, + Dwarf_Cie cur_cie_ptr, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Cie head_cie_ptr) +{ + Dwarf_Cie next = 0; + + if (cur_cie_ptr && cie_ptr == cur_cie_ptr->ci_cie_start) { + /* Usually, we use the same cie again and again. */ + *cie_ptr_to_use_out = cur_cie_ptr; + return DW_DLV_OK; + } + for (next = head_cie_ptr; next; next = next->ci_next) { + if (cie_ptr == next->ci_cie_start) { + *cie_ptr_to_use_out = next; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +/* We have a valid cie_ptr_val that has not been + turned into an internal Cie yet. Do so now. + Returns DW_DLV_OK or DW_DLV_ERROR, never + DW_DLV_NO_ENTRY. + + 'section_ptr' - Points to first byte of section data. + 'section_length' - Length of the section, in bytes. + 'section_ptr_end' - Points 1-past last byte of section data. */ +static int +_dwarf_create_cie_from_start(Dwarf_Debug dbg, + Dwarf_Small * cie_ptr_val, + Dwarf_Small * section_ptr, + Dwarf_Unsigned section_index, + Dwarf_Unsigned section_length, + Dwarf_Small * section_ptr_end, + Dwarf_Unsigned cie_id_value, + Dwarf_Unsigned cie_count, + int use_gnu_cie_calc, + Dwarf_Cie * cie_ptr_to_use_out, + Dwarf_Error * error) +{ + struct cie_fde_prefix_s prefix; + int res = DW_DLV_ERROR; + Dwarf_Small *frame_ptr = cie_ptr_val; + + if (frame_ptr < section_ptr || frame_ptr >= section_ptr_end) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); + return DW_DLV_ERROR; + } + /* First read in the 'common prefix' to figure out + what * we are to + do with this entry. If it is not a cie * + we are in big trouble. */ + memset(&prefix, 0, sizeof(prefix)); + res = _dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr, + section_index, section_length, + &prefix, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* error. */ + _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR); + return DW_DLV_ERROR; + + } + + if (prefix.cf_cie_id != cie_id_value) { + _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR); + return DW_DLV_ERROR; + } + frame_ptr = prefix.cf_addr_after_prefix; + res = _dwarf_create_cie_from_after_start(dbg, + &prefix, + section_ptr, + frame_ptr, + section_ptr_end, + cie_count, + use_gnu_cie_calc, + cie_ptr_to_use_out, error); + return res; + +} + +/* This is for gnu eh frames, the 'z' case. + We find the letter involved + Return the augmentation character and, if applicable, + the personality routine address. + + personality_routine_out - + if 'P' is augchar, is personality handler addr. + Otherwise is not set. + aug_data - if 'P' points to data space of the + aug_data_len - length of areas aug_data points to. +*/ + +/* It is not clear if this is entirely correct. */ +static int +_dwarf_gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation, + Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len, + Dwarf_Half address_size, + unsigned char *pers_hand_enc_out, + unsigned char *lsda_enc_out, + unsigned char *fde_begin_enc_out, + Dwarf_Addr * gnu_pers_addr_out, + Dwarf_Error * error) +{ + char *nc = 0; + Dwarf_Small *cur_aug_p = aug_data; + Dwarf_Small *end_aug_p = aug_data + aug_data_len; + + for (nc = augmentation; *nc; ++nc) { + char c = *nc; + + switch (c) { + case 'z': + /* Means that the augmentation data is present. */ + continue; + + case 'S': + /* Indicates this is a signal stack frame. + Debuggers have to do + special handling. We don't need to do more than + print this flag at the right time, though + (see dwarfdump where it prints the augmentation + string). + A signal stack frame (in some OS's) can only be + unwound (backtraced) by knowing it is a signal + stack frame (perhaps by noticing the name of the + function for the stack frame if the name can be + found somehow) and figuring + out (or knowing) how the kernel and libc + pushed a structure + onto the stack and loading registers from + that structure. + Totally different from normal stack unwinding. + This flag gives an unwinder a big leg up by + decoupling the 'hint: this is a stack frame' + from knowledge like + the function name (the name might be + unavailable at unwind time). + */ + break; + + case 'L': + if (cur_aug_p >= end_aug_p) { + _dwarf_error_string(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN, + "DW_DLE_FRAME_AUGMENTATION_UNKNOWN: " + " Augmentation L runs off the end" + " of augmentation bytes"); + return DW_DLV_ERROR; + } + *lsda_enc_out = *(unsigned char *) cur_aug_p; + ++cur_aug_p; + break; + case 'R': + /* Followed by a one byte argument giving the + pointer encoding for the address + pointers in the fde. */ + if (cur_aug_p >= end_aug_p) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + *fde_begin_enc_out = *(unsigned char *) cur_aug_p; + ++cur_aug_p; + break; + case 'P':{ + int res = DW_DLV_ERROR; + Dwarf_Small *updated_aug_p = 0; + unsigned char encoding = 0; + + if (cur_aug_p >= end_aug_p) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + encoding = *(unsigned char *) cur_aug_p; + *pers_hand_enc_out = encoding; + ++cur_aug_p; + if (cur_aug_p > end_aug_p) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + /* DW_EH_PE_pcrel makes no sense here, so we turn it + off via a section pointer of NULL. */ + res = _dwarf_read_encoded_ptr(dbg, + (Dwarf_Small *) NULL, + cur_aug_p, + encoding, + end_aug_p, + address_size, + gnu_pers_addr_out, + &updated_aug_p, + error); + if (res != DW_DLV_OK) { + return res; + } + cur_aug_p = updated_aug_p; + if (cur_aug_p > end_aug_p) { + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + } + } + break; + default: + _dwarf_error(dbg, error, + DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + + } + } + return DW_DLV_OK; +} + +/* Given augmentation character (the encoding) giving the + address format, read the address from input_field + and return an incremented value 1 past the input bytes of the + address. + Push the address read back thru the *addr pointer. + See LSB (Linux Standard Base) exception handling documents. */ +static int +_dwarf_read_encoded_ptr(Dwarf_Debug dbg, + Dwarf_Small * section_pointer, + Dwarf_Small * input_field, + int gnu_encoding, + Dwarf_Small * section_end, + Dwarf_Half address_size, + Dwarf_Unsigned * addr, + Dwarf_Small ** input_field_updated, + Dwarf_Error *error) +{ + int value_type = gnu_encoding & 0xf; + Dwarf_Small *input_field_original = input_field; + + if (gnu_encoding == 0xff) { + /* There is no data here. */ + + *addr = 0; + *input_field_updated = input_field; + /* Should we return DW_DLV_NO_ENTRY? */ + return DW_DLV_OK; + } + switch (value_type) { + case DW_EH_PE_absptr:{ + /* value_type is zero. Treat as pointer size of the object. + */ + Dwarf_Unsigned ret_value = 0; + + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + input_field, address_size,error,section_end); + *addr = ret_value; + *input_field_updated = input_field + address_size; + } + break; + case DW_EH_PE_uleb128:{ + Dwarf_Unsigned val = 0; + + DECODE_LEB128_UWORD_CK(input_field,val,dbg,error,section_end); + *addr = val; + *input_field_updated = input_field; + } + break; + case DW_EH_PE_udata2:{ + Dwarf_Unsigned ret_value = 0; + + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + input_field, 2,error,section_end); + *addr = ret_value; + *input_field_updated = input_field + 2; + } + break; + + case DW_EH_PE_udata4:{ + Dwarf_Unsigned ret_value = 0; + + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + input_field, DWARF_32BIT_SIZE,error,section_end); + *addr = ret_value; + *input_field_updated = input_field + DWARF_32BIT_SIZE; + } + break; + + case DW_EH_PE_udata8:{ + Dwarf_Unsigned ret_value = 0; + + /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */ + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + input_field, DWARF_64BIT_SIZE,error,section_end); + *addr = ret_value; + *input_field_updated = input_field + DWARF_64BIT_SIZE; + } + break; + + case DW_EH_PE_sleb128:{ + Dwarf_Signed val = 0; + + DECODE_LEB128_SWORD_CK(input_field,val,dbg,error,section_end); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field; + } + break; + case DW_EH_PE_sdata2:{ + Dwarf_Unsigned val = 0; + + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, input_field, 2, + error,section_end); + SIGN_EXTEND(val, 2); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + 2; + } + break; + + case DW_EH_PE_sdata4:{ + Dwarf_Unsigned val = 0; + + READ_UNALIGNED_CK(dbg, val, + Dwarf_Unsigned, input_field, + DWARF_32BIT_SIZE,error,section_end); + SIGN_EXTEND(val, DWARF_32BIT_SIZE); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + DWARF_32BIT_SIZE; + } + break; + case DW_EH_PE_sdata8:{ + Dwarf_Unsigned val = 0; + + /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */ + READ_UNALIGNED_CK(dbg, val, + Dwarf_Unsigned, input_field, + DWARF_64BIT_SIZE,error,section_end); + *addr = (Dwarf_Unsigned) val; + *input_field_updated = input_field + DWARF_64BIT_SIZE; + } + break; + default: + _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + + }; + /* The ELF ABI for gnu does not document the meaning of + DW_EH_PE_pcrel, which is awkward. + It apparently means the value + we got above is pc-relative (meaning section-relative), + so we adjust the value. Section_pointer may be null + if it is known DW_EH_PE_pcrel cannot apply, + such as for .debug_frame or for an + address-range value. */ + if (section_pointer && ((gnu_encoding & 0x70) == + DW_EH_PE_pcrel)) { + /* Address (*addr) above is pc relative with respect to a + section. Add to the offset the base address (from elf) of + section and the distance of the field we are reading from + the section-beginning to get the actual address. */ + /* ASSERT: input_field_original >= section_pointer */ + Dwarf_Unsigned distance = + input_field_original - section_pointer; + *addr += dbg->de_debug_frame_eh_gnu.dss_addr + distance; + } + return DW_DLV_OK; +} + +/* All augmentation string checking done here now. + + For .eh_frame, gcc from 3.3 uses the z style, earlier used + only "eh" as augmentation. We don't yet handle + decoding .eh_frame with the z style extensions like L P. + _dwarf_gnu_aug_encodings() does handle L P. + + These are nasty heuristics, but then that's life + as augmentations are implementation specific. */ +/* ARGSUSED */ +enum Dwarf_augmentation_type +_dwarf_get_augmentation_type(Dwarf_Debug dbg, + Dwarf_Small * augmentation_string, + int is_gcc_eh_frame) +{ + enum Dwarf_augmentation_type t = aug_unknown; + char *ag_string = (char *) augmentation_string; + + (void)dbg; + if (!ag_string[0]) { + /* Empty string. We'll just guess that we know + what this means: + standard dwarf2/3 with no + implementation-defined fields. */ + t = aug_empty_string; + } else if (!strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING)) { + /* The string is "mti v1". Used internally at SGI, probably + never shipped. Replaced by "z". Treat like 'nothing + special'. */ + t = aug_irix_mti_v1; + } else if (ag_string[0] == 'z') { + /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2 + were designed as for IRIX CC, but never implemented */ + /* If it's gcc, z may be any of several things. "z" or z + followed optionally followed by one or more of L R P, + each of which means a value may be present. + Should be in eh_frame + only, I think. */ + if (is_gcc_eh_frame) { + t = aug_gcc_eh_z; + } else if (!ag_string[1]) { + /* This is the normal IRIX C++ case, where there is an + offset into a table in each fde. The table being for + IRIX CC exception handling. */ + /* DW_CIE_AUGMENTER_STRING_V0 "z" */ + t = aug_irix_exception_table; + } /* Else unknown. */ + } else if (!strncmp(ag_string, "eh", 2)) { + /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least + for x86. */ + t = aug_eh; + } else if (!strcmp(ag_string, "armcc+")) { + /* Arm uses this string to mean a bug in + in Arm compilers was fixed, changing to the standard + calculation of the CFA. See + http://sourceware.org/ml/gdb-patches/ + 2006-12/msg00249.html + for details. */ + t = aug_armcc; + } else if (!strcmp(ag_string, "HC")) { + t = aug_metaware; + } else { + } + return t; +} + +/* Using augmentation, and version + read in the augmentation data for GNU eh. + + Return DW_DLV_OK if we succeeded, + DW_DLV_ERR if we fail. + + On success, update 'size_of_augmentation_data' with + the length of the fields that are part of augmentation (so the + caller can increment frame_ptr appropriately). + + 'frame_ptr' points within section. + 'section_end' points to end of section area of interest. + +*/ +/* ARGSUSED */ +static int +_dwarf_get_gcc_eh_augmentation(Dwarf_Debug dbg, + Dwarf_Small * frame_ptr, + unsigned long *size_of_augmentation_data, + enum Dwarf_augmentation_type augtype, + Dwarf_Small * section_ptr_end, + char *augmentation, + Dwarf_Error *error) +{ + char *suffix = 0; + Dwarf_Unsigned augdata_size = 0; + + if (augtype == aug_gcc_eh_z) { + /* Has leading 'z'. */ + Dwarf_Unsigned leb128_length = 0; + + /* Dwarf_Unsigned eh_value = */ + SKIP_LEB128_LEN_CK(frame_ptr,leb128_length, + dbg,error,section_ptr_end); + augdata_size += leb128_length; + suffix = augmentation + 1; + } else { + /* Prefix is 'eh'. As in gcc 3.2. No suffix present + apparently. */ + suffix = augmentation + 2; + } + if (*suffix) { + /* We have no idea what this is as yet. + Some extensions beyond + dwarf exist which we do not yet handle. */ + _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); + return DW_DLV_ERROR; + + } + + *size_of_augmentation_data = augdata_size; + return DW_DLV_OK; +} + +/* To properly release all spaced used. + Earlier approaches (before July 15, 2005) + letting client do the dealloc directly left + some data allocated. + This is directly called by consumer code. +*/ +void +dwarf_dealloc_fde_cie_list(Dwarf_Debug dbg, + Dwarf_Cie * cie_data, + Dwarf_Signed cie_element_count, + Dwarf_Fde * fde_data, + Dwarf_Signed fde_element_count) +{ + Dwarf_Signed i = 0; + + for (i = 0; i < cie_element_count; ++i) { + Dwarf_Frame frame = cie_data[i]->ci_initial_table; + + if (frame) { + dwarf_dealloc(dbg, frame, DW_DLA_FRAME); + } + dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE); + } + for (i = 0; i < fde_element_count; ++i) { + dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE); + } + if (cie_data) { + dwarf_dealloc(dbg, cie_data, DW_DLA_LIST); + } + if (fde_data) { + dwarf_dealloc(dbg, fde_data, DW_DLA_LIST); + } +} diff --git a/src/lib/libdwarf/dwarf_gdbindex.c b/src/lib/libdwarf/dwarf_gdbindex.c new file mode 100644 index 0000000..46b0566 --- /dev/null +++ b/src/lib/libdwarf/dwarf_gdbindex.c @@ -0,0 +1,850 @@ +/* + + Copyright (C) 2014-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. +*/ +/* see +https://sourceware.org/gdb/onlinedocs/gdb/\ +Index-Section-Format.html#Index-Section-Format +*/ + +#include + +#include /* memcpy() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_gdbindex.h" + +/* The dwarf_util macro READ_UNALIGNED + cannot be directly used because + gdb defines the section contents of + .gdb_index as little-endian always. +*/ + +#if WORDS_BIGENDIAN /* meaning on this host */ +#define READ_GDBINDEX(dest,desttype, source, length) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + _dwarf_memcpy_swap_bytes((((char *)(&_ltmp)) \ + + sizeof(_ltmp) - (length)), \ + (source), (length)) ; \ + (dest) = (desttype)_ltmp; \ + } while (0) +#else /* little-endian on this host */ +#define READ_GDBINDEX(dest,desttype, source, length) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + memcpy(((char *)(&_ltmp)) , \ + (source), (length)) ; \ + (dest) = (desttype)_ltmp; \ + } while (0) +#endif + +struct dwarf_64bitpair { + gdbindex_64 offset; + gdbindex_64 length; +}; + +static void +emit_no_value_msg(Dwarf_Debug dbg, + int errnum, + const char * errstr_text, + Dwarf_Error *error) +{ + _dwarf_error_string(dbg,error,errnum, + (char *)errstr_text); +} + +static void +emit_one_value_msg(Dwarf_Debug dbg, + int errnum, + const char * errstr_text, + Dwarf_Unsigned value, + Dwarf_Error *error) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + (char *)errstr_text,value); + _dwarf_error_string(dbg,error,errnum, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +static int +set_base(Dwarf_Debug dbg, + struct Dwarf_Gdbindex_array_instance_s * hdr, + Dwarf_Small *start, + Dwarf_Small *end, + /* entrylen is the length of a single struct as seen + in the object. */ + Dwarf_Unsigned entrylen, + /* The size of each field in the struct in the object. */ + Dwarf_Unsigned fieldlen, + enum gdbindex_type_e type, + Dwarf_Error * error) +{ + + if (type == git_std || type == git_cuvec) { + /* cuvec is sort of a fake as a simple + section, but a useful one. */ + Dwarf_Unsigned count = 0; + if ( end < start) { + _dwarf_error(dbg, error,DW_DLE_GDB_INDEX_COUNT_ERROR); + return DW_DLV_ERROR; + } + count = end - start; + count = count / entrylen; + hdr->dg_type = type; + hdr->dg_base = start; + hdr->dg_count = count; + hdr->dg_entry_length = entrylen; + hdr->dg_fieldlen = (unsigned)fieldlen; + } else { + /* address area. */ + /* 64bit, 64bit, offset. Then 32bit pad. */ + Dwarf_Unsigned count = 0; + hdr->dg_base = start; + if ( end < start) { + _dwarf_error(dbg, error, + DW_DLE_GDB_INDEX_COUNT_ADDR_ERROR); + return DW_DLV_ERROR; + } + /* entry length includes pad. */ + hdr->dg_entry_length = 2*sizeof(gdbindex_64) + + DWARF_32BIT_SIZE; + count = end - start; + count = count / hdr->dg_entry_length; + hdr->dg_count = count; + /* The dg_fieldlen is a fake, the fields are not + all the same length. */ + hdr->dg_fieldlen = DWARF_32BIT_SIZE; + hdr->dg_type = type; + } + return DW_DLV_OK; +} + +int +dwarf_gdbindex_header(Dwarf_Debug dbg, + Dwarf_Gdbindex * gdbindexptr, + Dwarf_Unsigned * version, + Dwarf_Unsigned * cu_list_offset, + Dwarf_Unsigned * types_cu_list_offset, + Dwarf_Unsigned * address_area_offset, + Dwarf_Unsigned * symbol_table_offset, + Dwarf_Unsigned * constant_pool_offset, + Dwarf_Unsigned * section_size, + const char ** section_name, + Dwarf_Error * error) +{ + Dwarf_Gdbindex indexptr = 0; + int res = DW_DLV_ERROR; + Dwarf_Small *data = 0; + Dwarf_Small *startdata = 0; + Dwarf_Unsigned version_in = 0; + + if (!dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL Dwarf_Debut to" + " dwarf_gdbindex_header"); + return DW_DLV_ERROR; + } + if (!dbg->de_debug_gdbindex.dss_size) { + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_debug_gdbindex.dss_data) { + res = _dwarf_load_section(dbg, &dbg->de_debug_gdbindex,error); + if (res != DW_DLV_OK) { + return res; + } + } + data = dbg->de_debug_gdbindex.dss_data; + startdata = data; + + if (dbg->de_debug_gdbindex.dss_size < (DWARF_32BIT_SIZE*6)) { + _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION); + return DW_DLV_ERROR; + } + indexptr = (Dwarf_Gdbindex)_dwarf_get_alloc(dbg, + DW_DLA_GDBINDEX,1); + if (indexptr == NULL) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating Dwarf_Gdbindex"); + return DW_DLV_ERROR; + } + READ_GDBINDEX(version_in,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + indexptr->gi_version = version_in; + + indexptr->gi_dbg = dbg; + indexptr->gi_section_data = startdata; + indexptr->gi_section_length = dbg->de_debug_gdbindex.dss_size; + /* 7 and lower are different format in some way */ + if (indexptr->gi_version != 8 && + indexptr->gi_version != 7) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION: " + " version number %u is not" + " supported", + indexptr->gi_version,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + READ_GDBINDEX(indexptr->gi_cu_list_offset ,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + if (indexptr->gi_cu_list_offset > indexptr->gi_section_length) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION" + " cu list offset of %u is too large for the section", + indexptr->gi_cu_list_offset,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + READ_GDBINDEX(indexptr->gi_types_cu_list_offset ,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + if (indexptr->gi_types_cu_list_offset > + indexptr->gi_section_length) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION" + " types cu list offset of %u is too " + "large for the section", + indexptr->gi_cu_list_offset,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + READ_GDBINDEX(indexptr->gi_address_area_offset ,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + if (indexptr->gi_address_area_offset > + indexptr->gi_section_length) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION" + " address area offset of %u is too " + "large for the section", + indexptr->gi_address_area_offset ,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + READ_GDBINDEX(indexptr->gi_symbol_table_offset ,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + if (indexptr->gi_symbol_table_offset > + indexptr->gi_section_length) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION" + " symbol table offset of %u is too " + "large for the section", + indexptr->gi_symbol_table_offset,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + READ_GDBINDEX(indexptr->gi_constant_pool_offset ,Dwarf_Unsigned, + data, DWARF_32BIT_SIZE); + if (indexptr->gi_constant_pool_offset > + indexptr->gi_section_length) { + emit_one_value_msg(dbg, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION, + "DW_DLE_ERRONEOUS_GDB_INDEX_SECTION" + " constant pool offset of %u is too " + "large for the section", + indexptr->gi_constant_pool_offset,error); + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return DW_DLV_ERROR; + } + data += DWARF_32BIT_SIZE; + + res = set_base(dbg,&indexptr->gi_culisthdr, + startdata + indexptr->gi_cu_list_offset, + startdata + indexptr->gi_types_cu_list_offset, + 2*sizeof(gdbindex_64), + sizeof(gdbindex_64), + git_std,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return res; + } + res = set_base(dbg,&indexptr->gi_typesculisthdr, + startdata+ indexptr->gi_types_cu_list_offset, + startdata+ indexptr->gi_address_area_offset, + 3*sizeof(gdbindex_64), + sizeof(gdbindex_64), + git_std,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return res; + } + res = set_base(dbg,&indexptr->gi_addressareahdr, + startdata + indexptr->gi_address_area_offset, + startdata + indexptr->gi_symbol_table_offset, + 3*sizeof(gdbindex_64), + sizeof(gdbindex_64), + git_address,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return res; + } + res = set_base(dbg,&indexptr->gi_symboltablehdr, + startdata + indexptr->gi_symbol_table_offset, + startdata + indexptr->gi_constant_pool_offset, + 2*DWARF_32BIT_SIZE, + DWARF_32BIT_SIZE, + git_std,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return res; + } + res = set_base(dbg,&indexptr->gi_cuvectorhdr, + startdata + indexptr->gi_constant_pool_offset, + /* There is no real single vector size. + but we'll use the entire rest as if there was. */ + startdata + indexptr->gi_section_length, + DWARF_32BIT_SIZE, + DWARF_32BIT_SIZE, + git_cuvec,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + return res; + } + *gdbindexptr = indexptr; + *version = indexptr->gi_version; + *cu_list_offset = indexptr->gi_cu_list_offset; + *types_cu_list_offset = indexptr->gi_types_cu_list_offset; + *address_area_offset = indexptr->gi_address_area_offset; + *symbol_table_offset = indexptr->gi_symbol_table_offset; + *constant_pool_offset = indexptr->gi_constant_pool_offset; + *section_size = indexptr->gi_section_length; + *section_name = dbg->de_debug_gdbindex.dss_name; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_culist_array(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned * list_length, + Dwarf_Error * error) +{ + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_culist_array"); + return DW_DLV_ERROR; + } + (void)error; + *list_length = gdbindexptr->gi_culisthdr.dg_count; + return DW_DLV_OK; +} + +/* entryindex: 0 to list_length-1 */ +int +dwarf_gdbindex_culist_entry(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned entryindex, + Dwarf_Unsigned * cu_offset, + Dwarf_Unsigned * cu_length, + Dwarf_Error * error) +{ + Dwarf_Small * base = 0; + Dwarf_Small * endptr = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned max = 0; + unsigned fieldlen = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_culist_entry"); + return DW_DLV_ERROR; + } + max = gdbindexptr->gi_culisthdr.dg_count; + fieldlen = gdbindexptr->gi_culisthdr.dg_fieldlen; + if (entryindex >= max) { + return DW_DLV_NO_ENTRY; + } + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + + base = gdbindexptr->gi_culisthdr.dg_base; + base += entryindex*gdbindexptr->gi_culisthdr.dg_entry_length; + if ((base + 2*fieldlen) >endptr) { + Dwarf_Debug dbg = 0; + + dbg = gdbindexptr->gi_dbg; + emit_one_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of data for index %u is past the" + " end of the section", + entryindex,error); + return DW_DLV_ERROR; + } + + READ_GDBINDEX(offset ,Dwarf_Unsigned, + base, + fieldlen); + READ_GDBINDEX(length ,Dwarf_Unsigned, + base+ fieldlen, + fieldlen); + *cu_offset = offset; + *cu_length = length; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_types_culist_array(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned * list_length, + Dwarf_Error * error) +{ + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_types_culist_entry"); + return DW_DLV_ERROR; + } + + (void)error; + *list_length = gdbindexptr->gi_typesculisthdr.dg_count; + return DW_DLV_OK; +} + +/* entryindex: 0 to list_length-1 */ +int +dwarf_gdbindex_types_culist_entry(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned entryindex, + Dwarf_Unsigned * t_offset, + Dwarf_Unsigned * t_length, + Dwarf_Unsigned * t_signature, + Dwarf_Error * error) +{ + Dwarf_Unsigned max = 0; + Dwarf_Small * base = 0; + Dwarf_Small * endptr = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned signature = 0; + unsigned fieldlen = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_types_culist_entry"); + return DW_DLV_ERROR; + } + fieldlen = gdbindexptr->gi_typesculisthdr.dg_fieldlen; + max = gdbindexptr->gi_typesculisthdr.dg_count; + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + + if (entryindex >= max) { + return DW_DLV_NO_ENTRY; + } + base = gdbindexptr->gi_typesculisthdr.dg_base; + base += entryindex*gdbindexptr->gi_typesculisthdr.dg_entry_length; + if ((base + 3*fieldlen) >endptr) { + Dwarf_Debug dbg = gdbindexptr->gi_dbg; + emit_one_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of data for type index %u is past the" + " end of the section", + entryindex,error); + return DW_DLV_ERROR; + } + READ_GDBINDEX(offset ,Dwarf_Unsigned, + base, + fieldlen); + READ_GDBINDEX(length ,Dwarf_Unsigned, + base+ (1*fieldlen), + fieldlen); + READ_GDBINDEX(signature ,Dwarf_Unsigned, + base+ (2*fieldlen), + fieldlen); + *t_offset = offset; + *t_length = length; + *t_signature = signature; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_addressarea(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned * list_length, + Dwarf_Error * error) +{ + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_addressarea"); + return DW_DLV_ERROR; + } + (void)error; + *list_length = gdbindexptr->gi_addressareahdr.dg_count; + return DW_DLV_OK; +} + +/* entryindex: 0 to addressarea_list_length-1 */ +int +dwarf_gdbindex_addressarea_entry( + Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned entryindex, + Dwarf_Unsigned * low_address, + Dwarf_Unsigned * high_address, + Dwarf_Unsigned * cu_index, + Dwarf_Error * error) +{ + Dwarf_Unsigned max = 0; + Dwarf_Small * base = 0; + Dwarf_Small * endptr = 0; + Dwarf_Unsigned lowaddr = 0; + Dwarf_Unsigned highaddr = 0; + Dwarf_Unsigned cuindex = 0; + Dwarf_Unsigned fieldslen = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_addressarea_entry"); + return DW_DLV_ERROR; + } + max = gdbindexptr->gi_addressareahdr.dg_count; + if (entryindex >= max) { + _dwarf_error(gdbindexptr->gi_dbg, error, + DW_DLE_GDB_INDEX_INDEX_ERROR); + return DW_DLV_ERROR; + } + base = gdbindexptr->gi_addressareahdr.dg_base; + base += entryindex*gdbindexptr->gi_addressareahdr.dg_entry_length; + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + fieldslen = 2*sizeof(gdbindex_64) + DWARF_32BIT_SIZE; + if ((base + fieldslen) > endptr) { + Dwarf_Debug dbg = gdbindexptr->gi_dbg; + emit_one_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of data for " + " dwarf_gdbindex_addressarea_entry %u is past the" + " end of the section", + entryindex,error); + return DW_DLV_ERROR; + } + + READ_GDBINDEX(lowaddr ,Dwarf_Unsigned, + base, + sizeof(gdbindex_64)); + READ_GDBINDEX(highaddr ,Dwarf_Unsigned, + base+ (1*sizeof(gdbindex_64)), + sizeof(gdbindex_64)); + READ_GDBINDEX(cuindex ,Dwarf_Unsigned, + base+ (2*sizeof(gdbindex_64)), + DWARF_32BIT_SIZE); + *low_address = lowaddr; + *high_address = highaddr; + *cu_index = cuindex; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_symboltable_array(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned * list_length, + Dwarf_Error * error) +{ + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_symboltable_array"); + return DW_DLV_ERROR; + } + (void)error; + *list_length = gdbindexptr->gi_symboltablehdr.dg_count; + return DW_DLV_OK; +} + +/* entryindex: 0 to symtab_list_length-1 */ +int +dwarf_gdbindex_symboltable_entry( + Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned entryindex, + Dwarf_Unsigned * string_offset, + Dwarf_Unsigned * cu_vector_offset, + Dwarf_Error * error) +{ + Dwarf_Unsigned max = 0; + Dwarf_Small * base = 0; + Dwarf_Small * endptr = 0; + Dwarf_Unsigned symoffset = 0; + Dwarf_Unsigned cuoffset = 0; + unsigned fieldlen = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL inindexptr to" + " dwarf_gdbindex_symboltable_entry"); + return DW_DLV_ERROR; + } + max = gdbindexptr->gi_symboltablehdr.dg_count; + fieldlen = gdbindexptr->gi_symboltablehdr.dg_fieldlen; + if (entryindex >= max) { + return DW_DLV_NO_ENTRY; + } + base = gdbindexptr->gi_symboltablehdr.dg_base; + base += entryindex*gdbindexptr->gi_symboltablehdr.dg_entry_length; + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + + if (( base + 2*fieldlen) >endptr) { + Dwarf_Debug dbg = gdbindexptr->gi_dbg; + emit_one_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of data for symboltable entry " + "%u is past the" + " end of the section", + entryindex,error); + return DW_DLV_ERROR; + } + READ_GDBINDEX(symoffset ,Dwarf_Unsigned, + base, + fieldlen); + READ_GDBINDEX(cuoffset ,Dwarf_Unsigned, + base + fieldlen, + fieldlen); + *string_offset = symoffset; + *cu_vector_offset = cuoffset; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_cuvector_length(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned cuvector_offset, + Dwarf_Unsigned * innercount, + Dwarf_Error * error) +{ + Dwarf_Small *base = 0; + Dwarf_Small *endptr = 0; + Dwarf_Unsigned fieldlen = 0; + Dwarf_Unsigned val = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL indexptr to" + " dwarf_gdbindex_cuvector_length"); + return DW_DLV_ERROR; + } + + base = gdbindexptr->gi_cuvectorhdr.dg_base; + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + fieldlen = gdbindexptr->gi_cuvectorhdr.dg_entry_length; + base += cuvector_offset; + if (( base + fieldlen) >endptr) { + Dwarf_Debug dbg = gdbindexptr->gi_dbg; + emit_no_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of count of gdbindex cuvector " + " is past the" + " end of the section", + error); + return DW_DLV_ERROR; + } + READ_GDBINDEX(val,Dwarf_Unsigned, + base, + fieldlen); + *innercount = val; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_cuvector_inner_attributes(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned cuvector_offset, + Dwarf_Unsigned innerindex, + /* The attr_value is a field of bits. For expanded version + use dwarf_gdbindex_instance_expand_value() */ + Dwarf_Unsigned * attributes, + Dwarf_Error * error) +{ + Dwarf_Small *base = 0; + Dwarf_Small *endptr = 0; + Dwarf_Unsigned fieldlen = 0; + Dwarf_Unsigned val = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, + DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " passed in NULL indexptr to" + " dwarf_gdbindex_cuvector_length"); + return DW_DLV_ERROR; + } + base = gdbindexptr->gi_cuvectorhdr.dg_base; + base += cuvector_offset; + endptr = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + fieldlen = gdbindexptr->gi_cuvectorhdr.dg_entry_length; + /* The initial 4 bytes is not part of the array, + it is some sort of count. Get past it.*/ + base += fieldlen; + base += fieldlen*innerindex; + if ((base+fieldlen) >= endptr) { + Dwarf_Debug dbg = gdbindexptr->gi_dbg; + emit_one_value_msg(dbg, DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR:" + " end offset of data for cuvector_inner_attribute " + "%u is past the" + " end of the section", + innerindex,error); + return DW_DLV_ERROR; + } + + READ_GDBINDEX(val ,Dwarf_Unsigned, + base, + fieldlen); + *attributes = val; + return DW_DLV_OK; +} + +int +dwarf_gdbindex_cuvector_instance_expand_value( + Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned value, + Dwarf_Unsigned * cu_index, + Dwarf_Unsigned * symbol_kind, + Dwarf_Unsigned * is_static, + Dwarf_Error * error) +{ + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: The call to " + "dwarf_gdbindex_cuvector_instance_expand_value" + " provides no dbg pointer"); + return DW_DLV_ERROR; + } + *cu_index = value & 0xffffff; + *symbol_kind = (value >> 28) & 0x7; + *is_static = (value >> 31) & 1; + return DW_DLV_OK; + +} + +/* The strings in the pool follow (in memory) the cu index + set and are NUL terminated. */ +int +dwarf_gdbindex_string_by_offset(Dwarf_Gdbindex gdbindexptr, + Dwarf_Unsigned stringoffsetinpool, + const char ** string_ptr, + Dwarf_Error * error) +{ + Dwarf_Small *pooldata = 0; + Dwarf_Small *section_end = 0; + Dwarf_Small *stringitself = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned fulloffset = 0; + int res = 0; + + if (!gdbindexptr || !gdbindexptr->gi_dbg) { + emit_no_value_msg(NULL,DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR: " + "The gdbindex pointer to " + "dwarf_gdbindex_string_by_offset()" + " is NULL",error); + return DW_DLV_ERROR; + } + dbg = gdbindexptr->gi_dbg; + if (!dbg) { + emit_no_value_msg(NULL,DW_DLE_GDB_INDEX_INDEX_ERROR, + "DW_DLE_GDB_INDEX_INDEX_ERROR: " + "The gdbindex Dwarf_Debug in" + "dwarf_gdbindex_string_by_offset()" + " is NULL",error); + return DW_DLV_ERROR; + } + section_end = gdbindexptr->gi_section_data + + gdbindexptr->gi_section_length; + fulloffset = gdbindexptr->gi_constant_pool_offset + + stringoffsetinpool; + stringitself = gdbindexptr->gi_section_data + fulloffset; + if (stringitself > section_end) { + emit_one_value_msg(dbg,DW_DLE_GDBINDEX_STRING_ERROR, + "DW_DLE_GDBINDEX_STRING_ERROR: " + "The dwarf_gdbindex_string_by_offset() " + "string starts past the end of the " + "section at section_offset 0x%" + DW_PR_XZEROS DW_PR_DUx ".", + fulloffset, + error); + return DW_DLV_ERROR; + } + res = _dwarf_check_string_valid(dbg,pooldata, + stringitself, section_end, + DW_DLE_GDBINDEX_STRING_ERROR, + error); + if (res != DW_DLV_OK) { + return res; + } + *string_ptr = (const char *)stringitself; + return DW_DLV_OK; +} + +void +dwarf_dealloc_gdbindex(Dwarf_Gdbindex indexptr) +{ + if (indexptr) { + Dwarf_Debug dbg = indexptr->gi_dbg; + dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX); + } +} diff --git a/src/lib/libdwarf/dwarf_gdbindex.h b/src/lib/libdwarf/dwarf_gdbindex.h new file mode 100644 index 0000000..74ef5f3 --- /dev/null +++ b/src/lib/libdwarf/dwarf_gdbindex.h @@ -0,0 +1,84 @@ +/* + + Copyright (C) 2014-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* The following is based on + The gdb online documentation at + https://sourceware.org/gdb/onlinedocs/gdb/ + Appendix J, ".gdb_index section format". +*/ + +/* These are the two types .gdb_index uses. + the offset_type (32 bits) and other fields + defined 64 bits. We use our own Dwarf_Unsigned + for all the interfaces, these are just for reading + the section data. + + The section data is defined to be in little-endian regardless of + the target machine. + We use our host endianness in all interfaces. + + We simply assume unsigned int is 32 bits FIXME. +*/ + +typedef Dwarf_Unsigned gdbindex_64; +enum gdbindex_type_e { + git_unknown, + git_std, + git_address, + git_cuvec +}; + +struct Dwarf_Gdbindex_array_instance_s { + Dwarf_Small * dg_base; + Dwarf_Unsigned dg_count; + /* the in_object struct size. */ + Dwarf_Unsigned dg_entry_length; + /* The size of a single field in the in-object struct */ + unsigned dg_fieldlen; + /* The address_area type is a bit irregular. */ + enum gdbindex_type_e dg_type; +}; + +struct Dwarf_Gdbindex_s { + Dwarf_Debug gi_dbg; + Dwarf_Small * gi_section_data; /* dss_data */ + Dwarf_Unsigned gi_section_length; /* dss_size */ + + Dwarf_Unsigned gi_version; + Dwarf_Unsigned gi_cu_list_offset; + Dwarf_Unsigned gi_types_cu_list_offset; + Dwarf_Unsigned gi_address_area_offset; + Dwarf_Unsigned gi_symbol_table_offset; + Dwarf_Unsigned gi_constant_pool_offset; + struct Dwarf_Gdbindex_array_instance_s gi_culisthdr; + struct Dwarf_Gdbindex_array_instance_s gi_typesculisthdr; + struct Dwarf_Gdbindex_array_instance_s gi_addressareahdr; + struct Dwarf_Gdbindex_array_instance_s gi_symboltablehdr; + struct Dwarf_Gdbindex_array_instance_s gi_cuvectorhdr; +}; diff --git a/src/lib/libdwarf/dwarf_generic_init.c b/src/lib/libdwarf/dwarf_generic_init.c new file mode 100644 index 0000000..1a24aef --- /dev/null +++ b/src/lib/libdwarf/dwarf_generic_init.c @@ -0,0 +1,557 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + Portions Copyright 2011-2020 David Anderson. All rights reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ +/* +Here is the deepest routes through dwarf_init_path_dl(), +depending on arguments. +It is called by dwarfdump to open an fd and return Dwarf_Debug. +Much of this is to handle GNU debuglink. +dwarf_init_path_dl(path true_path and globals, dbg1 + dwarf_object_detector_path_dSYM (dsym only( + if returns DW_DLV_OK itis dSYM + dwarf_object_detector_path_b( &debuglink with global paths. + dwarf_object_detector_path_b ftype + check for dSYM if found it is the object to run on. + dwarf_object_detector_fd (gets size ftype) + return + _dwarf_debuglink_finder_internal(TRUE passing + in globals paths listr) + new local dbg + dwarf_init_path(path no dysm or debuglink + no global paths) + dwarf_object_detector_path_b( path no dsym + or debuglink no global paths + dwarf_object_detector (path + dwarf_object_detector_fd (gets size ftype) + for each global pathin list, add to dbg + dwarf_gnu_debuglink(dbg + for each global path in debuglink list + _dwarf_debuglink_finder_internal(FALSE + no global paths) + if crc match return OK with + pathname and fd returned + else return NO_ENTRY +*/ + +#include + +#include /* size_t */ +#include /* free() */ +#include /* strdup() */ +#include /* debugging */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* close() open() */ +#elif defined HAVE_UNISTD_H +#include /* close() */ +#endif /* _WIN32 */ + +#ifdef HAVE_FCNTL_H +#include /* open() O_RDONLY */ +#endif /* HAVE_FCNTL_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_object_detector.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif /* O_CLOEXEC */ + +/* This is the initialization set intended to + handle multiple object formats. + Created September 2018 + + The init functions here cannot process archives. + Archives cannot be read by libdwarf. +*/ +static int +open_a_file(const char * name) +{ + /* Set to a file number that cannot be legal. */ + int fd = -1; + + fd = open(name, O_RDONLY | O_BINARY|O_CLOEXEC); + return fd; +} + +static int +set_global_paths_init(Dwarf_Debug dbg, Dwarf_Error* error) +{ + int res = 0; + + res = dwarf_add_debuglink_global_path(dbg, + "/usr/lib/debug",error); + return res; +} + +/* New in September 2023. */ +int dwarf_init_path_a(const char *path, + char * true_path_out_buffer, + unsigned true_path_bufferlen, + unsigned groupnumber, + unsigned universalnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + Dwarf_Error * error) +{ + return dwarf_init_path_dl_a(path, + true_path_out_buffer,true_path_bufferlen, + groupnumber,universalnumber, + errhand,errarg,ret_dbg, + 0,0,0, + error); +} + +int dwarf_init_path(const char *path, + char * true_path_out_buffer, + unsigned true_path_bufferlen, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + Dwarf_Error * error) +{ + unsigned int universalnumber = 0; + return dwarf_init_path_dl_a(path, + true_path_out_buffer,true_path_bufferlen, + groupnumber,universalnumber, + errhand,errarg,ret_dbg, + 0,0,0, + error); +} + +static void +final_common_settings(Dwarf_Debug dbg, + const char *file_path, + int fd, + unsigned char lpath_source, + unsigned char *path_source, + Dwarf_Error *error) +{ + int res = 0; + + dbg->de_path = strdup(file_path); + dbg->de_fd = fd; + dbg->de_owns_fd = TRUE; + dbg->de_path_source = lpath_source; + if (path_source) { + *path_source = lpath_source; + } + dbg->de_owns_fd = TRUE; + res = set_global_paths_init(dbg,error); + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + return; +} +/* New October 2020 + Given true_path_out_buffer (and true_path_bufferlen) + non-zero this finds a dSYM (if such exists) with the + file name in true_path_out_buffer + + If not a dSYM it follows debuglink rules to try to find a file + that matches requirements. If found returns DW_DLV_OK and + copies the name to true_path_out_buffer; + If none of the above found, it copies path into true_path + and returns DW_DLV_OK, we know the name is good; + + The pathn_fd is owned by libdwarf and is in the created dbg->de_fd + field. +*/ +int +dwarf_init_path_dl(const char *path, + char * true_path_out_buffer, + unsigned true_path_bufferlen, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + char ** dl_path_array, + unsigned int dl_path_count, + unsigned char * path_source, + Dwarf_Error * error) +{ + unsigned int universalnumber = 0; + int res = 0; + + res = dwarf_init_path_dl_a(path, + true_path_out_buffer, true_path_bufferlen, + groupnumber,universalnumber, + errhand,errarg,ret_dbg, dl_path_array, + dl_path_count,path_source,error); + return res; +} +int +dwarf_init_path_dl_a(const char *path, + char * true_path_out_buffer, + unsigned true_path_bufferlen, + unsigned groupnumber, + unsigned universalnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + char ** dl_path_array, + unsigned int dl_path_count, + unsigned char * path_source, + Dwarf_Error * error) +{ + unsigned ftype = 0; + unsigned endian = 0; + unsigned offsetsize = 0; + Dwarf_Unsigned filesize = 0; + int res = DW_DLV_ERROR; + int errcode = 0; + int fd = -1; + Dwarf_Debug dbg = 0; + char *file_path = 0; + unsigned char lpath_source = DW_PATHSOURCE_basic; + + if (!ret_dbg) { + DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL, + DW_DLV_ERROR); + } + /* Non-null *ret_dbg will cause problems dealing with + DW_DLV_ERROR */ + *ret_dbg = 0; + if (!path) { + /* Oops. Null path */ + _dwarf_error_string(NULL, + error,DW_DLE_STRING_PTR_NULL, + "DW_DLE_STRING_PTR_NULL: Passing a" + " null path argument to " + "dwarf_init_path or dwarf_init_path_dl" + " cannot work. Error."); + return DW_DLV_ERROR; + } + /* a special dsym call so we only check once. */ + if (true_path_out_buffer) { + res = dwarf_object_detector_path_dSYM(path, + true_path_out_buffer, + true_path_bufferlen, + dl_path_array,dl_path_count, + &ftype,&endian,&offsetsize,&filesize, + &lpath_source, + &errcode); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR) { + /* ignore error. Look further. */ + errcode = 0; + } + } + } + if (res != DW_DLV_OK) { + res = dwarf_object_detector_path_b(path, + true_path_out_buffer, + true_path_bufferlen, + dl_path_array,dl_path_count, + &ftype,&endian,&offsetsize,&filesize, + &lpath_source, + &errcode); + if (res != DW_DLV_OK ) { + if (res == DW_DLV_ERROR) { + errcode = 0; + } + } + } + if (res != DW_DLV_OK) { + /* So as a last resort in case + of data corruption in the object. + Lets try without + investigating debuglink or dSYM. */ + res = dwarf_object_detector_path_b(path, + 0, + 0, + dl_path_array,dl_path_count, + &ftype,&endian,&offsetsize,&filesize, + &lpath_source, + &errcode); + } + if (res != DW_DLV_OK) { + /* impossible. The last above *had* to work */ + if (res == DW_DLV_ERROR) { + _dwarf_error(NULL, error, errcode); + } + return res; + } + /* ASSERT: lpath_source != DW_PATHSOURCE_unspecified */ + if (lpath_source != DW_PATHSOURCE_basic && + true_path_out_buffer && *true_path_out_buffer) { + /* MacOS dSYM or GNU debuglink */ + file_path = true_path_out_buffer; + fd = open_a_file(true_path_out_buffer); + } else { + /* ASSERT: lpath_source = DW_PATHSOURCE_basic */ + file_path = (char *)path; + fd = open_a_file(path); + } + + if (fd == -1) { + DWARF_DBG_ERROR(NULL, DW_DLE_FILE_UNAVAILABLE, + DW_DLV_ERROR); + } + switch(ftype) { + case DW_FTYPE_ELF: { + res = _dwarf_elf_nlsetup(fd, + file_path, + ftype,endian,offsetsize,filesize, + groupnumber,errhand,errarg,&dbg,error); + if (res != DW_DLV_OK) { + close(fd); + return res; + } + final_common_settings(dbg,file_path,fd, + lpath_source,path_source,error); + *ret_dbg = dbg; + return res; + } + case DW_FTYPE_APPLEUNIVERSAL: + case DW_FTYPE_MACH_O: { + res = _dwarf_macho_setup(fd, + file_path, + universalnumber, + ftype,endian,offsetsize,filesize, + groupnumber,errhand,errarg,&dbg,error); + if (res != DW_DLV_OK) { + close(fd); + return res; + } + final_common_settings(dbg,file_path,fd, + lpath_source,path_source,error); + *ret_dbg = dbg; + return res; + } + case DW_FTYPE_PE: { + res = _dwarf_pe_setup(fd, + file_path, + ftype,endian,offsetsize,filesize, + groupnumber,errhand,errarg,&dbg,error); + if (res != DW_DLV_OK) { + close(fd); + return res; + } + final_common_settings(dbg,file_path,fd, + lpath_source,path_source,error); + *ret_dbg = dbg; + return res; + } + default: + close(fd); + DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, + DW_DLV_ERROR); + /* Macro returns, cannot reach this line. */ + } + /* Cannot reach this line */ +} + +/* New March 2017, this provides for reading + object files with multiple elf section groups. + If you are unsure about group_number, use + DW_GROUPNUMBER_ANY as groupnumber. +*/ +int +dwarf_init_b(int fd, + unsigned group_number, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug * ret_dbg, + Dwarf_Error * error) +{ + unsigned ftype = 0; + unsigned endian = 0; + unsigned offsetsize = 0; + unsigned universalnumber = 0; + Dwarf_Unsigned filesize = 0; + int res = 0; + int errcode = 0; + + if (!ret_dbg) { + DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL,DW_DLV_ERROR); + } + /* Non-null *ret_dbg will cause problems dealing with + DW_DLV_ERROR */ + *ret_dbg = 0; + res = dwarf_object_detector_fd(fd, &ftype, + &endian,&offsetsize,&filesize,&errcode); + if (res == DW_DLV_NO_ENTRY) { + return res; + } + if (res == DW_DLV_ERROR) { + /* This macro does a return. */ + DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR); + } + switch(ftype) { + case DW_FTYPE_ELF: { + int res2 = 0; + + res2 = _dwarf_elf_nlsetup(fd,"", + ftype,endian,offsetsize,filesize, + group_number,errhand,errarg,ret_dbg,error); + if (res2 != DW_DLV_OK) { + return res2; + } + set_global_paths_init(*ret_dbg,error); + return res2; + } + case DW_FTYPE_APPLEUNIVERSAL: + case DW_FTYPE_MACH_O: { + int resm = 0; + + resm = _dwarf_macho_setup(fd,"", + universalnumber, + ftype,endian,offsetsize,filesize, + group_number,errhand,errarg,ret_dbg,error); + if (resm != DW_DLV_OK) { + return resm; + } + set_global_paths_init(*ret_dbg,error); + return resm; + } + + case DW_FTYPE_PE: { + int resp = 0; + + resp = _dwarf_pe_setup(fd, + "", + ftype,endian,offsetsize,filesize, + group_number,errhand,errarg,ret_dbg,error); + if (resp != DW_DLV_OK) { + return resp; + } + set_global_paths_init(*ret_dbg,error); + return resp; + } + default: break; + } + DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR); + /* Macro above returns. cannot reach here. */ +} + +/* + Frees all memory that was not previously freed + by dwarf_dealloc. + Aside from certain categories. + + Applicable when dwarf_init() or dwarf_elf_init() + or the -b() form was used to init 'dbg'. +*/ +int +dwarf_finish(Dwarf_Debug dbg) +{ + if (!dbg) { + _dwarf_free_static_errlist(); + return DW_DLV_OK; + } + if (dbg->de_obj_file) { + /* The initial character of a valid + dbg->de_obj_file->object struct is a letter: + E, F, M, or P */ + char otype = *(char *)(dbg->de_obj_file->ai_object); + + switch(otype) { + case 'E': + break; + case 'F': + /* Non-libelf elf access */ + _dwarf_destruct_elf_nlaccess(dbg->de_obj_file); + break; + case 'M': + _dwarf_destruct_macho_access(dbg->de_obj_file); + break; + case 'P': + _dwarf_destruct_pe_access(dbg->de_obj_file); + break; + default: + /* Do nothing. A serious internal error */ + break; + } + } + if (dbg->de_owns_fd) { + close(dbg->de_fd); + dbg->de_owns_fd = FALSE; + } + free((void *)dbg->de_path); + dbg->de_path = 0; + /* dwarf_object_finish() also frees de_path, + but that is safe because we set it to zero + here so no duplicate free will occur. + It never returns DW_DLV_ERROR. + Not all code uses libdwarf exactly as we do + hence the free() there. */ + return dwarf_object_finish(dbg); +} + +/* + tieddbg should be the executable or .o + that has the .debug_addr section that + the base dbg refers to. See Split Objects in DWARF5. + + Allows setting to NULL (NULL is the default + of de_tied_data.td_tied_object). + New September 2015. +*/ +int +dwarf_set_tied_dbg(Dwarf_Debug dbg, + Dwarf_Debug tieddbg, + Dwarf_Error*error) +{ + if (!dbg) { + DWARF_DBG_ERROR(NULL, DW_DLE_DBG_NULL, DW_DLV_ERROR); + } + dbg->de_tied_data.td_tied_object = tieddbg; + if (tieddbg) { + tieddbg->de_tied_data.td_is_tied_object = TRUE; + } + return DW_DLV_OK; +} + +/* New September 2015. */ +int +dwarf_get_tied_dbg(Dwarf_Debug dbg, Dwarf_Debug *tieddbg_out, + Dwarf_Error*error) +{ + (void)error; + *tieddbg_out = dbg->de_tied_data.td_tied_object; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_global.c b/src/lib/libdwarf/dwarf_global.c new file mode 100644 index 0000000..1c1c66f --- /dev/null +++ b/src/lib/libdwarf/dwarf_global.c @@ -0,0 +1,1674 @@ +/* + + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include +#include + +#include /* strlen() */ +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_global.h" + +#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */ +/* The 'fixup' here intended for IRIX targets only. + With a 2+GB Elf64 IRIX executable (under 4GB in size), + some DIE offsets wrongly + got the 32bit upper bit sign extended. For the cu-header + offset in the .debug_pubnames section and in the + .debug_aranges section. + the 'varp' here is a pointer to an offset into .debug_info. + We fix up the offset here if it seems advisable.. + + As of June 2005 we have identified a series of mistakes + in ldx64 that can cause this (64 bit values getting passed + thru 32-bit signed knothole). +*/ +void +_dwarf_fix_up_offset_irix(Dwarf_Debug dbg, + Dwarf_Unsigned * varp, char *caller_site_name) +{ + + Dwarf_Unsigned var = *varp; + +#define UPPER33 0xffffffff80000000LL +#define LOWER32 0xffffffffLL + /* Restrict the hack to the known case. Upper 32 bits erroneously + sign extended from lower 32 upper bit. */ + if ((var & UPPER33) == UPPER33) { + var &= LOWER32; + /* Apply the fix. Dreadful hack. */ + *varp = var; + } +#undef UPPER33 +#undef LOWER32 + return; +} +#endif /* __sgi */ + +#if 0 +/* Debugging only. Requires start. can calulate one of len, end */ +static void +debug_print_range(const char *msg, + int lineno, + void *start, signed long len, + void *end) +{ + + char *st = (char *)start; + char *en = (char *)end; + signed long le = len; + + if (len) { + if (en) { + le = (long)(en-st); + } else { + en= start+len; + } + } else if (en) { + le = (long)(en-st); + } + printf("RANGEdebug %s st=0x%lx le=%ld en=0x%lx line %d\n", + msg,(unsigned long)st,le,(unsigned long)en,lineno); +} +#endif /* 0 */ + +static void +dealloc_globals_chain(Dwarf_Debug dbg, + Dwarf_Chain head_chain) +{ + Dwarf_Chain curr_chain = 0; + int chaintype = DW_DLA_CHAIN; + Dwarf_Global_Context lastcontext = 0; + Dwarf_Global_Context curcontext = 0; + + curr_chain = head_chain; + for (; curr_chain; ) { + Dwarf_Global item = 0; + int itemtype = 0; + Dwarf_Chain prev = 0; + + item = (Dwarf_Global)curr_chain->ch_item; + itemtype = curr_chain->ch_itemtype; + curcontext = item->gl_context; + if (curcontext && curcontext != lastcontext) { + /* First time we see a context, dealloc it. */ + lastcontext = curcontext; + dwarf_dealloc(dbg,curcontext,curcontext->pu_alloc_type); + } + prev = curr_chain; + dwarf_dealloc(dbg, item,itemtype); + prev->ch_item = 0; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, chaintype); + } +} + +/* INVARIANTS: + 1) on error does not leak Dwarf_Global + 2) glname is not malloc space. Never free. +*/ +static int +_dwarf_make_global_add_to_chain(Dwarf_Debug dbg, + Dwarf_Global_Context pubnames_context, + Dwarf_Off die_offset_in_cu, + unsigned char *glname, + Dwarf_Signed *global_count, + Dwarf_Bool *pubnames_context_on_list, + Dwarf_Unsigned global_DLA_code, + Dwarf_Chain **plast_chain, + Dwarf_Half tag, + Dwarf_Error *error) +{ + Dwarf_Chain curr_chain = 0; + Dwarf_Global global = 0; + + global = (Dwarf_Global) + _dwarf_get_alloc(dbg, (Dwarf_Small)global_DLA_code, 1); + if (!global) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocating Dwarf_Global"); + return DW_DLV_ERROR; + } + (*global_count)++; + /* Recording the same context in another Dwarf_Global */ + global->gl_context = pubnames_context; + global->gl_alloc_type = (Dwarf_Small)global_DLA_code; + global->gl_named_die_offset_within_cu = die_offset_in_cu; + global->gl_name = glname; + global->gl_tag = tag; + /* Finish off current entry chain */ + curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, + (Dwarf_Small)DW_DLA_CHAIN, 1); + if (!curr_chain) { + dwarf_dealloc(dbg,global,pubnames_context->pu_alloc_type); + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating a Dwarf_Chain" + " internal structure."); + return DW_DLV_ERROR; + } + /* Put current global on singly_linked list. */ + curr_chain->ch_item = (Dwarf_Global) global; + curr_chain->ch_itemtype = (int)global_DLA_code; + **plast_chain = curr_chain; + *plast_chain = &(curr_chain->ch_next); + *pubnames_context_on_list = TRUE; + return DW_DLV_OK; +} + +static int +_dwarf_chain_to_array(Dwarf_Debug dbg, + Dwarf_Chain head_chain, + Dwarf_Signed global_count, + Dwarf_Global **globals, + Dwarf_Error *error) +{ + Dwarf_Global *ret_globals = 0; + + if (!head_chain ) { + /* ASSERT: global_count == 0 */ + return DW_DLV_NO_ENTRY; + } + /* Now turn list into a block */ + /* Points to contiguous block of Dwarf_Global. */ + ret_globals = (Dwarf_Global *) + _dwarf_get_alloc(dbg, (Dwarf_Small)DW_DLA_LIST, + (Dwarf_Unsigned)global_count); + if (!ret_globals) { + dealloc_globals_chain(dbg,head_chain); + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocating a Dwarf_Global"); + return DW_DLV_ERROR; + } + + /* Store pointers to Dwarf_Global_s structs in contiguous block, + and deallocate the chain. This ignores the various + headers, since they are not involved. */ + { + Dwarf_Signed i = 0; + Dwarf_Chain curr_chain = 0; + + curr_chain = head_chain; + for ( ; i < global_count; i++) { + Dwarf_Chain prev = 0; + + *(ret_globals + i) = curr_chain->ch_item; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + prev->ch_item = 0; /* Not actually necessary. */ + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + } + head_chain = 0; /* Unneccesary, but showing intent. */ + *globals = ret_globals; + return DW_DLV_OK; +} + +static void +pubnames_error_length(Dwarf_Debug dbg, + Dwarf_Error *error, + Dwarf_Unsigned spaceneeded, + const char *secname, + const char *specificloc) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m,"DW_DLE_PUBNAMES_LENGTH_BAD: " + " In section "); + dwarfstring_append(&m,(char *)secname); + dwarfstring_append_printf_u(&m, + " %u bytes of space needed " + "but the section is out of space ", + spaceneeded); + dwarfstring_append(&m, "reading "); + dwarfstring_append(&m, (char *)specificloc); + dwarfstring_append(&m, "."); + _dwarf_error_string(dbg,error,DW_DLE_PUBNAMES_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* There are only 6 DW_IDX values defined in DWARF5 + so 7 would suffice, but lets allow for future DW_IDX too. + + On returning DW_DLV_ERROR the caller will free the + chain, we do not need to here. */ +#define IDX_ARRAY_SIZE 12 +static int +_dwarf_internal_get_debug_names_globals(Dwarf_Debug dbg, + Dwarf_Chain **pplast_chain, + Dwarf_Signed *total_count, + Dwarf_Error *error, + int context_DLA_code, + int global_DLA_code) +{ + int res = 0; + Dwarf_Off cur_offset = 0; + Dwarf_Off next_table_offset = 0; + Dwarf_Dnames_Head dn_head = 0; + Dwarf_Bool pubnames_context_on_list = FALSE; + Dwarf_Global_Context pubnames_context = 0; + + res = _dwarf_load_section(dbg, &dbg->de_debug_names,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_names.dss_size) { + return DW_DLV_NO_ENTRY; + } + + for ( ; ; cur_offset = next_table_offset) { + Dwarf_Unsigned comp_unit_count = 0; + Dwarf_Unsigned name_count = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Half table_version = 0; + Dwarf_Half offset_size = 0; + Dwarf_Unsigned n = 0; + + res = dwarf_dnames_header(dbg,cur_offset,&dn_head, + &next_table_offset,error); + if (res == DW_DLV_NO_ENTRY) { + /* Detected the end point */ + break; + } + if (res == DW_DLV_ERROR) { + return res; + } + /* DW_DLV_NO_ENTRY impossible here */ + res = dwarf_dnames_sizes(dn_head,&comp_unit_count, + 0,0,0,&name_count,0,0,0,0,§ion_size,&table_version, + &offset_size,error); + if (res != DW_DLV_OK) { + dwarf_dealloc_dnames(dn_head); + return res; + } + + for (n = 1 ; n <= name_count; ++n) { + Dwarf_Unsigned aindex = 0; + Dwarf_Unsigned bucket_number = 0; + Dwarf_Unsigned hash_value = 0; + Dwarf_Unsigned offset_to_debug_str = 0; + char *ptrtostr = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned offset_in_entrypool = 0; + Dwarf_Unsigned offset_of_next_entrypool = 0; + Dwarf_Half abbrev_tag = 0; + Dwarf_Half idxattr_array[IDX_ARRAY_SIZE]; + Dwarf_Half form_array[IDX_ARRAY_SIZE]; + Dwarf_Unsigned attr_count = 0; + + Dwarf_Unsigned epool_abbrev_code = 0; + Dwarf_Half epool_abbrev_tag = 0; + Dwarf_Unsigned epool_value_count = 0; + Dwarf_Unsigned epool_index_of_abbrev = 0; + Dwarf_Unsigned epool_offset_of_initial_value = 0; + + Dwarf_Unsigned offset_array[IDX_ARRAY_SIZE]; + Dwarf_Sig8 signature_array[IDX_ARRAY_SIZE]; + Dwarf_Bool single_cu = FALSE; + Dwarf_Unsigned single_cu_hdr_offset = 0; + Dwarf_Unsigned die_local_offset = 0; + Dwarf_Unsigned cu_header_global_offset = 0; + Dwarf_Unsigned cu_header_index = 0; + Dwarf_Bool have_die_local_offset = FALSE; + Dwarf_Bool have_cu_header_index = FALSE; + Dwarf_Bool have_cu_header_global_offset = 0; + Dwarf_Bool have_cu_header_offset = FALSE; + + memset(idxattr_array,0,sizeof(Dwarf_Half)*IDX_ARRAY_SIZE); + memset(form_array,0,sizeof(Dwarf_Half)*IDX_ARRAY_SIZE); + memset(offset_array,0,sizeof(Dwarf_Unsigned)* + IDX_ARRAY_SIZE); + memset(signature_array,0,sizeof(Dwarf_Sig8)* + IDX_ARRAY_SIZE); + res = dwarf_dnames_name(dn_head,n,&bucket_number, + &hash_value,&offset_to_debug_str,&ptrtostr, + &offset_in_entrypool, + &abbrev_code,&abbrev_tag,IDX_ARRAY_SIZE, + idxattr_array,form_array,&attr_count,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc_dnames(dn_head); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* internal error or corruption or simply past + the end of section. Normal.*/ + dwarf_dealloc_dnames(dn_head); + return res; + } + switch (abbrev_tag) { + case DW_TAG_subprogram: + case DW_TAG_variable: + case DW_TAG_label: + case DW_TAG_member: + case DW_TAG_common_block: + case DW_TAG_enumerator: + case DW_TAG_namelist: + case DW_TAG_module: + break; + default: + continue; + } + if (attr_count >= IDX_ARRAY_SIZE) { + dwarf_dealloc_dnames(dn_head); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "a .debug_names index attribute count " + "is unreasonable. " + "Corrupt data."); + return DW_DLV_ERROR; + } + + res = dwarf_dnames_entrypool(dn_head, + offset_in_entrypool,&epool_abbrev_code, + &epool_abbrev_tag,&epool_value_count, + &epool_index_of_abbrev, + &epool_offset_of_initial_value,error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc_dnames(dn_head); + return DW_DLV_ERROR; + } + if (res == DW_DLV_NO_ENTRY) { + dwarf_dealloc_dnames(dn_head); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "a .debug_names entry has no entrypool. " + "Unreasonable. " + "Corrupt data."); + return DW_DLV_ERROR; + } + res = dwarf_dnames_entrypool_values(dn_head, + epool_index_of_abbrev, + epool_offset_of_initial_value,IDX_ARRAY_SIZE, + idxattr_array,form_array, + offset_array, signature_array, + &single_cu,&single_cu_hdr_offset, + &offset_of_next_entrypool, + error); + + if (res == DW_DLV_ERROR) { + dwarf_dealloc_dnames(dn_head); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + dwarf_dealloc_dnames(dn_head); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_NAMES_ERROR, + "DW_DLE_DEBUG_NAMES_ERROR: " + "a .debug_names entry entrypool value " + " improperly empty. " + "Unreasonable. " + "Corrupt data."); + return DW_DLV_ERROR; + } + for (aindex = 0; aindex < epool_value_count; aindex++) { + Dwarf_Half idx = idxattr_array[aindex]; + + switch(idx) { + case DW_IDX_type_unit: + case DW_IDX_parent: + case DW_IDX_type_hash: + break; + case DW_IDX_compile_unit: + cu_header_index = offset_array[aindex]; + have_cu_header_index = TRUE; + break; + case DW_IDX_die_offset: + die_local_offset = offset_array[aindex]; + have_die_local_offset = TRUE; + break; + default: + /* Non-standard DW_IDX. */ + break; + } + } + if (!have_cu_header_index) { + if (single_cu) { + have_cu_header_global_offset = TRUE; + cu_header_global_offset = single_cu_hdr_offset; + } else { + /* Ignore this entry, not global? */ + continue; + } + } + + if (!have_die_local_offset) { + /* Ignore this entry */ + continue; + } + if (!have_cu_header_offset) { + int ores = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Sig8 signature; + Dwarf_Error cuterr = 0; + + ores = dwarf_dnames_cu_table(dn_head, + "cu", cu_header_index, + &offset,&signature,&cuterr); + if (ores != DW_DLV_OK) { + } else { + cu_header_global_offset = offset; + have_cu_header_global_offset = TRUE; + } + } + if (!have_cu_header_global_offset) { + /* Ignore this entry */ + continue; + } + + if (!pubnames_context || + (pubnames_context->pu_offset_of_cu_header != + cu_header_global_offset)) { + pubnames_context_on_list = FALSE; + pubnames_context = (Dwarf_Global_Context) + _dwarf_get_alloc(dbg, + (Dwarf_Small)context_DLA_code, 1); + if (!pubnames_context) { + dwarf_dealloc_dnames(dn_head); + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating " + "Dwarf_Global_Context"); + return DW_DLV_ERROR; + } + /* Dwarf_Global_Context initialization. */ + pubnames_context->pu_dbg = dbg; + pubnames_context->pu_alloc_type = context_DLA_code; + pubnames_context->pu_is_debug_names = TRUE; + pubnames_context->pu_offset_of_cu_header = + cu_header_global_offset; + /* For .debug_names we don't need to + set the rest of the fields. + All the translations from disk + form to libdwarf types and the sanity + chacking are already done. */ + } + /* we have an entry to set up Dwarf_Global */ + res = _dwarf_make_global_add_to_chain(dbg, + pubnames_context, + die_local_offset, + (unsigned char *)ptrtostr, + total_count, + &pubnames_context_on_list, + global_DLA_code, + pplast_chain, + abbrev_tag, + error); + if (res == DW_DLV_ERROR) { + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + dwarf_dealloc_dnames(dn_head); + return res; + } + } + dwarf_dealloc_dnames(dn_head); + dn_head = 0; + } + return DW_DLV_OK; +} +#undef IDX_ARRAY_SIZE +static void +_dwarf_get_DLE_name(int errnum,dwarfstring *out) +{ + char * basemsg = 0; + char * curp = 0; + unsigned long count = 0; + + basemsg = dwarf_errmsg_by_number(errnum); + curp = basemsg; + while (*curp) { + if (*curp == ' ') { + break; + } + if (*curp == '(') { + break; + } + ++count; + ++curp; + } + dwarfstring_append_length(out,basemsg,count); +} + +static void +_dwarf_global_cu_len_error_msg(Dwarf_Debug dbg, + int errornumber, + const char * section_name, + Dwarf_Unsigned section_length, + int cu_number, + Dwarf_Unsigned length_section_offset, + Dwarf_Unsigned length_field, + Dwarf_Error *error) +{ + dwarfstring m; + Dwarf_Unsigned remaining = 0; + + remaining = section_length - length_section_offset; + dwarfstring_constructor(&m); + _dwarf_get_DLE_name(errornumber,&m); + dwarfstring_append_printf_u(&m, + ": For cu context %u ", + cu_number); + dwarfstring_append_printf_s(&m,"of section %s ", + (char *)section_name); + dwarfstring_append_printf_u(&m,"the length field at " + "offset %u ",length_section_offset); + dwarfstring_append_printf_u(&m,"has value %u ", + length_field); + dwarfstring_append_printf_u(&m,"though just %u bytes " + "remain in the section. Corrupt DWARF",remaining); + _dwarf_error_string(dbg, error,errornumber, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +/* Sweeps the complete section. + On error it frees the head_chain, + and the caller never sees the head_chain data. + On success, if the out*chain data exists + it updates the caller head_chain through + the pointers. +*/ +static int +_dwarf_internal_get_pubnames_like(Dwarf_Debug dbg, + int category, /* DW_GL_GLOBAL or ... */ + const char *secname, + Dwarf_Small * section_data_ptr, + Dwarf_Unsigned section_length, + Dwarf_Chain * out_phead_chain, + Dwarf_Chain ** out_pplast_chain, + Dwarf_Signed * return_count, + Dwarf_Error * error, + int length_err_num, + int version_err_num) +{ + Dwarf_Small *pubnames_like_ptr = 0; + /* Section offset to the above pointer. */ + Dwarf_Unsigned pubnames_like_offset = 0; + + Dwarf_Small *section_end_ptr = section_data_ptr +section_length; + + /* Points to the context for the current set of global names, + and contains information to identify the compilation-unit + that the set refers to. */ + Dwarf_Global_Context pubnames_context = 0; + Dwarf_Bool pubnames_context_on_list = FALSE; + Dwarf_Unsigned context_DLA_code = DW_DLA_GLOBAL_CONTEXT; + Dwarf_Unsigned global_DLA_code = DW_DLA_GLOBAL; + + Dwarf_Unsigned version = 0; + + /* Offset from the start of compilation-unit for the current + global. */ + Dwarf_Off die_offset_in_cu = 0; + Dwarf_Signed global_count = 0; + + /* The count is just to improve the error message + a few lines above. */ + Dwarf_Unsigned context_count = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "calling for pubnames-like data Dwarf_Debug " + "either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + /* We will eventually need the .debug_info data. Load it now. */ + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + } + if (section_data_ptr == NULL) { + return DW_DLV_NO_ENTRY; + } + pubnames_like_ptr = section_data_ptr; + pubnames_like_offset = 0; + do { + int mres = 0; + Dwarf_Unsigned length = 0; + int local_extension_size = 0; + int local_length_size = 0; + Dwarf_Off pubnames_section_cu_offset = + pubnames_like_offset; + + /* Some compilers emit padding at the end of each cu's area. + pubnames_ptr_past_end_cu records the true area end for the + pubnames(like) content of a cu. + Essentially the length in the header and the 0 + terminator of the data are redundant information. The + dwarf2/3 spec does not mention what to do if the length is + past the 0 terminator. So we take any bytes left + after the 0 as padding and ignore them. */ + Dwarf_Small *pubnames_ptr_past_end_cu = 0; + + pubnames_context_on_list = FALSE; + pubnames_context = (Dwarf_Global_Context) + _dwarf_get_alloc(dbg, + (Dwarf_Small)context_DLA_code, 1); + if (!pubnames_context) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocating a" + " Dwarf_Global_Context for a pubnames entry."); + return DW_DLV_ERROR; + } + /* ========pubnames_context not recorded anywhere yet. */ + /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed + bytes. */ + if ((pubnames_like_ptr + DWARF_32BIT_SIZE + + DWARF_HALF_SIZE + DWARF_32BIT_SIZE) > + /* A minimum size needed */ + section_end_ptr) { + pubnames_error_length(dbg,error, + DWARF_32BIT_SIZE + DWARF_HALF_SIZE + DWARF_32BIT_SIZE, + secname, + "header-record"); + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return DW_DLV_ERROR; + } + mres = _dwarf_read_area_length_ck_wrapper(dbg, + &length,&pubnames_like_ptr,&local_length_size, + &local_extension_size,section_length,section_end_ptr, + error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return mres; + } + { + Dwarf_Small * localend =pubnames_like_ptr + length; + if ((length > section_length) || + (localend > section_end_ptr)){ + _dwarf_global_cu_len_error_msg(dbg, + length_err_num, + secname, section_length, + context_count, + (Dwarf_Unsigned)pubnames_like_offset, + (Dwarf_Unsigned)length, + error); + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return DW_DLV_ERROR; + } + } + pubnames_like_offset += local_length_size + + local_extension_size; + /* The count is just to improve the error message + a few lines above. */ + ++context_count; + /* Dwarf_Global_Context initialization. */ + pubnames_context->pu_global_category = category; + pubnames_context->pu_alloc_type = + (unsigned)context_DLA_code; + pubnames_context->pu_length_size = + (unsigned char)local_length_size; + pubnames_context->pu_length = (unsigned char)length; + pubnames_context->pu_extension_size = + (unsigned char)local_extension_size; + pubnames_context->pu_dbg = dbg; + pubnames_context->pu_pub_offset = pubnames_section_cu_offset; + pubnames_ptr_past_end_cu = pubnames_like_ptr + length; + pubnames_context->pu_pub_entries_end_ptr = + pubnames_ptr_past_end_cu; + if ((pubnames_like_ptr + (DWARF_HALF_SIZE) ) >= + /* A minimum size needed */ + section_end_ptr) { + pubnames_error_length(dbg,error, + DWARF_HALF_SIZE, + secname,"version-number"); + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return DW_DLV_ERROR; + } + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &version,pubnames_like_ptr,DWARF_HALF_SIZE, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return mres; + } + pubnames_context->pu_version = (Dwarf_Half)version; + pubnames_like_ptr += DWARF_HALF_SIZE; + pubnames_like_offset += DWARF_HALF_SIZE; + /* ASSERT: DW_PUBNAMES_VERSION2 == DW_PUBTYPES_VERSION2 */ + if (version != DW_PUBNAMES_VERSION2) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + _dwarf_error(dbg, error, version_err_num); + return DW_DLV_ERROR; + } + + /* Offset of CU header in debug section. */ + if ((pubnames_like_ptr + 3*pubnames_context->pu_length_size)> + section_end_ptr) { + pubnames_error_length(dbg,error, + 3*pubnames_context->pu_length_size, + secname, + "header/DIE offsets"); + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return DW_DLV_ERROR; + } + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &pubnames_context->pu_offset_of_cu_header, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return mres; + } + + pubnames_like_ptr += pubnames_context->pu_length_size; + pubnames_like_offset += pubnames_context->pu_length_size; + + FIX_UP_OFFSET_IRIX_BUG(dbg, + pubnames_context->pu_offset_of_cu_header, + "pubnames cu header offset"); + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &pubnames_context->pu_info_length, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return mres; + } + pubnames_like_ptr += pubnames_context->pu_length_size; + pubnames_like_offset += pubnames_context->pu_length_size; + + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + _dwarf_error(dbg, error, length_err_num); + return DW_DLV_ERROR; + } + + /* Read initial offset (of DIE within CU) of a pubname, final + entry is not a pair, just a zero offset. */ + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &die_offset_in_cu, + pubnames_like_ptr, + pubnames_context->pu_length_size, + pubnames_context->pu_pub_entries_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + return mres; + } + pubnames_like_ptr += pubnames_context->pu_length_size; + pubnames_like_offset += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, "offset of die in cu"); + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + _dwarf_error(dbg, error, length_err_num); + return DW_DLV_ERROR; + } + + /* Check if empty section */ + if (!die_offset_in_cu) { + if (dbg->de_return_empty_pubnames) { + int res = 0; + + /* Here we have a pubnames CU with no actual + entries so we fake up an entry to hold the + header data. There are no 'pairs' here, + just the end of list zero value. We do this + only if de_return_empty_pubnames is set + so that we by default return exactly the same + data this always returned, yet dwarfdump can + request the empty-cu records get created + to test that feature. + see dwarf_get_globals_header() */ + res = _dwarf_make_global_add_to_chain(dbg, + pubnames_context, + die_offset_in_cu, + /* It is a fake global, so empty name */ + (unsigned char *)"", + &global_count, + &pubnames_context_on_list, + global_DLA_code, + out_pplast_chain, + 0, + error); + if (res != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return res; + } + /* ========pubnames_context recorded in chain. */ + } else { + /* The section is empty. + Nowhere to record pubnames_context); */ + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + pubnames_context = 0; + continue; + } + } + /* Loop thru pairs. DIE off with CU followed by string. */ + /* Now read pairs of entries */ + while (die_offset_in_cu) { + int res = 0; + unsigned char *glname = 0; + Dwarf_Unsigned nstrlen = 0; + + /* non-zero die_offset_in_cu already read, so + pubnames_like_ptr points to a string. */ + res = _dwarf_check_string_valid(dbg,section_data_ptr, + pubnames_like_ptr, + pubnames_context->pu_pub_entries_end_ptr, + DW_DLE_STRING_OFF_END_PUBNAMES_LIKE,error); + if (res != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return res; + } + glname = (unsigned char *)pubnames_like_ptr; + nstrlen = strlen((char *)pubnames_like_ptr); + pubnames_like_ptr += nstrlen + 1; + pubnames_like_offset += nstrlen + 1; + /* Already read offset and verified string, glname + now points to the string. */ + res = _dwarf_make_global_add_to_chain(dbg, + pubnames_context, + die_offset_in_cu, + glname, + &global_count, + &pubnames_context_on_list, + global_DLA_code, + out_pplast_chain, + 0, + error); + if (res != DW_DLV_OK) { + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return res; + } + /* ========pubnames_context recorded in chain. */ + /* Ensure room for a next entry to exist. */ + if ((pubnames_like_ptr + + pubnames_context->pu_length_size ) > + section_end_ptr) { + pubnames_error_length(dbg,error, + 2*pubnames_context->pu_length_size, + secname, + "global record offset"); + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + return DW_DLV_ERROR; + } + /* Read die offset for the *next* entry */ + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &die_offset_in_cu, + pubnames_like_ptr, + pubnames_context->pu_length_size, + pubnames_context->pu_pub_entries_end_ptr, + error); + if (mres != DW_DLV_OK) { + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + return mres; + } + /* die_offset_in_cu may now be zero, meaing + end of the pairs list */ + pubnames_like_ptr += pubnames_context->pu_length_size; + pubnames_like_offset += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, "offset of next die in cu"); + if (pubnames_like_ptr > + (section_data_ptr + section_length)) { + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context, + context_DLA_code); + } + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + _dwarf_error(dbg, error, length_err_num); + return DW_DLV_ERROR; + } + } + /* ASSERT: die_offset_in_cu == 0 */ + if (pubnames_like_ptr > pubnames_ptr_past_end_cu) { + /* This is some kind of error. This simply cannot happen. + The encoding is wrong or the length in the header for + this cu's contribution is wrong. */ + _dwarf_error(dbg, error, length_err_num); + if (!pubnames_context_on_list) { + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + } + dealloc_globals_chain(dbg,*out_phead_chain); + *out_phead_chain = 0; + return DW_DLV_ERROR; + } +#if 1 + /* If there is some kind of padding at the end of + the section, following a pairs terminator, + as emitted by some compilers, skip over that padding and + simply ignore the bytes thus passed-over. */ + { + Dwarf_Unsigned finaloffset = + pubnames_section_cu_offset+ + pubnames_context->pu_length_size + + pubnames_context->pu_length + + pubnames_context->pu_extension_size; + if (finaloffset > pubnames_like_offset) { + pubnames_like_offset = finaloffset; + } + } +#endif + pubnames_like_ptr = pubnames_ptr_past_end_cu; + } while (pubnames_like_ptr < section_end_ptr); + *return_count = global_count; + return DW_DLV_OK; +#if 0 + if (!globals) { + return DW_DLV_OK; + } + { + int cbres = 0; + /* Cannot return DW_DLV_NO_ENTRY */ + cbres = _dwarf_chain_to_array(dbg,*out_phead_chain, + global_count, globals, error); + /* head_chain no longer points to anything */ + *out_phead_chain = 0; + return cbres; + } +#endif +} + +static const int err3[]= +{ +DW_DLE_PUBNAMES_LENGTH_BAD, +DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD, +DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD, +DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD, +DW_DLE_DEBUG_VARNAMES_LENGTH_BAD, +DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD +}; +static const int err4[]= +{ +DW_DLE_PUBNAMES_VERSION_ERROR, +DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR, +DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR, +DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR, +DW_DLE_DEBUG_VARNAMES_VERSION_ERROR, +DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR +}; +static const char * secna[] = +{ +".debug_pubnames", +".debug_pubtypes", +".debug_funcnames", +".debug_typenames", +".debug_varnames", +".debug_weaknames", +}; + +/* New in 0.6.0, unifies all the access routines + for the sections like .debug_pubtypes. +*/ +int +dwarf_globals_by_type(Dwarf_Debug dbg, + int requested_section, + Dwarf_Global **contents, + Dwarf_Signed *ret_count, + Dwarf_Error *error) +{ + struct Dwarf_Section_s *section = 0; + Dwarf_Chain head_chain = 0; + Dwarf_Chain *plast_chain = &head_chain; + Dwarf_Bool have_base_sec = FALSE; + Dwarf_Bool have_second_sec = FALSE; + int res = 0; + + /* Zero caller's fields in case caller + failed to do so. Bad input here causes + segfault! */ + *contents = 0; + *ret_count = 0; + switch(requested_section){ + case DW_GL_GLOBALS: + section = &dbg->de_debug_pubnames; + break; + case DW_GL_PUBTYPES: + section = &dbg->de_debug_pubtypes; + break; + /* The Following are IRIX only. */ + case DW_GL_FUNCS: + section = &dbg->de_debug_funcnames; + break; + case DW_GL_TYPES: + section = &dbg->de_debug_typenames; + break; + case DW_GL_VARS: + section = &dbg->de_debug_varnames; + break; + case DW_GL_WEAKS: + section = &dbg->de_debug_weaknames; + break; + default: { + dwarfstring m; + char buf[100]; + + dwarfstring_constructor_static(&m,buf,sizeof(buf)); + dwarfstring_append_printf_u(&m, + "ERROR DW_DLE_GLOBAL_NULL: Passed in Dwarf_Global " + "requested section " + "%u which is unknown to dwarf_globals_by_type().", + requested_section); + _dwarf_error_string(dbg, error, DW_DLE_GLOBAL_NULL, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + res = _dwarf_load_section(dbg, section, error); + if (res == DW_DLV_ERROR) { + return res; + } + if (section->dss_size) { + have_base_sec = TRUE; + } + + if (have_base_sec) { + res = _dwarf_internal_get_pubnames_like(dbg, + requested_section, + secna[requested_section], + section->dss_data, + section->dss_size, + &head_chain, + &plast_chain, + ret_count, + error, + err3[requested_section], + err4[requested_section]); + if (res == DW_DLV_ERROR) { + dealloc_globals_chain(dbg,head_chain); + return res; + } + } + if (0 == requested_section) { + res = _dwarf_load_section(dbg, &dbg->de_debug_names,error); + if (res == DW_DLV_ERROR) { + return res; + } else if (dbg->de_debug_names.dss_size) { + have_second_sec = TRUE; + } + } + if (have_second_sec) { + res = _dwarf_internal_get_debug_names_globals(dbg, + &plast_chain, + ret_count, + error, + DW_DLA_GLOBAL_CONTEXT, + DW_DLA_GLOBAL); + if (res == DW_DLV_ERROR) { + dealloc_globals_chain(dbg,head_chain); + head_chain = 0; + return res; + } + } + res = _dwarf_chain_to_array(dbg,head_chain, + *ret_count, contents, error); + if (res == DW_DLV_ERROR) { + /* head chain maybe zero. Is ok. */ + dealloc_globals_chain(dbg,head_chain); + return res; + } + /* Must not return DW_DLV_NO_ENTRY. Count + is set zero in caller so no need for NO_ENTRY. */ + return DW_DLV_OK; +} + +int +dwarf_get_globals(Dwarf_Debug dbg, + Dwarf_Global **ret_globals, + Dwarf_Signed *return_count, + Dwarf_Error *error) +{ + int res = 0; + res = dwarf_globals_by_type(dbg, + DW_GL_GLOBALS,ret_globals,return_count,error); + return res; +} +/* This now returns Dwarf_Global for types so + all the dwarf_global data retrieval calls work. + This is just a shorthand. + + Before 0.6.0 this would return Dwarf_Type. +*/ +int +dwarf_get_pubtypes(Dwarf_Debug dbg, + Dwarf_Global **types, + Dwarf_Signed *return_count, + Dwarf_Error *error) +{ + int res = 0; + res = dwarf_globals_by_type(dbg, + DW_GL_PUBTYPES,types,return_count,error); + return res; +} + +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ +void +dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, dwgl, count); + return; +} + +void +_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, + Dwarf_Global * dwgl, + Dwarf_Signed count) +{ + Dwarf_Signed i = 0; + struct Dwarf_Global_Context_s *glcp = 0; + struct Dwarf_Global_Context_s *lastglcp = 0; + + if (!dwgl) { + return; + } + for (i = 0; i < count; i++) { + Dwarf_Global dgd = dwgl[i]; + + if (!dgd) { + continue; + } + /* Avoids duplicate frees of repeated + use of contexts (while assuming that + all uses of a particular gl_context + will appear next to each other. */ + glcp = dgd->gl_context; + if (glcp && lastglcp != glcp) { + lastglcp = glcp; + dwarf_dealloc(dbg, glcp, glcp->pu_alloc_type); + } + dwarf_dealloc(dbg, dgd, dgd->gl_alloc_type); + } + dwarf_dealloc(dbg, dwgl, DW_DLA_LIST); + return; +} + +/* Given a pubnames entry (or other like section entry) + return thru the ret_name pointer + a pointer to the string which is the entry name. */ +int +dwarf_globname(Dwarf_Global glob, + char **ret_name, + Dwarf_Error * error) +{ + if (glob == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return DW_DLV_ERROR; + } + + *ret_name = (char *) (glob->gl_name); + return DW_DLV_OK; +} + +/* Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + global offset of the DIE for this entry. + The global offset is the offset within the .debug_info + section as a whole. */ +int +dwarf_global_die_offset(Dwarf_Global global, + Dwarf_Off * ret_off, Dwarf_Error * error) +{ + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return DW_DLV_ERROR; + } + + if (global->gl_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return DW_DLV_ERROR; + } + + *ret_off = (global->gl_named_die_offset_within_cu + + global->gl_context->pu_offset_of_cu_header); + return DW_DLV_OK; +} + +/* Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + offset of the compilation unit header of the + compilation unit the global is part of. +*/ +int +dwarf_global_cu_offset(Dwarf_Global global, + Dwarf_Off * cu_header_offset, + Dwarf_Error * error) +{ + Dwarf_Global_Context con = 0; + + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return DW_DLV_ERROR; + } + con = global->gl_context; + if (con == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return DW_DLV_ERROR; + } + *cu_header_offset = con->pu_offset_of_cu_header; + return DW_DLV_OK; +} + +static void +build_off_end_msg(Dwarf_Unsigned offval, + Dwarf_Unsigned withincr, + Dwarf_Unsigned secsize, + dwarfstring *m) +{ + const char *msg = "past"; + if (offval < secsize){ + msg = "too near"; + } + dwarfstring_append_printf_u(m,"DW_DLE_OFFSET_BAD: " + "The CU header offset of %u in a pubnames-like entry ", + withincr); + dwarfstring_append_printf_s(m, + "would put us %s the end of .debug_info. " + "No room for a DIE there... " + "Corrupt Dwarf.",(char *)msg); + return; +} + +/* + Give back the pubnames entry (or any other like section) + name, symbol DIE offset, and the cu-DIE offset. + + This provides all the information that + dwarf_globname(), dwarf_global_die_offset() + and dwarf_global_cu_offset() do, but do it + in one call. + + The string pointer returned thru ret_name is not + dwarf_get_alloc()ed, so no dwarf_dealloc() + DW_DLA_STRING should be applied to it. + +*/ +int +dwarf_global_name_offsets(Dwarf_Global global, + char **ret_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) +{ + Dwarf_Global_Context con = 0; + Dwarf_Debug dbg = 0; + Dwarf_Off cuhdr_off = 0; + + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return DW_DLV_ERROR; + } + + con = global->gl_context; + if (con == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return DW_DLV_ERROR; + } + + cuhdr_off = con->pu_offset_of_cu_header; + /* The offset had better not be too close to the end. If it is, + _dwarf_length_of_cu_header() will step off the end + and therefore + must not be used. 10 is a meaningless heuristic, but no CU + header is that small so it is safe. An erroneous offset is due + to a bug in the tool chain. A bug like this has been seen on + IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and + with 2 million pubnames entries. */ +#define MIN_CU_HDR_SIZE 10 + dbg = con->pu_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + /* Cannot refer to debug_types, see p141 of + DWARF4 Standard */ + if (dbg->de_debug_info.dss_size && + ((cuhdr_off + MIN_CU_HDR_SIZE) >= + dbg->de_debug_info.dss_size)) { + dwarfstring m; + + dwarfstring_constructor(&m); + build_off_end_msg(cuhdr_off,cuhdr_off, + dbg->de_debug_info.dss_size,&m); + _dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + /* If global->gl_named_die_offset_within_cu + is zero then this is a fake global for + a pubnames CU with no pubnames. The offset is from the + start of the CU header, so no die can have a zero + offset, all valid offsets are positive numbers */ + if (die_offset) { + if (global->gl_named_die_offset_within_cu) { + *die_offset = global->gl_named_die_offset_within_cu + + cuhdr_off; + } else { + *die_offset = 0; + } + } +#undef MIN_CU_HDR_SIZE + *ret_name = (char *) global->gl_name; + if (cu_die_offset) { + /* Global cannot refer to debug_types */ + int cres = 0; + Dwarf_Unsigned headerlen = 0; + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + /* We already checked to make sure enough room + with MIN_CU_HDR_SIZE */ +#if 0 + /* The offset had better not be too close to the end. + If it is, + _dwarf_length_of_cu_header() will step off the end and + therefore must not be used. 10 is a meaningless heuristic, + but no CU header is that small so it is safe. */ + /* Global cannot refer to debug_types */ + if ((cuhdr_off + MIN_CU_HDR_SIZE) + >= dbg->de_debug_info.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + build_off_end_msg(cuhdr_off,cuhdr_off, + dbg->de_debug_info.dss_size,&m); + _dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } +#endif /* 0 */ + cres = _dwarf_length_of_cu_header(dbg, cuhdr_off,true, + &headerlen,error); + if (cres != DW_DLV_OK) { + return cres; + } + *cu_die_offset = cuhdr_off + headerlen; + } + return DW_DLV_OK; +} + +/* New February 2019 from better dwarfdump printing + of debug_pubnames and pubtypes. + For all the Dwarf_Global records in one pubnames + CU group exactly the same data will be returned. + +*/ +int +dwarf_get_globals_header(Dwarf_Global global, + int *category,/* DW_GL_GLOBAL for example*/ + Dwarf_Off *pub_section_hdr_offset, + Dwarf_Unsigned *pub_offset_size, + Dwarf_Unsigned *pub_cu_length, + Dwarf_Unsigned *version, + Dwarf_Off *info_header_offset, + Dwarf_Unsigned *info_length, + Dwarf_Error* error) +{ + Dwarf_Global_Context con = 0; + Dwarf_Debug dbg = 0; + + if (global == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return DW_DLV_ERROR; + } + con = global->gl_context; + if (con == NULL) { + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return DW_DLV_ERROR; + } + dbg = con->pu_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "calling dwarf_get_globals_header() " + "either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (category) { + *category = con->pu_global_category; + } + if (pub_section_hdr_offset) { + *pub_section_hdr_offset = con->pu_pub_offset; + } + if (pub_offset_size) { + *pub_offset_size = con->pu_length_size; + } + if (pub_cu_length) { + *pub_cu_length = con->pu_length; + } + if (version) { + *version = con->pu_version; + } + if (info_header_offset) { + *info_header_offset = con->pu_offset_of_cu_header; + } + if (info_length) { + *info_length = con->pu_info_length; + } + return DW_DLV_OK; +} + +/* We have the offset to a CU header. + Return thru outFileOffset the offset of the CU DIE. + + New June, 2001. + Used by SGI IRIX debuggers. + No error used to be possible. + As of May 2016 an error is possible if the DWARF is + corrupted! (IRIX debuggers are no longer built ...) + + See also dwarf_CU_dieoffset_given_die(). + + This is assumed to never apply to data in .debug_types, it + only refers to .debug_info. + +*/ + +/* ARGSUSED */ +/* The following version new in October 2011, does allow finding + the offset if one knows whether debug_info or debug_types + or any .debug_info type including the DWARF5 flavors. + + It indirectly calls _dwarf_length_of_cu_header() + which knows all the varieties of header. */ +int +dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Bool is_info, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error * error) +{ + Dwarf_Off headerlen = 0; + int cres = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "calling dwarf_get_cu_die_offset_given" + "cu_header_offset_b Dwarf_Debug is" + "either null or it is" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + cres = _dwarf_length_of_cu_header(dbg, + in_cu_header_offset,is_info, &headerlen,error); + if (cres != DW_DLV_OK) { + return cres; + } + *out_cu_die_offset = in_cu_header_offset + headerlen; + return DW_DLV_OK; +} +/* dwarf_CU_dieoffset_given_die returns + the global debug_info section offset of the CU die + that is the CU containing the given (passed-in) die. + This information makes it possible for a consumer to + find and print context information for any die. + + Use dwarf_offdie_b() passing in the offset this returns + to get a die pointer to the CU die. */ +int +dwarf_CU_dieoffset_given_die(Dwarf_Die die, + Dwarf_Off* return_offset, + Dwarf_Error* error) +{ + Dwarf_Off dieoff = 0; + Dwarf_CU_Context cucontext = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cucontext = die->di_cu_context; + dieoff = cucontext->cc_debug_offset; + /* The following call cannot fail, so no error check. */ + dwarf_get_cu_die_offset_given_cu_header_offset_b( + cucontext->cc_dbg, dieoff, + die->di_is_info, return_offset,error); + return DW_DLV_OK; +} + +int dwarf_return_empty_pubnames(Dwarf_Debug dbg, int flag) +{ + if (dbg == NULL) { + return DW_DLV_OK; + } + if (flag && flag != 1) { + return DW_DLV_OK; + } + dbg->de_return_empty_pubnames = (unsigned char)flag; + return DW_DLV_OK; +} + +Dwarf_Half +dwarf_global_tag_number(Dwarf_Global dw_global) +{ + if (!dw_global) { + return 0; + } + return dw_global->gl_tag; +} diff --git a/src/lib/libdwarf/dwarf_global.h b/src/lib/libdwarf/dwarf_global.h new file mode 100644 index 0000000..9ae1f74 --- /dev/null +++ b/src/lib/libdwarf/dwarf_global.h @@ -0,0 +1,135 @@ +/* + + Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +typedef struct Dwarf_Global_Context_s *Dwarf_Global_Context; + +/* + This struct contains header information for a set of pubnames. + Essentially, they contain the context for a set of pubnames + belonging to a compilation-unit. + + Also used for the sgi-specific + weaknames, typenames, varnames, funcnames data: + the structs for those are incomplete and + instances of this are used instead. + + Also used for DWARF3,4 .debug_pubtypes and DWARF5 .debug_names. + + These never refer to .debug_types, only to .debug_info. +*/ +struct Dwarf_Global_Context_s { + unsigned pu_is_dnames; /* 0 if not .debug_names. */ + unsigned pu_alloc_type; /* DW_DLA something */ + Dwarf_Debug pu_dbg; + + /* One of DW_GL_GLOBAL,DW_GL_PUBTYPES,etc */ + int pu_global_category; + + /* The following set with the DW_TAG of the DIE + involved. Left 0 with .debug_pubnames. */ + Dwarf_Bool pu_is_debug_names; + + /* For DWARF5 .debug_names the following + are irellevant, left 0. */ + /* For this context, size of a length (offset). 4 or 8 */ + unsigned char pu_length_size; + + /* Size of the data section for the CU */ + unsigned char pu_length; + + /* For this CU, size of the extension. 0 except + for dwarf2 extension (IRIX) 64bit, in which case is 4. */ + unsigned char pu_extension_size; + + Dwarf_Half pu_version; /* 2,3,4 or 5 */ + + /* offset in pubnames or debug_names of the pu header. */ + Dwarf_Off pu_pub_offset; + /* One past end of the section entries for this CU. */ + Dwarf_Byte_Ptr pu_pub_entries_end_ptr; + + /* Offset into .debug_info of the compilation-unit header + (not DIE) for this set of pubnames. */ + Dwarf_Off pu_offset_of_cu_header; + + /* Size of compilation-unit that these pubnames are in. */ + Dwarf_Unsigned pu_info_length; + +}; + +/* This struct contains information for a single pubname. */ +struct Dwarf_Global_s { + + /* Offset from the start of the corresponding compilation-unit of + the DIE for the given pubname CU. */ + Dwarf_Off gl_named_die_offset_within_cu; + + /* Points to the given pubname. */ + Dwarf_Small *gl_name; + + /* Context for this pubname. */ + Dwarf_Global_Context gl_context; + + Dwarf_Half gl_alloc_type; /* DW_DLA something */ + Dwarf_Half gl_tag; /* .debug_names only. Else 0. */ +}; + +/* In all but pubnames, head_chain and globals + should be passed in as NULL. + So that .debug_names entries can be added to the chain + before making an array. +*/ + +int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, + const char *secname, + Dwarf_Small *section_data_ptr, + Dwarf_Unsigned section_length, + Dwarf_Global ** globals, + Dwarf_Chain * head_chain, + Dwarf_Chain ** plast_chain, + Dwarf_Signed * return_count, + Dwarf_Error * error, + int context_code, + int global_code, + int length_err_num, + int version_err_num); + +void _dwarf_internal_globals_dealloc( Dwarf_Debug dbg, + Dwarf_Global *dwgl, Dwarf_Signed count); + +#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */ +void _dwarf_fix_up_offset_irix(Dwarf_Debug dbg, + Dwarf_Unsigned *varp, + char *caller_site_name); +#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) \ + _dwarf_fix_up_offset_irix((ldbg),&(var),(name)) +#else /* ! __sgi */ +#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) +#endif /* __sgi */ diff --git a/src/lib/libdwarf/dwarf_gnu_index.c b/src/lib/libdwarf/dwarf_gnu_index.c new file mode 100644 index 0000000..4c29b36 --- /dev/null +++ b/src/lib/libdwarf/dwarf_gnu_index.c @@ -0,0 +1,791 @@ +/* + Copyright (C) 2020 David Anderson. All Rights Reserved. + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* This is for accessing .debug_gnu_pubnames + and .debug_gnu_pubtypes. + + These sections are designed to be compiler-generated + to be used by the linker to create the .gdb_index + section for DWARF3 and DWARF4 as part of + Split Dwarf (aka Debug Fission). + They are not expected to be in an executable. */ + +#include + +#include /* calloc() free() */ +#include /* debugging */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_gnu_index.h" +#include "dwarf_string.h" + +#if 0 +static void +dump_head(const char *msg,int lno, + struct Dwarf_Gnu_Index_Head_s *h) +{ + printf("HEAD block line %d\n",__LINE__); + printf("data : %p\n", + (void *)h->gi_section_data); + printf("sec len : %llu 0x%llx\n", + h->gi_section_length, + h->gi_section_length); + printf("data end : %p\n", + (void *)(h->gi_section_end)); + printf("blockarray : %p\n", + (void *)h->gi_blockarray); + printf("block count : %llu 0x%llx\n", + h->gi_blockcount, + h->gi_blockcount); + printf("gnu_pubnames: %u\n",h->gi_is_pubnames); +} + +static void +dump_block(const char *msg,int bn, int lno, + struct Dwarf_Gnu_IBlock_s *b) +{ + printf("BLOCK dump block %d %s line %d\n", + bn,msg,lno); + printf("head : 0x%lx\n", + (unsigned long)b->ib_head); + printf("index : %lu\n", + (unsigned long)b->ib_index); + printf("blk len offset : %lu 0x%lx\n", + (unsigned long)b->ib_block_length_offset, + (unsigned long)b->ib_block_length_offset); + printf("block length : %lu 0x%lx\n", + (unsigned long)b->ib_block_length, + (unsigned long)b->ib_block_length); + printf("offset size : %u\n", + b->ib_offset_size); + printf("extension size : %u\n", + b->ib_extension_size); + printf("version : %u\n", + b->ib_version); + printf("built entries? : %s\n", + b->ib_counted_entries?"yes":"no"); + printf("debug_info offset: %lu 0x%lx\n", + (unsigned long)b->ib_offset_in_debug_info, + (unsigned long)b->ib_offset_in_debug_info); + printf("debug_info size : %lu 0x%lx\n", + (unsigned long)b->ib_size_in_debug_info, + (unsigned long)b->ib_size_in_debug_info); + printf("data offset : %lu 0x%lx\n", + (unsigned long)b->ib_b_data_offset, + (unsigned long)b->ib_b_data_offset); + printf("entries offset : %lu 0x%lx\n", + (unsigned long)b->ib_b_offset, + (unsigned long)b->ib_b_offset); + printf("entries ptr : 0x%lx\n", + (unsigned long)b->ib_b_data); + printf("entries length : %lu 0x%lx\n", + (unsigned long)b->ib_b_entrylength, + (unsigned long)b->ib_b_entrylength); + printf("entry count : %lu 0x%lx\n", + (unsigned long)b->ib_entry_count, + (unsigned long)b->ib_entry_count); + printf("entries array : 0x%lx\n", + (unsigned long)b->ib_entryarray); + fflush(stdout); +} +#endif /*0*/ +/* We could use dwarf_get_real_section_name() + to determine the real name (perhaps ending in .dwo) + but for now we just use the standard name here. */ +static void +get_pubxx_fields(Dwarf_Debug dbg, + Dwarf_Bool for_gnu_pubnames, + struct Dwarf_Section_s **sec_out, + const char **sec_name_out, + int *errnum_out, + const char **errstr_out) +{ + if (!dbg) { + return; + } + if (for_gnu_pubnames) { + if (sec_name_out) { + *sec_name_out = ".debug_gnu_pubnames"; + } + if (sec_out) { + *sec_out = &dbg->de_debug_gnu_pubnames; + } + if (errnum_out) { + *errnum_out = DW_DLE_GNU_PUBNAMES_ERROR; + } + + if (errstr_out) { + *errstr_out = "DW_DLE_GNU_PUBNAMES_ERROR"; + } + } else { + if (sec_name_out) { + *sec_name_out = ".debug_gnu_pubtypes"; + } + if (sec_out) { + *sec_out = &dbg->de_debug_gnu_pubtypes; + } + if (errnum_out) { + *errnum_out = DW_DLE_GNU_PUBTYPES_ERROR; + } + if (errstr_out) { + *errstr_out = "DW_DLE_GNU_PUBTYPES_ERROR"; + } + } +} +static void +build_errm_no_v(Dwarf_Debug dbg, + Dwarf_Bool is_for_pubnames, + const char * str1, + Dwarf_Error *error) +{ + const char *errstr = 0; + int errnum = 0; + const char *secname = 0; + dwarfstring m; + + get_pubxx_fields(dbg,is_for_pubnames, + 0,&secname,&errnum, &errstr); + dwarfstring_constructor(&m); + dwarfstring_append(&m,(char *)errstr); + dwarfstring_append(&m," "); + dwarfstring_append(&m,(char *)str1); + dwarfstring_append_printf_s(&m," for section %s", + (char*)secname); + _dwarf_error_string(dbg,error,errnum, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return; +} + +static void +build_errm_one_num(Dwarf_Debug dbg, + Dwarf_Bool is_for_pubnames, + const char * str1, + Dwarf_Unsigned val1, + Dwarf_Error *error) +{ + const char *errstr = 0; + int errnum = 0; + const char *secname = 0; + dwarfstring m; + + /* Something is very wrong */ + get_pubxx_fields(dbg,is_for_pubnames, + 0,&secname,&errnum, &errstr); + dwarfstring_constructor(&m); + dwarfstring_append(&m,(char *)errstr); + dwarfstring_append(&m," "); + dwarfstring_append_printf_u(&m,(char *)str1,val1); + dwarfstring_append_printf_s(&m," for section %s", + (char*)secname); + _dwarf_error_string(dbg,error,errnum, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return; +} + +static int +load_pub_section(Dwarf_Debug dbg, + Dwarf_Bool for_gnu_pubnames, + Dwarf_Error *error) +{ + struct Dwarf_Section_s * sec = 0; + int res; + + get_pubxx_fields(dbg,for_gnu_pubnames,&sec,0,0,0); + if (sec) { + res = _dwarf_load_section(dbg,sec,error); + return res; + } + return DW_DLV_NO_ENTRY; +} + +static int +scan_block_entries(Dwarf_Debug dbg, + Dwarf_Bool for_gnu_pubnames, + Dwarf_Unsigned *count_out, + Dwarf_Error *error) +{ + struct Dwarf_Section_s *sec = 0; + Dwarf_Small *startptr = 0; + Dwarf_Small *curptr = 0; + Dwarf_Small *endptr = 0; + Dwarf_Unsigned seclen = 0; + Dwarf_Unsigned count = 0; + Dwarf_Unsigned filesize = 0; + int errnum = 0; + Dwarf_Unsigned totalframessize = 0; + const char * errstr = 0; + const char * secname = 0; + + get_pubxx_fields(dbg,for_gnu_pubnames,&sec,&secname, + &errnum,&errstr); + filesize = dbg->de_filesize; + startptr = sec->dss_data; + curptr = startptr; + seclen = sec->dss_size; + endptr = startptr + seclen; + if (filesize) { + if (seclen >= filesize) { + build_errm_one_num(dbg,for_gnu_pubnames, + ": section length %u" + " is larger than the file size in", + seclen,error); + return DW_DLV_ERROR; + } + } + for (;;) { + Dwarf_Unsigned length = 0; + unsigned int offsetsize = 0; + unsigned int extensize = 0; + + if (curptr == endptr) { + *count_out = count; + return DW_DLV_OK; + } + /* Not sure how the coders think about + the initial value. But the last + 4 bytes are zero, ignore those. + Unclear 64bit is not allowed. */ + READ_AREA_LENGTH_CK(dbg,length,Dwarf_Unsigned, + curptr,offsetsize,extensize,error,seclen,endptr); + totalframessize += length +offsetsize+extensize; + if (length > seclen || totalframessize > seclen) { + build_errm_one_num(dbg,for_gnu_pubnames, + "Sum of frame fde/cies sizes 0x%" DW_PR_DUx + " exceeds section size",totalframessize,error); + return DW_DLV_ERROR; + } + + ++count; + curptr += length -offsetsize - extensize; + curptr += 4; + } + /* NOTREACHED */ + *count_out = count; + return DW_DLV_OK; +} + +static int +_dwarf_count_entries_in_block(struct Dwarf_Gnu_IBlock_s * gib, + struct DGI_Entry_s* entries, + Dwarf_Bool for_gnu_pubnames, + Dwarf_Error* error) +{ + Dwarf_Small *curptr = gib->ib_b_data; + Dwarf_Small *endptr = curptr + gib->ib_b_entrylength; + Dwarf_Unsigned entrycount = 0; + Dwarf_Half offsetsize = gib->ib_offset_size; + struct DGI_Entry_s *curentry = 0; + Dwarf_Debug dbg = 0; + Dwarf_Gnu_Index_Head head = 0; + Dwarf_Bool for_pubnames = 0; + char *strptr = 0; + + head = gib->ib_head; + for_pubnames = head->gi_is_pubnames; + dbg = head->gi_dbg; + for ( ; curptr < endptr; ++entrycount) { + Dwarf_Unsigned infooffset = 0; + Dwarf_Unsigned offset = 0; + char flagbyte = 0; + + if ((curptr+offsetsize) == endptr) { + break; + } + if ((curptr+offsetsize) > endptr) { + build_errm_one_num(dbg,for_gnu_pubnames, + " Reading an address runs off the end of " + "this entry at entry %" DW_PR_DUu, + entrycount,error); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,offset, + Dwarf_Unsigned,curptr, + offsetsize,error,endptr); + infooffset = offset; + curptr += offsetsize; + if (entries) { + curentry = entries +entrycount; + curentry->ge_debug_info_offset = infooffset; + } + /* Ensure flag and start-of-string possible. */ + if ((curptr+2) >= endptr) { + build_errm_one_num(dbg,for_gnu_pubnames, + "Past end of current block reading strings" + " Reading an address runs off the end of " + "this entry at entry %" DW_PR_DUu, + entrycount,error); + return DW_DLV_ERROR; + } + flagbyte = *curptr; + curptr += 1; + strptr = (char *)curptr; + if (curentry) { + curentry->ge_flag_byte = flagbyte; + curentry->ge_string = (char *)strptr; + } + for ( ; curptr && curptr < endptr ;++curptr,++offset ) { + if (! *curptr ) { + /* end of string */ + break; + } + if (curptr > endptr) { + build_errm_no_v(dbg,for_gnu_pubnames, + "Past end of current block reading strings", + error); + return DW_DLV_ERROR; + } + } + /* string-terminating null byte */ + curptr += 1; + } + if (!entries) { + gib->ib_entry_count = entrycount; + } else if (gib->ib_entry_count != entrycount) { + int err = 0; + const char *errstr = 0; + const char *secname = 0; + char buf[120]; + dwarfstring m; + + buf[0] = 0; + get_pubxx_fields(dbg,for_pubnames,0,&secname, + &err,&errstr); + dwarfstring_constructor_static(&m,buf,sizeof(buf)); + dwarfstring_append(&m,(char *)errstr); + dwarfstring_append_printf_s(&m,":mismatch counts " + "creating %s" + "block_entries.", + (char *)secname); + dwarfstring_append_printf_u(&m," Origcount %u", + gib->ib_entry_count); + dwarfstring_append_printf_u(&m," new count %u", + entrycount); + _dwarf_error_string(dbg,error,err, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} + +static int +fill_in_blocks(Dwarf_Gnu_Index_Head head, + Dwarf_Error *error) +{ + Dwarf_Unsigned i = 0; + Dwarf_Unsigned dataoffset = 0; + Dwarf_Small * endptr = 0; + Dwarf_Small * curptr = 0; + Dwarf_Small * baseptr = 0; + Dwarf_Bool is_for_pubnames = head->gi_is_pubnames; + Dwarf_Debug dbg = head->gi_dbg; + Dwarf_Unsigned seclen = head->gi_section_length; + + baseptr = head->gi_section_data; + endptr = baseptr + head->gi_section_length; + for ( ;i < head->gi_blockcount; ++i) { + Dwarf_Unsigned length = 0; + unsigned int offsetsize = 0; + unsigned int extensize = 0; + Dwarf_Half version = 0; + Dwarf_Unsigned offset_into_debug_info = 0; + Dwarf_Unsigned length_of_CU_in_debug_info = 0; + struct Dwarf_Gnu_IBlock_s *gib = 0; + int res = 0; + + gib = head->gi_blockarray+i; + /* gib is a blank slate ready to be filled */ + curptr = baseptr+ dataoffset; + READ_AREA_LENGTH_CK(dbg,length,Dwarf_Unsigned, + curptr,offsetsize,extensize,error,seclen,endptr); + if (!length) { + /* Must be end of the section */ + if (curptr != endptr) { + build_errm_no_v(dbg,is_for_pubnames, + ": encountered zero area length " + "before the section end.", + error); + return DW_DLV_ERROR; + } + return DW_DLV_OK; + } + if (length > head->gi_section_length || + (length+offsetsize+extensize) > + head->gi_section_length) { + build_errm_one_num(dbg,is_for_pubnames, + ": block" + " length %" DW_PR_DUu " is too big", + length,error); + return DW_DLV_ERROR; + } + /* offsetsize will be set to a constant + of either 4 or 8 by READ_AREA_LENGTH_CK. + So any check for a usable offsetsize + here is dead code. + see dwarf_util.h */ + gib->ib_index = i; + gib->ib_head = head; + gib->ib_offset_size = offsetsize; + gib->ib_block_length = length; + gib->ib_block_length_offset = dataoffset; + dataoffset += offsetsize + extensize; + /* Now past length field. */ + gib->ib_b_data_offset = dataoffset; + if ((dataoffset + length) > head->gi_section_length){ + build_errm_one_num(dbg,is_for_pubnames, + " header length is %u which runs past the " + "end of section suggesting corrupt data", + length,error); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,version,Dwarf_Half,curptr, + DWARF_HALF_SIZE,error,endptr); + if (version != 2) { + build_errm_one_num(dbg,is_for_pubnames, + " version is %u, not 2," + " which suggests corrupt data",version,error); + return DW_DLV_ERROR; + } + curptr += DWARF_HALF_SIZE; + dataoffset += DWARF_HALF_SIZE; + gib->ib_version = version; + READ_UNALIGNED_CK(dbg,offset_into_debug_info, + Dwarf_Unsigned,curptr, + offsetsize,error,endptr); + curptr += offsetsize; + dataoffset += offsetsize; + gib->ib_offset_in_debug_info = offset_into_debug_info; + READ_UNALIGNED_CK(dbg,length_of_CU_in_debug_info, + Dwarf_Unsigned,curptr, + offsetsize,error,endptr); + gib->ib_size_in_debug_info = length_of_CU_in_debug_info; + dataoffset += offsetsize; + curptr += offsetsize; + gib->ib_b_data = curptr; + gib->ib_b_offset = dataoffset; + gib->ib_b_entrylength = length - (2 + + (2*offsetsize)) -4; + if ((gib->ib_b_data +gib->ib_b_entrylength) + > endptr) { + build_errm_one_num(dbg,is_for_pubnames, + " length is %u which runs past the " + "end of section suggesting corrupt data", + length,error); + return DW_DLV_ERROR; + } + res = _dwarf_count_entries_in_block(gib,0,is_for_pubnames, + error); + if (res != DW_DLV_OK) { + return res; + } + /* Set for next block., add in 4 for ending zeros */ + dataoffset = gib->ib_block_length_offset + length + 4; + } + return DW_DLV_OK; +} + +static int +fill_in_entries(Dwarf_Gnu_Index_Head head, + struct Dwarf_Gnu_IBlock_s *gib, + Dwarf_Error *error) +{ + Dwarf_Unsigned count = gib->ib_entry_count; + struct DGI_Entry_s * entryarray = 0; + Dwarf_Bool for_gnu_pubnames = head->gi_is_pubnames; + int res = 0; + Dwarf_Debug dbg = 0; + + dbg = head->gi_dbg; + entryarray = (struct DGI_Entry_s*)calloc(count, + sizeof(struct DGI_Entry_s)); + if (!entryarray) { + build_errm_no_v(dbg,for_gnu_pubnames, + ": Unable to allocate " + "block_entries. Out of memory creating record.", + error); + return DW_DLV_ERROR; + } + res = _dwarf_count_entries_in_block(gib, + entryarray,for_gnu_pubnames,error); + if (res != DW_DLV_OK) { + free(entryarray); + return res; + } + gib->ib_entryarray = entryarray; + entryarray = 0; + return DW_DLV_OK; +} + +int +dwarf_get_gnu_index_head(Dwarf_Debug dbg, + /* The following arg false to select gnu_pubtypes */ + Dwarf_Bool for_gnu_pubnames , + Dwarf_Gnu_Index_Head * index_head_out, + Dwarf_Unsigned * index_block_count_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned count = 0; + Dwarf_Gnu_Index_Head head = 0; + struct Dwarf_Gnu_IBlock_s *iblock_array = 0; + int res = 0; + + if (!dbg) { + _dwarf_error_string(dbg,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: in " + "dwarf_get_gnu_index_head"); + return DW_DLV_ERROR; + } + res = load_pub_section(dbg,for_gnu_pubnames,error); + if (res != DW_DLV_OK) { + return res; + } + /* We want this loaded for error checking by callers + in case they had no reason to load already. */ + res = _dwarf_load_debug_info(dbg,error); + if (res == DW_DLV_ERROR) { + return res; + } + /* if count zero, returns DW_DLV_NO_ENTRY */ + res = scan_block_entries(dbg,for_gnu_pubnames,&count,error); + if (res != DW_DLV_OK) { + return res; + } + head = (Dwarf_Gnu_Index_Head) + _dwarf_get_alloc(dbg,DW_DLA_GNU_INDEX_HEAD,1); + if (!head) { + build_errm_no_v(dbg,for_gnu_pubnames, + " Unable to allocate " + "a header record. Out of memory creating record.", + error); + return DW_DLV_ERROR; + } + head->gi_dbg = dbg; + head->gi_section_data = for_gnu_pubnames? + dbg->de_debug_gnu_pubnames.dss_data: + dbg->de_debug_gnu_pubtypes.dss_data; + head->gi_section_length = for_gnu_pubnames? + dbg->de_debug_gnu_pubnames.dss_size: + dbg->de_debug_gnu_pubtypes.dss_size; + head->gi_section_end = head->gi_section_data + + head->gi_section_length; + head->gi_is_pubnames = for_gnu_pubnames; + iblock_array = calloc(count, + sizeof(struct Dwarf_Gnu_IBlock_s)); + if (!iblock_array) { + build_errm_one_num(dbg,for_gnu_pubnames, + "Unable to allocate " + " %u block records. Out of memory.", + count,error); + dwarf_gnu_index_dealloc(head); + head = 0; + return DW_DLV_ERROR; + } + head->gi_blockarray = iblock_array; + head->gi_blockcount = count; + res = fill_in_blocks(head,error); + if (res != DW_DLV_OK) { + dwarf_gnu_index_dealloc(head); + head = 0; + return res; + } + *index_head_out = head; + *index_block_count_out = count; + return DW_DLV_OK; +} + +/* Frees all resources used for the indexes. */ +void +_dwarf_free_gnu_index_head_content(Dwarf_Gnu_Index_Head head) +{ + if (!head) { + return; + } + if (head->gi_blockarray) { + Dwarf_Unsigned i = 0; + struct Dwarf_Gnu_IBlock_s *block = + head->gi_blockarray; + + for ( ; i < head->gi_blockcount; ++i,block++) { + if (block->ib_entryarray) { + free(block->ib_entryarray); + block->ib_entryarray = 0; + } + block->ib_entry_count = 0; + } + free(head->gi_blockarray); + head->gi_blockarray = 0; + head->gi_blockcount = 0; + } +} + +void +dwarf_gnu_index_dealloc(Dwarf_Gnu_Index_Head head) +{ + Dwarf_Debug dbg; + if (!head) { + return; + } + dbg = head->gi_dbg; + if (!dbg) { + return; + } + _dwarf_free_gnu_index_head_content(head); + dwarf_dealloc(dbg,head,DW_DLA_GNU_INDEX_HEAD); +} + +void +_dwarf_gnu_index_head_destructor(void *incoming) +{ + Dwarf_Gnu_Index_Head head = 0; + + head = (Dwarf_Gnu_Index_Head)incoming; + if (!head) { + return; + } + _dwarf_free_gnu_index_head_content(head); + return; +} + +int +dwarf_get_gnu_index_block(Dwarf_Gnu_Index_Head head, + Dwarf_Unsigned number, + Dwarf_Unsigned * block_length, + Dwarf_Half * version, + Dwarf_Unsigned * offset_into_debug_info, + Dwarf_Unsigned * size_of_debug_info_area, + Dwarf_Unsigned * count_of_entries, + Dwarf_Error * error) +{ + struct Dwarf_Gnu_IBlock_s *gib = 0; + + if (!head) { + _dwarf_error_string(0,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: in " + "dwarf_get_gnu_index_block"); + return DW_DLV_ERROR; + } + if (number >= head->gi_blockcount) { + return DW_DLV_NO_ENTRY; + } + gib = head->gi_blockarray + number; + if (block_length) { + *block_length = gib->ib_block_length; + } + if (version) { + *version = gib->ib_version; + } + if (offset_into_debug_info) { + *offset_into_debug_info = gib->ib_offset_in_debug_info; + } + if (size_of_debug_info_area) { + *size_of_debug_info_area = gib->ib_size_in_debug_info; + } + if (count_of_entries) { + *count_of_entries = gib->ib_entry_count; + } + return DW_DLV_OK; +} + +int +dwarf_get_gnu_index_block_entry(Dwarf_Gnu_Index_Head head, + Dwarf_Unsigned blocknumber, + Dwarf_Unsigned entrynumber, + Dwarf_Unsigned * offset_in_debug_info, + const char ** name_string, + unsigned char * flagbyte, + unsigned char * staticorglobal, + unsigned char * typeofentry, + Dwarf_Error * error) +{ + struct Dwarf_Gnu_IBlock_s *gib = 0; + struct DGI_Entry_s *be = 0; + + if (!head) { + _dwarf_error_string(0,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: in " + "dwarf_get_gnu_index_block_entry"); + return DW_DLV_ERROR; + } + if (blocknumber >= head->gi_blockcount) { + return DW_DLV_NO_ENTRY; + } + gib = head->gi_blockarray + blocknumber; + if (!gib->ib_counted_entries) { + int res = 0; + + gib->ib_counted_entries = TRUE; + res = fill_in_entries(head,gib,error); + if (res != DW_DLV_OK) { + return res; + } + } + if (entrynumber >= gib->ib_entry_count) { + return DW_DLV_NO_ENTRY; + } + be = gib->ib_entryarray + entrynumber; + + if (offset_in_debug_info) { + *offset_in_debug_info = be->ge_debug_info_offset; + } + if (name_string) { + *name_string = be->ge_string; + } + if (flagbyte) { + *flagbyte = be->ge_flag_byte; + } + if (staticorglobal) { + if (be->ge_flag_byte &0x80) { + /* value 1, of course... */ + *staticorglobal = DW_GNUIVIS_global; + } else { + *staticorglobal = DW_GNUIVIS_static; + } + } + if (typeofentry) { + /* DW_GNUIKIND_ */ + unsigned v = be->ge_flag_byte & 0x70; + v = v>>4; + *typeofentry = v; + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_gnu_index.h b/src/lib/libdwarf/dwarf_gnu_index.h new file mode 100644 index 0000000..348a5e2 --- /dev/null +++ b/src/lib/libdwarf/dwarf_gnu_index.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2020-2023 David Anderson. All Rights Reserved. + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* This is for accessing .debug_gnu_pubnames + and .debug_gnu_pubtypes. + It has nothing to do with .gdb_index. */ + +struct DGI_Entry_s { + char * ge_string; + Dwarf_Unsigned ge_debug_info_offset; + char ge_flag_byte; +#if 0 + /* Following is DW_GNUIVIS bit 7 of flag byte + shifted right 7. */ + char ge_flag_global_static; + /* Following is DW_GNUIKIND bits 4,5,6 of flag byte + shifted right 4. + Bits 0-3 are reserved and should de zero. */ + char ge_flag_type; +#endif +}; +/* + each block data on disk looks like: + LENGTH (which determines offset size) + version + offset into .debug_info (offsetsize) + size of area in .debug_info (offsetsize) + For each entry + offset in debug_info of DIE (offsetsize) + 1 byte flag + strlen+1 string + Trailing LENGTH 4 bytes zero. +*/ +struct Dwarf_Gnu_IBlock_s { + Dwarf_Gnu_Index_Head ib_head; + Dwarf_Unsigned ib_index; /*of this ib */ + Dwarf_Unsigned ib_block_length_offset; + Dwarf_Unsigned ib_block_length; + Dwarf_Half ib_offset_size; /* 4 or 8 */ + Dwarf_Half ib_extension_size; /* 0 or 4 */ + Dwarf_Half ib_version; + Dwarf_Bool ib_counted_entries; /* see ib_entry_count*/ + Dwarf_Unsigned ib_offset_in_debug_info; + Dwarf_Unsigned ib_size_in_debug_info; + + /* following the length field*/ + Dwarf_Unsigned ib_b_data_offset; + + Dwarf_Unsigned ib_b_offset; /* offset of entry area */ + Dwarf_Small * ib_b_data; /* the entry area */ + /* entrylength = LENGTH - 2 - 2*offsetsize */ + Dwarf_Unsigned ib_b_entrylength; + + Dwarf_Unsigned ib_entry_count; + struct DGI_Entry_s *ib_entryarray; +}; + +struct Dwarf_Gnu_Index_Head_s { + Dwarf_Debug gi_dbg; + Dwarf_Small * gi_section_data; + Dwarf_Unsigned gi_section_length; + Dwarf_Small * gi_section_end; + struct Dwarf_Gnu_IBlock_s *gi_blockarray; + Dwarf_Unsigned gi_blockcount; + Dwarf_Bool gi_is_pubnames; /* if false is pubtypes */ +}; +void _dwarf_gnu_index_head_destructor(void *incoming); +void _dwarf_free_gnu_index_head_content(Dwarf_Gnu_Index_Head); diff --git a/src/lib/libdwarf/dwarf_groups.c b/src/lib/libdwarf/dwarf_groups.c new file mode 100644 index 0000000..ff2737c --- /dev/null +++ b/src/lib/libdwarf/dwarf_groups.c @@ -0,0 +1,396 @@ +/* + Copyright (C) 2017-2018 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ +#include /* strcmp() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" +#include "dwarf_tsearch.h" + +#define HASHSEARCH + +/* It has not escaped our attention that the section-group + tsearch hash table could + be replaced by a simple array with space for each possible + section number, each element being the group number. + This would be much simpler than what follows here. */ + +/* Each section number can appear in at most one record in the hash + because each section belongs in only one group. + Each group number appears as often as appropriate. */ + +struct Dwarf_Group_Map_Entry_s { + unsigned gm_key; /* section number */ + unsigned gm_group_number; /* What group number is. */ + + /* The name is from static storage or from elf, + so there is nothing to free on record delete. */ + const char * gm_section_name; +}; + +static void * +grp_make_entry(unsigned section, unsigned group,const char *name) +{ + struct Dwarf_Group_Map_Entry_s *e = 0; + e = calloc(1,sizeof(struct Dwarf_Group_Map_Entry_s)); + if (e) { + e->gm_key = section; + e->gm_group_number = group; + e->gm_section_name = name; + } + return e; +} + +static DW_TSHASHTYPE +grp_data_hashfunc(const void *keyp) +{ + const struct Dwarf_Group_Map_Entry_s * enp = keyp; + DW_TSHASHTYPE hashv = 0; + + hashv = enp->gm_key; + return hashv; +} + +static int +grp_compare_function(const void *l, const void *r) +{ + const struct Dwarf_Group_Map_Entry_s * lp = l; + const struct Dwarf_Group_Map_Entry_s * rp = r; + + if (lp->gm_key < rp->gm_key) { + return -1; + } + if (lp->gm_key > rp->gm_key) { + return 1; + } + + /* match. */ + return 0; +} + +int +_dwarf_insert_in_group_map(Dwarf_Debug dbg, + unsigned groupnum, + unsigned section_index, + const char *name, + Dwarf_Error * error) +{ + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + void *entry2 = 0; + struct Dwarf_Group_Map_Entry_s * entry3 = 0; + + if (!grp->gd_map) { + /* Number of sections is a kind of decent guess + as to how much space would be useful. */ + dwarf_initialize_search_hash(&grp->gd_map, + grp_data_hashfunc,grp->gd_number_of_sections); + if (!grp->gd_map) { + /* It's really an error I suppose. */ + return DW_DLV_NO_ENTRY; + } + } + entry3 = grp_make_entry(section_index,groupnum,name); + if (!entry3) { + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } + entry2 = dwarf_tsearch(entry3,&grp->gd_map,grp_compare_function); + if (!entry2) { + free(entry3); + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } else { + struct Dwarf_Group_Map_Entry_s *re = 0; + re = *(struct Dwarf_Group_Map_Entry_s **)entry2; + if (re != entry3) { + free(entry3); + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_DUPLICATE); + return DW_DLV_ERROR; + } else { + ++grp->gd_map_entry_count; + /* OK. Added. Fall thru */ + } + } + return DW_DLV_OK; +} + +int +_dwarf_section_get_target_group_from_map(Dwarf_Debug dbg, + unsigned obj_section_index, + unsigned * groupnumber_out, + Dwarf_Error * error) +{ + struct Dwarf_Group_Map_Entry_s entry; + struct Dwarf_Group_Map_Entry_s *entry2; + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + (void)error; + if (!grp->gd_map) { + return DW_DLV_NO_ENTRY; + } + entry.gm_key = obj_section_index; + entry.gm_group_number = 0; /* FAKE */ + entry.gm_section_name = ""; /* FAKE */ + + entry2 = dwarf_tfind(&entry, &grp->gd_map,grp_compare_function); + if (entry2) { + struct Dwarf_Group_Map_Entry_s *e2 = + *(struct Dwarf_Group_Map_Entry_s **)entry2;; + *groupnumber_out = e2->gm_group_number; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +/* New May 2017. So users can find out what groups (dwo or COMDAT) + are in the object and how much to allocate so one can get the + group-section map data. */ +int dwarf_sec_group_sizes(Dwarf_Debug dbg, + Dwarf_Unsigned * section_count_out, + Dwarf_Unsigned * group_count_out, + Dwarf_Unsigned * selected_group_out, + Dwarf_Unsigned * map_entry_count_out, + Dwarf_Error * error) +{ + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + (void)error; + *section_count_out = grp->gd_number_of_sections; + *group_count_out = grp->gd_number_of_groups; + *selected_group_out = dbg->de_groupnumber; + *map_entry_count_out = grp->gd_map_entry_count; + return DW_DLV_OK; +} + +static Dwarf_Unsigned map_reccount = 0; +static struct temp_map_struc_s { + Dwarf_Unsigned section; + Dwarf_Unsigned group; + const char *name; +} *temp_map_data; + +static void +grp_walk_map(const void *nodep, + const DW_VISIT which, + const int depth) +{ + struct Dwarf_Group_Map_Entry_s *re = 0; + + (void)depth; + re = *(struct Dwarf_Group_Map_Entry_s **)nodep; + if (which == dwarf_postorder || which == dwarf_endorder) { + return; + } + temp_map_data[map_reccount].group = re->gm_group_number; + temp_map_data[map_reccount].section = re->gm_key; + temp_map_data[map_reccount].name = re->gm_section_name; + map_reccount += 1; +} + +/* Looks better sorted by group then sec num. */ +static int +map_sort_compar(const void*l, const void*r) +{ + struct temp_map_struc_s *lv = (struct temp_map_struc_s *)l; + struct temp_map_struc_s *rv = (struct temp_map_struc_s *)r; + + if (lv->group < rv->group) { + return -1; + } + if (lv->group > rv->group) { + return 1; + } + if (lv->section < rv->section) { + return -1; + } + if (lv->section > rv->section) { + return 1; + } + /* Should never get here! */ + return 0; + +} + +/* New May 2017. Reveals the map between group numbers + and section numbers. + Caller must allocate the arrays with space for 'map_entry_count' + values and this function fills in the array entries. + Output ordered by group number and section number. + */ +int dwarf_sec_group_map(Dwarf_Debug dbg, + Dwarf_Unsigned map_entry_count, + Dwarf_Unsigned * group_numbers_array, + Dwarf_Unsigned * sec_numbers_array, + const char ** sec_names_array, + Dwarf_Error * error) +{ + Dwarf_Unsigned i = 0; + struct Dwarf_Group_Data_s *grp = 0; + + if (temp_map_data) { + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + map_reccount = 0; + grp = &dbg->de_groupnumbers; + if (map_entry_count < grp->gd_map_entry_count) { + _dwarf_error(dbg,error,DW_DLE_GROUP_COUNT_ERROR); + return DW_DLV_ERROR; + } + temp_map_data = calloc(map_entry_count, + sizeof(struct temp_map_struc_s)); + if (!temp_map_data) { + _dwarf_error(dbg,error,DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } + dwarf_twalk(grp->gd_map,grp_walk_map); + if (map_reccount != grp->gd_map_entry_count) { + /* Impossible. */ + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + + qsort(temp_map_data,map_reccount,sizeof(struct temp_map_struc_s), + map_sort_compar); + for (i =0 ; i < map_reccount; ++i) { + sec_numbers_array[i] = temp_map_data[i].section; + group_numbers_array[i] = temp_map_data[i].group; + sec_names_array[i] = temp_map_data[i].name; + } + free(temp_map_data); + map_reccount = 0; + temp_map_data = 0; + return DW_DLV_OK; +} + +static const char *dwo_secnames[] = { +".debug_info.dwo", +".debug_types.dwo", +".debug_abbrev.dwo", +".debug_line.dwo", +".debug_loc.dwo", +".debug_str.dwo", +".debug_loclists.dwo", +".debug_rnglists.dwo", +".debug_str_offsets.dwo", +".debug_macro.dwo", +".debug_cu_index", +".debug_tu_index", +0 }; + +/* Assumption: dwo sections are never in a COMDAT group + (groupnumber >2) + and by definition here are never group 1. + Assumption: the map of COMDAT groups (not necessarily all + sections, but at least all COMDAT) is complete. */ +int +_dwarf_dwo_groupnumber_given_name( + const char *name, + unsigned *grpnum_out) +{ + const char **s = 0; + + for (s = dwo_secnames; *s; s++) { + if (!strcmp(name,*s)) { + *grpnum_out = DW_GROUPNUMBER_DWO; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +static unsigned target_group = 0; +static int found_name_in_group = 0; +const char *lookfor_name = 0; + +static void +grp_walk_for_name(const void *nodep, + const DW_VISIT which, + const int depth) +{ + struct Dwarf_Group_Map_Entry_s *re = 0; + + (void)depth; + re = *(struct Dwarf_Group_Map_Entry_s **)nodep; + if (which == dwarf_postorder || which == dwarf_endorder) { + return; + } + if (re->gm_group_number == target_group) { + if (!strcmp(lookfor_name,re->gm_section_name)) { + found_name_in_group = TRUE; + } + } +} + +/* returns TRUE or FALSE */ +int +_dwarf_section_in_group_by_name(Dwarf_Debug dbg, + const char * scn_name, + unsigned groupnum) +{ + struct Dwarf_Group_Data_s *grp = 0; + + grp = &dbg->de_groupnumbers; + found_name_in_group = FALSE; + target_group = groupnum; + lookfor_name = scn_name; + dwarf_twalk(grp->gd_map,grp_walk_for_name); + return found_name_in_group; +} + +static void +_dwarf_grp_destroy_free_node(void*nodep) +{ + struct Dwarf_Group_Map_Entry_s * enp = nodep; + free(enp); + return; +} + +void +_dwarf_destroy_group_map(Dwarf_Debug dbg) +{ + dwarf_tdestroy(dbg->de_groupnumbers.gd_map, + _dwarf_grp_destroy_free_node); + dbg->de_groupnumbers.gd_map = 0; +} diff --git a/src/lib/libdwarf/dwarf_harmless.c b/src/lib/libdwarf/dwarf_harmless.c new file mode 100644 index 0000000..803e9a8 --- /dev/null +++ b/src/lib/libdwarf/dwarf_harmless.c @@ -0,0 +1,240 @@ +/* + Copyright (C) 2010-2022 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* This implements _dwarf_insert_harmless_error + and related helper functions for recording + compiler errors that need not make the input + unusable. + + Applications can use dwarf_get_harmless_error_list to + find (and possibly print) a warning about such errors. + + The initial error reported here is + DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a + bug in a specific compiler. + + It is a fixed length circular list to constrain + the space used for errors. + + The assumption is that these errors are exceedingly + rare, and indicate a broken compiler (the one that + produced the object getting the error(s)). + + dh_maxcount is recorded internally as 1 greater than + requested. Hiding the fact we always leave one + slot unused (at least). So a user request for + N slots really gives the user N usable slots. */ + +#include + +#include /* size_t */ +#include /* free() malloc() */ +#include /* memcpy() strcpy() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_frame.h" +#include "dwarf_harmless.h" + +/* Not user configurable. */ +#define DW_HARMLESS_ERROR_MSG_STRING_SIZE 300 + +/* The pointers returned here through errmsg_ptrs_array + become invalidated by any call to libdwarf. Any call. +*/ +int dwarf_get_harmless_error_list(Dwarf_Debug dbg, + unsigned count, + const char ** errmsg_ptrs_array, + unsigned * errs_count) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + if (!dhp->dh_errors) { + dhp->dh_errs_count = 0; + return DW_DLV_NO_ENTRY; + } + if (dhp->dh_errs_count == 0) { + return DW_DLV_NO_ENTRY; + } + if (errs_count) { + *errs_count = dhp->dh_errs_count; + } + if (count) { + /* NULL terminate the array of pointers */ + --count; + errmsg_ptrs_array[count] = 0; + + if (dhp->dh_next_to_use != dhp->dh_first) { + unsigned i = 0; + unsigned cur = dhp->dh_first; + for (i = 0; cur != dhp->dh_next_to_use; + ++i, cur = (cur +1) % dhp->dh_maxcount) { + if (i >= count ) { + /* All output spaces are used. */ + break; + } + errmsg_ptrs_array[i] = dhp->dh_errors[cur]; + } + errmsg_ptrs_array[i] = 0; + } + } + dhp->dh_next_to_use = 0; + dhp->dh_first = 0; + dhp->dh_errs_count = 0; + return DW_DLV_OK; +} + +/* Insertion made public is only for testing the harmless error code, + it is not necessarily useful for libdwarf client code aside + from code testing libdwarf. */ +void dwarf_insert_harmless_error(Dwarf_Debug dbg, + char *newerror) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + unsigned next = 0; + unsigned cur = dhp->dh_next_to_use; + char *msgspace; + if (!dhp->dh_errors) { + dhp->dh_errs_count++; + return; + } + msgspace = dhp->dh_errors[cur]; + _dwarf_safe_strcpy(msgspace, + DW_HARMLESS_ERROR_MSG_STRING_SIZE, + newerror, + strlen(newerror)); + next = (cur+1) % dhp->dh_maxcount; + dhp->dh_errs_count++; + dhp->dh_next_to_use = next; + if (dhp->dh_next_to_use == dhp->dh_first) { + /* Array is full set full invariant. */ + dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount; + } +} + +/* The size of the circular list of strings may be set + and reset as desired. Returns the previous size of + the list. If the list is shortened excess error entries + are simply dropped. + If the reallocation fails the list size is left unchanged. + Do not make this a long list! + + Remember the maxcount we record is 1 > the user count, + so we adjust it so it looks like the user count. +*/ +unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg, + unsigned maxcount ) +{ + struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors; + unsigned prevcount = dhp->dh_maxcount; + if (maxcount != 0) { + ++maxcount; + if (maxcount != dhp->dh_maxcount) { + /* Assign transfers 'ownership' of the malloc areas + to oldarray. */ + struct Dwarf_Harmless_s oldarray = *dhp; + /* Do not double increment the max, the init() func + increments it too. */ + _dwarf_harmless_init(dhp,maxcount-1); + if (oldarray.dh_next_to_use != oldarray.dh_first) { + unsigned i = 0; + for (i = oldarray.dh_first; + i != oldarray.dh_next_to_use; + i = (i+1)%oldarray.dh_maxcount) { + dwarf_insert_harmless_error(dbg, + oldarray.dh_errors[i]); + } + if (oldarray.dh_errs_count > dhp->dh_errs_count) { + dhp->dh_errs_count = oldarray.dh_errs_count; + } + } + _dwarf_harmless_cleanout(&oldarray); + } + } + return prevcount-1; +} + +/* Only callable from within libdwarf (as a practical matter) +*/ +void +_dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size) +{ + unsigned i = 0; + memset(dhp,0,sizeof(*dhp)); + dhp->dh_maxcount = size +1; + dhp->dh_errors = (char **)calloc(sizeof(char *), + dhp->dh_maxcount); + if (!dhp->dh_errors) { + dhp->dh_maxcount = 0; + return; + } + + for (i = 0; i < dhp->dh_maxcount; ++i) { + char *newstr = + (char *)calloc(1, + DW_HARMLESS_ERROR_MSG_STRING_SIZE); + dhp->dh_errors[i] = newstr; +#if 0 + /* BAD IDEA. just use the NULL pointer, + so we avoid problems later with + freeing. */ + if (!newstr) { + dhp->dh_maxcount = 0; + /* Let it leak, the leak is a constrained amount. */ + free(dhp->dh_errors); + dhp->dh_errors = 0; + return; + } +#endif /* 0 */ + dhp->dh_errors[i] = newstr; + } +} + +void +_dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp) +{ + unsigned i = 0; + if (!dhp->dh_errors) { + return; + } + for (i = 0; i < dhp->dh_maxcount; ++i) { + free(dhp->dh_errors[i]); + dhp->dh_errors[i] = 0; + } + free(dhp->dh_errors); + dhp->dh_errors = 0; + dhp->dh_maxcount = 0; +} diff --git a/src/lib/libdwarf/dwarf_harmless.h b/src/lib/libdwarf/dwarf_harmless.h new file mode 100644 index 0000000..a253758 --- /dev/null +++ b/src/lib/libdwarf/dwarf_harmless.h @@ -0,0 +1,31 @@ +/* + + Copyright (C) 2012-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +void _dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size); +void _dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp); diff --git a/src/lib/libdwarf/dwarf_init_finish.c b/src/lib/libdwarf/dwarf_init_finish.c new file mode 100644 index 0000000..86ea80a --- /dev/null +++ b/src/lib/libdwarf/dwarf_init_finish.c @@ -0,0 +1,1745 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2022 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ +#include /* memset() strcmp() strncmp() strlen() */ +#include /* debugging */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_harmless.h" +#include "dwarf_string.h" +#include "dwarf_secname_ck.h" +#include "dwarf_setup_sections.h" + +#ifdef HAVE_ZLIB_H +#include "zlib.h" +#endif +#ifdef HAVE_ZSTD_H +#include "zstd.h" +#endif + +#ifndef ELFCOMPRESS_ZLIB +#define ELFCOMPRESS_ZLIB 1 +#endif +#ifndef ELFCOMPRESS_ZSTD +#define ELFCOMPRESS_ZSTD 2 +#endif + +/* If your mingw elf.h is missing SHT_RELA and you do not + need SHT_RELA support + this define should work for you. + It is the elf value, hopefully it will + not cause trouble. If does not work, try -1 + or something else + and let us know what works. */ +#ifndef SHT_RELA +#define SHT_RELA 4 +#endif +#ifndef SHT_REL +#define SHT_REL 9 +# endif +/* For COMDAT GROUPS. Guarantees we can compile. We hope. */ +#ifndef SHT_GROUP +#define SHT_GROUP 17 +#endif + +#ifndef SHF_COMPRESSED +/* This from ubuntu xenial. Is in top of trunk binutils + as of February 2016. Elf Section Flag */ +#define SHF_COMPRESSED (1 << 11) +#endif + +/* This static is copied to the dbg on dbg init + so that the static need not be referenced at + run time, preserving better locality of + reference. + Value is 0 means do the string check. + Value non-zero means do not do the check. +*/ +static Dwarf_Small _dwarf_assume_string_in_bounds; +static Dwarf_Small _dwarf_apply_relocs = 1; + +/* Call this after calling dwarf_init but before doing anything else. + It applies to all objects, not just the current object. */ +int +dwarf_set_reloc_application(int apply) +{ + int oldval = _dwarf_apply_relocs; + _dwarf_apply_relocs = apply; + return oldval; +} + +int +dwarf_set_stringcheck(int newval) +{ + int oldval = _dwarf_assume_string_in_bounds; + + _dwarf_assume_string_in_bounds = newval; + return oldval; +} + +/* Unifies the basic duplicate/empty testing and section + data setting to one place. */ +static int +get_basic_section_data(Dwarf_Debug dbg, + struct Dwarf_Section_s *secdata, + struct Dwarf_Obj_Access_Section_a_s *doas, + Dwarf_Unsigned section_index, + unsigned group_number, + Dwarf_Error* error, + int duperr, int emptyerr ) +{ + /* There is an elf convention that section index 0 is reserved, + and that section is always empty. + Non-elf object formats must honor that by ensuring that + (when they assign numbers to 'sections' or + 'section-like-things') + they never assign a real section section-number + 0 to dss_index. */ + if (secdata->dss_index != 0) { + DWARF_DBG_ERROR(dbg, duperr, DW_DLV_ERROR); + } + if (doas->as_size == 0) { + /* As of 2018 it seems impossible to detect + (via dwarfdump) whether emptyerr has any + practical effect, whether TRUE or FALSE. */ + if (emptyerr == 0 ) { + /* Allow empty section. */ + return DW_DLV_OK; + } + /* Know no reason to allow section */ + DWARF_DBG_ERROR(dbg, emptyerr, DW_DLV_ERROR); + } + secdata->dss_index = section_index; + secdata->dss_size = doas->as_size; + secdata->dss_group_number = group_number; + secdata->dss_addr = doas->as_addr; + secdata->dss_link = doas->as_link; + secdata->dss_flags = doas->as_flags; + if (secdata->dss_flags & SHF_COMPRESSED) { + secdata->dss_shf_compressed = TRUE; + } + secdata->dss_entrysize = doas->as_entrysize; + secdata->dss_addralign = doas->as_addralign; + return DW_DLV_OK; +} + +static void +add_relx_data_to_secdata( struct Dwarf_Section_s *secdata, + struct Dwarf_Obj_Access_Section_a_s *doas, + Dwarf_Unsigned section_index, + int is_rela) +{ + secdata->dss_reloc_index = section_index; + secdata->dss_reloc_size = doas->as_size; + secdata->dss_reloc_entrysize = doas->as_entrysize; + secdata->dss_reloc_addr = doas->as_addr; + secdata->dss_reloc_symtab = doas->as_link; + secdata->dss_reloc_link = doas->as_link; + secdata->dss_is_rela = is_rela; +} + +#if 0 +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("dump_bytes: %s ",msg); + for (; cur < end; cur++) { + printf("%02x",*cur); + } + printf("\n"); +} + +static int +all_sig8_bits_zero(Dwarf_Sig8 *val) +{ + unsigned u = 0; + for ( ; u < sizeof(*val); ++u) { + if (val->signature[u] != 0) { + return FALSE; + } + } + return TRUE; +} +#endif /*0*/ + +static int +is_section_name_known_already(Dwarf_Debug dbg, const char *scn_name) +{ + unsigned i = 0; + for ( ; i < dbg->de_debug_sections_total_entries; ++i) { + struct Dwarf_dbg_sect_s *section = &dbg->de_debug_sections[i]; + if (!strcmp(scn_name, section->ds_name)) { + /* The caller will declare this a duplicate, an error. */ + return DW_DLV_OK; + } + } + /* This is normal, we expect we've not accepted + scn_name already. */ + return DW_DLV_NO_ENTRY; +} + +/* Given an Elf ptr, set up dbg with pointers + to all the Dwarf data sections. + Return NULL on error. + + This function is also responsible for determining + whether the given object contains Dwarf information + or not. The test currently used is that it contains + either a .debug_info or a .debug_frame section. If + not, it returns DW_DLV_NO_ENTRY causing dwarf_init() also to + return DW_DLV_NO_ENTRY. Earlier, we had thought of using only + the presence/absence of .debug_info to test, but we + added .debug_frame since there could be stripped objects + that have only a .debug_frame section for exception + processing. + DW_DLV_NO_ENTRY or DW_DLV_OK or DW_DLV_ERROR + + This does not allow for section-groups in object files, + for which many .debug_info (and other DWARF) sections may exist. + + We process. .rela (SHT_RELA) and .rel (SHT_REL) + sections because with .rela the referencing section + offset value is zero whereas with .rel the + referencing section value is already correct for + the object itself. In other words, we do it because + of the definition of .rela relocations in Elf. + + However! In some cases clang emits a .rel section (at least + for .rel.debug_info) where symtab entries have an st_value + that must be treated like an addend: the compiler did not + bother to backpatch the DWARF information for these. +*/ + +/* For an object file with an incorrect rela section name, + readelf prints correct debug information, + as the tool takes the section type instead + of the section name. So check the + section name but test section type. */ +static int +is_a_relx_section(const char *scn_name,int type,int *is_rela) +{ + if (_dwarf_startswith(scn_name,".rela.")) { + + *is_rela = TRUE; + return TRUE; + } + if (_dwarf_startswith(scn_name,".rel.")) { + *is_rela = FALSE; + return TRUE; + } + if (type == SHT_RELA) { + *is_rela = TRUE; + return TRUE; + } + if (type == SHT_REL) { + *is_rela = FALSE; + return TRUE; + } + *is_rela = FALSE; + return FALSE; +} + +/* ASSERT: names like .debug_ or .zdebug_ never passed in here! */ +static int +is_a_special_section_semi_dwarf(const char *scn_name) +{ + if (!strcmp(scn_name,".strtab") || + !strcmp(scn_name,".symtab")) { + return TRUE; + } + /* It's not one of these special sections referenced in + the test. */ + return FALSE; +} + +static int +this_section_dwarf_relevant(const char *scn_name, + int type, + int *is_rela) +{ + /* A small helper function for _dwarf_setup(). */ + if (_dwarf_startswith(scn_name, ".zdebug_") || + _dwarf_startswith(scn_name, ".debug_")) { + /* standard debug */ + return TRUE; + } + if (_dwarf_ignorethissection(scn_name)) { + return FALSE; + } + /* Now check if a special section could be + in a section_group, but though seems unlikely. */ + if (!strcmp(scn_name, ".eh_frame")) { + /* This is not really a group related file, but + it is harmless to consider it such. */ + return TRUE; + } + if (!strcmp(scn_name, ".gnu_debuglink")) { + /* This is not a group or DWARF related file, but + it is useful for split dwarf. */ + return TRUE; + } + if (!strcmp(scn_name, ".note.gnu.build-id")) { + /* This is not a group or DWARF related file, but + it is useful for split dwarf. */ + return TRUE; + } + if (!strcmp(scn_name, ".gdb_index")) { + return TRUE; + } + if (is_a_special_section_semi_dwarf(scn_name)) { + return TRUE; + } + if (is_a_relx_section(scn_name,type,is_rela)) { + return TRUE; + } + /* All sorts of sections are of no interest: .text + .rel. and many others. */ + return FALSE; +} + +/* This assumes any non-Elf object files have no SHT_GROUP + sections. So this code will not be invoked on non-Elf objects. + One supposes this is unlikely to match any non-Elf + version of COMDAT. */ +static int +insert_sht_list_in_group_map(Dwarf_Debug dbg, + struct Dwarf_Obj_Access_Section_a_s *doas, + unsigned comdat_group_number, + unsigned section_number, + Dwarf_Unsigned section_count, + struct Dwarf_Obj_Access_Interface_a_s * obj, + unsigned *did_add_map, + Dwarf_Error *error) +{ + struct Dwarf_Section_s secdata; + Dwarf_Small * data = 0; + int res = 0; + Dwarf_Small* secend = 0; + + memset(&secdata,0,sizeof(secdata)); + secdata.dss_size = doas->as_size; + secdata.dss_entrysize = doas->as_entrysize; + secdata.dss_group_number = 1; /* arbitrary. */ + secdata.dss_index = section_number; + secdata.dss_name = ".group"; + secdata.dss_standard_name = ".group"; + secdata.dss_number = section_number; + secdata.dss_ignore_reloc_group_sec = TRUE; + res = _dwarf_load_section(dbg,&secdata,error); + if (res != DW_DLV_OK) { + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + return res; + } + if (!secdata.dss_data) { + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + if (doas->as_entrysize != 4) { + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + /* So now pick up the data in dss_data. + It is an array of 32 bit fields. + Entry zero is just a constant 1. + Each additional is a section number. */ + data = secdata.dss_data; + secend = data + secdata.dss_size; + { + unsigned i = 1; + unsigned count = doas->as_size/doas->as_entrysize; + Dwarf_Unsigned fval = 0; + + /* The fields treatments with regard + to endianness is unclear. In any case a single + bit should be on, as 0x01000000 + without any endiannes swapping. + Or so it seems given limited evidence. + We read with length checking and allow the + reader to byte swap and then fix things. + At least one test case has big-endian + data but little-endian SHT_GROUP data. */ + if ((data+DWARF_32BIT_SIZE) > secend) { + /* Duplicates the check in READ_UNALIGNED_CK + so we can free allocated memory bere. */ + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,fval,Dwarf_Unsigned, + data, + DWARF_32BIT_SIZE, + error, + secend); + if (fval != 1 && fval != 0x1000000) { + /* Could be corrupted elf object. */ + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + + data = data + doas->as_entrysize; + for (i = 1 ; i < count ; ++i) { + Dwarf_Unsigned val = 0; + + if ((data+DWARF_32BIT_SIZE) > secend) { + /* Duplicates the check in READ_UNALIGNED_CK + so we can free allocated memory bere. */ + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,val,Dwarf_Unsigned, + data, + DWARF_32BIT_SIZE, + error, + secend); + if (val > section_count) { + /* Might be confused endianness by + the compiler generating the SHT_GROUP. + This is pretty horrible. */ + Dwarf_Unsigned valr = 0; + _dwarf_memcpy_swap_bytes(&valr,&val, + DWARF_32BIT_SIZE); + if (valr > section_count) { + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error, + DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + /* Ok. Yes, ugly. */ + val = valr; + } + { + /* Ensure this group entry DWARF relevant before + adding to group map */ + struct Dwarf_Obj_Access_Section_a_s doasx; + int resx = DW_DLV_ERROR; + int err = 0; + int is_rela = FALSE; + + memset(&doasx,0,sizeof(doasx)); + resx = obj->ai_methods-> + om_get_section_info(obj->ai_object, + val, + &doasx, &err); + if (resx == DW_DLV_NO_ENTRY){ + /* Should we really ignore this? */ + continue; + } + if (resx == DW_DLV_ERROR){ + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + _dwarf_error(dbg,error,err); + return resx; + } + if (!this_section_dwarf_relevant(doasx.as_name, + doasx.as_type,&is_rela) ) { + continue; + } + data += DWARF_32BIT_SIZE; + *did_add_map = TRUE; + res = _dwarf_insert_in_group_map(dbg, + comdat_group_number,val, + doasx.as_name, + error); + if (res != DW_DLV_OK) { + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + return res; + } + } + } + } + if (secdata.dss_data_was_malloc) { + free(secdata.dss_data); + secdata.dss_data = 0; + } + return DW_DLV_OK; +} + +/* Split dwarf CUs can be in an object with non-split + or split may be in a separate object. + If all in one object the default is to deal with group_number + and ignore DW_GROUPNUMBER_DWO. + If only .dwo the default is DW_GROUPNUMBER_DWO(2). + Otherwise use DW_GROUP_NUMBER_BASE(1). + + If there are COMDAT SHT_GROUP sections, these + are assigned group numbers 3-N as needed. + + At present this makes the assumption that COMDAT group + (ie, SHT_GROUP) sections + have lower section numbers than the sections COMDAT refers to. + It is not clear whether this is guaranteed, COMDAT is not + an official Elf thing and documentation is scarce. + In the 1990's SGI folks and others formed a committee + and attempted to get COMDAT and a feature allowing section + numbers greater than 16 bits into Elf, but there was no + group that was able to approve such things. + + This is called once at dbg init time. +*/ + +static int +determine_target_group(Dwarf_Unsigned section_count, + struct Dwarf_Obj_Access_Interface_a_s * obj, + unsigned *group_number_out, + Dwarf_Debug dbg, + Dwarf_Error *error) +{ + unsigned obj_section_index = 0; + int found_group_one = 0; + int found_group_two = 0; + struct Dwarf_Group_Data_s *grp = 0; + unsigned comdat_group_next = 3; + unsigned lowest_comdat_groupnum = 0; + + grp = &dbg->de_groupnumbers; + grp->gd_number_of_groups = 0; + grp->gd_number_of_sections = section_count; + if (grp->gd_map) { + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_OK; + } + for (obj_section_index = 0; obj_section_index < section_count; + ++obj_section_index) { + + struct Dwarf_Obj_Access_Section_a_s doas; + int res = DW_DLV_ERROR; + int err = 0; + const char *scn_name = 0; + unsigned groupnumber = 0; + unsigned mapgroupnumber = 0; + int is_rela = FALSE; + + memset(&doas,0,sizeof(doas)); + res = obj->ai_methods->om_get_section_info(obj->ai_object, + obj_section_index, + &doas, &err); + if (res == DW_DLV_NO_ENTRY){ + return res; + } + if (res == DW_DLV_ERROR){ + _dwarf_error(dbg, error,err); + return res; + } + + if (doas.as_type == SHT_GROUP) { + /* See assumptions in function comment above. */ + unsigned did_add_map = 0; + /* Add to our map. Here we + are assuming SHT_GROUP records come first. + Till proven wrong. */ + res = insert_sht_list_in_group_map(dbg,&doas, + comdat_group_next, + obj_section_index, + section_count, + obj, + &did_add_map,error); + if (res != DW_DLV_OK) { + return res; + } + if (!lowest_comdat_groupnum) { + lowest_comdat_groupnum = comdat_group_next; + } + if (did_add_map) { + ++grp->gd_number_of_groups; + ++comdat_group_next; + } + continue; + } + scn_name = doas.as_name; + if (!this_section_dwarf_relevant(scn_name,doas.as_type, + &is_rela) ) { + continue; + } + + /* Now at a 'normal' section, though we do not + quite know what group it is. */ + + res = _dwarf_section_get_target_group_from_map(dbg, + obj_section_index,&groupnumber,error); + if (res == DW_DLV_OK ) { + /* groupnumber is set. Fall through. + All COMDAT group should get here. */ + mapgroupnumber = groupnumber; + } else if (res == DW_DLV_ERROR) { + return res; + } else { /* DW_DLV_NO_ENTRY */ + /* Normal non-COMDAT. groupnumber is zero. */ + } + + /* BUILDING_MAP. See also BUILDING_SECTIONS, SETUP_SECTION */ + if (!groupnumber) { + res =_dwarf_dwo_groupnumber_given_name(scn_name, + &groupnumber); + /* DW_DLV_ERROR impossible here. */ + if (res == DW_DLV_OK) { + /* groupnumber set 2 */ + } else { + /* This is what it has to be. + .rela in here too. */ + groupnumber = DW_GROUPNUMBER_BASE; + } + } + if (is_a_relx_section(scn_name,doas.as_type,&is_rela)) { + continue; + } + + /* ASSERT: groupnumber non-zero now */ + if (!is_a_special_section_semi_dwarf(scn_name)) { + if (mapgroupnumber) { + /* Already in group map */ + continue; + } + /* !mapgroupnumber */ + res = _dwarf_insert_in_group_map(dbg, + groupnumber,obj_section_index, + scn_name, + error); + if (res != DW_DLV_OK) { + return res; + } + if (groupnumber == 1) { + found_group_one++; + } else if (groupnumber == 2) { + found_group_two++; + } else { /* fall through to continue */ } + continue; + } + } + if (found_group_two) { + ++grp->gd_number_of_groups; + } + if (found_group_one) { + *group_number_out = DW_GROUPNUMBER_BASE; + ++grp->gd_number_of_groups; + } else { + if (found_group_two) { + *group_number_out = DW_GROUPNUMBER_DWO; + } else { + if (lowest_comdat_groupnum) { + *group_number_out = lowest_comdat_groupnum; + } else { + *group_number_out = DW_GROUPNUMBER_BASE; + } + } + } + return DW_DLV_OK; +} + +static int +_dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error) +{ + const char *scn_name = 0; + struct Dwarf_Obj_Access_Interface_a_s * obj = 0; + int resn = 0; + struct Dwarf_Section_s **sections = 0; + Dwarf_Small endianness = 0; + Dwarf_Unsigned section_count = 0; + unsigned default_group_number = 0; + unsigned foundDwarf = FALSE; + Dwarf_Unsigned obj_section_index = 0; + + dbg->de_assume_string_in_bounds = + _dwarf_assume_string_in_bounds; + /* First make an arbitrary assumption. */ + dbg->de_same_endian = 1; + dbg->de_copy_word = _dwarf_memcpy_noswap_bytes; + obj = dbg->de_obj_file; + endianness = obj->ai_methods->om_get_byte_order(obj->ai_object); + /* Then adjust any changes we need. */ +#ifdef WORDS_BIGENDIAN + dbg->de_big_endian_object = 1; + if (endianness == DW_END_little) { + dbg->de_same_endian = 0; + dbg->de_big_endian_object = 0; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#else /* little endian */ + dbg->de_big_endian_object = 0; + if (endianness == DW_END_big ) { + dbg->de_same_endian = 0; + dbg->de_big_endian_object = 1; + dbg->de_copy_word = _dwarf_memcpy_swap_bytes; + } +#endif /* !WORDS_BIGENDIAN */ + + /* The following de_length_size is Not Too Significant. + Only used one calculation, and an approximate one + at that. */ + dbg->de_length_size = obj->ai_methods-> + om_get_length_size(obj->ai_object); + dbg->de_pointer_size = + obj->ai_methods->om_get_pointer_size(obj->ai_object); + section_count = obj->ai_methods-> + om_get_section_count(obj->ai_object); + resn = determine_target_group(section_count,obj, + &default_group_number,dbg,error); + if (resn == DW_DLV_ERROR) { + return DW_DLV_ERROR; + } + if (dbg->de_groupnumber == DW_GROUPNUMBER_ANY) { + dbg->de_groupnumber = default_group_number; + } + /* Allocate space to record references to debug sections + that can be referenced by RELA sections in + the 'sh_info' field. */ + sections = (struct Dwarf_Section_s **)calloc(section_count + 1, + sizeof(struct Dwarf_Section_s *)); + if (!sections) { + /* Impossible case, we hope. Give up. */ + _dwarf_error(dbg, error, DW_DLE_SECTION_ERROR); + return DW_DLV_ERROR; + } + + /* We can skip index 0 when considering ELF files, but not other + object types. Indeed regardless of the object type we should + skip section 0 here. + This is a convention. We depend on it. + Non-elf object access code should + (in itself) understand we will index beginning at 1 and adjust + itself to deal with this Elf convention. Without this + convention various parts of the code in this file won't + work correctly. + A dss_index of 0 must not be used, even though we start at 0 + here. So the get_section_info() must adapt to the situation + (the elf version does automatically as a result of Elf having + a section zero with zero length and an empty name). */ + + /* ASSERT: all group map entries set up. */ + + for (obj_section_index = 0; obj_section_index < section_count; + ++obj_section_index) { + + struct Dwarf_Obj_Access_Section_a_s doas; + int res = DW_DLV_ERROR; + int err = 0; + unsigned groupnumber = 0; + unsigned mapgroupnumber = 0; + int is_rela = FALSE; + + res = _dwarf_section_get_target_group_from_map(dbg, + obj_section_index, &groupnumber,error); + if (res == DW_DLV_OK ) { + /* groupnumber is set. Fall through */ + mapgroupnumber = groupnumber; + } else if (res == DW_DLV_ERROR) { + free(sections); + return res; + } else { /* DW_DLV_NO_ENTRY */ + /* fall through, a BASE or DWO group, possibly */ + } + memset(&doas,0,sizeof(doas)); + + res = obj->ai_methods->om_get_section_info(obj->ai_object, + obj_section_index, + &doas, &err); + if (res == DW_DLV_NO_ENTRY){ + free(sections); + return res; + } + if (res == DW_DLV_ERROR){ + free(sections); + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + scn_name = doas.as_name; + if (!groupnumber) { + /* This finds dwo sections, group 2 */ + res = _dwarf_dwo_groupnumber_given_name(scn_name, + &groupnumber); + if (res == DW_DLV_NO_ENTRY) { + /* No, must be group 1 */ + groupnumber = DW_GROUPNUMBER_BASE; + } + } + if (!this_section_dwarf_relevant(scn_name,doas.as_type, + &is_rela) ) { + continue; + } + if (!is_a_relx_section(scn_name,doas.as_type,&is_rela) + && !is_a_special_section_semi_dwarf(scn_name)) { + /* We do these actions only for group-related + sections. Do for .debug_info etc, + never for .strtab or .rela.* + We already tested for relevance, so that part + is not news. */ + if (mapgroupnumber == dbg->de_groupnumber) { + /* OK. Mapped. Part of the group.. This will + catch the cases where there are versions of + a section in multiple COMDATs and in BASE + an DWO to get the right one */ + } else { + /* This section not mapped into this group. */ + if (groupnumber == 1 && dbg->de_groupnumber > 2 && + !_dwarf_section_in_group_by_name(dbg,scn_name, + dbg->de_groupnumber)) { + /* Load the section (but as group 1) */ + } else { + continue; + } + } + } + /* BUILDING_SECTIONS. See also BUILDING_MAP, SETUP_SECTION */ + { + /* Build up the sections table and the + de_debug* etc pointers in Dwarf_Debug. */ + struct Dwarf_dbg_sect_s *section = 0; + int found_match = FALSE; + + res = is_section_name_known_already(dbg,scn_name); + if (res == DW_DLV_OK) { + /* DUPLICATE */ + free(sections); + DWARF_DBG_ERROR(dbg, DW_DLE_SECTION_DUPLICATION, + DW_DLV_ERROR); + } + if (res == DW_DLV_ERROR) { + free(sections); + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + /* No entry: new-to-us section, the normal case. */ + res = _dwarf_enter_section_in_de_debug_sections_array(dbg, + scn_name, obj_section_index, groupnumber,&err); + if (res == DW_DLV_OK) { + section = &dbg->de_debug_sections[ + dbg->de_debug_sections_total_entries-1]; + res = get_basic_section_data(dbg, + section->ds_secdata, &doas, + obj_section_index, + groupnumber, + error, + section->ds_duperr, + section->ds_emptyerr); + if (res != DW_DLV_OK) { + free(sections); + return res; + } + sections[obj_section_index] = section->ds_secdata; + foundDwarf += section->ds_have_dwarf; + found_match = TRUE; + /* Normal section set up. + Fall through. */ + } else if (res == DW_DLV_NO_ENTRY) { + /* We get here for relocation sections. + Fall through. */ + } else { + free(sections); + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + + if (!found_match) { + /* For an object file with incorrect rel[a] + section name, the 'readelf' tool, + prints correct debug information, + as the tool takes the section type instead + of the section name. If the current section + is a RELA one and the 'sh_info' + refers to a debug section, add the + relocation data. */ + if (is_a_relx_section(scn_name,doas.as_type, + &is_rela)) { + if ( doas.as_info < section_count) { + if (sections[doas.as_info]) { + add_relx_data_to_secdata( + sections[doas.as_info], + &doas, + obj_section_index,is_rela); + } + } else { + /* Something is wrong with the ELF file. */ + free(sections); + DWARF_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR, + DW_DLV_ERROR); + } + } + } + /* Fetch next section */ + } + } + + /* Free table with section information. */ + free(sections); + if (foundDwarf) { + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +/* There is one table per CU and one per TU, and each + table refers to the associated other DWARF data + for that CU or TU. + See DW_SECT_* + + In DWARF4 the type units are in .debug_types + In DWARF5 the type units are in .debug_info. +*/ + +static int +load_debugfission_tables(Dwarf_Debug dbg,Dwarf_Error *error) +{ + int i = 0; + if (dbg->de_debug_cu_index.dss_size ==0 && + dbg->de_debug_tu_index.dss_size ==0) { + /* This is the normal case. + No debug fission. Not a .dwp object. */ + return DW_DLV_NO_ENTRY; + } + + for (i = 0; i < 2; ++i) { + Dwarf_Xu_Index_Header xuptr = 0; + struct Dwarf_Section_s* dwsect = 0; + Dwarf_Unsigned version = 0; + Dwarf_Unsigned number_of_cols /* L */ = 0; + Dwarf_Unsigned number_of_CUs /* N */ = 0; + Dwarf_Unsigned number_of_slots /* M */ = 0; + const char *secname = 0; + int res = 0; + const char *type = 0; + + if (i == 0) { + dwsect = &dbg->de_debug_cu_index; + type = "cu"; + } else { + dwsect = &dbg->de_debug_tu_index; + type = "tu"; + } + if ( !dwsect->dss_size ) { + continue; + } + res = dwarf_get_xu_index_header(dbg,type, + &xuptr,&version,&number_of_cols, + &number_of_CUs,&number_of_slots, + &secname,error); + if (res == DW_DLV_NO_ENTRY) { + continue; + } + if (res != DW_DLV_OK) { + return res; + } + if (i == 0) { + dbg->de_cu_hashindex_data = xuptr; + } else { + dbg->de_tu_hashindex_data = xuptr; + } + } + return DW_DLV_OK; +} + +/* + Use a Dwarf_Obj_Access_Interface to kick things off. + All other init routines eventually use this one. + The returned Dwarf_Debug contains a copy of *obj + the callers copy of *obj may be freed whenever the caller + wishes. + + New March 2017. Enables dealing with DWARF5 split + dwarf more fully. */ +int +dwarf_object_init_b(Dwarf_Obj_Access_Interface_a* obj, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + unsigned groupnumber, + Dwarf_Debug* ret_dbg, + Dwarf_Error* error) +{ + Dwarf_Debug dbg = 0; + int setup_result = DW_DLV_OK; + Dwarf_Unsigned filesize = 0; + + if (!ret_dbg) { + DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL, + DW_DLV_ERROR); + } + /* Non-null *ret_dbg will cause problems dealing with + DW_DLV_ERROR */ + *ret_dbg = 0; + filesize = obj->ai_methods->om_get_filesize(obj->ai_object); + /* Initializes Dwarf_Debug struct and returns + a pointer to that empty record. + Filesize is to set up a sensible default hash tree + size. */ + dbg = _dwarf_get_debug(filesize); + if (!dbg) { + DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR); + } + dbg->de_errhand = errhand; + dbg->de_errarg = errarg; + dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE; + dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM; + dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL3; + dbg->de_frame_same_value_number = DW_FRAME_SAME_VAL; + dbg->de_frame_undefined_value_number = DW_FRAME_UNDEFINED_VAL; + + dbg->de_obj_file = obj; + dbg->de_filesize = filesize; + dbg->de_groupnumber = groupnumber; + setup_result = _dwarf_setup(dbg, error); + if (setup_result == DW_DLV_OK) { + int fission_result = load_debugfission_tables(dbg,error); + /* In most cases we get + setup_result == DW_DLV_NO_ENTRY here + as having debugfission (.dwp objects) + is fairly rare. */ + if (fission_result == DW_DLV_ERROR) { + /* Something is very wrong. */ + setup_result = fission_result; + } + if (setup_result == DW_DLV_OK) { + _dwarf_harmless_init(&dbg->de_harmless_errors, + DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE); + *ret_dbg = dbg; + /* This is the normal return. */ + return setup_result; + } + } + if (setup_result == DW_DLV_NO_ENTRY) { + _dwarf_free_all_of_one_debug(dbg); + dbg = 0; + /* ASSERT: _dwarf_free_all_of_one_debug() never returns + DW_DLV_ERROR */ + return setup_result; + } + /* An error of some sort. Report it as well as + possible. + ASSERT: setup_result == DW_DLV_ERROR + here */ + { + int myerr = 0; + dwarfstring msg; + + dwarfstring_constructor(&msg); + /* We cannot use any _dwarf_setup() + error here as + we are freeing dbg, making that error (setup + as part of dbg) stale. + Hence we have to make a new error without a dbg. + But error might be NULL and the init call + error-handler function might be set. + */ + if (error && *error) { + /* Preserve our _dwarf_setup error number, but + this does not apply if error NULL. */ + /* *error safe */ + myerr = dwarf_errno(*error); + /* *error safe */ + dwarfstring_append(&msg,dwarf_errmsg(*error)); + /* deallocate the soon-stale error pointer. */ + dwarf_dealloc(dbg,*error,DW_DLA_ERROR); + /* *error safe */ + *error = 0; + } + /* The status we want to return here is of _dwarf_setup, + not of the _dwarf_free_all_of_one_debug(dbg) call. + So use a local status variable for the free. */ + _dwarf_free_all_of_one_debug(dbg); + dbg = 0; + if (myerr) { + /* Use the _dwarf_setup error number. + If error is NULL the following will issue + a message on stderr, as without + dbg there is no error-handler function. + */ + _dwarf_error_string(dbg,error,myerr, + dwarfstring_string(&msg)); + dwarfstring_destructor(&msg); + } /* else return quietly, a serious error + was already reported. */ + } + return setup_result; +} + +/* A finish routine that is completely unaware of ELF. + + Frees all memory that was not previously freed by + dwarf_dealloc. + NEVER returns DW_DLV_ERROR; + + Aside from certain categories. */ +int +dwarf_object_finish(Dwarf_Debug dbg) +{ + int res = 0; + + _dwarf_harmless_cleanout(&dbg->de_harmless_errors); + res = _dwarf_free_all_of_one_debug(dbg); + /* see dwarf_error.h dwarf_error.c Relevant + to trying and failing to open/read corrupt + object files. */ + return res; +} + +#if defined(HAVE_ZLIB) || defined(HAVE_ZSTD) +/* case 1: + The input stream is assumed to contain + the four letters + ZLIB + Followed by 8 bytes of the size of the + uncompressed stream. Presented as + a big-endian binary number. + Following that is the stream to decompress. + + case 2,3: + The section flag bit SHF_COMPRESSED (1 << 11) + must be set. + we then do the equivalent of reading a + Elf32_External_Chdr + or + Elf64_External_Chdr + to get the type (which must be 1 (zlib) or 2 (zstd)) + and the decompressed_length. + Then what follows the implicit Chdr is decompressed. + + */ + +/* ALLOWED_ZLIB_INFLATION is a heuristic, not necessarily right. + The test case klingler2/compresseddebug.amd64 actually + inflates about 8 times. */ +#define ALLOWED_ZLIB_INFLATION 16 +#define ALLOWED_ZSTD_INFLATION 16 +static int +do_decompress(Dwarf_Debug dbg, + struct Dwarf_Section_s *section, + Dwarf_Error * error) +{ + Dwarf_Small *basesrc = section->dss_data; + Dwarf_Small *src = basesrc; + Dwarf_Small *dest = 0; + Dwarf_Unsigned destlen = 0; + Dwarf_Unsigned srclen = section->dss_size; + Dwarf_Unsigned flags = section->dss_flags; + Dwarf_Small *endsection = 0; + int zstdcompress = FALSE; + Dwarf_Unsigned uncompressed_len = 0; + + endsection = basesrc + section->dss_size; + if ((basesrc + 12) > endsection) { + _dwarf_error_string(dbg, error,DW_DLE_ZLIB_SECTION_SHORT, + "DW_DLE_ZLIB_SECTION_SHORT" + "Section too short to be either zlib or zstd related"); + return DW_DLV_ERROR; + } + section->dss_compressed_length = srclen; + if (!strncmp("ZLIB",(const char *)src,4)) { + unsigned i = 0; + unsigned l = 8; + unsigned char *c = src+4; + for ( ; i < l; ++i,c++) { + uncompressed_len <<= 8; + uncompressed_len += *c; + } + src = src + 12; + srclen -= 12; + section->dss_uncompressed_length = uncompressed_len; + section->dss_ZLIB_compressed = TRUE; + } else if (flags & SHF_COMPRESSED) { + /* The prefix is a struct: + unsigned int type; followed by pad if following are 64bit! + size-of-target-address size + size-of-target-address + */ + Dwarf_Small *ptr = (Dwarf_Small *)src; + Dwarf_Unsigned type = 0; + Dwarf_Unsigned size = 0; + /* Dwarf_Unsigned addralign = 0; */ + unsigned fldsize = dbg->de_pointer_size; + unsigned structsize = 3* fldsize; + READ_UNALIGNED_CK(dbg,type,Dwarf_Unsigned,ptr, + DWARF_32BIT_SIZE, + error,endsection); + ptr += fldsize; + READ_UNALIGNED_CK(dbg,size,Dwarf_Unsigned,ptr,fldsize, + error,endsection); + switch(type) { + case ELFCOMPRESS_ZLIB: + break; + case ELFCOMPRESS_ZSTD: + zstdcompress = TRUE; + break; + default: { + char buf[100]; + dwarfstring m; + + dwarfstring_constructor_static(&m,buf,sizeof(buf)); + dwarfstring_append_printf_u(&m, + "DW_DLE_ZDEBUG_INPUT_FORMAT_ODD" + " The SHF_COMPRESSED type field is 0x%x, neither" + " zlib (1) or zstd(2). Corrupt dwarf.", type); + _dwarf_error_string(dbg, error, + DW_DLE_ZDEBUG_INPUT_FORMAT_ODD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + uncompressed_len = size; + section->dss_uncompressed_length = uncompressed_len; + src += structsize; + srclen -= structsize; + section->dss_shf_compressed = TRUE; + } else { + _dwarf_error_string(dbg, error, + DW_DLE_ZDEBUG_INPUT_FORMAT_ODD, + "DW_DLE_ZDEBUG_INPUT_FORMAT_ODD" + " The compressed section is not properly formatted"); + return DW_DLV_ERROR; + } +#ifdef HAVE_ZLIB + if (!zstdcompress) { + /* According to zlib.net zlib essentially never expands + the data when compressing. There is no statement + about any effective limit in the compression factor + though we, here, assume such a limit to check + for sanity in the object file. + These tests are heuristics. */ + Dwarf_Unsigned max_inflated_len = + srclen*ALLOWED_ZLIB_INFLATION; + + if (srclen > 50) { + /* If srclen not super tiny lets check the following. */ + if (uncompressed_len < (srclen/2)) { + /* Violates the approximate invariant about + compression not actually inflating. */ + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR" + " The zlib compressed section is" + "absurdly small. Corrupt dwarf"); + return DW_DLV_ERROR; + } + } + if (max_inflated_len < srclen) { + /* The calculation overflowed. */ + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR:" + " The zlib compressed section is" + " absurdly large so arithmentic overflow." + " So corrupt dwarf"); + return DW_DLV_ERROR; + } + if (uncompressed_len > max_inflated_len) { + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR" + " The zlib compressed section is" + " absurdly large given the input section" + " length. So corrupt dwarf"); + return DW_DLV_ERROR; + } + } +#else /* !HAVE_ZLIB */ + if (!zstdcompress) { + _dwarf_error_string(dbg, error, + DW_DLE_ZDEBUG_REQUIRES_ZLIB, + "DW_DLE_ZDEBUG_REQUIRES_ZLIB: " + " zlib is missing, cannot decomreess a zlib section"); + return DW_DLV_ERROR; + } +#endif /* HAVE_ZLIB */ +#ifdef HAVE_ZSTD + if (zstdcompress) { + /* According to zlib.net zlib essentially never expands + the data when compressing. There is no statement + about any effective limit in the compression factor + though we, here, assume such a limit to check + for sanity in the object file. + These tests are heuristics. */ + Dwarf_Unsigned max_inflated_len = + srclen*ALLOWED_ZSTD_INFLATION; + + if (srclen > 50) { + /* If srclen not super tiny lets check the following. */ + if (uncompressed_len < (srclen/2)) { + /* Violates the approximate invariant about + compression not actually inflating. */ + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR" + " The zstd compressed section is" + "absurdly small. Corrupt dwarf"); + return DW_DLV_ERROR; + } + } + if (max_inflated_len < srclen) { + /* The calculation overflowed. */ + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR" + " The zstd compressed section is" + " absurdly large so arithmentic overflow." + " So corrupt dwarf"); + return DW_DLV_ERROR; + } + if (uncompressed_len > max_inflated_len) { + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_UNCOMPRESS_ERROR, + "DW_DLE_ZLIB_UNCOMPRESS_ERROR" + " The zstd compressed section is" + " absurdly large given the input section" + " length. So corrupt dwarf"); + return DW_DLV_ERROR; + } + } +#else /* !HAVE_ZSTD */ + if (zstdcompress) { + _dwarf_error_string(dbg, error, + DW_DLE_ZDEBUG_REQUIRES_ZLIB, + "DW_DLE_ZDEBUG_REQUIRES_ZLIB: " + " zstd is missing, cannot decomreess a libzstd section"); + return DW_DLV_ERROR; + } +#endif /* HAVE_ZSTD */ + if ((src +srclen) > endsection) { + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_SECTION_SHORT, + "DW_DLE_ZDEBUG_ZLIB_SECTION_SHORT" + " The zstd or zlib compressed section is" + " longer than the section" + " length. So corrupt dwarf"); + return DW_DLV_ERROR; + } + destlen = uncompressed_len; + dest = malloc(destlen); + if (!dest) { + _dwarf_error_string(dbg, error, + DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL" + " The zstd or zlib uncompressed space" + " malloc failed: out of memory"); + return DW_DLV_ERROR; + } + /* uncompress is a zlib function. */ +#ifdef HAVE_ZLIB + if (!zstdcompress) { + int res = 0; + uLongf dlen = destlen; + + res = uncompress(dest,&dlen,src,srclen); + if (res == Z_BUF_ERROR) { + free(dest); + DWARF_DBG_ERROR(dbg, DW_DLE_ZLIB_BUF_ERROR, DW_DLV_ERROR); + } else if (res == Z_MEM_ERROR) { + free(dest); + DWARF_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_ERROR); + } else if (res != Z_OK) { + free(dest); + /* Probably Z_DATA_ERROR. */ + DWARF_DBG_ERROR(dbg, DW_DLE_ZLIB_DATA_ERROR, + DW_DLV_ERROR); + } + } +#endif /* HAVE_ZLIB */ +#ifdef HAVE_ZSTD + if (zstdcompress) { + size_t zsize = + ZSTD_decompress(dest,destlen,src,srclen); + if (zsize != destlen) { + free(dest); + _dwarf_error_string(dbg, error, + DW_DLE_ZLIB_DATA_ERROR, + "DW_DLE_ZLIB_DATA_ERROR" + " The zstd ZSTD_decompress() failed."); + return DW_DLV_ERROR; + } + } +#endif /* HAVE_ZSTD */ + /* Z_OK */ + section->dss_data = dest; + section->dss_size = destlen; + section->dss_data_was_malloc = TRUE; + section->dss_did_decompress = TRUE; + return DW_DLV_OK; +} +#endif /* HAVE_ZLIB || HAVE_ZSTD */ + +/* Load the ELF section with the specified index and set its + dss_data pointer to the memory where it was loaded. */ +int +_dwarf_load_section(Dwarf_Debug dbg, + struct Dwarf_Section_s *section, + Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + int err = 0; + struct Dwarf_Obj_Access_Interface_a_s *o = 0; + + /* check to see if the section is already loaded */ + if (section->dss_data != NULL) { + return DW_DLV_OK; + } + o = dbg->de_obj_file; + /* There is an elf convention that section index 0 + is reserved, and that section is always empty. + Non-elf object formats must honor + that by ensuring that (when they + assign numbers to 'sections' or + 'section-like-things') they never + assign a real section section-number + 0 to dss_index. + + There is also a convention for 'bss' that that section + and its like sections have no data but do have a size. + That is never true of DWARF sections */ + res = o->ai_methods->om_load_section( + o->ai_object, section->dss_index, + §ion->dss_data, &err); + if (res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + /* For PE and mach-o all section data was always + malloc'd. We do not need to set dss_data_was_malloc + though as the o->object data will eventually free + the original section data. + The first character of any o->object struct gives the type. */ + + if (res == DW_DLV_NO_ENTRY) { + /* Gets this for section->dss_index 0. + Which by ELF definition is a section index + which is not used (reserved by Elf to + mean no-section-index). + Otherwise NULL dss_data gets error. + BSS would legitimately have no data, but + no DWARF related section could possibly be bss. + We also get it if the section is present but + zero-size. */ + return res; + } + if (section->dss_ignore_reloc_group_sec) { + /* Neither zdebug nor reloc apply to .group sections. */ + return res; + } + if ((section->dss_zdebug_requires_decompress || + section->dss_shf_compressed || + section->dss_ZLIB_compressed) && + !section->dss_did_decompress) { + if (!section->dss_data) { + /* Impossible. This makes no sense. + Corrupt object. */ + DWARF_DBG_ERROR(dbg, DW_DLE_COMPRESSED_EMPTY_SECTION, + DW_DLV_ERROR); + } +#if defined(HAVE_ZLIB) || defined(HAVE_ZSTD) + res = do_decompress(dbg,section,error); + if (res != DW_DLV_OK) { + return res; + } +#else + _dwarf_error_string(dbg, error, + DW_DLE_ZDEBUG_REQUIRES_ZLIB, + "DW_DLE_ZDEBUG_REQUIRES_ZLIB: " + " zlib and zstd are missing, cannot" + " decompress section."); + return DW_DLV_ERROR; +#endif + section->dss_did_decompress = TRUE; + } + if (_dwarf_apply_relocs == 0) { + return res; + } + if (section->dss_reloc_size == 0) { + return res; + } + if (!o->ai_methods->om_relocate_a_section) { + return res; + } + /*apply relocations */ + res = o->ai_methods->om_relocate_a_section(o->ai_object, + section->dss_index, dbg, &err); + if (res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, err, res); + } + return res; +} + +/* This is a hack so clients can verify offsets. + Added (without so many sections to report) April 2005 + so that debugger can detect broken offsets + (which happened in an IRIX -64 executable larger than 2GB + using MIPSpro 7.3.1.3 compilers. A couple .debug_pubnames + offsets were wrong.). +*/ +/* Now with sections new to DWARF5 */ +int +dwarf_get_section_max_offsets_d(Dwarf_Debug dbg, + Dwarf_Unsigned * debug_info_size, + Dwarf_Unsigned * debug_abbrev_size, + Dwarf_Unsigned * debug_line_size, + Dwarf_Unsigned * debug_loc_size, + Dwarf_Unsigned * debug_aranges_size, + Dwarf_Unsigned * debug_macinfo_size, + Dwarf_Unsigned * debug_pubnames_size, + Dwarf_Unsigned * debug_str_size, + Dwarf_Unsigned * debug_frame_size, + Dwarf_Unsigned * debug_ranges_size, + Dwarf_Unsigned * debug_typenames_size, + Dwarf_Unsigned * debug_types_size, + Dwarf_Unsigned * debug_macro_size, + Dwarf_Unsigned * debug_str_offsets_size, + Dwarf_Unsigned * debug_sup_size, + Dwarf_Unsigned * debug_cu_index_size, + Dwarf_Unsigned * debug_tu_index_size, + Dwarf_Unsigned * debug_names_size, + Dwarf_Unsigned * debug_loclists_size, + Dwarf_Unsigned * debug_rnglists_size) +{ + if (debug_info_size) { + *debug_info_size = dbg->de_debug_info.dss_size; + } + if (debug_abbrev_size) { + *debug_abbrev_size = dbg->de_debug_abbrev.dss_size; + } + if (debug_line_size) { + *debug_line_size = dbg->de_debug_line.dss_size; + } + if (debug_loc_size) { + *debug_loc_size = dbg->de_debug_loc.dss_size; + } + if (debug_aranges_size) { + *debug_aranges_size = dbg->de_debug_aranges.dss_size; + } + if (debug_macinfo_size) { + *debug_macinfo_size = dbg->de_debug_macinfo.dss_size; + } + if (debug_pubnames_size) { + *debug_pubnames_size = dbg->de_debug_pubnames.dss_size; + } + if (debug_str_size) { + *debug_str_size = dbg->de_debug_str.dss_size; + } + if (debug_frame_size) { + *debug_frame_size = dbg->de_debug_frame.dss_size; + } + if (debug_ranges_size) { + *debug_ranges_size = dbg->de_debug_ranges.dss_size; + } + if (debug_typenames_size) { + *debug_typenames_size = dbg->de_debug_typenames.dss_size; + } + if (debug_types_size) { + *debug_types_size = dbg->de_debug_types.dss_size; + } + if (debug_macro_size) { + *debug_macro_size = dbg->de_debug_macro.dss_size; + } + if (debug_str_offsets_size) { + *debug_str_offsets_size = dbg->de_debug_str_offsets.dss_size; + } + if (debug_sup_size) { + *debug_sup_size = dbg->de_debug_sup.dss_size; + } + if (debug_cu_index_size) { + *debug_cu_index_size = dbg->de_debug_cu_index.dss_size; + } + if (debug_tu_index_size) { + *debug_tu_index_size = dbg->de_debug_tu_index.dss_size; + } + if (debug_names_size) { + *debug_names_size = dbg->de_debug_names.dss_size; + } + if (debug_loclists_size) { + *debug_loclists_size = dbg->de_debug_loclists.dss_size; + } + if (debug_rnglists_size) { + *debug_rnglists_size = dbg->de_debug_rnglists.dss_size; + } + return DW_DLV_OK; +} + +const struct Dwarf_Obj_Access_Section_a_s zerodoas; +/* Given a section name, get its size and address */ +int +dwarf_get_section_info_by_name(Dwarf_Debug dbg, + const char *section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error * error) +{ + struct Dwarf_Obj_Access_Interface_a_s * obj = 0; + Dwarf_Unsigned section_count = 0; + Dwarf_Unsigned section_index = 0; + struct Dwarf_Obj_Access_Section_a_s doas; + + *section_addr = 0; + *section_size = 0; + + if (!dbg) { + _dwarf_error_string(dbg,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: null dbg passed to " + "dwarf_get_section_info_by_name"); + return DW_DLV_ERROR; + } + if (!section_name) { + _dwarf_error_string(dbg,error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: null section_name pointer " + "passed to " + "dwarf_get_section_info_by_name"); + return DW_DLV_ERROR; + } + if (!section_name[0]) { + return DW_DLV_NO_ENTRY; + } + obj = dbg->de_obj_file; + if (!obj) { + return DW_DLV_NO_ENTRY; + } + section_count = obj->ai_methods-> + om_get_section_count(obj->ai_object); + + /* We can skip index 0 when considering ELF files, but not other + object types. */ + for (section_index = 0; section_index < section_count; + ++section_index) { + int errnum = 0; + int res = 0; + + doas = zerodoas; + res = obj->ai_methods-> + om_get_section_info(obj->ai_object, + section_index, &doas, &errnum); + if (res == DW_DLV_ERROR) { + DWARF_DBG_ERROR(dbg, errnum, DW_DLV_ERROR); + } + if (res == DW_DLV_NO_ENTRY) { + /* This should be impossible */ + continue; + } + if (!strcmp(section_name,doas.as_name)) { + *section_addr = doas.as_addr; + *section_size = doas.as_size; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +/* Given a section index, get its size and address */ +int +dwarf_get_section_info_by_index(Dwarf_Debug dbg, + int section_index, + const char **section_name, + Dwarf_Addr *section_addr, + Dwarf_Unsigned *section_size, + Dwarf_Error * error) +{ + *section_addr = 0; + *section_size = 0; + *section_name = NULL; + + /* Check if we have a valid section index */ + if (section_index >= 0 && section_index < + dwarf_get_section_count(dbg)) { + int res = 0; + int err = 0; + struct Dwarf_Obj_Access_Section_a_s doas; + struct Dwarf_Obj_Access_Interface_a_s * obj = + dbg->de_obj_file; + if (NULL == obj) { + return DW_DLV_NO_ENTRY; + } + res = obj->ai_methods->om_get_section_info(obj->ai_object, + section_index, &doas, &err); + if (res == DW_DLV_ERROR){ + DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR); + } + + *section_addr = doas.as_addr; + *section_size = doas.as_size; + *section_name = doas.as_name; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +/* Get section count */ +int +dwarf_get_section_count(Dwarf_Debug dbg) +{ + struct Dwarf_Obj_Access_Interface_a_s * obj = dbg->de_obj_file; + if (NULL == obj) { + /* -1 */ + return DW_DLV_NO_ENTRY; + } + return obj->ai_methods->om_get_section_count(obj->ai_object); +} + +Dwarf_Cmdline_Options dwarf_cmdline_options = { + FALSE /* Use quiet mode by default. */ +}; + +/* Lets libdwarf reflect a command line option, so we can get details + of some errors printed using libdwarf-internal information. */ +void +dwarf_record_cmdline_options(Dwarf_Cmdline_Options options) +{ + dwarf_cmdline_options = options; +} diff --git a/src/lib/libdwarf/dwarf_leb.c b/src/lib/libdwarf/dwarf_leb.c new file mode 100644 index 0000000..7098d7a --- /dev/null +++ b/src/lib/libdwarf/dwarf_leb.c @@ -0,0 +1,430 @@ +/* + Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2011-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* size_t */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" +#include "dwarf_util.h" + +#define MORE_BYTES 0x80 +#define DATA_MASK 0x7f +#define DIGIT_WIDTH 7 +#define SIGN_BIT 0x40 + +/* Note that with 'make check') + many of the test items + only make sense if Dwarf_Unsigned (and Dwarf_Signed) + are 64 bits. The encode/decode logic should + be fine whether those types are 64 or 32 bits. + See runtests.sh */ + +/* The encode/decode functions here are public */ + +/* 10 bytes of leb, 7 bits each part of the number, gives + room for a 64bit number. + While any number of leading zeroes would be legal, so + no max is really truly required here, why would a + compiler generate leading zeros (for unsigned leb)? + That would seem strange except in rare circumstances + a compiler may want, for overall alignment, to + add extra bytes.. + + So we allow more than 10 as it is legal for a compiler to + generate an leb with correct but useless trailing + zero bytes (note the interaction with sign in the signed case). + The value of BYTESLEBMAX is arbitrary but allows catching + corrupt data before dark. + Before April 2021 BYTESLEBMAX was 10. +*/ +#define BYTESLEBMAX 24 +#define BITSPERBYTE 8 + +/* When an leb value needs to reveal its length, + but the value is not needed */ +int +_dwarf_skip_leb128(char * leb128, + Dwarf_Unsigned * leb128_length, + char * endptr) +{ + unsigned byte = 0; + /* The byte_length value will be a small non-negative integer. */ + unsigned byte_length = 1; + + if (leb128 >=endptr) { + return DW_DLV_ERROR; + } + + byte = *leb128; + if ((byte & 0x80) == 0) { + *leb128_length = 1; + return DW_DLV_OK; + } else { + unsigned byte2 = 0; + if ((leb128+1) >=endptr) { + return DW_DLV_ERROR; + } + byte2 = *(leb128 + 1); + if ((byte2 & 0x80) == 0) { + *leb128_length = 2; + return DW_DLV_OK; + } + /* Gets messy to hand-inline more byte checking. + One or two byte leb is very frequent. */ + } + + ++byte_length; + ++leb128; + /* Validity of leb128+1 checked above */ + for (;;byte_length++,leb128++) { + if (leb128 >= endptr) { + /* Off end of available space. */ + return DW_DLV_ERROR; + } + byte = *leb128; + if (byte & 0x80) { + if (byte_length >= BYTESLEBMAX) { + /* Too long. Not sane length. */ + return DW_DLV_ERROR; + } + continue; + } + break; + } + *leb128_length = byte_length; + return DW_DLV_OK; + +} +/* Decode ULEB with checking. */ +int +dwarf_decode_leb128(char * leb128, + Dwarf_Unsigned * leb128_length, + Dwarf_Unsigned *outval, + char * endptr) +{ + unsigned byte = 0; + Dwarf_Unsigned word_number = 0; + Dwarf_Unsigned number = 0; + size_t shift = 0; + /* The byte_length value will be a small non-negative integer. */ + unsigned byte_length = 0; + + if (leb128 >=endptr) { + return DW_DLV_ERROR; + } + /* The following unrolls-the-loop for the first two bytes and + unpacks into 32 bits to make this as fast as possible. + word_number is assumed big enough that the shift has a defined + result. */ + byte = *leb128; + if ((byte & 0x80) == 0) { + if (leb128_length) { + *leb128_length = 1; + } + if (outval) { + *outval = byte; + } + return DW_DLV_OK; + } else { + unsigned byte2 = 0; + if ((leb128+1) >=endptr) { + return DW_DLV_ERROR; + } + byte2 = *(leb128 + 1); + if ((byte2 & 0x80) == 0) { + if (leb128_length) { + *leb128_length = 2; + } + word_number = byte & 0x7f; + word_number |= (byte2 & 0x7f) << 7; + if (outval) { + *outval = word_number; + } + return DW_DLV_OK; + } + /* Gets messy to hand-inline more byte checking. */ + } + + /* The rest handles long numbers. Because the 'number' + may be larger than the default int/unsigned, + we must cast the 'byte' before + the shift for the shift to have a defined result. */ + number = 0; + shift = 0; + byte_length = 1; + for (;;) { + unsigned b = byte & 0x7f; + if (shift >= (sizeof(number)*BITSPERBYTE)) { + /* Shift is large. Maybe corrupt value, + maybe some padding high-end byte zeroes + that we can ignore. */ + if (!b) { + if (byte_length >= BYTESLEBMAX) { + /* Erroneous input. */ + if (leb128_length) { + *leb128_length = BYTESLEBMAX; + } + return DW_DLV_ERROR; + } + ++leb128; + /* shift cannot overflow as + BYTESLEBMAX is not a large value */ + shift += 7; + if (leb128 >=endptr ) { + if (leb128 == endptr && !byte) { + /* Meaning zero bits a padding byte */ + if (leb128_length) { + *leb128_length = byte_length; + } + if (outval) { + *outval = number; + } + return DW_DLV_OK; + } + return DW_DLV_ERROR; + } + ++byte_length; + byte = *leb128; + continue; + } + /* Too big, corrupt data given the non-zero + byte content */ + return DW_DLV_ERROR; + } + number |= ((Dwarf_Unsigned)b << shift); + if ((byte & 0x80) == 0) { + if (leb128_length) { + *leb128_length = byte_length; + } + if (outval) { + *outval = number; + } + return DW_DLV_OK; + } + shift += 7; + byte_length++; + if (byte_length > BYTESLEBMAX) { + /* Erroneous input. */ + if (leb128_length) { + *leb128_length = BYTESLEBMAX; + } + break; + } + ++leb128; + if (leb128 >= endptr) { + return DW_DLV_ERROR; + } + byte = *leb128; + } + return DW_DLV_ERROR; +} + +/* Decode SLEB with checking */ +int +dwarf_decode_signed_leb128(char * leb128, + Dwarf_Unsigned * leb128_length, + Dwarf_Signed *outval,char * endptr) +{ + Dwarf_Unsigned byte = 0; + unsigned int b = 0; + Dwarf_Signed number = 0; + size_t shift = 0; + int sign = FALSE; + /* The byte_length value will be a small non-negative integer. */ + unsigned byte_length = 1; + + /* byte_length being the number of bytes + of data absorbed so far in + turning the leb into a Dwarf_Signed. */ + if (!outval) { + return DW_DLV_ERROR; + } + if (leb128 >= endptr) { + return DW_DLV_ERROR; + } + byte = *leb128; + for (;;) { + b = byte & 0x7f; + if (shift >= (sizeof(number)*BITSPERBYTE)) { + /* Shift is large. Maybe corrupt value, + maybe some padding high-end byte zeroes + that we can ignore (but notice sign bit + from the last usable byte). */ + sign = b & 0x40; + if (!byte || byte == 0x40) { + /* The value is complete. */ + break; + } + if (b == 0) { + ++byte_length; + if (byte_length > BYTESLEBMAX) { + /* Erroneous input. */ + if (leb128_length) { + *leb128_length = BYTESLEBMAX; + } + return DW_DLV_ERROR; + } + ++leb128; + /* shift cannot overflow as + BYTESLEBMAX is not a large value */ + shift += 7; + if (leb128 >= endptr) { + return DW_DLV_ERROR; + } + byte = *leb128; + continue; + } + /* Too big, corrupt data given the non-zero + byte content */ + return DW_DLV_ERROR; + } + /* This bit of the last byte indicates sign */ + sign = b & 0x40; + number |= ((Dwarf_Unsigned)b) << shift; + shift += 7; + if ((byte & 0x80) == 0) { + break; + } + ++leb128; + if (leb128 >= endptr) { + return DW_DLV_ERROR; + } + byte = *leb128; + byte_length++; + if (byte_length > BYTESLEBMAX) { + /* Erroneous input. */ + if (leb128_length) { + *leb128_length = BYTESLEBMAX; + } + return DW_DLV_ERROR; + } + } + if (sign) { + /* The following avoids undefined behavior. */ + unsigned shiftlim = sizeof(Dwarf_Signed) * BITSPERBYTE -1; + if (shift < shiftlim) { + Dwarf_Signed y = (Dwarf_Signed) + (((Dwarf_Unsigned)1) << shift); + Dwarf_Signed x = -y; + number |= x; + } else if (shift == shiftlim) { + Dwarf_Signed x= (((Dwarf_Unsigned)1) << shift); + number |= x; + } else { + /* trailing zeroes case */ + Dwarf_Signed x= (((Dwarf_Unsigned)1) << shiftlim); + number |= x; + } + } + if (leb128_length) { + *leb128_length = byte_length; + } + *outval = number; + return DW_DLV_OK; +} + +/* Encode val as a uleb128. This encodes it as an unsigned + number. + Return DW_DLV_ERROR or DW_DLV_OK. + space to write leb number is provided by caller, with caller + passing length. + number of bytes used returned thru nbytes arg. + This never emits padding, it emits the minimum + number of bytes that can hold the value. */ +int dwarf_encode_leb128(Dwarf_Unsigned val, int *nbytes, + char *space, int splen) +{ + char *a; + char *end = space + splen; + + a = space; + do { + unsigned char uc; + + if (a >= end) { + return DW_DLV_ERROR; + } + uc = val & DATA_MASK; + val >>= DIGIT_WIDTH; + if (val != 0) { + uc |= MORE_BYTES; + } + *a = uc; + a++; + } while (val); + *nbytes = (int)(a - space); + return DW_DLV_OK; +} + +/* This never emits padding at the end, so it + says nothing about what such would look like + for a negative value. */ +int dwarf_encode_signed_leb128(Dwarf_Signed value, int *nbytes, + char *space, int splen) +{ + char *str; + Dwarf_Signed sign = -(value < 0); + int more = 1; + char *end = space + splen; + + str = space; + + do { + unsigned char byte = value & DATA_MASK; + + value >>= DIGIT_WIDTH; + + if (str >= end) { + return DW_DLV_ERROR; + } + /* Remaining chunks would just contain the sign + bit, and this chunk + has already captured at least one sign bit. */ + if (value == sign && + ((byte & SIGN_BIT) == (sign & SIGN_BIT))) { + more = 0; + } else { + byte |= MORE_BYTES; + } + *str = byte; + str++; + } while (more); + *nbytes = (int)(str - space); + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_line.c b/src/lib/libdwarf/dwarf_line.c new file mode 100644 index 0000000..3d4f6d3 --- /dev/null +++ b/src/lib/libdwarf/dwarf_line.c @@ -0,0 +1,2649 @@ +/* Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2015-2015 Google, Inc. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ +#include /* free() malloc() realloc() */ +#include /* memset() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_line.h" +#include "dwarf_string.h" +#include "dwarf_debuglink.h" + +/* Line Register Set initial conditions. */ +static struct Dwarf_Line_Registers_s + _dwarf_line_table_regs_default_values = { + /* Dwarf_Addr lr_address */ 0, + /* Dwarf_Unsigned lr_file */ 1, + /* Dwarf_Unsigned lr_line */ 1, + /* Dwarf_Unsigned lr_column */ 0, + /* Dwarf_Bool lr_is_stmt */ false, + /* Dwarf_Bool lr_basic_block */ false, + /* Dwarf_Bool lr_end_sequence */ false, + /* Dwarf_Bool lr_prologue_end */ false, + /* Dwarf_Bool lr_epilogue_begin */ false, + /* Dwarf_Small lr_isa */ 0, + /* Dwarf_Unsigned lr_op_index */ 0, + /* Dwarf_Unsigned lr_discriminator */ 0, + /* Dwarf_Unsigned lr_call_context */ 0, + /* Dwarf_Unsigned lr_subprogram */ 0, +}; + +void +_dwarf_set_line_table_regs_default_values(Dwarf_Line_Registers regs, + unsigned lineversion, + Dwarf_Bool is_stmt) +{ + (void)lineversion; + *regs = _dwarf_line_table_regs_default_values; + /* Remember that 0xf006 is the version of + the experimental line table */ + if (lineversion == DW_LINE_VERSION5) { + /* DWARF5 Section 2.14 says default 0 for line table + file numbering.. + DWARF5 Table 6.4 says the line table file + register defaults to 1 (as did DWARF2,3,4). + + gcc 11.2.0 uses line register + default 1, while correctly numbering files from 0. + it sets file 0 and file 2 to the file of the CU + and file 1 applies to an included file + so things work when the first line table + entries needed come from an included file + (such as a static inline function definition). + See regressiontests/issue137gh/README + + clang 14 entirely avoids use of the default + file register value, it always uses + DW_LNS_set_file in the line table. */ + regs->lr_file = 1; + } + regs->lr_is_stmt = is_stmt; +} + +/* Detect Windows full paths as well as Unix/Linux. + ASSERT: fname != NULL */ +Dwarf_Bool +_dwarf_file_name_is_full_path(Dwarf_Small *fname) +{ + Dwarf_Small firstc = *fname; + /* Not relative path if + - path begins with \\ (UNC path) + - path begins with ?:\, with ? being a letter + - path bagins with \ + see + https://docs.microsoft.com/en-us/windows/win32/\ + fileio/naming-a-file#paths */ + if (!firstc) { + return FALSE; + } + if (firstc == '/') { + return TRUE; + } + if (firstc == '\\') { + return TRUE; + } + /* We assume anything starting with c: (etc) + is a genuine Windows name. That turns out + to be important as we dump PE objects on + linux! It's safe too, as a specially crafted + file might have add path output, but would + not break anything. */ + if (((firstc >= 'a') && (firstc <= 'z')) || + ((firstc >= 'A') && (firstc <= 'Z'))) { + if (fname[1] == ':') { + /* Some test cases use /, some \\ */ + if (fname[2] == '\\') { + return TRUE; + } + if (fname[2] == '/') { + return TRUE; + } + /* This is a relative path to the current + directory on the drive named. + Windows has a 'current directory' + with each drive letter in use. */ + } + } + return FALSE; +} +#include "dwarf_line_table_reader_common.h" + +/* Used for a short time in the next two functions. + Not saved. If multithreading ever allowed this + will have to change to be function local + non-static buffers. */ +static char targbuf[300]; +static char nbuf[300]; + +static int +ret_simple_full_path(Dwarf_Debug dbg, + char *file_name, + char ** name_ptr_out, + Dwarf_Error *error) +{ + char *tmp = 0; + char * mstr = 0; + unsigned long mlen = 0; + dwarfstring targ; + dwarfstring nxt; + + dwarfstring_constructor_static(&targ, + targbuf,sizeof(targbuf)); + dwarfstring_constructor_static(&nxt, + nbuf,sizeof(nbuf)); + + dwarfstring_append(&nxt,file_name); + _dwarf_pathjoinl(&targ,&nxt); + mstr= dwarfstring_string(&targ); + mlen = dwarfstring_strlen(&targ) +1; + tmp = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING, + mlen); + if (tmp) { + _dwarf_safe_strcpy(tmp,mlen, mstr,mlen-1); + *name_ptr_out = tmp; + dwarfstring_destructor(&targ); + dwarfstring_destructor(&nxt); + return DW_DLV_OK; + } + dwarfstring_destructor(&targ); + dwarfstring_destructor(&nxt); + _dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: " + "Allocation of space for a simple full path " + "from line table header data fails." ); + return DW_DLV_ERROR; +} + +static void +_dwarf_dirno_string(Dwarf_Line_Context line_context, + Dwarf_Unsigned dirno, + unsigned include_dir_offset, + dwarfstring *dwstr_out) +{ + if ((dirno - include_dir_offset) >= + line_context->lc_include_directories_count) { + + /* Corrupted data. We try to continue. + Make the text look like a full-path */ + dwarfstring_append_printf_u(dwstr_out, + "/ERROR", + line_context->lc_include_directories_count); + return; + } + { + char *inc_dir_name = + (char *)line_context->lc_include_directories[ + dirno - include_dir_offset]; + if (!inc_dir_name) { + /* This should never ever happen except in case + of a corrupted object file. + Make the text look like a full-path */ + inc_dir_name = + "/ERROR"; + } + dwarfstring_append(dwstr_out,inc_dir_name); + } + return; +} + +/* With this routine we ensure the file full path + is calculated identically for + dwarf_srcfiles() and _dwarf_filename() + + As of March 14 2020 this *always* + does an allocation for the string. dwarf_dealloc + is crucial to do no matter what. + So we have consistency. + + dwarf_finish() will do the dealloc if nothing else does. + Unless the calling application did the call + dwarf_set_de_alloc_flag(0). + + The treatment of DWARF5 differs from DWARF < 5 + as the line table header in DW5 lists the + compilation directory directly. 10 August 2023. + + _dwarf_pathjoinl() takes care of / and Windows \ +*/ +static int +create_fullest_file_path(Dwarf_Debug dbg, + Dwarf_File_Entry fe, + Dwarf_Line_Context line_context, + char ** name_ptr_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned dirno = 0; + char *full_name = 0; + char *file_name = 0; + /* Large enough that almost never will any malloc + be needed by dwarfstring. Arbitrary size. */ + dwarfstring targ; + unsigned linetab_version = line_context->lc_version_number; + + file_name = (char *) fe->fi_file_name; + if (!file_name) { + _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME); + return DW_DLV_ERROR; + } + if (_dwarf_file_name_is_full_path((Dwarf_Small *)file_name)) { + int res = 0; + + res = ret_simple_full_path(dbg, + file_name, + name_ptr_out, + error); + return res; + } + { + int need_dir = FALSE; + unsigned include_dir_offset = 1; + static char compdirbuf[300]; + static char filenamebuf[300]; + dwarfstring compdir; + dwarfstring incdir; + dwarfstring filename; + + dwarfstring_constructor_static(&targ, + targbuf,sizeof(targbuf)); + dwarfstring_constructor_static(&compdir, + compdirbuf,sizeof(compdirbuf)); + dwarfstring_constructor_fixed(&incdir,300); + dwarfstring_constructor_static(&filename, + filenamebuf,sizeof(filenamebuf)); + if (line_context->lc_compilation_directory) { + char * comp_dir_name = + (char *)line_context->lc_compilation_directory; + dwarfstring_append(&compdir,comp_dir_name); + } + need_dir = FALSE; + dirno = fe->fi_dir_index; + include_dir_offset = 0; + /* Remember that 0xf006 is the version of + the experimental line table */ + if (linetab_version == DW_LINE_VERSION5) { + /* DWARF5 */ + need_dir = TRUE; + include_dir_offset = 0; + } else { + /* EXPERIMENTAL_LINE_TABLES_VERSION or 2,3, or 4 */ + if (dirno) { + need_dir = TRUE; + include_dir_offset = 1; + }/* else, no dirno, need_dir = FALSE + Take directory from DW_AT_comp_dir */ + } + + if (dirno > line_context->lc_include_directories_count) { + /* This is quite corrupted. */ + dwarfstring_destructor(&targ); + dwarfstring_destructor(&compdir); + dwarfstring_destructor(&filename); + dwarfstring_reset(&incdir); + dwarfstring_append_printf_u(&incdir, + "DW_DLE_INCL_DIR_NUM_BAD: " + "corrupt include directory index %u" + " unusable,", dirno); + dwarfstring_append_printf_u(&incdir, + " only %u directories present.", + line_context->lc_include_directories_count); + _dwarf_error_string(dbg, error, DW_DLE_INCL_DIR_NUM_BAD, + dwarfstring_string(&incdir)); + dwarfstring_destructor(&incdir); + return DW_DLV_ERROR; + } + if (need_dir ) { + _dwarf_dirno_string(line_context,dirno, + include_dir_offset,&incdir); + } + dwarfstring_append(&filename,file_name); + if (dwarfstring_strlen(&incdir) > 0 && + _dwarf_file_name_is_full_path( + (Dwarf_Small*)dwarfstring_string(&incdir))) { + + /* incdir is full path,Ignore DW_AT_comp_dir + and (for DWARF5 include_dir[0]) */ + _dwarf_pathjoinl(&targ,&incdir); + _dwarf_pathjoinl(&targ,&filename); + } else { + /* Join two or all three strings, + ignoring empty/irrelevant ones. */ + /* Remember that 0xf006 is the version of + the experimental line table */ + if (linetab_version != DW_LINE_VERSION5) { + if (dwarfstring_strlen(&compdir) > 0) { + _dwarf_pathjoinl(&targ,&compdir); + } + } else if (!include_dir_offset && dirno) { + /* Don't do this if DW5 and dirno + was zero, doing 0 here will + duplicate the comp dir */ + dwarfstring_reset(&compdir); + _dwarf_dirno_string(line_context,0, + include_dir_offset,&compdir); + if (dwarfstring_strlen(&compdir) > 0) { + _dwarf_pathjoinl(&targ,&compdir); + } + } + if (dwarfstring_strlen(&incdir) > 0) { + _dwarf_pathjoinl(&targ,&incdir); + } + _dwarf_pathjoinl(&targ,&filename); + } + { + char *mname = dwarfstring_string(&targ); + unsigned long mlen = dwarfstring_strlen(&targ)+1; + full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING, + mlen); + if (!full_name) { + dwarfstring_destructor(&targ); + dwarfstring_destructor(&incdir); + dwarfstring_destructor(&compdir); + dwarfstring_destructor(&filename); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + _dwarf_safe_strcpy(full_name,mlen,mname,mlen-1); + } + *name_ptr_out = full_name; + dwarfstring_destructor(&targ); + dwarfstring_destructor(&incdir); + dwarfstring_destructor(&compdir); + dwarfstring_destructor(&filename); + } + return DW_DLV_OK; +} + +static void +report_bogus_stmt_list_form(Dwarf_Debug dbg, + Dwarf_Half attrform, Dwarf_Error *error) +{ + dwarfstring m; /* OK constructor_fixed */ + dwarfstring f; /* Ok constructor_static */ + char buf[32]; + const char *formname = 0; + + buf[0] = 0; + dwarfstring_constructor_static(&f,buf,sizeof(buf)); + dwarf_get_FORM_name(attrform,&formname); + if (!formname) { + dwarfstring_append_printf_u(&f,"Invalid Form Code " + " 0x" DW_PR_DUx,attrform); + } else { + dwarfstring_append(&f,(char *)formname); + } + dwarfstring_constructor_fixed(&m,200); + dwarfstring_append_printf_s(&m, + "DW_DLE_LINE_OFFSET_WRONG_FORM: form %s " + "instead of an allowed section offset form.", + dwarfstring_string(&f)); + _dwarf_error_string(dbg, error, DW_DLE_LINE_OFFSET_WRONG_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + dwarfstring_destructor(&f); +} + +/* Although source files is supposed to return the + source files in the compilation-unit, it does + not look for any in the statement program. In + other words, it ignores those defined using the + extended opcode DW_LNE_define_file. + We do not know of a producer that uses DW_LNE_define_file. + + In DWARF2,3,4 the array of sourcefiles is represented + differently than DWARF5. + DWARF 2,3,4, and experimental line table: + Subtract 1 from the DW_AT_decl_file etc + to index into the array of names. + zero means there is no file. + DWARF 5: + DW_AT_decl_file etc numbers should be directly + used to index into the array of names. + Do not subtract anything. + For further information + see the discussion of dwarf_srcfiles() in + libdwarf2.1.pdf version 3.16 and later, Section + 6.14 around page 117. +*/ +int +dwarf_srcfiles(Dwarf_Die die, + char ***srcfiles, + Dwarf_Signed * srcfilecount, + Dwarf_Error * error) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr = 0; + + /* Pointer to a DW_AT_stmt_list attribute + in case it exists in the die. */ + Dwarf_Attribute stmt_list_attr = 0; + + const char * const_comp_name = 0; + /* Pointer to name of compilation directory. */ + const char * const_comp_dir = 0; + Dwarf_Small *comp_dir = 0; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + /* This points to a block of char *'s, each of which points to a + file name. */ + char **ret_files = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context context = 0; + Dwarf_Line_Context line_context = 0; + + /* Used to chain the file names. */ + Dwarf_Chain curr_chain = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Chain * plast = &head_chain; + + Dwarf_Half attrform = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + unsigned i = 0; + int res = DW_DLV_ERROR; + Dwarf_Small *section_start = 0; + + /* ***** BEGIN CODE ***** */ + /* Reset error. */ + + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + + resattr = dwarf_attr(die, DW_AT_stmt_list, + &stmt_list_attr, error); + if (resattr != DW_DLV_OK) { + return resattr; + } + + if (dbg->de_debug_line.dss_index == 0) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL); + return DW_DLV_ERROR; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return res; + } + if (!dbg->de_debug_line.dss_size) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return DW_DLV_NO_ENTRY; + } + section_start = dbg->de_debug_line.dss_data; + + lres = dwarf_whatform(stmt_list_attr,&attrform,error); + if (lres != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return lres; + } + if (attrform == DW_FORM_addr) { + Dwarf_Addr addr = 0; + /* DW_AT_producer + 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2.9) + generated DW_FORM_addr for DW_AT_stmt_list! */ + lres = dwarf_formaddr(stmt_list_attr,&addr,error); + if (lres != DW_DLV_OK) { + if (lres == DW_DLV_ERROR) { + report_bogus_stmt_list_form(dbg, + attrform,error); + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + } + return lres; + } + line_offset = (Dwarf_Unsigned)addr; + } else if (attrform != DW_FORM_data4 && + attrform != DW_FORM_data8 && + attrform != DW_FORM_sec_offset && + attrform != DW_FORM_GNU_ref_alt) { + report_bogus_stmt_list_form(dbg, + attrform,error); + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return DW_DLV_ERROR; + } else { + /* standard setup. */ + lres = dwarf_global_formref(stmt_list_attr, + &line_offset, error); + if (lres != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return lres; + } + } + if (line_offset >= dbg->de_debug_line.dss_size) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + line_ptr = dbg->de_debug_line.dss_data + line_offset; + { + Dwarf_Unsigned fission_offset = 0; + Dwarf_Unsigned fission_size = 0; + int resl = _dwarf_get_fission_addition_die(die, DW_SECT_LINE, + &fission_offset,&fission_size,error); + if (resl != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return resl; + } + line_ptr += fission_offset; + if (line_ptr > dbg->de_debug_line.dss_data + + dbg->de_debug_line.dss_size) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + _dwarf_error(dbg, error, DW_DLE_FISSION_ADDITION_ERROR); + return DW_DLV_ERROR; + } + } + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + stmt_list_attr = 0; + + resattr = _dwarf_internal_get_die_comp_dir(die, &const_comp_dir, + &const_comp_name,error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + + /* Horrible cast away const to match historical interfaces. */ + comp_dir = (Dwarf_Small *)const_comp_dir; + line_context = (Dwarf_Line_Context) + _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); + if (line_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + line_context->lc_new_style_access = false; + /* We are in dwarf_srcfiles() */ + { + Dwarf_Small *line_ptr_out = 0; + int dres = 0; + + dres = _dwarf_read_line_table_header(dbg, + context, + section_start, + line_ptr, + dbg->de_debug_line.dss_size, + &line_ptr_out, + line_context, + NULL, NULL,error, + 0); + + if (dres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + line_context = 0; + return dres; + } + if (dres == DW_DLV_NO_ENTRY) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + line_context = 0; + return dres; + } + } + /* For DWARF5, use of DW_AT_comp_dir not needed. + Line table file names and directories + start with comp_dir and name. */ + line_context->lc_compilation_directory = comp_dir; + /* We are in dwarf_srcfiles() */ + { + Dwarf_File_Entry fe = 0; + Dwarf_File_Entry fe2 =line_context->lc_file_entries; + Dwarf_Signed baseindex = 0; + Dwarf_Signed file_count = 0; + Dwarf_Signed endindex = 0; + + res = dwarf_srclines_files_indexes(line_context, &baseindex, + &file_count, &endindex, error); + if (res != DW_DLV_OK) { + return res; + } + for (i = baseindex; i < endindex; ++i,fe2 = fe->fi_next ) { + int sres = 0; + char *name_out = 0; + + fe = fe2; + sres = create_fullest_file_path(dbg,fe,line_context, + &name_out,error); + if (sres != DW_DLV_OK) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + /* This can leak some strings */ + return sres; + } + curr_chain = + (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + dwarf_dealloc(dbg,name_out,DW_DLA_STRING); + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + curr_chain->ch_item = name_out; + (*plast) = curr_chain; + plast = &(curr_chain->ch_next); + } + } + if (!head_chain) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + *srcfiles = NULL; + *srcfilecount = 0; + return DW_DLV_NO_ENTRY; + } + + /* We are in dwarf_srcfiles() */ + if (line_context->lc_file_entry_count == 0) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + *srcfiles = NULL; + *srcfilecount = 0; + return DW_DLV_NO_ENTRY; + } + + ret_files = (char **) + _dwarf_get_alloc(dbg, DW_DLA_LIST, + line_context->lc_file_entry_count); + if (ret_files == NULL) { + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + curr_chain = head_chain; + for (i = 0; i < line_context->lc_file_entry_count; i++) { + Dwarf_Chain prev = 0; + *(ret_files + i) = curr_chain->ch_item; + curr_chain->ch_item = 0; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + /* Our chain is not recorded in the line_context so + the line_context destructor will not destroy our + list of strings or our strings. + Our caller has to do the deallocations. */ + { + Dwarf_Signed srccount = + (Dwarf_Signed)line_context->lc_file_entry_count; + if (srccount < 0) { + /* Impossible corruption! */ + _dwarf_error_string(dbg,error,DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srcfiles finds an impossible " + "source files count"); + return DW_DLV_ERROR; + } + *srcfiles = ret_files; + *srcfilecount = srccount; + } + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + return DW_DLV_OK; +} + +/* Return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR + doaddrs is true iff this is being called for + SGI IRIX rqs processing + (ie, not a normal libdwarf dwarf_srclines or + two-level user call at all). + dolines is true iff this is called by a dwarf_srclines call. + + In case of error or NO_ENTRY in this code we use the + dwarf_srcline_dealloc(line_context) + and dealloc of DW_DLA_LINE_CONTEXT + from the new interface for uniformity here. +*/ +int +_dwarf_internal_srclines(Dwarf_Die die, + Dwarf_Bool is_new_interface, + Dwarf_Unsigned * version, + Dwarf_Small * table_count, /* returns 0,1, or 2 */ + Dwarf_Line_Context *line_context_out, + Dwarf_Line ** linebuf, + Dwarf_Signed * linecount, + Dwarf_Line ** linebuf_actuals, + Dwarf_Signed * linecount_actuals, + Dwarf_Bool doaddrs, + Dwarf_Bool dolines, + Dwarf_Error * error) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr = 0; + + /* This points to the last byte of the + .debug_line portion for the current cu. */ + Dwarf_Small *line_ptr_end = 0; + + /* For two-level line tables, this points to the + first byte of the + actuals table (and the end of the logicals table) + for the current cu. */ + Dwarf_Small *line_ptr_actuals = 0; + Dwarf_Small *section_start = 0; + Dwarf_Small *section_end = 0; + + /* Pointer to a DW_AT_stmt_list attribute in case + it exists in the die. */ + Dwarf_Attribute stmt_list_attr = 0; + + const char * const_comp_name = 0; + /* Pointer to name of compilation directory. */ + const char * const_comp_dir = NULL; + Dwarf_Small *comp_dir = NULL; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + /* Pointer to a Dwarf_Line_Context_s structure that contains the + context such as file names and include directories for the set + of lines being generated. + This is always recorded on an + DW_LNS_end_sequence operator, + on all special opcodes, and on DW_LNS_copy. + */ + Dwarf_Line_Context line_context = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned fission_offset = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + Dwarf_Half address_size = 0; + Dwarf_Small * orig_line_ptr = 0; + + int res = DW_DLV_ERROR; + + /* ***** BEGIN CODE ***** */ + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + dbg = cu_context->cc_dbg; + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_line.dss_size) { + return DW_DLV_NO_ENTRY; + } + + address_size = _dwarf_get_address_size(dbg, die); + resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, + error); + if (resattr != DW_DLV_OK) { + return resattr; + } + lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); + if (lres != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return lres; + } + + if (line_offset >= dbg->de_debug_line.dss_size) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + section_start = dbg->de_debug_line.dss_data; + section_end = section_start +dbg->de_debug_line.dss_size; + { + Dwarf_Unsigned fission_size = 0; + uintptr_t line_ptr_as_uint = (uintptr_t)line_ptr; + int resf = _dwarf_get_fission_addition_die(die, DW_SECT_LINE, + &fission_offset,&fission_size,error); + if (resf != DW_DLV_OK) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + return resf; + } + + /* fission_offset may be 0, and adding 0 to a null pointer + is undefined behavior with some compilers. */ + line_ptr_as_uint += fission_offset; + line_ptr = (Dwarf_Small *)line_ptr_as_uint; + if (line_ptr > section_end) { + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + _dwarf_error(dbg, error, DW_DLE_FISSION_ADDITION_ERROR); + return DW_DLV_ERROR; + } + } + + section_start = dbg->de_debug_line.dss_data; + section_end = section_start +dbg->de_debug_line.dss_size; + orig_line_ptr = section_start + line_offset + fission_offset; + line_ptr = orig_line_ptr; + dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); + if ((line_offset + fission_offset) > + dbg->de_debug_line.dss_size) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + if (line_ptr > section_end) { + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + + /* If die has DW_AT_comp_dir attribute, get the string that names + the compilation directory. */ + resattr = _dwarf_internal_get_die_comp_dir(die, &const_comp_dir, + &const_comp_name,error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + /* Horrible cast to match historic interfaces. */ + comp_dir = (Dwarf_Small *)const_comp_dir; + line_context = (Dwarf_Line_Context) + _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); + if (line_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + line_context->lc_new_style_access = is_new_interface; + line_context->lc_compilation_directory = comp_dir; + /* We are in dwarf_internal_srclines() */ + { + Dwarf_Small *newlinep = 0; + int resp = _dwarf_read_line_table_header(dbg, + cu_context, + section_start, + line_ptr, + dbg->de_debug_line.dss_size, + &newlinep, + line_context, + NULL,NULL, + error, + 0); + + if (resp == DW_DLV_ERROR) { + if (is_new_interface) { + dwarf_srclines_dealloc_b(line_context); + } else { + dwarf_dealloc(dbg,line_context,DW_DLA_LINE_CONTEXT); + } + return resp; + } + if (resp == DW_DLV_NO_ENTRY) { + if (is_new_interface) { + dwarf_srclines_dealloc_b(line_context); + } else { + dwarf_dealloc(dbg,line_context,DW_DLA_LINE_CONTEXT); + } + return resp; + } + line_ptr_end = line_context->lc_line_ptr_end; + line_ptr = newlinep; + if (line_context->lc_actuals_table_offset > 0) { + line_ptr_actuals = line_context->lc_line_prologue_start + + line_context->lc_actuals_table_offset; + } + } + + if (line_ptr_actuals == 0) { + /* ASSERT: lc_table_count == 1 or lc_table_count == 0 */ + int err_count_out = 0; + /* Normal style (single level) line table. */ + Dwarf_Bool is_actuals_table = false; + Dwarf_Bool local_is_single_table = true; + res = read_line_table_program(dbg, + line_ptr, line_ptr_end, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + local_is_single_table, + is_actuals_table, + error, + &err_count_out); + if (res != DW_DLV_OK) { + if (is_new_interface) { + dwarf_srclines_dealloc_b(line_context); + } else { + dwarf_dealloc(dbg,line_context,DW_DLA_LINE_CONTEXT); + } + return res; + } + if (linebuf) { + *linebuf = line_context->lc_linebuf_logicals; + } + if (linecount) { + Dwarf_Signed lcl = + (Dwarf_Signed)line_context->lc_linecount_logicals; + if (lcl < 0) { + _dwarf_error_string(dbg,error,DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines finds an impossible " + "lines count"); + return DW_DLV_ERROR; + } + *linecount = lcl; + } + if (linebuf_actuals) { + *linebuf_actuals = NULL; + } + if (linecount_actuals) { + *linecount_actuals = 0; + } + } else { + Dwarf_Bool is_actuals_table = false; + Dwarf_Bool local2_is_single_table = false; + int err_count_out = 0; + + line_context->lc_is_single_table = false; + /* Two-level line table. + First read the logicals table. */ + res = read_line_table_program(dbg, + line_ptr, line_ptr_actuals, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + local2_is_single_table, + is_actuals_table, error, + &err_count_out); + if (res != DW_DLV_OK) { + if (is_new_interface) { + dwarf_srclines_dealloc_b(line_context); + } else { + dwarf_dealloc(dbg,line_context,DW_DLA_LINE_CONTEXT); + } + return res; + } + + if (linecount) { + Dwarf_Signed lcl = + (Dwarf_Signed)line_context->lc_linecount_logicals; + if (lcl < 0) { + _dwarf_error_string(dbg,error,DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines finds an Impossible " + "lines count"); + return DW_DLV_ERROR; + } + *linecount = lcl; + } + if (linebuf) { + *linebuf = line_context->lc_linebuf_logicals; + } + if (is_new_interface) { + /* ASSERT: linebuf_actuals == NULL */ + is_actuals_table = true; + /* The call requested an actuals table + and one is present. So now read that one. */ + res = read_line_table_program(dbg, + + line_ptr_actuals, line_ptr_end, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + local2_is_single_table, + is_actuals_table, error, + &err_count_out); + if (res != DW_DLV_OK) { + dwarf_srclines_dealloc_b(line_context); + return res; + } + if (linebuf_actuals) { + *linebuf_actuals = line_context->lc_linebuf_actuals; + } + if (linecount_actuals) { + Dwarf_Signed lca = + (Dwarf_Signed)line_context->lc_linecount_actuals; + if (lca < 0) { + _dwarf_error_string(dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines finds an Impossible " + "lines count"); + return DW_DLV_ERROR; + } + *linecount_actuals = lca; + } + } + } + if (!is_new_interface && linecount && + (linecount == 0 ||*linecount == 0) && + (linecount_actuals == 0 || *linecount_actuals == 0)) { + /* Here we have no actual lines of any kind. In other words, + it looks like a debugfission + (now called split dwarf) line table skeleton or + a caller not prepared for skeletons or two-level reading.. + In that case there are no line entries so the context + had nowhere to be recorded. Hence we have to delete it + else we would leak the context. */ + dwarf_dealloc(dbg, line_context, DW_DLA_LINE_CONTEXT); + line_context = 0; + return DW_DLV_OK; + } + *table_count = line_context->lc_table_count; + if (version != NULL) { + *version = line_context->lc_version_number; + } + *line_context_out = line_context; + return DW_DLV_OK; +} + +int +dwarf_get_ranges_section_name(Dwarf_Debug dbg, + const char **section_name_out, + Dwarf_Error * error) +{ + struct Dwarf_Section_s *sec = 0; + if (error != NULL) { + *error = NULL; + } + sec = &dbg->de_debug_ranges; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *section_name_out = sec->dss_name; + return DW_DLV_OK; +} + +int +dwarf_get_aranges_section_name(Dwarf_Debug dbg, + const char **section_name_out, + Dwarf_Error * error) +{ + struct Dwarf_Section_s *sec = 0; + if (error != NULL) { + *error = NULL; + } + sec = &dbg->de_debug_aranges; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *section_name_out = sec->dss_name; + return DW_DLV_OK; +} +int +dwarf_get_line_section_name(Dwarf_Debug dbg, + const char **section_name_out, + Dwarf_Error * error) +{ + struct Dwarf_Section_s *sec = 0; + if (error != NULL) { + *error = NULL; + } + sec = &dbg->de_debug_line; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *section_name_out = sec->dss_name; + return DW_DLV_OK; +} + +int +dwarf_get_line_section_name_from_die(Dwarf_Die die, + const char **section_name_out, + Dwarf_Error * error) +{ + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + struct Dwarf_Section_s *sec = 0; + + /* ***** BEGIN CODE ***** */ + if (error) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + sec = &dbg->de_debug_line; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *section_name_out = sec->dss_name; + return DW_DLV_OK; +} + +int +dwarf_get_string_section_name(Dwarf_Debug dbg, + const char **section_name_out, + Dwarf_Error * error) +{ + struct Dwarf_Section_s *sec = 0; + + /* ***** BEGIN CODE ***** */ + if (error != NULL) { + *error = NULL; + } + + sec = &dbg->de_debug_str; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *section_name_out = sec->dss_name; + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_b(Dwarf_Die die, + Dwarf_Unsigned * version_out, + Dwarf_Small * table_count, + Dwarf_Line_Context * line_context, + Dwarf_Error * error) +{ + Dwarf_Signed linecount_actuals = 0; + Dwarf_Line *linebuf = 0; + Dwarf_Line *linebuf_actuals = 0; + Dwarf_Signed linecount = 0; + Dwarf_Bool is_new_interface = true; + int res = 0; + Dwarf_Unsigned tcount = 0; + + res = _dwarf_internal_srclines(die, + is_new_interface, + version_out, + table_count, + line_context, + &linebuf, + &linecount, + &linebuf_actuals, + &linecount_actuals, + /* addrlist= */ false, + /* linelist= */ true, + error); + if (res == DW_DLV_OK) { + (*line_context)->lc_new_style_access = true; + } + if (linecount_actuals) { + tcount++; + } + if (linecount) { + tcount++; + } + *table_count = tcount; + return res; +} + +/* New October 2015. */ +int +dwarf_srclines_from_linecontext(Dwarf_Line_Context line_context, + Dwarf_Line** linebuf, + Dwarf_Signed * linecount, + Dwarf_Error * error) +{ + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (!line_context->lc_new_style_access) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + { + Dwarf_Signed lc = + (Dwarf_Signed)line_context->lc_linecount_logicals; + if (lc < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_from_linecontext " + "finds an Impossible " + "lines count"); + return DW_DLV_ERROR; + } + *linebuf = line_context->lc_linebuf_logicals; + *linecount = lc; + } + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_two_level_from_linecontext( + Dwarf_Line_Context line_context, + Dwarf_Line** linebuf, + Dwarf_Signed * linecount, + Dwarf_Line** linebuf_actuals, + Dwarf_Signed * linecount_actuals, + Dwarf_Error * error) +{ + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (!line_context->lc_new_style_access) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + { + Dwarf_Signed lcl = + (Dwarf_Signed)line_context->lc_linecount_logicals; + Dwarf_Signed lca = + (Dwarf_Signed)line_context->lc_linecount_actuals; + if (lcl < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_two_level_from_linecontext " + "finds an Impossible " + "lines count"); + return DW_DLV_ERROR; + } + if (lca < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_two_level_from_linecontext " + "finds an Impossible " + "lines count"); + return DW_DLV_ERROR; + } + + *linebuf = line_context->lc_linebuf_logicals; + *linecount = line_context->lc_linecount_logicals; + *linebuf_actuals = line_context->lc_linebuf_actuals; + *linecount_actuals = line_context->lc_linecount_actuals; + } + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_table_offset(Dwarf_Line_Context line_context, + Dwarf_Unsigned * offset, + Dwarf_Error * error) +{ + if (!line_context ){ + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if ( line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, + DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + *offset = line_context->lc_section_offset; + return DW_DLV_OK; +} + +/* New October 2015. */ +/* If the CU DIE has no DW_AT_comp_dir then + the pointer pushed back to *compilation_directory + will be NULL. + For DWARF5 the line table header has the compilation + directory. */ +int +dwarf_srclines_comp_dir(Dwarf_Line_Context line_context, + const char ** compilation_directory, + Dwarf_Error * error) +{ + if (!line_context ){ + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, + DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + *compilation_directory = + (const char *)line_context->lc_compilation_directory; + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_subprog_count(Dwarf_Line_Context line_context, + Dwarf_Signed * count_out, + Dwarf_Error * error) +{ + if (!line_context ){ + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (count_out) { + Dwarf_Signed co = + (Dwarf_Signed) line_context->lc_subprogs_count; + if (co < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_subprog_count " + "finds an Impossible " + "subprogs count"); + return DW_DLV_ERROR; + } + *count_out = co; + } + return DW_DLV_OK; +} +/* New October 2015. */ +/* Index says which to return. Valid indexes are + 1-lc_subprogs_count + */ +int +dwarf_srclines_subprog_data(Dwarf_Line_Context line_context, + Dwarf_Signed index_in, + const char ** name, + Dwarf_Unsigned *decl_file, + Dwarf_Unsigned *decl_line, + Dwarf_Error *error) +{ + Dwarf_Unsigned index = 0; + Dwarf_Subprog_Entry sub = 0; + /* Negative values not sensible. Leaving traditional + signed interfaces. */ + if (index_in < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_subprog_data " + "finds an Impossible " + "index argument value"); + return DW_DLV_ERROR; + } + index = (Dwarf_Unsigned)index_in; + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + if (index < 1 || index > line_context->lc_subprogs_count) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_INDEX_WRONG); + return DW_DLV_ERROR; + } + sub = line_context->lc_subprogs + (index-1); + *name = (const char *)sub->ds_subprog_name; + *decl_file = sub->ds_decl_file; + *decl_line = sub->ds_decl_line; + return DW_DLV_OK; +} + +/* New March 2018 making iteration through file names. */ +int +dwarf_srclines_files_indexes(Dwarf_Line_Context line_context, + Dwarf_Signed *baseindex, + Dwarf_Signed *file_count, + Dwarf_Signed *endindex, + Dwarf_Error * error) +{ + if (line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + { + Dwarf_Signed bi = + (Dwarf_Signed)line_context->lc_file_entry_baseindex; + Dwarf_Signed fc = + (Dwarf_Signed)line_context->lc_file_entry_count; + Dwarf_Signed ei = + (Dwarf_Signed)line_context->lc_file_entry_endindex; + if (bi < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_subprog_data " + "finds an Impossible " + "file entry index value"); + return DW_DLV_ERROR; + } + if (fc < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_subprog_data " + "finds an Impossible " + "file count index value"); + return DW_DLV_ERROR; + } + if (ei < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_subprog_data " + "finds an Impossible " + "endindex value"); + return DW_DLV_ERROR; + } + *baseindex = bi; + *file_count = fc; + *endindex = ei; + } + return DW_DLV_OK; +} + +int +dwarf_srclines_files_data_b(Dwarf_Line_Context line_context, + Dwarf_Signed index_in, + const char ** name, + Dwarf_Unsigned * directory_index, + Dwarf_Unsigned * last_mod_time, + Dwarf_Unsigned * file_length, + Dwarf_Form_Data16 ** data16ptr, + Dwarf_Error * error) +{ + Dwarf_File_Entry fi = 0; + Dwarf_Signed i =0; + Dwarf_Signed baseindex = 0; + Dwarf_Signed file_count = 0; + Dwarf_Signed endindex = 0; + /* Negative values not sensible. Leaving traditional + signed interfaces. */ + Dwarf_Signed index = index_in; + int res = 0; + + if (index_in < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_files_data_b " + "passes an Impossible " + "index argument value"); + return DW_DLV_ERROR; + } + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + + /* Special accommodation of the special gnu experimental + version number (a high number) so we cannot just + say '5 or greater'. This is awkward, but at least + if there is a version 6 or later it still allows + the experimental table. */ + res = dwarf_srclines_files_indexes(line_context, &baseindex, + &file_count, &endindex, error); + if (res != DW_DLV_OK) { + return res; + } + fi = line_context->lc_file_entries; + if (baseindex < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_file_data_b " + "finds an Impossible " + "file entry index value"); + return DW_DLV_ERROR; + } + if (file_count < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_file_data_b " + "finds an Impossible " + "file count value"); + return DW_DLV_ERROR; + } + if (endindex < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_file_data_b " + "finds an Impossible " + "endindex value"); + return DW_DLV_ERROR; + } + + if (index < baseindex || index >= endindex) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_INDEX_WRONG); + return DW_DLV_ERROR; + } + for ( i = baseindex;i < index; i++) { + fi = fi->fi_next; + if (!fi) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_HEADER_CORRUPT); + return DW_DLV_ERROR; + } + } + + if (name) { + *name = (const char *)fi->fi_file_name; + } + if (directory_index) { + *directory_index = fi->fi_dir_index; + } + if (last_mod_time) { + *last_mod_time = fi->fi_time_last_mod; + } + if (file_length) { + *file_length = fi->fi_file_length; + } + if (data16ptr) { + if (fi->fi_md5_present) { + *data16ptr = &fi->fi_md5_value; + } else { + *data16ptr = 0; + } + } + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_include_dir_count(Dwarf_Line_Context line_context, + Dwarf_Signed * count, + Dwarf_Error * error) +{ + Dwarf_Signed scount = 0; + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + scount = (Dwarf_Signed)line_context->lc_include_directories_count; + if (scount < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_COUNT_WRONG, + "DW_DLE_LINE_COUNT_WRONG " + "Call to dwarf_srclines_include_dir_count " + "finds an Impossible " + "include directories count"); + return DW_DLV_ERROR; + } + *count = scount; + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_include_dir_data(Dwarf_Line_Context line_context, + Dwarf_Signed index_in, + const char ** name, + Dwarf_Error * error) +{ + /* It never made sense that the srclines used a signed count. + But that cannot be fixed in interfaces for compatibility. + So we adjust here. */ + Dwarf_Unsigned index = (Dwarf_Unsigned)index_in; + unsigned int version = 0; + + if (index_in < 0) { + _dwarf_error_string(line_context->lc_dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "Call to dwarf_srclines_include_dir_data " + "finds an Impossible " + "include directories count"); + return DW_DLV_ERROR; + } + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + version = line_context->lc_version_number; + /* Remember that 0xf006 is the version of + the experimental line table */ + if (version == DW_LINE_VERSION5) { + if (index >= line_context->lc_include_directories_count) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_INDEX_WRONG); + return DW_DLV_ERROR; + } + *name = (const char *) + (line_context->lc_include_directories[index]); + } else { + if (index < 1 || + index > line_context->lc_include_directories_count) { + _dwarf_error(line_context->lc_dbg, error, + DW_DLE_LINE_CONTEXT_INDEX_WRONG); + return DW_DLV_ERROR; + } + *name = (const char *) + (line_context->lc_include_directories[index-1]); + } + return DW_DLV_OK; +} + +/* New October 2015. */ +int +dwarf_srclines_version(Dwarf_Line_Context line_context, + Dwarf_Unsigned *version_out, + Dwarf_Small *table_count_out, + Dwarf_Error *error) +{ + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_BOTCH); + return DW_DLV_ERROR; + } + *version_out = line_context->lc_version_number; + *table_count_out = line_context->lc_table_count; + return DW_DLV_OK; +} + +/* Every line table entry (except DW_DLE_end_sequence, + which is returned using dwarf_lineendsequence()) + potentially has the begin-statement + flag marked 'on'. This returns thru *return_bool, + the begin-statement flag. */ + +int +dwarf_linebeginstatement(Dwarf_Line line, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + if (line == NULL || return_bool == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *return_bool = (line->li_l_data.li_is_stmt); + return DW_DLV_OK; +} + +/* At the end of any contiguous line-table there may be + a DW_LNE_end_sequence operator. + This returns non-zero thru *return_bool + if and only if this 'line' entry was a DW_LNE_end_sequence. + + Within a compilation unit or function there may be multiple + line tables, each ending with a DW_LNE_end_sequence. + Each table describes a contiguous region. + Because compilers may split function code up in arbitrary ways + compilers may need to emit multiple contigous regions (ie + line tables) for a single function. + See the DWARF3 spec section 6.2. */ +int +dwarf_lineendsequence(Dwarf_Line line, + Dwarf_Bool * return_bool, + Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *return_bool = (line->li_l_data.li_end_sequence); + return DW_DLV_OK; +} + +/* Each 'line' entry has a line-number. + If the entry is a DW_LNE_end_sequence the line-number is + meaningless (see dwarf_lineendsequence(), just above). */ +int +dwarf_lineno(Dwarf_Line line, + Dwarf_Unsigned * ret_lineno, Dwarf_Error * error) +{ + if (line == NULL || ret_lineno == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *ret_lineno = (line->li_l_data.li_line); + return DW_DLV_OK; +} + +/* Each 'line' entry has a file-number, an index + into the file table. + If the entry is a DW_LNE_end_sequence the index is + meaningless (see dwarf_lineendsequence(), just above). + The file number returned is an index into the file table + produced by dwarf_srcfiles(), but care is required: the + li_file begins with 1 for DWARF2,3,4 + files, so that the li_file returned here + is 1 greater than its index into the dwarf_srcfiles() + output array. + + And entries from DW_LNE_define_file don't appear in + the dwarf_srcfiles() output so file indexes from here may exceed + the size of the dwarf_srcfiles() output array size. +*/ +int +dwarf_line_srcfileno(Dwarf_Line line, + Dwarf_Unsigned * ret_fileno, Dwarf_Error * error) +{ + if (line == NULL || ret_fileno == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + /* li_file must be <= line->li_context->lc_file_entry_count else + it is trash. li_file 0 means not attributable to + any source file per dwarf2/3 spec. + For DWARF5, li_file < lc_file_entry_count */ + *ret_fileno = (line->li_l_data.li_file); + return DW_DLV_OK; +} + +/* Each 'line' entry has an is_addr_set attribute. + If the entry is a DW_LNE_set_address, return TRUE through + the *is_addr_set pointer. */ +int +dwarf_line_is_addr_set(Dwarf_Line line, + Dwarf_Bool *is_addr_set, Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *is_addr_set = (line->li_l_data.li_is_addr_set); + return DW_DLV_OK; +} + +/* Each 'line' entry has a line-address. + If the entry is a DW_LNE_end_sequence the adddress + is one-beyond the last address this contigous region + covers, so the address is not inside the region, + but is just outside it. */ +int +dwarf_lineaddr(Dwarf_Line line, + Dwarf_Addr * ret_lineaddr, Dwarf_Error * error) +{ + if (line == NULL || ret_lineaddr == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *ret_lineaddr = (line->li_address); + return DW_DLV_OK; +} + +/* Each 'line' entry has a column-within-line (offset + within the line) where the + source text begins. + If the entry is a DW_LNE_end_sequence the line-number is + meaningless (see dwarf_lineendsequence(), just above). + Lines of text begin at column 1. The value 0 + means the line begins at the left edge of the line. + (See the DWARF3 spec, section 6.2.2). + So 0 and 1 mean essentially the same thing. + dwarf_lineoff_b() is new in December 2011. + */ +int +dwarf_lineoff_b(Dwarf_Line line, + Dwarf_Unsigned * ret_lineoff, Dwarf_Error * error) +{ + if (line == NULL || ret_lineoff == 0) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + + *ret_lineoff = line->li_l_data.li_column; + return DW_DLV_OK; +} + +static int +_dwarf_filename(Dwarf_Line_Context context, + Dwarf_Unsigned fileno_in, + char **ret_filename, + const char *callername, + Dwarf_Error *error) +{ + Dwarf_Signed i = 0; + Dwarf_File_Entry file_entry = 0; + Dwarf_Debug dbg = context->lc_dbg; + int res = 0; + Dwarf_Signed baseindex = 0; + Dwarf_Signed file_count = 0; + Dwarf_Signed endindex = 0; + /* Negative values not sensible. Leaving traditional + signed interfaces in place. */ + Dwarf_Signed fileno = (Dwarf_Signed)fileno_in; + unsigned linetab_version = context->lc_version_number; + + if (fileno < 0) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_LINE_COUNT_WRONG " + "Call to %s " + "finds an Impossible " + "file number ", + (char *)callername); + _dwarf_error_string(dbg,error, + DW_DLE_LINE_COUNT_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } +#if 0 + if (fileno_in >= context->lc_file_entry_count) { + _dwarf_error_string(dbg,error, DW_DLE_NO_FILE_NAME, + "DW_DLE_NO_FILE_NAME " + "A file number is too larg. Corrupt dwarf"); + return DW_DLV_ERROR; + } +#endif + res = dwarf_srclines_files_indexes(context, &baseindex, + &file_count, &endindex, error); + if (res != DW_DLV_OK) { + return res; + } + { + Dwarf_Signed bi = + (Dwarf_Signed)context->lc_file_entry_baseindex; + Dwarf_Signed fc = + (Dwarf_Signed)context->lc_file_entry_count; + Dwarf_Signed ei = + (Dwarf_Signed)context->lc_file_entry_endindex; + if (bi < 0) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_LINE_INDEX_WRONG " + "Call to %s " + "finds an Impossible " + "base index ", + (char *)callername); + _dwarf_error_string(dbg,error, + DW_DLE_LINE_COUNT_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (fc < 0) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_LINE_COUNT_WRONG " + "Call to %s " + "finds an Impossible " + "file entry count ", + (char *)callername); + _dwarf_error_string(dbg,error, + DW_DLE_LINE_COUNT_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (ei < 0) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_LINE_INDEX_WRONG " + "Call to %s " + "finds an Impossible " + "end index ", + (char *)callername); + _dwarf_error_string(dbg,error, + DW_DLE_LINE_COUNT_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + + /* FIXME: what about comparing to file_count? */ + if (fileno >= endindex) { + dwarfstring m; /* ok constructor_fixed */ + + dwarfstring_constructor_fixed(&m, 200); + dwarfstring_append_printf_i(&m, + "DW_DLE_NO_FILE_NAME: the file number is %d ", + fileno); + dwarfstring_append_printf_u(&m, + "( this is a DWARF 0x%x linetable)", + linetab_version); + dwarfstring_append_printf_i(&m, + " yet the highest allowed file name index is %d.", + endindex-1); + _dwarf_error_string(dbg, error, DW_DLE_NO_FILE_NAME, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } else { + if (linetab_version <= DW_LINE_VERSION4 || + linetab_version == EXPERIMENTAL_LINE_TABLES_VERSION) { + if (!fileno) { + return DW_DLV_NO_ENTRY; + } else { + /* else ok */ + } + } else { + /* Remember that 0xf006 is the version of + the experimental line table */ + /* DW_LINE_VERSION5 so file index 0 is fine */ + } + } + + file_entry = context->lc_file_entries; + /* zero fileno allowed for DWARF5 table. For DWARF4, + zero fileno handled above. */ + for (i = baseindex; i < fileno ; i++) { + file_entry = file_entry->fi_next; + } + + res = create_fullest_file_path(dbg, + file_entry,context, ret_filename,error); + return res; +} + +int +dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, + Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + if (line->li_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL); + return DW_DLV_ERROR; + } + return _dwarf_filename(line->li_context, + line->li_l_data.li_file, ret_linesrc, + "dwarf_linesrc",error); +} + +/* Every line table entry potentially has the basic-block-start + flag marked 'on'. This returns thru *return_bool, + the basic-block-start flag. +*/ +int +dwarf_lineblock(Dwarf_Line line, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + *return_bool = (line->li_l_data.li_basic_block); + return DW_DLV_OK; +} + +/* We gather these into one call as it's likely one + will want all or none of them. */ +int +dwarf_prologue_end_etc(Dwarf_Line line, + Dwarf_Bool * prologue_end, + Dwarf_Bool * epilogue_begin, + Dwarf_Unsigned * isa, + Dwarf_Unsigned * discriminator, + Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + *prologue_end = line->li_l_data.li_prologue_end; + *epilogue_begin = + line->li_l_data.li_epilogue_begin; + *isa = line->li_l_data.li_isa; + *discriminator = line->li_l_data.li_discriminator; + return DW_DLV_OK; +} + +int +dwarf_linelogical(Dwarf_Line line, + Dwarf_Unsigned * logical, + Dwarf_Error* error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + *logical = line->li_l_data.li_line; + return DW_DLV_OK; +} + +int +dwarf_linecontext(Dwarf_Line line, + Dwarf_Unsigned * context, + Dwarf_Error* error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + *context = (line->li_l_data.li_call_context); + return DW_DLV_OK; +} + +int +dwarf_line_subprogno(Dwarf_Line line, + Dwarf_Unsigned * subprog, + Dwarf_Error * error) +{ + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + *subprog = (line->li_l_data.li_subprogram); + return DW_DLV_OK; +} + +int +dwarf_line_subprog(Dwarf_Line line, + char ** subprog_name, + char ** decl_filename, + Dwarf_Unsigned * decl_line, + Dwarf_Error * error) +{ + Dwarf_Unsigned subprog_no; + Dwarf_Subprog_Entry subprog; + Dwarf_Debug dbg; + int res; + + if (line == NULL) { + _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL); + return DW_DLV_ERROR; + } + if (line->li_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL); + return DW_DLV_ERROR; + } + dbg = line->li_context->lc_dbg; + subprog_no = line->li_l_data.li_subprogram; + if (subprog_no == 0) { + *subprog_name = NULL; + *decl_filename = NULL; + *decl_line = 0; + return DW_DLV_OK; + } + if (subprog_no > line->li_context->lc_subprogs_count) { + _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME); + return DW_DLV_ERROR; + } + /* Adjusting for 1 origin subprog no */ + subprog = &line->li_context->lc_subprogs[subprog_no - 1]; + *subprog_name = (char *)subprog->ds_subprog_name; + *decl_line = subprog->ds_decl_line; + res = _dwarf_filename(line->li_context, + subprog->ds_decl_file, + decl_filename, + "dwarf_line_subprog",error); + if (res != DW_DLV_OK) { + *decl_filename = NULL; + return res; + } + return DW_DLV_OK; +} + +/* This is another line_context_destructor. */ +static void +delete_line_context_itself(Dwarf_Line_Context context) +{ + + Dwarf_Debug dbg = 0; + Dwarf_File_Entry fe = 0; + + if (context->lc_magic != DW_CONTEXT_MAGIC) { + /* Something is wrong. */ + return; + } + dbg = context->lc_dbg; + fe = context->lc_file_entries; + while (fe) { + Dwarf_File_Entry fenext = fe->fi_next; + fe->fi_next = 0; + free(fe); + fe = fenext; + } + context->lc_file_entries = 0; + context->lc_file_entry_count = 0; + context->lc_file_entry_baseindex = 0; + context->lc_file_entry_endindex = 0; + if (context->lc_subprogs) { + free(context->lc_subprogs); + context->lc_subprogs = 0; + } + free(context->lc_directory_format_values); + context->lc_directory_format_values = 0; + free(context->lc_file_format_values); + context->lc_file_format_values = 0; + if (context->lc_include_directories) { + free(context->lc_include_directories); + context->lc_include_directories = 0; + } + context->lc_magic = 0xdead; + dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT); +} + +/* It's impossible for callers of dwarf_srclines() to get to and + free all the resources (in particular, the li_context and its + lc_file_entries). + So this function, new July 2005, does it. + + Those using standard DWARF should use + dwarf_srclines_b() and dwarf_srclines_dealloc_b() + instead of dwarf_srclines and dwarf_srclines_dealloc() + as that gives access to various bits of useful information. + + New October 2015. + This should be used to deallocate all + lines data that is + set up by dwarf_srclines_b(). + This and dwarf_srclines_b() are now (October 2015) + the preferred routine to use. */ +void +dwarf_srclines_dealloc_b(Dwarf_Line_Context line_context) +{ + Dwarf_Line *linestable = 0; + Dwarf_Signed linescount = 0; + Dwarf_Signed i = 0; + Dwarf_Debug dbg = 0; + + if (!line_context) { + return; + } + if (!line_context || line_context->lc_magic != DW_CONTEXT_MAGIC) { + /* Something is badly wrong here.*/ + return; + } + dbg = line_context->lc_dbg; + linestable = line_context->lc_linebuf_logicals; + if (linestable) { + linescount = line_context->lc_linecount_logicals; + if (linescount >= 0) { + for (i = 0; i < linescount ; ++i) { + dwarf_dealloc(dbg, linestable[i], DW_DLA_LINE); + } + } /* else bogus negative count. do not dealloc things. */ + dwarf_dealloc(dbg, linestable, DW_DLA_LIST); + } + line_context->lc_linebuf_logicals = 0; + line_context->lc_linecount_logicals = 0; + + linestable = line_context->lc_linebuf_actuals; + if (linestable) { + linescount = line_context->lc_linecount_actuals; + if (linescount >= 0) { + for (i = 0; i lc_linebuf_actuals = 0; + line_context->lc_linecount_actuals = 0; + delete_line_context_itself(line_context); +} + +/* There is an error, so count it. If we are printing + errors by command line option, print the details. */ +void +_dwarf_print_header_issue(Dwarf_Debug dbg, + const char *specific_msg, + Dwarf_Small *data_start, + Dwarf_Signed value, + unsigned index, + unsigned tabv, + unsigned linetabv, + int *err_count_out) +{ + if (!err_count_out) { + return; + } + /* Are we in verbose mode */ + if (dwarf_cmdline_options.check_verbose_mode){ + dwarfstring m1; + + dwarfstring_constructor(&m1); + dwarfstring_append(&m1, + "\n*** DWARF CHECK: " + ".debug_line: "); + dwarfstring_append(&m1,(char *)specific_msg); + dwarfstring_append_printf_i(&m1, + " %" DW_PR_DSd,value); + if (index || tabv || linetabv) { + dwarfstring_append_printf_u(&m1, + "; Mismatch index %u",index); + dwarfstring_append_printf_u(&m1, + " stdval %u",tabv); + dwarfstring_append_printf_u(&m1, + " linetabval %u",linetabv); + } + if (data_start >= dbg->de_debug_line.dss_data && + (data_start < (dbg->de_debug_line.dss_data + + dbg->de_debug_line.dss_size))) { + Dwarf_Unsigned off = + data_start - dbg->de_debug_line.dss_data; + + dwarfstring_append_printf_u(&m1, + " at offset 0x%" DW_PR_XZEROS DW_PR_DUx,off); + dwarfstring_append_printf_u(&m1, + " ( %" DW_PR_DUu " ) ",off); + } else { + dwarfstring_append(&m1, + " (unknown section location) "); + } + dwarfstring_append(&m1,"***\n"); + _dwarf_printf(dbg,dwarfstring_string(&m1)); + dwarfstring_destructor(&m1); + } + *err_count_out += 1; +} + +void +_dwarf_report_bad_lnct( Dwarf_Debug dbg, + Dwarf_Unsigned ltype, + int dlecode, + const char *dlename, + Dwarf_Error *error) +{ + dwarfstring m; /* constructor_static ok */ + dwarfstring f2; /* constructor_static ok */ + const char *typename = 0; + char tnbuf[48]; + char mnbuf[100]; + + dwarfstring_constructor_static(&f2,tnbuf,sizeof(tnbuf)); + dwarf_get_LNCT_name(ltype,&typename); + if (!typename) { + dwarfstring_append_printf_u(&f2, + "Invalid attribute " + " 0x" DW_PR_DUx,ltype); + } else { + dwarfstring_append(&f2,(char *)typename); + } + dwarfstring_constructor_static(&m,mnbuf,sizeof(mnbuf)); + dwarfstring_append_printf_s(&m, + "%s: Unexpected DW_LNCT type",(char *)dlename); + dwarfstring_append_printf_s(&m, + " %s ", + dwarfstring_string(&f2)); + _dwarf_error_string(dbg, error, dlecode, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + dwarfstring_destructor(&f2); +} + +static void +report_ltype_form_issue(Dwarf_Debug dbg, + int ltype, + int form, + const char *splmsg, + Dwarf_Error *error) +{ + dwarfstring m; /* constructor_fixed ok */ + dwarfstring f2; /* construcot_static ok */ + dwarfstring f; /* construcot_static ok */ + const char *formname = 0; + const char *typename = 0; + char fnbuf[32]; + char f2buf[32]; + char mbuf[120]; + + dwarfstring_constructor_static(&f,fnbuf,sizeof(fnbuf)); + dwarfstring_constructor_static(&f2,f2buf,sizeof(f2buf)); + dwarf_get_LNCT_name(ltype,&typename); + if (!typename) { + dwarfstring_append_printf_u(&f2, + "Invalid DW_LNCT " + " 0x" DW_PR_DUx,ltype); + } else { + dwarfstring_append(&f2,(char *)typename); + } + dwarf_get_FORM_name(form,&formname); + if (!formname) { + dwarfstring_append_printf_u(&f, + "Invalid Form Code " + " 0x" DW_PR_DUx,form); + } else { + dwarfstring_append(&f,(char *)formname); + } + dwarfstring_constructor_static(&m,mbuf,sizeof(mbuf)); + dwarfstring_append_printf_s(&m, + "DW_DLE_LNCT_FORM_CODE_NOT_HANDLED: form %s " + "instead of a specifically " + "allowed offset form", + dwarfstring_string(&f)); + dwarfstring_append_printf_s(&m, + " on line type %s", + dwarfstring_string(&f2)); + if (splmsg) { + dwarfstring_append(&m," "); + dwarfstring_append(&m,(char *)splmsg); + } + _dwarf_error_string(dbg, error, + DW_DLE_LNCT_FORM_CODE_NOT_HANDLED, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + dwarfstring_destructor(&f); + dwarfstring_destructor(&f2); +} + +int +_dwarf_decode_line_string_form(Dwarf_Debug dbg, + Dwarf_Unsigned ltype, + Dwarf_Unsigned form, + Dwarf_Unsigned offset_size, + Dwarf_Small **line_ptr, + Dwarf_Small *line_ptr_end, + char **return_str, + Dwarf_Error * error) +{ + int res = 0; + + switch (form) { + case DW_FORM_line_strp: { + Dwarf_Small *secstart = 0; + Dwarf_Small *secend = 0; + Dwarf_Small *strptr = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Small *offsetptr = *line_ptr; + + res = _dwarf_load_section(dbg, + &dbg->de_debug_line_str,error); + if (res != DW_DLV_OK) { + return res; + } + + secstart = dbg->de_debug_line_str.dss_data; + secend = secstart + dbg->de_debug_line_str.dss_size; + + READ_UNALIGNED_CK(dbg, offset, Dwarf_Unsigned, + offsetptr, offset_size, + error,line_ptr_end); + *line_ptr += offset_size; + strptr = secstart + offset; + res = _dwarf_check_string_valid(dbg, + secstart,strptr,secend, + DW_DLE_LINE_STRP_OFFSET_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + *return_str = (char *) strptr; + return DW_DLV_OK; + } + case DW_FORM_string: { + Dwarf_Small *secend = line_ptr_end; + Dwarf_Small *strptr = *line_ptr; + + res = _dwarf_check_string_valid(dbg, + strptr ,strptr,secend, + DW_DLE_LINE_STRING_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + *return_str = (char *)strptr; + *line_ptr += strlen((const char *)strptr) + 1; + return DW_DLV_OK; + } + default: + report_ltype_form_issue(dbg, ltype, + form,0,error); + return DW_DLV_ERROR; + } +} + +int +_dwarf_decode_line_udata_form(Dwarf_Debug dbg, + Dwarf_Unsigned ltype, + Dwarf_Unsigned form, + Dwarf_Small **line_ptr, + Dwarf_Unsigned *return_val, + Dwarf_Small *line_end_ptr, + Dwarf_Error * error) +{ + Dwarf_Unsigned val = 0; + Dwarf_Small * lp = *line_ptr; + const char *splmsg = 0; + + /* We will not get here for DW_LNCT_MD5, + no need to consider DW_FORM_data16. */ + switch (form) { + case DW_FORM_udata: + if (ltype != DW_LNCT_directory_index && + ltype != DW_LNCT_timestamp && + ltype != DW_LNCT_GNU_decl_file && + ltype != DW_LNCT_GNU_decl_line && + ltype != DW_LNCT_size) { + break; + } + DECODE_LEB128_UWORD_CK(lp, val,dbg,error,line_end_ptr); + *return_val = val; + *line_ptr = lp; + return DW_DLV_OK; + case DW_FORM_data1: + if (ltype != DW_LNCT_directory_index && + ltype != DW_LNCT_GNU_decl_file && + ltype != DW_LNCT_GNU_decl_line && + ltype != DW_LNCT_size) { + break; + } + *return_val = *lp; + *line_ptr = lp+1; + return DW_DLV_OK; + case DW_FORM_data2: + if (ltype != DW_LNCT_directory_index && + ltype != DW_LNCT_GNU_decl_file && + ltype != DW_LNCT_GNU_decl_line && + ltype != DW_LNCT_size) { + break; + } + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + lp,DWARF_HALF_SIZE, + error,line_end_ptr); + *return_val = val; + *line_ptr = lp + DWARF_HALF_SIZE; + return DW_DLV_OK; + case DW_FORM_data4: + if (ltype != DW_LNCT_timestamp && + ltype != DW_LNCT_GNU_decl_file && + ltype != DW_LNCT_GNU_decl_line && + ltype != DW_LNCT_size) { + break; + } + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + lp,DWARF_32BIT_SIZE, + error,line_end_ptr); + *return_val = val; + *line_ptr = lp + DWARF_32BIT_SIZE; + return DW_DLV_OK; + case DW_FORM_block: { + Dwarf_Unsigned leblen = 0; + Dwarf_Unsigned length = 0; + Dwarf_Small *dataptr = 0; + + if (ltype != DW_LNCT_timestamp) { + break; + } + DECODE_LEB128_UWORD_LEN_CK(lp, length, leblen, + dbg,error,line_end_ptr); + dataptr = lp +leblen; + if (length > sizeof(Dwarf_Unsigned)) { + splmsg = "FORM_block length bigger than Dwarf_Unsigned"; + break; + } + if (dataptr >= line_end_ptr ) { + splmsg = "FORM_block data starts past end of data"; + break; + } + if ((dataptr + length) > line_end_ptr) { + splmsg = "FORM_block data runs past end of data"; + break; + } + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + dataptr,length, + error,line_end_ptr); + *return_val = val; + *line_ptr = dataptr+length; + return DW_DLV_OK; + } + + case DW_FORM_data8: + if (ltype != DW_LNCT_size && + ltype != DW_LNCT_size) { + break; + } + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + lp,DWARF_64BIT_SIZE, + error,line_end_ptr); + *return_val = val; + *line_ptr = lp + DWARF_64BIT_SIZE; + return DW_DLV_OK; + default: break; + } + report_ltype_form_issue(dbg, ltype, + form,splmsg,error); + return DW_DLV_ERROR; +} + +void +_dwarf_update_chain_list( Dwarf_Chain chain_line, + Dwarf_Chain *head_chain, Dwarf_Chain *curr_chain) +{ + if (*head_chain == NULL) { + *head_chain = chain_line; + } else { + (*curr_chain)->ch_next = chain_line; + } + *curr_chain = chain_line; +} + +void +_dwarf_free_chain_entries(Dwarf_Debug dbg,Dwarf_Chain head,int count) +{ + int i = 0; + Dwarf_Chain curr_chain = head; + for (i = 0; i < count; i++) { + Dwarf_Chain t = curr_chain; + void *item = t->ch_item; + int itype = t->ch_itemtype; + + if (item && itype) { /* valid DW_DLA types are never 0 */ + dwarf_dealloc(dbg,item,itype); + t->ch_item = 0; + } + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, t, DW_DLA_CHAIN); + } +} + +int +_dwarf_add_to_files_list(Dwarf_Line_Context context, + Dwarf_File_Entry fe) +{ + unsigned int version = context->lc_version_number; + if (!context->lc_file_entries) { + context->lc_file_entries = fe; + } else { + context->lc_last_entry->fi_next = fe; + } + context->lc_last_entry = fe; + context->lc_file_entry_count++; + /* Here we attempt to write code to make it easy to interate + though source file names without having to code specially + for DWARF2,3,4 vs DWARF5 */ + /* Remember that 0xf006 is the version of + the experimental line table */ + if (version == DW_LINE_VERSION5) { + context->lc_file_entry_baseindex = 0; + context->lc_file_entry_endindex = + context->lc_file_entry_count; + } else { + context->lc_file_entry_baseindex = 1; + context->lc_file_entry_endindex = + context->lc_file_entry_count +1; + } + return DW_DLV_OK; +} + +int +_dwarf_line_context_constructor(Dwarf_Debug dbg, void *m) +{ + Dwarf_Line_Context line_context = (Dwarf_Line_Context)m; + /* dwarf_get_alloc ensures the bytes are all zero + when m is passed to us. */ + line_context->lc_magic = DW_CONTEXT_MAGIC; + line_context->lc_dbg = dbg; + return DW_DLV_OK; +} + +/* This cleans up a contex record. + The lines tables (actuals and logicals) + are themselves items that will + be dealloc'd either manually + or, at closing the libdwarf dbg, + automatically. So we DO NOT + touch the lines tables here + See also: delete_line_context_itself() +*/ +void +_dwarf_line_context_destructor(void *m) +{ + Dwarf_Line_Context line_context = (Dwarf_Line_Context)m; + if (line_context->lc_magic != DW_CONTEXT_MAGIC) { + /* Nothing is safe, do nothing. */ + return; + } + if (line_context->lc_include_directories) { + free(line_context->lc_include_directories); + line_context->lc_include_directories = 0; + line_context->lc_include_directories_count = 0; + } + if (line_context->lc_file_entries) { + Dwarf_File_Entry fe = line_context->lc_file_entries; + while(fe) { + Dwarf_File_Entry t = fe; + fe = t->fi_next; + t->fi_next = 0; + free(t); + } + line_context->lc_file_entries = 0; + line_context->lc_last_entry = 0; + line_context->lc_file_entry_count = 0; + line_context->lc_file_entry_baseindex = 0; + line_context->lc_file_entry_endindex = 0; + } + free(line_context->lc_directory_format_values); + line_context->lc_directory_format_values = 0; + free(line_context->lc_file_format_values); + line_context->lc_file_format_values = 0; + + if (line_context->lc_subprogs) { + free(line_context->lc_subprogs); + line_context->lc_subprogs = 0; + line_context->lc_subprogs_count = 0; + } + line_context->lc_magic = 0; + return; +} diff --git a/src/lib/libdwarf/dwarf_line.h b/src/lib/libdwarf/dwarf_line.h new file mode 100644 index 0000000..7fa8a9a --- /dev/null +++ b/src/lib/libdwarf/dwarf_line.h @@ -0,0 +1,491 @@ +/* +Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2009-2023 David Anderson. All Rights Reserved. +Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#define DW_EXTENDED_OPCODE 0 + +/* + This is used as the starting value for an algorithm + to get the minimum difference between 2 values. + UINT_MAX is used as our approximation to infinity. +*/ +#define MAX_LINE_DIFF UINT_MAX + +/* This is for a sanity check on line + table extended opcodes. + It is entirely arbitrary, and 100 is surely too small if + someone was inserting strings in the opcode. */ +#define DW_LNE_LEN_MAX 100 + +/* + This structure is used to build a list of all the + files that are used in the current compilation unit. + All of the fields execpt fi_next have meanings that + are obvious from section 6.2.4 of the Libdwarf Doc. + Because of DW_LNE_define_file we + make this a list, not an array. +*/ +struct Dwarf_File_Entry_s { + struct Dwarf_File_Entry_s *fi_next; + + /* Points to string naming the file: DW_LNCT_path. */ + Dwarf_Small *fi_file_name; + /* Points to string naming the source, with \n endings + and null terminated (UTF-8). Embedded source. */ + Dwarf_Small *fi_llvm_source; + + /* Index into the list of directories of the directory in which + this file exits. + For DWARF5, values are 0 to N-1 + For DWARF4 etc values are 1 to N + so the test for overrun differs. */ + Dwarf_Unsigned fi_dir_index; + + /* Time of last modification of the file. */ + Dwarf_Unsigned fi_time_last_mod; + + /* Length in bytes of the file. */ + Dwarf_Unsigned fi_file_length; + + Dwarf_Small * fi_gnu_subprogram_name; + Dwarf_Unsigned fi_gnu_decl_file; + Dwarf_Unsigned fi_gnu_decl_line; + + Dwarf_Form_Data16 fi_md5_value; + char fi_dir_index_present; + char fi_time_last_mod_present; + char fi_file_length_present; + char fi_md5_present; + char fi_gnu_decl_file_present; + char fi_gnu_decl_line_present; +}; + +/* Part of two-level line tables support. */ +struct Dwarf_Subprog_Entry_s { + Dwarf_Small *ds_subprog_name; + Dwarf_Unsigned ds_decl_file; + Dwarf_Unsigned ds_decl_line; +}; + +typedef struct Dwarf_Subprog_Entry_s *Dwarf_Subprog_Entry; + +struct Dwarf_Unsigned_Pair_s { + Dwarf_Unsigned up_first; + Dwarf_Unsigned up_second; +}; + +/* + This structure provides the context in which the fields of + a Dwarf_Line structure are interpreted. They come from the + statement program prologue. **Updated by dwarf_srclines in + dwarf_line.c. + + lc_magic will be DW_CONTEXT_MAGIC unless there is a serious + programming error somewhere. + It's set zero when a Line_Context is deallocated. + Any other value indicates there is bug somewhere. +*/ +#define DW_CONTEXT_MAGIC 0xd00d1111 +struct Dwarf_Line_Context_s { + unsigned lc_magic; + + /* lc_new_style_access is non-zero if this was allocated + via a dwarf_srclines_b() call or equivalent. + Otherwise this is 0. */ + unsigned char lc_new_style_access; + + Dwarf_Unsigned lc_unit_length; /* all versions */ + + /* The section offset (in .debug_line + or .debug_line.dwo of the line table */ + Dwarf_Unsigned lc_section_offset; + + /* 2 for DWARF2, 3 for DWARF3, 4 for DWARF4, 5 for DWARF5. + 0xf006 for experimental two-level line tables. */ + Dwarf_Half lc_version_number; /* all versions */ + + /* Total length of the line data for this CU */ + Dwarf_Unsigned lc_total_length; /* all versions */ + + /* Length of the initial length field itself. */ + Dwarf_Half lc_length_field_length; /* all versions */ + + /* address size and segment sizefields new in DWARF5 header. */ + Dwarf_Small lc_address_size; /* DWARF5 */ + Dwarf_Small lc_segment_selector_size; /* DWARF5 */ + + Dwarf_Unsigned lc_header_length; /* all versions */ + + Dwarf_Unsigned lc_prologue_length; + Dwarf_Unsigned lc_actuals_table_offset; + Dwarf_Unsigned lc_logicals_table_offset; + Dwarf_Small lc_minimum_instruction_length; /* all versions */ + Dwarf_Ubyte lc_maximum_ops_per_instruction; /*DWARF5*/ + + /* Start and end of this CU line area. pf_line_ptr_start + + pf_total_length + pf_length_field_length == pf_line_ptr_end. + Meaning lc_line_ptr_start is before the length info. */ + Dwarf_Small *lc_line_ptr_start; + Dwarf_Small *lc_line_ptr_end; + /* Start of the lines themselves. */ + Dwarf_Small *lc_line_ptr_lines; + + /* Used to check that decoding of the line prologue + is done right. */ + Dwarf_Small *lc_line_prologue_start; + + Dwarf_Small lc_default_is_stmt; /* all versions */ + Dwarf_Sbyte lc_line_base; /* all versions */ + Dwarf_Small lc_line_range; /* all versions */ + + /* Highest std opcode (+1). */ + Dwarf_Small lc_opcode_base; /* all versions */ + /* pf_opcode_base -1 entries (each a count, + normally the value of + each entry is 0 or 1). */ + Dwarf_Small *lc_opcode_length_table; /* all versions */ + + /* The number to treat as standard ops. This is a special + accommodation of gcc using the new standard opcodes but not + updating the version number. + It's legal dwarf2, but much better + for the user to understand as dwarf3 when 'it looks ok'. */ + Dwarf_Small lc_std_op_count; + + /* ======== includes =========*/ + /* Points to the portion of .debug_line section that + contains a list of strings naming the included + directories. Do not free(). + No free even DWARF5? + An array of pointers to strings. */ + /* DWARF 2,3,4: does not name the current dir of the compilation. + DWARF5: Initial entry is the dir of the compilation. */ + Dwarf_Small **lc_include_directories; + /* Count of the number of included directories. */ + Dwarf_Unsigned lc_include_directories_count; + + /* count of uleb pairs */ + Dwarf_Unsigned lc_directory_entry_format_count; /* DWARF5 */ + + Dwarf_Unsigned lc_directory_entry_values_count; /* DWARF5 */ + + /* This must be freed,malloc space, an array of the + values of each entry. DWARF5 */ + struct Dwarf_Unsigned_Pair_s * lc_directory_format_values; + + /* ======== end includes =========*/ + + /* ======== file names =========*/ + + Dwarf_Unsigned lc_file_name_format_count; /* DWARF5 */ + Dwarf_Unsigned * lc_file_name_format; /* DWARF5 */ + Dwarf_Unsigned lc_file_entry_values_count; /* DWARF5 */ + /* This must be freed,malloc space, an array of the + values of each entry. */ + struct Dwarf_Unsigned_Pair_s * lc_file_format_values; /* DWARF5 */ + + /* Points to a singly-linked list of entries providing info + about source files + for the current set of Dwarf_Line structures. + The initial entry on the list is 'file 1' + per DWARF2,3,4 rules. + And so on. lc_last_entry points at the last entry + in the list (so we can easily expand the list). + It's a list (not a table) since we may encounter + DW_LNE_define_file entries. + For Dwarf5 the initial entry is 'file 0' + and must match the CU-DIE DW_AT_name string. */ + Dwarf_File_Entry lc_file_entries; + Dwarf_File_Entry lc_last_entry; + /* Count of number of source files for this set of Dwarf_Line + structures. */ + Dwarf_Unsigned lc_file_entry_count; /* all versions */ + /* Values Easing the process of indexing + through lc_file_entries. */ + Dwarf_Unsigned lc_file_entry_baseindex; + Dwarf_Unsigned lc_file_entry_endindex; + /* ======== end file names =========*/ + + /* Points to an array of subprogram entries. + With Two level line tables this may be non-zero. + An array of Dwarf_Subprogram_Entry_s structs. */ + Dwarf_Subprog_Entry lc_subprogs; + /* Count of the number of subprogram entries + With Two level line tables this may be non-zero. */ + Dwarf_Unsigned lc_subprogs_count; + + /* Count of the number of lines for this cu. */ + Dwarf_Unsigned lc_line_count; + + /* Points to name of compilation directory. + That string is in a .debug section (DWARF 2,3,4) + so do not free this. For DWARF5 must be the same + as lc_include_directories[0] */ + Dwarf_Small *lc_compilation_directory; + Dwarf_Debug lc_dbg; + /* zero table count is skeleton, or just missing names. + 1 is standard table. + 2 means two-level table (experimental) + Other is a bug somewhere. */ + Dwarf_Small lc_table_count; + Dwarf_Bool lc_is_single_table; + + /* For standard line tables the logicals are + the only tables and linecount_actuals is 0. */ + Dwarf_Line *lc_linebuf_logicals; + Dwarf_Unsigned lc_linecount_logicals; + + /* Non-zero only if two-level table with actuals */ + Dwarf_Line *lc_linebuf_actuals; + Dwarf_Unsigned lc_linecount_actuals; +}; + +/* The line table set of registers. + The state machine state variables. + Using names from the DWARF documentation + but preceded by lr_. */ +struct Dwarf_Line_Registers_s { + Dwarf_Addr lr_address; /* DWARF2 */ + Dwarf_Unsigned lr_file ; /* DWARF2 */ + Dwarf_Unsigned lr_line ; /* DWARF2 */ + Dwarf_Unsigned lr_column ; /* DWARF2 */ + Dwarf_Bool lr_is_stmt; /* DWARF2 */ + Dwarf_Bool lr_basic_block; /* DWARF2 */ + Dwarf_Bool lr_end_sequence; /* DWARF2 */ + Dwarf_Bool lr_prologue_end; /* DWARF3 */ + Dwarf_Bool lr_epilogue_begin; /* DWARF3 */ + Dwarf_Small lr_isa; /* DWARF3 */ + Dwarf_Unsigned lr_op_index; /* DWARF4, operation + within VLIW instruction. */ + Dwarf_Unsigned lr_discriminator; /* DWARF4 */ + Dwarf_Unsigned lr_call_context; /* EXPERIMENTAL */ + Dwarf_Unsigned lr_subprogram; /* EXPERIMENTAL */ +}; +typedef struct Dwarf_Line_Registers_s *Dwarf_Line_Registers; +void _dwarf_set_line_table_regs_default_values( + Dwarf_Line_Registers regs, + unsigned lineversion, + Dwarf_Bool is_stmt); + +/* + This structure defines a row of the line table. + All of the fields + same meaning that is defined in Section 6.2.2 + of the Libdwarf Document. + +*/ +struct Dwarf_Line_s { + Dwarf_Addr li_address; /* pc value of machine instr */ +#if 1 + struct li_inner_s { + /* New as of DWARF4 */ + Dwarf_Unsigned li_discriminator; + + /* int identifying src file + li_file is a number 1-N, indexing into a conceptual + source file table as described in dwarf2/3 spec line + table doc. (see Dwarf_File_Entry lc_file_entries; and + Dwarf_Unsigned lc_file_entry_count;) */ + Dwarf_Unsigned li_file; + + /* In single-level table is line number in + source file. 1-N + In logicals table is not used. + In actuals table is index into logicals table. 1-N*/ + Dwarf_Unsigned li_line; + + Dwarf_Half li_column; /*source file column number 1-N */ + Dwarf_Small li_isa; /*New as of DWARF4. */ + + /* Two-level line tables. + Is index from logicals table + into logicals table. 1-N */ + Dwarf_Unsigned li_call_context; + + /* Two-level line tables. + is index into subprograms table. 1-N */ + Dwarf_Unsigned li_subprogram; + + /* To save space, use bit flags. */ + /* indicate start of stmt */ + unsigned li_is_stmt:1; + + /* indicate start basic block */ + unsigned li_basic_block:1; + + /* first post sequence instr */ + unsigned li_end_sequence:1; + + unsigned li_prologue_end:1; + unsigned li_epilogue_begin:1; + + /* Mark a line record as being DW_LNS_set_address. */ + unsigned li_is_addr_set:1; + } li_l_data; +#endif /* 1 */ + Dwarf_Line_Context li_context; /* assoc Dwarf_Line_Context_s */ + + /* Set only on the actuals table of a two-level line table. + Assists in the dealloc code. + */ + Dwarf_Bool li_is_actuals_table; +}; + +int _dwarf_line_address_offsets(Dwarf_Debug dbg, + Dwarf_Die die, + Dwarf_Addr ** addrs, + Dwarf_Off ** offs, + Dwarf_Unsigned * returncount, + Dwarf_Error * err); +int _dwarf_internal_srclines(Dwarf_Die die, + Dwarf_Bool old_interface, + Dwarf_Unsigned * version, + Dwarf_Small * table_count, + Dwarf_Line_Context *line_context, + Dwarf_Line ** linebuf, + Dwarf_Signed * count, + Dwarf_Line ** linebuf_actuals, + Dwarf_Signed * count_actuals, + Dwarf_Bool doaddrs, + Dwarf_Bool dolines, + Dwarf_Error * error); + +/* The LOP, WHAT_IS_OPCODE stuff is here so it can + be reused in 3 places. Seemed hard to keep + the 3 places the same without an inline func or + a macro. + + Handling the line section where the header and the + file being processed do not match (unusual, but + planned for in the design of .debug_line) + is too tricky to recode this several times and keep + it right. + +*/ +#define LOP_EXTENDED 1 +#define LOP_DISCARD 2 +#define LOP_STANDARD 3 +#define LOP_SPECIAL 4 + +/* ASSERT: sets type to one of the above 4. Never anything else. */ +#define WHAT_IS_OPCODE(type,opcode,base,opcode_length,\ +line_ptr,highest_std) \ + if ((opcode) < (base)) { \ + /* we know we must treat as a standard op \ + or a special case. */ \ + if ((opcode) == DW_EXTENDED_OPCODE) { \ + (type) = LOP_EXTENDED; \ + } else if (((highest_std)+1) >= (base)) { \ + /* == Standard case: compile of \ + dwarf_line.c and object \ + have same standard op codes set. \ + == Special case: compile of dwarf_line.c \ + has things in standard op codes list \ + in dwarf.h header not \ + in the object: handle this as a standard \ + op code in switch below. \ + The header special ops overlap the \ + object standard ops. \ + The new standard op codes will not \ + appear in the object. */ \ + (type) = LOP_STANDARD; \ + } else { \ + /* These are standard opcodes in the object \ + ** that were not defined in the header \ + ** at the time dwarf_line.c \ + ** was compiled. Provides the ability of \ + ** out-of-date dwarf reader to read newer \ + ** line table data transparently. \ + */ \ + (type) = LOP_DISCARD; \ + } \ + } else { \ + /* Is a special op code. */ \ + (type) = LOP_SPECIAL; \ + } + +/* The following is from the dwarf definition of 'ubyte' + and is specifically mentioned in section 6.2.5.1, page 54 + of the Rev 2.0.0 dwarf specification. +*/ + +#define MAX_LINE_OP_CODE 255 + +/* Operand counts per standard operand. + The initial zero is for DW_LNS_copy. + This is an economical way to verify we understand the table + of standard-opcode-lengths in the line table prologue. */ +#define STANDARD_OPERAND_COUNT_DWARF2 9 +#define STANDARD_OPERAND_COUNT_DWARF3 12 +/* For two-level line tables, we have three additional + standard opcodes. */ +#define STANDARD_OPERAND_COUNT_TWO_LEVEL 15 + +void _dwarf_print_header_issue(Dwarf_Debug dbg, + const char *specific_msg, + Dwarf_Small *data_start, + Dwarf_Signed value, + unsigned index, + unsigned tabv, + unsigned linetabv, + int *err_count_out); +int _dwarf_decode_line_string_form(Dwarf_Debug dbg, + Dwarf_Unsigned attrnum, + Dwarf_Unsigned form, + Dwarf_Unsigned offset_size, + Dwarf_Small **line_ptr, + Dwarf_Small *line_ptr_end, + char **return_str, + Dwarf_Error * error); +int _dwarf_decode_line_udata_form(Dwarf_Debug dbg, + Dwarf_Unsigned attrnum, + Dwarf_Unsigned form, + Dwarf_Small **line_ptr, + Dwarf_Unsigned *return_val, + Dwarf_Small *line_end_ptr, + Dwarf_Error * error); +void _dwarf_report_bad_lnct( Dwarf_Debug dbg, + Dwarf_Unsigned ltype, + int dlecode, + const char * dlename, + Dwarf_Error *err); + +void _dwarf_update_chain_list( Dwarf_Chain chain_line, + Dwarf_Chain *head_chain, Dwarf_Chain *curr_chain); +void _dwarf_free_chain_entries(Dwarf_Debug dbg,Dwarf_Chain head, + int count); + +int _dwarf_line_context_constructor(Dwarf_Debug dbg, void *m); +void _dwarf_line_context_destructor(void *m); + +void _dwarf_print_line_context_record(Dwarf_Debug dbg, + Dwarf_Line_Context line_context); +void _dwarf_context_src_files_destroy(Dwarf_Line_Context context); +int _dwarf_add_to_files_list(Dwarf_Line_Context context, + Dwarf_File_Entry fe); diff --git a/src/lib/libdwarf/dwarf_line_table_reader_common.h b/src/lib/libdwarf/dwarf_line_table_reader_common.h new file mode 100644 index 0000000..1a9d539 --- /dev/null +++ b/src/lib/libdwarf/dwarf_line_table_reader_common.h @@ -0,0 +1,2857 @@ +/* + Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2023 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2015-2015 Google, Inc. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. + +*/ +#include + +/* This is #included twice. Once for + libdwarf callers and one for dwarfdump which prints + the internals. + + This way we have just one blob of code that reads + the table operations. */ + +static unsigned char +dwarf_standard_opcode_operand_count[ +STANDARD_OPERAND_COUNT_TWO_LEVEL] = { + /* DWARF2 */ + 0, + 1, 1, 1, 1, + 0, 0, 0, + 1, + /* Following are new for DWARF3. */ + 0, 0, 1, + /* Experimental opcodes. */ + 1, 2, 0, +}; + +/* We have a normal standard opcode base, but + an arm compiler emitted a non-standard table! + This could lead to problems... + ARM C/C++ Compiler, RVCT4.0 [Build 4 + 00] seems to get the table wrong . */ +static unsigned char +dwarf_arm_standard_opcode_operand_count[ +STANDARD_OPERAND_COUNT_DWARF3] = { + /* DWARF2 */ + 0, + 1, 1, 1, 1, + 0, 0, 0, + 0, /* <<< --- this is wrong */ + /* Following are new for DWARF3. */ + 0, 0, 1 +}; + +/* Rather like memcmp but identifies which value pair + mismatches (the return value is non-zero if mismatch, + zero if match).. + This is used only in determining which kind of + standard-opcode-table we have in the DWARF: std-original, + or std-later. + mismatch_entry returns the table index that mismatches. + tabval returns the table byte value. + lineval returns the value from the line table header. */ +static int +operandmismatch(unsigned char * table,unsigned table_length, + unsigned char *linetable, + unsigned check_count, + unsigned * mismatch_entry, unsigned * tabval,unsigned *lineval) +{ + unsigned i = 0; + + /* ASSERT: check_count is <= table_length, which + is guaranteed by the caller. */ + for (i = 0; i= table_length) { + *mismatch_entry = i; + *lineval = linetable[i]; + *tabval = 0; /* No entry present. */ + /* A kind of mismatch */ + return TRUE; + } + if (table[i] == linetable[i]) { + continue; + } + *mismatch_entry = i; + *tabval = table[i]; + *lineval = linetable[i]; + return TRUE; + } + /* Matches. */ + return FALSE; +} + +/* Encapsulates DECODE_LEB128_UWORD_CK + so the caller can free resources + in case of problems. */ +static int +read_uword_de(Dwarf_Small **lp, + Dwarf_Unsigned *out_p, + Dwarf_Debug dbg, + Dwarf_Error *err, + Dwarf_Small *lpend) +{ + Dwarf_Small *inptr = *lp; + Dwarf_Unsigned out = 0; + DECODE_LEB128_UWORD_CK(inptr, + out, + dbg,err,lpend); + *lp = inptr; + *out_p = out; + return DW_DLV_OK; +} + +/* A bogus value read from a line table */ +static void +IssueExpError(Dwarf_Debug dbg, + Dwarf_Error *err, + const char * msg, + Dwarf_Unsigned val) +{ + dwarfstring m; + char buf[200]; + + dwarfstring_constructor_static(&m, buf,sizeof(buf)); + dwarfstring_append(&m , "ERROR: "); + dwarfstring_append(&m ,(char *)msg); + dwarfstring_append_printf_u(&m , " Bad value: 0x%x", val); + _dwarf_error_string(dbg, err, DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +static int +read_sword_de(Dwarf_Small **lp, + Dwarf_Signed *out_p, + Dwarf_Debug dbg, + Dwarf_Error *err, + Dwarf_Small *lpend) +{ + Dwarf_Small *inptr = *lp; + Dwarf_Signed out = 0; + DECODE_LEB128_SWORD_CK(inptr, + out, + dbg,err,lpend); + *lp = inptr; + *out_p = out; + return DW_DLV_OK; +} + +/* Common line table header reading code. + Returns DW_DLV_OK, DW_DLV_ERROR. + DW_DLV_NO_ENTRY cannot be returned, but callers should + assume it is possible. + + The line_context area must be initialized properly before + calling this. + + Has the side effect of allocating arrays which + must be freed (see the Line_Table_Context which + holds the pointers to space we allocate here). + + bogus_bytes_ptr and bogus_bytes are output values which + let a print-program notify the user of some surprising bytes + after a line table header and before the line table instructions. + These can be ignored unless one is printing. + And are ignored if NULL passed as the pointer. + + err_count_out may be NULL, in which case we + make no attempt to count checking-type errors. + Checking-type errors do not stop us, we just report them. + + See dw-linetableheader.txt for the ordering of text fields + across the various dwarf versions. The code + follows this ordering closely. + + Some of the arguments remaining are in line_context + so can be deleted from the + argument list (after a close look for correctness). */ +static int +_dwarf_read_line_table_header(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Small * section_start, + Dwarf_Small * data_start, + Dwarf_Unsigned section_length, + Dwarf_Small ** updated_data_start_out, + Dwarf_Line_Context line_context, + Dwarf_Small ** bogus_bytes_ptr, + Dwarf_Unsigned *bogus_bytes, + Dwarf_Error * err, + int *err_count_out) +{ + Dwarf_Small *line_ptr = data_start; + Dwarf_Small *starting_line_ptr = data_start; + Dwarf_Unsigned total_length = 0; + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Unsigned prologue_length = 0; + Dwarf_Half version = 0; + /* Both of the next two should point *one past* + the end of actual data of interest. */ + Dwarf_Small *section_end = section_start + section_length; + Dwarf_Small *line_ptr_end = 0; + Dwarf_Small *lp_begin = 0; + int res = 0; + Dwarf_Unsigned htmp = 0; + + if (bogus_bytes_ptr) *bogus_bytes_ptr = 0; + if (bogus_bytes) *bogus_bytes= 0; + + line_context->lc_line_ptr_start = starting_line_ptr; + /* READ_AREA_LENGTH updates line_ptr for consumed bytes */ + READ_AREA_LENGTH_CK(dbg, total_length, Dwarf_Unsigned, + line_ptr, local_length_size, local_extension_size, + err, section_length,section_end); + line_ptr_end = line_ptr + total_length; + line_context->lc_line_ptr_end = line_ptr_end; + line_context->lc_length_field_length = local_length_size + + local_extension_size; + line_context->lc_section_offset = starting_line_ptr - + dbg->de_debug_line.dss_data; + /* ASSERT: line_context->lc_length_field_length == line_ptr + -line_context->lc_line_ptr_start; + The following test allows the == case too + as that is normal for the last CUs line table. */ + if (line_ptr_end > section_end) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m,"DW_DLE_DEBUG_LINE_LENGTH_BAD " + " the total length of this line table is too large at" + " %" DW_PR_DUu " bytes",total_length); + _dwarf_error_string(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + line_context->lc_total_length = total_length; + + /* READ_UNALIGNED_CK(dbg, version, Dwarf_Half, + line_ptr, DWARF_HALF_SIZE, + err,line_ptr_end); */ + res = _dwarf_read_unaligned_ck_wrapper(dbg, + &htmp,line_ptr,DWARF_HALF_SIZE,line_ptr_end,err); + if (res == DW_DLV_ERROR) { + return res; + } + version = htmp; + + line_context->lc_version_number = version; + line_ptr += DWARF_HALF_SIZE; + if (version != DW_LINE_VERSION2 && + version != DW_LINE_VERSION3 && + version != DW_LINE_VERSION4 && + version != DW_LINE_VERSION5 && + version != EXPERIMENTAL_LINE_TABLES_VERSION) { + _dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR); + return DW_DLV_ERROR; + } + if (version == DW_LINE_VERSION5) { + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_address_size = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_segment_selector_size = + *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + } else { + line_context->lc_address_size = cu_context->cc_address_size; + line_context->lc_segment_selector_size = + cu_context->cc_segment_selector_size; + } + + READ_UNALIGNED_CK(dbg, prologue_length, Dwarf_Unsigned, + line_ptr, local_length_size, + err,line_ptr_end); + if (prologue_length > total_length) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_LINE_LENGTH_BAD " + " the prologue length of " + " this line table is too large at" + " %" DW_PR_DUu " bytes",prologue_length); + _dwarf_error_string(dbg, err, + DW_DLE_DEBUG_LINE_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + line_context->lc_prologue_length = prologue_length; + line_ptr += local_length_size; + line_context->lc_line_prologue_start = line_ptr; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_minimum_instruction_length = + *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + if (version == DW_LINE_VERSION4 || + version == DW_LINE_VERSION5 || + version == EXPERIMENTAL_LINE_TABLES_VERSION) { + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_maximum_ops_per_instruction = + *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + } + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_default_is_stmt = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD); + return DW_DLV_ERROR; + } + line_context->lc_line_base = *(signed char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Sbyte); + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + line_context->lc_line_range = *(unsigned char *) line_ptr; + if (!line_context->lc_line_range) { + _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_RANGE_ZERO); + return DW_DLV_ERROR; + } + line_ptr = line_ptr + sizeof(Dwarf_Small); + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + line_context->lc_opcode_base = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + /* Set up the array of standard opcode lengths. */ + /* We think this works ok even for cross-endian processing of + objects. It might be wrong, we might need to + specially process the array of ubyte into host order. */ + line_context->lc_opcode_length_table = line_ptr; + + /* lc_opcode_base is one greater than the size of the array. */ + line_ptr += line_context->lc_opcode_base - 1; + line_context->lc_std_op_count = line_context->lc_opcode_base -1; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + { + /* Determine (as best we can) whether the + lc_opcode_length_table holds 9 or 12 standard-conforming + entries. gcc4 upped to DWARF3's 12 without updating the + version number. + EXPERIMENTAL_LINE_TABLES_VERSION upped to 15. */ + unsigned check_count = line_context->lc_std_op_count; + unsigned tab_count = + sizeof(dwarf_standard_opcode_operand_count); + + int operand_ck_fail = true; + if (line_context->lc_std_op_count > tab_count) { + _dwarf_print_header_issue(dbg, + "Too many standard operands in linetable header: ", + data_start, + line_context->lc_std_op_count, + 0,0,0, + err_count_out); + check_count = tab_count; + } + if ((line_context->lc_opcode_length_table + check_count) >= + section_end) { + _dwarf_error_string(dbg, err, + DW_DLE_LINE_NUM_OPERANDS_BAD, + "DW_DLE_LINE_NUM_OPERANDS_BAD: " + "The .debug_line section is too short to be real " + "as a standard opcode table does not fit"); + return DW_DLV_ERROR; + } + { + unsigned entrynum = 0; + unsigned tabv = 0; + unsigned linetabv = 0; + + int mismatch = operandmismatch( + dwarf_standard_opcode_operand_count, + tab_count, + line_context->lc_opcode_length_table, + check_count,&entrynum,&tabv,&linetabv); + if (mismatch) { + if (err_count_out) { + _dwarf_print_header_issue(dbg, + "standard-operands did not match, checked", + data_start, + check_count, + entrynum,tabv,linetabv,err_count_out); + } + if (check_count > + sizeof(dwarf_arm_standard_opcode_operand_count)) { + check_count = + sizeof( + dwarf_arm_standard_opcode_operand_count); + } + mismatch = operandmismatch( + dwarf_arm_standard_opcode_operand_count, + sizeof(dwarf_arm_standard_opcode_operand_count), + line_context->lc_opcode_length_table, + check_count,&entrynum,&tabv,&linetabv); + if (!mismatch && err_count_out) { + _dwarf_print_header_issue(dbg, + "arm (incorrect) operands in use: ", + data_start, + check_count, + entrynum,tabv,linetabv,err_count_out); + } + } + if (!mismatch) { + if (version == 2) { + if (line_context->lc_std_op_count == + STANDARD_OPERAND_COUNT_DWARF3) { + _dwarf_print_header_issue(dbg, + "standard DWARF3 operands matched," + " but is DWARF2 linetable: count", + data_start, + check_count, + 0,0,0, err_count_out); + } + } + operand_ck_fail = false; + } + } + if (operand_ck_fail) { + /* Here we are not sure what the lc_std_op_count is. */ + _dwarf_error_string(dbg, err, + DW_DLE_LINE_NUM_OPERANDS_BAD, + "DW_DLE_LINE_NUM_OPERANDS_BAD " + "we cannot determine the size of the standard opcode" + " table in the line table header"); + return DW_DLV_ERROR; + } + } + /* At this point we no longer need to check operand counts. */ + if (line_ptr >= line_ptr_end) { + _dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD, + "DW_DLE_LINE_OFFSET_BAD " + "we run off the end of the .debug_line section " + "reading a line table header"); + return DW_DLV_ERROR; + } + + if (version < DW_LINE_VERSION5){ + Dwarf_Unsigned directories_count = 0; + Dwarf_Unsigned directories_malloc = 5; + line_context->lc_include_directories = + malloc(sizeof(Dwarf_Small *) * directories_malloc); + if (line_context->lc_include_directories == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + memset(line_context->lc_include_directories, 0, + sizeof(Dwarf_Small *) * directories_malloc); + + while ((*(char *) line_ptr) != '\0') { + if (directories_count >= directories_malloc) { + Dwarf_Unsigned expand = 2 * directories_malloc; + Dwarf_Unsigned bytesalloc = + sizeof(Dwarf_Small *) * expand; + Dwarf_Small **newdirs = + realloc(line_context->lc_include_directories, + bytesalloc); + + if (!newdirs) { + _dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL " + "reallocating an array of include directories" + " in a line table"); + return DW_DLV_ERROR; + } + /* Doubled size, zero out second half. */ + memset(newdirs + directories_malloc, 0, + sizeof(Dwarf_Small *) * directories_malloc); + directories_malloc = expand; + line_context->lc_include_directories = newdirs; + } + line_context->lc_include_directories[directories_count] = + line_ptr; + res = _dwarf_check_string_valid(dbg, + data_start,line_ptr,line_ptr_end, + DW_DLE_LINE_STRING_BAD,err); + if (res != DW_DLV_OK) { + return res; + } + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + directories_count++; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + } + line_ptr++; + line_context->lc_include_directories_count = + directories_count; + } else if (version == EXPERIMENTAL_LINE_TABLES_VERSION) { + /* Empty old style dir entry list. */ + line_ptr++; + } else if (version == DW_LINE_VERSION5) { + /* handled below */ + } else { + /* No old style directory entries. */ + } + /* Later tests will deal with the == case as required. */ + if (line_ptr > line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + if (version < DW_LINE_VERSION5) { + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + while (*(char *) line_ptr != '\0') { + Dwarf_Unsigned utmp; + Dwarf_Unsigned dir_index = 0; + Dwarf_Unsigned lastmod = 0; + Dwarf_Unsigned file_length = 0; + int resl = 0; + Dwarf_File_Entry currfile = 0; + + currfile = (Dwarf_File_Entry) + malloc(sizeof(struct Dwarf_File_Entry_s)); + if (currfile == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + memset(currfile,0,sizeof(struct Dwarf_File_Entry_s)); + /* Insert early so in case of error we can find + and free the record. */ + _dwarf_add_to_files_list(line_context,currfile); + + currfile->fi_file_name = line_ptr; + resl = _dwarf_check_string_valid(dbg, + data_start,line_ptr,line_ptr_end, + DW_DLE_LINE_STRING_BAD,err); + if (resl != DW_DLV_OK) { + return resl; + } + line_ptr = line_ptr + strlen((char *) line_ptr) + 1; + /* DECODE_LEB128_UWORD_CK(line_ptr, utmp,dbg, + err,line_ptr_end); */ + res = read_uword_de(&line_ptr,&utmp, + dbg,err,line_ptr_end); + if (res == DW_DLV_ERROR) { + return DW_DLV_ERROR; + } + dir_index = (Dwarf_Unsigned) utmp; + if (dir_index > + line_context->lc_include_directories_count) { + _dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD); + return DW_DLV_ERROR; + } + currfile->fi_dir_index = dir_index; + currfile->fi_dir_index_present = TRUE; + + /*DECODE_LEB128_UWORD_CK(line_ptr,lastmod, + dbg,err, line_ptr_end); */ + res = read_uword_de( &line_ptr,&lastmod, + dbg,err,line_ptr_end); + if (res == DW_DLV_ERROR) { + return DW_DLV_ERROR; + } + + currfile->fi_time_last_mod = lastmod; + currfile->fi_time_last_mod_present = TRUE; + + DECODE_LEB128_UWORD_CK(line_ptr,file_length, + dbg,err, line_ptr_end); + currfile->fi_file_length = file_length; + currfile->fi_file_length_present = TRUE; + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + } + /* Skip trailing nul byte */ + ++line_ptr; + } else if (version == EXPERIMENTAL_LINE_TABLES_VERSION) { + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (*line_ptr != 0) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + line_ptr++; + } else if (version == 5) { + /* handled below */ + } else { + /* No old style filenames entries. */ + } + /* Later tests will deal with the == case as required. */ + if (line_ptr > line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + + if (version == EXPERIMENTAL_LINE_TABLES_VERSION) { + static unsigned char expbytes[5] = {0,0xff,0xff,0x7f, 0x7f }; + Dwarf_Unsigned logicals_table_offset = 0; + Dwarf_Unsigned actuals_table_offset = 0; + unsigned i = 0; + + for ( ; i < 5; ++i) { + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + if (*line_ptr != expbytes[i]) { + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + line_ptr++; + } + READ_UNALIGNED_CK(dbg, logicals_table_offset, Dwarf_Unsigned, + line_ptr, local_length_size,err,line_ptr_end); + line_context->lc_logicals_table_offset = + logicals_table_offset; + line_ptr += local_length_size; + READ_UNALIGNED_CK(dbg, actuals_table_offset, Dwarf_Unsigned, + line_ptr, local_length_size,err,line_ptr_end); + line_context->lc_actuals_table_offset = actuals_table_offset; + line_ptr += local_length_size; + /* Later tests will deal with the == case as required. */ + if (line_ptr > line_ptr_end) { + _dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD, + "DW_DLE_LINE_OFFSET_BAD " + "The line table pointer points past end " + "of line table."); + return DW_DLV_ERROR; + } + if (actuals_table_offset > dbg->de_filesize) { + _dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD, + "DW_DLE_LINE_OFFSET_BAD " + "The line table actuals offset is larger than " + " the size of the object file. Corrupt DWARF"); + return DW_DLV_ERROR; + } + if ((line_ptr+actuals_table_offset) > line_ptr_end) { + _dwarf_error_string(dbg, err, DW_DLE_LINE_OFFSET_BAD, + "DW_DLE_LINE_OFFSET_BAD " + "The line table actuals offset is too large " + "to be real."); + return DW_DLV_ERROR; + } + } + + if (version == DW_LINE_VERSION5 || + version == EXPERIMENTAL_LINE_TABLES_VERSION) { + /* DWARF 5. directory names.*/ + Dwarf_Unsigned directory_format_count = 0; + struct Dwarf_Unsigned_Pair_s * format_values = 0; + Dwarf_Unsigned directories_count = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned j = 0; + int dres = 0; + + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + directory_format_count = *(unsigned char *) line_ptr; + line_context->lc_directory_entry_format_count = + directory_format_count; + line_ptr = line_ptr + sizeof(Dwarf_Small); + if (directory_format_count > 0) { + format_values = malloc( + sizeof(struct Dwarf_Unsigned_Pair_s) * + directory_format_count); + if (format_values == NULL) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + for (i = 0; i < directory_format_count; i++) { + dres=read_uword_de(&line_ptr, + &format_values[i].up_first, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(format_values); + format_values = 0; + return dres; + } + dres=read_uword_de(&line_ptr, + &format_values[i].up_second, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(format_values); + format_values = 0; + return dres; + } + /* FIXME: what would be appropriate tests + of this pair of values? */ + } + } + dres = read_uword_de(&line_ptr,&directories_count, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(format_values); + format_values = 0; + return dres; + } + if (directories_count > total_length) { + dwarfstring m; + + free(format_values); + format_values = 0; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_LINE_LENGTH_BAD " + " the directories count of " + " this line table is too large at" + " %" DW_PR_DUu ,directories_count); + _dwarf_error_string(dbg, err, + DW_DLE_DEBUG_LINE_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + line_context->lc_include_directories = + malloc(sizeof(Dwarf_Small *) * directories_count); + if (line_context->lc_include_directories == NULL) { + free(format_values); + format_values = 0; + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + if (directory_format_count == 0 && + directories_count > 0) { + free(format_values); + format_values = 0; + _dwarf_error_string(dbg, err, + DW_DLE_DIRECTORY_FORMAT_COUNT_VS_DIRECTORIES_MISMATCH, + "DW_DLE_DIRECTORY_FORMAT_COUNT_" + "VS_DIRECTORIES_MISMATCH" + ": format count is zero yet directories count > 0"); + return DW_DLV_ERROR; + } + memset(line_context->lc_include_directories, 0, + sizeof(Dwarf_Small *) * directories_count); + + for (i = 0; i < directories_count; i++) { + for (j = 0; j < directory_format_count; j++) { + Dwarf_Unsigned lntype = + format_values[j].up_first; + Dwarf_Unsigned lnform = + format_values[j].up_second; + switch (lntype) { + case DW_LNCT_path: { + char *inc_dir_ptr = 0; + res = _dwarf_decode_line_string_form(dbg, + lntype,lnform, + local_length_size, + &line_ptr, + line_ptr_end, + &inc_dir_ptr, + err); + if (res != DW_DLV_OK) { + free(format_values); + format_values = 0; + return res; + } + line_context->lc_include_directories[i] = + (unsigned char *)inc_dir_ptr; + break; + } + default: + free(format_values); + format_values = 0; + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + } + /* Later tests will deal with the == case as required. */ + if (line_ptr > line_ptr_end) { + free(format_values); + format_values = 0; + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + } + line_context->lc_directory_format_values = + format_values; + format_values = 0; + line_context->lc_include_directories_count = + directories_count; + } + if (version == DW_LINE_VERSION5 || + version == EXPERIMENTAL_LINE_TABLES_VERSION) { + /* DWARF 5. file names.*/ + struct Dwarf_Unsigned_Pair_s * + filename_entry_pairs = 0; + Dwarf_Unsigned filename_format_count = 0; + Dwarf_Unsigned files_count = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned j = 0; + int dres = 0; + + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + filename_format_count = *(unsigned char *) line_ptr; + line_context->lc_file_name_format_count = + filename_format_count; + line_ptr = line_ptr + sizeof(Dwarf_Small); + filename_entry_pairs = malloc( + sizeof(struct Dwarf_Unsigned_Pair_s) * + filename_format_count); + if (!filename_entry_pairs) { + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + for (i = 0; i < filename_format_count; i++) { + dres=read_uword_de(&line_ptr, + &filename_entry_pairs[i].up_first, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(filename_entry_pairs); + return dres; + } + dres=read_uword_de(&line_ptr, + &filename_entry_pairs[i]. + up_second, dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(filename_entry_pairs); + return dres; + } + /* FIXME: what would be appropriate tests + of this pair of values? */ + } + /* DECODE_LEB128_UWORD_CK(line_ptr, files_count, + dbg,err,line_ptr_end); */ + dres=read_uword_de(&line_ptr,&files_count, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(filename_entry_pairs); + return dres; + } + if (files_count > total_length) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_LINE_LENGTH_BAD " + " the files count of " + " this line table is too large at" + " %" DW_PR_DUu " files",files_count); + _dwarf_error_string(dbg, err, + DW_DLE_DEBUG_LINE_LENGTH_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + free(filename_entry_pairs); + return DW_DLV_ERROR; + } + + for (i = 0; i < files_count; i++) { + Dwarf_File_Entry curline = 0; + curline = (Dwarf_File_Entry) + malloc(sizeof(struct Dwarf_File_Entry_s)); + if (curline == NULL) { + free(filename_entry_pairs); + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + memset(curline,0,sizeof(*curline)); + _dwarf_add_to_files_list(line_context,curline); + for (j = 0; j < filename_format_count; j++) { + Dwarf_Unsigned dirindex = 0; + Dwarf_Unsigned lntype = + filename_entry_pairs[j].up_first; + Dwarf_Unsigned lnform = + filename_entry_pairs[j].up_second; + switch (lntype) { + /* The LLVM LNCT is documented in + https://releases.llvm.org/9.0.0/docs + /AMDGPUUsage.html + */ + + /* Cannot find the GNU items documented.? */ + case DW_LNCT_GNU_decl_file: /* FORM udata*/ + res = _dwarf_decode_line_udata_form(dbg, + lntype,lnform, + &line_ptr, + &dirindex, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_gnu_decl_file = dirindex; + curline->fi_gnu_decl_file_present = TRUE; + break; + case DW_LNCT_GNU_decl_line: /* FORM udata */ + res = _dwarf_decode_line_udata_form(dbg, + lntype,lnform, + &line_ptr, + &dirindex, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_gnu_decl_line = dirindex; + curline->fi_gnu_decl_line_present = TRUE; + break; + + case DW_LNCT_path: { + res = _dwarf_decode_line_string_form(dbg, + lntype, lnform, + local_length_size, + &line_ptr, + line_ptr_end, + (char **)&curline->fi_file_name, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + } + break; + case DW_LNCT_GNU_subprogram_name: { + res = _dwarf_decode_line_string_form(dbg, + lntype, lnform, + local_length_size, + &line_ptr, + line_ptr_end, + (char **)&curline->fi_gnu_subprogram_name, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + } + break; + case DW_LNCT_LLVM_source: { + res = _dwarf_decode_line_string_form(dbg, + lntype, lnform, + local_length_size, + &line_ptr, + line_ptr_end, + (char **)&curline->fi_llvm_source, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + } + break; + case DW_LNCT_directory_index: + res = _dwarf_decode_line_udata_form(dbg, + lntype,lnform, + &line_ptr, + &dirindex, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_dir_index = dirindex; + curline->fi_dir_index_present = TRUE; + break; + case DW_LNCT_timestamp: + res = _dwarf_decode_line_udata_form(dbg, + lntype, lnform, + &line_ptr, + &curline->fi_time_last_mod, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_time_last_mod_present = TRUE; + break; + case DW_LNCT_size: + res = _dwarf_decode_line_udata_form(dbg, + lntype, lnform, + &line_ptr, + &curline->fi_file_length, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_file_length_present = TRUE; + break; + case DW_LNCT_MD5: { /* form DW_FORM_data16 */ + if (filename_entry_pairs[j].up_second != + DW_FORM_data16) { + free(filename_entry_pairs); + _dwarf_error(dbg, err, + DW_DLE_LNCT_MD5_WRONG_FORM); + return DW_DLV_ERROR; + } + res = _dwarf_extract_data16(dbg, + line_ptr, + line_ptr, + line_ptr_end, + &curline->fi_md5_value, + err); + if (res != DW_DLV_OK) { + free(filename_entry_pairs); + return res; + } + curline->fi_md5_present = TRUE; + line_ptr = line_ptr + + sizeof(curline->fi_md5_value); + } + break; + + default: + _dwarf_report_bad_lnct(dbg, + lntype, + DW_DLE_LINE_NUMBER_HEADER_ERROR, + "DW_DLE_LINE_NUMBER_HEADER_ERROR", + err); + free(filename_entry_pairs); + return DW_DLV_ERROR; + } + if (line_ptr > line_ptr_end) { + free(filename_entry_pairs); + _dwarf_error(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + } + } + line_context->lc_file_format_values = filename_entry_pairs; + filename_entry_pairs = 0; + } + /* For two-level line tables, read the + subprograms table. */ + if (version == EXPERIMENTAL_LINE_TABLES_VERSION) { + Dwarf_Unsigned subprog_format_count = 0; + Dwarf_Unsigned *subprog_entry_types = 0; + Dwarf_Unsigned *subprog_entry_forms = 0; + Dwarf_Unsigned subprogs_count = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned j = 0; + int dres = 0; + + /* line_ptr_end is *after* the valid area */ + if (line_ptr >= line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_NUMBER_HEADER_ERROR); + return DW_DLV_ERROR; + } + subprog_format_count = *(unsigned char *) line_ptr; + line_ptr = line_ptr + sizeof(Dwarf_Small); + subprog_entry_types = malloc(sizeof(Dwarf_Unsigned) * + subprog_format_count); + if (subprog_entry_types == NULL) { + _dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL allocating subprog_entry_types"); + return DW_DLV_ERROR; + } + if (subprog_format_count > total_length) { + IssueExpError(dbg,err, + "Subprog format count Count too " + "large to be real", + subprog_format_count); + free(subprog_entry_types); + return DW_DLV_ERROR; + } + subprog_entry_forms = malloc(sizeof(Dwarf_Unsigned) * + subprog_format_count); + if (subprog_entry_forms == NULL) { + free(subprog_entry_types); + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + _dwarf_error_string(dbg, err, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL allocating subprog_entry_forms"); + return DW_DLV_ERROR; + } + + for (i = 0; i < subprog_format_count; i++) { + + dres=read_uword_de(&line_ptr,subprog_entry_types+i, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(subprog_entry_types); + free(subprog_entry_forms); + return dres; + } + if (subprog_entry_types[i] > total_length) { + IssueExpError(dbg,err, + "Subprog entry_types[i] count Count too " + "large to be real", + subprog_entry_types[i]); + free(subprog_entry_types); + free(subprog_entry_forms); + return DW_DLV_ERROR; + } + dres=read_uword_de(&line_ptr,subprog_entry_forms+i, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(subprog_entry_types); + free(subprog_entry_forms); + return dres; + } + if (subprog_entry_forms[i] > total_length) { + IssueExpError(dbg,err, + "Subprog entry_forms[i] count Count too " + "large to be real", + subprog_entry_forms[i]); + free(subprog_entry_types); + free(subprog_entry_forms); + return DW_DLV_ERROR; + } + } + dres=read_uword_de(&line_ptr,&subprogs_count, + dbg,err,line_ptr_end); + if (dres != DW_DLV_OK) { + free(subprog_entry_types); + free(subprog_entry_forms); + return dres; + } + if (subprogs_count > total_length) { + IssueExpError(dbg,err, + "Subprogs Count too large to be real", + subprogs_count); + free(subprog_entry_types); + free(subprog_entry_forms); + return DW_DLV_ERROR; + } + line_context->lc_subprogs = + malloc(sizeof(struct Dwarf_Subprog_Entry_s) * + subprogs_count); + if (line_context->lc_subprogs == NULL) { + free(subprog_entry_types); + free(subprog_entry_forms); + _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + memset(line_context->lc_subprogs, 0, + sizeof(struct Dwarf_Subprog_Entry_s) * subprogs_count); + for (i = 0; i < subprogs_count; i++) { + struct Dwarf_Subprog_Entry_s *curline = + line_context->lc_subprogs + i; + for (j = 0; j < subprog_format_count; j++) { + Dwarf_Unsigned lntype = + subprog_entry_types[j]; + Dwarf_Unsigned lnform = + subprog_entry_forms[j]; + switch (lntype) { + case DW_LNCT_GNU_subprogram_name: + res = _dwarf_decode_line_string_form(dbg, + lntype,lnform, + local_length_size, + &line_ptr, + line_ptr_end, + (char **)&curline->ds_subprog_name, + err); + if (res != DW_DLV_OK) { + free(subprog_entry_types); + free(subprog_entry_forms); + return res; + } + break; + case DW_LNCT_GNU_decl_file: + res = _dwarf_decode_line_udata_form(dbg, + lntype,lnform, + &line_ptr, + &curline->ds_decl_file, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(subprog_entry_forms); + free(subprog_entry_types); + return res; + } + break; + case DW_LNCT_GNU_decl_line: + res = _dwarf_decode_line_udata_form(dbg, + lntype,lnform, + &line_ptr, + &curline->ds_decl_line, + line_ptr_end, + err); + if (res != DW_DLV_OK) { + free(subprog_entry_forms); + free(subprog_entry_types); + return res; + } + break; + default: + free(subprog_entry_forms); + free(subprog_entry_types); + _dwarf_report_bad_lnct(dbg, + lntype, + DW_DLE_LINE_NUMBER_HEADER_ERROR, + "DW_DLE_LINE_NUMBER_HEADER_ERROR", + err); + return DW_DLV_ERROR; + } + if (line_ptr >= line_ptr_end) { + free(subprog_entry_types); + free(subprog_entry_forms); + _dwarf_error_string(dbg, err, + DW_DLE_LINE_NUMBER_HEADER_ERROR, + "DW_DLE_LINE_NUMBER_HEADER_ERROR:" + " Reading suprogram entry DW_LNCT* types " + " we run off the end of the table"); + return DW_DLV_ERROR; + } + } + } + + free(subprog_entry_types); + free(subprog_entry_forms); + line_context->lc_subprogs_count = subprogs_count; + } + if (version == EXPERIMENTAL_LINE_TABLES_VERSION) { + lp_begin = line_context->lc_line_prologue_start + + line_context->lc_logicals_table_offset; + } else { + lp_begin = line_context->lc_line_prologue_start + + line_context->lc_prologue_length; + } + if (line_ptr > line_ptr_end) { + _dwarf_error(dbg, err, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + if (line_ptr != lp_begin) { + if (line_ptr > lp_begin) { + _dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD); + return DW_DLV_ERROR; + } else { + /* Bug in compiler. These + bytes are really part of the instruction + stream. The line_context->lc_prologue_length is + wrong (12 too high). */ + if (bogus_bytes_ptr) { + *bogus_bytes_ptr = line_ptr; + } + if (bogus_bytes) { + /* How far off things are. We expect the + value 12 ! Negative value seems impossible. */ + /* ptrdiff_t is generated but not named */ + *bogus_bytes = (lp_begin - line_ptr); + } + } + /* Ignore the lp_begin calc. Assume line_ptr right. + Making up for compiler bug. */ + lp_begin = line_ptr; + } + line_context->lc_line_ptr_start = lp_begin; + if (line_context->lc_actuals_table_offset) { + /* This means two tables. */ + line_context->lc_table_count = 2; + } else { + if (line_context->lc_line_ptr_end > lp_begin) { + line_context->lc_table_count = 1; + } else { + line_context->lc_table_count = 0; + } + } + *updated_data_start_out = lp_begin; + return DW_DLV_OK; +} + +/* Read one line table program. For two-level line tables, this + function is called once for each table. */ +static int +read_line_table_program(Dwarf_Debug dbg, + Dwarf_Small *line_ptr, + Dwarf_Small *line_ptr_end, + Dwarf_Small *orig_line_ptr, + Dwarf_Small *section_start, + Dwarf_Line_Context line_context, + Dwarf_Half address_size, + Dwarf_Bool doaddrs, /* Only true if SGI IRIX rqs calling. */ + Dwarf_Bool dolines, + Dwarf_Bool is_single_table, + Dwarf_Bool is_actuals_table, + Dwarf_Error *error, + int *err_count_out) +{ + Dwarf_Unsigned i = 0; + Dwarf_File_Entry cur_file_entry = 0; + Dwarf_Line *logicals = line_context->lc_linebuf_logicals; + Dwarf_Unsigned logicals_count = + line_context->lc_linecount_logicals; + + struct Dwarf_Line_Registers_s regs; + + /* This is a pointer to the current line being added to the line + matrix. */ + Dwarf_Line curr_line = 0; + + /* These variables are used to decode leb128 numbers. Leb128_num + holds the decoded number, and leb128_length is its length in + bytes. */ + Dwarf_Unsigned leb128_num = 0; + Dwarf_Signed advance_line = 0; + + /* This is the operand of the latest fixed_advance_pc extended + opcode. */ + Dwarf_Half fixed_advance_pc = 0; + + /* Counts the number of lines in the line matrix. */ + Dwarf_Unsigned line_count = 0; + + /* This is the length of an extended opcode instr. */ + Dwarf_Unsigned instr_length = 0; + + /* Used to chain together pointers to line table entries that are + later used to create a block of Dwarf_Line entries. */ + Dwarf_Chain chain_line = NULL; + Dwarf_Chain head_chain = NULL; + Dwarf_Chain curr_chain = NULL; + + /* This points to a block of Dwarf_Lines, a pointer to which is + returned in linebuf. */ + Dwarf_Line *block_line = 0; + + /* Mark a line record as being DW_LNS_set_address */ + Dwarf_Bool is_addr_set = false; + + (void)orig_line_ptr; + (void)err_count_out; + /* Initialize the one state machine variable that depends on the + prefix. */ + _dwarf_set_line_table_regs_default_values(®s, + line_context->lc_version_number, + line_context->lc_default_is_stmt); + + /* Start of statement program. */ + while (line_ptr < line_ptr_end) { + int type = 0; + Dwarf_Small opcode = 0; + +#ifdef PRINTING_DETAILS + { + dwarfstring m9a; + dwarfstring_constructor(&m9a); + dwarfstring_append_printf_u(&m9a, + " [0x%06" DW_PR_DSx "] ", + /* ptrdiff_t generated but not named */ + (line_ptr - section_start)); + _dwarf_printf(dbg,dwarfstring_string(&m9a)); + dwarfstring_destructor(&m9a); + } +#endif /* PRINTING_DETAILS */ + opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + /* 'type' is the output */ + WHAT_IS_OPCODE(type, opcode, line_context->lc_opcode_base, + line_context->lc_opcode_length_table, line_ptr, + line_context->lc_std_op_count); + + if (type == LOP_DISCARD) { + int oc = 0; + int opcnt = line_context->lc_opcode_length_table[opcode]; +#ifdef PRINTING_DETAILS + { + dwarfstring m9b; + dwarfstring_constructor(&m9b); + dwarfstring_append_printf_i(&m9b, + "*** DWARF CHECK: DISCARD standard opcode %d ", + opcode); + dwarfstring_append_printf_i(&m9b, + "with %d operands: not understood.", opcnt); + _dwarf_printf(dbg,dwarfstring_string(&m9b)); + *err_count_out += 1; + dwarfstring_destructor(&m9b); + } +#endif /* PRINTING_DETAILS */ + for (oc = 0; oc < opcnt; oc++) { + int ocres = 0; + /* Read and discard operands we don't + understand. + arbitrary choice of unsigned read. + signed read would work as well. */ + Dwarf_Unsigned utmp2 = 0; + + (void) utmp2; + ocres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (ocres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + curr_line = 0; + } + return DW_DLV_ERROR; + } + +#ifdef PRINTING_DETAILS + { + dwarfstring m9e; + dwarfstring_constructor(&m9e); + dwarfstring_append_printf_u(&m9e, + " %" DW_PR_DUu, + utmp2); + dwarfstring_append_printf_u(&m9e, + " (0x%" DW_PR_XZEROS DW_PR_DUx ")", + utmp2); + _dwarf_printf(dbg,dwarfstring_string(&m9e)); + dwarfstring_destructor(&m9e); + } +#endif /* PRINTING_DETAILS */ + } +#ifdef PRINTING_DETAILS + _dwarf_printf(dbg,"***\n"); +#endif /* PRINTING_DETAILS */ + } else if (type == LOP_SPECIAL) { + /* This op code is a special op in the object, no matter + that it might fall into the standard op range in this + compile. That is, these are special opcodes between + opcode_base and MAX_LINE_OP_CODE. (including + opcode_base and MAX_LINE_OP_CODE) */ +#ifdef PRINTING_DETAILS + unsigned origop = opcode; +#endif /* PRINTING_DETAILS */ + Dwarf_Unsigned operation_advance = 0; + + opcode = opcode - line_context->lc_opcode_base; + operation_advance = + (opcode / line_context->lc_line_range); + + if (line_context->lc_maximum_ops_per_instruction < 2) { + regs.lr_address = regs.lr_address + + (operation_advance * + line_context->lc_minimum_instruction_length); + } else { + regs.lr_address = regs.lr_address + + (line_context->lc_minimum_instruction_length * + ((regs.lr_op_index + operation_advance)/ + line_context->lc_maximum_ops_per_instruction)); + regs.lr_op_index = + (regs.lr_op_index +operation_advance)% + line_context->lc_maximum_ops_per_instruction; + } + + regs.lr_line = regs.lr_line + line_context->lc_line_base + + opcode % line_context->lc_line_range; + if ((Dwarf_Signed)regs.lr_line < 0) { + /* Something is badly wrong */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR " + "The line number computes as %d " + "and negative line numbers " + "are not correct.",(Dwarf_Signed)regs.lr_line); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_LINENO_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + regs.lr_line = 0; + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + curr_line = 0; + } + return DW_DLV_ERROR; + } +#ifdef PRINTING_DETAILS + { + dwarfstring ma; + dwarfstring mb; + + dwarfstring_constructor(&ma); + dwarfstring_constructor(&mb); + dwarfstring_append_printf_u(&mb,"Specialop %3u", origop); + _dwarf_printf(dbg,dwarfstring_string(&ma)); + dwarfstring_destructor(&ma); + print_line_detail(dbg,dwarfstring_string(&mb), + opcode,line_count+1, ®s,is_single_table, + is_actuals_table); + dwarfstring_destructor(&mb); + dwarfstring_destructor(&ma); + } +#endif /* PRINTING_DETAILS */ + + if (dolines) { + curr_line = + (Dwarf_Line) _dwarf_get_alloc(dbg,DW_DLA_LINE,1); + if (curr_line == NULL) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + /* Mark a line record as being DW_LNS_set_address */ + curr_line->li_l_data.li_is_addr_set = + is_addr_set; + is_addr_set = false; + curr_line->li_address = regs.lr_address; + curr_line->li_l_data.li_file = + (Dwarf_Signed) regs.lr_file; + curr_line->li_l_data.li_line = + (Dwarf_Signed) regs.lr_line; + curr_line->li_l_data.li_column = + (Dwarf_Half) regs.lr_column; + curr_line->li_l_data.li_is_stmt = + regs.lr_is_stmt; + curr_line->li_l_data.li_basic_block = + regs.lr_basic_block; + curr_line->li_l_data.li_end_sequence = + curr_line->li_l_data. + li_epilogue_begin = regs.lr_epilogue_begin; + curr_line->li_l_data.li_prologue_end = + regs.lr_prologue_end; + curr_line->li_l_data.li_isa = + regs.lr_isa; + curr_line->li_l_data.li_discriminator = + regs.lr_discriminator; + curr_line->li_l_data.li_call_context = + regs.lr_call_context; + curr_line->li_l_data.li_subprogram = + regs.lr_subprogram; + curr_line->li_context = line_context; + curr_line->li_is_actuals_table = is_actuals_table; + line_count++; + + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + chain_line->ch_itemtype = DW_DLA_LINE; + chain_line->ch_item = curr_line; + _dwarf_update_chain_list(chain_line,&head_chain, + &curr_chain); + curr_line = 0; + } + + regs.lr_basic_block = false; + regs.lr_prologue_end = false; + regs.lr_epilogue_begin = false; + regs.lr_discriminator = 0; +#ifdef PRINTING_DETAILS +#endif /* PRINTING_DETAILS */ + } else if (type == LOP_STANDARD) { +#ifdef PRINTING_DETAILS + dwarfstring mb; +#endif /* PRINTING_DETAILS */ + + switch (opcode) { + case DW_LNS_copy:{ + +#ifdef PRINTING_DETAILS + print_line_detail(dbg,"DW_LNS_copy", + opcode,line_count+1, ®s,is_single_table, + is_actuals_table); +#endif /* PRINTING_DETAILS */ + if (dolines) { + curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, + DW_DLA_LINE, 1); + if (curr_line == NULL) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + /* Mark a line record as DW_LNS_set_address */ + curr_line->li_l_data.li_is_addr_set = + is_addr_set; + is_addr_set = false; + + curr_line->li_address = regs.lr_address; + curr_line->li_l_data.li_file = + (Dwarf_Signed) regs.lr_file; + curr_line->li_l_data.li_line = + (Dwarf_Signed) regs.lr_line; + curr_line->li_l_data.li_column = + (Dwarf_Half) regs.lr_column; + curr_line->li_l_data.li_is_stmt = + regs.lr_is_stmt; + curr_line->li_l_data. + li_basic_block = regs.lr_basic_block; + curr_line->li_l_data. + li_end_sequence = regs.lr_end_sequence; + curr_line->li_context = line_context; + curr_line->li_is_actuals_table = is_actuals_table; + curr_line->li_l_data. + li_epilogue_begin = regs.lr_epilogue_begin; + curr_line->li_l_data. + li_prologue_end = regs.lr_prologue_end; + curr_line->li_l_data.li_isa = + regs.lr_isa; + curr_line->li_l_data.li_discriminator + = regs.lr_discriminator; + curr_line->li_l_data.li_call_context + = regs.lr_call_context; + curr_line->li_l_data.li_subprogram = + regs.lr_subprogram; + line_count++; + + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + chain_line->ch_itemtype = DW_DLA_LINE; + chain_line->ch_item = curr_line; + _dwarf_update_chain_list(chain_line,&head_chain, + &curr_chain); + curr_line = 0; + } + + regs.lr_basic_block = false; + regs.lr_prologue_end = false; + regs.lr_epilogue_begin = false; + regs.lr_discriminator = 0; + } + break; + case DW_LNS_advance_pc:{ + Dwarf_Unsigned utmp2 = 0; + int advres = 0; + + advres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (advres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_advance_pc val %" DW_PR_DSd, + utmp2); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + utmp2); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + leb128_num = utmp2; + regs.lr_address = regs.lr_address + + line_context->lc_minimum_instruction_length * + leb128_num; + } + break; + case DW_LNS_advance_line:{ + Dwarf_Signed stmp = 0; + int alres = 0; + + alres = read_sword_de( &line_ptr,&stmp, + dbg,error,line_ptr_end); + if (alres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + advance_line = (Dwarf_Signed) stmp; + +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_advance_line val %" DW_PR_DSd, + advance_line); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx "\n", + advance_line); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + regs.lr_line = regs.lr_line + advance_line; + if ((Dwarf_Signed)regs.lr_line < 0) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR" + " The line number is %d " + "and negative line numbers after " + "DW_LNS_ADVANCE_LINE ", + (Dwarf_Signed)regs.lr_line); + dwarfstring_append_printf_i(&m, + " of %d " + "are not correct.",stmp); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_LINENO_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + regs.lr_line = 0; + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } + } + break; + case DW_LNS_set_file:{ + Dwarf_Unsigned utmp2 = 0; + int sfres = 0; + + sfres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (sfres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + { + Dwarf_Signed fno = (Dwarf_Signed)utmp2; + if (fno < 0) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_error_string(dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "A DW_LNS_set_file has an " + "Impossible " + "file number "); + return DW_DLV_ERROR; + } + } + + regs.lr_file = utmp2; +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_set_file %ld\n", + regs.lr_file); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + case DW_LNS_set_column:{ + Dwarf_Unsigned utmp2 = 0; + int scres = 0; + + scres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (scres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + { + Dwarf_Signed cno = (Dwarf_Signed)utmp2; + if (cno < 0) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_error_string(dbg,error, + DW_DLE_LINE_INDEX_WRONG, + "DW_DLE_LINE_INDEX_WRONG " + "A DW_LNS_set_column has an " + "impossible " + "column number "); + return DW_DLV_ERROR; + } + } + + regs.lr_column = utmp2; +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + + dwarfstring_append_printf_i(&mb, + "DW_LNS_set_column val %" DW_PR_DSd , + regs.lr_column); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx "\n", + regs.lr_column); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + case DW_LNS_negate_stmt:{ + regs.lr_is_stmt = !regs.lr_is_stmt; +#ifdef PRINTING_DETAILS + _dwarf_printf(dbg, "DW_LNS_negate_stmt\n"); +#endif /* PRINTING_DETAILS */ + } + break; + case DW_LNS_set_basic_block:{ + regs.lr_basic_block = true; +#ifdef PRINTING_DETAILS + _dwarf_printf(dbg, + "DW_LNS_set_basic_block\n"); +#endif /* PRINTING_DETAILS */ + } + break; + + case DW_LNS_const_add_pc:{ + opcode = MAX_LINE_OP_CODE - + line_context->lc_opcode_base; + if (line_context->lc_maximum_ops_per_instruction < 2){ + Dwarf_Unsigned operation_advance = + (opcode / line_context->lc_line_range); + regs.lr_address = regs.lr_address + + line_context->lc_minimum_instruction_length * + operation_advance; + } else { + Dwarf_Unsigned operation_advance = + (opcode / line_context->lc_line_range); + regs.lr_address = regs.lr_address + + line_context->lc_minimum_instruction_length * + ((regs.lr_op_index + operation_advance)/ + line_context->lc_maximum_ops_per_instruction); + regs.lr_op_index = + (regs.lr_op_index +operation_advance)% + line_context->lc_maximum_ops_per_instruction; + } +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_u(&mb, + "DW_LNS_const_add_pc new address 0x%" + DW_PR_XZEROS DW_PR_DSx "\n", + regs.lr_address); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + case DW_LNS_fixed_advance_pc:{ + Dwarf_Unsigned fpc = 0; + int apres = 0; + /*READ_UNALIGNED_CK(dbg, fixed_advance_pc, + Dwarf_Half, line_ptr, + DWARF_HALF_SIZE,error,line_ptr_end); */ + apres = _dwarf_read_unaligned_ck_wrapper(dbg, + &fpc,line_ptr,DWARF_HALF_SIZE,line_ptr_end, + error); + fixed_advance_pc = fpc; + if (apres == DW_DLV_ERROR) { + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return apres; + } + line_ptr += DWARF_HALF_SIZE; + if (line_ptr > line_ptr_end) { + dwarfstring g; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "DW_LNS_fixed_advance_pc we are " + "off this line table at section " + "offset. 0x%x .", + localoff); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } + regs.lr_address = regs.lr_address + fixed_advance_pc; + regs.lr_op_index = 0; +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_fixed_advance_pc val %" + DW_PR_DSd, fixed_advance_pc); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx, + fixed_advance_pc); + dwarfstring_append_printf_u(&mb, + " new address 0x%" + DW_PR_XZEROS DW_PR_DSx "\n", + regs.lr_address); + _dwarf_printf(dbg, + dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + + /* New in DWARF3 */ + case DW_LNS_set_prologue_end:{ + regs.lr_prologue_end = true; + } + break; + /* New in DWARF3 */ + case DW_LNS_set_epilogue_begin:{ + regs.lr_epilogue_begin = true; +#ifdef PRINTING_DETAILS + _dwarf_printf(dbg, + "DW_LNS_set_prologue_end set true.\n"); +#endif /* PRINTING_DETAILS */ + } + break; + + /* New in DWARF3 */ + case DW_LNS_set_isa:{ + Dwarf_Unsigned utmp2 = 0; + int sires = 0; + + sires = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (sires == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + + regs.lr_isa = utmp2; + +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_u(&mb, + "DW_LNS_set_isa new value 0x%" + DW_PR_XZEROS DW_PR_DUx ".\n", + utmp2); + _dwarf_printf(dbg,dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + if (regs.lr_isa != utmp2) { + /* The value of the isa did + not fit in our + local so we record it wrong. + declare an error. */ + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg, + head_chain,line_count); + _dwarf_error(dbg, error, + DW_DLE_LINE_NUM_OPERANDS_BAD); + return DW_DLV_ERROR; + } + } + break; + + /* Experimental two-level line tables */ + /* DW_LNS_set_address_from_logical and + DW_LNS_set_subprogram + share the same opcode. Disambiguate by checking + is_actuals_table. */ + case DW_LNS_set_subprogram: + + if (is_actuals_table) { + /* DW_LNS_set_address_from_logical */ + Dwarf_Signed stmp = 0; + int atres = 0; + + atres = read_sword_de( &line_ptr,&stmp, + dbg,error,line_ptr_end); + if (atres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + advance_line = (Dwarf_Signed) stmp; + regs.lr_line = regs.lr_line + advance_line; + if ((Dwarf_Signed)regs.lr_line < 0) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "\nERROR: DW_DLE_LINE_TABLE_LINENO_ERROR" + " The line number is %d " + "and negative line numbers after " + "DW_LNS_set_subprogram ", + (Dwarf_Signed)regs.lr_line); + dwarfstring_append_printf_i(&m, + " of %d applied " + "are not correct.",stmp); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_LINENO_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + regs.lr_line = 0; + _dwarf_free_chain_entries(dbg, + head_chain,line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + + } + if (regs.lr_line >= 1 && + regs.lr_line - 1 < logicals_count) { + regs.lr_address = + logicals[regs.lr_line - 1]->li_address; + regs.lr_op_index = 0; +#ifdef PRINTING_DETAILS /* block 1 print */ + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_set_address_from" + "_logical " + "%" DW_PR_DSd, + stmp); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx, + stmp); + dwarfstring_append_printf_u(&mb, + " newaddr=" + " 0x%" DW_PR_XZEROS DW_PR_DUx ".\n", + regs.lr_address); + _dwarf_printf(dbg, + dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } else { +#ifdef PRINTING_DETAILS /* block 2 print */ + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_set_address_from_logical line" + " is %" DW_PR_DSd , + regs.lr_line); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx ".\n", + regs.lr_line); + _dwarf_printf(dbg, + dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + } else { + /* DW_LNS_set_subprogram, + building logicals table. */ + Dwarf_Unsigned utmp2 = 0; + int spres = 0; + + regs.lr_call_context = 0; + spres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (spres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + regs.lr_subprogram = utmp2; +#ifdef PRINTING_DETAILS /* block 3 print */ + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_set_subprogram " + "%" DW_PR_DSd, + utmp2); + dwarfstring_append_printf_u(&mb, + " 0x%" DW_PR_XZEROS DW_PR_DSx "\n", + utmp2); + _dwarf_printf(dbg, + dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + /* Experimental two-level line tables */ + case DW_LNS_inlined_call: { + Dwarf_Signed stmp = 0; + Dwarf_Unsigned ilcuw = 0; + int icres = 0; + + icres = read_sword_de( &line_ptr,&stmp, + dbg,error,line_ptr_end); + if (icres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + regs.lr_call_context = line_count + stmp; + icres = read_uword_de(&line_ptr,&ilcuw, + dbg,error,line_ptr_end); + regs.lr_subprogram = ilcuw; + if (icres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + +#ifdef PRINTING_DETAILS + dwarfstring_constructor(&mb); + dwarfstring_append_printf_i(&mb, + "DW_LNS_inlined_call " + "%" DW_PR_DSd ,stmp); + dwarfstring_append_printf_u(&mb, + " (0x%" DW_PR_XZEROS DW_PR_DSx "),", + stmp); + dwarfstring_append_printf_i(&mb, + "%" DW_PR_DSd, + regs.lr_subprogram); + dwarfstring_append_printf_u(&mb, + " (0x%" DW_PR_XZEROS DW_PR_DSx ")", + regs.lr_subprogram); + dwarfstring_append_printf_i(&mb, + " callcontext=" "%" DW_PR_DSd , + regs.lr_call_context); + dwarfstring_append_printf_u(&mb, + " (0x%" DW_PR_XZEROS DW_PR_DSx ")\n", + regs.lr_call_context); + _dwarf_printf(dbg, + dwarfstring_string(&mb)); + dwarfstring_destructor(&mb); +#endif /* PRINTING_DETAILS */ + } + break; + + /* Experimental two-level line tables */ + case DW_LNS_pop_context: { + Dwarf_Unsigned logical_num = regs.lr_call_context; + Dwarf_Chain logical_chain = head_chain; + Dwarf_Line logical_line = 0; + + if (logical_num > 0 && logical_num <= line_count) { + for (i = 1; i < logical_num; i++) { + logical_chain = logical_chain->ch_next; + } + logical_line = + (Dwarf_Line) logical_chain->ch_item; + regs.lr_file = + logical_line->li_l_data.li_file; + regs.lr_line = + logical_line->li_l_data.li_line; + regs.lr_column = + logical_line-> + li_l_data.li_column; + regs.lr_discriminator = + logical_line-> + li_l_data.li_discriminator; + regs.lr_is_stmt = + logical_line-> + li_l_data.li_is_stmt; + regs.lr_call_context = + logical_line-> + li_l_data.li_call_context; + regs.lr_subprogram = + logical_line-> + li_l_data.li_subprogram; +#ifdef PRINTING_DETAILS + { + dwarfstring pcon; + dwarfstring_constructor(&pcon); + dwarfstring_append_printf_u(&pcon, + "DW_LNS_pop_context set" + " from logical " + "%" DW_PR_DUu ,logical_num); + dwarfstring_append_printf_u(&pcon, + " (0x%" DW_PR_XZEROS DW_PR_DUx ")\n", + logical_num); + _dwarf_printf(dbg, + dwarfstring_string(&pcon)); + dwarfstring_destructor(&pcon); + } + } else { + dwarfstring pcon; + dwarfstring_constructor(&pcon); + dwarfstring_append_printf_u(&pcon, + "DW_LNS_pop_context does nothing, logical" + "%" DW_PR_DUu , + logical_num); + dwarfstring_append_printf_u(&pcon, + " (0x%" DW_PR_XZEROS DW_PR_DUx ")\n", + logical_num); + _dwarf_printf(dbg, + dwarfstring_string(&pcon)); + dwarfstring_destructor(&pcon); +#endif /* PRINTING_DETAILS */ + } + } + break; + default: + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + "DW_DLE_LINE_TABLE_BAD: " + "Impossible standard line table operator"); + return DW_DLV_ERROR; + } /* End switch (opcode) */ + } else if (type == LOP_EXTENDED) { + Dwarf_Unsigned utmp3 = 0; + Dwarf_Small ext_opcode = 0; + int leres = 0; + + leres = read_uword_de( &line_ptr,&utmp3, + dbg,error,line_ptr_end); + if (leres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + + instr_length = utmp3; + /* Dwarf_Small is a ubyte and the extended opcode is a + ubyte, though not stated as clearly in the + 2.0.0 spec as one might hope. */ + if (line_ptr >= line_ptr_end) { + dwarfstring g; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned localoffset = + (line_ptr >= section_start)? + (line_ptr - section_start) : 0; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "extended op we are " + "off this line table at section " + "offset 0x%x .", + localoffset); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain,line_count); + return DW_DLV_ERROR; + } + ext_opcode = *(Dwarf_Small *) line_ptr; + line_ptr++; + if (line_ptr > line_ptr_end) { + dwarfstring g; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "extended op opcode we are " + "off this line table at section " + "offset 0x%x .", + localoff); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + _dwarf_free_chain_entries(dbg,head_chain,line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + switch (ext_opcode) { + + case DW_LNE_end_sequence:{ + regs.lr_end_sequence = true; + if (dolines) { + curr_line = (Dwarf_Line) + _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); + if (!curr_line) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + +#ifdef PRINTING_DETAILS + print_line_detail(dbg, + "DW_LNE_end_sequence extended", + ext_opcode, line_count+1,®s, + is_single_table, is_actuals_table); +#endif /* PRINTING_DETAILS */ + curr_line->li_address = regs.lr_address; + curr_line->li_l_data.li_file = + (Dwarf_Signed) regs.lr_file; + curr_line->li_l_data.li_line = + (Dwarf_Signed) regs.lr_line; + curr_line->li_l_data.li_column = + (Dwarf_Half) regs.lr_column; + curr_line->li_l_data.li_is_stmt = + regs.lr_is_stmt; + curr_line->li_l_data. + li_basic_block = regs.lr_basic_block; + curr_line->li_l_data. + li_end_sequence = regs.lr_end_sequence; + curr_line->li_context = line_context; + curr_line->li_is_actuals_table = is_actuals_table; + curr_line->li_l_data. + li_epilogue_begin = regs.lr_epilogue_begin; + curr_line->li_l_data. + li_prologue_end = regs.lr_prologue_end; + curr_line->li_l_data.li_isa = + regs.lr_isa; + curr_line->li_l_data.li_discriminator + = regs.lr_discriminator; + curr_line->li_l_data.li_call_context + = regs.lr_call_context; + curr_line->li_l_data.li_subprogram = + regs.lr_subprogram; + line_count++; + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + chain_line->ch_itemtype = DW_DLA_LINE; + chain_line->ch_item = curr_line; + _dwarf_update_chain_list(chain_line, + &head_chain,&curr_chain); + curr_line = 0; + } + _dwarf_set_line_table_regs_default_values(®s, + line_context->lc_version_number, + line_context->lc_default_is_stmt); + } + break; + + case DW_LNE_set_address:{ + int sares = 0; + /* READ_UNALIGNED_CK(dbg, regs.lr_address, + Dwarf_Addr, + line_ptr, address_size,error,line_ptr_end); */ + sares = _dwarf_read_unaligned_ck_wrapper(dbg, + ®s.lr_address,line_ptr, + address_size,line_ptr_end, + error); + if (sares == DW_DLV_ERROR) { + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return sares; + } + + /* Mark a line record as being DW_LNS_set_address */ + is_addr_set = true; +#ifdef PRINTING_DETAILS + { + dwarfstring sadd; + dwarfstring_constructor(&sadd); + dwarfstring_append_printf_u(&sadd, + "DW_LNE_set_address address 0x%" + DW_PR_XZEROS DW_PR_DUx "\n", + regs.lr_address); + _dwarf_printf(dbg,dwarfstring_string(&sadd)); + dwarfstring_destructor(&sadd); + } +#endif /* PRINTING_DETAILS */ + if (doaddrs) { + /* SGI IRIX rqs processing only. */ + curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, + DW_DLA_LINE, 1); + if (!curr_line) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + /* Mark a line record as being + DW_LNS_set_address */ + curr_line->li_l_data.li_is_addr_set + = is_addr_set; + is_addr_set = false; + curr_line->li_address = regs.lr_address; +#ifdef __sgi /* SGI IRIX ONLY */ + /* ptrdiff_t is generated but not named */ + curr_line->li_offset = + line_ptr - dbg->de_debug_line.dss_data; +#endif /* __sgi */ + line_count++; + chain_line = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (chain_line == NULL) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + chain_line->ch_itemtype = DW_DLA_LINE; + chain_line->ch_item = curr_line; + _dwarf_update_chain_list(chain_line, + &head_chain,&curr_chain); + curr_line = 0; + } + regs.lr_op_index = 0; + line_ptr += address_size; + if (line_ptr > line_ptr_end) { + dwarfstring g; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "DW_LNE_set_address we are " + "off this line table at section " + "offset 0x%x .", + localoff); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } + } + break; + + case DW_LNE_define_file: + if (dolines) { + int dlres = 0; + Dwarf_Unsigned value = 0; + + cur_file_entry = (Dwarf_File_Entry) + malloc(sizeof(struct Dwarf_File_Entry_s)); + if (cur_file_entry == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } + memset(cur_file_entry,0, + sizeof(struct Dwarf_File_Entry_s)); + _dwarf_add_to_files_list(line_context, + cur_file_entry); + cur_file_entry->fi_file_name = + (Dwarf_Small *) line_ptr; + dlres = _dwarf_check_string_valid(dbg, + line_ptr,line_ptr,line_ptr_end, + DW_DLE_DEFINE_FILE_STRING_BAD,error); + if (dlres != DW_DLV_OK) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return dlres; + } + line_ptr = line_ptr + strlen((char *) line_ptr) + + 1; + dlres = read_uword_de( &line_ptr,&value, + dbg,error,line_ptr_end); + if (dlres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + cur_file_entry->fi_dir_index = + (Dwarf_Signed)value; + cur_file_entry->fi_dir_index_present = TRUE; + dlres = read_uword_de( &line_ptr,&value, + dbg,error,line_ptr_end); + if (dlres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + cur_file_entry->fi_time_last_mod = value; + dlres = read_uword_de( &line_ptr,&value, + dbg,error,line_ptr_end); + if (dlres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + cur_file_entry->fi_file_length = value; + cur_file_entry->fi_dir_index_present = TRUE; + cur_file_entry->fi_time_last_mod_present = TRUE; + cur_file_entry->fi_file_length_present = TRUE; +#ifdef PRINTING_DETAILS + { + dwarfstring m9c; + dwarfstring_constructor(&m9c); + dwarfstring_append_printf_s(&m9c, + "DW_LNE_define_file %s \n", + (char *)cur_file_entry->fi_file_name); + dwarfstring_append_printf_i(&m9c, + " dir index %d\n", + (int) cur_file_entry->fi_dir_index); + + { + time_t tt3 = (time_t) cur_file_entry-> + fi_time_last_mod; + + /* ctime supplies newline */ + dwarfstring_append_printf_u(&m9c, + " last time 0x%x ", + (Dwarf_Unsigned)tt3); + dwarfstring_append_printf_s(&m9c, + "%s", + ctime(&tt3)); + } + dwarfstring_append_printf_i(&m9c, + " file length %ld ", + cur_file_entry->fi_file_length); + dwarfstring_append_printf_u(&m9c, + "0x%lx\n", + cur_file_entry->fi_file_length); + _dwarf_printf(dbg,dwarfstring_string(&m9c)); + dwarfstring_destructor(&m9c); + } +#endif /* PRINTING_DETAILS */ + } + break; + case DW_LNE_set_discriminator:{ + /* New in DWARF4 */ + int sdres = 0; + Dwarf_Unsigned utmp2 = 0; + + sdres = read_uword_de( &line_ptr,&utmp2, + dbg,error,line_ptr_end); + if (sdres == DW_DLV_ERROR) { + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + return DW_DLV_ERROR; + } + regs.lr_discriminator = utmp2; + +#ifdef PRINTING_DETAILS + { + dwarfstring mk; + dwarfstring_constructor(&mk); + dwarfstring_append_printf_u(&mk, + "DW_LNE_set_discriminator 0x%" + DW_PR_XZEROS DW_PR_DUx "\n", + utmp2); + _dwarf_printf(dbg,dwarfstring_string(&mk)); + dwarfstring_destructor(&mk); + } +#endif /* PRINTING_DETAILS */ + } + break; + default:{ + /* This is an extended op code we do not know about, + other than we know now many bytes it is + and the op code and the bytes of operand. */ + Dwarf_Unsigned remaining_bytes = instr_length -1; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned space_left = + (line_ptr <= line_ptr_end)? + (line_ptr_end - line_ptr):0xfffffff; + + /* By catching this here instead of PRINTING_DETAILS + we avoid reading off of our data of interest*/ + if (instr_length < 1 || + space_left < remaining_bytes || + remaining_bytes > DW_LNE_LEN_MAX) { + dwarfstring g; + /* ptrdiff_t is generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "unknown DW_LNE_extended op opcode 0x%x ", + ext_opcode); + dwarfstring_append_printf_u(&g, + "we are " + "off this line table at section " + "offset 0x%x and ", + localoff); + dwarfstring_append_printf_u(&g, + "instruction length " + "%u.",instr_length); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } + +#ifdef PRINTING_DETAILS + { + dwarfstring m9d; + dwarfstring_constructor(&m9d); + dwarfstring_append_printf_u(&m9d, + "DW_LNE extended op 0x%x ", + ext_opcode); + dwarfstring_append_printf_u(&m9d, + "Bytecount: %" DW_PR_DUu , + (Dwarf_Unsigned)instr_length); + if (remaining_bytes > 0) { + /* If remaining bytes > distance to end + we will have an error. */ + dwarfstring_append(&m9d," linedata: 0x"); + while (remaining_bytes > 0) { + dwarfstring_append_printf_u(&m9d, + "%02x", + (unsigned char)(*(line_ptr))); + line_ptr++; +#if 0 + /* A test above (see space_left above) + proves we will not run off the end here. + The following test is too late anyway, + we might have read off the end just + before line_ptr incremented! */ + if (line_ptr >= line_ptr_end) { + dwarfstring g; + /* ptrdiff_t generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "DW_LNE extended op remaining bytes " + "we are " + "off this line table at section " + "offset 0x%x .", + localoff); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + dwarfstring_destructor(&m9d); + if (curr_line) { + dwarf_dealloc(dbg,curr_line, + DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg, + head_chain,line_count); + return DW_DLV_ERROR; + } +#endif + remaining_bytes--; + } + } + _dwarf_printf(dbg,dwarfstring_string(&m9d)); + dwarfstring_destructor(&m9d); + } +#else /* ! PRINTING_DETAILS */ + line_ptr += remaining_bytes; + if (line_ptr > line_ptr_end) { + dwarfstring g; + /* ptrdiff_t generated but not named */ + Dwarf_Unsigned localoff = + (line_ptr >= section_start)? + (line_ptr - section_start):0xfffffff; + + dwarfstring_constructor(&g); + dwarfstring_append_printf_u(&g, + "DW_DLE_LINE_TABLE_BAD reading " + "DW_LNE extended op remaining bytes " + "we are " + "off this line table at section " + "offset 0x%x .", + localoff); + _dwarf_error_string(dbg, error, + DW_DLE_LINE_TABLE_BAD, + dwarfstring_string(&g)); + dwarfstring_destructor(&g); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + } + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + return DW_DLV_ERROR; + } +#endif /* PRINTING_DETAILS */ + _dwarf_printf(dbg,"\n"); + } + break; + } /* End switch. */ + } else { + /* ASSERT: impossible, see the macro definition */ + _dwarf_free_chain_entries(dbg,head_chain, + line_count); + _dwarf_error_string(dbg,error, + DW_DLE_LINE_TABLE_BAD, + "DW_DLE_LINE_TABLE_BAD: Actually is " + "an impossible type from WHAT_IS_CODE"); + return DW_DLV_ERROR; + } + } + block_line = (Dwarf_Line *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, line_count); + if (block_line == NULL) { + curr_chain = head_chain; + _dwarf_free_chain_entries(dbg,head_chain,line_count); + if (curr_line) { + dwarf_dealloc(dbg,curr_line,DW_DLA_LINE); + curr_line = 0; + } + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + curr_chain = head_chain; + for (i = 0; i < line_count; i++) { + Dwarf_Chain t = 0; + *(block_line + i) = curr_chain->ch_item; + curr_chain->ch_item = 0; + curr_chain->ch_itemtype = 0; + t = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, t, DW_DLA_CHAIN); + } + + if (is_single_table || !is_actuals_table) { + line_context->lc_linebuf_logicals = block_line; + line_context->lc_linecount_logicals = line_count; + } else { + line_context->lc_linebuf_actuals = block_line; + line_context->lc_linecount_actuals = line_count; + } +#ifdef PRINTING_DETAILS + { + dwarfstring mc; + dwarfstring_constructor(&mc); + if (is_single_table) { + if (!line_count) { + dwarfstring_append_printf_u(&mc, + " Line table is present (offset 0x%" + DW_PR_XZEROS DW_PR_DUx + ") but no lines present\n", + line_context->lc_section_offset); + } + } else if (is_actuals_table) { + if (!line_count) { + dwarfstring_append_printf_u(&mc, + " Line table present (offset 0x%" + DW_PR_XZEROS DW_PR_DUx + ") but no actuals lines present\n", + line_context->lc_section_offset); + } + } else { + if (!line_count) { + dwarfstring_append_printf_u(&mc, + " Line table present (offset 0x%" + DW_PR_XZEROS DW_PR_DUx + ") but no logicals lines present\n", + line_context->lc_section_offset); + } + } + if (dwarfstring_strlen(&mc)) { + _dwarf_printf(dbg,dwarfstring_string(&mc)); + } + dwarfstring_destructor(&mc); + } +#endif /* PRINTING_DETAILS */ + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_loc.c b/src/lib/libdwarf/dwarf_loc.c new file mode 100644 index 0000000..d2b3201 --- /dev/null +++ b/src/lib/libdwarf/dwarf_loc.c @@ -0,0 +1,1929 @@ +/* + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2018 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_loc.h" +#include "dwarf_string.h" + +static int _dwarf_read_loc_section_dwo(Dwarf_Debug dbg, + Dwarf_Block_c * return_block, + Dwarf_Addr * lowpc, + Dwarf_Addr * highpc, + Dwarf_Bool * at_end, + Dwarf_Half * lle_op, + Dwarf_Off sec_offset, + Dwarf_Half address_size, + Dwarf_Half lkind, + Dwarf_Error *error); + +/* Used to enable sanity checking of these data + items before we return to caller. */ +int +_dwarf_locdesc_c_constructor(Dwarf_Debug dbg, void *locd) +{ + Dwarf_Locdesc_c ldp = (Dwarf_Locdesc_c)locd; + + if (!dbg) { + return DW_DLV_ERROR; + } + ldp->ld_lle_value = DW_LLE_VALUE_BOGUS; + ldp->ld_kind = DW_LKIND_unknown; + return DW_DLV_OK; +} + +static void +_dwarf_lkind_name(unsigned lkind, dwarfstring *m) +{ + switch(lkind) { + case DW_LKIND_expression: + dwarfstring_append(m,"DW_LKIND_expression"); + return; + case DW_LKIND_loclist: + dwarfstring_append(m,"DW_LKIND_loclist"); + return; + case DW_LKIND_GNU_exp_list: + dwarfstring_append(m,"DW_LKIND_GNU_exp_list"); + return; + case DW_LKIND_loclists: + dwarfstring_append(m,"DW_LKIND_loclists"); + return; + case DW_LKIND_unknown: + dwarfstring_append(m,"DW_LKIND_unknown"); + return; + default: break; + } + dwarfstring_append_printf_u(m, + ".", + lkind); +} + +static int +determine_location_lkind(unsigned int version, + unsigned int form, + Dwarf_Bool is_dwo) +{ + switch(form) { + case DW_FORM_exprloc: /* only defined for + DW_CFA_def_cfa_expression */ + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + return DW_LKIND_expression; + break; + case DW_FORM_data4: + case DW_FORM_data8: + if (version > 1 && version < 4) { + return DW_LKIND_loclist; + } + break; + case DW_FORM_sec_offset: + if (version == 5 ) { + return DW_LKIND_loclists; + } + if (version == 4 && is_dwo ) { + return DW_LKIND_GNU_exp_list; + } + return DW_LKIND_loclist; + break; + case DW_FORM_loclistx: + if (version == 5 ) { + return DW_LKIND_loclists; + } + break; + default: + break; + } + return DW_LKIND_unknown; +} + +static void +_dwarf_free_op_chain(Dwarf_Debug dbg, + Dwarf_Loc_Chain headloc) +{ + Dwarf_Loc_Chain cur = headloc; + + while (cur) { + Dwarf_Loc_Chain next = cur->lc_next; + dwarf_dealloc(dbg, cur, DW_DLA_LOC_CHAIN); + cur = next; + } +} + +/* Using a loclist offset to get the in-memory + address of .debug_loc data to read, returns the loclist + 'header' info in return_block. +*/ + +#define MAX_ADDR \ + ((address_size == 8)?0xffffffffffffffffULL:0xffffffff) + +static int +_dwarf_read_loc_section(Dwarf_Debug dbg, + Dwarf_Block_c * return_block, + Dwarf_Addr * lowpc, + Dwarf_Addr * hipc, + Dwarf_Half * lle_val, + Dwarf_Off sec_offset, + Dwarf_Half address_size, + Dwarf_Error * error) +{ + Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset; + Dwarf_Small *loc_section_end = + dbg->de_debug_loc.dss_data + dbg->de_debug_loc.dss_size; + + /* start_addr and end_addr are actually offsets + of the applicable base address of the CU. + They are address-size. */ + Dwarf_Addr start_addr = 0; + Dwarf_Addr end_addr = 0; + Dwarf_Half exprblock_size = 0; + Dwarf_Unsigned exprblock_off = + 2 * address_size + DWARF_HALF_SIZE; + + if (sec_offset >= dbg->de_debug_loc.dss_size) { + /* We're at the end. No more present. */ + return DW_DLV_NO_ENTRY; + } + + /* If it goes past end, error */ + if (exprblock_off > dbg->de_debug_loc.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); + return DW_DLV_ERROR; + } + + READ_UNALIGNED_CK(dbg, start_addr, Dwarf_Addr, beg, address_size, + error,loc_section_end); + READ_UNALIGNED_CK(dbg, end_addr, Dwarf_Addr, + beg + address_size, address_size, + error,loc_section_end); + if (start_addr == 0 && end_addr == 0) { + /* If start_addr and end_addr are 0, it's the end and no + exprblock_size field follows. */ + exprblock_size = 0; + exprblock_off -= DWARF_HALF_SIZE; + *lle_val = DW_LLE_end_of_list; + } else if (start_addr == MAX_ADDR) { + /* End address is a base address, + no exprblock_size field here either */ + exprblock_size = 0; + exprblock_off -= DWARF_HALF_SIZE; + *lle_val = DW_LLE_base_address; + } else { + /* Here we note the address and length of the + expression operators, DW_OP_reg0 etc */ + READ_UNALIGNED_CK(dbg, exprblock_size, Dwarf_Half, + beg + 2 * address_size, DWARF_HALF_SIZE, + error,loc_section_end); + /* exprblock_size can be zero, means no expression */ + if ( exprblock_size >= dbg->de_debug_loc.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); + return DW_DLV_ERROR; + } + if ((sec_offset +exprblock_off + exprblock_size) > + dbg->de_debug_loc.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT); + return DW_DLV_ERROR; + } + *lle_val = DW_LLE_start_end; + } + *lowpc = start_addr; + *hipc = end_addr; + + return_block->bl_len = exprblock_size; + return_block->bl_kind = DW_LKIND_loclist; + return_block->bl_data = beg + exprblock_off; + return_block->bl_section_offset = + ((Dwarf_Small *) return_block->bl_data) - + dbg->de_debug_loc.dss_data; + return DW_DLV_OK; +} + +static int +_dwarf_get_loclist_lle_count_dwo(Dwarf_Debug dbg, + Dwarf_Off loclist_offset, + Dwarf_Half address_size, + Dwarf_Half lkind, + int *loclist_count, + Dwarf_Error * error) +{ + int count = 0; + Dwarf_Off offset = loclist_offset; + + for (;;) { + Dwarf_Block_c b; + Dwarf_Bool at_end = FALSE; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_Half lle_op = 0; + int res = _dwarf_read_loc_section_dwo(dbg, &b, + &lowpc, + &highpc, + &at_end, + &lle_op, + offset, + address_size, + lkind, + error); + if (res != DW_DLV_OK) { + return res; + } + if (at_end) { + count++; + break; + } + offset = b.bl_len + b.bl_section_offset; + count++; + } + *loclist_count = count; + return DW_DLV_OK; +} + +static int +_dwarf_get_loclist_lle_count(Dwarf_Debug dbg, + Dwarf_Off loclist_offset, + Dwarf_Half address_size, + int *loclist_count, + Dwarf_Error * error) +{ + int count = 0; + Dwarf_Off offset = loclist_offset; + + for (;;) { + Dwarf_Block_c b; + Dwarf_Addr lowpc = 0; + Dwarf_Addr highpc = 0; + Dwarf_Half lle_val = DW_LLE_VALUE_BOGUS; + + int res = _dwarf_read_loc_section(dbg, &b, + &lowpc, &highpc, + &lle_val, + offset, address_size,error); + if (res != DW_DLV_OK) { + return res; + } + offset = b.bl_len + b.bl_section_offset; + if (lowpc == 0 && highpc == 0) { + break; + } + count++; + } + *loclist_count = count; + return DW_DLV_OK; +} + +/* Helper routine to avoid code duplication. +*/ +static int +_dwarf_setup_loc(Dwarf_Attribute attr, + Dwarf_Debug * dbg_ret, + Dwarf_CU_Context *cucontext_ret, + Dwarf_Half *form_ret, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Half form = 0; + int blkres = DW_DLV_ERROR; + + /* Creating an error with NULL dbg is not a good thing. + These won't be freed if we later call dealloc + with a non-NULL dbg. + */ + if (!attr) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_NULL, + "DW_DLE_ATTR_NULL: the attribute passed to " + "dwarf_get_loclist_c() is a NULL pointer"); + return DW_DLV_ERROR; + } + if (attr->ar_cu_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + *cucontext_ret = attr->ar_cu_context; + + dbg = attr->ar_cu_context->cc_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_ATTR_DBG_NULL, + "DW_DLE_ATTR_DBG_NULL The Attribute passed to " + "dwarf_get_loclist_c() " + "points to an invalid Dwarf_Debug"); + return DW_DLV_ERROR; + } + *dbg_ret = dbg; + blkres = dwarf_whatform(attr, &form, error); + if (blkres != DW_DLV_OK) { + return blkres; + } + *form_ret = form; + return DW_DLV_OK; +} + +/* Helper routine to avoid code duplication. +*/ +static int +_dwarf_get_loclist_header_start(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_Unsigned * loclist_offset_out, + Dwarf_Error * error) +{ + Dwarf_Unsigned loc_sec_size = 0; + Dwarf_Unsigned loclist_offset = 0; + + int blkres = dwarf_global_formref(attr, &loclist_offset, error); + if (blkres != DW_DLV_OK) { + return blkres; + } + if (!dbg->de_debug_loc.dss_data) { + int secload = _dwarf_load_section(dbg, + &dbg->de_debug_loc,error); + if (secload != DW_DLV_OK) { + return secload; + } + if (!dbg->de_debug_loc.dss_size) { + return DW_DLV_NO_ENTRY; + } + } + loc_sec_size = dbg->de_debug_loc.dss_size; + if (loclist_offset >= loc_sec_size) { + _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); + return DW_DLV_ERROR; + } + + { + int fisres = 0; + Dwarf_Unsigned fissoff = 0; + Dwarf_Unsigned size = 0; + fisres = _dwarf_get_fission_addition_die(attr->ar_die, + DW_SECT_LOCLISTS, + &fissoff, &size,error); + if (fisres != DW_DLV_OK) { + return fisres; + } + if (fissoff >= loc_sec_size) { + _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); + return DW_DLV_ERROR; + } + loclist_offset += fissoff; + if (loclist_offset >= loc_sec_size) { + _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD); + return DW_DLV_ERROR; + } + } + *loclist_offset_out = loclist_offset; + return DW_DLV_OK; +} + +static int +context_is_cu_not_tu(Dwarf_CU_Context context, + Dwarf_Bool *r) +{ + int ut = context->cc_unit_type; + + if (ut == DW_UT_type || ut == DW_UT_split_type ) { + *r =FALSE; + return DW_DLV_OK; + } + *r = TRUE; + return DW_DLV_OK; +} + +/* Handles only a location expression. + It returns the location expression as a loclist with + a single entry. + + Usable to access dwarf expressions from any source, but + specifically from + DW_CFA_def_cfa_expression + DW_CFA_expression + DW_CFA_val_expression + expression_in must point to a valid dwarf expression +*/ + +/* ============== the October 2015 interfaces. */ +int +_dwarf_loc_block_sanity_check(Dwarf_Debug dbg, + Dwarf_Block_c *loc_block,Dwarf_Error* error) +{ + unsigned lkind = loc_block->bl_kind; + if (lkind == DW_LKIND_loclist) { + Dwarf_Small *loc_ptr = 0; + Dwarf_Unsigned loc_len = 0; + Dwarf_Small *end_ptr = 0; + + loc_ptr = loc_block->bl_data; + loc_len = loc_block->bl_len; + end_ptr = dbg->de_debug_loc.dss_size + + dbg->de_debug_loc.dss_data; + if ((loc_ptr +loc_len) > end_ptr) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_LOC_SECTION_SHORT kind: "); + _dwarf_lkind_name(lkind, &m); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_LOC_SECTION_SHORT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + return DW_DLV_OK; + } + if (lkind == DW_LKIND_loclists) { + Dwarf_Small *loc_ptr = 0; + Dwarf_Unsigned loc_len = 0; + Dwarf_Small *end_ptr = 0; + + loc_ptr = loc_block->bl_data; + loc_len = loc_block->bl_len; + end_ptr = dbg->de_debug_loclists.dss_size + + dbg->de_debug_loclists.dss_data; + if ((loc_ptr +loc_len) > end_ptr) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_LOC_SECTION_SHORT " + "(the .debug_loclists section is short), kind: "); + _dwarf_lkind_name(lkind, &m); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_LOC_SECTION_SHORT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + return DW_DLV_OK; +} + +/* ld_kind was checked before calling this, so we + know its value is an intended value. */ +static const char *kindset[] = { +"DW_LKIND_expression", +"DW_LKIND_loclist", +"DW_LKIND_GNU_exp_list", +"DW_LKIND_unknown3", +"DW_LKIND_unknown4", +"DW_LKIND_loclists" +}; +static const char * +get_loc_kind_str(Dwarf_Small lkind) +{ + if (lkind <= DW_LKIND_loclists) { + return kindset[lkind]; + } + if (lkind == DW_LKIND_unknown) { + return "DW_LKIND_unknown"; + } + return "UNKNOWN DW_LKIND!"; +} +static int +validate_lle_value(Dwarf_Debug dbg, + Dwarf_Locdesc_c locdesc, + Dwarf_Error *error) +{ + dwarfstring m; + + if (locdesc->ld_kind != DW_LKIND_GNU_exp_list) { + switch(locdesc->ld_lle_value) { + case DW_LLE_end_of_list: + case DW_LLE_base_addressx: + case DW_LLE_startx_endx: + case DW_LLE_startx_length: + case DW_LLE_offset_pair: + case DW_LLE_default_location: + case DW_LLE_base_address: + case DW_LLE_start_end: + case DW_LLE_start_length: + return DW_DLV_OK; + default: break; + } + dwarfstring_constructor(&m); + + dwarfstring_append_printf_s(&m, + "DW_DLE_LOCATION_ERROR: For location kind %s (", + (char *)get_loc_kind_str(locdesc->ld_kind)); + dwarfstring_append_printf_u(&m,"%u) the DW_LLE value is " + "not properly set", + locdesc->ld_kind); + dwarfstring_append_printf_u(&m," but is %u " + " which is a libdwarf bug", + locdesc->ld_lle_value); + _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + switch(locdesc->ld_lle_value) { + case DW_LLEX_end_of_list_entry: + case DW_LLEX_base_address_selection_entry: + case DW_LLEX_start_end_entry: + case DW_LLEX_start_length_entry: + case DW_LLEX_offset_pair_entry: + return DW_DLV_OK; + default: break; /* ERROR */ + } + { + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_LOCATION_ERROR: For location kind %s (", + (char *)get_loc_kind_str(locdesc->ld_kind)); + dwarfstring_append_printf_u(&m,"%u) the DW_LLEX value is " + "not properly set", + locdesc->ld_kind); + dwarfstring_append_printf_u(&m," but is %u " + " which is a libdwarf bug", + locdesc->ld_lle_value); + _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; +} +/* Sets locdesc operator list information in locdesc. + Sets the locdesc values (rawlow, rawhigh etc). + This synthesizes the ld_lle_value of the locdesc + if it's not already provided. + Not passing in locdesc pointer, the locdesc_index suffices + to index to the relevant locdesc pointer. + See also dwarf_loclists.c: build_array_of_lle*/ +int +_dwarf_fill_in_locdesc_op_c(Dwarf_Debug dbg, + Dwarf_Unsigned locdesc_index, + Dwarf_Loc_Head_c loc_head, + Dwarf_Block_c * loc_block, + Dwarf_Half address_size, + Dwarf_Half offset_size, + Dwarf_Small version_stamp, + Dwarf_Addr lowpc, + Dwarf_Addr highpc, + Dwarf_Half lle_op, + Dwarf_Error * error) +{ + /* Offset of current operator from start of block. */ + Dwarf_Unsigned offset = 0; + + /* Chain the DW_OPerator structs. */ + Dwarf_Loc_Chain new_loc = NULL; + Dwarf_Loc_Chain prev_loc = NULL; + Dwarf_Loc_Chain head_loc = NULL; + Dwarf_Loc_Chain *plast = &head_loc; + + Dwarf_Unsigned op_count = 0; + + /* Contiguous block of Dwarf_Loc_Expr_Op_s + for Dwarf_Locdesc. */ + Dwarf_Loc_Expr_Op block_loc = 0; + + Dwarf_Locdesc_c locdesc = loc_head->ll_locdesc + locdesc_index; + Dwarf_Unsigned i = 0; + int res = 0; + Dwarf_Small *section_start = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Small *section_end = 0; + const char *section_name = 0; + Dwarf_Small *blockdataptr = 0; + unsigned lkind = loc_head->ll_kind; + + /* ***** BEGIN CODE ***** */ + blockdataptr = loc_block->bl_data; + if (!blockdataptr || !loc_block->bl_len) { + /* an empty block has no operations so + no section or tests need be done.. */ + } else { + res = _dwarf_what_section_are_we(dbg, + blockdataptr,§ion_name,§ion_start, + §ion_size,§ion_end); + if (res != DW_DLV_OK) { + _dwarf_error(dbg, error,DW_DLE_POINTER_SECTION_UNKNOWN); + return DW_DLV_ERROR; + } + res = _dwarf_loc_block_sanity_check(dbg,loc_block,error); + if (res != DW_DLV_OK) { + return res; + } + } + /* New loop getting Loc operators. Non DWO */ + while (offset <= loc_block->bl_len) { + Dwarf_Unsigned nextoffset = 0; + struct Dwarf_Loc_Expr_Op_s temp_loc; + + /* This call is ok even if bl_data NULL and bl_len 0 */ + res = _dwarf_read_loc_expr_op(dbg,loc_block, + op_count, + version_stamp, + offset_size, + address_size, + offset, + section_end, + &nextoffset, + &temp_loc, + error); + if (res == DW_DLV_ERROR) { + _dwarf_free_op_chain(dbg,head_loc); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* Normal end. + Also the end for an empty loc_block. */ + break; + } + op_count++; + new_loc = (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, + DW_DLA_LOC_CHAIN, 1); + if (new_loc == NULL) { + _dwarf_free_op_chain(dbg,head_loc); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + /* Copying all the fields. DWARF 2,3,4,5. */ + new_loc->lc_atom = temp_loc.lr_atom; + new_loc->lc_opnumber= temp_loc.lr_opnumber; + new_loc->lc_number = temp_loc.lr_number; + new_loc->lc_number2 = temp_loc.lr_number2; + new_loc->lc_number3 = temp_loc.lr_number3; + new_loc->lc_offset = temp_loc.lr_offset; + *plast = new_loc; + plast= &(new_loc->lc_next); + offset = nextoffset; + } + block_loc = + (Dwarf_Loc_Expr_Op ) _dwarf_get_alloc(dbg, + DW_DLA_LOC_BLOCK_C, op_count); + new_loc = head_loc; + if (!block_loc) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + for (i = 0; i < op_count; i++) { + prev_loc = new_loc; + new_loc = prev_loc->lc_next; + dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN); + } + return DW_DLV_ERROR; + } + + /* op_count could be zero. */ + new_loc = head_loc; + for (i = 0; i < op_count; i++) { + /* Copying only the fields needed by DWARF 2,3,4 */ + (block_loc + i)->lr_atom = new_loc->lc_atom; + (block_loc + i)->lr_number = new_loc->lc_number; + (block_loc + i)->lr_number2 = new_loc->lc_number2; + (block_loc + i)->lr_number3 = new_loc->lc_number3; + (block_loc + i)->lr_offset = new_loc->lc_offset; + (block_loc + i)->lr_opnumber = new_loc->lc_opnumber; + prev_loc = new_loc; + new_loc = prev_loc->lc_next; + dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN); + } + /* Synthesizing the DW_LLE values for the old loclist + versions. */ + switch(loc_head->ll_kind) { + case DW_LKIND_loclist: { + if (highpc == 0 && lowpc == 0) { + locdesc->ld_lle_value = DW_LLE_end_of_list; + } else if (lowpc == MAX_ADDR) { + locdesc->ld_lle_value = DW_LLE_base_address; + } else { + locdesc->ld_lle_value = DW_LLE_offset_pair; + } + } + break; + case DW_LKIND_GNU_exp_list: + /* DW_LKIND_GNU_exp_list */ + locdesc->ld_lle_value = lle_op; + break; + case DW_LKIND_expression: + /* This is a kind of fake, but better than 0 */ + locdesc->ld_lle_value = DW_LLE_start_end; + break; + case DW_LKIND_loclists: + /* ld_lle_value already set */ + break; + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCATION_ERROR: An impossible DW_LKIND" + " value of %u encountered, likely internal " + "libdwarf error or data corruption", + (unsigned)loc_head->ll_kind); + _dwarf_error_string(dbg,error, + DW_DLE_LOCATION_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C); + return DW_DLV_ERROR; + } + } + locdesc->ld_cents = op_count; + locdesc->ld_s = block_loc; + + locdesc->ld_kind = lkind; + locdesc->ld_section_offset = loc_block->bl_section_offset; + locdesc->ld_locdesc_offset = loc_block->bl_locdesc_offset; + locdesc->ld_rawlow = lowpc; + locdesc->ld_rawhigh = highpc; + + res = validate_lle_value(dbg,locdesc,error); + if (res != DW_DLV_OK) { + dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C); + locdesc->ld_s = 0; + return res; + } + /* Leaving the cooked values zero. Filled in later. */ + /* We have not yet looked for debug_addr, so we'll + set it as not-missing. */ + locdesc->ld_index_failed = FALSE; + return DW_DLV_OK; +} + +/* Non-standard DWARF4 dwo loclist */ +static int +_dwarf_read_loc_section_dwo(Dwarf_Debug dbg, + Dwarf_Block_c * return_block, + Dwarf_Addr * lowpc, + Dwarf_Addr * highpc, + Dwarf_Bool *at_end, + Dwarf_Half * lle_op, + Dwarf_Off sec_offset, + Dwarf_Half address_size, + Dwarf_Half lkind, + Dwarf_Error * error) +{ + Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset; + Dwarf_Small *locptr = 0; + Dwarf_Small llecode = 0; + Dwarf_Unsigned expr_offset = sec_offset; + Dwarf_Byte_Ptr section_end = dbg->de_debug_loc.dss_data + + dbg->de_debug_loc.dss_size; + + if (sec_offset >= dbg->de_debug_loc.dss_size) { + /* We're at the end. No more present. */ + return DW_DLV_NO_ENTRY; + } + memset(return_block,0,sizeof(*return_block)); + + /* not the same as non-split loclist, but still a list. */ + return_block->bl_kind = lkind; + + /* This is non-standard GNU Dwarf4 loclist */ + return_block->bl_locdesc_offset = sec_offset; + llecode = *beg; + locptr = beg +1; + expr_offset++; + switch(llecode) { + case DW_LLEX_end_of_list_entry: + *at_end = TRUE; + return_block->bl_section_offset = expr_offset; + expr_offset++; + break; + case DW_LLEX_base_address_selection_entry: { + Dwarf_Unsigned addr_index = 0; + + DECODE_LEB128_UWORD_CK(locptr,addr_index, + dbg,error,section_end); + return_block->bl_section_offset = expr_offset; + /* So this behaves much like non-dwo loclist */ + *lowpc=MAX_ADDR; + *highpc=addr_index; + } + break; + case DW_LLEX_start_end_entry: { + Dwarf_Unsigned addr_indexs = 0; + Dwarf_Unsigned addr_indexe= 0; + Dwarf_Unsigned exprlen = 0; + Dwarf_Unsigned leb128_length = 0; + + DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexs, + leb128_length, + dbg,error,section_end); + expr_offset += leb128_length; + + DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexe, + leb128_length, + dbg,error,section_end); + expr_offset +=leb128_length; + + *lowpc=addr_indexs; + *highpc=addr_indexe; + + READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, + DWARF_HALF_SIZE, + error,section_end); + locptr += DWARF_HALF_SIZE; + expr_offset += DWARF_HALF_SIZE; + + return_block->bl_len = exprlen; + return_block->bl_data = locptr; + return_block->bl_section_offset = expr_offset; + + expr_offset += exprlen; + if (expr_offset > dbg->de_debug_loc.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); + dwarfstring_append_printf_u(&m, + " in DW_LLEX_start_end_entry " + "The expression offset is 0x%x", + expr_offset); + dwarfstring_append_printf_u(&m, + " which is greater than the section size" + " of 0x%x. Corrupt Dwarf.", + dbg->de_debug_loc.dss_size); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_LOC_SECTION_SHORT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + break; + case DW_LLEX_start_length_entry: { + Dwarf_Unsigned addr_index = 0; + Dwarf_Unsigned range_length = 0; + Dwarf_Unsigned exprlen = 0; + Dwarf_Unsigned leb128_length = 0; + + DECODE_LEB128_UWORD_LEN_CK(locptr,addr_index, + leb128_length, + dbg,error,section_end); + expr_offset +=leb128_length; + + READ_UNALIGNED_CK(dbg, range_length, Dwarf_Unsigned, locptr, + DWARF_32BIT_SIZE, + error,section_end); + locptr += DWARF_32BIT_SIZE; + expr_offset += DWARF_32BIT_SIZE; + + READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, + DWARF_HALF_SIZE, + error,section_end); + locptr += DWARF_HALF_SIZE; + expr_offset += DWARF_HALF_SIZE; + + *lowpc = addr_index; + *highpc = range_length; + return_block->bl_len = exprlen; + return_block->bl_data = locptr; + return_block->bl_section_offset = expr_offset; + /* exprblock_size can be zero, means no expression */ + + expr_offset += exprlen; + if (expr_offset > dbg->de_debug_loc.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); + dwarfstring_append_printf_u(&m, + " in DW_LLEX_start_length_entry " + "The expression offset is 0x%x", + expr_offset); + dwarfstring_append_printf_u(&m, + " which is greater than the section size" + " of 0x%x. Corrupt Dwarf.", + dbg->de_debug_loc.dss_size); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_LOC_SECTION_SHORT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + break; + case DW_LLEX_offset_pair_entry: { + Dwarf_Unsigned startoffset = 0; + Dwarf_Unsigned endoffset = 0; + Dwarf_Unsigned exprlen = 0; + + READ_UNALIGNED_CK(dbg, startoffset, + Dwarf_Unsigned, locptr, + DWARF_32BIT_SIZE, + error,section_end); + locptr += DWARF_32BIT_SIZE; + expr_offset += DWARF_32BIT_SIZE; + + READ_UNALIGNED_CK(dbg, endoffset, + Dwarf_Unsigned, locptr, + DWARF_32BIT_SIZE, + error,section_end); + locptr += DWARF_32BIT_SIZE; + expr_offset += DWARF_32BIT_SIZE; + *lowpc= startoffset; + *highpc = endoffset; + + READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr, + DWARF_HALF_SIZE, + error,section_end); + locptr += DWARF_HALF_SIZE; + expr_offset += DWARF_HALF_SIZE; + + return_block->bl_len = exprlen; + return_block->bl_data = locptr; + return_block->bl_section_offset = expr_offset; + + expr_offset += exprlen; + if (expr_offset > dbg->de_debug_loc.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_LOC_SECTION_SHORT:"); + dwarfstring_append_printf_u(&m, + " in DW_LLEX_offset_pair_entry " + "The expression offset is 0x%x", + expr_offset); + dwarfstring_append_printf_u(&m, + " which is greater than the section size" + " of 0x%x. Corrupt Dwarf.", + dbg->de_debug_loc.dss_size); + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_LOC_SECTION_SHORT, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + break; + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_LLE_CODE_UNKNOWN:"); + dwarfstring_append_printf_u(&m, + " in DW_LLEX_ code value " + " is 0x%x ,not an expected value.", + llecode); + _dwarf_error_string(dbg,error, + DW_DLE_LLE_CODE_UNKNOWN, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + *lle_op = llecode; + return DW_DLV_OK; +} + +int +dwarf_get_loclist_head_kind(Dwarf_Loc_Head_c ll_header, + unsigned int * kind, + Dwarf_Error * error) +{ + if (!ll_header) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "NULL Dwarf_Loc_Head_c " + "argument passed to " + "dwarf_get_loclist_head_kind()"); + return DW_DLV_ERROR; + } + *kind = ll_header->ll_kind; + return DW_DLV_OK; +} + +static int +_dwarf_original_loclist_build(Dwarf_Debug dbg, + Dwarf_Loc_Head_c llhead, + Dwarf_Attribute attr, + Dwarf_Error *error) +{ + Dwarf_Unsigned loclist_offset = 0; + Dwarf_Unsigned starting_loclist_offset = 0; + int off_res = DW_DLV_ERROR; + int count_res = DW_DLV_ERROR; + int loclist_count = 0; + Dwarf_Unsigned lli = 0; + unsigned lkind = llhead->ll_kind; + unsigned address_size = llhead->ll_address_size; + Dwarf_Unsigned listlen = 0; + Dwarf_Locdesc_c llbuf = 0; + Dwarf_CU_Context cucontext; + + off_res = _dwarf_get_loclist_header_start(dbg, + attr, &loclist_offset, error); + if (off_res != DW_DLV_OK) { + return off_res; + } + starting_loclist_offset = loclist_offset; + + if (lkind == DW_LKIND_GNU_exp_list) { + count_res = _dwarf_get_loclist_lle_count_dwo(dbg, + loclist_offset, + address_size, + lkind, + &loclist_count, + error); + } else { + count_res = _dwarf_get_loclist_lle_count(dbg, + loclist_offset, address_size, + &loclist_count, + error); + } + if (count_res != DW_DLV_OK) { + return count_res; + } + if (loclist_count == 0) { + return DW_DLV_NO_ENTRY; + } + + listlen = loclist_count; + llbuf = (Dwarf_Locdesc_c) + _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); + if (!llbuf) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + llbuf->ld_magic = LOCLISTS_MAGIC; + llhead->ll_locdesc = llbuf; + llhead->ll_locdesc_count = listlen; + cucontext = llhead->ll_context; + llhead->ll_llearea_offset = loclist_offset; + /* Now get loc ops */ + for (lli = 0; lli < listlen; ++lli) { + int lres = 0; + Dwarf_Half lle_op = 0; + Dwarf_Bool at_end = 0; + Dwarf_Block_c loc_block; + Dwarf_Unsigned rawlowpc = 0; + Dwarf_Unsigned rawhighpc = 0; + int blkres = 0; + + memset(&loc_block,0,sizeof(loc_block)); + if (lkind == DW_LKIND_GNU_exp_list) { + blkres = _dwarf_read_loc_section_dwo(dbg, + &loc_block, + &rawlowpc, &rawhighpc, + &at_end, &lle_op, + loclist_offset, + address_size, + lkind, + error); + } else { + blkres = _dwarf_read_loc_section(dbg, + &loc_block, + &rawlowpc, &rawhighpc, + &lle_op, + loclist_offset, + address_size, + error); + } + if (blkres != DW_DLV_OK) { + return blkres; + } + /* Fills in the locdesc and its operators list at index lli */ + lres = _dwarf_fill_in_locdesc_op_c(dbg, + lli, + llhead, + &loc_block, + address_size, + cucontext->cc_length_size, + cucontext->cc_version_stamp, + rawlowpc, + rawhighpc, + lle_op, + error); + if (lres != DW_DLV_OK) { + return lres; + } + /* Now get to next loclist entry offset. */ + loclist_offset = loc_block.bl_section_offset + + loc_block.bl_len; + } + /* We need to calculate the cooked values for + each locldesc entry, that will be done + in dwarf_get_loclist_c(). */ + + llhead->ll_bytes_total = loclist_offset - + starting_loclist_offset; + return DW_DLV_OK; +} + +static int +_dwarf_original_expression_build(Dwarf_Debug dbg, + Dwarf_Loc_Head_c llhead, + Dwarf_Attribute attr, + Dwarf_Error *error) +{ + + Dwarf_Block_c loc_blockc; + Dwarf_Unsigned rawlowpc = 0; + Dwarf_Unsigned rawhighpc = 0; + unsigned form = llhead->ll_attrform; + int blkres = 0; + Dwarf_Locdesc_c llbuf = 0; + unsigned listlen = 1; + Dwarf_CU_Context cucontext = llhead->ll_context; + unsigned address_size = llhead->ll_address_size; + + memset(&loc_blockc,0,sizeof(loc_blockc)); + if (form == DW_FORM_exprloc) { + /* A bit ugly. dwarf_formexprloc should use a + Dwarf_Block argument. */ + blkres = dwarf_formexprloc(attr,&loc_blockc.bl_len, + (Dwarf_Ptr)&loc_blockc.bl_data,error); + if (blkres != DW_DLV_OK) { + return blkres; + } + loc_blockc.bl_kind = llhead->ll_kind; + loc_blockc.bl_section_offset = + (char *)loc_blockc.bl_data - + (char *)dbg->de_debug_info.dss_data; + loc_blockc.bl_locdesc_offset = 0; /* not relevant */ + } else { + Dwarf_Block loc_block; + + memset(&loc_block,0,sizeof(loc_block)); + blkres = _dwarf_formblock_internal(dbg,attr, + llhead->ll_context, + &loc_block, + error); + if (blkres != DW_DLV_OK) { + return blkres; + } + loc_blockc.bl_len = loc_block.bl_len; + loc_blockc.bl_data = loc_block.bl_data; + loc_blockc.bl_kind = llhead->ll_kind; + loc_blockc.bl_section_offset = + loc_block.bl_section_offset; + loc_blockc.bl_locdesc_offset = 0; /* not relevant */ + } + /* We will mark the Locdesc_c DW_LLE_start_end + shortly. Here we fake the address range + as 'all addresses'. */ + rawlowpc = 0; + rawhighpc = MAX_ADDR; + + llbuf = (Dwarf_Locdesc_c) + _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen); + if (!llbuf) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + llbuf->ld_magic = LOCLISTS_MAGIC; + llhead->ll_locdesc = llbuf; + /* Count is one by definition of a location entry. */ + llhead->ll_locdesc_count = listlen; + llbuf = 0; + + /* An empty location description (block length 0) + means the code generator emitted no variable, + the variable was not generated, it was unused + or perhaps never tested after being set. Dwarf2, + section 2.4.1 In other words, it is not an error, + and we don't test for block length 0 specially here. */ + + /* Fills in the locdesc and its operators list + at index 0 */ + blkres = _dwarf_fill_in_locdesc_op_c(dbg, + 0, /* fake locdesc is index 0 */ + llhead, + &loc_blockc, + llhead->ll_address_size, + cucontext->cc_length_size, + cucontext->cc_version_stamp, + rawlowpc, rawhighpc, + 0, + error); + llhead->ll_bytes_total += loc_blockc.bl_len; + if (blkres != DW_DLV_OK) { + /* low level error already set: let problem be passed back */ + dwarf_dealloc(dbg,llhead->ll_locdesc,DW_DLA_LOCDESC_C); + llhead->ll_locdesc = 0; + llhead->ll_locdesc_count = 0; + return blkres; + } + return DW_DLV_OK; +} + +/* Following the original loclist definition the low + value is all one bits, the high value is the base + address. */ +static int +cook_original_loclist_contents(Dwarf_Debug dbg, + Dwarf_Loc_Head_c llhead, + Dwarf_Error *error) +{ + Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; + Dwarf_Unsigned count = llhead->ll_locdesc_count; + Dwarf_Unsigned i = 0; + + for ( i = 0 ; i < count; ++i) { + Dwarf_Locdesc_c llc = 0; + + llc = llhead->ll_locdesc +i; + switch(llc->ld_lle_value) { + case DW_LLE_end_of_list: { + /* nothing to do */ + break; + } + case DW_LLE_base_address: { + llc->ld_lopc = llc->ld_rawhigh; + llc->ld_highpc = llc->ld_rawhigh; + baseaddress = llc->ld_rawhigh; + break; + } + case DW_LLE_offset_pair: { + llc->ld_lopc = llc->ld_rawlow + baseaddress; + llc->ld_highpc = llc->ld_rawhigh + baseaddress; + break; + } + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: " + "improper synthesized LLE code " + "of 0x%x is unknown. In standard DWARF3/4 loclist", + llc->ld_lle_value); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + } + return DW_DLV_OK; +} + +static int +cook_gnu_loclist_contents(Dwarf_Debug dbg, + Dwarf_Loc_Head_c llhead, + Dwarf_Error *error) +{ + Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; + Dwarf_Unsigned count = llhead->ll_locdesc_count; + Dwarf_Unsigned i = 0; + Dwarf_CU_Context cucontext = llhead->ll_context; + int res = 0; + + for (i = 0 ; i < count ; ++i) { + Dwarf_Locdesc_c llc = 0; + + llc = llhead->ll_locdesc +i; + switch(llc->ld_lle_value) { + case DW_LLEX_base_address_selection_entry:{ + Dwarf_Addr targaddr = 0; + + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawhigh,&targaddr, + error); + if (res != DW_DLV_OK) { + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + llc->ld_highpc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_lopc = targaddr; + llc->ld_highpc = targaddr; + } + break; + } + case DW_LLEX_end_of_list_entry:{ + /* Nothing to do. */ + break; + } + case DW_LLEX_start_length_entry:{ + Dwarf_Addr targaddr = 0; + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + if (res != DW_DLV_OK) { + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_lopc = targaddr; + llc->ld_highpc = llc->ld_lopc +llc->ld_rawhigh; + } + break; + } + case DW_LLEX_offset_pair_entry:{ + llc->ld_lopc = llc->ld_rawlow + baseaddress; + llc->ld_highpc = llc->ld_rawhigh + baseaddress; + break; + } + case DW_LLEX_start_end_entry:{ + Dwarf_Addr targaddr = 0; + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + if (res != DW_DLV_OK) { + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_lopc = targaddr; + } + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + if (res != DW_DLV_OK) { + llc->ld_index_failed = TRUE; + llc->ld_highpc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_highpc = targaddr; + } + + break; + } + default:{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: improper LLEX code " + "of 0x%x is unknown. GNU LLEX dwo loclists error", + llc->ld_lle_value); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + + break; + } + } + } + return DW_DLV_OK; +} + +/* DWARF5 */ +static int +cook_loclists_contents(Dwarf_Debug dbg, + Dwarf_Loc_Head_c llhead, + Dwarf_Error *error) +{ + Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address; + Dwarf_Unsigned count = llhead->ll_locdesc_count; + Dwarf_Unsigned i = 0; + Dwarf_CU_Context cucontext = llhead->ll_context; + int res = 0; + Dwarf_Bool base_address_fail = FALSE; + Dwarf_Bool debug_addr_fail = FALSE; + + if (!llhead->ll_cu_base_address_present) { + base_address_fail = TRUE; + } + for (i = 0 ; i < count ; ++i) { + Dwarf_Locdesc_c llc = 0; + + llc = llhead->ll_locdesc +i; + switch(llc->ld_lle_value) { + case DW_LLE_base_addressx: { + Dwarf_Addr targaddr = 0; + if (debug_addr_fail) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + } + if (res != DW_DLV_OK) { + debug_addr_fail = TRUE; + base_address_fail = TRUE; + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + base_address_fail = FALSE; + baseaddress = targaddr; + llc->ld_lopc = targaddr; + } + break; + } + case DW_LLE_startx_endx:{ + /* two indexes into debug_addr */ + Dwarf_Addr targaddr = 0; + if (debug_addr_fail) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + } + if (res != DW_DLV_OK) { + debug_addr_fail = TRUE; + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_lopc = targaddr; + } + if (debug_addr_fail) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawhigh,&targaddr, + error); + + } + if (res != DW_DLV_OK) { + debug_addr_fail = TRUE; + llc->ld_index_failed = TRUE; + llc->ld_highpc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_highpc = targaddr; + } + break; + } + case DW_LLE_startx_length:{ + /* one index to debug_addr other a length */ + Dwarf_Addr targaddr = 0; + if (debug_addr_fail) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,cucontext,llc->ld_rawlow,&targaddr, + error); + } + if (res != DW_DLV_OK) { + debug_addr_fail = TRUE; + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg, *error); + *error = 0; + } + } else { + llc->ld_lopc = targaddr; + llc->ld_highpc = targaddr + llc->ld_rawhigh; + } + break; + } + case DW_LLE_offset_pair:{ + if (base_address_fail) { + llc->ld_index_failed = TRUE; + llc->ld_lopc = 0; + llc->ld_highpc = 0; + } else { + /*offsets of the current base address*/ + llc->ld_lopc = llc->ld_rawlow +baseaddress; + llc->ld_highpc = llc->ld_rawhigh +baseaddress; + } + break; + } + case DW_LLE_default_location:{ + /* nothing to do here, just has a counted + location description */ + break; + } + case DW_LLE_base_address:{ + llc->ld_lopc = llc->ld_rawlow; + llc->ld_highpc = llc->ld_rawlow; + baseaddress = llc->ld_rawlow; + base_address_fail = FALSE; + break; + } + case DW_LLE_start_end:{ + llc->ld_lopc = llc->ld_rawlow; + llc->ld_highpc = llc->ld_rawhigh; + break; + } + case DW_LLE_start_length:{ + llc->ld_lopc = llc->ld_rawlow; + llc->ld_highpc = llc->ld_rawlow + llc->ld_rawhigh; + break; + } + case DW_LLE_end_of_list:{ + /* do nothing */ + break; + } + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: improper DW_LLE code " + "of 0x%x is unknown. DWARF5 loclists error", + llc->ld_lle_value); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + } + return DW_DLV_OK; +} + +/* New October 2015 + This interface requires the use of interface functions + to get data from Dwarf_Locdesc_c. The structures + are not visible to callers. */ +int +dwarf_get_loclist_c(Dwarf_Attribute attr, + Dwarf_Loc_Head_c * ll_header_out, + Dwarf_Unsigned * listlen_out, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Half form = 0; + Dwarf_Loc_Head_c llhead = 0; + Dwarf_CU_Context cucontext = 0; + unsigned address_size = 0; + int cuversionstamp = 0; + Dwarf_Bool is_cu = FALSE; + Dwarf_Unsigned attrnum = 0; + Dwarf_Bool is_dwo = 0; + int setup_res = DW_DLV_ERROR; + int lkind = 0; + + if (!attr) { + _dwarf_error_string(dbg, error,DW_DLE_ATTR_NULL, + "DW_DLE_ATTR_NULL" + "NULL Dwarf_Attribute " + "argument passed to " + "dwarf_get_loclist_c()"); + return DW_DLV_ERROR; + } + dbg = attr->ar_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Debug, improper Dwarf_Attribute " + "argument passed to " + "dwarf_get_loclist_c()"); + return DW_DLV_ERROR; + } + + /* ***** BEGIN CODE ***** */ + setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error); + if (setup_res != DW_DLV_OK) { + return setup_res; + } + attrnum = attr->ar_attribute; + cuversionstamp = cucontext->cc_version_stamp; + address_size = cucontext->cc_address_size; + is_dwo = cucontext->cc_is_dwo; + lkind = determine_location_lkind(cuversionstamp, + form, is_dwo); + if (lkind == DW_LKIND_unknown) { + dwarfstring m; + const char * formname = ""; + const char * attrname = ""; + + dwarfstring_constructor(&m); + dwarf_get_FORM_name(form,&formname); + dwarf_get_AT_name(attrnum,&attrname); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOC_EXPR_BAD: For Compilation Unit " + "version %u",cuversionstamp); + dwarfstring_append_printf_u(&m, + ", attribute 0x%x (",attrnum); + dwarfstring_append(&m,(char *)attrname); + dwarfstring_append_printf_u(&m, + ") form 0x%x (",form); + dwarfstring_append(&m,(char *)formname); + if (is_dwo) { + dwarfstring_append(&m,") (the CU is a .dwo) "); + } else { + dwarfstring_append(&m,") (the CU is not a .dwo) "); + } + dwarfstring_append(&m," we don't understand the location"); + _dwarf_error_string(dbg,error,DW_DLE_LOC_EXPR_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + /* Doing this early (first) to avoid repeating the alloc code + for each type */ + llhead = (Dwarf_Loc_Head_c) + _dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1); + if (!llhead) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + llhead->ll_cuversion = cuversionstamp; + llhead->ll_kind = lkind; + llhead->ll_attrnum = attrnum; + llhead->ll_attrform = form; + llhead->ll_dbg = dbg; + llhead->ll_address_size = address_size; + llhead->ll_offset_size = cucontext->cc_length_size; + llhead->ll_context = cucontext; + llhead->ll_magic = LOCLISTS_MAGIC; + + llhead->ll_at_loclists_base_present = + cucontext->cc_loclists_base_present; + llhead->ll_at_loclists_base = cucontext->cc_loclists_base; + llhead->ll_cu_base_address_present = cucontext->cc_low_pc_present; + llhead->ll_cu_base_address = cucontext->cc_low_pc; + llhead->ll_cu_addr_base = cucontext->cc_addr_base; + llhead->ll_cu_addr_base_present = + cucontext->cc_addr_base_present; + + if (lkind == DW_LKIND_loclist || + lkind == DW_LKIND_GNU_exp_list) { + int ores = 0; + /* Here we have a loclist to deal with. */ + ores = context_is_cu_not_tu(cucontext,&is_cu); + if (ores != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return setup_res; + } + ores = _dwarf_original_loclist_build(dbg, + llhead, attr, error); + if (ores != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return ores; + } + if (lkind == DW_LKIND_loclist) { + ores = cook_original_loclist_contents(dbg,llhead, + error); + } else { + ores = cook_gnu_loclist_contents(dbg,llhead,error); + } + if (ores != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return ores; + } + } else if (lkind == DW_LKIND_expression) { + /* DWARF2,3,4,5 */ + int eres = 0; + eres = _dwarf_original_expression_build(dbg, + llhead, attr, error); + if (eres != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return eres; + } + } else if (lkind == DW_LKIND_loclists) { + /* DWARF5! */ + int leres = 0; + + leres = _dwarf_loclists_fill_in_lle_head(dbg, + attr,llhead,error); + if (leres != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return leres; + } + leres = cook_loclists_contents(dbg,llhead,error); + if (leres != DW_DLV_OK) { + dwarf_dealloc_loc_head_c(llhead); + return leres; + } + } /* ASSERT else impossible */ + *ll_header_out = llhead; + *listlen_out = llhead->ll_locdesc_count; + return DW_DLV_OK; +} + +/* An interface giving us no cu context! + This is not going to be quite right. */ +int +dwarf_loclist_from_expr_c(Dwarf_Debug dbg, + Dwarf_Ptr expression_in, + Dwarf_Unsigned expression_length, + Dwarf_Half address_size, + Dwarf_Half offset_size, + Dwarf_Small dwarf_version, + Dwarf_Loc_Head_c *loc_head, + Dwarf_Unsigned * listlen, + Dwarf_Error * error) +{ + /* Dwarf_Block that describes a single location expression. */ + Dwarf_Block_c loc_block; + Dwarf_Loc_Head_c llhead = 0; + Dwarf_Locdesc_c llbuf = 0; + int local_listlen = 1; + Dwarf_Addr rawlowpc = 0; + Dwarf_Addr rawhighpc = MAX_ADDR; + Dwarf_Small version_stamp = dwarf_version; + int res = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL or bad Dwarf_Debug " + "argument passed to " + "dwarf_loclist_from_expr_c()"); + return DW_DLV_ERROR; + } + llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg, + DW_DLA_LOC_HEAD_C, 1); + if (!llhead) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + llhead->ll_magic = LOCLISTS_MAGIC; + memset(&loc_block,0,sizeof(loc_block)); + loc_block.bl_len = expression_length; + loc_block.bl_data = expression_in; + loc_block.bl_kind = DW_LKIND_expression; /* Not from loclist. */ + loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */ + loc_block.bl_locdesc_offset = 0; /* Fake. Not meaningful. */ + llbuf = (Dwarf_Locdesc_c) + _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, local_listlen); + if (!llbuf) { + dwarf_dealloc_loc_head_c(llhead); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + llbuf->ld_magic = LOCLISTS_MAGIC; + llhead->ll_locdesc = llbuf; + llhead->ll_locdesc_count = local_listlen; + llhead->ll_context = 0; /* Not available! */ + llhead->ll_dbg = dbg; + llhead->ll_kind = DW_LKIND_expression; + + /* An empty location description (block length 0) + means the code generator emitted no variable, + the variable was not generated, + it was unused or perhaps never tested + after being set. Dwarf2, + section 2.4.1 In other words, it is not + an error, and we don't + test for block length 0 specially here. */ + + /* Fills in the locdesc and its operators list at index 0 */ + res = _dwarf_fill_in_locdesc_op_c(dbg, + 0, + llhead, + &loc_block, + address_size, + offset_size, + version_stamp, + rawlowpc, + rawhighpc, + DW_LKIND_expression, + error); + if (res != DW_DLV_OK) { + /* low level error already set: let it be passed back */ + dwarf_dealloc(dbg,llbuf,DW_DLA_LOCDESC_C); + llhead->ll_locdesc = 0; + llhead->ll_locdesc_count = 0; + dwarf_dealloc_loc_head_c(llhead); + return DW_DLV_ERROR; + } + *loc_head = llhead; + *listlen = local_listlen; + return DW_DLV_OK; +} + +/* New June 2020 Supports all versions of DWARF. + Distinguishes location entry values as in the + file directly (raw) from the computed + value (lowpc_out,hipc_out) after + applying base values (if any). */ +int +dwarf_get_locdesc_entry_d(Dwarf_Loc_Head_c loclist_head, + Dwarf_Unsigned index, + Dwarf_Small * lle_value_out, + Dwarf_Unsigned * rawval1, + Dwarf_Unsigned * rawval2, + Dwarf_Bool * debug_addr_unavailable, + Dwarf_Addr * lowpc_out, /* 'cooked' value */ + Dwarf_Addr * hipc_out, /* 'cooked' value */ + Dwarf_Unsigned * loclist_expr_op_count_out, + /* Returns pointer to the specific locdesc of the index; */ + Dwarf_Locdesc_c* locdesc_entry_out, + Dwarf_Small * loclist_source_out, /* 0,1, or 2 */ + Dwarf_Unsigned * expression_offset_out, + Dwarf_Unsigned * locdesc_offset_out, + Dwarf_Error * error) +{ + Dwarf_Locdesc_c descs_base = 0; + Dwarf_Locdesc_c desc = 0; + Dwarf_Unsigned desc_count = 0; + Dwarf_Debug dbg = 0; + + if (!loclist_head || loclist_head->ll_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: " + "Dwarf_Loc_Head_c NULL or not " + "marked LOCLISTS_MAGIC " + "in calling " + "dwarf_get_locdesc_entry_d()"); + return DW_DLV_ERROR; + } + desc_count = loclist_head->ll_locdesc_count; + descs_base = loclist_head->ll_locdesc; + dbg = loclist_head->ll_dbg; + if (index >= desc_count) { + _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR); + return DW_DLV_ERROR; + } + desc = descs_base + index; + *lle_value_out = desc->ld_lle_value; + *rawval1 = desc->ld_rawlow; + *rawval2 = desc->ld_rawhigh; + *lowpc_out = desc->ld_lopc; + *hipc_out = desc->ld_highpc; + *debug_addr_unavailable = desc->ld_index_failed; + *loclist_expr_op_count_out = desc->ld_cents; + *locdesc_entry_out = desc; + *loclist_source_out = desc->ld_kind; + *expression_offset_out = desc->ld_section_offset; + *locdesc_offset_out = desc->ld_locdesc_offset; + return DW_DLV_OK; +} + +int +dwarf_get_location_op_value_c(Dwarf_Locdesc_c locdesc, + Dwarf_Unsigned index, + Dwarf_Small * atom_out, + Dwarf_Unsigned * operand1, + Dwarf_Unsigned * operand2, + Dwarf_Unsigned * operand3, + Dwarf_Unsigned * offset_for_branch, + Dwarf_Error* error) +{ + Dwarf_Loc_Expr_Op op = 0; + Dwarf_Unsigned max = 0; + + if (!locdesc) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "Dwarf_Locdesc_c_Head_c NULL " + "in calling " + "dwarf_get_location_op_value_c()"); + return DW_DLV_ERROR; + } + max = locdesc->ld_cents; + if (index >= max) { + Dwarf_Debug dbg = locdesc->ld_loclist_head->ll_dbg; + _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR); + return DW_DLV_ERROR; + } + op = locdesc->ld_s + index; + *atom_out = op->lr_atom; + *operand1 = op->lr_number; + *operand2 = op->lr_number2; + *operand3 = op->lr_number3; + *offset_for_branch = op->lr_offset; + return DW_DLV_OK; +} +/* ============== End of the October 2015 interfaces. */ diff --git a/src/lib/libdwarf/dwarf_loc.h b/src/lib/libdwarf/dwarf_loc.h new file mode 100644 index 0000000..2000098 --- /dev/null +++ b/src/lib/libdwarf/dwarf_loc.h @@ -0,0 +1,339 @@ +/* + Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2015-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. +*/ +#ifndef DWARF_LOC_H +#define DWARF_LOC_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define LOCLISTS_MAGIC 0xadab4 + +typedef struct Dwarf_Loc_Chain_s *Dwarf_Loc_Chain; +struct Dwarf_Loc_Chain_s { + Dwarf_Small lc_atom; + Dwarf_Unsigned lc_number; + Dwarf_Unsigned lc_number2; + Dwarf_Unsigned lc_number3; + Dwarf_Unsigned lc_offset; + Dwarf_Unsigned lc_opnumber; + Dwarf_Loc_Chain lc_next; +}; + +/* Dwarf_Loclists_Context_s contains the data from + the .debug_loclists + section headers (if that section exists). Dwarf 2,3,4 .debug_loc + has no such data. The array (one of these per header in + .debug_loclists) is recorded in Dwarf_Debug. These + are filled in at startup at the same time .debug_info + is opened. Nothing of this struct is exposed to + libdwarf callers */ +struct Dwarf_Loclists_Context_s { + Dwarf_Debug lc_dbg; + Dwarf_Unsigned lc_index; /* An index assigned by + libdwarf to each loclists context. Starting + with zero at the zero offset in .debug_loclists. */ + + /* Offset of the .debug_loclists header involved. */ + Dwarf_Unsigned lc_header_offset; + Dwarf_Unsigned lc_length; + unsigned long lc_magic; + + /* Many places in in libdwarf this is called length_size. */ + Dwarf_Small lc_offset_size; + + /* rc_extension_size is zero unless this is standard + DWARF3 and later 64bit dwarf using the extension mechanism. + 64bit DWARF3 and later: rc_extension_size is 4. + 64bit DWARF2 MIPS/IRIX: rc_extension_size is zero. + 32bit DWARF: rc_extension_size is zero. */ + Dwarf_Small lc_extension_size; + + unsigned lc_version; /* 5 */ + Dwarf_Small lc_address_size; + Dwarf_Small lc_segment_selector_size; + Dwarf_Unsigned lc_offset_entry_count; + + /* offset in the section of the offset entries */ + Dwarf_Unsigned lc_offsets_off_in_sect; + + /* Do not free. Points into section memory */ + Dwarf_Small * lc_offsets_array; + + /* Offset in the .debug_loclists section of the + first loclist in the set of loclists for the + CU. */ + Dwarf_Unsigned lc_first_loclist_offset; + Dwarf_Unsigned lc_past_last_loclist_offset; + + /* pointer to 1st byte of loclist header*/ + Dwarf_Small * lc_loclists_header; + /* pointer to first byte of the loclist data + for loclist involved. Do not free. */ + Dwarf_Small *lc_startaddr; + /* pointer one past end of the loclist data. */ + Dwarf_Small *lc_endaddr; +}; + +/* Contains info on an uninterpreted block of data, + the data is DWARF location expression operators. */ +struct Dwarf_Block_c_s { + /* length of block bl_data points at */ + Dwarf_Unsigned bl_len; + + /* Uninterpreted data, location expressions, + DW_OP_reg31 etc */ + Dwarf_Byte_Ptr bl_data; + + /* DW_LKIND, see libdwarf.h.in */ + Dwarf_Small bl_kind; + + /* Section (not CU) offset which 'data' comes from. */ + Dwarf_Unsigned bl_section_offset; + + /* Section offset where the location description + itself starts. So a few bytes lower than + bl_section_offset */ + Dwarf_Unsigned bl_locdesc_offset; +}; +typedef struct Dwarf_Block_c_s Dwarf_Block_c; + +/* Location record. Records up to 3 operand values. + For DWARF5 ops with a 1 byte size and then a block + of data of that size we the size in an operand + and follow that with the next operand as a + pointer to the block. The pointer is inserted + via cast, so an ugly hack. + This struct is opaque. Not visible to callers. +*/ +typedef struct Dwarf_Loc_Expr_Op_s *Dwarf_Loc_Expr_Op; +struct Dwarf_Loc_Expr_Op_s { + Dwarf_Small lr_atom; /* Location operation */ + + Dwarf_Unsigned lr_raw1; + Dwarf_Unsigned lr_raw2; + Dwarf_Unsigned lr_raw3; + + Dwarf_Unsigned lr_number; /* First operand */ + + /* Second operand. + For OP_bregx, OP_bit_piece, OP_[GNU_]const_type, + OP_[GNU_]deref_type, OP_[GNU_]entry_value, + OP_implicit_value, + OP_[GNU_]implicit_pointer, OP_[GNU_]regval_type, + OP_xderef_type, */ + Dwarf_Unsigned lr_number2; + + /* Third Operand. + For OP_[GNU_]const type, pointer to + block of length 'lr_number2' + FIXME: retrieve the value at the pointer, + store the value here instead*/ + Dwarf_Unsigned lr_number3; + + /* The number assigned. 0 to the number-of-ops-1 in + the expression we are expanding. */ + Dwarf_Unsigned lr_opnumber; + Dwarf_Unsigned lr_offset; /* offset for OP_BRA etc */ + Dwarf_Loc_Expr_Op lr_next; /* When a list is useful.*/ +}; + +/* Used at construction to enable verifying we set + sensibly before returning to callers. */ + +#define DW_LLE_VALUE_BOGUS 254 + +/* Location description DWARF 2,3,4,5 + Adds the DW_LLE value (new in DWARF5). + This struct is opaque. Not visible to callers. */ +struct Dwarf_Locdesc_c_s { + Dwarf_Small ld_kind; /* DW_LKIND */ + + /* A DW_LLEX or DW_LLE value, real or synthesized */ + Dwarf_Small ld_lle_value; + /* Failed means .debug_addr section needed but missing. + (possibly tied file needed) */ + Dwarf_Bool ld_index_failed; + unsigned long ld_magic; + + /* Beginning of active range. This is actually an offset + of an applicable base address, not a pc value. */ + Dwarf_Addr ld_rawlow; + /* Translated to address */ + Dwarf_Addr ld_lopc; + + /* End of active range. This is actually an offset + of an applicable base address, + or a length, never a pc value. */ + Dwarf_Addr ld_rawhigh; + /* Translated to address */ + Dwarf_Addr ld_highpc; + + /* Byte length of the entire record for this entry, + including any DW_OP entries */ + Dwarf_Unsigned ld_entrylen; + + /* For .debug_loclists, eases building record. */ + Dwarf_Block_c ld_opsblock; + + /* count of struct Dwarf_Loc_Expr_Op_s (expression operators) + in array. */ + Dwarf_Half ld_cents; + /* pointer to array of expression operator structs */ + Dwarf_Loc_Expr_Op ld_s; + + /* Section (not CU) offset where loc-expr begins*/ + Dwarf_Unsigned ld_section_offset; + + /* Section (not CU) offset where location descr begins*/ + Dwarf_Unsigned ld_locdesc_offset; + + /* Pointer to our header (in which we are located). */ + Dwarf_Loc_Head_c ld_loclist_head; + Dwarf_Locdesc_c ld_next; /*helps building the locdescs*/ +}; + +int _dwarf_locdesc_c_constructor(Dwarf_Debug dbg, void *locd); + +/* A 'header' to the loclist and the + location description(s) attached to an attribute. + This struct is opaque. The contents not visible to + callers. */ +struct Dwarf_Loc_Head_c_s { + /* The array (1 or more entries) of + struct Loc_Desc_c_s + If 1 it may really be a locexpr */ + Dwarf_Locdesc_c ll_locdesc; + + /* Entry count of the ll_locdesc array. */ + Dwarf_Unsigned ll_locdesc_count; + + unsigned ll_attrnum; + unsigned ll_attrform; + unsigned ll_cuversion; + unsigned ll_address_size; + unsigned ll_offset_size; + /* The CU Context of this loclist or locexpr. */ + Dwarf_CU_Context ll_context; + /* DW_LKIND* */ + Dwarf_Small ll_kind; + Dwarf_Debug ll_dbg; + unsigned long ll_magic; + + /* If ll_kind == DW_LKIND_loclists the following + pointer is non-null and index is the index + of the localcontext */ + Dwarf_Unsigned ll_index; + Dwarf_Loclists_Context ll_localcontext; + + /* rh_last and rh_first used during build-up. + Zero when array rh_loclists built. */ + Dwarf_Locdesc_c ll_first; + Dwarf_Locdesc_c ll_last; + Dwarf_Unsigned ll_bytes_total; + unsigned ll_segment_selector_size; + + /* DW_AT_loclists_base */ + Dwarf_Bool ll_at_loclists_base_present; + Dwarf_Unsigned ll_at_loclists_base; + + /* DW_AT_low_pc of CU or zero if none. */ + Dwarf_Bool ll_cu_base_address_present; + Dwarf_Unsigned ll_cu_base_address; + + /* DW_AT_addr_base, so we can use .debug_addr + if such is needed. */ + Dwarf_Bool ll_cu_addr_base_present; + Dwarf_Unsigned ll_cu_addr_base; + + Dwarf_Small * ll_llepointer; + Dwarf_Unsigned ll_llearea_offset; + Dwarf_Small * ll_end_data_area; +}; + +int _dwarf_fill_in_locdesc_op_c(Dwarf_Debug dbg, + Dwarf_Unsigned locdesc_index, + Dwarf_Loc_Head_c loc_head, + Dwarf_Block_c * loc_block, + Dwarf_Half address_size, + Dwarf_Half offset_size, + Dwarf_Small version_stamp, + Dwarf_Addr lowpc, + Dwarf_Addr highpc, + Dwarf_Half lle_op, + Dwarf_Error * error); + +int _dwarf_loc_block_sanity_check(Dwarf_Debug dbg, + Dwarf_Block_c *loc_block,Dwarf_Error*error); + +int _dwarf_internal_read_loclists_header(Dwarf_Debug dbg, + Dwarf_Unsigned contextnum, + Dwarf_Unsigned sectionlength, + Dwarf_Small *data, + Dwarf_Small *end_data, + Dwarf_Unsigned offset, + Dwarf_Loclists_Context buildhere, + Dwarf_Unsigned *next_offset, + Dwarf_Error *error); + +void _dwarf_loclists_head_destructor(void *l); + +int _dwarf_loclists_fill_in_lle_head(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_Loc_Head_c llhead, + Dwarf_Error *error); + +int _dwarf_loclists_expression_build(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_Loc_Head_c* llhead, + Dwarf_Error *error); + +int _dwarf_read_loc_expr_op(Dwarf_Debug dbg, + Dwarf_Block_c * loc_block, + /* Caller: Start numbering at 0. */ + Dwarf_Signed opnumber, + + /* 2 for DWARF 2 etc. */ + Dwarf_Half version_stamp, + Dwarf_Half offset_size, /* 4 or 8 */ + Dwarf_Half address_size, /* 2,4, 8 */ + Dwarf_Signed startoffset_in, /* offset in block, + not section offset */ + Dwarf_Small *section_end, + + /* nextoffset_out so caller knows next entry startoffset */ + Dwarf_Unsigned *nextoffset_out, + + /* The values picked up. */ + Dwarf_Loc_Expr_Op curr_loc, + Dwarf_Error * error); +void _dwarf_free_loclists_head_content(Dwarf_Loc_Head_c head); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_LOC_H */ diff --git a/src/lib/libdwarf/dwarf_locationop_read.c b/src/lib/libdwarf/dwarf_locationop_read.c new file mode 100644 index 0000000..3fe83f7 --- /dev/null +++ b/src/lib/libdwarf/dwarf_locationop_read.c @@ -0,0 +1,895 @@ +/* + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2018 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* memcpy() memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_loc.h" +#include "dwarf_string.h" + +/* Richard Henderson, on DW_OP_GNU_encoded_addr: + The operand is an absolute address. + The first byte of the value is an encoding length: + 0 2 4 or 8. + If zero it means the following is address-size. + The address then follows immediately for + that number of bytes. */ +static int +read_encoded_addr(Dwarf_Small *loc_ptr, + Dwarf_Debug dbg, + Dwarf_Small *section_end_ptr, + Dwarf_Half address_size, + Dwarf_Unsigned * val_out, + int * len_out, + Dwarf_Error *error) +{ + int len = 0; + Dwarf_Small op = *loc_ptr; + Dwarf_Unsigned operand = 0; + + len++; + if (!op) { + op = address_size; + } + switch (op) { + case 1: + *val_out = *loc_ptr; + len++; + break; + + case 2: + READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 2, + error,section_end_ptr); + *val_out = operand; + len +=2; + break; + case 4: + READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 4, + error,section_end_ptr); + *val_out = operand; + len +=4; + break; + case 8: + READ_UNALIGNED_CK(dbg, operand, Dwarf_Unsigned, loc_ptr, 8, + error,section_end_ptr); + *val_out = operand; + len +=8; + break; + default: + /* We do not know how much to read. */ + _dwarf_error(dbg, error, DW_DLE_GNU_OPCODE_ERROR); + return DW_DLV_ERROR; + }; + *len_out = len; + return DW_DLV_OK; +} + +/* Return DW_DLV_NO_ENTRY when at the end of + the ops for this block (a single Dwarf_Loccesc + and multiple Dwarf_Locs will eventually result + from calling this till DW_DLV_NO_ENTRY). + + All op reader code should call this to + extract operator fields. For any + DWARF version. +*/ +int +_dwarf_read_loc_expr_op(Dwarf_Debug dbg, + Dwarf_Block_c * loc_block, + /* Caller: Start numbering at 0. */ + Dwarf_Signed opnumber, + + /* 2 for DWARF 2 etc. */ + Dwarf_Half version_stamp, + Dwarf_Half offset_size, /* 4 or 8 */ + Dwarf_Half address_size, /* 2,4, 8 */ + Dwarf_Signed startoffset_in, /* offset in block, + not section offset */ + Dwarf_Small *section_end, + + /* nextoffset_out so caller knows next entry startoffset */ + Dwarf_Unsigned *nextoffset_out, + + /* The values picked up. */ + Dwarf_Loc_Expr_Op curr_loc, + Dwarf_Error * error) +{ + Dwarf_Small *loc_ptr = 0; + Dwarf_Unsigned loc_len = 0; + Dwarf_Unsigned offset = startoffset_in; + Dwarf_Unsigned operand1 = 0; + Dwarf_Unsigned operand2 = 0; + Dwarf_Unsigned operand3 = 0; + Dwarf_Small atom = 0; + Dwarf_Unsigned leb128_length = 0; + + if (offset > loc_block->bl_len) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + loc_len = loc_block->bl_len; + if (offset == loc_len) { + return DW_DLV_NO_ENTRY; + } + + loc_ptr = (Dwarf_Small*)loc_block->bl_data + offset; + if ((loc_ptr+1) > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + memset(curr_loc,0,sizeof(*curr_loc)); + + curr_loc->lr_opnumber = opnumber; + curr_loc->lr_offset = offset; + + /* loc_ptr is ok to deref, see loc_ptr+1 test just above. */ + atom = *(Dwarf_Small *) loc_ptr; + loc_ptr++; + offset++; + curr_loc->lr_atom = atom; + switch (atom) { + 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: + break; + + case DW_OP_regx: + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + 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: + operand1 = atom - DW_OP_lit0; + break; + + case DW_OP_addr: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, + loc_ptr, address_size, + error,section_end); + loc_ptr += address_size; + offset += address_size; + break; + + case DW_OP_const1u: + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + break; + + case DW_OP_const1s: + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Sbyte *) loc_ptr; + SIGN_EXTEND(operand1,1); + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + break; + + case DW_OP_const2u: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2, + error,section_end); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_const2s: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2, + error, section_end); + SIGN_EXTEND(operand1,2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_const4u: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4, + error, section_end); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + + case DW_OP_const4s: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4, + error, section_end); + SIGN_EXTEND(operand1,4); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + + case DW_OP_const8u: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8, + error, section_end); + loc_ptr = loc_ptr + 8; + offset = offset + 8; + break; + + case DW_OP_const8s: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8, + error, section_end); + loc_ptr = loc_ptr + 8; + offset = offset + 8; + break; + + case DW_OP_constu: + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_consts: + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_fbreg: + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + 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: + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_bregx: + /* uleb reg num followed by sleb offset */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_dup: + case DW_OP_drop: + break; + + case DW_OP_pick: + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + break; + + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_deref: + break; + + case DW_OP_deref_size: + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + break; + + case DW_OP_xderef: + break; + + case DW_OP_xderef_type: /* DWARF5 */ + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + break; + + case DW_OP_xderef_size: + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + break; + + 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: + break; + + case DW_OP_plus_uconst: + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + break; + + case DW_OP_le: + case DW_OP_ge: + case DW_OP_eq: + case DW_OP_lt: + case DW_OP_gt: + case DW_OP_ne: + break; + + case DW_OP_skip: + case DW_OP_bra: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2, + error,section_end); + SIGN_EXTEND(operand1,2); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_piece: + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + case DW_OP_nop: + break; + case DW_OP_push_object_address: /* DWARF3 */ + break; + case DW_OP_call2: /* DWARF3 */ + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2, + error,section_end); + loc_ptr = loc_ptr + 2; + offset = offset + 2; + break; + + case DW_OP_call4: /* DWARF3 */ + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4, + error,section_end); + loc_ptr = loc_ptr + 4; + offset = offset + 4; + break; + case DW_OP_call_ref: /* DWARF3 */ + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, + offset_size, + error,section_end); + loc_ptr = loc_ptr + offset_size; + offset = offset + offset_size; + break; + + case DW_OP_form_tls_address: /* DWARF3f */ + break; + case DW_OP_call_frame_cfa: /* DWARF3f */ + break; + case DW_OP_bit_piece: /* DWARF3f */ + /* uleb size in bits followed by uleb offset in bits */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + /* The operator means: push the currently computed + (by the operations encountered so far in this + expression) onto the expression stack as the offset + in thread-local-storage of the variable. */ + case DW_OP_GNU_push_tls_address: /* 0xe0 */ + /* Believed to have no operands. */ + /* Unimplemented in gdb 7.5.1 ? */ + break; + case DW_OP_deref_type: /* DWARF5 */ + case DW_OP_GNU_deref_type: /* 0xf6 */ + if (loc_ptr >= section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + operand1 = *(Dwarf_Small *) loc_ptr; + loc_ptr = loc_ptr + 1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + 1; + + /* die offset (uleb128). */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_implicit_value: /* DWARF4 0xa0 */ + /* uleb length of value bytes followed by that + number of bytes of the value. */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + /* Second operand is block of 'operand1' bytes of stuff. */ + /* This using the second operand as a pointer + is quite ugly. */ + /* This gets an ugly compiler warning. Sorry. */ + operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr; + offset = offset + operand1; + loc_ptr = loc_ptr + operand1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + break; + case DW_OP_stack_value: /* DWARF4 */ + break; + case DW_OP_GNU_uninit: /* 0xf0 */ + /* Unimplemented in gdb 7.5.1 */ + /* Carolyn Tice: Follows a DW_OP_reg or DW_OP_regx + and marks the reg as being uninitialized. */ + break; + case DW_OP_GNU_encoded_addr: { /* 0xf1 */ + /* Richard Henderson: The operand is an absolute + address. The first byte of the value + is an encoding length: 0 2 4 or 8. If zero + it means the following is address-size. + The address then follows immediately for + that number of bytes. */ + int length = 0; + int reares = 0; + + if (loc_ptr >= section_end) { + _dwarf_error_string(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END, + "DW_DLE_LOCEXPR_OFF_SECTION_END " + "at DW_OP_GNU_encoded_addr. " + "Corrupt DWARF"); + return DW_DLV_ERROR; + } + reares = read_encoded_addr(loc_ptr,dbg, + section_end, + address_size, + &operand1, &length,error); + if (reares != DW_DLV_OK) { + return reares; + } + loc_ptr += length; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset += length; + } + break; + case DW_OP_implicit_pointer: /* DWARF5 */ + case DW_OP_GNU_implicit_pointer:{ /* 0xf2 */ + /* Jakub Jelinek: The value is an optimized-out + pointer value. Represented as + an offset_size DIE offset + (a simple unsigned integer) in DWARF3,4 + followed by a signed leb128 offset. + For DWARF2, it is actually pointer size + (address size). + The offset is global a section offset, not cu-relative. + Relocation to a different object file is up to + the user, per DWARF5 Page 41. + http://www.dwarfstd.org/ShowIssue.php?issue=100831.1 */ + Dwarf_Small iplen = offset_size; + if (version_stamp == DW_CU_VERSION2 /* 2 */ ) { + iplen = address_size; + } + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, + iplen,error,section_end); + loc_ptr = loc_ptr + iplen; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + iplen; + + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + } + + break; + case DW_OP_entry_value: /* DWARF5 */ + case DW_OP_GNU_entry_value: /* 0xf3 */ + /* Jakub Jelinek: A register reused really soon, + but the value is unchanged. So to represent + that value we have a uleb128 size followed + by a DWARF expression block that size. + http://www.dwarfstd.org/ShowIssue.php?issue=100909.1 */ + + /* uleb length of value bytes followed by that + number of bytes of the value. */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + /* Second operand is block of 'operand1' bytes of stuff. */ + /* This using the second operand as a pointer + is quite ugly. */ + /* This gets an ugly compiler warning. Sorry. */ + operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr; + offset = offset + operand1; + loc_ptr = loc_ptr + operand1; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + break; + case DW_OP_const_type: /* DWARF5 */ + case DW_OP_GNU_const_type: /* 0xf4 */ + { + /* die offset as uleb. cu-relative */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + if (loc_ptr >= section_end) { + _dwarf_error_string(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END, + "DW_DLE_LOCEXPR_OFF_SECTION_END: Error reading " + "DW_OP_const_type/DW_OP_GNU_const_type content"); + return DW_DLV_ERROR; + } + /* Next byte is size of following data block. */ + operand2 = *loc_ptr; + loc_ptr = loc_ptr + 1; + offset = offset + 1; + + /* Operand 3 points to a value in the block of size + just gotten as operand2. + It must fit in a Dwarf_Unsigned. + Get the type from the die at operand1 + (a CU relative offset). */ + /* FIXME: We should do something very different than + what we do here! */ + operand3 = (Dwarf_Unsigned)(uintptr_t)loc_ptr; + loc_ptr = loc_ptr + operand2; + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + offset = offset + operand2; + } + break; + + case DW_OP_regval_type: /* DWARF5 */ + case DW_OP_GNU_regval_type: /* 0xf5 */ + /* reg num uleb*/ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + /* cu die off uleb*/ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + case DW_OP_convert: /* DWARF5 */ + case DW_OP_GNU_convert: /* 0xf7 */ + case DW_OP_reinterpret: /* DWARF5 */ + case DW_OP_GNU_reinterpret: /* 0xf9 */ + /* die offset or zero */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + case DW_OP_GNU_parameter_ref : /* 0xfa */ + /* 4 byte unsigned int */ + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4, + error,section_end);; + loc_ptr = loc_ptr + 4; + if (loc_ptr > section_end) { + _dwarf_error_string(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END, + "DW_DLE_LOCEXPR_OFF_SECTION_END: Error reading " + "DW_OP_GNU_parameter_ref."); + return DW_DLV_ERROR; + } + offset = offset + 4; + break; + case DW_OP_addrx : /* DWARF5 */ + case DW_OP_GNU_addr_index : /* 0xfb DebugFission */ + /* Index into .debug_addr. The value in .debug_addr + is an address. */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + case DW_OP_constx : /* DWARF5 */ + case DW_OP_GNU_const_index : /* 0xfc DebugFission */ + /* Index into .debug_addr. The value in .debug_addr + is a constant that fits in an address. */ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + case DW_OP_GNU_variable_value: { /* 0xfd, 2017 By J Jelinek */ + /* https://gcc.gnu.org/legacy-ml/gcc-patches/2017-02/ + msg01499.html */ + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, + offset_size,error,section_end); + loc_ptr = loc_ptr + offset_size; + if (loc_ptr > section_end) { + _dwarf_error_string(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END, + "DW_DLE_LOCEXPR_OFF_SECTION_END: Error reading " + "DW_OP_GNU_variable_value."); + return DW_DLV_ERROR; + } + break; + } + /* See https://www.llvm.org/docs/ + AMDGPUDwarfExtensionsForHeterogeneousDebugging.html */ + case DW_OP_LLVM_form_aspace_address: + case DW_OP_LLVM_push_lane: + case DW_OP_LLVM_offset: + case DW_OP_LLVM_bit_offset: + case DW_OP_LLVM_undefined: + case DW_OP_LLVM_piece_end: + /* no operands on these */ + break; + case DW_OP_LLVM_offset_uconst: /*uleb operand*/ + case DW_OP_LLVM_call_frame_entry_reg: /*uleb operand*/ + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_LLVM_aspace_implicit_pointer: + READ_UNALIGNED_CK(dbg, operand1, Dwarf_Unsigned, loc_ptr, + offset_size,error,section_end); + loc_ptr = loc_ptr + offset_size; + if (loc_ptr > section_end) { + _dwarf_error_string(dbg,error, + DW_DLE_LOCEXPR_OFF_SECTION_END, + "DW_DLE_LOCEXPR_OFF_SECTION_END: Error reading " + "DW_OP_LLVM_aspace_implicit_pointer."); + return DW_DLV_ERROR; + } + + DECODE_LEB128_SWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + case DW_OP_LLVM_aspace_bregx: + case DW_OP_LLVM_extend: + case DW_OP_LLVM_select_bit_piece: + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand1,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + + DECODE_LEB128_UWORD_LEN_CK(loc_ptr, operand2,leb128_length, + dbg,error,section_end); + offset = offset + leb128_length; + break; + + default: { + dwarfstring m; + const char *atomname = 0; + + /* This can happen if the offset_size or address_size + in the OP stream was incorrect for the object file.*/ + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "ERROR: DW_DLE_LOC_EXPR_BAD as DW_OP atom " + "0x%x ",atom); + dwarfstring_append(&m, "("); + dwarf_get_OP_name(atom,&atomname); + dwarfstring_append(&m,(char *)(atomname? + atomname:"")); + dwarfstring_append(&m, ")"); + dwarfstring_append(&m,"is unknown."); + _dwarf_error_string(dbg, error, DW_DLE_LOC_EXPR_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + if (loc_ptr > section_end) { + _dwarf_error(dbg,error,DW_DLE_LOCEXPR_OFF_SECTION_END); + return DW_DLV_ERROR; + } + /* If offset == loc_len this would be normal end-of-expression. */ + if (offset > loc_len) { + /* We stepped past the end of the expression. + This has to be a compiler bug. + Operators missing their values cannot be detected + as such except at the end of an expression (like this). + The results would be wrong if returned. + */ + _dwarf_error(dbg, error, DW_DLE_LOC_BAD_TERMINATION); + return DW_DLV_ERROR; + } + curr_loc->lr_atom = atom; + curr_loc->lr_number = operand1; + curr_loc->lr_number2 = operand2; + /* lr_number 3 is a pointer to a value iff DW_OP_const or + DW_OP_GNU_const_type */ + curr_loc->lr_number3 = operand3; + *nextoffset_out = offset; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_loclists.c b/src/lib/libdwarf/dwarf_loclists.c new file mode 100644 index 0000000..c6061cb --- /dev/null +++ b/src/lib/libdwarf/dwarf_loclists.c @@ -0,0 +1,1360 @@ +/* +Copyright (c) 2020, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include /* free() malloc() */ +#include /* memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_loc.h" + +#define SIZEOFT8 1 +#define SIZEOFT16 2 +#define SIZEOFT32 4 +#define SIZEOFT64 8 + +#if 0 +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* Used in case of error reading the + loclists headers (not referring to Dwarf_Loc_Head_c + here), to clean up. */ +static void +free_loclists_chain(Dwarf_Debug dbg, Dwarf_Chain head) +{ + Dwarf_Chain cur = head; + Dwarf_Chain next = 0; + + if (!head || !dbg) { + return; + } + for ( ;cur; cur = next) { + next = cur->ch_next; + if (cur->ch_item) { + free(cur->ch_item); + cur->ch_item = 0; + dwarf_dealloc(dbg,cur,DW_DLA_CHAIN); + } + } +} + +static int +counted_loc_descr(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Small *enddata, + Dwarf_Unsigned offset, + Dwarf_Unsigned *loc_ops_overall_size, + Dwarf_Unsigned *loc_ops_count_len, + Dwarf_Unsigned *loc_ops_len, + Dwarf_Small **opsdata, + Dwarf_Unsigned *opsoffset, + Dwarf_Error * error) +{ + Dwarf_Unsigned ops_len = 0; + Dwarf_Unsigned leblen = 0; + DECODE_LEB128_UWORD_LEN_CK(data,ops_len,leblen, + dbg,error,enddata); + *loc_ops_count_len = leblen; + *loc_ops_overall_size = ops_len+leblen; + *loc_ops_len = ops_len; + *opsdata = data; + *opsoffset = offset +leblen; + return DW_DLV_OK; +} + +static int +read_single_lle_entry(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Unsigned dataoffset, + Dwarf_Small *enddata, + unsigned address_size, + unsigned *bytes_count_out, + unsigned *entry_kind, + Dwarf_Unsigned *entry_operand1, + Dwarf_Unsigned *entry_operand2, + Dwarf_Unsigned *opsblocksize, /* Just the expr data */ + Dwarf_Unsigned *opsoffset, /* Just the expr ops data */ + Dwarf_Small **ops, /* pointer to expr ops ops */ + Dwarf_Error* error) +{ + Dwarf_Unsigned count = 0; + unsigned int leblen = 0; + unsigned int code = 0; + Dwarf_Unsigned val1 = 0; + Dwarf_Unsigned val2 = 0; + Dwarf_Unsigned loc_ops_overall_size = 0; + Dwarf_Unsigned loc_ops_count_len = 0; + Dwarf_Unsigned loc_ops_len = 0; + Dwarf_Small *lopsdata = 0; + Dwarf_Unsigned lopsoffset = 0; + + /* Some of these have a Counted Location Description + in them. */ + code = *data; + ++data; + ++count; + switch(code) { + case DW_LLE_end_of_list: break; + case DW_LLE_base_addressx:{ + DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, + dbg,error,enddata); + count += leblen; + } + break; + case DW_LLE_startx_endx: + case DW_LLE_startx_length: + case DW_LLE_offset_pair: { + int res = 0; + + DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, + dbg,error,enddata); + count += leblen; + DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, + dbg,error,enddata); + count += leblen; + res = counted_loc_descr(dbg,data,enddata, + dataoffset, + &loc_ops_overall_size, + &loc_ops_count_len, + &loc_ops_len, + &lopsdata, + &lopsoffset, + error); + if (res != DW_DLV_OK) { + return res; + } + count += loc_ops_overall_size; + data += loc_ops_overall_size; + + } + break; + case DW_LLE_default_location: { + int res = 0; + + res = counted_loc_descr(dbg,data,enddata, + dataoffset, + &loc_ops_overall_size, + &loc_ops_count_len, + &loc_ops_len, + &lopsdata, + &lopsoffset, + error); + if (res != DW_DLV_OK) { + return res; + } + data += loc_ops_overall_size; + count += loc_ops_overall_size; + } + break; + case DW_LLE_base_address: { + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + } + break; + case DW_LLE_start_end: { + int res = 0; + + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + READ_UNALIGNED_CK(dbg,val2, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + res = counted_loc_descr(dbg,data,enddata, + dataoffset, + &loc_ops_overall_size, + &loc_ops_count_len, + &loc_ops_len, + &lopsdata, + &lopsoffset, + error); + if (res != DW_DLV_OK) { + return res; + } + count += loc_ops_overall_size; + data += loc_ops_overall_size; + } + break; + case DW_LLE_start_length: { + int res = 0; + + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, + dbg,error,enddata); + count += leblen; + res = counted_loc_descr(dbg,data,enddata, + dataoffset, + &loc_ops_overall_size, + &loc_ops_count_len, + &loc_ops_len, + &lopsdata, + &lopsoffset, + error); + if (res != DW_DLV_OK) { + return res; + } + count += loc_ops_overall_size; + data += loc_ops_overall_size; + } + break; + default: { + if (error) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: " + "The loclists entry at .debug_loclists" + " offset 0x%x" ,dataoffset); + dwarfstring_append_printf_u(&m, + " has code 0x%x which is unknown",code); + _dwarf_error_string(dbg,error,DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; + } + break; + } + *bytes_count_out = count; + *entry_kind = code; + *entry_operand1 = val1; + *entry_operand2 = val2; + *opsblocksize = loc_ops_len; + *opsoffset = lopsoffset; + *ops = lopsdata; + return DW_DLV_OK; +} + +/* Reads the header. Determines the + various offsets, including offset + of the next header. Does no memory + allocations here. */ +int +_dwarf_internal_read_loclists_header(Dwarf_Debug dbg, + Dwarf_Unsigned contextnum, + Dwarf_Unsigned sectionlength, + Dwarf_Small *data, + Dwarf_Small *end_data, + Dwarf_Unsigned offset, + Dwarf_Loclists_Context buildhere, + Dwarf_Unsigned *next_offset, + Dwarf_Error *error) +{ + Dwarf_Small *startdata = data; + Dwarf_Unsigned arealen = 0; + int offset_size = 0; + int exten_size = 0; + Dwarf_Unsigned version = 0; + unsigned address_size = 0; + unsigned segment_selector_size= 0; + Dwarf_Unsigned offset_entry_count = 0; + Dwarf_Unsigned localoff = 0; + Dwarf_Unsigned lists_len = 0; + + READ_AREA_LENGTH_CK(dbg,arealen,Dwarf_Unsigned, + data,offset_size,exten_size, + error, + sectionlength,end_data); + if (arealen > sectionlength || + (arealen+offset_size+exten_size) > sectionlength) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_SECTION_SIZE_ERROR: A .debug_loclists " + "area size of 0x%x ",arealen); + dwarfstring_append_printf_u(&m, + "at offset 0x%x ",offset); + dwarfstring_append_printf_u(&m, + "is larger than the entire section size of " + "0x%x. Corrupt DWARF.",sectionlength); + _dwarf_error_string(dbg,error,DW_DLE_SECTION_SIZE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + buildhere->lc_length = arealen +offset_size+exten_size; + buildhere->lc_dbg = dbg; + buildhere->lc_index = contextnum; + buildhere->lc_header_offset = offset; + buildhere->lc_offset_size = offset_size; + buildhere->lc_extension_size = exten_size; + READ_UNALIGNED_CK(dbg,version,Dwarf_Unsigned,data, + SIZEOFT16,error,end_data); + if (version != DW_CU_VERSION5) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_VERSION_STAMP_ERROR: The version should be 5 " + "but we find %u instead.",version); + _dwarf_error_string(dbg,error,DW_DLE_VERSION_STAMP_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->lc_version = version; + data += SIZEOFT16; + + READ_UNALIGNED_CK(dbg,address_size,unsigned,data, + SIZEOFT8,error,end_data); + if (address_size != 4 && address_size != 8 && + address_size != 2) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_ADDRESS_SIZE_ERROR: The address size " + "of %u is not supported.",address_size); + _dwarf_error_string(dbg,error,DW_DLE_ADDRESS_SIZE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->lc_address_size = address_size; + data++; + + READ_UNALIGNED_CK(dbg,segment_selector_size,unsigned,data, + SIZEOFT8,error,end_data); + buildhere->lc_segment_selector_size = segment_selector_size; + data++; + + READ_UNALIGNED_CK(dbg,offset_entry_count,Dwarf_Unsigned,data, + SIZEOFT32,error,end_data); + buildhere->lc_offset_entry_count = offset_entry_count; + data += SIZEOFT32; + if (offset_entry_count ){ + buildhere->lc_offsets_array = data; + } + localoff = data - startdata; + lists_len = offset_size *offset_entry_count; + + data += lists_len; + + buildhere->lc_offsets_off_in_sect = offset+localoff; + buildhere->lc_first_loclist_offset = offset+localoff+ + lists_len; + buildhere->lc_loclists_header = startdata; + buildhere->lc_endaddr = startdata +buildhere->lc_length; + buildhere->lc_past_last_loclist_offset = + buildhere->lc_header_offset +buildhere->lc_length; + *next_offset = buildhere->lc_past_last_loclist_offset; + return DW_DLV_OK; +} + +/* We return a pointer to an array of contexts + (not context pointers through *cxt if + we succeed and are returning DW_DLV_OK. + We never return DW_DLV_NO_ENTRY here. */ +static int +internal_load_loclists_contexts(Dwarf_Debug dbg, + Dwarf_Loclists_Context **cxt, + Dwarf_Unsigned *count, + Dwarf_Error *error) +{ + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned nextoffset = 0; + Dwarf_Small * data = dbg->de_debug_loclists.dss_data; + Dwarf_Unsigned section_size = dbg->de_debug_loclists.dss_size; + Dwarf_Small * startdata = data; + Dwarf_Small * end_data = data +section_size; + Dwarf_Chain curr_chain = 0; + Dwarf_Chain head_chain = 0; + Dwarf_Chain *plast = &head_chain; + int res = 0; + Dwarf_Unsigned chainlength = 0; + Dwarf_Loclists_Context *fullarray = 0; + Dwarf_Unsigned i = 0; + + for ( ; data < end_data ; data = startdata+nextoffset) { + Dwarf_Loclists_Context newcontext = 0; + + /* sizeof the context struct, not sizeof a pointer */ + newcontext = malloc(sizeof(*newcontext)); + if (!newcontext) { + free_loclists_chain(dbg,head_chain); + _dwarf_error_string(dbg,error, + DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocation of " + "Loclists_Context failed"); + return DW_DLV_ERROR; + } + memset(newcontext,0,sizeof(*newcontext)); + res = _dwarf_internal_read_loclists_header(dbg, + chainlength, + section_size, + data,end_data,offset, + newcontext,&nextoffset,error); + if (res == DW_DLV_ERROR) { + free(newcontext); + free_loclists_chain(dbg,head_chain); + return DW_DLV_ERROR; + } + newcontext->lc_magic = LOCLISTS_MAGIC; + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating Loclists_Context" + " chain entry"); + free_loclists_chain(dbg,head_chain); + free(newcontext); + return DW_DLV_ERROR; + } + curr_chain->ch_item = newcontext; + ++chainlength; + (*plast) = curr_chain; + plast = &(curr_chain->ch_next); + offset = nextoffset; + } + fullarray= (Dwarf_Loclists_Context *)malloc( + chainlength *sizeof(Dwarf_Loclists_Context /*pointer*/)); + if (!fullarray) { + free_loclists_chain(dbg,head_chain); + _dwarf_error_string(dbg,error, + DW_DLE_ALLOC_FAIL,"Allocation of " + "Loclists_Context pointer array failed"); + return DW_DLV_ERROR; + } + curr_chain = head_chain; + for (i = 0; i < chainlength; ++i) { + Dwarf_Chain prev = 0; + fullarray[i] = (Dwarf_Loclists_Context)curr_chain->ch_item; + curr_chain->ch_item = 0; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + /* ASSERT: the chain is entirely alloc'd + and the array of pointers points to + individually malloc'd Dwarf_Loclists_Context_s */ + *cxt = fullarray; + *count = chainlength; + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw loclists data. + Loads all the .debug_loclists[.dwo] headers and + returns DW_DLV_NO_ENTRY if the section + is missing or empty. + Intended to be done quite early and + done exactly once. + Harmless to do more than once. + With DW_DLV_OK it returns the number of + loclists headers in the section through + loclists_count. */ +int +dwarf_load_loclists(Dwarf_Debug dbg, + Dwarf_Unsigned *loclists_count, + Dwarf_Error *error) +{ + int res = DW_DLV_ERROR; + Dwarf_Loclists_Context *cxt = 0; + Dwarf_Unsigned count = 0; + + if (!dbg) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Debug " + "argument passed to " + "dwarf_load_loclists()"); + return DW_DLV_ERROR; + } + if (dbg->de_loclists_context) { + if (loclists_count) { + *loclists_count = dbg->de_loclists_context_count; + } + return DW_DLV_OK; + } + if (!dbg->de_debug_loclists.dss_size) { + /* nothing there. */ + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_debug_loclists.dss_data) { + res = _dwarf_load_section(dbg, &dbg->de_debug_loclists, + error); + if (res != DW_DLV_OK) { + return res; + } + } + res = internal_load_loclists_contexts(dbg,&cxt,&count,error); + if (res == DW_DLV_ERROR) { + return res; + } + dbg->de_loclists_context = cxt; + dbg->de_loclists_context_count = count; + if (loclists_count) { + *loclists_count = count; + } + return DW_DLV_OK; +} + +/* Frees the memory in use in all loclists contexts. + Done by dwarf_finish() */ +void +_dwarf_dealloc_loclists_context(Dwarf_Debug dbg) +{ + Dwarf_Unsigned i = 0; + Dwarf_Loclists_Context * loccon = 0; + + if (!dbg->de_loclists_context) { + return; + } + loccon = dbg->de_loclists_context; + for ( ; i < dbg->de_loclists_context_count; ++i) { + Dwarf_Loclists_Context con = loccon[i]; + con->lc_offsets_array = 0; + con->lc_offset_entry_count = 0; + con->lc_magic = 0; + free(con); + loccon[i] = 0; + } + free(dbg->de_loclists_context); + dbg->de_loclists_context = 0; + dbg->de_loclists_context_count = 0; +} + +/* Used by dwarfdump to print raw loclists data. */ +int +dwarf_get_loclist_offset_index_value(Dwarf_Debug dbg, + Dwarf_Unsigned context_index, + Dwarf_Unsigned offsetentry_index, + Dwarf_Unsigned * offset_value_out, + Dwarf_Unsigned * global_offset_value_out, + Dwarf_Error *error) +{ + Dwarf_Loclists_Context con = 0; + unsigned offset_len = 0; + Dwarf_Small *offsetptr = 0; + Dwarf_Unsigned targetoffset = 0; + + if (!dbg) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Debug " + "argument passed to " + "dwarf_get_loclist_offset_index_value()"); + return DW_DLV_ERROR; + } + + if (!dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (context_index >= dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + con = dbg->de_loclists_context[context_index]; + if (!con || con->lc_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "context NULL or not LOCLISTS_MAGIC " + "found in " + "dwarf_get_loclist_offset_index_value()"); + return DW_DLV_ERROR; + } + + if (offsetentry_index >= con->lc_offset_entry_count) { + return DW_DLV_NO_ENTRY; + } + offset_len = con->lc_offset_size; + offsetptr = con->lc_offsets_array + + (offsetentry_index*offset_len); + READ_UNALIGNED_CK(dbg,targetoffset,Dwarf_Unsigned, + offsetptr, + offset_len,error,con->lc_endaddr); + if (offset_value_out) { + *offset_value_out = targetoffset; + } + if (global_offset_value_out) { + *global_offset_value_out = targetoffset + + con->lc_offsets_off_in_sect; + } + return DW_DLV_OK; +} + +/* Used by dwarfdump to print basic data from the + data generated to look at a specific loclist + as returned by dwarf_loclists_index_get_rle_head() + or dwarf_loclists_offset_get_rle_head. */ +int dwarf_get_loclist_head_basics(Dwarf_Loc_Head_c head, + Dwarf_Small * lkind, + Dwarf_Unsigned * lle_count, + Dwarf_Unsigned * lle_version, + Dwarf_Unsigned * loclists_index_returned, + Dwarf_Unsigned * bytes_total_in_lle, + Dwarf_Half * offset_size, + Dwarf_Half * address_size, + Dwarf_Half * segment_selector_size, + Dwarf_Unsigned * overall_offset_of_this_context, + Dwarf_Unsigned * total_length_of_this_context, + Dwarf_Unsigned * offset_table_offset, + Dwarf_Unsigned * offset_table_entrycount, + Dwarf_Bool * loclists_base_present, + Dwarf_Unsigned * loclists_base, + Dwarf_Bool * loclists_base_address_present, + Dwarf_Unsigned * loclists_base_address, + Dwarf_Bool * loclists_debug_addr_base_present, + Dwarf_Unsigned * loclists_debug_addr_base, + Dwarf_Unsigned * loclists_offset_lle_set, + Dwarf_Error *error) +{ + Dwarf_Loclists_Context loccontext = 0; + + if (!head) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Loc_Head_c " + "argument passed to " + "dwarf_get_loclist_head_basics()"); + return DW_DLV_ERROR; + } + if (head->ll_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Loc_Head_c " + " not set with LOCLISTS_MAGIC in " + "argument passed to " + "dwarf_get_loclist_head_basics()"); + return DW_DLV_ERROR; + } + *lkind = head->ll_kind; + *lle_count = head->ll_locdesc_count; + *lle_version = head->ll_cuversion; + *loclists_index_returned = head->ll_index; + *bytes_total_in_lle = head->ll_bytes_total; + *offset_size = head->ll_offset_size; + *address_size = head->ll_address_size; + *segment_selector_size = head->ll_segment_selector_size; + /* If a dwarf_expression, no ll_loccontext */ + loccontext = head->ll_localcontext; + if (loccontext) { + *overall_offset_of_this_context = + loccontext->lc_header_offset; + *total_length_of_this_context = loccontext->lc_length; + *offset_table_offset = loccontext->lc_offsets_off_in_sect; + *offset_table_entrycount = loccontext->lc_offset_entry_count; + } + *loclists_base_present = head->ll_at_loclists_base_present; + *loclists_base= head->ll_at_loclists_base; + + *loclists_base_address_present = head->ll_cu_base_address_present; + *loclists_base_address= head->ll_cu_base_address; + + *loclists_debug_addr_base_present = head->ll_cu_addr_base_present; + *loclists_debug_addr_base = head->ll_cu_addr_base; + *loclists_offset_lle_set = head->ll_llearea_offset; + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw loclists data. + Enables printing of details about the Range List Table + Headers, one header per call. Index starting at 0. + Returns DW_DLV_NO_ENTRY if index is too high for the table. + A .debug_loclists section may contain any number + of Range List Table Headers with their details. */ +int +dwarf_get_loclist_context_basics(Dwarf_Debug dbg, + Dwarf_Unsigned context_index, + Dwarf_Unsigned * header_offset, + Dwarf_Small * offset_size, + Dwarf_Small * extension_size, + unsigned * version, /* 5 */ + Dwarf_Small * address_size, + Dwarf_Small * segment_selector_size, + Dwarf_Unsigned * offset_entry_count, + Dwarf_Unsigned * offset_of_offset_array, + Dwarf_Unsigned * offset_of_first_loclistentry, + Dwarf_Unsigned * offset_past_last_loclistentry, + Dwarf_Error *error) +{ + Dwarf_Loclists_Context con = 0; + + if (!dbg) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Debug " + "argument passed to " + "dwarf_get_loclist_context_basics()"); + return DW_DLV_ERROR; + } + if (!dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (context_index >= dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + con = dbg->de_loclists_context[context_index]; + if (!con || con->lc_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "context NULL or not LOCLISTS_MAGIC " + "found in " + "dwarf_get_loclist_context_basics()"); + return DW_DLV_ERROR; + } + if (header_offset) { + *header_offset = con->lc_header_offset; + } + if (offset_size) { + *offset_size = con->lc_offset_size; + } + if (extension_size) { + *extension_size = con->lc_extension_size; + } + if (version) { + *version = con->lc_version; + } + if (address_size) { + *address_size = con->lc_address_size; + } + if (segment_selector_size) { + *segment_selector_size = con->lc_segment_selector_size; + } + if (offset_entry_count) { + *offset_entry_count = con->lc_offset_entry_count; + } + if (offset_of_offset_array) { + *offset_of_offset_array = con->lc_offsets_off_in_sect; + } + if (offset_of_first_loclistentry) { + *offset_of_first_loclistentry = con->lc_first_loclist_offset; + } + if (offset_past_last_loclistentry) { + *offset_past_last_loclistentry = + con->lc_past_last_loclist_offset; + } + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw loclists data. + entry offset is offset_of_first_loclistentry. + Stop when the returned *next_entry_offset + is == offset_past_last_loclistentry (from + dwarf_get_loclist_context_plus). + This only makes sense within those loclists + This retrieves raw detail from the section, + no base values or anything are added. + So this returns raw individual entries + for a single loclist header, meaning a + a single Dwarf_Loclists_Context. */ +int dwarf_get_loclist_lle(Dwarf_Debug dbg, + Dwarf_Unsigned contextnumber, + Dwarf_Unsigned entry_offset, + Dwarf_Unsigned endoffset, + unsigned *entrylen, + unsigned *entry_kind, + Dwarf_Unsigned *entry_operand1, + Dwarf_Unsigned *entry_operand2, + Dwarf_Unsigned *expr_ops_blocksize, + Dwarf_Unsigned *expr_ops_offset, + Dwarf_Small **expr_opsdata, + Dwarf_Error *error) +{ + Dwarf_Loclists_Context con = 0; + Dwarf_Small *data = 0; + Dwarf_Small *enddata = 0; + int res = 0; + unsigned address_size = 0; + + if (!dbg) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Debug " + "argument passed to " + "dwarf_get_loclist_lle()"); + return DW_DLV_ERROR; + } + if (!dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + data = dbg->de_debug_loclists.dss_data + + entry_offset; + enddata = dbg->de_debug_loclists.dss_data + + endoffset; + if (contextnumber >= dbg->de_loclists_context_count) { + return DW_DLV_NO_ENTRY; + } + con = dbg->de_loclists_context[contextnumber]; + if (!con || con->lc_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(dbg, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "context NULL or not LOCLISTS_MAGIC " + "found in " + "dwarf_get_loclist_lle()"); + return DW_DLV_ERROR; + } + address_size = con->lc_address_size; + res = read_single_lle_entry(dbg, + data,entry_offset,enddata, + address_size, entrylen, + entry_kind, entry_operand1, entry_operand2, + expr_ops_blocksize, + expr_ops_offset, + expr_opsdata, + error); + return res; +} + +static int +_dwarf_which_loclists_context(Dwarf_Debug dbg, + Dwarf_CU_Context ctx, + Dwarf_Unsigned loclist_offset, + Dwarf_Unsigned *index, + Dwarf_Error *error) +{ + Dwarf_Unsigned count = 0; + Dwarf_Loclists_Context *array = 0; + Dwarf_Unsigned i = 0; + Dwarf_Loclists_Context rcx = 0; + Dwarf_Unsigned rcxoff = 0; + Dwarf_Unsigned rcxend = 0; + + array = dbg->de_loclists_context; + count = dbg->de_loclists_context_count; + if (!array) { + return DW_DLV_NO_ENTRY; + } + rcx = array[i]; + rcxoff = rcx->lc_header_offset; + rcxend = rcxoff + rcx->lc_length; + if (!ctx->cc_loclists_base_present) { + /* We look at the location of each loclist context + to find one with the offset the DIE gave us. */ + for ( i = 0 ; i < count; ++i) { + rcx = array[i]; + rcxoff = rcx->lc_header_offset; + rcxend = rcxoff + + rcx->lc_length; + rcxend = rcxoff + + rcx->lc_length; + if (loclist_offset < rcxoff){ + continue; + } + if (loclist_offset < rcxend ){ + *index = i; + return DW_DLV_OK; + } + } + { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: loclist ran off end " + " finding target offset of" + " 0x%" DW_PR_XZEROS DW_PR_DUx ,loclist_offset); + dwarfstring_append(&m, + " Not found anywhere in .debug_loclists " + "data. Corrupted data?"); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } else { + /* We have a DW_AT_loclists_base (lc_loclists_base), + let's use it. */ + Dwarf_Unsigned lookfor = 0;; + + lookfor = ctx->cc_loclists_base; + for ( i = 0 ; i < count; ++i) { + dwarfstring m; + + rcx = array[i]; + if (rcx->lc_offsets_off_in_sect == lookfor){ + *index = i; + return DW_DLV_OK; + } + if (rcx->lc_offsets_off_in_sect < lookfor){ + continue; + } + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: loclists base of " + " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); + dwarfstring_append_printf_u(&m, + " was not found though we are now at base " + " 0x%" DW_PR_XZEROS DW_PR_DUx , + rcx->lc_offsets_off_in_sect); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: loclist base of " + " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); + dwarfstring_append(&m, + " was not found anywhere in .debug_loclists " + "data. Corrupted data?"); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + return DW_DLV_ERROR; +} + +/* Caller will eventually free as appropriate. */ +static int +alloc_rle_and_append_to_list(Dwarf_Debug dbg, + Dwarf_Loc_Head_c rctx, + Dwarf_Locdesc_c *e_out, + Dwarf_Error *error) +{ + Dwarf_Locdesc_c e = 0; + + e = malloc(sizeof(struct Dwarf_Locdesc_c_s)); + if (!e) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Out of memory in " + "building list of loclists entries on a DIE."); + return DW_DLV_ERROR; + } + memset(e,0,sizeof(struct Dwarf_Locdesc_c_s)); + _dwarf_locdesc_c_constructor(dbg,e); + e->ld_magic = LOCLISTS_MAGIC; + if (rctx->ll_first) { + rctx->ll_last->ld_next = e; + rctx->ll_last = e; + } else { + rctx->ll_first = e; + rctx->ll_last = e; + } + rctx->ll_locdesc_count++; + *e_out = e; + return DW_DLV_OK; +} + +/* Read the group of loclists entries, and + finally build an array of Dwarf_Locdesc_c + records. Attach to rctx here. + Since on error the caller will destruct the rctx + and we ensure to attach allocations there + the caller will destruct the allocations here + in case we return DW_DLV_ERROR*/ +static int +build_array_of_lle(Dwarf_Debug dbg, + Dwarf_Loc_Head_c rctx, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Small *data = rctx->ll_llepointer; + Dwarf_Unsigned dataoffset = rctx->ll_llearea_offset; + Dwarf_Small *enddata = rctx->ll_end_data_area; + unsigned int offset_size = rctx->ll_offset_size; + unsigned int address_size = rctx->ll_address_size; + Dwarf_Unsigned bytescounttotal= 0; + int done = FALSE; + Dwarf_Unsigned i = 0; + + for ( ; !done ; ) { + unsigned entrylen = 0; + unsigned code = 0; + Dwarf_Unsigned val1 = 0; + Dwarf_Unsigned val2 = 0; + Dwarf_Locdesc_c e = 0; + Dwarf_Unsigned opsblocksize = 0; + Dwarf_Unsigned opsoffset = 0; + Dwarf_Small *ops = 0; + Dwarf_Block_c eops; + + memset(&eops,0,sizeof(eops)); + res = read_single_lle_entry(dbg, + data,dataoffset, enddata, + address_size,&entrylen, + &code,&val1, &val2, + &opsblocksize,&opsoffset,&ops, + error); + if (res != DW_DLV_OK) { + return res; + } + res = alloc_rle_and_append_to_list(dbg,rctx,&e,error); + if (res != DW_DLV_OK) { + return res; + } + eops.bl_len =opsblocksize; + eops.bl_data = ops; + eops.bl_kind = rctx->ll_kind; + eops.bl_section_offset = opsoffset; + eops.bl_locdesc_offset = dataoffset; + e->ld_kind = rctx->ll_kind; + e->ld_magic = LOCLISTS_MAGIC; + e->ld_lle_value = code, + e->ld_entrylen = entrylen; + e->ld_rawlow = val1; + e->ld_rawhigh = val2; + e->ld_opsblock = eops; + bytescounttotal += entrylen; + data += entrylen; + if (code == DW_LLE_end_of_list) { + done = TRUE; + break; + } + } + if (rctx->ll_locdesc_count > 0) { + Dwarf_Locdesc_c array = 0; + Dwarf_Locdesc_c cur = 0; + Dwarf_Locdesc_c prev = 0; + + /* array of structs. Here we copy the previous + malloc set of Dwarf_Locdesc_c into + a dwarf_get_alloc set and free the malloc set */ + + array = (Dwarf_Locdesc_c)_dwarf_get_alloc(dbg, + DW_DLA_LOCDESC_C, rctx->ll_locdesc_count); + if (!array) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Out of memory in " + "copying list of locdescs into array "); + return DW_DLV_ERROR; + } + rctx->ll_locdesc = array; + cur = rctx->ll_first; + for (i = 0 ; i < rctx->ll_locdesc_count; ++i) { + prev = cur; + array[i] = *cur; + cur = cur->ld_next; + free(prev); + } + rctx->ll_first = 0; + rctx->ll_last = 0; + } + for (i = 0; i < rctx->ll_locdesc_count; ++i) { + Dwarf_Locdesc_c ldc = rctx->ll_locdesc + i; + + res = _dwarf_fill_in_locdesc_op_c(dbg, + i, + rctx, + &ldc->ld_opsblock, + address_size, offset_size, + rctx->ll_cuversion, + ldc->ld_rawlow, ldc->ld_rawhigh, + ldc->ld_lle_value, + error); + if (res != DW_DLV_OK) { + return res; + } + } + rctx->ll_bytes_total = bytescounttotal; + return DW_DLV_OK; +} + +/* Build a head with all the relevent Entries + attached, all the locdescs and for each such, + all its expression operators. +*/ +int +_dwarf_loclists_fill_in_lle_head(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_Loc_Head_c llhead, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Unsigned loclists_contextnum = 0; + Dwarf_Small *table_base = 0; + Dwarf_Small *table_entry = 0; + Dwarf_Small *enddata = 0; + Dwarf_Loclists_Context *array = 0; + Dwarf_Loclists_Context rctx = 0; + Dwarf_Unsigned entrycount = 0; + unsigned offsetsize = 0; + Dwarf_Unsigned lle_global_offset = 0; + Dwarf_CU_Context ctx = 0; + Dwarf_Unsigned offset_in_loclists = 0; + Dwarf_Bool is_loclistx = FALSE; + int theform = llhead->ll_attrform; + Dwarf_Unsigned attr_val = 0; + + ctx = attr->ar_cu_context; + array = dbg->de_loclists_context; + if ( theform == DW_FORM_sec_offset) { + /* DW_FORM_sec_offset is not formudata , often + seen in in DW5 DW_AT_location etc */ + res = dwarf_global_formref(attr, &attr_val,error); + if (res != DW_DLV_OK) { + return res; + } + offset_in_loclists = attr_val; + } else { + if (theform == DW_FORM_loclistx) { + is_loclistx = TRUE; + } + res = dwarf_formudata(attr,&attr_val,error); + if (res != DW_DLV_OK) { + return res; + } + /* the context cc_loclists_base gives the offset + of the array. of offsets (if cc_loclists_base_present) */ + offset_in_loclists = attr_val; + if (is_loclistx) { + if (ctx->cc_loclists_base_present) { + offset_in_loclists = ctx->cc_loclists_base; + } else if (dbg->de_loclists_context_count == 1) { + /* missing a DW_AT_loclists_base! */ + offset_in_loclists = 0; + } else { + /* FIXME: check in tied file for a cc_loclists_base + possibly? Make any sense? */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: loclists table index of" + " %u" ,attr_val); + dwarfstring_append(&m, + " is unusable without a tied file." + ); + _dwarf_error_string(dbg,error,DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } else { + offset_in_loclists = attr_val; + } + } + res = _dwarf_which_loclists_context(dbg,ctx, + offset_in_loclists, + &loclists_contextnum,error); + if (res != DW_DLV_OK) { + return res; + } + rctx = array[loclists_contextnum]; + table_base = rctx->lc_offsets_array; + entrycount = rctx->lc_offset_entry_count; + offsetsize = rctx->lc_offset_size; + enddata = rctx->lc_endaddr; + + if (is_loclistx && attr_val >= entrycount) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_LOCLISTS_ERROR: loclists table index of" + " %u" ,attr_val); + dwarfstring_append_printf_u(&m, + " too large for table of %u " + "entries.",entrycount); + _dwarf_error_string(dbg,error, + DW_DLE_LOCLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + llhead->ll_localcontext = rctx; + llhead->ll_index = loclists_contextnum; + llhead->ll_cuversion = rctx->lc_version; + llhead->ll_offset_size = offsetsize; + llhead->ll_address_size = rctx->lc_address_size; + llhead->ll_segment_selector_size = + rctx->lc_segment_selector_size; + + if (is_loclistx) { + Dwarf_Unsigned table_entryval = 0; + + table_entry = attr_val*offsetsize + table_base; + /* No malloc here yet so no leak if the macro returns + DW_DLV_ERROR */ + READ_UNALIGNED_CK(dbg,table_entryval, Dwarf_Unsigned, + table_entry,offsetsize,error,enddata); + lle_global_offset = rctx->lc_offsets_off_in_sect + + table_entryval; + } else { + lle_global_offset = attr_val; + } + llhead->ll_end_data_area = enddata; + + llhead->ll_llearea_offset = lle_global_offset; + llhead->ll_llepointer = lle_global_offset + + dbg->de_debug_loclists.dss_data; + + res = build_array_of_lle(dbg,llhead,error); + if (res != DW_DLV_OK) { + return res; + } + return DW_DLV_OK; +} + +#if 0 +int +dwarf_get_loclists_entry_fields( + Dwarf_Loc_Head_c head, + Dwarf_Unsigned entrynum, + unsigned *entrylen, + unsigned *code, + Dwarf_Unsigned *raw1, + Dwarf_Unsigned *raw2, + Dwarf_Unsigned *cooked1, + Dwarf_Unsigned *cooked2, + /* FIXME not right for loclists or their loc exprs */ + Dwarf_Error *error) +{ + Dwarf_Locdesc_c e = 0; + if (!head || head->ll_magic != LOCLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL Dwarf_Loc_Head_c " + " not set with LOCLISTS_MAGIC in " + "argument passed to " + "dwarf_get_loclist_entry_fields()"); + return DW_DLV_ERROR; + } + + if (entrynum >= head->ll_locdesc_count) { + return DW_DLV_NO_ENTRY; + } + e = head->ll_locdesc + entrynum; + *entrylen = e->ld_entrylen; + *code = e->ld_lle_value; + *raw1 = e->ld_rawlow; + *raw2 = e->ld_rawhigh; + *cooked1 = e->ld_lopc; + *cooked2 = e->ld_highpc; + return DW_DLV_OK; +} +#endif /*0*/ + +static void +_dwarf_free_loclists_limited_head_content(Dwarf_Loc_Head_c head) +{ + if (head->ll_first) { + /* partially built head. */ + /* ASSERT: ll_loclists is NULL */ + Dwarf_Locdesc_c cur = head->ll_first; + Dwarf_Locdesc_c next = 0; + + for ( ; cur ; cur = next) { + next = cur->ld_next; + cur->ld_next = 0; + cur->ld_magic = 0; + free(cur); + } + head->ll_first = 0; + head->ll_last = 0; + head->ll_locdesc_count = 0; + } +} +/* Deals with both fully and partially build head, + called by user calls to clean up or by + libdwarf to clean up on error. */ +void +dwarf_dealloc_loc_head_c(Dwarf_Loc_Head_c head) +{ + Dwarf_Debug dbg = 0; + + if (!head) { + return; + } + if (head->ll_magic != LOCLISTS_MAGIC) { + return; + } + dbg = head->ll_dbg; + if (!dbg) { + return; + } + if (head->ll_first) { + _dwarf_free_loclists_limited_head_content(head); + } + if (head->ll_locdesc) { + Dwarf_Locdesc_c desc = head->ll_locdesc; + /* ASSERT: ll_first and ll_last are NULL */ + /* fully built head. */ + Dwarf_Unsigned listlen = head->ll_locdesc_count; + Dwarf_Unsigned i = 0; + + /* It's an array of desc. */ + for ( ; i < listlen; ++i) { + Dwarf_Loc_Expr_Op loc = desc[i].ld_s; + if (loc) { + dwarf_dealloc(dbg,loc,DW_DLA_LOC_BLOCK_C); + desc[i].ld_s = 0; + } + } + /* It is an array of structs, + and the block in each is gone. + It will be a simple single free. */ + dwarf_dealloc(dbg,head->ll_locdesc,DW_DLA_LOCDESC_C); + head->ll_locdesc_count = 0; + head->ll_locdesc = 0; + } + dwarf_dealloc(dbg,head,DW_DLA_LOC_HEAD_C); +} + +/* dwarf_alloc calls this on dealloc. head is freed there + after this returns. */ +void +_dwarf_loclists_head_destructor(void *head) +{ + Dwarf_Loc_Head_c h = head; + + _dwarf_free_loclists_limited_head_content(h); +} diff --git a/src/lib/libdwarf/dwarf_macho_loader.h b/src/lib/libdwarf/dwarf_macho_loader.h new file mode 100644 index 0000000..be16a99 --- /dev/null +++ b/src/lib/libdwarf/dwarf_macho_loader.h @@ -0,0 +1,1959 @@ +/* This is a cut-down version of loader.h from cctools-895, + shrunk to eliminate aspects unwanted in libdwarf and to avoid + #include entirely. All tab characters replaced with 4 spaces + so various things no line up as they used to. + Comment reformatting for line length may have left + some original comments hard to follow. + cctools-895 in its original form + is available from https://opensource.apple.com/ + see Developer Tools version 8.2.1. cctools-895/include/loader.h */ +/* +* Copyright (c) 1999-2010 Apple Inc. All Rights Reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* This file contains Original Code and/or +* Modifications of Original Code +* as defined in and that are subject to the +* Apple Public Source License +* Version 2.0 (the 'License'). You may not use this file except in +* compliance with the License. Please obtain a copy of the License at +* http://www.opensource.apple.com/apsl/ and read it before using this +* file. +* +* The Original Code and all software distributed under +* the License are +* distributed on an 'AS IS' basis, WITHOUT +* WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE, +* QUIET ENJOYMENT OR NON-INFRINGEMENT. +* Please see the License for the +* specific language governing rights and +* limitations under the License. +* +* @APPLE_LICENSE_HEADER_END@ +*/ +#ifndef MACHO_LOADER_H +#define MACHO_LOADER_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if 0 /* Not used here. DavidA. September 2018 */ +/* +* This file describes the format of mach object files. +*/ +#include + +/* +* is needed here for +* the cpu_type_t and cpu_subtype_t types +* and contains the constants for the possible values of these types. +*/ +#include + +/* +* is needed here for the +* vm_prot_t type and contains the +* constants that are or'ed together for the +* possible values of this type. +*/ +#include + +/* +* is expected to define +* the flavors of the thread +* states and the structures of those flavors for each machine. +*/ +#include +#include +#endif /* 0 */ + +#ifndef TYP +#define TYP(n,l) char (n)[(l)] +#endif /* TYP */ + +/* This is Apple internal naming for Universal Binaries + and is not 'Inclusive Terminology" !! */ +#define FAT_MAGIC 0xcafebabe +#define FAT_CIGAM 0xbebafeca +#define FAT_MAGIC_64 0xcafebabf +#define FAT_CIGAM_64 0xbfbafeca + +struct fat_header { + TYP(magic,4); /* FAT_MAGIC or FAT_MAGIC_64 */ + TYP(nfat_arch,4); /* number of structs that follow */ +}; + +struct fat_arch { + TYP(cputype ,4); /* cpu specifier (int) */ + TYP(cpusubtype,4); /* machine specifier (int) */ + TYP(offset,4); /* file offset to this object file */ + TYP(size,4); /* size of this object file */ + TYP(align,4); /* alignment as a power of 2 */ +}; + +struct fat_arch_64 { + TYP(cputype,4); /* cpu specifier (int) */ + TYP(cpusubtype,4); /* machine specifier (int) */ + TYP(offset,8); /* file offset to this object file */ + TYP(size,8); /* size of this object file */ + TYP(align,4); /* alignment as a power of 2 */ + TYP(reserved,4); /* reserved */ +}; + +/* +* The 32-bit mach header appears at the very +* beginning of the object file for +* 32-bit architectures. +*/ +struct mach_header { + TYP(magic,4); /* mach magic number identifier */ + TYP(cputype,4); /* cpu specifier */ + TYP(cpusubtype,4); /* machine specifier */ + TYP(filetype,4); /* type of file */ + TYP(ncmds,4); /* number of load commands */ + TYP(sizeofcmds,4); /* the size of all the load commands */ + TYP(flags,4); /* flags */ +}; + +/* Constant for the magic field of the + mach_header (32-bit architectures) + MH_MAGIC MH_MAGIC_64 appear in big-endian objects + MH_CIGAM MH_CIGAM_64 appear in little-endian objects */ +#define MH_MAGIC 0xfeedface /* the mach magic number */ +#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ + +/* +* The 64-bit mach header appears at the +* very beginning of object files for +* 64-bit architectures. +*/ +struct mach_header_64 { + TYP(magic,4); /* mach magic number identifier */ + TYP(cputype,4); /* cpu specifier */ + TYP(cpusubtype,4); /* machine specifier */ + TYP(filetype,4); /* type of file */ + TYP(ncmds,4); /* number of load commands */ + TYP(sizeofcmds,4); /* the size of all the load commands */ + TYP(flags,4); /* flags */ + TYP(reserved,4); /* reserved */ +}; + +/* Constant for the magic field of the mach_header_64 +* (64-bit architectures) */ +#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ +#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ + +/* +* The layout of the file depends on the filetype. +* For all but the MH_OBJECT +* file type the segments are padded +* out and aligned on a segment alignment +* boundary for efficient demand paging. +* The MH_EXECUTE, MH_FVMLIB, MH_DYLIB, +* MH_DYLINKER and MH_BUNDLE file types also +* have the headers included as part +* of their first segment. +* +* The file type MH_OBJECT is a compact +* format intended as output of the +* assembler and input (and possibly output) of the link editor (the .o +* format). All sections are in one unnamed +* segment with no segment padding. +* This format is used as an executable +* format when the file is so small the +* segment padding greatly increases its size. +* +* The file type MH_PRELOAD is an executable +* format intended for things that +* are not executed under the kernel (proms, +* stand alones, kernels, etc). The +* format can be executed under the kernel +* but may demand paged it and not +* preload it before execution. +* +* A core file is in MH_CORE format and can be +* in any legal +* Mach-O file. +* +* Constants for the filetype field of the mach_header +*/ +#define MH_OBJECT 0x1 /* relocatable object file */ +#define MH_EXECUTE 0x2 /* demand paged executable file */ +#define MH_FVMLIB 0x3 /* fixed VM shared library file */ +#define MH_CORE 0x4 /* core file */ +#define MH_PRELOAD 0x5 /* preloaded executable file */ +#define MH_DYLIB 0x6 /* dynamically bound shared library */ +#define MH_DYLINKER 0x7 /* dynamic link editor */ +#define MH_BUNDLE 0x8 /* dynamically bound bundle file */ +#define MH_DYLIB_STUB 0x9 /* shared library stub for static */ + /* linking only, no section contents */ +#define MH_DSYM 0xa /* companion file with only debug */ + /* sections */ +#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */ + +/* Constants for the flags field of the mach_header */ +#define MH_NOUNDEFS 0x1 /* the object file has no undefined + references */ +#define MH_INCRLINK 0x2 /* the object file is the output of an + incremental link against a base file + and can't be link edited again */ +#define MH_DYLDLINK 0x4 /* the object file is input for the + dynamic linker and can't be staticly + link edited again */ +#define MH_BINDATLOAD 0x8 /* the object file's undefined + references are bound by the dynamic + linker when loaded. */ +#define MH_PREBOUND 0x10 /* the file has its dynamic undefined + references prebound. */ +#define MH_SPLIT_SEGS 0x20 /* the file has its read-only and + read-write segments split */ +#define MH_LAZY_INIT 0x40 /* the shared library init routine is + to be run lazily via catching memory + faults to its writeable segments + (obsolete) */ +#define MH_TWOLEVEL 0x80 /* the image is using two-level name + space bindings */ +#define MH_FORCE_FLAT 0x100 /* the executable is forcing all images + to use flat name space bindings */ +#define MH_NOMULTIDEFS 0x200 /* this umbrella guarantees no multiple + definitions of symbols in its + sub-images so the two-level namespace + hints can always be used. */ +#define MH_NOFIXPREBINDING 0x400 /* do not have dyld notify the + prebinding agent about this + executable */ +#define MH_PREBINDABLE 0x800 /* the binary is not prebound but can + have its prebinding redone. only used + when MH_PREBOUND is not set. */ +#define MH_ALLMODSBOUND 0x1000 /* indicates that this binary binds to + all two-level namespace modules of + its dependent libraries. only used + when MH_PREBINDABLE and MH_TWOLEVEL + are both set. */ + +#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000 + /* safe to divide up the sections into + sub-sections via symbols for dead + code stripping */ + +#define MH_CANONICAL 0x4000 + /* the binary has been canonicalized + via the unprebind operation */ +#define MH_WEAK_DEFINES 0x8000 + /* the final linked image contains + external weak symbols */ +#define MH_BINDS_TO_WEAK 0x10000 + /* the final linked image uses + weak symbols */ + +#define MH_ALLOW_STACK_EXECUTION 0x20000 + /* When this bit is set, all stacks + in the task will be given stack + execution privilege. Only used in + MH_EXECUTE filetypes. */ +#define MH_ROOT_SAFE 0x40000 /* When this bit is set, the binary + declares it is safe for use in + processes with uid zero */ + +#define MH_SETUID_SAFE 0x80000 /* When this bit is set, the binary + declares it is safe for use in + processes when issetugid() is true */ + +#define MH_NO_REEXPORTED_DYLIBS 0x100000 + /* When this bit is set on a dylib, + the static linker does not need to + examine dependent dylibs to see + if any are re-exported */ + +#define MH_PIE 0x200000 /* When this bit is set, the OS will + load the main executable at a + random address. Only used in + MH_EXECUTE filetypes. */ + +#define MH_DEAD_STRIPPABLE_DYLIB 0x400000 + /* Only for use on dylibs. When + linking against a dylib that + has this bit set, the static linker + will automatically not create a + LC_LOAD_DYLIB load command to the + dylib if no symbols are being + referenced from the dylib. */ + +#define MH_HAS_TLV_DESCRIPTORS 0x800000 + /* Contains a section of type + S_THREAD_LOCAL_VARIABLES */ + +#define MH_NO_HEAP_EXECUTION 0x1000000 /* When this bit is set, + the OS will + run the main executable with + a non-executable heap even on + platforms (e.g. i386) that don't + require it. Only used in MH_EXECUTE + filetypes. */ + +#define MH_APP_EXTENSION_SAFE 0x02000000 +/* The code was linked for use in an +application extension. */ + +/* +* The load commands directly follow the mach_header. +* The total size of all +* of the commands is given by the sizeofcmds +* field in the mach_header. All +* load commands must have as their first two +* fields cmd and cmdsize. The cmd +* field is filled in with a constant for that command type. +* Each command type +* has a structure specifically for it. +* The cmdsize field is the size in bytes +* of the particular load command structure +* plus anything that follows it that +* is a part of the load command (i.e. +* section structures, strings, etc.). To +* advance to the next load command the +* cmdsize can be added to the offset or +* pointer of the current load command. +* The cmdsize for 32-bit architectures +* MUST be a multiple of 4 bytes and for +* 64-bit architectures MUST be a multiple +* of 8 bytes (these are forever the maximum +* alignment of any load commands). +* The padded bytes must be zero. +* All tables in the object file must also +* follow these rules so the file can be memory mapped. +* Otherwise the pointers +* to these tables will not work well or at all +* on some machines. With all +* padding zeroed like objects will compare byte for byte. +*/ +struct load_command { + TYP(cmd,4); /* type of load command */ + TYP(cmdsize,4); /* total size of command in bytes */ +}; + +/* +* After MacOS X 10.1 when a new load command +* is added that is required to be +* understood by the dynamic linker for the +* image to execute properly the +* LC_REQ_DYLD bit will be or'ed into the load +* command constant. If the dynamic +* linker sees such a load command it it does +* not understand will issue a +* "unknown load command required for execution" +* error and refuse to use the +* image. Other load commands without this bit +* that are not understood will +* simply be ignored. +*/ +#define LC_REQ_DYLD 0x80000000 + +/* Constants for the cmd field of all load commands, the type */ +#define LC_SEGMENT 0x1 /* segment of this file to be mapped */ +#define LC_SYMTAB 0x2 /* link-edit stab symbol table info */ +#define LC_SYMSEG 0x3 /* link-edit gdb symbol table info (obsolete) */ +#define LC_THREAD 0x4 /* thread */ +#define LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */ +#define LC_LOADFVMLIB 0x6 /*load a specified fixed VM shared library*/ +#define LC_IDFVMLIB 0x7 /* fixed VM shared library identification */ +#define LC_IDENT 0x8 /* object identification info (obsolete) */ +#define LC_FVMFILE 0x9 /* fixed VM file inclusion (internal use) */ +#define LC_PREPAGE 0xa /* prepage command (internal use) */ + +#define LC_DYSYMTAB 0xb +/* dynamic link-edit symbol table info */ + +#define LC_LOAD_DYLIB 0xc +/* load a dynamically linked shared library */ + +#define LC_ID_DYLIB 0xd +/* dynamically linked shared lib ident */ + +#define LC_LOAD_DYLINKER 0xe /* load a dynamic linker */ + +#define LC_ID_DYLINKER 0xf +/* dynamic linker identification */ + +#define LC_PREBOUND_DYLIB 0x10 +/* modules prebound for a dynamically */ +/* linked shared library */ + +#define LC_ROUTINES 0x11 /* image routines */ +#define LC_SUB_FRAMEWORK 0x12 /* sub framework */ +#define LC_SUB_UMBRELLA 0x13 /* sub umbrella */ +#define LC_SUB_CLIENT 0x14 /* sub client */ +#define LC_SUB_LIBRARY 0x15 /* sub library */ + +#define LC_TWOLEVEL_HINTS 0x16 +/* two-level namespace lookup hints */ + +#define LC_PREBIND_CKSUM 0x17 /* prebind checksum */ + +/* +* load a dynamically linked shared library +* that is allowed to be missing +* (all symbols are weak imported). +*/ +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) + +#define LC_SEGMENT_64 0x19 +/* 64-bit segment of this file to be +mapped */ + +#define LC_ROUTINES_64 0x1a /* 64-bit image routines */ +#define LC_UUID 0x1b /* the uuid */ +#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ +#define LC_CODE_SIGNATURE 0x1d /* local of code signature */ + +#define LC_SEGMENT_SPLIT_INFO 0x1e +/* local of info to split segments */ + +#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) +/* load and re-export dylib */ + +#define LC_LAZY_LOAD_DYLIB 0x20 +/* delay load of dylib until first use */ + +#define LC_ENCRYPTION_INFO 0x21 +/* encrypted segment information */ + +#define LC_DYLD_INFO 0x22 +/* compressed dyld information */ + +#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) +/* compressed dyld information only */ + +#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) +/* load upward dylib */ + +#define LC_VERSION_MIN_MACOSX 0x24 +/* build for MacOSX min OS version */ + +#define LC_VERSION_MIN_IPHONEOS 0x25 +/* build for iPhoneOS min OS version */ + +#define LC_FUNCTION_STARTS 0x26 +/* compressed table of function start addresses */ + +#define LC_DYLD_ENVIRONMENT 0x27 +/* string for dyld to treat +like environment variable */ + +#define LC_MAIN (0x28|LC_REQ_DYLD) +/* replacement for LC_UNIXTHREAD */ + +#define LC_DATA_IN_CODE 0x29 +/* table of non-instructions in __text */ + +#define LC_SOURCE_VERSION 0x2A +/* source version used to build binary */ + +#define LC_DYLIB_CODE_SIGN_DRS 0x2B +/* Code signing DRs copied from linked dylibs */ + +#define LC_ENCRYPTION_INFO_64 0x2C +/* 64-bit encrypted segment information */ + +#define LC_LINKER_OPTION 0x2D +/* linker options in MH_OBJECT files */ + +#define LC_LINKER_OPTIMIZATION_HINT 0x2E +/* optimization hints in MH_OBJECT files */ + +#define LC_VERSION_MIN_TVOS 0x2F +/* build for AppleTV min OS version */ + +#define LC_VERSION_MIN_WATCHOS 0x30 +/* build for Watch min OS version */ + +/* +* A variable length string in a load command +* is represented by an lc_str +* union. The strings are stored just after +* the load command structure and +* the offset is from the start of the load +* command structure. The size +* of the string is reflected in the cmdsize field of the load command. +* Once again any padded bytes to bring the cmdsize field to a multiple +* of 4 bytes must be zero. +*/ +union lc_str { + TYP(offset,4); /* offset to the string */ +#ifndef __LP64__ + char *ptr; /* pointer to the string */ +#endif +}; + +/* +* The segment load command indicates that a part of this file is to be +* mapped into the task's address space. +* The size of this segment in memory, +* vmsize, maybe equal to or larger than the amount +* to map from this file, +* filesize. The file is mapped starting at fileoff +* to the beginning of +* the segment in memory, vmaddr. +* The rest of the memory of the segment, +* if any, is allocated zero fill on demand. +* The segment's maximum virtual +* memory protection and initial virtual memory +* protection are specified +* by the maxprot and initprot fields. +* If the segment has sections then the +* section structures directly follow the segment +* command and their size is +* reflected in cmdsize. +*/ +struct segment_command { /* for 32-bit architectures */ + TYP(cmd,4); /* LC_SEGMENT */ + TYP(cmdsize,4); /* includes sizeof section structs */ + char segname[16]; /* segment name */ + TYP(vmaddr,4); /* memory address of this segment */ + TYP(vmsize,4); /* memory size of this segment */ + TYP(fileoff,4); /* file offset of this segment */ + TYP(filesize,4); /* amount to map from the file */ + TYP(maxprot,4); /* maximum VM protection */ + TYP(initprot,4); /* initial VM protection */ + TYP(nsects,4); /* number of sections in segment */ + TYP(flags,4); /* flags */ +}; + +/* +* The 64-bit segment load command indicates +* that a part of this file is to be +* mapped into a 64-bit task's address space. +* If the 64-bit segment has +* sections then section_64 structures directly +* follow the 64-bit segment +* command and their size is reflected in cmdsize. +*/ +struct segment_command_64 { /* for 64-bit architectures */ + TYP(cmd,4); /* LC_SEGMENT_64 */ + TYP(cmdsize,4); /* includes sizeof section_64 structs */ + char segname[16]; /* segment name */ + TYP(vmaddr,8); /* memory address of this segment */ + TYP(vmsize,8); /* memory size of this segment */ + TYP(fileoff,8); /* file offset of this segment */ + TYP(filesize,8); /* amount to map from the file */ + TYP(maxprot,4); /* maximum VM protection */ + TYP(initprot,4); /* initial VM protection */ + TYP(nsects,4); /* number of sections in segment */ + TYP(flags,4); /* flags */ +}; + +/* Constants for the flags field of the segment_command */ +#define SG_HIGHVM 0x1 + /* the file contents for this segment is for + the high part of the VM space, the low part + is zero filled (for stacks in core files) */ +#define SG_FVMLIB 0x2 + /* this segment is the VM that is allocated by + a fixed VM library, for overlap checking in + the link editor */ +#define SG_NORELOC 0x4 + /* this segment has nothing that was relocated + in it and nothing relocated to it, that is + it maybe safely replaced without relocation*/ +#define SG_PROTECTED_VERSION_1 0x8 + /* This segment is protected. If the + segment starts at file offset 0, the + first page of the segment is not + protected. All other pages of the + segment are protected. */ + +/* +* A segment is made up of zero or more sections. +* Non-MH_OBJECT files have +* all of their segments with the proper sections +* in each, and padded to the +* specified segment alignment when produced by +* the link editor. The first +* segment of a MH_EXECUTE and MH_FVMLIB format file +* contains the mach_header +* and load commands of the object file before its +* first section. The zero +* fill sections are always last in their segment +* (in all formats). This +* allows the zeroed segment padding to be mapped +* into memory where zero fill +* sections might be. The gigabyte zero fill sections, +* those with the section +* type S_GB_ZEROFILL, can only be in a segment +* with sections of this type. +* These segments are then placed after all other segments. +* +* The MH_OBJECT format has all of its sections in one segment for +* compactness. There is no padding to a specified +* segment boundary and the +* mach_header and load commands are not part of the segment. +* +* Sections with the same section name, sectname, +* going into the same segment, +* segname, are combined by the link editor. +* The resulting section is aligned +* to the maximum alignment of the combined sections +* and is the new section's +* alignment. The combined sections are aligned to +* their original alignment in +* the combined section. Any padded bytes to get +* the specified alignment are +* zeroed. +* +* The format of the relocation entries referenced by +* the reloff and nreloc +* fields of the section structure for mach +* object files is described in the +* header file . +*/ +struct section { /* for 32-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + TYP(addr,4); /* memory address of this section */ + TYP(size,4); /* size in bytes of this section */ + TYP(offset,4); /* file offset of this section */ + TYP(align,4); /* section alignment (power of 2) */ + TYP(reloff,4); /* file offset of relocation entries */ + TYP(nreloc,4); /* number of relocation entries */ + TYP(flags,4); /* flags (section type and attributes)*/ + TYP(reserved1,4); /* reserved (for offset or index) */ + TYP(reserved2,4); /* reserved (for count or sizeof) */ +}; + +struct section_64 { /* for 64-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + TYP(addr,8); /* memory address of this section */ + TYP(size,8); /* size in bytes of this section */ + TYP(offset,4); /* file offset of this section */ + TYP(align,4); /* section alignment (power of 2) */ + TYP(reloff,4); /* file offset of relocation entries */ + TYP(nreloc,4); /* number of relocation entries */ + TYP(flags,4); /* flags (section type and attributes)*/ + TYP(reserved1,4); /* reserved (for offset or index) */ + TYP(reserved2,4); /* reserved (for count or sizeof) */ + TYP(reserved3,4); /* reserved */ +}; + +/* +* The flags field of a section structure is +* separated into two parts a section +* type and section attributes. +* The section types are mutually exclusive (it +* can only have one type) but the section attributes +* are not (it may have more +* than one attribute). +*/ +#define SECTION_TYPE 0x000000ff /* 256 section types */ + +#define SECTION_ATTRIBUTES 0xffffff00 +/* 24 section attributes */ + +/* Constants for the type of a section */ +#define S_REGULAR 0x0 /* regular section */ +#define S_ZEROFILL 0x1 /* zero fill on demand section */ + +#define S_CSTRING_LITERALS 0x2 + /* section with only literal C strings*/ + +#define S_4BYTE_LITERALS 0x3 + /* section with only 4 byte literals */ + +#define S_8BYTE_LITERALS 0x4 + /* section with only 8 byte literals */ + +#define S_LITERAL_POINTERS 0x5 + /* section with only pointers to */ + /* literals */ +/* +* For the two types of symbol pointers +* sections and the symbol stubs section +* they have indirect symbol table entries. +* For each of the entries in the +* section the indirect symbol table entries, +* in corresponding order in the +* indirect symbol table, start at the +* index stored in the reserved1 field +* of the section structure. Since the indirect symbol table entries +* correspond to the entries in the section +* the number of indirect symbol table +* entries is inferred from the size of the +* section divided by the size of the +* entries in the section. +* For symbol pointers sections the size of the entries +* in the section is 4 bytes and for symbol stubs +* sections the byte size of the +* stubs is stored in the reserved2 field of the section structure. +*/ +#define S_NON_LAZY_SYMBOL_POINTERS 0x6 + /* section with only non-lazy + symbol pointers */ +#define S_LAZY_SYMBOL_POINTERS 0x7 + /* section with only lazy symbol + pointers */ +#define S_SYMBOL_STUBS 0x8 + /* section with only symbol + stubs, byte size of stub in + the reserved2 field */ +#define S_MOD_INIT_FUNC_POINTERS 0x9 + /* section with only function + pointers for initialization*/ +#define S_MOD_TERM_FUNC_POINTERS 0xa + /* section with only function + pointers for termination */ +#define S_COALESCED 0xb + /* section contains symbols that + are to be coalesced */ +#define S_GB_ZEROFILL 0xc + /* zero fill on demand section + (that can be larger than 4 + gigabytes) */ +#define S_INTERPOSING 0xd + /* section with only pairs of + function pointers for + interposing */ +#define S_16BYTE_LITERALS 0xe + /* section with only 16 byte + literals */ +#define S_DTRACE_DOF 0xf + /* section contains + DTrace Object Format */ +#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 + /* section with only lazy + symbol pointers to lazy + loaded dylibs */ +/* +* Section types to support thread local variables +*/ +#define S_THREAD_LOCAL_REGULAR 0x11 + /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_ZEROFILL 0x12 + /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_VARIABLES 0x13 + /* TLV descriptors */ +#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 + /* pointers to TLV + descriptors */ +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 + /* functions to call + to initialize TLV + values */ + +/* +* Constants for the section attributes part of the +* flags field of a section +* structure. +*/ +#define SECTION_ATTRIBUTES_USR 0xff000000 + /* User setable attributes */ +#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 + /* section contains only true + machine instructions */ +#define S_ATTR_NO_TOC 0x40000000 + /* section contains coalesced + symbols that are not to be + in a ranlib table of + contents */ +#define S_ATTR_STRIP_STATIC_SYMS 0x20000000 + /* ok to strip static symbols + in this section in files + with the MH_DYLDLINK flag */ +#define S_ATTR_NO_DEAD_STRIP 0x10000000 /* no dead stripping */ + +#define S_ATTR_LIVE_SUPPORT 0x08000000 + /* blocks are live if they + reference live blocks */ + +#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 + /* Used with i386 code stubs + written on by dyld */ +/* +* If a segment contains any sections marked with S_ATTR_DEBUG then all +* sections in that segment must have this attribute. +* No section other than +* a section marked with this attribute may reference +* the contents of this +* section. A section with this attribute may +* contain no symbols and must have +* a section type S_REGULAR. +* The static linker will not copy section contents +* from sections with this attribute into its output file. +* These sections +* generally contain DWARF debugging info. +*/ +#define S_ATTR_DEBUG 0x02000000 /* a debug section */ + +#define SECTION_ATTRIBUTES_SYS 0x00ffff00 + /* system setable attributes */ + +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 + /* section contains some + machine instructions */ + +#define S_ATTR_EXT_RELOC 0x00000200 /* section has external + relocation entries */ +#define S_ATTR_LOC_RELOC 0x00000100 /* section has local + relocation entries */ + +/* +* The names of segments and sections in them are +* mostly meaningless to the +* link-editor. But there are few things to support traditional UNIX +* executables that require the link-editor and assembler +* to use some names +* agreed upon by convention. +* +* The initial protection of the "__TEXT" segment +* has write protection turned +* off (not writeable). +* +* The link-editor will allocate common symbols at +* the end of the "__common" +* section in the "__DATA" segment. +* It will create the section and segment +* if needed. +*/ + +/* The currently known segment names and the +* section names in those segments */ + +#define SEG_PAGEZERO "__PAGEZERO" + /* the pagezero segment which has no */ + /* protections and catches NULL */ + /* references for MH_EXECUTE files */ + +#define SEG_TEXT "__TEXT" /* the tradition UNIX text segment */ +#define SECT_TEXT "__text" + /* the real text part of the text */ + /* section no headers, and no padding */ + +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" + /* the fvmlib initialization */ + /* section */ + +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" + /* the section following the */ + /* fvmlib initialization */ + /* section */ + +#define SEG_DATA "__DATA" /* the tradition UNIX data segment */ +#define SECT_DATA "__data" /* the real initialized data section */ + /* no padding, no bss overlap */ +#define SECT_BSS "__bss" /* the real uninitialized data section*/ + /* no padding */ +#define SECT_COMMON "__common" + /* the section common symbols are */ + /* allocated in by the link editor */ + +#define SEG_OBJC "__OBJC" /* objective-C runtime segment */ +#define SECT_OBJC_SYMBOLS "__symbol_table" /* symbol table */ +#define SECT_OBJC_MODULES "__module_info" /* module information */ +#define SECT_OBJC_STRINGS "__selector_strs" /* string table */ +#define SECT_OBJC_REFS "__selector_refs" /* string table */ + +#define SEG_ICON "__ICON" /* the icon segment */ +#define SECT_ICON_HEADER "__header" /* the icon headers */ +#define SECT_ICON_TIFF "__tiff" /* the icons in tiff format */ + +#define SEG_LINKEDIT "__LINKEDIT" + /* the segment containing all structs */ + /* created and maintained by the link */ + /* editor. Created with -seglinkedit */ + /* option to ld(1) for MH_EXECUTE and */ + /* FVMLIB file types only */ + +#define SEG_UNIXSTACK "__UNIXSTACK" /* the unix stack segment */ + +#define SEG_IMPORT "__IMPORT" /* the segment for the self (dyld) */ + /* modifing code stubs that has read, */ + /* write and execute permissions */ + +/* +* Fixed virtual memory shared libraries are +* identified by two things. The +* target pathname (the name of the library +* as found for execution), and the +* minor version number. +* The address of where the headers are loaded is in +* header_addr. (THIS IS OBSOLETE and no longer supported). +*/ +struct fvmlib { + union lc_str name; /* library's target pathname */ + TYP(minor_version,4); /* library's minor version number */ + TYP(header_addr,4); /* library's header address */ +}; + +/* +* A fixed virtual shared library (filetype == MH_FVMLIB +* in the mach header) +* contains a fvmlib_command (cmd == LC_IDFVMLIB) to +* identify the library. +* An object that uses a fixed virtual shared library also contains a +* fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses. +* (THIS IS OBSOLETE and no longer supported). +*/ +struct fvmlib_command { + TYP(cmd,4); /* LC_IDFVMLIB or LC_LOADFVMLIB */ + TYP(cmdsize,4); /* includes pathname string */ + struct fvmlib fvmlib; /* the library identification */ +}; + +/* +* Dynamicly linked shared libraries are identified by two things. The +* pathname (the name of the library as found for execution), and the +* compatibility version number. The pathname must match +* and the compatibility +* number in the user of the library must be greater than or +* equal to the +* library being used. The time stamp is used to record the +* time a library was +* built and copied into user so it can be use to determined +* if the library used +* at runtime is exactly the same as used to built the program. +*/ +struct dylib { + union lc_str name; /* library's path name */ + TYP(timestamp,4); /* library's build time stamp */ + TYP(current_version,4); /* library's current version number */ + + TYP(compatibility_version,4); + /* library's compatibility vers number*/ +}; + +/* +* A dynamically linked shared library (filetype == MH_DYLIB +* in the mach header) +* contains a dylib_command (cmd == LC_ID_DYLIB) to +* identify the library. +* An object that uses a dynamically linked shared library +* also contains a +* dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or +* LC_REEXPORT_DYLIB) for each library it uses. +*/ +struct dylib_command { + TYP(cmd,4); /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, + LC_REEXPORT_DYLIB */ + TYP(cmdsize,4); /* includes pathname string */ + struct dylib dylib; /* the library identification */ +}; + +/* +* A dynamically linked shared library may be a +* subframework of an umbrella +* framework. If so it will be linked with "-umbrella +* umbrella_name" where +* Where "umbrella_name" is the name of the umbrella framework. +* A subframework +* can only be linked against by its umbrella framework +* or other subframeworks +* that are part of the same umbrella framework. +* Otherwise the static link +* editor produces an error and states to link against +* the umbrella framework. +* The name of the umbrella framework for subframeworks +* is recorded in the +* following structure. +*/ +struct sub_framework_command { + TYP(cmd,4); /* LC_SUB_FRAMEWORK */ + TYP(cmdsize,4); /* includes umbrella string */ + union lc_str umbrella; /* the umbrella framework name */ +}; + +/* +* For dynamically linked shared libraries that +* are subframework of an umbrella +* framework they can allow clients other than +* the umbrella framework or other +* subframeworks in the same umbrella framework. +* To do this the subframework +* is built with "-allowable_client client_name" +* and an LC_SUB_CLIENT load +* command is created for each -allowable_client flag. +* The client_name is +* usually a framework name. +* It can also be a name used for bundles clients +* where the bundle is built with "-client_name client_name". +*/ +struct sub_client_command { + TYP(cmd,4); /* LC_SUB_CLIENT */ + TYP(cmdsize,4); /* includes client string */ + union lc_str client; /* the client name */ +}; + +/* +* A dynamically linked shared library may be a +* sub_umbrella of an umbrella +* framework. If so it will be linked with +* "-sub_umbrella umbrella_name" where +* Where "umbrella_name" is the name of the +* sub_umbrella framework. When +* staticly linking when -twolevel_namespace is +* in effect a twolevel namespace +* umbrella framework will only cause its subframeworks +* and those frameworks +* listed as sub_umbrella frameworks to be +* implicited linked in. Any other +* dependent dynamic libraries will not be linked +* it when -twolevel_namespace +* is in effect. The primary library recorded +* by the static linker when +* resolving a symbol in these libraries will +* be the umbrella framework. +* Zero or more sub_umbrella frameworks may be +* use by an umbrella framework. +* The name of a sub_umbrella framework is +* recorded in the following structure. +*/ +struct sub_umbrella_command { + TYP(cmd,4); /* LC_SUB_UMBRELLA */ + TYP(cmdsize,4); /* includes sub_umbrella string */ + union lc_str sub_umbrella; /* the sub_umbrella framework name */ +}; + +/* +* A dynamically linked shared library may be a +* sub_library of another shared +* library. If so it will be linked with +* "-sub_library library_name" where +* Where "library_name" is the name of the +* sub_library shared library. When +* staticly linking when -twolevel_namespace is in +* effect a twolevel namespace +* shared library will only cause its subframeworks +* and those frameworks +* listed as sub_umbrella frameworks and libraries +* listed as sub_libraries to +* be implicited linked in. Any other dependent +* dynamic libraries will not be +* linked it when -twolevel_namespace is in effect. +* The primary library +* recorded by the static linker when resolving a +* symbol in these libraries +* will be the umbrella framework (or dynamic library). +* Zero or more sub_library +* shared libraries may be use by an umbrella framework +* or (or dynamic library). +* The name of a sub_library framework is recorded +* in the following structure. +* For example /usr/lib/libobjc_profile.A.dylib +* would be recorded as "libobjc". +*/ +struct sub_library_command { + TYP(cmd,4); /* LC_SUB_LIBRARY */ + TYP(cmdsize,4); /* includes sub_library string */ + union lc_str sub_library; /* the sub_library name */ +}; + +/* +* A program (filetype == MH_EXECUTE) that is +* prebound to its dynamic libraries has one of +* these for each library that +* the static linker used in prebinding. +* It contains a bit vector for the +* modules in the library. +* The bits indicate which modules are bound (1) and +* which are not (0) from the library. +* The bit for module 0 is the low bit +* of the first byte. So the bit for the Nth module is: +* (linked_modules[N/8] >> N%8) & 1 +*/ +struct prebound_dylib_command { + TYP(cmd,4); /* LC_PREBOUND_DYLIB */ + TYP(cmdsize,4); /* includes strings */ + union lc_str name; /* library's path name */ + TYP(nmodules,4); /* number of modules in library */ + union lc_str linked_modules; /* bit vector of linked modules */ +}; + +/* +* A program that uses a dynamic linker contains a +* dylinker_command to identify +* the name of the dynamic linker (LC_LOAD_DYLINKER). +* And a dynamic linker +* contains a dylinker_command to identify the dynamic +* linker (LC_ID_DYLINKER). +* A file can have at most one of these. +* This struct is also used for the +* LC_DYLD_ENVIRONMENT load command and +* contains string for dyld to treat like environment variable. +*/ +struct dylinker_command { + TYP(cmd,4); /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or + LC_DYLD_ENVIRONMENT */ + TYP(cmdsize,4); /* includes pathname string */ + union lc_str name; /* dynamic linker's path name */ +}; + +/* +* Thread commands contain machine-specific +* data structures suitable for +* use in the thread state primitives. +* The machine specific data structures +* follow the struct thread_command as follows. +* Each flavor of machine specific data structure +* is preceded by an unsigned +* long constant for the flavor of that data structure, an uint32_t +* that is the count of longs of the size of the state +* data structure and then +* the state data structure follows. This triple may be +* repeated for many +* flavors. The constants for the flavors, counts and +* state data structure +* definitions are expected to be in the header file +* . +* These machine specific data structures sizes must be multiples of +* 4 bytes The cmdsize reflects the total size of the thread_command +* and all of the sizes of the constants for the flavors, +* counts and state +* data structures. +* +* For executable objects that are unix processes there will be one +* thread_command (cmd == LC_UNIXTHREAD) created for it +* by the link-editor. +* This is the same as a LC_THREAD, except that a stack +* is automatically +* created (based on the shell's limit for the stack size). +* Command arguments +* and environment variables are copied onto that stack. +*/ +struct thread_command { + TYP(cmd,4); /* LC_THREAD or LC_UNIXTHREAD */ + TYP(cmdsize,4); /* total size of this command */ + /* uint32_t flavor flavor of thread state */ + /* uint32_t count count of longs in thread state */ + /* struct XXX_thread_state state thread state for this flavor */ + /* ... */ +}; + +/* +* The routines command contains the address of the +* dynamic shared library +* initialization routine and an index into the module +* table for the module +* that defines the routine. Before any modules are +* used from the library the +* dynamic linker fully binds the module that defines +* the initialization routine +* and then calls it. This gets called before any +* module initialization +* routines (used for C++ static constructors) in the library. +*/ +struct routines_command { /* for 32-bit architectures */ + TYP(cmd,4); /* LC_ROUTINES */ + TYP(cmdsize,4); /* total size of this command */ + TYP(init_address,4); /* address of initialization routine */ + TYP(init_module,4); /* index into the module table that */ + /* the init routine is defined in */ + TYP(reserved1,4); + TYP(reserved2,4); + TYP(reserved3,4); + TYP(reserved4,4); + TYP(reserved5,4); + TYP(reserved6,4); +}; + +/* +* The 64-bit routines command. Same use as above. +*/ +struct routines_command_64 { /* for 64-bit architectures */ + TYP(cmd,4); /* LC_ROUTINES_64 */ + TYP(cmdsize,4); /* total size of this command */ + TYP(init_address,8); /* address of initialization routine */ + TYP(init_module,8); /* index into the module table that */ + /* the init routine is defined in */ + TYP(reserved1,8); + TYP(reserved2,8); + TYP(reserved3,8); + TYP(reserved4,8); + TYP(reserved5,8); + TYP(reserved6,8); +}; + +/* +* The symtab_command contains the offsets and sizes +* of the link-edit 4.3BSD +* "stab" style symbol table information as described +* in the header files +* and . +*/ +struct symtab_command { + TYP(cmd,4); /* LC_SYMTAB */ + TYP(cmdsize,4); /* sizeof(struct symtab_command) */ + TYP(symoff,4); /* symbol table offset */ + TYP(nsyms,4); /* number of symbol table entries */ + TYP(stroff,4); /* string table offset */ + TYP(strsize,4); /* string table size in bytes */ +}; + +/* +* This is the second set of the symbolic information +* which is used to support +* the data structures for the dynamically link editor. +* +* The original set of symbolic information in the +* symtab_command which contains +* the symbol and string tables must also be present +* when this load command is +* present. When this load command is present the symbol +* table is organized +* into three groups of symbols: +* local symbols (static and debugging symbols) - grouped by module +* defined external symbols - grouped by module +* (sorted by name if not lib) +* undefined external symbols +* (sorted by name if MH_BINDATLOAD is not set, +* and in order the were seen by the static +* linker if MH_BINDATLOAD is set) +* In this load command there are offsets +* and counts to each of the three groups +* of symbols. +* +* This load command contains a the offsets +* and sizes of the following new +* symbolic information tables: +* table of contents +* module table +* reference symbol table +* indirect symbol table +* The first three tables above (the table of contents, +* module table and +* reference symbol table) are only present if the +* file is a dynamically linked +* shared library. For executable and object modules, which are files +* containing only one module, the information that +* would be in these three +* tables is determined as follows: +* table of contents - the defined external symbols +* are sorted by name +* module table - the file contains only one module +* so everything in the file is part of the module. +* reference symbol table - is the defined and +* undefined external symbols +* +* For dynamically linked shared library files this +* load command also contains +* offsets and sizes to the pool of relocation entries for all sections +* separated into two groups: +* external relocation entries +* local relocation entries +* For executable and object modules the +* relocation entries continue to hang +* off the section structures. +*/ +struct dysymtab_command { + TYP(cmd,4); /* LC_DYSYMTAB */ + TYP(cmdsize,4); /* sizeof(struct dysymtab_command) */ + + /* + * The symbols indicated by symoff and nsyms + * of the LC_SYMTAB load command + * are grouped into the following three groups: + * local symbols (further grouped by the module they are from) + * defined external symbols (further grouped + * by the module they are from) + * undefined symbols + * + * The local symbols are used only for debugging. + * The dynamic binding + * process may have to use them to indicate to the + * debugger the local + * symbols for a module that is being bound. + * + * The last two groups are used by the dynamic + * binding process to do the + * binding (indirectly through the module table + * and the reference symbol + * table when this is a dynamically linked shared library file). + */ + TYP(ilocalsym,4); /* index to local symbols */ + TYP(nlocalsym,4); /* number of local symbols */ + + TYP(iextdefsym,4); /* index to externally defined symbols */ + TYP(nextdefsym,4); /* number of externally defined symbols */ + + TYP(iundefsym,4); /* index to undefined symbols */ + TYP(nundefsym,4); /* number of undefined symbols */ + + /* + * For the for the dynamic binding process to + * find which module a symbol + * is defined in the table of contents is used + * (analogous to the ranlib + * structure in an archive) which maps defined + * external symbols to modules + * they are defined in. This exists only in a + * dynamically linked shared + * library file. For executable and object modules + * the defined external + * symbols are sorted by name and is use as the table of contents. + */ + TYP(tocoff,4); /* file offset to table of contents */ + TYP(ntoc,4); /* number of entries in table of contents */ + + /* + * To support dynamic binding of "modules" (whole + * object files) the symbol + * table must reflect the modules that the file was + * created from. This is + * done by having a module table that has indexes + * and counts into the merged + * tables for each module. + * The module structure that these two entries + * refer to is described below. + * This exists only in a dynamically linked + * shared library file. For executable and object + * modules the file only + * contains one module so everything in the file belongs + * to the module. + */ + TYP(modtaboff,4); /* file offset to module table */ + TYP(nmodtab,4); /* number of module table entries */ + + /* + * To support dynamic module binding the module structure + * for each module + * indicates the external references (defined and undefined) + * each module + * makes. For each module there is an offset and a count into the + * reference symbol table for the symbols that the module + * references. + * This exists only in a dynamically linked shared + * library file. For + * executable and object modules the defined external + * symbols and the + * undefined external symbols indicates the external references. + */ + TYP(extrefsymoff,4); /* offset to referenced symbol table */ + TYP(nextrefsyms,4);/* number of referenced symbol table entries */ + + /* + * The sections that contain "symbol pointers" and + * "routine stubs" have + * indexes and (implied counts based on the size of + * the section and fixed + * size of the entry) into the "indirect symbol" table + * for each pointer + * and stub. For every section of these two types the + * index into the + * indirect symbol table is stored in the section header + * in the field + * reserved1. An indirect symbol table entry is simply + * a 32bit index into + * the symbol table to the symbol that the pointer or + * stub is referring to. + * The indirect symbol table is ordered to match the + * entries in the section. + */ + TYP(indirectsymoff,4); + /* file offset to the indirect symbol table */ + + TYP(nindirectsyms,4); + /* number of indirect symbol table entries */ + + /* + * To support relocating an individual module in a library + * file quickly the + * external relocation entries for each module in the + * library need to be + * accessed efficiently. Since the relocation entries + * can't be accessed + * through the section headers for a library file + * they are separated into + * groups of local and external entries further + * grouped by module. In this + * case the presents of this load command who's extreloff, nextrel, + * locreloff and nlocrel fields are non-zero indicates + * that the relocation + * entries of non-merged sections are not referenced + * through the section + * structures (and the reloff and nreloc fields + * in the section headers are + * set to zero). + * + * Since the relocation entries are not accessed + * through the section headers + * this requires the r_address field to be something other + * than a section + * offset to identify the item to be relocated. + * In this case r_address is + * set to the offset from the vmaddr of the first + * LC_SEGMENT command. + * For MH_SPLIT_SEGS images r_address is set to + * the the offset from the + * vmaddr of the first read-write LC_SEGMENT command. + * + * The relocation entries are grouped by module and the + * module table + * entries have indexes and counts into them for the + * group of external + * relocation entries for that the module. + * + * For sections that are merged across modules there must + * not be any + * remaining external relocation entries for them + * (for merged sections + * remaining relocation entries must be local). + */ + TYP(extreloff,4); /* offset to external relocation entries */ + TYP(nextrel,4); /* number of external relocation entries */ + + /* + * All the local relocation entries are + * grouped together (they are not + * grouped by their module since they are only + * used if the object is moved + * from it staticly link edited address). + */ + TYP(locreloff,4); /* offset to local relocation entries */ + TYP(nlocrel,4); /* number of local relocation entries */ +}; + +/* +* An indirect symbol table entry is simply a 32bit index into +* the symbol table to the symbol that the pointer or stub is +* referring to. Unless it is for a * non-lazy symbol pointer +* section for a defined symbol which strip(1) has +* removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. +* If the * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed +* with that. +*/ +#define INDIRECT_SYMBOL_LOCAL 0x80000000 +#define INDIRECT_SYMBOL_ABS 0x40000000 + +/* a table of contents entry */ +struct dylib_table_of_contents { + TYP(symbol_index,4); /* the defined external symbol + (index into the symbol table) */ + TYP(module_index,4); /* index into the module table this symbol + is defined in */ +}; + +/* a module table entry */ +struct dylib_module { + /* the module name (index into string table) */ + TYP(module_name,4); + + TYP(iextdefsym,4); /* index into externally defined symbols */ + TYP(nextdefsym,4); /* number of externally defined symbols */ + TYP(irefsym,4); /* index into reference symbol table */ + TYP(nrefsym,4); /* number of reference symbol table entries */ + TYP(ilocalsym,4); /* index into symbols for local symbols */ + TYP(nlocalsym,4); /* number of local symbols */ + + TYP(iextrel,4); /* index into external relocation entries */ + TYP(nextrel,4); /* number of external relocation entries */ + + TYP(iinit_iterm,4); /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + TYP(ninit_nterm,4); /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + /* for this module address of the start of */ + /* the (__OBJC,__module_info) section */ + TYP(objc_module_info_addr,4); + + /* for this module size of */ + /* the (__OBJC,__module_info) section */ + TYP(objc_module_info_size,4); +}; + +/* a 64-bit module table entry */ +struct dylib_module_64 { + /* the module name (index into string table) */ + TYP(module_name,4); + + TYP(iextdefsym,4); /* index into externally defined symbols */ + TYP(nextdefsym,4); /* number of externally defined symbols */ + TYP(irefsym,4); /* index into reference symbol table */ + TYP(nrefsym,4); /* number of reference symbol table entries */ + TYP(ilocalsym,4); /* index into symbols for local symbols */ + TYP(nlocalsym,4); /* number of local symbols */ + + TYP(iextrel,4); /* index into external relocation entries */ + TYP(nextrel,4); /* number of external relocation entries */ + + TYP(iinit_iterm,4); /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + TYP(ninit_nterm,4); /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + TYP(objc_module_info_size,4); /* for this module size of */ + /* the (__OBJC,__module_info) section */ + TYP(objc_module_info_addr,8); + /* for this module address of the start of */ + /* the (__OBJC,__module_info) section */ +}; + +/* +* The entries in the reference symbol +* table are used when loading the module +* (both by the static and dynamic link +* editors) and if the module is unloaded +* or replaced. Therefore all external +* symbols (defined and undefined) are +* listed in the module's reference table. +* The flags describe the type of +* reference that is being made. +* The constants for the flags are defined in +* as they are also used for symbol table entries. +*/ +#if 0 /* dwarf readers not using this */ +struct dylib_reference { + UNUSED uint32_t isym:24, /* index into the symbol table */ + UNUSED flags:8; /* flags to indicate the type of reference */ +}; +#endif /* 0 */ + +/* +* The twolevel_hints_command contains the +* offset and number of hints in the +* two-level namespace lookup hints table. +*/ +struct twolevel_hints_command { + TYP(cmd,4); /* LC_TWOLEVEL_HINTS */ + TYP(cmdsize,4); /* sizeof(struct twolevel_hints_command) */ + TYP(offset,4); /* offset to the hint table */ + TYP(nhints,4); /* number of hints in the hint table */ +}; + +/* +* The entries in the two-level namespace lookup +* hints table are twolevel_hint +* structs. These provide hints to the +* dynamic link editor where to start +* looking for an undefined symbol in a two-level namespace image. The +* isub_image field is an index into the sub-images (sub-frameworks and +* sub-umbrellas list) that made up the +* two-level image that the undefined +* symbol was found in when it was built by the static link editor. If +* isub-image is 0 the the symbol is expected +* to be defined in library and not +* in the sub-images. +* If isub-image is non-zero it is an index into the array +* of sub-images for the umbrella with the first +* index in the sub-images being +* 1. The array of sub-images is the ordered +* list of sub-images of the umbrella +* that would be searched for a symbol that +* has the umbrella recorded as its +* primary library. +* The table of contents index is an index into the +* library's table of contents. +* This is used as the starting point of the +* binary search or a directed linear search. +*/ +#if 0 +/* Not used by dwarf readers. */ +struct twolevel_hint { + UNUSED uint32_t + isub_image:8, /* index into the sub images */ + itoc:24; /* index into the table of contents */ +}; +#endif + +/* +* The prebind_cksum_command contains the value of +* the original check sum for +* prebound files or zero. +* When a prebound file is first created or modified +* for other than updating its prebinding information +* the value of the check sum +* is set to zero. +* When the file has it prebinding re-done and if the value of +* the check sum is zero the original check sum is +* calculated and stored in +* cksum field of this load command in the output file. +* If when the prebinding +* is re-done and the cksum field is non-zero it +* is left unchanged from the +* input file. +*/ +struct prebind_cksum_command { + TYP(cmd,4); /* LC_PREBIND_CKSUM */ + TYP(cmdsize,4); /* sizeof(struct prebind_cksum_command) */ + TYP(cksum,4); /* the check sum or zero */ +}; + +/* +* The uuid load command contains a single 128-bit +* unique random number that +* identifies an object produced by the static link editor. +*/ +struct uuid_command { + TYP(cmd,4); /* LC_UUID */ + TYP(cmdsize,4); /* sizeof(struct uuid_command) */ + unsigned char uuid[16]; /* the 128-bit uuid */ +}; + +/* +* The rpath_command contains a path which +* at runtime should be added to +* the current run path used to find @rpath prefixed dylibs. +*/ +struct rpath_command { + TYP(cmd,4); /* LC_RPATH */ + TYP(cmdsize,4); /* includes string */ + union lc_str path; /* path to add to run path */ +}; + +/* +* The linkedit_data_command contains the offsets and sizes of a blob +* of data in the __LINKEDIT segment. +*/ +struct linkedit_data_command { + TYP(cmd,4); /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, + LC_FUNCTION_STARTS, LC_DATA_IN_CODE, + LC_DYLIB_CODE_SIGN_DRS or + LC_LINKER_OPTIMIZATION_HINT. */ + TYP(cmdsize,4); /* sizeof(struct linkedit_data_command) */ + TYP(dataoff,4); /* file offset of data in __LINKEDIT segment */ + TYP(datasize,4); /* file size of data in __LINKEDIT segment */ +}; + +/* +* The encryption_info_command contains the file offset and size of an +* of an encrypted segment. +*/ +struct encryption_info_command { + TYP(cmd,4); /* LC_ENCRYPTION_INFO */ + TYP(cmdsize,4); /* sizeof(struct encryption_info_command) */ + TYP(cryptoff,4); /* file offset of encrypted range */ + TYP(cryptsize,4); /* file size of encrypted range */ + TYP(cryptid,4); /* which encryption system, + 0 means not-encrypted yet */ +}; + +/* +* The encryption_info_command_64 contains +* the file offset and size of an +* of an encrypted segment (for use in x86_64 targets). +*/ +struct encryption_info_command_64 { + TYP(cmd,4); /* LC_ENCRYPTION_INFO_64 */ + TYP(cmdsize,4); /* sizeof(struct encryption_info_command_64) */ + TYP(cryptoff,4); /* file offset of encrypted range */ + TYP(cryptsize,4); /* file size of encrypted range */ + TYP(cryptid,4); /* which encryption system, + 0 means not-encrypted yet */ + TYP(pad,4); /* padding to make this struct's size a multiple + of 8 bytes */ +}; + +/* +* The version_min_command contains the min OS version on which this +* binary was built to run. +*/ +struct version_min_command { + TYP(cmd,4); /* LC_VERSION_MIN_MACOSX or + LC_VERSION_MIN_IPHONEOS or + LC_VERSION_MIN_WATCHOS or + LC_VERSION_MIN_TVOS */ + TYP(cmdsize,4); /* sizeof(struct min_version_command) */ + TYP(version,4); /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + TYP(sdk,4); /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ +}; + +/* +* The dyld_info_command contains the file offsets and sizes of +* the new compressed form of the information dyld needs to +* load the image. This information is used by dyld on Mac OS X +* 10.6 and later. All information pointed to by this command +* is encoded using byte streams, so no endian swapping is needed +* to interpret it. +*/ +struct dyld_info_command { + TYP(cmd,4); /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ + TYP(cmdsize,4); /* sizeof(struct dyld_info_command) */ + + /* + * Dyld rebases an image whenever dyld loads it at + * an address different + * from its preferred address. The rebase information is a stream + * of byte sized opcodes whose symbolic names start + * with REBASE_OPCODE_. + * Conceptually the rebase information is a table of tuples: + * + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like "every n'th offset for m times" can be encoded in a few + * bytes. + */ + TYP(rebase_off,4); /* file offset to rebase info */ + TYP(rebase_size,4); /* size of rebase info */ + + /* + * Dyld binds an image during the loading process, if the image + * requires any pointers to be initialized to symbols + * in other images. + * The bind information is a stream of byte sized + * opcodes whose symbolic names start with BIND_OPCODE_. + * Conceptually the bind information is a table of tuples: + * + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like for runs of pointers initialzed to the same value can be + * encoded in a few bytes. + */ + TYP(bind_off,4); /* file offset to binding info */ + TYP(bind_size,4); /* size of binding info */ + + /* + * Some C++ programs require dyld to unique symbols so that all + * images in the process use the same copy of some code/data. + * This step is done after binding. The content of the weak_bind + * info is an opcode stream like the bind_info. But it is sorted + * alphabetically by symbol name. This enable dyld to walk + * all images with weak binding information in order and look + * for collisions. If there are no collisions, dyld does + * no updating. That means that some fixups are also encoded + * in the bind_info. For instance, all calls to "operator new" + * are first bound to libstdc++.dylib using the information + * in bind_info. Then if some image overrides operator new + * that is detected when the weak_bind information is processed + * and the call to operator new is then rebound. + */ + TYP(weak_bind_off,4); /* file offset to weak binding info */ + TYP(weak_bind_size,4); /* size of weak binding info */ + + /* + * Some uses of external symbols do not need to be + * bound immediately. + * Instead they can be lazily bound on first use. The lazy_bind + * are contains a stream of BIND opcodes to bind all lazy symbols. + * Normal use is that dyld ignores the lazy_bind section when + * loading an image. Instead the static linker arranged for the + * lazy pointer to initially point to a helper function which + * pushes the offset into the lazy_bind area for the symbol + * needing to be bound, then jumps to dyld which simply adds + * the offset to lazy_bind_off to get the information on what + * to bind. + */ + TYP(lazy_bind_off,4); /* file offset to lazy binding info */ + TYP(lazy_bind_size,4); /* size of lazy binding infs */ + + /* + * The symbols exported by a dylib are encoded in a trie. This + * is a compact representation that factors out common prefixes. + * It also reduces LINKEDIT pages in RAM because it encodes all + * information (name, address, flags) in one + * small, contiguous range. + * The export area is a stream of nodes. + * The first node sequentially + * is the start node for the trie. + * + * Nodes for a symbol start with a uleb128 that is the length of + * the exported symbol information for the string so far. + * If there is no exported symbol, the node starts with + * a zero byte. + * If there is exported info, it follows the length. + * + * First is a uleb128 containing flags. Normally, it is followed by + * a uleb128 encoded offset which is location of the content named + * by the symbol from the mach_header for the image. If the flags + * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is + * a uleb128 encoded library ordinal, then a zero terminated + * UTF8 string. If the string is zero length, then the symbol + * is re-export from the specified dylib with the same name. + * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, + * then following + * the flags is two uleb128s: the stub offset and + * the resolver offset. + * The stub is used by non-lazy pointers. The resolver is used + * by lazy pointers and must be called to get + * the actual address to use. + * + * After the optional exported symbol information is a byte of + * how many edges (0-255) that this node has leaving it, + * followed by each edge. + * Each edge is a zero terminated UTF8 of the addition chars + * in the symbol, followed by a uleb128 offset for the node that + * edge points to. + * + */ + TYP(export_off,4); /* file offset to lazy binding info */ + TYP(export_size,4); /* size of lazy binding infs */ +}; + +/* +* The following are used to encode rebasing information +*/ +#define REBASE_TYPE_POINTER 1 +#define REBASE_TYPE_TEXT_ABSOLUTE32 2 +#define REBASE_TYPE_TEXT_PCREL32 3 + +#define REBASE_OPCODE_MASK 0xF0 +#define REBASE_IMMEDIATE_MASK 0x0F +#define REBASE_OPCODE_DONE 0x00 +#define REBASE_OPCODE_SET_TYPE_IMM 0x10 +#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 +#define REBASE_OPCODE_ADD_ADDR_ULEB 0x30 +#define REBASE_OPCODE_ADD_ADDR_IMM_SCALED 0x40 +#define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES 0x60 +#define REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB 0x70 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB 0x80 + +/* +* The following are used to encode binding information +*/ +#define BIND_TYPE_POINTER 1 +#define BIND_TYPE_TEXT_ABSOLUTE32 2 +#define BIND_TYPE_TEXT_PCREL32 3 + +#define BIND_SPECIAL_DYLIB_SELF 0 +#define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1 +#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 + +#define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 +#define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8 + +#define BIND_OPCODE_MASK 0xF0 +#define BIND_IMMEDIATE_MASK 0x0F +#define BIND_OPCODE_DONE 0x00 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20 +#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 +#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 +#define BIND_OPCODE_SET_TYPE_IMM 0x50 +#define BIND_OPCODE_SET_ADDEND_SLEB 0x60 +#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 +#define BIND_OPCODE_ADD_ADDR_ULEB 0x80 +#define BIND_OPCODE_DO_BIND 0x90 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0 +#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0 + +/* +* The following are used on the flags byte of a terminal node +* in the export information. +*/ +#define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03 +#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 +#define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01 +#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 +#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 +#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 + +/* +* The linker_option_command contains linker +* options embedded in object files. +*/ +struct linker_option_command { + TYP(cmd,4); /* LC_LINKER_OPTION only used in MH_OBJECT filetypes*/ + TYP(cmdsize,4); + TYP(count,4); /* number of strings */ + /* concatenation of zero terminated UTF8 strings. + Zero filled at end to align */ +}; + +/* +* The symseg_command contains the offset and size of the GNU style +* symbol table information as described in the header file . +* The symbol roots of the symbol segments must +* also be aligned properly +* in the file. So the requirement of keeping the offsets aligned to a +* multiple of a 4 bytes translates to the length field of the symbol +* roots also being a multiple of a long. +* Also the padding must again be +* zeroed. (THIS IS OBSOLETE and no longer supported). +*/ +struct symseg_command { + TYP(cmd,4); /* LC_SYMSEG */ + TYP(cmdsize,4); /* sizeof(struct symseg_command) */ + TYP(offset,4); /* symbol segment offset */ + TYP(size,4); /* symbol segment size in bytes */ +}; + +/* +* The ident_command contains a free format string table following the +* ident_command structure. +* The strings are null terminated and the size of +* the command is padded out with zero bytes to a multiple of 4 bytes/ +* (THIS IS OBSOLETE and no longer supported). +*/ +struct ident_command { + TYP(cmd,4); /* LC_IDENT */ + TYP(cmdsize,4); /* strings that follow this command */ +}; + +/* +* The fvmfile_command contains a reference to a +* file to be loaded at the +* specified virtual address. (Presently, this command is +* reserved for internal use. The kernel ignores +* this command when loading a program into +* memory). +*/ +struct fvmfile_command { + TYP(cmd,4); /* LC_FVMFILE */ + TYP(cmdsize,4); /* includes pathname string */ + union lc_str name; /* files pathname */ + TYP(header_addr,4); /* files virtual address */ +}; + +/* +* The entry_point_command is a replacement for thread_command. +* It is used for main executables to specify the +* location (file offset) +* of main(). If -stack_size was used at link time, the stacksize +* field will contain the stack size need for the main thread. +*/ +struct entry_point_command { + TYP(cmd,4); /* LC_MAIN only used in MH_EXECUTE filetypes */ + TYP(cmdsize,4); /* 24 */ + TYP(entryoff,8); /* file (__TEXT) offset of main() */ + TYP(stacksize,8); /* if not zero, initial stack size */ +}; + +/* +* The source_version_command is an optional load command containing +* the version of the sources used to build the binary. +*/ +struct source_version_command { + TYP(cmd,4); /* LC_SOURCE_VERSION */ + TYP(cmdsize,4); /* 16 */ + TYP(version,8); /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */ +}; + +/* +* The LC_DATA_IN_CODE load commands uses a linkedit_data_command +* to point to an array of data_in_code_entry entries. Each entry +* describes a range of data in a code section. +*/ +struct data_in_code_entry { + TYP(offset,4); /* from mach_header to start of data range*/ + TYP(length,2); /* number of bytes in data range */ + TYP(kind,2); /* a DICE_KIND_* value */ +}; +#define DICE_KIND_DATA 0x0001 +#define DICE_KIND_JUMP_TABLE8 0x0002 +#define DICE_KIND_JUMP_TABLE16 0x0003 +#define DICE_KIND_JUMP_TABLE32 0x0004 +#define DICE_KIND_ABS_JUMP_TABLE32 0x0005 + +/* +* Sections of type S_THREAD_LOCAL_VARIABLES contain an array +* of tlv_descriptor structures. +*/ +struct tlv_descriptor +{ + void* (*thunk)(struct tlv_descriptor*); + unsigned long key; + unsigned long offset; +}; +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* MACHO_LOADER_H */ diff --git a/src/lib/libdwarf/dwarf_machoread.c b/src/lib/libdwarf/dwarf_machoread.c new file mode 100644 index 0000000..4633500 --- /dev/null +++ b/src/lib/libdwarf/dwarf_machoread.c @@ -0,0 +1,1427 @@ +/* +Copyright (c) 2019, David Anderson All rights reserved. +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* This file reads the parts of an Apple mach-o object + file appropriate to reading DWARF debugging data. + Overview: + _dwarf_macho_setup() Does all macho setup. + calls _dwarf_macho_access_init() + calls _dwarf_macho_object_access_internals_init() + Creates internals record 'M', + dwarf_macho_object_access_internals_t + Sets flags/data in internals record + Loads macho object data needed later. + Sets methods struct to access macho object. + calls _dwarf_object_init_b() Creates Dwarf_Debug, independent + of any macho code. + Sets internals record into dbg. + ---------------------- + _dwarf_destruct_macho_access(). This frees + the macho internals record created in + _dwarf_macho_object_access_internals_init() + in case of errors during setup or when + dwarf_finish() is called. Works safely for + partially or fully set-up macho internals record. + + Other than in _dwarf_macho_setup() the macho code + knows nothing about Dwarf_Debug, and the rest of + libdwarf knows nothing about the content of the + macho internals record. + +*/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif /* _WIN32 */ + +#include + +#include /* calloc() free() malloc() */ +#include /* memcpy() memset() strcmp() strdup() */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* close() */ +#elif defined HAVE_UNISTD_H +#include /* close() */ +#endif /* _WIN32 */ + +#include /* debugging printf */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" /* for _dwarf_error() declaration */ +#include "dwarf_reading.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_object_read_common.h" +#include "dwarf_universal.h" +#include "dwarf_machoread.h" +#include "dwarf_object_detector.h" +#include "dwarf_macho_loader.h" + +#if 0 +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* MACH-O and dwarf section names */ +static struct macho_sect_names_s { + char const *ms_moname; + char const *ms_dwname; +} const SectionNames [] = { + { "", "" }, /* ELF index-0 entry */ + { "__debug_abbrev", ".debug_abbrev" }, + { "__debug_aranges", ".debug_aranges" }, + { "__debug_frame", ".debug_frame" }, + { "__debug_info", ".debug_info" }, + { "__debug_line", ".debug_line" }, + { "__debug_macinfo", ".debug_macinfo" }, + { "__debug_loc", ".debug_loc" }, + { "__debug_pubnames", ".debug_pubnames" }, + { "__debug_pubtypes", ".debug_pubtypes" }, + { "__debug_str", ".debug_str" }, + { "__debug_ranges", ".debug_ranges" }, + { "__debug_macro", ".debug_macro" }, + { "__debug_gdb_scri", ".debug_gdb_scripts" } +}; + +static int +_dwarf_object_detector_universal_head_fd( + int fd, + Dwarf_Unsigned dw_filesize, + unsigned int *dw_contentcount, + Dwarf_Universal_Head * dw_head, + int *errcode); + +static int _dwarf_macho_object_access_init( + int fd, + unsigned uninumber, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + unsigned * universalbinary_count, + Dwarf_Unsigned filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum); + +static Dwarf_Small macho_get_byte_order (void *obj) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + return macho->mo_endian; +} + +static Dwarf_Small macho_get_length_size (void *obj) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + return macho->mo_offsetsize/8; +} + +static Dwarf_Small macho_get_pointer_size (void *obj) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + return macho->mo_pointersize/8; +} +static Dwarf_Unsigned macho_get_file_size (void *obj) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + return macho->mo_filesize; +} + +static Dwarf_Unsigned macho_get_section_count (void *obj) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + return macho->mo_dwarf_sectioncount; +} + +static int macho_get_section_info (void *obj, + Dwarf_Unsigned section_index, + Dwarf_Obj_Access_Section_a *return_section, + int *error) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + + (void)error; + if (section_index < macho->mo_dwarf_sectioncount) { + struct generic_macho_section *sp = 0; + + sp = macho->mo_dwarf_sections + section_index; + return_section->as_name = sp->dwarfsectname; + return_section->as_type = 0; + return_section->as_flags = 0; + return_section->as_addr = 0; + return_section->as_offset = 0; + return_section->as_size = sp->size; + return_section->as_link = 0; + return_section->as_info = 0; + return_section->as_addralign = 0; + return_section->as_entrysize = 0; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static int +macho_load_section (void *obj, Dwarf_Unsigned section_index, + Dwarf_Small **return_data, int *error) +{ + dwarf_macho_object_access_internals_t *macho = + (dwarf_macho_object_access_internals_t*)(obj); + + if (0 < section_index && + section_index < macho->mo_dwarf_sectioncount) { + int res = 0; + Dwarf_Unsigned inner = macho->mo_inner_offset; + + struct generic_macho_section *sp = + macho->mo_dwarf_sections + section_index; + if (sp->loaded_data) { + *return_data = sp->loaded_data; + return DW_DLV_OK; + } + if (!sp->size) { + return DW_DLV_NO_ENTRY; + } + if ((sp->size + sp->offset) > + macho->mo_filesize) { + *error = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + + sp->loaded_data = malloc((size_t)sp->size); + if (!sp->loaded_data) { + *error = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = RRMOA(macho->mo_fd, + sp->loaded_data, (off_t)(inner+sp->offset), + (size_t)sp->size, + (off_t)(inner+macho->mo_filesize), error); + if (res != DW_DLV_OK) { + free(sp->loaded_data); + sp->loaded_data = 0; + return res; + } + *return_data = sp->loaded_data; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static void +_dwarf_destruct_macho_internals( + dwarf_macho_object_access_internals_t *mp) +{ + Dwarf_Unsigned i = 0; + + if (mp->mo_destruct_close_fd) { + close(mp->mo_fd); + mp->mo_fd = -1; + } + if (mp->mo_commands){ + free(mp->mo_commands); + mp->mo_commands = 0; + } + if (mp->mo_segment_commands){ + free(mp->mo_segment_commands); + mp->mo_segment_commands = 0; + } + free((char *)mp->mo_path); + if (mp->mo_dwarf_sections) { + struct generic_macho_section *sp = 0; + + sp = mp->mo_dwarf_sections; + for ( i=0; i < mp->mo_dwarf_sectioncount; ++i,++sp) { + if (sp->loaded_data) { + free(sp->loaded_data); + sp->loaded_data = 0; + } + } + free(mp->mo_dwarf_sections); + mp->mo_dwarf_sections = 0; + } + free(mp); + return; +} +void +_dwarf_destruct_macho_access( + struct Dwarf_Obj_Access_Interface_a_s *aip) +{ + dwarf_macho_object_access_internals_t *mp = 0; + + if (!aip) { + return; + } + mp = (dwarf_macho_object_access_internals_t *)aip->ai_object; + _dwarf_destruct_macho_internals(mp); + aip->ai_object = 0; + free(aip); + return; +} + +/* load_macho_header32(dwarf_macho_object_access_internals_t *mfp)*/ +static int +load_macho_header32(dwarf_macho_object_access_internals_t *mfp, + int *errcode) +{ + struct mach_header mh32; + int res = 0; + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + if (sizeof(mh32) > mfp->mo_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = RRMOA(mfp->mo_fd, &mh32, inner, sizeof(mh32), + (off_t)(inner+mfp->mo_filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + /* Do not adjust endianness of magic, leave as-is. */ + ASNAR(memcpy,mfp->mo_header.magic,mh32.magic); + ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh32.cputype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype, + mh32.cpusubtype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh32.filetype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh32.ncmds); + ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds, + mh32.sizeofcmds); + ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh32.flags); + mfp->mo_header.reserved = 0; + mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds; + if (mfp->mo_command_count >= mfp->mo_filesize || + mfp->mo_header.sizeofcmds >= mfp->mo_filesize || + mfp->mo_command_count >= mfp->mo_header.sizeofcmds) { + *errcode = DW_DLE_MACHO_CORRUPT_HEADER; + return DW_DLV_ERROR; + } + + mfp->mo_command_start_offset = sizeof(mh32); + return DW_DLV_OK; +} + +/* load_macho_header64(dwarf_macho_object_access_internals_t *mfp) */ +static int +load_macho_header64(dwarf_macho_object_access_internals_t *mfp, + int *errcode) +{ + struct mach_header_64 mh64; + int res = 0; + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + if (sizeof(mh64) > mfp->mo_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = RRMOA(mfp->mo_fd, &mh64, inner, sizeof(mh64), + (off_t)(inner+mfp->mo_filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + /* Do not adjust endianness of magic, leave as-is. */ + ASNAR(memcpy,mfp->mo_header.magic,mh64.magic); + ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh64.cputype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype, + mh64.cpusubtype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh64.filetype); + ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh64.ncmds); + ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds, + mh64.sizeofcmds); + ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh64.flags); + ASNAR(mfp->mo_copy_word,mfp->mo_header.reserved,mh64.reserved); + mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds; + if (mfp->mo_command_count >= mfp->mo_filesize || + mfp->mo_header.sizeofcmds >= mfp->mo_filesize || + mfp->mo_command_count >= mfp->mo_header.sizeofcmds) { + *errcode = DW_DLE_MACHO_CORRUPT_HEADER; + return DW_DLV_ERROR; + } + mfp->mo_command_start_offset = sizeof(mh64); + return DW_DLV_OK; +} + +int +_dwarf_load_macho_header(dwarf_macho_object_access_internals_t *mfp, + int *errcode) +{ + int res = 0; + + if (mfp->mo_offsetsize == 32) { + res = load_macho_header32(mfp,errcode); + } else if (mfp->mo_offsetsize == 64) { + res = load_macho_header64(mfp,errcode); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + return res; +} + +static int +load_segment_command_content32( + dwarf_macho_object_access_internals_t *mfp, + struct generic_macho_command *mmp, + struct generic_macho_segment_command *msp, + Dwarf_Unsigned mmpindex, + int *errcode) +{ + struct segment_command sc; + int res = 0; + Dwarf_Unsigned filesize = mfp->mo_filesize; + Dwarf_Unsigned segoffset = mmp->offset_this_command; + Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + if (segoffset > filesize || + mmp->cmdsize > filesize || + (mmp->cmdsize + segoffset) > filesize ) { + *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; + return DW_DLV_ERROR; + } + res = RRMOA(mfp->mo_fd, &sc, (off_t)(inner+segoffset), + sizeof(sc), (off_t)(inner+filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd); + ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize); + _dwarf_safe_strcpy(msp->segname, + sizeof(msp->segname), + sc.segname,sizeof(sc.segname)); + ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr); + ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize); + ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff); + ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize); + if (msp->fileoff > mfp->mo_filesize || + msp->filesize > mfp->mo_filesize) { + /* corrupt */ + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + if ((msp->fileoff+msp->filesize ) > filesize) { + /* corrupt */ + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot); + ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot); + ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects); + if (msp->nsects >= mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + ASNAR(mfp->mo_copy_word,msp->flags,sc.flags); + msp->macho_command_index = mmpindex; + msp->sectionsoffset = afterseghdr; + return DW_DLV_OK; +} + +static int +load_segment_command_content64( + dwarf_macho_object_access_internals_t *mfp, + struct generic_macho_command *mmp, + struct generic_macho_segment_command *msp, + Dwarf_Unsigned mmpindex,int *errcode) +{ + struct segment_command_64 sc; + int res = 0; + Dwarf_Unsigned filesize = mfp->mo_filesize; + Dwarf_Unsigned segoffset = mmp->offset_this_command; + Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + if (segoffset > filesize || + mmp->cmdsize > filesize || + (mmp->cmdsize + segoffset) > filesize ) { + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + res = RRMOA(mfp->mo_fd,&sc,inner+segoffset, + sizeof(sc), (off_t)(inner+filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd); + ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize); + _dwarf_safe_strcpy(msp->segname,sizeof(msp->segname), + sc.segname,sizeof(sc.segname)); + ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr); + ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize); + ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff); + ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize); + if (msp->fileoff > filesize || + msp->filesize > filesize) { + /* corrupt */ + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + if ((msp->fileoff+msp->filesize ) > filesize) { + /* corrupt */ + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot); + ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot); + ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects); + if (msp->nsects >= mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_COMMAND; + return DW_DLV_ERROR; + } + ASNAR(mfp->mo_copy_word,msp->flags,sc.flags); + msp->macho_command_index = mmpindex; + msp->sectionsoffset = afterseghdr; + return DW_DLV_OK; +} + +static int +_dwarf_macho_load_segment_commands( + dwarf_macho_object_access_internals_t *mfp,int *errcode) +{ + Dwarf_Unsigned i = 0; + struct generic_macho_command *mmp = 0; + struct generic_macho_segment_command *msp = 0; + + if (mfp->mo_segment_count < 1) { + return DW_DLV_OK; + } + mfp->mo_segment_commands = + (struct generic_macho_segment_command *) + calloc(sizeof(struct generic_macho_segment_command), + (size_t)mfp->mo_segment_count); + if (!mfp->mo_segment_commands) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + + mmp = mfp->mo_commands; + msp = mfp->mo_segment_commands; + for (i = 0 ; i < mfp->mo_command_count; ++i,++mmp) { + unsigned cmd = (unsigned)mmp->cmd; + int res = 0; + + if (cmd == LC_SEGMENT) { + res = load_segment_command_content32(mfp,mmp,msp, + i,errcode); + ++msp; + } else if (cmd == LC_SEGMENT_64) { + res = load_segment_command_content64(mfp,mmp,msp, + i,errcode); + ++msp; + } else { /* fall through, not a command of interest */ } + if (res != DW_DLV_OK) { + free(mfp->mo_segment_commands); + mfp->mo_segment_commands = 0; + return res; + } + } + return DW_DLV_OK; +} + +static int +_dwarf_macho_load_dwarf_section_details32( + dwarf_macho_object_access_internals_t *mfp, + struct generic_macho_segment_command *segp, + Dwarf_Unsigned segi, int *errcode) +{ + Dwarf_Unsigned seci = 0; + Dwarf_Unsigned seccount = segp->nsects; + Dwarf_Unsigned secalloc = seccount+1; + Dwarf_Unsigned curoff = segp->sectionsoffset; + Dwarf_Unsigned shdrlen = sizeof(struct section); + + struct generic_macho_section *secs = 0; + + secs = (struct generic_macho_section *)calloc( + sizeof(struct generic_macho_section), + (size_t)secalloc); + if (!secs) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_OK; + } + mfp->mo_dwarf_sections = secs; + mfp->mo_dwarf_sectioncount = secalloc; + if ((curoff > mfp->mo_filesize) || + (seccount > mfp->mo_filesize) || + (curoff+(seccount*sizeof(struct section)) > + mfp->mo_filesize)) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + secs->offset_of_sec_rec = curoff; + /* Leave 0 section all zeros except our offset, + elf-like in a sense */ + secs->dwarfsectname = ""; + ++secs; + seci = 1; + for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) { + struct section mosec; + int res = 0; + Dwarf_Unsigned endoffset = 0; + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + endoffset = curoff + sizeof(mosec); + if (curoff >= mfp->mo_filesize || + endoffset > mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS; + return DW_DLV_ERROR; + } + res = RRMOA(mfp->mo_fd, &mosec, + (off_t)(inner+curoff), sizeof(mosec), + (off_t)(inner+mfp->mo_filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + _dwarf_safe_strcpy(secs->sectname, + sizeof(secs->sectname), + mosec.sectname,sizeof(mosec.sectname)); + _dwarf_safe_strcpy(secs->segname, + sizeof(secs->segname), + mosec.segname,sizeof(mosec.segname)); + ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr); + ASNAR(mfp->mo_copy_word,secs->size,mosec.size); + ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset); + ASNAR(mfp->mo_copy_word,secs->align,mosec.align); + ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff); + ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc); + ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags); + if (secs->offset > mfp->mo_filesize || + secs->size > mfp->mo_filesize || + (secs->offset+secs->size) > mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS; + return DW_DLV_ERROR; + } + secs->reserved1 = 0; + secs->reserved2 = 0; + secs->reserved3 = 0; + secs->generic_segment_num = segi; + secs->offset_of_sec_rec = curoff; + } + return DW_DLV_OK; +} +static int +_dwarf_macho_load_dwarf_section_details64( + dwarf_macho_object_access_internals_t *mfp, + struct generic_macho_segment_command *segp, + Dwarf_Unsigned segi, + int *errcode) +{ + Dwarf_Unsigned seci = 0; + Dwarf_Unsigned seccount = segp->nsects; + Dwarf_Unsigned secalloc = seccount+1; + Dwarf_Unsigned curoff = segp->sectionsoffset; + Dwarf_Unsigned shdrlen = sizeof(struct section_64); + struct generic_macho_section *secs = 0; + + secs = (struct generic_macho_section *)calloc( + sizeof(struct generic_macho_section), + (size_t)secalloc); + if (!secs) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + mfp->mo_dwarf_sections = secs; + mfp->mo_dwarf_sectioncount = secalloc; + secs->offset_of_sec_rec = curoff; + /* Leave 0 section all zeros except our offset, + elf-like in a sense */ + secs->dwarfsectname = ""; + ++secs; + if ((curoff > mfp->mo_filesize) || + (seccount > mfp->mo_filesize) || + (curoff+(seccount*sizeof(struct section_64)) > + mfp->mo_filesize)) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + seci = 1; + for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) { + int res = 0; + struct section_64 mosec; + Dwarf_Unsigned endoffset = 0; + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + endoffset = curoff + sizeof(mosec); + if (curoff >= mfp->mo_filesize || + endoffset > mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS; + return DW_DLV_ERROR; + } + + res = RRMOA(mfp->mo_fd, &mosec, + (off_t)(inner+curoff), sizeof(mosec), + (off_t)(inner+mfp->mo_filesize), errcode); + if (res != DW_DLV_OK) { + return res; + } + _dwarf_safe_strcpy(secs->sectname, + sizeof(secs->sectname), + mosec.sectname,sizeof(mosec.sectname)); + _dwarf_safe_strcpy(secs->segname, + sizeof(secs->segname), + mosec.segname,sizeof(mosec.segname)); + ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr); + ASNAR(mfp->mo_copy_word,secs->size,mosec.size); + ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset); + ASNAR(mfp->mo_copy_word,secs->align,mosec.align); + ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff); + ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc); + ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags); + if (secs->offset > mfp->mo_filesize || + secs->size > mfp->mo_filesize || + (secs->offset+secs->size) > mfp->mo_filesize) { + *errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS; + return DW_DLV_ERROR; + } + secs->reserved1 = 0; + secs->reserved2 = 0; + secs->reserved3 = 0; + secs->offset_of_sec_rec = curoff; + secs->generic_segment_num = segi; + } + return DW_DLV_OK; +} + +static int +_dwarf_macho_load_dwarf_section_details( + dwarf_macho_object_access_internals_t *mfp, + struct generic_macho_segment_command *segp, + Dwarf_Unsigned segi,int *errcode) +{ + int res = 0; + + if (mfp->mo_offsetsize == 32) { + res = _dwarf_macho_load_dwarf_section_details32(mfp, + segp,segi,errcode); + } else if (mfp->mo_offsetsize == 64) { + res = _dwarf_macho_load_dwarf_section_details64(mfp, + segp,segi,errcode); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + return res; +} + +static int +_dwarf_macho_load_dwarf_sections( + dwarf_macho_object_access_internals_t *mfp,int *errcode) +{ + Dwarf_Unsigned segi = 0; + + struct generic_macho_segment_command *segp = + mfp->mo_segment_commands; + for ( ; segi < mfp->mo_segment_count; ++segi,++segp) { + int res = 0; + + if (strcmp(segp->segname,"__DWARF")) { + continue; + } + /* Found DWARF, for now assume only one such. */ + res = _dwarf_macho_load_dwarf_section_details(mfp, + segp,segi,errcode); + return res; + } + return DW_DLV_OK; +} + +/* Works the same, 32 or 64 bit */ +int +_dwarf_load_macho_commands( + dwarf_macho_object_access_internals_t *mfp,int *errcode) +{ + Dwarf_Unsigned cmdi = 0; + Dwarf_Unsigned curoff = mfp->mo_command_start_offset; + struct load_command mc; + struct generic_macho_command *mcp = 0; + unsigned segment_command_count = 0; + int res = 0; + Dwarf_Unsigned inner = mfp->mo_inner_offset; + + if (mfp->mo_command_count >= mfp->mo_filesize) { + /* corrupt object. */ + *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; + return DW_DLV_ERROR; + } + if ((curoff + mfp->mo_command_count * sizeof(mc)) >= + mfp->mo_filesize) { + /* corrupt object. */ + *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; + return DW_DLV_ERROR; + } + + mfp->mo_commands = (struct generic_macho_command *) calloc( + mfp->mo_command_count,sizeof(struct generic_macho_command)); + if (!mfp->mo_commands) { + /* out of memory */ + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + mcp = mfp->mo_commands; + for ( ; cmdi < mfp->mo_header.ncmds; ++cmdi,++mcp ) { + res = RRMOA(mfp->mo_fd, &mc, + (off_t)(inner+curoff), sizeof(mc), + (off_t)(inner+mfp->mo_filesize), errcode); + if (res != DW_DLV_OK) { + free(mfp->mo_commands); + mfp->mo_commands = 0; + return res; + } + ASNAR(mfp->mo_copy_word,mcp->cmd,mc.cmd); + ASNAR(mfp->mo_copy_word,mcp->cmdsize,mc.cmdsize); + mcp->offset_this_command = curoff; + curoff += mcp->cmdsize; + if (mcp->cmdsize > mfp->mo_filesize || + curoff > mfp->mo_filesize) { + /* corrupt object */ + free(mfp->mo_commands); + mfp->mo_commands = 0; + *errcode = DW_DLE_FILE_OFFSET_BAD; + return DW_DLV_ERROR; + } + if (mcp->cmd == LC_SEGMENT || mcp->cmd == LC_SEGMENT_64) { + segment_command_count++; + } + } + mfp->mo_segment_count = segment_command_count; + res = _dwarf_macho_load_segment_commands(mfp,errcode); + if (res != DW_DLV_OK) { + free(mfp->mo_commands); + mfp->mo_commands = 0; + return res; + } + res = _dwarf_macho_load_dwarf_sections(mfp,errcode); + if (res != DW_DLV_OK) { + free(mfp->mo_commands); + mfp->mo_commands = 0; + } + return res; +} +int +_dwarf_macho_setup(int fd, + char *true_path, + unsigned universalnumber, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + Dwarf_Unsigned filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error) +{ + Dwarf_Obj_Access_Interface_a *binary_interface = 0; + dwarf_macho_object_access_internals_t *intfc = 0; + int res = DW_DLV_OK; + int localerrnum = 0; + unsigned universalbinary_count = 0; + + res = _dwarf_macho_object_access_init( + fd, + universalnumber, + ftype,endian,offsetsize, + &universalbinary_count, + filesize, + &binary_interface, + &localerrnum); + if (res != DW_DLV_OK) { + if (res == DW_DLV_NO_ENTRY) { + return res; + } + _dwarf_error(NULL, error, localerrnum); + return DW_DLV_ERROR; + } + /* allocates and initializes Dwarf_Debug, + generic code */ + res = dwarf_object_init_b(binary_interface, errhand, errarg, + groupnumber, dbg, error); + if (res != DW_DLV_OK){ + _dwarf_destruct_macho_access(binary_interface); + return res; + } + intfc = binary_interface->ai_object; + intfc->mo_path = strdup(true_path); + (*dbg)->de_universalbinary_index = universalnumber; + (*dbg)->de_universalbinary_count = universalbinary_count; + return res; +} + +static Dwarf_Obj_Access_Methods_a const macho_methods = { + macho_get_section_info, + macho_get_byte_order, + macho_get_length_size, + macho_get_pointer_size, + macho_get_file_size, + macho_get_section_count, + macho_load_section, + /* We do not do macho relocations. + dsym files do not require it. */ + NULL +}; + +/* Reads universal binary headers, gets to + the chosen inner binary, and returns the + values from the inner binary. + The filesize being that of the inner binary, + and the fileoffset being the offset of the inner + binary (so by definition > 0); +*/ + +static int +_dwarf_macho_inner_object_fd(int fd, + unsigned int uninumber, + Dwarf_Unsigned outer_filesize, + unsigned int *ftype, + unsigned int *unibinarycount, + unsigned int *endian, + unsigned int *offsetsize, + Dwarf_Unsigned *fileoffset, + Dwarf_Unsigned *filesize, + int *errcode) +{ + int res = 0; + Dwarf_Universal_Head head = 0; + Dwarf_Unsigned innerbase = 0; + Dwarf_Unsigned innersize = 0; + + res = _dwarf_object_detector_universal_head_fd( + fd, outer_filesize, unibinarycount, + &head, errcode); + if (res != DW_DLV_OK) { + return res; + } + if (uninumber >= *unibinarycount) { + *errcode = DW_DLE_UNIVERSAL_BINARY_ERROR; + _dwarf_dealloc_universal_head(head); + return DW_DLV_ERROR; + } + /* Now find the precise details of uninumber + instance we want */ + + innerbase = head->au_arches[uninumber].au_offset; + innersize = head->au_arches[uninumber].au_size; + if (innersize >= outer_filesize || + innerbase >= outer_filesize) { + *errcode = DW_DLE_UNIVERSAL_BINARY_ERROR; + _dwarf_dealloc_universal_head(head); + return DW_DLV_ERROR; + } + /* Now access inner to return its specs */ + { + /* But ignore the size this returns! + we determined that above. the following call + does not get the inner size, we got that + just above here! */ + Dwarf_Unsigned fake_size = 0; + + res = _dwarf_object_detector_fd_a(fd, + ftype,endian,offsetsize,innerbase,&fake_size, + errcode); + if (res != DW_DLV_OK) { + _dwarf_dealloc_universal_head(head); + return res; + } + } + *fileoffset = innerbase; + *filesize = innersize; + _dwarf_dealloc_universal_head(head); + return DW_DLV_OK; +} + +/* On any error this frees internals argument. */ +static int +_dwarf_macho_object_access_internals_init( + dwarf_macho_object_access_internals_t * internals, + int fd, + unsigned uninumber, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + unsigned *unibinarycount, + Dwarf_Unsigned filesize, + int *errcode) +{ + Dwarf_Unsigned i = 0; + struct generic_macho_section *sp = 0; + int res = 0; + unsigned int ftypei = ftype; + unsigned int endiani = endian; + unsigned int offsetsizei = offsetsize; + Dwarf_Unsigned filesizei = filesize; + Dwarf_Unsigned fileoffseti = 0; + unsigned int unibinarycounti = 0; + + if (ftype == DW_FTYPE_APPLEUNIVERSAL) { + res = _dwarf_macho_inner_object_fd(fd, + uninumber, + filesize, + &ftypei,&unibinarycounti,&endiani, + &offsetsizei,&fileoffseti,&filesizei,errcode); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR) { + } + return res; + } + *unibinarycount = unibinarycounti; + endian = endiani; + } + + internals->mo_ident[0] = 'M'; + internals->mo_ident[1] = '1'; + internals->mo_fd = fd; + internals->mo_offsetsize = offsetsizei; + internals->mo_pointersize = offsetsizei; + internals->mo_inner_offset = fileoffseti; + internals->mo_filesize = filesizei; + internals->mo_ftype = ftypei; + internals->mo_uninumber = uninumber; + internals->mo_universal_count = unibinarycounti; + +#ifdef WORDS_BIGENDIAN + if (endian == DW_END_little ) { + internals->mo_copy_word = _dwarf_memcpy_swap_bytes; + internals->mo_endian = DW_END_little; + } else { + internals->mo_copy_word = _dwarf_memcpy_noswap_bytes; + internals->mo_endian = DW_END_big; + } +#else /* LITTLE ENDIAN */ + if (endian == DW_END_little ) { + internals->mo_copy_word = _dwarf_memcpy_noswap_bytes; + internals->mo_endian = DW_END_little; + } else { + internals->mo_copy_word = _dwarf_memcpy_swap_bytes; + internals->mo_endian = DW_END_big; + } +#endif /* LITTLE- BIG-ENDIAN */ + res = _dwarf_load_macho_header(internals,errcode); + if (res != DW_DLV_OK) { + return res; + } + /* Load sections */ + res = _dwarf_load_macho_commands(internals,errcode); + if (res != DW_DLV_OK) { + return res; + } + if (internals->mo_dwarf_sections) { + sp = internals->mo_dwarf_sections+1; + } else { + /* There are no dwarf sections, + count better be zero. */ + if (internals->mo_dwarf_sectioncount) { + *errcode = DW_DLE_MACHO_CORRUPT_HEADER; + return DW_DLV_ERROR; + } + } + for (i = 1; i < internals->mo_dwarf_sectioncount ; ++i,++sp) { + int j = 1; + int lim = sizeof(SectionNames)/sizeof(SectionNames[0]); + sp->dwarfsectname = ""; + for ( ; j < lim; ++j) { + if (!strcmp(sp->sectname,SectionNames[j].ms_moname)) { + sp->dwarfsectname = SectionNames[j].ms_dwname; + break; + } + } + } + return DW_DLV_OK; +} + +static int +_dwarf_macho_object_access_init( + int fd, + unsigned uninumber, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + unsigned * universalbinary_count, + Dwarf_Unsigned filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum) +{ + int res = 0; + dwarf_macho_object_access_internals_t *internals = 0; + Dwarf_Obj_Access_Interface_a *intfc = 0; + + internals = malloc( + sizeof(dwarf_macho_object_access_internals_t)); + if (!internals) { + *localerrnum = DW_DLE_ALLOC_FAIL; + /* Impossible case, we hope. Give up. */ + return DW_DLV_ERROR; + } + memset(internals,0,sizeof(*internals)); + res = _dwarf_macho_object_access_internals_init(internals, + fd, + uninumber, + ftype, endian, offsetsize, + universalbinary_count, + filesize, + localerrnum); + if (res != DW_DLV_OK){ + _dwarf_destruct_macho_internals(internals); + return DW_DLV_ERROR; + } + intfc = malloc(sizeof(Dwarf_Obj_Access_Interface_a)); + if (!intfc) { + /* Impossible case, we hope. Give up. */ + _dwarf_destruct_macho_internals(internals); + *localerrnum = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + /* Initialize the interface struct */ + intfc->ai_object = internals; + intfc->ai_methods = &macho_methods; + *binary_interface = intfc; + return DW_DLV_OK; +} + +static unsigned long +magic_copy(unsigned char *d, unsigned len) +{ + unsigned i = 0; + unsigned long v = 0; + + v = d[0]; + for (i = 1 ; i < len; ++i) { + v <<= 8; + v |= d[i]; + } + return v; +} + +static int +fill_in_uni_arch_32( + struct fat_arch * fa, + struct Dwarf_Universal_Head_s *duhd, + void (*word_swap) (void *, const void *, unsigned long), + int *errcode) +{ + Dwarf_Unsigned i = 0; + struct Dwarf_Universal_Arch_s * dua = 0; + + dua = duhd->au_arches; + for ( ; i < duhd->au_count; ++i,++fa,++dua) { + ASNAR(word_swap,dua->au_cputype,fa->cputype); + ASNAR(word_swap,dua->au_cpusubtype,fa->cpusubtype); + ASNAR(word_swap,dua->au_offset,fa->offset); + if (dua->au_offset >= duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + ASNAR(word_swap,dua->au_size,fa->size); + if (dua->au_size >= duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + if ((dua->au_size+dua->au_offset) > duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + + ASNAR(word_swap,dua->au_align,fa->align); + if (dua->au_align >= 32) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + dua->au_reserved = 0; + } + return DW_DLV_OK; +} + +static int +fill_in_uni_arch_64( + struct fat_arch_64 * fa, + struct Dwarf_Universal_Head_s *duhd, + void (*word_swap) (void *, const void *, unsigned long), + int *errcode) +{ + Dwarf_Unsigned i = 0; + struct Dwarf_Universal_Arch_s * dua = 0; + + dua = duhd->au_arches; + for ( ; i < duhd->au_count; ++i,++fa,++dua) { + ASNAR(word_swap,dua->au_cputype,fa->cputype); + ASNAR(word_swap,dua->au_cpusubtype,fa->cpusubtype); + ASNAR(word_swap,dua->au_offset,fa->offset); + if (dua->au_offset >= duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + ASNAR(word_swap,dua->au_size,fa->size); + if (dua->au_size >= duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + if ((dua->au_size+dua->au_offset) > duhd->au_filesize) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + ASNAR(word_swap,dua->au_align,fa->align); + if (dua->au_align >= 32) { + *errcode = DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR; + return DW_DLV_ERROR; + } + ASNAR(word_swap,dua->au_reserved,fa->reserved); + } + return DW_DLV_OK; +} + +static const struct Dwarf_Universal_Head_s duhzero; +static const struct fat_header fhzero; +static int +_dwarf_object_detector_universal_head_fd( + int fd, + Dwarf_Unsigned dw_filesize, + unsigned int *dw_contentcount, + Dwarf_Universal_Head * dw_head, + int *errcode) +{ + struct Dwarf_Universal_Head_s duhd; + struct Dwarf_Universal_Head_s *duhdp = 0; + struct fat_header fh; + int res = 0; + void (*word_swap) (void *, const void *, unsigned long); + int locendian = 0; + int locoffsetsize = 0; + + duhd = duhzero; + fh = fhzero; + /* A universal head is always at offset zero. */ + duhd.au_filesize = dw_filesize; + if (sizeof(fh) >= dw_filesize) { + *errcode = DW_DLE_UNIVERSAL_BINARY_ERROR; + return DW_DLV_ERROR; + } + res = RRMOA(fd,&fh,0,sizeof(fh), dw_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + duhd.au_magic = magic_copy((unsigned char *)&fh.magic[0],4); + if (duhd.au_magic == FAT_MAGIC) { + locendian = DW_END_big; + locoffsetsize = 32; + } else if (duhd.au_magic == FAT_CIGAM) { + locendian = DW_END_little; + locoffsetsize = 32; + }else if (duhd.au_magic == FAT_MAGIC_64) { + locendian = DW_END_big; + locoffsetsize = 64; + } else if (duhd.au_magic == FAT_CIGAM_64) { + locendian = DW_END_little; + locoffsetsize = 64; + } else { + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } +#ifdef WORDS_BIGENDIAN + if (locendian == DW_END_little) { + word_swap = _dwarf_memcpy_swap_bytes; + } else { + word_swap = _dwarf_memcpy_noswap_bytes; + } +#else /* LITTLE ENDIAN */ + if (locendian == DW_END_little) { + word_swap = _dwarf_memcpy_noswap_bytes; + } else { + word_swap = _dwarf_memcpy_swap_bytes; + } +#endif /* LITTLE- BIG-ENDIAN */ + ASNAR(word_swap,duhd.au_count,fh.nfat_arch); + /* The limit is a first-cut safe heuristic. */ + if (duhd.au_count >= (dw_filesize/2) ) { + *errcode = DW_DLE_UNIVERSAL_BINARY_ERROR ; + return DW_DLV_ERROR; + } + duhd.au_arches = (struct Dwarf_Universal_Arch_s*) + calloc(duhd.au_count, sizeof(struct Dwarf_Universal_Arch_s)); + if (!duhd.au_arches) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + if (locoffsetsize == 32) { + struct fat_arch * fa = 0; + fa = (struct fat_arch *)calloc(duhd.au_count, + sizeof(struct fat_arch)); + if (!fa) { + *errcode = DW_DLE_ALLOC_FAIL; + free(duhd.au_arches); + duhd.au_arches = 0; + free(fa); + return DW_DLV_ERROR; + } + if (sizeof(fh)+duhd.au_count*sizeof(*fa) >= dw_filesize) { + free(duhd.au_arches); + duhd.au_arches = 0; + free(fa); + *errcode = DW_DLE_FILE_OFFSET_BAD; + return DW_DLV_ERROR; + } + res = RRMOA(fd,fa,/*offset=*/sizeof(fh), + duhd.au_count*sizeof(*fa), + dw_filesize,errcode); + if (res != DW_DLV_OK) { + free(duhd.au_arches); + duhd.au_arches = 0; + free(fa); + return res; + } + res = fill_in_uni_arch_32(fa,&duhd,word_swap, + errcode); + free(fa); + fa = 0; + if (res != DW_DLV_OK) { + free(duhd.au_arches); + duhd.au_arches = 0; + return res; + } + } else { /* 64 */ + struct fat_arch_64 * fa = 0; + fa = (struct fat_arch_64 *)calloc(duhd.au_count, + sizeof(struct fat_arch_64)); + if (!fa) { + *errcode = DW_DLE_ALLOC_FAIL; + free(duhd.au_arches); + duhd.au_arches = 0; + return DW_DLV_ERROR; + } + if (sizeof(fh)+duhd.au_count*sizeof(*fa) >= dw_filesize) { + free(duhd.au_arches); + duhd.au_arches = 0; + free(fa); + *errcode = DW_DLE_FILE_OFFSET_BAD ; + return DW_DLV_ERROR; + } + res = RRMOA(fd,fa,/*offset*/sizeof(fh), + duhd.au_count*sizeof(fa), + dw_filesize,errcode); + if (res == DW_DLV_ERROR) { + free(duhd.au_arches); + duhd.au_arches = 0; + free(fa); + return res; + } + res = fill_in_uni_arch_64(fa,&duhd,word_swap, + errcode); + free(fa); + fa = 0; + if (res != DW_DLV_OK) { + free(duhd.au_arches); + duhd.au_arches = 0; + return res; + } + } + + duhdp = malloc(sizeof(*duhdp)); + if (!duhdp) { + free(duhd.au_arches); + duhd.au_arches = 0; + *errcode = DW_DLE_ALLOC_FAIL; + return res; + } + memcpy(duhdp,&duhd,sizeof(duhd)); + *dw_contentcount = duhd.au_count; + duhdp->au_arches = duhd.au_arches; + *dw_head = duhdp; + return DW_DLV_OK; +} + +#if 0 +static void +print_arch_item(unsigned int i, + struct Dwarf_Universal_Arch_s* arch) +{ + printf(" Universal Binary Index " LONGESTUFMT "\n",i); + printf(" cpu " LONGESTXFMT "\n",arch->au_cputype); + printf(" cpusubt " LONGESTXFMT "\n",arch->au_cpusubtype); + printf(" offset " LONGESTXFMT "\n",arch->au_offset); + printf(" size " LONGESTXFMT "\n",arch->au_size); + printf(" align " LONGESTXFMT "\n",arch->au_align); +} +#endif + +int +_dwarf_object_detector_universal_instance( + Dwarf_Universal_Head dw_head, + Dwarf_Unsigned dw_index_of, + Dwarf_Unsigned *dw_cpu_type, + Dwarf_Unsigned *dw_cpusubtype, + Dwarf_Unsigned *dw_offset, + Dwarf_Unsigned *dw_size, + Dwarf_Unsigned *dw_align, + int *errcode) +{ + struct Dwarf_Universal_Arch_s* arch = 0; + + if (!dw_head) { + *errcode = DW_DLE_UNIVERSAL_BINARY_ERROR; + return DW_DLV_ERROR; + } + if (dw_index_of >= dw_head->au_count){ + return DW_DLV_NO_ENTRY; + } + arch = dw_head->au_arches +dw_index_of; + *dw_cpu_type = arch->au_cputype; + *dw_cpusubtype = arch->au_cpusubtype; + *dw_offset = arch->au_offset; + *dw_size = arch->au_size; + *dw_align = arch->au_align; + return DW_DLV_OK; +} + +void +_dwarf_dealloc_universal_head(Dwarf_Universal_Head dw_head) +{ + if (!dw_head) { + return; + } + free(dw_head->au_arches); + dw_head->au_arches = 0; + free(dw_head); +} diff --git a/src/lib/libdwarf/dwarf_machoread.h b/src/lib/libdwarf/dwarf_machoread.h new file mode 100644 index 0000000..6d9627f --- /dev/null +++ b/src/lib/libdwarf/dwarf_machoread.h @@ -0,0 +1,158 @@ +/* +Copyright (c) 2018-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#ifndef DWARF_MACHOREAD_H +#define DWARF_MACHOREAD_H + +struct Dwarf_Universal_Arch_s; +struct Dwarf_Universal_Head_s { + Dwarf_Unsigned au_magic; + Dwarf_Unsigned au_count; + Dwarf_Unsigned au_filesize; /* physical file size */ + struct Dwarf_Universal_Arch_s * au_arches; + +}; +struct Dwarf_Universal_Arch_s { + Dwarf_Unsigned au_cputype; + Dwarf_Unsigned au_cpusubtype; + Dwarf_Unsigned au_offset; + Dwarf_Unsigned au_size; + Dwarf_Unsigned au_align; + Dwarf_Unsigned au_reserved; +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct generic_macho_header { + Dwarf_Unsigned magic; + Dwarf_Unsigned cputype; + Dwarf_Unsigned cpusubtype; + Dwarf_Unsigned filetype; + Dwarf_Unsigned ncmds; /* number of load commands */ + + /* the size of all the load commands */ + Dwarf_Unsigned sizeofcmds; + + Dwarf_Unsigned flags; + Dwarf_Unsigned reserved; +}; +struct generic_macho_command { + Dwarf_Unsigned cmd; + Dwarf_Unsigned cmdsize; + Dwarf_Unsigned offset_this_command; +}; + +struct generic_macho_segment_command { + Dwarf_Unsigned cmd; + Dwarf_Unsigned cmdsize; + char segname[24]; + Dwarf_Unsigned vmaddr; + Dwarf_Unsigned vmsize; + Dwarf_Unsigned fileoff; + Dwarf_Unsigned filesize; + Dwarf_Unsigned maxprot; + Dwarf_Unsigned initprot; + Dwarf_Unsigned nsects; + Dwarf_Unsigned flags; + + /* our index into mo_commands */ + Dwarf_Unsigned macho_command_index; + Dwarf_Unsigned sectionsoffset; +}; + +struct generic_macho_section { + /* Larger than in file, room for NUL guaranteed */ + char sectname[24]; + char segname[24]; + const char * dwarfsectname; + Dwarf_Unsigned addr; + Dwarf_Unsigned size; + Dwarf_Unsigned offset; + Dwarf_Unsigned align; + Dwarf_Unsigned reloff; + Dwarf_Unsigned nreloc; + Dwarf_Unsigned flags; + Dwarf_Unsigned reserved1; + Dwarf_Unsigned reserved2; + Dwarf_Unsigned reserved3; + Dwarf_Unsigned generic_segment_num; + Dwarf_Unsigned offset_of_sec_rec; + Dwarf_Small* loaded_data; +}; + +/* ident[0] == 'M' means this is a macho header. + ident[1] will be 1 indicating version 1. + Other bytes in ident not defined, should be zero. */ +typedef struct dwarf_macho_filedata_s { + char mo_ident[8]; + const char * mo_path; /* libdwarf must free.*/ + int mo_fd; + int mo_destruct_close_fd; /*aka: lib owns fd */ + Dwarf_Unsigned mo_filesize; + Dwarf_Unsigned mo_inner_offset; /* for universal inner */ + Dwarf_Small mo_offsetsize; /* 32 or 64 section data */ + Dwarf_Small mo_pointersize; + int mo_ftype; + Dwarf_Small mo_endian; + unsigned mo_uninumber; /* for universal binary */ + unsigned mo_universal_count; /* for universal binary*/ + /*Dwarf_Small mo_machine; */ + void (*mo_copy_word) (void *, const void *, unsigned long); + + /* Used to hold 32 and 64 header data */ + struct generic_macho_header mo_header; + + unsigned mo_command_count; + Dwarf_Unsigned mo_command_start_offset; + struct generic_macho_command *mo_commands; + Dwarf_Unsigned mo_offset_after_commands; + + Dwarf_Unsigned mo_segment_count; + struct generic_macho_segment_command *mo_segment_commands; + + Dwarf_Unsigned mo_dwarf_sectioncount; + struct generic_macho_section *mo_dwarf_sections; +} dwarf_macho_object_access_internals_t; + +int _dwarf_load_macho_header( + dwarf_macho_object_access_internals_t * mfp, + int *errcode); +int _dwarf_load_macho_commands( + dwarf_macho_object_access_internals_t * mfp, + int *errcode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_MACHOREAD_H */ diff --git a/src/lib/libdwarf/dwarf_macro.c b/src/lib/libdwarf/dwarf_macro.c new file mode 100644 index 0000000..c4ad8c6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_macro.c @@ -0,0 +1,517 @@ +/* + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* ULONG_MAX */ +#include /* memcpy() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_macro.h" + +#define LEFTPAREN '(' +#define RIGHTPAREN ')' +#define SPACE ' ' + +/* Given the dwarf macro string, return a pointer to + the value. Returns pointer to 0 byte at end of string + if no value found (meaning the value is the empty string). + + Only understands well-formed .debug_macinfo + and .debug_macro strings. + +*/ +char * +dwarf_find_macro_value_start(char *str) +{ + char *lcp; + int funclike = 0; + + for (lcp = str; *lcp; ++lcp) { + switch (*lcp) { + case LEFTPAREN: + ++funclike; + break; + case RIGHTPAREN: + --funclike; + break; + case SPACE: + /* We allow extraneous spaces inside macro parameter ** + list, just in case... This is not really needed. */ + if (!funclike) { + return lcp + 1; + } + break; + default: + break; + } + } + /* Never found value: returns pointer to the 0 byte at end of + string. + Or maybe the parentheses are unbalanced! Compiler error? + */ + return lcp; +} + +/* + Try to keep fileindex correct in every Macro_Details + record by tracking file starts and ends. + Uses high water mark: space reused, not freed. + Presumption is that this makes sense for most uses. + STARTERMAX is set so that the array need not be expanded for + most files: it is the initial include file depth. +*/ +struct macro_stack_s { + Dwarf_Signed *st_base; + long st_max; + long st_next_to_use; + int st_was_fault; +}; + +static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms); +static void +free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms) +{ + dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING); + _dwarf_reset_index_macro_stack(ms); +} + +#define STARTERMAX 10 +static void +_dwarf_reset_index_macro_stack(struct macro_stack_s *ms) +{ + ms->st_base = 0; + ms->st_max = 0; + ms->st_next_to_use = 0; + ms->st_was_fault = 0; +} +static int +_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx, + struct macro_stack_s *ms) +{ + + if (!ms->st_max || ms->st_next_to_use >= ms->st_max) { + long new_size = ms->st_max; + Dwarf_Signed *newbase = 0; + + if (!new_size) { + new_size = STARTERMAX; + } + new_size = new_size * 2; + newbase = + (Dwarf_Signed *)_dwarf_get_alloc(dbg, DW_DLA_STRING, + new_size * sizeof(Dwarf_Signed)); + if (!newbase) { + /* just leave the old array in place */ + ms->st_was_fault = 1; + return DW_DLV_ERROR; + } + if (ms->st_base) { + memcpy(newbase, ms->st_base, + ms->st_next_to_use * sizeof(*newbase)); + dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING); + } + ms->st_base = newbase; + ms->st_max = new_size; + } + ms->st_base[ms->st_next_to_use] = indx; + ++ms->st_next_to_use; + return DW_DLV_OK; +} + +static Dwarf_Signed +_dwarf_macro_stack_pop_index(struct macro_stack_s *ms) +{ + if (ms->st_was_fault) { + return -1; + } + if (ms->st_next_to_use > 0) { + ms->st_next_to_use--; + return (ms->st_base[ms->st_next_to_use]); + } else { + ms->st_was_fault = 1; + } + return -1; +} + +/* Starting at macro_offset in .debug_macinfo, + if maximum_count is 0, treat as if it is infinite. + get macro data up thru + maximum_count entries or the end of a compilation + unit's entries (whichever comes first). + + .debug_macinfo never appears in a .dwp Package File. + So offset adjustment for such is not needed. +*/ + +int +dwarf_get_macro_details(Dwarf_Debug dbg, + Dwarf_Off macro_offset, + Dwarf_Unsigned maximum_count, + Dwarf_Signed * entry_count, + Dwarf_Macro_Details ** details, + Dwarf_Error * error) +{ + Dwarf_Small *macro_base = 0; + Dwarf_Small *macro_end = 0; + Dwarf_Small *pnext = 0; + Dwarf_Unsigned endloc = 0; + unsigned char uc = 0; + unsigned long depth = 0; + /* By section 6.3.2 Dwarf3 draft 8/9, + the base file should appear as + DW_MACINFO_start_file. See + http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html + on "[Bug debug/20253] New: [3.4/4.0 regression]: + Macro debug info broken due to lexer change" for how + gcc is broken in some versions. We no longer use + depth as a stopping point, it's not needed as a + stopping point anyway. */ + int res = 0; + /* count space used by strings */ + unsigned long str_space = 0; + int done = 0; + unsigned long space_needed = 0; + unsigned long space_used = 0; + unsigned long string_offset = 0; + Dwarf_Small *return_data = 0; + Dwarf_Small *pdata = 0; + unsigned long final_count = 0; + Dwarf_Signed fileindex = -1; + Dwarf_Small *latest_str_loc = 0; + struct macro_stack_s msdata; + + unsigned long count = 0; + unsigned long max_count = (unsigned long) maximum_count; + _dwarf_reset_index_macro_stack(&msdata); + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL: Either null or it contains" + "a stale Dwarf_Debug pointer"); + free_macro_stack(dbg,&msdata); + return DW_DLV_ERROR; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error); + if (res != DW_DLV_OK) { + free_macro_stack(dbg,&msdata); + return res; + } + if (!dbg->de_debug_abbrev.dss_size) { + free_macro_stack(dbg,&msdata); + return DW_DLV_NO_ENTRY; + } + + macro_base = dbg->de_debug_macinfo.dss_data; + if (macro_base == NULL) { + free_macro_stack(dbg,&msdata); + return DW_DLV_NO_ENTRY; + } + if (macro_offset >= dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + return DW_DLV_NO_ENTRY; + } + macro_end = macro_base + dbg->de_debug_macinfo.dss_size; + /* FIXME debugfission is NOT handled here. */ + + pnext = macro_base + macro_offset; + if (maximum_count == 0) { + max_count = ULONG_MAX; + } + + /* how many entries and how much space will they take? */ + endloc = (pnext - macro_base); + if (endloc >= dbg->de_debug_macinfo.dss_size) { + if (endloc == dbg->de_debug_macinfo.dss_size) { + /* normal: found last entry */ + free_macro_stack(dbg,&msdata); + return DW_DLV_NO_ENTRY; + } + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + free_macro_stack(dbg,&msdata); + return DW_DLV_ERROR; + } + for (count = 0; !done && count < max_count; ++count) { + unsigned long slen = 0; + + uc = *pnext; + ++pnext; /* get past the type code */ + switch (uc) { + case DW_MACINFO_define: + case DW_MACINFO_undef: + /* line, string */ + case DW_MACINFO_vendor_ext: + /* number, string */ + SKIP_LEB128_CK(pnext,dbg,error, + macro_end); + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + res = _dwarf_check_string_valid(dbg, + macro_base,pnext,macro_end, + DW_DLE_MACINFO_STRING_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + slen = strlen((char *) pnext) + 1; + pnext += slen; + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + str_space += slen; + break; + case DW_MACINFO_start_file: + /* line, file index */ + SKIP_LEB128_CK(pnext,dbg,error, + macro_end); + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + SKIP_LEB128_CK(pnext,dbg,error, + macro_end); + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + ++depth; + break; + + case DW_MACINFO_end_file: + if (--depth == 0) { + /* done = 1; no, do not stop here, + at least one gcc had + the wrong depth settings in the + gcc 3.4 timeframe. */ + } + /* no string or number here */ + break; + case 0: + /* end of cu's entries */ + done = 1; + break; + default: + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + /* bogus macinfo! */ + } + + endloc = (pnext - macro_base); + if (endloc == dbg->de_debug_macinfo.dss_size) { + done = 1; + } else if (endloc > dbg->de_debug_macinfo.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + free_macro_stack(dbg,&msdata); + return DW_DLV_ERROR; + } + } + /* ASSERT: The above loop will never let us get here + with count < 1. No need to test for a zero count. + + We have 'count' array entries to allocate and + str_space bytes of string space to provide for. */ + + string_offset = count * sizeof(Dwarf_Macro_Details); + + /* extra 2 not really needed */ + space_needed = string_offset + str_space + 2; + space_used = 0; + return_data = pdata = (Dwarf_Small *)_dwarf_get_alloc( + dbg, DW_DLA_STRING, space_needed); + latest_str_loc = pdata + string_offset; + if (pdata == 0) { + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE); + return DW_DLV_ERROR; + } + pnext = macro_base + macro_offset; + + done = 0; + + /* A series ends with a type code of 0. */ + + for (final_count = 0; !done && final_count < count; + ++final_count) { + unsigned long slen = 0; + Dwarf_Unsigned v1 = 0; + Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata + + (final_count * sizeof (Dwarf_Macro_Details))); + + endloc = (pnext - macro_base); + if (endloc > dbg->de_debug_macinfo.dss_size) { + dwarf_dealloc(dbg,return_data,DW_DLA_STRING); + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD); + return DW_DLV_ERROR; + } + uc = *pnext; + pdmd->dmd_offset = (pnext - macro_base); + pdmd->dmd_type = uc; + pdmd->dmd_fileindex = fileindex; + pdmd->dmd_lineno = 0; + pdmd->dmd_macro = 0; + ++pnext; /* get past the type code */ + switch (uc) { + case DW_MACINFO_define: + case DW_MACINFO_undef: + /* line, string */ + case DW_MACINFO_vendor_ext: + /* number, string */ + res = _dwarf_leb128_uword_wrapper(dbg,&pnext, + macro_end,&v1,error); + if (res != DW_DLV_OK) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + return res; + } + pdmd->dmd_lineno = v1; + + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + res = _dwarf_check_string_valid(dbg, + macro_base,pnext,macro_end, + DW_DLE_MACINFO_STRING_BAD,error); + if (res != DW_DLV_OK) { + dwarf_dealloc(dbg,return_data,DW_DLA_STRING); + return res; + } + slen = strlen((char *) pnext) + 1; + + _dwarf_safe_strcpy((char *)latest_str_loc, + space_needed - space_used, + (const char *)pnext,slen-1); + pdmd->dmd_macro = (char *) latest_str_loc; + latest_str_loc += slen; + space_used +=slen; + pnext += slen; + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + break; + case DW_MACINFO_start_file: + /* Line, file index */ + res = _dwarf_leb128_uword_wrapper(dbg,&pnext, + macro_end,&v1,error); + if (res != DW_DLV_OK) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + return res; + } + pdmd->dmd_lineno = v1; + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + res = _dwarf_leb128_uword_wrapper(dbg,&pnext, + macro_end,&v1,error); + if (res != DW_DLV_OK) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + return res; + } + pdmd->dmd_fileindex = v1; + (void) _dwarf_macro_stack_push_index(dbg, fileindex, + &msdata); + /* We ignore the error, we just let + fileindex ** be -1 when + we pop this one. */ + fileindex = v1; + if (((Dwarf_Unsigned)(pnext - macro_base)) >= + dbg->de_debug_macinfo.dss_size) { + free_macro_stack(dbg,&msdata); + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + _dwarf_error(dbg, error, + DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + break; + + case DW_MACINFO_end_file: + fileindex = _dwarf_macro_stack_pop_index(&msdata); + break; /* no string or number here */ + case 0: + /* Type code of 0 means the end of cu's entries. */ + done = 1; + break; + default: + /* Bogus macinfo! */ + dwarf_dealloc(dbg, return_data, DW_DLA_STRING); + free_macro_stack(dbg,&msdata); + _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT); + return DW_DLV_ERROR; + } + } + *entry_count = count; + *details = (Dwarf_Macro_Details *) return_data; + free_macro_stack(dbg,&msdata); + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_macro.h b/src/lib/libdwarf/dwarf_macro.h new file mode 100644 index 0000000..12e1adc --- /dev/null +++ b/src/lib/libdwarf/dwarf_macro.h @@ -0,0 +1,36 @@ +/* + + Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* + + dwarf_macro.h + + $Revision: 1.4 $ $Date: 2004/10/28 22:19:14 $ + +*/ diff --git a/src/lib/libdwarf/dwarf_macro5.c b/src/lib/libdwarf/dwarf_macro5.c new file mode 100644 index 0000000..5fb035c --- /dev/null +++ b/src/lib/libdwarf/dwarf_macro5.c @@ -0,0 +1,1666 @@ +/* + Copyright (C) 2015-2022 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() malloc() */ +#include /* memset() strcat() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_macro5.h" +#include "dwarf_string.h" +#include "dwarf_str_offsets.h" + +#define MC_SENTINEL 0xada + +#define CHECKNULLCONTEXT(m,d,e) \ +if (!(m) || (m)->mc_sentinel != MC_SENTINEL) { \ + if (m) { (d) = (m)->mc_dbg; } \ + _dwarf_error_string((d), (e), \ + DW_DLE_BAD_MACRO_HEADER_POINTER, \ + "DW_DLE_BAD_MACRO_HEADER_POINTER " \ + " NULL header or corrupt header"); \ + return DW_DLV_ERROR; \ +} + +/* Section 6.3: Macro Information: + Each macro unit ends with an entry + containing an opcode of 0. */ + +static const Dwarf_Small dwarf_udata_string_form[] = + {DW_FORM_udata,DW_FORM_string}; +static const Dwarf_Small dwarf_udata_udata_form[] = + {DW_FORM_udata,DW_FORM_udata}; +static const Dwarf_Small dwarf_udata_strp_form[] = + {DW_FORM_udata,DW_FORM_strp}; +static const Dwarf_Small dwarf_udata_strp_sup_form[] = + {DW_FORM_udata,DW_FORM_strp_sup}; +static const Dwarf_Small dwarf_secoffset_form[] = + {DW_FORM_sec_offset}; +static const Dwarf_Small dwarf_udata_strx_form[] = + {DW_FORM_udata,DW_FORM_strx}; + +struct Dwarf_Macro_Forms_s dw5formsarray[] = { + {0,0,0}, + {DW_MACRO_define,2,dwarf_udata_string_form}, + {DW_MACRO_undef,2,dwarf_udata_string_form}, + {DW_MACRO_start_file,2,dwarf_udata_udata_form}, + {DW_MACRO_end_file,0,0}, + + {DW_MACRO_define_strp,2,dwarf_udata_strp_form}, + {DW_MACRO_undef_strp,2,dwarf_udata_strp_form}, + {DW_MACRO_import,1,dwarf_secoffset_form}, + + {DW_MACRO_define_sup,2,dwarf_udata_strp_sup_form}, + {DW_MACRO_undef_sup,2,dwarf_udata_strp_sup_form}, + {DW_MACRO_import_sup,1,dwarf_secoffset_form}, + + {DW_MACRO_define_strx,2,dwarf_udata_strx_form}, + {DW_MACRO_undef_strx,2,dwarf_udata_strx_form}, +}; + +/* Represents DWARF 5 macro info */ +/* .debug_macro predefined, in order by value */ +static const struct Dwarf_Macro_OperationsList_s + dwarf_default_macro_opslist = { +13, dw5formsarray +}; + +static int _dwarf_internal_macro_context_by_offset(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context_out, + Dwarf_Unsigned *macro_ops_count_out, + Dwarf_Unsigned *macro_ops_data_length, + char **srcfiles, + Dwarf_Signed srcfilescount, + const char *comp_dir, + const char *comp_name, + Dwarf_CU_Context cu_context, + Dwarf_Error * error); + +static int _dwarf_internal_macro_context(Dwarf_Die die, + Dwarf_Bool offset_specified, + Dwarf_Unsigned offset, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context_out, + Dwarf_Unsigned *macro_unit_offset_out, + Dwarf_Unsigned *macro_ops_count_out, + Dwarf_Unsigned *macro_ops_data_length, + Dwarf_Error * error); + +static int +is_std_moperator(Dwarf_Small op) +{ + if (op >= 1 && op <= DW_MACRO_undef_strx) { + return TRUE; + } + return FALSE; +} + +static int +_dwarf_skim_forms(Dwarf_Debug dbg, + Dwarf_Macro_Context mcontext, + Dwarf_Small *mdata_start, + unsigned formcount, + const Dwarf_Small *forms, + Dwarf_Small *section_end, + Dwarf_Unsigned *forms_length, + Dwarf_Error *error) +{ + unsigned i = 0; + Dwarf_Small curform = 0 ; + Dwarf_Unsigned totallen = 0; + Dwarf_Unsigned v = 0; + Dwarf_Unsigned ret_value = 0; + Dwarf_Unsigned length; + Dwarf_Small *mdata = mdata_start; + Dwarf_Unsigned leb128_length = 0; + + for ( ; i < formcount; ++i) { + curform = forms[i]; + if (mdata >= section_end) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + switch(curform) { + default: + _dwarf_error(dbg,error, + DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE); + return DW_DLV_ERROR; + case DW_FORM_block1: + v = *(Dwarf_Small *) mdata; + totallen += v+1; + mdata += v+1; + break; + case DW_FORM_block2: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + mdata, DWARF_HALF_SIZE, + error,section_end); + v = ret_value + DWARF_HALF_SIZE; + totallen += v; + mdata += v; + break; + case DW_FORM_block4: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + mdata, DWARF_32BIT_SIZE, + error,section_end); + v = ret_value + DWARF_32BIT_SIZE; + totallen += v; + mdata += v; + break; + case DW_FORM_data1: + v = 1; + totallen += v; + mdata += v; + break; + case DW_FORM_data2: + v = 2; + totallen += v; + mdata += v; + break; + case DW_FORM_data4: + v = 4; + totallen += v; + mdata += v; + break; + case DW_FORM_data8: + v = 8; + totallen += v; + mdata += v; + break; + case DW_FORM_data16: + v = 8; + totallen += v; + mdata += v; + break; + case DW_FORM_string: { + int res = _dwarf_check_string_valid(dbg, + mdata,mdata, section_end, + DW_DLE_MACRO_STRING_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + v = strlen((char *) mdata) + 1; + totallen += v; + mdata += v; + } + break; + case DW_FORM_block: + DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length, + dbg, error,section_end); + v = length + leb128_length; + totallen += v; + break; + case DW_FORM_flag: + v = 1; + totallen += v; + mdata += v; + break; + case DW_FORM_sec_offset: + /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */ + v = mcontext->mc_offset_size; + totallen += v; + mdata += v; + break; + case DW_FORM_sdata: + /* Discard the decoded value, we just want the length + of the value. */ + DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length, + dbg, error,section_end); + totallen += v; + break; + case DW_FORM_strx: + DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length, + dbg, error,section_end); + totallen += leb128_length;; + break; + case DW_FORM_strp: + v = mcontext->mc_offset_size; + mdata += v; + totallen += v; + break; + case DW_FORM_udata: + /* Discard the decoded value, we just want the length + of the value. */ + DECODE_LEB128_UWORD_LEN_CK(mdata,length,leb128_length, + dbg, error,section_end); + totallen += leb128_length; + break; + } + } + if (mdata > section_end) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + *forms_length = totallen; + return DW_DLV_OK; +} + +#if 0 /* FOR DEBUGGING */ +static void +dump_bytes_x(Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + unsigned pos = 0; + + printf("dump %ld bytes, start at 0x%lx\n", + len,(unsigned long)start); + printf("0x"); + for (; cur < end;pos++, cur++) { + if (!(pos %4)) { + printf(" "); + } + printf("%02x",*cur); + } + printf("\n"); +} +Dwarf_Bool +is_defundef(unsigned op) +{ + switch(op){ + case DW_MACRO_define: + case DW_MACRO_undef: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: + case DW_MACRO_define_strx: + case DW_MACRO_undef_strx: + case DW_MACRO_define_sup: + case DW_MACRO_undef_sup: + return TRUE; + default: break; + } + return FALSE; +} +#endif /*0*/ + +/* On first call (for this macro_context), + build_ops_array is FALSE. On second, + it is TRUE and we know the count so we allocate and fill in + the ops array. */ +static int +_dwarf_get_macro_ops_count_internal(Dwarf_Macro_Context macro_context, + Dwarf_Bool build_ops_array, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Small *mdata = 0; + Dwarf_Small *section_end = 0; + Dwarf_Small *section_base = 0; + Dwarf_Unsigned opcount = 0; + Dwarf_Unsigned known_ops_count = 0; + struct Dwarf_Macro_Operator_s *opsarray = 0; + struct Dwarf_Macro_Operator_s *curopsentry = 0; + int res = 0; + + dbg = macro_context->mc_dbg; + if (build_ops_array) { + known_ops_count = macro_context->mc_macro_ops_count; + opsarray = (struct Dwarf_Macro_Operator_s *) + calloc(known_ops_count, + sizeof(struct Dwarf_Macro_Operator_s)); + if (!opsarray) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + curopsentry = opsarray; + macro_context->mc_ops = opsarray; + } + section_base = dbg->de_debug_macro.dss_data; + section_end = section_base + dbg->de_debug_macro.dss_size; + mdata = macro_context->mc_macro_ops; + + while (mdata < section_end) { + Dwarf_Small op = 0; + + op = *mdata; + ++opcount; + ++mdata; + if (!op) { + Dwarf_Unsigned opslen = 0; + /* End of ops, this is terminator, count the ending 0 + as an operator so dwarfdump can print it. + Normally we don't see this, the end operator + signals end. */ + opslen = mdata - macro_context->mc_macro_ops; + macro_context->mc_macro_ops_count = opcount; + macro_context->mc_ops_data_length = opslen; + macro_context->mc_total_length = opslen + + macro_context->mc_macro_header_length; + if (build_ops_array) { + curopsentry->mo_opcode = op; + curopsentry->mo_form = 0; + curopsentry->mo_data = 0; + } + return DW_DLV_OK; + } + if (is_std_moperator(op)) { + struct Dwarf_Macro_Forms_s * ourform = + dw5formsarray + op; + /* ASSERT: op == ourform->mf_code */ + unsigned formcount = ourform->mf_formcount; + const Dwarf_Small *forms = ourform->mf_formbytes; + Dwarf_Unsigned forms_length = 0; + + res = _dwarf_skim_forms(dbg,macro_context,mdata, + formcount,forms, + section_end, + &forms_length,error); + if ( res != DW_DLV_OK) { + return res; + } + if (build_ops_array) { + curopsentry->mo_opcode = op; + curopsentry->mo_form = ourform; + curopsentry->mo_data = mdata; + } + mdata += forms_length; + } else { + /* FIXME Add support for user defined ops. */ + _dwarf_error(dbg, error, DW_DLE_MACRO_OP_UNHANDLED); + return DW_DLV_ERROR; + } + if (mdata > section_end) { + _dwarf_error(dbg, error, DW_DLE_MACRO_PAST_END); + return DW_DLV_ERROR; + } + if (build_ops_array) { + curopsentry++; + } + } + _dwarf_error(dbg, error, DW_DLE_MACRO_PAST_END); + return DW_DLV_ERROR; +} + +int +dwarf_get_macro_op(Dwarf_Macro_Context macro_context, + Dwarf_Unsigned op_number, + Dwarf_Unsigned * op_start_section_offset, + Dwarf_Half * macro_operator, + Dwarf_Half * forms_count, + const Dwarf_Small ** formcode_array, + Dwarf_Error *error) +{ + struct Dwarf_Macro_Operator_s *curop = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned op_offset = 0; + Dwarf_Half operator = 0; + + CHECKNULLCONTEXT(macro_context,dbg,error); + dbg = macro_context->mc_dbg; + if (op_number >= macro_context->mc_macro_ops_count) { + _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX); + return DW_DLV_ERROR; + } + curop = macro_context->mc_ops + op_number; + operator = curop->mo_opcode; + if (!operator) { + /* For the null byte at the end + of an operator list. */ + *op_start_section_offset = macro_context->mc_total_length+ + macro_context->mc_section_offset -1; + *macro_operator = operator; + *forms_count = 0; + *formcode_array = 0; + return DW_DLV_OK; + } + op_offset = + ((curop->mo_data -1) - macro_context->mc_macro_header) + + macro_context->mc_section_offset; + if (op_offset >= macro_context->mc_section_size) { + dwarfstring m; + char buf[50]; + + dwarfstring_constructor_static(&m,buf,sizeof(buf)); + dwarfstring_append_printf_u(&m, + "DW_DLE_MACRO_OFFSET_BAD: offset 0x%lx", + op_offset); + dwarfstring_append_printf_u(&m, + " >= section size of 0x%lx", + macro_context->mc_section_size); + _dwarf_error_string(dbg,error,DW_DLE_MACRO_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *op_start_section_offset = op_offset; + *macro_operator = operator; + if (curop->mo_form) { + *forms_count = curop->mo_form->mf_formcount; + *formcode_array = curop->mo_form->mf_formbytes; + } else { + /* ASSERT: macro_operator == 0 */ + *forms_count = 0; + *formcode_array = 0; + } + return DW_DLV_OK; +} + +/* Here a DW_DLV_NO_ENTRY return means the macro operator + is not a def/undef operator. */ +int +dwarf_get_macro_defundef(Dwarf_Macro_Context macro_context, + Dwarf_Unsigned op_number, + Dwarf_Unsigned * line_number, + Dwarf_Unsigned * index, + Dwarf_Unsigned * offset, + Dwarf_Half * forms_count, + const char ** macro_string, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Small *mdata = 0; + int res = 0; + Dwarf_Small *startptr = 0; + Dwarf_Small *endptr = 0; + Dwarf_Half lformscount = 0; + struct Dwarf_Macro_Operator_s *curop = 0; + unsigned macop = 0; + + CHECKNULLCONTEXT(macro_context,dbg,error); + dbg = macro_context->mc_dbg; + if (op_number >= macro_context->mc_macro_ops_count) { + _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX); + return DW_DLV_ERROR; + } + curop = macro_context->mc_ops + op_number; + macop = curop->mo_opcode; + startptr = macro_context->mc_macro_header; + endptr = startptr + macro_context->mc_total_length; + mdata = curop->mo_data; + lformscount = curop->mo_form->mf_formcount; + if (lformscount != 2) { + /*_dwarf_error(dbg, error,DW_DLE_MACRO_OPCODE_FORM_BAD);*/ + return DW_DLV_NO_ENTRY; + } + switch(macop){ + case DW_MACRO_define: + case DW_MACRO_undef: { + Dwarf_Unsigned linenum = 0; + const char * content = 0; + + DECODE_LEB128_UWORD_CK(mdata,linenum, + dbg, error,endptr); + content = (const char *)mdata; + res = _dwarf_check_string_valid(dbg, + startptr,mdata, endptr, + DW_DLE_MACRO_STRING_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + *line_number = linenum; + *index = 0; + *offset = 0; + *forms_count = lformscount; + *macro_string = content; + } + return DW_DLV_OK; + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: { + Dwarf_Unsigned linenum = 0; + Dwarf_Unsigned stringoffset = 0; + Dwarf_Small form1 = curop->mo_form->mf_formbytes[1]; + char * localstr = 0; + + DECODE_LEB128_UWORD_CK(mdata,linenum, + dbg, error,endptr); + READ_UNALIGNED_CK(dbg,stringoffset,Dwarf_Unsigned, + mdata,macro_context->mc_offset_size, + error,endptr); + res = _dwarf_extract_local_debug_str_string_given_offset(dbg, + form1, + stringoffset, + &localstr, + error); + *index = 0; + *line_number = linenum; + *offset = stringoffset; + *forms_count = lformscount; + if (res == DW_DLV_ERROR) { + *macro_string = ""; + return res; + } else if (res == DW_DLV_NO_ENTRY) { + *macro_string = ""; + } else { + *macro_string = (const char *)localstr; + } + } + return DW_DLV_OK; + case DW_MACRO_define_strx: + case DW_MACRO_undef_strx: { + Dwarf_Unsigned linenum = 0; + Dwarf_Unsigned stringindex = 0; + Dwarf_Unsigned offsettostr= 0; + int ress = 0; + Dwarf_Byte_Ptr mdata_copy = 0; + Dwarf_Small form1 = curop->mo_form->mf_formbytes[1]; + + DECODE_LEB128_UWORD_CK(mdata,linenum, dbg, error,endptr); + *line_number = linenum; + mdata_copy = mdata; + DECODE_LEB128_UWORD_CK(mdata_copy,stringindex, + dbg, error,endptr); + /* mdata_copy is for call below */ + + *index = stringindex; + *forms_count = lformscount; + + /* Redoes the index-getting. Gets offset. */ + ress = _dwarf_extract_string_offset_via_str_offsets(dbg, + mdata_copy, + endptr, + form1, + macro_context->mc_cu_context, + &offsettostr, + error); + if (ress == DW_DLV_ERROR) { + return ress; + } + if (ress == DW_DLV_OK) { + char *localstr = 0; + + *index = stringindex; + *offset = offsettostr; + ress = + _dwarf_extract_local_debug_str_string_given_offset( + dbg, + form1, + offsettostr, + &localstr, + error); + if (ress == DW_DLV_ERROR) { + return ress; + } else if (ress == DW_DLV_NO_ENTRY){ + *macro_string = "<:No string available>"; + } else { + *macro_string = (const char *)localstr; + /* All is ok. */ + } + } else { + *index = stringindex; + *offset = 0; + *macro_string = "<.debug_str_offsets not available>"; + } + } + return DW_DLV_OK; + case DW_MACRO_define_sup: + case DW_MACRO_undef_sup: { + Dwarf_Unsigned linenum = 0; + Dwarf_Unsigned supoffset = 0; + char *localstring = 0; + int resup = 0; + Dwarf_Error lerr = 0; + + DECODE_LEB128_UWORD_CK(mdata,linenum, + dbg, error,endptr); + READ_UNALIGNED_CK(dbg,supoffset,Dwarf_Unsigned, + mdata,macro_context->mc_offset_size, + error,endptr); + *line_number = linenum; + *index = 0; + *offset = supoffset; + *forms_count = lformscount; + resup = _dwarf_get_string_from_tied(dbg, supoffset, + &localstring, &lerr); + if (resup != DW_DLV_OK) { + if (resup == DW_DLV_ERROR) { + int myerrno = dwarf_errno(lerr); + if (myerrno == DW_DLE_NO_TIED_FILE_AVAILABLE) { + *macro_string = + (char *)""; + } else { + _dwarf_error(dbg,error,myerrno); + *macro_string = + (char *)""; + } + dwarf_dealloc(dbg,lerr,DW_DLA_ERROR); + } else { + *macro_string = ""; + } + return resup; + } + *macro_string = (const char *)localstring; + /* If NO ENTRY available, return DW_DLV_NO_ENTRY. + We suspect this is better than DW_DLV_OK. */ + return resup; + } + default: + _dwarf_error(dbg,error,DW_DLE_MACRO_OP_UNHANDLED); + return DW_DLV_ERROR; + } + return DW_DLV_NO_ENTRY; +} + +/* ASSERT: we elsewhere guarantee room to copy into. + If trimtarg ==1, trim trailing slash in targ. + Caller should not pass in 'src' + with leading / */ +static void +specialcat(char *targ,char *src,int trimtarg) +{ + char *last = 0; + + while( *targ) { + last = targ; + targ++; + } + /* TARG now points at terminating NUL */ + /* LAST points at final character in targ. */ + if (trimtarg ) { + if (last && *last == '/') { + /* Truncate. */ + *last = 0; + targ = last; + /* TARG again points at terminating NUL */ + } + } + while (*src) { + *targ = *src; + targ++; + src++; + } + *targ = 0; +} + +/* If returns NULL caller must handle it. */ +static const char * +construct_from_dir_and_name(const char *dir, + const char *name) +{ + size_t truelen = 0; + char *final = 0; + + /* Allow for NUL char and added / */ + truelen = strlen(dir) + strlen(name) + 1 +1; + final = (char *)malloc(truelen); + if (!final) { + return NULL; + } + final[0] = 0; + specialcat(final,(char *)dir,1); + strcat(final,"/"); + specialcat(final,(char *)name,0); + return final; +} + +/* If returns NULL caller must handle it. */ +static const char * +construct_at_path_from_parts(Dwarf_Macro_Context mc) +{ + if (mc->mc_file_path) { + return mc->mc_file_path; + } + if (!mc->mc_at_comp_dir || !mc->mc_at_comp_dir[0]) { + return mc->mc_at_name; + } + if (!mc->mc_at_name || !mc->mc_at_name[0]) { + return NULL; + } + if (_dwarf_file_name_is_full_path( + (Dwarf_Small *)mc->mc_at_name)) { + return mc->mc_at_name; + } + /* Dwarf_Macro_Context destructor will free this. */ + mc->mc_file_path = construct_from_dir_and_name( + mc->mc_at_comp_dir,mc->mc_at_name); + return mc->mc_file_path; +} + +int +dwarf_get_macro_startend_file(Dwarf_Macro_Context macro_context, + Dwarf_Unsigned op_number, + Dwarf_Unsigned * line_number, + Dwarf_Unsigned * name_index_to_line_tab, + const char ** src_file_name, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Small *mdata = 0; + unsigned macop = 0; + struct Dwarf_Macro_Operator_s *curop = 0; + Dwarf_Byte_Ptr startptr = 0; + Dwarf_Byte_Ptr endptr = 0; + + CHECKNULLCONTEXT(macro_context,dbg,error); + dbg = macro_context->mc_dbg; + if (op_number >= macro_context->mc_macro_ops_count) { + _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX); + return DW_DLV_ERROR; + } + startptr = macro_context->mc_macro_header; + endptr = startptr + macro_context->mc_total_length; + + curop = macro_context->mc_ops + op_number; + macop = curop->mo_opcode; + mdata = curop->mo_data; + if (macop != DW_MACRO_start_file && macop != DW_MACRO_end_file) { + return DW_DLV_NO_ENTRY; + } + if (macop == DW_MACRO_start_file) { + Dwarf_Unsigned linenum = 0; + Dwarf_Unsigned srcindex = 0; + Dwarf_Signed trueindex = 0; + + DECODE_LEB128_UWORD_CK(mdata,linenum, dbg, error,endptr); + DECODE_LEB128_UWORD_CK(mdata,srcindex, dbg, error,endptr); + *line_number = linenum; + *name_index_to_line_tab = srcindex; + /* We deal with DWARF4 GNU extension + with .debug_macro version number 4 + and DWARF5 .debug_macro version number 5. + */ + if (macro_context->mc_version_number == DW_MACRO_VERSION5) { + trueindex = srcindex; + if (trueindex < 0) { + *src_file_name = + ""; + return DW_DLV_OK; + } + if (trueindex < macro_context->mc_srcfiles_count) { + *src_file_name = + macro_context->mc_srcfiles[trueindex]; + return DW_DLV_OK; + } else { + *src_file_name = + ""; + return DW_DLV_OK; + } + } else { + /* All except DWARF5 */ + /* Unsigned to signed here. */ + trueindex = srcindex; + /* Protects against crazy big srcindex, + overflow territory. */ + if (trueindex < 0 ) { + /* Something insane here. */ + *src_file_name = + ""; + return DW_DLV_OK; + } + /* Protects against crazy big srcindex, + overflow territory. */ + if (trueindex > (macro_context->mc_srcfiles_count+1)) { + /* Something insane here. */ + *src_file_name = + ""; + return DW_DLV_OK; + } + --trueindex; /* might now be -1 */ + if (trueindex > macro_context->mc_srcfiles_count) { + *src_file_name = + ""; + } + if (srcindex > 0 && + trueindex < macro_context->mc_srcfiles_count) { + *src_file_name = + macro_context->mc_srcfiles[trueindex]; + } else { + const char *mcatcomp = + construct_at_path_from_parts(macro_context); + if (mcatcomp) { + *src_file_name = mcatcomp; + } else { + *src_file_name = + ""; + } + } + } + } else { + /* DW_MACRO_end_file. No operands. */ + } + return DW_DLV_OK; +} + +/* Target_offset is the offset in a .debug_macro section, + of a macro unit header. + Returns DW_DLV_NO_ENTRY if the macro operator is not + one of the import operators. */ +int +dwarf_get_macro_import(Dwarf_Macro_Context macro_context, + Dwarf_Unsigned op_number, + Dwarf_Unsigned * target_offset, + Dwarf_Error *error) +{ + Dwarf_Unsigned supoffset = 0; + Dwarf_Debug dbg = 0; + unsigned macop = 0; + struct Dwarf_Macro_Operator_s *curop = 0; + Dwarf_Small *mdata = 0; + Dwarf_Byte_Ptr startptr = 0; + Dwarf_Byte_Ptr endptr = 0; + + CHECKNULLCONTEXT(macro_context,dbg,error); + startptr = macro_context->mc_macro_header; + endptr = startptr + macro_context->mc_total_length; + dbg = macro_context->mc_dbg; + if (op_number >= macro_context->mc_macro_ops_count) { + _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX); + return DW_DLV_ERROR; + } + curop = macro_context->mc_ops + op_number; + macop = curop->mo_opcode; + mdata = curop->mo_data; + if (macop != DW_MACRO_import && macop != DW_MACRO_import_sup) { + return DW_DLV_NO_ENTRY; + } + READ_UNALIGNED_CK(dbg,supoffset,Dwarf_Unsigned, + mdata,macro_context->mc_offset_size, + error,endptr); + *target_offset = supoffset; + return DW_DLV_OK; +} + +/* */ +static int +valid_macro_form(Dwarf_Half form) +{ + switch(form) { + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_data16: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_flag: + case DW_FORM_sec_offset: + case DW_FORM_string: + case DW_FORM_strp: + case DW_FORM_strx: + return TRUE; + default: break; + } + return FALSE; +} + +static int +validate_opcode(Dwarf_Debug dbg, + struct Dwarf_Macro_Forms_s *curform, + Dwarf_Error * error) +{ + unsigned i = 0; + struct Dwarf_Macro_Forms_s *stdfptr = 0; + if (curform->mf_code >= DW_MACRO_lo_user) { + /* Nothing to check. user level. */ + return DW_DLV_OK; + } + if (curform->mf_code > DW_MACRO_undef_strx) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_BAD); + return DW_DLV_ERROR; + } + if (!curform->mf_code){ + _dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_BAD); + return DW_DLV_ERROR; + } + stdfptr = &dwarf_default_macro_opslist.mol_data[curform->mf_code]; + + if (curform->mf_formcount != stdfptr->mf_formcount) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_FORM_BAD); + return DW_DLV_ERROR; + } + for (i = 0; i < curform->mf_formcount; ++i) { + if (curform->mf_formbytes[i] != stdfptr->mf_formbytes[1]) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OPCODE_FORM_BAD); + return DW_DLV_ERROR; + } + } + return DW_DLV_OK; +} + +static int +read_operands_table(Dwarf_Macro_Context macro_context, + Dwarf_Small * macro_header, + Dwarf_Small * macro_data, + Dwarf_Small * section_base, + Dwarf_Unsigned section_size, + Dwarf_Unsigned *table_size_out, + Dwarf_Error *error) +{ + Dwarf_Small* table_data_start = macro_data; + Dwarf_Unsigned local_size = 0; + Dwarf_Unsigned cur_offset = 0; + Dwarf_Small operand_table_count = 0; + unsigned i = 0; + struct Dwarf_Macro_Forms_s *curformentry = 0; + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr startptr = 0; + Dwarf_Byte_Ptr endptr = 0; + + CHECKNULLCONTEXT(macro_context,dbg,error); + dbg = macro_context->mc_dbg; + cur_offset = (1+ macro_data) - macro_header; + if (cur_offset >= section_size) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + + startptr = macro_context->mc_macro_header; + endptr = startptr + macro_context->mc_total_length; + READ_UNALIGNED_CK(dbg,operand_table_count,Dwarf_Small, + macro_data,sizeof(Dwarf_Small),error,endptr); + macro_data += sizeof(Dwarf_Small); + /* Estimating minimum size */ + local_size = operand_table_count * 4; + + cur_offset = (local_size+ macro_data) - section_base; + if (cur_offset >= section_size) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + /* first, get size of table. */ + table_data_start = macro_data; + for (i = 0; i < operand_table_count; ++i) { + /* Compiler warning about unused opcode_number + variable should be ignored. */ + Dwarf_Unsigned formcount = 0; +#if 0 /* No need to actually read, just update pointer*/ + Dwarf_Small opcode_number = 0; + READ_UNALIGNED_CK(dbg,opcode_number,Dwarf_Small, + macro_data,sizeof(Dwarf_Small),error,endptr); +#endif /*0*/ + macro_data += sizeof(Dwarf_Small); + + DECODE_LEB128_UWORD_CK(macro_data,formcount, + dbg, error, endptr); + cur_offset = (formcount+ macro_data) - section_base; + if (cur_offset >= section_size) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + /* The 1 ubyte forms follow. Step past them. */ + macro_data += formcount; + } + /* reset for reread. */ + macro_data = table_data_start; + /* allocate table */ + macro_context->mc_opcode_forms = (struct Dwarf_Macro_Forms_s *) + calloc(operand_table_count, + sizeof(struct Dwarf_Macro_Forms_s)); + macro_context->mc_opcode_count = operand_table_count; + if (!macro_context->mc_opcode_forms) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + curformentry = macro_context->mc_opcode_forms; + for (i = 0; i < operand_table_count; ++i,++curformentry) { + Dwarf_Small opcode_number = 0; + Dwarf_Unsigned formcount = 0; + int res = 0; + + cur_offset = (2 + macro_data) - section_base; + if (cur_offset >= section_size) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,opcode_number,Dwarf_Small, + macro_data,sizeof(Dwarf_Small), + error,endptr); + macro_data += sizeof(Dwarf_Small); + DECODE_LEB128_UWORD_CK(macro_data,formcount, + dbg, error, endptr); + + curformentry->mf_code = opcode_number; + curformentry->mf_formcount = formcount; + + cur_offset = (formcount+ macro_data) - section_base; + if (cur_offset >= section_size) { + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + curformentry->mf_formbytes = macro_data; + macro_data += formcount; + if (opcode_number > DW_MACRO_undef_strx ) { + Dwarf_Half k = 0; + for (k = 0; k < formcount; ++k) { + if (!valid_macro_form( + curformentry->mf_formbytes[k])) { + _dwarf_error(dbg, error, + DW_DLE_MACRO_OP_UNHANDLED); + return DW_DLV_ERROR; + } + } + } + res = validate_opcode(macro_context->mc_dbg, + curformentry, error); + if (res != DW_DLV_OK) { + return res; + } + } + *table_size_out = macro_data - table_data_start; + return DW_DLV_OK; +} + +/* This is not the normal srcfiles from dwarf_srcfiles. + See translate translate_srcfiles_to_srcfiles2(). + It is a list, but the contents were directly malloc, + not _dwarf_get_alloc. +*/ +static void +dealloc_macro_srcfiles(char ** srcfiles, + Dwarf_Signed srcfiles_count) +{ + Dwarf_Signed i = 0; + if (!srcfiles || !srcfiles_count) { + return; + } + for (i = 0; i < srcfiles_count; ++i) { + if (srcfiles[i]) { + free(srcfiles[i]); + srcfiles[i] = 0; + } + } + free(srcfiles); +} + +/* This makes the macro context safe from + duplicate frees in case of error. */ +static int +translate_srcfiles_to_srcfiles2(char **srcfiles, + Dwarf_Signed srcfiles_count, + char **srcfiles2) +{ + Dwarf_Signed i = 0; + + for (i = 0; i < srcfiles_count; ++i) { + char * ostr = 0; + char * newstr = 0; + size_t slen = 0; + + ostr = srcfiles[i]; + slen = strlen(ostr); + newstr = calloc(1,slen+1); + if (!newstr) { + return DW_DLV_ERROR; + } + _dwarf_safe_strcpy(newstr,slen+1,ostr,slen); + srcfiles2[i] = newstr; + } + return DW_DLV_OK; +} + +static void +drop_srcfiles(Dwarf_Debug dbg,char ** srcfiles, + Dwarf_Signed srcfiles_count) +{ + Dwarf_Signed i = 0; + for (i = 0; i < srcfiles_count; ++i) { + if (srcfiles[i]) { + dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); + } + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); +} + +static int +_dwarf_internal_macro_context(Dwarf_Die die, + Dwarf_Bool offset_specified, + Dwarf_Unsigned offset_in, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context_out, + Dwarf_Unsigned * macro_unit_offset_out, + Dwarf_Unsigned * macro_ops_count_out, + Dwarf_Unsigned * macro_ops_data_length, + Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + int res = DW_DLV_ERROR; + Dwarf_Unsigned macro_offset = 0; + Dwarf_Attribute macro_attr = 0; + Dwarf_Signed srcfiles_count = 0; + Dwarf_Signed srcfiles2_count = 0; + char ** srcfiles = 0; + + /* srcfiles uses dwarf_get_alloc for strings + so dealloc_macro_srcfiles() here will result in double-dealloc + when dwarf_finish() happens to see the string deallocs + before the macro context dealloc (the context dealloc + will call dealloc_macro_srcfiles() !). + + Also see the comment at _dwarf_macro_destructor() here. + */ + char ** srcfiles2 = 0; + + const char *comp_dir = 0; + const char *comp_name = 0; + + /* ***** BEGIN CODE ***** */ + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + dbg = cu_context->cc_dbg; + + /* Doing the load here results in duplication of the + section-load call (in the by_offset + interface below) but detects the missing section + quickly. */ + res = _dwarf_load_section(dbg, &dbg->de_debug_macro,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_macro.dss_size) { + return DW_DLV_NO_ENTRY; + } + resattr = dwarf_attr(die, DW_AT_macros, ¯o_attr, error); + if (resattr == DW_DLV_NO_ENTRY) { + resattr = dwarf_attr(die, DW_AT_GNU_macros, + ¯o_attr, error); + } + if (resattr != DW_DLV_OK) { + return resattr; + } + if (!offset_specified) { + lres = dwarf_global_formref(macro_attr, + ¯o_offset, error); + if (lres != DW_DLV_OK) { + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + return lres; + } + } else { + macro_offset = offset_in; + } + /* If DWP cc_macro_base may be non-zero */ + macro_offset += cu_context->cc_macro_base; + + lres = dwarf_srcfiles(die,&srcfiles,&srcfiles_count, error); + if (lres == DW_DLV_ERROR) { + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + return lres; + } + lres = _dwarf_internal_get_die_comp_dir(die, &comp_dir, + &comp_name,error); + if (lres == DW_DLV_ERROR) { + drop_srcfiles(dbg,srcfiles,srcfiles_count); + srcfiles = 0; + srcfiles_count = 0; + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + srcfiles = 0; + return lres; + } + *macro_unit_offset_out = macro_offset; + /* We cannot use space allocated by + _dwarf_get_alloc() in the macro_context + we will allocate shortly. + So copy from what we have to a similar data set + but malloc space directly. */ + + if (srcfiles_count > 0) { + srcfiles2 = (char **) calloc(srcfiles_count, sizeof(char *)); + if (!srcfiles2) { + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + drop_srcfiles(dbg,srcfiles,srcfiles_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + lres = translate_srcfiles_to_srcfiles2(srcfiles, + srcfiles_count,srcfiles2); + drop_srcfiles(dbg,srcfiles,srcfiles_count); + srcfiles2_count = srcfiles_count; + srcfiles = 0; + srcfiles_count = 0; + if (lres != DW_DLV_OK) { + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + dealloc_macro_srcfiles(srcfiles2, srcfiles2_count); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return lres; + } + } else { + drop_srcfiles(dbg,srcfiles,srcfiles_count); + srcfiles = 0; + srcfiles_count = 0; + } + + dwarf_dealloc(dbg,macro_attr,DW_DLA_ATTR); + /* NO ENTRY or OK we accept, though NO ENTRY means there + are no source files available. */ + lres = _dwarf_internal_macro_context_by_offset(dbg, + macro_offset,version_out,macro_context_out, + macro_ops_count_out, + macro_ops_data_length, + srcfiles2,srcfiles2_count, + comp_dir, + comp_name, + cu_context, + error); + /* In case of ERROR or NO_ENTRY srcfiles2 is already freed. */ + return lres; +} + +static int +_dwarf_internal_macro_context_by_offset(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context_out, + Dwarf_Unsigned * macro_ops_count_out, + Dwarf_Unsigned * macro_ops_data_length, + char **srcfiles, + Dwarf_Signed srcfilescount, + const char *comp_dir, + const char *comp_name, + Dwarf_CU_Context cu_context, + Dwarf_Error * error) +{ + Dwarf_Unsigned line_table_offset = 0; + Dwarf_Small * macro_header = 0; + Dwarf_Small * macro_data = 0; + Dwarf_Unsigned version = 0; + Dwarf_Unsigned flags = 0; + Dwarf_Small offset_size = 4; + Dwarf_Unsigned cur_offset = 0; + Dwarf_Unsigned section_size = 0; + Dwarf_Small *section_base = 0; + Dwarf_Small *section_end = 0; + Dwarf_Unsigned optablesize = 0; + Dwarf_Unsigned macro_offset = offset; + int res = 0; + Dwarf_Macro_Context macro_context = 0; + Dwarf_Bool build_ops_array = FALSE; + + res = _dwarf_load_section(dbg, &dbg->de_debug_macro,error); + if (res != DW_DLV_OK) { + dealloc_macro_srcfiles(srcfiles,srcfilescount); + return res; + } + if (!dbg->de_debug_macro.dss_size) { + dealloc_macro_srcfiles(srcfiles,srcfilescount); + return DW_DLV_NO_ENTRY; + } + + section_base = dbg->de_debug_macro.dss_data; + section_size = dbg->de_debug_macro.dss_size; + /* The '3' ensures the header initial bytes present too. */ + if ((3+macro_offset) >= section_size) { + dealloc_macro_srcfiles(srcfiles,srcfilescount); + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + macro_header = macro_offset + section_base; + macro_data = macro_header; + section_end = section_base +section_size; + + macro_context = (Dwarf_Macro_Context) + _dwarf_get_alloc(dbg,DW_DLA_MACRO_CONTEXT,1); + if (!macro_context) { + dealloc_macro_srcfiles(srcfiles,srcfilescount); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + if ((section_base + DWARF_HALF_SIZE + sizeof(Dwarf_Small)) > + section_end ) { + dealloc_macro_srcfiles(srcfiles,srcfilescount); + dwarf_dealloc_macro_context(macro_context); + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + /* Note here so if error return we get these freed eventually. */ + macro_context->mc_srcfiles = srcfiles; + macro_context->mc_srcfiles_count = srcfilescount; + macro_context->mc_cu_context = cu_context; + + res = _dwarf_read_unaligned_ck_wrapper(dbg, + &version,macro_data,DWARF_HALF_SIZE,section_end, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + if (version != DW_MACRO_VERSION4 && + version != DW_MACRO_VERSION5) { + dwarfstring ms; + + dwarfstring_constructor(&ms); + dwarfstring_append_printf_u(&ms, + "DW_DLE_MACRO_VERSION_ERROR: " + "version 0x%x ",version); + dwarfstring_append_printf_u(&ms, + "at section offset " + "0x%" DW_PR_XZEROS DW_PR_DUx " " + "is incorrect, only 5 " + "or the GNU extension value of 4 are valid. " + "Corrupt dwarf.", + macro_offset); + _dwarf_error_string(dbg,error, + DW_DLE_MACRO_VERSION_ERROR, + dwarfstring_string(&ms)); + dwarfstring_destructor(&ms); + dwarf_dealloc_macro_context(macro_context); + return DW_DLV_ERROR; + } + macro_data += DWARF_HALF_SIZE; + res = _dwarf_read_unaligned_ck_wrapper(dbg, + &flags,macro_data,sizeof(Dwarf_Small),section_end, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + macro_data += sizeof(Dwarf_Small); + + macro_context->mc_at_comp_dir = comp_dir; + macro_context->mc_at_name = comp_name; + macro_context->mc_macro_header = macro_header; + macro_context->mc_section_offset = macro_offset; + macro_context->mc_section_size = section_size; + macro_context->mc_version_number = version; + macro_context->mc_flags = flags; + macro_context->mc_dbg = dbg; + macro_context->mc_offset_size_flag = + flags& MACRO_OFFSET_SIZE_FLAG?TRUE:FALSE; + macro_context->mc_debug_line_offset_flag = + flags& MACRO_LINE_OFFSET_FLAG?TRUE:FALSE; + macro_context->mc_operands_table_flag = + flags& MACRO_OP_TABLE_FLAG?TRUE:FALSE; + offset_size = macro_context->mc_offset_size_flag?8:4; + macro_context->mc_offset_size = offset_size; + if (macro_context->mc_debug_line_offset_flag) { + cur_offset = (offset_size+ macro_data) - section_base; + if (cur_offset >= section_size) { + dwarf_dealloc_macro_context(macro_context); + _dwarf_error(dbg, error, DW_DLE_MACRO_OFFSET_BAD); + return DW_DLV_ERROR; + } + res = _dwarf_read_unaligned_ck_wrapper(dbg, + &line_table_offset,macro_data, + offset_size,section_end, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + macro_data += offset_size; + macro_context->mc_debug_line_offset = line_table_offset; + } + if (macro_context->mc_operands_table_flag) { + res = read_operands_table(macro_context, + macro_header, + macro_data, + section_base, + section_size, + &optablesize, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + } + + macro_data += optablesize; + macro_context->mc_macro_ops = macro_data; + macro_context->mc_macro_header_length =macro_data - macro_header; + + build_ops_array = FALSE; + res = _dwarf_get_macro_ops_count_internal(macro_context, + build_ops_array, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + build_ops_array = TRUE; + res = _dwarf_get_macro_ops_count_internal(macro_context, + build_ops_array, + error); + if (res != DW_DLV_OK) { + dwarf_dealloc_macro_context(macro_context); + return res; + } + *macro_ops_count_out = macro_context->mc_macro_ops_count; + *macro_ops_data_length = macro_context->mc_ops_data_length; + *version_out = version; + *macro_context_out = macro_context; + return DW_DLV_OK; +} + +int +dwarf_macro_context_total_length(Dwarf_Macro_Context head, + Dwarf_Unsigned * mac_total_len, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + + if (head) { + dbg = head->mc_dbg; + } + CHECKNULLCONTEXT(head,dbg,error); + *mac_total_len = head->mc_total_length; + return DW_DLV_OK; +} + +int +dwarf_macro_context_head(Dwarf_Macro_Context head, + Dwarf_Half * version, + Dwarf_Unsigned * mac_offset, + Dwarf_Unsigned * mac_len, + Dwarf_Unsigned * mac_header_len, + unsigned * flags, + Dwarf_Bool * has_line_offset, + Dwarf_Unsigned * line_offset, + Dwarf_Bool * has_offset_size_64, + Dwarf_Bool * has_operands_table, + Dwarf_Half * opcode_count, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + + CHECKNULLCONTEXT(head,dbg,error); + *version = head->mc_version_number; + *mac_offset = head->mc_section_offset; + *mac_len = head->mc_total_length; + *mac_header_len = head->mc_macro_header_length; + *flags = head->mc_flags; + *line_offset = head->mc_debug_line_offset; + *has_line_offset = head->mc_debug_line_offset_flag; + *has_offset_size_64 = head->mc_offset_size_flag; + *has_operands_table = head->mc_operands_table_flag; + *opcode_count = head->mc_opcode_count; + return DW_DLV_OK; +} +int +dwarf_macro_operands_table(Dwarf_Macro_Context head, + Dwarf_Half index, /* 0 to opcode_count -1 */ + Dwarf_Half *opcode_number, + Dwarf_Half *operand_count, + const Dwarf_Small **operand_array, + Dwarf_Error *error) +{ + struct Dwarf_Macro_Forms_s * ops = 0; + Dwarf_Debug dbg = 0; + + CHECKNULLCONTEXT(head,dbg,error); + dbg = head->mc_dbg; + if (index >= head->mc_opcode_count) { + _dwarf_error(dbg, error, DW_DLE_BAD_MACRO_INDEX); + return DW_DLV_ERROR; + } + ops = head->mc_opcode_forms + index; + *opcode_number = ops->mf_code; + *operand_count = ops->mf_formcount; + *operand_array = ops->mf_formbytes; + return DW_DLV_OK; +} + +/* The base interface to the .debug_macro section data + for a specific CU. + + The version number passed back by *version_out + may be 4 (a gnu extension of DWARF) or 5. */ +int +dwarf_get_macro_context(Dwarf_Die cu_die, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context, + Dwarf_Unsigned * macro_unit_offset_out, + Dwarf_Unsigned * macro_ops_count_out, + Dwarf_Unsigned * macro_ops_data_length, + Dwarf_Error * error) +{ + int res = 0; + Dwarf_Bool offset_specified = FALSE; + Dwarf_Unsigned offset = 0; + + res = _dwarf_internal_macro_context(cu_die, + offset_specified, + offset, + version_out, + macro_context, + macro_unit_offset_out, + macro_ops_count_out, + macro_ops_data_length, + error); + return res; +} + +/* Like dwarf_get_macro_context but + here we use a specified offset instead of + the offset in the cu_die. */ +int +dwarf_get_macro_context_by_offset(Dwarf_Die cu_die, + Dwarf_Unsigned offset, + Dwarf_Unsigned * version_out, + Dwarf_Macro_Context * macro_context, + Dwarf_Unsigned * macro_ops_count_out, + Dwarf_Unsigned * macro_ops_data_length, + Dwarf_Error * error) +{ + int res = 0; + Dwarf_Bool offset_specified = TRUE; + Dwarf_Unsigned macro_unit_offset_out = 0; + + res = _dwarf_internal_macro_context(cu_die, + offset_specified, + offset, + version_out, + macro_context, + ¯o_unit_offset_out, + macro_ops_count_out, + macro_ops_data_length, + error); + return res; +} + +int dwarf_get_macro_section_name(Dwarf_Debug dbg, + const char **sec_name_out, + Dwarf_Error *error) +{ + struct Dwarf_Section_s *sec = 0; + + (void)error; + sec = &dbg->de_debug_macro; + if (sec->dss_size == 0) { + /* We don't have such a section at all. */ + return DW_DLV_NO_ENTRY; + } + *sec_name_out = sec->dss_name; + return DW_DLV_OK; +} + +void +dwarf_dealloc_macro_context(Dwarf_Macro_Context mc) +{ + Dwarf_Debug dbg = 0; + + if (!mc) { + return; + } + dbg = mc->mc_dbg; + /* See _dwarf_macro_destructor() here */ + dwarf_dealloc(dbg,mc,DW_DLA_MACRO_CONTEXT); +} + +int +_dwarf_macro_constructor(Dwarf_Debug dbg, void *m) +{ + /* Nothing to do, the space is zeroed out */ + Dwarf_Macro_Context mc= (Dwarf_Macro_Context)m; + /* Arbitrary sentinel. For debugging. */ + mc->mc_sentinel = MC_SENTINEL; + mc->mc_dbg = dbg; + return DW_DLV_OK; +} + +/* Here we free various fields of Dwarf_Macro_Context. + The fields do not get dealloc'd. + If we had a separate destructor for hand-calling + (meaning when an error is detected during creation + of a Dwarf_Macro_Context) + and one for calling by dwarf_dealloc() then + we could have the hand-calling dwarf_dealloc the fields + and the one called on the dealloc of a Dwarf_Macro_Context + could leave the _dwarf_get_alloc() fields for for + normal dwarf_finish() cleanup. + + But for now we share this destructor for both purposes + so no fields are _dwarf_get_alloc() and all are free-d + here.. +*/ +void +_dwarf_macro_destructor(void *m) +{ + Dwarf_Macro_Context mc= (Dwarf_Macro_Context)m; + + dealloc_macro_srcfiles(mc->mc_srcfiles, mc->mc_srcfiles_count); + mc->mc_srcfiles = 0; + mc->mc_srcfiles_count = 0; + free((void *)mc->mc_file_path); + mc->mc_file_path = 0; + free(mc->mc_ops); + mc->mc_ops = 0; + free(mc->mc_opcode_forms); + mc->mc_opcode_forms = 0; + memset(mc,0,sizeof(*mc)); + /* Just a recognizable sentinel. + For debugging. No real meaning . */ + mc->mc_sentinel = 0xdeadbeef; +} diff --git a/src/lib/libdwarf/dwarf_macro5.h b/src/lib/libdwarf/dwarf_macro5.h new file mode 100644 index 0000000..fa9e453 --- /dev/null +++ b/src/lib/libdwarf/dwarf_macro5.h @@ -0,0 +1,151 @@ +/* + Copyright (C) 2015-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* + dwarf_macro5.h + For the DWARF5 .debug_macro section + (also appears as an extension to DWARF4) +*/ + +struct Dwarf_Macro_Forms_s { + /* Code means DW_MACRO_define etc. */ + Dwarf_Small mf_code; + + /* How many entries in mf_formbytes array. */ + Dwarf_Small mf_formcount; + + /* Never free these, these are in the object file memory */ + const Dwarf_Small * mf_formbytes; +}; + +struct Dwarf_Macro_OperationsList_s { + unsigned mol_count; + struct Dwarf_Macro_Forms_s * mol_data; +}; + +struct Dwarf_Macro_Operator_s { + /* mo_opcode == mo_form->mf_code unless it is + the final 0 byte in which case all 3 values + are zero */ + Dwarf_Small mo_opcode; + + struct Dwarf_Macro_Forms_s * mo_form; + + /* Points at the first byte of the data, meaning + it points one-past the macro operation code byte. */ + Dwarf_Small * mo_data; +}; + +#define MACRO_OFFSET_SIZE_FLAG 1 +#define MACRO_LINE_OFFSET_FLAG 2 +#define MACRO_OP_TABLE_FLAG 4 +#define DW_MACRO_VERSION4 4 /* GNU Extension for DWARF 4 */ +#define DW_MACRO_VERSION5 5 /* DWARF 5 */ + +/* Could be reordered to be most space efficient. + That might be a little harder to read. Hmm. */ +struct Dwarf_Macro_Context_s { + Dwarf_Unsigned mc_sentinel; + Dwarf_Half mc_version_number; + + /* Section_offset in .debug_macro of macro header */ + Dwarf_Unsigned mc_section_offset; + Dwarf_Unsigned mc_section_size; + + /* Total length of the macro data for this + macro unit. + Calculated, not part of header. */ + Dwarf_Unsigned mc_total_length; + + Dwarf_Half mc_macro_header_length; + + Dwarf_Small mc_flags; + + /* If DW_MACRO_start_file is in the operators of this + table then the mc_debug_line_offset must be present from + the header. */ + Dwarf_Unsigned mc_debug_line_offset; + + /* the following three set from the bits in mc_flags */ + /* If 1, offsets 64 bits */ + Dwarf_Bool mc_offset_size_flag; + + /* if 1, debug_line offset is present. */ + Dwarf_Bool mc_debug_line_offset_flag; + + /* 4 or 8, depending on mc_offset_size_flag */ + Dwarf_Small mc_offset_size; + + /* If one the operands/opcodes (mc_opcode_forms) table is present + in the header. If not we use a default table. + + Even when there are operands in the header + the standardops may or may not be + defined in the header. */ + Dwarf_Bool mc_operands_table_flag; + + /* Count of the Dwarf_Macro_Forms_s structs pointed to by + mc_opcode_forms. These from the header. */ + Dwarf_Small mc_opcode_count; + struct Dwarf_Macro_Forms_s *mc_opcode_forms; + + /* mc_ops must be free()d, but pointers inside + mc_ops are to static or section data so must not + be freed. */ + Dwarf_Unsigned mc_macro_ops_count; + Dwarf_Unsigned mc_ops_data_length; + struct Dwarf_Macro_Operator_s *mc_ops; + + Dwarf_Small * mc_macro_header; + Dwarf_Small * mc_macro_ops; + + /* These are malloc space, not _dwarf_get_alloc() + so the DW_DLA_MACRO_CONTEXT dealloc will + free them. */ + char ** mc_srcfiles; + Dwarf_Signed mc_srcfiles_count; + + /* These are from CU DIE attribute names. + They may be NULL or point at data in + a dwarf section. Do not free(). + This attempts to make up for the lack of a + base file name + in DWARF2,3,4 line tables. + */ + const char * mc_at_comp_dir; + const char * mc_at_name; + /* The following is malloc,so macro_context_s destructor + needs to free it. */ + const char * mc_file_path; + + Dwarf_Debug mc_dbg; + Dwarf_CU_Context mc_cu_context; +}; + +int _dwarf_macro_constructor(Dwarf_Debug dbg, void *m); +void _dwarf_macro_destructor(void *m); diff --git a/src/lib/libdwarf/dwarf_memcpy_swap.c b/src/lib/libdwarf/dwarf_memcpy_swap.c new file mode 100644 index 0000000..ad4e6d6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_memcpy_swap.c @@ -0,0 +1,74 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + Portions Copyright 2020 Google All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* size_t */ +#include /* memcpy() */ + +#include "dwarf_memcpy_swap.h" + +/* + A byte-swapping version of memcpy + for cross-endian use. + Only 2,4,8 should be lengths passed in. +*/ +void +_dwarf_memcpy_noswap_bytes(void *s1, + const void *s2, + unsigned long len) +{ + memcpy(s1,s2,(size_t)len); + return; +} + +void +_dwarf_memcpy_swap_bytes(void *s1, + const void *s2, + unsigned long len) +{ + unsigned char *targ = (unsigned char *) s1; + const unsigned char *src = (const unsigned char *) s2; + unsigned long i = 0; + unsigned long n = (long)(len-1); + + if (len > 8) { + /* Really we should not be here! + Not writing an integer, we think, so + best to not swap bytes! */ + memcpy(s1,s2,(size_t)len); + return; + } + for ( ; i < len; ++i,--n) { + targ[n] = src[i]; + } + return; +} diff --git a/src/lib/libdwarf/dwarf_memcpy_swap.h b/src/lib/libdwarf/dwarf_memcpy_swap.h new file mode 100644 index 0000000..f1a5928 --- /dev/null +++ b/src/lib/libdwarf/dwarf_memcpy_swap.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2018-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the + Free Software Foundation. + + This program is distributed in the hope that it would + be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to + this software file. Patent licenses, if any, provided + herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. +*/ + +#ifndef MEMCPY_SWAP_H +#define MEMCPY_SWAP_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void _dwarf_memcpy_swap_bytes(void *s1, const void *s2, + unsigned long len); +/* It was once inconvenient to use memcpy directly as it + uses size_t and that requires , + although stddef.h is a part of C90, so..ok. */ +void _dwarf_memcpy_noswap_bytes(void *s1, + const void *s2, unsigned long len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* MEMCPY_SWAP_H */ diff --git a/src/lib/libdwarf/dwarf_names.c b/src/lib/libdwarf/dwarf_names.c new file mode 100644 index 0000000..0761867 --- /dev/null +++ b/src/lib/libdwarf/dwarf_names.c @@ -0,0 +1,3834 @@ +/* Generated routines, do not edit. */ +/* Generated for source version 0.9.0 */ + +/* BEGIN FILE */ + +#include "dwarf.h" + +#include "libdwarf.h" + +/* ARGSUSED */ +int +dwarf_get_TAG_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_TAG_array_type: + *s_out = "DW_TAG_array_type"; + return DW_DLV_OK; + case DW_TAG_class_type: + *s_out = "DW_TAG_class_type"; + return DW_DLV_OK; + case DW_TAG_entry_point: + *s_out = "DW_TAG_entry_point"; + return DW_DLV_OK; + case DW_TAG_enumeration_type: + *s_out = "DW_TAG_enumeration_type"; + return DW_DLV_OK; + case DW_TAG_formal_parameter: + *s_out = "DW_TAG_formal_parameter"; + return DW_DLV_OK; + case DW_TAG_imported_declaration: + *s_out = "DW_TAG_imported_declaration"; + return DW_DLV_OK; + case DW_TAG_label: + *s_out = "DW_TAG_label"; + return DW_DLV_OK; + case DW_TAG_lexical_block: + *s_out = "DW_TAG_lexical_block"; + return DW_DLV_OK; + case DW_TAG_member: + *s_out = "DW_TAG_member"; + return DW_DLV_OK; + case DW_TAG_pointer_type: + *s_out = "DW_TAG_pointer_type"; + return DW_DLV_OK; + case DW_TAG_reference_type: + *s_out = "DW_TAG_reference_type"; + return DW_DLV_OK; + case DW_TAG_compile_unit: + *s_out = "DW_TAG_compile_unit"; + return DW_DLV_OK; + case DW_TAG_string_type: + *s_out = "DW_TAG_string_type"; + return DW_DLV_OK; + case DW_TAG_structure_type: + *s_out = "DW_TAG_structure_type"; + return DW_DLV_OK; + case DW_TAG_subroutine_type: + *s_out = "DW_TAG_subroutine_type"; + return DW_DLV_OK; + case DW_TAG_typedef: + *s_out = "DW_TAG_typedef"; + return DW_DLV_OK; + case DW_TAG_union_type: + *s_out = "DW_TAG_union_type"; + return DW_DLV_OK; + case DW_TAG_unspecified_parameters: + *s_out = "DW_TAG_unspecified_parameters"; + return DW_DLV_OK; + case DW_TAG_variant: + *s_out = "DW_TAG_variant"; + return DW_DLV_OK; + case DW_TAG_common_block: + *s_out = "DW_TAG_common_block"; + return DW_DLV_OK; + case DW_TAG_common_inclusion: + *s_out = "DW_TAG_common_inclusion"; + return DW_DLV_OK; + case DW_TAG_inheritance: + *s_out = "DW_TAG_inheritance"; + return DW_DLV_OK; + case DW_TAG_inlined_subroutine: + *s_out = "DW_TAG_inlined_subroutine"; + return DW_DLV_OK; + case DW_TAG_module: + *s_out = "DW_TAG_module"; + return DW_DLV_OK; + case DW_TAG_ptr_to_member_type: + *s_out = "DW_TAG_ptr_to_member_type"; + return DW_DLV_OK; + case DW_TAG_set_type: + *s_out = "DW_TAG_set_type"; + return DW_DLV_OK; + case DW_TAG_subrange_type: + *s_out = "DW_TAG_subrange_type"; + return DW_DLV_OK; + case DW_TAG_with_stmt: + *s_out = "DW_TAG_with_stmt"; + return DW_DLV_OK; + case DW_TAG_access_declaration: + *s_out = "DW_TAG_access_declaration"; + return DW_DLV_OK; + case DW_TAG_base_type: + *s_out = "DW_TAG_base_type"; + return DW_DLV_OK; + case DW_TAG_catch_block: + *s_out = "DW_TAG_catch_block"; + return DW_DLV_OK; + case DW_TAG_const_type: + *s_out = "DW_TAG_const_type"; + return DW_DLV_OK; + case DW_TAG_constant: + *s_out = "DW_TAG_constant"; + return DW_DLV_OK; + case DW_TAG_enumerator: + *s_out = "DW_TAG_enumerator"; + return DW_DLV_OK; + case DW_TAG_file_type: + *s_out = "DW_TAG_file_type"; + return DW_DLV_OK; + case DW_TAG_friend: + *s_out = "DW_TAG_friend"; + return DW_DLV_OK; + case DW_TAG_namelist: + *s_out = "DW_TAG_namelist"; + return DW_DLV_OK; + case DW_TAG_namelist_item: + *s_out = "DW_TAG_namelist_item"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2c. DW_TAG_namelist_items */ + case DW_TAG_packed_type: + *s_out = "DW_TAG_packed_type"; + return DW_DLV_OK; + case DW_TAG_subprogram: + *s_out = "DW_TAG_subprogram"; + return DW_DLV_OK; + case DW_TAG_template_type_parameter: + *s_out = "DW_TAG_template_type_parameter"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2f. DW_TAG_template_type_param */ + case DW_TAG_template_value_parameter: + *s_out = "DW_TAG_template_value_parameter"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x30. DW_TAG_template_value_param */ + case DW_TAG_thrown_type: + *s_out = "DW_TAG_thrown_type"; + return DW_DLV_OK; + case DW_TAG_try_block: + *s_out = "DW_TAG_try_block"; + return DW_DLV_OK; + case DW_TAG_variant_part: + *s_out = "DW_TAG_variant_part"; + return DW_DLV_OK; + case DW_TAG_variable: + *s_out = "DW_TAG_variable"; + return DW_DLV_OK; + case DW_TAG_volatile_type: + *s_out = "DW_TAG_volatile_type"; + return DW_DLV_OK; + case DW_TAG_dwarf_procedure: + *s_out = "DW_TAG_dwarf_procedure"; + return DW_DLV_OK; + case DW_TAG_restrict_type: + *s_out = "DW_TAG_restrict_type"; + return DW_DLV_OK; + case DW_TAG_interface_type: + *s_out = "DW_TAG_interface_type"; + return DW_DLV_OK; + case DW_TAG_namespace: + *s_out = "DW_TAG_namespace"; + return DW_DLV_OK; + case DW_TAG_imported_module: + *s_out = "DW_TAG_imported_module"; + return DW_DLV_OK; + case DW_TAG_unspecified_type: + *s_out = "DW_TAG_unspecified_type"; + return DW_DLV_OK; + case DW_TAG_partial_unit: + *s_out = "DW_TAG_partial_unit"; + return DW_DLV_OK; + case DW_TAG_imported_unit: + *s_out = "DW_TAG_imported_unit"; + return DW_DLV_OK; + case DW_TAG_mutable_type: + *s_out = "DW_TAG_mutable_type"; + return DW_DLV_OK; + case DW_TAG_condition: + *s_out = "DW_TAG_condition"; + return DW_DLV_OK; + case DW_TAG_shared_type: + *s_out = "DW_TAG_shared_type"; + return DW_DLV_OK; + case DW_TAG_type_unit: + *s_out = "DW_TAG_type_unit"; + return DW_DLV_OK; + case DW_TAG_rvalue_reference_type: + *s_out = "DW_TAG_rvalue_reference_type"; + return DW_DLV_OK; + case DW_TAG_template_alias: + *s_out = "DW_TAG_template_alias"; + return DW_DLV_OK; + case DW_TAG_coarray_type: + *s_out = "DW_TAG_coarray_type"; + return DW_DLV_OK; + case DW_TAG_generic_subrange: + *s_out = "DW_TAG_generic_subrange"; + return DW_DLV_OK; + case DW_TAG_dynamic_type: + *s_out = "DW_TAG_dynamic_type"; + return DW_DLV_OK; + case DW_TAG_atomic_type: + *s_out = "DW_TAG_atomic_type"; + return DW_DLV_OK; + case DW_TAG_call_site: + *s_out = "DW_TAG_call_site"; + return DW_DLV_OK; + case DW_TAG_call_site_parameter: + *s_out = "DW_TAG_call_site_parameter"; + return DW_DLV_OK; + case DW_TAG_skeleton_unit: + *s_out = "DW_TAG_skeleton_unit"; + return DW_DLV_OK; + case DW_TAG_immutable_type: + *s_out = "DW_TAG_immutable_type"; + return DW_DLV_OK; + case DW_TAG_lo_user: + *s_out = "DW_TAG_lo_user"; + return DW_DLV_OK; + case DW_TAG_MIPS_loop: + *s_out = "DW_TAG_MIPS_loop"; + return DW_DLV_OK; + case DW_TAG_HP_array_descriptor: + *s_out = "DW_TAG_HP_array_descriptor"; + return DW_DLV_OK; + case DW_TAG_format_label: + *s_out = "DW_TAG_format_label"; + return DW_DLV_OK; + case DW_TAG_function_template: + *s_out = "DW_TAG_function_template"; + return DW_DLV_OK; + case DW_TAG_class_template: + *s_out = "DW_TAG_class_template"; + return DW_DLV_OK; + case DW_TAG_GNU_BINCL: + *s_out = "DW_TAG_GNU_BINCL"; + return DW_DLV_OK; + case DW_TAG_GNU_EINCL: + *s_out = "DW_TAG_GNU_EINCL"; + return DW_DLV_OK; + case DW_TAG_GNU_template_template_parameter: + *s_out = "DW_TAG_GNU_template_template_parameter"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x4106. DW_TAG_GNU_template_template_param */ + case DW_TAG_GNU_template_parameter_pack: + *s_out = "DW_TAG_GNU_template_parameter_pack"; + return DW_DLV_OK; + case DW_TAG_GNU_formal_parameter_pack: + *s_out = "DW_TAG_GNU_formal_parameter_pack"; + return DW_DLV_OK; + case DW_TAG_GNU_call_site: + *s_out = "DW_TAG_GNU_call_site"; + return DW_DLV_OK; + case DW_TAG_GNU_call_site_parameter: + *s_out = "DW_TAG_GNU_call_site_parameter"; + return DW_DLV_OK; + case DW_TAG_SUN_function_template: + *s_out = "DW_TAG_SUN_function_template"; + return DW_DLV_OK; + case DW_TAG_SUN_class_template: + *s_out = "DW_TAG_SUN_class_template"; + return DW_DLV_OK; + case DW_TAG_SUN_struct_template: + *s_out = "DW_TAG_SUN_struct_template"; + return DW_DLV_OK; + case DW_TAG_SUN_union_template: + *s_out = "DW_TAG_SUN_union_template"; + return DW_DLV_OK; + case DW_TAG_SUN_indirect_inheritance: + *s_out = "DW_TAG_SUN_indirect_inheritance"; + return DW_DLV_OK; + case DW_TAG_SUN_codeflags: + *s_out = "DW_TAG_SUN_codeflags"; + return DW_DLV_OK; + case DW_TAG_SUN_memop_info: + *s_out = "DW_TAG_SUN_memop_info"; + return DW_DLV_OK; + case DW_TAG_SUN_omp_child_func: + *s_out = "DW_TAG_SUN_omp_child_func"; + return DW_DLV_OK; + case DW_TAG_SUN_rtti_descriptor: + *s_out = "DW_TAG_SUN_rtti_descriptor"; + return DW_DLV_OK; + case DW_TAG_SUN_dtor_info: + *s_out = "DW_TAG_SUN_dtor_info"; + return DW_DLV_OK; + case DW_TAG_SUN_dtor: + *s_out = "DW_TAG_SUN_dtor"; + return DW_DLV_OK; + case DW_TAG_SUN_f90_interface: + *s_out = "DW_TAG_SUN_f90_interface"; + return DW_DLV_OK; + case DW_TAG_SUN_fortran_vax_structure: + *s_out = "DW_TAG_SUN_fortran_vax_structure"; + return DW_DLV_OK; + case DW_TAG_SUN_hi: + *s_out = "DW_TAG_SUN_hi"; + return DW_DLV_OK; + case DW_TAG_ALTIUM_circ_type: + *s_out = "DW_TAG_ALTIUM_circ_type"; + return DW_DLV_OK; + case DW_TAG_ALTIUM_mwa_circ_type: + *s_out = "DW_TAG_ALTIUM_mwa_circ_type"; + return DW_DLV_OK; + case DW_TAG_ALTIUM_rev_carry_type: + *s_out = "DW_TAG_ALTIUM_rev_carry_type"; + return DW_DLV_OK; + case DW_TAG_ALTIUM_rom: + *s_out = "DW_TAG_ALTIUM_rom"; + return DW_DLV_OK; + case DW_TAG_LLVM_annotation: + *s_out = "DW_TAG_LLVM_annotation"; + return DW_DLV_OK; + case DW_TAG_ghs_namespace: + *s_out = "DW_TAG_ghs_namespace"; + return DW_DLV_OK; + case DW_TAG_ghs_using_namespace: + *s_out = "DW_TAG_ghs_using_namespace"; + return DW_DLV_OK; + case DW_TAG_ghs_using_declaration: + *s_out = "DW_TAG_ghs_using_declaration"; + return DW_DLV_OK; + case DW_TAG_ghs_template_templ_param: + *s_out = "DW_TAG_ghs_template_templ_param"; + return DW_DLV_OK; + case DW_TAG_upc_shared_type: + *s_out = "DW_TAG_upc_shared_type"; + return DW_DLV_OK; + case DW_TAG_upc_strict_type: + *s_out = "DW_TAG_upc_strict_type"; + return DW_DLV_OK; + case DW_TAG_upc_relaxed_type: + *s_out = "DW_TAG_upc_relaxed_type"; + return DW_DLV_OK; + case DW_TAG_PGI_kanji_type: + *s_out = "DW_TAG_PGI_kanji_type"; + return DW_DLV_OK; + case DW_TAG_PGI_interface_block: + *s_out = "DW_TAG_PGI_interface_block"; + return DW_DLV_OK; + case DW_TAG_BORLAND_property: + *s_out = "DW_TAG_BORLAND_property"; + return DW_DLV_OK; + case DW_TAG_BORLAND_Delphi_string: + *s_out = "DW_TAG_BORLAND_Delphi_string"; + return DW_DLV_OK; + case DW_TAG_BORLAND_Delphi_dynamic_array: + *s_out = "DW_TAG_BORLAND_Delphi_dynamic_array"; + return DW_DLV_OK; + case DW_TAG_BORLAND_Delphi_set: + *s_out = "DW_TAG_BORLAND_Delphi_set"; + return DW_DLV_OK; + case DW_TAG_BORLAND_Delphi_variant: + *s_out = "DW_TAG_BORLAND_Delphi_variant"; + return DW_DLV_OK; + case DW_TAG_hi_user: + *s_out = "DW_TAG_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_children_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_children_no: + *s_out = "DW_children_no"; + return DW_DLV_OK; + case DW_children_yes: + *s_out = "DW_children_yes"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_FORM_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_FORM_addr: + *s_out = "DW_FORM_addr"; + return DW_DLV_OK; + case DW_FORM_block2: + *s_out = "DW_FORM_block2"; + return DW_DLV_OK; + case DW_FORM_block4: + *s_out = "DW_FORM_block4"; + return DW_DLV_OK; + case DW_FORM_data2: + *s_out = "DW_FORM_data2"; + return DW_DLV_OK; + case DW_FORM_data4: + *s_out = "DW_FORM_data4"; + return DW_DLV_OK; + case DW_FORM_data8: + *s_out = "DW_FORM_data8"; + return DW_DLV_OK; + case DW_FORM_string: + *s_out = "DW_FORM_string"; + return DW_DLV_OK; + case DW_FORM_block: + *s_out = "DW_FORM_block"; + return DW_DLV_OK; + case DW_FORM_block1: + *s_out = "DW_FORM_block1"; + return DW_DLV_OK; + case DW_FORM_data1: + *s_out = "DW_FORM_data1"; + return DW_DLV_OK; + case DW_FORM_flag: + *s_out = "DW_FORM_flag"; + return DW_DLV_OK; + case DW_FORM_sdata: + *s_out = "DW_FORM_sdata"; + return DW_DLV_OK; + case DW_FORM_strp: + *s_out = "DW_FORM_strp"; + return DW_DLV_OK; + case DW_FORM_udata: + *s_out = "DW_FORM_udata"; + return DW_DLV_OK; + case DW_FORM_ref_addr: + *s_out = "DW_FORM_ref_addr"; + return DW_DLV_OK; + case DW_FORM_ref1: + *s_out = "DW_FORM_ref1"; + return DW_DLV_OK; + case DW_FORM_ref2: + *s_out = "DW_FORM_ref2"; + return DW_DLV_OK; + case DW_FORM_ref4: + *s_out = "DW_FORM_ref4"; + return DW_DLV_OK; + case DW_FORM_ref8: + *s_out = "DW_FORM_ref8"; + return DW_DLV_OK; + case DW_FORM_ref_udata: + *s_out = "DW_FORM_ref_udata"; + return DW_DLV_OK; + case DW_FORM_indirect: + *s_out = "DW_FORM_indirect"; + return DW_DLV_OK; + case DW_FORM_sec_offset: + *s_out = "DW_FORM_sec_offset"; + return DW_DLV_OK; + case DW_FORM_exprloc: + *s_out = "DW_FORM_exprloc"; + return DW_DLV_OK; + case DW_FORM_flag_present: + *s_out = "DW_FORM_flag_present"; + return DW_DLV_OK; + case DW_FORM_strx: + *s_out = "DW_FORM_strx"; + return DW_DLV_OK; + case DW_FORM_addrx: + *s_out = "DW_FORM_addrx"; + return DW_DLV_OK; + case DW_FORM_ref_sup4: + *s_out = "DW_FORM_ref_sup4"; + return DW_DLV_OK; + case DW_FORM_strp_sup: + *s_out = "DW_FORM_strp_sup"; + return DW_DLV_OK; + case DW_FORM_data16: + *s_out = "DW_FORM_data16"; + return DW_DLV_OK; + case DW_FORM_line_strp: + *s_out = "DW_FORM_line_strp"; + return DW_DLV_OK; + case DW_FORM_ref_sig8: + *s_out = "DW_FORM_ref_sig8"; + return DW_DLV_OK; + case DW_FORM_implicit_const: + *s_out = "DW_FORM_implicit_const"; + return DW_DLV_OK; + case DW_FORM_loclistx: + *s_out = "DW_FORM_loclistx"; + return DW_DLV_OK; + case DW_FORM_rnglistx: + *s_out = "DW_FORM_rnglistx"; + return DW_DLV_OK; + case DW_FORM_ref_sup8: + *s_out = "DW_FORM_ref_sup8"; + return DW_DLV_OK; + case DW_FORM_strx1: + *s_out = "DW_FORM_strx1"; + return DW_DLV_OK; + case DW_FORM_strx2: + *s_out = "DW_FORM_strx2"; + return DW_DLV_OK; + case DW_FORM_strx3: + *s_out = "DW_FORM_strx3"; + return DW_DLV_OK; + case DW_FORM_strx4: + *s_out = "DW_FORM_strx4"; + return DW_DLV_OK; + case DW_FORM_addrx1: + *s_out = "DW_FORM_addrx1"; + return DW_DLV_OK; + case DW_FORM_addrx2: + *s_out = "DW_FORM_addrx2"; + return DW_DLV_OK; + case DW_FORM_addrx3: + *s_out = "DW_FORM_addrx3"; + return DW_DLV_OK; + case DW_FORM_addrx4: + *s_out = "DW_FORM_addrx4"; + return DW_DLV_OK; + case DW_FORM_GNU_addr_index: + *s_out = "DW_FORM_GNU_addr_index"; + return DW_DLV_OK; + case DW_FORM_GNU_str_index: + *s_out = "DW_FORM_GNU_str_index"; + return DW_DLV_OK; + case DW_FORM_GNU_ref_alt: + *s_out = "DW_FORM_GNU_ref_alt"; + return DW_DLV_OK; + case DW_FORM_GNU_strp_alt: + *s_out = "DW_FORM_GNU_strp_alt"; + return DW_DLV_OK; + case DW_FORM_LLVM_addrx_offset: + *s_out = "DW_FORM_LLVM_addrx_offset"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_AT_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_AT_sibling: + *s_out = "DW_AT_sibling"; + return DW_DLV_OK; + case DW_AT_location: + *s_out = "DW_AT_location"; + return DW_DLV_OK; + case DW_AT_name: + *s_out = "DW_AT_name"; + return DW_DLV_OK; + case DW_AT_ordering: + *s_out = "DW_AT_ordering"; + return DW_DLV_OK; + case DW_AT_subscr_data: + *s_out = "DW_AT_subscr_data"; + return DW_DLV_OK; + case DW_AT_byte_size: + *s_out = "DW_AT_byte_size"; + return DW_DLV_OK; + case DW_AT_bit_offset: + *s_out = "DW_AT_bit_offset"; + return DW_DLV_OK; + case DW_AT_bit_size: + *s_out = "DW_AT_bit_size"; + return DW_DLV_OK; + case DW_AT_element_list: + *s_out = "DW_AT_element_list"; + return DW_DLV_OK; + case DW_AT_stmt_list: + *s_out = "DW_AT_stmt_list"; + return DW_DLV_OK; + case DW_AT_low_pc: + *s_out = "DW_AT_low_pc"; + return DW_DLV_OK; + case DW_AT_high_pc: + *s_out = "DW_AT_high_pc"; + return DW_DLV_OK; + case DW_AT_language: + *s_out = "DW_AT_language"; + return DW_DLV_OK; + case DW_AT_member: + *s_out = "DW_AT_member"; + return DW_DLV_OK; + case DW_AT_discr: + *s_out = "DW_AT_discr"; + return DW_DLV_OK; + case DW_AT_discr_value: + *s_out = "DW_AT_discr_value"; + return DW_DLV_OK; + case DW_AT_visibility: + *s_out = "DW_AT_visibility"; + return DW_DLV_OK; + case DW_AT_import: + *s_out = "DW_AT_import"; + return DW_DLV_OK; + case DW_AT_string_length: + *s_out = "DW_AT_string_length"; + return DW_DLV_OK; + case DW_AT_common_reference: + *s_out = "DW_AT_common_reference"; + return DW_DLV_OK; + case DW_AT_comp_dir: + *s_out = "DW_AT_comp_dir"; + return DW_DLV_OK; + case DW_AT_const_value: + *s_out = "DW_AT_const_value"; + return DW_DLV_OK; + case DW_AT_containing_type: + *s_out = "DW_AT_containing_type"; + return DW_DLV_OK; + case DW_AT_default_value: + *s_out = "DW_AT_default_value"; + return DW_DLV_OK; + case DW_AT_inline: + *s_out = "DW_AT_inline"; + return DW_DLV_OK; + case DW_AT_is_optional: + *s_out = "DW_AT_is_optional"; + return DW_DLV_OK; + case DW_AT_lower_bound: + *s_out = "DW_AT_lower_bound"; + return DW_DLV_OK; + case DW_AT_producer: + *s_out = "DW_AT_producer"; + return DW_DLV_OK; + case DW_AT_prototyped: + *s_out = "DW_AT_prototyped"; + return DW_DLV_OK; + case DW_AT_return_addr: + *s_out = "DW_AT_return_addr"; + return DW_DLV_OK; + case DW_AT_start_scope: + *s_out = "DW_AT_start_scope"; + return DW_DLV_OK; + case DW_AT_bit_stride: + *s_out = "DW_AT_bit_stride"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2e. DW_AT_stride_size */ + case DW_AT_upper_bound: + *s_out = "DW_AT_upper_bound"; + return DW_DLV_OK; + case DW_AT_abstract_origin: + *s_out = "DW_AT_abstract_origin"; + return DW_DLV_OK; + case DW_AT_accessibility: + *s_out = "DW_AT_accessibility"; + return DW_DLV_OK; + case DW_AT_address_class: + *s_out = "DW_AT_address_class"; + return DW_DLV_OK; + case DW_AT_artificial: + *s_out = "DW_AT_artificial"; + return DW_DLV_OK; + case DW_AT_base_types: + *s_out = "DW_AT_base_types"; + return DW_DLV_OK; + case DW_AT_calling_convention: + *s_out = "DW_AT_calling_convention"; + return DW_DLV_OK; + case DW_AT_count: + *s_out = "DW_AT_count"; + return DW_DLV_OK; + case DW_AT_data_member_location: + *s_out = "DW_AT_data_member_location"; + return DW_DLV_OK; + case DW_AT_decl_column: + *s_out = "DW_AT_decl_column"; + return DW_DLV_OK; + case DW_AT_decl_file: + *s_out = "DW_AT_decl_file"; + return DW_DLV_OK; + case DW_AT_decl_line: + *s_out = "DW_AT_decl_line"; + return DW_DLV_OK; + case DW_AT_declaration: + *s_out = "DW_AT_declaration"; + return DW_DLV_OK; + case DW_AT_discr_list: + *s_out = "DW_AT_discr_list"; + return DW_DLV_OK; + case DW_AT_encoding: + *s_out = "DW_AT_encoding"; + return DW_DLV_OK; + case DW_AT_external: + *s_out = "DW_AT_external"; + return DW_DLV_OK; + case DW_AT_frame_base: + *s_out = "DW_AT_frame_base"; + return DW_DLV_OK; + case DW_AT_friend: + *s_out = "DW_AT_friend"; + return DW_DLV_OK; + case DW_AT_identifier_case: + *s_out = "DW_AT_identifier_case"; + return DW_DLV_OK; + case DW_AT_macro_info: + *s_out = "DW_AT_macro_info"; + return DW_DLV_OK; + case DW_AT_namelist_item: + *s_out = "DW_AT_namelist_item"; + return DW_DLV_OK; + case DW_AT_priority: + *s_out = "DW_AT_priority"; + return DW_DLV_OK; + case DW_AT_segment: + *s_out = "DW_AT_segment"; + return DW_DLV_OK; + case DW_AT_specification: + *s_out = "DW_AT_specification"; + return DW_DLV_OK; + case DW_AT_static_link: + *s_out = "DW_AT_static_link"; + return DW_DLV_OK; + case DW_AT_type: + *s_out = "DW_AT_type"; + return DW_DLV_OK; + case DW_AT_use_location: + *s_out = "DW_AT_use_location"; + return DW_DLV_OK; + case DW_AT_variable_parameter: + *s_out = "DW_AT_variable_parameter"; + return DW_DLV_OK; + case DW_AT_virtuality: + *s_out = "DW_AT_virtuality"; + return DW_DLV_OK; + case DW_AT_vtable_elem_location: + *s_out = "DW_AT_vtable_elem_location"; + return DW_DLV_OK; + case DW_AT_allocated: + *s_out = "DW_AT_allocated"; + return DW_DLV_OK; + case DW_AT_associated: + *s_out = "DW_AT_associated"; + return DW_DLV_OK; + case DW_AT_data_location: + *s_out = "DW_AT_data_location"; + return DW_DLV_OK; + case DW_AT_byte_stride: + *s_out = "DW_AT_byte_stride"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x51. DW_AT_stride */ + case DW_AT_entry_pc: + *s_out = "DW_AT_entry_pc"; + return DW_DLV_OK; + case DW_AT_use_UTF8: + *s_out = "DW_AT_use_UTF8"; + return DW_DLV_OK; + case DW_AT_extension: + *s_out = "DW_AT_extension"; + return DW_DLV_OK; + case DW_AT_ranges: + *s_out = "DW_AT_ranges"; + return DW_DLV_OK; + case DW_AT_trampoline: + *s_out = "DW_AT_trampoline"; + return DW_DLV_OK; + case DW_AT_call_column: + *s_out = "DW_AT_call_column"; + return DW_DLV_OK; + case DW_AT_call_file: + *s_out = "DW_AT_call_file"; + return DW_DLV_OK; + case DW_AT_call_line: + *s_out = "DW_AT_call_line"; + return DW_DLV_OK; + case DW_AT_description: + *s_out = "DW_AT_description"; + return DW_DLV_OK; + case DW_AT_binary_scale: + *s_out = "DW_AT_binary_scale"; + return DW_DLV_OK; + case DW_AT_decimal_scale: + *s_out = "DW_AT_decimal_scale"; + return DW_DLV_OK; + case DW_AT_small: + *s_out = "DW_AT_small"; + return DW_DLV_OK; + case DW_AT_decimal_sign: + *s_out = "DW_AT_decimal_sign"; + return DW_DLV_OK; + case DW_AT_digit_count: + *s_out = "DW_AT_digit_count"; + return DW_DLV_OK; + case DW_AT_picture_string: + *s_out = "DW_AT_picture_string"; + return DW_DLV_OK; + case DW_AT_mutable: + *s_out = "DW_AT_mutable"; + return DW_DLV_OK; + case DW_AT_threads_scaled: + *s_out = "DW_AT_threads_scaled"; + return DW_DLV_OK; + case DW_AT_explicit: + *s_out = "DW_AT_explicit"; + return DW_DLV_OK; + case DW_AT_object_pointer: + *s_out = "DW_AT_object_pointer"; + return DW_DLV_OK; + case DW_AT_endianity: + *s_out = "DW_AT_endianity"; + return DW_DLV_OK; + case DW_AT_elemental: + *s_out = "DW_AT_elemental"; + return DW_DLV_OK; + case DW_AT_pure: + *s_out = "DW_AT_pure"; + return DW_DLV_OK; + case DW_AT_recursive: + *s_out = "DW_AT_recursive"; + return DW_DLV_OK; + case DW_AT_signature: + *s_out = "DW_AT_signature"; + return DW_DLV_OK; + case DW_AT_main_subprogram: + *s_out = "DW_AT_main_subprogram"; + return DW_DLV_OK; + case DW_AT_data_bit_offset: + *s_out = "DW_AT_data_bit_offset"; + return DW_DLV_OK; + case DW_AT_const_expr: + *s_out = "DW_AT_const_expr"; + return DW_DLV_OK; + case DW_AT_enum_class: + *s_out = "DW_AT_enum_class"; + return DW_DLV_OK; + case DW_AT_linkage_name: + *s_out = "DW_AT_linkage_name"; + return DW_DLV_OK; + case DW_AT_string_length_bit_size: + *s_out = "DW_AT_string_length_bit_size"; + return DW_DLV_OK; + case DW_AT_string_length_byte_size: + *s_out = "DW_AT_string_length_byte_size"; + return DW_DLV_OK; + case DW_AT_rank: + *s_out = "DW_AT_rank"; + return DW_DLV_OK; + case DW_AT_str_offsets_base: + *s_out = "DW_AT_str_offsets_base"; + return DW_DLV_OK; + case DW_AT_addr_base: + *s_out = "DW_AT_addr_base"; + return DW_DLV_OK; + case DW_AT_rnglists_base: + *s_out = "DW_AT_rnglists_base"; + return DW_DLV_OK; + case DW_AT_dwo_id: + *s_out = "DW_AT_dwo_id"; + return DW_DLV_OK; + case DW_AT_dwo_name: + *s_out = "DW_AT_dwo_name"; + return DW_DLV_OK; + case DW_AT_reference: + *s_out = "DW_AT_reference"; + return DW_DLV_OK; + case DW_AT_rvalue_reference: + *s_out = "DW_AT_rvalue_reference"; + return DW_DLV_OK; + case DW_AT_macros: + *s_out = "DW_AT_macros"; + return DW_DLV_OK; + case DW_AT_call_all_calls: + *s_out = "DW_AT_call_all_calls"; + return DW_DLV_OK; + case DW_AT_call_all_source_calls: + *s_out = "DW_AT_call_all_source_calls"; + return DW_DLV_OK; + case DW_AT_call_all_tail_calls: + *s_out = "DW_AT_call_all_tail_calls"; + return DW_DLV_OK; + case DW_AT_call_return_pc: + *s_out = "DW_AT_call_return_pc"; + return DW_DLV_OK; + case DW_AT_call_value: + *s_out = "DW_AT_call_value"; + return DW_DLV_OK; + case DW_AT_call_origin: + *s_out = "DW_AT_call_origin"; + return DW_DLV_OK; + case DW_AT_call_parameter: + *s_out = "DW_AT_call_parameter"; + return DW_DLV_OK; + case DW_AT_call_pc: + *s_out = "DW_AT_call_pc"; + return DW_DLV_OK; + case DW_AT_call_tail_call: + *s_out = "DW_AT_call_tail_call"; + return DW_DLV_OK; + case DW_AT_call_target: + *s_out = "DW_AT_call_target"; + return DW_DLV_OK; + case DW_AT_call_target_clobbered: + *s_out = "DW_AT_call_target_clobbered"; + return DW_DLV_OK; + case DW_AT_call_data_location: + *s_out = "DW_AT_call_data_location"; + return DW_DLV_OK; + case DW_AT_call_data_value: + *s_out = "DW_AT_call_data_value"; + return DW_DLV_OK; + case DW_AT_noreturn: + *s_out = "DW_AT_noreturn"; + return DW_DLV_OK; + case DW_AT_alignment: + *s_out = "DW_AT_alignment"; + return DW_DLV_OK; + case DW_AT_export_symbols: + *s_out = "DW_AT_export_symbols"; + return DW_DLV_OK; + case DW_AT_deleted: + *s_out = "DW_AT_deleted"; + return DW_DLV_OK; + case DW_AT_defaulted: + *s_out = "DW_AT_defaulted"; + return DW_DLV_OK; + case DW_AT_loclists_base: + *s_out = "DW_AT_loclists_base"; + return DW_DLV_OK; + case DW_AT_ghs_namespace_alias: + *s_out = "DW_AT_ghs_namespace_alias"; + return DW_DLV_OK; + case DW_AT_ghs_using_namespace: + *s_out = "DW_AT_ghs_using_namespace"; + return DW_DLV_OK; + case DW_AT_ghs_using_declaration: + *s_out = "DW_AT_ghs_using_declaration"; + return DW_DLV_OK; + case DW_AT_HP_block_index: + *s_out = "DW_AT_HP_block_index"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2000. DW_AT_lo_user */ + case DW_AT_MIPS_fde: + *s_out = "DW_AT_MIPS_fde"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2001. DW_AT_HP_unmodifiable */ + /* Skipping alternate spelling of value + 0x2001. DW_AT_CPQ_discontig_ranges */ + case DW_AT_MIPS_loop_begin: + *s_out = "DW_AT_MIPS_loop_begin"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2002. DW_AT_CPQ_semantic_events */ + case DW_AT_MIPS_tail_loop_begin: + *s_out = "DW_AT_MIPS_tail_loop_begin"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2003. DW_AT_CPQ_split_lifetimes_var */ + case DW_AT_MIPS_epilog_begin: + *s_out = "DW_AT_MIPS_epilog_begin"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2004. DW_AT_CPQ_split_lifetimes_rtn */ + case DW_AT_MIPS_loop_unroll_factor: + *s_out = "DW_AT_MIPS_loop_unroll_factor"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2005. DW_AT_HP_prologue */ + /* Skipping alternate spelling of value + 0x2005. DW_AT_CPQ_prologue_length */ + case DW_AT_MIPS_software_pipeline_depth: + *s_out = "DW_AT_MIPS_software_pipeline_depth"; + return DW_DLV_OK; + case DW_AT_MIPS_linkage_name: + *s_out = "DW_AT_MIPS_linkage_name"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2007. DW_AT_ghs_mangled */ + case DW_AT_MIPS_stride: + *s_out = "DW_AT_MIPS_stride"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2008. DW_AT_HP_epilogue */ + case DW_AT_MIPS_abstract_name: + *s_out = "DW_AT_MIPS_abstract_name"; + return DW_DLV_OK; + case DW_AT_MIPS_clone_origin: + *s_out = "DW_AT_MIPS_clone_origin"; + return DW_DLV_OK; + case DW_AT_MIPS_has_inlines: + *s_out = "DW_AT_MIPS_has_inlines"; + return DW_DLV_OK; + case DW_AT_MIPS_stride_byte: + *s_out = "DW_AT_MIPS_stride_byte"; + return DW_DLV_OK; + case DW_AT_MIPS_stride_elem: + *s_out = "DW_AT_MIPS_stride_elem"; + return DW_DLV_OK; + case DW_AT_MIPS_ptr_dopetype: + *s_out = "DW_AT_MIPS_ptr_dopetype"; + return DW_DLV_OK; + case DW_AT_MIPS_allocatable_dopetype: + *s_out = "DW_AT_MIPS_allocatable_dopetype"; + return DW_DLV_OK; + case DW_AT_MIPS_assumed_shape_dopetype: + *s_out = "DW_AT_MIPS_assumed_shape_dopetype"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2010. DW_AT_HP_actuals_stmt_list */ + case DW_AT_MIPS_assumed_size: + *s_out = "DW_AT_MIPS_assumed_size"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2011. DW_AT_HP_proc_per_section */ + case DW_AT_HP_raw_data_ptr: + *s_out = "DW_AT_HP_raw_data_ptr"; + return DW_DLV_OK; + case DW_AT_HP_pass_by_reference: + *s_out = "DW_AT_HP_pass_by_reference"; + return DW_DLV_OK; + case DW_AT_HP_opt_level: + *s_out = "DW_AT_HP_opt_level"; + return DW_DLV_OK; + case DW_AT_HP_prof_version_id: + *s_out = "DW_AT_HP_prof_version_id"; + return DW_DLV_OK; + case DW_AT_HP_opt_flags: + *s_out = "DW_AT_HP_opt_flags"; + return DW_DLV_OK; + case DW_AT_HP_cold_region_low_pc: + *s_out = "DW_AT_HP_cold_region_low_pc"; + return DW_DLV_OK; + case DW_AT_HP_cold_region_high_pc: + *s_out = "DW_AT_HP_cold_region_high_pc"; + return DW_DLV_OK; + case DW_AT_HP_all_variables_modifiable: + *s_out = "DW_AT_HP_all_variables_modifiable"; + return DW_DLV_OK; + case DW_AT_HP_linkage_name: + *s_out = "DW_AT_HP_linkage_name"; + return DW_DLV_OK; + case DW_AT_HP_prof_flags: + *s_out = "DW_AT_HP_prof_flags"; + return DW_DLV_OK; + case DW_AT_HP_unit_name: + *s_out = "DW_AT_HP_unit_name"; + return DW_DLV_OK; + case DW_AT_HP_unit_size: + *s_out = "DW_AT_HP_unit_size"; + return DW_DLV_OK; + case DW_AT_HP_widened_byte_size: + *s_out = "DW_AT_HP_widened_byte_size"; + return DW_DLV_OK; + case DW_AT_HP_definition_points: + *s_out = "DW_AT_HP_definition_points"; + return DW_DLV_OK; + case DW_AT_HP_default_location: + *s_out = "DW_AT_HP_default_location"; + return DW_DLV_OK; + case DW_AT_INTEL_other_endian: + *s_out = "DW_AT_INTEL_other_endian"; + return DW_DLV_OK; + case DW_AT_HP_is_result_param: + *s_out = "DW_AT_HP_is_result_param"; + return DW_DLV_OK; + case DW_AT_ghs_rsm: + *s_out = "DW_AT_ghs_rsm"; + return DW_DLV_OK; + case DW_AT_ghs_frsm: + *s_out = "DW_AT_ghs_frsm"; + return DW_DLV_OK; + case DW_AT_ghs_frames: + *s_out = "DW_AT_ghs_frames"; + return DW_DLV_OK; + case DW_AT_ghs_rso: + *s_out = "DW_AT_ghs_rso"; + return DW_DLV_OK; + case DW_AT_ghs_subcpu: + *s_out = "DW_AT_ghs_subcpu"; + return DW_DLV_OK; + case DW_AT_ghs_lbrace_line: + *s_out = "DW_AT_ghs_lbrace_line"; + return DW_DLV_OK; + case DW_AT_sf_names: + *s_out = "DW_AT_sf_names"; + return DW_DLV_OK; + case DW_AT_src_info: + *s_out = "DW_AT_src_info"; + return DW_DLV_OK; + case DW_AT_mac_info: + *s_out = "DW_AT_mac_info"; + return DW_DLV_OK; + case DW_AT_src_coords: + *s_out = "DW_AT_src_coords"; + return DW_DLV_OK; + case DW_AT_body_begin: + *s_out = "DW_AT_body_begin"; + return DW_DLV_OK; + case DW_AT_body_end: + *s_out = "DW_AT_body_end"; + return DW_DLV_OK; + case DW_AT_GNU_vector: + *s_out = "DW_AT_GNU_vector"; + return DW_DLV_OK; + case DW_AT_GNU_guarded_by: + *s_out = "DW_AT_GNU_guarded_by"; + return DW_DLV_OK; + case DW_AT_GNU_pt_guarded_by: + *s_out = "DW_AT_GNU_pt_guarded_by"; + return DW_DLV_OK; + case DW_AT_GNU_guarded: + *s_out = "DW_AT_GNU_guarded"; + return DW_DLV_OK; + case DW_AT_GNU_pt_guarded: + *s_out = "DW_AT_GNU_pt_guarded"; + return DW_DLV_OK; + case DW_AT_GNU_locks_excluded: + *s_out = "DW_AT_GNU_locks_excluded"; + return DW_DLV_OK; + case DW_AT_GNU_exclusive_locks_required: + *s_out = "DW_AT_GNU_exclusive_locks_required"; + return DW_DLV_OK; + case DW_AT_GNU_shared_locks_required: + *s_out = "DW_AT_GNU_shared_locks_required"; + return DW_DLV_OK; + case DW_AT_GNU_odr_signature: + *s_out = "DW_AT_GNU_odr_signature"; + return DW_DLV_OK; + case DW_AT_GNU_template_name: + *s_out = "DW_AT_GNU_template_name"; + return DW_DLV_OK; + case DW_AT_GNU_call_site_value: + *s_out = "DW_AT_GNU_call_site_value"; + return DW_DLV_OK; + case DW_AT_GNU_call_site_data_value: + *s_out = "DW_AT_GNU_call_site_data_value"; + return DW_DLV_OK; + case DW_AT_GNU_call_site_target: + *s_out = "DW_AT_GNU_call_site_target"; + return DW_DLV_OK; + case DW_AT_GNU_call_site_target_clobbered: + *s_out = "DW_AT_GNU_call_site_target_clobbered"; + return DW_DLV_OK; + case DW_AT_GNU_tail_call: + *s_out = "DW_AT_GNU_tail_call"; + return DW_DLV_OK; + case DW_AT_GNU_all_tail_call_sites: + *s_out = "DW_AT_GNU_all_tail_call_sites"; + return DW_DLV_OK; + case DW_AT_GNU_all_call_sites: + *s_out = "DW_AT_GNU_all_call_sites"; + return DW_DLV_OK; + case DW_AT_GNU_all_source_call_sites: + *s_out = "DW_AT_GNU_all_source_call_sites"; + return DW_DLV_OK; + case DW_AT_GNU_macros: + *s_out = "DW_AT_GNU_macros"; + return DW_DLV_OK; + case DW_AT_GNU_deleted: + *s_out = "DW_AT_GNU_deleted"; + return DW_DLV_OK; + case DW_AT_GNU_dwo_name: + *s_out = "DW_AT_GNU_dwo_name"; + return DW_DLV_OK; + case DW_AT_GNU_dwo_id: + *s_out = "DW_AT_GNU_dwo_id"; + return DW_DLV_OK; + case DW_AT_GNU_ranges_base: + *s_out = "DW_AT_GNU_ranges_base"; + return DW_DLV_OK; + case DW_AT_GNU_addr_base: + *s_out = "DW_AT_GNU_addr_base"; + return DW_DLV_OK; + case DW_AT_GNU_pubnames: + *s_out = "DW_AT_GNU_pubnames"; + return DW_DLV_OK; + case DW_AT_GNU_pubtypes: + *s_out = "DW_AT_GNU_pubtypes"; + return DW_DLV_OK; + case DW_AT_GNU_discriminator: + *s_out = "DW_AT_GNU_discriminator"; + return DW_DLV_OK; + case DW_AT_GNU_locviews: + *s_out = "DW_AT_GNU_locviews"; + return DW_DLV_OK; + case DW_AT_GNU_entry_view: + *s_out = "DW_AT_GNU_entry_view"; + return DW_DLV_OK; + case DW_AT_SUN_template: + *s_out = "DW_AT_SUN_template"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2201. DW_AT_VMS_rtnbeg_pd_address */ + case DW_AT_SUN_alignment: + *s_out = "DW_AT_SUN_alignment"; + return DW_DLV_OK; + case DW_AT_SUN_vtable: + *s_out = "DW_AT_SUN_vtable"; + return DW_DLV_OK; + case DW_AT_SUN_count_guarantee: + *s_out = "DW_AT_SUN_count_guarantee"; + return DW_DLV_OK; + case DW_AT_SUN_command_line: + *s_out = "DW_AT_SUN_command_line"; + return DW_DLV_OK; + case DW_AT_SUN_vbase: + *s_out = "DW_AT_SUN_vbase"; + return DW_DLV_OK; + case DW_AT_SUN_compile_options: + *s_out = "DW_AT_SUN_compile_options"; + return DW_DLV_OK; + case DW_AT_SUN_language: + *s_out = "DW_AT_SUN_language"; + return DW_DLV_OK; + case DW_AT_SUN_browser_file: + *s_out = "DW_AT_SUN_browser_file"; + return DW_DLV_OK; + case DW_AT_SUN_vtable_abi: + *s_out = "DW_AT_SUN_vtable_abi"; + return DW_DLV_OK; + case DW_AT_SUN_func_offsets: + *s_out = "DW_AT_SUN_func_offsets"; + return DW_DLV_OK; + case DW_AT_SUN_cf_kind: + *s_out = "DW_AT_SUN_cf_kind"; + return DW_DLV_OK; + case DW_AT_SUN_vtable_index: + *s_out = "DW_AT_SUN_vtable_index"; + return DW_DLV_OK; + case DW_AT_SUN_omp_tpriv_addr: + *s_out = "DW_AT_SUN_omp_tpriv_addr"; + return DW_DLV_OK; + case DW_AT_SUN_omp_child_func: + *s_out = "DW_AT_SUN_omp_child_func"; + return DW_DLV_OK; + case DW_AT_SUN_func_offset: + *s_out = "DW_AT_SUN_func_offset"; + return DW_DLV_OK; + case DW_AT_SUN_memop_type_ref: + *s_out = "DW_AT_SUN_memop_type_ref"; + return DW_DLV_OK; + case DW_AT_SUN_profile_id: + *s_out = "DW_AT_SUN_profile_id"; + return DW_DLV_OK; + case DW_AT_SUN_memop_signature: + *s_out = "DW_AT_SUN_memop_signature"; + return DW_DLV_OK; + case DW_AT_SUN_obj_dir: + *s_out = "DW_AT_SUN_obj_dir"; + return DW_DLV_OK; + case DW_AT_SUN_obj_file: + *s_out = "DW_AT_SUN_obj_file"; + return DW_DLV_OK; + case DW_AT_SUN_original_name: + *s_out = "DW_AT_SUN_original_name"; + return DW_DLV_OK; + case DW_AT_SUN_hwcprof_signature: + *s_out = "DW_AT_SUN_hwcprof_signature"; + return DW_DLV_OK; + case DW_AT_SUN_amd64_parmdump: + *s_out = "DW_AT_SUN_amd64_parmdump"; + return DW_DLV_OK; + case DW_AT_SUN_part_link_name: + *s_out = "DW_AT_SUN_part_link_name"; + return DW_DLV_OK; + case DW_AT_SUN_link_name: + *s_out = "DW_AT_SUN_link_name"; + return DW_DLV_OK; + case DW_AT_SUN_pass_with_const: + *s_out = "DW_AT_SUN_pass_with_const"; + return DW_DLV_OK; + case DW_AT_SUN_return_with_const: + *s_out = "DW_AT_SUN_return_with_const"; + return DW_DLV_OK; + case DW_AT_SUN_import_by_name: + *s_out = "DW_AT_SUN_import_by_name"; + return DW_DLV_OK; + case DW_AT_SUN_f90_pointer: + *s_out = "DW_AT_SUN_f90_pointer"; + return DW_DLV_OK; + case DW_AT_SUN_pass_by_ref: + *s_out = "DW_AT_SUN_pass_by_ref"; + return DW_DLV_OK; + case DW_AT_SUN_f90_allocatable: + *s_out = "DW_AT_SUN_f90_allocatable"; + return DW_DLV_OK; + case DW_AT_SUN_f90_assumed_shape_array: + *s_out = "DW_AT_SUN_f90_assumed_shape_array"; + return DW_DLV_OK; + case DW_AT_SUN_c_vla: + *s_out = "DW_AT_SUN_c_vla"; + return DW_DLV_OK; + case DW_AT_SUN_return_value_ptr: + *s_out = "DW_AT_SUN_return_value_ptr"; + return DW_DLV_OK; + case DW_AT_SUN_dtor_start: + *s_out = "DW_AT_SUN_dtor_start"; + return DW_DLV_OK; + case DW_AT_SUN_dtor_length: + *s_out = "DW_AT_SUN_dtor_length"; + return DW_DLV_OK; + case DW_AT_SUN_dtor_state_initial: + *s_out = "DW_AT_SUN_dtor_state_initial"; + return DW_DLV_OK; + case DW_AT_SUN_dtor_state_final: + *s_out = "DW_AT_SUN_dtor_state_final"; + return DW_DLV_OK; + case DW_AT_SUN_dtor_state_deltas: + *s_out = "DW_AT_SUN_dtor_state_deltas"; + return DW_DLV_OK; + case DW_AT_SUN_import_by_lname: + *s_out = "DW_AT_SUN_import_by_lname"; + return DW_DLV_OK; + case DW_AT_SUN_f90_use_only: + *s_out = "DW_AT_SUN_f90_use_only"; + return DW_DLV_OK; + case DW_AT_SUN_namelist_spec: + *s_out = "DW_AT_SUN_namelist_spec"; + return DW_DLV_OK; + case DW_AT_SUN_is_omp_child_func: + *s_out = "DW_AT_SUN_is_omp_child_func"; + return DW_DLV_OK; + case DW_AT_SUN_fortran_main_alias: + *s_out = "DW_AT_SUN_fortran_main_alias"; + return DW_DLV_OK; + case DW_AT_SUN_fortran_based: + *s_out = "DW_AT_SUN_fortran_based"; + return DW_DLV_OK; + case DW_AT_ALTIUM_loclist: + *s_out = "DW_AT_ALTIUM_loclist"; + return DW_DLV_OK; + case DW_AT_use_GNAT_descriptive_type: + *s_out = "DW_AT_use_GNAT_descriptive_type"; + return DW_DLV_OK; + case DW_AT_GNAT_descriptive_type: + *s_out = "DW_AT_GNAT_descriptive_type"; + return DW_DLV_OK; + case DW_AT_GNU_numerator: + *s_out = "DW_AT_GNU_numerator"; + return DW_DLV_OK; + case DW_AT_GNU_denominator: + *s_out = "DW_AT_GNU_denominator"; + return DW_DLV_OK; + case DW_AT_GNU_bias: + *s_out = "DW_AT_GNU_bias"; + return DW_DLV_OK; + case DW_AT_go_kind: + *s_out = "DW_AT_go_kind"; + return DW_DLV_OK; + case DW_AT_go_key: + *s_out = "DW_AT_go_key"; + return DW_DLV_OK; + case DW_AT_go_elem: + *s_out = "DW_AT_go_elem"; + return DW_DLV_OK; + case DW_AT_go_embedded_field: + *s_out = "DW_AT_go_embedded_field"; + return DW_DLV_OK; + case DW_AT_go_runtime_type: + *s_out = "DW_AT_go_runtime_type"; + return DW_DLV_OK; + case DW_AT_upc_threads_scaled: + *s_out = "DW_AT_upc_threads_scaled"; + return DW_DLV_OK; + case DW_AT_IBM_wsa_addr: + *s_out = "DW_AT_IBM_wsa_addr"; + return DW_DLV_OK; + case DW_AT_IBM_home_location: + *s_out = "DW_AT_IBM_home_location"; + return DW_DLV_OK; + case DW_AT_IBM_alt_srcview: + *s_out = "DW_AT_IBM_alt_srcview"; + return DW_DLV_OK; + case DW_AT_PGI_lbase: + *s_out = "DW_AT_PGI_lbase"; + return DW_DLV_OK; + case DW_AT_PGI_soffset: + *s_out = "DW_AT_PGI_soffset"; + return DW_DLV_OK; + case DW_AT_PGI_lstride: + *s_out = "DW_AT_PGI_lstride"; + return DW_DLV_OK; + case DW_AT_BORLAND_property_read: + *s_out = "DW_AT_BORLAND_property_read"; + return DW_DLV_OK; + case DW_AT_BORLAND_property_write: + *s_out = "DW_AT_BORLAND_property_write"; + return DW_DLV_OK; + case DW_AT_BORLAND_property_implements: + *s_out = "DW_AT_BORLAND_property_implements"; + return DW_DLV_OK; + case DW_AT_BORLAND_property_index: + *s_out = "DW_AT_BORLAND_property_index"; + return DW_DLV_OK; + case DW_AT_BORLAND_property_default: + *s_out = "DW_AT_BORLAND_property_default"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_unit: + *s_out = "DW_AT_BORLAND_Delphi_unit"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_class: + *s_out = "DW_AT_BORLAND_Delphi_class"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_record: + *s_out = "DW_AT_BORLAND_Delphi_record"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_metaclass: + *s_out = "DW_AT_BORLAND_Delphi_metaclass"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_constructor: + *s_out = "DW_AT_BORLAND_Delphi_constructor"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_destructor: + *s_out = "DW_AT_BORLAND_Delphi_destructor"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_anonymous_method: + *s_out = "DW_AT_BORLAND_Delphi_anonymous_method"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_interface: + *s_out = "DW_AT_BORLAND_Delphi_interface"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_ABI: + *s_out = "DW_AT_BORLAND_Delphi_ABI"; + return DW_DLV_OK; + case DW_AT_BORLAND_Delphi_frameptr: + *s_out = "DW_AT_BORLAND_Delphi_frameptr"; + return DW_DLV_OK; + case DW_AT_BORLAND_closure: + *s_out = "DW_AT_BORLAND_closure"; + return DW_DLV_OK; + case DW_AT_LLVM_include_path: + *s_out = "DW_AT_LLVM_include_path"; + return DW_DLV_OK; + case DW_AT_LLVM_config_macros: + *s_out = "DW_AT_LLVM_config_macros"; + return DW_DLV_OK; + case DW_AT_LLVM_sysroot: + *s_out = "DW_AT_LLVM_sysroot"; + return DW_DLV_OK; + case DW_AT_LLVM_tag_offset: + *s_out = "DW_AT_LLVM_tag_offset"; + return DW_DLV_OK; + case DW_AT_LLVM_apinotes: + *s_out = "DW_AT_LLVM_apinotes"; + return DW_DLV_OK; + case DW_AT_LLVM_active_lane: + *s_out = "DW_AT_LLVM_active_lane"; + return DW_DLV_OK; + case DW_AT_LLVM_augmentation: + *s_out = "DW_AT_LLVM_augmentation"; + return DW_DLV_OK; + case DW_AT_LLVM_lanes: + *s_out = "DW_AT_LLVM_lanes"; + return DW_DLV_OK; + case DW_AT_LLVM_lane_pc: + *s_out = "DW_AT_LLVM_lane_pc"; + return DW_DLV_OK; + case DW_AT_LLVM_vector_size: + *s_out = "DW_AT_LLVM_vector_size"; + return DW_DLV_OK; + case DW_AT_APPLE_optimized: + *s_out = "DW_AT_APPLE_optimized"; + return DW_DLV_OK; + case DW_AT_APPLE_flags: + *s_out = "DW_AT_APPLE_flags"; + return DW_DLV_OK; + case DW_AT_APPLE_isa: + *s_out = "DW_AT_APPLE_isa"; + return DW_DLV_OK; + case DW_AT_APPLE_block: + *s_out = "DW_AT_APPLE_block"; + return DW_DLV_OK; + case DW_AT_APPLE_major_runtime_vers: + *s_out = "DW_AT_APPLE_major_runtime_vers"; + return DW_DLV_OK; + case DW_AT_APPLE_runtime_class: + *s_out = "DW_AT_APPLE_runtime_class"; + return DW_DLV_OK; + case DW_AT_APPLE_omit_frame_ptr: + *s_out = "DW_AT_APPLE_omit_frame_ptr"; + return DW_DLV_OK; + case DW_AT_APPLE_property_name: + *s_out = "DW_AT_APPLE_property_name"; + return DW_DLV_OK; + case DW_AT_APPLE_property_getter: + *s_out = "DW_AT_APPLE_property_getter"; + return DW_DLV_OK; + case DW_AT_APPLE_property_setter: + *s_out = "DW_AT_APPLE_property_setter"; + return DW_DLV_OK; + case DW_AT_APPLE_property_attribute: + *s_out = "DW_AT_APPLE_property_attribute"; + return DW_DLV_OK; + case DW_AT_APPLE_objc_complete_type: + *s_out = "DW_AT_APPLE_objc_complete_type"; + return DW_DLV_OK; + case DW_AT_APPLE_property: + *s_out = "DW_AT_APPLE_property"; + return DW_DLV_OK; + case DW_AT_APPLE_objc_direct: + *s_out = "DW_AT_APPLE_objc_direct"; + return DW_DLV_OK; + case DW_AT_APPLE_sdk: + *s_out = "DW_AT_APPLE_sdk"; + return DW_DLV_OK; + case DW_AT_hi_user: + *s_out = "DW_AT_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_OP_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_OP_addr: + *s_out = "DW_OP_addr"; + return DW_DLV_OK; + case DW_OP_deref: + *s_out = "DW_OP_deref"; + return DW_DLV_OK; + case DW_OP_const1u: + *s_out = "DW_OP_const1u"; + return DW_DLV_OK; + case DW_OP_const1s: + *s_out = "DW_OP_const1s"; + return DW_DLV_OK; + case DW_OP_const2u: + *s_out = "DW_OP_const2u"; + return DW_DLV_OK; + case DW_OP_const2s: + *s_out = "DW_OP_const2s"; + return DW_DLV_OK; + case DW_OP_const4u: + *s_out = "DW_OP_const4u"; + return DW_DLV_OK; + case DW_OP_const4s: + *s_out = "DW_OP_const4s"; + return DW_DLV_OK; + case DW_OP_const8u: + *s_out = "DW_OP_const8u"; + return DW_DLV_OK; + case DW_OP_const8s: + *s_out = "DW_OP_const8s"; + return DW_DLV_OK; + case DW_OP_constu: + *s_out = "DW_OP_constu"; + return DW_DLV_OK; + case DW_OP_consts: + *s_out = "DW_OP_consts"; + return DW_DLV_OK; + case DW_OP_dup: + *s_out = "DW_OP_dup"; + return DW_DLV_OK; + case DW_OP_drop: + *s_out = "DW_OP_drop"; + return DW_DLV_OK; + case DW_OP_over: + *s_out = "DW_OP_over"; + return DW_DLV_OK; + case DW_OP_pick: + *s_out = "DW_OP_pick"; + return DW_DLV_OK; + case DW_OP_swap: + *s_out = "DW_OP_swap"; + return DW_DLV_OK; + case DW_OP_rot: + *s_out = "DW_OP_rot"; + return DW_DLV_OK; + case DW_OP_xderef: + *s_out = "DW_OP_xderef"; + return DW_DLV_OK; + case DW_OP_abs: + *s_out = "DW_OP_abs"; + return DW_DLV_OK; + case DW_OP_and: + *s_out = "DW_OP_and"; + return DW_DLV_OK; + case DW_OP_div: + *s_out = "DW_OP_div"; + return DW_DLV_OK; + case DW_OP_minus: + *s_out = "DW_OP_minus"; + return DW_DLV_OK; + case DW_OP_mod: + *s_out = "DW_OP_mod"; + return DW_DLV_OK; + case DW_OP_mul: + *s_out = "DW_OP_mul"; + return DW_DLV_OK; + case DW_OP_neg: + *s_out = "DW_OP_neg"; + return DW_DLV_OK; + case DW_OP_not: + *s_out = "DW_OP_not"; + return DW_DLV_OK; + case DW_OP_or: + *s_out = "DW_OP_or"; + return DW_DLV_OK; + case DW_OP_plus: + *s_out = "DW_OP_plus"; + return DW_DLV_OK; + case DW_OP_plus_uconst: + *s_out = "DW_OP_plus_uconst"; + return DW_DLV_OK; + case DW_OP_shl: + *s_out = "DW_OP_shl"; + return DW_DLV_OK; + case DW_OP_shr: + *s_out = "DW_OP_shr"; + return DW_DLV_OK; + case DW_OP_shra: + *s_out = "DW_OP_shra"; + return DW_DLV_OK; + case DW_OP_xor: + *s_out = "DW_OP_xor"; + return DW_DLV_OK; + case DW_OP_bra: + *s_out = "DW_OP_bra"; + return DW_DLV_OK; + case DW_OP_eq: + *s_out = "DW_OP_eq"; + return DW_DLV_OK; + case DW_OP_ge: + *s_out = "DW_OP_ge"; + return DW_DLV_OK; + case DW_OP_gt: + *s_out = "DW_OP_gt"; + return DW_DLV_OK; + case DW_OP_le: + *s_out = "DW_OP_le"; + return DW_DLV_OK; + case DW_OP_lt: + *s_out = "DW_OP_lt"; + return DW_DLV_OK; + case DW_OP_ne: + *s_out = "DW_OP_ne"; + return DW_DLV_OK; + case DW_OP_skip: + *s_out = "DW_OP_skip"; + return DW_DLV_OK; + case DW_OP_lit0: + *s_out = "DW_OP_lit0"; + return DW_DLV_OK; + case DW_OP_lit1: + *s_out = "DW_OP_lit1"; + return DW_DLV_OK; + case DW_OP_lit2: + *s_out = "DW_OP_lit2"; + return DW_DLV_OK; + case DW_OP_lit3: + *s_out = "DW_OP_lit3"; + return DW_DLV_OK; + case DW_OP_lit4: + *s_out = "DW_OP_lit4"; + return DW_DLV_OK; + case DW_OP_lit5: + *s_out = "DW_OP_lit5"; + return DW_DLV_OK; + case DW_OP_lit6: + *s_out = "DW_OP_lit6"; + return DW_DLV_OK; + case DW_OP_lit7: + *s_out = "DW_OP_lit7"; + return DW_DLV_OK; + case DW_OP_lit8: + *s_out = "DW_OP_lit8"; + return DW_DLV_OK; + case DW_OP_lit9: + *s_out = "DW_OP_lit9"; + return DW_DLV_OK; + case DW_OP_lit10: + *s_out = "DW_OP_lit10"; + return DW_DLV_OK; + case DW_OP_lit11: + *s_out = "DW_OP_lit11"; + return DW_DLV_OK; + case DW_OP_lit12: + *s_out = "DW_OP_lit12"; + return DW_DLV_OK; + case DW_OP_lit13: + *s_out = "DW_OP_lit13"; + return DW_DLV_OK; + case DW_OP_lit14: + *s_out = "DW_OP_lit14"; + return DW_DLV_OK; + case DW_OP_lit15: + *s_out = "DW_OP_lit15"; + return DW_DLV_OK; + case DW_OP_lit16: + *s_out = "DW_OP_lit16"; + return DW_DLV_OK; + case DW_OP_lit17: + *s_out = "DW_OP_lit17"; + return DW_DLV_OK; + case DW_OP_lit18: + *s_out = "DW_OP_lit18"; + return DW_DLV_OK; + case DW_OP_lit19: + *s_out = "DW_OP_lit19"; + return DW_DLV_OK; + case DW_OP_lit20: + *s_out = "DW_OP_lit20"; + return DW_DLV_OK; + case DW_OP_lit21: + *s_out = "DW_OP_lit21"; + return DW_DLV_OK; + case DW_OP_lit22: + *s_out = "DW_OP_lit22"; + return DW_DLV_OK; + case DW_OP_lit23: + *s_out = "DW_OP_lit23"; + return DW_DLV_OK; + case DW_OP_lit24: + *s_out = "DW_OP_lit24"; + return DW_DLV_OK; + case DW_OP_lit25: + *s_out = "DW_OP_lit25"; + return DW_DLV_OK; + case DW_OP_lit26: + *s_out = "DW_OP_lit26"; + return DW_DLV_OK; + case DW_OP_lit27: + *s_out = "DW_OP_lit27"; + return DW_DLV_OK; + case DW_OP_lit28: + *s_out = "DW_OP_lit28"; + return DW_DLV_OK; + case DW_OP_lit29: + *s_out = "DW_OP_lit29"; + return DW_DLV_OK; + case DW_OP_lit30: + *s_out = "DW_OP_lit30"; + return DW_DLV_OK; + case DW_OP_lit31: + *s_out = "DW_OP_lit31"; + return DW_DLV_OK; + case DW_OP_reg0: + *s_out = "DW_OP_reg0"; + return DW_DLV_OK; + case DW_OP_reg1: + *s_out = "DW_OP_reg1"; + return DW_DLV_OK; + case DW_OP_reg2: + *s_out = "DW_OP_reg2"; + return DW_DLV_OK; + case DW_OP_reg3: + *s_out = "DW_OP_reg3"; + return DW_DLV_OK; + case DW_OP_reg4: + *s_out = "DW_OP_reg4"; + return DW_DLV_OK; + case DW_OP_reg5: + *s_out = "DW_OP_reg5"; + return DW_DLV_OK; + case DW_OP_reg6: + *s_out = "DW_OP_reg6"; + return DW_DLV_OK; + case DW_OP_reg7: + *s_out = "DW_OP_reg7"; + return DW_DLV_OK; + case DW_OP_reg8: + *s_out = "DW_OP_reg8"; + return DW_DLV_OK; + case DW_OP_reg9: + *s_out = "DW_OP_reg9"; + return DW_DLV_OK; + case DW_OP_reg10: + *s_out = "DW_OP_reg10"; + return DW_DLV_OK; + case DW_OP_reg11: + *s_out = "DW_OP_reg11"; + return DW_DLV_OK; + case DW_OP_reg12: + *s_out = "DW_OP_reg12"; + return DW_DLV_OK; + case DW_OP_reg13: + *s_out = "DW_OP_reg13"; + return DW_DLV_OK; + case DW_OP_reg14: + *s_out = "DW_OP_reg14"; + return DW_DLV_OK; + case DW_OP_reg15: + *s_out = "DW_OP_reg15"; + return DW_DLV_OK; + case DW_OP_reg16: + *s_out = "DW_OP_reg16"; + return DW_DLV_OK; + case DW_OP_reg17: + *s_out = "DW_OP_reg17"; + return DW_DLV_OK; + case DW_OP_reg18: + *s_out = "DW_OP_reg18"; + return DW_DLV_OK; + case DW_OP_reg19: + *s_out = "DW_OP_reg19"; + return DW_DLV_OK; + case DW_OP_reg20: + *s_out = "DW_OP_reg20"; + return DW_DLV_OK; + case DW_OP_reg21: + *s_out = "DW_OP_reg21"; + return DW_DLV_OK; + case DW_OP_reg22: + *s_out = "DW_OP_reg22"; + return DW_DLV_OK; + case DW_OP_reg23: + *s_out = "DW_OP_reg23"; + return DW_DLV_OK; + case DW_OP_reg24: + *s_out = "DW_OP_reg24"; + return DW_DLV_OK; + case DW_OP_reg25: + *s_out = "DW_OP_reg25"; + return DW_DLV_OK; + case DW_OP_reg26: + *s_out = "DW_OP_reg26"; + return DW_DLV_OK; + case DW_OP_reg27: + *s_out = "DW_OP_reg27"; + return DW_DLV_OK; + case DW_OP_reg28: + *s_out = "DW_OP_reg28"; + return DW_DLV_OK; + case DW_OP_reg29: + *s_out = "DW_OP_reg29"; + return DW_DLV_OK; + case DW_OP_reg30: + *s_out = "DW_OP_reg30"; + return DW_DLV_OK; + case DW_OP_reg31: + *s_out = "DW_OP_reg31"; + return DW_DLV_OK; + case DW_OP_breg0: + *s_out = "DW_OP_breg0"; + return DW_DLV_OK; + case DW_OP_breg1: + *s_out = "DW_OP_breg1"; + return DW_DLV_OK; + case DW_OP_breg2: + *s_out = "DW_OP_breg2"; + return DW_DLV_OK; + case DW_OP_breg3: + *s_out = "DW_OP_breg3"; + return DW_DLV_OK; + case DW_OP_breg4: + *s_out = "DW_OP_breg4"; + return DW_DLV_OK; + case DW_OP_breg5: + *s_out = "DW_OP_breg5"; + return DW_DLV_OK; + case DW_OP_breg6: + *s_out = "DW_OP_breg6"; + return DW_DLV_OK; + case DW_OP_breg7: + *s_out = "DW_OP_breg7"; + return DW_DLV_OK; + case DW_OP_breg8: + *s_out = "DW_OP_breg8"; + return DW_DLV_OK; + case DW_OP_breg9: + *s_out = "DW_OP_breg9"; + return DW_DLV_OK; + case DW_OP_breg10: + *s_out = "DW_OP_breg10"; + return DW_DLV_OK; + case DW_OP_breg11: + *s_out = "DW_OP_breg11"; + return DW_DLV_OK; + case DW_OP_breg12: + *s_out = "DW_OP_breg12"; + return DW_DLV_OK; + case DW_OP_breg13: + *s_out = "DW_OP_breg13"; + return DW_DLV_OK; + case DW_OP_breg14: + *s_out = "DW_OP_breg14"; + return DW_DLV_OK; + case DW_OP_breg15: + *s_out = "DW_OP_breg15"; + return DW_DLV_OK; + case DW_OP_breg16: + *s_out = "DW_OP_breg16"; + return DW_DLV_OK; + case DW_OP_breg17: + *s_out = "DW_OP_breg17"; + return DW_DLV_OK; + case DW_OP_breg18: + *s_out = "DW_OP_breg18"; + return DW_DLV_OK; + case DW_OP_breg19: + *s_out = "DW_OP_breg19"; + return DW_DLV_OK; + case DW_OP_breg20: + *s_out = "DW_OP_breg20"; + return DW_DLV_OK; + case DW_OP_breg21: + *s_out = "DW_OP_breg21"; + return DW_DLV_OK; + case DW_OP_breg22: + *s_out = "DW_OP_breg22"; + return DW_DLV_OK; + case DW_OP_breg23: + *s_out = "DW_OP_breg23"; + return DW_DLV_OK; + case DW_OP_breg24: + *s_out = "DW_OP_breg24"; + return DW_DLV_OK; + case DW_OP_breg25: + *s_out = "DW_OP_breg25"; + return DW_DLV_OK; + case DW_OP_breg26: + *s_out = "DW_OP_breg26"; + return DW_DLV_OK; + case DW_OP_breg27: + *s_out = "DW_OP_breg27"; + return DW_DLV_OK; + case DW_OP_breg28: + *s_out = "DW_OP_breg28"; + return DW_DLV_OK; + case DW_OP_breg29: + *s_out = "DW_OP_breg29"; + return DW_DLV_OK; + case DW_OP_breg30: + *s_out = "DW_OP_breg30"; + return DW_DLV_OK; + case DW_OP_breg31: + *s_out = "DW_OP_breg31"; + return DW_DLV_OK; + case DW_OP_regx: + *s_out = "DW_OP_regx"; + return DW_DLV_OK; + case DW_OP_fbreg: + *s_out = "DW_OP_fbreg"; + return DW_DLV_OK; + case DW_OP_bregx: + *s_out = "DW_OP_bregx"; + return DW_DLV_OK; + case DW_OP_piece: + *s_out = "DW_OP_piece"; + return DW_DLV_OK; + case DW_OP_deref_size: + *s_out = "DW_OP_deref_size"; + return DW_DLV_OK; + case DW_OP_xderef_size: + *s_out = "DW_OP_xderef_size"; + return DW_DLV_OK; + case DW_OP_nop: + *s_out = "DW_OP_nop"; + return DW_DLV_OK; + case DW_OP_push_object_address: + *s_out = "DW_OP_push_object_address"; + return DW_DLV_OK; + case DW_OP_call2: + *s_out = "DW_OP_call2"; + return DW_DLV_OK; + case DW_OP_call4: + *s_out = "DW_OP_call4"; + return DW_DLV_OK; + case DW_OP_call_ref: + *s_out = "DW_OP_call_ref"; + return DW_DLV_OK; + case DW_OP_form_tls_address: + *s_out = "DW_OP_form_tls_address"; + return DW_DLV_OK; + case DW_OP_call_frame_cfa: + *s_out = "DW_OP_call_frame_cfa"; + return DW_DLV_OK; + case DW_OP_bit_piece: + *s_out = "DW_OP_bit_piece"; + return DW_DLV_OK; + case DW_OP_implicit_value: + *s_out = "DW_OP_implicit_value"; + return DW_DLV_OK; + case DW_OP_stack_value: + *s_out = "DW_OP_stack_value"; + return DW_DLV_OK; + case DW_OP_implicit_pointer: + *s_out = "DW_OP_implicit_pointer"; + return DW_DLV_OK; + case DW_OP_addrx: + *s_out = "DW_OP_addrx"; + return DW_DLV_OK; + case DW_OP_constx: + *s_out = "DW_OP_constx"; + return DW_DLV_OK; + case DW_OP_entry_value: + *s_out = "DW_OP_entry_value"; + return DW_DLV_OK; + case DW_OP_const_type: + *s_out = "DW_OP_const_type"; + return DW_DLV_OK; + case DW_OP_regval_type: + *s_out = "DW_OP_regval_type"; + return DW_DLV_OK; + case DW_OP_deref_type: + *s_out = "DW_OP_deref_type"; + return DW_DLV_OK; + case DW_OP_xderef_type: + *s_out = "DW_OP_xderef_type"; + return DW_DLV_OK; + case DW_OP_convert: + *s_out = "DW_OP_convert"; + return DW_DLV_OK; + case DW_OP_reinterpret: + *s_out = "DW_OP_reinterpret"; + return DW_DLV_OK; + case DW_OP_GNU_push_tls_address: + *s_out = "DW_OP_GNU_push_tls_address"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe0. DW_OP_lo_user */ + /* Skipping alternate spelling of value + 0xe0. DW_OP_HP_unknown */ + case DW_OP_LLVM_form_aspace_address: + *s_out = "DW_OP_LLVM_form_aspace_address"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe1. DW_OP_HP_is_value */ + case DW_OP_LLVM_push_lane: + *s_out = "DW_OP_LLVM_push_lane"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe2. DW_OP_HP_fltconst4 */ + case DW_OP_LLVM_offset: + *s_out = "DW_OP_LLVM_offset"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe3. DW_OP_HP_fltconst8 */ + case DW_OP_LLVM_offset_uconst: + *s_out = "DW_OP_LLVM_offset_uconst"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe4. DW_OP_HP_mod_range */ + case DW_OP_LLVM_bit_offset: + *s_out = "DW_OP_LLVM_bit_offset"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe5. DW_OP_HP_unmod_range */ + case DW_OP_LLVM_call_frame_entry_reg: + *s_out = "DW_OP_LLVM_call_frame_entry_reg"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe6. DW_OP_HP_tls */ + case DW_OP_LLVM_undefined: + *s_out = "DW_OP_LLVM_undefined"; + return DW_DLV_OK; + case DW_OP_LLVM_aspace_bregx: + *s_out = "DW_OP_LLVM_aspace_bregx"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xe8. DW_OP_INTEL_bit_piece */ + case DW_OP_LLVM_aspace_implicit_pointer: + *s_out = "DW_OP_LLVM_aspace_implicit_pointer"; + return DW_DLV_OK; + case DW_OP_LLVM_piece_end: + *s_out = "DW_OP_LLVM_piece_end"; + return DW_DLV_OK; + case DW_OP_LLVM_extend: + *s_out = "DW_OP_LLVM_extend"; + return DW_DLV_OK; + case DW_OP_LLVM_select_bit_piece: + *s_out = "DW_OP_LLVM_select_bit_piece"; + return DW_DLV_OK; + case DW_OP_WASM_location: + *s_out = "DW_OP_WASM_location"; + return DW_DLV_OK; + case DW_OP_WASM_location_int: + *s_out = "DW_OP_WASM_location_int"; + return DW_DLV_OK; + case DW_OP_GNU_uninit: + *s_out = "DW_OP_GNU_uninit"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xf0. DW_OP_APPLE_uninit */ + case DW_OP_GNU_encoded_addr: + *s_out = "DW_OP_GNU_encoded_addr"; + return DW_DLV_OK; + case DW_OP_GNU_implicit_pointer: + *s_out = "DW_OP_GNU_implicit_pointer"; + return DW_DLV_OK; + case DW_OP_GNU_entry_value: + *s_out = "DW_OP_GNU_entry_value"; + return DW_DLV_OK; + case DW_OP_GNU_const_type: + *s_out = "DW_OP_GNU_const_type"; + return DW_DLV_OK; + case DW_OP_GNU_regval_type: + *s_out = "DW_OP_GNU_regval_type"; + return DW_DLV_OK; + case DW_OP_GNU_deref_type: + *s_out = "DW_OP_GNU_deref_type"; + return DW_DLV_OK; + case DW_OP_GNU_convert: + *s_out = "DW_OP_GNU_convert"; + return DW_DLV_OK; + case DW_OP_PGI_omp_thread_num: + *s_out = "DW_OP_PGI_omp_thread_num"; + return DW_DLV_OK; + case DW_OP_GNU_reinterpret: + *s_out = "DW_OP_GNU_reinterpret"; + return DW_DLV_OK; + case DW_OP_GNU_parameter_ref: + *s_out = "DW_OP_GNU_parameter_ref"; + return DW_DLV_OK; + case DW_OP_GNU_addr_index: + *s_out = "DW_OP_GNU_addr_index"; + return DW_DLV_OK; + case DW_OP_GNU_const_index: + *s_out = "DW_OP_GNU_const_index"; + return DW_DLV_OK; + case DW_OP_GNU_variable_value: + *s_out = "DW_OP_GNU_variable_value"; + return DW_DLV_OK; + case DW_OP_hi_user: + *s_out = "DW_OP_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ATE_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ATE_address: + *s_out = "DW_ATE_address"; + return DW_DLV_OK; + case DW_ATE_boolean: + *s_out = "DW_ATE_boolean"; + return DW_DLV_OK; + case DW_ATE_complex_float: + *s_out = "DW_ATE_complex_float"; + return DW_DLV_OK; + case DW_ATE_float: + *s_out = "DW_ATE_float"; + return DW_DLV_OK; + case DW_ATE_signed: + *s_out = "DW_ATE_signed"; + return DW_DLV_OK; + case DW_ATE_signed_char: + *s_out = "DW_ATE_signed_char"; + return DW_DLV_OK; + case DW_ATE_unsigned: + *s_out = "DW_ATE_unsigned"; + return DW_DLV_OK; + case DW_ATE_unsigned_char: + *s_out = "DW_ATE_unsigned_char"; + return DW_DLV_OK; + case DW_ATE_imaginary_float: + *s_out = "DW_ATE_imaginary_float"; + return DW_DLV_OK; + case DW_ATE_packed_decimal: + *s_out = "DW_ATE_packed_decimal"; + return DW_DLV_OK; + case DW_ATE_numeric_string: + *s_out = "DW_ATE_numeric_string"; + return DW_DLV_OK; + case DW_ATE_edited: + *s_out = "DW_ATE_edited"; + return DW_DLV_OK; + case DW_ATE_signed_fixed: + *s_out = "DW_ATE_signed_fixed"; + return DW_DLV_OK; + case DW_ATE_unsigned_fixed: + *s_out = "DW_ATE_unsigned_fixed"; + return DW_DLV_OK; + case DW_ATE_decimal_float: + *s_out = "DW_ATE_decimal_float"; + return DW_DLV_OK; + case DW_ATE_UTF: + *s_out = "DW_ATE_UTF"; + return DW_DLV_OK; + case DW_ATE_UCS: + *s_out = "DW_ATE_UCS"; + return DW_DLV_OK; + case DW_ATE_ASCII: + *s_out = "DW_ATE_ASCII"; + return DW_DLV_OK; + case DW_ATE_ALTIUM_fract: + *s_out = "DW_ATE_ALTIUM_fract"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x80. DW_ATE_lo_user */ + /* Skipping alternate spelling of value + 0x80. DW_ATE_HP_float80 */ + case DW_ATE_ALTIUM_accum: + *s_out = "DW_ATE_ALTIUM_accum"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x81. DW_ATE_HP_complex_float80 */ + case DW_ATE_HP_float128: + *s_out = "DW_ATE_HP_float128"; + return DW_DLV_OK; + case DW_ATE_HP_complex_float128: + *s_out = "DW_ATE_HP_complex_float128"; + return DW_DLV_OK; + case DW_ATE_HP_floathpintel: + *s_out = "DW_ATE_HP_floathpintel"; + return DW_DLV_OK; + case DW_ATE_HP_imaginary_float80: + *s_out = "DW_ATE_HP_imaginary_float80"; + return DW_DLV_OK; + case DW_ATE_HP_imaginary_float128: + *s_out = "DW_ATE_HP_imaginary_float128"; + return DW_DLV_OK; + case DW_ATE_HP_VAX_float: + *s_out = "DW_ATE_HP_VAX_float"; + return DW_DLV_OK; + case DW_ATE_HP_VAX_float_d: + *s_out = "DW_ATE_HP_VAX_float_d"; + return DW_DLV_OK; + case DW_ATE_HP_packed_decimal: + *s_out = "DW_ATE_HP_packed_decimal"; + return DW_DLV_OK; + case DW_ATE_HP_zoned_decimal: + *s_out = "DW_ATE_HP_zoned_decimal"; + return DW_DLV_OK; + case DW_ATE_HP_edited: + *s_out = "DW_ATE_HP_edited"; + return DW_DLV_OK; + case DW_ATE_HP_signed_fixed: + *s_out = "DW_ATE_HP_signed_fixed"; + return DW_DLV_OK; + case DW_ATE_HP_unsigned_fixed: + *s_out = "DW_ATE_HP_unsigned_fixed"; + return DW_DLV_OK; + case DW_ATE_HP_VAX_complex_float: + *s_out = "DW_ATE_HP_VAX_complex_float"; + return DW_DLV_OK; + case DW_ATE_HP_VAX_complex_float_d: + *s_out = "DW_ATE_HP_VAX_complex_float_d"; + return DW_DLV_OK; + case DW_ATE_SUN_interval_float: + *s_out = "DW_ATE_SUN_interval_float"; + return DW_DLV_OK; + case DW_ATE_SUN_imaginary_float: + *s_out = "DW_ATE_SUN_imaginary_float"; + return DW_DLV_OK; + case DW_ATE_hi_user: + *s_out = "DW_ATE_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_DEFAULTED_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_DEFAULTED_no: + *s_out = "DW_DEFAULTED_no"; + return DW_DLV_OK; + case DW_DEFAULTED_in_class: + *s_out = "DW_DEFAULTED_in_class"; + return DW_DLV_OK; + case DW_DEFAULTED_out_of_class: + *s_out = "DW_DEFAULTED_out_of_class"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_IDX_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_IDX_compile_unit: + *s_out = "DW_IDX_compile_unit"; + return DW_DLV_OK; + case DW_IDX_type_unit: + *s_out = "DW_IDX_type_unit"; + return DW_DLV_OK; + case DW_IDX_die_offset: + *s_out = "DW_IDX_die_offset"; + return DW_DLV_OK; + case DW_IDX_parent: + *s_out = "DW_IDX_parent"; + return DW_DLV_OK; + case DW_IDX_type_hash: + *s_out = "DW_IDX_type_hash"; + return DW_DLV_OK; + case DW_IDX_GNU_internal: + *s_out = "DW_IDX_GNU_internal"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2000. DW_IDX_lo_user */ + case DW_IDX_GNU_external: + *s_out = "DW_IDX_GNU_external"; + return DW_DLV_OK; + case DW_IDX_hi_user: + *s_out = "DW_IDX_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LLEX_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LLEX_end_of_list_entry: + *s_out = "DW_LLEX_end_of_list_entry"; + return DW_DLV_OK; + case DW_LLEX_base_address_selection_entry: + *s_out = "DW_LLEX_base_address_selection_entry"; + return DW_DLV_OK; + case DW_LLEX_start_end_entry: + *s_out = "DW_LLEX_start_end_entry"; + return DW_DLV_OK; + case DW_LLEX_start_length_entry: + *s_out = "DW_LLEX_start_length_entry"; + return DW_DLV_OK; + case DW_LLEX_offset_pair_entry: + *s_out = "DW_LLEX_offset_pair_entry"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LLE_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LLE_end_of_list: + *s_out = "DW_LLE_end_of_list"; + return DW_DLV_OK; + case DW_LLE_base_addressx: + *s_out = "DW_LLE_base_addressx"; + return DW_DLV_OK; + case DW_LLE_startx_endx: + *s_out = "DW_LLE_startx_endx"; + return DW_DLV_OK; + case DW_LLE_startx_length: + *s_out = "DW_LLE_startx_length"; + return DW_DLV_OK; + case DW_LLE_offset_pair: + *s_out = "DW_LLE_offset_pair"; + return DW_DLV_OK; + case DW_LLE_default_location: + *s_out = "DW_LLE_default_location"; + return DW_DLV_OK; + case DW_LLE_base_address: + *s_out = "DW_LLE_base_address"; + return DW_DLV_OK; + case DW_LLE_start_end: + *s_out = "DW_LLE_start_end"; + return DW_DLV_OK; + case DW_LLE_start_length: + *s_out = "DW_LLE_start_length"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_RLE_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_RLE_end_of_list: + *s_out = "DW_RLE_end_of_list"; + return DW_DLV_OK; + case DW_RLE_base_addressx: + *s_out = "DW_RLE_base_addressx"; + return DW_DLV_OK; + case DW_RLE_startx_endx: + *s_out = "DW_RLE_startx_endx"; + return DW_DLV_OK; + case DW_RLE_startx_length: + *s_out = "DW_RLE_startx_length"; + return DW_DLV_OK; + case DW_RLE_offset_pair: + *s_out = "DW_RLE_offset_pair"; + return DW_DLV_OK; + case DW_RLE_base_address: + *s_out = "DW_RLE_base_address"; + return DW_DLV_OK; + case DW_RLE_start_end: + *s_out = "DW_RLE_start_end"; + return DW_DLV_OK; + case DW_RLE_start_length: + *s_out = "DW_RLE_start_length"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_GNUIVIS_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_GNUIVIS_global: + *s_out = "DW_GNUIVIS_global"; + return DW_DLV_OK; + case DW_GNUIVIS_static: + *s_out = "DW_GNUIVIS_static"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_GNUIKIND_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_GNUIKIND_none: + *s_out = "DW_GNUIKIND_none"; + return DW_DLV_OK; + case DW_GNUIKIND_type: + *s_out = "DW_GNUIKIND_type"; + return DW_DLV_OK; + case DW_GNUIKIND_variable: + *s_out = "DW_GNUIKIND_variable"; + return DW_DLV_OK; + case DW_GNUIKIND_function: + *s_out = "DW_GNUIKIND_function"; + return DW_DLV_OK; + case DW_GNUIKIND_other: + *s_out = "DW_GNUIKIND_other"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_UT_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_UT_compile: + *s_out = "DW_UT_compile"; + return DW_DLV_OK; + case DW_UT_type: + *s_out = "DW_UT_type"; + return DW_DLV_OK; + case DW_UT_partial: + *s_out = "DW_UT_partial"; + return DW_DLV_OK; + case DW_UT_skeleton: + *s_out = "DW_UT_skeleton"; + return DW_DLV_OK; + case DW_UT_split_compile: + *s_out = "DW_UT_split_compile"; + return DW_DLV_OK; + case DW_UT_split_type: + *s_out = "DW_UT_split_type"; + return DW_DLV_OK; + case DW_UT_lo_user: + *s_out = "DW_UT_lo_user"; + return DW_DLV_OK; + case DW_UT_hi_user: + *s_out = "DW_UT_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_SECT_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_SECT_INFO: + *s_out = "DW_SECT_INFO"; + return DW_DLV_OK; + case DW_SECT_TYPES: + *s_out = "DW_SECT_TYPES"; + return DW_DLV_OK; + case DW_SECT_ABBREV: + *s_out = "DW_SECT_ABBREV"; + return DW_DLV_OK; + case DW_SECT_LINE: + *s_out = "DW_SECT_LINE"; + return DW_DLV_OK; + case DW_SECT_LOCLISTS: + *s_out = "DW_SECT_LOCLISTS"; + return DW_DLV_OK; + case DW_SECT_STR_OFFSETS: + *s_out = "DW_SECT_STR_OFFSETS"; + return DW_DLV_OK; + case DW_SECT_MACRO: + *s_out = "DW_SECT_MACRO"; + return DW_DLV_OK; + case DW_SECT_RNGLISTS: + *s_out = "DW_SECT_RNGLISTS"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_DS_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_DS_unsigned: + *s_out = "DW_DS_unsigned"; + return DW_DLV_OK; + case DW_DS_leading_overpunch: + *s_out = "DW_DS_leading_overpunch"; + return DW_DLV_OK; + case DW_DS_trailing_overpunch: + *s_out = "DW_DS_trailing_overpunch"; + return DW_DLV_OK; + case DW_DS_leading_separate: + *s_out = "DW_DS_leading_separate"; + return DW_DLV_OK; + case DW_DS_trailing_separate: + *s_out = "DW_DS_trailing_separate"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_END_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_END_default: + *s_out = "DW_END_default"; + return DW_DLV_OK; + case DW_END_big: + *s_out = "DW_END_big"; + return DW_DLV_OK; + case DW_END_little: + *s_out = "DW_END_little"; + return DW_DLV_OK; + case DW_END_lo_user: + *s_out = "DW_END_lo_user"; + return DW_DLV_OK; + case DW_END_hi_user: + *s_out = "DW_END_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ATCF_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ATCF_lo_user: + *s_out = "DW_ATCF_lo_user"; + return DW_DLV_OK; + case DW_ATCF_SUN_mop_bitfield: + *s_out = "DW_ATCF_SUN_mop_bitfield"; + return DW_DLV_OK; + case DW_ATCF_SUN_mop_spill: + *s_out = "DW_ATCF_SUN_mop_spill"; + return DW_DLV_OK; + case DW_ATCF_SUN_mop_scopy: + *s_out = "DW_ATCF_SUN_mop_scopy"; + return DW_DLV_OK; + case DW_ATCF_SUN_func_start: + *s_out = "DW_ATCF_SUN_func_start"; + return DW_DLV_OK; + case DW_ATCF_SUN_end_ctors: + *s_out = "DW_ATCF_SUN_end_ctors"; + return DW_DLV_OK; + case DW_ATCF_SUN_branch_target: + *s_out = "DW_ATCF_SUN_branch_target"; + return DW_DLV_OK; + case DW_ATCF_SUN_mop_stack_probe: + *s_out = "DW_ATCF_SUN_mop_stack_probe"; + return DW_DLV_OK; + case DW_ATCF_SUN_func_epilog: + *s_out = "DW_ATCF_SUN_func_epilog"; + return DW_DLV_OK; + case DW_ATCF_hi_user: + *s_out = "DW_ATCF_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ACCESS_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ACCESS_public: + *s_out = "DW_ACCESS_public"; + return DW_DLV_OK; + case DW_ACCESS_protected: + *s_out = "DW_ACCESS_protected"; + return DW_DLV_OK; + case DW_ACCESS_private: + *s_out = "DW_ACCESS_private"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_VIS_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_VIS_local: + *s_out = "DW_VIS_local"; + return DW_DLV_OK; + case DW_VIS_exported: + *s_out = "DW_VIS_exported"; + return DW_DLV_OK; + case DW_VIS_qualified: + *s_out = "DW_VIS_qualified"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_VIRTUALITY_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_VIRTUALITY_none: + *s_out = "DW_VIRTUALITY_none"; + return DW_DLV_OK; + case DW_VIRTUALITY_virtual: + *s_out = "DW_VIRTUALITY_virtual"; + return DW_DLV_OK; + case DW_VIRTUALITY_pure_virtual: + *s_out = "DW_VIRTUALITY_pure_virtual"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LANG_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LANG_C89: + *s_out = "DW_LANG_C89"; + return DW_DLV_OK; + case DW_LANG_C: + *s_out = "DW_LANG_C"; + return DW_DLV_OK; + case DW_LANG_Ada83: + *s_out = "DW_LANG_Ada83"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus: + *s_out = "DW_LANG_C_plus_plus"; + return DW_DLV_OK; + case DW_LANG_Cobol74: + *s_out = "DW_LANG_Cobol74"; + return DW_DLV_OK; + case DW_LANG_Cobol85: + *s_out = "DW_LANG_Cobol85"; + return DW_DLV_OK; + case DW_LANG_Fortran77: + *s_out = "DW_LANG_Fortran77"; + return DW_DLV_OK; + case DW_LANG_Fortran90: + *s_out = "DW_LANG_Fortran90"; + return DW_DLV_OK; + case DW_LANG_Pascal83: + *s_out = "DW_LANG_Pascal83"; + return DW_DLV_OK; + case DW_LANG_Modula2: + *s_out = "DW_LANG_Modula2"; + return DW_DLV_OK; + case DW_LANG_Java: + *s_out = "DW_LANG_Java"; + return DW_DLV_OK; + case DW_LANG_C99: + *s_out = "DW_LANG_C99"; + return DW_DLV_OK; + case DW_LANG_Ada95: + *s_out = "DW_LANG_Ada95"; + return DW_DLV_OK; + case DW_LANG_Fortran95: + *s_out = "DW_LANG_Fortran95"; + return DW_DLV_OK; + case DW_LANG_PLI: + *s_out = "DW_LANG_PLI"; + return DW_DLV_OK; + case DW_LANG_ObjC: + *s_out = "DW_LANG_ObjC"; + return DW_DLV_OK; + case DW_LANG_ObjC_plus_plus: + *s_out = "DW_LANG_ObjC_plus_plus"; + return DW_DLV_OK; + case DW_LANG_UPC: + *s_out = "DW_LANG_UPC"; + return DW_DLV_OK; + case DW_LANG_D: + *s_out = "DW_LANG_D"; + return DW_DLV_OK; + case DW_LANG_Python: + *s_out = "DW_LANG_Python"; + return DW_DLV_OK; + case DW_LANG_OpenCL: + *s_out = "DW_LANG_OpenCL"; + return DW_DLV_OK; + case DW_LANG_Go: + *s_out = "DW_LANG_Go"; + return DW_DLV_OK; + case DW_LANG_Modula3: + *s_out = "DW_LANG_Modula3"; + return DW_DLV_OK; + case DW_LANG_Haskel: + *s_out = "DW_LANG_Haskel"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus_03: + *s_out = "DW_LANG_C_plus_plus_03"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus_11: + *s_out = "DW_LANG_C_plus_plus_11"; + return DW_DLV_OK; + case DW_LANG_OCaml: + *s_out = "DW_LANG_OCaml"; + return DW_DLV_OK; + case DW_LANG_Rust: + *s_out = "DW_LANG_Rust"; + return DW_DLV_OK; + case DW_LANG_C11: + *s_out = "DW_LANG_C11"; + return DW_DLV_OK; + case DW_LANG_Swift: + *s_out = "DW_LANG_Swift"; + return DW_DLV_OK; + case DW_LANG_Julia: + *s_out = "DW_LANG_Julia"; + return DW_DLV_OK; + case DW_LANG_Dylan: + *s_out = "DW_LANG_Dylan"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus_14: + *s_out = "DW_LANG_C_plus_plus_14"; + return DW_DLV_OK; + case DW_LANG_Fortran03: + *s_out = "DW_LANG_Fortran03"; + return DW_DLV_OK; + case DW_LANG_Fortran08: + *s_out = "DW_LANG_Fortran08"; + return DW_DLV_OK; + case DW_LANG_RenderScript: + *s_out = "DW_LANG_RenderScript"; + return DW_DLV_OK; + case DW_LANG_BLISS: + *s_out = "DW_LANG_BLISS"; + return DW_DLV_OK; + case DW_LANG_Kotlin: + *s_out = "DW_LANG_Kotlin"; + return DW_DLV_OK; + case DW_LANG_Zig: + *s_out = "DW_LANG_Zig"; + return DW_DLV_OK; + case DW_LANG_Crystal: + *s_out = "DW_LANG_Crystal"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus_17: + *s_out = "DW_LANG_C_plus_plus_17"; + return DW_DLV_OK; + case DW_LANG_C_plus_plus_20: + *s_out = "DW_LANG_C_plus_plus_20"; + return DW_DLV_OK; + case DW_LANG_C17: + *s_out = "DW_LANG_C17"; + return DW_DLV_OK; + case DW_LANG_Fortran18: + *s_out = "DW_LANG_Fortran18"; + return DW_DLV_OK; + case DW_LANG_Ada2005: + *s_out = "DW_LANG_Ada2005"; + return DW_DLV_OK; + case DW_LANG_Ada2012: + *s_out = "DW_LANG_Ada2012"; + return DW_DLV_OK; + case DW_LANG_HIP: + *s_out = "DW_LANG_HIP"; + return DW_DLV_OK; + case DW_LANG_Assembly: + *s_out = "DW_LANG_Assembly"; + return DW_DLV_OK; + case DW_LANG_C_sharp: + *s_out = "DW_LANG_C_sharp"; + return DW_DLV_OK; + case DW_LANG_Mojo: + *s_out = "DW_LANG_Mojo"; + return DW_DLV_OK; + case DW_LANG_lo_user: + *s_out = "DW_LANG_lo_user"; + return DW_DLV_OK; + case DW_LANG_Mips_Assembler: + *s_out = "DW_LANG_Mips_Assembler"; + return DW_DLV_OK; + case DW_LANG_Upc: + *s_out = "DW_LANG_Upc"; + return DW_DLV_OK; + case DW_LANG_GOOGLE_RenderScript: + *s_out = "DW_LANG_GOOGLE_RenderScript"; + return DW_DLV_OK; + case DW_LANG_SUN_Assembler: + *s_out = "DW_LANG_SUN_Assembler"; + return DW_DLV_OK; + case DW_LANG_ALTIUM_Assembler: + *s_out = "DW_LANG_ALTIUM_Assembler"; + return DW_DLV_OK; + case DW_LANG_BORLAND_Delphi: + *s_out = "DW_LANG_BORLAND_Delphi"; + return DW_DLV_OK; + case DW_LANG_hi_user: + *s_out = "DW_LANG_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ID_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ID_case_sensitive: + *s_out = "DW_ID_case_sensitive"; + return DW_DLV_OK; + case DW_ID_up_case: + *s_out = "DW_ID_up_case"; + return DW_DLV_OK; + case DW_ID_down_case: + *s_out = "DW_ID_down_case"; + return DW_DLV_OK; + case DW_ID_case_insensitive: + *s_out = "DW_ID_case_insensitive"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_CC_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_CC_normal: + *s_out = "DW_CC_normal"; + return DW_DLV_OK; + case DW_CC_program: + *s_out = "DW_CC_program"; + return DW_DLV_OK; + case DW_CC_nocall: + *s_out = "DW_CC_nocall"; + return DW_DLV_OK; + case DW_CC_pass_by_reference: + *s_out = "DW_CC_pass_by_reference"; + return DW_DLV_OK; + case DW_CC_pass_by_value: + *s_out = "DW_CC_pass_by_value"; + return DW_DLV_OK; + case DW_CC_lo_user: + *s_out = "DW_CC_lo_user"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x40. DW_CC_GNU_renesas_sh */ + case DW_CC_GNU_borland_fastcall_i386: + *s_out = "DW_CC_GNU_borland_fastcall_i386"; + return DW_DLV_OK; + case DW_CC_ALTIUM_interrupt: + *s_out = "DW_CC_ALTIUM_interrupt"; + return DW_DLV_OK; + case DW_CC_ALTIUM_near_system_stack: + *s_out = "DW_CC_ALTIUM_near_system_stack"; + return DW_DLV_OK; + case DW_CC_ALTIUM_near_user_stack: + *s_out = "DW_CC_ALTIUM_near_user_stack"; + return DW_DLV_OK; + case DW_CC_ALTIUM_huge_user_stack: + *s_out = "DW_CC_ALTIUM_huge_user_stack"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_safecall: + *s_out = "DW_CC_GNU_BORLAND_safecall"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_stdcall: + *s_out = "DW_CC_GNU_BORLAND_stdcall"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_pascal: + *s_out = "DW_CC_GNU_BORLAND_pascal"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_msfastcall: + *s_out = "DW_CC_GNU_BORLAND_msfastcall"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_msreturn: + *s_out = "DW_CC_GNU_BORLAND_msreturn"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_thiscall: + *s_out = "DW_CC_GNU_BORLAND_thiscall"; + return DW_DLV_OK; + case DW_CC_GNU_BORLAND_fastcall: + *s_out = "DW_CC_GNU_BORLAND_fastcall"; + return DW_DLV_OK; + case DW_CC_LLVM_vectorcall: + *s_out = "DW_CC_LLVM_vectorcall"; + return DW_DLV_OK; + case DW_CC_LLVM_Win64: + *s_out = "DW_CC_LLVM_Win64"; + return DW_DLV_OK; + case DW_CC_LLVM_X86_64SysV: + *s_out = "DW_CC_LLVM_X86_64SysV"; + return DW_DLV_OK; + case DW_CC_LLVM_AAPCS: + *s_out = "DW_CC_LLVM_AAPCS"; + return DW_DLV_OK; + case DW_CC_LLVM_AAPCS_VFP: + *s_out = "DW_CC_LLVM_AAPCS_VFP"; + return DW_DLV_OK; + case DW_CC_LLVM_IntelOclBicc: + *s_out = "DW_CC_LLVM_IntelOclBicc"; + return DW_DLV_OK; + case DW_CC_LLVM_SpirFunction: + *s_out = "DW_CC_LLVM_SpirFunction"; + return DW_DLV_OK; + case DW_CC_LLVM_OpenCLKernel: + *s_out = "DW_CC_LLVM_OpenCLKernel"; + return DW_DLV_OK; + case DW_CC_LLVM_Swift: + *s_out = "DW_CC_LLVM_Swift"; + return DW_DLV_OK; + case DW_CC_LLVM_PreserveMost: + *s_out = "DW_CC_LLVM_PreserveMost"; + return DW_DLV_OK; + case DW_CC_LLVM_PreserveAll: + *s_out = "DW_CC_LLVM_PreserveAll"; + return DW_DLV_OK; + case DW_CC_LLVM_X86RegCall: + *s_out = "DW_CC_LLVM_X86RegCall"; + return DW_DLV_OK; + case DW_CC_GDB_IBM_OpenCL: + *s_out = "DW_CC_GDB_IBM_OpenCL"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xff. DW_CC_hi_user */ + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_INL_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_INL_not_inlined: + *s_out = "DW_INL_not_inlined"; + return DW_DLV_OK; + case DW_INL_inlined: + *s_out = "DW_INL_inlined"; + return DW_DLV_OK; + case DW_INL_declared_not_inlined: + *s_out = "DW_INL_declared_not_inlined"; + return DW_DLV_OK; + case DW_INL_declared_inlined: + *s_out = "DW_INL_declared_inlined"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ORD_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ORD_row_major: + *s_out = "DW_ORD_row_major"; + return DW_DLV_OK; + case DW_ORD_col_major: + *s_out = "DW_ORD_col_major"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_DSC_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_DSC_label: + *s_out = "DW_DSC_label"; + return DW_DLV_OK; + case DW_DSC_range: + *s_out = "DW_DSC_range"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LNCT_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LNCT_path: + *s_out = "DW_LNCT_path"; + return DW_DLV_OK; + case DW_LNCT_directory_index: + *s_out = "DW_LNCT_directory_index"; + return DW_DLV_OK; + case DW_LNCT_timestamp: + *s_out = "DW_LNCT_timestamp"; + return DW_DLV_OK; + case DW_LNCT_size: + *s_out = "DW_LNCT_size"; + return DW_DLV_OK; + case DW_LNCT_MD5: + *s_out = "DW_LNCT_MD5"; + return DW_DLV_OK; + case DW_LNCT_GNU_subprogram_name: + *s_out = "DW_LNCT_GNU_subprogram_name"; + return DW_DLV_OK; + case DW_LNCT_GNU_decl_file: + *s_out = "DW_LNCT_GNU_decl_file"; + return DW_DLV_OK; + case DW_LNCT_GNU_decl_line: + *s_out = "DW_LNCT_GNU_decl_line"; + return DW_DLV_OK; + case DW_LNCT_lo_user: + *s_out = "DW_LNCT_lo_user"; + return DW_DLV_OK; + case DW_LNCT_LLVM_source: + *s_out = "DW_LNCT_LLVM_source"; + return DW_DLV_OK; + case DW_LNCT_LLVM_is_MD5: + *s_out = "DW_LNCT_LLVM_is_MD5"; + return DW_DLV_OK; + case DW_LNCT_hi_user: + *s_out = "DW_LNCT_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LNS_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LNS_copy: + *s_out = "DW_LNS_copy"; + return DW_DLV_OK; + case DW_LNS_advance_pc: + *s_out = "DW_LNS_advance_pc"; + return DW_DLV_OK; + case DW_LNS_advance_line: + *s_out = "DW_LNS_advance_line"; + return DW_DLV_OK; + case DW_LNS_set_file: + *s_out = "DW_LNS_set_file"; + return DW_DLV_OK; + case DW_LNS_set_column: + *s_out = "DW_LNS_set_column"; + return DW_DLV_OK; + case DW_LNS_negate_stmt: + *s_out = "DW_LNS_negate_stmt"; + return DW_DLV_OK; + case DW_LNS_set_basic_block: + *s_out = "DW_LNS_set_basic_block"; + return DW_DLV_OK; + case DW_LNS_const_add_pc: + *s_out = "DW_LNS_const_add_pc"; + return DW_DLV_OK; + case DW_LNS_fixed_advance_pc: + *s_out = "DW_LNS_fixed_advance_pc"; + return DW_DLV_OK; + case DW_LNS_set_prologue_end: + *s_out = "DW_LNS_set_prologue_end"; + return DW_DLV_OK; + case DW_LNS_set_epilogue_begin: + *s_out = "DW_LNS_set_epilogue_begin"; + return DW_DLV_OK; + case DW_LNS_set_isa: + *s_out = "DW_LNS_set_isa"; + return DW_DLV_OK; + case DW_LNS_set_address_from_logical: + *s_out = "DW_LNS_set_address_from_logical"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0xd. DW_LNS_set_subprogram */ + case DW_LNS_inlined_call: + *s_out = "DW_LNS_inlined_call"; + return DW_DLV_OK; + case DW_LNS_pop_context: + *s_out = "DW_LNS_pop_context"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_LNE_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_LNE_end_sequence: + *s_out = "DW_LNE_end_sequence"; + return DW_DLV_OK; + case DW_LNE_set_address: + *s_out = "DW_LNE_set_address"; + return DW_DLV_OK; + case DW_LNE_define_file: + *s_out = "DW_LNE_define_file"; + return DW_DLV_OK; + case DW_LNE_set_discriminator: + *s_out = "DW_LNE_set_discriminator"; + return DW_DLV_OK; + case DW_LNE_HP_negate_is_UV_update: + *s_out = "DW_LNE_HP_negate_is_UV_update"; + return DW_DLV_OK; + case DW_LNE_HP_push_context: + *s_out = "DW_LNE_HP_push_context"; + return DW_DLV_OK; + case DW_LNE_HP_pop_context: + *s_out = "DW_LNE_HP_pop_context"; + return DW_DLV_OK; + case DW_LNE_HP_set_file_line_column: + *s_out = "DW_LNE_HP_set_file_line_column"; + return DW_DLV_OK; + case DW_LNE_HP_set_routine_name: + *s_out = "DW_LNE_HP_set_routine_name"; + return DW_DLV_OK; + case DW_LNE_HP_set_sequence: + *s_out = "DW_LNE_HP_set_sequence"; + return DW_DLV_OK; + case DW_LNE_HP_negate_post_semantics: + *s_out = "DW_LNE_HP_negate_post_semantics"; + return DW_DLV_OK; + case DW_LNE_HP_negate_function_exit: + *s_out = "DW_LNE_HP_negate_function_exit"; + return DW_DLV_OK; + case DW_LNE_HP_negate_front_end_logical: + *s_out = "DW_LNE_HP_negate_front_end_logical"; + return DW_DLV_OK; + case DW_LNE_HP_define_proc: + *s_out = "DW_LNE_HP_define_proc"; + return DW_DLV_OK; + case DW_LNE_HP_source_file_correlation: + *s_out = "DW_LNE_HP_source_file_correlation"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x80. DW_LNE_lo_user */ + case DW_LNE_hi_user: + *s_out = "DW_LNE_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ISA_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ISA_UNKNOWN: + *s_out = "DW_ISA_UNKNOWN"; + return DW_DLV_OK; + case DW_ISA_ARM_thumb: + *s_out = "DW_ISA_ARM_thumb"; + return DW_DLV_OK; + case DW_ISA_ARM_arm: + *s_out = "DW_ISA_ARM_arm"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_MACRO_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_MACRO_define: + *s_out = "DW_MACRO_define"; + return DW_DLV_OK; + case DW_MACRO_undef: + *s_out = "DW_MACRO_undef"; + return DW_DLV_OK; + case DW_MACRO_start_file: + *s_out = "DW_MACRO_start_file"; + return DW_DLV_OK; + case DW_MACRO_end_file: + *s_out = "DW_MACRO_end_file"; + return DW_DLV_OK; + case DW_MACRO_define_strp: + *s_out = "DW_MACRO_define_strp"; + return DW_DLV_OK; + case DW_MACRO_undef_strp: + *s_out = "DW_MACRO_undef_strp"; + return DW_DLV_OK; + case DW_MACRO_import: + *s_out = "DW_MACRO_import"; + return DW_DLV_OK; + case DW_MACRO_define_sup: + *s_out = "DW_MACRO_define_sup"; + return DW_DLV_OK; + case DW_MACRO_undef_sup: + *s_out = "DW_MACRO_undef_sup"; + return DW_DLV_OK; + case DW_MACRO_import_sup: + *s_out = "DW_MACRO_import_sup"; + return DW_DLV_OK; + case DW_MACRO_define_strx: + *s_out = "DW_MACRO_define_strx"; + return DW_DLV_OK; + case DW_MACRO_undef_strx: + *s_out = "DW_MACRO_undef_strx"; + return DW_DLV_OK; + case DW_MACRO_lo_user: + *s_out = "DW_MACRO_lo_user"; + return DW_DLV_OK; + case DW_MACRO_hi_user: + *s_out = "DW_MACRO_hi_user"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_MACINFO_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_MACINFO_define: + *s_out = "DW_MACINFO_define"; + return DW_DLV_OK; + case DW_MACINFO_undef: + *s_out = "DW_MACINFO_undef"; + return DW_DLV_OK; + case DW_MACINFO_start_file: + *s_out = "DW_MACINFO_start_file"; + return DW_DLV_OK; + case DW_MACINFO_end_file: + *s_out = "DW_MACINFO_end_file"; + return DW_DLV_OK; + case DW_MACINFO_vendor_ext: + *s_out = "DW_MACINFO_vendor_ext"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_CFA_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_CFA_nop: + *s_out = "DW_CFA_nop"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x0. DW_CFA_extended */ + case DW_CFA_set_loc: + *s_out = "DW_CFA_set_loc"; + return DW_DLV_OK; + case DW_CFA_advance_loc1: + *s_out = "DW_CFA_advance_loc1"; + return DW_DLV_OK; + case DW_CFA_advance_loc2: + *s_out = "DW_CFA_advance_loc2"; + return DW_DLV_OK; + case DW_CFA_advance_loc4: + *s_out = "DW_CFA_advance_loc4"; + return DW_DLV_OK; + case DW_CFA_offset_extended: + *s_out = "DW_CFA_offset_extended"; + return DW_DLV_OK; + case DW_CFA_restore_extended: + *s_out = "DW_CFA_restore_extended"; + return DW_DLV_OK; + case DW_CFA_undefined: + *s_out = "DW_CFA_undefined"; + return DW_DLV_OK; + case DW_CFA_same_value: + *s_out = "DW_CFA_same_value"; + return DW_DLV_OK; + case DW_CFA_register: + *s_out = "DW_CFA_register"; + return DW_DLV_OK; + case DW_CFA_remember_state: + *s_out = "DW_CFA_remember_state"; + return DW_DLV_OK; + case DW_CFA_restore_state: + *s_out = "DW_CFA_restore_state"; + return DW_DLV_OK; + case DW_CFA_def_cfa: + *s_out = "DW_CFA_def_cfa"; + return DW_DLV_OK; + case DW_CFA_def_cfa_register: + *s_out = "DW_CFA_def_cfa_register"; + return DW_DLV_OK; + case DW_CFA_def_cfa_offset: + *s_out = "DW_CFA_def_cfa_offset"; + return DW_DLV_OK; + case DW_CFA_def_cfa_expression: + *s_out = "DW_CFA_def_cfa_expression"; + return DW_DLV_OK; + case DW_CFA_expression: + *s_out = "DW_CFA_expression"; + return DW_DLV_OK; + case DW_CFA_offset_extended_sf: + *s_out = "DW_CFA_offset_extended_sf"; + return DW_DLV_OK; + case DW_CFA_def_cfa_sf: + *s_out = "DW_CFA_def_cfa_sf"; + return DW_DLV_OK; + case DW_CFA_def_cfa_offset_sf: + *s_out = "DW_CFA_def_cfa_offset_sf"; + return DW_DLV_OK; + case DW_CFA_val_offset: + *s_out = "DW_CFA_val_offset"; + return DW_DLV_OK; + case DW_CFA_val_offset_sf: + *s_out = "DW_CFA_val_offset_sf"; + return DW_DLV_OK; + case DW_CFA_val_expression: + *s_out = "DW_CFA_val_expression"; + return DW_DLV_OK; + case DW_CFA_lo_user: + *s_out = "DW_CFA_lo_user"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x1c. DW_CFA_low_user */ + case DW_CFA_MIPS_advance_loc8: + *s_out = "DW_CFA_MIPS_advance_loc8"; + return DW_DLV_OK; + case DW_CFA_GNU_window_save: + *s_out = "DW_CFA_GNU_window_save"; + return DW_DLV_OK; + /* Skipping alternate spelling of value + 0x2d. DW_CFA_AARCH64_negate_ra_state */ + case DW_CFA_GNU_args_size: + *s_out = "DW_CFA_GNU_args_size"; + return DW_DLV_OK; + case DW_CFA_GNU_negative_offset_extended: + *s_out = "DW_CFA_GNU_negative_offset_extended"; + return DW_DLV_OK; + case DW_CFA_LLVM_def_aspace_cfa: + *s_out = "DW_CFA_LLVM_def_aspace_cfa"; + return DW_DLV_OK; + case DW_CFA_LLVM_def_aspace_cfa_sf: + *s_out = "DW_CFA_LLVM_def_aspace_cfa_sf"; + return DW_DLV_OK; + case DW_CFA_METAWARE_info: + *s_out = "DW_CFA_METAWARE_info"; + return DW_DLV_OK; + case DW_CFA_high_user: + *s_out = "DW_CFA_high_user"; + return DW_DLV_OK; + case DW_CFA_advance_loc: + *s_out = "DW_CFA_advance_loc"; + return DW_DLV_OK; + case DW_CFA_offset: + *s_out = "DW_CFA_offset"; + return DW_DLV_OK; + case DW_CFA_restore: + *s_out = "DW_CFA_restore"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_EH_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_EH_PE_absptr: + *s_out = "DW_EH_PE_absptr"; + return DW_DLV_OK; + case DW_EH_PE_uleb128: + *s_out = "DW_EH_PE_uleb128"; + return DW_DLV_OK; + case DW_EH_PE_udata2: + *s_out = "DW_EH_PE_udata2"; + return DW_DLV_OK; + case DW_EH_PE_udata4: + *s_out = "DW_EH_PE_udata4"; + return DW_DLV_OK; + case DW_EH_PE_udata8: + *s_out = "DW_EH_PE_udata8"; + return DW_DLV_OK; + case DW_EH_PE_sleb128: + *s_out = "DW_EH_PE_sleb128"; + return DW_DLV_OK; + case DW_EH_PE_sdata2: + *s_out = "DW_EH_PE_sdata2"; + return DW_DLV_OK; + case DW_EH_PE_sdata4: + *s_out = "DW_EH_PE_sdata4"; + return DW_DLV_OK; + case DW_EH_PE_sdata8: + *s_out = "DW_EH_PE_sdata8"; + return DW_DLV_OK; + case DW_EH_PE_pcrel: + *s_out = "DW_EH_PE_pcrel"; + return DW_DLV_OK; + case DW_EH_PE_textrel: + *s_out = "DW_EH_PE_textrel"; + return DW_DLV_OK; + case DW_EH_PE_datarel: + *s_out = "DW_EH_PE_datarel"; + return DW_DLV_OK; + case DW_EH_PE_funcrel: + *s_out = "DW_EH_PE_funcrel"; + return DW_DLV_OK; + case DW_EH_PE_aligned: + *s_out = "DW_EH_PE_aligned"; + return DW_DLV_OK; + case DW_EH_PE_omit: + *s_out = "DW_EH_PE_omit"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_FRAME_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_FRAME_LAST_REG_NUM: + *s_out = "DW_FRAME_LAST_REG_NUM"; + return DW_DLV_OK; + case DW_FRAME_REG1: + *s_out = "DW_FRAME_REG1"; + return DW_DLV_OK; + case DW_FRAME_REG2: + *s_out = "DW_FRAME_REG2"; + return DW_DLV_OK; + case DW_FRAME_REG3: + *s_out = "DW_FRAME_REG3"; + return DW_DLV_OK; + case DW_FRAME_REG4: + *s_out = "DW_FRAME_REG4"; + return DW_DLV_OK; + case DW_FRAME_REG5: + *s_out = "DW_FRAME_REG5"; + return DW_DLV_OK; + case DW_FRAME_REG6: + *s_out = "DW_FRAME_REG6"; + return DW_DLV_OK; + case DW_FRAME_REG7: + *s_out = "DW_FRAME_REG7"; + return DW_DLV_OK; + case DW_FRAME_REG8: + *s_out = "DW_FRAME_REG8"; + return DW_DLV_OK; + case DW_FRAME_REG9: + *s_out = "DW_FRAME_REG9"; + return DW_DLV_OK; + case DW_FRAME_REG10: + *s_out = "DW_FRAME_REG10"; + return DW_DLV_OK; + case DW_FRAME_REG11: + *s_out = "DW_FRAME_REG11"; + return DW_DLV_OK; + case DW_FRAME_REG12: + *s_out = "DW_FRAME_REG12"; + return DW_DLV_OK; + case DW_FRAME_REG13: + *s_out = "DW_FRAME_REG13"; + return DW_DLV_OK; + case DW_FRAME_REG14: + *s_out = "DW_FRAME_REG14"; + return DW_DLV_OK; + case DW_FRAME_REG15: + *s_out = "DW_FRAME_REG15"; + return DW_DLV_OK; + case DW_FRAME_REG16: + *s_out = "DW_FRAME_REG16"; + return DW_DLV_OK; + case DW_FRAME_REG17: + *s_out = "DW_FRAME_REG17"; + return DW_DLV_OK; + case DW_FRAME_REG18: + *s_out = "DW_FRAME_REG18"; + return DW_DLV_OK; + case DW_FRAME_REG19: + *s_out = "DW_FRAME_REG19"; + return DW_DLV_OK; + case DW_FRAME_REG20: + *s_out = "DW_FRAME_REG20"; + return DW_DLV_OK; + case DW_FRAME_REG21: + *s_out = "DW_FRAME_REG21"; + return DW_DLV_OK; + case DW_FRAME_REG22: + *s_out = "DW_FRAME_REG22"; + return DW_DLV_OK; + case DW_FRAME_REG23: + *s_out = "DW_FRAME_REG23"; + return DW_DLV_OK; + case DW_FRAME_REG24: + *s_out = "DW_FRAME_REG24"; + return DW_DLV_OK; + case DW_FRAME_REG25: + *s_out = "DW_FRAME_REG25"; + return DW_DLV_OK; + case DW_FRAME_REG26: + *s_out = "DW_FRAME_REG26"; + return DW_DLV_OK; + case DW_FRAME_REG27: + *s_out = "DW_FRAME_REG27"; + return DW_DLV_OK; + case DW_FRAME_REG28: + *s_out = "DW_FRAME_REG28"; + return DW_DLV_OK; + case DW_FRAME_REG29: + *s_out = "DW_FRAME_REG29"; + return DW_DLV_OK; + case DW_FRAME_REG30: + *s_out = "DW_FRAME_REG30"; + return DW_DLV_OK; + case DW_FRAME_REG31: + *s_out = "DW_FRAME_REG31"; + return DW_DLV_OK; + case DW_FRAME_FREG0: + *s_out = "DW_FRAME_FREG0"; + return DW_DLV_OK; + case DW_FRAME_FREG1: + *s_out = "DW_FRAME_FREG1"; + return DW_DLV_OK; + case DW_FRAME_FREG2: + *s_out = "DW_FRAME_FREG2"; + return DW_DLV_OK; + case DW_FRAME_FREG3: + *s_out = "DW_FRAME_FREG3"; + return DW_DLV_OK; + case DW_FRAME_FREG4: + *s_out = "DW_FRAME_FREG4"; + return DW_DLV_OK; + case DW_FRAME_FREG5: + *s_out = "DW_FRAME_FREG5"; + return DW_DLV_OK; + case DW_FRAME_FREG6: + *s_out = "DW_FRAME_FREG6"; + return DW_DLV_OK; + case DW_FRAME_FREG7: + *s_out = "DW_FRAME_FREG7"; + return DW_DLV_OK; + case DW_FRAME_FREG8: + *s_out = "DW_FRAME_FREG8"; + return DW_DLV_OK; + case DW_FRAME_FREG9: + *s_out = "DW_FRAME_FREG9"; + return DW_DLV_OK; + case DW_FRAME_FREG10: + *s_out = "DW_FRAME_FREG10"; + return DW_DLV_OK; + case DW_FRAME_FREG11: + *s_out = "DW_FRAME_FREG11"; + return DW_DLV_OK; + case DW_FRAME_FREG12: + *s_out = "DW_FRAME_FREG12"; + return DW_DLV_OK; + case DW_FRAME_FREG13: + *s_out = "DW_FRAME_FREG13"; + return DW_DLV_OK; + case DW_FRAME_FREG14: + *s_out = "DW_FRAME_FREG14"; + return DW_DLV_OK; + case DW_FRAME_FREG15: + *s_out = "DW_FRAME_FREG15"; + return DW_DLV_OK; + case DW_FRAME_FREG16: + *s_out = "DW_FRAME_FREG16"; + return DW_DLV_OK; + case DW_FRAME_FREG17: + *s_out = "DW_FRAME_FREG17"; + return DW_DLV_OK; + case DW_FRAME_FREG18: + *s_out = "DW_FRAME_FREG18"; + return DW_DLV_OK; + case DW_FRAME_FREG19: + *s_out = "DW_FRAME_FREG19"; + return DW_DLV_OK; + case DW_FRAME_FREG20: + *s_out = "DW_FRAME_FREG20"; + return DW_DLV_OK; + case DW_FRAME_FREG21: + *s_out = "DW_FRAME_FREG21"; + return DW_DLV_OK; + case DW_FRAME_FREG22: + *s_out = "DW_FRAME_FREG22"; + return DW_DLV_OK; + case DW_FRAME_FREG23: + *s_out = "DW_FRAME_FREG23"; + return DW_DLV_OK; + case DW_FRAME_FREG24: + *s_out = "DW_FRAME_FREG24"; + return DW_DLV_OK; + case DW_FRAME_FREG25: + *s_out = "DW_FRAME_FREG25"; + return DW_DLV_OK; + case DW_FRAME_FREG26: + *s_out = "DW_FRAME_FREG26"; + return DW_DLV_OK; + case DW_FRAME_FREG27: + *s_out = "DW_FRAME_FREG27"; + return DW_DLV_OK; + case DW_FRAME_FREG28: + *s_out = "DW_FRAME_FREG28"; + return DW_DLV_OK; + case DW_FRAME_FREG29: + *s_out = "DW_FRAME_FREG29"; + return DW_DLV_OK; + case DW_FRAME_FREG30: + *s_out = "DW_FRAME_FREG30"; + return DW_DLV_OK; + case DW_FRAME_FREG31: + *s_out = "DW_FRAME_FREG31"; + return DW_DLV_OK; + case DW_FRAME_FREG32: + *s_out = "DW_FRAME_FREG32"; + return DW_DLV_OK; + case DW_FRAME_FREG33: + *s_out = "DW_FRAME_FREG33"; + return DW_DLV_OK; + case DW_FRAME_FREG34: + *s_out = "DW_FRAME_FREG34"; + return DW_DLV_OK; + case DW_FRAME_FREG35: + *s_out = "DW_FRAME_FREG35"; + return DW_DLV_OK; + case DW_FRAME_FREG36: + *s_out = "DW_FRAME_FREG36"; + return DW_DLV_OK; + case DW_FRAME_FREG37: + *s_out = "DW_FRAME_FREG37"; + return DW_DLV_OK; + case DW_FRAME_FREG38: + *s_out = "DW_FRAME_FREG38"; + return DW_DLV_OK; + case DW_FRAME_FREG39: + *s_out = "DW_FRAME_FREG39"; + return DW_DLV_OK; + case DW_FRAME_FREG40: + *s_out = "DW_FRAME_FREG40"; + return DW_DLV_OK; + case DW_FRAME_FREG41: + *s_out = "DW_FRAME_FREG41"; + return DW_DLV_OK; + case DW_FRAME_FREG42: + *s_out = "DW_FRAME_FREG42"; + return DW_DLV_OK; + case DW_FRAME_FREG43: + *s_out = "DW_FRAME_FREG43"; + return DW_DLV_OK; + case DW_FRAME_FREG44: + *s_out = "DW_FRAME_FREG44"; + return DW_DLV_OK; + case DW_FRAME_FREG45: + *s_out = "DW_FRAME_FREG45"; + return DW_DLV_OK; + case DW_FRAME_FREG46: + *s_out = "DW_FRAME_FREG46"; + return DW_DLV_OK; + case DW_FRAME_FREG47: + *s_out = "DW_FRAME_FREG47"; + return DW_DLV_OK; + case DW_FRAME_FREG48: + *s_out = "DW_FRAME_FREG48"; + return DW_DLV_OK; + case DW_FRAME_FREG49: + *s_out = "DW_FRAME_FREG49"; + return DW_DLV_OK; + case DW_FRAME_FREG50: + *s_out = "DW_FRAME_FREG50"; + return DW_DLV_OK; + case DW_FRAME_FREG51: + *s_out = "DW_FRAME_FREG51"; + return DW_DLV_OK; + case DW_FRAME_FREG52: + *s_out = "DW_FRAME_FREG52"; + return DW_DLV_OK; + case DW_FRAME_FREG53: + *s_out = "DW_FRAME_FREG53"; + return DW_DLV_OK; + case DW_FRAME_FREG54: + *s_out = "DW_FRAME_FREG54"; + return DW_DLV_OK; + case DW_FRAME_FREG55: + *s_out = "DW_FRAME_FREG55"; + return DW_DLV_OK; + case DW_FRAME_FREG56: + *s_out = "DW_FRAME_FREG56"; + return DW_DLV_OK; + case DW_FRAME_FREG57: + *s_out = "DW_FRAME_FREG57"; + return DW_DLV_OK; + case DW_FRAME_FREG58: + *s_out = "DW_FRAME_FREG58"; + return DW_DLV_OK; + case DW_FRAME_FREG59: + *s_out = "DW_FRAME_FREG59"; + return DW_DLV_OK; + case DW_FRAME_FREG60: + *s_out = "DW_FRAME_FREG60"; + return DW_DLV_OK; + case DW_FRAME_FREG61: + *s_out = "DW_FRAME_FREG61"; + return DW_DLV_OK; + case DW_FRAME_FREG62: + *s_out = "DW_FRAME_FREG62"; + return DW_DLV_OK; + case DW_FRAME_FREG63: + *s_out = "DW_FRAME_FREG63"; + return DW_DLV_OK; + case DW_FRAME_FREG64: + *s_out = "DW_FRAME_FREG64"; + return DW_DLV_OK; + case DW_FRAME_FREG65: + *s_out = "DW_FRAME_FREG65"; + return DW_DLV_OK; + case DW_FRAME_FREG66: + *s_out = "DW_FRAME_FREG66"; + return DW_DLV_OK; + case DW_FRAME_FREG67: + *s_out = "DW_FRAME_FREG67"; + return DW_DLV_OK; + case DW_FRAME_FREG68: + *s_out = "DW_FRAME_FREG68"; + return DW_DLV_OK; + case DW_FRAME_FREG69: + *s_out = "DW_FRAME_FREG69"; + return DW_DLV_OK; + case DW_FRAME_FREG70: + *s_out = "DW_FRAME_FREG70"; + return DW_DLV_OK; + case DW_FRAME_FREG71: + *s_out = "DW_FRAME_FREG71"; + return DW_DLV_OK; + case DW_FRAME_FREG72: + *s_out = "DW_FRAME_FREG72"; + return DW_DLV_OK; + case DW_FRAME_FREG73: + *s_out = "DW_FRAME_FREG73"; + return DW_DLV_OK; + case DW_FRAME_FREG74: + *s_out = "DW_FRAME_FREG74"; + return DW_DLV_OK; + case DW_FRAME_FREG75: + *s_out = "DW_FRAME_FREG75"; + return DW_DLV_OK; + case DW_FRAME_FREG76: + *s_out = "DW_FRAME_FREG76"; + return DW_DLV_OK; + case DW_FRAME_HIGHEST_NORMAL_REGISTER: + *s_out = "DW_FRAME_HIGHEST_NORMAL_REGISTER"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_CHILDREN_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_CHILDREN_no: + *s_out = "DW_CHILDREN_no"; + return DW_DLV_OK; + case DW_CHILDREN_yes: + *s_out = "DW_CHILDREN_yes"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} +/* ARGSUSED */ +int +dwarf_get_ADDR_name (unsigned int val, + const char ** s_out) +{ + switch (val) { + case DW_ADDR_none: + *s_out = "DW_ADDR_none"; + return DW_DLV_OK; + default: break; + } + return DW_DLV_NO_ENTRY; +} + +/* END FILE */ diff --git a/src/lib/libdwarf/dwarf_object_detector.c b/src/lib/libdwarf/dwarf_object_detector.c new file mode 100644 index 0000000..16dd70d --- /dev/null +++ b/src/lib/libdwarf/dwarf_object_detector.c @@ -0,0 +1,1019 @@ +/* +Copyright (c) 2018-2020, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include /* free() */ +#include /* SEEK_END SEEK_SET */ +#include /* memset() strlen() */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* lseek() off_t ssize_t */ +#elif defined HAVE_UNISTD_H +#include /* lseek() off_t */ +#endif /* _WIN32 */ + +#ifdef HAVE_FCNTL_H +#include /* open() O_RDONLY */ +#endif /* HAVE_FCNTL_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_object_read_common.h" +#include "dwarf_object_detector.h" +#include "dwarf_macho_loader.h" +#include "dwarf_string.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif /* O_CLOEXEC */ + +/* TYP, SIZEOFT32 and ASNAR + mean we can use correctly-sized arrays of char for the + struct members instead of determining a proper integer + that size. + + We are dealing with carefully constructed structs + that do not have any alignment-forced (hidden) + unused bytes so reading lengths from the real structs + works for each variable. */ + +#define TYP(n,l) char (n)[(l)] +#define SIZEOFT32 4 + +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_OK 0 +#define DW_DLV_ERROR 1 + +#ifndef EI_NIDENT +#define EI_NIDENT 16 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +#endif /* EI_NIDENT */ + +#define DSYM_SUFFIX ".dSYM/Contents/Resources/DWARF/" +#define PATHSIZE 2000 + +#ifndef MH_MAGIC +/* mach-o 32bit */ +#define MH_MAGIC 0xfeedface +#define MH_CIGAM 0xcefaedfe +#endif /* MH_MAGIC */ +#ifndef MH_MAGIC_64 +/* mach-o 64bit */ +#define MH_MAGIC_64 0xfeedfacf +#define MH_CIGAM_64 0xcffaedfe +#endif /* MH_MAGIC_64 */ + +/* A flag not public to users. */ +static int _dwarf_global_debuglink_crc_suppress; + +int +dwarf_suppress_debuglink_crc(int dw_suppress) +{ + int old = _dwarf_global_debuglink_crc_suppress; + _dwarf_global_debuglink_crc_suppress = dw_suppress; + return old; +} + +int _dwarf_get_suppress_debuglink_crc(void) +{ + return _dwarf_global_debuglink_crc_suppress; +} + +static unsigned long +magic_copy(unsigned char *d, unsigned len) +{ + unsigned i = 0; + unsigned long v = 0; + + v = d[0]; + for (i = 1 ; i < len; ++i) { + v <<= 8; + v |= d[i]; + } + return v; +} + +#define EI_NIDENT 16 +/* An incomplete elf header, good for 32 and 64bit elf */ +struct elf_header { + unsigned char e_ident[EI_NIDENT]; + TYP(e_type,2); + TYP(e_machine,2); + TYP(e_version,4); +}; + +/* Windows. Certain PE objects. + The following references may be of interest. +https://msdn.microsoft.com/library/windows/\ +desktop/ms680547(v=vs.85).aspx +#PE format overview and various machine magic numbers + +https://msdn.microsoft.com/en-us/library/\ +ms809762.aspx +# describes some details of PE headers, basically an overview + +https://msdn.microsoft.com/en-us/library/\ +windows/desktop/aa383751(v=vs.85).aspx +#defines sizes of various types + +https://msdn.microsoft.com/fr-fr/library/\ +windows/desktop/ms680313(v=vs.85).aspx +#defines IMAGE_FILE_HEADER and Machine fields (32/64) + +https://msdn.microsoft.com/fr-fr/library/\ +windows/desktop/ms680305(v=vs.85).aspx +#defines IMAGE_DATA_DIRECTORY + +https://msdn.microsoft.com/en-us/library/\ +windows/desktop/ms680339(v=vs.85).aspx +#Defines IMAGE_OPTIONAL_HEADER and some magic numbers + +https://msdn.microsoft.com/fr-fr/library/\ +windows/desktop/ms680336(v=vs.85).aspx +# defines _IMAGE_NT_HEADERS 32 64 + +https://msdn.microsoft.com/en-us/library/\ +windows/desktop/ms680341(v=vs.85).aspx +# defines _IMAGE_SECTION_HEADER + +*/ + +/* ===== START pe structures */ + +struct dos_header { + TYP(dh_mz,2); + TYP(dh_dos_data,58); + TYP(dh_image_offset,4); +}; + +#define IMAGE_DOS_SIGNATURE_dw 0x5A4D +#define IMAGE_DOS_REVSIGNATURE_dw 0x4D5A +#define IMAGE_NT_SIGNATURE_dw 0x00004550 +#define IMAGE_FILE_MACHINE_I386_dw 0x14c +#define IMAGE_FILE_MACHINE_IA64_dw 0x200 +#define IMAGE_FILE_MACHINE_AMD64_dw 0x8664 + +struct pe_image_file_header { + TYP(im_machine,2); + TYP(im_sectioncount,2); + TYP(im_ignoring,(3*4)); + TYP(im_opt_header_size,2); + TYP(im_ignoringb,2); +}; + +/* ===== END pe structures */ + +/* For following MacOS file naming convention */ +static const char * +getseparator (const char *f) +{ + const char *p = 0; + const char *q = 0; + char c = 0;; + + p = NULL; + q = f; + do { + c = *q++; + if (c == '\\' || c == '/' || c == ':') { + p = q; + } + } while (c); + return p; +} + +static const char * +getbasename (const char *f) +{ + const char *pseparator = getseparator (f); + if (!pseparator) { + return f; + } + return pseparator; +} + +/* Not a standard function. */ +static int +dw_stpcpy(char *dest,const char *src,char **destend, char *endpoint) +{ + const char *cp = src; + char *dp = dest; + + for ( ; *cp; ++cp,++dp) { + if (dp >= endpoint) { + return DW_DLV_ERROR; + } + *dp = *cp; + } + if (dp >= endpoint) { + return DW_DLV_ERROR; + } + *dp = 0; + *destend = dp; + return DW_DLV_OK; +} + +/* This started like Elf, so check initial fields. */ +static int +fill_in_elf_fields(struct elf_header *h, + unsigned *endian, + /* Size of the object file offsets, not DWARF offset + size. */ + unsigned *objoffsetsize, + int *errcode) +{ + unsigned locendian = 0; + unsigned locoffsetsize = 0; + + switch(h->e_ident[EI_CLASS]) { + case ELFCLASS32: + locoffsetsize = 32; + break; + case ELFCLASS64: + locoffsetsize = 64; + break; + default: + *errcode = DW_DLE_ELF_CLASS_BAD; + return DW_DLV_ERROR; + } + switch(h->e_ident[EI_DATA]) { + case ELFDATA2LSB: + locendian = DW_END_little; + break; + case ELFDATA2MSB: + locendian = DW_END_big; + break; + default: + *errcode = DW_DLE_ELF_ENDIAN_BAD; + return DW_DLV_ERROR; + } + if (h->e_ident[EI_VERSION] != 1 /* EV_CURRENT */) { + *errcode = DW_DLE_ELF_VERSION_BAD; + return DW_DLV_ERROR; + } + *endian = locendian; + *objoffsetsize = locoffsetsize; + return DW_DLV_OK; +} +static char archive_magic[8] = { +'!','<','a','r','c','h','>',0x0a +}; +static int +is_archive_magic(struct elf_header *h) { + int i = 0; + int len = sizeof(archive_magic); + const char *cp = (const char *)h; + for ( ; i < len; ++i) { + if (cp[i] != archive_magic[i]) { + return FALSE; + } + } + return TRUE; +} + +/* A bit unusual in that it always sets *is_pe_flag + Return of DW_DLV_OK it is a PE file we recognize. */ +static int +is_pe_object(int fd, + unsigned long filesize, + unsigned *endian, + unsigned *offsetsize, + int *errcode) +{ + unsigned dos_sig = 0; + unsigned locendian = 0; + void (*word_swap) (void *, const void *, unsigned long); + unsigned long nt_address = 0; + struct dos_header dhinmem; + char nt_sig_array[4]; + unsigned long nt_sig = 0; + struct pe_image_file_header ifh; + int res = 0; + + if (filesize < (sizeof (struct dos_header) + + SIZEOFT32 + sizeof(struct pe_image_file_header))) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(fd,(char *)&dhinmem, + 0,sizeof(dhinmem),filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + /* No swap here, want it as in the file */ + dos_sig = magic_copy((unsigned char *)dhinmem.dh_mz, + sizeof(dhinmem.dh_mz)); + if (dos_sig == IMAGE_DOS_SIGNATURE_dw) { + /* IMAGE_DOS_SIGNATURE_dw assumes bytes + reversed by little-endian + load, so we intrepet a match the other way. */ + /* BIG ENDIAN. From looking at hex characters in object */ +#ifdef WORDS_BIGENDIAN + word_swap = _dwarf_memcpy_noswap_bytes; +#else /* LITTLE ENDIAN */ + word_swap = _dwarf_memcpy_swap_bytes; +#endif /* LITTLE- BIG-ENDIAN */ + locendian = DW_END_big; + } else if (dos_sig == IMAGE_DOS_REVSIGNATURE_dw) { + /* raw load, so intrepet a match the other way. */ + /* LITTLE ENDIAN */ +#ifdef WORDS_BIGENDIAN + word_swap = _dwarf_memcpy_swap_bytes; +#else /* LITTLE ENDIAN */ + word_swap = _dwarf_memcpy_noswap_bytes; +#endif /* LITTLE- BIG-ENDIAN */ + locendian = DW_END_little; + } else { + /* Not dos header not a PE file we recognize */ + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } + ASNAR(word_swap,nt_address, dhinmem.dh_image_offset); + if (filesize < nt_address) { + /* Not dos header not a PE file we recognize */ + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + if (filesize < (nt_address + SIZEOFT32 + + sizeof(struct pe_image_file_header))) { + *errcode = DW_DLE_FILE_TOO_SMALL; + /* Not dos header not a PE file we recognize */ + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(fd,(char *)&nt_sig_array[0], + nt_address, sizeof(nt_sig_array),filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + { unsigned long lsig = 0; + + ASNAR(word_swap,lsig,nt_sig_array); + nt_sig = lsig; + } + if (nt_sig != IMAGE_NT_SIGNATURE_dw) { + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(fd,(char *)&ifh, + nt_address + SIZEOFT32, + sizeof(struct pe_image_file_header), + filesize, + errcode); + if (res != DW_DLV_OK) { + return res; + } + { + unsigned long machine = 0; + + ASNAR(word_swap,machine,ifh.im_machine); + switch(machine) { + case IMAGE_FILE_MACHINE_I386_dw: + *offsetsize = 32; + *endian = locendian; + return DW_DLV_OK; + case IMAGE_FILE_MACHINE_IA64_dw: + case IMAGE_FILE_MACHINE_AMD64_dw: + *offsetsize = 64; + *endian = locendian; + return DW_DLV_OK; + default: break; + } + } + *errcode = DW_DLE_IMAGE_FILE_UNKNOWN_TYPE; + return DW_DLV_ERROR; +} + +static int +is_mach_o_universal(struct elf_header *h, + unsigned *endian, + unsigned *offsetsize) +{ + unsigned long magicval = 0; + unsigned locendian = 0; + unsigned locoffsetsize = 0; + + /* No swapping here. Need to match size of + the universal-object magic field. */ + magicval = magic_copy(h->e_ident,4); + if (magicval == FAT_MAGIC) { + locendian = DW_END_big; + locoffsetsize = 32; + } else if (magicval == FAT_CIGAM) { + locendian = DW_END_little; + locoffsetsize = 32; + }else if (magicval == FAT_MAGIC_64) { + locendian = DW_END_big; + locoffsetsize = 64; + } else if (magicval == FAT_CIGAM_64) { + locendian = DW_END_little; + locoffsetsize = 64; + } else { + return FALSE; + } + *endian = locendian; + *offsetsize = locoffsetsize; + return TRUE; +} + +static int +is_mach_o_magic(struct elf_header *h, + unsigned *endian, + unsigned *offsetsize) +{ + unsigned long magicval = 0; + unsigned locendian = 0; + unsigned locoffsetsize = 0; + + /* No swapping here. Need to match size of + Mach-o magic field. */ + magicval = magic_copy(h->e_ident,4); + if (magicval == MH_MAGIC) { + locendian = DW_END_big; + locoffsetsize = 32; + } else if (magicval == MH_CIGAM) { + locendian = DW_END_little; + locoffsetsize = 32; + }else if (magicval == MH_MAGIC_64) { + locendian = DW_END_big; + locoffsetsize = 64; + } else if (magicval == MH_CIGAM_64) { + locendian = DW_END_little; + locoffsetsize = 64; + } else { + return FALSE; + } + *endian = locendian; + *offsetsize = locoffsetsize; + return TRUE; +} + +int +dwarf_object_detector_fd(int fd, + unsigned *ftype, + unsigned *endian, + unsigned *offsetsize, + Dwarf_Unsigned *filesize, + int *errcode) +{ + Dwarf_Unsigned fileoffsetbase = 0; + int res = 0; + + res = _dwarf_object_detector_fd_a(fd, + ftype,endian,offsetsize, + fileoffsetbase,filesize, + errcode); + return res; +} + +int +_dwarf_object_detector_fd_a(int fd, + unsigned *ftype, + unsigned *endian, + unsigned *offsetsize, + Dwarf_Unsigned fileoffsetbase, + Dwarf_Unsigned *filesize, + int *errcode) +{ + struct elf_header h; + size_t readlen = sizeof(h); + int res = 0; + off_t fsize = 0; + off_t lsval = 0; + ssize_t readval = 0; + Dwarf_Unsigned remaininglen = 0; + + fsize = lseek(fd,0L,SEEK_END); + if (fsize < 0) { + *errcode = DW_DLE_SEEK_ERROR; + return DW_DLV_ERROR; + } + if (fsize <= (off_t)readlen) { + /* Not a real object file */ + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + remaininglen = fsize - fileoffsetbase; + if ((Dwarf_Unsigned)fsize <= fileoffsetbase) { + printf("FAIL: fsize <= offsetbase impossible\n"); + *errcode = DW_DLE_SEEK_ERROR; + return DW_DLV_ERROR; + } + if (remaininglen <= readlen) { + /* Not a real object file */ + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + + lsval = lseek(fd,fileoffsetbase,SEEK_SET); + if (lsval < 0) { + *errcode = DW_DLE_SEEK_ERROR; + return DW_DLV_ERROR; + } + readval = read(fd,&h,readlen); + if (readval != (ssize_t)readlen) { + *errcode = DW_DLE_READ_ERROR; + return DW_DLV_ERROR; + } + if (h.e_ident[0] == 0x7f && + h.e_ident[1] == 'E' && + h.e_ident[2] == 'L' && + h.e_ident[3] == 'F') { + /* is ELF */ + + res = fill_in_elf_fields(&h,endian,offsetsize,errcode); + if (res != DW_DLV_OK) { + return res; + } + *ftype = DW_FTYPE_ELF; + *filesize = (Dwarf_Unsigned)fsize; + return DW_DLV_OK; + } + if (is_mach_o_universal(&h,endian,offsetsize)) { + *ftype = DW_FTYPE_APPLEUNIVERSAL; + *filesize = (Dwarf_Unsigned)fsize; + return DW_DLV_OK; + } + if (is_mach_o_magic(&h,endian,offsetsize)) { + *ftype = DW_FTYPE_MACH_O; + *filesize = (Dwarf_Unsigned)fsize; + return DW_DLV_OK; + } + if (is_archive_magic(&h)) { + *ftype = DW_FTYPE_ARCHIVE; + *filesize = (Dwarf_Unsigned)fsize; + return DW_DLV_OK; + } + res = is_pe_object(fd,fsize,endian,offsetsize,errcode); + if (res == DW_DLV_OK ) { + *ftype = DW_FTYPE_PE; + *filesize = (Dwarf_Unsigned)fsize; + return DW_DLV_OK; + } + /* Unknown object format. */ + return DW_DLV_NO_ENTRY; +} + +int +dwarf_object_detector_path_dSYM( + const char *path, + char *outpath, unsigned long outpath_len, + char ** gl_pathnames, + unsigned gl_pathcount, + unsigned *ftype, + unsigned *endian, + unsigned *offsetsize, + Dwarf_Unsigned *filesize, + unsigned char *pathsource, + int *errcode) +{ + char *cp = 0; + size_t plen = strlen(path); + size_t dsprefixlen = sizeof(DSYM_SUFFIX); + int fd = -1; + int res = 0; + int have_outpath = outpath && outpath_len; + + (void)gl_pathnames; + (void)gl_pathcount; + if (have_outpath) { + /* Looking for MacOS dSYM */ + if ((2*plen + dsprefixlen +2) >= (size_t)outpath_len) { + *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = dw_stpcpy(outpath,path,&cp,outpath+outpath_len); + if (res == DW_DLV_ERROR) { + *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = dw_stpcpy(cp,DSYM_SUFFIX,&cp,outpath+outpath_len); + if (res == DW_DLV_ERROR) { + *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; + return DW_DLV_ERROR; + } + res= dw_stpcpy(cp,getbasename(path),&cp,outpath+outpath_len); + if (res == DW_DLV_ERROR) { + *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; + return DW_DLV_ERROR; + } + fd = open(outpath,O_RDONLY|O_BINARY|O_CLOEXEC); + if (fd < 0) { + outpath[0] = 0; + return DW_DLV_NO_ENTRY; + } + *pathsource = DW_PATHSOURCE_dsym; + res = dwarf_object_detector_fd(fd, + ftype,endian,offsetsize,filesize,errcode); + if (res != DW_DLV_OK) { + close(fd); + return res; + } + close(fd); + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static int +blockmatch(unsigned char *l, + unsigned char* r, + unsigned length) +{ + unsigned int i = 0; + for ( ; i < length; ++i) { + if (l[i] != r[i]) { + return FALSE; + } + } + return TRUE; +} + +/* The debug version we expect not to have debuglink, + checking here if buildid matches. + Returns TRUE or FALSE */ +static Dwarf_Bool +match_buildid( + unsigned char * crc_base, + unsigned buildid_length_base, + unsigned char *buildid_base, + /* *_base is executable info while + *_debug is the debug object. */ + unsigned char *crc_debug, + unsigned buildid_length_debug, + unsigned char *buildid_debug) +{ + if (!_dwarf_get_suppress_debuglink_crc() && \ + crc_debug && crc_base) { + /* crc available for both */ + if (!blockmatch(crc_debug,crc_base,4)) { + return FALSE; + } + return TRUE; + } + if (!blockmatch(buildid_base,buildid_debug, + buildid_length_base)) { + return FALSE; + } + if (buildid_length_base != buildid_length_debug) { + return FALSE; + } + return TRUE; +} + +static int +_dwarf_debuglink_finder_newpath( + char * path_in, + unsigned char *crc_in, + unsigned buildid_len_in, + unsigned char *buildid_in, + dwarfstring *m, + int * fd_out) +{ + unsigned char lcrc[4]; + char *debuglinkpath = 0; /* must be freed */ + unsigned char *crc = 0; + char *debuglinkfullpath = 0; + unsigned debuglinkfullpath_strlen = 0; + unsigned buildid_type = 0; + char * buildidownername = 0; + unsigned char *buildid = 0; + unsigned buildid_length = 0; + char ** paths = 0; /* must be freed */ + unsigned paths_count = 0; + Dwarf_Debug dbg = 0; + Dwarf_Error error = 0; + char *path = path_in; + Dwarf_Bool didmatch = FALSE; + int res = 0; + + res = dwarf_init_path(path, + 0,0, + DW_GROUPNUMBER_ANY, + 0,0, &dbg,&error); + if (res == DW_DLV_ERROR) { + /* ASSERT: dbg is NULL as init failed */ + dwarf_dealloc_error(dbg,error); + error = 0; + return DW_DLV_NO_ENTRY; + } + if (res == DW_DLV_NO_ENTRY) { + /* should never happen */ + return DW_DLV_NO_ENTRY; + } + res = dwarf_gnu_debuglink(dbg, + &debuglinkpath, + &crc, &debuglinkfullpath, &debuglinkfullpath_strlen, + &buildid_type, &buildidownername, + &buildid, &buildid_length, + &paths, &paths_count, &error); + if (res == DW_DLV_ERROR) { + dwarf_dealloc_error(dbg,error); + dwarf_finish(dbg); + error = 0; + dbg = 0; + return DW_DLV_NO_ENTRY; + } + if (res == DW_DLV_NO_ENTRY) { + /* There is no debuglink section */ + dwarf_finish(dbg); + dbg = 0; + return DW_DLV_NO_ENTRY; + } + free(paths); + paths = 0; + + memset(&lcrc[0],0,sizeof(lcrc)); + if (!_dwarf_get_suppress_debuglink_crc() &&crc_in && !crc) { + int res1 = 0; + + res1 = dwarf_crc32(dbg,lcrc,&error); + if (res1 == DW_DLV_ERROR) { + paths = 0; + free(debuglinkfullpath); + dwarf_dealloc_error(dbg,error); + dwarf_finish(dbg); + error = 0; + dbg = 0; + /* Cannot match the crc_in, give up. */ + return DW_DLV_NO_ENTRY; + } + if (res1 == DW_DLV_OK) { + crc = &lcrc[0]; + } + } + free(debuglinkfullpath); + didmatch = match_buildid( + /* This is about the executable */ + crc_in,buildid_len_in,buildid_in, + /* pass in local so we can calculate the missing crc */ + /* following is the target, ie, debug */ + crc,buildid_length,buildid); + if (error) { + /* This should never happen. It would mean + error was set without DW_DLV_ERROR */ + dwarf_dealloc_error(dbg,error); + error = 0; + } + if (didmatch) { + dwarfstring_append(m,path); + *fd_out = dbg->de_fd; + dbg->de_owns_fd = FALSE; + dwarf_finish(dbg); + dbg = 0; + return DW_DLV_OK; + } + dwarf_finish(dbg); + return DW_DLV_NO_ENTRY; +} + +static int +_dwarf_debuglink_finder_internal( + char **gl_pathnames, + unsigned int gl_pathcount, + char * path_in, + dwarfstring *m, + int * fd_out, + int * errcode) +{ + int res = 0; + /* This local dbg is opened and then dwarf_finish() + here. No dbg in the arguments! */ + Dwarf_Debug dbg = 0; + char * path = 0; + Dwarf_Error error = 0; + unsigned int p = 0; + char *debuglinkpath = 0; + unsigned char *crc = 0; + char *debuglinkfullpath = 0; /* must be freed*/ + unsigned debuglinkfullpath_strlen = 0; + unsigned buildid_type = 0; + char * buildidownername = 0; + unsigned char *buildid = 0; + unsigned buildid_length = 0; + char ** paths = 0; /* must be freed */ + unsigned paths_count = 0; + unsigned i = 0; + + path = path_in; + /* This path will work. + Already know the file is there. */ + res = dwarf_init_path(path, + 0,0, + DW_GROUPNUMBER_ANY, + 0,0, &dbg, &error); + if (res == DW_DLV_ERROR) { + *errcode = dwarf_errno(error); + dwarf_dealloc_error(dbg,error); + error = 0; + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + for (p = 0; p < gl_pathcount; ++p) { + const char *lpath = 0; + + lpath = (const char *)gl_pathnames[p]; + res = dwarf_add_debuglink_global_path(dbg, + lpath, &error); + if (res != DW_DLV_OK){ + if (res == DW_DLV_ERROR) { + *errcode = dwarf_errno(error); + dwarf_dealloc_error(dbg,error); + error = 0; + } + dwarf_finish(dbg); + return res; + } + } + res = dwarf_gnu_debuglink(dbg, + &debuglinkpath, + &crc, &debuglinkfullpath, &debuglinkfullpath_strlen, + &buildid_type, &buildidownername, + &buildid, &buildid_length, + &paths, &paths_count, &error); + if (res == DW_DLV_ERROR) { + *errcode = dwarf_errno(error); + dwarf_dealloc_error(dbg,error); + dwarf_finish(dbg); + return DW_DLV_NO_ENTRY; + } + if (res == DW_DLV_NO_ENTRY) { + /* There is no debuglink buildid section? */ + dwarf_finish(dbg); + return DW_DLV_NO_ENTRY; + } + for (i =0; i < paths_count; ++i) { + char *pa = paths[i]; + int pfd = 0; + + /* First, open the file to determine if it exists. + If not, loop again */ + + pfd = open(pa,O_RDONLY|O_BINARY| O_CLOEXEC); + if (pfd < 0) { + /* This is the usual path. */ + continue; + } + close(pfd); + /* ASSERT: never returns DW_DLV_ERROR */ + res = _dwarf_debuglink_finder_newpath( + pa,crc,buildid_length, buildid, + m,fd_out); + if (res == DW_DLV_OK) { + free(debuglinkfullpath); + free(paths); + paths = 0; + dwarf_finish(dbg); + return DW_DLV_OK; + } + *errcode = 0; + continue; + } + free(debuglinkfullpath); + free(paths); + paths = 0; + dwarf_finish(dbg); + return DW_DLV_NO_ENTRY; +} + +int +dwarf_object_detector_path_b( + const char * path, + char * outpath, + unsigned long outpath_len, + char ** gl_pathnames, + unsigned gl_pathcount, + unsigned * ftype, + unsigned * endian, + unsigned * offsetsize, + Dwarf_Unsigned * filesize, + unsigned char * pathsource, + int *errcode) +{ + int fd = -1; + int res = 0; + int have_outpath = outpath && outpath_len; + unsigned char lpathsource = DW_PATHSOURCE_basic; + + if (pathsource) { + lpathsource = *pathsource; + } + if (lpathsource == DW_PATHSOURCE_basic && have_outpath) { + /* On return from the following call we could well + close the fd above and open a new one. */ + int debuglink_fd = -1; + size_t dllenszt = 0; + char *cp = 0; + dwarfstring m; + + dwarfstring_constructor(&m); + res = _dwarf_debuglink_finder_internal( + gl_pathnames,gl_pathcount, + (char *)path, &m,&debuglink_fd, errcode); + if (res == DW_DLV_ERROR) { + dwarfstring_destructor(&m); + if (debuglink_fd != -1) { + close(debuglink_fd); + } + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* We did not find an alternative path */ + res = dw_stpcpy(outpath,path,&cp,outpath+outpath_len); + if (res != DW_DLV_OK) { + *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; + return DW_DLV_ERROR; + } + lpathsource = DW_PATHSOURCE_basic; + } else { + if (debuglink_fd != -1) { + close(debuglink_fd); + debuglink_fd = -1; + } + dllenszt = dwarfstring_strlen(&m)+1; + if (dllenszt >= (size_t)outpath_len) { + *errcode = DW_DLE_DEBUGLINK_PATH_SHORT; + return DW_DLV_ERROR; + } + res = dw_stpcpy(outpath,dwarfstring_string(&m), + &cp,outpath+outpath_len); + if (res != DW_DLV_OK) { + *errcode = DW_DLE_DEBUGLINK_PATH_SHORT; + return DW_DLV_ERROR; + } + lpathsource = DW_PATHSOURCE_debuglink; + } + dwarfstring_destructor(&m); + fd = open(outpath,O_RDONLY|O_BINARY|O_CLOEXEC); + /* fall through to get fsize etc */ + } else { + lpathsource = DW_PATHSOURCE_basic; + fd = open(path,O_RDONLY|O_BINARY|O_CLOEXEC); + } + if (fd < 0) { + if (pathsource) { + *pathsource = DW_PATHSOURCE_unspecified; + } + return DW_DLV_NO_ENTRY; + } + res = dwarf_object_detector_fd(fd, + ftype,endian,offsetsize,filesize,errcode); + if (res != DW_DLV_OK) { + lpathsource = DW_PATHSOURCE_unspecified; + } + if (pathsource) { + *pathsource = lpathsource; + } + close(fd); + return res; +} diff --git a/src/lib/libdwarf/dwarf_object_detector.h b/src/lib/libdwarf/dwarf_object_detector.h new file mode 100644 index 0000000..6f513e6 --- /dev/null +++ b/src/lib/libdwarf/dwarf_object_detector.h @@ -0,0 +1,91 @@ +/* Copyright (c) 2018-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#ifndef DWARF_OBJECT_DETECTOR_H +#define DWARF_OBJECT_DETECTOR_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Declares the interface function. + outpath is a place you provide, of a length outpath_len + you consider reasonable, + where the final path used is recorded. + outpath_len must be larger than strlen(path); + + This matters as for mach-o if the path is a directory + name the function will look in the standard macho-place + for the object file (useful for dSYM) and return the + constructed path in oupath. + returns DW_DLV_OK, DW_DLV_ERROR, or DW_DLV_NO_ENTRY */ + +#ifndef DW_FTYPE_UNKNOWN +#define DW_FTYPE_UNKNOWN 0 +#define DW_FTYPE_ELF 1 +#define DW_FTYPE_MACH_O 2 +#define DW_FTYPE_PE 3 +#define DW_FTYPE_ARCHIVE 4 /* unix archive */ +#endif /* DW_FTYPE_UNKNOWN */ + +/* offsetsize refers to the object-file-format. + Elf 32 or macho-32 or PE 32, for example. + Not to DWARF offset sizes. */ + +/* Path means look(first) for an dynsym object + of the same name per MacOS standards, + making the outpath space needed is more than + that in path. + Copies the actual path into outpath, (an error + if the length in outpath_len is less than needed + for the object found). + If DW_DLV_NO_ENTRY or DW_DLV_ERROR returned + the argument values other than path + must be considered to be in an unknown state. */ + +/* The errcode is a small integer distinct from libdwarf + and simply printing the integer (returned through + *errcode when the function returns DW_DLV_ERROR) + will hopefully suffice for most purposes. */ + +/* Added September 2023 for Mach-O universal binaries */ +int _dwarf_object_detector_fd_a(int dw_fd, + unsigned int *dw_ftype, + unsigned int *dw_endian, + unsigned int *dw_offsetsize, + Dwarf_Unsigned dw_offset_base, + Dwarf_Unsigned *dw_filesize, + int *dw_errcode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_OBJECT_DETECTOR_H */ diff --git a/src/lib/libdwarf/dwarf_object_read_common.c b/src/lib/libdwarf/dwarf_object_read_common.c new file mode 100644 index 0000000..afc9c92 --- /dev/null +++ b/src/lib/libdwarf/dwarf_object_read_common.c @@ -0,0 +1,96 @@ +/* +Copyright (c) 2018, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif /* _WIN32 */ + +#include + +#include /* size_t */ +#include /* SEEK_END SEEK_SET */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* off_t */ +#elif defined HAVE_UNISTD_H +#include /* off_t */ +#endif /* _WIN32*/ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_object_read_common.h" + +/* Neither off_t nor ssize_t is in C90. + However, both are in Posix: + IEEE Std 1003.1-1990, aka + ISO/IEC 9954-1:1990. */ +int +_dwarf_object_read_random(int fd, char *buf, off_t loc, + size_t size, off_t filesize, int *errc) +{ + off_t scode = 0; + ssize_t rcode = 0; + off_t endpoint = 0; + + if (loc >= filesize) { + /* Seek can seek off the end. Lets not allow that. + The object is corrupt. */ + *errc = DW_DLE_SEEK_OFF_END; + return DW_DLV_ERROR; + } + endpoint = loc+size; + if (endpoint > filesize) { + /* Let us -not- try to read past end of object. + The object is corrupt. */ + *errc = DW_DLE_READ_OFF_END; + return DW_DLV_ERROR; + } + scode = lseek(fd,loc,SEEK_SET); + if (scode == (off_t)-1) { + *errc = DW_DLE_SEEK_ERROR; + return DW_DLV_ERROR; + } + rcode = read(fd,buf,size); + if (rcode == -1 || + (size_t)rcode != size) { + *errc = DW_DLE_READ_ERROR; + return DW_DLV_ERROR; + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_object_read_common.h b/src/lib/libdwarf/dwarf_object_read_common.h new file mode 100644 index 0000000..07ddbd3 --- /dev/null +++ b/src/lib/libdwarf/dwarf_object_read_common.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 2018-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#ifndef DWARF_OBJECT_READ_COMMON_H +#define DWARF_OBJECT_READ_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int _dwarf_object_read_random(int fd,char *buf,off_t loc, + size_t size,off_t filesize,int *errc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_OBJECT_READ_COMMON_H */ diff --git a/src/lib/libdwarf/dwarf_opaque.h b/src/lib/libdwarf/dwarf_opaque.h new file mode 100644 index 0000000..9bd8c55 --- /dev/null +++ b/src/lib/libdwarf/dwarf_opaque.h @@ -0,0 +1,1108 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2023 David Anderson. All Rights Reserved. + Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ +/* Following the nomenclature of the DWARF standard + Section Version Numbers (DWARF 5): + * means not applicable. + - means not defined in that version. + The version numbers for .debug_info is the same as .debug_info.dwo + (etc for the other dwo sections). + The versions applicable by section are: + . DWARF2 DWARF3 DWARF4 DWARF5 + .debug_abbrev * * * * + .debug_addr - - - 5 + .debug_aranges 2 2 2 2 + .debug_frame 1 3 4 4 + .debug_info 2 3 4 5 + .debug_line 2 3 4 5 + .debug_line_str - - - 5 + .debug_loc * * * - + .debug_loclists - - - 5 + .debug_macinfo * * * - + .debug_macro - - - 5 + .debug_names - - - 5 + .debug_pubnames 2 2 2 - + .debug_pubtypes - 2 2 - + .debug_ranges - * * - + .debug_rnglists - - - 5 + .debug_str * * * * + .debug_str_offsets - - - 5 + .debug_sup - - - 5 + .debug_types - - 4 - + + .debug_abbrev.dwo - - - * + .debug_info.dwo - - - 5 + .debug_line.dwo - - - 5 + .debug_loc.dwo - - - - + .debug_loclists.dwo - - - 5 + .debug_macro.dwo - - - 5 + .debug_rnglists.dwo - - - 5 + .debug_str.dwo - - - * + .debug_str_offsets.dwo - - - 5 + + .debug_cu_index - - - 5 + .debug_tu_index - - - 5 + +*/ + +struct Dwarf_Rnglists_Context_s; +typedef struct Dwarf_Rnglists_Context_s *Dwarf_Rnglists_Context; +struct Dwarf_Loclists_Context_s; +typedef struct Dwarf_Loclists_Context_s *Dwarf_Loclists_Context; + +struct Dwarf_Die_s { + Dwarf_Byte_Ptr di_debug_ptr; + Dwarf_Abbrev_List di_abbrev_list; + Dwarf_CU_Context di_cu_context; + /* Abbrev codes are expected to be smallish numbers, + but the Standard does not require smallish numbers. */ + Dwarf_Unsigned di_abbrev_code; + /* TRUE if part of debug_info. FALSE if part of .debug_types. */ + Dwarf_Bool di_is_info; +}; + +struct Dwarf_Attribute_s { + Dwarf_Half ar_attribute; /* Attribute Value. */ + Dwarf_Half ar_attribute_form; /* Attribute Form. */ + Dwarf_Half ar_attribute_form_direct; + /* *form_direct Identical to ar_attribute_form + except that if + the original form uleb was DW_FORM_indirect, + ar_attribute_form_direct contains DW_FORM_indirect + but ar_attribute_form contains the true form. */ + + Dwarf_CU_Context ar_cu_context; + /* The following points to either debug_info or debug_types + depending on if context is cc_is_info or not. */ + Dwarf_Small *ar_debug_ptr; + /* If DW_FORM_implicit const, the value is here, not + in the DIE. */ + Dwarf_Signed ar_implicit_const; + Dwarf_Debug ar_dbg; /* dbg owning the attr */ + + Dwarf_Die ar_die;/* Access to the DIE owning the attribute */ + Dwarf_Attribute ar_next; +}; + +/* + This structure provides the context for a compilation unit. + Thus, it contains the Dwarf_Debug, cc_dbg, that this cu + belongs to. It contains the information + in the compilation unit header, cc_length, + cc_version_stamp, cc_abbrev_offset, + and cc_address_size, in the .debug_info section for that cu. + In addition, it contains the count, cc_count_cu, of the cu + number of that cu in the list of cu's in the .debug_info. + The count starts at 1, ie cc_count_cu is 1 for the first cu, + 2 for the second and so on. This struct also contains a + pointer, to a list of pairs of abbrev code + and a pointer to the start of that abbrev + in the .debug_abbrev section. + + Each die will also contain a pointer to such a struct to + record the context for that die. + + Notice that a pointer to the CU DIE itself is + Dwarf_Off off2 = cu_context->cc_debug_info_offset; + cu_die_info_ptr = dbg->de_debug_info.dss_data + + off2 + _dwarf_length_of_cu_header(dbg, off2); + Or similar for de_debug_types. + + **Updated by dwarf_next_cu_header in dwarf_die_deliv.c +*/ +struct Dwarf_CU_Context_s { + Dwarf_Debug cc_dbg; + /* The sum of cc_length, cc_length_size, and cc_extension_size + is the total length of the CU including its header. + cc_length is the length of the compilation unit excluding + cc_length_size and cc_extension_size. */ + Dwarf_Unsigned cc_length; + + /* cc_length_size is the size in bytes of an offset. + Should probably be renamed cc_offset_size. + 4 for 32bit dwarf, 8 for 64bit dwarf (whether MIPS/IRIX + 64bit dwarf or standard 64bit dwarf using the extension + mechanism). */ + Dwarf_Small cc_length_size; + + /* cc_extension_size is zero unless this is standard + DWARF3 and later 64bit dwarf using the extension mechanism. + 64bit DWARF3 and later: cc_extension_size is 4. + 64bit DWARF2 MIPS/IRIX: cc_extension_size is zero. + 32bit DWARF: cc_extension_size is zero. */ + Dwarf_Small cc_extension_size; + + /* cc_version_stamp is the DWARF version number applicable + to the DWARF in this compilation unit. 2,3,4,... */ + Dwarf_Half cc_version_stamp; + /* cc_abbrev_offset is the section-global offset + of the .debug_abbrev section this CU uses. + Data from CU header. Includes DWP adjustment made + as soon as we create a cu_context. */ + Dwarf_Unsigned cc_abbrev_offset; + + /* cc_address_size is the size of an address in this + compilation unit. */ + Dwarf_Small cc_address_size; + Dwarf_Small cc_segment_selector_size; + + /* cc_debug_offset is the global offset in the section + of the area length field of the CU. + The CU header of the CU is at offset + cc_debug_offset+cc_length_size+cc_extension_size; + This is a section global offset. + May be debug_info or debug_types. + Even in DWP this is set to true global offset + right away when cu_context created. + See cc_is_info flag. */ + Dwarf_Unsigned cc_debug_offset; + + /* === START DEBUG FISSION (Split Dwarf) data + cc_signature is in the TU header + of a type unit of a TU DIE (or for DW5 in the + skeleton or split_compile header is a dwo_id). + Ignore this field if cc_signature_present is zero. + (TU CUs signature is not the same namespace + as DW_AT_dwo_id signatures. The two must be + kept separate (for DWARF5)) + + If cc_unit_type == DW_UT_compile or DW_UT_partial + the signature is a CU signature (dwo_id). + Some early DW5 drafts encouraged DWARF4 output + of some compilers to include dwo_id, but + in a messier way(lacking DW_UT_*). + If cc_unit_type == DW_UT_split_type + the signature is a type signature. */ + Dwarf_Half cc_cu_die_tag; + + Dwarf_Sig8 cc_signature; + + /* cc_type_signature_offset contains the + section-local DIE offset of the type + the signature applies to if the cc_unit_type + is DW_UT_type or DW_UT_split_type. */ + Dwarf_Unsigned cc_signature_offset; + + /* For each CU and each TU + in a dwp package file there is + is a hash and + a set of offsets indexed by DW_SECT_* id. + Only one such set per CU or TU. + The data on all that is in cc_dwp_offsets + + If it is a TU the signature in cc_dwp_offsets + must match the signature in cc_signature. + */ + struct Dwarf_Debug_Fission_Per_CU_s cc_dwp_offsets; + + Dwarf_Bool cc_signature_present; /* Meaning type signature + in TU header or, for CU header, signature in CU DIE. */ + Dwarf_Bool cc_low_pc_present; + Dwarf_Bool cc_addr_base_present; /* Not TRUE in .dwo */ + + Dwarf_Bool cc_cu_die_has_children; + Dwarf_Bool cc_dwo_name_present; + Dwarf_Bool cc_at_strx_present; + + /* Non zero if this context is a dwo section. Either + dwo or dwp file. */ + Dwarf_Bool cc_is_dwo; + + /* cc_cu_die_offset_present is non-zero if + cc_cu_die_global_sec_offset is meaningful. */ + Dwarf_Bool cc_cu_die_offset_present; + + /* If present, is base address of CU. In DWARF2 + nothing says what attribute is the base address. + DW_AT_producer 4.2.1 (Based on Apple Inc. build 5658) + (LLVM build 2336.1.00) uses DW_AT_entry_pc as the + base address. DW_AT_entry_pc first appears + in DWARF3. + We allow DW_AT_entry_pc as an extension, + as a 'low_pc' if there is DW_AT_entry_pc with + no DW_AT_low_pc. 19 May 2022. + In DWARF3, DWARF4 DW_AT_low_pc is specifically + mentioned as the base address. */ + Dwarf_Unsigned cc_low_pc; + /* from DW_AT_addr_base in CU DIE, offset to .debug_addr table */ + Dwarf_Unsigned cc_addr_base; /* Zero in .dwo */ + + /* DW_SECT_LINE */ + Dwarf_Bool cc_line_base_present; /*DW5 */ + Dwarf_Unsigned cc_line_base; /*DW5 */ + Dwarf_Unsigned cc_line_base_contr_size; /*DW5 */ + + /* From DW_AT_loclists_base or DW_SECT_LOCLISTS */ + Dwarf_Unsigned cc_loclists_base; + Dwarf_Unsigned cc_loclists_base_contr_size; + Dwarf_Bool cc_loclists_base_present; + Dwarf_Bool cc_loclists_header_length_present; + + /* ======= str_offsets table data =======*/ + /* header_offset is global offset in str_offsets section + of an array of string offsets. Not a header offset + at all. + from DW_AT_str_offsets_base DW5 page 66 item 13. + Not related to the Name Table */ + /* Set from DW_AT_str_offsets_base. Global offset. */ + Dwarf_Bool cc_str_offsets_array_offset_present; + Dwarf_Unsigned cc_str_offsets_array_offset; + + /* Set from str_offsets header, means all the relevant + data from the header is present. Does not mean + the data from DW_AT_str_offsets_base is present */ + Dwarf_Bool cc_str_offsets_tab_present; + /* Set from str_offsets header. */ + Dwarf_Unsigned cc_str_offsets_header_offset; + + /* Set by reading str_offsets header. Local offset + from header to its array. */ + Dwarf_Unsigned cc_str_offsets_tab_to_array; + + /* The following three set but not used. Might + be useful for error checking. */ + Dwarf_Unsigned cc_str_offsets_offset_size; + /* The size of the table from table header + to end of this table. Not the size of array + in the table */ + Dwarf_Unsigned cc_str_offsets_table_size; + Dwarf_Half cc_str_offsets_version; + /* ======= end str_offsets table data =======*/ + + /* DW_SECT_MACRO */ + Dwarf_Unsigned cc_macro_base; /*DW5 */ + Dwarf_Unsigned cc_macro_base_contr_size; /*DW5 */ + Dwarf_Bool cc_macro_base_present; + Dwarf_Bool cc_macro_header_length_present; + + /* DW_SECT_RNGLISTS */ + Dwarf_Unsigned cc_rnglists_base; /*DW5 */ + Dwarf_Unsigned cc_rnglists_base_contr_size; /*DW5 */ + /* DW_AT_GNU_ranges_base was a GNU extension that appeared + but was unused. See dwarf_die_deliv.c for details. */ + Dwarf_Unsigned cc_ranges_base; + /* DW_AT_GNU_ranges_base is a GNU extension, DW4 */ + Dwarf_Bool cc_ranges_base_present; + /* .debug_rnglists */ + Dwarf_Bool cc_rnglists_base_present; /* DW5 */ + Dwarf_Bool cc_rnglists_header_length_present; + + char * cc_dwo_name; + /* === END DEBUG FISSION (Split Dwarf) data */ + + /* Global section offset to the bytes of the CU die for this CU. + Set when the CU die is accessed by dwarf_siblingof_b(). */ + Dwarf_Unsigned cc_cu_die_global_sec_offset; + + Dwarf_Byte_Ptr cc_last_abbrev_ptr; + Dwarf_Byte_Ptr cc_last_abbrev_endptr; + Dwarf_Hash_Table cc_abbrev_hash_table; + Dwarf_Unsigned cc_highest_known_code; + Dwarf_CU_Context cc_next; + + Dwarf_Bool cc_is_info; /* TRUE means context is + in debug_info, FALSE means is in debug_types. + FALSE only possible for DWARF4 .debug_types + section CUs. + For DWARF5 all DIEs are in .debug_info[.dwo] */ + + Dwarf_Half cc_unit_type; /* DWARF5 + Set from header as a DW_UT_ value. + For DWARF 2,3,4 this is filled in initially + from the CU header and refined by inspecting + the CU DIE to detect the correct setting. */ + +}; + +/* Consolidates section-specific data in one place. + Section is an Elf specific term, intended as a general + term (for non-Elf objects some code must synthesize the + values somehow). */ +struct Dwarf_Section_s { + Dwarf_Small * dss_data; + Dwarf_Unsigned dss_size; + /* Some Elf sections have a non-zero dss_entrysize which + is the size in bytes of a table entry in the section. + Relocations and symbols are both in tables, so have a + non-zero entrysize. Object formats which do not care + about this should leave this field zero. */ + Dwarf_Unsigned dss_entrysize; + /* dss_index is the section index as things are numbered in + an object file being read. An Elf section number. */ + Dwarf_Unsigned dss_index; + /* dss_addr is the 'section address' which is only + non-zero for a GNU eh section. + Purpose: to handle DW_EH_PE_pcrel encoding. Leaving + it zero is fine for non-elf. */ + Dwarf_Addr dss_addr; + Dwarf_Small dss_data_was_malloc; + /* is_in_use set during initial object reading to + detect duplicates. Ignored after setup done. */ + Dwarf_Small dss_is_in_use; + + /* When loading COMDAT they refer (sometimes) to + base sections, so we need to have the BASE + group sections filled in when the corresponding is + not in the COMDAT group list. .debug_abbrev is + an example. */ + Dwarf_Unsigned dss_group_number; + + /* These for reporting compression */ + Dwarf_Unsigned dss_uncompressed_length; + Dwarf_Unsigned dss_compressed_length; + + /* If this is zdebug, to start data/size are the + raw section bytes. + Initially for all sections dss_data_was_malloc set FALSE + and dss_requires_decompress set FALSE. + For zdebug set dss_zdebug_requires_decompress set TRUE + In that case it is likely ZLIB compressed but + we do not know that just scanning section headers. + If not .zdebug but it is SHF_COMPRESSED + then decompress is required. + + On translation (ie zlib use and malloc) + Set dss_data dss_size to point to malloc space and + malloc size. + Set dss_did_decompress FALSE + Set dss_was_malloc TRUE */ + Dwarf_Small dss_zdebug_requires_decompress; + Dwarf_Small dss_did_decompress; + Dwarf_Small dss_shf_compressed; /* section flag SHF_COMPRESS */ + + /* Section compression starts with ZLIB chars*/ + Dwarf_Small dss_ZLIB_compressed; + + /* For non-elf, leaving the following fields zero + will mean they are ignored. */ + /* dss_link should be zero unless a section has a link + to another (sh_link). Used to access relocation data for + a section (and for symtab section, access its strtab). */ + Dwarf_Unsigned dss_link; + /* The following is used when reading .rela sections + (such sections appear in some .o files). */ + Dwarf_Unsigned dss_reloc_index; /* Zero means ignore + the reloc fields. */ + Dwarf_Small * dss_reloc_data; + Dwarf_Unsigned dss_reloc_size; + Dwarf_Unsigned dss_reloc_entrysize; + Dwarf_Addr dss_reloc_addr; + /* dss_reloc_symtab is the sh_link of a .rela + to its .symtab, leave + it 0 if non-meaningful. */ + Dwarf_Addr dss_reloc_symtab; + /* dss_reloc_link should be zero unless a reloc section + has a link to another (sh_link). + Used to access the symtab for relocating a section. */ + Dwarf_Unsigned dss_reloc_link; + /* Pointer to the elf symtab, used for elf .rela. Leave it 0 + if not relevant. */ + struct Dwarf_Section_s *dss_symtab; + /* dss_name, dss_standard_name must never be freed, + they are static strings in libdwarf. */ + const char * dss_name; + const char * dss_standard_name; + + /* Object section number in object file. */ + unsigned dss_number; + + /* These are elf flags and non-elf object should + just leave these fields zero. */ + Dwarf_Unsigned dss_flags; + Dwarf_Unsigned dss_addralign; + + /* Set when loading .group section as those are special and + neither compressed nor have relocations so never malloc + space for libdwarf. */ + Dwarf_Small dss_ignore_reloc_group_sec; + char dss_is_rela; +}; + +/* Overview: if next_to_use== first, no error slots are used. + If next_to_use+1 (mod maxcount) == first the slots are all used +*/ +struct Dwarf_Harmless_s { + unsigned dh_maxcount; + unsigned dh_next_to_use; + unsigned dh_first; + unsigned dh_errs_count; + char ** dh_errors; +}; + +/* Data needed separately for debug_info and debug_types + as we may be reading both interspersed. So we always + select the one we need. */ +struct Dwarf_Debug_InfoTypes_s { + /* Context for the compilation_unit just read by a call to + dwarf_next_cu_header. **Updated by dwarf_next_cu_header in + dwarf_die_deliv.c */ + Dwarf_CU_Context de_cu_context; + /* Points to linked list of CU Contexts for the + CU's already read. These are only CU's read + by dwarf_next_cu_header(). */ + Dwarf_CU_Context de_cu_context_list; + /* Points to the last CU Context added to the list by + dwarf_next_cu_header(). */ + Dwarf_CU_Context de_cu_context_list_end; + + /* Offset of last byte of last CU read. + Actually one-past that last byte. So + use care and compare as offset >= de_last_offset + to know if offset is too big. */ + Dwarf_Unsigned de_last_offset; + /* de_last_di_info_ptr and de_last_die are used with + dwarf_siblingof, dwarf_child, and dwarf_validate_die_sibling. + dwarf_validate_die_sibling will not give meaningful results + if called inappropriately. */ + Dwarf_Byte_Ptr de_last_di_ptr; + Dwarf_Die de_last_die; +}; +typedef struct Dwarf_Debug_InfoTypes_s *Dwarf_Debug_InfoTypes; + +/* As the tasks performed on a debug related section is the same, + in order to make the process of adding a new section + (very unlikely) a little bit easy and to reduce the + possibility of errors, a simple table + build dynamically, will contain the relevant information. +*/ + +struct Dwarf_dbg_sect_s { + /* Debug section name must not be freed, is quoted string. + This is the name from the object file itself. */ + const char *ds_name; + /* The section number in object section numbering. */ + unsigned ds_number; + /* Debug section information, points to de_debug_*member + (or the like) of the dbg struct. */ + struct Dwarf_Section_s *ds_secdata; + + unsigned ds_groupnumber; + int ds_duperr; /* Error code for duplicated section */ + int ds_emptyerr; /* Error code for empty section */ + int ds_have_dwarf; /* Section contains DWARF */ + int ds_have_zdebug; /* Section compressed: .zdebug name */ +}; + +/* As the number of debug sections does not change very often, + in the case a + new section is added in 'enter_section_in_array()' + the 'MAX_DEBUG_SECTIONS' must + be updated accordingly. + This does not yet allow for section-groups in object files, + for which many .debug_info (and other) sections may exist. +*/ +#define DWARF_MAX_DEBUG_SECTIONS 50 +#define DWARFSTRING_ALLOC_SIZE 200 + +/* A 'magic number' to validate a Dwarf_Debug pointer is live.*/ +#define DBG_IS_VALID 0xebfdebfd + +/* All the Dwarf_Debug tied-file info in one place. */ +struct Dwarf_Tied_Data_s { + /* Used to access executable from .dwo or .dwp object. + Pointer to the tied_to Dwarf_Debug*/ + Dwarf_Debug td_tied_object; + + /* TRUE if this tied object is tied to. + It's extra work to look for a DW_AT_dwo_id. + Set when tied dbg (on the base) was created. + This helps us do it only when it may be productive. */ + Dwarf_Bool td_is_tied_object; + + /* Used for Type Unit signatures. + Type Units are in .debug_types in DW4 + but in .debug_info in DW5. + Some .debug_info point to them symbolically + via DW_AT_signature attributes. + If non-zero is a dwarf_tsearch 'tree'. + Only non-zero if td_is_tied_object is set and + we had a reason to build the search tree.. + Type Units have a Dwarf_Sig8 signature + in the header, and such is recorded here. + + Type Unit signatures can conflict with + signatures in split-dwarf (dwo/dwp) sections. + + The Key for each record is a Dwarf_Sig8 (8 bytes). + The data for each is a pointer to a Dwarf_CU_context + record in this dbg (cu_context in + one of tied dbg's de_cu_context_list). */ + void *td_tied_search; + +}; + +/* dg_groupnum 0 does not exist. + dg_groupnum 1 is base + dg_groupnum 2 is dwo + dg_groupnum 3 and higher are COMDAT groups (if any). +*/ +struct Dwarf_Group_Data_s { + /* For traditional DWARF the value is one, just one group. */ + unsigned gd_number_of_groups; + + /* Raw elf (elf-like) section count. */ + unsigned gd_number_of_sections; + + unsigned gd_map_entry_count; + + /* A map from section number to group number. */ + void *gd_map; +}; + +struct Dwarf_Debug_s { + Dwarf_Unsigned de_magic; + /* All file access methods and support data + are hidden in this structure. + We get a pointer, callers control the lifetime of the + structure and contents. */ + struct Dwarf_Obj_Access_Interface_a_s *de_obj_file; + + Dwarf_Handler de_errhand; + Dwarf_Ptr de_errarg; + + /* Enabling us to close an fd if we own it, + as in the case of dwarf_init_path(). + de_fd is only meaningful + if de_owns_fd is set. Each object + file type has any necessary fd recorded + under de_obj_file. */ + int de_fd; + char de_owns_fd; + char de_in_tdestroy; /* for de_alloc_tree DW202309-001 */ + /* DW_PATHSOURCE_BASIC or MACOS or DEBUGLINK */ + unsigned char de_path_source; + /* de_path is only set automatically if dwarf_init_path() + was used to initialize things. + Used with the .gnu_debuglink section. */ + const char *de_path; + + const char ** de_gnu_global_paths; + unsigned de_gnu_global_path_count; + + struct Dwarf_Debug_InfoTypes_s de_info_reading; + struct Dwarf_Debug_InfoTypes_s de_types_reading; + + /* DW_GROUPNUMBER_ANY, DW_GROUPNUMBER_BASE, DW_GROUPNUMBER_DWO, + or a comdat group number > 2 + Selected at init time of this dbg based on + user request and on data in the object. */ + unsigned de_groupnumber; + + /* Supporting data for groupnumbers. */ + struct Dwarf_Group_Data_s de_groupnumbers; + + /* Number of bytes in the length, and offset field in various + .debu* sections. It's not very meaningful, and is + only used in one 'approximate' calculation. + de_offset_size would be a more apropos name. */ + Dwarf_Small de_length_size; + + /* Size of the object file in bytes. If Unknown + leave this zero. */ + Dwarf_Unsigned de_filesize; + + /* number of bytes in a pointer of the target in various .debug_ + sections. 4 in 32bit, 8 in MIPS 64, ia64. */ + Dwarf_Small de_pointer_size; + + /* set at creation of a Dwarf_Debug to say if form_string + should be checked for valid length at every call. + 0 means do the check. + non-zero means do not do the check. */ + Dwarf_Small de_assume_string_in_bounds; + + /* Keep track of allocations so a dwarf_finish call can clean up. + Null till a tree is created */ + void * de_alloc_tree; + + /* These fields are used to process debug_frame section. + Updated + by dwarf_get_fde_list in dwarf_frame.h */ + /* Points to contiguous block of pointers to + Dwarf_Cie_s structs. */ + Dwarf_Cie *de_cie_data; + /* Count of number of Dwarf_Cie_s structs. */ + Dwarf_Signed de_cie_count; + /* Keep eh (GNU) separate!. */ + Dwarf_Cie *de_cie_data_eh; + Dwarf_Signed de_cie_count_eh; + /* Points to contiguous block of pointers to + Dwarf_Fde_s structs. */ + Dwarf_Fde *de_fde_data; + /* Count of number of Dwarf_Fde_s structs. */ + Dwarf_Unsigned de_fde_count; + /* Keep eh (GNU) separate!. */ + Dwarf_Fde *de_fde_data_eh; + Dwarf_Unsigned de_fde_count_eh; + + struct Dwarf_Section_s de_debug_info; + struct Dwarf_Section_s de_debug_types; + struct Dwarf_Section_s de_debug_abbrev; + struct Dwarf_Section_s de_debug_line; + struct Dwarf_Section_s de_debug_line_str; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_loc; + struct Dwarf_Section_s de_debug_aranges; + struct Dwarf_Section_s de_debug_macinfo; + struct Dwarf_Section_s de_debug_macro; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_names; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_pubnames; + struct Dwarf_Section_s de_debug_str; + struct Dwarf_Section_s de_debug_sup; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_loclists; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_rnglists; /* New in DWARF5 */ + struct Dwarf_Section_s de_debug_frame; + struct Dwarf_Section_s de_gnu_debuglink; /* New Sept. 2019 */ + struct Dwarf_Section_s de_note_gnu_buildid; /* New Sept. 2019 */ + + /* gnu: the g++ eh_frame section */ + struct Dwarf_Section_s de_debug_frame_eh_gnu; + + /* DWARF3 .debug_pubtypes */ + struct Dwarf_Section_s de_debug_pubtypes; + + /* Four SGI IRIX extensions essentially + identical to DWARF3 .debug_pubtypes. + Only on SGI IRIX. */ + struct Dwarf_Section_s de_debug_funcnames; + struct Dwarf_Section_s de_debug_typenames; + struct Dwarf_Section_s de_debug_varnames; + struct Dwarf_Section_s de_debug_weaknames; + + struct Dwarf_Section_s de_debug_ranges; + /* Following two part of DebugFission and DWARF5 */ + struct Dwarf_Section_s de_debug_str_offsets; + struct Dwarf_Section_s de_debug_addr; + + /* For the .debug_rnglists[.dwo] section */ + Dwarf_Unsigned de_rnglists_context_count; + /* pointer to array of pointers to + rnglists context instances */ + Dwarf_Rnglists_Context * de_rnglists_context; + + /* For the .debug_loclists[.dwo] section */ + Dwarf_Unsigned de_loclists_context_count; + /* pointer to array of pointers to + loclists context instances */ + Dwarf_Loclists_Context * de_loclists_context; + + /* Following for the .gdb_index section. */ + struct Dwarf_Section_s de_debug_gdbindex; + + /* Types in DWARF5 are in .debug_info + and in DWARF4 are in .debug_types. + These indexes first standardized in DWARF5, + DWARF4 can have them as an extension. + The next to refer to the DWP index sections and the + tu and cu indexes sections are distinct in DWARF4 & 5. */ + struct Dwarf_Section_s de_debug_cu_index; + struct Dwarf_Section_s de_debug_tu_index; + struct Dwarf_Section_s de_debug_gnu_pubnames; + struct Dwarf_Section_s de_debug_gnu_pubtypes; + + /* For non-elf, simply leave the following two structs + zeroed and they will be ignored. */ + struct Dwarf_Section_s de_elf_symtab; + struct Dwarf_Section_s de_elf_strtab; + + /* For a .dwp object file . + For DWARF4, type units are in .debug_types + (DWP is a GNU extension in DW4).. + For DWARF5, type units are in .debug_info. + */ + Dwarf_Xu_Index_Header de_cu_hashindex_data; + Dwarf_Xu_Index_Header de_tu_hashindex_data; + + void (*de_copy_word) (void *, const void *, unsigned long); + unsigned char de_same_endian; + unsigned char de_elf_must_close; /* If non-zero, then + it was dwarf_init (not dwarf_elf_init) + so must elf_end() */ + + /* Default is DW_FRAME_INITIAL_VALUE from header. */ + Dwarf_Unsigned de_frame_rule_initial_value; + + /* Default is DW_FRAME_LAST_REG_NUM. */ + Dwarf_Unsigned de_frame_reg_rules_entry_count; + + Dwarf_Unsigned de_frame_cfa_col_number; + Dwarf_Unsigned de_frame_same_value_number; + Dwarf_Unsigned de_frame_undefined_value_number; + + /* If count > 0 means the DW_FTYPE_APPLEUNIVERSAL + we initially read has this number of + binaries in it, and de_universalbinary_index + is the index of the current object inside + the universal binary. */ + unsigned int de_universalbinary_count; + unsigned int de_universalbinary_index; + + unsigned char de_big_endian_object; /* Non-zero if + object being read is big-endian. */ + + /* Non-zero if dwarf_get_globals(), dwarf_get_funcs, + dwarf_get_types,dwarf_get_pubtypes, + dwarf_get_vars,dwarf_get_weaks should create + and return a special zero-die-offset for the + corresponding pubnames-style section CU header with + zero pubnames-style named DIEs. In that case the + list returned will have an entry with a zero for + the die-offset (which is an impossible debug_info + die_offset). New March 2019. + See dwarf_return_empty_pubnames() */ + unsigned char de_return_empty_pubnames; + + struct Dwarf_dbg_sect_s de_debug_sections[ + DWARF_MAX_DEBUG_SECTIONS]; + + /* Number actually used. */ + unsigned de_debug_sections_total_entries; + + struct Dwarf_Harmless_s de_harmless_errors; + + struct Dwarf_Printf_Callback_Info_s de_printf_callback; + void * de_printf_callback_null_device_handle; + + /* Used in a tied dbg to hold global info + on the tied object (DW_AT_dwo_id). + And for Type Unit signatures whether tied + or not. It is not defined whether + the main object is executable and + the tied file is a dwo/dwp or the + reverse. The focus of reporting + is on the main file, but the tied + file is sometimes needed + and referenced.*/ + struct Dwarf_Tied_Data_s de_tied_data; +}; + +/* New style. takes advantage of dwarfstrings capability. + This not a public function. */ +int _dwarf_printf(Dwarf_Debug dbg, const char * data); + +typedef struct Dwarf_Chain_s *Dwarf_Chain; +struct Dwarf_Chain_s { + void *ch_item; + int ch_itemtype; /* Needed to dealloc chain contents */ + Dwarf_Chain ch_next; +}; + +typedef struct Dwarf_Chain_o *Dwarf_Chain_2; +struct Dwarf_Chain_o { + Dwarf_Off ch_item; + Dwarf_Chain_2 ch_next; +}; + + /* Size of cu header version stamp field. */ +#define CU_VERSION_STAMP_SIZE DWARF_HALF_SIZE + + /* Size of cu header address size field. */ +#define CU_ADDRESS_SIZE_SIZE sizeof(Dwarf_Small) + +#define ORIGINAL_DWARF_OFFSET_SIZE 4 +/* The DISTINGUISHED VALUE is 4 byte value defined by DWARF + since DWARF3. */ +#define DISTINGUISHED_VALUE 0xffffffff +#define DISTINGUISHED_VALUE_OFFSET_SIZE 8 +#define DISTINGUISHED_VALUE_ARRAY(x) char (x)[4] = \ + { 0xff,0xff,0xff,0xff } + +/* We don't load the sections until they are needed. + This function is used to load the section. */ +int _dwarf_load_section(Dwarf_Debug, + struct Dwarf_Section_s *, + Dwarf_Error *); + +void _dwarf_dealloc_rnglists_context(Dwarf_Debug dbg); +void _dwarf_dealloc_loclists_context(Dwarf_Debug dbg); + +int _dwarf_get_string_base_attr_value(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned *sbase_out, + Dwarf_Error *error); + +int _dwarf_look_in_local_and_tied_by_index( + Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned index, + Dwarf_Addr *return_addr, + Dwarf_Error *error); + +Dwarf_Bool _dwarf_file_has_debug_fission_cu_index(Dwarf_Debug dbg); +Dwarf_Bool _dwarf_file_has_debug_fission_tu_index(Dwarf_Debug dbg); +Dwarf_Bool _dwarf_file_has_debug_fission_index(Dwarf_Debug dbg); + +/* This should only be called on a CU. Never a TU. */ +int _dwarf_get_debugfission_for_offset(Dwarf_Debug dbg, + Dwarf_Off offset_wanted, + const char *keytype, /* "cu" or "tu" */ + Dwarf_Debug_Fission_Per_CU * percu_out, + Dwarf_Error *error); + +/* whichone: must be a valid DW_SECT* macro value. */ +Dwarf_Unsigned _dwarf_get_dwp_extra_offset( + struct Dwarf_Debug_Fission_Per_CU_s* dwp, + unsigned whichone, Dwarf_Unsigned * size); + +/* This will look into the tied Dwarf_Debug + to which should have a skeleton CU DIE + and an addr_base and also have the .debug_addr + section. */ + +int _dwarf_get_addr_from_tied(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned addrindex, + Dwarf_Addr *addr_out, + Dwarf_Error *error); + +int _dwarf_get_fission_addition_die(Dwarf_Die die, int dw_sect_index, + Dwarf_Unsigned* offset, Dwarf_Unsigned*size, + Dwarf_Error *error); +int _dwarf_get_addr_index_itself(int theform, + Dwarf_Small *info_ptr, + Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Unsigned *val_out, + Dwarf_Error * error); +Dwarf_Bool _dwarf_addr_form_is_indexed(int form); + +int _dwarf_load_die_containing_section(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Error *error); + +int _dwarf_create_a_new_cu_context_record_on_list( + Dwarf_Debug dbg, + Dwarf_Debug_InfoTypes dis, + Dwarf_Bool is_info, + Dwarf_Unsigned section_size, + Dwarf_Unsigned new_cu_offset, + Dwarf_CU_Context *context_out, + Dwarf_Error *error); +Dwarf_Unsigned _dwarf_calculate_next_cu_context_offset( + Dwarf_CU_Context cu_context); + +int _dwarf_search_for_signature(Dwarf_Debug dbg, + Dwarf_Sig8 sig, + Dwarf_CU_Context *context_out, + Dwarf_Error *error); + +int _dwarf_merge_all_base_attrs_of_cu_die(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Debug tieddbg, + Dwarf_CU_Context *tiedcontext_out, + Dwarf_Error *error); + +void _dwarf_tied_destroy_free_node(void *node); +void _dwarf_destroy_group_map(Dwarf_Debug dbg); + +int _dwarf_section_get_target_group(Dwarf_Debug dbg, + unsigned obj_section_index, + unsigned * groupnumber, + Dwarf_Error * error); + +int _dwarf_dwo_groupnumber_given_name( + const char *name, + unsigned *grpnum_out); + +int _dwarf_section_get_target_group_from_map(Dwarf_Debug dbg, + unsigned obj_section_index, + unsigned * groupnumber_out, + Dwarf_Error * error); + +int _dwarf_insert_in_group_map(Dwarf_Debug dbg, + unsigned groupnum, + unsigned section_index, + const char *name, + Dwarf_Error * error); + +/* returns TRUE/FALSE: meaning this section name is in + map for this groupnum or not.*/ +int _dwarf_section_in_group_by_name(Dwarf_Debug dbg, + const char * scn_name, + unsigned groupnum); + +int +_dwarf_next_cu_header_internal(Dwarf_Debug dbg, + Dwarf_Bool is_info, + Dwarf_Unsigned * cu_header_length, + Dwarf_Half * version_stamp, + Dwarf_Unsigned * abbrev_offset, + Dwarf_Half * address_size, + Dwarf_Half * offset_size, + Dwarf_Half * extension_size, + Dwarf_Sig8 * signature, + Dwarf_Bool * has_signature, + Dwarf_Unsigned *typeoffset, + Dwarf_Unsigned * next_cu_offset, + Dwarf_Half * header_cu_type, + Dwarf_Error * error); + +/* Relates to .debug_addr */ +int _dwarf_look_in_local_and_tied(Dwarf_Half attr_form, + Dwarf_CU_Context context, + Dwarf_Small *info_ptr, + Dwarf_Addr *return_addr, + Dwarf_Error *error); + +int _dwarf_get_ranges_base_attr_from_tied(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned * ranges_base_out, + Dwarf_Unsigned * addr_base_out, + Dwarf_Error * error); + +int _dwarf_get_string_from_tied(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + char **return_str, Dwarf_Error*error); + +int _dwarf_valid_form_we_know(Dwarf_Unsigned at_form, + Dwarf_Unsigned at_name); +int _dwarf_extract_local_debug_str_string_given_offset( + Dwarf_Debug dbg, + unsigned attrform, + Dwarf_Unsigned offset, + char ** return_str, + Dwarf_Error * error); + +int _dwarf_file_name_is_full_path(Dwarf_Small *fname); + +/* This is libelf access to Elf object. */ +extern int _dwarf_elf_setup(int fd, + char *true_path_out_buffer, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error); + +/* This is non-libelf Elf access */ +extern int +_dwarf_elf_nlsetup(int fd, + char *true_path, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error); +void _dwarf_destruct_elf_nlaccess( + struct Dwarf_Obj_Access_Interface_a_s *aip); + +extern int _dwarf_macho_setup(int fd, + char *true_path, + unsigned universalnumber, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + Dwarf_Unsigned filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error); +void _dwarf_destruct_macho_access( + struct Dwarf_Obj_Access_Interface_a_s *aip); + +extern int _dwarf_pe_setup(int fd, + char *path, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error); +void _dwarf_destruct_pe_access( + struct Dwarf_Obj_Access_Interface_a_s *aip); + +void _dwarf_create_address_size_dwarf_error(Dwarf_Debug dbg, + Dwarf_Error *error, + Dwarf_Unsigned addrsize, + int errcode,const char *errname); + +extern Dwarf_Bool _dwarf_allow_formudata(unsigned form); +extern int _dwarf_formudata_internal(Dwarf_Debug dbg, + Dwarf_Attribute attr, + unsigned form, + Dwarf_Byte_Ptr data, + Dwarf_Byte_Ptr section_end, + Dwarf_Unsigned *return_uval, + Dwarf_Unsigned *bytes_read, + Dwarf_Error *error); + +Dwarf_Byte_Ptr _dwarf_calculate_info_section_start_ptr( + Dwarf_CU_Context context, + Dwarf_Unsigned *section_len_out); + +Dwarf_Byte_Ptr _dwarf_calculate_info_section_end_ptr( + Dwarf_CU_Context context); +Dwarf_Byte_Ptr _dwarf_calculate_abbrev_section_end_ptr( + Dwarf_CU_Context context); + +int _dwarf_formblock_internal(Dwarf_Debug dbg, + Dwarf_Attribute attr, + Dwarf_CU_Context cu_context, + Dwarf_Block * return_block, + Dwarf_Error * error); + +int _dwarf_extract_data16(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Small *section_start, + Dwarf_Small *section_end, + Dwarf_Form_Data16 * returned_val, + Dwarf_Error *error); + +int _dwarf_fill_in_attr_form_abtable(Dwarf_CU_Context context, + Dwarf_Byte_Ptr abbrev_ptr, + Dwarf_Byte_Ptr abbrev_end, + Dwarf_Abbrev_List abbrev_list, + Dwarf_Error *error); + +int _dwarf_internal_find_die_given_sig8(Dwarf_Debug dbg, + int context_level, + Dwarf_Sig8 *ref, + Dwarf_Die *die_out, + Dwarf_Bool *is_info, + Dwarf_Error *error); +int +_dwarf_internal_global_formref_b(Dwarf_Attribute attr, + int context_level, + Dwarf_Off * ret_offset, + Dwarf_Bool * offset_is_info, + Dwarf_Error * error); + +int _dwarf_skip_leb128(char * /*leb*/, + Dwarf_Unsigned * /*leblen*/, + char * /*endptr*/); + +int _dwarf_get_suppress_debuglink_crc(void); +void _dwarf_dumpsig(const char *msg, Dwarf_Sig8 *sig, int lineno); diff --git a/src/lib/libdwarf/dwarf_pe_descr.h b/src/lib/libdwarf/dwarf_pe_descr.h new file mode 100644 index 0000000..7252b0b --- /dev/null +++ b/src/lib/libdwarf/dwarf_pe_descr.h @@ -0,0 +1,257 @@ +#ifndef DWARF_PE_DESCR_H +#define DWARF_PE_DESCR_H +/* +Copyright (c) 2018-2023, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define IMAGE_DOS_SIGNATURE_dw 0x5a4d /* le on disk 'M' 'Z' */ +#define IMAGE_DOS_REVSIGNATURE_dw 0x4d5a /* be on disk */ +#define IMAGE_NT_SIGNATURE_dw 0x00004550 + +#ifndef TYP +#define TYP(n,l) char (n)[(l)] +#endif /* TYPE */ + +/* Data types + see https://msdn.microsoft.com/en-us/library/\ + windows/desktop/aa383751(v=vs.85).aspx */ + +/*#define FIELD_OFFSET(type,field) \ + ((LONG)(LONG_PTR)&(((type *)0)->field))*/ + +#define IMAGE_SIZEOF_SYMBOL 18 + +struct dos_header_dw { + TYP(dh_mz,2); + TYP(dh_dos_data,58); + TYP(dh_image_offset,4); +}; + +/* IMAGE_FILE_HEADER_dw + see https://msdn.microsoft.com/fr-fr/library/\ + windows/desktop/ms680313(v=vs.85).aspx */ + +typedef struct +{ + TYP(Machine,2); + TYP(NumberOfSections,2); + TYP(TimeDateStamp,4); + TYP(PointerToSymbolTable,4); + TYP(NumberOfSymbols,4); + TYP(SizeOfOptionalHeader,2); + TYP(Characteristics,2); +} IMAGE_FILE_HEADER_dw; + +/* IMAGE_DATA_DIRECTORY_dw + see https://msdn.microsoft.com/fr-fr/library/\ + windows/desktop/ms680305(v=vs.85).aspx */ + +typedef struct +{ + TYP(VirtualAddress,4); + TYP(Size,4); +} IMAGE_DATA_DIRECTORY_dw; + +/* IMAGE_OPTIONAL_HEADER + see https://msdn.microsoft.com/en-us/library/\ + windows/desktop/ms680339(v=vs.85).aspx */ + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct +{ + TYP(Magic,2); + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + TYP(SizeOfCode,4); + TYP(SizeOfInitializedData,4); + TYP(SizeOfUninitializedData,4); + TYP(AddressOfEntryPoint,4); + TYP(BaseOfCode,4); + TYP(BaseOfData,4); + TYP(ImageBase,4); + TYP(SectionAlignment,4); + TYP(FileAlignment,4); + TYP(MajorOperatingSystemVersion,2); + TYP(MinorOperatingSystemVersion,2); + TYP(MajorImageVersion,2); + TYP(MinorImageVersion,2); + TYP(MajorSubsystemVersion,2); + TYP(MinorSubsystemVersion,2); + TYP(Win32VersionValue,4); + TYP(SizeOfImage,4); + TYP(SizeOfHeaders,4); + TYP(CheckSum,4); + TYP(Subsystem,2); + TYP(DllCharacteristics,2); + TYP(SizeOfStackReserve,4); + TYP(SizeOfStackCommit,4); + TYP(SizeOfHeapReserve,4); + TYP(SizeOfHeapCommit,4); + TYP(LoaderFlags,4); + TYP(NumberOfRvaAndSizes,4); + IMAGE_DATA_DIRECTORY_dw + DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32_dw; + +typedef struct +{ + TYP(Magic,2); + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + TYP(SizeOfCode,4); + TYP(SizeOfInitializedData,4); + TYP(SizeOfUninitializedData,4); + TYP(AddressOfEntryPoint,4); + TYP(BaseOfCode,4); + TYP(ImageBase,8); + TYP(SectionAlignment,4); + TYP(FileAlignment,4); + TYP(MajorOperatingSystemVersion,2); + TYP(MinorOperatingSystemVersion,2); + TYP(MajorImageVersion,2); + TYP(MinorImageVersion,2); + TYP(MajorSubsystemVersion,2); + TYP(MinorSubsystemVersion,2); + TYP(Win32VersionValue,4); + TYP(SizeOfImage,4); + TYP(SizeOfHeaders,4); + TYP(CheckSum,4); + TYP(Subsystem,2); + TYP(DllCharacteristics,2); + TYP(SizeOfStackReserve,8); + TYP(SizeOfStackCommit,8); + TYP(SizeOfHeapReserve,8); + TYP(SizeOfHeapCommit,8); + TYP(LoaderFlags,4); + TYP(NumberOfRvaAndSizes,4); + IMAGE_DATA_DIRECTORY_dw + DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64_dw; + +/* IMAGE_NT_HEADERS + see https://msdn.microsoft.com/fr-fr/library/\ + windows/desktop/ms680336(v=vs.85).aspx */ + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct +{ + TYP(Signature,4); + IMAGE_FILE_HEADER_dw FileHeader; + IMAGE_OPTIONAL_HEADER64_dw OptionalHeader; +} IMAGE_NT_HEADERS64_dw, *PIMAGE_NT_HEADERS64_dw; + +typedef struct +{ + TYP(Signature,4); + IMAGE_FILE_HEADER_dw FileHeader; + IMAGE_OPTIONAL_HEADER32_dw OptionalHeader; +} IMAGE_NT_HEADERS32_dw, *PIMAGE_NT_HEADERS32_dw; + +/* IMAGE_SECTION_HEADER_dw + see: + https://msdn.microsoft.com/en-us/library/windows/\ + desktop/ms680341(v=vs.85).aspx + and, for details on VirtualSize and SizeOfRawData: + https://docs.microsoft.com/en-us/windows/desktop/\ + api/winnt/ns-winnt-_image_section_header */ + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct +{ + char Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + TYP(PhysicalAddress,4); + TYP(VirtualSize,4); + } Misc; + TYP(VirtualAddress,4); + TYP(SizeOfRawData,4); + TYP(PointerToRawData,4); + TYP(PointerToRelocations,4); + TYP(PointerToLinenumbers,4); + TYP(NumberOfRelocations,2); + TYP(NumberOfLinenumbers,2); + TYP(Characteristics,4); +} IMAGE_SECTION_HEADER_dw, *PIMAGE_SECTION_HEADER_dw; + +#define IMAGE_SCN_SCALE_INDEX 0x00000001 +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 + +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_PE_DESCR_H */ diff --git a/src/lib/libdwarf/dwarf_peread.c b/src/lib/libdwarf/dwarf_peread.c new file mode 100644 index 0000000..6b6adec --- /dev/null +++ b/src/lib/libdwarf/dwarf_peread.c @@ -0,0 +1,1005 @@ +/* +Copyright (c) 2020-2021, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* This file reads the parts of a Windows PE + file appropriate to reading DWARF debugging data. +*/ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif /* _WIN32 */ + +#include + +#include /* size_t */ +#include /* atoi() calloc() free() malloc() */ +#include /* memset() strdup() strlen() */ + +#ifdef _WIN32 +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* close() off_t */ +#elif defined HAVE_UNISTD_H +#include /* close() off_t */ +#endif /* _WIN32*/ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_safe_strcpy.h" +#include "dwarf_opaque.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_error.h" /* for _dwarf_error() declaration */ +#include "dwarf_reading.h" +#include "dwarf_object_read_common.h" +#include "dwarf_object_detector.h" +#include "dwarf_pe_descr.h" +#include "dwarf_peread.h" + +#define DOS_HEADER_LEN 64 + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s len %ld ",msg,len); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ + +static int _dwarf_pe_object_access_init( + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum); + +static unsigned long +magic_copy(char *d, unsigned len) +{ + unsigned i = 0; + unsigned long v = 0; + + v = d[0]; + for (i = 1 ; i < len; ++i) { + v <<= 8; + v |= 0xff&d[i]; + } + return v; +} +static int +check_valid_string(char *tab, + Dwarf_Unsigned size, + Dwarf_Unsigned startindex) +{ + Dwarf_Unsigned i = startindex; + for ( ; i < size; ++i) { + if (!tab[i]) { + return DW_DLV_OK; + } + } + return DW_DLV_ERROR; +} + +#if 0 +#ifdef WORDS_BIGENDIAN +#define ASNAR(func,t,s) \ + do { \ + unsigned tbyte = sizeof(t) - sizeof(s); \ + (t) = 0; \ + (func)(((char *)&(t))+tbyte ,&(s)[0],sizeof(s)); \ + } while (0) +#else /* LITTLE ENDIAN */ +#define ASNAR(func,t,s) \ + do { \ + (t) = 0; \ + (func)(&(t),&(s)[0],sizeof(s)); \ + } while (0) +#endif /* end LITTLE- BIG-ENDIAN */ +#endif /*0*/ + +/* Name_array is 8 byte string, or it is supposed to be + anyway. */ +static int +pe_section_name_get(dwarf_pe_object_access_internals_t *pep, + const char *name_array, + + /* The name strlen */ + unsigned long size_name, + const char ** name_out, + int *errcode) +{ + if (name_array[0] == '/') { + long v = 0; + unsigned long u = 0; + const char *s = 0; + char temp_array[9]; + int res = 0; + + /* The value is an integer after the /, + and we want the value */ + _dwarf_safe_strcpy(temp_array,sizeof(temp_array), + name_array+1,size_name-1); + v = atoi(temp_array); + if (v < 0) { + *errcode = DW_DLE_STRING_OFFSET_BAD; + return DW_DLV_ERROR; + } + u = v; + if (!pep->pe_string_table) { + *errcode = DW_DLE_STRING_OFFSET_BAD; + return DW_DLV_ERROR; + } + if (u >= pep->pe_string_table_size) { + *errcode = DW_DLE_STRING_OFFSET_BAD; + return DW_DLV_ERROR; + } + res = check_valid_string(pep->pe_string_table, + pep->pe_string_table_size,u); + if (res != DW_DLV_OK) { + *errcode = DW_DLE_STRING_OFFSET_BAD; + return DW_DLV_ERROR; + } + s = pep->pe_string_table +u; + *name_out = s; + return DW_DLV_OK; + } + *name_out = name_array; + return DW_DLV_OK; +} + +static Dwarf_Small +pe_get_byte_order (void *obj) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + return pep->pe_endian; +} + +static Dwarf_Small +pe_get_length_size (void *obj) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + return pep->pe_offsetsize/8; +} + +static Dwarf_Unsigned +pe_get_file_size (void *obj) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + return pep->pe_filesize; +} + +static Dwarf_Small +pe_get_pointer_size (void *obj) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + return pep->pe_pointersize/8; +} + +static Dwarf_Unsigned +pe_get_section_count (void *obj) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + return pep->pe_section_count; +} + +static int +pe_get_section_info (void *obj, + Dwarf_Unsigned section_index, + Dwarf_Obj_Access_Section_a *return_section, + int *error) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + + (void)error; + if (section_index < pep->pe_section_count) { + struct dwarf_pe_generic_image_section_header *sp = 0; + sp = pep->pe_sectionptr + section_index; + return_section->as_name = sp->dwarfsectname; + return_section->as_type = 0; + return_section->as_flags = 0; + return_section->as_addr = pep->pe_OptionalHeader.ImageBase + + sp->VirtualAddress; + return_section->as_offset = 0; + /* SizeOfRawData can be rounded or truncated, + use VirtualSize for the real analog of Elf + section size. */ + return_section->as_size = sp->VirtualSize; + return_section->as_link = 0; + return_section->as_info = 0; + return_section->as_addralign = 0; + return_section->as_entrysize = 0; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static int +load_optional_header32(dwarf_pe_object_access_internals_t *pep, + Dwarf_Unsigned offset, int*errcode) +{ + int res = 0; + IMAGE_OPTIONAL_HEADER32_dw hdr; + + pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER32_dw); + + if ((pep->pe_optional_header_size + offset) > + pep->pe_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + + res = _dwarf_object_read_random(pep->pe_fd, + (char *)&hdr, + (off_t)offset, sizeof(IMAGE_OPTIONAL_HEADER32_dw), + (off_t)pep->pe_filesize, + errcode); + if (res != DW_DLV_OK) { + return res; + } + + /* This is a subset of fields. */ + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.Magic, + hdr.Magic); + pep->pe_OptionalHeader.MajorLinkerVersion= hdr.MajorLinkerVersion; + pep->pe_OptionalHeader.MinorLinkerVersion= hdr.MinorLinkerVersion; + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.ImageBase, + hdr.ImageBase); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfCode, + hdr.SizeOfCode); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfImage, + hdr.SizeOfImage); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfHeaders, + hdr.SizeOfHeaders); + pep->pe_OptionalHeader.SizeOfDataDirEntry = + sizeof(IMAGE_DATA_DIRECTORY_dw); + return DW_DLV_OK; +} +static int +load_optional_header64(dwarf_pe_object_access_internals_t *pep, + Dwarf_Unsigned offset, int*errcode ) +{ + IMAGE_OPTIONAL_HEADER64_dw hdr; + int res = 0; + + pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER64_dw); + if ((pep->pe_optional_header_size + offset) > + pep->pe_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(pep->pe_fd, + (char *)&hdr, + (off_t)offset, sizeof(IMAGE_OPTIONAL_HEADER64_dw), + (off_t)pep->pe_filesize, + errcode); + if (res != DW_DLV_OK) { + return res; + } + + /* This is a subset of fields. */ + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.Magic, + hdr.Magic); + pep->pe_OptionalHeader.MajorLinkerVersion= hdr.MajorLinkerVersion; + pep->pe_OptionalHeader.MinorLinkerVersion= hdr.MinorLinkerVersion; + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.ImageBase, + hdr.ImageBase); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfCode, + hdr.SizeOfCode); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfImage, + hdr.SizeOfImage); + ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfHeaders, + hdr.SizeOfHeaders); + pep->pe_OptionalHeader.SizeOfDataDirEntry = + sizeof(IMAGE_DATA_DIRECTORY_dw); + return DW_DLV_OK; +} + +static char *boringname[] = { +".text", +".bss", +".data", +".rdata", +0 +}; + +static int +in_name_list(char * name) +{ + int i = 0; + + if (!name) { + return FALSE; + } + for ( ; ; ++i) { + if (!boringname[i]) { + break; + } + if (!strcmp(name,boringname[i])) { + return TRUE; + } + } + return FALSE; +} + +static int +is_irrelevant_section(char * name, + Dwarf_Unsigned virtsz) +{ + int res = FALSE; + + res = in_name_list(name); + if (res) { + return TRUE; + } + if (!virtsz) { + return TRUE; + } + return FALSE; +} + +static int +pe_load_section (void *obj, Dwarf_Unsigned section_index, + Dwarf_Small **return_data, int *error) +{ + dwarf_pe_object_access_internals_t *pep = + (dwarf_pe_object_access_internals_t*)(obj); + + if (0 < section_index && + section_index < pep->pe_section_count) { + int res = 0; + struct dwarf_pe_generic_image_section_header *sp = + pep->pe_sectionptr + section_index; + Dwarf_Unsigned read_length = 0; + + if (sp->loaded_data) { + *return_data = sp->loaded_data; + return DW_DLV_OK; + } + if (!sp->VirtualSize) { + return DW_DLV_NO_ENTRY; + } + if (sp->SizeOfRawData >= pep->pe_filesize) { + *error = DW_DLE_PE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + read_length = sp->SizeOfRawData; + if (sp->VirtualSize < read_length) { + /* Don't read padding that wasn't allocated in memory */ + read_length = sp->VirtualSize; + } + if ((read_length + sp->PointerToRawData) > + pep->pe_filesize) { + *error = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + /* VirtualSize > SizeOfRawData if trailing zeros + in the section were not written to disc. + Malloc enough for the whole section, read in + the bytes we have. */ + sp->loaded_data = malloc((size_t)sp->VirtualSize); + if (!sp->loaded_data) { + *error = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(pep->pe_fd, + (char *)sp->loaded_data, + (off_t)sp->PointerToRawData, (size_t)read_length, + (off_t)pep->pe_filesize, + error); + if (res != DW_DLV_OK) { + free(sp->loaded_data); + sp->loaded_data = 0; + return res; + } + if (sp->VirtualSize > read_length) { + /* Zero space that was allocated but + truncated from the file */ + memset(sp->loaded_data + read_length, 0, + (size_t)(sp->VirtualSize - read_length)); + } + *return_data = sp->loaded_data; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +void +_dwarf_destruct_pe_access( + struct Dwarf_Obj_Access_Interface_a_s *aip) +{ + dwarf_pe_object_access_internals_t *pep = 0; + Dwarf_Unsigned i = 0; + + if (!aip) { + return; + } + pep = (dwarf_pe_object_access_internals_t*)(aip->ai_object); + if (pep->pe_destruct_close_fd && pep->pe_fd !=-1) { + close(pep->pe_fd); + pep->pe_fd = -1; + } + free((char *)pep->pe_path); + pep->pe_path = 0; + if (pep->pe_sectionptr) { + struct dwarf_pe_generic_image_section_header *sp = 0; + + sp = pep->pe_sectionptr; + for (i=0; i < pep->pe_section_count; ++i,++sp) { + if (sp->loaded_data) { + free(sp->loaded_data); + sp->loaded_data = 0; + } + free(sp->name); + sp->name = 0; + free(sp->dwarfsectname); + sp->dwarfsectname = 0; + } + free(pep->pe_sectionptr); + pep->pe_section_count = 0; + } + free(pep->pe_string_table); + pep->pe_string_table = 0; + free(pep); + free(aip); + return; +} + +static int +_dwarf_pe_load_dwarf_section_headers( + dwarf_pe_object_access_internals_t *pep,int *errcode) +{ + Dwarf_Unsigned i = 0; + Dwarf_Unsigned input_count = + pep->pe_FileHeader.NumberOfSections; + Dwarf_Unsigned offset_in_input = pep->pe_section_table_offset; + Dwarf_Unsigned section_hdr_size = sizeof(IMAGE_SECTION_HEADER_dw); + struct dwarf_pe_generic_image_section_header *sec_outp = 0; + Dwarf_Unsigned cur_offset = offset_in_input; + Dwarf_Unsigned past_end_hdrs = offset_in_input + + section_hdr_size*input_count; + + /* internal sections include null initial section */ + pep->pe_section_count = input_count+1; + + if (past_end_hdrs > pep->pe_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + + if (!offset_in_input) { + *errcode = DW_DLE_PE_OFFSET_BAD; + return DW_DLV_ERROR; + } + pep->pe_sectionptr = + (struct dwarf_pe_generic_image_section_header * ) + calloc((size_t)pep->pe_section_count, + sizeof(struct dwarf_pe_generic_image_section_header)); + if (!pep->pe_sectionptr) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + sec_outp = pep->pe_sectionptr; + sec_outp->name = strdup(""); + sec_outp->dwarfsectname = strdup(""); + sec_outp++; + for ( ; i < input_count; + ++i, cur_offset += section_hdr_size, sec_outp++) { + + int res = 0; + IMAGE_SECTION_HEADER_dw filesect; + char safe_name[IMAGE_SIZEOF_SHORT_NAME +1]; + const char *expname = 0; + int irrelevant = 0; + + res = _dwarf_object_read_random(pep->pe_fd, + (char *)&filesect,(off_t)cur_offset, + sizeof(filesect), + (off_t)pep->pe_filesize, + errcode); + if (res != DW_DLV_OK) { + return res; + } + /* The following is safe. filesect.Name is + IMAGE_SIZEOF_SHORT_NAME bytes long and may + not (not sure) have a NUL terminator. */ + _dwarf_safe_strcpy(safe_name, + sizeof(safe_name), + filesect.Name, + IMAGE_SIZEOF_SHORT_NAME); + /* Have NUL terminator now. */ + sec_outp->name = strdup(safe_name); + + res = pe_section_name_get(pep, + safe_name,strlen(safe_name),&expname,errcode); + if (res != DW_DLV_OK) { + return res; + } + if (expname) { + sec_outp->dwarfsectname = strdup(expname); + } else { + sec_outp->dwarfsectname = strdup(""); + } + if ( !sec_outp->name || !sec_outp->dwarfsectname) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + sec_outp->SecHeaderOffset = cur_offset; + ASNAR(pep->pe_copy_word,sec_outp->VirtualSize, + filesect.Misc.VirtualSize); + ASNAR(pep->pe_copy_word,sec_outp->VirtualAddress, + filesect.VirtualAddress); + ASNAR(pep->pe_copy_word,sec_outp->SizeOfRawData, + filesect.SizeOfRawData); + irrelevant = is_irrelevant_section(sec_outp->dwarfsectname, + sec_outp->VirtualSize); + if (irrelevant) { + sec_outp->VirtualSize = 0; + sec_outp->SizeOfRawData = 0; + }else{ + /* A Heuristic, allowing large virtual size + but not unlimited as we will malloc it + later, as Virtualsize. */ + Dwarf_Unsigned limit = 100*pep->pe_filesize; + if (limit < pep->pe_filesize) { + /* An overflow. Bad. */ + *errcode = DW_DLE_PE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (sec_outp->VirtualSize > + ((Dwarf_Unsigned)200* + (Dwarf_Unsigned)1000* + (Dwarf_Unsigned)1000)) { + /* Likely totally unreasonable. + the hard limit written this way + simply for clarity. + Hard to know what to set it to. */ + *errcode = DW_DLE_PE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + if (sec_outp->VirtualSize > limit) { + /* Likely totally unreasonable. Bad. */ + *errcode = DW_DLE_PE_SECTION_SIZE_ERROR; + return DW_DLV_ERROR; + } + } + ASNAR(pep->pe_copy_word,sec_outp->PointerToRawData, + filesect.PointerToRawData); + if (sec_outp->SizeOfRawData > pep->pe_filesize || + sec_outp->PointerToRawData > pep->pe_filesize || + (sec_outp->SizeOfRawData+ + sec_outp->PointerToRawData > pep->pe_filesize)) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + ASNAR(pep->pe_copy_word,sec_outp->PointerToRelocations, + filesect.PointerToRelocations); + ASNAR(pep->pe_copy_word,sec_outp->PointerToLinenumbers, + filesect.PointerToLinenumbers); + ASNAR(pep->pe_copy_word,sec_outp->NumberOfRelocations, + filesect.NumberOfRelocations); + ASNAR(pep->pe_copy_word,sec_outp->NumberOfLinenumbers, + filesect.NumberOfLinenumbers); + ASNAR(pep->pe_copy_word,sec_outp->Characteristics, + filesect.Characteristics); + /* sec_outp->loaded data set when we load a section */ + } + return DW_DLV_OK; +} + +static int +_dwarf_load_pe_sections( + dwarf_pe_object_access_internals_t *pep,int *errcode) +{ + struct dos_header_dw dhinmem; + IMAGE_FILE_HEADER_dw ifh; + void (*word_swap) (void *, const void *, unsigned long); + unsigned locendian = 0; + int res = 0; + Dwarf_Unsigned dos_sig = 0; + Dwarf_Unsigned nt_address = 0; + char nt_sig_array[4]; + unsigned long nt_signature = 0; + + if ( (sizeof(ifh) + sizeof(dhinmem)) >= pep->pe_filesize) { + /* corrupt object. */ + *errcode = DW_DLE_PE_SIZE_SMALL; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(pep->pe_fd,(char *)&dhinmem, + 0, sizeof(dhinmem),(off_t)pep->pe_filesize, errcode); + if (res != DW_DLV_OK) { + return res; + } + dos_sig = magic_copy((char *)dhinmem.dh_mz, + sizeof(dhinmem.dh_mz)); + if (dos_sig == IMAGE_DOS_SIGNATURE_dw) { + /* IMAGE_DOS_SIGNATURE_dw assumes bytes + reversed by little-endian + load, so we intrepet a match the other way. */ + /* BIG ENDIAN. From looking at hex characters in object */ +#ifdef WORDS_BIGENDIAN + word_swap = _dwarf_memcpy_noswap_bytes; +#else /* LITTLE ENDIAN */ + word_swap = _dwarf_memcpy_swap_bytes; +#endif /* LITTLE- BIG-ENDIAN */ + locendian = DW_END_big; + } else if (dos_sig == IMAGE_DOS_REVSIGNATURE_dw) { + /* raw load, so intrepet a match the other way. */ + /* LITTLE ENDIAN */ +#ifdef WORDS_BIGENDIAN + word_swap = _dwarf_memcpy_swap_bytes; +#else /* LITTLE ENDIAN */ + word_swap = _dwarf_memcpy_noswap_bytes; +#endif /* LITTLE- BIG-ENDIAN */ + locendian = DW_END_little; + } else { + /* Not dos header not a PE file we recognize */ + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } + if (locendian != pep->pe_endian) { + /* Really this is a coding botch somewhere here, + not an object corruption. */ + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } + pep->pe_copy_word = word_swap; + ASNAR(word_swap,nt_address,dhinmem.dh_image_offset); + if (pep->pe_filesize < (nt_address + sizeof(nt_sig_array))) { + /* The nt_address is really a file offset. */ + *errcode = DW_DLE_FILE_TOO_SMALL; + /* Not dos header not a PE file we recognize */ + return DW_DLV_ERROR; + } + + res = _dwarf_object_read_random(pep->pe_fd, + (char *)&nt_sig_array[0], + (off_t)nt_address, sizeof(nt_sig_array), + (off_t)pep->pe_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + { unsigned long lsig = 0; + + ASNAR(word_swap,lsig,nt_sig_array); + nt_signature = lsig; + } + if (nt_signature != IMAGE_NT_SIGNATURE_dw) { + *errcode = DW_DLE_FILE_WRONG_TYPE; + return DW_DLV_ERROR; + } + + pep->pe_nt_header_offset = nt_address + SIZEOFT32; + if (pep->pe_filesize < (pep->pe_nt_header_offset + + sizeof(ifh))) { + *errcode = DW_DLE_FILE_TOO_SMALL; + /* Not image header not a PE file we recognize */ + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(pep->pe_fd,(char *)&ifh, + (off_t)pep->pe_nt_header_offset, sizeof(ifh), + (off_t)pep->pe_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + ASNAR(word_swap,pep->pe_FileHeader.Machine,ifh.Machine); + ASNAR(word_swap,pep->pe_FileHeader.NumberOfSections, + ifh.NumberOfSections); + ASNAR(word_swap,pep->pe_FileHeader.TimeDateStamp, + ifh.TimeDateStamp); + ASNAR(word_swap,pep->pe_FileHeader.PointerToSymbolTable, + ifh.PointerToSymbolTable); + ASNAR(word_swap,pep->pe_FileHeader.NumberOfSymbols, + ifh.NumberOfSymbols); + ASNAR(word_swap,pep->pe_FileHeader.SizeOfOptionalHeader, + ifh.SizeOfOptionalHeader); + ASNAR(word_swap,pep->pe_FileHeader.Characteristics, + ifh.Characteristics); + + pep->pe_optional_header_offset = pep->pe_nt_header_offset+ + sizeof(ifh); + if (pep->pe_offsetsize == 32) { + res = load_optional_header32(pep, + pep->pe_optional_header_offset,errcode); + pep->pe_optional_header_size = + sizeof(IMAGE_OPTIONAL_HEADER32_dw); + } else if (pep->pe_offsetsize == 64) { + res = load_optional_header64(pep, + pep->pe_optional_header_offset,errcode); + pep->pe_optional_header_size = + sizeof(IMAGE_OPTIONAL_HEADER64_dw); + } else { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + if (res != DW_DLV_OK) { + return res; + } + + pep->pe_section_table_offset = pep->pe_optional_header_offset + + pep->pe_optional_header_size; + pep->pe_symbol_table_offset = + pep->pe_FileHeader.PointerToSymbolTable; + if (pep->pe_symbol_table_offset >= pep->pe_filesize) { + *errcode = DW_DLE_OFFSET_SIZE; + return DW_DLV_ERROR; + } + if (pep->pe_symbol_table_offset) { + pep->pe_string_table_offset = + pep->pe_symbol_table_offset + + (pep->pe_FileHeader.NumberOfSymbols * + IMAGE_SIZEOF_SYMBOL); + } + + if (pep->pe_string_table_offset >= pep->pe_filesize) { + *errcode = DW_DLE_OFFSET_SIZE; + pep->pe_string_table_size = 0; + return DW_DLV_ERROR; + } + if (pep->pe_string_table_offset) { + /* https://docs.microsoft.com/en-us/\ + windows/desktop/debug/pe-format#coff-string-table */ + /* The first 4 bytes of the string table contain + the size of the string table. */ + char size_field[4]; + + if ((pep->pe_string_table_offset+sizeof(size_field)) > + pep->pe_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + memset(size_field,0,sizeof(size_field)); + res = _dwarf_object_read_random(pep->pe_fd, + (char *)size_field, (off_t)pep->pe_string_table_offset, + sizeof(size_field), + (off_t)pep->pe_filesize,errcode); + if (res != DW_DLV_OK) { + return res; + } + ASNAR(pep->pe_copy_word,pep->pe_string_table_size, + size_field); + if (pep->pe_string_table_size >= pep->pe_filesize ) { + *errcode = DW_DLE_PE_OFFSET_BAD; + return DW_DLV_ERROR; + } + if ((pep->pe_string_table_offset+pep->pe_string_table_size) > + pep->pe_filesize) { + *errcode = DW_DLE_FILE_TOO_SMALL; + return DW_DLV_ERROR; + } + /* size+1 to ensure there is a terminating null character + in memory so CoverityScan knows there is always a + final null. CoverityScan is not aware + there may be multiple strings in the table. + If there is a compiler bug the final string + might be missing its intended null terminator! */ + pep->pe_string_table = + (char *)calloc(1,(size_t)pep->pe_string_table_size+1); + if (!pep->pe_string_table) { + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + res = _dwarf_object_read_random(pep->pe_fd, + (char *)pep->pe_string_table, + (off_t)pep->pe_string_table_offset, + (size_t)pep->pe_string_table_size, + (off_t)pep->pe_filesize,errcode); + if (res != DW_DLV_OK) { + free(pep->pe_string_table); + pep->pe_string_table = 0; + return res; + } + /* Should pass coverity now. */ + pep->pe_string_table[pep->pe_string_table_size] = 0; + } + res = _dwarf_pe_load_dwarf_section_headers(pep,errcode); + return res; +} + +int +_dwarf_pe_setup(int fd, + char *true_path, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + unsigned groupnumber, + Dwarf_Handler errhand, + Dwarf_Ptr errarg, + Dwarf_Debug *dbg,Dwarf_Error *error) +{ + Dwarf_Obj_Access_Interface_a *binary_interface = 0; + dwarf_pe_object_access_internals_t *pep = 0; + int res = DW_DLV_OK; + int localerrnum = 0; + + res = _dwarf_pe_object_access_init( + fd, + ftype,endian,offsetsize,filesize, + &binary_interface, + &localerrnum); + if (res != DW_DLV_OK) { + if (res == DW_DLV_NO_ENTRY) { + return res; + } + _dwarf_error(NULL, error, localerrnum); + return DW_DLV_ERROR; + } + /* allocates and initializes Dwarf_Debug, + generic code */ + res = dwarf_object_init_b(binary_interface, errhand, errarg, + groupnumber, dbg, error); + if (res != DW_DLV_OK){ + _dwarf_destruct_pe_access(binary_interface); + return res; + } + pep = binary_interface->ai_object; + pep->pe_path = strdup(true_path); + return res; +} + +static Dwarf_Obj_Access_Methods_a pe_methods = { + pe_get_section_info, + pe_get_byte_order, + pe_get_length_size, + pe_get_pointer_size, + pe_get_file_size, + pe_get_section_count, + pe_load_section, + 0 /* ignore pe relocations. */ +}; + +/* On any error this frees internals. */ +static int +_dwarf_pe_object_access_internals_init( + dwarf_pe_object_access_internals_t * internals, + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + int *errcode) +{ + dwarf_pe_object_access_internals_t * intfc = internals; + struct Dwarf_Obj_Access_Interface_a_s *localdoas = 0; + int res = 0; + + /* Must malloc as _dwarf_destruct_pe_access() + forces that due to other uses. */ + localdoas = (struct Dwarf_Obj_Access_Interface_a_s *) + malloc(sizeof(struct Dwarf_Obj_Access_Interface_a_s)); + if (!localdoas) { + free(internals); + *errcode = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_a_s)); + intfc->pe_ident[0] = 'P'; + intfc->pe_ident[1] = '1'; + intfc->pe_fd = fd; + intfc->pe_is_64bit = ((offsetsize==64)?TRUE:FALSE); + intfc->pe_offsetsize = offsetsize; + intfc->pe_pointersize = offsetsize; + intfc->pe_filesize = filesize; + intfc->pe_ftype = ftype; + /* pe_path set by caller */ + +#ifdef WORDS_BIGENDIAN + if (endian == DW_END_little) { + intfc->pe_copy_word = _dwarf_memcpy_swap_bytes; + intfc->pe_endian = DW_END_little; + } else { + intfc->pe_copy_word = _dwarf_memcpy_noswap_bytes; + intfc->pe_endian = DW_END_big; + } +#else /* LITTLE ENDIAN */ + if (endian == DW_END_little) { + intfc->pe_copy_word = _dwarf_memcpy_noswap_bytes; + intfc->pe_endian = DW_END_little; + } else { + intfc->pe_copy_word = _dwarf_memcpy_swap_bytes; + intfc->pe_endian = DW_END_big; + } +#endif /* LITTLE- BIG-ENDIAN */ + res = _dwarf_load_pe_sections(intfc,errcode); + if (res != DW_DLV_OK) { + localdoas->ai_object = intfc; + localdoas->ai_methods = 0; + _dwarf_destruct_pe_access(localdoas); + localdoas = 0; + return res; + } + free(localdoas); + localdoas = 0; + return DW_DLV_OK; +} + +static int +_dwarf_pe_object_access_init( + int fd, + unsigned ftype, + unsigned endian, + unsigned offsetsize, + size_t filesize, + Dwarf_Obj_Access_Interface_a **binary_interface, + int *localerrnum) +{ + + int res = 0; + dwarf_pe_object_access_internals_t *internals = 0; + Dwarf_Obj_Access_Interface_a *intfc = 0; + + internals = malloc(sizeof(dwarf_pe_object_access_internals_t)); + if (!internals) { + *localerrnum = DW_DLE_ALLOC_FAIL; + /* Impossible case, we hope. Give up. */ + return DW_DLV_ERROR; + } + memset(internals,0,sizeof(*internals)); + res = _dwarf_pe_object_access_internals_init(internals, + fd, + ftype, endian, offsetsize, filesize, + localerrnum); + if (res != DW_DLV_OK){ + /* *err is already set. and the call freed internals */ + return DW_DLV_ERROR; + } + + intfc = malloc(sizeof(Dwarf_Obj_Access_Interface_a)); + if (!intfc) { + /* Impossible case, we hope. Give up. */ + free(internals); + *localerrnum = DW_DLE_ALLOC_FAIL; + return DW_DLV_ERROR; + } + /* Initialize the interface struct */ + intfc->ai_object = internals; + intfc->ai_methods = &pe_methods; + *binary_interface = intfc; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_peread.h b/src/lib/libdwarf/dwarf_peread.h new file mode 100644 index 0000000..71d94dc --- /dev/null +++ b/src/lib/libdwarf/dwarf_peread.h @@ -0,0 +1,155 @@ +#ifndef PE_GENERIC_H +#define PE_GENERIC_H +/* +Copyright (c) 2018-2023, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct dwarf_pe_generic_file_header +{ + Dwarf_Unsigned Machine; + Dwarf_Unsigned NumberOfSections; + Dwarf_Unsigned TimeDateStamp; + Dwarf_Unsigned PointerToSymbolTable; + Dwarf_Unsigned NumberOfSymbols; + Dwarf_Unsigned SizeOfOptionalHeader; /* in object file */ + Dwarf_Unsigned Characteristics; +}; + +struct dwarf_pe_generic_data_directory +{ + Dwarf_Unsigned VirtualAddress; + Dwarf_Unsigned Size; +}; + +#define DWARF_PE_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 +struct dwarf_pe_generic_optional_header +{ + Dwarf_Unsigned Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + Dwarf_Unsigned SizeOfCode; + Dwarf_Unsigned SizeOfInitializedData; + Dwarf_Unsigned SizeOfUninitializedData; + Dwarf_Unsigned AddressOfEntryPoint; + Dwarf_Unsigned BaseOfCode; + Dwarf_Unsigned BaseOfData; + Dwarf_Unsigned ImageBase; + Dwarf_Unsigned SectionAlignment; + Dwarf_Unsigned FileAlignment; + Dwarf_Unsigned MajorOperatingSystemVersion; + Dwarf_Unsigned MinorOperatingSystemVersion; + Dwarf_Unsigned MajorImageVersion; + Dwarf_Unsigned MinorImageVersion; + Dwarf_Unsigned MajorSubsystemVersion; + Dwarf_Unsigned MinorSubsystemVersion; + Dwarf_Unsigned Win32VersionValue; + Dwarf_Unsigned SizeOfImage; /* size in object file */ + Dwarf_Unsigned SizeOfHeaders; /* size in object file */ + Dwarf_Unsigned CheckSum; + Dwarf_Unsigned Subsystem; + Dwarf_Unsigned DllCharacteristics; + Dwarf_Unsigned SizeOfStackReserve; + Dwarf_Unsigned SizeOfStackCommit; + Dwarf_Unsigned SizeOfHeapReserve; + Dwarf_Unsigned SizeOfHeapCommit; + Dwarf_Unsigned LoaderFlags; + Dwarf_Unsigned NumberOfRvaAndSizes; + Dwarf_Unsigned SizeOfDataDirEntry; /* size in object file */ + struct dwarf_pe_generic_data_directory + DataDirectory[DWARF_PE_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +}; + +struct dwarf_pe_generic_image_section_header +{ + char *name; /* Name must be freed */ + char *dwarfsectname; /* Name must be freed */ + Dwarf_Unsigned SecHeaderOffset; /* offset in object file */ + /* union { */ + /* Dwarf_Unsigned PhysicalAddress; */ + Dwarf_Unsigned VirtualSize; + /* } Misc; */ + Dwarf_Unsigned VirtualAddress; + Dwarf_Unsigned SizeOfRawData; /* size we need */ + Dwarf_Unsigned PointerToRawData; + Dwarf_Unsigned PointerToRelocations; + Dwarf_Unsigned PointerToLinenumbers; + Dwarf_Unsigned NumberOfRelocations; + Dwarf_Unsigned NumberOfLinenumbers; + Dwarf_Unsigned Characteristics; + Dwarf_Small * loaded_data; /* must be freed. */ +}; + +#define DWARF_PE_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define DWARF_PE_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define DWARF_PE_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +/* ident[0] == 'P' means this is a PE header. + ident[1] will be 1 indicating version 1. + Other bytes in ident not defined, should be zero. */ +typedef struct pe_filedata_s { + char pe_ident[8]; + const char * pe_path; /* must free.*/ + int pe_fd; + int pe_destruct_close_fd; /*aka: lib owns fd */ + int pe_is_64bit; + Dwarf_Unsigned pe_filesize; + Dwarf_Small pe_offsetsize; /* 32 or 64 section data */ + Dwarf_Small pe_pointersize; + int pe_ftype; + unsigned pe_endian; + /*Dwarf_Small pe_machine; */ + void (*pe_copy_word) (void *, const void *, unsigned long); + Dwarf_Unsigned pe_nt_header_offset; + Dwarf_Unsigned pe_optional_header_offset; + Dwarf_Unsigned pe_optional_header_size; + Dwarf_Unsigned pe_symbol_table_offset; + Dwarf_Unsigned pe_string_table_offset; + Dwarf_Unsigned pe_section_table_offset; + Dwarf_Unsigned pe_signature; + + struct dwarf_pe_generic_file_header pe_FileHeader; + + struct dwarf_pe_generic_optional_header pe_OptionalHeader; + + Dwarf_Unsigned pe_section_count; + struct dwarf_pe_generic_image_section_header *pe_sectionptr; + + Dwarf_Unsigned pe_string_table_size; + char *pe_string_table; +} dwarf_pe_object_access_internals_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PE_GENERIC_H */ diff --git a/src/lib/libdwarf/dwarf_print_lines.c b/src/lib/libdwarf/dwarf_print_lines.c new file mode 100644 index 0000000..a8af80e --- /dev/null +++ b/src/lib/libdwarf/dwarf_print_lines.c @@ -0,0 +1,1030 @@ +/* + Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2020 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* free() malloc() realloc() */ +#include /* memset() strlen() */ +#include /* ctime() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_line.h" +#include "dwarf_string.h" + +#define PRINTING_DETAILS 1 +/* for dwarfstring_constructor_static, saving lots of malloc + and free but beware: make sure each routine using + this DOES NOT call another routine using it. + And do not use it in Dwarf_Error related calls. + would be safer to have a buffer per function, but + currently not necessary. */ +static char locallinebuf[200]; + +static void +print_line_header(Dwarf_Debug dbg, + Dwarf_Bool is_single_tab, + Dwarf_Bool is_actuals_tab) +{ +if (!is_single_tab) { + /* Ugly indenting follows, it makes lines shorter + to see them better. + Best to use a wider text window to really + see how it looks.*/ +if (is_actuals_tab) { +_dwarf_printf(dbg,"\nActuals Table\n"); +_dwarf_printf(dbg, +" be\n" +" ls\n" +" ce\n" +" section op kq\n" +" offset code address/index row isa ??\n"); + return; +} else { +_dwarf_printf(dbg,"\nLogicals Table\n"); +_dwarf_printf(dbg, +" " + " s pe\n" +" " + " tirp\n" +" " + " msoi\n" +" section op " + " tall\n" +" offset row code address/indx fil l" + "ne col disc cntx subp ????\n"); + return; +} +} + +/* Single level table */ +_dwarf_printf(dbg, +" " + "s b e p e i d\n" +" " + "t l s r p s i\n" +" " + "m c e o i a s\n" +" section op col " + "t k q l l c\n" +" offset code address file line umn ? ? ? ? ?\n" +); +} /* End of function with ugly indenting. */ + +static void +print_line_detail( + Dwarf_Debug dbg, + const char *prefix, + int opcode, + unsigned curr_line, + struct Dwarf_Line_Registers_s * regs, + Dwarf_Bool is_single_table, Dwarf_Bool is_actuals_table) +{ + dwarfstring m1; + + dwarfstring_constructor_static(&m1,locallinebuf, + sizeof(locallinebuf)); + if (!is_single_table && is_actuals_table) { + dwarfstring_append_printf_s(&m1,"%-15s ",(char *)prefix); + dwarfstring_append_printf_i(&m1,"%3d ",opcode); + dwarfstring_append_printf_u(&m1,"0x%" DW_PR_XZEROS DW_PR_DUx, + regs->lr_address); + dwarfstring_append_printf_u(&m1,"/%01u",regs->lr_op_index); + dwarfstring_append_printf_u(&m1," %5lu", regs->lr_line); + dwarfstring_append_printf_u(&m1," %3u",regs->lr_isa); + dwarfstring_append_printf_i(&m1," %1d", + regs->lr_basic_block); + dwarfstring_append_printf_i(&m1,"%1d\n", + regs->lr_end_sequence); + _dwarf_printf(dbg,dwarfstring_string(&m1)); + dwarfstring_destructor(&m1); + return; + } + if (!is_single_table && !is_actuals_table) { + dwarfstring_append_printf_i(&m1, + "[%3d] " /* row number */, curr_line); + dwarfstring_append_printf_s(&m1, + "%-15s ",(char *)prefix); + dwarfstring_append_printf_i(&m1, + "%3d ",opcode); + dwarfstring_append_printf_u(&m1, + "x%" DW_PR_XZEROS DW_PR_DUx, regs->lr_address); + dwarfstring_append_printf_u(&m1, + "/%01u", regs->lr_op_index); + dwarfstring_append_printf_u(&m1," %2lu ",regs->lr_file); + dwarfstring_append_printf_u(&m1,"%4lu ",regs->lr_line); + dwarfstring_append_printf_u(&m1,"%1lu",regs->lr_column); + if (regs->lr_discriminator || + regs->lr_prologue_end || + regs->lr_epilogue_begin || + regs->lr_isa || + regs->lr_is_stmt || + regs->lr_call_context || + regs->lr_subprogram) { + dwarfstring_append_printf_u(&m1, + " x%02" DW_PR_DUx , + regs->lr_discriminator); /* DWARF4 */ + dwarfstring_append_printf_u(&m1, + " x%02" DW_PR_DUx, + regs->lr_call_context); /* EXPERIMENTAL */ + dwarfstring_append_printf_u(&m1, + " x%02" DW_PR_DUx , + regs->lr_subprogram); /* EXPERIMENTAL */ + dwarfstring_append_printf_i(&m1, + " %1d", regs->lr_is_stmt); + dwarfstring_append_printf_i(&m1, + "%1d", (int) regs->lr_isa); + dwarfstring_append_printf_i(&m1, + "%1d", regs->lr_prologue_end); /* DWARF3 */ + dwarfstring_append_printf_i(&m1, + "%1d", regs->lr_epilogue_begin); /* DWARF3 */ + } + dwarfstring_append(&m1,"\n"); + _dwarf_printf(dbg,dwarfstring_string(&m1)); + dwarfstring_destructor(&m1); + return; + } + /* In the first quoted line below: + 3d looks better than 2d, but best to do that as separate + change and test from two-level-line-tables. */ + dwarfstring_append_printf_s(&m1, + "%-15s ",(char *)prefix); + dwarfstring_append_printf_i(&m1, + "%2d ",opcode); + dwarfstring_append_printf_u(&m1, + "0x%" DW_PR_XZEROS DW_PR_DUx " ", + regs->lr_address); + dwarfstring_append_printf_u(&m1, + "%2lu ", regs->lr_file); + dwarfstring_append_printf_u(&m1, + "%4lu ", regs->lr_line); + dwarfstring_append_printf_u(&m1, + "%2lu ", regs->lr_column); + dwarfstring_append_printf_i(&m1, + "%1d ",regs->lr_is_stmt); + dwarfstring_append_printf_i(&m1, + "%1d ", regs->lr_basic_block); + dwarfstring_append_printf_i(&m1, + "%1d",regs->lr_end_sequence); + if (regs->lr_discriminator || + regs->lr_prologue_end || + regs->lr_epilogue_begin || + regs->lr_isa) { + dwarfstring_append_printf_i(&m1, + " %1d", regs->lr_prologue_end); /* DWARF3 */ + dwarfstring_append_printf_i(&m1, + " %1d", regs->lr_epilogue_begin); /* DWARF3 */ + dwarfstring_append_printf_i(&m1, + " %1d", regs->lr_isa); /* DWARF3 */ + dwarfstring_append_printf_u(&m1, + " 0x%" DW_PR_DUx , regs->lr_discriminator); /* DWARF4 */ + } + dwarfstring_append(&m1, "\n"); + _dwarf_printf(dbg,dwarfstring_string(&m1)); + dwarfstring_destructor(&m1); +} + +#include "dwarf_line_table_reader_common.h" + +static void +print_include_directory_details(Dwarf_Debug dbg, + unsigned int line_version, + Dwarf_Line_Context line_context) +{ + Dwarf_Unsigned u = 0; + dwarfstring m4; + Dwarf_Unsigned indexbase = 0; + Dwarf_Unsigned indexlimit = 0; + + dwarfstring_constructor_static(&m4,locallinebuf, + sizeof(locallinebuf)); + if (line_version == DW_LINE_VERSION5) { + unsigned i = 0; + unsigned dfcount = + line_context->lc_directory_entry_format_count; + + dwarfstring_constructor(&m4); + dwarfstring_append_printf_u(&m4, + " directory entry format count %u\n",dfcount); + _dwarf_printf(dbg,dwarfstring_string(&m4)); + dwarfstring_reset(&m4); + for ( ; i < dfcount;++i) { + struct Dwarf_Unsigned_Pair_s *valpair = 0; + const char *tname = 0; + const char *fname = 0; + int res; + + valpair = line_context->lc_directory_format_values +i; + dwarfstring_append_printf_u(&m4, + " format [%2u] ",i); + res = dwarf_get_LNCT_name(valpair->up_first, + &tname); + if ( res != DW_DLV_OK) { + tname = ""; + } + dwarfstring_append_printf_u (&m4, + " type 0x%" DW_PR_XZEROS DW_PR_DUx, + valpair->up_first); + dwarfstring_append_printf_s (&m4, + " %-20s\n",(char *)tname); + res = dwarf_get_FORM_name(valpair->up_second,&fname); + if ( res != DW_DLV_OK) { + fname = ""; + } + dwarfstring_append_printf_u(&m4, + " code 0x%" DW_PR_XZEROS DW_PR_DUx , + valpair->up_second); + dwarfstring_append_printf_s(&m4, + " %-20s\n", (char *)fname); + _dwarf_printf(dbg,dwarfstring_string(&m4)); + dwarfstring_reset(&m4); + + } + } + /* Common print of the directories. + For DWARF 2,3,4 it has always started + the indexing at 0 even though the directory index + in line entries starts at 1 (zero meaning + current directory at compile time). + That is odd, given the non-dash-v printed + starting at 1. So lets adjust for consistency. */ + if (line_version == DW_LINE_VERSION5) { + dwarfstring_append_printf_i(&m4, + " include directories count %d\n", + (int) line_context->lc_include_directories_count); + } else { + if (!line_context->lc_include_directories_count) { + dwarfstring_append_printf_i(&m4, + " include directories count %d\n", + (int) line_context->lc_include_directories_count); + } else { + dwarfstring_append_printf_i(&m4, + " include directories count %d" + " (index starts at 1)\n", + (int) line_context->lc_include_directories_count); + } + } + _dwarf_printf(dbg,dwarfstring_string(&m4)); + dwarfstring_reset(&m4); + if (line_version == DW_LINE_VERSION5) { + indexbase = 0; + indexlimit = line_context->lc_include_directories_count; + } else { + indexbase = 1; + indexlimit = 1 + line_context->lc_include_directories_count; + } + for (u = indexbase; u < indexlimit; ++u) { + dwarfstring_append_printf_u(&m4, + " include dir[%u] ",u); + dwarfstring_append_printf_s(&m4, + "%s\n",(char *) + line_context->lc_include_directories[u-indexbase]); + _dwarf_printf(dbg,dwarfstring_string(&m4)); + dwarfstring_reset(&m4); + } + dwarfstring_destructor(&m4); +} + +static void +print_just_file_entry_details(Dwarf_Debug dbg, + Dwarf_Line_Context line_context) +{ + unsigned fiu = 0; + Dwarf_File_Entry fe = line_context->lc_file_entries; + Dwarf_File_Entry fe2 = fe; + dwarfstring m3; + unsigned increment = 1; + + if (line_context->lc_version_number == DW_LINE_VERSION5 ) { + increment = 0; + } + dwarfstring_constructor_static(&m3,locallinebuf, + sizeof(locallinebuf)); + dwarfstring_append_printf_i(&m3, + " file names count %d\n", + line_context->lc_file_entry_count); + _dwarf_printf(dbg,dwarfstring_string(&m3)); + dwarfstring_reset(&m3); + for (fiu = 0 ; fe2 ; fe2 = fe->fi_next,++fiu ) { + Dwarf_Unsigned tlm2 = 0; + unsigned filenum = 0; + + fe = fe2; + tlm2 = fe->fi_time_last_mod; + filenum = fiu+increment; + + /* The space character at the end of line is silly, + but lets leave it there for the moment to avoid + changing output. */ + if (line_context->lc_file_entry_count > 9) { + dwarfstring_append_printf_u(&m3, + " file[%2u] ",fiu); + } else { + dwarfstring_append_printf_u(&m3, + " file[%u] ", fiu); + } + /* DWARF5 can have a null fi_file_name + if the format code in the + line table header is unknown, such + as in a corrupt object file. */ + dwarfstring_append_printf_s(&m3, + "%-20s ", + fe->fi_file_name? + (char *) fe->fi_file_name: + ""); + dwarfstring_append_printf_u(&m3, + "(file-number: %u)\n", + filenum); + _dwarf_printf(dbg,dwarfstring_string(&m3)); + dwarfstring_reset(&m3); + if (fe->fi_dir_index_present) { + Dwarf_Unsigned di = 0; + di = fe->fi_dir_index; + dwarfstring_append_printf_i(&m3, + " dir index %d\n", di); + } + if (fe->fi_time_last_mod_present) { + time_t tt = (time_t) tlm2; + + /* ctime supplies newline */ + dwarfstring_append_printf_u(&m3, + " last time 0x%x ",tlm2); + dwarfstring_append(&m3,(char *)ctime(&tt)); + } + if (fe->fi_file_length_present) { + Dwarf_Unsigned fl = 0; + + fl = fe->fi_file_length; + dwarfstring_append_printf_i(&m3, + " file length %ld ",fl); + dwarfstring_append_printf_u(&m3, + "0x%lx\n",fl); + } + if (fe->fi_md5_present) { + char *c = (char *)&fe->fi_md5_value; + char *end = c+sizeof(fe->fi_md5_value); + dwarfstring_append(&m3, " file md5 value 0x"); + while(c < end) { + dwarfstring_append_printf_u(&m3, + "%02x",0xff&*c); + ++c; + } + dwarfstring_append(&m3,"\n"); + } + if (fe->fi_llvm_source) { + dwarfstring_append_printf_s(&m3, + "%-20s\n", + (char *) fe->fi_llvm_source); + } + if (fe->fi_gnu_subprogram_name) { + dwarfstring_append_printf_s(&m3, + "%-20s\n", + (char *) fe->fi_gnu_subprogram_name); + } + if (fe->fi_gnu_decl_file_present) { + Dwarf_Unsigned di = 0; + di = fe->fi_gnu_decl_file; + dwarfstring_append_printf_i(&m3, + " gnu decl file %d\n", di); + } + if (fe->fi_gnu_decl_line_present) { + Dwarf_Unsigned di = 0; + di = fe->fi_gnu_decl_line; + dwarfstring_append_printf_i(&m3, + " gnu decl line %d\n", di); + } + if (dwarfstring_strlen(&m3)) { + _dwarf_printf(dbg,dwarfstring_string(&m3)); + dwarfstring_reset(&m3); + } + } + dwarfstring_destructor(&m3); +} + +static void +print_file_entry_details(Dwarf_Debug dbg, + unsigned int line_version, + Dwarf_Line_Context line_context) +{ + dwarfstring m5; + + dwarfstring_constructor_static(&m5,locallinebuf, + sizeof(locallinebuf)); + if (line_version == DW_LINE_VERSION5) { + unsigned i = 0; + unsigned dfcount = line_context->lc_file_name_format_count; + + dwarfstring_append_printf_u(&m5, + " file entry format count %u\n",dfcount); + for ( ; i < dfcount;++i) { + struct Dwarf_Unsigned_Pair_s *valpair = 0; + const char *tname = 0; + const char *fname = 0; + int res; + + valpair = line_context->lc_file_format_values +i; + dwarfstring_append_printf_u(&m5, + " format [%2u] ",i); + res = dwarf_get_LNCT_name(valpair->up_first,&tname); + if ( res != DW_DLV_OK) { + tname = ""; + } + dwarfstring_append_printf_u(&m5, + " type 0x%" DW_PR_XZEROS DW_PR_DUx, + valpair->up_first); + dwarfstring_append_printf_s(&m5, + " %-20s\n",(char *)tname); + res = dwarf_get_FORM_name(valpair->up_second,&fname); + if ( res != DW_DLV_OK) { + fname = ""; + } + dwarfstring_append_printf_u(&m5, + " code 0x%" + DW_PR_XZEROS DW_PR_DUx, + valpair->up_second); + dwarfstring_append_printf_s(&m5, " %-20s\n", + (char *)fname); + _dwarf_printf(dbg,dwarfstring_string(&m5)); + dwarfstring_reset(&m5); + } + dwarfstring_destructor(&m5); + print_just_file_entry_details(dbg,line_context); + } else { + print_just_file_entry_details(dbg,line_context); + dwarfstring_destructor(&m5); + } +} + +static void +print_experimental_subprograms_list(Dwarf_Debug dbg, + Dwarf_Line_Context line_context) +{ + /* Print the subprograms list. */ + Dwarf_Unsigned count = line_context->lc_subprogs_count; + Dwarf_Unsigned exu = 0; + Dwarf_Subprog_Entry sub = line_context->lc_subprogs; + dwarfstring m6; + + dwarfstring_constructor_static(&m6,locallinebuf, + sizeof(locallinebuf)); + dwarfstring_append_printf_u(&m6, + " subprograms count %" DW_PR_DUu "\n",count); + if (count > 0) { + dwarfstring_append(&m6," indx file line name\n"); + } + _dwarf_printf(dbg,dwarfstring_string(&m6)); + dwarfstring_reset(&m6); + for (exu = 0 ; exu < count ; exu++,sub++) { + dwarfstring_append_printf_u(&m6, + " [%2" DW_PR_DUu,exu+1); + dwarfstring_append_printf_u(&m6, + "] %4" DW_PR_DUu,sub->ds_decl_file); + dwarfstring_append_printf_u(&m6, + " %4" DW_PR_DUu ,sub->ds_decl_line); + dwarfstring_append_printf_s(&m6, + " %s\n",(char *)sub->ds_subprog_name); + _dwarf_printf(dbg,dwarfstring_string(&m6)); + dwarfstring_reset(&m6); + } + dwarfstring_destructor(&m6); +} + +static void +do_line_print_now(Dwarf_Debug dbg,int line_version, + Dwarf_Small * comp_dir, + Dwarf_Line_Context line_context) ; +static void print_experimental_counts(Dwarf_Debug dbg, + int line_version, + Dwarf_Line_Context line_context); + +static int print_actuals_and_locals(Dwarf_Debug dbg, + Dwarf_Line_Context line_context, + Dwarf_Unsigned bogus_bytes_count, + Dwarf_Small *bogus_bytes_ptr, + Dwarf_Small *orig_line_ptr, + Dwarf_Small *line_ptr, + Dwarf_Small *section_start, + Dwarf_Small *line_ptr_actuals, + Dwarf_Small *line_ptr_end, + Dwarf_Half address_size, + int * err_count_out, + Dwarf_Error *error); + +/* return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR + If err_count_out is non-NULL, this is a special 'check' + call. */ +static int +_dwarf_internal_printlines(Dwarf_Die die, + int * err_count_out, + int only_line_header, + Dwarf_Error * error) +{ + /* This pointer is used to scan the portion of the .debug_line + section for the current cu. */ + Dwarf_Small *line_ptr = 0; + Dwarf_Small *orig_line_ptr = 0; + + /* Pointer to a DW_AT_stmt_list attribute in case + it exists in the die. */ + Dwarf_Attribute stmt_list_attr = 0; + + /* Pointer to DW_AT_comp_dir attribute in die. */ + Dwarf_Attribute comp_dir_attr = 0; + + /* Pointer to name of compilation directory. */ + Dwarf_Small *comp_dir = NULL; + + /* Offset into .debug_line specified by a DW_AT_stmt_list + attribute. */ + Dwarf_Unsigned line_offset = 0; + + /* These variables are used to decode leb128 numbers. Leb128_num + holds the decoded number, and leb128_length is its length in + bytes. */ + Dwarf_Half attrform = 0; + + /* In case there are weird bytes 'after' the line table + prologue this lets us print something. This is a gcc + compiler bug and we expect the bytes count to be 12. */ + Dwarf_Small* bogus_bytes_ptr = 0; + Dwarf_Unsigned bogus_bytes_count = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned fission_offset = 0; + unsigned line_version = 0; + + /* The Dwarf_Debug this die belongs to. */ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Line_Context line_context = 0; + int resattr = DW_DLV_ERROR; + int lres = DW_DLV_ERROR; + int res = DW_DLV_ERROR; + Dwarf_Small *line_ptr_actuals = 0; + Dwarf_Small *line_ptr_end = 0; + Dwarf_Small *section_start = 0; + + /* ***** BEGIN CODE ***** */ + + if (error != NULL) { + *error = NULL; + } + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + dbg = cu_context->cc_dbg; + + res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_line.dss_size) { + return DW_DLV_NO_ENTRY; + } + + address_size = _dwarf_get_address_size(dbg, die); + resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, + error); + if (resattr != DW_DLV_OK) { + return resattr; + } + /* The list of relevant FORMs is small. + DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset + */ + lres = dwarf_whatform(stmt_list_attr,&attrform,error); + if (lres != DW_DLV_OK) { + dwarf_dealloc_attribute(stmt_list_attr); + return lres; + } + if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 && + attrform != DW_FORM_sec_offset ) { + dwarf_dealloc_attribute(stmt_list_attr); + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); + if (lres != DW_DLV_OK) { + dwarf_dealloc_attribute(stmt_list_attr); + return lres; + } + + if (line_offset >= dbg->de_debug_line.dss_size) { + dwarf_dealloc_attribute(stmt_list_attr); + _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); + return DW_DLV_ERROR; + } + section_start = dbg->de_debug_line.dss_data; + { + Dwarf_Unsigned fission_size = 0; + int resfis = _dwarf_get_fission_addition_die(die, + DW_SECT_LINE, + &fission_offset,&fission_size,error); + if (resfis != DW_DLV_OK) { + dwarf_dealloc_attribute(stmt_list_attr); + return resfis; + } + } + + orig_line_ptr = section_start + line_offset + fission_offset; + line_ptr = orig_line_ptr; + dwarf_dealloc_attribute(stmt_list_attr); + + /* If die has DW_AT_comp_dir attribute, get the string + that names the compilation directory. */ + resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *cdir = 0; + + cres = dwarf_formstring(comp_dir_attr, &cdir, error); + if (cres == DW_DLV_ERROR) { + dwarf_dealloc_attribute(comp_dir_attr); + comp_dir_attr = 0; + return cres; + } + if (cres == DW_DLV_OK) { + comp_dir = (Dwarf_Small *) cdir; + } + } + if (comp_dir_attr) { + dwarf_dealloc_attribute(comp_dir_attr); + comp_dir_attr = 0; + } + line_context = (Dwarf_Line_Context) + _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); + if (line_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + { + Dwarf_Small *newlinep = 0; + int dres = _dwarf_read_line_table_header(dbg, + cu_context, + section_start, + line_ptr, + dbg->de_debug_line.dss_size, + &newlinep, + line_context, + &bogus_bytes_ptr, + &bogus_bytes_count, + error, + err_count_out); + if (dres == DW_DLV_ERROR) { + dwarf_srclines_dealloc_b(line_context); + return dres; + } + if (dres == DW_DLV_NO_ENTRY) { + dwarf_srclines_dealloc_b(line_context); + return dres; + } + line_ptr_end = line_context->lc_line_ptr_end; + line_ptr = newlinep; + if (line_context->lc_actuals_table_offset > 0) { + line_ptr_actuals = line_context->lc_line_prologue_start + + line_context->lc_actuals_table_offset; + } + } + line_version = line_context->lc_version_number; + line_context->lc_compilation_directory = comp_dir; + if (only_line_header) { + /* Just checking for header errors, nothing more here.*/ + dwarf_srclines_dealloc_b(line_context); + return DW_DLV_OK; + } + do_line_print_now(dbg,line_version,comp_dir,line_context); + print_include_directory_details(dbg,line_version,line_context); + print_file_entry_details(dbg,line_version,line_context); + print_experimental_counts(dbg, line_version,line_context); + res = print_actuals_and_locals(dbg, line_context, + bogus_bytes_count,bogus_bytes_ptr, + orig_line_ptr, + line_ptr, + section_start, + line_ptr_actuals, + line_ptr_end, + address_size, + err_count_out, + error); + if (res != DW_DLV_OK) { + return res; + } + return DW_DLV_OK; +} + +static void +do_line_print_now(Dwarf_Debug dbg, + int line_version, + Dwarf_Small *comp_dir, + Dwarf_Line_Context line_context) +{ + dwarfstring m7; + Dwarf_Unsigned i = 0; + + dwarfstring_constructor(&m7); + dwarfstring_append_printf_i(&m7, + "total line info length %ld bytes,", + line_context->lc_total_length); + + dwarfstring_append_printf_u(&m7, + " line offset 0x%" DW_PR_XZEROS DW_PR_DUx, + line_context->lc_section_offset); + + dwarfstring_append_printf_u(&m7, + " %" DW_PR_DUu "\n", + line_context->lc_section_offset); + + if (line_version <= DW_LINE_VERSION5) { + dwarfstring_append_printf_i(&m7, + " line table version %d\n", + (int) line_context->lc_version_number); + } else { + dwarfstring_append_printf_u(&m7, + " line table version 0x%x\n", + (int) line_context->lc_version_number); + } + if (line_version == DW_LINE_VERSION5) { + dwarfstring_append_printf_i(&m7, + " address size %d\n", + line_context->lc_address_size); + dwarfstring_append_printf_i(&m7, + " segment selector size %d\n", + line_context->lc_segment_selector_size); + } + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + dwarfstring_append_printf_i(&m7, + " line table length field length %d\n", + line_context->lc_length_field_length); + dwarfstring_append_printf_i(&m7, + " prologue length %d\n", + line_context->lc_prologue_length); + dwarfstring_append_printf_s(&m7, + " compilation_directory %s\n", + comp_dir ? ((char *) comp_dir) : ""); + + dwarfstring_append_printf_i(&m7, + " min instruction length %d\n", + line_context->lc_minimum_instruction_length); + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + if (line_version == DW_LINE_VERSION5 || + line_version == DW_LINE_VERSION4 || + line_version == EXPERIMENTAL_LINE_TABLES_VERSION) { + dwarfstring_append_printf_u(&m7, + " maximum ops per instruction %u\n", + line_context->lc_maximum_ops_per_instruction); + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + } + if (line_version == EXPERIMENTAL_LINE_TABLES_VERSION) { + dwarfstring_append_printf_u(&m7, " actuals table offset " + "0x%" DW_PR_XZEROS DW_PR_DUx "\n", + line_context->lc_actuals_table_offset); + dwarfstring_append_printf_u(&m7," logicals table offset " + "0x%" DW_PR_XZEROS DW_PR_DUx "\n", + line_context->lc_logicals_table_offset); + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + } + dwarfstring_append_printf_i(&m7, + " default is stmt %d\n", + (int)line_context->lc_default_is_stmt); + dwarfstring_append_printf_i(&m7, + " line base %d\n", + (int)line_context->lc_line_base); + dwarfstring_append_printf_i(&m7, + " line_range %d\n", + (int)line_context->lc_line_range); + dwarfstring_append_printf_i(&m7, + " opcode base %d\n", + (int)line_context->lc_opcode_base); + dwarfstring_append_printf_i(&m7, + " standard opcode count %d\n", + (int)line_context->lc_std_op_count); + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + + for (i = 1; i < line_context->lc_opcode_base; i++) { + dwarfstring_append_printf_i(&m7, + " opcode[%2d] length", (int) i); + dwarfstring_append_printf_i(&m7, + " %d\n", + (int) line_context->lc_opcode_length_table[i - 1]); + _dwarf_printf(dbg,dwarfstring_string(&m7)); + dwarfstring_reset(&m7); + } + dwarfstring_destructor(&m7); +} + +static void +print_experimental_counts(Dwarf_Debug dbg, int line_version, + Dwarf_Line_Context line_context) +{ + if (line_version == EXPERIMENTAL_LINE_TABLES_VERSION) { + print_experimental_subprograms_list(dbg,line_context); + } +} + +static int +print_actuals_and_locals(Dwarf_Debug dbg, + Dwarf_Line_Context line_context, + Dwarf_Unsigned bogus_bytes_count, + Dwarf_Small *bogus_bytes_ptr, + Dwarf_Small *orig_line_ptr, + Dwarf_Small *line_ptr, + Dwarf_Small *section_start, + Dwarf_Small *line_ptr_actuals, + Dwarf_Small *line_ptr_end, + Dwarf_Half address_size, + int * err_count_out, + Dwarf_Error *error) +{ + int res = 0; + dwarfstring m8; + Dwarf_Unsigned offset = 0; + + dwarfstring_constructor(&m8); + if (bogus_bytes_count > 0) { + Dwarf_Unsigned wcount = bogus_bytes_count; + Dwarf_Unsigned boffset = bogus_bytes_ptr - section_start; + + dwarfstring_append_printf_u(&m8, + "*** DWARF CHECK: the line table prologue header_length " + " is %" DW_PR_DUu " too high, we pretend it is smaller.", + wcount); + dwarfstring_append_printf_u(&m8, + "Section offset: 0x%" + DW_PR_XZEROS DW_PR_DUx, + boffset); + dwarfstring_append_printf_u(&m8, + " (%" DW_PR_DUu ") ***\n", + boffset); + *err_count_out += 1; + } + offset = line_ptr - section_start; + dwarfstring_append_printf_u(&m8, + " statement prog offset in section: 0x%" + DW_PR_XZEROS DW_PR_DUx, + offset); + dwarfstring_append_printf_u(&m8, + " (%" DW_PR_DUu ")\n", + offset); + _dwarf_printf(dbg,dwarfstring_string(&m8)); + dwarfstring_reset(&m8); + + { + Dwarf_Bool doaddrs = false; + Dwarf_Bool dolines = true; + + if (!line_ptr_actuals) { + /* Normal single level line table. */ + + Dwarf_Bool is_single_table = true; + Dwarf_Bool is_actuals_table = false; + print_line_header(dbg, is_single_table, is_actuals_table); + res = read_line_table_program(dbg, + line_ptr, line_ptr_end, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + is_single_table, + is_actuals_table, + error, + err_count_out); + if (res != DW_DLV_OK) { + dwarfstring_destructor(&m8); + dwarf_srclines_dealloc_b(line_context); + return res; + } + } else { + Dwarf_Bool is_single_table = false; + Dwarf_Bool is_actuals_table = false; + if (line_context->lc_version_number != + EXPERIMENTAL_LINE_TABLES_VERSION) { + dwarf_srclines_dealloc_b(line_context); + dwarfstring_destructor(&m8); + _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); + return DW_DLV_ERROR; + } + /* Read Logicals */ + print_line_header(dbg, is_single_table, is_actuals_table); + res = read_line_table_program(dbg, + line_ptr, line_ptr_actuals, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + is_single_table, + is_actuals_table, + error,err_count_out); + if (res != DW_DLV_OK) { + dwarfstring_destructor(&m8); + dwarf_srclines_dealloc_b(line_context); + return res; + } + if (line_context->lc_actuals_table_offset > 0) { + is_actuals_table = true; + /* Read Actuals */ + + print_line_header(dbg, is_single_table, + is_actuals_table); + res = read_line_table_program(dbg, + line_ptr_actuals, line_ptr_end, orig_line_ptr, + section_start, + line_context, + address_size, doaddrs, dolines, + is_single_table, + is_actuals_table, + error, + err_count_out); + if (res != DW_DLV_OK) { + dwarfstring_destructor(&m8); + dwarf_srclines_dealloc_b(line_context); + return res; + } + } + } + } + dwarfstring_destructor(&m8); + dwarf_srclines_dealloc_b(line_context); + return DW_DLV_OK; +} + +/* This is support for dwarfdump: making it possible + for clients wanting line detail info on stdout + to get that detail without including internal libdwarf + header information. + Caller passes in compilation unit DIE. + + These *print_lines() functions print two-level tables in full + even when the user is not asking for both (ie, when + the caller asked for dwarf_srclines(). + It was an accident, but after a short reflection + this seems like a good idea for -vvv. */ +int +dwarf_print_lines(Dwarf_Die die, + Dwarf_Error * error, + int *error_count) +{ + int only_line_header = 0; + int res = _dwarf_internal_printlines(die, + error_count, + only_line_header,error); + return res; +} + +/* The check is in case we are not printing full line data, + this gets some of the issues noted with .debug_line, + but not all. Call dwarf_print_lines() to get all issues. + Intended for apps like dwarfdump. + dwarf_check_lineheader_b() new 14 April 2020. +*/ +int +dwarf_check_lineheader_b(Dwarf_Die die, int *err_count_out, + Dwarf_Error *error) +{ + int res = 0; + + int only_line_header = 1; + res = _dwarf_internal_printlines(die,err_count_out, + only_line_header,error); + return res; +} diff --git a/src/lib/libdwarf/dwarf_query.c b/src/lib/libdwarf/dwarf_query.c new file mode 100644 index 0000000..cbf2d09 --- /dev/null +++ b/src/lib/libdwarf/dwarf_query.c @@ -0,0 +1,2129 @@ +/* + Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2022 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + Portions Copyright 2020 Google All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* NULL size_t */ +#include /* debugging printf */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_die_deliv.h" +#include "dwarf_string.h" + +static int _dwarf_die_attr_unsigned_constant(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Unsigned *return_val, + Dwarf_Error *error); + +int dwarf_get_offset_size(Dwarf_Debug dbg, + Dwarf_Half * offset_size, + Dwarf_Error * error) +{ + if (dbg == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + *offset_size = dbg->de_length_size; + return DW_DLV_OK; +} + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s ",msg); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* This is normally reliable. +But not always. +If different compilation +units have different address sizes +this may not give the correct value in all contexts. +If the Elf offset size != address_size +(for example if address_size = 4 but recorded in elf64 object) +this may not give the correct value in all contexts. +*/ +int +dwarf_get_address_size(Dwarf_Debug dbg, + Dwarf_Half *ret_addr_size, Dwarf_Error *error) +{ + Dwarf_Half address_size = 0; + + if (dbg == 0) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + address_size = dbg->de_pointer_size; + *ret_addr_size = address_size; + return DW_DLV_OK; +} + +/* This will be correct in all contexts where the + CU context of a DIE is known. +*/ +int +dwarf_get_die_address_size(Dwarf_Die die, + Dwarf_Half * ret_addr_size, Dwarf_Error *error) +{ + Dwarf_Half address_size = 0; + CHECK_DIE(die, DW_DLV_ERROR); + address_size = die->di_cu_context->cc_address_size; + *ret_addr_size = address_size; + return DW_DLV_OK; +} + +int +dwarf_dieoffset(Dwarf_Die die, + Dwarf_Off *ret_offset, Dwarf_Error *error) +{ + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + *ret_offset = (die->di_debug_ptr - dataptr); + return DW_DLV_OK; +} + +/* This function returns the offset of + the die relative to the start of its + compilation-unit rather than .debug_info. + Returns DW_DLV_ERROR on error. */ +int +dwarf_die_CU_offset(Dwarf_Die die, + Dwarf_Off *cu_off, Dwarf_Error *error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + *cu_off = (die->di_debug_ptr - dataptr - + cu_context->cc_debug_offset); + return DW_DLV_OK; +} + +/* A common function to get both offsets (local and global) + It's unusual in that it sets both return offsets + to zero on entry. Normally we only set any + output-args (through their pointers) in case + of success. */ +int +dwarf_die_offsets(Dwarf_Die die, + Dwarf_Off *off, + Dwarf_Off *cu_off, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Off lcuoff = 0; + Dwarf_Off loff = 0; + + res = dwarf_dieoffset(die,&loff,error); + if (res == DW_DLV_OK) { + res = dwarf_die_CU_offset(die,&lcuoff,error); + } + if (res == DW_DLV_OK) { + /* Waiting till both succeed before + returning any value at all to retain + normal libdwarf call semantics. */ + *off = loff; + *cu_off = lcuoff; + } else { + *off = 0; + *cu_off = 0; + } + return res; +} + +/* This function returns the global offset + (meaning the section offset) and length of + the CU that this die is a part of. + Used for correctness checking by dwarfdump. */ +int +dwarf_die_CU_offset_range(Dwarf_Die die, + Dwarf_Off *cu_off, + Dwarf_Off *cu_length, + Dwarf_Error *error) +{ + Dwarf_CU_Context cu_context = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cu_context = die->di_cu_context; + + *cu_off = cu_context->cc_debug_offset; + *cu_length = cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size; + return DW_DLV_OK; +} + +int +dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error) +{ + CHECK_DIE(die, DW_DLV_ERROR); + *tag = die->di_abbrev_list->abl_tag; + return DW_DLV_OK; +} + +static void +free_dwarf_offsets_chain(Dwarf_Debug dbg, Dwarf_Chain_2 head_chain) +{ + Dwarf_Chain_2 cur = head_chain; + Dwarf_Chain_2 next = 0; + + for ( ; cur ; cur = next ) { + next = cur->ch_next; + dwarf_dealloc(dbg, cur, DW_DLA_CHAIN_2); + } +} + +/* Returns the children offsets for the given offset */ +int +dwarf_offset_list(Dwarf_Debug dbg, + Dwarf_Off offset, Dwarf_Bool is_info, + Dwarf_Off **offbuf, Dwarf_Unsigned *offcnt, + Dwarf_Error *error) +{ + Dwarf_Die die = 0; + Dwarf_Die child = 0; + Dwarf_Die sib_die = 0; + Dwarf_Die cur_die = 0; + int res = 0; + Dwarf_Unsigned off_count = 0; + Dwarf_Unsigned i = 0; + Dwarf_Off *ret_offsets = 0; + Dwarf_Chain_2 curr_chain = 0; + Dwarf_Chain_2 head_chain = 0; + Dwarf_Chain_2 *plast = &head_chain; + + *offbuf = NULL; + *offcnt = 0; + + res = dwarf_offdie_b(dbg,offset,is_info,&die,error); + if (DW_DLV_OK != res) { + return res; + } + + res = dwarf_child(die,&child,error); + if (DW_DLV_ERROR == res || DW_DLV_NO_ENTRY == res) { + return res; + } + dwarf_dealloc_die(die); + cur_die = child; + child = 0; + for (;;) { + if (DW_DLV_OK == res) { + int dres = 0; + Dwarf_Off cur_off = 0; + + dres = dwarf_dieoffset(cur_die,&cur_off,error); + if (dres == DW_DLV_OK) { + /* Normal. use cur_off. */ + } else if (dres == DW_DLV_ERROR) { + free_dwarf_offsets_chain(dbg,head_chain); + dwarf_dealloc_die(cur_die); + return DW_DLV_ERROR; + } else { /* DW_DLV_NO_ENTRY */ + /* Impossible, dwarf_dieoffset never returns this */ + } + /* Record offset in current entry chain */ + curr_chain = (Dwarf_Chain_2)_dwarf_get_alloc( + dbg,DW_DLA_CHAIN_2,1); + if (curr_chain == NULL) { + free_dwarf_offsets_chain(dbg,head_chain); + dwarf_dealloc_die(cur_die); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + /* Put current offset on singly_linked list. */ + curr_chain->ch_item = cur_off; + ++off_count; + (*plast) = curr_chain; + plast = &(curr_chain->ch_next); + } + /* Move to next sibling next sibling */ + sib_die = 0; + res = dwarf_siblingof_b(dbg,cur_die,is_info,&sib_die,error); + if (cur_die != die) { + dwarf_dealloc(dbg,cur_die,DW_DLA_DIE); + } + if (DW_DLV_ERROR == res) { + free_dwarf_offsets_chain(dbg,head_chain); + return res; + } + if (DW_DLV_NO_ENTRY == res) { + /* Done at this level. */ + break; + } + /* res == DW_DLV_OK */ + cur_die = sib_die; + } + + /* Points to contiguous block of Dwarf_Off's. */ + ret_offsets = (Dwarf_Off *) _dwarf_get_alloc(dbg, + DW_DLA_UARRAY, off_count); + if (ret_offsets == NULL) { + free_dwarf_offsets_chain(dbg,head_chain); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + + /* Store offsets in contiguous block, + and deallocate the chain. */ + curr_chain = head_chain; + for (i = 0; i < off_count; i++) { + Dwarf_Chain_2 prev =0; + + ret_offsets[i] = curr_chain->ch_item; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN_2); + } + *offbuf = ret_offsets; + *offcnt = off_count; + return DW_DLV_OK; +} + +static void +empty_local_attrlist(Dwarf_Debug dbg, + Dwarf_Attribute attr) +{ + Dwarf_Attribute cur = 0; + Dwarf_Attribute next = 0; + + for (cur = attr; cur ; cur = next) { + next = cur->ar_next; + dwarf_dealloc(dbg,cur,DW_DLA_ATTR); + } +} + +int +dwarf_attrlist(Dwarf_Die die, + Dwarf_Attribute **attrbuf, + Dwarf_Signed *attrcnt, Dwarf_Error *error) +{ + Dwarf_Unsigned attr_count = 0; + Dwarf_Unsigned attr = 0; + Dwarf_Unsigned attr_form = 0; + Dwarf_Unsigned i = 0; + Dwarf_Abbrev_List abbrev_list = 0; + Dwarf_Attribute head_attr = NULL; + Dwarf_Attribute curr_attr = NULL; + Dwarf_Attribute *last_attr = &head_attr; + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Byte_Ptr die_info_end = 0; + int lres = 0; + int bres = 0; + Dwarf_CU_Context context = 0; + Dwarf_Unsigned highest_code = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + die_info_end = + _dwarf_calculate_info_section_end_ptr(context); + lres = _dwarf_get_abbrev_for_code(context, + die->di_abbrev_list->abl_code, + &abbrev_list, + &highest_code,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ABBREV_MISSING " + "There is no abbrev present for code %u " + "in this compilation unit. ", + die->di_abbrev_list->abl_code); + dwarfstring_append_printf_u(&m, + "The highest known code " + "in any compilation unit is %u .", + highest_code); + _dwarf_error_string(dbg, error, + DW_DLE_ABBREV_MISSING, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + info_ptr = die->di_debug_ptr; + { + /* SKIP_LEB128 */ + Dwarf_Unsigned ignore_this = 0; + Dwarf_Unsigned len = 0; + + lres = dwarf_decode_leb128((char *)info_ptr, + &len,&ignore_this,(char *)die_info_end); + if (lres == DW_DLV_ERROR) { + /* Stepped off the end SKIPping the leb */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DIE_BAD: In building an attrlist " + "we run off the end of the DIE while skipping " + " the DIE tag, seeing the leb length as 0x%u ", + len); + _dwarf_error_string(dbg, error, DW_DLE_DIE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + info_ptr += len; + } + + if (!abbrev_list->abl_attr) { + Dwarf_Byte_Ptr abbrev_ptr = abbrev_list->abl_abbrev_ptr; + Dwarf_Byte_Ptr abbrev_end = + _dwarf_calculate_abbrev_section_end_ptr(context); + /* FIXME */ + bres = _dwarf_fill_in_attr_form_abtable(context, + abbrev_ptr, abbrev_end, abbrev_list, + error); + if (bres != DW_DLV_OK) { + return bres; + } + } + /* ASSERT list->abl_addr and list->abl_form + are non-null and if list->abl_implicit_const_count > 0 + list->abl_implicit_const is non-null. */ + + for ( i = 0; i abl_abbrev_count; ++i) { + Dwarf_Signed implicit_const = 0; + Dwarf_Half newattr_form = 0; + int ires = 0; + + attr = abbrev_list->abl_attr[i]; + attr_form = abbrev_list->abl_form[i]; + if (attr > DW_AT_hi_user) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error(dbg, error,DW_DLE_ATTR_CORRUPT); + return DW_DLV_ERROR; + } + if (attr_form == DW_FORM_implicit_const) { + implicit_const = abbrev_list->abl_implicit_const[i]; + } + if (!_dwarf_valid_form_we_know(attr_form,attr)) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error(dbg, error, DW_DLE_UNKNOWN_FORM); + return DW_DLV_ERROR; + } + newattr_form = attr_form; + if (attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6 = 0; + + if (_dwarf_reference_outside_section(die, + (Dwarf_Small*) info_ptr, + ((Dwarf_Small*) info_ptr )+1)) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + " Reading Attriutes: " + "For DW_FORM_indirect there is" + " no room for the form. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + ires = _dwarf_leb128_uword_wrapper(dbg, + &info_ptr,die_info_end,&utmp6,error); + if (ires != DW_DLV_OK) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + "Reading target of a DW_FORM_indirect " + "from an abbreviation failed. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + attr_form = (Dwarf_Half) utmp6; + if (attr_form == DW_FORM_implicit_const) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + " Reading Attriutes: an indirect form " + "leads to a DW_FORM_implicit_const " + "which is not handled. Corrupt Dwarf"); + return DW_DLV_ERROR; + } + if (!_dwarf_valid_form_we_know(attr_form,attr)) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_UNKNOWN_FORM " + " form indirect leads to form" + " of 0x%x which is unknown", + attr_form); + _dwarf_error_string(dbg, error, + DW_DLE_UNKNOWN_FORM, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + empty_local_attrlist(dbg,head_attr); + return DW_DLV_ERROR; + } + newattr_form = attr_form; + } + + if (attr) { + Dwarf_Attribute new_attr = 0; + + new_attr = (Dwarf_Attribute) + _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1); + if (!new_attr) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: attempting to allocate" + " a Dwarf_Attribute record"); + return DW_DLV_ERROR; + } + new_attr->ar_attribute = attr; + new_attr->ar_attribute_form_direct = attr_form; + new_attr->ar_attribute_form = newattr_form; + /* Here the final address must be *inside* the + section, as we will read from there, and read + at least one byte, we think. + We do not want info_ptr to point past end so + we add 1 to the end-pointer. */ + new_attr->ar_cu_context = die->di_cu_context; + new_attr->ar_debug_ptr = info_ptr; + new_attr->ar_die = die; + new_attr->ar_dbg = dbg; + if ( attr_form != DW_FORM_implicit_const && + _dwarf_reference_outside_section(die, + (Dwarf_Small*) info_ptr, + ((Dwarf_Small*) info_ptr )+1)) { + dwarf_dealloc_attribute(new_attr); + empty_local_attrlist(dbg,head_attr); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_OUTSIDE_SECTION, + "DW_DLE_ATTR_OUTSIDE_SECTION: " + " Reading Attriutes: " + "We have run off the end of the section. " + "Corrupt Dwarf"); + return DW_DLV_ERROR; + } + if (attr_form == DW_FORM_implicit_const) { + /* The value is here, not in a DIE. + Do not increment info_ptr */ + new_attr->ar_implicit_const = implicit_const; + } else { + Dwarf_Unsigned sov = 0; + int vres = 0; + + vres = _dwarf_get_size_of_val(dbg, + attr_form, + die->di_cu_context->cc_version_stamp, + die->di_cu_context->cc_address_size, + info_ptr, + die->di_cu_context->cc_length_size, + &sov, + die_info_end, + error); + if (vres!= DW_DLV_OK) { + dwarf_dealloc_attribute(new_attr); + empty_local_attrlist(dbg,head_attr); + return vres; + } + info_ptr += sov; + } + /* Add to single linked list */ + *last_attr = new_attr; + last_attr = &new_attr->ar_next; + new_attr = 0; + attr_count++; + } + } + if (!attr_count) { + *attrbuf = NULL; + *attrcnt = 0; + return DW_DLV_NO_ENTRY; + } + { + Dwarf_Attribute *attr_ptr = 0; + + attr_ptr = (Dwarf_Attribute *) + _dwarf_get_alloc(dbg, DW_DLA_LIST, attr_count); + if (attr_ptr == NULL) { + empty_local_attrlist(dbg,head_attr); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + curr_attr = head_attr; + for (i = 0; i < attr_count; i++) { + *(attr_ptr + i) = curr_attr; + curr_attr = curr_attr->ar_next; + } + *attrbuf = attr_ptr; + *attrcnt = attr_count; + } + return DW_DLV_OK; +} + +/* + This function takes a die, and an attr, and returns + a pointer to the start of the value of that attr in + the given die in the .debug_info section. The form + is returned in *attr_form. + + If the attr_form is DW_FORM_implicit_const + (known signed, so most callers) + that is fine, but in that case we do not + need to actually set the *ptr_to_value. + + Returns NULL on error, or if attr is not found. + However, *attr_form is 0 on error, and positive + otherwise. +*/ +static int +_dwarf_get_value_ptr(Dwarf_Die die, + Dwarf_Half attrnum_in, + Dwarf_Half *attr_form, + Dwarf_Byte_Ptr *ptr_to_value, + Dwarf_Signed *implicit_const_out, + Dwarf_Error *error) +{ + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr abbrev_end = 0; + Dwarf_Abbrev_List abbrev_list; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_CU_Context context = die->di_cu_context; + Dwarf_Byte_Ptr die_info_end = 0; + Dwarf_Debug dbg = 0; + int lres = 0; + Dwarf_Unsigned i = 0; + Dwarf_Unsigned highest_code = 0; + + if (!context) { + _dwarf_error(NULL,error,DW_DLE_DIE_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + dbg = context->cc_dbg; + die_info_end = + _dwarf_calculate_info_section_end_ptr(context); + + lres = _dwarf_get_abbrev_for_code(context, + die->di_abbrev_list->abl_code, + &abbrev_list,&highest_code,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (lres == DW_DLV_NO_ENTRY) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_CU_DIE_NO_ABBREV_LIST " + "There is no abbrev present for code %u " + "in this compilation unit. ", + die->di_abbrev_list->abl_code); + dwarfstring_append_printf_u(&m, + "The highest known code " + "in any compilation unit is %u.", + highest_code); + _dwarf_error_string(dbg, error, + DW_DLE_CU_DIE_NO_ABBREV_LIST, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + abbrev_ptr = abbrev_list->abl_abbrev_ptr; + abbrev_end = _dwarf_calculate_abbrev_section_end_ptr(context); + info_ptr = die->di_debug_ptr; + /* This ensures and checks die_info_end >= info_ptr */ + { + /* SKIP_LEB128 */ + Dwarf_Unsigned ignore_this = 0; + Dwarf_Unsigned len = 0; + + lres = dwarf_decode_leb128((char *)info_ptr, + &len,&ignore_this,(char *)die_info_end); + if (lres == DW_DLV_ERROR) { + /* Stepped off the end SKIPping the leb */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DIE_BAD: In building an attrlist " + "we run off the end of the DIE while skipping " + " the DIE tag, seeing the leb length as 0x%u ", + len); + _dwarf_error_string(dbg, error, DW_DLE_DIE_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + info_ptr += len; + } + if (!abbrev_list->abl_attr) { + int bres = 0; + /* FIXME */ + bres = _dwarf_fill_in_attr_form_abtable(context, + abbrev_ptr, abbrev_end, abbrev_list, + error); + if (bres != DW_DLV_OK) { + return bres; + } + } + + for (i = 0; i < abbrev_list->abl_abbrev_count; ++i) { + Dwarf_Unsigned curr_attr_form = 0; + Dwarf_Unsigned curr_attr = 0; + Dwarf_Unsigned value_size=0; + Dwarf_Signed implicit_const = 0; + int res = 0; + + curr_attr = abbrev_list->abl_attr[i]; + curr_attr_form = abbrev_list->abl_form[i]; + if (curr_attr_form == DW_FORM_indirect) { + Dwarf_Unsigned utmp6; + + /* DECODE_LEB128_UWORD updates info_ptr */ + DECODE_LEB128_UWORD_CK(info_ptr, utmp6,dbg, + error,die_info_end); + curr_attr_form = (Dwarf_Half) utmp6; + } + if (curr_attr_form == DW_FORM_indirect) { + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD: " + "A DW_FORM_indirect in an abbreviation " + " indirects to another " + "DW_FORM_indirect, which is inappropriate."); + return DW_DLV_ERROR; + } + if (curr_attr_form == DW_FORM_implicit_const) { + if (!abbrev_list->abl_implicit_const) { + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_BAD, + "DW_DLE_ATTR_FORM_BAD: " + "A DW_FORM_implicit_const in an abbreviation " + "has no implicit const value. Corrupt dwarf."); + return DW_DLV_ERROR; + } + implicit_const = abbrev_list->abl_implicit_const[i]; + } + if (curr_attr == attrnum_in) { + *attr_form = curr_attr_form; + if (implicit_const_out) { + *implicit_const_out = implicit_const; + } + *ptr_to_value = info_ptr; + return DW_DLV_OK; + } + res = _dwarf_get_size_of_val(dbg, + curr_attr_form, + die->di_cu_context->cc_version_stamp, + die->di_cu_context->cc_address_size, + info_ptr, + die->di_cu_context->cc_length_size, + &value_size, + die_info_end, + error); + if (res != DW_DLV_OK) { + return res; + } + { + Dwarf_Unsigned len = 0; + + /* ptrdiff_t is generated but not named */ + len = (die_info_end >= info_ptr)? + (die_info_end - info_ptr):0; + if (value_size > len) { + /* Something badly wrong. We point past end + of debug_info or debug_types or a + section is unreasonably sized or we are + pointing to two different sections? */ + _dwarf_error(dbg,error,DW_DLE_DIE_ABBREV_BAD); + return DW_DLV_ERROR; + } + } + info_ptr+= value_size; + } + return DW_DLV_NO_ENTRY; +} + +int +dwarf_die_text(Dwarf_Die die, + Dwarf_Half attrnum, + char **ret_name, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + int res = DW_DLV_ERROR; + Dwarf_Attribute attr = 0; + Dwarf_Error lerr = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + + res = dwarf_attr(die,attrnum,&attr,&lerr); + dbg = die->di_cu_context->cc_dbg; + if (res == DW_DLV_ERROR) { + return DW_DLV_NO_ENTRY; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + res = dwarf_formstring(attr,ret_name,error); + dwarf_dealloc(dbg,attr, DW_DLA_ATTR); + attr = 0; + return res; +} + +int +dwarf_diename(Dwarf_Die die, + char **ret_name, + Dwarf_Error *error) +{ + return dwarf_die_text(die,DW_AT_name,ret_name,error); +} + +int +dwarf_hasattr(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Bool *return_bool, Dwarf_Error *error) +{ + Dwarf_Half attr_form = 0; + Dwarf_Byte_Ptr info_ptr = 0; + int res = 0; + Dwarf_Signed implicit_const; + + CHECK_DIE(die, DW_DLV_ERROR); + + res = _dwarf_get_value_ptr(die, attr, &attr_form,&info_ptr, + &implicit_const,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + *return_bool = false; + return DW_DLV_OK; + } + *return_bool = (true); + return DW_DLV_OK; +} + +int +dwarf_attr(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Attribute *ret_attr, Dwarf_Error *error) +{ + Dwarf_Half attr_form = 0; + Dwarf_Attribute attrib = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Debug dbg = 0; + int res = 0; + int lres = 0; + Dwarf_Signed implicit_const = 0; + Dwarf_Abbrev_List abbrev_list = 0; + Dwarf_Unsigned highest_code = 0; + Dwarf_CU_Context context = 0; + + context = die->di_cu_context; + dbg = context->cc_dbg; + + CHECK_DIE(die, DW_DLV_ERROR); + lres = _dwarf_get_abbrev_for_code(die->di_cu_context, + die->di_abbrev_list->abl_code, + &abbrev_list, + &highest_code,error); + if (lres == DW_DLV_ERROR) { + return lres; + } + if (!abbrev_list->abl_attr) { + Dwarf_Byte_Ptr abbrev_ptr = abbrev_list->abl_abbrev_ptr; + Dwarf_Byte_Ptr abbrev_end = + _dwarf_calculate_abbrev_section_end_ptr(context); + int bres = 0; + + bres = _dwarf_fill_in_attr_form_abtable( + die->di_cu_context, + abbrev_ptr, abbrev_end, abbrev_list, + error); + if (bres != DW_DLV_OK) { + return bres; + } + } + res = _dwarf_get_value_ptr(die, attr, &attr_form,&info_ptr, + &implicit_const,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + + attrib = (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1); + if (!attrib) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL allocating a single Dwarf_Attribute" + " in function dwarf_attr()."); + return DW_DLV_ERROR; + } + + attrib->ar_attribute = attr; + attrib->ar_attribute_form = attr_form; + attrib->ar_attribute_form_direct = attr_form; + attrib->ar_cu_context = die->di_cu_context; + + /* Only nonzero if DW_FORM_implicit_const */ + attrib->ar_implicit_const = implicit_const; + /* Only nonnull if not DW_FORM_implicit_const */ + attrib->ar_debug_ptr = info_ptr; + attrib->ar_die = die; + attrib->ar_dbg = dbg; + *ret_attr = attrib; + return DW_DLV_OK; +} + +/* A DWP (.dwp) package object never contains .debug_addr, + only a normal .o or executable object. + Error returned here is on dbg, not tieddbg. + This looks for DW_AT_addr_base and if present + adds it in appropriately. + You should use _dwarf_look_in_local_and_tied_by_index() + instead of this, in general. + */ +static int +_dwarf_extract_address_from_debug_addr(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned index_to_addr, + Dwarf_Addr *addr_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned address_base = 0; + Dwarf_Unsigned addrindex = index_to_addr; + Dwarf_Unsigned addr_offset = 0; + Dwarf_Unsigned ret_addr = 0; + int res = 0; + Dwarf_Byte_Ptr sectionstart = 0; + Dwarf_Byte_Ptr sectionend = 0; + Dwarf_Unsigned sectionsize = 0; + + address_base = context->cc_addr_base; + res = _dwarf_load_section(dbg, &dbg->de_debug_addr,error); + if (res != DW_DLV_OK) { + /* Ignore the inner error, report something meaningful */ + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc(dbg,*error, DW_DLA_ERROR); + *error = 0; + } + _dwarf_error(dbg,error, + DW_DLE_MISSING_NEEDED_DEBUG_ADDR_SECTION); + return DW_DLV_ERROR; + } + /* DW_FORM_addrx has a base value from the CU die: + DW_AT_addr_base. DW_OP_addrx and DW_OP_constx + rely on DW_AT_addr_base too. */ + /* DW_FORM_GNU_addr_index relies on DW_AT_GNU_addr_base + which is in the CU die. */ + + sectionstart = dbg->de_debug_addr.dss_data; + addr_offset = address_base + + (addrindex * context->cc_address_size); + /* The offsets table is a series of address-size entries + but with a base. */ + sectionsize = dbg->de_debug_addr.dss_size; + sectionend = sectionstart + sectionsize; + /* At this point we have a local .debug_addr table + Might get here on dbg or tied-dbg. Check either way + ASSERT: cc_address_size is sensible (small) */ + if (addrindex >= sectionsize || + (addrindex*context->cc_address_size) >= sectionsize || + addr_offset > sectionsize || + addr_offset > (sectionsize - context->cc_address_size)) { + dwarfstring m; + + /* Was DW_DLE_ATTR_FORM_SIZE_BAD. Regression issue */ + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_ATTR_FORM_OFFSET_BAD: " + "Extracting an address from .debug_addr fails" + "as the offset is 0x%x ", + addr_offset); + dwarfstring_append_printf_u(&m, + "but the object section is just 0x%x " + "bytes long so there not enough space" + " for an address.", + sectionsize); + _dwarf_error_string(dbg, error, + DW_DLE_ATTR_FORM_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,ret_addr,Dwarf_Addr, + sectionstart + addr_offset, + context->cc_address_size, + error,sectionend); + *addr_out = ret_addr; + return DW_DLV_OK; +} + +int +_dwarf_look_in_local_and_tied_by_index( + Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned index, + Dwarf_Addr *return_addr, + Dwarf_Error *error) +{ + int res2 = 0; + + res2 = _dwarf_extract_address_from_debug_addr(dbg, + context, index, return_addr, error); + if (res2 != DW_DLV_OK) { + if (res2 == DW_DLV_ERROR && + error && dwarf_errno(*error) == + DW_DLE_MISSING_NEEDED_DEBUG_ADDR_SECTION + && dbg->de_tied_data.td_tied_object) { + int res3 = 0; + + /* We do not want to leak error structs... */ + /* *error safe */ + dwarf_dealloc(dbg,*error,DW_DLA_ERROR); + *error = 0; /* *error safe */ + /* Any error is returned on dbg, + not tieddbg. */ + res3 = _dwarf_get_addr_from_tied(dbg, + context,index,return_addr,error); + return res3; + } + return res2; + } + return DW_DLV_OK; +} + +/* The DIE here can be any DIE in the relevant CU. + index is an index into .debug_addr */ +int +dwarf_debug_addr_index_to_addr(Dwarf_Die die, + Dwarf_Unsigned index, + Dwarf_Addr *return_addr, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context context = 0; + int res = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + + /* error is returned on dbg, not tieddbg. */ + res = _dwarf_look_in_local_and_tied_by_index(dbg, + context, + index, + return_addr, + error); + return res; +} +/* ASSERT: + attr_form == DW_FORM_GNU_addr_index || + attr_form == DW_FORM_addrx +*/ +int +_dwarf_look_in_local_and_tied(Dwarf_Half attr_form, + Dwarf_CU_Context context, + Dwarf_Small *info_ptr, + Dwarf_Addr *return_addr, + Dwarf_Error *error) +{ + int res2 = 0; + Dwarf_Unsigned index_to_addr = 0; + Dwarf_Debug dbg = 0; + + /* We get the index. It might apply here + or in tied object. Checking that next. */ + dbg = context->cc_dbg; + res2 = _dwarf_get_addr_index_itself(attr_form, + info_ptr,dbg,context, &index_to_addr,error); + if (res2 != DW_DLV_OK) { + return res2; + } +#if 0 + Dwarf_Unsigned addrtabsize = 0; + addrtabsize = dbg->de_debug_addr.dss_size; + If there is no .debug_addr the error here should + not be reported as will report that + via _dwarf_look_in_local_and_tied_by_index + if (!dbg->de_tied_data.td_tied_object && + (index_to_addr > dbg->de_filesize || + index_to_addr > addrtabsize || + (index_to_addr*context->cc_address_size) > addrtabsize)) { + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_OFFSET_BAD, + "DW_DLE_ATTR_FORM_OFFSET_BAD " + "Looking for an index from an addr FORM " + "we find an impossibly large value. Corrupt DWARF"); + return DW_DLV_ERROR; + } +#endif + /* error is returned on dbg, not tieddbg. */ + res2 = _dwarf_look_in_local_and_tied_by_index( + dbg,context,index_to_addr,return_addr,error); + return res2; + +} + +int +dwarf_lowpc(Dwarf_Die die, + Dwarf_Addr *return_addr, + Dwarf_Error *error) +{ + Dwarf_Addr ret_addr = 0; + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Debug dbg = 0; + Dwarf_Half address_size = 0; + Dwarf_Half offset_size = 0; + int version = 0; + enum Dwarf_Form_Class class = DW_FORM_CLASS_UNKNOWN; + int res = 0; + Dwarf_CU_Context context = 0; + Dwarf_Small *die_info_end = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + context = die->di_cu_context; + dbg = context->cc_dbg; + address_size = context->cc_address_size; + offset_size = context->cc_length_size; + res = _dwarf_get_value_ptr(die, DW_AT_low_pc, + &attr_form,&info_ptr,0,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + version = context->cc_version_stamp; + class = dwarf_get_form_class(version,DW_AT_low_pc, + offset_size,attr_form); + if (class != DW_FORM_CLASS_ADDRESS) { + /* Not the correct form for DW_AT_low_pc */ + _dwarf_error(dbg, error, DW_DLE_LOWPC_WRONG_CLASS); + return DW_DLV_ERROR; + } + + if (attr_form == DW_FORM_GNU_addr_index || + attr_form == DW_FORM_addrx) { + /* error is returned on dbg, not tieddbg. */ + res = _dwarf_look_in_local_and_tied( + attr_form, + context, + info_ptr, + return_addr, + error); + return res; + } + die_info_end = _dwarf_calculate_info_section_end_ptr(context); + READ_UNALIGNED_CK(dbg, ret_addr, Dwarf_Addr, + info_ptr, address_size, + error,die_info_end); + + *return_addr = ret_addr; + return DW_DLV_OK; +} + +/* If 'die' contains the DW_AT_type attribute, it returns + the (global) offset referenced by the attribute through + the return_off pointer. + Returns through return_is_info which section applies. + In case of DW_DLV_NO_ENTRY or DW_DLV_ERROR it sets offset zero. */ +int +dwarf_dietype_offset(Dwarf_Die die, + Dwarf_Off *return_off, + Dwarf_Bool *return_is_info, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Off offset = 0; + Dwarf_Attribute attr = 0; + Dwarf_Bool is_info = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + /* Lets see where the input die is */ + is_info = dwarf_get_die_infotypes_flag(die); + res = dwarf_attr(die,DW_AT_type,&attr,error); + if (res == DW_DLV_OK) { + if (attr->ar_attribute_form_direct == DW_FORM_ref_sig8){ + is_info = FALSE; + } + res = dwarf_global_formref(attr,&offset,error); + if (res == DW_DLV_OK) { + *return_off = offset; + *return_is_info = is_info; + } + dwarf_dealloc_attribute(attr); + } + return res; +} + +int +_dwarf_merge_all_base_attrs_of_cu_die(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Debug tieddbg, + Dwarf_CU_Context *tiedcontext_out, + Dwarf_Error *error) +{ + Dwarf_CU_Context tiedcontext = 0; + int res = 0; + + if (!tieddbg) { + return DW_DLV_NO_ENTRY; + } + if (!context->cc_signature_present) { + return DW_DLV_NO_ENTRY; + } + res = _dwarf_search_for_signature(tieddbg, + context->cc_signature, + &tiedcontext, + error); + if ( res == DW_DLV_ERROR) { + /* Associate the error with dbg, not tieddbg */ + _dwarf_error_mv_s_to_t(tieddbg,error,dbg,error); + return res; + } + if ( res == DW_DLV_NO_ENTRY) { + return res; + } + if (!context->cc_low_pc_present) { + context->cc_low_pc_present = + tiedcontext->cc_low_pc_present; + context-> cc_low_pc= + tiedcontext->cc_low_pc; + } + if (!context->cc_addr_base_present) { + context-> cc_addr_base_present = + tiedcontext->cc_addr_base_present; + context-> cc_addr_base= + tiedcontext->cc_addr_base; + } + if (!context->cc_rnglists_base_present) { + context-> cc_rnglists_base_present = + tiedcontext->cc_rnglists_base_present; + context-> cc_rnglists_base= + tiedcontext->cc_rnglists_base; + } + if (!context->cc_loclists_base_present) { + context-> cc_loclists_base_present = + tiedcontext->cc_loclists_base_present; + context-> cc_loclists_base= + tiedcontext->cc_loclists_base; + } + if (!context->cc_str_offsets_tab_present) { + context-> cc_str_offsets_tab_present = + tiedcontext->cc_str_offsets_tab_present; + context-> cc_str_offsets_header_offset= + tiedcontext->cc_str_offsets_header_offset; + context-> cc_str_offsets_tab_to_array= + tiedcontext->cc_str_offsets_tab_to_array; + context-> cc_str_offsets_table_size= + tiedcontext->cc_str_offsets_table_size; + context-> cc_str_offsets_version= + tiedcontext->cc_str_offsets_version; + context-> cc_str_offsets_offset_size= + tiedcontext->cc_str_offsets_offset_size; + } + + /* GNU DW4 extension. */ + if (!context-> cc_ranges_base_present) { + context-> cc_ranges_base_present = + tiedcontext->cc_ranges_base_present; + context-> cc_ranges_base = + tiedcontext->cc_ranges_base; + } + + if (tiedcontext_out) { + *tiedcontext_out = tiedcontext; + } + return DW_DLV_OK; +} + +int +_dwarf_get_string_base_attr_value(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned *sbase_out, + Dwarf_Error *error) +{ + (void)dbg; + (void)error; + if (context->cc_str_offsets_tab_present) { + *sbase_out = context->cc_str_offsets_header_offset; + return DW_DLV_OK; + } + *sbase_out = 0; + return DW_DLV_OK; +} +/* Goes to the CU die and finds the DW_AT_GNU_addr_base + (or DW_AT_addr_base ) and gets the value from that CU die + and returns it through abase_out. If we cannot find the value + it is a serious error in the DWARF. + */ + +/* This works for all versions of DWARF. + The consumer has to check the return_form or + return_class to decide if the value returned + through return_value is an address or an address-offset. + + See DWARF4 section 2.17.2, + "Contiguous Address Range". + */ +int +dwarf_highpc_b(Dwarf_Die die, + Dwarf_Addr *return_value, + Dwarf_Half *return_form, + enum Dwarf_Form_Class *return_class, + Dwarf_Error *error) +{ + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Debug dbg = 0; + Dwarf_Half address_size = 0; + Dwarf_Half offset_size = 0; + enum Dwarf_Form_Class class = DW_FORM_CLASS_UNKNOWN; + Dwarf_Half version = 0; + Dwarf_Byte_Ptr die_info_end = 0; + int res = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + address_size = die->di_cu_context->cc_address_size; + + res = _dwarf_get_value_ptr(die, DW_AT_high_pc, + &attr_form,&info_ptr,0,error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + die_info_end = _dwarf_calculate_info_section_end_ptr( + die->di_cu_context); + + version = die->di_cu_context->cc_version_stamp; + offset_size = die->di_cu_context->cc_length_size; + class = dwarf_get_form_class(version,DW_AT_high_pc, + offset_size,attr_form); + + if (class == DW_FORM_CLASS_ADDRESS) { + Dwarf_Addr addr = 0; + if (dwarf_addr_form_is_indexed(attr_form)) { + Dwarf_Unsigned addr_out = 0; + Dwarf_Unsigned index_to_addr = 0; + int res2 = 0; + Dwarf_CU_Context context = die->di_cu_context; + + /* index_to_addr we get here might apply + to this dbg or to tieddbg. */ + /* error is returned on dbg, not tied */ + res2 = _dwarf_get_addr_index_itself(attr_form, + info_ptr,dbg,context,&index_to_addr,error); + if (res2 != DW_DLV_OK) { + return res2; + } + res2= _dwarf_look_in_local_and_tied_by_index(dbg, + context, + index_to_addr, + &addr_out, + error); + if (res2 != DW_DLV_OK) { + return res2; + } + } + READ_UNALIGNED_CK(dbg, addr, Dwarf_Addr, + info_ptr, address_size, + error,die_info_end); + *return_value = addr; + } else { + int res3 = 0; + Dwarf_Unsigned v = 0; + res3 = _dwarf_die_attr_unsigned_constant(die,DW_AT_high_pc, + &v,error); + if (res3 != DW_DLV_OK) { + Dwarf_Byte_Ptr info_ptr2 = 0; + + res3 = _dwarf_get_value_ptr(die, DW_AT_high_pc, + &attr_form,&info_ptr2,0,error); + if (res3 == DW_DLV_ERROR) { + return res3; + } + if (res3 == DW_DLV_NO_ENTRY) { + return res3; + } + if (attr_form == DW_FORM_sdata) { + Dwarf_Signed sval = 0; + + /* DWARF4 defines the value as an unsigned offset + in section 2.17.2. */ + DECODE_LEB128_UWORD_CK(info_ptr2, sval, + dbg,error,die_info_end); + *return_value = (Dwarf_Unsigned)sval; + } else { + _dwarf_error(dbg, error, DW_DLE_HIGHPC_WRONG_FORM); + return DW_DLV_ERROR; + } + } else { + *return_value = v; + } + } + /* Allow null args starting 22 April 2019. */ + if (return_form) { + *return_form = attr_form; + } + if (return_class) { + *return_class = class; + } + return DW_DLV_OK; +} + +/* The dbg and context here are a file with DW_FORM_addrx + but missing .debug_addr. So go to the tied file + and using the signature from the current context + locate the target CU in the tied file Then + get the address. + +*/ +int +_dwarf_get_addr_from_tied(Dwarf_Debug dbg, + Dwarf_CU_Context context, + Dwarf_Unsigned index, + Dwarf_Addr *addr_out, + Dwarf_Error*error) +{ + Dwarf_Debug tieddbg = 0; + int res = 0; + Dwarf_Addr local_addr = 0; + Dwarf_CU_Context tiedcontext = 0; + Dwarf_Unsigned addrtabsize = 0; + + if (!context->cc_signature_present) { + _dwarf_error(dbg, error, DW_DLE_NO_SIGNATURE_TO_LOOKUP); + return DW_DLV_ERROR; + } + tieddbg = dbg->de_tied_data.td_tied_object; + if (!tieddbg) { + _dwarf_error(dbg, error, DW_DLE_NO_TIED_ADDR_AVAILABLE); + return DW_DLV_ERROR; + } + if (!context->cc_addr_base_present) { + /* Does not exist. */ + return DW_DLV_NO_ENTRY; + } + res = _dwarf_search_for_signature(tieddbg, + context->cc_signature, + &tiedcontext, + error); + if (res == DW_DLV_ERROR) { + /* Associate the error with dbg, not tieddbg */ + _dwarf_error_mv_s_to_t(tieddbg,error,dbg,error); + return res; + } + if ( res == DW_DLV_NO_ENTRY) { + return res; + } + /* We have .debug_addr */ + addrtabsize = tieddbg->de_debug_addr.dss_size; + if ( (index > tieddbg->de_filesize || + index > addrtabsize || + (index*tiedcontext->cc_address_size) > addrtabsize)) { + _dwarf_error_string(dbg,error,DW_DLE_ATTR_FORM_OFFSET_BAD, + "DW_DLE_ATTR_FORM_OFFSET_BAD " + "Looking for an index from an addr FORM " + "we find an impossibly large index value for the tied " + "object. Corrupt DWARF"); + return DW_DLV_ERROR; + } + res = _dwarf_extract_address_from_debug_addr(tieddbg, + tiedcontext, + index, + &local_addr, + error); + if ( res == DW_DLV_ERROR) { + /* Associate the error with dbg, not tidedbg */ + _dwarf_error_mv_s_to_t(tieddbg,error,dbg,error); + return res; + } + if ( res == DW_DLV_NO_ENTRY) { + return res; + } + *addr_out = local_addr; + return DW_DLV_OK; +} + +/* + Takes a die, an attribute attr, and checks if attr + occurs in die. Attr is required to be an attribute + whose form is in the "constant" class. If attr occurs + in die, the value is returned. + + It does not really allow for a signed constant, and + DWARF does not always specify that only non-negative + values are allowed.. + + Returns DW_DLV_OK, DW_DLV_ERROR, or DW_DLV_NO_ENTRY as + appropriate. Sets the value thru the pointer return_val. + + This function is meant to do all the + processing for dwarf_bytesize, dwarf_bitsize, dwarf_bitoffset, + and dwarf_srclang. And it helps in dwarf_highpc_with_form(). +*/ +static int +_dwarf_die_attr_unsigned_constant(Dwarf_Die die, + Dwarf_Half attr, + Dwarf_Unsigned *return_val, + Dwarf_Error *error) +{ + Dwarf_Byte_Ptr info_ptr = 0; + Dwarf_Half attr_form = 0; + Dwarf_Unsigned ret_value = 0; + Dwarf_Signed implicit_const_value = 0; + Dwarf_Debug dbg = 0; + int res = 0; + Dwarf_Byte_Ptr die_info_end = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + + die_info_end = + _dwarf_calculate_info_section_end_ptr(die->di_cu_context); + dbg = die->di_cu_context->cc_dbg; + res = _dwarf_get_value_ptr(die,attr,&attr_form, + &info_ptr,&implicit_const_value,error); + if (res != DW_DLV_OK) { + return res; + } + switch (attr_form) { + case DW_FORM_data1: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Small), + error,die_info_end); + *return_val = ret_value; + return DW_DLV_OK; + + case DW_FORM_data2: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + info_ptr, sizeof(Dwarf_Shalf), + error,die_info_end); + *return_val = ret_value; + return DW_DLV_OK; + + case DW_FORM_data4: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + info_ptr, DWARF_32BIT_SIZE, + error,die_info_end); + *return_val = ret_value; + return DW_DLV_OK; + + case DW_FORM_data8: + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + info_ptr, DWARF_64BIT_SIZE, + error,die_info_end); + *return_val = ret_value; + return DW_DLV_OK; + + case DW_FORM_udata: { + Dwarf_Unsigned v = 0; + + DECODE_LEB128_UWORD_CK(info_ptr, v,dbg,error,die_info_end); + *return_val = v; + return DW_DLV_OK; + + } + case DW_FORM_implicit_const: { + if (implicit_const_value < (Dwarf_Signed)0) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "DW_DLE_NEGATIVE_SIZE " + "An implicit const value of " + "%d is inappropriate as a size", + implicit_const_value); + _dwarf_error_string(dbg, error, + DW_DLE_NEGATIVE_SIZE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + *return_val = implicit_const_value; + return DW_DLV_OK; + } + + default: + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return DW_DLV_ERROR; + } +} + +/* Size Value >= 0 is not specified in DWARF5, but + a negative value is surely not meaningful. */ +int +dwarf_bytesize(Dwarf_Die die, + Dwarf_Unsigned *ret_size, Dwarf_Error *error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_byte_size, + &luns, error); + *ret_size = luns; + return res; +} + +/* Size Value >= 0 is not specified in DWARF5, but + a negative value is not meaningful. */ +int +dwarf_bitsize(Dwarf_Die die, + Dwarf_Unsigned *ret_size, Dwarf_Error *error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_bit_size, + &luns, error); + *ret_size = luns; + return res; +} + +/* Size Value >= 0 required. DWARF5 sec5.7.6 + The definition of DW_AT_data_bit_offset + (DWARF4, DWARF5) is radically + different from DW_AT_bit_offset (DWARF2, + DWARF3. */ +int +dwarf_bitoffset(Dwarf_Die die, + Dwarf_Half *attribute, + Dwarf_Unsigned *ret_offset, + Dwarf_Error *error) +{ + Dwarf_Unsigned luns = 0; + int res = 0; + /* DWARF4,5 case */ + res = _dwarf_die_attr_unsigned_constant(die, + DW_AT_data_bit_offset, &luns, error); + if (res == DW_DLV_NO_ENTRY) { + /* DWARF2, DWARF3 case. */ + res = _dwarf_die_attr_unsigned_constant(die, + DW_AT_bit_offset, &luns, error); + if (res == DW_DLV_OK) { + *attribute = DW_AT_bit_offset; + *ret_offset = luns; + return DW_DLV_OK; + } + } else if (res == DW_DLV_OK) { + *attribute = DW_AT_data_bit_offset; + *ret_offset = luns; + return DW_DLV_OK; + } else { /* fall to return */ } + return res; +} + +/* Refer section 3.1, page 21 in Dwarf Definition. + Language codes are always non-negative + and specified in the DWARF standard*/ +int +dwarf_srclang(Dwarf_Die die, + Dwarf_Unsigned *ret_size, Dwarf_Error *error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_language, + &luns, error); + *ret_size = luns; + return res; +} + +/* Refer section 5.4, page 37 in Dwarf Definition. + array order values are always non-negative + and specified in the DWARF standard*/ +int +dwarf_arrayorder(Dwarf_Die die, + Dwarf_Unsigned *ret_size, Dwarf_Error *error) +{ + Dwarf_Unsigned luns = 0; + int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_ordering, + &luns, error); + *ret_size = luns; + return res; +} + +/* Return DW_DLV_OK if ok + DW_DLV_ERROR if failure. + + If the die and the attr are not related the result is + meaningless. */ +int +dwarf_attr_offset(Dwarf_Die die, Dwarf_Attribute attr, + Dwarf_Off *offset /* return offset thru this ptr */, + Dwarf_Error *error) +{ + Dwarf_Off attroff = 0; + Dwarf_Small *dataptr = 0; + Dwarf_Debug dbg = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + dbg = die->di_cu_context->cc_dbg; + dataptr = die->di_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + attroff = (attr->ar_debug_ptr - dataptr); + *offset = attroff; + return DW_DLV_OK; +} + +int +dwarf_die_abbrev_code(Dwarf_Die die) +{ + return die->di_abbrev_code; +} + +/* Returns a flag through ablhas_child. Non-zero if + the DIE has children, zero if it does not. + It has no Dwarf_Error arg! +*/ +int +dwarf_die_abbrev_children_flag(Dwarf_Die die,Dwarf_Half *ab_has_child) +{ + if (die->di_abbrev_list) { + *ab_has_child = die->di_abbrev_list->abl_has_child; + return DW_DLV_OK; + } + return DW_DLV_ERROR; +} + +/* Helper function for finding form class. + Only called for FORMs that might be offsets + to one or another section. */ +static enum Dwarf_Form_Class +dw_get_special_offset(Dwarf_Half attrnum, + Dwarf_Half dwversion) +{ + switch (attrnum) { + case DW_AT_stmt_list: + return DW_FORM_CLASS_LINEPTR; + case DW_AT_macro_info: /* DWARF2-DWARF4 */ + return DW_FORM_CLASS_MACPTR; + case DW_AT_start_scope: + case DW_AT_ranges: { + if (dwversion <= 4) { + return DW_FORM_CLASS_RANGELISTPTR; + } + return DW_FORM_CLASS_RNGLIST; + } + case DW_AT_GNU_ranges_base: /* DWARF5-like */ + case DW_AT_rnglists_base: /* DWARF5 */ + return DW_FORM_CLASS_RNGLISTSPTR; + case DW_AT_GNU_macros: /* DWARF5-like */ + case DW_AT_macros: /* DWARF5 */ + return DW_FORM_CLASS_MACROPTR; + case DW_AT_loclists_base: /* DWARF5 */ + return DW_FORM_CLASS_LOCLISTSPTR; + case DW_AT_GNU_addr_base: /* DWARF55-like */ + case DW_AT_addr_base: /* DWARF5 */ + return DW_FORM_CLASS_ADDRPTR; + case DW_AT_str_offsets_base: /* DWARF5 */ + return DW_FORM_CLASS_STROFFSETSPTR; + + case DW_AT_location: + case DW_AT_string_length: + case DW_AT_return_addr: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: { + if (dwversion <= 4) { + return DW_FORM_CLASS_LOCLIST; + } + return DW_FORM_CLASS_LOCLISTPTR; + } + case DW_AT_sibling: + case DW_AT_byte_size : + case DW_AT_bit_offset : + case DW_AT_bit_size : + case DW_AT_discr : + case DW_AT_import : + case DW_AT_common_reference: + case DW_AT_containing_type: + case DW_AT_default_value: + case DW_AT_lower_bound: + case DW_AT_bit_stride: + case DW_AT_upper_bound: + case DW_AT_abstract_origin: + case DW_AT_base_types: + case DW_AT_count: + case DW_AT_friend: + case DW_AT_namelist_item: + case DW_AT_priority: + case DW_AT_specification: + case DW_AT_type: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_byte_stride: + case DW_AT_extension: + case DW_AT_trampoline: + case DW_AT_small: + case DW_AT_object_pointer: + case DW_AT_signature: + return DW_FORM_CLASS_REFERENCE; + case DW_AT_MIPS_fde: /* SGI/IRIX extension */ + return DW_FORM_CLASS_FRAMEPTR; + default: break; + } + return DW_FORM_CLASS_UNKNOWN; +} + +static int +block_means_locexpr(Dwarf_Half attr) +{ + switch(attr) { + case DW_AT_bit_size: + case DW_AT_byte_size: + case DW_AT_call_data_location: + case DW_AT_call_data_value: + case DW_AT_call_value: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_GNU_call_site_target: + case DW_AT_GNU_call_site_value: + case DW_AT_location: + case DW_AT_return_addr: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + return TRUE; + default: break; + } + return FALSE; +} + +/* It takes 4 pieces of data (including the FORM) + to accurately determine the form 'class' as documented + in the DWARF spec. This is per DWARF4, but will work + for DWARF2 or 3 as well. */ +enum Dwarf_Form_Class +dwarf_get_form_class( + Dwarf_Half dwversion, + Dwarf_Half attrnum, + Dwarf_Half offset_size, + Dwarf_Half form) +{ + switch (form) { + case DW_FORM_addr: return DW_FORM_CLASS_ADDRESS; + case DW_FORM_data2: return DW_FORM_CLASS_CONSTANT; + + case DW_FORM_data4: + if (dwversion <= 3 && offset_size == 4) { + enum Dwarf_Form_Class class = + dw_get_special_offset(attrnum, dwversion); + if (class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + return DW_FORM_CLASS_CONSTANT; + case DW_FORM_data8: + if (dwversion <= 3 && offset_size == 8) { + enum Dwarf_Form_Class class = + dw_get_special_offset(attrnum, dwversion); + if (class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + return DW_FORM_CLASS_CONSTANT; + case DW_FORM_sec_offset: + { + enum Dwarf_Form_Class class = + dw_get_special_offset(attrnum, dwversion); + if (class != DW_FORM_CLASS_UNKNOWN) { + return class; + } + } + /* We do not know what this is. */ + return DW_FORM_CLASS_UNKNOWN; + break; + + case DW_FORM_string: return DW_FORM_CLASS_STRING; + case DW_FORM_strp: return DW_FORM_CLASS_STRING; + + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + if (dwversion <= 3) { + if (block_means_locexpr(attrnum)) { + return DW_FORM_CLASS_EXPRLOC; + } + } + return DW_FORM_CLASS_BLOCK; + /* DWARF4 and DWARF5 */ + case DW_FORM_exprloc: return DW_FORM_CLASS_EXPRLOC; + + case DW_FORM_data16: return DW_FORM_CLASS_CONSTANT; + case DW_FORM_data1: return DW_FORM_CLASS_CONSTANT; + case DW_FORM_sdata: return DW_FORM_CLASS_CONSTANT; + case DW_FORM_udata: return DW_FORM_CLASS_CONSTANT; + + case DW_FORM_ref_addr: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref1: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref2: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref4: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref8: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref_udata: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_ref_sig8: return DW_FORM_CLASS_REFERENCE; + + case DW_FORM_flag: return DW_FORM_CLASS_FLAG; + case DW_FORM_flag_present: return DW_FORM_CLASS_FLAG; + + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + return DW_FORM_CLASS_ADDRESS; /* DWARF5 */ + case DW_FORM_GNU_addr_index: return DW_FORM_CLASS_ADDRESS; + case DW_FORM_strx: /* DWARF5 */ + case DW_FORM_strx1: /* DWARF5 */ + case DW_FORM_strx2: /* DWARF5 */ + case DW_FORM_strx3: /* DWARF5 */ + case DW_FORM_line_strp: /* DWARF5 */ + case DW_FORM_strp_sup: /* DWARF5 */ + case DW_FORM_GNU_strp_alt: + return DW_FORM_CLASS_STRING; + case DW_FORM_GNU_str_index: return DW_FORM_CLASS_STRING; + + case DW_FORM_rnglistx: + return DW_FORM_CLASS_RNGLIST; /* DWARF5 */ + case DW_FORM_loclistx: + return DW_FORM_CLASS_LOCLIST; /* DWARF5 */ + + case DW_FORM_GNU_ref_alt: return DW_FORM_CLASS_REFERENCE; + case DW_FORM_implicit_const: + return DW_FORM_CLASS_CONSTANT; /* DWARF5 */ + + case DW_FORM_indirect: + default: + break; + }; + return DW_FORM_CLASS_UNKNOWN; +} + +/* Given a DIE, figure out what the CU's DWARF version is + and the size of an offset + and return it through the *version pointer and return + DW_DLV_OK. + + If we cannot find a CU, + return DW_DLV_ERROR on error. + In case of error no Dwarf_Debug was available, + so setting a Dwarf_Error is somewhat futile. + Never returns DW_DLV_NO_ENTRY. +*/ +int +dwarf_get_version_of_die(Dwarf_Die die, + Dwarf_Half *version, + Dwarf_Half *offset_size) +{ + Dwarf_CU_Context cucontext = 0; + if (!die) { + return DW_DLV_ERROR; + } + cucontext = die->di_cu_context; + if (!cucontext) { + return DW_DLV_ERROR; + } + *version = cucontext->cc_version_stamp; + *offset_size = cucontext->cc_length_size; + return DW_DLV_OK; +} + +Dwarf_Byte_Ptr +_dwarf_calculate_info_section_start_ptr(Dwarf_CU_Context context, + Dwarf_Unsigned *section_len) +{ + Dwarf_Debug dbg = 0; + Dwarf_Small *dataptr = 0; + struct Dwarf_Section_s *sec = 0; + + dbg = context->cc_dbg; + sec = context->cc_is_info? &dbg->de_debug_info: + &dbg->de_debug_types; + dataptr = sec->dss_data; + *section_len = sec->dss_size; + return dataptr; +} + +Dwarf_Byte_Ptr +_dwarf_calculate_info_section_end_ptr(Dwarf_CU_Context context) +{ + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr info_end = 0; + Dwarf_Byte_Ptr info_start = 0; + Dwarf_Off off2 = 0; + Dwarf_Small *dataptr = 0; + + dbg = context->cc_dbg; + dataptr = context->cc_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + off2 = context->cc_debug_offset; + info_start = dataptr + off2; + info_end = info_start + context->cc_length + + context->cc_length_size + + context->cc_extension_size; + return info_end; +} +Dwarf_Byte_Ptr +_dwarf_calculate_abbrev_section_end_ptr(Dwarf_CU_Context context) +{ + Dwarf_Debug dbg = 0; + Dwarf_Byte_Ptr abbrev_end = 0; + Dwarf_Byte_Ptr abbrev_start = 0; + struct Dwarf_Section_s *sec = 0; + + dbg = context->cc_dbg; + sec = &dbg->de_debug_abbrev; + abbrev_start = sec->dss_data; + abbrev_end = abbrev_start + sec->dss_size; + return abbrev_end; +} + +/* New December 2020. Any Dwarf_Die will work. + The values returned are about the CU itself, not a DIE. + extension_size is set zero unless it offset_size + is 64 and it is standard Dwarf, in which case + extension_size is set to 4. + If there is no signature *signature is set zero, + offset_of_length is the section offset of the first + byte of the compilation-unit length field. + total_byte_length includes the length field and + all the CU data. + The offset of the first byte of the CU is therefore + offset_of_lenth + offset_size + extension_size. + is_info is always non-zero except if the section + of the CU is DWARF4 .debug_types. +*/ +int dwarf_cu_header_basics(Dwarf_Die die, + Dwarf_Half *version, + Dwarf_Bool *is_info, + Dwarf_Bool *is_dwo, + Dwarf_Half *offset_size, + Dwarf_Half *address_size, + Dwarf_Half *extension_size, + Dwarf_Sig8 **signature, + Dwarf_Off *offset_of_length, + Dwarf_Unsigned *total_byte_length, + Dwarf_Error *error) +{ + Dwarf_CU_Context context = 0; + CHECK_DIE(die, DW_DLV_ERROR); + + context= die->di_cu_context; + if (version) { + *version = context->cc_version_stamp; + } + if (is_info) { + /* ASSERT: matches context->cc_is_info */ + *is_info = die->di_is_info; + } + if (is_dwo) { + *is_dwo = context->cc_is_dwo; + } + if (offset_size) { + *offset_size = context->cc_length_size; + } + if (address_size) { + *address_size = context->cc_address_size; + } + if (extension_size) { + *extension_size = context->cc_extension_size; + } + if (signature) { + if (context->cc_signature_present) { + *signature = &context->cc_signature; + } else { + *signature = 0; + } + } + if (offset_of_length) { + *offset_of_length = context->cc_debug_offset; + } + if (total_byte_length) { + *total_byte_length = context->cc_length + + context->cc_length_size + context->cc_extension_size; + } + return DW_DLV_OK; +} + +int +dwarf_get_universalbinary_count( + Dwarf_Debug dbg, + Dwarf_Unsigned *current_index, + Dwarf_Unsigned *available_count) +{ + if (!dbg) { + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_universalbinary_count ) { + return DW_DLV_NO_ENTRY; + } + if (current_index) { + *current_index = dbg->de_universalbinary_index; + } + if (available_count) { + *available_count = dbg->de_universalbinary_count; + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_ranges.c b/src/lib/libdwarf/dwarf_ranges.c new file mode 100644 index 0000000..4c65f73 --- /dev/null +++ b/src/lib/libdwarf/dwarf_ranges.c @@ -0,0 +1,356 @@ +/* + Copyright (C) 2008-2020 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" + +struct ranges_entry { + struct ranges_entry *next; + Dwarf_Ranges cur; +}; + +static void +free_allocated_ranges( struct ranges_entry *base) +{ + struct ranges_entry *cur = 0; + struct ranges_entry *next = 0; + for ( cur = base ; cur ; cur = next ) { + next = cur->next; + free(cur); + } +} + +/* We encapsulate the macro use so we can + free local malloc resources that would otherwise + leak. See the call points below. */ +static int +read_unaligned_addr_check(Dwarf_Debug dbg, + Dwarf_Addr *addr_out, + Dwarf_Small *rangeptr, + unsigned address_size, + Dwarf_Error *error, + Dwarf_Small *section_end) +{ + Dwarf_Addr a = 0; + + READ_UNALIGNED_CK(dbg,a, + Dwarf_Addr, rangeptr, + address_size, + error,section_end); + *addr_out = a; + return DW_DLV_OK; +} +/* As of DWARF5 the ranges section each range list set has + a range-list-table header. See "7.28 Range List Table" + in the DWARF5 standard. + For DWARF5 the offset should be the offset of + the range-list-table-header for that range list. + For DWARF3 and DWARF4 the offset has to be that + of a range list. +*/ +/* Ranges and pc values can be in a split dwarf object. + In that case the appropriate values need to be + incremented by data from the executable in + the compilation unit with the same dwo_id. + + We return an error which is on the incoming dbg, not + the possibly-tied-dbg localdbg. + If incoming die is NULL there is no context, so do not look + for a tied file, and address_size is the size + of the overall object, not the address_size of the context. */ +#define MAX_ADDR ((address_size == 8)? \ + 0xffffffffffffffffULL:0xffffffff) +/* New 10 September 2020 to accommodate the + GNU extension of DWARF4 split-dwarf. + The actual_offset field is set by the function + to the actual final offset of the ranges + in the separate tied (a.out) file. */ +int dwarf_get_ranges_b(Dwarf_Debug dbg, + Dwarf_Off rangesoffset, + Dwarf_Die die, + Dwarf_Off *actual_offset, + Dwarf_Ranges ** rangesbuf, + Dwarf_Signed * listlen, + Dwarf_Unsigned * bytecount, + Dwarf_Error * error) +{ + Dwarf_Small *rangeptr = 0; + Dwarf_Small *beginrangeptr = 0; + Dwarf_Small *section_end = 0; + unsigned entry_count = 0; + struct ranges_entry *base = 0; + struct ranges_entry *last = 0; + struct ranges_entry *curre = 0; + Dwarf_Ranges * ranges_data_out = 0; + unsigned copyindex = 0; + Dwarf_Half address_size = 0; + int res = DW_DLV_ERROR; + Dwarf_Unsigned ranges_base = 0; + Dwarf_Debug localdbg = dbg; + Dwarf_Error localerror = 0; + Dwarf_Half die_version = 3; /* default for dwarf_get_ranges() */ + Dwarf_Half offset_size= 4; + Dwarf_CU_Context cucontext = 0; + Dwarf_Bool rangeslocal = TRUE; + + (void)offset_size; + if (!dbg) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + address_size = localdbg->de_pointer_size; /* default */ + if (die) { + /* If we wind up using the tied file the die_version + had better match! It cannot be other than a match. */ + /* Can return DW_DLV_ERROR, not DW_DLV_NO_ENTRY. + Add err code if error. Version comes from the + cu context, not the DIE itself. */ + res = dwarf_get_version_of_die(die,&die_version, + &offset_size); + if (res == DW_DLV_ERROR) { + _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + if (!die->di_cu_context) { + _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); + return DW_DLV_ERROR; + } + cucontext = die->di_cu_context; + /* The DW4 ranges base was never used in GNU + but did get emitted, the note says, but + the note is probably obsolete (so, now wrong). + http://llvm.1065342.n5.nabble.com/DebugInfo\ + -DW-AT-GNU-ranges-base-in-non-fission-\ + td64194.html + */ + /* ranges_base was merged from tied context. */ + ranges_base = cucontext->cc_ranges_base; + address_size = cucontext->cc_address_size; + } + + localdbg = dbg; + res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges, + error); + if (res == DW_DLV_ERROR) { + return res; + } + if (res == DW_DLV_NO_ENTRY) { + /* data is in a.out, not dwp */ + localdbg = dbg->de_tied_data.td_tied_object; + if (!localdbg) { + return DW_DLV_NO_ENTRY; + } + res = _dwarf_load_section(localdbg, + &localdbg->de_debug_ranges, &localerror); + if (res == DW_DLV_ERROR) { + _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error); + return res; + } + if (res == DW_DLV_NO_ENTRY) { + return res; + } + rangeslocal = FALSE; + } + + /* Be safe in case adding rangesoffset and rangebase + overflows. */ + if (rangesoffset >= localdbg->de_debug_ranges.dss_size) { + /* Documented behavior in libdwarf2.1.mm */ + return DW_DLV_NO_ENTRY; + } + if (ranges_base >= localdbg->de_debug_ranges.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " + " ranges base is 0x%lx ",ranges_base); + dwarfstring_append_printf_u(&m, + " and section size is 0x%lx.", + localdbg->de_debug_ranges.dss_size); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_RANGES_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (!rangeslocal && ((rangesoffset +ranges_base) >= + localdbg->de_debug_ranges.dss_size)) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " + " ranges base+offset is 0x%lx ", + ranges_base+rangesoffset); + dwarfstring_append_printf_u(&m, + " and section size is 0x%lx.", + localdbg->de_debug_ranges.dss_size); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_RANGES_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + /* tied address_size must match the dwo address_size */ + section_end = localdbg->de_debug_ranges.dss_data + + localdbg->de_debug_ranges.dss_size; + rangeptr = localdbg->de_debug_ranges.dss_data; + if (!rangeslocal) { + /* printing ranges where range source is dwp, + here we just assume present. */ + rangesoffset += ranges_base; + } + rangeptr += rangesoffset; + beginrangeptr = rangeptr; + + for (;;) { + struct ranges_entry * re = 0; + + if (rangeptr == section_end) { + break; + } + if (rangeptr > section_end) { + dwarfstring m; + + free_allocated_ranges(base); + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " + " ranges pointer ran off the end " + "of the section"); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_RANGES_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + re = calloc(sizeof(struct ranges_entry),1); + if (!re) { + free_allocated_ranges(base); + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); + return DW_DLV_ERROR; + } + if ((rangeptr + (2*address_size)) > section_end) { + free(re); + free_allocated_ranges(base); + _dwarf_error_string(dbg, error, + DW_DLE_DEBUG_RANGES_OFFSET_BAD, + "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " + " Not at the end of the ranges section " + " but there is not enough room in the section " + " for the next ranges entry"); + return DW_DLV_ERROR; + } + entry_count++; + res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1, + rangeptr, address_size,error,section_end); + if (res != DW_DLV_OK) { + free(re); + free_allocated_ranges(base); + return res; + } + rangeptr += address_size; + res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2, + rangeptr, address_size,error,section_end); + if (res != DW_DLV_OK) { + free(re); + free_allocated_ranges(base); + return res; + } + rangeptr += address_size; + if (!base) { + base = re; + last = re; + } else { + last->next = re; + last = re; + } + if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { + re->cur.dwr_type = DW_RANGES_END; + break; + } else if (re->cur.dwr_addr1 == MAX_ADDR) { + re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; + } else { + re->cur.dwr_type = DW_RANGES_ENTRY; + } + } + + /* We return ranges on dbg, so use that to allocate. */ + ranges_data_out = (Dwarf_Ranges *) + _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); + if (!ranges_data_out) { + /* Error, apply to original, not local dbg. */ + free_allocated_ranges(base); + _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); + return DW_DLV_ERROR; + } + curre = base; + *rangesbuf = ranges_data_out; + *listlen = entry_count; + for (copyindex = 0; curre && (copyindex < entry_count); + ++copyindex,++ranges_data_out,curre=curre->next) { + *ranges_data_out = curre->cur; + } + /* ASSERT: curre == NULL */ + free_allocated_ranges(base); + base = 0; + /* Callers will often not care about the bytes used. */ + if (actual_offset) { + *actual_offset = rangesoffset; + } + if (bytecount) { + *bytecount = rangeptr - beginrangeptr; + } + return DW_DLV_OK; +} + +void +dwarf_dealloc_ranges(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf, + Dwarf_Signed rangecount) +{ + (void)rangecount; + dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES); +} diff --git a/src/lib/libdwarf/dwarf_reading.h b/src/lib/libdwarf/dwarf_reading.h new file mode 100644 index 0000000..3afc418 --- /dev/null +++ b/src/lib/libdwarf/dwarf_reading.h @@ -0,0 +1,72 @@ +/* +Copyright (c) 2018-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#ifndef DWARF_READING_H +#define DWARF_READING_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef DW_DLV_OK +/* DW_DLV_OK must match libdwarf.h */ +/* DW_DLV_NO_ENTRY must match libdwarf.h */ +#define DW_DLV_OK 0 +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_ERROR 1 +#endif /* DW_DLV_OK */ + +#define ALIGN4 4 +#define ALIGN8 8 + +#define PREFIX "\t" +#define LUFMT "%lu" +#define UFMT "%u" +#define DFMT "%d" +#define XFMT "0x%x" + +/* even if already seen, values must match, so no #ifdef needed. */ +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_OK 0 +#define DW_DLV_ERROR 1 + +#define P printf +#define F fflush(stdout) + +#define RRMOA(f,buf,loc,siz,fsiz,errc) _dwarf_object_read_random(\ + (f),(char *)(buf),(loc),(siz),(fsiz),(errc)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_READING_H */ diff --git a/src/lib/libdwarf/dwarf_rnglists.c b/src/lib/libdwarf/dwarf_rnglists.c new file mode 100644 index 0000000..07b367e --- /dev/null +++ b/src/lib/libdwarf/dwarf_rnglists.c @@ -0,0 +1,1541 @@ +/* +Copyright (c) 2020, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include /* free() malloc() */ +#include /* printf */ +#include /* memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_rnglists.h" + +#define SIZEOFT8 1 +#define SIZEOFT16 2 +#define SIZEOFT32 4 +#define SIZEOFT64 8 + +#if 0 +static void +dump_bytes(const char *msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + printf("%s (0x%lx) ",msg,(unsigned long)start); + for (; cur < end; cur++) { + printf("%02x", *cur); + } + printf("\n"); +} +#endif /*0*/ +#if 0 +static void +dump_rh(const char *msg, + int line, + struct Dwarf_Rnglists_Head_s *head) +{ + printf("Rnglists_Head: %s line %d\n", + msg,line); + printf(" count of entries: " + DW_PR_DUu + " (0x%" DW_PR_DUx ")\n", + head->rh_count,head->rh_count); + printf(" rh_rnglists : %p\n",(void *)) head->rh_rnglists); + if (head->rh_first) { + printf(" rh_first : %" DW_PR_DUu "\n", head->rh_first); + if (head->rh_last) { + printf(" rh_last : %" DW_PR_DUu "\n",head->rh_last); + } + printf(" rh_bytes total : %" DW_PR_DUu + " (0x%" DW_PR_DUx ")\n",head->rh_bytes_total, + head->rh_bytes_total); + printf(" CU Context : %p",(void *)head->rh_context); + printf(" Rnglists Context: %p",(void *)head->rh_localcontext); +} +#endif + +/* Used in case of error reading the + rnglists headers (not referring to Dwarf_Rnglists_Head + here), to clean up. */ +static void +free_rnglists_chain(Dwarf_Debug dbg, Dwarf_Chain head) +{ + Dwarf_Chain cur = head; + Dwarf_Chain next = 0; + + if (!head) { + return; + } + for ( ;cur; cur = next) { + next = cur->ch_next; + if (cur->ch_item) { + free(cur->ch_item); + cur->ch_item = 0; + dwarf_dealloc(dbg,cur,DW_DLA_CHAIN); + } + } +} + +static int +read_single_rle_entry(Dwarf_Debug dbg, + Dwarf_Small *data, + Dwarf_Unsigned dataoffset, + Dwarf_Small *enddata, + unsigned address_size, + unsigned *bytes_count_out, + unsigned *entry_kind, + Dwarf_Unsigned *entry_operand1, + Dwarf_Unsigned *entry_operand2, + Dwarf_Error* error) +{ + Dwarf_Unsigned count = 0; + unsigned leblen = 0; + unsigned code = 0; + Dwarf_Unsigned val1 = 0; + Dwarf_Unsigned val2 = 0; + + code = *data; + ++data; + ++count; + switch(code) { + case DW_RLE_end_of_list: break; + case DW_RLE_base_addressx:{ + DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, + dbg,error,enddata); + count += leblen; + } + break; + case DW_RLE_startx_endx: + case DW_RLE_startx_length: + case DW_RLE_offset_pair: { + DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, + dbg,error,enddata); + count += leblen; + DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, + dbg,error,enddata); + count += leblen; + } + break; + case DW_RLE_base_address: { + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + } + break; + case DW_RLE_start_end: { + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + READ_UNALIGNED_CK(dbg,val2, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + } + break; + case DW_RLE_start_length: { + READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, + data,address_size,error,enddata); + data += address_size; + count += address_size; + DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, + dbg,error,enddata); + count += leblen; + } + break; + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: " + "The rangelists entry at .debug_rnglists" + " offset 0x%x" ,dataoffset); + dwarfstring_append_printf_u(&m, + " has code 0x%x which is unknown",code); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + break; + } + *bytes_count_out = count; + *entry_kind = code; + *entry_operand1 = val1; + *entry_operand2 = val2; + return DW_DLV_OK; +} + +/* Reads the header. Determines the + various offsets, including offset + of the next header. Does no memory + allocations here. */ +int +_dwarf_internal_read_rnglists_header(Dwarf_Debug dbg, + Dwarf_Unsigned contextnum, + Dwarf_Unsigned sectionlength, + Dwarf_Small *data, + Dwarf_Small *end_data, + Dwarf_Unsigned offset, + Dwarf_Rnglists_Context buildhere, + Dwarf_Unsigned *next_offset, + Dwarf_Error *error) +{ + Dwarf_Small *startdata = data; + Dwarf_Unsigned arealen = 0; + int offset_size = 0; + int exten_size = 0; + Dwarf_Unsigned version = 0; + unsigned address_size = 0; + unsigned segment_selector_size= 0; + Dwarf_Unsigned offset_entry_count = 0; + Dwarf_Unsigned localoff = 0; + Dwarf_Unsigned lists_len = 0; + Dwarf_Unsigned secsize_dbg = 0; + + secsize_dbg = dbg->de_debug_rnglists.dss_size; + /* Sanity checks */ + if (sectionlength > secsize_dbg) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: " + " section_length argument (%lu) mismatch vs.", + sectionlength); + dwarfstring_append_printf_u(&m, + ".debug_rnglists" + " section length",secsize_dbg); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if (sectionlength > secsize_dbg) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append(&m, + "DW_DLE_RNGLISTS_ERROR: " + " section_length argument mismatch vs. .debug_rnglists" + " section length including header."); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->rc_startaddr = data; + READ_AREA_LENGTH_CK(dbg,arealen,Dwarf_Unsigned, + data,offset_size,exten_size, + error, + sectionlength,end_data); + if (arealen > sectionlength || + (arealen+offset_size+exten_size) > sectionlength) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: A .debug_rnglists " + "area size of 0x%x ",arealen); + dwarfstring_append_printf_u(&m, + "at offset 0x%x ",offset); + dwarfstring_append_printf_u(&m, + "is larger than the entire section size of " + "0x%x. Corrupt DWARF.",sectionlength); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + localoff = offset_size+exten_size; + buildhere->rc_length = arealen + localoff; + buildhere->rc_dbg = dbg; + buildhere->rc_index = contextnum; + buildhere->rc_header_offset = offset; + buildhere->rc_offset_size = offset_size; + buildhere->rc_extension_size = exten_size; + buildhere->rc_magic = RNGLISTS_MAGIC; + READ_UNALIGNED_CK(dbg,version,Dwarf_Unsigned,data, + SIZEOFT16,error,end_data); + if (version != DW_CU_VERSION5) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: The version should be 5 " + "but we find %u instead.",version); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->rc_version = version; + data += SIZEOFT16; + localoff += SIZEOFT16; + + READ_UNALIGNED_CK(dbg,address_size,unsigned,data, + SIZEOFT8,error,end_data); + if (address_size != 4 && address_size != 8 && + address_size != 2) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists " + "The address size " + "of %u is not supported.",address_size); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->rc_address_size = address_size; + localoff++; + data++; + + READ_UNALIGNED_CK(dbg,segment_selector_size,unsigned,data, + SIZEOFT8,error,end_data); + buildhere->rc_segment_selector_size = segment_selector_size; + data++; + localoff++; + if (segment_selector_size) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists" + " The segment selector size " + "of %u is not supported.",address_size); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if ((offset+localoff+SIZEOFT32) > secsize_dbg) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists" + " Header runs off the end of the section " + " with offset %u",offset+localoff+SIZEOFT32); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + READ_UNALIGNED_CK(dbg,offset_entry_count,Dwarf_Unsigned,data, + SIZEOFT32,error,end_data); + buildhere->rc_offset_entry_count = offset_entry_count; + data += SIZEOFT32; + localoff+= SIZEOFT32; + if (offset_entry_count ){ + buildhere->rc_offsets_array = data; + } + + lists_len = offset_size *offset_entry_count; + if (offset_entry_count >= secsize_dbg || + lists_len >= secsize_dbg) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists" + " offset entry count" + " of %u is clearly impossible. Corrupt data", + offset_entry_count); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + data += lists_len; + buildhere->rc_offsets_off_in_sect = offset+localoff; + localoff += lists_len; + if (localoff > buildhere->rc_length) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists" + " length of rnglists header too large at" + " of %u is clearly impossible. Corrupt data", + localoff); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->rc_first_rnglist_offset = offset+localoff; + buildhere->rc_rnglists_header = startdata; + buildhere->rc_endaddr = startdata +buildhere->rc_length; + if (buildhere->rc_endaddr > end_data) { + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: .debug_rnglists" + " length of rnglists header (%u) " + "runs off end of section. Corrupt data", + buildhere->rc_length); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + buildhere->rc_past_last_rnglist_offset = + buildhere->rc_header_offset +buildhere->rc_length; + *next_offset = buildhere->rc_past_last_rnglist_offset; + return DW_DLV_OK; +} + +/* We return a pointer to an array of contexts + (not context pointers) through *cxt if + we succeed and are returning DW_DLV_OK. + We never return DW_DLV_NO_ENTRY here. */ +static int +internal_load_rnglists_contexts(Dwarf_Debug dbg, + Dwarf_Rnglists_Context **cxt, + Dwarf_Unsigned *count, + Dwarf_Error *error) +{ + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned nextoffset = 0; + Dwarf_Small * data = dbg->de_debug_rnglists.dss_data; + Dwarf_Unsigned section_size = dbg->de_debug_rnglists.dss_size; + Dwarf_Small * startdata = data; + Dwarf_Small * end_data = data +section_size; + Dwarf_Chain curr_chain = 0; + Dwarf_Chain head_chain = 0; + Dwarf_Chain *plast = &head_chain; + int res = 0; + Dwarf_Unsigned chainlength = 0; + Dwarf_Rnglists_Context *fullarray = 0; + Dwarf_Unsigned i = 0; + + for (i = 0 ; data < end_data ; ++i,data = startdata+nextoffset) { + Dwarf_Rnglists_Context newcontext = 0; + + /* sizeof the context struct, not sizeof a pointer */ + newcontext = malloc(sizeof(*newcontext)); + if (!newcontext) { + free_rnglists_chain(dbg,head_chain); + _dwarf_error_string(dbg,error, + DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocation of " + "Rnglists_Context failed"); + return DW_DLV_ERROR; + } + memset(newcontext,0,sizeof(*newcontext)); + newcontext->rc_magic = RNGLISTS_MAGIC; + res = _dwarf_internal_read_rnglists_header(dbg, + chainlength, + section_size, + data,end_data,offset, + newcontext,&nextoffset,error); + if (res == DW_DLV_ERROR) { + free(newcontext); + newcontext = 0; + free_rnglists_chain(dbg,head_chain); + return res; + } + newcontext->rc_magic = RNGLISTS_MAGIC; + curr_chain = (Dwarf_Chain) + _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating Rnglists_Context" + " chain entry"); + free(newcontext); + newcontext = 0; + free_rnglists_chain(dbg,head_chain); + return DW_DLV_ERROR; + } + curr_chain->ch_item = newcontext; + ++chainlength; + (*plast) = curr_chain; + plast = &(curr_chain->ch_next); + offset = nextoffset; + newcontext = 0; + } + fullarray= (Dwarf_Rnglists_Context *)malloc( + chainlength *sizeof(Dwarf_Rnglists_Context /*pointer*/)); + if (!fullarray) { + free_rnglists_chain(dbg,head_chain); + _dwarf_error_string(dbg,error, + DW_DLE_ALLOC_FAIL,"Allocation of " + "Rnglists_Context pointer array failed"); + return DW_DLV_ERROR; + } + curr_chain = head_chain; + for (i = 0; i < chainlength; ++i) { + Dwarf_Chain prev = 0; + Dwarf_Rnglists_Context c = + (Dwarf_Rnglists_Context)curr_chain->ch_item; + fullarray[i] = c; + curr_chain->ch_item = 0; + prev = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev, DW_DLA_CHAIN); + } + /* ASSERT: the chain is entirely alloc'd + and the array of pointers points to + individually malloc'd Dwarf_Rnglists_Context_s */ + *cxt = fullarray; + *count = chainlength; + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw rnglists data. + Loads all the .debug_rnglists[.dwo] headers and + returns DW_DLV_NO_ENTRY if the section + is missing or empty. + Intended to be done quite early and + done exactly once. + Harmless to do more than once. + With DW_DLV_OK it returns the number of + rnglists headers in the section through + rnglists_count. */ +int dwarf_load_rnglists( + Dwarf_Debug dbg, + Dwarf_Unsigned *rnglists_count, + Dwarf_Error *error) +{ + int res = DW_DLV_ERROR; + Dwarf_Rnglists_Context *cxt = 0; + Dwarf_Unsigned count = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL" + "NULL or invalid Dwarf_Debug " + "argument passed to " + "dwarf_load_rnglists()"); + return DW_DLV_ERROR; + } + if (dbg->de_rnglists_context) { + if (rnglists_count) { + *rnglists_count = dbg->de_rnglists_context_count; + } + return DW_DLV_OK; + } + if (!dbg->de_debug_rnglists.dss_size) { + /* nothing there. */ + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_debug_rnglists.dss_data) { + res = _dwarf_load_section(dbg, &dbg->de_debug_rnglists, + error); + if (res != DW_DLV_OK) { + return res; + } + } + res = internal_load_rnglists_contexts(dbg,&cxt,&count,error); + if (res == DW_DLV_ERROR) { + return res; + } + dbg->de_rnglists_context = cxt; + dbg->de_rnglists_context_count = count; + if (rnglists_count) { + *rnglists_count = count; + } + return DW_DLV_OK; +} + +/* Frees the memory in use in all rnglists contexts. + Done by dwarf_finish() */ +void +_dwarf_dealloc_rnglists_context(Dwarf_Debug dbg) +{ + Dwarf_Unsigned i = 0; + Dwarf_Rnglists_Context * rngcon = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + return; + } + if (!dbg->de_rnglists_context) { + return; + } + rngcon = dbg->de_rnglists_context; + for ( ; i < dbg->de_rnglists_context_count; ++i) { + Dwarf_Rnglists_Context con = rngcon[i]; + con->rc_offsets_array = 0; + con->rc_magic = 0; + con->rc_offset_entry_count = 0; + free(con); + rngcon[i] = 0; + } + free(dbg->de_rnglists_context); + dbg->de_rnglists_context = 0; + dbg->de_rnglists_context_count = 0; +} + +/* Used by dwarfdump to print raw rnglists data. */ +int +dwarf_get_rnglist_offset_index_value( + Dwarf_Debug dbg, + Dwarf_Unsigned context_index, + Dwarf_Unsigned offsetentry_index, + Dwarf_Unsigned * offset_value_out, + Dwarf_Unsigned * global_offset_value_out, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Context con = 0; + unsigned offset_len = 0; + Dwarf_Small *offsetptr = 0; + Dwarf_Unsigned targetoffset = 0; + Dwarf_Unsigned localoffset = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL or invalid dbg " + "argument passed to " + "dwarf_get_rnglist_offset_index_value()"); + return DW_DLV_ERROR; + } + if (!dbg->de_rnglists_context) { + return DW_DLV_NO_ENTRY; + } + + if (!dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (context_index >= dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + con = dbg->de_rnglists_context[context_index]; + if (con->rc_magic != RNGLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "rnglists context magic wrong " + "not RNGLISTS_MAGIC"); + return DW_DLV_ERROR; + } + if (offsetentry_index >= con->rc_offset_entry_count) { + return DW_DLV_NO_ENTRY; + } + offset_len = con->rc_offset_size; + localoffset = offsetentry_index*offset_len; + offsetptr = con->rc_offsets_array + localoffset; + if ((con->rc_offsets_off_in_sect +localoffset + + offset_len) > + con->rc_past_last_rnglist_offset) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR " + "dwarf_get_rnglist_offset_index_value() " + " Offset for index %u is too large. ", + offsetentry_index); + _dwarf_error_string(dbg, error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + + } + READ_UNALIGNED_CK(dbg,targetoffset,Dwarf_Unsigned, + offsetptr, + offset_len,error,con->rc_endaddr); + if (offset_value_out) { + *offset_value_out = targetoffset; + } + if (global_offset_value_out) { + *global_offset_value_out = targetoffset + + con->rc_offsets_off_in_sect; + } + return DW_DLV_OK; +} + +/* Used by dwarfdump to print basic data from the + data generated to look at a specific rangelist + as returned by dwarf_rnglists_index_get_rle_head() + or dwarf_rnglists_offset_get_rle_head. */ +int dwarf_get_rnglist_head_basics( + Dwarf_Rnglists_Head head, + Dwarf_Unsigned * rle_count, + Dwarf_Unsigned * rle_version, + Dwarf_Unsigned * rnglists_index_returned, + Dwarf_Unsigned * bytes_total_in_rle, + Dwarf_Half * offset_size, + Dwarf_Half * address_size, + Dwarf_Half * segment_selector_size, + Dwarf_Unsigned * overall_offset_of_this_context, + Dwarf_Unsigned * total_length_of_this_context, + Dwarf_Unsigned * offset_table_offset, + Dwarf_Unsigned * offset_table_entrycount, + Dwarf_Bool * rnglists_base_present, + Dwarf_Unsigned * rnglists_base, + Dwarf_Bool * rnglists_base_address_present, + Dwarf_Unsigned * rnglists_base_address, + Dwarf_Bool * rnglists_debug_addr_base_present, + Dwarf_Unsigned * rnglists_debug_addr_base, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Context rngcontext = 0; + + if (!head || (!head->rh_dbg) || + head->rh_magic != RNGLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL or invalid Dwarf_Rnglists_Head " + "argument passed to " + "dwarf_get_rnglist_head_basics()"); + return DW_DLV_ERROR; + } + *rle_count = head->rh_count; + *rle_version = head->rh_version; + *rnglists_index_returned = head->rh_index; + *bytes_total_in_rle = head->rh_bytes_total; + *offset_size = head->rh_offset_size; + *address_size = head->rh_address_size; + *segment_selector_size = head->rh_segment_selector_size; + rngcontext = head->rh_localcontext; + if (rngcontext) { + *overall_offset_of_this_context = + rngcontext->rc_header_offset; + *total_length_of_this_context = rngcontext->rc_length; + *offset_table_offset = rngcontext->rc_offsets_off_in_sect; + *offset_table_entrycount = rngcontext->rc_offset_entry_count; + } + *rnglists_base_present = head->rh_at_rnglists_base_present; + *rnglists_base= head->rh_at_rnglists_base; + + *rnglists_base_address_present = head->rh_cu_base_address_present; + *rnglists_base_address= head->rh_cu_base_address; + + *rnglists_debug_addr_base_present = head->rh_cu_addr_base_present; + *rnglists_debug_addr_base = head->rh_cu_addr_base; + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw rnglists data. + Enables printing of details about the Range List Table + Headers, one header per call. Index starting at 0. + Returns DW_DLV_NO_ENTRY if index is too high for the table. + A .debug_rnglists section may contain any number + of Range List Table Headers with their details. */ +int dwarf_get_rnglist_context_basics( + Dwarf_Debug dbg, + Dwarf_Unsigned context_index, + Dwarf_Unsigned * header_offset, + Dwarf_Small * offset_size, + Dwarf_Small * extension_size, + unsigned * version, /* 5 */ + Dwarf_Small * address_size, + Dwarf_Small * segment_selector_size, + Dwarf_Unsigned * offset_entry_count, + Dwarf_Unsigned * offset_of_offset_array, + Dwarf_Unsigned * offset_of_first_rangeentry, + Dwarf_Unsigned * offset_past_last_rangeentry, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Context con = 0; + if (!dbg) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL dbg " + "argument passed to " + "dwarf_get_rnglist_context_basics()"); + return DW_DLV_ERROR; + } + if (!dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (context_index >= dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + con = dbg->de_rnglists_context[context_index]; + if (con->rc_magic != RNGLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "rnglists context " + "not RNGLISTS_MAGIC " + "in dwarf_get_rnglist_context_basics()"); + return DW_DLV_ERROR; + } + if (header_offset) { + *header_offset = con->rc_header_offset; + } + if (offset_size) { + *offset_size = con->rc_offset_size; + } + if (extension_size) { + *extension_size = con->rc_extension_size; + } + if (version) { + *version = con->rc_version; + } + if (address_size) { + *address_size = con->rc_address_size; + } + if (segment_selector_size) { + *segment_selector_size = con->rc_segment_selector_size; + } + if (offset_entry_count) { + *offset_entry_count = con->rc_offset_entry_count; + } + if (offset_of_offset_array) { + *offset_of_offset_array = con->rc_offsets_off_in_sect; + } + if (offset_of_first_rangeentry) { + *offset_of_first_rangeentry = con->rc_first_rnglist_offset; + } + if (offset_past_last_rangeentry) { + *offset_past_last_rangeentry = + con->rc_past_last_rnglist_offset; + } + return DW_DLV_OK; +} + +/* Used by dwarfdump to print raw rnglists data. + entry offset is offset_of_first_rangeentry. + Stop when the returned *next_entry_offset + is == offset_past_last_rangentry (from + dwarf_get_rnglist_context_plus). + This only makes sense within those ranges. + This retrieves raw detail from the section, + no base values or anything are added. + So this returns raw individual entries + for a single rnglist header, meaning a + a single Dwarf_Rnglists_Context. */ +int dwarf_get_rnglist_rle( + Dwarf_Debug dbg, + Dwarf_Unsigned contextnumber, + Dwarf_Unsigned entry_offset, + Dwarf_Unsigned endoffset, + unsigned *entrylen, + unsigned *entry_kind, + Dwarf_Unsigned *entry_operand1, + Dwarf_Unsigned *entry_operand2, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Context con = 0; + Dwarf_Small *data = 0; + Dwarf_Small *enddata = 0; + int res = 0; + unsigned address_size = 0; + Dwarf_Unsigned secsize = 0; + + if (!dbg) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL dbg " + "argument passed to " + "dwarf_get_rnglist_rle()"); + return DW_DLV_ERROR; + } + secsize = dbg->de_debug_rnglists.dss_size; + if (!dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (!dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (contextnumber >= dbg->de_rnglists_context_count) { + return DW_DLV_NO_ENTRY; + } + if (entry_offset >= secsize) { + return DW_DLV_NO_ENTRY; + } + if (endoffset > secsize) { + _dwarf_error_string(dbg, error, DW_DLE_RNGLISTS_ERROR, + " DW_DLE_RNGLISTS_ERROR " + "The end offset to " + "dwarf_get_rnglist_rle() is " + "too large for the section"); + return DW_DLV_ERROR; + } + if (endoffset <= entry_offset) { + _dwarf_error_string(dbg, error, DW_DLE_RNGLISTS_ERROR, + " DW_DLE_RNGLISTS_ERROR " + "The end offset to " + "dwarf_get_rnglist_rle() is smaller than " + "the entry offset! Corrupt data"); + return DW_DLV_ERROR; + } + if ((entry_offset +1) > endoffset) { + /* The read_single_rle_entry call will need + at least 1 byte as it reads at least one + ULEB */ + dwarfstring m; + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR " + "The entry offset+1 (%lu) " + "dwarf_get_rnglist_rle() is too close to the" + " end",entry_offset+1); + dwarfstring_append_printf_u(&m, + " of the offset of the end of the entry (%lu)" + " Apparently corrupt Dwarf",endoffset); + _dwarf_error_string(dbg, error, DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + data = dbg->de_debug_rnglists.dss_data + + entry_offset; + enddata = dbg->de_debug_rnglists.dss_data + + endoffset; + + con = dbg->de_rnglists_context[contextnumber]; + address_size = con->rc_address_size; + res = read_single_rle_entry(dbg, + data,entry_offset,enddata, + address_size,entrylen, + entry_kind, entry_operand1, entry_operand2, + error); + return res; +} + +static int +_dwarf_which_rnglists_context(Dwarf_Debug dbg, + Dwarf_CU_Context ctx, + Dwarf_Unsigned rnglist_offset, + Dwarf_Unsigned *index, + Dwarf_Error *error) +{ + Dwarf_Unsigned count; + Dwarf_Rnglists_Context *array; + Dwarf_Unsigned i = 0; + + array = dbg->de_rnglists_context; + count = dbg->de_rnglists_context_count; + /* Using the slow way, a simple linear search. */ + if (!ctx->cc_rnglists_base_present) { + /* We look at the location of each rnglist context + to find one with the offset the DIE gave us. */ + for ( i = 0 ; i < count; ++i) { + Dwarf_Rnglists_Context rcx = array[i]; + Dwarf_Unsigned rcxoff = rcx->rc_header_offset; + Dwarf_Unsigned rcxend = rcxoff + + rcx->rc_length; + + if (rnglist_offset < rcxoff){ + continue; + } + if (rnglist_offset < rcxend ){ + *index = i; + return DW_DLV_OK; + } + } + { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: rnglist ran off end " + " finding target offset of" + " 0x%" DW_PR_XZEROS DW_PR_DUx ,rnglist_offset); + dwarfstring_append(&m, + " Not found anywhere in .debug_rnglists " + "data. Corrupted data?"); + _dwarf_error_string(dbg,error, + DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } else { + /* We have a DW_AT_rnglists_base (cc_rangelists_base), + let's use it. */ + Dwarf_Unsigned lookfor = 0;; + + lookfor = ctx->cc_rnglists_base; + for ( i = 0 ; i < count; ++i) { + dwarfstring m; + + Dwarf_Rnglists_Context rcx = array[i]; + if (rcx->rc_offsets_off_in_sect == lookfor){ + *index = i; + return DW_DLV_OK; + } + if (rcx->rc_offsets_off_in_sect < lookfor){ + continue; + } + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: rnglists base of " + " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); + dwarfstring_append_printf_u(&m, + " was not found though we are now at base " + " 0x%" DW_PR_XZEROS DW_PR_DUx , + rcx->rc_offsets_off_in_sect); + _dwarf_error_string(dbg,error, + DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: rnglist base of " + " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); + dwarfstring_append(&m, + " was not found anywhere in .debug_rnglists " + "data. Corrupted data?"); + _dwarf_error_string(dbg,error, + DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + /* ASSERT: This line cannot be reached. */ +} + +void +dwarf_dealloc_rnglists_head(Dwarf_Rnglists_Head h) +{ + Dwarf_Debug dbg = 0; + + if (!h || !h->rh_dbg || h->rh_magic != RNGLISTS_MAGIC) { + return; + } + dbg = h->rh_dbg; + h->rh_magic = 0; + dwarf_dealloc(dbg,h,DW_DLA_RNGLISTS_HEAD); + return; +} + +/* Caller will eventually free as appropriate. */ +static int +alloc_rle_and_append_to_list(Dwarf_Debug dbg, + Dwarf_Rnglists_Head rctx, + Dwarf_Rnglists_Entry *e_out, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Entry e = 0; + + e = malloc(sizeof(struct Dwarf_Rnglists_Entry_s)); + if (!e) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Out of memory in " + "building list of rnglists entries on a DIE."); + return DW_DLV_ERROR; + } + memset(e,0,sizeof(struct Dwarf_Rnglists_Entry_s)); + if (rctx->rh_first) { + rctx->rh_last->rle_next = e; + rctx->rh_last = e; + } else { + rctx->rh_first = e; + rctx->rh_last = e; + } + rctx->rh_count++; + *e_out = e; + return DW_DLV_OK; +} + +/* Read the group of rangelists entries, and + finally build an array of Dwarf_Rnglists_Entry + records. Attach to rctx here. + Since on error the caller will destruct the rctx + and we ensure to attach allocations there + the caller will destruct the allocations here + in case we return DW_DLV_ERROR*/ +static int +build_array_of_rle(Dwarf_Debug dbg, + Dwarf_Rnglists_Head rctx, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Small * data = rctx->rh_rlepointer; + Dwarf_Unsigned dataoffset = rctx->rh_rlearea_offset; + Dwarf_Small *enddata = rctx->rh_end_data_area; + unsigned address_size = rctx->rh_address_size; + Dwarf_Unsigned bytescounttotal= 0; + Dwarf_Unsigned latestbaseaddr = 0; + Dwarf_Bool foundbaseaddr = FALSE; + int done = FALSE; + Dwarf_Bool no_debug_addr_available = FALSE; + + if (rctx->rh_cu_base_address_present) { + /* The CU DIE had DW_AT_low_pc + and it is a base address. */ + latestbaseaddr = rctx->rh_cu_base_address; + foundbaseaddr = TRUE; + } + for ( ; !done ; ) { + unsigned entrylen = 0; + unsigned code = 0; + Dwarf_Unsigned val1 = 0; + Dwarf_Unsigned val2 = 0; + Dwarf_Addr addr1= 0; + Dwarf_Addr addr2 = 0; + Dwarf_Rnglists_Entry e = 0; + + res = read_single_rle_entry(dbg, + data,dataoffset, enddata, + address_size,&entrylen, + &code,&val1, &val2,error); + if (res != DW_DLV_OK) { + return res; + } + res = alloc_rle_and_append_to_list(dbg,rctx,&e,error); + if (res != DW_DLV_OK) { + return res; + } + e->rle_code = code, + e->rle_entrylen = entrylen; + e->rle_raw1 = val1; + e->rle_raw2 = val2; + bytescounttotal += entrylen; + data += entrylen; + if (code == DW_RLE_end_of_list) { + done = TRUE; + break; + } + switch(code) { + case DW_RLE_base_addressx: + if (no_debug_addr_available) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,rctx->rh_context,val1,&addr1, + error); + } + if (res != DW_DLV_OK) { + no_debug_addr_available = TRUE; + e->rle_index_failed = TRUE; + e->rle_cooked1 = 0; + foundbaseaddr = FALSE; + } else { + foundbaseaddr = TRUE; + e->rle_cooked1 = addr1; + latestbaseaddr = addr1; + } + break; + case DW_RLE_startx_endx: + if (no_debug_addr_available) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,rctx->rh_context,val1,&addr1, + error); + } + if (res != DW_DLV_OK) { + no_debug_addr_available = TRUE; + e->rle_index_failed = TRUE; + e->rle_cooked1 = 0; + } else { + e->rle_cooked1 = addr1; + } + if (no_debug_addr_available) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,rctx->rh_context,val2,&addr2, + error); + } + if (res != DW_DLV_OK) { + no_debug_addr_available = TRUE; + e->rle_index_failed = TRUE; + e->rle_cooked2 = 0; + return res; + } else { + e->rle_cooked2 = addr2; + } + break; + case DW_RLE_startx_length: + if (no_debug_addr_available) { + res = DW_DLV_NO_ENTRY; + } else { + res = _dwarf_look_in_local_and_tied_by_index( + dbg,rctx->rh_context,val1,&addr1, + error); + } + if (res != DW_DLV_OK) { + no_debug_addr_available = TRUE; + e->rle_index_failed = TRUE; + e->rle_cooked2 = 0; + e->rle_cooked1 = 0; + return res; + + } else { + e->rle_cooked1 = addr1; + e->rle_cooked2 = val2+addr1; + } + break; + case DW_RLE_offset_pair: + if (foundbaseaddr) { + e->rle_cooked1 = val1+latestbaseaddr; + e->rle_cooked2 = val2+latestbaseaddr; + } else { + /* Well, something failed, could be + missing debug_addr. */ + e->rle_index_failed = TRUE; + e->rle_cooked2 = 0; + e->rle_cooked1 = 0; + } + break; + case DW_RLE_base_address: + foundbaseaddr = TRUE; + latestbaseaddr = val1; + e->rle_cooked1 = val1; + break; + case DW_RLE_start_end: + e->rle_cooked1 = val1; + e->rle_cooked2 = val2; + break; + case DW_RLE_start_length: + e->rle_cooked1 = val1; + e->rle_cooked2 = val2+val1; + break; + default: { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + " DW_DLE_RNGLISTS_ERROR: " + " The .debug_rnglists " + " rangelist code 0x%x is unknown, " + " DWARF5 is corrupted.",code); + _dwarf_error_string(dbg, error, + DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } + } + if (rctx->rh_count > 0) { + Dwarf_Rnglists_Entry* array = 0; + Dwarf_Rnglists_Entry cur = 0; + Dwarf_Unsigned i = 0; + + /* Creating an array of pointers. */ + array = (Dwarf_Rnglists_Entry*)malloc( + rctx->rh_count *sizeof(Dwarf_Rnglists_Entry)); + if (!array) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Out of memory in " + "turning list of rnglists entries on a DIE" + "into a pointer array"); + return DW_DLV_ERROR; + } + cur = rctx->rh_first; + for ( ; i < rctx->rh_count; ++i) { + array[i] = cur; + cur = cur->rle_next; + } + rctx->rh_rnglists = array; + rctx->rh_first = 0; + rctx->rh_last = 0; + } + rctx->rh_bytes_total = bytescounttotal; + return DW_DLV_OK; +} + +/* Build a head with all the relevent Entries + attached. +*/ +int +dwarf_rnglists_get_rle_head( + Dwarf_Attribute attr, + Dwarf_Half theform, + /* attr_val is either an offset + (theform == DW_FORM_sec_offset) + or an index DW_FORM_rnglistx. */ + Dwarf_Unsigned attr_val, + Dwarf_Rnglists_Head *head_out, + Dwarf_Unsigned *entries_count_out, + Dwarf_Unsigned *global_offset_of_rle_set, + Dwarf_Error *error) +{ + int res = 0; + Dwarf_Unsigned rnglists_contextnum = 0; + Dwarf_Small *table_base = 0; + Dwarf_Small *table_entry = 0; + Dwarf_Small *enddata = 0; + Dwarf_Rnglists_Context *array = 0; + Dwarf_Rnglists_Context rctx = 0; + Dwarf_Unsigned entrycount = 0; + unsigned offsetsize = 0; + Dwarf_Unsigned rle_global_offset = 0; + Dwarf_Rnglists_Head lhead = 0; + Dwarf_CU_Context ctx = 0; + struct Dwarf_Rnglists_Head_s shead; + Dwarf_Unsigned offset_in_rnglists = 0; + Dwarf_Debug dbg = 0; + Dwarf_Bool is_rnglistx = FALSE; + + if (!attr) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL attribute " + "argument passed to " + "dwarf_rnglists_get_rle_head()"); + return DW_DLV_ERROR; + } + memset(&shead,0,sizeof(shead)); + ctx = attr->ar_cu_context; + dbg = ctx->cc_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL or invalid dbg " + "argument passed to " + "dwarf_rnglists_get_rle_head()"); + return DW_DLV_ERROR; + } + array = dbg->de_rnglists_context; + if (theform == DW_FORM_rnglistx) { + is_rnglistx = TRUE; + } + /* ASSERT: the 3 pointers just set are non-null */ + /* the context cc_rnglists_base gives the offset + of the array. of offsets (if cc_rnglists_base_present) */ + offset_in_rnglists = attr_val; + if (is_rnglistx) { + if (ctx->cc_rnglists_base_present) { + offset_in_rnglists = ctx->cc_rnglists_base; + + } else { + /* FIXME: check in tied file for a cc_rnglists_base */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: rnglists table index of" + " %u" ,attr_val); + dwarfstring_append(&m, + " is unusable unless it is in a tied file." + " Possibly libdwarf is incomplete.FIXME"); + _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + } else { + offset_in_rnglists = attr_val; + } + res = _dwarf_which_rnglists_context(dbg,ctx, + offset_in_rnglists, + &rnglists_contextnum,error); + if (res != DW_DLV_OK) { + return res; + } + rctx = array[rnglists_contextnum]; + table_base = rctx->rc_offsets_array; + entrycount = rctx->rc_offset_entry_count; + offsetsize = rctx->rc_offset_size; + enddata = rctx->rc_endaddr; + + if (is_rnglistx && attr_val >= entrycount) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_RNGLISTS_ERROR: rnglists table index of" + " %u" ,attr_val); + dwarfstring_append_printf_u(&m, + " too large for table of %u " + "entries.",entrycount); + _dwarf_error_string(dbg,error, + DW_DLE_RNGLISTS_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + shead.rh_context = ctx; + shead.rh_magic = RNGLISTS_MAGIC; + shead.rh_localcontext = rctx; + shead.rh_index = rnglists_contextnum; + shead.rh_version = rctx->rc_version; + shead.rh_offset_size = offsetsize; + shead.rh_address_size = rctx->rc_address_size; + shead.rh_segment_selector_size = + rctx->rc_segment_selector_size; + + /* DW_AT_rnglists_base from CU */ + shead.rh_at_rnglists_base_present = + ctx->cc_rnglists_base_present; + shead.rh_at_rnglists_base = ctx->cc_rnglists_base; + + /* DW_AT_low_pc, if present. From CU */ + shead.rh_cu_base_address_present = ctx->cc_low_pc_present; + shead.rh_cu_base_address = ctx->cc_low_pc; + + /* base address DW_AT_addr_base of our part of + .debug_addr, from CU */ + shead.rh_cu_addr_base = ctx->cc_addr_base; + shead.rh_cu_addr_base_present = ctx->cc_addr_base_present; + if (is_rnglistx) { + Dwarf_Unsigned table_entryval = 0; + + table_entry = attr_val*offsetsize + table_base; + /* No malloc here yet so no leak if the macro returns + DW_DLV_ERROR */ + READ_UNALIGNED_CK(dbg,table_entryval, Dwarf_Unsigned, + table_entry,offsetsize,error,enddata); + rle_global_offset = rctx->rc_offsets_off_in_sect + + table_entryval; + } else { + rle_global_offset = attr_val; + } + + shead.rh_end_data_area = enddata; + shead.rh_rlearea_offset = rle_global_offset; + shead.rh_rlepointer = rle_global_offset + + dbg->de_debug_rnglists.dss_data; + lhead = (Dwarf_Rnglists_Head) + _dwarf_get_alloc(dbg,DW_DLA_RNGLISTS_HEAD,1); + if (!lhead) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "Allocating a Dwarf_Rnglists_Head struct fails" + " in libdwarf function " + "dwarf_rnglists_index_get_rle_head()"); + return DW_DLV_ERROR; + } + shead.rh_dbg = dbg; + *lhead = shead; + res = build_array_of_rle(dbg,lhead,error); + if (res != DW_DLV_OK) { + dwarf_dealloc(dbg,lhead,DW_DLA_RNGLISTS_HEAD); + return res; + } + if (global_offset_of_rle_set) { + *global_offset_of_rle_set = rle_global_offset; + } + /* Caller needs the head pointer else there will be leaks. */ + *head_out = lhead; + if (entries_count_out) { + *entries_count_out = lhead->rh_count; + } + return DW_DLV_OK; +} + +/* As of 18 Aug 2020 + this ignores null pointer inputs for the various + pointers-returning-values (rle_value_out etc) + for the convenience of callers. */ +int +dwarf_get_rnglists_entry_fields_a( + Dwarf_Rnglists_Head head, + Dwarf_Unsigned entrynum, + unsigned *entrylen, + unsigned *rle_value_out, + Dwarf_Unsigned *raw1, + Dwarf_Unsigned *raw2, + Dwarf_Bool *debug_addr_unavailable, + Dwarf_Unsigned *cooked1, + Dwarf_Unsigned *cooked2, + Dwarf_Error *error) +{ + Dwarf_Rnglists_Entry e = 0; + + if (!head || !head->rh_dbg || head->rh_magic != RNGLISTS_MAGIC) { + _dwarf_error_string(NULL, error,DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL " + "NULL or invalid Dwarf_Rnglists_Head " + "argument passed to " + "dwarf_get_rnglists_entry_fields_a()"); + return DW_DLV_ERROR; + } + if (entrynum >= head->rh_count) { + return DW_DLV_NO_ENTRY; + } + e = head->rh_rnglists[entrynum]; + if (entrylen) { + *entrylen = e->rle_entrylen; + } + if (rle_value_out) { + *rle_value_out = e->rle_code; + } + if (raw1) { + *raw1 = e->rle_raw1; + } + if (raw2) { + *raw2 = e->rle_raw2; + } + if (debug_addr_unavailable) { + *debug_addr_unavailable = e->rle_index_failed; + } + if (cooked1) { + *cooked1 = e->rle_cooked1; + } + if (cooked2) { + *cooked2 = e->rle_cooked2; + } + return DW_DLV_OK; +} + +/* Deals with both fully and partially build head */ +static void +_dwarf_free_rnglists_head(Dwarf_Rnglists_Head head) +{ + if (head->rh_first) { + /* partially built head. */ + /* ASSERT: rh_rnglists is NULL */ + Dwarf_Rnglists_Entry cur = head->rh_first; + Dwarf_Rnglists_Entry next = 0; + + for ( ; cur ; cur = next) { + next = cur->rle_next; + free(cur); + } + head->rh_first = 0; + head->rh_last = 0; + head->rh_count = 0; + } else { + /* ASSERT: rh_first and rh_last are NULL */ + /* fully built head. */ + Dwarf_Unsigned i = 0; + + /* Deal with the array form. */ + for ( ; i < head->rh_count; ++i) { + free(head->rh_rnglists[i]); + } + free(head->rh_rnglists); + head->rh_rnglists = 0; + } +} + +void +_dwarf_rnglists_head_destructor(void *head) +{ + Dwarf_Rnglists_Head h = head; + + _dwarf_free_rnglists_head(h); +} diff --git a/src/lib/libdwarf/dwarf_rnglists.h b/src/lib/libdwarf/dwarf_rnglists.h new file mode 100644 index 0000000..bb78f73 --- /dev/null +++ b/src/lib/libdwarf/dwarf_rnglists.h @@ -0,0 +1,157 @@ +/* +Copyright (c) 2020-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ +#ifndef DWARF_RNGLISTS_H +#define DWARF_RNGLISTS_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define RNGLISTS_MAGIC 0xabcd + +/* Rangelists header for a CU. The + type is never visible to libdwarf callers */ +struct Dwarf_Rnglists_Context_s { + Dwarf_Debug rc_dbg; + Dwarf_Unsigned rc_index; /* An index assigned by + libdwarf to each rnglists context. Starting + with zero at the zero offset in .debug_rnglists. */ + + /* Offset of the .debug_rnglists header involved. */ + Dwarf_Unsigned rc_header_offset; + Dwarf_Unsigned rc_length; + + /* Many places in in libdwarf this is called length_size. */ + Dwarf_Small rc_offset_size; + unsigned long rc_magic; + + /* rc_extension_size is zero unless this is standard + DWARF3 and later 64bit dwarf using the extension mechanism. + 64bit DWARF3 and later: rc_extension_size is 4. + 64bit DWARF2 MIPS/IRIX: rc_extension_size is zero. + 32bit DWARF: rc_extension_size is zero. */ + Dwarf_Small rc_extension_size; + + unsigned rc_version; /* 5 */ + Dwarf_Small rc_address_size; + Dwarf_Small rc_segment_selector_size; + Dwarf_Unsigned rc_offset_entry_count; + + /* offset in the section of the offset entries */ + Dwarf_Unsigned rc_offsets_off_in_sect; + + /* Do not free. Points into section memory */ + Dwarf_Small * rc_offsets_array; + + /* Offset in the .debug_rnglists section of the + first rangelist in the set of rangelists for the + CU. */ + Dwarf_Unsigned rc_first_rnglist_offset; + Dwarf_Unsigned rc_past_last_rnglist_offset; + + /* pointer to 1st byte of rangelist header*/ + Dwarf_Small * rc_rnglists_header; + /* pointer to first byte of the rnglist data + for rnglist involved. Do not free. */ + Dwarf_Small *rc_startaddr; + /* pointer one past end of the rnglist data. */ + Dwarf_Small *rc_endaddr; +}; + +typedef struct Dwarf_Rnglists_Entry_s *Dwarf_Rnglists_Entry; +struct Dwarf_Rnglists_Entry_s { + unsigned rle_entrylen; + unsigned rle_code; + /* Failed means .debug_addr section needed but missing. + (possibly tied file needed) */ + Dwarf_Bool rle_index_failed; + Dwarf_Unsigned rle_raw1; + Dwarf_Unsigned rle_raw2; + /* Cooked means the raw values from the .debug_rnglists + section translated to DIE-specific addresses. */ + Dwarf_Unsigned rle_cooked1; + Dwarf_Unsigned rle_cooked2; + Dwarf_Rnglists_Entry rle_next; +}; + +struct Dwarf_Rnglists_Head_s { + Dwarf_Rnglists_Entry *rh_rnglists; + /* rh_last and rh_first used during build-up. + Zero when array rh_rnglists built. */ + Dwarf_Rnglists_Entry rh_first; + Dwarf_Rnglists_Entry rh_last; + Dwarf_Unsigned rh_count; + Dwarf_Unsigned rh_bytes_total; + + /* A global Rnglists Context, */ + unsigned long rh_magic; + Dwarf_CU_Context rh_context; + Dwarf_Debug rh_dbg; + Dwarf_Rnglists_Context rh_localcontext; + Dwarf_Unsigned rh_version; + Dwarf_Unsigned rh_index; + Dwarf_Unsigned rh_offset_size; + Dwarf_Unsigned rh_address_size; + unsigned rh_segment_selector_size; + + /* DW_AT_rnglists_base */ + Dwarf_Bool rh_at_rnglists_base_present; + Dwarf_Unsigned rh_at_rnglists_base; + + /* DW_AT_low_pc of CU or zero if none. */ + Dwarf_Bool rh_cu_base_address_present; + Dwarf_Unsigned rh_cu_base_address; + + /* DW_AT_addr_base, so we can use .debug_addr + if such is needed. */ + Dwarf_Bool rh_cu_addr_base_present; + Dwarf_Unsigned rh_cu_addr_base; + Dwarf_Small * rh_rlepointer; + Dwarf_Unsigned rh_rlearea_offset; + Dwarf_Small * rh_end_data_area; +}; + +int _dwarf_internal_read_rnglists_header(Dwarf_Debug dbg, + Dwarf_Unsigned contextnum, + Dwarf_Unsigned sectionlength, + Dwarf_Small *data, + Dwarf_Small *end_data, + Dwarf_Unsigned offset, + Dwarf_Rnglists_Context buildhere, + Dwarf_Unsigned *next_offset, + Dwarf_Error *error); + +void _dwarf_rnglists_head_destructor(void *m); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_RNGLISTS_H */ diff --git a/src/lib/libdwarf/dwarf_safe_arithmetic.c b/src/lib/libdwarf/dwarf_safe_arithmetic.c new file mode 100644 index 0000000..0f0421e --- /dev/null +++ b/src/lib/libdwarf/dwarf_safe_arithmetic.c @@ -0,0 +1,167 @@ +/* +Copyright (c) 2023, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include + +#include /* calloc() free() */ +#include /* memset() */ +#include /* memset(), printf */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_safe_arithmetic.h" + +#ifndef LLONG_MAX +#define LLONG_MAX 9223372036854775807LL +#endif +#ifndef LLONG_MIN +#define LLONG_MIN (-LLONG_MAX - 1LL) +#endif +#ifndef ULLONG_MAX +#define ULLONG_MAX 18446744073709551615ULL +#endif + +/* Thanks to David Grayson/ +codereview.stackexchange.com/questions/98791/ +safe-multiplication-of-two-64-bit-signed-integers +*/ +int +_dwarf_int64_mult(Dwarf_Signed x, Dwarf_Signed y, + Dwarf_Signed * result, Dwarf_Debug dbg, + Dwarf_Error*error) +{ + if (result) { + *result = 0; + } + if (sizeof(Dwarf_Signed) != 8) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "Signed 64bit multiply overflow(a)"); + return DW_DLV_ERROR; + } + if (x > 0 && y > 0 && x > LLONG_MAX / y) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "Signed 64bit multiply overflow(b)"); + return DW_DLV_ERROR; + } + if (x < 0 && y > 0 && x < LLONG_MIN / y) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "Signed 64bit multiply overflow(c)"); + return DW_DLV_ERROR; + } + if (x > 0 && y < 0 && y < LLONG_MIN / x) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "Signed 64bit multiply overflow(d)"); + return DW_DLV_ERROR; + } + if (x < 0 && y < 0 && + (x <= LLONG_MIN || + y <= LLONG_MIN || + -x > LLONG_MAX / -y)) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "Signed 64bit multiply overflow(e)"); + return DW_DLV_ERROR; + } + if (result) { + *result = x * y; + } + return DW_DLV_OK; +} + +int +_dwarf_uint64_mult(Dwarf_Unsigned x, Dwarf_Unsigned y, + Dwarf_Unsigned * result, Dwarf_Debug dbg, + Dwarf_Error *error) +{ + if (y && (x > (ULLONG_MAX/y))) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW " + "unsigned 64bit multiply overflow"); + return DW_DLV_ERROR; + } + if (result) { + *result = x*y; + } + return DW_DLV_OK; +} + +#if 0 +/* See: +https://stackoverflow.com/questions/3944505/ +detecting-signed-overflow-in-c-c +*/ +int _dwarf_signed_add_check(Dwarf_Signed l, Dwarf_Signed r, + Dwarf_Signed *sum, Dwarf_Debug dbg, + Dwarf_Error *error) +{ + if (l >= 0) { + if ((0x7fffffffffffffffLL - l) < r) { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW: " + "Adding integers l+r (l >= 0) overflows"); + return DW_DLV_ERROR; + } + } else { + if (r < (0x7ffffffffffffffeLL -l)) + { + _dwarf_error_string(dbg,error, + DW_DLE_ARITHMETIC_OVERFLOW, + "DW_DLE_ARITHMETIC_OVERFLOW: " + "Adding integers l+r (l < 0) overflows"); + return DW_DLV_ERROR; + } + } + if (sum) { + *sum = l + r; + } + return DW_DLV_OK; +} +#endif /* 0 */ diff --git a/src/lib/libdwarf/dwarf_safe_arithmetic.h b/src/lib/libdwarf/dwarf_safe_arithmetic.h new file mode 100644 index 0000000..7fc604d --- /dev/null +++ b/src/lib/libdwarf/dwarf_safe_arithmetic.h @@ -0,0 +1,53 @@ +/* +Copyright (c) 2023, David Anderson All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* Thanks to David Grayson/ +codereview.stackexchange.com/questions/98791/ +safe-multiplication-of-two-64-bit-signed-integers +*/ + +int _dwarf_int64_mult(Dwarf_Signed x, Dwarf_Signed y, + Dwarf_Signed * result, + Dwarf_Debug dbg, Dwarf_Error*error); + +int _dwarf_uint64_mult(Dwarf_Unsigned x, Dwarf_Unsigned y, + Dwarf_Unsigned * result, + Dwarf_Debug dbg, Dwarf_Error *error); + +#if 0 +/* See: +https://stackoverflow.com/questions/ +3944505/detecting-signed-overflow-in-c-c +*/ +int _dwarf_signed_add_check(Dwarf_Signed l, Dwarf_Signed r, + Dwarf_Signed *sum, Dwarf_Debug dbg, + Dwarf_Error *error); +#endif /* 0 */ diff --git a/src/lib/libdwarf/dwarf_safe_strcpy.c b/src/lib/libdwarf/dwarf_safe_strcpy.c new file mode 100644 index 0000000..e3260fd --- /dev/null +++ b/src/lib/libdwarf/dwarf_safe_strcpy.c @@ -0,0 +1,100 @@ +/* +Copyright (c) 2021, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +#include +#include /* NULL size_t */ +#include "dwarf_safe_strcpy.h" + +/* An strcpy/strncpy which ensures NUL terminated string + and never overruns the output. + inlen is strlen() size of in_s + outlen is buffer and has to have space + for the NUL in in_s to avoid truncation. + So typically outlen == (inlen+1). + + If outlen is 0 it quietly returns. + If outlen is 1 it assigns a NUL byte to *out and returns. + If outlen > 0 then this function always writes + a trailing NUL byte. + + ISO C 9899:1990 specifies that if outlen has extra space + that the function zeroes the extra bytes. + And if outlen is too small no NUL byte is written + to out. + + This function writes only one NUL byte, the rest of + the 'out' buffer is untouched. Sometimes our callers + do not have a narrow bound to outlen, so zeroing + all the unused bytes is wasteful (hence we do not + do that here). + + If an input is only partly copied due to limited + target space this may destroy the + correctness of a multi-byte-string (UTF-8). + Note that this will not harm dwarfdump as + dwarfdump 'sanitizes' all printf output + in a uri-style. So it only prints true ASCII characters + in the printable range. + + PRECONDITION: + The pointer arguments are required to be non-null. +*/ +void +_dwarf_safe_strcpy(char *out, + size_t outlen, + const char *in_s, + size_t inlen) +{ + size_t full_inlen = inlen+1; + char *cpo = 0; + const char *cpi= 0; + const char *cpiend = 0; + + if (full_inlen >= outlen) { + if (!outlen) { + return; + } + cpo = out; + cpi= in_s; + cpiend = in_s +(outlen-1); + } else { + /* If outlen is very large + strncpy is very wasteful. */ + cpo = out; + cpi= in_s; + cpiend = in_s +inlen; + } + for ( ; *cpi && cpi < cpiend ; ++cpo, ++cpi) { + *cpo = *cpi; + } + *cpo = 0; +} diff --git a/src/lib/libdwarf/dwarf_safe_strcpy.h b/src/lib/libdwarf/dwarf_safe_strcpy.h new file mode 100644 index 0000000..87b5080 --- /dev/null +++ b/src/lib/libdwarf/dwarf_safe_strcpy.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 2021-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ +#ifndef DWARF_SAFE_STRCPY_H +#define DWARF_SAFE_STRCPY_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* The pointer arguments are required to be non-null. + If outlen is zero nothing will be written to out. */ +void _dwarf_safe_strcpy(char *out, size_t outlen, + const char *in, size_t inlen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARF_SAFE_STRCPY_H */ diff --git a/src/lib/libdwarf/dwarf_secname_ck.c b/src/lib/libdwarf/dwarf_secname_ck.c new file mode 100644 index 0000000..1d42d6c --- /dev/null +++ b/src/lib/libdwarf/dwarf_secname_ck.c @@ -0,0 +1,118 @@ +/* Copyright (c) 2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ +#include + +#include /* calloc() free() */ +#include /* memset() strcmp() strncmp() strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "libdwarf_private.h" /* for TRUE FALSE */ +#include "dwarf_secname_ck.h" + +/* Mainly important for Elf */ + +int +_dwarf_startswith(const char * input,const char* ckfor) +{ + size_t cklen = strlen(ckfor); + + if (! strncmp(input,ckfor,cklen)) { + return TRUE; + } + return FALSE; +} + +static int +_dwarf_startswithx(const char * input,const char* ckfor) +{ + size_t cklen = strlen(ckfor); + int res = 0; + + res = strncmp(input,ckfor,cklen); + return res; +} +/* If one uses the 'sort' command it ignores the proper place + of . and _ so the output needs modification to get what we want. + Here ensure _ and . before lowercase letters. + If any here someday have uppercase ensure _ above + uppercase letter. */ + +static const char *nonsec[] = { +".bss", +".comment", +".data", +".fini_array", +".fini", +".got", /* [5] */ +".init", +".interp", +".jcr", +".plt", +".rel.data", /* 10 */ +".rel.got", +".rel.plt", +".rel.text", +".rela.data", +".rela.got", /* 15 */ +".rela.plt", +".rela.text", +".sbss", +".text", /* [19] */ +}; + +/* These help us ignore some sections that are + irrelevant to libdwarf. */ +int +_dwarf_ignorethissection(const char *scn_name) +{ + int l = 0; + int h = sizeof(nonsec)/sizeof(const char *) -1; + int res = 0; + + while (l <= h) { + int m = (l+h)/2; + const char *s = nonsec[m]; + + res = _dwarf_startswithx(scn_name,s); + if (res < 0) { + h = m -1; + } else if (res > 0) { + l = m + 1; + } else { + return TRUE; + } + } + return FALSE; +} diff --git a/src/lib/libdwarf/dwarf_secname_ck.h b/src/lib/libdwarf/dwarf_secname_ck.h new file mode 100644 index 0000000..8747240 --- /dev/null +++ b/src/lib/libdwarf/dwarf_secname_ck.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ + +/* Mainly important for Elf */ + +int _dwarf_startswith(const char * input,const char* ckfor); +int _dwarf_ignorethissection(const char *scn_name); diff --git a/src/lib/libdwarf/dwarf_setup_sections.c b/src/lib/libdwarf/dwarf_setup_sections.c new file mode 100644 index 0000000..dd44290 --- /dev/null +++ b/src/lib/libdwarf/dwarf_setup_sections.c @@ -0,0 +1,521 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2022 David Anderson. All Rights Reserved. + Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* calloc() free() */ +#include /* memset() strcmp() strncmp() strlen() */ +#include /* debugging */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#if 0 +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_harmless.h" +#endif /* 0 */ +#include "dwarf_string.h" +#include "dwarf_secname_ck.h" +#include "dwarf_setup_sections.h" + +/* Used to add the specific information for a debug related section + Called on each section of interest by section name. + DWARF_MAX_DEBUG_SECTIONS must be large enough to allow + that all sections of interest fit in the table. + returns DW_DLV_ERROR or DW_DLV_OK. + */ +static int +add_debug_section_info(Dwarf_Debug dbg, + /* Name as seen in object file. */ + const char *name, + const char *standard_section_name, + Dwarf_Unsigned obj_sec_num, + struct Dwarf_Section_s *secdata, + unsigned groupnum, + /* The have_dwarf flag is a somewhat imprecise + way to determine if there is at least one 'meaningful' + DWARF information section present in the object file. + If not set on some section we claim (later) that there + is no DWARF info present. see 'foundDwarf' in this file */ + int duperr,int emptyerr,int have_dwarf, + int havezdebug, + int *err) +{ + unsigned total_entries = dbg->de_debug_sections_total_entries; + if (secdata->dss_is_in_use) { + *err = duperr; + return DW_DLV_ERROR; + } + if (total_entries < DWARF_MAX_DEBUG_SECTIONS) { + struct Dwarf_dbg_sect_s *debug_section = + &dbg->de_debug_sections[total_entries]; + secdata->dss_is_in_use = TRUE; + debug_section->ds_name = name; + debug_section->ds_number = obj_sec_num; + debug_section->ds_secdata = secdata; + debug_section->ds_groupnumber = groupnum; + secdata->dss_name = name; /* Actual name from object file. */ + secdata->dss_standard_name = standard_section_name; + secdata->dss_number = obj_sec_num; + secdata->dss_zdebug_requires_decompress = havezdebug; + /* We don't yet know about SHF_COMPRESSED */ + debug_section->ds_duperr = duperr; + debug_section->ds_emptyerr = emptyerr; + debug_section->ds_have_dwarf = have_dwarf; + debug_section->ds_have_zdebug = havezdebug; + ++dbg->de_debug_sections_total_entries; + return DW_DLV_OK; + } + /* This represents a bug in libdwarf. + Mis-setup-DWARF_MAX_DEBUG_SECTIONS. + Or possibly a use of section groups that is + not supported. */ + *err = DW_DLE_TOO_MANY_DEBUG; + return DW_DLV_ERROR; +} + +/* Return DW_DLV_OK etc. + PRECONDITION: secname and targname are non-null + pointers to strings. */ +static int +set_up_section(Dwarf_Debug dbg, + /* Section name from object format. + Might start with .zdebug not .debug if compressed section. */ + const char *secname, + /* Standard section name, such as .debug_info */ + const char *sec_standard_name, + /* Section number from object format */ + Dwarf_Unsigned obj_sec_num, + /* The name associated with this secdata in libdwarf */ + const char *targname, + /* DW_GROUPNUMBER_ANY or BASE or DWO or some other group num */ + unsigned groupnum_of_sec, + struct Dwarf_Section_s *secdata, + int duperr,int emptyerr,int have_dwarf, + int *err) +{ + /* Here accommodate the .debug or .zdebug version, (and of + course non- .debug too, but those never zlib) . + SECNAMEMAX should be a little bigger than any section + name we care about as possibly compressed, which + is to say bigger than any standard section name. */ +#define SECNAMEMAX 30 + int secnamelen = strlen(secname); + /* static const char *dprefix = ".debug_"; */ +#define DPREFIXLEN 7 + static const char *zprefix = ".zdebug_"; +#define ZPREFIXLEN 8 + int havezdebug = FALSE; + int namesmatch = FALSE; + const char *postzprefix = 0; + + /* For example, if the secname is .zdebug_info + we update the finaltargname to .debug_info + to match with the particular (known, predefined) + object section name. + We add one character, so check + to see if it will, in the end, fit. + See the SET_UP_SECTION macro. */ + + if (secnamelen >= SECNAMEMAX) { + /* This is not the target section. + our caller will keep looking. */ + return DW_DLV_NO_ENTRY; + } + havezdebug = !strncmp(secname,zprefix,ZPREFIXLEN); + if (havezdebug) { + postzprefix = secname+ZPREFIXLEN; + } + /* With Alpine gcc + 12.2.1_git20220924-r4) 12.2.1 20220924 + and some other gcc versions when compiling + with -Werror and -fsanitize: + we get + error: 'strcmp' reading 1 or more bytes + from a region of size 0 [-Werror=stringop-overread] + So we add -Wnostringop-overread to the build as the error is + a false positive. */ + if (postzprefix && + !strcmp(postzprefix,targname+DPREFIXLEN)) { + /* zprefix version matches the object section + name so the section is compressed and is + the section this targname applies to. */ + namesmatch = TRUE; + } else if (!strcmp(secname,targname)) { + namesmatch = TRUE; + } else { /* Fall to next statement */ } +#undef ZPREFIXLEN +#undef DPREFIXLEN +#undef SECNAMEMAX + if (!namesmatch) { + /* This is not the target section. + our caller will keep looking. */ + return DW_DLV_NO_ENTRY; + } + + /* SETUP_SECTION. See also BUILDING_SECTIONS, BUILDING_MAP */ + { + /* The section name is a match with targname, or + the .zdebug version of targname. */ + int sectionerr = 0; + + sectionerr = add_debug_section_info(dbg,secname, + sec_standard_name, + obj_sec_num, + secdata, + groupnum_of_sec, + duperr,emptyerr, have_dwarf, + havezdebug,err); + if (sectionerr != DW_DLV_OK) { + /* *err is set already */ + return sectionerr; + } + } + return DW_DLV_OK; +} + +#define SET_UP_SECTION(mdbg,mname,mtarg,mgrp,minfo,me1,me2,mdw,mer) \ + { \ + int lerr = 0; \ + lerr = set_up_section((mdbg), \ + (mname), /* actual section name */ \ + (mtarg), /* std section name */ \ + /* scn_number from macro use context */ \ + scn_number,(mtarg),(mgrp), \ + (minfo), \ + (me1),(me2),(mdw),(mer)); \ + if (lerr != DW_DLV_NO_ENTRY) { \ + return lerr; \ + } /* else fall through. */ \ + } + +/* If running this long set of tests is slow + enough to matter one could set up a local + tsearch tree with all this content and search + it instead of this set of sequential tests. + Or use a switch(){} here with a search tree + to to turn name into index for the switch(). */ +int +_dwarf_enter_section_in_de_debug_sections_array(Dwarf_Debug dbg, + const char *scn_name, + /* This is the number of the section in the object file. */ + Dwarf_Unsigned scn_number, + unsigned group_number, + int *err) +{ + /* Setup the table that contains the basic information about the + sections that are DWARF related. The entries are very unlikely + to change very often. */ + SET_UP_SECTION(dbg,scn_name,".debug_info", + group_number, + &dbg->de_debug_info, + DW_DLE_DEBUG_INFO_DUPLICATE,DW_DLE_DEBUG_INFO_NULL, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_info.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_info, + DW_DLE_DEBUG_INFO_DUPLICATE,DW_DLE_DEBUG_INFO_NULL, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_types", + group_number, + &dbg->de_debug_types, + DW_DLE_DEBUG_TYPES_DUPLICATE,DW_DLE_DEBUG_TYPES_NULL, + TRUE,err); + /* types.dwo is non-standard. DWARF4 GNU maybe. */ + SET_UP_SECTION(dbg,scn_name,".debug_types.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_types, + DW_DLE_DEBUG_TYPES_DUPLICATE,DW_DLE_DEBUG_TYPES_NULL, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_abbrev", + group_number, + &dbg->de_debug_abbrev, /*03*/ + DW_DLE_DEBUG_ABBREV_DUPLICATE,DW_DLE_DEBUG_ABBREV_NULL, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_abbrev.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_abbrev, /*03*/ + DW_DLE_DEBUG_ABBREV_DUPLICATE,DW_DLE_DEBUG_ABBREV_NULL, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_aranges", + group_number, + &dbg->de_debug_aranges, + DW_DLE_DEBUG_ARANGES_DUPLICATE,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_line", + group_number, + &dbg->de_debug_line, + DW_DLE_DEBUG_LINE_DUPLICATE,0, + TRUE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_line_str", + group_number, + &dbg->de_debug_line_str, + DW_DLE_DEBUG_LINE_DUPLICATE,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_line.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_line, + DW_DLE_DEBUG_LINE_DUPLICATE,0, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_frame", + group_number, + &dbg->de_debug_frame, + DW_DLE_DEBUG_FRAME_DUPLICATE,0, + TRUE,err); + /* gnu egcs-1.1.2 data */ + SET_UP_SECTION(dbg,scn_name,".eh_frame", + group_number, + &dbg->de_debug_frame_eh_gnu, + DW_DLE_DEBUG_FRAME_DUPLICATE,0, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_loc", + group_number, + &dbg->de_debug_loc, + DW_DLE_DEBUG_LOC_DUPLICATE,0, + FALSE,err); + /* .debug_loc.dwo would be non-standard. */ + SET_UP_SECTION(dbg,scn_name,".debug_loc.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_loc, + DW_DLE_DEBUG_LOC_DUPLICATE,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_pubnames", + group_number, + &dbg->de_debug_pubnames, + DW_DLE_DEBUG_PUBNAMES_DUPLICATE,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_str", + group_number, + &dbg->de_debug_str, + DW_DLE_DEBUG_STR_DUPLICATE,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_str.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_str, + DW_DLE_DEBUG_STR_DUPLICATE,0, + FALSE,err); + /* Section new in DWARF3. */ + SET_UP_SECTION(dbg,scn_name,".debug_pubtypes", + group_number, + &dbg->de_debug_pubtypes, + /*13*/ DW_DLE_DEBUG_PUBTYPES_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_loclists", + group_number, + &dbg->de_debug_loclists, + /*13*/ DW_DLE_DEBUG_LOClISTS_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_loclists.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_loclists, + /*13*/ DW_DLE_DEBUG_LOClISTS_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_rnglists", + group_number, + &dbg->de_debug_rnglists, + /*13*/ DW_DLE_DEBUG_RNGLISTS_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_rnglists.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_rnglists, + /*13*/ DW_DLE_DEBUG_RNGLISTS_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_str_offsets", + group_number, + &dbg->de_debug_str_offsets, + DW_DLE_DEBUG_STR_OFFSETS_DUPLICATE,0, + FALSE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_str_offsets.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_str_offsets, + DW_DLE_DEBUG_STR_OFFSETS_DUPLICATE,0, + FALSE,err); + + /* SGI IRIX-only. */ + SET_UP_SECTION(dbg,scn_name,".debug_funcnames", + group_number, + &dbg->de_debug_funcnames, + /*11*/ DW_DLE_DEBUG_FUNCNAMES_DUPLICATE,0, + FALSE,err); + /* SGI IRIX-only, created years before DWARF3. Content + essentially identical to .debug_pubtypes. */ + SET_UP_SECTION(dbg,scn_name,".debug_typenames", + group_number, + &dbg->de_debug_typenames, + /*12*/ DW_DLE_DEBUG_TYPENAMES_DUPLICATE,0, + FALSE,err); + /* SGI IRIX-only. */ + SET_UP_SECTION(dbg,scn_name,".debug_varnames", + group_number, + &dbg->de_debug_varnames, + DW_DLE_DEBUG_VARNAMES_DUPLICATE,0, + FALSE,err); + /* SGI IRIX-only. */ + SET_UP_SECTION(dbg,scn_name,".debug_weaknames", + group_number, + &dbg->de_debug_weaknames, + DW_DLE_DEBUG_WEAKNAMES_DUPLICATE,0, + FALSE,err); + + SET_UP_SECTION(dbg,scn_name,".debug_macinfo", + group_number, + &dbg->de_debug_macinfo, + DW_DLE_DEBUG_MACINFO_DUPLICATE,0, + TRUE,err); + /* ".debug_macinfo.dwo" is not allowed. */ + + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_macro", + group_number, + &dbg->de_debug_macro, + DW_DLE_DEBUG_MACRO_DUPLICATE,0, + TRUE,err); + /* DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_macro.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_macro, + DW_DLE_DEBUG_MACRO_DUPLICATE,0, + TRUE,err); + SET_UP_SECTION(dbg,scn_name,".debug_ranges", + group_number, + &dbg->de_debug_ranges, + DW_DLE_DEBUG_RANGES_DUPLICATE,0, + TRUE,err); + /* No .debug_ranges.dwo allowed. */ + + /* New DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_sup", + group_number, + &dbg->de_debug_sup, + DW_DLE_DEBUG_SUP_DUPLICATE,0, + TRUE,err); + /* No .debug_sup.dwo allowed. */ + + /* .symtab and .strtab have to be in any group. */ + SET_UP_SECTION(dbg,scn_name,".symtab", + group_number, + &dbg->de_elf_symtab, + DW_DLE_DEBUG_SYMTAB_ERR,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".strtab", + group_number, + &dbg->de_elf_strtab, + DW_DLE_DEBUG_STRTAB_ERR,0, + FALSE,err); + + /* New DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_addr", + group_number, + &dbg->de_debug_addr, + DW_DLE_DEBUG_ADDR_DUPLICATE,0, + TRUE,err); + /* No .debug_addr.dwo allowed. */ + + /* gdb added this. */ + SET_UP_SECTION(dbg,scn_name,".gdb_index", + group_number, + &dbg->de_debug_gdbindex, + DW_DLE_DUPLICATE_GDB_INDEX,0, + FALSE,err); + + /* New DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_names", + group_number, + &dbg->de_debug_names, + /*13*/ DW_DLE_DEBUG_NAMES_DUPLICATE,0, + FALSE,err); + /* No .debug_names.dwo allowed. */ + + /* gdb added this in DW4. It is in standard DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_cu_index", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_cu_index, + DW_DLE_DUPLICATE_CU_INDEX,0, + FALSE,err); + /* gdb added this in DW4. It is in standard DWARF5 */ + SET_UP_SECTION(dbg,scn_name,".debug_tu_index", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_tu_index, + DW_DLE_DUPLICATE_TU_INDEX,0, + FALSE,err); + + /* GNU added this. It is not part of DWARF */ + SET_UP_SECTION(dbg,scn_name,".gnu_debuglink", + DW_GROUPNUMBER_DWO, + &dbg->de_gnu_debuglink, + DW_DLE_DUPLICATE_GNU_DEBUGLINK,0, + FALSE,err); + + /* GNU added this. It is not part of DWARF */ + SET_UP_SECTION(dbg,scn_name,".note.gnu.build-id", + DW_GROUPNUMBER_DWO, + &dbg->de_note_gnu_buildid, + DW_DLE_DUPLICATE_GNU_DEBUGLINK,0, + FALSE,err); + /* GNU added this. It is not part of DWARF */ + SET_UP_SECTION(dbg,scn_name,".debug_gnu_pubtypes.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_gnu_pubtypes, + DW_DLE_DUPLICATE_GNU_DEBUG_PUBTYPES,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_gnu_pubtypes", + group_number, + &dbg->de_debug_gnu_pubtypes, + DW_DLE_DUPLICATE_GNU_DEBUG_PUBTYPES,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_gnu_pubnames.dwo", + DW_GROUPNUMBER_DWO, + &dbg->de_debug_gnu_pubnames, + DW_DLE_DUPLICATE_GNU_DEBUG_PUBNAMES,0, + FALSE,err); + SET_UP_SECTION(dbg,scn_name,".debug_gnu_pubnames", + group_number, + &dbg->de_debug_gnu_pubnames, + DW_DLE_DUPLICATE_GNU_DEBUG_PUBNAMES,0, + FALSE,err); + return DW_DLV_NO_ENTRY; +} diff --git a/src/lib/libdwarf/dwarf_setup_sections.h b/src/lib/libdwarf/dwarf_setup_sections.h new file mode 100644 index 0000000..15e5d2e --- /dev/null +++ b/src/lib/libdwarf/dwarf_setup_sections.h @@ -0,0 +1,42 @@ +#ifndef DWARF_SETUP_SECTIONS_H +#define DWARF_SETUP_SECTIONS_H +/* Copyright (c) 2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +int _dwarf_enter_section_in_de_debug_sections_array( + Dwarf_Debug dbg, + const char *scn_name, + /* This is the number of the section in the object file. */ + Dwarf_Unsigned scn_number, + unsigned group_number, + int *err); + +#endif /* DWARF_SETUP_SECTIONS_H */ diff --git a/src/lib/libdwarf/dwarf_str_offsets.c b/src/lib/libdwarf/dwarf_str_offsets.c new file mode 100644 index 0000000..fafb14f --- /dev/null +++ b/src/lib/libdwarf/dwarf_str_offsets.c @@ -0,0 +1,684 @@ +/* + Copyright (C) 2018-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the + Free Software Foundation. + + This program is distributed in the hope that it would + be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to + this software file. Patent licenses, if any, provided + herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write + the Free Software Foundation, Inc., 51 Franklin Street - + Fifth Floor, Boston MA 02110-1301, USA. +*/ + +#include + +#include /* NULL size_t */ +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ +#include /* printf */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_string.h" +#include "dwarf_str_offsets.h" + +#define STR_OFFSETS_MAGIC 0x2feed2 + +#define VALIDATE_SOT(xsot) \ + if (!(xsot)) { \ + _dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULLARGUMENT);\ + return DW_DLV_ERROR; \ + } \ + if (!(xsot)->so_dbg) { \ + _dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULL_DBG);\ + return DW_DLV_ERROR; \ + } \ + if ((xsot)->so_magic_value != STR_OFFSETS_MAGIC) { \ + _dwarf_error((xsot)->so_dbg,error, \ + DW_DLE_STR_OFFSETS_NO_MAGIC); \ + return DW_DLV_ERROR; \ + } + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s starting at %p \n",msg,(void*)start); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ + +int +dwarf_open_str_offsets_table_access(Dwarf_Debug dbg, + Dwarf_Str_Offsets_Table * table_data, + Dwarf_Error * error) +{ + int res = 0; + Dwarf_Str_Offsets_Table local_table_data = 0; + Dwarf_Small *offsets_start_ptr = 0; + Dwarf_Unsigned sec_size = 0; + + if (!dbg) { + _dwarf_error(NULL,error,DW_DLE_STR_OFFSETS_NULL_DBG); + return DW_DLV_ERROR; + } + if (!table_data) { + _dwarf_error(dbg,error,DW_DLE_STR_OFFSETS_NULLARGUMENT); + return DW_DLV_ERROR; + } + /* Considered testing for *table_data being NULL, but + not doing such a test. */ + + res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets,error); + if (res != DW_DLV_OK) { + return res; + } + offsets_start_ptr = dbg->de_debug_str_offsets.dss_data; + if (!offsets_start_ptr) { + return DW_DLV_NO_ENTRY; + } + sec_size = dbg->de_debug_str_offsets.dss_size; + local_table_data = (Dwarf_Str_Offsets_Table)_dwarf_get_alloc(dbg, + DW_DLA_STR_OFFSETS,1); + if (!local_table_data) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + local_table_data->so_dbg = dbg; + local_table_data->so_magic_value = STR_OFFSETS_MAGIC; + local_table_data->so_section_start_ptr = offsets_start_ptr; + local_table_data->so_section_end_ptr = offsets_start_ptr + + sec_size; + local_table_data->so_section_size = sec_size; + local_table_data->so_next_table_offset = 0; + local_table_data->so_wasted_section_bytes = 0; + /* get_alloc zeroed all the bits, no need to repeat that here. */ + *table_data = local_table_data; + return DW_DLV_OK; +} + +int +dwarf_close_str_offsets_table_access( + Dwarf_Str_Offsets_Table table_data, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + + VALIDATE_SOT(table_data) + dbg = table_data->so_dbg; + table_data->so_magic_value = 0xdead; + dwarf_dealloc(dbg,table_data, DW_DLA_STR_OFFSETS); + return DW_DLV_OK; +} + +int +dwarf_str_offsets_value_by_index(Dwarf_Str_Offsets_Table sot, + Dwarf_Unsigned index, + Dwarf_Unsigned *stroffset, + Dwarf_Error *error) +{ + Dwarf_Small *entryptr = 0; + Dwarf_Unsigned val = 0; + Dwarf_Unsigned entryoffset = 0; + Dwarf_Unsigned secsize = 0; + Dwarf_Debug dbg = 0; + Dwarf_Small *end_ptr = 0; +/* so_section_size */ + + VALIDATE_SOT(sot) + dbg = sot->so_dbg; + secsize = dbg->de_debug_str_offsets.dss_size; + if (index >= sot->so_array_entry_count) { + return DW_DLV_NO_ENTRY; + } + entryoffset = sot->so_table_start_offset + + sot->so_lcl_offset_to_array; + entryoffset += index*sot->so_array_entry_size; + entryptr = sot->so_section_start_ptr + entryoffset; + if (entryoffset > secsize || + (entryoffset+sot->so_array_entry_size) > secsize) { + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_ARRAY_INDEX_WRONG, + "DW_DLE_STR_OFFSETS_ARRAY_INDEX_WRONG: " + "A libdwarf internal bug. Report to the maintainers"); + return DW_DLV_ERROR; + } + end_ptr = entryptr+sot->so_array_entry_size; + READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned, + entryptr, sot->so_array_entry_size,error,end_ptr); + *stroffset = val; + return DW_DLV_OK; +} + +/* The minimum possible area .debug_str_offsets header . */ +#define MIN_HEADER_LENGTH 8 + +/* New April 2018. + Beginning at starting_offset zero, + returns data about the first table found. + The value *next_table_offset is the value + of the next table (if any), one byte past + the end of the table whose data is returned.. + Returns DW_DLV_NO_ENTRY if the starting offset + is past the end of valid data. + + There is no guarantee that there are no non-0 nonsense + bytes in the section outside of useful tables, + so this can fail and return nonsense or + DW_DLV_ERROR if such garbage exists. +*/ + +static int +is_all_zeroes(Dwarf_Small*start, + Dwarf_Small*end) +{ + if (start >= end) { + /* We should not get here, this is just + a defensive test. */ + return TRUE; + } + for ( ; start < end; ++start) { + if (!*start) { + /* There is some garbage here. */ + return FALSE; + } + } + /* All just zero bytes. */ + return TRUE; +} + +static void +emit_invalid_dw5tab(Dwarf_Debug dbg, + Dwarf_Unsigned headerlen, + Dwarf_Error *error) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_SECTION_SIZE_ERROR: " + "header length 0x%x is too small " + "to be a real .debug_str_offsets " + "DWARF5 section", + headerlen); + _dwarf_error_string(dbg,error, + DW_DLE_SECTION_SIZE_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} +static void +emit_offsets_array_msg(Dwarf_Debug dbg, + Dwarf_Unsigned tab_length, + Dwarf_Unsigned secsize, + Dwarf_Error *error) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_STR_OFFSETS_ARRAY_SIZE: " + " total length 0x%x with table offset larger than ", + tab_length); + dwarfstring_append_printf_u(&m, + ".debug_str_offsets section size of 0x%x." + " Perhaps the section is a GNU DWARF4" + " extension with a different format.", + secsize); + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_ARRAY_SIZE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +static void +emit_wrong_version(Dwarf_Debug dbg, + Dwarf_Half version, + Dwarf_Error *error) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_STR_OFFSETS_VERSION_WRONG: " + "%u. Only version 5 is supported " + "when reading .debug_str_offsets." + " Perhaps the section is a GNU DWARF4" + " extension with a different format.", + version); + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_VERSION_WRONG, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +int +_dwarf_trial_read_dwarf_five_hdr(Dwarf_Debug dbg, + Dwarf_Unsigned new_table_offset, + Dwarf_Unsigned secsize, + Dwarf_Unsigned *table_local_offset_of_array, + Dwarf_Unsigned *total_table_length, + Dwarf_Unsigned *length_out, + Dwarf_Half *local_offset_size_out, + Dwarf_Half *local_extension_size_out, + Dwarf_Half *version_out, + Dwarf_Half *padding_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned length = 0; /* length following the + local_offset_size + local_extension_size */ + Dwarf_Unsigned local_offset_size = 0; + Dwarf_Unsigned local_extension_size = 0; + Dwarf_Unsigned tab_length = 0; + Dwarf_Unsigned array_local_offset = 0; + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + Dwarf_Unsigned globloff = 0; + Dwarf_Unsigned net_end_offset = 0; + Dwarf_Small *secstart = dbg->de_debug_str_offsets.dss_data; + Dwarf_Small *table_start_ptr = secstart + new_table_offset; + Dwarf_Small *secendptr = secstart+secsize; + + READ_AREA_LENGTH_CK(dbg,length,Dwarf_Unsigned, + table_start_ptr,local_offset_size, + local_extension_size,error, + secsize,secendptr); + /* The 'length' part of any header is + local_extension_size + local_offset_size. + The length of an offset in the section is just + local_offset_size. + Standard DWARF2 sums to 4. + Standard DWARF3,4,5 sums to 4 or 12. + Nonstandard SGI IRIX 64bit dwarf sums to 8 (SGI IRIX + was all DWARF2 and could not have a .debug_str_offsets + section). + The header includes 2 bytes of version and two bytes + of padding. */ + if (length < 4) { + /* Usually DW4-style .debug_str_offsets + starts off with a zero value to ref the + base string in .debug_str. Should not apply here. + Any tiny value is guaranteed not to be a legal + DWARF5 .debug_str_offsets section. */ + emit_invalid_dw5tab(dbg,length,error); + return DW_DLV_ERROR; + } + globloff = new_table_offset; + array_local_offset = local_extension_size +local_offset_size + +4; /* 4 for the two Dwarf_Half in the table header */ + tab_length = local_extension_size +local_offset_size + + length; + + net_end_offset = tab_length+globloff; + + if (length > secsize || + array_local_offset > secsize || + tab_length > secsize || + net_end_offset > secsize) { + emit_offsets_array_msg(dbg,tab_length, + secsize,error); + return DW_DLV_ERROR; + } + /* table_start_ptr is incremented past + the length data by read-area-length-ck. */ + READ_UNALIGNED_CK(dbg, version, Dwarf_Half, + table_start_ptr, DWARF_HALF_SIZE, + error,secendptr); + table_start_ptr += DWARF_HALF_SIZE; + if (version != DW_STR_OFFSETS_VERSION5) { + emit_wrong_version(dbg,version,error); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg, padding, Dwarf_Half, + table_start_ptr, DWARF_HALF_SIZE, + error,secendptr); + + /* padding should be zero, but we are + not checking it here at present. */ + *table_local_offset_of_array = array_local_offset; + *total_table_length = tab_length; + *length_out = length; + *local_offset_size_out = local_offset_size; + *local_extension_size_out = local_extension_size; + *version_out = version; + *padding_out = padding; + return DW_DLV_OK; +} + +/* Used by code reading attributes/forms and + also by code reading the raw .debug_str_offsets + section, hence the code allows for + output arguments to be zero. + If cucontext is null it means the call part + of trying to print the section without + accessing any context. dwarfdump option + --print-str-offsets. + New 30 August 2020. */ +int +_dwarf_read_str_offsets_header(Dwarf_Str_Offsets_Table sot, + Dwarf_CU_Context cucontext, + /* Followed by return values/error */ + Dwarf_Unsigned *length_out, + Dwarf_Half *offset_size_out, + Dwarf_Half *extension_size_out, + Dwarf_Half *version_out, + Dwarf_Half *padding_out, + Dwarf_Unsigned *local_offset_to_array_out, + Dwarf_Unsigned *total_table_length_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned length = 0; + Dwarf_Half local_offset_size = 0; + Dwarf_Half local_extension_size = 0; + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + int res = 0; + Dwarf_Bool is_dwarf_five = TRUE; + Dwarf_Debug dbg = sot->so_dbg; + Dwarf_Unsigned secsize = sot->so_section_size; + Dwarf_Unsigned table_local_offset_of_array = 0; + Dwarf_Unsigned total_table_length = 0; + Dwarf_Unsigned globaltaboff = 0; + + globaltaboff = sot->so_next_table_offset; + if (cucontext) { + if (cucontext->cc_str_offsets_tab_present) { + /* cu_context has what it needs already and we do + not need the rest of what the interface + provides */ + return DW_DLV_OK; + } + } + res = _dwarf_trial_read_dwarf_five_hdr(dbg, + globaltaboff, + secsize, + &table_local_offset_of_array, + &total_table_length, + /* Length is the length field from the table involved */ + &length, + &local_offset_size, + &local_extension_size, + &version, + &padding, + error); + if (res != DW_DLV_OK) { + if (res == DW_DLV_ERROR && error) { + dwarf_dealloc_error(dbg,*error); + *error = 0; + } + /* If it's really DWARF5 but with a serious + problem this will think...NOT 5! */ + is_dwarf_five = FALSE; + } + if ( !is_dwarf_five) { + length = secsize; + /* This is possibly + GNU Dwarf4 extension .debug_str_offsets. + It could also just be corrupted data. + offset size is not going to be 8. + de_length_size is a guess and not set at this point . + We assume the data starts with the array + of string offsets, + and all in one simple array from start to end + of section. */ + table_local_offset_of_array = 0; + total_table_length = secsize; + length = secsize; + local_offset_size = 4; + local_extension_size = 0; + version = DW_STR_OFFSETS_VERSION4; + padding = 0; + } + + if (length_out) { + *length_out = length; + } + if (offset_size_out) { + *offset_size_out = local_offset_size; + } + if (extension_size_out) { + *extension_size_out = local_extension_size; + } + if (version_out) { + *version_out = version; + } + if (padding_out) { + *padding_out = padding; + } + if (cucontext) { + cucontext->cc_str_offsets_header_offset = globaltaboff; + cucontext->cc_str_offsets_tab_present = TRUE; + cucontext->cc_str_offsets_tab_to_array = + table_local_offset_of_array; + cucontext->cc_str_offsets_version = version; + cucontext->cc_str_offsets_offset_size = local_offset_size; + cucontext->cc_str_offsets_table_size = total_table_length; + } + if (local_offset_to_array_out) { + *local_offset_to_array_out = table_local_offset_of_array; + } + if (total_table_length_out) { + *total_table_length_out = total_table_length; + } + return DW_DLV_OK; +} + +int +dwarf_next_str_offsets_table(Dwarf_Str_Offsets_Table sot, + Dwarf_Unsigned *unit_length_out, + Dwarf_Unsigned *unit_length_offset_out, + Dwarf_Unsigned *table_start_offset_out, + Dwarf_Half *entry_size_out, + Dwarf_Half *version_out, + Dwarf_Half *padding_out, + Dwarf_Unsigned *table_value_count_out, + Dwarf_Error * error) +{ + + Dwarf_Small *table_header_ptr = 0; + Dwarf_Unsigned table_header_offset = 0; + Dwarf_Unsigned table_end_offset = 0; + Dwarf_Unsigned array_start_offset = 0; + Dwarf_Unsigned length = 0; + Dwarf_Half local_length_size = 0; + Dwarf_Half local_extension_size = 0; + Dwarf_Half version = 0; + Dwarf_Half padding = 0; + Dwarf_Unsigned local_offset_to_array= 0; + Dwarf_Unsigned total_table_length = 0; + Dwarf_Debug dbg = sot->so_dbg; + int res = 0; + + VALIDATE_SOT(sot) + + table_header_offset = sot->so_next_table_offset; + if (table_header_offset >= sot->so_section_size) { + return DW_DLV_NO_ENTRY; + } + table_header_ptr = sot->so_section_start_ptr + + table_header_offset; + if (table_header_offset >= sot->so_section_size) { + if (table_header_ptr == sot->so_section_end_ptr) { + /* At end of section. Done. */ + return DW_DLV_NO_ENTRY; + } else { + /* bogus table offset. */ + Dwarf_Unsigned len = 0; + dwarfstring m; + + len = (sot->so_section_end_ptr >= table_header_ptr)? + (Dwarf_Unsigned)(uintptr_t)sot->so_section_end_ptr - + (Dwarf_Unsigned)(uintptr_t)table_header_ptr: + (Dwarf_Unsigned)0xffffffff; + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "DW_DLE_STR_OFFSETS_EXTRA_BYTES: " + "Table Offset is %" DW_PR_DSd + " bytes past end of section",len); + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_EXTRA_BYTES, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + } + + if ((table_header_ptr + MIN_HEADER_LENGTH) > + sot->so_section_end_ptr) { + + /* We have a too-short section it appears. + Should we generate error? Or ignore? + As of March 10 2020 we check for garbage + bytes in-section. */ + dwarfstring m; + Dwarf_Small *hend = 0; + Dwarf_Unsigned len = 0; + + if (is_all_zeroes(table_header_ptr,sot->so_section_end_ptr)){ + return DW_DLV_NO_ENTRY; + } + hend = table_header_ptr + MIN_HEADER_LENGTH; + len = (hend >= sot->so_section_end_ptr)? + (Dwarf_Unsigned)(uintptr_t)sot->so_section_end_ptr - + (Dwarf_Unsigned)(uintptr_t)table_header_ptr: + (Dwarf_Unsigned)0xffffffff; + dwarfstring_constructor(&m); + dwarfstring_append_printf_i(&m, + "DW_DLE_STR_OFFSETS_EXTRA_BYTES: " + "Table Offset plus a minimal header is %" + DW_PR_DSd + " bytes past end of section" + " and some bytes in-section are non-zero",len); + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_EXTRA_BYTES, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + res = _dwarf_read_str_offsets_header(sot, + 0 /* cu_context */, + &length, + &local_length_size, + &local_extension_size, + &version, + &padding, + &local_offset_to_array, + &total_table_length, error); + if (res != DW_DLV_OK) { + return res; + } + if (version == DW_STR_OFFSETS_VERSION5) { + /* header_length includes length field plus 4 for + the rest of the header. Don't double count! + length includes space for 4 bytes of the header! */ + array_start_offset = table_header_offset + + local_offset_to_array; + table_end_offset = array_start_offset + total_table_length; + } else { + Dwarf_Unsigned space_left = 0; + + /* leave table header offset as-is */ + space_left = sot->so_section_size - table_header_offset; + array_start_offset = table_header_offset; + table_end_offset = table_header_offset + space_left; + } + { + Dwarf_Unsigned entrycount = 0; + Dwarf_Unsigned entrybytes = 0; + + entrybytes = table_end_offset - array_start_offset; + if (entrybytes % local_length_size) { + _dwarf_error_string(dbg,error, + DW_DLE_STR_OFFSETS_ARRAY_SIZE, + "DW_DLE_STR_OFFSETS_ARRAY_SIZE " + " array size not a multiple of the size of " + "a single entry"); + return DW_DLV_ERROR; + } + entrycount = entrybytes/local_length_size; + + /* On the next table loop this will be the new table offset */ + sot->so_next_table_offset = table_end_offset; + + sot->so_table_end_offset = table_end_offset; + sot->so_table_start_offset = table_header_offset; + sot->so_table_end_offset = table_header_offset+ + total_table_length; + sot->so_array_entry_count = entrycount; + sot->so_array_entry_size = local_length_size; + sot->so_table_count += 1; + + /* The data length in bytes following the unit_length field + of the header. includes any other header bytes + and the table space */ + *unit_length_out = length; + + /* Where the unit_length field starts in the section. */ + *unit_length_offset_out = sot->so_table_start_offset; + + /* Where the table of offsets starts in the section. */ + *table_start_offset_out = sot->so_table_start_offset; + + /* Entrysize: 4 or 8 */ + *entry_size_out = local_length_size; + + /* Version is 5. */ + *version_out = version; + + /* This is supposed to be zero. */ + *padding_out = padding; + + /* How many entry_size entries are in the array. */ + *table_value_count_out = entrycount; + return DW_DLV_OK; + } +} + +/* Meant to be called after all tables accessed using + dwarf_next_str_offsets_table(). */ +int +dwarf_str_offsets_statistics(Dwarf_Str_Offsets_Table table_data, + Dwarf_Unsigned * wasted_byte_count, + Dwarf_Unsigned * table_count, + Dwarf_Error * error) +{ + VALIDATE_SOT(table_data) + if (wasted_byte_count) { + *wasted_byte_count = table_data->so_wasted_section_bytes; + } + if (table_count) { + *table_count = table_data->so_table_count; + } + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_str_offsets.h b/src/lib/libdwarf/dwarf_str_offsets.h new file mode 100644 index 0000000..ef39fb3 --- /dev/null +++ b/src/lib/libdwarf/dwarf_str_offsets.h @@ -0,0 +1,104 @@ +#ifndef DWARF_STR_OFFSETS_H +#define DWARF_STR_OFFSETS_H +/* + Copyright (C) 2023 David Anderson + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of + the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. + Any license provided herein, whether implied or + otherwise, applies only to this software file. + Patent licenses, if any, provided herein do not + apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston MA 02110-1301, + USA. + +*/ + +struct Dwarf_Str_Offsets_Table_s { + /* pointers are to dwarf-memory valid till Dwarf_Debug + is closed.. None are to be deallocated. */ + Dwarf_Unsigned so_magic_value; + Dwarf_Debug so_dbg; + + /* Section data. */ + Dwarf_Small *so_section_start_ptr; + Dwarf_Small *so_section_end_ptr; + Dwarf_Unsigned so_section_size; + /* Overall data about wasted space in the section. */ + Dwarf_Unsigned so_wasted_section_bytes; + /* The number of tables processed in the section. */ + Dwarf_Unsigned so_table_count; + + /* Used to iterate through the section getting + to each table */ + Dwarf_Unsigned so_next_table_offset; + + /* Per table (ie, a table is a + header and array of offsets) inside the section. + Offset to first byte of a table + Offset one past last byte of a table. + Offset from first byte of table to its array. + Count of entries in the array + Size of each enntry in the array. */ + Dwarf_Unsigned so_table_start_offset; + Dwarf_Unsigned so_table_end_offset; + Dwarf_Unsigned so_lcl_offset_to_array; + Dwarf_Unsigned so_array_entry_count; + Dwarf_Half so_array_entry_size; + +}; +int _dwarf_extract_string_offset_via_str_offsets(Dwarf_Debug dbg, + Dwarf_Small *data_ptr, + Dwarf_Small *end_data_ptr, + Dwarf_Half attrform, + Dwarf_CU_Context cu_context, + Dwarf_Unsigned *str_sect_offset_out, + Dwarf_Error *error); + +int +_dwarf_read_str_offsets_header(Dwarf_Str_Offsets_Table sot, + Dwarf_CU_Context cucontext, + /* Followed by return values/error */ + Dwarf_Unsigned *length, + Dwarf_Half *offset_size_out, + Dwarf_Half *extension_size_out, + Dwarf_Half *version_out, + Dwarf_Half *padding_out, + Dwarf_Unsigned *local_offset_to_array_out, + Dwarf_Unsigned *total_table_length_out, + Dwarf_Error *error); + +int _dwarf_trial_read_dwarf_five_hdr(Dwarf_Debug dbg, + Dwarf_Unsigned table_start_offset, + Dwarf_Unsigned secsize, + Dwarf_Unsigned *table_local_offset_of_array, + Dwarf_Unsigned *total_table_length, + /* length_out is the initial DWARF length value + from the table header. */ + Dwarf_Unsigned *length_out, + Dwarf_Half *local_offset_size_out, + Dwarf_Half *local_extension_size_out, + Dwarf_Half *version_out, + Dwarf_Half *padding_out, + Dwarf_Error *error); +int +_dwarf_find_all_offsets_via_fission(Dwarf_Debug dbg, + Dwarf_CU_Context cu_context, + Dwarf_Error *error); + +#endif /* DWARF_STR_OFFSETS_H */ diff --git a/src/lib/libdwarf/dwarf_string.c b/src/lib/libdwarf/dwarf_string.c new file mode 100644 index 0000000..26a34aa --- /dev/null +++ b/src/lib/libdwarf/dwarf_string.c @@ -0,0 +1,863 @@ +/* +Copyright (c) 2019-2019, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* A lighly generalized data buffer. + Works for more than just strings, + but has features (such as ensuring + data always has a NUL byte following + the data area used) most useful for C strings. + + All these return either TRUE (the values altered) + or FALSE (something went wrong, quite likely + the caller presented a bad format string for the + value). Normally a string like + DWARFSTRINGERR is stuck in the output in case of error. + +*/ + +#include + +#include /* free() malloc() strtol() */ +#include /* memcpy() strlen() */ + +#include "libdwarf_private.h" +#include "dwarf_string.h" + +/* m must be a string, like "DWARFSTRINGERR..." for this to work */ +#define DWSERR(m) dwarfstring_append_length(data,(m),sizeof(m)-1) + +static unsigned long minimumnewlen = 30; + +int +dwarfstring_constructor(struct dwarfstring_s *g) +{ + g->s_data = ""; + g->s_size = 0; + g->s_avail = 0; + g->s_malloc = FALSE; + return TRUE; +} + +static int +dwarfstring_resize_to(struct dwarfstring_s *g,size_t newlen) +{ + char *b = 0; + size_t lastpos = g->s_size - g->s_avail; + size_t malloclen = newlen+1; + + if (malloclen < minimumnewlen) { + malloclen = minimumnewlen; + } + b = malloc(malloclen); + if (!b) { + return FALSE; + } + if (lastpos > 0) { + memcpy(b,g->s_data,lastpos); + } + if (g->s_malloc) { + free(g->s_data); + g->s_data = 0; + } + g->s_data = b; + g->s_data[lastpos] = 0; + g->s_size = newlen; + g->s_avail = newlen - lastpos; + g->s_malloc = TRUE; + return TRUE; +} + +int +dwarfstring_reset(struct dwarfstring_s *g) +{ + if (!g->s_size) { + /* In initial condition, nothing to do. */ + return TRUE; + } + g->s_avail = g->s_size; + g->s_data[0] = 0; + return TRUE; +} + +int +dwarfstring_constructor_fixed(struct dwarfstring_s *g, + size_t len) +{ + int r = FALSE; + + dwarfstring_constructor(g); + if (len == 0) { + return TRUE; + } + r = dwarfstring_resize_to(g,len); + if (!r) { + return FALSE; + } + return TRUE; +} + +int +dwarfstring_constructor_static(struct dwarfstring_s *g, + char * space, + size_t len) +{ + dwarfstring_constructor(g); + g->s_data = space; + g->s_data[0] = 0; + g->s_size = len; + g->s_avail = len; + g->s_malloc = FALSE; + return TRUE; +} + +void +dwarfstring_destructor(struct dwarfstring_s *g) +{ + if (g->s_malloc) { + free(g->s_data); + g->s_data = 0; + g->s_malloc = 0; + } + /* The constructor sets all the fields, most to zero. + s_data is set to point to static string "" + s_malloc set to FALSE. */ + dwarfstring_constructor(g); +} + +/* For the case where one wants just the first 'len' + characters of 'str'. NUL terminator provided + for you in s_data. +*/ +int +dwarfstring_append_length(struct dwarfstring_s *g,char *str, + size_t slen) +{ + size_t lastpos = g->s_size - g->s_avail; + int r = 0; + + if (!str || slen ==0) { + return TRUE; + } + if (slen >= g->s_avail) { + size_t newlen = 0; + + newlen = g->s_size + slen+2; + r = dwarfstring_resize_to(g,newlen); + if (!r) { + /* Unable to resize, dare not do anything. */ + return FALSE; + } + } + memcpy(g->s_data + lastpos,str,slen); + g->s_avail -= slen; + g->s_data[g->s_size - g->s_avail] = 0; + return TRUE; +} + +int +dwarfstring_append(struct dwarfstring_s *g,char *str) +{ + size_t dlenszt = 0; + + if (!str) { + return TRUE; + } + dlenszt = strlen(str); + return dwarfstring_append_length(g,str,dlenszt); +} + +char * +dwarfstring_string(struct dwarfstring_s *g) +{ + return g->s_data; +} + +size_t +dwarfstring_strlen(struct dwarfstring_s *g) +{ + return g->s_size - g->s_avail; +} + +static int +_dwarfstring_append_spaces(dwarfstring *data, + size_t count) +{ + int res = 0; + char spacebuf[] = {" "}; + size_t charct = sizeof(spacebuf)-1; + size_t l = count; + + while (l > charct) { + res = dwarfstring_append_length(data,spacebuf,charct); + l -= charct; + if (res != TRUE) { + return res; + } + } + /* ASSERT: l > 0 */ + res = dwarfstring_append_length(data,spacebuf,l); + return res; +} +static int +_dwarfstring_append_zeros(dwarfstring *data, size_t l) +{ + int res = 0; + static char zeros[] = { + "0000000000000000000000000000000000000000"}; + size_t charct = sizeof(zeros)-1; + + while (l > charct) { + res = dwarfstring_append_length(data,zeros,charct); + l -= charct; + if (res != TRUE) { + return res; + } + } + /* ASSERT: l > 0 */ + dwarfstring_append_length(data,zeros,l); + return res; +} + +int dwarfstring_append_printf_s(dwarfstring *data, + char *format,char *s) +{ + size_t stringlenszt = 0; + size_t next = 0; + long val = 0; + char *endptr = 0; + const char *numptr = 0; + /* was %[-]fixedlen. Zero means no len provided. */ + size_t fixedlen = 0; + /* was %-, nonzero means left-justify */ + long leftjustify = 0; + size_t prefixlen = 0; + int res = 0; + + if (!s) { + DWSERR(""); + return FALSE; + } + stringlenszt = strlen(s); + if (!format) { + DWSERR(""); + return FALSE; + } + while (format[next] && format[next] != '%') { + ++next; + ++prefixlen; + } + if (prefixlen) { + dwarfstring_append_length(data,format,prefixlen); + /* Fall through whether return value TRUE or FALSE */ + } + if (format[next] != '%') { + /* No % operator found, we are done */ + DWSERR(""); + return FALSE; + } + next++; + if (!format[next]) { + DWSERR(""); + return FALSE; + } + if (format[next] == ' ') { + DWSERR(""); + return FALSE; + } + + if (format[next] == '-') { + leftjustify++; + next++; + } + numptr = format+next; + val = strtol(numptr,&endptr,10); + if ( endptr != numptr) { + fixedlen = val; + } + next = (endptr - format); + if (format[next] != 's') { + DWSERR(""); + return FALSE; + } + next++; + + if (fixedlen && (stringlenszt >= fixedlen)) { + /* Ignore leftjustify (if any) and the stringlenszt + as the actual string overrides those. */ + leftjustify = 0; + } + if (leftjustify) { + + dwarfstring_append_length(data,s,stringlenszt); + /* Ignore return value */ + if (fixedlen) { + size_t trailingspaces = fixedlen - stringlenszt; + + _dwarfstring_append_spaces(data,trailingspaces); + } + } else { + if (fixedlen && fixedlen < stringlenszt) { + /* This lets us have fixedlen < stringlenszt by + taking all the chars from s*/ + dwarfstring_append_length(data,s,stringlenszt); + /* Ignore return value, just keep going */ + } else { + if (fixedlen) { + size_t leadingspaces = fixedlen - stringlenszt; + size_t k = 0; + + for ( ; k < leadingspaces; ++k) { + dwarfstring_append_length(data," ",1); + } + } + res = dwarfstring_append_length(data,s,stringlenszt); + if (res == FALSE) { + return res; + } + } + } + if (!format[next]) { + return TRUE; + } + { + char * startpt = format+next; + size_t suffixlen = strlen(startpt); + + res = dwarfstring_append_length(data,startpt,suffixlen); + } + return res; +} + +static char v32m[] = {"-2147483648"}; +static char v64m[] = {"-9223372036854775808"}; +static char dtable[10] = { +'0','1','2','3','4','5','6','7','8','9' +}; +static char xtable[16] = { +'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' +}; +static char Xtable[16] = { +'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' +}; + +/* We deal with formats like: + %d %5d %05d %+d %+5d %-5d (and ld and lld too). */ +int dwarfstring_append_printf_i(dwarfstring *data, + char *format, + dwarfstring_i v) +{ + int res = TRUE; + size_t next = 0; + long val = 0; + char *endptr = 0; + const char *numptr = 0; + size_t fixedlen = 0; + int leadingzero = 0; + int minuscount = 0; /*left justify */ + int pluscount = 0; + int lcount = 0; + int ucount = 0; + int dcount = 0; + int xcount = 0; + int Xcount = 0; + char *ctable = dtable; + size_t prefixlen = 0; + int done = 0; + + if (!format) { + DWSERR(""); + return FALSE; + } + while (format[next] && format[next] != '%') { + ++next; + ++prefixlen; + } + dwarfstring_append_length(data,format,prefixlen); + if (format[next] != '%') { + /* No % operator found, we are done */ + DWSERR(""); + return FALSE; + } + next++; + if (!format[next]) { + DWSERR(""); + return FALSE; + } + if (format[next] == ' ') { + DWSERR(""); + return FALSE; + } + if (format[next] == '-') { + minuscount++; + next++; + } + if (format[next] == '+') { + pluscount++; + next++; + } + if (format[next] == '-') { + minuscount++; + next++; + } + if (format[next] == '0') { + leadingzero = 1; + next++; + } + numptr = format+next; + val = strtol(numptr,&endptr,10); + if ( endptr != numptr) { + fixedlen = val; + } + next = (endptr - format); + /* Following is lx lu or u or llx llu , we take + all this to mean 64 bits, */ +#ifdef _WIN32 + if (format[next] == 'I') { + /*lcount++;*/ + next++; + } + if (format[next] == '6') { + /*lcount++;*/ + next++; + } + if (format[next] == '4') { + /*lcount++;*/ + next++; + } +#endif /* _WIN32 */ + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'u') { + ucount++; + next++; + } + if (format[next] == 'd') { + dcount++; + next++; + } + if (format[next] == 'x') { + xcount++; + next++; + } + if (format[next] == 'X') { + Xcount++; + next++; + } + if (format[next] == 's') { + DWSERR( ""); + return FALSE; + } + if (xcount || Xcount) { + /* Use the printf_u for %x and the like + just copying the entire format makes + it easier for coders to understand + nothing much was done */ + DWSERR(""); + return FALSE; + } + if (!dcount || (lcount >2) || + (Xcount+xcount+dcount+ucount) > 1) { + /* error */ + DWSERR( ""); + return FALSE; + } + if (pluscount && minuscount) { + /* We don't allow format +- */ + DWSERR(""); + return FALSE; + } + { + char digbuf[36]; + char *digptr = digbuf+sizeof(digbuf) -1; + size_t digcharlen = 0; + dwarfstring_i remaining = v; + int vissigned = 0; + dwarfstring_i divisor = 10; + + *digptr = 0; + --digptr; + if (v < 0) { + vissigned = 1; + /* This test is for twos-complement + machines and would be better done via + configure with a compile-time check + so we do not need a size test at runtime. */ + if (sizeof(v) == 8) { + dwarfstring_u vm = 0x7fffffffffffffffULL; + if (vm == (dwarfstring_u)~v) { + memcpy(digbuf,v64m,sizeof(v64m)); + digcharlen = sizeof(v64m)-1; + digptr = digbuf; + done = 1; + } else { + remaining = -v; + } + } else if (sizeof(v) == 4) { + dwarfstring_u vm = 0x7fffffffL; + if (vm == (dwarfstring_u)~v) { + memcpy(digbuf,v32m,sizeof(v32m)); + digcharlen = sizeof(v32m)-1; + digptr = digbuf; + done = 1; + } else { + remaining = -v; + } + }else { + DWSERR(""); + return FALSE; + } + } + if (!done) { + for ( ;; ) { + dwarfstring_u dig = 0; + + dig = remaining % divisor; + remaining /= divisor; + *digptr = ctable[dig]; + digcharlen++; + if (!remaining) { + break; + } + --digptr; + } + if (vissigned) { /* could check minuscount instead */ + --digptr; + digcharlen++; + *digptr = '-'; + } else if (pluscount) { + --digptr; + digcharlen++; + *digptr = '+'; + } else { /* Fall through */ } + } + if (fixedlen > 0) { + if (fixedlen <= digcharlen) { + dwarfstring_append_length(data,digptr,digcharlen); + } else { + size_t prefixcount = fixedlen - digcharlen; + if (!leadingzero) { + _dwarfstring_append_spaces(data,prefixcount); + dwarfstring_append_length(data,digptr,digcharlen); + } else { + if (*digptr == '-') { + dwarfstring_append_length(data,"-",1); + _dwarfstring_append_zeros(data,prefixcount); + digptr++; + dwarfstring_append_length(data,digptr, + digcharlen-1); + } else if (*digptr == '+') { + dwarfstring_append_length(data,"+",1); + _dwarfstring_append_zeros(data,prefixcount); + digptr++; + dwarfstring_append_length(data,digptr, + digcharlen-1); + } else { + _dwarfstring_append_zeros(data,prefixcount); + dwarfstring_append_length(data,digptr, + digcharlen); + } + } + } + } else { + res = dwarfstring_append_length(data,digptr,digcharlen); + } + } + if (format[next]) { + size_t trailinglen = strlen(format+next); + res = dwarfstring_append_length(data,format+next,trailinglen); + } + return res; +} + +#if 0 +/* Counts hex chars. divide by two to get bytes from input + integer. */ +static unsigned +trimleadingzeros(char *ptr,size_t digits,unsigned keepcount) +{ + char *cp = ptr; + size_t leadzeroscount = 0; + size_t trimoff = 0; + + for (; *cp; ++cp) { + if (*cp == '0') { + leadzeroscount++; + continue; + } + } + trimoff = keepcount - digits; + if (trimoff&1) { + trimoff--; + } + return trimoff; +} +#endif /*0*/ + +/* With gcc version 5.4.0 20160609 a version using + const char *formatp instead of format[next] + and deleting the 'next' variable + is a few hundredths of a second slower, repeatably. + + We deal with formats like: + %u %5u %05u (and ld and lld too). + %x %5x %05x (and ld and lld too). */ + +int dwarfstring_append_printf_u(dwarfstring *data, + char *format, + dwarfstring_u v) +{ + + size_t next = 0; + long val = 0; + char *endptr = 0; + const char *numptr = 0; + size_t fixedlen = 0; + int leadingzero = 0; + int lcount = 0; + int ucount = 0; + int dcount = 0; + int xcount = 0; + int Xcount = 0; + char *ctable = 0; + size_t divisor = 0; + size_t prefixlen = 0; + + if (!format) { + DWSERR(""); + return FALSE; + } + while (format[next] && format[next] != '%') { + ++next; + ++prefixlen; + } + dwarfstring_append_length(data,format,prefixlen); + if (format[next] != '%') { + /* No % operator found, we are done */ + DWSERR(""); + return FALSE; + } + next++; + if (!format[next]) { + DWSERR(""); + return FALSE; + } + if (format[next] == ' ') { + DWSERR(""); + return FALSE; + } + if (format[next] == '-') { + DWSERR(""); + return FALSE; + } + if (format[next] == '0') { + leadingzero = 1; + next++; + } + numptr = format+next; + val = strtol(numptr,&endptr,10); + if ( endptr != numptr) { + fixedlen = val; + } + next = (endptr - format); + /* Following is lx lu or u or llx llu , we take + all this to mean 64 bits, */ +#ifdef _WIN32 + if (format[next] == 'I') { + /*lcount++;*/ + next++; + } + if (format[next] == '6') { + /*lcount++;*/ + next++; + } + if (format[next] == '4') { + /*lcount++;*/ + next++; + } +#endif /* _WIN32 */ + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'l') { + lcount++; + next++; + } + if (format[next] == 'u') { + ucount++; + next++; + } + if (format[next] == 'd') { + dcount++; + next++; + } + if (format[next] == 'x') { + xcount++; + next++; + } + if (format[next] == 'X') { + Xcount++; + next++; + } + if (format[next] == 's') { + DWSERR(""); + return FALSE; + } + if ( (Xcount +xcount+dcount+ucount) > 1) { + DWSERR(""); + return FALSE; + } + if ( (Xcount +xcount+dcount+ucount) == 0) { + DWSERR(""); + return FALSE; + } + if (lcount > 2) { + DWSERR(""); + return FALSE; + } + if (dcount > 0) { + DWSERR(""); + return FALSE; + } + if (ucount) { + divisor = 10; + ctable = dtable; + } else { + divisor = 16; + if (xcount) { + ctable = xtable; + } else { + ctable = Xtable; + } + } + { + char digbuf[36]; + char *digptr = 0; + unsigned digcharlen = 0; + dwarfstring_u remaining = v; + + if (divisor == 16) { + digptr = digbuf+sizeof(digbuf) -1; + for ( ;; ) { + dwarfstring_u dig; + dig = remaining & 0xf; + remaining = remaining >> 4; + *digptr = ctable[dig]; + ++digcharlen; + if (!remaining) { + break; + } + --digptr; + } + } else { + digptr = digbuf+sizeof(digbuf) -1; + *digptr = 0; + --digptr; + for ( ;; ) { + dwarfstring_u dig; + dig = remaining % divisor; + remaining /= divisor; + *digptr = ctable[dig]; + ++digcharlen; + if (!remaining) { + break; + } + --digptr; + } + } + if (fixedlen <= digcharlen) { + dwarfstring_append_length(data,digptr,digcharlen); + } else { + if (!leadingzero) { + size_t justcount = fixedlen - digcharlen; + _dwarfstring_append_spaces(data,justcount); + dwarfstring_append_length(data,digptr,digcharlen); + } else { + size_t prefixcount = fixedlen - digcharlen; + _dwarfstring_append_zeros(data,prefixcount); + dwarfstring_append_length(data,digptr,digcharlen); + } + } + } + if (format[next]) { + size_t trailinglen = strlen(format+next); + dwarfstring_append_length(data,format+next,trailinglen); + } + return FALSE; +} diff --git a/src/lib/libdwarf/dwarf_string.h b/src/lib/libdwarf/dwarf_string.h new file mode 100644 index 0000000..e722b11 --- /dev/null +++ b/src/lib/libdwarf/dwarf_string.h @@ -0,0 +1,93 @@ +/* +Copyright (c) 2019-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* A lightly generalized string buffer for libdwarf. + The functions that return anything return either + TRUE (nonzero int) or FALSE (zero) + + On return of FALSE the dwarfstring_s struct + remains in a usable state. + + It is expected that most users will not check the + return value. +*/ +#ifndef DWARFSTRING_H +#define DWARFSTRING_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct dwarfstring_s { + char * s_data; + size_t s_size; + size_t s_avail; + unsigned char s_malloc; +}; + +typedef unsigned long long dwarfstring_u; +typedef signed long long dwarfstring_i; +typedef struct dwarfstring_s dwarfstring; + +int dwarfstring_constructor(struct dwarfstring_s *g); +int dwarfstring_constructor_fixed(struct dwarfstring_s *g, + size_t len); + +/* When you have an output of a limited length string + and can allocate a local array to hold it, + dwarfstring_constructor_static() is good since no malloc + is used unless the final string length exceeds the buffer + length. */ +int dwarfstring_constructor_static(struct dwarfstring_s *g, + char * space, size_t len); +void dwarfstring_destructor(struct dwarfstring_s *g); +int dwarfstring_reset(struct dwarfstring_s *g); + +int dwarfstring_append(struct dwarfstring_s *g,char *str); + +/* When one wants the first 'len' characters of str + appended. NUL termination is provided by dwarfstrings. */ +int dwarfstring_append_length(struct dwarfstring_s *g, + char *str,size_t len); + +int dwarfstring_append_printf_s(dwarfstring *data, + char *format,char *s); +int dwarfstring_append_printf_i(dwarfstring *data, + char *format,dwarfstring_i); +int dwarfstring_append_printf_u(dwarfstring *data, + char *format,dwarfstring_u); + +char * dwarfstring_string(struct dwarfstring_s *g); +size_t dwarfstring_strlen(struct dwarfstring_s *g); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DWARFSTRING_H */ diff --git a/src/lib/libdwarf/dwarf_stringsection.c b/src/lib/libdwarf/dwarf_stringsection.c new file mode 100644 index 0000000..930690b --- /dev/null +++ b/src/lib/libdwarf/dwarf_stringsection.c @@ -0,0 +1,100 @@ +/* + Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2009-2020 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* NULL, size_t */ +#include /* strlen() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_error.h" +#include "dwarf_util.h" + +int +dwarf_get_str(Dwarf_Debug dbg, + Dwarf_Off offset, + char **string, + Dwarf_Signed * returned_str_len, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + void *secptr = 0; + void *begin = 0; + void *end = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, + "DW_DLE_DBG_NULL:calling dwarf_get_str()" + "Either null or it contains" + "a stale Dwarf_Debug pointer"); + return DW_DLV_ERROR; + } + if (offset == dbg->de_debug_str.dss_size) { + /* Normal (if we've iterated thru the set of strings using + dwarf_get_str and are at the end). */ + return DW_DLV_NO_ENTRY; + } + if (offset > dbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD); + return DW_DLV_ERROR; + } + + if (string == NULL) { + _dwarf_error(dbg, error, DW_DLE_STRING_PTR_NULL); + return DW_DLV_ERROR; + } + + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + if (!dbg->de_debug_str.dss_size) { + return DW_DLV_NO_ENTRY; + } + secptr =dbg->de_debug_str.dss_data; + begin = (char *)secptr + offset; + end = (char *)secptr + dbg->de_debug_str.dss_size; + + res = _dwarf_check_string_valid(dbg,secptr,begin,end, + DW_DLE_DEBUG_STR_OFFSET_BAD,error); + if (res != DW_DLV_OK) { + return res; + } + + *string = (char *) begin; + *returned_str_len = strlen(*string); + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_tied.c b/src/lib/libdwarf/dwarf_tied.c new file mode 100644 index 0000000..1eeb8d1 --- /dev/null +++ b/src/lib/libdwarf/dwarf_tied.c @@ -0,0 +1,271 @@ +/* + + Copyright (C) 2015-2015 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* printf() */ +#include /* calloc() free() */ +#include /* memcpy() memset() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_tsearch.h" +#include "dwarf_tied_decls.h" + +void +_dwarf_dumpsig(const char *msg, Dwarf_Sig8 *sig,int lineno) +{ + const char *sigv = 0; + unsigned u = 0; + + printf("%s 0x",msg); + sigv = &sig->signature[0]; + for (u = 0; u < 8; u++) { + printf("%02x",0xff&sigv[u]); + } + printf(" line %d\n",lineno); +} + +void * +_dwarf_tied_make_entry(Dwarf_Sig8 *key, Dwarf_CU_Context val) +{ + struct Dwarf_Tied_Entry_s *e = 0; + e = calloc(1,sizeof(struct Dwarf_Tied_Entry_s)); + if (e) { + e->dt_key = *key; + e->dt_context = val; + } + return e; +} + +/* Tied data Key is Dwarf_Sig8. + A hash needed because we are using a hash search + here. Would not be needed for the other tree searchs + like balanced trees.. */ +DW_TSHASHTYPE +_dwarf_tied_data_hashfunc(const void *keyp) +{ + const struct Dwarf_Tied_Entry_s * enp = keyp; + DW_TSHASHTYPE hashv = 0; + /* Just take some of the 8 bytes of the signature. */ + memcpy(&hashv,enp->dt_key.signature,sizeof(hashv)); + return hashv; +} + +int +_dwarf_tied_compare_function(const void *l, const void *r) +{ + const struct Dwarf_Tied_Entry_s * lp = l; + const struct Dwarf_Tied_Entry_s * rp = r; + const char *lcp = (const char *)&lp->dt_key.signature; + const char *rcp = (const char *)&rp->dt_key.signature; + const char *lcpend = lcp + sizeof(Dwarf_Sig8); + + for ( ;lcp < lcpend; ++lcp,++rcp) { + if (*lcp < *rcp) { + return -1; + } + if (*lcp > *rcp) { + return 1; + } + } + /* match. */ + return 0; +} + +void +_dwarf_tied_destroy_free_node(void*nodep) +{ + struct Dwarf_Tied_Entry_s * enp = nodep; + free(enp); + return; +} + +/* This presumes only we are reading the debug_info + CUs from tieddbg. That is a reasonable + requirement, one hopes. + Currently it reads all the tied CUs at once up to + the point of finding a match unless there is an error.. + This the only way we call _dwarf_next_cu_header*( ) + on the tied file, so safe. + */ +static int +_dwarf_loop_reading_debug_info_for_cu( + Dwarf_Debug tieddbg, + Dwarf_Error *error) +{ + /* We will not find tied signatures + for .debug_addr (or line tables) in .debug_types. + it seems. Those signatures point from + 'normal' to 'dwo/dwp' (DWARF4) */ + int is_info = TRUE; + Dwarf_CU_Context startingcontext = 0; + Dwarf_Unsigned next_cu_offset = 0; + + startingcontext = tieddbg->de_info_reading.de_cu_context; + + if (startingcontext) { + next_cu_offset = + startingcontext->cc_debug_offset + + startingcontext->cc_length + + startingcontext->cc_length_size + + startingcontext->cc_extension_size; + } + + for (;;) { + int sres = DW_DLV_OK; + Dwarf_Half cu_type = 0; + Dwarf_CU_Context latestcontext = 0; + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Half address_size = 0; + Dwarf_Half extension_size = 0; + Dwarf_Half length_size = 0; + Dwarf_Sig8 signature; + Dwarf_Bool has_signature = FALSE; + Dwarf_Unsigned typeoffset = 0; + + memset(&signature,0,sizeof(signature)); + sres = _dwarf_next_cu_header_internal(tieddbg, + is_info, + &cu_header_length, &version_stamp, + &abbrev_offset, &address_size, + &length_size,&extension_size, + &signature, &has_signature, + &typeoffset, + &next_cu_offset, + &cu_type, error); + if (sres == DW_DLV_NO_ENTRY) { + break; + } + + latestcontext = tieddbg->de_info_reading.de_cu_context; + + if (has_signature) { + void *retval = 0; + Dwarf_Sig8 consign = + latestcontext->cc_signature; + void *entry = + _dwarf_tied_make_entry(&consign,latestcontext); + if (!entry) { + return DW_DLV_NO_ENTRY; + } + /* Insert this signature and context. */ + retval = dwarf_tsearch(entry, + &tieddbg->de_tied_data.td_tied_search, + _dwarf_tied_compare_function); + if (!retval) { + free(entry); + /* FAILED might be out of memory.*/ + return DW_DLV_NO_ENTRY; + } else { + struct Dwarf_Tied_Data_s * retent = + *(struct Dwarf_Tied_Data_s**) retval; + if (retent == entry) { + /* we added a record. */ + return DW_DLV_OK; + } else { + /* found existing, no add */ + free(entry); + return DW_DLV_OK; + } + } + } + } + /* Apparently we never found the sig we are looking for. + Pretend ok. Caller will check for success. */ + return DW_DLV_OK; +} + +/* If out of memory just return DW_DLV_NO_ENTRY. +*/ +int +_dwarf_search_for_signature(Dwarf_Debug tieddbg, + Dwarf_Sig8 sig, + Dwarf_CU_Context *context_out, + Dwarf_Error *error) +{ + + void *entry2 = 0; + struct Dwarf_Tied_Entry_s entry; + struct Dwarf_Tied_Data_s * tied = &tieddbg->de_tied_data; + int res = 0; + + if (!tied->td_tied_search) { + dwarf_initialize_search_hash(&tied->td_tied_search, + _dwarf_tied_data_hashfunc,0); + if (!tied->td_tied_search) { + return DW_DLV_NO_ENTRY; + } + } + entry.dt_key = sig; + entry.dt_context = 0; + entry2 = dwarf_tfind(&entry, + &tied->td_tied_search, + _dwarf_tied_compare_function); + if (entry2) { + struct Dwarf_Tied_Entry_s *e2 = + *(struct Dwarf_Tied_Entry_s **)entry2; + *context_out = e2->dt_context; + return DW_DLV_OK; + } + + /* We now ensure all tieddbg CUs signatures + are in the td_tied_search, + The caller is NOT doing + info section read operations + on the tieddbg in this (tied)dbg, so it + cannot goof up their _dwarf_next_cu_header*(). */ + res = _dwarf_loop_reading_debug_info_for_cu(tieddbg,error); + if (res == DW_DLV_ERROR) { + return res; + } + entry2 = dwarf_tfind(&entry, + &tied->td_tied_search, + _dwarf_tied_compare_function); + if (entry2) { + struct Dwarf_Tied_Entry_s *e2 = + *(struct Dwarf_Tied_Entry_s **)entry2; + *context_out = e2->dt_context; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} diff --git a/src/lib/libdwarf/dwarf_tied_decls.h b/src/lib/libdwarf/dwarf_tied_decls.h new file mode 100644 index 0000000..ae5817d --- /dev/null +++ b/src/lib/libdwarf/dwarf_tied_decls.h @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2015-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#define HASHSEARCH + +#ifdef HASHSEARCH +/* Only needed for hash based search in a tsearch style. */ +#define INITTREE(x,y) (x) = dwarf_initialize_search_hash(&(x),(y),0) +#else +#define INITTREE(x,y) +#endif /* HASHSEARCH */ + +/* Contexts are in a list in a dbg and + do not move once established. + So saving one is ok. as long as the dbg + exists. */ +struct Dwarf_Tied_Entry_s { + Dwarf_Sig8 dt_key; + Dwarf_CU_Context dt_context; +}; + +int _dwarf_tied_compare_function(const void *l, const void *r); +void * _dwarf_tied_make_entry(Dwarf_Sig8 *key, Dwarf_CU_Context val); +DW_TSHASHTYPE _dwarf_tied_data_hashfunc(const void *keyp); diff --git a/src/lib/libdwarf/dwarf_tsearch.h b/src/lib/libdwarf/dwarf_tsearch.h new file mode 100644 index 0000000..5f1000c --- /dev/null +++ b/src/lib/libdwarf/dwarf_tsearch.h @@ -0,0 +1,123 @@ +#ifndef DWARF_TSEARCH_H +#define DWARF_TSEARCH_H +/* Copyright (c) 2013-2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +*/ + +/* The following interfaces follow tsearch (See the Single + Unix Specification) but the implementation is + written without reference to the source code + of any version of tsearch. Only uses + of tsearch were examined, not tsearch source code. + + See https://www.prevanders.net/tsearch.html + and https://www.prevanders.net/dwarf.html#tsearch + for information about tsearch. + + We are matching the standard functional + interface here, but to avoid interfering with + libc implementations or code using libc + implementations, we change all the names. + +*/ + +/* configure/cmake ensure uintptr_t defined, but if not, + possibly "-Duintptr_t=unsigned long" might help */ +#ifndef DW_TSHASHTYPE +#define DW_TSHASHTYPE uintptr_t +#endif + +/* The DW_VISIT values passed back to you through + the callback function in dwarf_twalk(); +*/ +typedef enum +{ + dwarf_preorder, + dwarf_postorder, + dwarf_endorder, + dwarf_leaf +} +DW_VISIT; + +/* void * return values are actually + void **key so you must dereference these + once to get a key you passed in. +*/ + +/* We rename these so there is no conflict with another version + of the tsearch sources, such as is used in dwarfdump. */ +#define dwarf_tsearch _dwarf_tsearch +#define dwarf_tfind _dwarf_tfind +#define dwarf_tdelete _dwarf_tdelete +#define dwarf_twalk _dwarf_twalk +#define dwarf_tdestroy _dwarf_tdestroy +#define dwarf_tdump _dwarf_tdump +#define dwarf_initialize_search_hash _dwarf_initialize_search_hash + +void *dwarf_tsearch(const void * /*key*/, void ** /*rootp*/, + int (* /*compar*/)(const void *, const void *)); + +void *dwarf_tfind(const void * /*key*/, void *const * /*rootp*/, + int (* /*compar*/)(const void *, const void *)); + +/* + dwarf_tdelete() returns NULL if it cannot delete anything + or if the tree is now empty (if empty, *rootp + is set NULL by dwarf_tdelete()). + If the delete succeeds and the tree is non-empty returns + a pointer to the parent node of the deleted item, + unless the deleted item was at the root, in which + case the returned pointer relates to the new root. +*/ +void *dwarf_tdelete(const void * /*key*/, void ** /*rootp*/, + int (* /*compar*/)(const void *, const void *)); + +void dwarf_twalk(const void * /*root*/, + void (* /*action*/)(const void * /*nodep*/, + const DW_VISIT /*which*/, + const int /*depth*/)); + +/* dwarf_tdestroy() cannot set the root pointer NULL, you must do + so on return from dwarf_tdestroy(). */ +void dwarf_tdestroy(void * /*root*/, + void (* /*free_node*/)(void * /*nodep*/)); + +/* Prints a simple tree representation to stdout. For debugging. +*/ +void dwarf_tdump(const void*root, + char *(* /*keyprint*/)(const void *), + const char *msg); + +/* Returns NULL and does nothing + unless the implemenation used uses a hash tree. */ +void * dwarf_initialize_search_hash( void **treeptr, + DW_TSHASHTYPE (*hashfunc)(const void *key), + unsigned long size_estimate); +#endif /* DWARF_TSEARCH_H */ diff --git a/src/lib/libdwarf/dwarf_tsearchhash.c b/src/lib/libdwarf/dwarf_tsearchhash.c new file mode 100644 index 0000000..89476ae --- /dev/null +++ b/src/lib/libdwarf/dwarf_tsearchhash.c @@ -0,0 +1,708 @@ +/* Copyright (c) 2013-2022, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +*/ + +/* The interfaces follow tsearch (See the Single + Unix Specification) but the implementation is + written without reference to the source of any + version of tsearch or any hashing code. + + An additional interface is added (compared to + a real tsearch) to let the caller identify a + 'hash' function with each hash table (called + a tree below, but that is a misnomer). + + So read 'tree' below as hash table. + + See http://www.prevanders.net/tsearch.html + for information and an example of use. + + Based on Knuth, chapter 6.4 + + This uses a hash based on the key. + Collision resolution is by chaining. + + twalk() and tdestroy() walk in a random order. + The 'preorder' etc labels mean nothing in a hash, so everything + is called a leaf. + + Since libdwarf never calls dwarf_tdump we + never define BUILD_TDUMP + +*/ + +#include + +#include /* NULL */ +#include /* printf() */ +#include /* calloc() free() malloc() */ + +#ifdef HAVE_STDINT_H +#include /* uintptr_t */ +#endif /* HAVE_STDINT_H */ + +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_tsearch.h" + +/* A table of primes used to size and resize the hash table. + From public sources of prime numbers, arbitrarily chosen + to approximately double in size at each step. +*/ +static unsigned long primes[] = +{ +#if 0 /* for testing only */ +5,11, 17,23, 31, 47, 53, +79, +#endif /*0*/ +521, +1009, +5591, +10007, +21839, +41413, +99907, +199967, +400009, +800029, +1600141, +3000089, +6000121, +12000257, +24000143, +48000203, +100000127, +200001611, +400000669, +800000573, +0 /* Here we are giving up */ +}; + +static unsigned long allowed_fill_percent = 90; + +struct hs_base { + unsigned long tablesize_; + unsigned long tablesize_entry_index_; + unsigned long allowed_fill_; + /* Record_count means number of active records, + counting all records on chains. + When the record_count is > 90% of a full + tablesize_ we redo the table before adding + a new entry. */ + unsigned long record_count_; + /* hashtab_ is an array of hs_entry, + indexes 0 through tablesize_ -1. */ + struct ts_entry * hashtab_; + DW_TSHASHTYPE (*hashfunc_)(const void *key); +}; + +struct ts_entry { + const void * keyptr; + /* So that a keyptr of 0 (if added) is + not confused with an empty hash slot, + we must mark used slots as used in the hash tab */ + unsigned char entryused; + struct ts_entry *next; +}; + +enum search_intent_t +{ + want_insert, + only_find, + want_delete +}; + +static struct ts_entry * +_tsearch_inner( const void *key, struct hs_base* head, + int (*compar)(const void *, const void *), + const enum search_intent_t intent, int*inserted, + struct ts_entry **parent_ptr); +static void +_dwarf_tdestroy_inner(struct hs_base*h, + void (*free_node)(void *nodep)); + +/* A trivial integer-based percentage calculation. + Percents >100 are reasonable for a hash-with-chains + situation (even if they might not be the best choice + for performance). */ +static unsigned long +calculate_allowed_fill(unsigned long fill_percent, unsigned long ct) +{ + unsigned long v = 0; + if (ct < 100000) { + unsigned long v2 = (ct *fill_percent)/100; + return v2; + } + v = (ct /100)*fill_percent; + return v; +} + +/* Initialize the hash and pass in the hash function. + If the entry count needed is unknown, pass in + 0 as a count estimate, + but if the number of hash entries needed can be estimated, + pass in the estimate (which need not be prime, + we actually use + the nearest higher prime from the above table). + If the estimated count is + Return the tree base, or return NULL if insufficient + memory. */ +void * +dwarf_initialize_search_hash( void **treeptr, + DW_TSHASHTYPE(*hashfunc)(const void *key), + unsigned long size_estimate) +{ + unsigned long prime_to_use = primes[0]; + unsigned entry_index = 0; + unsigned k = 0; + struct hs_base *base = 0; + + base = *(struct hs_base **)treeptr; + if (base) { + /* initialized already. */ + return base ; + } + base = calloc(sizeof(struct hs_base),1); + if (!base) { + /* Out of memory. */ + return NULL ; + } + prime_to_use = primes[0]; + while(size_estimate && (size_estimate > prime_to_use)) { + k = k +1; + prime_to_use = primes[k]; + if (prime_to_use == 0) { + /* Oops. Too large. */ + free(base); + return NULL; + } + entry_index = k; + } +#ifdef TESTINGHASHTAB +printf("debugging: initial alloc size estimate %lu\n",size_estimate); +printf("debugging: initial alloc prime to use %lu\n",prime_to_use); +#endif + base->tablesize_ = prime_to_use; + base->allowed_fill_ = calculate_allowed_fill(allowed_fill_percent, + prime_to_use); + if (base->allowed_fill_< (base->tablesize_/2)) { + free(base); + /* Oops. We are in trouble. Coding mistake here. */ + return NULL; + } + base->record_count_ = 0; + base->tablesize_entry_index_ = entry_index; + /* hashtab_ is an array of hs_entry, + indexes 0 through tablesize_ -1. */ + base->hashfunc_ = hashfunc; + base->hashtab_ = calloc(sizeof(struct ts_entry),base->tablesize_); + if (!base->hashtab_) { + free(base); + return NULL; + } + *treeptr = base; + return base; +} + +#ifdef BUILD_TDUMP +/* We don't really care whether hashpos or chainpos + are 32 or 64 bits. 32 suffices. */ +static void print_entry(struct ts_entry *t,const char *descr, + char *(* keyprint)(const void *), + unsigned long hashpos, + unsigned long chainpos) +{ + char *v = 0; + if (!t->entryused) { + return; + } + v = keyprint(t->keyptr); + printf("[%4lu.%02lu] 0x%08" DW_PR_DUx + " %s\n", + hashpos,chainpos, + (Dwarf_Unsigned)(uintptr_t)t, + (Dwarf_Unsigned)(uintptr_t)t->keyptr, + v, + descr); +} + +/* For debugging */ +static void +dumptree_inner(const struct hs_base *h, + char *(* keyprint)(const void *), + const char *descr, int printdetails) +{ + unsigned long ix = 0; + unsigned long tsize = h->tablesize_; + struct ts_entry *p = &h->hashtab_[0]; + unsigned long hashused = 0; + unsigned long maxchainlength = 0; + unsigned long chainsgt1 = 0; + printf("dumptree head ptr : 0x%08" DW_PR_DUx + " size %" DW_PR_DUu + " entries %" DW_PR_DUu + " allowed %" DW_PR_DUu " %s\n", + (Dwarf_Unsigned)(uintptr_t)h, + (Dwarf_Unsigned)h->tablesize_, + (Dwarf_Unsigned)h->record_count_, + (Dwarf_Unsigned)h->allowed_fill_, + descr); + for ( ; ix < tsize; ix++,p++) { + unsigned long chainlength = 0; + struct ts_entry*n = 0; + int chainpos = 0; + if (p->entryused) { + ++hashused; + chainlength = 1; + if (printdetails) { + print_entry(p,"head",keyprint,ix,chainpos); + } + } + chainpos++; + for (n = p->next; n ; n = n->next) { + chainlength++; + if (printdetails) { + print_entry(n,"chain",keyprint,ix,chainpos); + } + } + if (chainlength > maxchainlength) { + maxchainlength = chainlength; + } + if (chainlength > 1) { + chainsgt1++; + } + } + printf("Hashtable: %lu of %lu hash entries used.\n", + hashused,tsize); + printf("Hashtable: %lu chains length longer than 1. \n", + chainsgt1); + printf("Hashtable: %lu is maximum chain length.\n", + maxchainlength); +} + +/* Dumping the tree. + */ +void +dwarf_tdump(const void*headp_in, + char *(* keyprint)(const void *), + const char *msg) +{ + const struct hs_base *head = (const struct hs_base *)headp_in; + if (!head) { + printf("dumptree null tree ptr : %s\n",msg); + return; + } + dumptree_inner(head,keyprint,msg,1); +} +#endif /* BUILD_TDUMP */ + +static struct ts_entry * +allocate_ts_entry(const void *key) +{ + struct ts_entry *e = 0; + + e = (struct ts_entry *) malloc(sizeof(struct ts_entry)); + if (!e) { + return NULL; + } + e->keyptr = key; + e->entryused = 1; + e->next = 0; + return e; +} + +static void +resize_table(struct hs_base *head, + int (*compar)(const void *, const void *)) +{ + struct hs_base newhead; + unsigned new_entry_index = 0; + unsigned long prime_to_use = 0; + + /* Copy the values we have. */ + newhead = *head; + /* But drop the hashtab_ from new. calloc below. */ + newhead.hashtab_ = 0; + newhead.record_count_ = 0; + new_entry_index = head->tablesize_entry_index_ +1; + prime_to_use = primes[new_entry_index]; + if (!prime_to_use) { + /* Oops, too large. Leave table size as is, though + it will get slow as it overfills. */ + return; + } + newhead.tablesize_ = prime_to_use; + newhead.allowed_fill_ = calculate_allowed_fill( + allowed_fill_percent, prime_to_use); + if (newhead.allowed_fill_< (newhead.tablesize_/2)) { + /* Oops. We are in trouble. */ + return; + } + newhead.tablesize_entry_index_ = new_entry_index; + newhead.hashtab_ = calloc(sizeof(struct ts_entry), + newhead.tablesize_); + if (!newhead.hashtab_) { + /* Oops, too large. Leave table size as is, though + things will get slow as it overfills. */ + free(newhead.hashtab_); + return; + } + { + /* Insert all the records from the old table into + the new table. */ + int fillnewfail = 0; + unsigned long ix = 0; + unsigned long tsize = head->tablesize_; + struct ts_entry *p = &head->hashtab_[0]; +#ifdef TESTINGHASHTAB +printf("debugging: Resize %lu to %lu\n",tsize,prime_to_use); +#endif + for ( ; ix < tsize; ix++,p++) { + int inserted = 0; + struct ts_entry*n = 0; + if (fillnewfail) { + break; + } + if (p->keyptr) { + _tsearch_inner(p->keyptr, + &newhead,compar, + want_insert, + &inserted, + 0); + if (!inserted) { + fillnewfail = 1; + break; + } + } + for (n = p->next; n ; n = n->next) { + inserted = 0; + _tsearch_inner(n->keyptr, + &newhead,compar, + want_insert, + &inserted, + 0); + if (!inserted) { + fillnewfail = 1; + break; + } + } + } + if (fillnewfail) { + free(newhead.hashtab_); + return; + } + } + /* Now get rid of the chain entries of the old table. */ + _dwarf_tdestroy_inner(head,0); + /* Now get rid of the old table itself. */ + free(head->hashtab_); + head->hashtab_ = 0; + *head = newhead; + return; +} + +/* Inner search of the hash and synonym chains. */ +static struct ts_entry * +_tsearch_inner( const void *key, struct hs_base* head, + int (*compar)(const void *, const void *), + const enum search_intent_t intent, int*inserted, + /* owner_ptr used for delete. Only set + if the to-be-deleted item is on a chain, + not in the hashtab. Points to the item + pointing to the to-be-deleted-item.*/ + struct ts_entry **owner_ptr) +{ + struct ts_entry *s =0; + struct ts_entry *c =0; + struct ts_entry *q =0; + int kc = 0; + DW_TSHASHTYPE keyhash = 0; + DW_TSHASHTYPE hindx = 0; + struct ts_entry *chain_parent = 0; + + if (! head->hashfunc_) { + /* Not fully initialized. */ + return NULL; + } + keyhash = head->hashfunc_(key); + if (intent == want_insert) { + if (head->record_count_ > head->allowed_fill_) { + resize_table(head,compar); + } + } + hindx = keyhash%head->tablesize_; + s = &head->hashtab_[hindx]; + if (!s->entryused) { + /* Not found. */ + if (intent != want_insert) { + return NULL; + } + /* Insert in the base hash table in an + empty slot. */ + *inserted = 1; + head->record_count_++; + s->keyptr = (const void *)key; + s->entryused = 1; + s->next = 0; + return s; + } + kc = compar(key,s->keyptr); + if (kc == 0 ) { + /* found! */ + if (intent == want_delete) { + *owner_ptr = 0; + } + return (void *)&(s->keyptr); + } + chain_parent = s; + for (c = s->next; c; c = c->next) { + kc = compar(key,c->keyptr); + if (kc == 0 ) { + /* found! */ + if (intent == want_delete) { + *owner_ptr = chain_parent; + } + return (void *)&(c->keyptr); + } + chain_parent = c; + } + if (intent != want_insert) { + return NULL; + } + /* Insert following head record of the chain. */ + q = allocate_ts_entry(key); + if (!q) { + return q; + } + q->next = s->next; + s->next = q; + head->record_count_++; + *inserted = 1; + return q; +} +/* Search and, if missing, insert. */ +void * +dwarf_tsearch(const void *key, void **headin, + int (*compar)(const void *, const void *)) +{ + struct hs_base **rootp = (struct hs_base **)headin; + struct hs_base *head = *rootp; + struct ts_entry *r = 0; + int inserted = 0; + /* nullme won't be set. */ + struct ts_entry *nullme = 0; + + if (!head) { + /* something is wrong here, not initialized. */ + return NULL; + } + r = _tsearch_inner(key,head,compar,want_insert,&inserted,&nullme); + if (!r) { + return NULL; + } + return (void *)&(r->keyptr); +} + +/* Search. */ +void * +dwarf_tfind(const void *key, void *const *rootp, + int (*compar)(const void *, const void *)) +{ + /* Nothing will change, but we discard const + so we can use tsearch_inner(). */ + struct hs_base **proot = (struct hs_base **)rootp; + struct hs_base *head = *proot; + struct ts_entry *r = 0; + /* inserted flag won't be set. */ + int inserted = 0; + /* nullme won't be set. */ + struct ts_entry * nullme = 0; + /* Get to actual tree. */ + + if (!head) { + return NULL; + } + + r = _tsearch_inner(key,head,compar,only_find,&inserted,&nullme); + if (!r) { + return NULL; + } + return (void *)(&(r->keyptr)); +} + +/* Unlike the simple binary tree case, + a fully-empty hash situation does not null the *rootp +*/ +void * +dwarf_tdelete(const void *key, void **rootp, + int (*compar)(const void *, const void *)) +{ + struct hs_base **proot = (struct hs_base **)rootp; + struct hs_base *head = *proot; + struct ts_entry *found = 0; + /* inserted flag won't be set. */ + int inserted = 0; + struct ts_entry * parentp = 0; + + if (!head) { + return NULL; + } + + found = _tsearch_inner(key,head,compar,want_delete,&inserted, + &parentp); + if (found) { + if (parentp) { + /* Delete a chain entry. */ + head->record_count_--; + parentp->next = found->next; + /* We free our storage. It would be up + to caller to do a tfind to find + a record and delete content if necessary. */ + free(found); + return (void *)&(parentp->keyptr); + } + /* So found is the head of a chain. */ + if (found->next) { + /* Delete a chain entry, pull up to hash tab, freeing + up the chain entry. */ + struct ts_entry *pullup = found->next; + *found = *pullup; + free(pullup); + head->record_count_--; + return (void *)&(found->keyptr); + } else { + /* Delete a main hash table entry. + Problem: what the heck to return as a keyptr pointer? + Well, we return NULL. As in the standard + tsearch, returning NULL does not mean + failure! Here it just means 'empty chain somewhere'. + */ + head->record_count_--; + found->next = 0; + found->keyptr = 0; + found->entryused = 0; + return NULL; + } + } + return NULL; +} + +static void +_dwarf_twalk_inner(const struct hs_base *h, + struct ts_entry *p, + void (*action)(const void *nodep, const DW_VISIT which, + const int depth ) + ) +{ + unsigned long ix = 0; + int depth = 0; + unsigned long tsize = h->tablesize_; + for ( ; ix < tsize; ix++,p++) { + struct ts_entry*n = 0; + if (p->keyptr) { + action((void *)(&(p->keyptr)),dwarf_leaf,depth); + } + for (n = p->next; n ; n = n->next) { + action((void *)(&(n->keyptr)),dwarf_leaf,depth); + } + } +} + +void +dwarf_twalk(const void *rootp, + void (*action)(const void *nodep, const DW_VISIT which, + const int depth)) +{ + const struct hs_base *head = (const struct hs_base *)rootp; + struct ts_entry *root = 0; + if (!head) { + return; + } + root = head->hashtab_; + /* Get to actual tree. */ + _dwarf_twalk_inner(head,root,action); +} + +static void +_dwarf_tdestroy_inner(struct hs_base*h, + void (*free_node)(void *nodep)) +{ + unsigned long ix = 0; + unsigned long tsize = h->tablesize_; + struct ts_entry *p = &h->hashtab_[0]; +#ifdef TESTINGHASHTAB + printf("debugging: destroyhashtable blocks %lu\n",tsize); + printf("debugging: destroyhashtable recordcount %lu\n", + h->record_count_); +#endif + for ( ; ix < tsize; ix++,p++) { + struct ts_entry*n = 0; + struct ts_entry*prev = 0; + if (p->keyptr && p->entryused) { + if (free_node) { + free_node((void *)(p->keyptr)); + } + --h->record_count_; + } + /* Now walk and free up the chain entries. */ + for (n = p->next; n ; ) { + if (free_node) { + free_node((void *)(n->keyptr)); + } + --h->record_count_; + prev = n; + n = n->next; + free(prev); + } + } +} + +/* Walk the tree, freeing all space in the tree + and calling the user's callback function on each node. + + It is up to the caller to zero out anything pointing to + head (ie, that has the value rootp holds) after this + returns. +*/ +void +dwarf_tdestroy(void *rootp, void (*free_node)(void *nodep)) +{ + struct hs_base *head = (struct hs_base *)rootp; + struct ts_entry *root = 0; + if (!head) { + return; + } + root = head->hashtab_; + _dwarf_tdestroy_inner(head,free_node); + free(root); + free(head); +} diff --git a/src/lib/libdwarf/dwarf_universal.h b/src/lib/libdwarf/dwarf_universal.h new file mode 100644 index 0000000..9742067 --- /dev/null +++ b/src/lib/libdwarf/dwarf_universal.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2023, David Anderson +All rights reserved. + +Redistribution and use in source and binary forms, with +or without modification, are permitted provided that the +following conditions are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ + +#ifndef DWARF_UNIVERSAL_H +#define DWARF_UNIVERSAL_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct Dwarf_Universal_Head_s; +typedef struct Dwarf_Universal_Head_s * Dwarf_Universal_Head; + +int _dwarf_object_detector_universal_head( + char *dw_path, + Dwarf_Unsigned dw_filesize, + unsigned int *dw_contentcount, + Dwarf_Universal_Head * dw_head, + int *errcode); + +int _dwarf_object_detector_universal_instance( + Dwarf_Universal_Head dw_head, + Dwarf_Unsigned dw_index_of, + Dwarf_Unsigned *dw_cpu_type, + Dwarf_Unsigned *dw_cpu_subtype, + Dwarf_Unsigned *dw_offset, + Dwarf_Unsigned *dw_size, + Dwarf_Unsigned *dw_align, + int *errcode); +void _dwarf_dealloc_universal_head(Dwarf_Universal_Head dw_head); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DWARF_UNIVERSAL_H */ diff --git a/src/lib/libdwarf/dwarf_util.c b/src/lib/libdwarf/dwarf_util.c new file mode 100644 index 0000000..99113ef --- /dev/null +++ b/src/lib/libdwarf/dwarf_util.c @@ -0,0 +1,1606 @@ +/* + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2022 David Anderson. All Rights Reserved. + Portions Copyright 2012 SN Systems Ltd. All rights reserved. + Portions Copyright 2020 Google All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include + +#include /* NULL size_t */ +#include /* free() */ +#include /* memset() strlen() */ +#include /* for debugging */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_abbrev.h" +#include "dwarf_memcpy_swap.h" +#include "dwarf_die_deliv.h" +#include "dwarf_string.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif /* O_BINARY */ + +#define MINBUFLEN 1000 + +#define MORE_BYTES 0x80 +#define DATA_MASK 0x7f +#define DIGIT_WIDTH 7 +#define SIGN_BIT 0x40 + +/* The function returned allows dwarfdump and other callers to + do an endian-sensitive copy-word with a chosen + source-length. */ +typedef void (*endian_funcp_type)(void *, const void *,unsigned long); + +const char * +dwarf_package_version(void) +{ + return PACKAGE_VERSION; +} + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s ",msg); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ +#if 0 +static void +dump_ab_list(const char *prefix,const char *msg, + unsigned long hash_num, + Dwarf_Abbrev_List entry_base, int line) +{ + Dwarf_Abbrev_List listent = 0; + Dwarf_Abbrev_List nextlistent = 0; + printf("%s abb dump %s hashnum %lu line %d\n",prefix,msg, + hash_num,line); + + listent = entry_base; + for ( ; listent; listent = nextlistent) { + printf("%s ptr %p code %lu ", + prefix, + (void *)listent, + (unsigned long)listent->abl_code); + printf(" tag %u has child %u \n", + listent->abl_tag,listent->abl_has_child); + printf("%s abbrev count %lu impl-ct %lu \n", + prefix, + (unsigned long)listent->abl_abbrev_count, + (unsigned long)listent->abl_implicit_const_count); + nextlistent = listent->abl_next; + printf("%s next %p \n",prefix,(void *)nextlistent); + } +} +static void dump_hash_table(char *msg, + Dwarf_Hash_Table tab, int line) +{ + static char buf[200]; + unsigned long i = 0; + printf("debugging: hash tab: %s ptr %p line %d\n", + msg,(void *)tab,line); + printf(" entryct: %lu abbrevct: %lu highestused: %lu\n", + tab->tb_table_entry_count, + tab->tb_total_abbrev_count, + tab->tb_highest_used_entry); + + for (i = 0; i < tab->tb_table_entry_count; ++i) { + sprintf(buf,"Tab entry %lu:",i); + dump_ab_list(" ",buf,i,tab->tb_entries[i],__LINE__); + } + printf(" ---end hash tab---\n"); +} +#endif + +endian_funcp_type +dwarf_get_endian_copy_function(Dwarf_Debug dbg) +{ + if (dbg) { + return dbg->de_copy_word; + } + return 0; +} + +Dwarf_Bool +_dwarf_file_has_debug_fission_cu_index(Dwarf_Debug dbg) +{ + if (!dbg) { + return FALSE; + } + if (dbg->de_cu_hashindex_data) { + return TRUE; + } + return FALSE; +} +Dwarf_Bool +_dwarf_file_has_debug_fission_tu_index(Dwarf_Debug dbg) +{ + if (!dbg) { + return FALSE; + } + if (dbg->de_tu_hashindex_data ) { + return TRUE; + } + return FALSE; +} + +Dwarf_Bool +_dwarf_file_has_debug_fission_index(Dwarf_Debug dbg) +{ + if (!dbg) { + return FALSE; + } + if (dbg->de_cu_hashindex_data || + dbg->de_tu_hashindex_data) { + return 1; + } + return FALSE; +} + +void +_dwarf_create_area_len_error(Dwarf_Debug dbg, Dwarf_Error *error, + Dwarf_Unsigned targ, + Dwarf_Unsigned sectionlen) +{ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_HEADER_LEN_BIGGER_THAN_SECSIZE: " + " The header length of 0x%x is larger", + targ); + dwarfstring_append_printf_u(&m," than the " + "section length of 0x%x.",sectionlen); + _dwarf_error_string(dbg, + error,DW_DLE_HEADER_LEN_BIGGER_THAN_SECSIZE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); +} + +int +_dwarf_internal_get_die_comp_dir(Dwarf_Die die, + const char **compdir_out, + const char **compname_out, + Dwarf_Error *error) +{ + Dwarf_Attribute comp_dir_attr = 0; + Dwarf_Attribute comp_name_attr = 0; + int resattr = 0; + Dwarf_Debug dbg = 0; + + dbg = die->di_cu_context->cc_dbg; + resattr = dwarf_attr(die, DW_AT_name, &comp_name_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *name = 0; + + cres = dwarf_formstring(comp_name_attr, &name, error); + if (cres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, comp_name_attr, DW_DLA_ATTR); + return cres; + } else if (cres == DW_DLV_OK) { + *compname_out = (const char *)name; + } else { + /* FALL thru */ + } + } + if (resattr == DW_DLV_OK) { + dwarf_dealloc(dbg, comp_name_attr, DW_DLA_ATTR); + } + resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); + if (resattr == DW_DLV_ERROR) { + return resattr; + } + if (resattr == DW_DLV_OK) { + int cres = DW_DLV_ERROR; + char *cdir = 0; + + cres = dwarf_formstring(comp_dir_attr, &cdir, error); + if (cres == DW_DLV_ERROR) { + dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); + return cres; + } else if (cres == DW_DLV_OK) { + *compdir_out = (const char *) cdir; + } else { + /* FALL thru */ + } + } + if (resattr == DW_DLV_OK) { + dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); + } + return resattr; +} + +/* Given a form, and a pointer to the bytes encoding + a value of that form, val_ptr, this function returns + the length, in bytes, of a value of that form. + When using this function, check for a return of 0 + a recursive DW_FORM_INDIRECT value. */ +int +_dwarf_get_size_of_val(Dwarf_Debug dbg, + Dwarf_Unsigned form, + Dwarf_Half cu_version, + Dwarf_Half address_size, + Dwarf_Small * val_ptr, + int v_length_size, + Dwarf_Unsigned *size_out, + Dwarf_Small *section_end_ptr, + Dwarf_Error*error) +{ + Dwarf_Unsigned length = 0; + Dwarf_Unsigned leb128_length = 0; + Dwarf_Unsigned form_indirect = 0; + Dwarf_Unsigned ret_value = 0; + + switch (form) { + case 0: return DW_DLV_OK; + + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: + *size_out = v_length_size; + return DW_DLV_OK; + + case DW_FORM_addr: + if (address_size) { + *size_out = address_size; + } else { + /* This should never happen, + address_size should be set. */ + *size_out = dbg->de_pointer_size; + } + return DW_DLV_OK; + case DW_FORM_ref_sig8: + *size_out = 8; + /* sizeof Dwarf_Sig8 */ + return DW_DLV_OK; + + /* DWARF2 was wrong on the size of the attribute for + DW_FORM_ref_addr. We assume compilers are using the + corrected DWARF3 text (for 32bit pointer target + objects pointer and + offsets are the same size anyway). + It is clear (as of 2014) that for 64bit folks used + the V2 spec in the way V2 was + written, so the ref_addr has to account for that.*/ + case DW_FORM_ref_addr: + if (cu_version == DW_CU_VERSION2) { + *size_out = address_size; + } else { + *size_out = v_length_size; + } + return DW_DLV_OK; + + case DW_FORM_block1: { + Dwarf_Unsigned space_left = 0; + + if (val_ptr >= section_end_ptr) { + _dwarf_error_string(dbg,error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: DW_FORM_block1" + " itself is off the end of the section." + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + ret_value = *(Dwarf_Small *) val_ptr; + /* ptrdiff_t is generated but not named */ + space_left = (section_end_ptr >= val_ptr)? + (section_end_ptr - val_ptr):0; + if (ret_value > space_left) { + _dwarf_error_string(dbg,error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: DW_FORM_block1" + " runs off the end of the section." + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + *size_out = ret_value +1; + } + return DW_DLV_OK; + + case DW_FORM_block2: { + Dwarf_Unsigned space_left = 0; + + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + val_ptr, DWARF_HALF_SIZE,error,section_end_ptr); + /* ptrdiff_t is generated but not named */ + space_left = (section_end_ptr >= val_ptr)? + (section_end_ptr - val_ptr):0; + if (ret_value > space_left) { + _dwarf_error_string(dbg,error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: DW_FORM_block2" + " runs off the end of the section." + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + *size_out = ret_value + DWARF_HALF_SIZE; + } + return DW_DLV_OK; + + case DW_FORM_block4: { + Dwarf_Unsigned space_left = 0; + + READ_UNALIGNED_CK(dbg, ret_value, Dwarf_Unsigned, + val_ptr, DWARF_32BIT_SIZE, + error,section_end_ptr); + /* ptrdiff_t is generated but not named */ + space_left = (section_end_ptr >= val_ptr)? + (section_end_ptr - val_ptr):0; + if (ret_value > space_left) { + _dwarf_error_string(dbg,error, + DW_DLE_FORM_BLOCK_LENGTH_ERROR, + "DW_DLE_FORM_BLOCK_LENGTH_ERROR: DW_FORM_block4" + " runs off the end of the section." + " Corrupt Dwarf."); + return DW_DLV_ERROR; + } + *size_out = ret_value + DWARF_32BIT_SIZE; + } + return DW_DLV_OK; + + case DW_FORM_data1: + *size_out = 1; + return DW_DLV_OK; + + case DW_FORM_data2: + *size_out = 2; + return DW_DLV_OK; + + case DW_FORM_data4: + *size_out = 4; + return DW_DLV_OK; + + case DW_FORM_data8: + *size_out = 8; + return DW_DLV_OK; + + case DW_FORM_data16: + *size_out = 16; + return DW_DLV_OK; + + case DW_FORM_string: { + int res = 0; + res = _dwarf_check_string_valid(dbg,val_ptr, + val_ptr, + section_end_ptr, + DW_DLE_FORM_STRING_BAD_STRING, + error); + if ( res != DW_DLV_OK) { + return res; + } + } + *size_out = strlen((char *) val_ptr) + 1; + return DW_DLV_OK; + + case DW_FORM_block: + case DW_FORM_exprloc: { + DECODE_LEB128_UWORD_LEN_CK(val_ptr,length,leb128_length, + dbg,error,section_end_ptr); + *size_out = length + leb128_length; + return DW_DLV_OK;; + } + + case DW_FORM_flag_present: + *size_out = 0; + return DW_DLV_OK; + + case DW_FORM_flag: + *size_out = 1; + return DW_DLV_OK; + + case DW_FORM_sec_offset: + /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */ + *size_out = v_length_size; + return DW_DLV_OK; + + case DW_FORM_ref_udata: { + /* Discard the decoded value, we just want the length + of the value. */ + SKIP_LEB128_LEN_CK(val_ptr,leb128_length, + dbg,error,section_end_ptr); + *size_out = leb128_length; + return DW_DLV_OK;; + } + + case DW_FORM_indirect: + { + Dwarf_Unsigned indir_len = 0; + int res = 0; + Dwarf_Unsigned info_data_len = 0; + + DECODE_LEB128_UWORD_LEN_CK(val_ptr,form_indirect, + indir_len, + dbg,error,section_end_ptr); + if (form_indirect == DW_FORM_indirect) { + /* We are in big trouble: The true form + of DW_FORM_indirect is + DW_FORM_indirect? Nonsense. Should + never happen. */ + _dwarf_error(dbg,error, + DW_DLE_NESTED_FORM_INDIRECT_ERROR); + return DW_DLV_ERROR; + } + /* If form_indirect is DW_FORM_implicit_const then + the following call will set info_data_len 0 */ + res = _dwarf_get_size_of_val(dbg, + form_indirect, + cu_version, + address_size, + val_ptr + indir_len, + v_length_size, + &info_data_len, + section_end_ptr, + error); + if (res != DW_DLV_OK) { + return res; + } + *size_out = indir_len + info_data_len; + return DW_DLV_OK; + } + + case DW_FORM_ref1: + *size_out = 1; + return DW_DLV_OK; + + case DW_FORM_ref2: + *size_out = 2; + return DW_DLV_OK; + + case DW_FORM_ref4: + *size_out = 4; + return DW_DLV_OK; + + case DW_FORM_ref8: + *size_out = 8; + return DW_DLV_OK; + + /* DW_FORM_implicit_const is a value in the + abbreviations, not in the DIEs and this + functions measures DIE size. */ + case DW_FORM_implicit_const: + *size_out = 0; + return DW_DLV_OK; + + case DW_FORM_sdata: { + /* Discard the decoded value, we just want the length + of the value. */ + SKIP_LEB128_LEN_CK(val_ptr,leb128_length, + dbg,error,section_end_ptr); + *size_out = leb128_length; + return DW_DLV_OK; + } + case DW_FORM_ref_sup4: + *size_out = 4; + return DW_DLV_OK; + case DW_FORM_ref_sup8: + *size_out = 8; + return DW_DLV_OK; + case DW_FORM_addrx1: + *size_out = 1; + return DW_DLV_OK; + case DW_FORM_addrx2: + *size_out = 2; + return DW_DLV_OK; + case DW_FORM_addrx3: + *size_out = 3; + return DW_DLV_OK; + case DW_FORM_addrx4: + *size_out = 4; + return DW_DLV_OK; + case DW_FORM_strx1: + *size_out = 1; + return DW_DLV_OK; + case DW_FORM_strx2: + *size_out = 2; + return DW_DLV_OK; + case DW_FORM_strx3: + *size_out = 3; + return DW_DLV_OK; + case DW_FORM_strx4: + *size_out = 4; + return DW_DLV_OK; + + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + case DW_FORM_strx: + case DW_FORM_GNU_str_index: { + SKIP_LEB128_LEN_CK(val_ptr,leb128_length, + dbg,error,section_end_ptr); + *size_out = leb128_length; + return DW_DLV_OK; + } + + case DW_FORM_line_strp: + case DW_FORM_strp: + *size_out = v_length_size; + return DW_DLV_OK; + + case DW_FORM_LLVM_addrx_offset: + SKIP_LEB128_LEN_CK(val_ptr,leb128_length, + dbg,error,section_end_ptr); + *size_out = leb128_length + SIZEOFT32; + return DW_DLV_OK; + case DW_FORM_udata: { + /* Discard the decoded value, we just want the length + of the value. */ + SKIP_LEB128_LEN_CK(val_ptr,leb128_length, + dbg,error,section_end_ptr); + *size_out = leb128_length; + return DW_DLV_OK; + } + default: break; + } + /* When we encounter a FORM here that + we know about but forgot to enter here, + we had better not just continue. + Usually means we forgot to update this function + when implementing form handling of a new FORM. + Disaster results from using a bogus value, + so generate error. */ + { + dwarfstring m; + dwarfstring_constructor(&m); + + dwarfstring_append_printf_u(&m, + "DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE: " + "DW_FORM 0x%x" + " is not being handled!", + form); + + _dwarf_error_string(dbg,error, + DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + } + return DW_DLV_ERROR; +} + +/* Table size is always a power of two so + we can use "val2 = val1 & (size-1)" + instead of a slower 'hash' function. */ +#define HT_DEFAULT_TABLE_SIZE 128 +#define HT_MULTIPLE 2 +#define HT_MOD_OP & + +/* Copy the old entries, updating each to be in + a new list. Don't delete anything. Leave the + htin with stale data. */ +static void +copy_abbrev_table_to_new_table(Dwarf_Hash_Table htin, + Dwarf_Hash_Table htout) +{ + Dwarf_Abbrev_List *entry_in = htin->tb_entries; + unsigned long entry_in_count = htin->tb_table_entry_count; + Dwarf_Abbrev_List *entry_out = htout->tb_entries; + unsigned long entry_out_count = htout->tb_table_entry_count; + unsigned long k = 0; + + for (k = 0; k < entry_in_count; ++k) { + Dwarf_Abbrev_List listent = entry_in[k]; + Dwarf_Abbrev_List nextlistent = 0; + for (; listent ; listent = nextlistent) { + unsigned long newtmp = listent->abl_code; + unsigned long newhash = newtmp HT_MOD_OP + (entry_out_count -1); + + nextlistent = listent->abl_next; + /* Move_entry_to_new_hash. This reverses the + order of the entries, effectively, but + that does not seem significant. */ + if (newhash > htout->tb_highest_used_entry) { + htout->tb_highest_used_entry = newhash; + } + listent->abl_next = entry_out[newhash]; + entry_out[newhash] = listent; + htout->tb_total_abbrev_count++; + } + } +} + +/* We allow zero form here, end of list. */ +int +_dwarf_valid_form_we_know(Dwarf_Unsigned at_form, + Dwarf_Unsigned at_name) +{ + if (at_form == 0 && at_name == 0) { + return TRUE; + } + if (at_name == 0) { + return FALSE; + } + if (at_form <= DW_FORM_addrx4 ) { + return TRUE; + } + if (at_form == DW_FORM_GNU_addr_index || + at_form == DW_FORM_GNU_str_index || + at_form == DW_FORM_GNU_ref_alt || + at_form == DW_FORM_GNU_strp_alt) { + return TRUE; + } + return FALSE; +} + +int +_dwarf_format_TAG_err_msg(Dwarf_Debug dbg, + Dwarf_Unsigned tag, + const char *m, + Dwarf_Error *errp) +{ + dwarfstring v; + + dwarfstring_constructor(&v); + dwarfstring_append(&v,(char *)m); + dwarfstring_append(&v," The value "); + dwarfstring_append_printf_u(&v,"0x%" DW_PR_DUx + " is outside the valid TAG range.",tag); + dwarfstring_append(&v," Corrupt DWARF."); + _dwarf_error_string(dbg, errp,DW_DLE_TAG_CORRUPT, + dwarfstring_string(&v)); + dwarfstring_destructor(&v); + return DW_DLV_ERROR; +} + +/* This function returns a pointer to a Dwarf_Abbrev_List_s + struct for the abbrev with the given code. It puts the + struct on the appropriate hash table. It also adds all + the abbrev between the last abbrev added and this one to + the hash table. In other words, the .debug_abbrev section + is scanned sequentially from the top for an abbrev with + the given code. All intervening abbrevs are also put + into the hash table. + + This function hashes the given code, and checks the chain + at that hash table entry to see if a Dwarf_Abbrev_List_s + with the given code exists. If yes, it returns a pointer + to that struct. Otherwise, it scans the .debug_abbrev + section from the last byte scanned for that CU till either + an abbrev with the given code is found, or an abbrev code + of 0 is read. It puts Dwarf_Abbrev_List_s entries for all + abbrev's read till that point into the hash table. The + hash table contains both a head pointer and a tail pointer + for each entry. + + While the lists can move and entries can be moved between + lists on reallocation, any given Dwarf_Abbrev_list entry + never moves once allocated, so the pointer is safe to return. + + See also dwarf_get_abbrev() in dwarf_abbrev.c. + + On returning DW_DLV_NO_ENTRY (as well + as DW_DLV_OK) it sets + *highest_known_code as a side effect + for better error messages by callers. + + Returns DW_DLV_ERROR on error. */ +int +_dwarf_get_abbrev_for_code(Dwarf_CU_Context context, + Dwarf_Unsigned code, + Dwarf_Abbrev_List *list_out, + Dwarf_Unsigned *highest_known_code, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = context->cc_dbg; + Dwarf_Hash_Table hash_table_base = + context->cc_abbrev_hash_table; + Dwarf_Abbrev_List *entry_base = 0; + Dwarf_Abbrev_List entry_cur = 0; + Dwarf_Unsigned hash_num = 0; + Dwarf_Unsigned abbrev_code = 0; + Dwarf_Unsigned abbrev_tag = 0; + Dwarf_Abbrev_List hash_abbrev_entry = 0; + Dwarf_Abbrev_List inner_list_entry = 0; + Dwarf_Byte_Ptr abbrev_ptr = 0; + Dwarf_Byte_Ptr end_abbrev_ptr = 0; + Dwarf_Small *abbrev_section_start = + dbg->de_debug_abbrev.dss_data; + unsigned long hashable_val = 0; + + if (!hash_table_base->tb_entries) { + hash_table_base->tb_table_entry_count = + HT_DEFAULT_TABLE_SIZE; + hash_table_base->tb_total_abbrev_count= 0; +#ifdef TESTINGHASHTAB +printf("debugging: initial size %u\n",HT_DEFAULT_TABLE_SIZE); +#endif + hash_table_base->tb_entries = + (Dwarf_Abbrev_List *) + calloc(hash_table_base->tb_table_entry_count, + sizeof(Dwarf_Abbrev_List)); + if (!hash_table_base->tb_entries) { + *highest_known_code = + context->cc_highest_known_code; + return DW_DLV_NO_ENTRY; + } + } else if (hash_table_base->tb_total_abbrev_count > + (hash_table_base->tb_table_entry_count * HT_MULTIPLE)) { + struct Dwarf_Hash_Table_s * newht = 0; + + newht = (Dwarf_Hash_Table) calloc(1, + sizeof(struct Dwarf_Hash_Table_s)); + if (!newht) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: allocating a " + "struct Dwarf_Hash_Table_s"); + return DW_DLV_ERROR; + } + + /* This grows the hash table, likely too much. + Since abbrev codes are usually assigned + from 1 and increasing by one the hash usually + results in no hash collisions whatever, + so searching the list of collisions + is normally very quick. */ + newht->tb_table_entry_count = + hash_table_base->tb_table_entry_count * HT_MULTIPLE; +#ifdef TESTINGHASHTAB + printf("debugging: Resize size to %lu\n", + (unsigned long)newht->tb_table_entry_count); +#endif + newht->tb_total_abbrev_count = 0; + newht->tb_entries = + (Dwarf_Abbrev_List *) + calloc(newht->tb_table_entry_count, + sizeof(Dwarf_Abbrev_List)); + if (!newht->tb_entries) { + free(newht); + *highest_known_code = + context->cc_highest_known_code; + return DW_DLV_NO_ENTRY; + } + /* Copy the existing entries to the new table, + rehashing each. */ + copy_abbrev_table_to_new_table(hash_table_base, newht); + _dwarf_free_abbrev_hash_table_contents(hash_table_base, + TRUE /* keep abbrev content */); + /* Now overwrite the existing table pointer + the new, newly valid, pointer. */ + free(context->cc_abbrev_hash_table); + context->cc_abbrev_hash_table = newht; + hash_table_base = context->cc_abbrev_hash_table; + } /* Else is ok as is */ + /* Now add entry. */ + if (code > context->cc_highest_known_code) { + context->cc_highest_known_code = code; + } + hashable_val = code; + hash_num = hashable_val HT_MOD_OP + (hash_table_base->tb_table_entry_count-1); + if (hash_num > hash_table_base->tb_highest_used_entry) { + hash_table_base->tb_highest_used_entry = hash_num; + } + entry_base = hash_table_base->tb_entries; + entry_cur = entry_base[hash_num]; + + /* Determine if the 'code' is the list of synonyms already. */ + hash_abbrev_entry = entry_cur; + for ( ; hash_abbrev_entry && hash_abbrev_entry->abl_code != code; + hash_abbrev_entry = hash_abbrev_entry->abl_next) {} + if (hash_abbrev_entry) { + /* This returns a pointer to an abbrev + list entry, not the list itself. */ + *highest_known_code = + context->cc_highest_known_code; + hash_abbrev_entry->abl_reference_count++; + *list_out = hash_abbrev_entry; + return DW_DLV_OK; + } + + if (context->cc_last_abbrev_ptr) { + abbrev_ptr = context->cc_last_abbrev_ptr; + end_abbrev_ptr = context->cc_last_abbrev_endptr; + } else { + /* This is ok because cc_abbrev_offset includes DWP + offset if appropriate. + */ + end_abbrev_ptr = dbg->de_debug_abbrev.dss_data + + dbg->de_debug_abbrev.dss_size; + abbrev_ptr = dbg->de_debug_abbrev.dss_data + + context->cc_abbrev_offset; + + if (context->cc_dwp_offsets.pcu_type) { + /* In a DWP the abbrevs + for this context are known quite precisely. */ + Dwarf_Unsigned size = 0; + + /* Ignore the offset returned. + Already in cc_abbrev_offset. */ + _dwarf_get_dwp_extra_offset( + &context->cc_dwp_offsets, + DW_SECT_ABBREV,&size); + /* ASSERT: size != 0 */ + end_abbrev_ptr = abbrev_ptr + size; + } + } + + /* End of abbrev's as we are past the end entirely. + This can happen,though it seems wrong. + Or we are at the end of the data block, + which we also take as + meaning done with abbrevs for this CU. + An abbreviations table + is supposed to end with a zero byte. + Not ended by end of data block. + But we are allowing what is possibly a bit + more flexible end policy here. */ + if (abbrev_ptr >= end_abbrev_ptr) { + return DW_DLV_NO_ENTRY; + } + /* End of abbrev's for this cu, since abbrev code + is 0. */ + if (*abbrev_ptr == 0) { + *highest_known_code = + context->cc_highest_known_code; + return DW_DLV_NO_ENTRY; + } + do { + unsigned long new_hashable_val = 0; + Dwarf_Off abb_goff = 0; + Dwarf_Unsigned atcount = 0; + Dwarf_Unsigned impl_const_count = 0; + Dwarf_Byte_Ptr abbrev_ptr2 = 0; + int res = 0; + + abb_goff = abbrev_ptr - abbrev_section_start; + DECODE_LEB128_UWORD_CK(abbrev_ptr, abbrev_code, + dbg,error,end_abbrev_ptr); + DECODE_LEB128_UWORD_CK(abbrev_ptr, abbrev_tag, + dbg,error,end_abbrev_ptr); + if (abbrev_tag > DW_TAG_hi_user) { + return _dwarf_format_TAG_err_msg(dbg, + abbrev_tag,"DW_DLE_TAG_CORRUPT", + error); + } + if (abbrev_ptr >= end_abbrev_ptr) { + _dwarf_error(dbg, error, DW_DLE_ABBREV_OFF_END); + return DW_DLV_ERROR; + } + inner_list_entry = (Dwarf_Abbrev_List) + calloc(1,sizeof(struct Dwarf_Abbrev_List_s)); + if (!inner_list_entry) { + _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, + "DW_DLE_ALLOC_FAIL: Allocating an " + "abbrev list entry"); + return DW_DLV_ERROR; + } + new_hashable_val = abbrev_code; + if (abbrev_code > context->cc_highest_known_code) { + context->cc_highest_known_code = abbrev_code; + } + hash_num = new_hashable_val HT_MOD_OP + (hash_table_base->tb_table_entry_count-1); + if (hash_num > hash_table_base->tb_highest_used_entry) { + hash_table_base->tb_highest_used_entry = hash_num; + } + + hash_table_base->tb_total_abbrev_count++; + inner_list_entry->abl_code = abbrev_code; + inner_list_entry->abl_tag = abbrev_tag; + inner_list_entry->abl_has_child = *(abbrev_ptr++); + inner_list_entry->abl_abbrev_ptr = abbrev_ptr; + inner_list_entry->abl_goffset = abb_goff; + + /* Move_entry_to_new_hash list recording + in cu_context. */ + inner_list_entry->abl_next = entry_base[hash_num]; + entry_base[hash_num] = inner_list_entry; + /* Cycle thru the abbrev content, + ignoring the content except + to find the end of the content. */ + res = _dwarf_count_abbrev_entries(dbg,abbrev_ptr, + end_abbrev_ptr,&atcount,&impl_const_count, + &abbrev_ptr2,error); + if (res != DW_DLV_OK) { + *highest_known_code = + context->cc_highest_known_code; + return res; + } + inner_list_entry->abl_implicit_const_count = + impl_const_count; + abbrev_ptr = abbrev_ptr2; + inner_list_entry->abl_abbrev_count = atcount; + } while ((abbrev_ptr < end_abbrev_ptr) && + *abbrev_ptr != 0 && abbrev_code != code); + + *highest_known_code = context->cc_highest_known_code; + context->cc_last_abbrev_ptr = abbrev_ptr; + context->cc_last_abbrev_endptr = end_abbrev_ptr; + if (abbrev_code == code) { + *list_out = inner_list_entry; + inner_list_entry->abl_reference_count++; + return DW_DLV_OK; + } + /* We cannot find an abbrev_code matching code. + ERROR will be declared eventually. + Might be better to declare + specific errors here? */ + return DW_DLV_NO_ENTRY; +} + +/* + We check that: + areaptr <= strptr. + a NUL byte (*p) exists at p < end. + and return DW_DLV_ERROR if a check fails. + + de_assume_string_in_bounds +*/ +int +_dwarf_check_string_valid(Dwarf_Debug dbg,void *areaptr, + void *strptr, void *areaendptr, + int suggested_error, + Dwarf_Error*error) +{ + Dwarf_Small *start = areaptr; + Dwarf_Small *p = strptr; + Dwarf_Small *end = areaendptr; + + if (p < start) { + _dwarf_error(dbg,error,suggested_error); + return DW_DLV_ERROR; + } + if (p >= end) { + _dwarf_error(dbg,error,suggested_error); + return DW_DLV_ERROR; + } + if (dbg->de_assume_string_in_bounds) { + /* This NOT the default. But folks can choose + to live dangerously and just assume strings ok. */ + return DW_DLV_OK; + } + while (p < end) { + if (*p == 0) { + return DW_DLV_OK; + } + ++p; + } + _dwarf_error(dbg,error,DW_DLE_STRING_NOT_TERMINATED); + return DW_DLV_ERROR; +} + +/* Return non-zero if the start/end are not valid for the + die's section. + If pastend matches the dss_data+dss_size then + pastend is a pointer that cannot be dereferenced. + But we allow it as valid here, it is normal for + a pointer to point one-past-end in + various circumstances (one must + avoid dereferencing it, of course). + Return 0 if valid. Return 1 if invalid. */ +int +_dwarf_reference_outside_section(Dwarf_Die die, + Dwarf_Small * startaddr, + Dwarf_Small * pastend) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context contxt = 0; + struct Dwarf_Section_s *sec = 0; + + contxt = die->di_cu_context; + dbg = contxt->cc_dbg; + if (die->di_is_info) { + sec = &dbg->de_debug_info; + } else { + sec = &dbg->de_debug_types; + } + if (startaddr < sec->dss_data) { + return 1; + } + if (pastend > (sec->dss_data + sec->dss_size)) { + return 1; + } + return 0; +} + +/* This calculation used to be sprinkled all over. + Now brought to one place. + + We try to accurately compute the size of a cu header + given a known cu header location ( an offset in .debug_info + or debug_types). */ +/* ARGSUSED */ + +int +_dwarf_length_of_cu_header(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Bool is_info, + Dwarf_Unsigned *area_length_out, + Dwarf_Error *error) +{ + int local_length_size = 0; + int local_extension_size = 0; + Dwarf_Half version = 0; + Dwarf_Unsigned length = 0; + Dwarf_Unsigned final_size = 0; + Dwarf_Small *section_start = + is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + Dwarf_Small *cuptr = section_start + offset; + Dwarf_Unsigned section_length = + is_info? dbg->de_debug_info.dss_size: + dbg->de_debug_types.dss_size; + Dwarf_Small * section_end_ptr = + section_start + section_length; + + READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned, + cuptr, local_length_size, local_extension_size, + error,section_length,section_end_ptr); + if (length > section_length || + (length+local_length_size + local_extension_size) > + section_length) { + _dwarf_create_area_len_error(dbg, error, + length+local_length_size + local_extension_size, + section_length); + return DW_DLV_ERROR; + } + + READ_UNALIGNED_CK(dbg, version, Dwarf_Half, + cuptr, DWARF_HALF_SIZE,error,section_end_ptr); + cuptr += DWARF_HALF_SIZE; + if (version == 5) { + Dwarf_Ubyte unit_type = 0; + + READ_UNALIGNED_CK(dbg, unit_type, Dwarf_Ubyte, + cuptr, sizeof(Dwarf_Ubyte),error,section_end_ptr); + switch (unit_type) { + case DW_UT_compile: + case DW_UT_partial: + final_size = local_extension_size + + local_length_size + /* Size of cu length field. */ + DWARF_HALF_SIZE + /* Size of version stamp field. */ + sizeof(Dwarf_Small)+ /* Size of unit type field. */ + sizeof(Dwarf_Small)+ /* Size of address size field. */ + local_length_size ; /* Size of abbrev offset field. */ + break; + case DW_UT_type: + case DW_UT_split_type: + final_size = local_extension_size + + local_length_size +/*Size of type unit length field.*/ + DWARF_HALF_SIZE + /* Size of version stamp field. */ + sizeof(Dwarf_Small)+ /*Size of unit type field. */ + sizeof(Dwarf_Small)+ /*Size of address size field. */ + local_length_size + /*Size of abbrev offset field. */ + sizeof(Dwarf_Sig8) + /*Size of type signature field.*/ + local_length_size; /* Size of type offset field. */ + break; + case DW_UT_skeleton: + case DW_UT_split_compile: + final_size = local_extension_size + + local_length_size + /* Size of unit length field. */ + DWARF_HALF_SIZE + /* Size of version stamp field. */ + sizeof(Dwarf_Small) + /* Size of unit type field. */ + sizeof(Dwarf_Small)+ /* Size of address size field. */ + local_length_size + /* Size of abbrev offset field. */ + sizeof(Dwarf_Sig8); /* Size of dwo id field. */ + break; + default: + _dwarf_error(dbg,error,DW_DLE_UNIT_TYPE_NOT_HANDLED); + return DW_DLV_ERROR; + } + } else if (version == 4) { + final_size = local_extension_size + + local_length_size + /* Size of cu length field. */ + DWARF_HALF_SIZE + /* Size of version stamp field. */ + local_length_size + /* Size of abbrev offset field. */ + sizeof(Dwarf_Small); /* Size of address size field. */ + if (!is_info) { + final_size += + /* type signature size */ + sizeof (Dwarf_Sig8) + + /* type offset size */ + local_length_size; + } + } else if (version < 4) { + final_size = local_extension_size + + local_length_size + + DWARF_HALF_SIZE + + local_length_size + + sizeof(Dwarf_Small); /* Size of address size field. */ + } + + *area_length_out = final_size; + return DW_DLV_OK; +} + +/* Pretend we know nothing about the CU + and just roughly compute the result. */ +Dwarf_Unsigned +_dwarf_length_of_cu_header_simple(Dwarf_Debug dbg, + Dwarf_Bool dinfo) +{ + Dwarf_Unsigned finalsize = 0; + finalsize = dbg->de_length_size + /* Size of cu length field. */ + DWARF_HALF_SIZE + /* Size of version stamp field. */ + dbg->de_length_size + /* Size of abbrev offset field. */ + sizeof(Dwarf_Small); /* Size of address size field. */ + if (!dinfo) { + finalsize += + /* type signature size */ + sizeof (Dwarf_Sig8) + + /* type offset size */ + dbg->de_length_size; + } + return finalsize; +} + +/* Now that we delay loading .debug_info, we need to do the + load in more places. So putting the load + code in one place now instead of replicating it in multiple + places. */ +int +_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + if (dbg->de_debug_info.dss_data) { + return DW_DLV_OK; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_info, error); + if (res != DW_DLV_OK) { + return res; + } + /* debug_info won't be meaningful without + .debug_rnglists and .debug_rnglists if there + is one or both such sections. */ + res = dwarf_load_rnglists(dbg,0,error); + if (res == DW_DLV_ERROR) { + return res; + } + res = dwarf_load_loclists(dbg,0,error); + if (res == DW_DLV_ERROR) { + return res; + } + return DW_DLV_OK; +} +int +_dwarf_load_debug_types(Dwarf_Debug dbg, Dwarf_Error * error) +{ + int res = DW_DLV_ERROR; + if (dbg->de_debug_types.dss_data) { + return DW_DLV_OK; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error); + if (res != DW_DLV_OK) { + return res; + } + res = _dwarf_load_section(dbg, &dbg->de_debug_types, error); + return res; +} +void +_dwarf_free_abbrev_hash_table_contents(Dwarf_Hash_Table hash_table, + Dwarf_Bool keep_abbrev_list) +{ +#ifdef TESTINGHASHTAB + Dwarf_Unsigned max_refs = 0; +#endif + /* A Hash Table is an array with tb_table_entry_count + struct Dwarf_Hash_Table_Entry_s entries in the array. */ + unsigned long hashnum = 0; + + if (!hash_table) { + /* Not fully set up yet. There is nothing to do. */ + return; + } + if (!hash_table->tb_entries) { + /* Not fully set up yet. There is nothing to do. */ + return; + } + + if (!keep_abbrev_list) { + for (hashnum=0; hashnum <= hash_table->tb_highest_used_entry; + ++hashnum) { + Dwarf_Abbrev_List nextabbrev = 0; + Dwarf_Abbrev_List abbrev = + hash_table->tb_entries[hashnum]; +#ifdef TESTINGHASHTAB + unsigned listcount = 0; +#endif + + if (!abbrev) { + continue; + } + for (; abbrev; abbrev = nextabbrev) { +#ifdef TESTINGHASHTAB + if (abbrev->abl_reference_count > max_refs) { + max_refs = abbrev->abl_reference_count; + } +#endif + free(abbrev->abl_attr); + abbrev->abl_attr = 0; + free(abbrev->abl_form); + abbrev->abl_form = 0; + free(abbrev->abl_implicit_const); + abbrev->abl_implicit_const = 0; + nextabbrev = abbrev->abl_next; + abbrev->abl_next = 0; + /* dealloc single list entry */ + free(abbrev); + abbrev = 0; +#ifdef TESTINGHASHTAB + ++listcount; +#endif + } +#ifdef TESTINGHASHTAB +printf("debugging: hashnum %lu listcount %u\n",hashnum,listcount); +#endif + } + } +#ifdef TESTINGHASHTAB +printf("debugging: max ref count of any abbrev %lu, \n", +(unsigned long)max_refs); +#endif + /* Frees all the pointers at once: an array. */ + free(hash_table->tb_entries); + hash_table->tb_entries = 0; +} + +/* + If no die provided the size value returned might be wrong. + If different compilation units have different address sizes + this may not give the correct value in all contexts if the die + pointer is NULL. + If the Elf offset size != address_size + (for example if address_size = 4 but recorded in elf64 object) + this may not give the correct value in all contexts if the die + pointer is NULL. + If the die pointer is non-NULL (in which case it must point to + a valid DIE) this will return the correct size. +*/ +int +_dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die) +{ + Dwarf_CU_Context context = 0; + Dwarf_Half addrsize = 0; + if (!die) { + return dbg->de_pointer_size; + } + context = die->di_cu_context; + addrsize = context->cc_address_size; + return addrsize; +} + +struct Dwarf_Printf_Callback_Info_s +dwarf_register_printf_callback( Dwarf_Debug dbg, + struct Dwarf_Printf_Callback_Info_s * newvalues) +{ + struct Dwarf_Printf_Callback_Info_s oldval = + dbg->de_printf_callback; + + if (!newvalues) { + return oldval; + } + if ( newvalues->dp_buffer_user_provided) { + if ( oldval.dp_buffer_user_provided) { + /* User continues to control the buffer. */ + dbg->de_printf_callback = *newvalues; + }else { + /* Switch from our control of buffer to user + control. */ + free(oldval.dp_buffer); + oldval.dp_buffer = 0; + dbg->de_printf_callback = *newvalues; + } + } else if (oldval.dp_buffer_user_provided){ + /* Switch from user control to our control */ + dbg->de_printf_callback = *newvalues; + dbg->de_printf_callback.dp_buffer_len = 0; + dbg->de_printf_callback.dp_buffer= 0; + } else { + /* User does not control the buffer. */ + dbg->de_printf_callback = *newvalues; + dbg->de_printf_callback.dp_buffer_len = + oldval.dp_buffer_len; + dbg->de_printf_callback.dp_buffer = + oldval.dp_buffer; + } + return oldval; +} + +/* No varargs required */ +int +_dwarf_printf(Dwarf_Debug dbg, + const char * data) +{ + int nlen = 0; + struct Dwarf_Printf_Callback_Info_s *bufdata = + &dbg->de_printf_callback; + + dwarf_printf_callback_function_type func = bufdata->dp_fptr; + if (!func) { + return 0; + } + nlen = strlen(data); + func(bufdata->dp_user_pointer,data); + return nlen; +} + +/* Often errs and errt point to the same Dwarf_Error, + So exercise care. + All the arguments MUST be non-null, though + we deal with null errs/errt as best we can. + We ensure null dbg? will not cause problem either. */ +void +_dwarf_error_mv_s_to_t(Dwarf_Debug dbgs,Dwarf_Error *errs, + Dwarf_Debug dbgt,Dwarf_Error *errt) +{ + int mydw_errno = 0; + if (!errt) { + if (!errs) { + /* Nobody here! Surely this is impossible. */ + return; + } else { + /* There is no errt to copy errs to! */ + dwarf_dealloc(dbgs,*errs, DW_DLA_ERROR); + *errs = 0; + } + return; + } + if (!errs) { + /* there is no useful errs to build errt with! */ + return; + } + if (dbgs == dbgt) { + /* nothing much to do here. */ + if (errs != errt) { + /* Trivial copy of an error. */ + Dwarf_Error ers = *errs; + *errs = 0; + *errt = ers; + } + return; + } + /* copy errs errno to errt by building + a new errt. + variable if there is one! + Move the error from dbgs to dbgt. */ + mydw_errno = dwarf_errno(*errs); + + dwarf_dealloc(dbgs,*errs, DW_DLA_ERROR); + *errs = 0; + _dwarf_error(dbgt,errt, mydw_errno); +} + +static int +inthissection(struct Dwarf_Section_s *sec,Dwarf_Small *ptr) +{ + if (!sec->dss_data) { + return FALSE; + } + if (ptr < sec->dss_data ) { + return FALSE; + } + if (ptr >= (sec->dss_data + sec->dss_size) ) { + return FALSE; + } + return TRUE; +} + +#define FINDSEC(m_s,m_p,n,st,l,e) \ +do { \ + if (inthissection((m_s),(m_p))) { \ + *(n) = (m_s)->dss_name; \ + *(st)= (m_s)->dss_data; \ + *(l) = (m_s)->dss_size; \ + *(e) = (m_s)->dss_data + (m_s)->dss_size; \ + return DW_DLV_OK; \ + } \ +} while (0) + +/* So we can know a section end even when we do not + have the section info apriori It's only + needed for a subset of sections. */ +int +_dwarf_what_section_are_we(Dwarf_Debug dbg, + Dwarf_Small * our_pointer, + const char ** section_name_out, + Dwarf_Small ** sec_start_ptr_out, + Dwarf_Unsigned * sec_len_out, + Dwarf_Small ** sec_end_ptr_out) +{ + FINDSEC(&dbg->de_debug_info, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_loc, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_loclists, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_rnglists, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_addr, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_line, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_aranges, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_macro, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_ranges, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_str_offsets, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_addr, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_pubtypes, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_gdbindex, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_abbrev, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_cu_index, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_tu_index, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_line_str, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_types, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_sup, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_frame, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_debug_frame_eh_gnu, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_gnu_debuglink, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + FINDSEC(&dbg->de_note_gnu_buildid, + our_pointer, section_name_out, + sec_start_ptr_out, sec_len_out, sec_end_ptr_out); + return DW_DLV_NO_ENTRY; +} + +/* New late April 2020. + All the crucial macros will surely + need to use wrapper code to ensure we do not leak + memory at certain points. */ +int +_dwarf_read_unaligned_ck_wrapper(Dwarf_Debug dbg, + Dwarf_Unsigned *out_value, + Dwarf_Small *readfrom, + int readlength, + Dwarf_Small *end_arange, + Dwarf_Error *error) +{ + Dwarf_Unsigned val = 0; + + READ_UNALIGNED_CK(dbg,val,Dwarf_Unsigned, + readfrom,readlength,error,end_arange); + *out_value = val; + return DW_DLV_OK; +} + +int +_dwarf_read_area_length_ck_wrapper(Dwarf_Debug dbg, + Dwarf_Unsigned *out_value, + Dwarf_Small **readfrom, + int *length_size_out, + int *exten_size_out, + Dwarf_Unsigned sectionlength, + Dwarf_Small *endsection, + Dwarf_Error *error) +{ + Dwarf_Small *ptr = *readfrom; + Dwarf_Unsigned length = 0; + int length_size = 0; + int exten_size = 0; + + /* This verifies the lenght itself can be read, + callers must verify the length is appropriate. */ + READ_AREA_LENGTH_CK(dbg,length,Dwarf_Unsigned, + ptr,length_size,exten_size, + error, + sectionlength,endsection); + /* It is up to callers to check the length etc. */ + *readfrom = ptr; + *out_value = length; + *length_size_out = length_size; + *exten_size_out = exten_size; + return DW_DLV_OK; +} +/* New March 2020 */ +/* We need to increment startptr for the caller + in these wrappers so the caller passes in + wrappers return either DW_DLV_OK or DW_DLV_ERROR. + Never DW_DLV_NO_ENTRY. */ +int +_dwarf_leb128_uword_wrapper(Dwarf_Debug dbg, + Dwarf_Small ** startptr, + Dwarf_Small * endptr, + Dwarf_Unsigned *out_value, + Dwarf_Error * error) +{ + Dwarf_Unsigned utmp2 = 0; + Dwarf_Small * start = *startptr; + DECODE_LEB128_UWORD_CK(start, utmp2, + dbg,error,endptr); + *out_value = utmp2; + *startptr = start; + return DW_DLV_OK; +} +int +_dwarf_leb128_sword_wrapper(Dwarf_Debug dbg, + Dwarf_Small ** startptr, + Dwarf_Small * endptr, + Dwarf_Signed *out_value, + Dwarf_Error * error) +{ + Dwarf_Small * start = *startptr; + Dwarf_Signed stmp2 = 0; + DECODE_LEB128_SWORD_CK(start, stmp2, + dbg,error,endptr); + *out_value = stmp2; + *startptr = start; + return DW_DLV_OK; +} diff --git a/src/lib/libdwarf/dwarf_util.h b/src/lib/libdwarf/dwarf_util.h new file mode 100644 index 0000000..c2d7d4b --- /dev/null +++ b/src/lib/libdwarf/dwarf_util.h @@ -0,0 +1,516 @@ +#ifndef DWARF_UTIL_H +#define DWARF_UTIL_H +/* +Copyright (C) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. +Portions Copyright (C) 2007-2023 David Anderson. All Rights Reserved. +Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include "dwarf_base_types.h" + +void +_dwarf_create_area_len_error(Dwarf_Debug dbg, Dwarf_Error *error, + Dwarf_Unsigned targ, Dwarf_Unsigned sectionlen); + +#define SKIP_LEB128_CK(ptr,dbg,errptr,endptr) \ + do { \ + Dwarf_Unsigned lu_leblen = 0; \ + int lu_res = 0; \ + lu_res = _dwarf_skip_leb128((char *)(ptr),&lu_leblen, \ + (char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: skipping leb128" \ + " runs past allowed area.a"); \ + return DW_DLV_ERROR; \ + } \ + (ptr) += lu_leblen; \ + } while (0) +#define SKIP_LEB128_LEN_CK(ptr,leblen,dbg,errptr,endptr) \ + do { \ + Dwarf_Unsigned lu_leblen = 0; \ + int lu_res = 0; \ + lu_res = _dwarf_skip_leb128((char *)(ptr),&lu_leblen, \ + (char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: skipping leb128 w/len" \ + " runs past allowed area.b"); \ + return DW_DLV_ERROR; \ + } \ + (ptr) += lu_leblen; \ + (leblen) = lu_leblen; \ + } while (0) + +#define DECODE_LEB128_UWORD_CK(ptr, value,dbg,errptr,endptr) \ + do { \ + Dwarf_Unsigned lu_leblen = 0; \ + Dwarf_Unsigned lu_local = 0; \ + int lu_res = 0; \ + lu_res = dwarf_decode_leb128((char *)(ptr),&lu_leblen,\ + &lu_local,(char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: decode uleb" \ + " runs past allowed area.c"); \ + return DW_DLV_ERROR; \ + } \ + (value) = lu_local; \ + (ptr) += lu_leblen; \ + } while (0) + +#define DECODE_LEB128_UWORD_LEN_CK(ptr, value,leblen,dbg,\ + errptr,endptr) \ + do { \ + Dwarf_Unsigned lu_leblen = 0; \ + Dwarf_Unsigned lu_local = 0; \ + int lu_res = 0; \ + lu_res = dwarf_decode_leb128((char *)(ptr), \ + &lu_leblen,&lu_local,(char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: decode uleb w/len" \ + " runs past allowed area.d"); \ + return DW_DLV_ERROR; \ + } \ + (value) = lu_local; \ + (ptr) += lu_leblen; \ + (leblen) = lu_leblen; \ + } while (0) + +/* + Decodes signed leb128 encoded numbers. + Make sure ptr is a pointer to a 1-byte type. + In 2003 and earlier this was a hand-inlined + version of dwarf_decode_leb128() which did + not work correctly if Dwarf_Unsigned was 64 bits. + +*/ +#define DECODE_LEB128_SWORD_CK(ptr, value,dbg,errptr,endptr) \ + do { \ + Dwarf_Unsigned uleblen = 0; \ + Dwarf_Signed local = 0; \ + int lu_res = 0; \ + lu_res = dwarf_decode_signed_leb128((char *)(ptr),\ + &uleblen, \ + &local,(char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: decode sleb" \ + " runs past allowed area.e"); \ + return DW_DLV_ERROR; \ + } \ + (value) = local; \ + (ptr) += uleblen; \ + } while (0) +#define DECODE_LEB128_SWORD_LEN_CK(ptr, value,leblen,dbg,\ + errptr,endptr) \ + do { \ + Dwarf_Unsigned lu_leblen = 0; \ + Dwarf_Signed lu_local = 0; \ + int lu_res = 0; \ + lu_res = dwarf_decode_signed_leb128((char *)(ptr),\ + &lu_leblen,\ + &lu_local,(char *)(endptr)); \ + if (lu_res == DW_DLV_ERROR) { \ + _dwarf_error_string((dbg), (errptr), \ + DW_DLE_LEB_IMPROPER, \ + "DW_DLE_LEB_IMPROPER: decode sleb w/len " \ + " runs past allowed area.f"); \ + return DW_DLV_ERROR; \ + } \ + (leblen) = lu_leblen; \ + (value) = lu_local; \ + (ptr) += lu_leblen; \ + } while (0) + +/* Any error found here represents a bug that cannot + be dealloc-d as the caller will not know there was no dbg */ +#define CHECK_DIE(die, error_ret_value) \ + do { \ + Dwarf_Debug ckdi_dbg = 0; \ + if (!(die)) { \ + _dwarf_error(NULL, error, DW_DLE_DIE_NULL);\ + return(error_ret_value); \ + } \ + if ((die)->di_cu_context == NULL) { \ + _dwarf_error(NULL, error, \ + DW_DLE_DIE_NO_CU_CONTEXT); \ + return(error_ret_value); \ + } \ + ckdi_dbg = (die)->di_cu_context->cc_dbg; \ + if (!ckdi_dbg || ckdi_dbg->de_magic != DBG_IS_VALID) {\ + _dwarf_error_string(NULL, error, DW_DLE_DBG_NULL, \ + "DW_DLE_DBG_NULL: " \ + "accesing a cu context, Dwarf_Debug " \ + "either null or it contains" \ + "a stale Dwarf_Debug pointer"); \ + return DW_DLV_ERROR; \ + } \ + } while (0) + +/* + Reads 'source' for 'length' bytes from unaligned addr. + + Avoids any constant-in-conditional warnings and + avoids a test in the generated code (for non-const cases, + which are in the majority.) + Uses a temp to avoid the test. + The decl here should avoid any problem of size in the temp. + This code is ENDIAN DEPENDENT + The memcpy args are the endian issue. + + Does not update the 'source' field. + + for READ_UNALIGNED_CK the error code refers to host endianness. +*/ +typedef Dwarf_Unsigned BIGGEST_UINT; + +#ifdef WORDS_BIGENDIAN +#define READ_UNALIGNED_CK(dbg,dest,desttype, source,\ + length,error,endptr) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + Dwarf_Byte_Ptr readend = (source)+(length); \ + if (readend < (source)) { \ + _dwarf_error_string((dbg), (error), \ + DW_DLE_READ_BIGENDIAN_ERROR, \ + "DW_DLE_READ_BIGENDIAN_ERROR " \ + "Read would start past the end of section");\ + return DW_DLV_ERROR; \ + } \ + if (readend > (endptr)) { \ + _dwarf_error_string((dbg), (error),\ + DW_DLE_READ_BIGENDIAN_ERROR, \ + "DW_DLE_READ_BIGENDIAN_ERROR " \ + "Read would end past the end of section"); \ + return DW_DLV_ERROR; \ + } \ + (dbg)->de_copy_word( (((char *)(&_ltmp)) + \ + sizeof(_ltmp) - (length)),(source), (length)) ; \ + (dest) = (desttype)_ltmp; \ + } while (0) +#else /* LITTLE ENDIAN */ +#define READ_UNALIGNED_CK(dbg,dest,desttype, source,\ + length,error,endptr) \ + do { \ + BIGGEST_UINT _ltmp = 0; \ + Dwarf_Byte_Ptr readend = (source)+(length); \ + if (readend < (source)) { \ + _dwarf_error_string((dbg), (error), \ + DW_DLE_READ_LITTLEENDIAN_ERROR, \ + "DW_DLE_READ_LITTLEENDIAN_ERROR "\ + "Read starts past the end of section");\ + return DW_DLV_ERROR; \ + } \ + if (readend > (endptr)) { \ + _dwarf_error_string((dbg), (error), \ + DW_DLE_READ_LITTLEENDIAN_ERROR, \ + "DW_DLE_READ_LITTLEENDIAN_ERROR "\ + "Read would end past the end of section");\ + return DW_DLV_ERROR; \ + } \ + (dbg)->de_copy_word((char *)(&_ltmp), \ + (source), (length)) ; \ + (dest) = (desttype)_ltmp; \ + } while (0) +#endif + +/* + READ_AREA LENGTH reads the length (the older way + of pure 32 or 64 bit + or the dwarf v3 64bit-extension way) + + It reads the bits from where rw_src_data_p points to + and updates the rw_src_data_p to point past what was just read. + + It updates w_length_size (to the size of an offset, either 4 or 8) + and w_exten_size (set 0 unless this frame has the DWARF3 + and later 64bit + extension, in which case w_exten_size is set to 4). + + r_dbg is just the current dbg pointer. + w_target is the output length field. + r_targtype is the output type. Always Dwarf_Unsigned so far. + +*/ +/* This one handles the v3 64bit extension + and 32bit (and SGI/MIPS fixed 64 bit via the + dwarf_init-set r_dbg->de_length_size).. + It does not recognize any but the one distinguished value + (the only one with defined meaning). + It assumes that no CU will have a length + 0xffffffxx (32bit length) + or + 0xffffffxx xxxxxxxx (64bit length) + which makes possible auto-detection of the extension. + + This depends on knowing that only a non-zero length + is legitimate (AFAICT), and for IRIX non-standard -64 + dwarf that the first 32 bits of the 64bit offset will be + zero (because the compiler could not handle a truly large + value as of Jan 2003 and because no app has that much debug + info anyway, at least not in the IRIX case). + + At present not testing for '64bit elf' here as that + does not seem necessary (none of the 64bit length seems + appropriate unless it's ident[EI_CLASS] == ELFCLASS64). +*/ +/* The w_target > r_sectionlen compare is done without adding in case + the w_target value read is so large any addition would overflow. + A basic value sanity check. */ +#define READ_AREA_LENGTH_CK(r_dbg,w_target,r_targtype, \ + rw_src_data_p,w_length_size,w_exten_size,w_error, \ + r_sectionlen,r_endptr) \ + do { \ + READ_UNALIGNED_CK(r_dbg,w_target,r_targtype, \ + rw_src_data_p, ORIGINAL_DWARF_OFFSET_SIZE, \ + w_error,r_endptr); \ + if ((w_target) == DISTINGUISHED_VALUE) { \ + /* dwarf3 64bit extension */ \ + (w_length_size) = DISTINGUISHED_VALUE_OFFSET_SIZE; \ + (rw_src_data_p) += ORIGINAL_DWARF_OFFSET_SIZE; \ + (w_exten_size) = ORIGINAL_DWARF_OFFSET_SIZE; \ + READ_UNALIGNED_CK(r_dbg,w_target,r_targtype, \ + rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE,\ + w_error,r_endptr); \ + if ((w_target) > (r_sectionlen)) { \ + _dwarf_create_area_len_error((r_dbg),(w_error),\ + (w_target),(r_sectionlen)); \ + return DW_DLV_ERROR; \ + } \ + (rw_src_data_p) += DISTINGUISHED_VALUE_OFFSET_SIZE; \ + } else { \ + if (!(w_target) && (r_dbg)->de_big_endian_object) {\ + /* Might be IRIX: We have to distinguish between */\ + /* 32-bit DWARF format and IRIX 64-bit \ + DWARF format. */ \ + if ((r_dbg)->de_length_size == 8) { \ + /* IRIX 64 bit, big endian. This test */ \ + /* is not a truly precise test, a precise test*/ \ + /* would check if the target was IRIX. */ \ + READ_UNALIGNED_CK(r_dbg, w_target , \ + r_targtype, \ + rw_src_data_p, \ + DISTINGUISHED_VALUE_OFFSET_SIZE, \ + (w_error),(r_endptr)); \ + if ((w_target) > (r_sectionlen)) { \ + _dwarf_create_area_len_error((r_dbg), \ + (w_error), \ + (w_target),(r_sectionlen)); \ + return DW_DLV_ERROR; \ + } \ + (w_length_size) = \ + DISTINGUISHED_VALUE_OFFSET_SIZE; \ + (rw_src_data_p) += \ + DISTINGUISHED_VALUE_OFFSET_SIZE; \ + (w_exten_size) = 0; \ + } else { \ + /* 32 bit, big endian */ \ + (w_length_size) = ORIGINAL_DWARF_OFFSET_SIZE;\ + (rw_src_data_p) += (w_length_size); \ + (w_exten_size) = 0; \ + } \ + } else { \ + if ((w_target) > (r_sectionlen)) { \ + _dwarf_create_area_len_error((r_dbg), \ + (w_error), \ + (w_target),(r_sectionlen)); \ + return DW_DLV_ERROR; \ + } \ + /* Standard 32 bit dwarf2/dwarf3 */ \ + (w_exten_size) = 0; \ + (w_length_size) = ORIGINAL_DWARF_OFFSET_SIZE; \ + (rw_src_data_p) += (w_length_size); \ + } \ + } \ + } while (0) + +int _dwarf_format_TAG_err_msg(Dwarf_Debug dbg, + Dwarf_Unsigned tag,const char *m, + Dwarf_Error *error); + +int +_dwarf_get_size_of_val(Dwarf_Debug dbg, + Dwarf_Unsigned form, + Dwarf_Half cu_version, + Dwarf_Half address_size, + Dwarf_Small * val_ptr, + int v_length_size, + Dwarf_Unsigned *size_out, + Dwarf_Small *section_end_ptr, + Dwarf_Error *error); + +/* + Dwarf_Hash_Table_s is the base for the 'hash' table. + The table occurs exactly once per CU. + + The intent is that once the total_abbrev_count across + one should build a new Dwarf_Hash_Table_Base_s, rehash + all the existing entries, and delete the old table and entries. + One (500MB) application had + 127000 abbreviations in one compilation unit but + that is clearly an outlier, so this goes for + good performance for more normal compilation units. + The incoming 'code' is an abbrev number and those simply + increase linearly so the hashing is perfect always. + As a result we have + tb_highest_used_entry to tell us the highest + hash value seen, shorting some operations, like + dealloc. +*/ +struct Dwarf_Hash_Table_s { + unsigned long tb_table_entry_count; + unsigned long tb_total_abbrev_count; + unsigned long tb_highest_used_entry; + /* Each table entry is a pointer to + a list of abbrev-codes and their details. + Each Dwarf_Abbrev_List pointer in the array here, + and in each singly-linked list starting + there points to the entries for one abbrev code. */ + Dwarf_Abbrev_List *tb_entries; +}; + +/* Perhaps not actually useful. */ +struct Dwarf_Abbrev_Common_s { + /* From cu_context */ + Dwarf_Debug ac_dbg; + Dwarf_Hash_Table ac_hashtable_base; + Dwarf_Unsigned ac_highest_known_code; + Dwarf_Byte_Ptr ac_last_abbrev_ptr; + Dwarf_Byte_Ptr ac_last_abbrev_endptr; + /* section global offset of relevant abbrev data. */ + Dwarf_Unsigned ac_abbrev_offset; + /* pointer to the start of abbrevs (section or table) */ + Dwarf_Byte_Ptr ac_abbrev_ptr; + /* The following NULL if this is debug_names abbrevs */ + struct Dwarf_Debug_Fission_Per_CU_s *ac_dwp_offsets; + + /* The Following Apply to a single abbrev. */ + /* ac_implicit_const_count Usually zero */ + Dwarf_Unsigned ac_implict_const_count; + + Dwarf_Unsigned ac_abbrev_count; + /* Array of ac_abbrev_count attr/form pairs. */ + Dwarf_Half *ac_attr; + Dwarf_Small *ac_form; + /* Array of ac_abbrev_count implicit const values + iff ac_implicit_const_count > 0 */ + Dwarf_Signed *ac_implicit_const; + + /* For single abbrev */ + Dwarf_Byte_Ptr ac_abbrev_section_start; + + /* pointer to end of abbrevs (section to start, + then table when known) */ + Dwarf_Byte_Ptr ac_end_abbrev_ptr; +}; + +int _dwarf_get_abbrev_for_code(struct Dwarf_CU_Context_s *abcom, + Dwarf_Unsigned code, + Dwarf_Abbrev_List *list_out, + Dwarf_Unsigned * highest_known_code, + Dwarf_Error *error); + +/* return 1 if string ends before 'endptr' else +** return 0 meaning string is not properly terminated. +** Presumption is the 'endptr' pts to end of some dwarf section data. +*/ +int _dwarf_check_string_valid(Dwarf_Debug dbg,void *areaptr, + void *startptr, void *endptr, + int suggested_error, Dwarf_Error *error); + +int _dwarf_length_of_cu_header(Dwarf_Debug dbg, + Dwarf_Unsigned offset, + Dwarf_Bool is_info, + Dwarf_Unsigned *area_length_out, + Dwarf_Error *error); + +Dwarf_Unsigned _dwarf_length_of_cu_header_simple(Dwarf_Debug, + Dwarf_Bool dinfo); + +int _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error *error); +int _dwarf_load_debug_types(Dwarf_Debug dbg, Dwarf_Error *error); +void _dwarf_free_abbrev_hash_table_contents( + struct Dwarf_Hash_Table_s* hash_table, + Dwarf_Bool keep_abbrev_content); +int _dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die); +int _dwarf_reference_outside_section(Dwarf_Die die, + Dwarf_Small * startaddr, + Dwarf_Small * pastend); +void _dwarf_error_mv_s_to_t(Dwarf_Debug dbgs,Dwarf_Error *errs, + Dwarf_Debug dbgt,Dwarf_Error *errt); + +int _dwarf_internal_get_die_comp_dir(Dwarf_Die die, + const char **compdir_out, + const char **comp_name_out, + Dwarf_Error *error); + +int _dwarf_what_section_are_we(Dwarf_Debug dbg, + Dwarf_Small *our_pointer, + const char ** section_name_out, + Dwarf_Small **sec_start_ptr_out, + Dwarf_Unsigned *sec_len_out, + Dwarf_Small **sec_end_ptr_out); + +/* wrappers return either DW_DLV_OK or DW_DLV_ERROR. + Never DW_DLV_NO_ENTRY. */ +int +_dwarf_read_unaligned_ck_wrapper(Dwarf_Debug dbg, + Dwarf_Unsigned *out_value, + Dwarf_Small *readfrom, + int readlength, + Dwarf_Small *end_arange, + Dwarf_Error *err); +int +_dwarf_read_area_length_ck_wrapper(Dwarf_Debug dbg, + Dwarf_Unsigned *out_value, + Dwarf_Small **readfrom, + int * length_size_out, + int * exten_size_out, + Dwarf_Unsigned sectionlength, + Dwarf_Small *endsection, + Dwarf_Error *err); +int +_dwarf_leb128_uword_wrapper(Dwarf_Debug dbg, + Dwarf_Small ** startptr, + Dwarf_Small * endptr, + Dwarf_Unsigned *out_value, + Dwarf_Error * error); +int +_dwarf_leb128_sword_wrapper(Dwarf_Debug dbg, + Dwarf_Small ** startptr, + Dwarf_Small * endptr, + Dwarf_Signed *out_value, + Dwarf_Error * error); + +#endif /* DWARF_UTIL_H */ diff --git a/src/lib/libdwarf/dwarf_xu_index.c b/src/lib/libdwarf/dwarf_xu_index.c new file mode 100644 index 0000000..85a19b8 --- /dev/null +++ b/src/lib/libdwarf/dwarf_xu_index.c @@ -0,0 +1,1009 @@ +/* + Copyright (C) 2014-2021 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* The file and functions have 'xu' because + the .debug_cu_index and .debug_tu_index + sections have the same layout and this deals with both. + + This is DebugFission, part of DWARF5. + + It allows fast section access in a .dwp object file + with debug-information to locate offsets + within and between sections. + + See the DWARF5 Standard: section 7.3.5 and + examples in Appendix F.3. + + A note about the index field from the index table. + See DWARF5 7.5.3.5. + The index table array index values are [1,S) + These value ae used to call functions requesting + values from the offset table and size table. + + Inside the code in this file we subtract 1 and use + 0 origin as that is how we arranged the + table access here. + A zero in the index table is an unused signature + table signature and unused index. + + By subtracting one and arranging things properly + in the offset table and size table we can refer + to the tables in an identical simple fashion + These tables are thus U rows and N columns. + Technically the Offset table physically + row zero is a separate set of numbers translating + the column number to a DW_SECT* value + so callers can request specific bases(offsets) + and sizes from the offset and size tables. + But we change things a little internally so both + tables look zero-origin. +*/ + +#include + +#include /* memcmp() memcpy() strcmp() */ + +#if defined(_WIN32) && defined(HAVE_STDAFX_H) +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "dwarf.h" +#include "libdwarf.h" +#include "libdwarf_private.h" +#include "dwarf_base_types.h" +#include "dwarf_opaque.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarf_xu_index.h" +#include "dwarf_string.h" + +#define HASHSIGNATURELEN 8 + +/* zerohashkey used as all-zero-bits for comparison. */ +static const Dwarf_Sig8 zerohashkey; + +#if 0 +static void +dump_bytes(char * msg,Dwarf_Small * start, long len) +{ + Dwarf_Small *end = start + len; + Dwarf_Small *cur = start; + + printf("%s ",msg); + for (; cur < end; cur++) { + printf("%02x ", *cur); + } + printf("\n"); +} +#endif /*0*/ + +/* Precondition: headerline_offset + N*32 is within + the section. */ +static int +fill_in_offsets_headerline(Dwarf_Debug dbg, + Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned headerline_offset, + Dwarf_Unsigned num_sects, + Dwarf_Error *error) +{ + Dwarf_Small *section_start = xuhdr->gx_section_data; + Dwarf_Small *section_end = xuhdr->gx_section_data+ + xuhdr->gx_section_length; + Dwarf_Small *data = 0; + unsigned i = 0; + + data = section_start +headerline_offset; + for ( ; i < num_sects ; ++i) { + Dwarf_Unsigned v = 0; + + READ_UNALIGNED_CK(dbg,v, Dwarf_Unsigned, + data,SIZEOFT32, + error,section_end); + data += SIZEOFT32; + if (v > DW_SECT_RNGLISTS) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR The " + "section number of %u ",v); + dwarfstring_append(&s," is too high. " + "Sections 1-8 are listed in " + "DWARF5 Table 7.1."); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + xuhdr->gx_section_id[i] = v; + } + return DW_DLV_OK; +} + +/* Read in a cu or tu section and + return overview information. + + For libdwarf-internal lookups + dwarf_init*() calls + dwarf_get_xu_index_header() when + the object file is opened and + dwarf_dealloc_xu_header() is called + by dwarf_finish(), there is + no need for users to do this. + + If one wants to call the various + tu/cu functions oneself (possibly to print the + .debug_cu_index or .debug_tu_index sections). + then you will need to call dwarf_get_xu_index_header() + and eventually dwarf_dealloc_xu_header(). + + The libdwarf-internal data is kept in Dwarf_Debug + fields de_cu_hashindex_data/de_tu_hashindex_data. +*/ +int +dwarf_get_xu_index_header(Dwarf_Debug dbg, + /* Pass in section_type "tu" or "cu" */ + const char *section_type, + Dwarf_Xu_Index_Header *xuptr, + Dwarf_Unsigned *version, + Dwarf_Unsigned *number_of_columns, /* L section count.*/ + Dwarf_Unsigned *number_of_CUs, /* U unit count */ + Dwarf_Unsigned *number_of_slots, /* S slot count */ + /* Standard says S > U DWARF5 sec 7.3.5.3 */ + const char **section_name, + Dwarf_Error *error) +{ + Dwarf_Xu_Index_Header indexptr = 0; + int res = DW_DLV_ERROR; + struct Dwarf_Section_s *sect = 0; + Dwarf_Unsigned local_version = 0; + Dwarf_Unsigned num_secs = 0; + Dwarf_Unsigned num_CUs = 0; + Dwarf_Unsigned num_slots = 0; + Dwarf_Small *data = 0; + Dwarf_Unsigned tables_end_offset = 0; + Dwarf_Unsigned hash_tab_offset = 0; + Dwarf_Unsigned indexes_tab_offset = 0; + Dwarf_Unsigned section_offsets_tab_offset = 0; + Dwarf_Unsigned section_offsets_headerline_offset = 0; + Dwarf_Unsigned section_sizes_tab_offset = 0; + unsigned datalen32 = SIZEOFT32; + Dwarf_Small *section_end = 0; +/* FIXME */ + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: Dwarf_Debug pointer " + "is not valid"); + return DW_DLV_ERROR; + } + if (!section_type || !xuptr) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: section type or header " + "return pointer is not valid"); + return DW_DLV_ERROR; + } + + if (!strcmp(section_type,"cu") ) { + sect = &dbg->de_debug_cu_index; + } else if (!strcmp(section_type,"tu") ) { + sect = &dbg->de_debug_tu_index; + } else { + _dwarf_error(dbg, error, DW_DLE_XU_TYPE_ARG_ERROR); + return DW_DLV_ERROR; + } + if (!sect->dss_size) { + return DW_DLV_NO_ENTRY; + } + if (!sect->dss_data) { + res = _dwarf_load_section(dbg, sect,error); + if (res != DW_DLV_OK) { + return res; + } + } + + data = sect->dss_data; + section_end = data + sect->dss_size; + + if (sect->dss_size < (4*datalen32) ) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: " + "The size of the %s ", + (char *)section_type); + dwarfstring_append_printf_u(&m, + "is just %u bytes, much to small to be " + " a correct section", + sect->dss_size); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,local_version, Dwarf_Unsigned, + data,datalen32, + error,section_end); + data += datalen32; + + /* reading N */ + READ_UNALIGNED_CK(dbg,num_secs, Dwarf_Unsigned, + data,datalen32, + error,section_end); + if (num_secs > DW_SECT_RNGLISTS) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_XU_NAME_COL_ERROR: " + " %s index section header ", + (char *)section_type); + dwarfstring_append_printf_u(&m, + "shows N, the sections count, " + "as %u but only values " + " 1 through 8 (DW_SECT_RNGLISTS) are valid.", + num_secs); + _dwarf_error_string(dbg,error,DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + data += datalen32; + /* reading U */ + READ_UNALIGNED_CK(dbg,num_CUs, Dwarf_Unsigned, + data,datalen32, + error,section_end); + data += datalen32; + /* reading S */ + READ_UNALIGNED_CK(dbg,num_slots, Dwarf_Unsigned, + data,datalen32, + error,section_end); + hash_tab_offset = datalen32*4; + indexes_tab_offset = hash_tab_offset + + (num_slots * HASHSIGNATURELEN); + /* Look for corrupt section data. */ + if (num_slots > sect->dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: " + "The size of the %s ",(char *)section_type); + dwarfstring_append_printf_u(&m, + " is just %u bytes,",sect->dss_size); + dwarfstring_append_printf_u(&m, + "while the number of slots (S) is %u. " + "which is clearly wrong",num_slots ); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if ( (4*num_slots) > sect->dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: " + "The size of the %s ",(char *)section_type); + dwarfstring_append_printf_u(&m, + " is just %u bytes,",sect->dss_size); + dwarfstring_append_printf_u(&m, + "while the number of slots bytes (S) is at least %u. " + "which is clearly wrong",num_slots*4); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + + /* This offset is to 1 row of N columns, each 32bit. */ + section_offsets_headerline_offset = indexes_tab_offset + + (num_slots *datalen32); + /* Now we can make the real table part index normally. + This offset is to U row of N columns, each 32bit. */ + section_offsets_tab_offset = section_offsets_headerline_offset + + (num_secs*datalen32); + if ( num_secs > sect->dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: " + "The size of the %s ",(char *)section_type); + dwarfstring_append_printf_u(&m, + " is just %u bytes,",sect->dss_size); + dwarfstring_append_printf_u(&m, + "while the number of sections/columns (S) is %u. " + "which is clearly wrong",num_secs ); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + if ( (datalen32*num_secs) > sect->dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_s(&m, + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: " + "The size of the %s ",(char *)section_type); + dwarfstring_append_printf_u(&m, + " is just %u bytes,",sect->dss_size); + dwarfstring_append_printf_u(&m, + "while the number of sections/columns bytes (S)" + " is at least %u. " + "which is clearly wrong",num_secs*4); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + section_sizes_tab_offset = section_offsets_tab_offset + + (num_CUs *num_secs* datalen32) ; + tables_end_offset = section_sizes_tab_offset + + (num_CUs * num_secs * datalen32); + if ( tables_end_offset > sect->dss_size) { + /* Something is badly wrong here. */ + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m,"ERROR: " + "DW_DLE_ERRONEOUS_XU_INDEX_SECTION as the end offset " + "0x%lx is greater than ",tables_end_offset); + dwarfstring_append_printf_u(&m,"the section size " + "0x%lx.",sect->dss_size); + _dwarf_error_string(dbg, error, + DW_DLE_ERRONEOUS_XU_INDEX_SECTION, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + indexptr = (Dwarf_Xu_Index_Header) + _dwarf_get_alloc(dbg,DW_DLA_XU_INDEX,1); + if (indexptr == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + /* Only "cu" or "tu" allowed, that is checked above. + But for safety we just copy the allowed bytes*/ + indexptr->gx_type[0] = section_type[0]; + indexptr->gx_type[1] = section_type[1]; + indexptr->gx_type[2] = 0; + indexptr->gx_dbg = dbg; + indexptr->gx_section_length = sect->dss_size; + indexptr->gx_section_data = sect->dss_data; + indexptr->gx_section_name = sect->dss_name; + indexptr->gx_version = local_version; + indexptr->gx_column_count_sections = num_secs; + indexptr->gx_units_in_index = num_CUs; + indexptr->gx_slots_in_hash = num_slots; + indexptr->gx_hash_table_offset = hash_tab_offset; + indexptr->gx_index_table_offset = indexes_tab_offset; + indexptr->gx_section_offsets_headerline_offset= + section_offsets_headerline_offset; + indexptr->gx_section_offsets_offset= section_offsets_tab_offset; + indexptr->gx_section_sizes_offset = section_sizes_tab_offset; + res = fill_in_offsets_headerline(dbg,indexptr, + section_offsets_headerline_offset, + num_secs,error); + if (res != DW_DLV_OK) { + dwarf_dealloc(dbg,indexptr,DW_DLA_XU_INDEX); + return res; + } + *xuptr = indexptr; + *version = indexptr->gx_version; + *number_of_columns = indexptr->gx_column_count_sections; + *number_of_CUs = indexptr->gx_units_in_index; + *number_of_slots = indexptr->gx_slots_in_hash; + *section_name = indexptr->gx_section_name; + return DW_DLV_OK; +} + +int dwarf_get_xu_index_section_type(Dwarf_Xu_Index_Header xuhdr, + /* the function returns a pointer to + the immutable string "tu" or "cu" via + this arg. Do not free. */ + const char **typename, + /* the function returns a pointer to + the immutable section name. Do not free. + .debug_cu_index or .debug_tu_index */ + const char **sectionname, + Dwarf_Error *error) +{ + (void)error; + *typename = &xuhdr->gx_type[0]; + *sectionname = xuhdr->gx_section_name; + return DW_DLV_OK; +} + +/* Index values 0 to S-1 are valid. */ +int dwarf_get_xu_hash_entry(Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned index, + /* returns the hash value. 64 bits. */ + Dwarf_Sig8 *hash_value, + + /* returns the index into rows of offset/size tables. */ + Dwarf_Unsigned *index_to_sections, + Dwarf_Error *error) +{ + Dwarf_Debug dbg = xuhdr->gx_dbg; + Dwarf_Small *hashtab = xuhdr->gx_section_data + + xuhdr->gx_hash_table_offset; + Dwarf_Small *indextab = xuhdr->gx_section_data + + xuhdr->gx_index_table_offset; + Dwarf_Small *indexentry = 0; + Dwarf_Small *hashentry = 0; + Dwarf_Unsigned indexval = 0; + Dwarf_Small *section_end = xuhdr->gx_section_data + + xuhdr->gx_section_length; + + if (!xuhdr->gx_slots_in_hash) { + _dwarf_error_string(dbg, error, DW_DLE_XU_HASH_ROW_ERROR, + "DW_DLE_XU_HASH_ROW_ERROR the number of slots is zero" + " which seems wrong."); + return DW_DLV_ERROR; + } + if (index >= xuhdr->gx_slots_in_hash) { + return DW_DLV_NO_ENTRY; + } + hashentry = hashtab + (index * HASHSIGNATURELEN); + memcpy(hash_value,hashentry,HASHSIGNATURELEN); + indexentry = indextab + (index * SIZEOFT32); + if (indexentry >= section_end || + (indexentry+SIZEOFT32) > section_end) { + dwarfstring m; + + dwarfstring_constructor(&m); + dwarfstring_append_printf_u(&m, + "DW_DLE_XU_HASH_ROW_ERROR the index passed in, " + " %u, results in entry not fitting" + " in the hash table (past end of section)",index); + _dwarf_error_string(dbg, error, DW_DLE_XU_HASH_ROW_ERROR, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); + return DW_DLV_ERROR; + } + READ_UNALIGNED_CK(dbg,indexval,Dwarf_Unsigned, indexentry, + SIZEOFT32, + error,section_end); + indexentry += SIZEOFT32; + if (indexval > xuhdr->gx_units_in_index) { + _dwarf_error(dbg, error, DW_DLE_XU_HASH_INDEX_ERROR); + return DW_DLV_ERROR; + } + *index_to_sections = indexval; + return DW_DLV_OK; +} + +static const char * dwp_secnames[] = { +"No name for zero", +"DW_SECT_INFO" /* 1 */ /*".debug_info.dwo"*/, +"DW_SECT_TYPES" /* 2 */ /*".debug_types.dwo"*/, +"DW_SECT_ABBREV" /* 3 */ /*".debug_abbrev.dwo"*/, +"DW_SECT_LINE" /* 4 */ /*".debug_line.dwo"*/, +"DW_SECT_LOC" /* 5 */ /*".debug_loc.dwo"*/, +"DW_SECT_STR_OFFSETS" /* 6 */ /*".debug_str_offsets.dwo"*/, +"DW_SECT_MACRO" /* 7 */ /*".debug_macro.dwo"*/, +"DW_SECT_RNGLISTS" /* 8 */ /*".debug_rnglists.dwo"*/, +"No name > 8", +}; + +/* Row 0 of the Table of Section Offsets, + columns 0 to N-1, are the section id's, + and names, such as DW_SECT_INFO (ie, 1) */ +int +dwarf_get_xu_section_names(Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned column_index, + Dwarf_Unsigned *number, + const char **name, + Dwarf_Error *error) +{ + Dwarf_Unsigned sec_num = 0; + Dwarf_Debug dbg = 0; + if (!xuhdr) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: " + "Dwarf_Xu_Index_Header is NULL"); + return DW_DLV_ERROR; + } + dbg = xuhdr->gx_dbg; +/* FIXME */ + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: Dwarf_Debug pointer " + "from Dwarf_Xu_Index_Header is not valid"); + return DW_DLV_ERROR; + } + if ( column_index >= xuhdr->gx_column_count_sections) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR as the " + "column index of %u ",column_index); + dwarfstring_append_printf_u(&s," is too high. " + "There are %u sections.", + xuhdr->gx_column_count_sections); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + sec_num = xuhdr->gx_section_id[column_index]; + if (sec_num < 1) { + return DW_DLV_NO_ENTRY; + } + *number = sec_num; + *name = dwp_secnames[sec_num]; + return DW_DLV_OK; +} + +/* Rows 0 to U-1 + col 0 to L-1 + are section offset and length values from + the Table of Section Offsets and Table of Section Sizes. + The formally the table of section offsets is a header + line of the section offsets we subtract 1 from + the incoming irow_index as our tables are + now zero origin. */ +int +dwarf_get_xu_section_offset(Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned irow_index, + Dwarf_Unsigned column_index, + Dwarf_Unsigned *sec_offset, + Dwarf_Unsigned *sec_size, + Dwarf_Error *error) +{ + /* We use zero origin in the arrays, Users see + one origin from the hash table. */ + Dwarf_Debug dbg = 0; + /* get to base of tables first. */ + Dwarf_Small *offsetrow = 0; + Dwarf_Small *sizerow = 0; + Dwarf_Small *offsetentry = 0; + Dwarf_Small *sizeentry = 0; + Dwarf_Unsigned offset = 0; + Dwarf_Unsigned size = 0; + Dwarf_Unsigned column_count = 0; + Dwarf_Small *section_end = 0; + Dwarf_Unsigned row_index = irow_index-1; + + if (!xuhdr) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: " + "Dwarf_Xu_Index_Header pointer is null"); + return DW_DLV_ERROR; + } +/* FIXME */ + dbg = xuhdr->gx_dbg; + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: Dwarf_Debug pointer " + "from Dwarf_Xu_Index_Header is not valid"); + return DW_DLV_ERROR; + } + sizerow = xuhdr->gx_section_sizes_offset + + xuhdr->gx_section_data; + offsetrow = xuhdr->gx_section_offsets_offset + + xuhdr->gx_section_data; + column_count = xuhdr->gx_column_count_sections; + section_end = xuhdr->gx_section_data + xuhdr->gx_section_length; + + if (!irow_index) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append(&s, + "ERROR: DW_DLE_ERRONEOUS_XU_INDEX_SECTION " + "The row index passed to dwarf_get_xu_section_offset() " + "is zero, which is not a valid row in " + " the offset-table or the size table as we think" + " of them as 1-origin."); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + if (row_index >= xuhdr->gx_units_in_index) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR as the " + "row index of %u ",row_index); + dwarfstring_append_printf_u(&s," is too high. " + "Valid units must be < %u ",xuhdr->gx_units_in_index); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + + if (column_index >= xuhdr->gx_column_count_sections) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR as the " + "column index of %u ",column_index); + dwarfstring_append_printf_u(&s," is too high. " + "Valid column indexes must be < %u ", + xuhdr->gx_column_count_sections); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + /* As noted above we have hidden the extra initial + row from the offsets table so it is just + 0 to U-1. */ + offsetrow = offsetrow + (row_index*column_count * SIZEOFT32); + offsetentry = offsetrow + (column_index * SIZEOFT32); + + sizerow = sizerow + (row_index*column_count * SIZEOFT32); + sizeentry = sizerow + (column_index * SIZEOFT32); + + { + READ_UNALIGNED_CK(dbg,offset,Dwarf_Unsigned, + offsetentry, + SIZEOFT32,error,section_end); + offsetentry += SIZEOFT32; + + READ_UNALIGNED_CK(dbg,size,Dwarf_Unsigned, + sizeentry, + SIZEOFT32,error,section_end); + sizeentry += SIZEOFT32; + } + *sec_offset = offset; + *sec_size = size; + return DW_DLV_OK; +} + +static int +_dwarf_search_fission_for_key(Dwarf_Debug dbg, + Dwarf_Xu_Index_Header xuhdr, + Dwarf_Sig8 *key_in, + Dwarf_Unsigned * percu_index_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned key = 0; + Dwarf_Unsigned slots = xuhdr->gx_slots_in_hash; + Dwarf_Sig8 hashentry_key; + Dwarf_Unsigned percu_index = 0; + Dwarf_Unsigned h = 0; + + (void)dbg; + hashentry_key = zerohashkey; + /* Look for corrupt section data. */ + if (slots > xuhdr->gx_section_length) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR as the " + "slots count of %u ",slots); + dwarfstring_append_printf_u(&s," is too high. " + "given the section length of %u\n", + xuhdr->gx_section_length); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + if (!slots) { + return DW_DLV_NO_ENTRY; + } + if ( (4*slots) > xuhdr->gx_section_length) { + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "ERROR: DW_DLE_XU_NAME_COL_ERROR as the " + "slots count *4 of %u ",slots*4); + dwarfstring_append_printf_u(&s," is too high. " + "given the section length of %u\n", + xuhdr->gx_section_length); + _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + if (sizeof(key) != sizeof(*key_in)) { + /* The hash won't work right in this case */ + dwarfstring s; + + dwarfstring_constructor(&s); + dwarfstring_append_printf_u(&s, + "DW_DLE_XU_HASH_ROW_ERROR " + "We require 8 byte keys, not %u byte keys", + sizeof(key)); + _dwarf_error_string(dbg, error, DW_DLE_XU_HASH_ROW_ERROR, + dwarfstring_string(&s)); + dwarfstring_destructor(&s); + return DW_DLV_ERROR; + } + ASNARL(key,key_in,sizeof(*key_in)); + /* If we built a lookup based on hash key + this loop would not be necessary. */ + for (h = 0; h < slots; ++h) { + int res = 0; + + res = dwarf_get_xu_hash_entry(xuhdr, + h,&hashentry_key, + &percu_index,error); + if (res != DW_DLV_OK) { + return res; + } + if (percu_index == 0 && + !memcmp(&hashentry_key,&zerohashkey,sizeof(Dwarf_Sig8))) { + continue; + } + if (!memcmp(key_in,&hashentry_key,sizeof(Dwarf_Sig8))) { + /* FOUND */ + *percu_index_out = percu_index; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +/* Slow. Consider tsearch. */ +/* For type units and for CUs. */ +/* We're finding an index entry refers + to a global offset in some CU + and hence is unique in the target. */ +static int +_dwarf_search_fission_for_offset(Dwarf_Debug dbg, + Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned offset, + Dwarf_Unsigned dfp_sect_num, /* DW_SECT_INFO or TYPES */ + Dwarf_Unsigned * percu_index_out, + Dwarf_Sig8 * key_out, + Dwarf_Error *error) +{ + Dwarf_Unsigned i = 0; + Dwarf_Unsigned m = 0; + int secnum_index = -1; /* N index */ + int res = 0; + + for ( i = 0; i< xuhdr->gx_column_count_sections; i++) { + /* We could put the secnums array into xuhdr + if looping here is too slow. */ + const char *name = 0; + Dwarf_Unsigned num = 0; + res = dwarf_get_xu_section_names(xuhdr,i,&num,&name,error); + if (res != DW_DLV_OK) { + return res; + } + if (num == dfp_sect_num) { + secnum_index = i; + break; + } + } + if (secnum_index == -1) { + _dwarf_error(dbg,error,DW_DLE_FISSION_SECNUM_ERR); + return DW_DLV_ERROR; + } + for ( m = 0; m < xuhdr->gx_slots_in_hash; ++m) { + Dwarf_Sig8 hash; + Dwarf_Unsigned indexn = 0; + Dwarf_Unsigned sec_offset = 0; + Dwarf_Unsigned sec_size = 0; + + res = dwarf_get_xu_hash_entry(xuhdr,m,&hash,&indexn,error); + if (res != DW_DLV_OK) { + return res; + } + if (indexn == 0 && + !memcmp(&hash,&zerohashkey,sizeof(Dwarf_Sig8))) { + /* Empty slot. */ + continue; + } + + res = dwarf_get_xu_section_offset(xuhdr, + indexn,secnum_index,&sec_offset,&sec_size,error); + if (res != DW_DLV_OK) { + return res; + } + if (sec_offset != offset) { + continue; + } + *percu_index_out = indexn; + *key_out = hash; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + +static int +_dwarf_get_xuhdr(Dwarf_Debug dbg, + const char *sigtype, + Dwarf_Xu_Index_Header *xuout, + Dwarf_Error *error) +{ + if (!strcmp(sigtype,"tu")) { + if (!dbg->de_tu_hashindex_data) { + return DW_DLV_NO_ENTRY; + } + *xuout = dbg->de_tu_hashindex_data; + } else if (!strcmp(sigtype,"cu")) { + if (!dbg->de_cu_hashindex_data) { + return DW_DLV_NO_ENTRY; + } + *xuout = dbg->de_cu_hashindex_data; + } else { + _dwarf_error(dbg,error,DW_DLE_SIG_TYPE_WRONG_STRING); + return DW_DLV_ERROR; + } + return DW_DLV_OK; + +} + +static int +transform_xu_to_dfp(Dwarf_Xu_Index_Header xuhdr, + Dwarf_Unsigned percu_index, + Dwarf_Sig8 *key, + const char *sig_type, + Dwarf_Debug_Fission_Per_CU * percu_out, + Dwarf_Error *error) +{ + unsigned i = 0; + unsigned l = 0; + unsigned n = 1; + unsigned max_cols = xuhdr->gx_column_count_sections; /* L */ + unsigned secnums[DW_FISSION_SECT_COUNT]; + int res; + for ( i = 0; i< max_cols; i++) { + /* We could put the secnums array into xuhdr + if recreating it is too slow. */ + const char *name = 0; + Dwarf_Unsigned num = 0; + res = dwarf_get_xu_section_names(xuhdr,i,&num,&name,error); + if (res != DW_DLV_OK) { + return res; + } + secnums[i] = num; + } + n = percu_index; + for (l = 0; l < max_cols; ++l) { /* L */ + Dwarf_Unsigned sec_off = 0; + Dwarf_Unsigned sec_size = 0; + unsigned l_as_sect = secnums[l]; + res = dwarf_get_xu_section_offset(xuhdr,n,l, + &sec_off,&sec_size,error); + if (res != DW_DLV_OK) { + return res; + } + percu_out->pcu_offset[l_as_sect] = sec_off; + percu_out->pcu_size[l_as_sect] = sec_size; + } + percu_out->pcu_type = sig_type; + percu_out->pcu_index = percu_index; + percu_out->pcu_hash = *key; + return DW_DLV_OK; +} + +/* This should only be called for a CU, never a TU. + For a TU the type hash is known while reading + the TU Header. Not so for a CU. */ +int +_dwarf_get_debugfission_for_offset(Dwarf_Debug dbg, + Dwarf_Off offset_wanted, + const char * key_type, /* "cu" or "tu" */ + struct Dwarf_Debug_Fission_Per_CU_s * percu_out, + Dwarf_Error *error) +{ + Dwarf_Xu_Index_Header xuhdr = 0; + int sres = 0; + Dwarf_Unsigned percu_index = 0; + Dwarf_Unsigned sect_index_base = 0; + Dwarf_Sig8 key; + + sect_index_base = DW_SECT_INFO; + key = zerohashkey; + sres = _dwarf_get_xuhdr(dbg,key_type, &xuhdr,error); + if (sres != DW_DLV_OK) { + return sres; + } + sres = _dwarf_search_fission_for_offset(dbg, + xuhdr,offset_wanted, sect_index_base, &percu_index, + &key, + error); + if (sres != DW_DLV_OK) { + return sres; + } + sres = transform_xu_to_dfp(xuhdr,percu_index,&key, + key_type,percu_out, error); + return sres; + +} +int +dwarf_get_debugfission_for_key(Dwarf_Debug dbg, + Dwarf_Sig8 *key /* pointer to hash signature */, + const char *key_type /* "cu" or "tu" */, + Dwarf_Debug_Fission_Per_CU * percu_out, + Dwarf_Error *error) +{ + int sres = 0; + Dwarf_Unsigned percu_index = 0; + Dwarf_Xu_Index_Header xuhdr = 0; + + if (!dbg || dbg->de_magic != DBG_IS_VALID) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: Dwarf_Debug pointer " + "is not valid"); + return DW_DLV_ERROR; +/*FIXME */ + } + if (!key || !key_type || !percu_out) { + _dwarf_error_string(0,error,DW_DLE_XU_TYPE_ARG_ERROR, + "DW_DLE_XU_TYPE_ARG_ERROR: dw_key, dw_keytype, or " + "Dwarf_Debug_Fission_Per_CU pointer* to return " + "is not valid"); + return DW_DLV_ERROR; + } + + sres = _dwarf_load_debug_info(dbg,error); + if (sres == DW_DLV_ERROR) { + return sres; + } + sres = _dwarf_load_debug_types(dbg,error); + if (sres == DW_DLV_ERROR) { + return sres; + } + /* Returns already existing xuhdr */ + sres = _dwarf_get_xuhdr(dbg,key_type, &xuhdr,error); + if (sres != DW_DLV_OK) { + return sres; + } + /* Search in that xu data. */ + sres = _dwarf_search_fission_for_key(dbg, + xuhdr,key,&percu_index,error); + if (sres != DW_DLV_OK) { + return sres; + } + sres = transform_xu_to_dfp(xuhdr,percu_index,key, + key_type,percu_out,error); + return sres; +} + +void +dwarf_dealloc_xu_header(Dwarf_Xu_Index_Header indexptr) +{ + if (indexptr) { + Dwarf_Debug dbg = indexptr->gx_dbg; + dwarf_dealloc(dbg,indexptr,DW_DLA_XU_INDEX); + } +} diff --git a/src/lib/libdwarf/dwarf_xu_index.h b/src/lib/libdwarf/dwarf_xu_index.h new file mode 100644 index 0000000..5ed9db5 --- /dev/null +++ b/src/lib/libdwarf/dwarf_xu_index.h @@ -0,0 +1,63 @@ +#ifndef DWARF_XU_INDEX_H +#define DWARF_XU_INDEX_H +/* + + Copyright (C) 2014-2023 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +/* The following is based on + The gdb online documentation at + https://gcc.gnu.org/wiki/DebugFissionDWP + and the draft DWARF5 standard. +*/ + +struct Dwarf_Xu_Index_Header_s { + Dwarf_Debug gx_dbg; + Dwarf_Small * gx_section_data; + Dwarf_Unsigned gx_section_length; + + Dwarf_Unsigned gx_version; + Dwarf_Unsigned gx_column_count_sections; /* N */ + Dwarf_Unsigned gx_units_in_index; /* U */ + Dwarf_Unsigned gx_slots_in_hash; /* S */ + Dwarf_Unsigned gx_hash_table_offset; + Dwarf_Unsigned gx_index_table_offset; + Dwarf_Unsigned gx_section_offsets_headerline_offset; + Dwarf_Unsigned gx_section_offsets_offset; + Dwarf_Unsigned gx_section_sizes_offset; + /* Taken from gx_section_offsets_headerline, these + are the section ids. DW_SECT_* (0 - N-1) */ + unsigned long gx_section_id[9]; + + /* "tu" or "cu" without the quotes, of course. NUL terminated. */ + char gx_type[4]; + + /* Do not free gx_section_name. */ + const char * gx_section_name; +}; + +#endif /* DWARF_XU_INDEX_H */ diff --git a/src/lib/libdwarf/libdwarf.h b/src/lib/libdwarf/libdwarf.h new file mode 100644 index 0000000..9a0783e --- /dev/null +++ b/src/lib/libdwarf/libdwarf.h @@ -0,0 +1,8991 @@ +/* + Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2023 David Anderson. All rights reserved. + Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved. + Portions Copyright 2010-2012 SN Systems Ltd. All rights reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ +/*! @file*/ +/*! @page libdwarf.h + @tableofcontents + libdwarf.h contains all the type declarations + and function function declarations + needed to use the library. It is essential + that coders include dwarf.h before + including libdwarf.h. + + All identifiers here in the public namespace begin with + DW_ or Dwarf_ or dwarf_ . + All function argument names declared here begin with dw_ . +*/ + +#ifndef _LIBDWARF_H +#define _LIBDWARF_H + +#ifdef DW_API +#undef DW_API +#endif /* DW_API */ + +#ifndef LIBDWARF_STATIC +# if defined(_WIN32) || defined(__CYGWIN__) +# ifdef LIBDWARF_BUILD +# define DW_API __declspec(dllexport) +# else /* !LIBDWARF_BUILD */ +# define DW_API __declspec(dllimport) +# endif /* LIBDWARF_BUILD */ +# elif (defined(__SUNPRO_C) || defined(__SUNPRO_CC)) +# if defined(PIC) || defined(__PIC__) +# define DW_API __global +# endif /* __PIC__ */ +# elif (defined(__GNUC__) && __GNUC__ >= 4) || \ + defined(__INTEL_COMPILER) +# if defined(PIC) || defined(__PIC__) +# define DW_API __attribute__ ((visibility("default"))) +# endif /* PIC */ +# endif /* WIN32 SUNPRO GNUC */ +#endif /* !LIBDWARF_STATIC */ + +#ifndef DW_API +#define DW_API +#endif /* DW_API */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + libdwarf.h + $Revision: #9 $ $Date: 2008/01/17 $ + + For libdwarf consumers (reading DWARF2 and later) + + The interface is defined as having 8-byte signed and unsigned + values so it can handle 64-or-32bit target on 64-or-32bit host. + Dwarf_Ptr is the native size: it represents pointers on + the host machine (not the target!). + + This contains declarations for types and all producer + and consumer functions. + + Function declarations are written on a single line each here + so one can use grep to each declaration in its entirety. + The declarations are a little harder to read this way, but... +*/ +/*! @section defines Defines and Types +*/ + +/* Semantic Version identity for this libdwarf.h */ +#define DW_LIBDWARF_VERSION "0.9.0" +#define DW_LIBDWARF_VERSION_MAJOR 0 +#define DW_LIBDWARF_VERSION_MINOR 9 +#define DW_LIBDWARF_VERSION_MICRO 0 + +#define DW_PATHSOURCE_unspecified 0 +#define DW_PATHSOURCE_basic 1 +#define DW_PATHSOURCE_dsym 2 /* MacOS dSYM */ +#define DW_PATHSOURCE_debuglink 3 /* GNU debuglink */ + +#ifndef DW_FTYPE_UNKNOWN +#define DW_FTYPE_UNKNOWN 0 +#define DW_FTYPE_ELF 1 /* Unix/Linux/etc */ +#define DW_FTYPE_MACH_O 2 /* MacOS. */ +#define DW_FTYPE_PE 3 /* Windows */ +#define DW_FTYPE_ARCHIVE 4 /* unix archive */ +#define DW_FTYPE_APPLEUNIVERSAL 5 +#endif /* DW_FTYPE_UNKNOWN */ +/* standard return values for functions */ +#define DW_DLV_NO_ENTRY -1 +#define DW_DLV_OK 0 +#define DW_DLV_ERROR 1 +/* These support opening DWARF5 split dwarf objects and + Elf SHT_GROUP blocks of DWARF sections. */ +#define DW_GROUPNUMBER_ANY 0 +#define DW_GROUPNUMBER_BASE 1 +#define DW_GROUPNUMBER_DWO 2 + +/* Special values for offset_into_exception_table field + of dwarf fde's. */ +/* The following value indicates that there is no + Exception table offset + associated with a dwarf frame. */ +#define DW_DLX_NO_EH_OFFSET (-1LL) +/* The following value indicates that the producer + was unable to analyse the + source file to generate Exception tables for this function. */ +#define DW_DLX_EH_OFFSET_UNAVAILABLE (-2LL) + +/* The augmenter string for CIE */ +#define DW_CIE_AUGMENTER_STRING_V0 "z" + +/* FRAME special values */ +/* The following 3 are assigned numbers, but + are only present at run time. + Must not conflict with DW_FRAME values in dwarf.h */ +/* Taken as meaning 'undefined value', this is not + a column or register number. */ +#ifndef DW_FRAME_UNDEFINED_VAL +#define DW_FRAME_UNDEFINED_VAL 12288 +#endif +/* Taken as meaning 'same value' as caller had, + not a column or register number */ +#ifndef DW_FRAME_SAME_VAL +#define DW_FRAME_SAME_VAL 12289 +#endif +/* DW_FRAME_CFA_COL is assigned a virtual table position + but is accessed via CFA specific calls. */ +#ifndef DW_FRAME_CFA_COL +#define DW_FRAME_CFA_COL 12290 +#endif +#define DW_FRAME_CFA_COL3 DW_FRAME_CFA_COL /*compatibility name*/ +/* END FRAME special values */ + +/* dwarf_pcline function, slide arguments +*/ +#define DW_DLS_BACKWARD -1 /* slide backward to find line */ +#define DW_DLS_NOSLIDE 0 /* match exactly without sliding */ +#define DW_DLS_FORWARD 1 /* slide forward to find line */ + +/* Defined larger than necessary. + struct Dwarf_Debug_Fission_Per_CU_s, + being visible, will be difficult to change: + binary compatibility. The count is for arrays + inside the struct, the struct itself is + a single struct. */ +#define DW_FISSION_SECT_COUNT 12 + +/*! @defgroup basicdatatypes Basic Library Datatypes Group + @{ + @typedef Dwarf_Unsigned + The basic unsigned data type. + Intended to be an unsigned 64bit value. + @typedef Dwarf_Signed + The basic signed data type. + Intended to be a signed 64bit value. + @typedef Dwarf_Off + Used for offsets. It should be same size as Dwarf_Unsigned. + @typedef Dwarf_Addr + Used when a data item is a an address represented + in DWARF. 64 bits. Must be as large as the largest + object address size. + @typedef Dwarf_Half + Many libdwarf values (attribute codes, for example) + are defined by the standard to be 16 bits, and + this datatype reflects that (the type must be + at least 16 bits wide). + @typedef Dwarf_Bool + A TRUE(non-zero)/FALSE(zero) data item. + @typedef Dwarf_Ptr + A generic pointer type. It uses void * + so it cannot be added-to or subtracted-from. + @typedef Dwarf_Small + Used for small unsigned integers and + used as Dwarf_Small* for pointers and + it supports pointer addition and subtraction + conveniently. +*/ +typedef unsigned long long Dwarf_Unsigned; +typedef signed long long Dwarf_Signed; +typedef unsigned long long Dwarf_Off; +typedef unsigned long long Dwarf_Addr; + /* Dwarf_Bool as int is wasteful, but for compatibility + it must stay as int, not unsigned char. */ +typedef int Dwarf_Bool; /* boolean type */ +typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */ +typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */ +/* If sizeof(Dwarf_Half) is greater than 2 + we believe libdwarf still works properly. */ + +typedef void* Dwarf_Ptr; /* host machine pointer */ +/*! @} endgroup basicdatatypes */ + +/*! @defgroup enums Enumerators with various purposes + @{ + @enum Dwarf_Ranges_Entry_Type + The dwr_addr1/addr2 data is either an offset (DW_RANGES_ENTRY) + or an address (dwr_addr2 in DW_RANGES_ADDRESS_SELECTION) or + both are zero (DW_RANGES_END). + For DWARF5 each table starts with a header + followed by range list entries defined + as here. + Dwarf_Ranges* apply to DWARF2,3, and 4. + Not to DWARF5 (the data is different and + in a new DWARF5 section). +*/ +enum Dwarf_Ranges_Entry_Type { DW_RANGES_ENTRY, + DW_RANGES_ADDRESS_SELECTION, + DW_RANGES_END +}; + +/*! @enum Dwarf_Form_Class + The dwarf specification separates FORMs into + different classes. To do the separation properly + requires 4 pieces of data as of DWARF4 (thus the + function arguments listed here). + The DWARF4 specification class definition suffices to + describe all DWARF versions. + See section 7.5.4, Attribute Encodings. + A return of DW_FORM_CLASS_UNKNOWN means we + could not properly figure + out what form-class it is. + + DW_FORM_CLASS_FRAMEPTR is MIPS/IRIX only, and refers + to the DW_AT_MIPS_fde attribute (a reference to the + .debug_frame section). + + DWARF5: + DW_FORM_CLASS_LOCLISTSPTR is like DW_FORM_CLASS_LOCLIST + except that LOCLISTSPTR is aways a section offset, + never an index, and LOCLISTSPTR is only referenced + by DW_AT_loclists_base. + Note DW_FORM_CLASS_LOCLISTSPTR spelling to distinguish + from DW_FORM_CLASS_LOCLISTPTR. + + DWARF5: + DW_FORM_CLASS_RNGLISTSPTR is like DW_FORM_CLASS_RNGLIST + except that RNGLISTSPTR is aways a section offset, + never an index. DW_FORM_CLASS_RNGLISTSPTR is only + referenced by DW_AT_rnglists_base. +*/ +enum Dwarf_Form_Class { + DW_FORM_CLASS_UNKNOWN = 0, + DW_FORM_CLASS_ADDRESS = 1, + DW_FORM_CLASS_BLOCK = 2, + DW_FORM_CLASS_CONSTANT =3, + DW_FORM_CLASS_EXPRLOC = 4, + DW_FORM_CLASS_FLAG = 5, + DW_FORM_CLASS_LINEPTR = 6, + DW_FORM_CLASS_LOCLISTPTR=7, /* DWARF2,3,4 only */ + DW_FORM_CLASS_MACPTR = 8, /* DWARF2,3,4 only */ + DW_FORM_CLASS_RANGELISTPTR=9, /* DWARF2,3,4 only */ + DW_FORM_CLASS_REFERENCE=10, + DW_FORM_CLASS_STRING = 11, + DW_FORM_CLASS_FRAMEPTR= 12, /* MIPS/IRIX DWARF2 only */ + DW_FORM_CLASS_MACROPTR= 13, /* DWARF5 */ + DW_FORM_CLASS_ADDRPTR = 14, /* DWARF5 */ + DW_FORM_CLASS_LOCLIST = 15, /* DWARF5 */ + DW_FORM_CLASS_LOCLISTSPTR=16, /* DWARF5 */ + DW_FORM_CLASS_RNGLIST =17, /* DWARF5 */ + DW_FORM_CLASS_RNGLISTSPTR=18, /* DWARF5 */ + DW_FORM_CLASS_STROFFSETSPTR=19 /* DWARF5 */ +}; +/*! @} endgroupenums*/ + +/*! @defgroup allstructs Defined and Opaque Structs + @{ + + @typedef Dwarf_Form_Data16 + a container for a DW_FORM_data16 data item. + We have no integer types suitable so this special + struct is used instead. It is up to consumers/producers + to deal with the contents. +*/ +typedef struct Dwarf_Form_Data16_s { + unsigned char fd_data[16]; +} Dwarf_Form_Data16; + +/*! @typedef Dwarf_Sig8 + Used for signatures where ever they appear. + It is not a string, it + is 8 bytes of a signature one would use to find + a type unit. + @see dwarf_formsig8 +*/ +typedef struct Dwarf_Sig8_s { + char signature[8]; +} Dwarf_Sig8; + +/*! @typedef Dwarf_Block + + Used to hold uninterpreted blocks of data. + bl_data refers to on an uninterpreted block of data + Used with certain location information functions, + a frame expression function, expanded + frame instructions, and + DW_FORM_block functions. + + @see dwarf_formblock + @see explainformblock + +*/ +typedef struct Dwarf_Block_s { + Dwarf_Unsigned bl_len; + Dwarf_Ptr bl_data; + Dwarf_Small bl_from_loclist; + Dwarf_Unsigned bl_section_offset; +} Dwarf_Block; + +/*! @typedef Dwarf_Locdesc_c + Provides access to Dwarf_Locdesc_c, a single + location description +*/ +typedef struct Dwarf_Locdesc_c_s * Dwarf_Locdesc_c; + +/*! @typedef Dwarf_Loc_Head_c + provides access to any sort of location description + for DWARF2,3,4, or 5. +*/ +typedef struct Dwarf_Loc_Head_c_s * Dwarf_Loc_Head_c; + +/* This provides access to data from sections + .debug_gnu_pubtypes or .debug_gnu_pubnames. + These are not standard DWARF, and can appear + with gcc -gdwarf-5 + */ +typedef struct Dwarf_Gnu_Index_Head_s * Dwarf_Gnu_Index_Head; + +/*! @typedef Dwarf_Dsc_Head + Access to DW_AT_discr_list + array of discriminant values. +*/ +typedef struct Dwarf_Dsc_Head_s * Dwarf_Dsc_Head; + +/*! @typedef Dwarf_Frame_Instr_Head + The basis for access to DWARF frame instructions + (FDE or CIE) + in full detail. +*/ +typedef struct Dwarf_Frame_Instr_Head_s * Dwarf_Frame_Instr_Head; + +/*! @typedef dwarf_printf_callback_function_type + + Used as a function pointer to a user-written + callback function. +*/ +typedef void (* dwarf_printf_callback_function_type) + (void * /*user_pointer*/, const char * /*linecontent*/); + +struct Dwarf_Printf_Callback_Info_s { + void * dp_user_pointer; + dwarf_printf_callback_function_type dp_fptr; + char * dp_buffer; + unsigned int dp_buffer_len; + int dp_buffer_user_provided; + void * dp_reserved; +}; + +/*! @typedef Dwarf_Cmdline_Options. + + check_verbose_mode defaults to FALSE. + If a libdwarf-calling program sets + this TRUE it means some errors in Line Table + headers get a much more detailed description + of the error which is reported the caller via + printf_callback() function (the caller + can do something with the message). + Or the libdwarf calling code can call + dwarf_record_cmdline_options() to set + the new value. +*/ +typedef struct Dwarf_Cmdline_Options_s { + Dwarf_Bool check_verbose_mode; +} Dwarf_Cmdline_Options; + +/*! @typedef Dwarf_Str_Offsets_Table + Provides an access to the .debug_str_offsets + section independently of other DWARF sections. + Mainly of use in examining the .debug_str_offsets + section content for problems. +*/ +typedef struct Dwarf_Str_Offsets_Table_s * Dwarf_Str_Offsets_Table; + +/*! @typedef Dwarf_Ranges + Details of of non-contiguous address ranges + of DIEs for DWARF2, DWARF3, and DWARF4. + Sufficient for older dwarf. +*/ +typedef struct Dwarf_Ranges_s { + Dwarf_Addr dwr_addr1; + Dwarf_Addr dwr_addr2; + enum Dwarf_Ranges_Entry_Type dwr_type; +} Dwarf_Ranges; + +/*! @typedef Dwarf_Regtable_Entry3 + For each index i (naming a hardware register with dwarf number + i) the following is true and defines the value of that register: + + If dw_regnum is Register DW_FRAME_UNDEFINED_VAL + it is not DWARF register number but + a place holder indicating the register + has no defined value. + If dw_regnum is Register DW_FRAME_SAME_VAL + it is not DWARF register number but + a place holder indicating the register has the same + value in the previous frame. + + DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL and + DW_FRAME_CFA_COL are only present at libdwarf runtime. + Never on disk. + DW_FRAME_* Values present on disk are in dwarf.h + Because DW_FRAME_SAME_VAL and DW_FRAME_UNDEFINED_VAL + and DW_FRAME_CFA_COL are definable at runtime + consider the names symbolic in this comment, + not absolute. + + Otherwise: the register number is a DWARF register number + (see ABI documents for how this translates to hardware/ + software register numbers in the machine hardware) + and the following applies: + + In a cfa-defining entry (rt3_cfa_rule) the regnum is the + CFA 'register number'. Which is some 'normal' register, + not DW_FRAME_CFA_COL, nor DW_FRAME_SAME_VAL, nor + DW_FRAME_UNDEFINED_VAL. + + If dw_value_type == DW_EXPR_OFFSET (the only + possible case for dwarf2): + If dw_offset_relevant is non-zero, then + the value is stored at at the address + CFA+N where N (dw_offset) is a signed offset, + (not unsigned) and must be cast to Dwarf_Signed + before use. + dw_regnum is the cfa register rule which means + one ignores dw_regnum and uses the CFA appropriately. + Rule: Offset(N) + If dw_offset_relevant is zero, then the + value of the register + is the value of (DWARF) register number dw_regnum. + Rule: register(R) + If dw_value_type == DW_EXPR_VAL_OFFSET + the value of this register is CFA +N where + N (dw_offset) is a signed offset (not unsigned) + and must be cast to Dwarf_Signed before use. + dw_regnum is the cfa register rule which means + one ignores dw_regnum and uses the CFA appropriately. + Rule: val_offset(N) + If dw_value_type == DW_EXPR_EXPRESSION + The value of the register is the value at the address + computed by evaluating the DWARF expression E. + Rule: expression(E) + The expression E byte stream is pointed to by + block.bl_data. + The expression length in bytes is given by + block.bl_len. + If dw_value_type == DW_EXPR_VAL_EXPRESSION + The value of the register is the value + computed by evaluating the DWARF expression E. + Rule: val_expression(E) + The expression E byte stream is pointed to + by block.bl_data. + The expression length in bytes is given by + block.bl_len. + Other values of dw_value_type are an error. + + Note that this definition can only deal correctly + with register numbers that fit in a 16 bit + unsigned value. Changing this would be an incompatible + change to several functions in the libdwarf API. +*/ + +typedef struct Dwarf_Regtable_Entry3_s { + Dwarf_Small dw_offset_relevant; + Dwarf_Small dw_value_type; + Dwarf_Half dw_regnum; + Dwarf_Unsigned dw_offset; /* Should be Dwarf_Signed */ + Dwarf_Unsigned dw_args_size; /* Always zero. */ + Dwarf_Block dw_block; +} Dwarf_Regtable_Entry3; + +/*! @typedef Dwarf_Regtable3 + This structs provides a way for applications + to select the number of frame registers + and to select names for them. + + rt3_rules and rt3_reg_table_size must be filled in before + calling libdwarf. Filled in with a pointer to an array + (pointer and array set up by the calling application) + of rt3_reg_table_size Dwarf_Regtable_Entry3_s structs. + libdwarf does not allocate or deallocate space for the + rules, you must do so. libdwarf will initialize the + contents rules array, you do not need to do so (though + if you choose to initialize the array somehow that is ok: + libdwarf will overwrite your initializations with its own). + + Note that this definition can only deal correctly + with register table size that fits in a 16 bit + unsigned value. */ +typedef struct Dwarf_Regtable3_s { + struct Dwarf_Regtable_Entry3_s rt3_cfa_rule; + Dwarf_Half rt3_reg_table_size; + struct Dwarf_Regtable_Entry3_s * rt3_rules; +} Dwarf_Regtable3; + +/* Opaque types for Consumer Library. */ +/*! @typedef Dwarf_Error + &error is used in most calls to return error details + when the call returns DW_DLV_ERROR. +*/ +typedef struct Dwarf_Error_s* Dwarf_Error; + +/*! @typedef Dwarf_Debug + An open Dwarf_Debug points to data that libdwarf + maintains to support libdwarf calls. +*/ +typedef struct Dwarf_Debug_s* Dwarf_Debug; + +/*! @typedef Dwarf_Die + Used to reference a DWARF Debugging Information Entry. +*/ +typedef struct Dwarf_Die_s* Dwarf_Die; + +/*! @typedef Dwarf_Debug_Addr_Table + Used to reference a table in section .debug_addr +*/ +typedef struct Dwarf_Debug_Addr_Table_s* Dwarf_Debug_Addr_Table; + +/*! @typedef Dwarf_Line + Used to reference a line reference from the .debug_line + section. +*/ +typedef struct Dwarf_Line_s* Dwarf_Line; + +/*! @typedef Dwarf_Global + Used to reference a reference to an entry in + the .debug_pubnames section. +*/ +typedef struct Dwarf_Global_s* Dwarf_Global; + +/*! @typedef Dwarf_Type + Used to reference a reference to an entry in + the .debug_pubtypes section (as well as + the SGI-only extension .debug_types). +*/ +typedef struct Dwarf_Type_s* Dwarf_Type; + +/* The next three are SGI extensions not used elsewhere. */ +typedef struct Dwarf_Func_s* Dwarf_Func; +typedef struct Dwarf_Var_s* Dwarf_Var; +typedef struct Dwarf_Weak_s* Dwarf_Weak; + +/*! @typedef Dwarf_Attribute + Used to reference a Dwarf_Die attribute +*/ +typedef struct Dwarf_Attribute_s* Dwarf_Attribute; + +/*! @typedef Dwarf_Abbrev + Used to reference a Dwarf_Abbrev, though + usually such are handled transparently + in the library +*/ +typedef struct Dwarf_Abbrev_s* Dwarf_Abbrev; + +/*! @typedef Dwarf_Fde + Used to reference .debug_frame or .eh_frame FDE. +*/ +typedef struct Dwarf_Fde_s* Dwarf_Fde; +/*! @typedef Dwarf_Cie + Used to reference .debug_frame or .eh_frame CIE. +*/ +typedef struct Dwarf_Cie_s* Dwarf_Cie; + +/*! @typedef Dwarf_Arange + Used to reference a code address range + in a section such as .debug_info. +*/ +typedef struct Dwarf_Arange_s* Dwarf_Arange; +/*! @typedef Dwarf_Gdbindex + Used to reference .gdb_index section data + which is a fast-access section by and for gdb. +*/ +typedef struct Dwarf_Gdbindex_s* Dwarf_Gdbindex; +/*! @typedef Dwarf_Xu_Index_Header + Used to reference .debug_cu_index or + .debug_tu_index sections in a split-dwarf + package file. +*/ +typedef struct Dwarf_Xu_Index_Header_s *Dwarf_Xu_Index_Header; +/*! @typedef Dwarf_Line_Context + Used as the general reference line data (.debug_line). +*/ +typedef struct Dwarf_Line_Context_s *Dwarf_Line_Context; + +/*! @typedef Dwarf_Macro_Context + Used as the general reference to DWARF5 .debug_macro data. +*/ +typedef struct Dwarf_Macro_Context_s *Dwarf_Macro_Context; + +/*! @typedef Dwarf_Dnames_Head + Used as the general reference to the DWARF5 .debug_names + section. +*/ +typedef struct Dwarf_Dnames_Head_s *Dwarf_Dnames_Head; + +/*! @typedef Dwarf_Handler + Used in rare cases (mainly tiny programs) + with dwarf_init_path() etc + initialization calls. +*/ +typedef void (*Dwarf_Handler)(Dwarf_Error dw_error, + Dwarf_Ptr dw_errarg); + +/*! @struct Dwarf_Macro_Details_s + + This applies to DWARF2, DWARF3, and DWARF4 + compilation units. + DWARF5 .debug_macro has its own function interface + which does not use this struct. +*/ +struct Dwarf_Macro_Details_s { + Dwarf_Off dmd_offset; /* offset, in the section, + of this macro info */ + Dwarf_Small dmd_type; /* the type, DW_MACINFO_define etc*/ + Dwarf_Signed dmd_lineno; /* the source line number where + applicable and vend_def number if + vendor_extension op */ + Dwarf_Signed dmd_fileindex;/* the source file index */ + char * dmd_macro; /* macro name string */ +}; +typedef struct Dwarf_Macro_Details_s Dwarf_Macro_Details; +typedef struct Dwarf_Debug_Fission_Per_CU_s + Dwarf_Debug_Fission_Per_CU; + +/* ===== BEGIN Obj_Access data ===== */ +/*! @typedef Dwarf_Obj_Access_Interface_a + Used for access to and settint up special data + allowing access to DWARF even with no object + files present +*/ +typedef struct Dwarf_Obj_Access_Interface_a_s + Dwarf_Obj_Access_Interface_a; + +/*! @typedef Dwarf_Obj_Access_Methods_a + Used for access to and settint up special data + allowing access to DWARF even with no object + files present +*/ +typedef struct Dwarf_Obj_Access_Methods_a_s + Dwarf_Obj_Access_Methods_a; + +/*! @typedef Dwarf_Obj_Access_Section_a + Used for access to and setting up special data + allowing access to DWARF even with no object + files present. + The fields match up with Elf section headers, + but for non-Elf many of the fields can be set + to zero. +*/ +typedef struct Dwarf_Obj_Access_Section_a_s + Dwarf_Obj_Access_Section_a; +struct Dwarf_Obj_Access_Section_a_s { + const char* as_name; + Dwarf_Unsigned as_type; + Dwarf_Unsigned as_flags; + Dwarf_Addr as_addr; + Dwarf_Unsigned as_offset; + Dwarf_Unsigned as_size; + Dwarf_Unsigned as_link; + Dwarf_Unsigned as_info; + Dwarf_Unsigned as_addralign; + Dwarf_Unsigned as_entrysize; +}; + +/*! @struct Dwarf_Obj_Access_Methods_a_s: + The functions we need to access object data + from libdwarf are declared here. + +*/ +struct Dwarf_Obj_Access_Methods_a_s { + int (*om_get_section_info)(void* obj, + Dwarf_Unsigned section_index, + Dwarf_Obj_Access_Section_a* return_section, + int * error); + Dwarf_Small (*om_get_byte_order)(void* obj); + Dwarf_Small (*om_get_length_size)(void* obj); + Dwarf_Small (*om_get_pointer_size)(void* obj); + Dwarf_Unsigned (*om_get_filesize)(void* obj); + Dwarf_Unsigned (*om_get_section_count)(void* obj); + int (*om_load_section)(void* obj, + Dwarf_Unsigned section_index, + Dwarf_Small** return_data, + int * error); + int (*om_relocate_a_section)(void* obj, + Dwarf_Unsigned section_index, + Dwarf_Debug dbg, + int * error); +}; +struct Dwarf_Obj_Access_Interface_a_s { + void* ai_object; + const Dwarf_Obj_Access_Methods_a *ai_methods; +}; +/* ===== END Obj_Access data ===== */ + +/* User code must allocate this struct, zero it, + and pass a pointer to it + into dwarf_get_debugfission_for_cu . */ +struct Dwarf_Debug_Fission_Per_CU_s { + /* Do not free the string. It contains "cu" or "tu". */ + /* If this is not set (ie, not a CU/TU in DWP Package File) + then pcu_type will be NULL. */ + const char * pcu_type; + /* pcu_index is the index (range 1 to N ) + into the tu/cu table of offsets and the table + of sizes. 1 to N as the zero index is reserved + for special purposes. Not a value one + actually needs. */ + Dwarf_Unsigned pcu_index; + Dwarf_Sig8 pcu_hash; /* 8 byte */ + /* [0] has offset and size 0. + [1]-[8] are DW_SECT_* indexes and the + values are the offset and size + of the respective section contribution + of a single .dwo object. When pcu_size[n] is + zero the corresponding section is not present. */ + Dwarf_Unsigned pcu_offset[DW_FISSION_SECT_COUNT]; + Dwarf_Unsigned pcu_size[DW_FISSION_SECT_COUNT]; + Dwarf_Unsigned unused1; + Dwarf_Unsigned unused2; +}; + +/*! @typedef Dwarf_Rnglists_Head + Used for access to a set of DWARF5 debug_rnglists + entries. +*/ +typedef struct Dwarf_Rnglists_Head_s * Dwarf_Rnglists_Head; + +/*! @} endgroup allstructs */ + +/*! @defgroup framedefines Default stack frame #defines + @{ +*/ +/* Special values for offset_into_exception_table field + of dwarf fde's. */ +/* The following value indicates that there is no + Exception table offset + associated with a dwarf frame. */ +#define DW_DLX_NO_EH_OFFSET (-1LL) +/* The following value indicates that the producer + was unable to analyse the + source file to generate Exception tables for this function. */ +#define DW_DLX_EH_OFFSET_UNAVAILABLE (-2LL) + +/* The augmenter string for CIE */ +#define DW_CIE_AUGMENTER_STRING_V0 "z" + +/* ***IMPORTANT NOTE, TARGET DEPENDENCY **** + DW_REG_TABLE_SIZE must be at least as large as + the number of registers + DW_FRAME_LAST_REG_NUM as defined in dwarf.h +*/ +#ifndef DW_REG_TABLE_SIZE +#define DW_REG_TABLE_SIZE DW_FRAME_LAST_REG_NUM +#endif + +/* For MIPS, DW_FRAME_SAME_VAL is the correct default value + for a frame register value. For other CPUS another value + may be better, such as DW_FRAME_UNDEFINED_VAL. + See dwarf_set_frame_rule_table_size +*/ +#ifndef DW_FRAME_REG_INITIAL_VALUE +#define DW_FRAME_REG_INITIAL_VALUE DW_FRAME_SAME_VAL +#endif + +/* The following are all needed to evaluate DWARF3 register rules. + These have nothing to do simply printing + frame instructions. +*/ +#define DW_EXPR_OFFSET 0 /* offset is from CFA reg */ +#define DW_EXPR_VAL_OFFSET 1 +#define DW_EXPR_EXPRESSION 2 +#define DW_EXPR_VAL_EXPRESSION 3 +/*! @} */ + +/*! @defgroup dwdla DW_DLA alloc/dealloc typename&number + @{ + + These identify the various allocate/dealloc + types. The allocation happens within libdwarf, + and the deallocation is usually done by + user code. +*/ +#define DW_DLA_STRING 0x01 /* char* */ +#define DW_DLA_LOC 0x02 /* Dwarf_Loc */ +#define DW_DLA_LOCDESC 0x03 /* Dwarf_Locdesc */ +#define DW_DLA_ELLIST 0x04 /* Dwarf_Ellist (not used)*/ +#define DW_DLA_BOUNDS 0x05 /* Dwarf_Bounds (not used) */ +#define DW_DLA_BLOCK 0x06 /* Dwarf_Block */ +#define DW_DLA_DEBUG 0x07 /* Dwarf_Debug */ +#define DW_DLA_DIE 0x08 /* Dwarf_Die */ +#define DW_DLA_LINE 0x09 /* Dwarf_Line */ +#define DW_DLA_ATTR 0x0a /* Dwarf_Attribute */ +#define DW_DLA_TYPE 0x0b /* Dwarf_Type (not used) */ +#define DW_DLA_SUBSCR 0x0c /* Dwarf_Subscr (not used) */ +#define DW_DLA_GLOBAL 0x0d /* Dwarf_Global */ +#define DW_DLA_ERROR 0x0e /* Dwarf_Error */ +#define DW_DLA_LIST 0x0f /* a list */ +#define DW_DLA_LINEBUF 0x10 /* Dwarf_Line* (not used) */ +#define DW_DLA_ARANGE 0x11 /* Dwarf_Arange */ +#define DW_DLA_ABBREV 0x12 /* Dwarf_Abbrev */ +#define DW_DLA_FRAME_INSTR_HEAD 0x13 /* Dwarf_Frame_Instr_Head */ +#define DW_DLA_CIE 0x14 /* Dwarf_Cie */ +#define DW_DLA_FDE 0x15 /* Dwarf_Fde */ +#define DW_DLA_LOC_BLOCK 0x16 /* Dwarf_Loc */ + +#define DW_DLA_FRAME_OP 0x17 /* Dwarf_Frame_Op (not used) */ +#define DW_DLA_FUNC 0x18 /* Dwarf_Func */ +#define DW_DLA_UARRAY 0x19 /* Array of Dwarf_Off:Jan2023 */ +#define DW_DLA_VAR 0x1a /* Dwarf_Var */ +#define DW_DLA_WEAK 0x1b /* Dwarf_Weak */ +#define DW_DLA_ADDR 0x1c /* Dwarf_Addr sized entries */ +#define DW_DLA_RANGES 0x1d /* Dwarf_Ranges */ +/* 0x1e (30) to 0x34 (52) reserved for internal to libdwarf types. */ +/* .debug_gnu_typenames/pubnames, 2020 */ +#define DW_DLA_GNU_INDEX_HEAD 0x35 + +#define DW_DLA_RNGLISTS_HEAD 0x36 /* .debug_rnglists DW5 */ +#define DW_DLA_GDBINDEX 0x37 /* Dwarf_Gdbindex */ +#define DW_DLA_XU_INDEX 0x38 /* Dwarf_Xu_Index_Header */ +#define DW_DLA_LOC_BLOCK_C 0x39 /* Dwarf_Loc_c*/ +#define DW_DLA_LOCDESC_C 0x3a /* Dwarf_Locdesc_c */ +#define DW_DLA_LOC_HEAD_C 0x3b /* Dwarf_Loc_Head_c */ +#define DW_DLA_MACRO_CONTEXT 0x3c /* Dwarf_Macro_Context */ +/* 0x3d (61) is for libdwarf internal use. */ +#define DW_DLA_DSC_HEAD 0x3e /* Dwarf_Dsc_Head */ +#define DW_DLA_DNAMES_HEAD 0x3f /* Dwarf_Dnames_Head */ + +/* struct Dwarf_Str_Offsets_Table_s */ +#define DW_DLA_STR_OFFSETS 0x40 +/* struct Dwarf_Debug_Addr_Table_s */ +#define DW_DLA_DEBUG_ADDR 0x41 +/*! @} */ + +/*! @defgroup dwdle DW_DLE Dwarf_Error numbers + @{ + + These identify the various error codes that have been + used. Not all of them are still use. + We do not recycle obsolete codes into new uses. + The codes 1 through 22 are historic and it is + unlikely they are used anywhere in the library. +*/ +/* libdwarf error numbers */ +#define DW_DLE_NE 0 /* no error */ +#define DW_DLE_VMM 1 /* dwarf format/library version mismatch */ +#define DW_DLE_MAP 2 /* memory map failure */ +#define DW_DLE_LEE 3 /* libelf error */ +#define DW_DLE_NDS 4 /* no debug section */ +#define DW_DLE_NLS 5 /* no line section */ +#define DW_DLE_ID 6 /* invalid descriptor for query */ +#define DW_DLE_IOF 7 /* I/O failure */ +#define DW_DLE_MAF 8 /* memory allocation failure */ +#define DW_DLE_IA 9 /* invalid argument */ +#define DW_DLE_MDE 10 /* mangled debugging entry */ +#define DW_DLE_MLE 11 /* mangled line number entry */ +#define DW_DLE_FNO 12 /* file not open */ +#define DW_DLE_FNR 13 /* file not a regular file */ +#define DW_DLE_FWA 14 /* file open with wrong access */ +#define DW_DLE_NOB 15 /* not an object file */ +#define DW_DLE_MOF 16 /* mangled object file header */ +#define DW_DLE_EOLL 17 /* end of location list entries */ +#define DW_DLE_NOLL 18 /* no location list section */ +#define DW_DLE_BADOFF 19 /* Invalid offset */ +#define DW_DLE_EOS 20 /* end of section */ +#define DW_DLE_ATRUNC 21 /* abbreviations section appears truncated*/ +#define DW_DLE_BADBITC 22 /* Address size passed to dwarf bad,*/ + /* It is not an allowed size (64 or 32) */ + /* Error codes defined by the current Libdwarf Implementation. */ +#define DW_DLE_DBG_ALLOC 23 +#define DW_DLE_FSTAT_ERROR 24 +#define DW_DLE_FSTAT_MODE_ERROR 25 +#define DW_DLE_INIT_ACCESS_WRONG 26 +#define DW_DLE_ELF_BEGIN_ERROR 27 +#define DW_DLE_ELF_GETEHDR_ERROR 28 +#define DW_DLE_ELF_GETSHDR_ERROR 29 +#define DW_DLE_ELF_STRPTR_ERROR 30 +#define DW_DLE_DEBUG_INFO_DUPLICATE 31 +#define DW_DLE_DEBUG_INFO_NULL 32 +#define DW_DLE_DEBUG_ABBREV_DUPLICATE 33 +#define DW_DLE_DEBUG_ABBREV_NULL 34 +#define DW_DLE_DEBUG_ARANGES_DUPLICATE 35 +#define DW_DLE_DEBUG_ARANGES_NULL 36 +#define DW_DLE_DEBUG_LINE_DUPLICATE 37 +#define DW_DLE_DEBUG_LINE_NULL 38 +#define DW_DLE_DEBUG_LOC_DUPLICATE 39 +#define DW_DLE_DEBUG_LOC_NULL 40 +#define DW_DLE_DEBUG_MACINFO_DUPLICATE 41 +#define DW_DLE_DEBUG_MACINFO_NULL 42 +#define DW_DLE_DEBUG_PUBNAMES_DUPLICATE 43 +#define DW_DLE_DEBUG_PUBNAMES_NULL 44 +#define DW_DLE_DEBUG_STR_DUPLICATE 45 +#define DW_DLE_DEBUG_STR_NULL 46 +#define DW_DLE_CU_LENGTH_ERROR 47 +#define DW_DLE_VERSION_STAMP_ERROR 48 +#define DW_DLE_ABBREV_OFFSET_ERROR 49 +#define DW_DLE_ADDRESS_SIZE_ERROR 50 +#define DW_DLE_DEBUG_INFO_PTR_NULL 51 +#define DW_DLE_DIE_NULL 52 +#define DW_DLE_STRING_OFFSET_BAD 53 +#define DW_DLE_DEBUG_LINE_LENGTH_BAD 54 +#define DW_DLE_LINE_PROLOG_LENGTH_BAD 55 +#define DW_DLE_LINE_NUM_OPERANDS_BAD 56 +#define DW_DLE_LINE_SET_ADDR_ERROR 57 +#define DW_DLE_LINE_EXT_OPCODE_BAD 58 +#define DW_DLE_DWARF_LINE_NULL 59 +#define DW_DLE_INCL_DIR_NUM_BAD 60 +#define DW_DLE_LINE_FILE_NUM_BAD 61 +#define DW_DLE_ALLOC_FAIL 62 +#define DW_DLE_NO_CALLBACK_FUNC 63 +#define DW_DLE_SECT_ALLOC 64 +#define DW_DLE_FILE_ENTRY_ALLOC 65 +#define DW_DLE_LINE_ALLOC 66 +#define DW_DLE_FPGM_ALLOC 67 +#define DW_DLE_INCDIR_ALLOC 68 +#define DW_DLE_STRING_ALLOC 69 +#define DW_DLE_CHUNK_ALLOC 70 +#define DW_DLE_BYTEOFF_ERR 71 +#define DW_DLE_CIE_ALLOC 72 +#define DW_DLE_FDE_ALLOC 73 +#define DW_DLE_REGNO_OVFL 74 +#define DW_DLE_CIE_OFFS_ALLOC 75 +#define DW_DLE_WRONG_ADDRESS 76 +#define DW_DLE_EXTRA_NEIGHBORS 77 +#define DW_DLE_WRONG_TAG 78 +#define DW_DLE_DIE_ALLOC 79 +#define DW_DLE_PARENT_EXISTS 80 +#define DW_DLE_DBG_NULL 81 +#define DW_DLE_DEBUGLINE_ERROR 82 +#define DW_DLE_DEBUGFRAME_ERROR 83 +#define DW_DLE_DEBUGINFO_ERROR 84 +#define DW_DLE_ATTR_ALLOC 85 +#define DW_DLE_ABBREV_ALLOC 86 +#define DW_DLE_OFFSET_UFLW 87 +#define DW_DLE_ELF_SECT_ERR 88 +#define DW_DLE_DEBUG_FRAME_LENGTH_BAD 89 +#define DW_DLE_FRAME_VERSION_BAD 90 +#define DW_DLE_CIE_RET_ADDR_REG_ERROR 91 +#define DW_DLE_FDE_NULL 92 +#define DW_DLE_FDE_DBG_NULL 93 +#define DW_DLE_CIE_NULL 94 +#define DW_DLE_CIE_DBG_NULL 95 +#define DW_DLE_FRAME_TABLE_COL_BAD 96 +#define DW_DLE_PC_NOT_IN_FDE_RANGE 97 +#define DW_DLE_CIE_INSTR_EXEC_ERROR 98 +#define DW_DLE_FRAME_INSTR_EXEC_ERROR 99 +#define DW_DLE_FDE_PTR_NULL 100 +#define DW_DLE_RET_OP_LIST_NULL 101 +#define DW_DLE_LINE_CONTEXT_NULL 102 +#define DW_DLE_DBG_NO_CU_CONTEXT 103 +#define DW_DLE_DIE_NO_CU_CONTEXT 104 +#define DW_DLE_FIRST_DIE_NOT_CU 105 +#define DW_DLE_NEXT_DIE_PTR_NULL 106 +#define DW_DLE_DEBUG_FRAME_DUPLICATE 107 +#define DW_DLE_DEBUG_FRAME_NULL 108 +#define DW_DLE_ABBREV_DECODE_ERROR 109 +#define DW_DLE_DWARF_ABBREV_NULL 110 +#define DW_DLE_ATTR_NULL 111 +#define DW_DLE_DIE_BAD 112 +#define DW_DLE_DIE_ABBREV_BAD 113 +#define DW_DLE_ATTR_FORM_BAD 114 +#define DW_DLE_ATTR_NO_CU_CONTEXT 115 +#define DW_DLE_ATTR_FORM_SIZE_BAD 116 +#define DW_DLE_ATTR_DBG_NULL 117 +#define DW_DLE_BAD_REF_FORM 118 +#define DW_DLE_ATTR_FORM_OFFSET_BAD 119 +#define DW_DLE_LINE_OFFSET_BAD 120 +#define DW_DLE_DEBUG_STR_OFFSET_BAD 121 +#define DW_DLE_STRING_PTR_NULL 122 +#define DW_DLE_PUBNAMES_VERSION_ERROR 123 +#define DW_DLE_PUBNAMES_LENGTH_BAD 124 +#define DW_DLE_GLOBAL_NULL 125 +#define DW_DLE_GLOBAL_CONTEXT_NULL 126 +#define DW_DLE_DIR_INDEX_BAD 127 +#define DW_DLE_LOC_EXPR_BAD 128 +#define DW_DLE_DIE_LOC_EXPR_BAD 129 +#define DW_DLE_ADDR_ALLOC 130 +#define DW_DLE_OFFSET_BAD 131 +#define DW_DLE_MAKE_CU_CONTEXT_FAIL 132 +#define DW_DLE_REL_ALLOC 133 +#define DW_DLE_ARANGE_OFFSET_BAD 134 +#define DW_DLE_SEGMENT_SIZE_BAD 135 +#define DW_DLE_ARANGE_LENGTH_BAD 136 +#define DW_DLE_ARANGE_DECODE_ERROR 137 +#define DW_DLE_ARANGES_NULL 138 +#define DW_DLE_ARANGE_NULL 139 +#define DW_DLE_NO_FILE_NAME 140 +#define DW_DLE_NO_COMP_DIR 141 +#define DW_DLE_CU_ADDRESS_SIZE_BAD 142 +#define DW_DLE_INPUT_ATTR_BAD 143 +#define DW_DLE_EXPR_NULL 144 +#define DW_DLE_BAD_EXPR_OPCODE 145 +#define DW_DLE_EXPR_LENGTH_BAD 146 +#define DW_DLE_MULTIPLE_RELOC_IN_EXPR 147 +#define DW_DLE_ELF_GETIDENT_ERROR 148 +#define DW_DLE_NO_AT_MIPS_FDE 149 +#define DW_DLE_NO_CIE_FOR_FDE 150 +#define DW_DLE_DIE_ABBREV_LIST_NULL 151 +#define DW_DLE_DEBUG_FUNCNAMES_DUPLICATE 152 +#define DW_DLE_DEBUG_FUNCNAMES_NULL 153 +#define DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR 154 +#define DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD 155 +#define DW_DLE_FUNC_NULL 156 +#define DW_DLE_FUNC_CONTEXT_NULL 157 +#define DW_DLE_DEBUG_TYPENAMES_DUPLICATE 158 +#define DW_DLE_DEBUG_TYPENAMES_NULL 159 +#define DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR 160 +#define DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD 161 +#define DW_DLE_TYPE_NULL 162 +#define DW_DLE_TYPE_CONTEXT_NULL 163 +#define DW_DLE_DEBUG_VARNAMES_DUPLICATE 164 +#define DW_DLE_DEBUG_VARNAMES_NULL 165 +#define DW_DLE_DEBUG_VARNAMES_VERSION_ERROR 166 +#define DW_DLE_DEBUG_VARNAMES_LENGTH_BAD 167 +#define DW_DLE_VAR_NULL 168 +#define DW_DLE_VAR_CONTEXT_NULL 169 +#define DW_DLE_DEBUG_WEAKNAMES_DUPLICATE 170 +#define DW_DLE_DEBUG_WEAKNAMES_NULL 171 +#define DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR 172 +#define DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD 173 +#define DW_DLE_WEAK_NULL 174 +#define DW_DLE_WEAK_CONTEXT_NULL 175 +#define DW_DLE_LOCDESC_COUNT_WRONG 176 +#define DW_DLE_MACINFO_STRING_NULL 177 +#define DW_DLE_MACINFO_STRING_EMPTY 178 +#define DW_DLE_MACINFO_INTERNAL_ERROR_SPACE 179 +#define DW_DLE_MACINFO_MALLOC_FAIL 180 +#define DW_DLE_DEBUGMACINFO_ERROR 181 +#define DW_DLE_DEBUG_MACRO_LENGTH_BAD 182 +#define DW_DLE_DEBUG_MACRO_MAX_BAD 183 +#define DW_DLE_DEBUG_MACRO_INTERNAL_ERR 184 +#define DW_DLE_DEBUG_MACRO_MALLOC_SPACE 185 +#define DW_DLE_DEBUG_MACRO_INCONSISTENT 186 +#define DW_DLE_DF_NO_CIE_AUGMENTATION 187 +#define DW_DLE_DF_REG_NUM_TOO_HIGH 188 +#define DW_DLE_DF_MAKE_INSTR_NO_INIT 189 +#define DW_DLE_DF_NEW_LOC_LESS_OLD_LOC 190 +#define DW_DLE_DF_POP_EMPTY_STACK 191 +#define DW_DLE_DF_ALLOC_FAIL 192 +#define DW_DLE_DF_FRAME_DECODING_ERROR 193 +#define DW_DLE_DEBUG_LOC_SECTION_SHORT 194 +#define DW_DLE_FRAME_AUGMENTATION_UNKNOWN 195 +#define DW_DLE_PUBTYPE_CONTEXT 196 /* Unused. */ +#define DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD 197 +#define DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR 198 +#define DW_DLE_DEBUG_PUBTYPES_DUPLICATE 199 +#define DW_DLE_FRAME_CIE_DECODE_ERROR 200 +#define DW_DLE_FRAME_REGISTER_UNREPRESENTABLE 201 +#define DW_DLE_FRAME_REGISTER_COUNT_MISMATCH 202 +#define DW_DLE_LINK_LOOP 203 +#define DW_DLE_STRP_OFFSET_BAD 204 +#define DW_DLE_DEBUG_RANGES_DUPLICATE 205 +#define DW_DLE_DEBUG_RANGES_OFFSET_BAD 206 +#define DW_DLE_DEBUG_RANGES_MISSING_END 207 +#define DW_DLE_DEBUG_RANGES_OUT_OF_MEM 208 +#define DW_DLE_DEBUG_SYMTAB_ERR 209 +#define DW_DLE_DEBUG_STRTAB_ERR 210 +#define DW_DLE_RELOC_MISMATCH_INDEX 211 +#define DW_DLE_RELOC_MISMATCH_RELOC_INDEX 212 +#define DW_DLE_RELOC_MISMATCH_STRTAB_INDEX 213 +#define DW_DLE_RELOC_SECTION_MISMATCH 214 +#define DW_DLE_RELOC_SECTION_MISSING_INDEX 215 +#define DW_DLE_RELOC_SECTION_LENGTH_ODD 216 +#define DW_DLE_RELOC_SECTION_PTR_NULL 217 +#define DW_DLE_RELOC_SECTION_MALLOC_FAIL 218 +#define DW_DLE_NO_ELF64_SUPPORT 219 +#define DW_DLE_MISSING_ELF64_SUPPORT 220 +#define DW_DLE_ORPHAN_FDE 221 +#define DW_DLE_DUPLICATE_INST_BLOCK 222 +#define DW_DLE_BAD_REF_SIG8_FORM 223 +#define DW_DLE_ATTR_EXPRLOC_FORM_BAD 224 +#define DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD 225 +#define DW_DLE_NOT_REF_FORM 226 +#define DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE 227 +#define DW_DLE_REF_SIG8_NOT_HANDLED 228 +#define DW_DLE_DEBUG_FRAME_POSSIBLE_ADDRESS_BOTCH 229 +#define DW_DLE_LOC_BAD_TERMINATION 230 +#define DW_DLE_SYMTAB_SECTION_LENGTH_ODD 231 +#define DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD 232 +#define DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN 233 +#define DW_DLE_SYMTAB_SECTION_ENTRYSIZE_ZERO 234 +#define DW_DLE_LINE_NUMBER_HEADER_ERROR 235 +#define DW_DLE_DEBUG_TYPES_NULL 236 +#define DW_DLE_DEBUG_TYPES_DUPLICATE 237 +#define DW_DLE_DEBUG_TYPES_ONLY_DWARF4 238 +#define DW_DLE_DEBUG_TYPEOFFSET_BAD 239 +#define DW_DLE_GNU_OPCODE_ERROR 240 +#define DW_DLE_DEBUGPUBTYPES_ERROR 241 +#define DW_DLE_AT_FIXUP_NULL 242 +#define DW_DLE_AT_FIXUP_DUP 243 +#define DW_DLE_BAD_ABINAME 244 +#define DW_DLE_TOO_MANY_DEBUG 245 +#define DW_DLE_DEBUG_STR_OFFSETS_DUPLICATE 246 +#define DW_DLE_SECTION_DUPLICATION 247 +#define DW_DLE_SECTION_ERROR 248 +#define DW_DLE_DEBUG_ADDR_DUPLICATE 249 +#define DW_DLE_DEBUG_CU_UNAVAILABLE_FOR_FORM 250 +#define DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE 251 +#define DW_DLE_NEXT_DIE_PAST_END 252 +#define DW_DLE_NEXT_DIE_WRONG_FORM 253 +#define DW_DLE_NEXT_DIE_NO_ABBREV_LIST 254 +#define DW_DLE_NESTED_FORM_INDIRECT_ERROR 255 +#define DW_DLE_CU_DIE_NO_ABBREV_LIST 256 +#define DW_DLE_MISSING_NEEDED_DEBUG_ADDR_SECTION 257 +#define DW_DLE_ATTR_FORM_NOT_ADDR_INDEX 258 +#define DW_DLE_ATTR_FORM_NOT_STR_INDEX 259 +#define DW_DLE_DUPLICATE_GDB_INDEX 260 +#define DW_DLE_ERRONEOUS_GDB_INDEX_SECTION 261 +#define DW_DLE_GDB_INDEX_COUNT_ERROR 262 +#define DW_DLE_GDB_INDEX_COUNT_ADDR_ERROR 263 +#define DW_DLE_GDB_INDEX_INDEX_ERROR 264 +#define DW_DLE_GDB_INDEX_CUVEC_ERROR 265 +#define DW_DLE_DUPLICATE_CU_INDEX 266 +#define DW_DLE_DUPLICATE_TU_INDEX 267 +#define DW_DLE_XU_TYPE_ARG_ERROR 268 +#define DW_DLE_XU_IMPOSSIBLE_ERROR 269 +#define DW_DLE_XU_NAME_COL_ERROR 270 +#define DW_DLE_XU_HASH_ROW_ERROR 271 +#define DW_DLE_XU_HASH_INDEX_ERROR 272 +/* ..._FAILSAFE_ERRVAL is an aid when out of memory. */ +#define DW_DLE_FAILSAFE_ERRVAL 273 +#define DW_DLE_ARANGE_ERROR 274 +#define DW_DLE_PUBNAMES_ERROR 275 +#define DW_DLE_FUNCNAMES_ERROR 276 +#define DW_DLE_TYPENAMES_ERROR 277 +#define DW_DLE_VARNAMES_ERROR 278 +#define DW_DLE_WEAKNAMES_ERROR 279 +#define DW_DLE_RELOCS_ERROR 280 +#define DW_DLE_ATTR_OUTSIDE_SECTION 281 +#define DW_DLE_FISSION_INDEX_WRONG 282 +#define DW_DLE_FISSION_VERSION_ERROR 283 +#define DW_DLE_NEXT_DIE_LOW_ERROR 284 +#define DW_DLE_CU_UT_TYPE_ERROR 285 +#define DW_DLE_NO_SUCH_SIGNATURE_FOUND 286 +#define DW_DLE_SIGNATURE_SECTION_NUMBER_WRONG 287 +#define DW_DLE_ATTR_FORM_NOT_DATA8 288 +#define DW_DLE_SIG_TYPE_WRONG_STRING 289 +#define DW_DLE_MISSING_REQUIRED_TU_OFFSET_HASH 290 +#define DW_DLE_MISSING_REQUIRED_CU_OFFSET_HASH 291 +#define DW_DLE_DWP_MISSING_DWO_ID 292 +#define DW_DLE_DWP_SIBLING_ERROR 293 +#define DW_DLE_DEBUG_FISSION_INCOMPLETE 294 +#define DW_DLE_FISSION_SECNUM_ERR 295 +#define DW_DLE_DEBUG_MACRO_DUPLICATE 296 +#define DW_DLE_DEBUG_NAMES_DUPLICATE 297 +#define DW_DLE_DEBUG_LINE_STR_DUPLICATE 298 +#define DW_DLE_DEBUG_SUP_DUPLICATE 299 +#define DW_DLE_NO_SIGNATURE_TO_LOOKUP 300 +#define DW_DLE_NO_TIED_ADDR_AVAILABLE 301 +#define DW_DLE_NO_TIED_SIG_AVAILABLE 302 +#define DW_DLE_STRING_NOT_TERMINATED 303 +#define DW_DLE_BAD_LINE_TABLE_OPERATION 304 +#define DW_DLE_LINE_CONTEXT_BOTCH 305 +#define DW_DLE_LINE_CONTEXT_INDEX_WRONG 306 +#define DW_DLE_NO_TIED_STRING_AVAILABLE 307 +#define DW_DLE_NO_TIED_FILE_AVAILABLE 308 +#define DW_DLE_CU_TYPE_MISSING 309 +#define DW_DLE_LLE_CODE_UNKNOWN 310 +#define DW_DLE_LOCLIST_INTERFACE_ERROR 311 +#define DW_DLE_LOCLIST_INDEX_ERROR 312 +#define DW_DLE_INTERFACE_NOT_SUPPORTED 313 +#define DW_DLE_ZDEBUG_REQUIRES_ZLIB 314 +#define DW_DLE_ZDEBUG_INPUT_FORMAT_ODD 315 +#define DW_DLE_ZLIB_BUF_ERROR 316 +#define DW_DLE_ZLIB_DATA_ERROR 317 +#define DW_DLE_MACRO_OFFSET_BAD 318 +#define DW_DLE_MACRO_OPCODE_BAD 319 +#define DW_DLE_MACRO_OPCODE_FORM_BAD 320 +#define DW_DLE_UNKNOWN_FORM 321 +#define DW_DLE_BAD_MACRO_HEADER_POINTER 322 +#define DW_DLE_BAD_MACRO_INDEX 323 +#define DW_DLE_MACRO_OP_UNHANDLED 324 +#define DW_DLE_MACRO_PAST_END 325 +#define DW_DLE_LINE_STRP_OFFSET_BAD 326 +#define DW_DLE_STRING_FORM_IMPROPER 327 +#define DW_DLE_ELF_FLAGS_NOT_AVAILABLE 328 +#define DW_DLE_LEB_IMPROPER 329 +#define DW_DLE_DEBUG_LINE_RANGE_ZERO 330 +#define DW_DLE_READ_LITTLEENDIAN_ERROR 331 +#define DW_DLE_READ_BIGENDIAN_ERROR 332 +#define DW_DLE_RELOC_INVALID 333 +#define DW_DLE_INFO_HEADER_ERROR 334 +#define DW_DLE_ARANGES_HEADER_ERROR 335 +#define DW_DLE_LINE_OFFSET_WRONG_FORM 336 +#define DW_DLE_FORM_BLOCK_LENGTH_ERROR 337 +#define DW_DLE_ZLIB_SECTION_SHORT 338 +#define DW_DLE_CIE_INSTR_PTR_ERROR 339 +#define DW_DLE_FDE_INSTR_PTR_ERROR 340 +#define DW_DLE_FISSION_ADDITION_ERROR 341 +#define DW_DLE_HEADER_LEN_BIGGER_THAN_SECSIZE 342 +#define DW_DLE_LOCEXPR_OFF_SECTION_END 343 +#define DW_DLE_POINTER_SECTION_UNKNOWN 344 +#define DW_DLE_ERRONEOUS_XU_INDEX_SECTION 345 +#define DW_DLE_DIRECTORY_FORMAT_COUNT_VS_DIRECTORIES_MISMATCH 346 +#define DW_DLE_COMPRESSED_EMPTY_SECTION 347 +#define DW_DLE_SIZE_WRAPAROUND 348 +#define DW_DLE_ILLOGICAL_TSEARCH 349 +#define DW_DLE_BAD_STRING_FORM 350 +#define DW_DLE_DEBUGSTR_ERROR 351 +#define DW_DLE_DEBUGSTR_UNEXPECTED_REL 352 +#define DW_DLE_DISCR_ARRAY_ERROR 353 +#define DW_DLE_LEB_OUT_ERROR 354 +#define DW_DLE_SIBLING_LIST_IMPROPER 355 +#define DW_DLE_LOCLIST_OFFSET_BAD 356 +#define DW_DLE_LINE_TABLE_BAD 357 +#define DW_DLE_DEBUG_LOClISTS_DUPLICATE 358 +#define DW_DLE_DEBUG_RNGLISTS_DUPLICATE 359 +#define DW_DLE_ABBREV_OFF_END 360 +#define DW_DLE_FORM_STRING_BAD_STRING 361 +#define DW_DLE_AUGMENTATION_STRING_OFF_END 362 +#define DW_DLE_STRING_OFF_END_PUBNAMES_LIKE 363 +#define DW_DLE_LINE_STRING_BAD 364 +#define DW_DLE_DEFINE_FILE_STRING_BAD 365 +#define DW_DLE_MACRO_STRING_BAD 366 +#define DW_DLE_MACINFO_STRING_BAD 367 +#define DW_DLE_ZLIB_UNCOMPRESS_ERROR 368 +#define DW_DLE_IMPROPER_DWO_ID 369 +#define DW_DLE_GROUPNUMBER_ERROR 370 +#define DW_DLE_ADDRESS_SIZE_ZERO 371 +#define DW_DLE_DEBUG_NAMES_HEADER_ERROR 372 +#define DW_DLE_DEBUG_NAMES_AUG_STRING_ERROR 373 +#define DW_DLE_DEBUG_NAMES_PAD_NON_ZERO 374 +#define DW_DLE_DEBUG_NAMES_OFF_END 375 +#define DW_DLE_DEBUG_NAMES_ABBREV_OVERFLOW 376 +#define DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION 377 +#define DW_DLE_DEBUG_NAMES_NULL_POINTER 378 +#define DW_DLE_DEBUG_NAMES_BAD_INDEX_ARG 379 +#define DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET 380 +#define DW_DLE_DEBUG_NAMES_UNHANDLED_FORM 381 +#define DW_DLE_LNCT_CODE_UNKNOWN 382 +#define DW_DLE_LNCT_FORM_CODE_NOT_HANDLED 383 +#define DW_DLE_LINE_HEADER_LENGTH_BOTCH 384 +#define DW_DLE_STRING_HASHTAB_IDENTITY_ERROR 385 +#define DW_DLE_UNIT_TYPE_NOT_HANDLED 386 +#define DW_DLE_GROUP_MAP_ALLOC 387 +#define DW_DLE_GROUP_MAP_DUPLICATE 388 +#define DW_DLE_GROUP_COUNT_ERROR 389 +#define DW_DLE_GROUP_INTERNAL_ERROR 390 +#define DW_DLE_GROUP_LOAD_ERROR 391 +#define DW_DLE_GROUP_LOAD_READ_ERROR 392 +#define DW_DLE_AUG_DATA_LENGTH_BAD 393 +#define DW_DLE_ABBREV_MISSING 394 +#define DW_DLE_NO_TAG_FOR_DIE 395 +#define DW_DLE_LOWPC_WRONG_CLASS 396 +#define DW_DLE_HIGHPC_WRONG_FORM 397 +#define DW_DLE_STR_OFFSETS_BASE_WRONG_FORM 398 +#define DW_DLE_DATA16_OUTSIDE_SECTION 399 +#define DW_DLE_LNCT_MD5_WRONG_FORM 400 +#define DW_DLE_LINE_HEADER_CORRUPT 401 +#define DW_DLE_STR_OFFSETS_NULLARGUMENT 402 +#define DW_DLE_STR_OFFSETS_NULL_DBG 403 +#define DW_DLE_STR_OFFSETS_NO_MAGIC 404 +#define DW_DLE_STR_OFFSETS_ARRAY_SIZE 405 +#define DW_DLE_STR_OFFSETS_VERSION_WRONG 406 +#define DW_DLE_STR_OFFSETS_ARRAY_INDEX_WRONG 407 +#define DW_DLE_STR_OFFSETS_EXTRA_BYTES 408 +#define DW_DLE_DUP_ATTR_ON_DIE 409 +#define DW_DLE_SECTION_NAME_BIG 410 +#define DW_DLE_FILE_UNAVAILABLE 411 +#define DW_DLE_FILE_WRONG_TYPE 412 +#define DW_DLE_SIBLING_OFFSET_WRONG 413 +#define DW_DLE_OPEN_FAIL 414 +#define DW_DLE_OFFSET_SIZE 415 +#define DW_DLE_MACH_O_SEGOFFSET_BAD 416 +#define DW_DLE_FILE_OFFSET_BAD 417 +#define DW_DLE_SEEK_ERROR 418 +#define DW_DLE_READ_ERROR 419 +#define DW_DLE_ELF_CLASS_BAD 420 +#define DW_DLE_ELF_ENDIAN_BAD 421 +#define DW_DLE_ELF_VERSION_BAD 422 +#define DW_DLE_FILE_TOO_SMALL 423 +#define DW_DLE_PATH_SIZE_TOO_SMALL 424 +#define DW_DLE_BAD_TYPE_SIZE 425 +#define DW_DLE_PE_SIZE_SMALL 426 +#define DW_DLE_PE_OFFSET_BAD 427 +#define DW_DLE_PE_STRING_TOO_LONG 428 +#define DW_DLE_IMAGE_FILE_UNKNOWN_TYPE 429 +#define DW_DLE_LINE_TABLE_LINENO_ERROR 430 +#define DW_DLE_PRODUCER_CODE_NOT_AVAILABLE 431 +#define DW_DLE_NO_ELF_SUPPORT 432 +#define DW_DLE_NO_STREAM_RELOC_SUPPORT 433 +#define DW_DLE_RETURN_EMPTY_PUBNAMES_ERROR 434 +#define DW_DLE_SECTION_SIZE_ERROR 435 +#define DW_DLE_INTERNAL_NULL_POINTER 436 +#define DW_DLE_SECTION_STRING_OFFSET_BAD 437 +#define DW_DLE_SECTION_INDEX_BAD 438 +#define DW_DLE_INTEGER_TOO_SMALL 439 +#define DW_DLE_ELF_SECTION_LINK_ERROR 440 +#define DW_DLE_ELF_SECTION_GROUP_ERROR 441 +#define DW_DLE_ELF_SECTION_COUNT_MISMATCH 442 +#define DW_DLE_ELF_STRING_SECTION_MISSING 443 +#define DW_DLE_SEEK_OFF_END 444 +#define DW_DLE_READ_OFF_END 445 +#define DW_DLE_ELF_SECTION_ERROR 446 +#define DW_DLE_ELF_STRING_SECTION_ERROR 447 +#define DW_DLE_MIXING_SPLIT_DWARF_VERSIONS 448 +#define DW_DLE_TAG_CORRUPT 449 +#define DW_DLE_FORM_CORRUPT 450 +#define DW_DLE_ATTR_CORRUPT 451 +#define DW_DLE_ABBREV_ATTR_DUPLICATION 452 +#define DW_DLE_DWP_SIGNATURE_MISMATCH 453 +#define DW_DLE_CU_UT_TYPE_VALUE 454 +#define DW_DLE_DUPLICATE_GNU_DEBUGLINK 455 +#define DW_DLE_CORRUPT_GNU_DEBUGLINK 456 +#define DW_DLE_CORRUPT_NOTE_GNU_DEBUGID 457 +#define DW_DLE_CORRUPT_GNU_DEBUGID_SIZE 458 +#define DW_DLE_CORRUPT_GNU_DEBUGID_STRING 459 +#define DW_DLE_HEX_STRING_ERROR 460 +#define DW_DLE_DECIMAL_STRING_ERROR 461 +#define DW_DLE_PRO_INIT_EXTRAS_UNKNOWN 462 +#define DW_DLE_PRO_INIT_EXTRAS_ERR 463 +#define DW_DLE_NULL_ARGS_DWARF_ADD_PATH 464 +#define DW_DLE_DWARF_INIT_DBG_NULL 465 +#define DW_DLE_ELF_RELOC_SECTION_ERROR 466 +#define DW_DLE_USER_DECLARED_ERROR 467 +#define DW_DLE_RNGLISTS_ERROR 468 +#define DW_DLE_LOCLISTS_ERROR 469 +#define DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE 470 +#define DW_DLE_GDBINDEX_STRING_ERROR 471 +#define DW_DLE_GNU_PUBNAMES_ERROR 472 +#define DW_DLE_GNU_PUBTYPES_ERROR 473 +#define DW_DLE_DUPLICATE_GNU_DEBUG_PUBNAMES 474 +#define DW_DLE_DUPLICATE_GNU_DEBUG_PUBTYPES 475 +#define DW_DLE_DEBUG_SUP_STRING_ERROR 476 +#define DW_DLE_DEBUG_SUP_ERROR 477 +#define DW_DLE_LOCATION_ERROR 478 +#define DW_DLE_DEBUGLINK_PATH_SHORT 479 +#define DW_DLE_SIGNATURE_MISMATCH 480 +#define DW_DLE_MACRO_VERSION_ERROR 481 +#define DW_DLE_NEGATIVE_SIZE 482 +#define DW_DLE_UDATA_VALUE_NEGATIVE 483 +#define DW_DLE_DEBUG_NAMES_ERROR 484 +#define DW_DLE_CFA_INSTRUCTION_ERROR 485 +#define DW_DLE_MACHO_CORRUPT_HEADER 486 +#define DW_DLE_MACHO_CORRUPT_COMMAND 487 +#define DW_DLE_MACHO_CORRUPT_SECTIONDETAILS 488 +#define DW_DLE_RELOCATION_SECTION_SIZE_ERROR 489 +#define DW_DLE_SYMBOL_SECTION_SIZE_ERROR 490 +#define DW_DLE_PE_SECTION_SIZE_ERROR 491 +#define DW_DLE_DEBUG_ADDR_ERROR 492 +#define DW_DLE_NO_SECT_STRINGS 493 +#define DW_DLE_TOO_FEW_SECTIONS 494 +#define DW_DLE_BUILD_ID_DESCRIPTION_SIZE 495 +#define DW_DLE_BAD_SECTION_FLAGS 496 +#define DW_DLE_IMPROPER_SECTION_ZERO 497 +#define DW_DLE_INVALID_NULL_ARGUMENT 498 +#define DW_DLE_LINE_INDEX_WRONG 499 +#define DW_DLE_LINE_COUNT_WRONG 500 +#define DW_DLE_ARITHMETIC_OVERFLOW 501 +#define DW_DLE_UNIVERSAL_BINARY_ERROR 502 +#define DW_DLE_UNIV_BIN_OFFSET_SIZE_ERROR 503 + +/*! @note DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */ +#define DW_DLE_LAST 503 +#define DW_DLE_LO_USER 0x10000 +/*! @} */ + +/*! @section initfinish Initialization And Finish Operations */ + +/*! @defgroup initfunctions Libdwarf Initialization Functions + + @{ + Opening and closing libdwarf on object files. + +*/ + +/*! @brief Initialization based on path, the most common + initialization. + + On a Mach-O universal binary this function can + only return information about the first (zero index) + object in the universal binary. + + @param dw_path + Pass in the path to the object file to open. + @param dw_true_path_out_buffer + Pass in NULL or the name of a string buffer + (The buffer should be initialized with an initial NUL byte) + The returned string will be null-terminated. + The path actually used is copied to true_path_out. + If true_path_buffer len is zero or true_path_out_buffer + is zero then the Special MacOS processing will not + occur, nor will the GNU_debuglink processing occur. + In case GNU debuglink data was followed or MacOS + dSYM applies the true_path_out + will not match path and the initial byte will be + non-null. + The value put in true_path_out is the actual file name. + @param dw_true_path_bufferlen + Pass in the length in bytes of the buffer. + @param dw_groupnumber + The value passed in should be DW_GROUPNUMBER_ANY + unless one wishes to other than a standard + group. + @param dw_errhand + Pass in NULL unless one wishes libdwarf to call + this error handling function (which you must write) + instead of passing meaningful values to the + dw_error argument. + @param dw_errarg + If dw_errorhand is non-null, then this value + (a pointer or integer that means something + to you) is passed to the dw_errhand function + in case that is helpful to you. + @param dw_dbg + On success, *dw_dbg is set to a pointer to + a new Dwarf_Debug structure to be used in + calls to libdwarf functions. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return DW_DLV_OK etc. + + @link dwsec_separatedebug Details on separate DWARF object access @endlink + @see dwarf_init_path_dl dwarf_init_b + @see exampleinit +*/ + +DW_API int dwarf_init_path(const char * dw_path, + char * dw_true_path_out_buffer, + unsigned int dw_true_path_bufferlen, + unsigned int dw_groupnumber, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + Dwarf_Debug* dw_dbg, + Dwarf_Error* dw_error); + +/*! @brief Initialization based on path + + This identical to dwarf_init_path() except that it + adds a new argument, dw_universalnumber, + with which you can specify which object in + a Mach-O universal binary you wish to open. + + It is always safe and appropriate to pass + zero as the dw_universalnumber. + Elf and PE and (non-universal) Mach-O object + files ignore the value of dw_universalnumber. +*/ +DW_API int dwarf_init_path_a(const char * dw_path, + char * dw_true_path_out_buffer, + unsigned int dw_true_path_bufferlen, + unsigned int dw_groupnumber, + unsigned int dw_universalnumber, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + Dwarf_Debug* dw_dbg, + Dwarf_Error* dw_error); + +/*! @brief Initialization following GNU debuglink section data. + + Sets the true-path with DWARF if there is + appropriate debuglink data available. + + In case DW_DLV_ERROR returned be sure to + call dwarf_dealloc_error even though + the returned Dwarf_Debug is NULL. + + @param dw_path + Pass in the path to the object file to open. + @param dw_true_path_out_buffer + Pass in NULL or the name of a string buffer. + @param dw_true_path_bufferlen + Pass in the length in bytes of the buffer. + @param dw_groupnumber + The value passed in should be DW_GROUPNUMBER_ANY + unless one wishes to other than a standard + group. + @param dw_errhand + Pass in NULL, normally. + If non-null one wishes libdwarf to call + this error handling function (which you must write) + instead of passing meaningful values to the + dw_error argument. + @param dw_errarg + Pass in NULL, normally. + If dw_errorhand is non-null, then this value + (a pointer or integer that means something + to you) is passed to the dw_errhand function + in case that is helpful to you. + @param dw_dbg + On success, *dw_dbg is set to a pointer to + a new Dwarf_Debug structure to be used in + calls to libdwarf functions. + @param dw_dl_path_array + debuglink processing allows a user-specified set of file paths + and this argument allows one to specify these. + Pass in a pointer to array of pointers to strings + which you, the caller, have filled in. The strings + should be alternate paths (see the GNU debuglink + documentation.) + @param dw_dl_path_array_size + Specify the size of the dw_dl_path_array. + @param dw_dl_path_source + returns DW_PATHSOURCE_basic or other such value so the caller can + know how the true-path was resolved. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return DW_DLV_OK etc. + + @link dwsec_separatedebug Details on separate DWARF object access @endlink + @see exampleinit_dl + */ +DW_API int dwarf_init_path_dl(const char * dw_path, + char * dw_true_path_out_buffer, + unsigned int dw_true_path_bufferlen, + unsigned int dw_groupnumber, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + Dwarf_Debug* dw_dbg, + char ** dw_dl_path_array, + unsigned int dw_dl_path_array_size, + unsigned char * dw_dl_path_source, + Dwarf_Error* dw_error); + +/*! @brief Initialization based on path with debuglink + + This identical to dwarf_init_path_dl() except that it + adds a new argument, dw_universalnumber, + with which you can specify which object in + a Mach-O universal binary you wish to open. + + It is always safe and appropriate to pass + zero as the dw_universalnumber. + Elf and PE and (non-universal) Mach-O object + files ignore the value of dw_universalnumber. + + Mach-O objects do not contain or use debuglink + data. +*/ + +DW_API int dwarf_init_path_dl_a(const char * dw_path, + char * dw_true_path_out_buffer, + unsigned int dw_true_path_bufferlen, + unsigned int dw_groupnumber, + unsigned int dw_universalnumber, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + Dwarf_Debug* dw_dbg, + char ** dw_dl_path_array, + unsigned int dw_dl_path_array_size, + unsigned char * dw_dl_path_source, + Dwarf_Error* dw_error); + +/*! @brief Initialization based on Unix/Linux (etc) path + This version allows specifying any number of debuglink + global paths to search on for debuglink targets. + + In case DW_DLV_ERROR returned be sure to + call dwarf_dealloc_error even though + the returned Dwarf_Debug is NULL. + + @param dw_fd + An open Unix/Linux/etc fd on the object file. + @param dw_groupnumber + The value passed in should be DW_GROUPNUMBER_ANY + unless one wishes to other than a standard + group. + @param dw_errhand + Pass in NULL unless one wishes libdwarf to call + this error handling function (which you must write) + instead of passing meaningful values to the + dw_error argument. + @param dw_errarg + If dw_errorhand is non-null, then this value + (a pointer or integer that means something + to you) is passed to the dw_errhand function + in case that is helpful to you. + @param dw_dbg + On success, *dw_dbg is set to a pointer to + a new Dwarf_Debug structure to be used in + calls to libdwarf functions. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return + DW_DLV_OK etc. +*/ +DW_API int dwarf_init_b(int dw_fd, + unsigned int dw_groupnumber, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + Dwarf_Debug* dw_dbg, + Dwarf_Error* dw_error); + +/*! @brief Close the initialized dw_dbg and + free all data libdwarf has for this dw_dbg. + @param dw_dbg + Close the dbg. + @return + May return DW_DLV_ERROR if something + is very wrong: no further information is available.. + May return DW_DLV_NO_ENTRY + but no further information is available. + Normally returns DW_DLV_OK. +*/ +DW_API int dwarf_finish(Dwarf_Debug dw_dbg); + +/*! @brief Used to access DWARF information in memory + or in an object format unknown to libdwarf. + + In case DW_DLV_ERROR returned be sure to + call dwarf_dealloc_error even though + the returned Dwarf_Debug is NULL. + + @see jitreader + + and @see dw_noobject Reading DWARF not in object file + + @param dw_obj + A data structure filled out by the caller so libdwarf + can access DWARF data not in a supported object file format. + @param dw_errhand + Pass in NULL normally. + @param dw_errarg + Pass in NULL normally. + @param dw_groupnumber + The value passed in should be DW_GROUPNUMBER_ANY + unless one wishes to other than a standard + group (quite unlikely for this interface). + @param dw_dbg + On success, *dw_dbg is set to a pointer to + a new Dwarf_Debug structure to be used in + calls to libdwarf functions. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_object_init_b(Dwarf_Obj_Access_Interface_a* dw_obj, + Dwarf_Handler dw_errhand, + Dwarf_Ptr dw_errarg, + unsigned int dw_groupnumber, + Dwarf_Debug* dw_dbg, + Dwarf_Error* dw_error); + +/*! @brief Used to close the object_init dw_dbg. + + Close the dw_dbg opened by dwarf_object_init_b(). + + @param dw_dbg + Must be an open Dwarf_Debug opened by + dwarf_object_init_b(). + The init call dw_obj data is not freed + by the call to dwarf_object_finish. + @return + The return value DW_DLV_OK etc is pretty useless, there + is not much you can do with it. +*/ +DW_API int dwarf_object_finish(Dwarf_Debug dw_dbg); + +/*! @brief Use with split dwarf. + + @param dw_basedbg + Pass in an open dbg, on an object file + with (normally) lots of DWARF.. + @param dw_tied_dbg + Pass in an open dbg on an executable + which has minimal DWARF to save space + in the executable. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return DW_DLV_OK etc. + + @see example2 + @see example3 +*/ +DW_API int dwarf_set_tied_dbg(Dwarf_Debug dw_basedbg, + Dwarf_Debug dw_tied_dbg, + Dwarf_Error* dw_error); + +/*! @brief Use with split dwarf. + + Given a base Dwarf_Debug this returns + the tied Dwarf_Debug. + Unlikely anyone uses this call as + you had the tied and base dbg when calling + dwarf_set_tied_dbg(). +*/ +DW_API int dwarf_get_tied_dbg(Dwarf_Debug dw_dbg, + Dwarf_Debug * dw_tieddbg_out, + Dwarf_Error * dw_error); +/*! @} +*/ +/*! @defgroup compilationunit Compilation Unit (CU) Access + + @{ +*/ +/*! @brief Return information on the next CU header. + + The library keeps track of where it is in the object file + and it knows where to find 'next'. + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_is_info + Pass in TRUE if reading through .debug_info + Pass in FALSE if reading through DWARF4 + .debug_types. + @param dw_cu_header_length + Returns the length of the just-read CU header. + @param dw_version_stamp + Returns the version number (2 to 5) of the CU + header just read. + @param dw_abbrev_offset + Returns the .debug_abbrev offset from the + the CU header just read. + @param dw_address_size + Returns the address size specified for this CU, + usually either 4 or 8. + @param dw_length_size + Returns the offset size (the length + of the size field from the header) + specified for this CU, either 4 or 4. + @param dw_extension_size + If the section is standard 64bit DWARF + then this value is 4. Else the value is zero. + @param dw_type_signature + If the CU is DW_UT_skeleton DW_UT_split_compile, + DW_UT_split_type or DW_UT_type this is the + type signature from the CU_header + compiled into this field. + @param dw_typeoffset + For DW_UT_split_type or DW_UT_type this is the + type offset from the CU header. + @param dw_next_cu_header_offset + The offset in the section of the next CU + (unless there is a compiler bug this is rarely + of interest). + @param dw_header_cu_type + Returns DW_UT_compile, or other DW_UT value. + @param dw_error + In case return is DW_DLV_ERROR + dw_error is set to point to + the error details. + @return + Returns DW_DLV_OK on success. + Returns DW_DLV_NO_ENTRY if all CUs have been read. + + @see examplecuhdr + +*/ +DW_API int dwarf_next_cu_header_d(Dwarf_Debug dw_dbg, + Dwarf_Bool dw_is_info, + Dwarf_Unsigned *dw_cu_header_length, + Dwarf_Half *dw_version_stamp, + Dwarf_Off *dw_abbrev_offset, + Dwarf_Half *dw_address_size, + Dwarf_Half *dw_length_size, + Dwarf_Half *dw_extension_size, + Dwarf_Sig8 *dw_type_signature, + Dwarf_Unsigned *dw_typeoffset, + Dwarf_Unsigned *dw_next_cu_header_offset, + Dwarf_Half *dw_header_cu_type, + Dwarf_Error *dw_error); + +/*! @brief Return the first DIE or the next sibling DIE. + + @param dw_dbg + The Dwarf_Debug one is operating on. + @param dw_die + Immediately after calling dwarf_next_cu_header_d + pass in NULL to retrieve the CU DIE. + Or pass in a known DIE and this will retrieve + the next sibling in the chain. + @param dw_is_info + Pass TRUE or FALSE to match the applicable + dwarf_next_cu_header_d call. + @param dw_return_siblingdie + The DIE returned through the pointer. + @param dw_error + The usual error information, if any. + @return + Returns DW_DLV_OK etc. + + @see example4 + @see dwarf_get_die_infotypes +*/ +DW_API int dwarf_siblingof_b(Dwarf_Debug dw_dbg, + Dwarf_Die dw_die, + Dwarf_Bool dw_is_info, + Dwarf_Die *dw_return_siblingdie, + Dwarf_Error *dw_error); + +/*! @brief Return some CU-relative facts. + + Any Dwarf_Die will work. + The values returned through the pointers + are about the CU for a DIE + @param dw_die + Some open Dwarf_Die. + @param dw_version + Returns the DWARF version: 2,3,4, or 5 + @param dw_is_info + Returns non-zero if the CU is .debug_info. + Returns zero if the CU is .debug_types (DWARF4). + @param dw_is_dwo + Returns ton-zero if the CU is a dwo/dwp object and + zero if it is a standard object. + @param dw_offset_size + Returns offset size, 4 and 8 are possible. + @param dw_address_size + Almost always returns 4 or 8. Could be 2 + in unusual circumstances. + @param dw_extension_size + The sum of dw_offset_size and dw_extension_size + are the count of the initial bytes of the CU. + Standard lengths are 4 and 12. + For 1990's SGI objects the length could be 8. + @param dw_signature + Returns a pointer to an 8 byte signature. + @param dw_offset_of_length + Returns the section offset of the initial + byte of the CU. + @param dw_total_byte_length + Returns the total length of the CU including + the length field and the content of the CU. + @param dw_error + The usual Dwarf_Error*. + @return + Returns DW_DLV_OK etc. +*/ + +DW_API int dwarf_cu_header_basics(Dwarf_Die dw_die, + Dwarf_Half *dw_version, + Dwarf_Bool *dw_is_info, + Dwarf_Bool *dw_is_dwo, + Dwarf_Half *dw_offset_size, + Dwarf_Half *dw_address_size, + Dwarf_Half *dw_extension_size, + Dwarf_Sig8 **dw_signature, + Dwarf_Off *dw_offset_of_length, + Dwarf_Unsigned *dw_total_byte_length, + Dwarf_Error *dw_error); + +/*! @brief Return the child DIE, if any. + The child may be the first of a list of + sibling DIEs. + + @param dw_die + We will return the first child of this DIE. + @param dw_return_childdie + Returns the first child through the pointer. + For subsequent dies siblings of the first, use + dwarf_siblingof_b(). + @param dw_error + The usual Dwarf_Error*. + @return + Returns DW_DLV_OK etc. Returns DW_DLV_NO_ENTRY + if dw_die has no children. + + @see example5 +*/ + +DW_API int dwarf_child(Dwarf_Die dw_die, + Dwarf_Die* dw_return_childdie, + Dwarf_Error* dw_error); + +/*! @brief Deallocate (free) a DIE. + @param dw_die + Frees (deallocs) memory associated with this Dwarf_Die. +*/ +DW_API void dwarf_dealloc_die( Dwarf_Die dw_die); + +/*! @brief Return a CU DIE given a has signature + + @param dw_dbg + @param dw_hash_sig + A pointer to an 8 byte signature to be looked up. + in .debug_names. + @param dw_sig_type + Valid type requests are "cu" and "tu" + @param dw_returned_CU_die + Returns the found CU DIE if one is found. + @param dw_error + The usual Dwarf_Error*. + @return + DW_DLV_OK means dw_returned_CU_die was set. + DW_DLV_NO_ENTRY means the signature could + not be found. +*/ +DW_API int dwarf_die_from_hash_signature(Dwarf_Debug dw_dbg, + Dwarf_Sig8 * dw_hash_sig, + const char * dw_sig_type, + Dwarf_Die* dw_returned_CU_die, + Dwarf_Error* dw_error); + +/*! @brief Return DIE given global (not CU-relative) offset. + + This works whether or not the target section + has had dwarf_next_cu_header_d() applied, + the CU the offset exists in has + been seen at all, or the target offset is one + libdwarf has seen before. + + @param dw_dbg + The applicable Dwarf_Debug + @param dw_offset + The global offset of the DIE in the appropriate + section. + @param dw_is_info + Pass TRUE if the target is .debug_info, else + pass FALSE if the target is .debug_types. + @param dw_return_die + On success this returns a DIE pointer to + the found DIE. + @param dw_error + The usual Dwarf_Error*. + @return + DW_DLV_OK means dw_returned_die was found + DW_DLV_NO_ENTRY is only possible if the offset + is to a null DIE, and that is very unusual. + Otherwise expect DW_DLV_ERROR. + + @see example6 + +*/ +DW_API int dwarf_offdie_b(Dwarf_Debug dw_dbg, + Dwarf_Off dw_offset, + Dwarf_Bool dw_is_info, + Dwarf_Die* dw_return_die, + Dwarf_Error* dw_error); + +/*! @brief Return a DIE given a Dwarf_Sig8 hash. + + Returns DIE and is_info flag if it finds the hash + signature of a DIE. Often will be the CU DIE of + DW_UT_split_type or DW_UT_type CU. + + @param dw_dbg + The applicable Dwarf_Debug + @param dw_ref + A pointer to a Dwarf_Sig8 struct whose + content defines what is being searched for. + @param dw_die_out + If found, this returns the found DIE itself. + @param dw_is_info + If found, this returns section (.debug_is_info + or .debug_is_types). + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_find_die_given_sig8(Dwarf_Debug dw_dbg, + Dwarf_Sig8 *dw_ref, + Dwarf_Die *dw_die_out, + Dwarf_Bool *dw_is_info, + Dwarf_Error *dw_error); + +/*! @brief Return the is_info flag. + + So client software knows if a DIE is in debug_info or + (DWARF4-only) debug_types. + @param dw_die + The DIE being queried. + @return + If non-zero the flag means the DIE is in .debug_info. + Otherwise it means the DIE is in .debug_types. +*/ +DW_API Dwarf_Bool dwarf_get_die_infotypes_flag(Dwarf_Die dw_die); +/*! @} */ + +/*! @defgroup dieentry Debugging Information Entry (DIE) content + @{ + This is the main interface to attributes of a DIE. +*/ + +/*! @brief Return the abbrev section offset of a DIE's abbrevs. + + So we can associate a DIE's abbreviations with the contents + the abbreviations section. + Useful for detailed printing and analysis of + abbreviations + + @param dw_die + The DIE of interest + @param dw_abbrev_offset + On success is set to the global offset + in the .debug_abbrev section of the abbreviations + for the DIE. + @param dw_abbrev_count + On success is set to the count of abbreviations + in the .debug_abbrev section of the abbreviations + for the DIE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_die_abbrev_global_offset(Dwarf_Die dw_die, + Dwarf_Off * dw_abbrev_offset, + Dwarf_Unsigned * dw_abbrev_count, + Dwarf_Error* dw_error); + +/*! @brief Get TAG value of DIE. + @param dw_die + The DIE of interest + @param dw_return_tag + On success, set to the DW_TAG value of the DIE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_tag(Dwarf_Die dw_die, + Dwarf_Half* dw_return_tag, + Dwarf_Error* dw_error); + +/*! @brief Return the global section offset of the DIE. + + @param dw_die + The DIE of interest + @param dw_return_offset + On success the offset refers to the section of the DIE + itself, which may be .debug_offset or .debug_types. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_dieoffset(Dwarf_Die dw_die, + Dwarf_Off* dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Extract address given address index. DWARF5 + + @param dw_die + The DIE of interest + @param dw_index + An index into .debug_addr. This will look first for + .debug_addr in the dbg object DIE and if not there + will look in the tied object if that is available. + @param dw_return_addr + On success the address is returned through the pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_debug_addr_index_to_addr(Dwarf_Die dw_die, + Dwarf_Unsigned dw_index, + Dwarf_Addr * dw_return_addr, + Dwarf_Error * dw_error); + +/*! @brief Informs if a DW_FORM is an indexed form + + Reading a CU DIE with DW_AT_low_pc an indexed value can + be problematic as several different FORMs are indexed. + Some in DWARF5 others being extensions to DWARF4 + and DWARF5. Indexed forms interact with DW_AT_addr_base + in a DIE making this a very relevant distinction. +*/ +DW_API Dwarf_Bool dwarf_addr_form_is_indexed(int dw_form); + +/*! @brief Return the CU DIE offset given any DIE + + Returns + the global debug_info section offset of the CU die + in the CU containing the given_die + (the passed in DIE can be any DIE). + + @see dwarf_get_cu_die_offset_given_cu_header_offset_b + @see example7 + + @param dw_die + The DIE being queried. + @param dw_return_offset + Returns the section offset of the CU DIE for dw_die. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_CU_dieoffset_given_die(Dwarf_Die dw_die, + Dwarf_Off* dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Return the CU DIE section offset given CU header offset + + Returns the CU DIE global offset if one knows the + CU header global offset. + @see dwarf_CU_dieoffset_given_die + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_in_cu_header_offset + The CU header offset. + @param dw_is_info + If TRUE the CU header offset is in .debug_info. + Otherwise the CU header offset is in .debug_types. + @param dw_out_cu_die_offset + The CU DIE offset returned through this pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_cu_die_offset_given_cu_header_offset_b( + Dwarf_Debug dw_dbg, + Dwarf_Off dw_in_cu_header_offset, + Dwarf_Bool dw_is_info, + Dwarf_Off * dw_out_cu_die_offset, + Dwarf_Error *dw_error); + +/*! @brief returns the CU relative offset of the DIE. + + @see dwarf_CU_dieoffset_given_die + + @param dw_die + The DIE being queried. + @param dw_return_offset + Returns the CU relative offset of this DIE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_die_CU_offset(Dwarf_Die dw_die, + Dwarf_Off* dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Return the offset length of the entire CU of a DIE. + @param dw_die + The DIE being queried. + @param dw_return_CU_header_offset + On success returns the section offset of the CU + this DIE is in. + @param dw_return_CU_length_bytes + On success returns the CU length of the CU + this DIE is in, including the CU length, header, + and all DIEs. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_die_CU_offset_range(Dwarf_Die dw_die, + Dwarf_Off* dw_return_CU_header_offset, + Dwarf_Off* dw_return_CU_length_bytes, + Dwarf_Error* dw_error); + +/*! @brief Given DIE and attribute number return a Dwarf_attribute + + Returns DW_DLV_NO_ENTRY if the DIE has no attribute dw_attrnum. + + @param dw_die + The DIE of interest. + @param dw_attrnum + An attribute number, for example DW_AT_name. + @param dw_returned_attr + On success a Dwarf_Attribute pointer is returned + and it should eventually be deallocated. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_attr(Dwarf_Die dw_die, + Dwarf_Half dw_attrnum, + Dwarf_Attribute * dw_returned_attr, + Dwarf_Error* dw_error); + +/*! @brief Given DIE and attribute number return a string + + Returns DW_DLV_NO_ENTRY if the DIE has no attribute dw_attrnum. + + @param dw_die + The DIE of interest. + @param dw_attrnum + An attribute number, for example DW_AT_name. + @param dw_ret_name + On success a pointer to the string + is returned. + Do not free the string. + Many attributes allow various forms that directly or + indirectly contain strings and this + follows all of them to their string. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_die_text(Dwarf_Die dw_die, + Dwarf_Half dw_attrnum, + char ** dw_ret_name, + Dwarf_Error * dw_error); + +/*! @brief Return the string from a DW_AT_name attribute + + Returns DW_DLV_NO_ENTRY if the DIE has no attribute + DW_AT_name + + @param dw_die + The DIE of interest. + @param dw_diename + On success a pointer to the string + is returned. + Do not free the string. + Various forms directly or + indirectly contain strings and this + follows all of them to their string. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_diename(Dwarf_Die dw_die, + char ** dw_diename, + Dwarf_Error* dw_error); + +/*! @brief Return the DIE abbrev code + + The Abbrev code for a DIE is an integer assigned + by the compiler within a particular CU. + For .debug_names abbreviations the + situation is different. + + Returns the abbrev code of the die. Cannot fail. + + @param dw_die + The DIE of interest. + @return + The abbrev code. of the DIE. +*/ +DW_API int dwarf_die_abbrev_code(Dwarf_Die dw_die); + +/*! @brief Return TRUE if the DIE has children + + @param dw_die + A DIE. + @param dw_ab_has_child + Sets TRUE though the pointer if the DIE + has children. + Otherwise sets FALSE. + @return + Returns TRUE if the DIE has a child DIE. + Else returns FALSE. + +*/ +DW_API int dwarf_die_abbrev_children_flag(Dwarf_Die dw_die, + Dwarf_Half * dw_ab_has_child); + +/*! @brief Validate a sibling DIE. + + This is used by dwarfdump (when + dwarfdump is checking for valid DWARF) + to try to catch a corrupt DIE tree. + + @see example_sibvalid + + @param dw_sibling + Pass in a DIE returned by dwarf_siblingof_b(). + @param dw_offset + Set to zero through the pointer. + @return + Returns DW_DLV_OK if the sibling is + at an appropriate place in the section. + Otherwise it returns DW_DLV_ERROR indicating + the DIE tree is corrupt. + +*/ +DW_API int dwarf_validate_die_sibling(Dwarf_Die dw_sibling, + Dwarf_Off* dw_offset); + +/* convenience functions, alternative to using dwarf_attrlist */ + +/*! @brief Tells whether a DIE has a particular attribute. + + @param dw_die + The DIE of interest. + @param dw_attrnum + The attribute number we are asking about, + DW_AT_name for example. + @param dw_returned_bool + On success is set TRUE if dw_die has + dw_attrnum. + @param dw_error + The usual error detail return pointer. + @return + Never returns DW_DLV_NO_ENTRY. + Returns DW_DLV_OK unless there is an error, + in which case it returns DW_DLV_ERROR + and sets dw_error to the error details. +*/ +DW_API int dwarf_hasattr(Dwarf_Die dw_die, + Dwarf_Half dw_attrnum, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error* dw_error); + +/*! @brief Return an array of DIE children offsets + + Given a DIE section offset and dw_is_info, + returns an array of DIE global [section] + offsets of the children of DIE. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_offset + A DIE offset. + @param dw_is_info + If TRUE says to use the offset in .debug_info. + Else use the offset in .debug_types. + @param dw_offbuf + A pointer to an array of children + DIE global [section] offsets is returned + through the pointer. + @param dw_offcount + The number of elements in dw_offbuf. + If the DIE has no children it could + be zero, in which case dw_offbuf + and dw_offcount are not touched. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + DW_DLV_NO_ENTRY means there are no children of the DIE, + hence no list of child offsets. + + On successful return, use + dwarf_dealloc(dbg, dw_offbuf, DW_DLA_UARRAY); + to dealloc the allocated space. + + @see exampleoffset_list +*/ +DW_API int dwarf_offset_list(Dwarf_Debug dw_dbg, + Dwarf_Off dw_offset, + Dwarf_Bool dw_is_info, + Dwarf_Off ** dw_offbuf, + Dwarf_Unsigned * dw_offcount, + Dwarf_Error * dw_error); + +/*! @brief Get the address size applying to a DIE + + @param dw_die + The DIE of interest. + @param dw_addr_size + On success, returns the address size that applies + to dw_die. Normally 4 or 8. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_die_address_size(Dwarf_Die dw_die, + Dwarf_Half * dw_addr_size, + Dwarf_Error * dw_error); + +/* Get both offsets (local and global) */ +/*! @brief Return section and CU-local offsets of a DIE + @param dw_die + The DIE of interest. + @param dw_global_offset + On success returns the offset of the DIE in + its section. + @param dw_local_offset + On success returns the offset of the DIE within + its CU. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_die_offsets(Dwarf_Die dw_die, + Dwarf_Off* dw_global_offset, + Dwarf_Off* dw_local_offset, + Dwarf_Error* dw_error); + +/*! @brief Get the version and offset size + + The values returned apply to the CU this DIE + belongs to. + This is useful as preparation for calling + dwarf_get_form_class + + @param dw_die + The DIE of interest. + @param dw_version + Returns the version of the CU this DIE is contained in. + Standard version numbers are 2 through 5. + @param dw_offset_size + Returns the offset_size (4 or 8) of the CU + this DIE is contained in. +*/ +DW_API int dwarf_get_version_of_die(Dwarf_Die dw_die, + Dwarf_Half * dw_version, + Dwarf_Half * dw_offset_size); + +/*! @brief Return the DW_AT_low_pc value + + @param dw_die + The DIE of interest. + @param dw_returned_addr + On success returns, through the pointer, + the address DW_AT_low_pc defines. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_lowpc(Dwarf_Die dw_die, + Dwarf_Addr * dw_returned_addr, + Dwarf_Error* dw_error); + +/* When the highpc attribute is of class 'constant' + it is not an address, it is an offset from the + base address (such as lowpc) of the function. + This is therefore a required interface for DWARF4 + style DW_AT_highpc. */ + +/*! @brief Return the DW_AT_hipc address value + + This is accessing the DW_AT_high_pc attribute. + Calculating the high pc involves elements + which we don't describe here, but which + are shown in the example. See the DWARF5 standard. + + @see examplehighpc + + @param dw_die + The DIE of interest. + @param dw_return_addr + On success returns the high-pc address for this DIE. + If the high-pc is a not DW_FORM_addr + and is a non-indexed constant form + one must add the value of the DW_AT_low_pc to this + to get the true high-pc value as the value returned + is an unsigned offset of the associated low-pc value. + @param dw_return_form + On success returns the actual FORM for this attribute. + Needed for certain cases to calculate the true + dw_return_addr; + @param dw_return_class + On success returns the FORM CLASS for this attribute. + Needed for certain cases to calculate the true + dw_return_addr; + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_highpc_b(Dwarf_Die dw_die, + Dwarf_Addr * dw_return_addr, + Dwarf_Half * dw_return_form, + enum Dwarf_Form_Class * dw_return_class, + Dwarf_Error * dw_error); + +/*! @brief Return the offset from the DW_AT_type attribute + + The offset returned is is a global offset from + the DW_AT_type of the DIE passed in. + If this CU is DWARF4 the offset could be in + .debug_types, otherwise it is in .debug_info + Check the section of the DIE to know which + it is, dwarf_cu_header_basics() will return that. + + Added pointer argument to return the section + the offset applies to. December 2022. + + @param dw_die + The DIE of interest. + @param dw_return_offset + If successful, returns the offset through the pointer. + @param dw_is_info + If successful, set to TRUE if the dw_return_offset + is in .debug_info and FALSE if the dw_return_offset + is in .debug_types. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_dietype_offset(Dwarf_Die dw_die, + Dwarf_Off * dw_return_offset, + Dwarf_Bool * dw_is_info, + Dwarf_Error * dw_error); + +/*! @brief Return the value of the attribute DW_AT_byte_size + + @param dw_die + The DIE of interest. + @param dw_returned_size + If successful, returns the size through the pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_bytesize(Dwarf_Die dw_die, + Dwarf_Unsigned * dw_returned_size, + Dwarf_Error* dw_error); + +/*! @brief Return the value of the attribute DW_AT_bitsize + + @param dw_die + The DIE of interest. + @param dw_returned_size + If successful, returns the size through the pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_bitsize(Dwarf_Die dw_die, + Dwarf_Unsigned * dw_returned_size, + Dwarf_Error* dw_error); + +/*! @brief Return the bit offset attribute of a DIE + + If the attribute is DW_AT_data_bit_offset + (DWARF4, DWARF5) the returned bit offset + has one meaning. + If the attribute is DW_AT_bit_offset + (DWARF2, DWARF3) the meaning is quite different. + + @param dw_die + The DIE of interest. + @param dw_attrnum + If successful, returns the number of the attribute + (DW_AT_data_bit_offset or DW_AT_bit_offset) + @param dw_returned_offset + If successful, returns the bit offset value. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_bitoffset(Dwarf_Die dw_die, + Dwarf_Half * dw_attrnum, + Dwarf_Unsigned * dw_returned_offset, + Dwarf_Error* dw_error); +/*! @brief Return the value of the DW_AT_language attribute. + + The DIE should be a CU DIE. + @param dw_die + The DIE of interest. + @param dw_returned_lang + On success returns the language code (normally + only found on a CU DIE). For example DW_LANG_C + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_srclang(Dwarf_Die dw_die, + Dwarf_Unsigned * dw_returned_lang, + Dwarf_Error * dw_error); + +/*! @brief Return the value of the DW_AT_ordering attribute. + + @param dw_die + The DIE of interest. + @param dw_returned_order + On success returns the ordering value. + For example DW_ORD_row_major + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_arrayorder(Dwarf_Die dw_die, + Dwarf_Unsigned * dw_returned_order, + Dwarf_Error* dw_error); + +/*! @} */ +/*! @defgroup attrform DIE Attribute and Attribute-Form Details + @{ + Access to the details of DIEs +*/ +/*! @brief Gets the full list of attributes + + @param dw_die + The DIE from which to pull attributes. + @param dw_attrbuf + The pointer is set to point to an array + of Dwarf_Attribute (pointers to attribute data). + This array must eventually be deallocated. + @param dw_attrcount + The number of entries in the array of pointers. + There is no null-pointer to terminate the list, + use this count. + @param dw_error + A place to return error details. + @return + If it returns DW_DLV_ERROR and dw_error is non-null + it creates an Dwarf_Error and places it in this argument. + Usually returns DW_DLV_OK. + + @see example1 + + @see example8 +*/ +DW_API int dwarf_attrlist(Dwarf_Die dw_die, + Dwarf_Attribute** dw_attrbuf, + Dwarf_Signed * dw_attrcount, + Dwarf_Error* dw_error); + +/*! @brief Sets TRUE if a Dwarf_Attribute has the indicated FORM + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_form + The DW_FORM you are asking about, DW_FORM_strp for example. + @param dw_returned_bool + The pointer passed in must be a valid non-null pointer + to a Dwarf_Bool. + On success, sets the value to TRUE or FALSE. + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_returned_bool. + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_hasform(Dwarf_Attribute dw_attr, + Dwarf_Half dw_form, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error* dw_error); + +/*! @brief Return the form of the Dwarf_Attribute + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_final_form + The form of the item is returned + through the pointer. If the base form is DW_FORM_indirect + the function resolves the final form and + returns that final form. + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_returned_final_form + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_whatform(Dwarf_Attribute dw_attr, + Dwarf_Half * dw_returned_final_form, + Dwarf_Error* dw_error); + +/*! @brief Return the initial form of the Dwarf_Attribute + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_initial_form + The form of the item is returned + through the pointer. If the base form is DW_FORM_indirect + the value set is DW_FORM_indirect. + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_returned_initial_form. + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_whatform_direct(Dwarf_Attribute dw_attr, + Dwarf_Half * dw_returned_initial_form, + Dwarf_Error* dw_error); + +/*! @brief Return the attribute number of the Dwarf_Attribute + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_attrnum + The attribute number of the attribute is returned + through the pointer. For example, DW_AT_name + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_returned_attrnum + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_whatattr(Dwarf_Attribute dw_attr, + Dwarf_Half * dw_returned_attrnum, + Dwarf_Error* dw_error); + +/*! @brief Retrieve the CU-relative offset of a reference + + The DW_FORM of the attribute must be one of a small set + of local reference forms: DW_FORM_ref or + DW_FORM_udata. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_return_offset + Returns the CU-relative offset through the pointer. + @param dw_is_info + Returns a flag through the pointer. TRUE if the + offset is in .debug_info, FALSE if it is in .debug_types + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_returned_attrnum + If attribute is passed in NULL or + the attribute is badly broken or + the FORM of this attribute is not one of the small + set of local references + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_formref(Dwarf_Attribute dw_attr, + Dwarf_Off* dw_return_offset, + Dwarf_Bool *dw_is_info, + Dwarf_Error *dw_error); + +/*! @brief Return the section-relative offset of a Dwarf_Attribute + + The target section of the returned offset can be in + various sections depending on the FORM. + Only a DW_FORM_ref_sig8 can change the returned offset of + a .debug_info DIE via a lookup into .debug_types + by changing dw_offset_is_info to FALSE (DWARF4). + + The caller must determine the target section from + the FORM. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_return_offset + Returns the CU-relative offset through the pointer. + @param dw_offset_is_info + For references to DIEs this informs whether the target + DIE (the target the offset refers to) is in .debug_info + or .debug_types. For non-DIE targets this field + is not meaningful. Refer to the attribute FORM to determine + the target section of the offset. + @param dw_error + A place to return error details. + @return + Returns DW_DLV_OK and sets dw_return_offset + and dw_offset_is_info. + If attribute is passed in NULL or + the attribute is badly broken or + the FORM of this attribute is not one of the + many reference types the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY; +*/ +DW_API int dwarf_global_formref_b(Dwarf_Attribute dw_attr, + Dwarf_Off *dw_return_offset, + Dwarf_Bool *dw_offset_is_info, + Dwarf_Error *dw_error); + +/*! @brief Same as dwarf_global_formref_b except... + + @see dwarf_global_formref_b + + This is the same, except there is no + dw_offset_is_info pointer so in the case of + DWARF4 and DW_FORM_ref_sig8 it is not + possible to determine which section the offset + applies to! +*/ +DW_API int dwarf_global_formref(Dwarf_Attribute dw_attr, + Dwarf_Off* dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Return an 8 byte reference form for DW_FORM_ref_sig8 + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_sig_bytes + On success returns DW_DLV_OK and copies the 8 bytes + into dw_returned_sig_bytes. + @param dw_error + A place to return error details. + @return + On success returns DW_DLV_OK and copies the 8 bytes + into dw_returned_sig_bytes. + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + If the dw_attr has a form other than DW_FORM_ref_sig8 + the function returns DW_DLV_NO_ENTRY +*/ +DW_API int dwarf_formsig8(Dwarf_Attribute dw_attr, + Dwarf_Sig8 * dw_returned_sig_bytes, + Dwarf_Error* dw_error); + +/*! @brief Return an 8 byte reference form for DW_FORM_data8 + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_sig_bytes + On success Returns DW_DLV_OK and copies the 8 bytes + into dw_returned_sig_bytes. + @param dw_error + A place to return error details. + @return + On success returns DW_DLV_OK and copies the 8 bytes + into dw_returned_sig_bytes. + If attribute is passed in NULL or + the attribute is badly broken + the call returns DW_DLV_ERROR. + If the dw_attr has a form other than DW_FORM_data8 + the function returns DW_DLV_NO_ENTRY +*/ +DW_API int dwarf_formsig8_const(Dwarf_Attribute dw_attr, + Dwarf_Sig8 * dw_returned_sig_bytes, + Dwarf_Error* dw_error); + +/*! @brief Return the address when the attribute has form address. + + There are several address forms, some of them indexed. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_addr + On success this set through the pointer to + the address in the attribute. + @param dw_error + A place to return error details. + @return + On success returns DW_DLV_OK sets dw_returned_addr . + If attribute is passed in NULL or + the attribute is badly broken + or the address cannot be retrieved + the call returns DW_DLV_ERROR. + Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formaddr(Dwarf_Attribute dw_attr, + Dwarf_Addr * dw_returned_addr, + Dwarf_Error* dw_error); + +/*! @brief Get the addr index of a Dwarf_Attribute + + So a consumer can get the index when + the object with the actual .debug_addr section is + elsewhere (Debug Fission). Or if the caller just wants the index. + Only call it when you know it should does have an index + address FORM such as DW_FORM_addrx1 or one of the GNU + address index forms. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_return_index + If successful it returns the index + through the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_debug_addr_index(Dwarf_Attribute dw_attr, + Dwarf_Unsigned * dw_return_index, + Dwarf_Error * dw_error); + +/*! @brief Return the flag value of a flag form. + + It is an error if the FORM is not a flag form. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_bool + Returns either TRUE or FALSE through the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formflag(Dwarf_Attribute dw_attr, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error* dw_error); + +/*! @brief Return an unsigned value + + The form can be an unsigned or signed integral type + but if it is a signed type the value must be non-negative. + It is an error otherwise. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_val + On success returns the unsigned value through the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formudata(Dwarf_Attribute dw_attr, + Dwarf_Unsigned * dw_returned_val, + Dwarf_Error* dw_error); + +/*! @brief Return a signed value + + The form must be a signed integral type. + It is an error otherwise. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_val + On success returns the signed value through the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formsdata(Dwarf_Attribute dw_attr, + Dwarf_Signed * dw_returned_val, + Dwarf_Error* dw_error); + +/*! @brief Return a 16 byte Dwarf_Form_Data16 value. + + We just store the bytes in a struct, we have no + 16 byte integer type. + It is an error if the FORM is not DW_FORM_data16 + @see Dwarf_Form_Data16 + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_val + Copies the 16 byte value into the pointed + to area. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formdata16(Dwarf_Attribute dw_attr, + Dwarf_Form_Data16 * dw_returned_val, + Dwarf_Error* dw_error); + +/*! @brief Return an allocated filled-in Form_Block + + It is an error if the DW_FORM in the attribute is not a + block form. DW_FORM_block2 is an example of a block form. + + @see Dwarf_Block + @see examplediscrlist + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_block + Allocates a Dwarf_Block and returns + a pointer to the filled-in block. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. Never returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_formblock(Dwarf_Attribute dw_attr, + Dwarf_Block ** dw_returned_block, + Dwarf_Error* dw_error); + +/*! @brief Return a pointer to a string. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_returned_string + Puts a pointer to a string in the DWARF information + if the FORM of the attribute is some sort of string FORM. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_formstring(Dwarf_Attribute dw_attr, + char ** dw_returned_string, + Dwarf_Error* dw_error); + +/*! @brief Return a string index + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_return_index + If the form is a string index form (for example + DW_FORM_strx) the string index value is + returned via the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + If the attribute form is not one of the string index + forms it returns DW_DLV_ERROR and sets dw_error to point + to the error details. +*/ +DW_API int dwarf_get_debug_str_index(Dwarf_Attribute dw_attr, + Dwarf_Unsigned * dw_return_index, + Dwarf_Error * dw_error); + +/*! @brief Return a pointer-to and length-of a block of data. + + @param dw_attr + The Dwarf_Attribute of interest. + @param dw_return_exprlen + Returns the length in bytes of the block + if it succeeds. + @param dw_block_ptr + Returns a pointer to the first byte of the block + of data if it succeeds. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + If the attribute form is not DW_FORM_exprloc + it returns DW_DLV_ERROR and sets dw_error to point + to the error details. +*/ +DW_API int dwarf_formexprloc(Dwarf_Attribute dw_attr, + Dwarf_Unsigned * dw_return_exprlen, + Dwarf_Ptr * dw_block_ptr, + Dwarf_Error * dw_error); + +/*! @brief Return the FORM_CLASS applicable. + Four pieces of information are necessary + to get the correct FORM_CLASS. + + @param dw_version + The CU's DWARF version. Standard numbers are 2,3,4, or 5. + @param dw_attrnum + For example DW_AT_name + @param dw_offset_size + The offset size applicable to the compilation unit + relevant to the attribute and form. + @param dw_form + The FORM number, for example DW_FORM_data4 + @return + Returns a form class, for example DW_FORM_CLASS_CONSTANT. + The FORM_CLASS names are mentioned (for example + as 'address' in Table 2.3 of DWARF5) but + are not assigned formal names & numbers in the standard. +*/ +DW_API enum Dwarf_Form_Class dwarf_get_form_class( + Dwarf_Half dw_version, + Dwarf_Half dw_attrnum, + Dwarf_Half dw_offset_size, + Dwarf_Half dw_form); + +/*! @brief Return the offset of an attribute in its section + + @param dw_die + The DIE of interest. + @param dw_attr + A Dwarf_Attribute of interest in this DIE + @param dw_return_offset + The offset is in .debug_info if the DIE is there. + The offset is in .debug_types if the DIE is there. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + DW_DLV_NO_ENTRY is impossible. +*/ +DW_API int dwarf_attr_offset(Dwarf_Die dw_die, + Dwarf_Attribute dw_attr, + Dwarf_Off * dw_return_offset, + Dwarf_Error * dw_error); + +/*! @brief Uncompress a block of sleb numbers + It's not much of a compression so not much + of an uncompression. + Developed by Sun Microsystems and it is unclear if it + was ever used. + @see dwarf_dealloc_uncompressed_block +*/ +DW_API int dwarf_uncompress_integer_block_a(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_input_length_in_bytes, + void * dw_input_block, + Dwarf_Unsigned * dw_value_count, + Dwarf_Signed ** dw_value_array, + Dwarf_Error * dw_error); + +/*! @brief Dealloc what dwarf_uncompress_integer_block_a allocated + @param dw_dbg + The Dwarf_Debug of interest + @param dw_value_array + The array was called an array of Dwarf_Signed. + We dealloc all of it without needing dw_value_count. +*/ +DW_API void dwarf_dealloc_uncompressed_block(Dwarf_Debug dw_dbg, + void *dw_value_array); + +/*! @brief Convert local offset to global offset + + Uses the DW_FORM of the attribute to determine + if the dw_offset is local, and if so, adds + the CU base offset to adjust dw_offset. + + @param dw_attr + The attribute the local offset was extracted from. + @param dw_offset + The global offset of the attribute. + @param dw_return_offset + The returned section (global) offset. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + Returns DW_DLV_ERROR if the dw_attr form is not + an offset form (for example, DW_FORM_ref_udata). +*/ +DW_API int dwarf_convert_to_global_offset(Dwarf_Attribute dw_attr, + Dwarf_Off dw_offset, + Dwarf_Off* dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Dealloc a Dwarf_Attribute + When this call returns the dw_attr is a stale pointer. + @param dw_attr + The attribute to dealloc. +*/ +DW_API void dwarf_dealloc_attribute(Dwarf_Attribute dw_attr); + +/*! @brief Return an array of discriminant values. + + This applies if a DW_TAG_variant has one of the + DW_FORM_block forms. + @see dwarf_formblock + + For an example of use and dealloc: + @see examplediscrlist + + @param dw_dbg + The applicable Dwarf_Debug + @param dw_blockpointer + The bl_data value from a Dwarf_Block. + @param dw_blocklen + The bl_len value from a Dwarf_Block. + @param dw_dsc_head_out + On success returns a pointer to an array + of discriminant values in an opaque struct. + @param dw_dsc_array_length_out + On success returns the number of entries + in the dw_dsc_head_out array. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_discr_list(Dwarf_Debug dw_dbg, + Dwarf_Small * dw_blockpointer, + Dwarf_Unsigned dw_blocklen, + Dwarf_Dsc_Head * dw_dsc_head_out, + Dwarf_Unsigned * dw_dsc_array_length_out, + Dwarf_Error * dw_error); + +/*! @brief Access a single unsigned discriminant list entry + + It is up to the caller to know whether the discriminant + values are signed or unsigned (therefore to know + whether this or dwarf_discr_entry_s. + should be called) + + @param dw_dsc + The Dwarf_Dsc_Head applicable. + @param dw_entrynum + Valid values are zero to dw_dsc_array_length_out-1 + @param dw_out_type + On success is set to either DW_DSC_label or + DW_DSC_range through the pointer. + @param dw_out_discr_low + On success set to + the lowest in this discriminant range + @param dw_out_discr_high + On success set to + the highest in this discriminant range + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_discr_entry_u(Dwarf_Dsc_Head dw_dsc, + Dwarf_Unsigned dw_entrynum, + Dwarf_Half * dw_out_type, + Dwarf_Unsigned * dw_out_discr_low, + Dwarf_Unsigned * dw_out_discr_high, + Dwarf_Error * dw_error); + +/*! @brief Access to a single signed discriminant list entry + + The same as dwarf_discr_entry_u except here the values + are signed. +*/ +DW_API int dwarf_discr_entry_s(Dwarf_Dsc_Head dw_dsc, + Dwarf_Unsigned dw_entrynum, + Dwarf_Half * dw_out_type, + Dwarf_Signed * dw_out_discr_low, + Dwarf_Signed * dw_out_discr_high, + Dwarf_Error * dw_error); + +/*! @} */ + +/*! @defgroup linetable Line Table For a CU + @{ + Access to all the line table details. +*/ + +/*! @brief The list of source files from the line table header + + @param dw_cu_die + The CU DIE in this CU. + @param dw_srcfiles + On success allocates an array of pointers to strings + and for each such, computes the fullest path possible + given the CU DIE data for each file name listed + in the line table header. + @param dw_filecount + On success returns the number of entries + in the array of pointers to strings. + The number returned is non-negative. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + If there is no .debug_line[.dwo] returns DW_DLV_NO_ENTRY. + + @see examplee + +*/ +DW_API int dwarf_srcfiles(Dwarf_Die dw_cu_die, + char *** dw_srcfiles, + Dwarf_Signed * dw_filecount, + Dwarf_Error * dw_error); + +/*! @brief Initialize Dwarf_Line_Context for line table access + + Returns Dwarf_Line_Context pointer, needed for + access to line table data. + + @see exampled + + @param dw_cudie + The Compilation Unit (CU) DIE of interest. + @param dw_version_out + The DWARF Line Table version number (Standard: 2,3,4, or 5) + Version 0xf006 is an experimental (two-level) line table. + @param dw_table_count + Zero or one means this is a normal DWARF line table. + Two means this is an experimental two-level line table. + @param dw_linecontext + On success sets the pointer to point to an opaque structure + usable for further queries. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_b(Dwarf_Die dw_cudie, + Dwarf_Unsigned * dw_version_out, + Dwarf_Small * dw_table_count, + Dwarf_Line_Context * dw_linecontext, + Dwarf_Error * dw_error); + +/*! @brief Access source lines from line context + + The access to Dwarf_Line data from + a Dwarf_Line_Context on a standard line table. + + @param dw_linecontext + The line context of interest. + @param dw_linebuf + On success returns + an array of pointers to Dwarf_Line. + @param dw_linecount + On success returns the count of entries + in dw_linebuf. + If dw_linecount is returned as zero this is + a line table with no lines. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_from_linecontext( + Dwarf_Line_Context dw_linecontext, + Dwarf_Line ** dw_linebuf, + Dwarf_Signed * dw_linecount, + Dwarf_Error * dw_error); + +/*! @brief Returns line table counts and data + + Works for DWARF2,3,4,5 and for experimental + two-level line tables. A single level table will + have *linebuf_actuals and *linecount_actuals set + to 0. + + Two-level line tables are non-standard and not + documented further. + For standard (one-level) tables, it + will return the single table through dw_linebuf, and the + value returned through dw_linecount_actuals will be 0. + + People not using these two-level tables + should dwarf_srclines_from_linecontext instead. +*/ +DW_API int dwarf_srclines_two_level_from_linecontext( + Dwarf_Line_Context dw_context, + Dwarf_Line ** dw_linebuf , + Dwarf_Signed * dw_linecount, + Dwarf_Line ** dw_linebuf_actuals, + Dwarf_Signed * dw_linecount_actuals, + Dwarf_Error * dw_error); + +/*! @brief Dealloc the memory allocated by dwarf_srclines_b + + The way to deallocate (free) a Dwarf_Line_Context + + @param dw_context + The context to be dealloced (freed). + On return the pointer passed in is stale and + calling applications should zero the pointer. +*/ +DW_API void dwarf_srclines_dealloc_b(Dwarf_Line_Context dw_context); + +/*! @brief Return the srclines table offset + + The offset is in the relevant .debug_line or .debug_line.dwo + section (and in a split dwarf package file includes + the base line table offset). + + @param dw_context + @param dw_offset + On success returns the section offset of the + dw_context. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_table_offset(Dwarf_Line_Context dw_context, + Dwarf_Unsigned * dw_offset, + Dwarf_Error * dw_error); + +/*! @brief Compilation Directory name for the CU + + Do not free() or dealloc the string, + it is in a dwarf section. + + @param dw_context + The Line Context of interest. + @param dw_compilation_directory + On success returns a pointer to a string + identifying the compilation directory of the CU. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_comp_dir(Dwarf_Line_Context dw_context, + const char ** dw_compilation_directory, + Dwarf_Error * dw_error); + +/*! @brief Subprog count: Part of the two-level line table extension. + + A non-standard table. + The actual meaning of subprog count left undefined here. + + @param dw_context + The Dwarf_Line_Context of interest. + @param dw_count + On success returns the two-level line table subprogram + array size in this line context. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_subprog_count(Dwarf_Line_Context dw_context, + Dwarf_Signed * dw_count, + Dwarf_Error * dw_error); + +/*! @brief Retrieve data from the line table subprog array + + A non-standard table. Not defined here. + @param dw_context + The Dwarf_Line_Context of interest. + @param dw_index + The item to retrieve. Valid indexes are 1 through dw_count. + @param dw_name + On success returns a pointer to the subprog name. + @param dw_decl_file + On success returns a file number through the pointer. + @param dw_decl_line + On success returns a line number through the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_subprog_data(Dwarf_Line_Context dw_context, + Dwarf_Signed dw_index, + const char ** dw_name, + Dwarf_Unsigned * dw_decl_file, + Dwarf_Unsigned * dw_decl_line, + Dwarf_Error * dw_error); + +/*! @brief Return values easing indexing line table file numbers. + Count is the real count of files array entries. + Since DWARF 2,3,4 are zero origin indexes and + DWARF5 and later are one origin, this function + replaces dwarf_srclines_files_count(). + @param dw_context + The line context of interest. + @param dw_baseindex + On success returns the base index of valid file indexes. + With DWARF2,3,4 the value is 1. With DWARF5 the + value is 0. + @param dw_count + On success returns the real count of entries. + @param dw_endindex + On success returns value such that + callers should index as dw_baseindex through + dw_endindex-1. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + + @see examplec +*/ +DW_API int dwarf_srclines_files_indexes( + Dwarf_Line_Context dw_context, + Dwarf_Signed * dw_baseindex, + Dwarf_Signed * dw_count, + Dwarf_Signed * dw_endindex, + Dwarf_Error * dw_error); + +/*! @brief Access data for each line table file. + + Has the md5ptr field so cases where DW_LNCT_MD5 + is present can return pointer to the MD5 value. + With DWARF 5 index starts with 0. + dwarf_srclines_files_indexes makes + indexing through the files easy. + + @see dwarf_srclines_files_indexes + @see examplec + + @param dw_context + The line context of interest. + @param dw_index_in + The entry of interest. + Callers should index as dw_baseindex through + dw_endindex-1. + @param dw_name + If dw_name non-null + on success returns + The file name in the line table header + through the pointer. + @param dw_directory_index + If dw_directory_index non-null + on success returns + the directory number in the line table header + through the pointer. + @param dw_last_mod_time + If dw_last_mod_time non-null + on success returns + the directory last modification date/time + through the pointer. + @param dw_file_length + If dw_file_length non-null + on success returns + the file length recorded in the line table + through the pointer. + @param dw_md5ptr + If dw_md5ptr non-null + on success returns + a pointer to the 16byte MD5 hash + of the file + through the pointer. + If there is no md5 value present it returns 0 through + the pointer. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + + @see examplec +*/ +DW_API int dwarf_srclines_files_data_b( + Dwarf_Line_Context dw_context, + Dwarf_Signed dw_index_in, + const char ** dw_name, + Dwarf_Unsigned * dw_directory_index, + Dwarf_Unsigned * dw_last_mod_time, + Dwarf_Unsigned * dw_file_length, + Dwarf_Form_Data16 ** dw_md5ptr, + Dwarf_Error * dw_error); + +/*! @brief Return the number of include directories in the Line Table + + @param dw_line_context + The line context of interest. + @param dw_count + On success returns the count of directories. + How to use this depends on the line table version number. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + + @see dwarf_srclines_include_dir_data +*/ +DW_API int dwarf_srclines_include_dir_count( + Dwarf_Line_Context dw_line_context, + Dwarf_Signed * dw_count, + Dwarf_Error * dw_error); + +/*! @brief Return the include directories in the Line Table + + @param dw_line_context + The line context of interest. + @param dw_index + Pass in an index to the line context list of include + directories. + If the line table is version 2,3, or 4, the + valid indexes are 1 through dw_count. + If the line table is version 5 the + valid indexes are 0 through dw_count-1. + @param dw_name + On success it returns a pointer to a directory name. + Do not free/deallocate the string. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. + + @see dwarf_srclines_include_dir_count +*/ + +DW_API int dwarf_srclines_include_dir_data( + Dwarf_Line_Context dw_line_context, + Dwarf_Signed dw_index, + const char ** dw_name, + Dwarf_Error * dw_error); + +/*! @brief The DWARF version number of this compile-unit + The .debug_lines[.dwo] t + actual tables:0 (header with no lines), + 1 (standard table), or 2 (experimental). + + @param dw_line_context + The Line Context of interest. + @param dw_version + On success, returns + the line table version through the pointer. + @param dw_table_count + On success, returns + the tablecount through the pointer. + If the table count is zero the line table is a header + with no lines. If the table count is 1 this is a standard + line table. If the table count is this is an experimental + two-level line table. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_srclines_version(Dwarf_Line_Context dw_line_context, + Dwarf_Unsigned * dw_version, + Dwarf_Small * dw_table_count, + Dwarf_Error * dw_error); + +/*! @brief Read Line beginstatement register + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_bool + On success it sets the value TRUE (if the dw_line + has the is_stmt register set) and FALSE if is_stmt + is not set. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_linebeginstatement(Dwarf_Line dw_line, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error * dw_error); + +/*! @brief Read Line endsequence register flag + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_bool + On success it sets the value TRUE (if the dw_line + has the end_sequence register set) and FALSE if end_sequence + is not set. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_lineendsequence(Dwarf_Line dw_line, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error * dw_error); + +/*! @brief Read Line line register + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_linenum + On success it sets the value to the line number + from the Dwarf_Line line register + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_lineno(Dwarf_Line dw_line, + Dwarf_Unsigned * dw_returned_linenum, + Dwarf_Error * dw_error); + +/*! @brief Read Line file register + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_filenum + On success it sets the value to the file number + from the Dwarf_Line file register + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_line_srcfileno(Dwarf_Line dw_line, + Dwarf_Unsigned * dw_returned_filenum, + Dwarf_Error * dw_error); + +/*! @brief Is the Dwarf_Line address from DW_LNS_set_address? + This is not a line register, but it is a flag set + by the library in each Dwarf_Line, and it + is derived from reading the line table. + @param dw_line + The Dwarf_Line of interest. + @param dw_is_addr_set + On success it sets the flag to TRUE or FALSE. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_line_is_addr_set(Dwarf_Line dw_line, + Dwarf_Bool * dw_is_addr_set, + Dwarf_Error * dw_error); + +/*! @brief Return the address of the Dwarf_Line + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_addr + On success it sets the value to the value of + the address register in the Dwarf_Line. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_lineaddr(Dwarf_Line dw_line, + Dwarf_Addr * dw_returned_addr, + Dwarf_Error* dw_error); + +/*! @brief Return a column number through the pointer + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_lineoffset + On success it sets the value to the column + register from the Dwarf_Line. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_lineoff_b(Dwarf_Line dw_line, + Dwarf_Unsigned * dw_returned_lineoffset, + Dwarf_Error* dw_error); + +/*! @brief Return the file name applicable to the Dwarf_Line + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_name + On success it reads the file register and finds + the source file name from the line table header + and returns a pointer to that file name string + through the pointer. + @param dw_error + The usual error pointer. + Do not dealloc or free the string. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_linesrc(Dwarf_Line dw_line, + char ** dw_returned_name, + Dwarf_Error* dw_error); + +/*! @brief Return the basic_block line register. + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_returned_bool + On success it sets the flag to TRUE or FALSE + from the basic_block register in the line table. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_lineblock(Dwarf_Line dw_line, + Dwarf_Bool * dw_returned_bool, + Dwarf_Error* dw_error); + +/* We gather these into one call as it's likely one + will want all or none of them. */ +/*! @brief Return various line table registers in one call + + @link dwsec_linetabreg Link to Line Table Registers @endlink + + @param dw_line + The Dwarf_Line of interest. + @param dw_prologue_end + On success it sets the flag to TRUE or FALSE + from the prologue_end register in the line table. + @param dw_epilogue_begin + On success it sets the flag to TRUE or FALSE + from the epilogue_begin register in the line table. + @param dw_isa + On success it sets the value to the value of + from the isa register in the line table. + @param dw_discriminator + On success it sets the value to the value of + from the discriminator register in the line table. + @param dw_error + The usual error pointer. + @return + DW_DLV_OK if it succeeds. +*/ +DW_API int dwarf_prologue_end_etc(Dwarf_Line dw_line, + Dwarf_Bool * dw_prologue_end, + Dwarf_Bool * dw_epilogue_begin, + Dwarf_Unsigned * dw_isa, + Dwarf_Unsigned * dw_discriminator, + Dwarf_Error * dw_error); +/* End line table operations */ + +/*! @brief Experimental Two-level logical Row Number + Experimental two level line tables. Not explained here. + When reading from an actuals table, dwarf_line_logical() + returns the logical row number for the line. +*/ +DW_API int dwarf_linelogical(Dwarf_Line dw_line, + Dwarf_Unsigned * dw_returned_logical, + Dwarf_Error* dw_error); + +/*! @brief Experimental Two-level line tables call contexts + Experimental two level line tables. Not explained here. + When reading from a logicals table, dwarf_linecontext() + returns the logical row number corresponding the the + calling context for an inlined call. +*/ +DW_API int dwarf_linecontext(Dwarf_Line dw_line, + Dwarf_Unsigned * dw_returned_context, + Dwarf_Error* dw_error); + +/*! @brief Two-level line tables get subprogram number + Experimental two level line tables. Not explained here. + When reading from a logicals table, dwarf_line_subprogno() + returns the index in the subprograms table of the inlined + subprogram. Currently this always returns + zero through the pointer as the relevant field + is never updated from the default of zero. +*/ +DW_API int dwarf_line_subprogno(Dwarf_Line /*line*/, + Dwarf_Unsigned * /*ret_subprogno*/, + Dwarf_Error * /*error*/); + +/*! @brief Two-level line tables get subprog, file, line + Experimental two level line tables. Not explained here. + When reading from a logicals table, dwarf_line_subprog() + returns the name of the inlined subprogram, its declaration + filename, and its declaration line number, if available. +*/ +DW_API int dwarf_line_subprog(Dwarf_Line /*line*/, + char ** /*returned_subprog_name*/, + char ** /*returned_filename*/, + Dwarf_Unsigned * /*returned_lineno*/, + Dwarf_Error * /*error*/); + +/*! @brief Access to detailed line table header issues. + + Lets the caller get detailed messages + about some compiler errors we detect. + Calls back, the caller should do something + with the messages (likely just print them). + The lines passed back already have newlines. + + @see dwarf_check_lineheader + @see Dwarf_Printf_Callback_Info_s + + @param dw_cu_die + The CU DIE of interest + @param dw_error + If DW_DLV_ERROR this shows one error encountered. + @param dw_errcount_out + Returns the count of detected errors through the pointer. + @return + DW_DLV_OK etc. +*/ +DW_API int dwarf_check_lineheader_b(Dwarf_Die dw_cu_die, + int * dw_errcount_out, + Dwarf_Error * dw_error); + +/*! @brief Print line information in great detail. + + dwarf_print_lines lets the caller + prints line information + for a CU in great detail. + Does not use printf. + Instead it calls back to the application using a function + pointer once per line-to-print. The lines passed back + already have any needed + newlines. + + Failing to call the dwarf_register_printf_callback() + function will prevent the lines from being passed back + but such omission is not an error. + the same function, but focused on checking for errors + is + @see dwarf_check_lineheader_b + @see Dwarf_Printf_Callback_Info_s + + @param dw_cu_die + The CU DIE of interest + @param dw_error + @param dw_errorcount_out + @return + DW_DLV_OK etc. + +*/ +DW_API int dwarf_print_lines(Dwarf_Die dw_cu_die, + Dwarf_Error * dw_error, + int * dw_errorcount_out); + +/*! @brief For line details this records callback details + + For the structure you must fill in: + @see Dwarf_Printf_Callback_Info_s + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_callbackinfo + If non-NULL pass in a pointer to your + instance of struct Dwarf_Printf_Callback_Info_s + with all the fields filled in. + @return + If dw_callbackinfo NULL it returns a copy + of the current Dwarf_Printf_Callback_Info_s for dw_dbg. + Otherwise it returns the previous contents of the + struct. +*/ +DW_API struct Dwarf_Printf_Callback_Info_s + dwarf_register_printf_callback(Dwarf_Debug dw_dbg, + struct Dwarf_Printf_Callback_Info_s * dw_callbackinfo); + +/*! @} */ +/*! @defgroup ranges Ranges: code addresses in DWARF3-4 + + @{ + + In DWARF3 and DWARF4 the DW_AT_ranges attribute + provides an offset into the .debug_ranges section, + which contains code address ranges. + + @see Dwarf_Ranges + + DWARF3 and DWARF4. + DW_AT_ranges with an unsigned constant FORM (DWARF3) + or DW_FORM_sec_offset(DWARF4). + +*/ +/*! @brief Access to code ranges from a CU or just + reading through the raw .debug_ranges section. + + Adds return of the dw_realoffset to accommodate + DWARF4 GNU split-dwarf, where the ranges could + be in the tieddbg (meaning the real executable, a.out, not + in a dwp). DWARF4 split-dwarf is an extension, not + standard DWARF4. + + If printing all entries in the section pass + in an initial dw_rangesoffset of zero and dw_die of NULL. + Then increment dw_rangesoffset by dw_bytecount and call + again to get the next batch of ranges. + With a specific option dwarfdump can do this. + This not a normal thing to do! + + @see examplev + + @param dw_dbg + The Dwarf_Debug of interest + @param dw_rangesoffset + The offset to read from in the section. + @param dw_die + Pass in the DIE whose DW_AT_ranges brought us to ranges. + @param dw_return_realoffset + The actual offset in the section actually read. + In a tieddbg this + @param dw_rangesbuf + A pointer to an array of structs is returned here. + @param dw_rangecount + The count of structs in the array is returned here. + @param dw_bytecount + The number of bytes in the .debug_ranges section + applying to the returned array. This makes possible + just marching through the section by offset. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_ranges_b(Dwarf_Debug dw_dbg, + Dwarf_Off dw_rangesoffset, + Dwarf_Die dw_die, + Dwarf_Off * dw_return_realoffset, + Dwarf_Ranges ** dw_rangesbuf, + Dwarf_Signed * dw_rangecount, + Dwarf_Unsigned * dw_bytecount, + Dwarf_Error * dw_error); + +/*! @brief Dealloc the array dw_rangesbuf + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_rangesbuf + The dw_rangesbuf pointer returned by dwarf_get_ranges_b + @param dw_rangecount + The dw_rangecount returned by dwarf_get_ranges_b +*/ +DW_API void dwarf_dealloc_ranges(Dwarf_Debug dw_dbg, + Dwarf_Ranges * dw_rangesbuf, + Dwarf_Signed dw_rangecount); +/*! @} */ + +/*! @defgroup rnglists Rnglists: code addresses in DWARF5 + + @{ + + Used in DWARF5 to define valid address ranges for + code. + + DW_FORM_rnglistx or + DW_AT_ranges with DW_FORM_sec_offset +*/ + +/*! @brief Get Access to DWARF5 rnglists + + Opens a Dwarf_Rnglists_Head to access a set of + DWARF5 rangelists .debug_rnglists + DW_FORM_sec_offset DW_FORM_rnglistx + (DW_AT_ranges in DWARF5). + + @see example_rnglist_for_attribute + + @param dw_attr + The attribute referring to .debug_rnglists + @param dw_theform + The form number, DW_FORM_sec_offset or + DW_FORM_rnglistx. + @param dw_index_or_offset_value + If the form is an index, pass it here. + If the form is an offset, pass that here. + @param dw_head_out + On success creates a record owning the + rnglists data for this attribute. + @param dw_count_of_entries_in_head + On success this is set to the number of + entry in the rnglists for this attribute. + @param dw_global_offset_of_rle_set + On success set to the global offset of the rnglists + in the rnglists section. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_rnglists_get_rle_head(Dwarf_Attribute dw_attr, + Dwarf_Half dw_theform, + Dwarf_Unsigned dw_index_or_offset_value, + Dwarf_Rnglists_Head * dw_head_out, + Dwarf_Unsigned * dw_count_of_entries_in_head, + Dwarf_Unsigned * dw_global_offset_of_rle_set, + Dwarf_Error * dw_error); + +/*! @brief Access rnglist entry details. + + @see example_rnglist_for_attribute + + @param dw_head + The Dwarf_Rnglists_Head of interest. + @param dw_entrynum + Valid values are 0 through dw_count_of_entries_in_head-1. + @param dw_entrylen + On success returns + the length in bytes of this individual entry. + @param dw_rle_value_out + On success returns + the RLE value of the entry, such as DW_RLE_startx_endx. + This determines which of dw_raw1 and dw_raw2 + contain meaningful data. + @param dw_raw1 + On success returns + a value directly recorded in the rangelist entry + if that applies to this rle. + @param dw_raw2 + On success returns + a value directly recorded in the rangelist entry + if that applies to this rle. + @param dw_debug_addr_unavailable + On success returns a flag. + If the .debug_addr section is required but absent or + unavailable the flag is set to TRUE. + Otherwise sets the flag FALSE. + @param dw_cooked1 + On success returns (if appropriate) the + dw_raw1 value turned into a valid address. + @param dw_cooked2 + On success returns (if appropriate) the + dw_raw2 value turned into a valid address. + Ignore the value if dw_debug_addr_unavailable is set. + @param dw_error + The usual error detail return pointer. + Ignore the value if dw_debug_addr_unavailable is set. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_rnglists_entry_fields_a( + Dwarf_Rnglists_Head dw_head, + Dwarf_Unsigned dw_entrynum, + unsigned int * dw_entrylen, + unsigned int * dw_rle_value_out, + Dwarf_Unsigned * dw_raw1, + Dwarf_Unsigned * dw_raw2, + Dwarf_Bool * dw_debug_addr_unavailable, + Dwarf_Unsigned * dw_cooked1, + Dwarf_Unsigned * dw_cooked2, + Dwarf_Error * dw_error); + +/*! @brief Dealloc a Dwarf_Rnglists_Head + + @param dw_head + dealloc all the memory associated with dw_head. + The caller should then immediately set + the pointer to zero/NULL as it is stale. +*/ +DW_API void dwarf_dealloc_rnglists_head(Dwarf_Rnglists_Head dw_head); + +/*! @brief Loads all .debug_rnglists headers. + + Loads all the rnglists headers and + returns DW_DLV_NO_ENTRY if the section + is missing or empty. + Intended to be done quite early. + It is automatically done if anything + needing CU or DIE information is called, + so it is not necessary for you to call this + in any normal situation. + + @see example_raw_rnglist + + Doing it more than once is never necessary + or harmful. There is no deallocation call + made visible, deallocation happens + when dwarf_finish() is called. + + @param dw_dbg + @param dw_rnglists_count + On success it returns the number of + rnglists headers in the section through + dw_rnglists_count. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If the section does not exist the function returns + DW_DLV_OK. +*/ +DW_API int dwarf_load_rnglists(Dwarf_Debug dw_dbg, + Dwarf_Unsigned * dw_rnglists_count, + Dwarf_Error * dw_error); + +/*! @brief Retrieve the section offset of a rnglist. + + Can be used to access raw rnglist data. + Not used by most callers. + See DWARF5 Section 7.28 Range List Table Page 242 + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_context_index + Begin this at zero. + @param dw_offsetentry_index + Begin this at zero. + @param dw_offset_value_out + On success returns the rangelist entry + offset within the rangelist set. + @param dw_global_offset_value_out + On success returns the rangelist entry + offset within rnglist section. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If there are no rnglists at all, or + if one of the above index values is too high + to be valid it returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_rnglist_offset_index_value(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_context_index, + Dwarf_Unsigned dw_offsetentry_index, + Dwarf_Unsigned * dw_offset_value_out, + Dwarf_Unsigned * dw_global_offset_value_out, + Dwarf_Error * dw_error); + +/*! @brief Access to internal data on rangelists. + + Returns detailed data from a Dwarf_Rnglists_Head + Since this is primarily internal data we don't + describe the details of the returned fields here. +*/ +DW_API int dwarf_get_rnglist_head_basics(Dwarf_Rnglists_Head dw_head, + Dwarf_Unsigned * dw_rle_count, + Dwarf_Unsigned * dw_rnglists_version, + Dwarf_Unsigned * dw_rnglists_index_returned, + Dwarf_Unsigned * dw_bytes_total_in_rle, + Dwarf_Half * dw_offset_size, + Dwarf_Half * dw_address_size, + Dwarf_Half * dw_segment_selector_size, + Dwarf_Unsigned * dw_overall_offset_of_this_context, + Dwarf_Unsigned * dw_total_length_of_this_context, + Dwarf_Unsigned * dw_offset_table_offset, + Dwarf_Unsigned * dw_offset_table_entrycount, + Dwarf_Bool * dw_rnglists_base_present, + Dwarf_Unsigned * dw_rnglists_base, + Dwarf_Bool * dw_rnglists_base_address_present, + Dwarf_Unsigned * dw_rnglists_base_address, + Dwarf_Bool * dw_rnglists_debug_addr_base_present, + Dwarf_Unsigned * dw_rnglists_debug_addr_base, + Dwarf_Error * dw_error); + +/*! @brief Access to rnglists header data + + This returns, independent of any DIEs or CUs + information on the .debug_rnglists headers + present in the section. + + We do not document the details here. + See the DWARF5 standard. + + Enables printing of details about the Range List Table + Headers, one header per call. Index starting at 0. + Returns DW_DLV_NO_ENTRY if index is too high for the table. + A .debug_rnglists section may contain any number + of Range List Table Headers with their details. +*/ +DW_API int dwarf_get_rnglist_context_basics(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_index, + Dwarf_Unsigned * dw_header_offset, + Dwarf_Small * dw_offset_size, + Dwarf_Small * dw_extension_size, + unsigned int * dw_version, + Dwarf_Small * dw_address_size, + Dwarf_Small * dw_segment_selector_size, + Dwarf_Unsigned * dw_offset_entry_count, + Dwarf_Unsigned * dw_offset_of_offset_array, + Dwarf_Unsigned * dw_offset_of_first_rangeentry, + Dwarf_Unsigned * dw_offset_past_last_rangeentry, + Dwarf_Error * dw_error); + +/*! @brief Access to raw rnglists range data + + Describes the actual raw data recorded in a particular + range entry. + + We do not describe all these fields for now, the + raw values are mostly useful for people debugging + compiler-generated DWARF. +*/ +DW_API int dwarf_get_rnglist_rle(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_contextnumber, + Dwarf_Unsigned dw_entry_offset, + Dwarf_Unsigned dw_endoffset, + unsigned int * dw_entrylen, + unsigned int * dw_entry_kind, + Dwarf_Unsigned * dw_entry_operand1, + Dwarf_Unsigned * dw_entry_operand2, + Dwarf_Error * dw_error); +/*! @} */ +/*! @defgroup locations Locations of data: DWARF2-DWARF5 + @{ +*/ +/*! @brief Location Lists and Expressions + + This works on DWARF2 through DWARF5. + + @see example_loclistcv5 + + @param dw_attr + The attribute must refer to a location expression + or a location list, so must be DW_FORM_block, + DW_FORM_exprloc, or a loclist reference form.. + @param dw_loclist_head + On success returns a pointer to the created + loclist head record. + @param dw_locentry_count + On success returns the count of records. + For an expression it will be one. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_loclist_c(Dwarf_Attribute dw_attr, + Dwarf_Loc_Head_c * dw_loclist_head, + Dwarf_Unsigned * dw_locentry_count, + Dwarf_Error * dw_error); + +#define DW_LKIND_expression 0 /* DWARF2,3,4,5 */ +#define DW_LKIND_loclist 1 /* DWARF 2,3,4 */ +#define DW_LKIND_GNU_exp_list 2 /* GNU DWARF4 .dwo extension */ +#define DW_LKIND_loclists 5 /* DWARF5 loclists */ +#define DW_LKIND_unknown 99 + +/*! @brief Know what kind of location data it is + + @param dw_loclist_head + Pass in a loclist head pointer. + @param dw_lkind + On success returns the loclist kind + through the pointer. For example DW_LKIND_expression. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_loclist_head_kind( + Dwarf_Loc_Head_c dw_loclist_head, + unsigned int * dw_lkind, + Dwarf_Error * dw_error); + +/*! @brief Retrieve the details of a location expression + + Cooked value means the addresses from the location + description after base values applied, so they + are actual addresses. + debug_addr_unavailable non-zero means the record from a + Split Dwarf skeleton unit could not be accessed from + the .dwo section or dwp object so the + cooked values could not be calculated. + + @param dw_loclist_head + A loclist head pointer. + @param dw_index + Pass in an index value less than dw_locentry_count . + @param dw_lle_value_out + On success returns the DW_LLE value applicable, such + as DW_LLE_start_end . + @param dw_rawlowpc + On success returns the first operand in the expression + (if the expression has an operand). + @param dw_rawhipc + On success returns the second operand in the expression. + (if the expression has a second operand). + @param dw_debug_addr_unavailable + On success returns FALSE if the data required to calculate + dw_lowpc_cooked or dw_hipc_cooked was present + or TRUE if some required + data was missing (for example in split dwarf). + @param dw_lowpc_cooked + On success and if dw_debug_addr_unavailable FALSE + returns the true low address. + @param dw_hipc_cooked + On success and if dw_debug_addr_unavailable FALSE + returns the true high address. + @param dw_locexpr_op_count_out + On success returns the count of operations + in the expression. + @param dw_locentry_out + On success returns a pointer to a specific location + description. + @param dw_loclist_source_out + On success returns the applicable DW_LKIND value. + @param dw_expression_offset_out + On success returns the offset of the expression + in the applicable section. + @param dw_locdesc_offset_out + On return sets the offset to the location description + offset (if that is meaningful) or zero for + simple location expressions. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_locdesc_entry_d(Dwarf_Loc_Head_c dw_loclist_head, + Dwarf_Unsigned dw_index, + Dwarf_Small * dw_lle_value_out, + Dwarf_Unsigned * dw_rawlowpc, + Dwarf_Unsigned * dw_rawhipc, + Dwarf_Bool * dw_debug_addr_unavailable, + Dwarf_Addr * dw_lowpc_cooked, + Dwarf_Addr * dw_hipc_cooked, + Dwarf_Unsigned * dw_locexpr_op_count_out, + Dwarf_Locdesc_c * dw_locentry_out, + Dwarf_Small * dw_loclist_source_out, + Dwarf_Unsigned * dw_expression_offset_out, + Dwarf_Unsigned * dw_locdesc_offset_out, + Dwarf_Error * dw_error); + +/*! @brief Get the raw values from a single location operation + + @param dw_locdesc + Pass in a valid Dwarf_Locdesc_c. + @param dw_index + Pass in the operator index. zero through + dw_locexpr_op_count_out-1. + @param dw_operator_out + On success returns the DW_OP operator, such as DW_OP_plus . + @param dw_operand1 + On success returns the value of the operand or zero. + @param dw_operand2 + On success returns the value of the operand or zero. + @param dw_operand3 + On success returns the value of the operand or zero. + @param dw_offset_for_branch + On success returns + The byte offset of the operator within the + entire expression. Useful for checking the correctness + of operators that branch.. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_location_op_value_c(Dwarf_Locdesc_c dw_locdesc, + Dwarf_Unsigned dw_index, + Dwarf_Small * dw_operator_out, + Dwarf_Unsigned * dw_operand1, + Dwarf_Unsigned * dw_operand2, + Dwarf_Unsigned * dw_operand3, + Dwarf_Unsigned * dw_offset_for_branch, + Dwarf_Error* dw_error); +/*! @brief Generate a Dwarf_Loc_Head_c from an expression block + + Useful if you have an expression block (from somewhere), + do not have a Dwarf_Attribute available, + and wish to deal with the expression. + + @see example_locexprc + + @param dw_dbg + The applicable Dwarf_Debug + @param dw_expression_in + Pass in a pointer to the expression bytes. + @param dw_expression_length + Pass in the length, in bytes, of the expression. + @param dw_address_size + Pass in the applicable address_size. + @param dw_offset_size + Pass in the applicable offset size. + @param dw_dwarf_version + Pass in the applicable dwarf version. + @param dw_loc_head + On success returns a pointer to a dwarf location + head record for use in getting to the details + of the expression. + @param dw_listlen + On success, sets the listlen to one. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_loclist_from_expr_c(Dwarf_Debug dw_dbg, + Dwarf_Ptr dw_expression_in, + Dwarf_Unsigned dw_expression_length, + Dwarf_Half dw_address_size, + Dwarf_Half dw_offset_size, + Dwarf_Small dw_dwarf_version, + Dwarf_Loc_Head_c* dw_loc_head, + Dwarf_Unsigned * dw_listlen, + Dwarf_Error * dw_error); + +/*! @brief Dealloc (free) all memory allocated for Dwarf_Loc_Head_c + @param dw_head + A head pointer. + + The caller should zero the passed-in pointer on return + as it is stale at that point. +*/ +DW_API void dwarf_dealloc_loc_head_c(Dwarf_Loc_Head_c dw_head); + +/* These interfaces allow reading the .debug_loclists + section. Independently of DIEs. + Normal use of .debug_loclists uses + dwarf_get_loclist_c() to open access to any kind of location + or loclist and uses dwarf_loc_head_c_dealloc() to + deallocate that memory once one is finished with + that data. So for most purposes you do not need + to use these functions + See dwarf_get_loclist_c() to open a Dwarf_Loc_Head_c + on any type of location list or expression. */ + +/* Loads all the loclists headers and + returns DW_DLV_NO_ENTRY if the section + is missing or empty. + Intended to be done quite early and + it is automatically + done if .debug_info is loaded. + Doing it more than once is never necessary + or harmful. There is no deallocation call + made visible, deallocation happens + when dwarf_finish() is called. + With DW_DLV_OK it returns the number of + loclists headers in the section through + loclists_count. */ +/*! @brief Load Loclists + + This loads raw .debug_loclists (DWARF5). + It is unlikely you have a reason to use this function. + If CUs or DIES have been referenced in any way + loading is already done. A duplicate loading + attempt returns DW_DLV_OK immediately, returning + dw_loclists_count filled in and does nothing else. + + Doing it more than once is never necessary + or harmful. There is no deallocation call + made visible, deallocation happens + when dwarf_finish() is called. + + @param dw_dbg + The applicable Dwarf_Debug. + @param dw_loclists_count + On success, returns the number of + DWARF5 loclists contexts in the section, + whether this is the first or a duplicate + load. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK if it loaded successfully + or if it is a duplicate load. + If no .debug_loclists + present returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_load_loclists(Dwarf_Debug dw_dbg, + Dwarf_Unsigned * dw_loclists_count, + Dwarf_Error * dw_error); + +/*! @brief Return certain loclists offsets + + Useful with the DWARF5 .debug_loclists section. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_context_index + Pass in the loclists context index. + @param dw_offsetentry_index + Pass in the offset array index. + @param dw_offset_value_out + On success returns the offset value at + offset table[dw_offsetentry_index], + an offset local to this context. + @param dw_global_offset_value_out + On success returns the same offset value + but with the offset of the table added in + to form a section offset. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If one of the indexes passed in is out of range + it returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_loclist_offset_index_value(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_context_index, + Dwarf_Unsigned dw_offsetentry_index, + Dwarf_Unsigned * dw_offset_value_out, + Dwarf_Unsigned * dw_global_offset_value_out, + Dwarf_Error * dw_error); + +/*! @brief Return basic data about a loclists head + + Used by dwarfdump to print basic data from the + data generated to look at a specific loclist + context as returned by + dwarf_loclists_index_get_lle_head() + or + dwarf_loclists_offset_get_lle_head. + Here we know there was a Dwarf_Attribute so + additional things are known as compared to calling + dwarf_get_loclist_context_basics + See DWARF5 Section 7.20 Location List Table + page 243. +*/ +DW_API int dwarf_get_loclist_head_basics(Dwarf_Loc_Head_c dw_head, + Dwarf_Small * dw_lkind, + Dwarf_Unsigned * dw_lle_count, + Dwarf_Unsigned * dw_loclists_version, + Dwarf_Unsigned * dw_loclists_index_returned, + Dwarf_Unsigned * dw_bytes_total_in_rle, + Dwarf_Half * dw_offset_size, + Dwarf_Half * dw_address_size, + Dwarf_Half * dw_segment_selector_size, + Dwarf_Unsigned * dw_overall_offset_of_this_context, + Dwarf_Unsigned * dw_total_length_of_this_context, + Dwarf_Unsigned * dw_offset_table_offset, + Dwarf_Unsigned * dw_offset_table_entrycount, + Dwarf_Bool * dw_loclists_base_present, + Dwarf_Unsigned * dw_loclists_base, + Dwarf_Bool * dw_loclists_base_address_present, + Dwarf_Unsigned * dw_loclists_base_address, + Dwarf_Bool * dw_loclists_debug_addr_base_present, + Dwarf_Unsigned * dw_loclists_debug_addr_base, + Dwarf_Unsigned * dw_offset_this_lle_area, + Dwarf_Error * dw_error); + +/*! @brief Return basic data about a loclists context + + Some of the same values as from + dwarf_get_loclist_head_basics + but here without any dependence on data + derived from a CU context. + Useful to print raw loclist data. +*/ +DW_API int dwarf_get_loclist_context_basics(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_index, + Dwarf_Unsigned * dw_header_offset, + Dwarf_Small * dw_offset_size, + Dwarf_Small * dw_extension_size, + unsigned int * dw_version, + Dwarf_Small * dw_address_size, + Dwarf_Small * dw_segment_selector_size, + Dwarf_Unsigned * dw_offset_entry_count, + Dwarf_Unsigned * dw_offset_of_offset_array, + Dwarf_Unsigned * dw_offset_of_first_locentry, + Dwarf_Unsigned * dw_offset_past_last_locentry, + Dwarf_Error * dw_error); + +/*! @brief Return basic data about a loclists context entry + + Useful to print raw loclist data. +*/ +DW_API int dwarf_get_loclist_lle( Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_contextnumber, + Dwarf_Unsigned dw_entry_offset, + Dwarf_Unsigned dw_endoffset, + unsigned int * dw_entrylen, + unsigned int * dw_entry_kind, + Dwarf_Unsigned * dw_entry_operand1, + Dwarf_Unsigned * dw_entry_operand2, + Dwarf_Unsigned * dw_expr_ops_blocksize, + Dwarf_Unsigned * dw_expr_ops_offset, + Dwarf_Small ** dw_expr_opsdata, + Dwarf_Error * dw_error); +/*! @} */ + +/*! @defgroup debugaddr .debug_addr access: DWARF5 + @{ + Reading just the .debug_addr section. + + These functions solely useful for reading + that section. It seems unlikely you would + have a reason to call these. The functions + getting attribute values use the section + when appropriate without using these + functions. +*/ + +/*! @brief Return a .debug_addr table + + Allocates and returns a pointer to a + Dwarf_Debug_Addr_Table as well as the contents + of the record. + + Other than dw_debug and dw_error and dw_table_header + a NULL passed in as a pointer + argument means the return value + will not be set through the pointer, so a caller + can pass NULL for return values of no + immediate interest. + + It is only intended to enable printing of the + simple .debug_addr section (by dwarfdump). + Not at all clear it is of any other use. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_section_offset + Pass in the section offset of a table header. + Start with zero. + If the passed-in offset is past the last byte + of the table the function returns DW_DLV_NO_ENTRY. + @param dw_table_header + On success + Returns a pointer to a Dwarf_Debug_Addr_Table + for use with dwarf_get_attr_by_index(). + @param dw_length + On success + Returns the length in bytes of this + contribution to .debug_addr from the table header, + including the table length field and the array + of addresses. + @param dw_version + On success returns the version number, which + should be 5. + @param dw_address_size + On success returns the address size of the address + entries in this table. + @param dw_at_addr_base + On success returns the value that will appear + in some DW_AT_addr_base attribute. + @param dw_entry_count + On success returns the number of table entries + in this table instance. + @param dw_next_table_offset + On success returns the offset of the next table + in the section. Use the offset returned in the + next call to this function. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If the dw_section_offset passed in is out of range + it returns DW_DLV_NO_ENTRY. + If it returns DW_DLV_ERROR only dw_error is + set, none of the other + return values are set through the pointers. +*/ + +DW_API int dwarf_debug_addr_table(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_section_offset, + Dwarf_Debug_Addr_Table *dw_table_header, + Dwarf_Unsigned *dw_length, + Dwarf_Half *dw_version, + Dwarf_Small *dw_address_size, + Dwarf_Unsigned *dw_dw_at_addr_base, + Dwarf_Unsigned *dw_entry_count, + Dwarf_Unsigned *dw_next_table_offset, + Dwarf_Error *dw_error); + +/*! @brief Return .debug_addr address given table index + + @param dw_table_header + Pass in a Dwarf_Debug_Addr_Table pointer. + @param dw_table_header + Pass in a Dwarf_Debug_Addr_Table index to an address. + If out of the valid range 0 through + dw_entry_count-1 the function returns + DW_DLV_NO_ENTRY. + @param dw_address + Returns an address in the program through + the pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If the dw_section_offset passed in is out of range + it returns DW_DLV_NO_ENTRY. + If it returns DW_DLV_ERROR only dw_error is + set, dw_address and dw_segment are not + set through the pointers. +*/ + +DW_API int dwarf_debug_addr_by_index(Dwarf_Debug_Addr_Table dw_dat, + Dwarf_Unsigned dw_entry_index, + Dwarf_Unsigned *dw_address, + Dwarf_Error *dw_error); + +/*! @brief dealloc (free) a Dwarf_Attr_Table record. + + @param dw_table_header + Pass in a valid Dwarf_Debug_Addr_Table pointer. + Does nothing if the dw_dat field is NULL. + +*/ +DW_API void dwarf_dealloc_debug_addr_table( + Dwarf_Debug_Addr_Table dw_dat); + +/*! @} */ + +/*! @defgroup macro Macro Access: DWARF5 + + @{ + Reading the .debug_macro section. + + @see examplep5 An example reading .debug_macro +*/ + +/*! @brief DWARF5 .debug_macro access via Dwarf_Die + + @see examplep5 + + @param dw_die + The CU DIE of interest. + @param dw_version_out + On success returns the macro context version (5) + @param dw_macro_context + On success returns a pointer to a macro context + which allows access to the context content. + @param dw_macro_unit_offset_out + On success returns the offset of the macro context. + @param dw_macro_ops_count_out + On success returns the number of macro operations + in the context. + @param dw_macro_ops_data_length_out + On success returns the length in bytes of the + operations in the context. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If no .debug_macro section exists for the + CU it returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_macro_context(Dwarf_Die dw_die, + Dwarf_Unsigned * dw_version_out, + Dwarf_Macro_Context * dw_macro_context, + Dwarf_Unsigned * dw_macro_unit_offset_out, + Dwarf_Unsigned * dw_macro_ops_count_out, + Dwarf_Unsigned * dw_macro_ops_data_length_out, + Dwarf_Error * dw_error); + +/*! @brief DWARF5 .debug_macro access via Dwarf_Die and an offset + + @param dw_die + The CU DIE of interest. + @param dw_offset + The offset in the section to begin reading. + @param dw_version_out + On success returns the macro context version (5) + @param dw_macro_context + On success returns a pointer to a macro context + which allows access to the context content. + @param dw_macro_ops_count_out + On success returns the number of macro operations + in the context. + @param dw_macro_ops_data_length + On success returns the length in bytes of the + macro context, starting at the offset of the first + byte of the context. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If no .debug_macro section exists for the + CU it returns DW_DLV_NO_ENTRY. + If the dw_offset is outside the section it + returns DW_DLV_ERROR. +*/ +DW_API int dwarf_get_macro_context_by_offset(Dwarf_Die dw_die, + Dwarf_Unsigned dw_offset, + Dwarf_Unsigned * dw_version_out, + Dwarf_Macro_Context * dw_macro_context, + Dwarf_Unsigned * dw_macro_ops_count_out, + Dwarf_Unsigned * dw_macro_ops_data_length, + Dwarf_Error * dw_error); + +/* New December 2020. Sometimes its necessary to know + a context total length including macro 5 header */ +/*! @brief Return a macro context total length + + @param dw_context + A pointer to the macro context of interest. + @param dw_mac_total_len + On success returns the length in bytes of + the macro context. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_macro_context_total_length( + Dwarf_Macro_Context dw_context, + Dwarf_Unsigned * dw_mac_total_len, + Dwarf_Error * dw_error); + +/*! @brief Dealloc a macro context + + @param dw_mc + A pointer to the macro context of interest. + On return the caller should zero the pointer + as the pointer is then stale. +*/ +DW_API void dwarf_dealloc_macro_context(Dwarf_Macro_Context dw_mc); + +/*! @brief Access the internal details of a Dwarf_Macro_Context + + Not described in detail here. See DWARF5 Standard + Section 6.3.1 Macro Information Header page 166. +*/ +DW_API int dwarf_macro_context_head(Dwarf_Macro_Context dw_mc, + Dwarf_Half * dw_version, + Dwarf_Unsigned * dw_mac_offset, + Dwarf_Unsigned * dw_mac_len, + Dwarf_Unsigned * dw_mac_header_len, + unsigned int * dw_flags, + Dwarf_Bool * dw_has_line_offset, + Dwarf_Unsigned * dw_line_offset, + Dwarf_Bool * dw_has_offset_size_64, + Dwarf_Bool * dw_has_operands_table, + Dwarf_Half * dw_opcode_count, + Dwarf_Error * dw_error); + +/*! @brief Access to the details of the opcode operands table + + Not of much interest to most libdwarf users. + + @param dw_mc + The macro context of interest. + @param dw_index + The opcode operands table index. 0 through dw_opcode_count-1. + @param dw_opcode_number + On success returns the opcode number in the table. + @param dw_operand_count + On success returns the number of forms + for that dw_index. + @param dw_operand_array + On success returns the array of op operand + forms + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_macro_operands_table(Dwarf_Macro_Context dw_mc, + Dwarf_Half dw_index, /* 0 to opcode_count -1 */ + Dwarf_Half * dw_opcode_number, + Dwarf_Half * dw_operand_count, + const Dwarf_Small ** dw_operand_array, + Dwarf_Error * dw_error); + +/*! @brief Access macro operation details of a single operation + + Useful for printing basic data about the operation. + + @param dw_macro_context + The macro context of interest. + @param dw_op_number + valid values are 0 through dw_macro_ops_count_out-1. + @param dw_op_start_section_offset + On success returns the section offset of this + operator. + @param dw_macro_operator + On success returns the the macro operator itself, + for example DW_MACRO_define. + @param dw_forms_count + On success returns the number of forms in the formcode array. + @param dw_formcode_array + On success returns a pointer to the formcode array + of operand forms. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_macro_op(Dwarf_Macro_Context dw_macro_context, + Dwarf_Unsigned dw_op_number, + Dwarf_Unsigned * dw_op_start_section_offset, + Dwarf_Half * dw_macro_operator, + Dwarf_Half * dw_forms_count, + const Dwarf_Small ** dw_formcode_array, + Dwarf_Error * dw_error); + +/*! @brief Get Macro defundef + + To extract the value portion of a macro define: + @see dwarf_find_macro_value_start + + @param dw_macro_context + The macro context of interest. + @param dw_op_number + valid values are 0 through dw_macro_ops_count_out-1. + The op number must be for a def/undef. + @param dw_line_number + The line number in the user source for this define/undef + @param dw_index + On success if the macro is an strx form + the value returned + is the string index in the record, + otherwise zero is returned. + @param dw_offset + On success if the macro is an strp or sup form the value + returned is the string offset in the appropriate section, + otherwise zero is returned. + @param dw_forms_count + On success the value 2 is returned. + @param dw_macro_string + On success a pointer to a null-terminated + string is returned. + Do not dealloc or free this string. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + It is an error if operator dw_op_number is not a + DW_MACRO_define, DW_MACRO_undef, DW_MACRO_define_strp + DW_MACRO_undef_strp, DW_MACRO_undef_sup, + DW_MACRO_undef_sup, + DW_MACRO_define_strx, or DW_MACRO_undef_strx, +*/ +DW_API int dwarf_get_macro_defundef( + Dwarf_Macro_Context dw_macro_context, + Dwarf_Unsigned dw_op_number, + Dwarf_Unsigned * dw_line_number, + Dwarf_Unsigned * dw_index, + Dwarf_Unsigned * dw_offset, + Dwarf_Half * dw_forms_count, + const char ** dw_macro_string, + Dwarf_Error * dw_error); + +/*! @brief Get Macro start end + + @param dw_macro_context + The macro context of interest. + @param dw_op_number + Valid values are 0 through dw_macro_ops_count_out-1. + The op number must be for a start/end. + @param dw_line_number + If end_file nothing is returned here. + If start_file on success returns the line number + of the source line of the include directive. + @param dw_name_index_to_line_tab + If end_file nothing is returned here. + If start_file on success returns the file name + index in the line table file names table. + @param dw_src_file_name + If end_file nothing is returned here. + If start_file on success returns a pointer to + the null-terminated source file name. + Do not free or dealloc this string. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + It is an error if the operator is not + DW_MACRO_start_file or DW_MACRO_end_file. +*/ +DW_API int dwarf_get_macro_startend_file( + Dwarf_Macro_Context dw_macro_context, + Dwarf_Unsigned dw_op_number, + Dwarf_Unsigned * dw_line_number, + Dwarf_Unsigned * dw_name_index_to_line_tab, + const char ** dw_src_file_name, + Dwarf_Error * dw_error); + +/*! @brief Get Macro import + + @param dw_macro_context + The macro context of interest. + @param dw_op_number + Valid values are 0 through dw_macro_ops_count_out-1. + @param dw_target_offset + Returns the offset in the imported section. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + It is an error if the operator is not + DW_MACRO_import or DW_MACRO_import_sup. +*/ +DW_API int dwarf_get_macro_import( + Dwarf_Macro_Context dw_macro_context, + Dwarf_Unsigned dw_op_number, + Dwarf_Unsigned * dw_target_offset, + Dwarf_Error * dw_error); +/*! @} */ + +/*! @defgroup macinfo Macro Access: DWARF2-4 + + @{ + Reading the .debug_macinfo section. + + The section is rarely used since it takes a lot + of disk space. DWARF5 has much more compact + macro data (in section .debug_macro). + + For an example see + @see examplep2 An example reading .debug_macinfo + +*/ +/*! @brief Return a pointer to the value part of a macro + + This function Works for all versions, DWARF2-DWARF5 + + @param dw_macro_string + The macro string passed in should be properly formatted + with a name, a space, and then the value portion (whether + a function-like macro or not function-like). + @returns + On success it returns a pointer to the value portion + of the macro. On failure it returns a pointer + to a NUL byte (so a zero-length string). +*/ +DW_API char* dwarf_find_macro_value_start(char * dw_macro_string); + +/*! @brief Getting .debug_macinfo macro details. + + @link examplep2 An example calling this function @endlink + + @see examplep2 + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_macro_offset + The offset in the section you wish to start from. + @param dw_maximum_count + Pass in a count to ensure we will not allocate + an excessive amount (guarding against a + + @param dw_entry_count + On success returns a count of the macro operations + in a CU macro set. + @param dw_details + On success returns a pointer to an array of + struct DW_Macro_Details_s . + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_macro_details(Dwarf_Debug dw_dbg, + Dwarf_Off dw_macro_offset, + Dwarf_Unsigned dw_maximum_count, + Dwarf_Signed * dw_entry_count, + Dwarf_Macro_Details ** dw_details, + Dwarf_Error * dw_error); + +/*! @} */ + +/*! @defgroup frame Stack Frame Access + + @{ + Use to access DWARF2-5 .debug_frame and GNU .eh_frame + sections. Does not evaluate frame instructions, but + provides detailed data so it is possible do that + yourself. + +*/ + +/*! @brief Get lists of .debug_frame FDEs and CIEs + + See DWARF5 Section 6.4 Call Frame Information, + page 171. + + @see exampleq + + The FDE array returned through dw_fde_data + is sorted low-to-high by the lowest-pc in each FDE. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_cie_data + On success + returns a pointer to an array of pointers to CIE data. + @param dw_cie_element_count + On success returns a count of the number of elements + in the dw_cie_data array. + @param dw_fde_data + On success + returns a pointer to an array of pointers to FDE data. + @param dw_fde_element_count + On success returns a count of the number of elements + in the dw_fde_data array. + On success + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_fde_list(Dwarf_Debug dw_dbg, + Dwarf_Cie** dw_cie_data, + Dwarf_Signed* dw_cie_element_count, + Dwarf_Fde** dw_fde_data, + Dwarf_Signed* dw_fde_element_count, + Dwarf_Error* dw_error); +/*! @brief Get lists of .eh_frame FDEs and CIEs + + The arguments are identical to the previous + function, the difference is the section read. + The GNU-defined .eh_frame section is very similar to + .debug_frame but has unique features that + matter when following a stack trace. + @see dwarf_get_fde_list +*/ +DW_API int dwarf_get_fde_list_eh(Dwarf_Debug dw_dbg, + Dwarf_Cie** dw_cie_data, + Dwarf_Signed* dw_cie_element_count, + Dwarf_Fde** dw_fde_data, + Dwarf_Signed* dw_fde_element_count, + Dwarf_Error* dw_error); + +/*! @brief Release storage associated with FDE and CIE arrays + + Applies to .eh_frame and .debug_frame + lists. + + @param dw_dbg + The Dwarf_Debug used in the list setup. + @param dw_cie_data + As returned from the list setup call. + @param dw_cie_element_count + @param dw_fde_data + As returned from the list setup call. + @param dw_fde_element_count + As returned from the list setup call. + + On return the pointers passed in dw_cie_data + and dw_fde_data should be zeroed by the + caller as they are then stale pointers. +*/ +DW_API void dwarf_dealloc_fde_cie_list(Dwarf_Debug dw_dbg, + Dwarf_Cie * dw_cie_data, + Dwarf_Signed dw_cie_element_count, + Dwarf_Fde * dw_fde_data, + Dwarf_Signed dw_fde_element_count); + +/*! @brief Return the FDE data for a single FDE + + @param dw_fde + The FDE of interest. + @param dw_low_pc + On success + returns the low pc value for the function involved. + @param dw_func_length + On success returns the length of the function + code in bytes. + @param dw_fde_bytes + On success + returns a pointer to the bytes of the FDE. + @param dw_fde_byte_length + On success returns the length of the + dw_fde_bytes area. + @param dw_cie_offset + On success returns the section offset of the associated CIE. + @param dw_cie_index + On success returns the CIE index of the associated CIE. + @param dw_fde_offset + On success returns the section offset of this FDE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_fde_range(Dwarf_Fde dw_fde, + Dwarf_Addr* dw_low_pc, + Dwarf_Unsigned* dw_func_length, + Dwarf_Small **dw_fde_bytes, + Dwarf_Unsigned* dw_fde_byte_length, + Dwarf_Off* dw_cie_offset, + Dwarf_Signed* dw_cie_index, + Dwarf_Off* dw_fde_offset, + Dwarf_Error* dw_error); + +/*! @brief IRIX only access to C++ destructor tables + + This applies only to IRIX C++ destructor information + which was never documented and is unlikely to be of interest. +*/ +DW_API int dwarf_get_fde_exception_info(Dwarf_Fde dw_fde, + Dwarf_Signed* dw_offset_into_exception_tables, + Dwarf_Error* dw_error); + +/*! @brief Given FDE get CIE + + @param dw_fde + The FDE of interest. + @param dw_cie_returned + On success returns a pointer to the applicable CIE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_cie_of_fde(Dwarf_Fde dw_fde, + Dwarf_Cie * dw_cie_returned, + Dwarf_Error* dw_error); + +/*! @brief Given a CIE get access to its content + + @param dw_cie + Pass in the CIE of interest. + @param dw_bytes_in_cie + On success, returns the length of the CIE in bytes. + @param dw_version + On success, returns the CIE version number. + @param dw_augmenter + On success, returns a pointer to the augmentation + string (which could be the empty string). + @param dw_code_alignment_factor + On success, returns a the code_alignment_factor + used to interpret CIE/FDE operations. + @param dw_data_alignment_factor + On success, returns a the data_alignment_factor + used to interpret CIE/FDE operations. + @param dw_return_address_register_rule + On success, returns a register number of the + return address register. + @param dw_initial_instructions + On success, returns a pointer to the bytes + of initial_instructions in the CIE. + @param dw_initial_instructions_length + On success, returns the length in bytes of + the initial_instructions. + @param dw_offset_size + On success, returns the offset_size within this CIE. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_cie_info_b(Dwarf_Cie dw_cie, + Dwarf_Unsigned * dw_bytes_in_cie, + Dwarf_Small* dw_version, + char ** dw_augmenter, + Dwarf_Unsigned* dw_code_alignment_factor, + Dwarf_Signed* dw_data_alignment_factor, + Dwarf_Half* dw_return_address_register_rule, + Dwarf_Small ** dw_initial_instructions, + Dwarf_Unsigned* dw_initial_instructions_length, + Dwarf_Half* dw_offset_size, + Dwarf_Error* dw_error); + +/*! @brief Return CIE index given CIE + + @param dw_cie + Pass in the CIE of interest. + @param dw_index + On success, returns the index (the position + of the CIE in the CIE pointer array). + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_cie_index(Dwarf_Cie dw_cie, + Dwarf_Signed* dw_index, + Dwarf_Error * dw_error); + +/*! @brief Return length and pointer to access frame instructions. + + @see dwarf_expand_frame_instructions + @see examples + + @param dw_fde + Pass in the FDE of interest. + @param dw_outinstrs + On success returns a pointer to the FDE instruction byte + stream. + @param dw_outlen + On success returns the length of the dw_outinstrs byte + stream. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_fde_instr_bytes(Dwarf_Fde dw_fde, + Dwarf_Small ** dw_outinstrs, + Dwarf_Unsigned * dw_outlen, + Dwarf_Error * dw_error); + +/*! @brief Return information on frame registers at a given pc value + + An FDE at a given pc (code address) + + @param dw_fde + Pass in the FDE of interest. + @param dw_pc_requested + Pass in a pc (code) address inside that FDE. + @param dw_reg_table + On success, returns a pointer to a struct + given the frame state. + @param dw_row_pc + On success returns the address of the row of + frame data which may be a few counts off of + the pc requested. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK if the dw_pc_requested is in the + FDE passed in and there is some applicable row + in the table. + +*/ +DW_API int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde dw_fde, + Dwarf_Addr dw_pc_requested, + Dwarf_Regtable3* dw_reg_table, + Dwarf_Addr* dw_row_pc, + Dwarf_Error* dw_error); + +/* See discussion of dw_value_type, libdwarf.h. */ +/*! @brief Return details about a particular pc and register. + + It is inefficient to iterate across all table_columns (registers) + using this function (dwarf_get_fde_info_for_reg3_c()). + Instead call dwarf_get_fde_info_for_all_regs3() + and index into the table it fills in. + + If dw_value_type == DW_EXPR_EXPRESSION or + DW_EXPR_VALUE_EXPRESSION dw_offset + is not set and the caller must + evaluate the expression, which usually depends + on runtime frame data which cannot be calculated + without a stack frame including registers (etc). + + dwarf_get_fde_info_for_reg3_c() is new in Septmber 2023 + to correct the incorrect type of the dw_offset + argument in dwarf_get_fde_info_for_reg3_b(). + Both versions operate correctly. + + @param dw_fde + Pass in the FDE of interest. + @param dw_table_column + Pass in the table_column, column numbers in the table + are 0 through the number_of_registers-1. + @param dw_pc_requested + Pass in the pc of interest within dw_fde. + @param dw_value_type + On success returns the value type, a DW_EXPR value. + For example DW_EXPR_EXPRESSION + @param dw_offset_relevant + On success returns FALSE if the offset value is + irrelevant, otherwise TRUE. + @param dw_register + On success returns a register number. + @param dw_offset + On success returns a signed register offset value when + dw_value_tyoe is DW_EXPR_OFFSET or DW_EXPER_VAL_OFFSET. + @param dw_block_content + On success returns a pointer to a block. + For example, for DW_EXPR_EXPRESSION the block + gives access to the expression bytes. + @param dw_row_pc_out + On success returns the address of the actual pc + for this register at this pc. + @param dw_has_more_rows + On success returns FALSE if there are no more rows, + otherwise returns TRUE. + @param dw_subsequent_pc + On success this returns the address of the next pc + for which there is a register row, making access + to all the rows in sequence much more efficient + than just adding 1 to a pc value. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK if the dw_pc_requested is in the + FDE passed in and there is a row for the pc + in the table. +*/ +DW_API int dwarf_get_fde_info_for_reg3_c(Dwarf_Fde dw_fde, + Dwarf_Half dw_table_column, + Dwarf_Addr dw_pc_requested, + Dwarf_Small * dw_value_type, + Dwarf_Unsigned * dw_offset_relevant, + Dwarf_Unsigned * dw_register, + Dwarf_Signed * dw_offset, + Dwarf_Block * dw_block_content, + Dwarf_Addr * dw_row_pc_out, + Dwarf_Bool * dw_has_more_rows, + Dwarf_Addr * dw_subsequent_pc, + Dwarf_Error * dw_error); + +/*! @brief Return details about a particular pc and register. + + Identical to dwarf_get_fde_info_for_reg3_c() except that + this returns dw_offset as a Dwarf_Unsigned, which + was never appropriate, and required you to + cast that value to Dwarf_Signed to use it properly.. + + Please switch to using dwarf_get_fde_info_for_reg3_c() +*/ +DW_API int dwarf_get_fde_info_for_reg3_b(Dwarf_Fde dw_fde, + Dwarf_Half dw_table_column, + Dwarf_Addr dw_pc_requested, + Dwarf_Small * dw_value_type, + Dwarf_Unsigned * dw_offset_relevant, + Dwarf_Unsigned * dw_register, + Dwarf_Unsigned * dw_offset, + Dwarf_Block * dw_block_content, + Dwarf_Addr * dw_row_pc_out, + Dwarf_Bool * dw_has_more_rows, + Dwarf_Addr * dw_subsequent_pc, + Dwarf_Error * dw_error); + +/*! @brief Get the value of the CFA for a particular pc value + + @see dwarf_get_fde_info_for_reg3_c + has essentially the same return values as + dwarf_get_fde_info_for_reg3_c but + it refers to the CFA (which is not part of the register + table) so function has no table column argument. + + New in September 2023, release 0.8.0. + dwarf_get_fde_info_for_cfa_reg3_c() returns dw_offset + as a signed type. + dwarf_get_fde_info_for_cfa_reg3_b() returns dw_offset + as an unsigned type, requiring the caller to cast + to Dwarf_Signed before using the value. + Both versions exist and operate properly. + + If dw_value_type == DW_EXPR_EXPRESSION or + DW_EXPR_VALUE_EXPRESSION dw_offset + is not set and the caller must + evaluate the expression, which usually depends + on runtime frame data which cannot be calculated + without a stack frame including register values (etc). +*/ +DW_API int dwarf_get_fde_info_for_cfa_reg3_c(Dwarf_Fde dw_fde, + Dwarf_Addr dw_pc_requested, + Dwarf_Small * dw_value_type, + Dwarf_Unsigned* dw_offset_relevant, + Dwarf_Unsigned* dw_register, + Dwarf_Signed * dw_offset, + Dwarf_Block * dw_block, + Dwarf_Addr * dw_row_pc_out, + Dwarf_Bool * dw_has_more_rows, + Dwarf_Addr * dw_subsequent_pc, + Dwarf_Error * dw_error); +/*! @brief Get the value of the CFA for a particular pc value + + @see dwarf_get_fde_info_for_cfa_reg3_c + + This is the earlier version that returns a dw_offset + of type Dwarf_Unsigned, requiring you to cast to Dwarf_Signed + to work with the value. + +*/ +DW_API int dwarf_get_fde_info_for_cfa_reg3_b(Dwarf_Fde dw_fde, + Dwarf_Addr dw_pc_requested, + Dwarf_Small * dw_value_type, + Dwarf_Unsigned* dw_offset_relevant, + Dwarf_Unsigned* dw_register, + Dwarf_Unsigned* dw_offset, + Dwarf_Block * dw_block, + Dwarf_Addr * dw_row_pc_out, + Dwarf_Bool * dw_has_more_rows, + Dwarf_Addr * dw_subsequent_pc, + Dwarf_Error * dw_error); + +/*! @brief Get the fde given DW_AT_MIPS_fde in a DIE. + + This is essentially useless as only SGI/MIPS compilers + from the 1990's had DW_AT_MIPS_fde in + DW_TAG_subprogram DIEs and this relies + on that attribute to work. + +*/ +DW_API int dwarf_get_fde_for_die(Dwarf_Debug dw_dbg, + Dwarf_Die dw_subr_die, + Dwarf_Fde * dw_returned_fde, + Dwarf_Error* dw_error); + +/*! @brief Retrieve an FDE from an FDE table + + This is just like indexing into the FDE array + but with extra checking of the pointer and + index. + @see dwarf_get_fde_list +*/ +DW_API int dwarf_get_fde_n(Dwarf_Fde* dw_fde_data, + Dwarf_Unsigned dw_fde_index, + Dwarf_Fde * dw_returned_fde, + Dwarf_Error * dw_error); + +/*! @brief Retrieve an FDE given a pc + + Using binary search this finds the FDE + that contains this dw_pc_of_interest + That works because libdwarf ensures the + array of FDEs is sorted by the low-pc + @see dwarf_get_fde_list + + @param dw_fde_data + Pass in a pointer an array of fde pointers. + @param dw_pc_of_interest + The pc value of interest. + @param dw_returned_fde + On success a pointer to the applicable FDE + is set through the pointer. + @param dw_lopc + On success a pointer to the low pc in dw_returned_fde + is set through the pointer. + @param dw_hipc + On success a pointer to the high pc (one past + the actual last byte address) in dw_returned_fde + is set through the pointer. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK if the dw_pc_of_interest found + in some FDE in the array. + If no FDE is found containing dw_pc_of_interest + DW_DLV_NO_ENTRY is returned. +*/ +DW_API int dwarf_get_fde_at_pc(Dwarf_Fde* dw_fde_data, + Dwarf_Addr dw_pc_of_interest, + Dwarf_Fde * dw_returned_fde, + Dwarf_Addr * dw_lopc, + Dwarf_Addr * dw_hipc, + Dwarf_Error* dw_error); + +/*! @brief Return .eh_frame CIE augmentation data. + + GNU .eh_frame CIE augmentation information. + See Linux Standard Base Core Specification version 3.0 . + @see https://gcc.gnu.org/legacy-ml/gcc/2003-12/msg01168.html + + @param dw_cie + The CIE of interest. + @param dw_augdata + On success returns a pointer to the augmentation data. + @param dw_augdata_len + On success returns the length in bytes of the augmentation data. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If the augmentation data length is zero it + returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_cie_augmentation_data(Dwarf_Cie dw_cie, + Dwarf_Small ** dw_augdata, + Dwarf_Unsigned * dw_augdata_len, + Dwarf_Error* dw_error); + +/*! @brief Return .eh_frame FDE augmentation data. + + GNU .eh_frame FDE augmentation information. + See Linux Standard Base Core Specification version 3.0 . + @see https://gcc.gnu.org/legacy-ml/gcc/2003-12/msg01168.html + + @param dw_fde + The FDE of interest. + @param dw_augdata + On success returns a pointer to the augmentation data. + @param dw_augdata_len + On success returns the length in bytes of the augmentation data. + @param dw_error + The usual error detail return pointer. + @return + Returns DW_DLV_OK etc. + If the augmentation data length is zero it + returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_fde_augmentation_data(Dwarf_Fde dw_fde, + Dwarf_Small ** dw_augdata, + Dwarf_Unsigned * dw_augdata_len, + Dwarf_Error* dw_error); + +/*! @brief Expands CIE or FDE instructions for detailed examination. + Called for CIE initial instructions and + FDE instructions. + Call dwarf_get_fde_instr_bytes() or + dwarf_get_cie_info_b() to get the initial instruction bytes + and instructions byte count you wish to expand. + + Combined with dwarf_get_frame_instruction() + or dwarf_get_frame_instruction_a() + (the second is like the first but adds an argument for LLVM + address space numbers) it enables detailed access to + frame instruction fields for evaluation or printing. + + Free allocated memory with + dwarf_dealloc_frame_instr_head(). + + @see examples + + @param dw_cie + The cie relevant to the instructions. + @param dw_instructionspointer + points to the instructions + @param dw_length_in_bytes + byte length of the instruction sequence. + @param dw_head + The address of an allocated dw_head + @param dw_instr_count + Returns the number of instructions in the byte stream + @param dw_error + Error return details + @return + On success returns DW_DLV_OK +*/ +DW_API int dwarf_expand_frame_instructions(Dwarf_Cie dw_cie, + Dwarf_Small * dw_instructionspointer, + Dwarf_Unsigned dw_length_in_bytes, + Dwarf_Frame_Instr_Head * dw_head, + Dwarf_Unsigned * dw_instr_count, + Dwarf_Error * dw_error); + +/*! + @brief Return information about a single instruction + Fields_description means a sequence of up to three + letters including u,s,r,c,d,b, terminated by NUL byte. + It is a string but we test individual bytes instead + of using string compares. Do not free any of the + returned values. + + @see examples + + @param dw_head + A head record + @param dw_instr_index + index 0 < i < instr_count + @param dw_instr_offset_in_instrs + Returns the byte offset of this instruction + within instructions. + @param dw_cfa_operation + Returns a DW_CFA opcode. + @param dw_fields_description + Returns a string. Do not free. + @param dw_u0 + May be set to an unsigned value + @param dw_u1 + May be set to an unsigned value + @param dw_s0 + May be set to a signed value + @param dw_s1 + May be set to a signed value + @param dw_code_alignment_factor + May be set by the call + @param dw_data_alignment_factor + May be set by the call + @param dw_expression_block + Pass in a pointer to a block + @param dw_error + If DW_DLV_ERROR and the argument is non-NULL, returns + details about the error. + @return On success returns DW_DLV_OK + If there is no such instruction with that index + it returns DW_DLV_NO_ENTRY + On error it returns DW_DLV_ERROR and if dw_error + is NULL it pushes back a pointer to a Dwarf_Error + to the caller. + + Frame expressions have a variety of formats + and content. The dw_fields parameter is set to + a pointer to a short string with some set of the letters + s,u,r,d,c,b,a which enables determining exactly + which values the call sets. + Some examples: + A @c s in fields[0] means s0 is a signed number. + + A @c b somewhere in fields means the expression block + passed in has been filled in. + + A @c r in fields[1] means u1 is set to a register number. + + A @c d in fields means data_alignment_factor is set + + A @c c in fields means code_alignment_factor is set + + An @c a in fields means an LLVM address space value and + only exists if calling dwarf_get_frame_instruction_a(). + + The possible frame instruction formats are: + @code + "" "b" "r" "rb" "rr" "rsd" "rsda" "ru" "rua" "rud" + "sd" "u" "uc" + @endcode + are the possible frame instruction formats. +*/ +DW_API int dwarf_get_frame_instruction( + Dwarf_Frame_Instr_Head dw_head, + Dwarf_Unsigned dw_instr_index, + Dwarf_Unsigned * dw_instr_offset_in_instrs, + Dwarf_Small * dw_cfa_operation, + const char ** dw_fields_description, + Dwarf_Unsigned * dw_u0, + Dwarf_Unsigned * dw_u1, + Dwarf_Signed * dw_s0, + Dwarf_Signed * dw_s1, + Dwarf_Unsigned * dw_code_alignment_factor, + Dwarf_Signed * dw_data_alignment_factor, + Dwarf_Block * dw_expression_block, + Dwarf_Error * dw_error); + +/*! @brief Expands CIE or FDE instructions for detailed examination. + Called for CIE initial instructions and + FDE instructions. This is the same as + dwarf_get_frame_instruction() except that it adds a + dw_u2 field which contains an address-space identifier + if the letter @c a appears in dw_fields_description. + The dw_u2 field is non-standard and only applies + to Heterogeneous Debugging + frame instructions defined by LLVM + (DW_CFA_LLVM_def_aspace_cfa and DW_CFA_LLVM_def_aspace_cfa_sf) + + Where multiplication is called for (via dw_code_alignment_factor + or dw_data_alignment_factor) to produce an offset there + is no need to check for overflow as libdwarf has already + verified there is no overflow. + + The return values are the same except here we have: + an @c a in fields[2] or fields[3] means + dw_u2 is an address-space + identifier for the LLVM CFA instruction. +*/ +DW_API int dwarf_get_frame_instruction_a( + Dwarf_Frame_Instr_Head dw_/* head*/, + Dwarf_Unsigned dw_instr_index, + Dwarf_Unsigned * dw_instr_offset_in_instrs, + Dwarf_Small * dw_cfa_operation, + const char ** dw_fields_description, + Dwarf_Unsigned * dw_u0, + Dwarf_Unsigned * dw_u1, + Dwarf_Unsigned * dw_u2, + Dwarf_Signed * dw_s0, + Dwarf_Signed * dw_s1, + Dwarf_Unsigned * dw_code_alignment_factor, + Dwarf_Signed * dw_data_alignment_factor, + Dwarf_Block * dw_expression_block, + Dwarf_Error * dw_error); + +/*! + @brief Deallocates the frame instruction data in dw_head + @param dw_head + A head pointer. + Frees all data created by dwarf_expand_frame_instructions() + and makes the head pointer stale. The caller should + set to NULL. +*/ +DW_API void dwarf_dealloc_frame_instr_head(Dwarf_Frame_Instr_Head + dw_head); + +/*! @brief Return FDE and CIE offsets from debugging info. + + @param dw_dbg + The Dwarf_Debug of interest + @param dw_in_fde + Pass in the FDE of interest. + @param dw_fde_off + On success returns the section offset of the FDE. + @param dw_cie_off + On success returns the section offset of the CIE. + @param dw_error + Error return details + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_fde_section_offset(Dwarf_Debug dw_dbg, + Dwarf_Fde dw_in_fde, + Dwarf_Off * dw_fde_off, + Dwarf_Off * dw_cie_off, + Dwarf_Error * dw_error); + +/*! @brief Use to print CIE offsets from debugging info. + + @param dw_dbg + The Dwarf_Debug of interest + @param dw_in_cie + Pass in the CIE of interest. + @param dw_cie_off + On success returns the section offset of the CIE. + @param dw_error + Error return details + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_cie_section_offset(Dwarf_Debug dw_dbg, + Dwarf_Cie dw_in_cie, + Dwarf_Off * dw_cie_off, + Dwarf_Error * dw_error); + +/*! @brief Frame Rule Table Size + @link frameregs Invariants for setting frame registers @endlink + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Pass in the value to record for the library to use. + @return + Returns the previous value. +*/ +DW_API Dwarf_Half dwarf_set_frame_rule_table_size( + Dwarf_Debug dw_dbg, + Dwarf_Half dw_value); +/*! @brief Frame Rule Initial Value + + @link frameregs Invariants for setting frame registers @endlink + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Pass in the value to record for the library to use. + @return + Returns the previous value. +*/ +DW_API Dwarf_Half dwarf_set_frame_rule_initial_value( + Dwarf_Debug dw_dbg, + Dwarf_Half dw_value); +/*! @brief Frame CFA Column + @link frameregs Invariants for setting frame registers @endlink + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Pass in the value to record for the library to use. + @return + Returns the previous value. +*/ +DW_API Dwarf_Half dwarf_set_frame_cfa_value( + Dwarf_Debug dw_dbg, + Dwarf_Half dw_value); + +/*! @brief Frame Same Value Default + @link frameregs Invariants for setting frame registers @endlink + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Pass in the value to record for the library to use. + @return + Returns the previous value. +*/ +DW_API Dwarf_Half dwarf_set_frame_same_value( + Dwarf_Debug dw_dbg, + Dwarf_Half dw_value); +/*! @brief Frame Undefined Value Default + @link frameregs Invariants for setting frame registers @endlink + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Pass in the value to record for the library to use. + @return + Returns the previous value. +*/ +DW_API Dwarf_Half dwarf_set_frame_undefined_value( + Dwarf_Debug dw_dbg, + Dwarf_Half dw_value); +/*! @} */ + +/*! @defgroup abbrev Abbreviations Section Details + + @{ + Allows reading section .debug_abbrev independently of + CUs or DIEs. Normally not done (libdwarf uses it + as necessary to access DWARF DIEs and DWARF attributes) + unless one is interested in + the content of the section. + + @link dwsec_independentsec About Reading Independently. @endlink +*/ +/*! @brief Reading Abbreviation Data + + Normally you never need to call these functions. + Calls that involve DIEs do all this for you + behind the scenes in the library. + + This reads the data for a single abbrev code + starting at dw_offset. + Essentially, opening access to an abbreviation entry. + + When libdwarf itself reads abbreviations to + access DIEs the offset comes + from the Compilation Unit Header debug_abbrev_offset field. + @see dwarf_next_cu_header_d + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_offset + Pass in the offset where a Debug_Abbrev starts. + @param dw_returned_abbrev + On success, sets a pointer to a Dwarf_Abbrev + through the pointer to allow further access. + @param dw_length + On success, returns the length of the entire abbreviation + block (bytes), useful to calculate the next offset + if reading the section independently + of any compilation unit. + @param dw_attr_count + On success, returns the number of attributes in this + abbreviation entry. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + If the abbreviation is a single zero byte it is + a null abbreviation. DW_DLV_OK is returned. + + Close the abbrev by calling + dwarf_dealloc(dbg,*dw_returned_abbrev, DW_DLA_ABBREV) +*/ +DW_API int dwarf_get_abbrev(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_offset, + Dwarf_Abbrev * dw_returned_abbrev, + Dwarf_Unsigned* dw_length, + Dwarf_Unsigned* dw_attr_count, + Dwarf_Error* dw_error); + +/*! @brief Get abbreviation tag + + @param dw_abbrev + The Dwarf_Abbrev of interest. + @param dw_return_tag_number + Returns the tag value, for example DW_TAG_compile_unit. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_abbrev_tag(Dwarf_Abbrev dw_abbrev, + Dwarf_Half* dw_return_tag_number, + Dwarf_Error* dw_error); + +/*! @brief Get Abbreviation Code + + @param dw_abbrev + The Dwarf_Abbrev of interest. + @param dw_return_code_number + Returns the code for this abbreviation, a number + assigned to the abbreviation and unique within + the applicable CU. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_abbrev_code(Dwarf_Abbrev dw_abbrev, + Dwarf_Unsigned* dw_return_code_number, + Dwarf_Error* dw_error); + +/*! @brief Get Abbrev Children Flag + + @param dw_abbrev + The Dwarf_Abbrev of interest. + @param dw_return_flag + On success returns the flag TRUE (greater than zero) if the DIE + referencing the abbreviation has children, + else returns FALSE (zero). + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_abbrev_children_flag(Dwarf_Abbrev dw_abbrev, + Dwarf_Signed* dw_return_flag, + Dwarf_Error* dw_error); + +/*! @brief Get Abbrev Entry Details + + Most will will call with filter_outliers non-zero. + + @param dw_abbrev + The Dwarf_Abbrev of interest. + @param dw_indx + Valid dw_index values are 0 through dw_attr_count-1 + @param dw_filter_outliers + Pass non-zero (TRUE) so the function will check for unreasonable + abbreviation content and return DW_DLV_ERROR if such found. + If zero (FALSE) passed in + even a nonsensical attribute number and/or unknown DW_FORM + are allowed (used by dwarfdump to report the issue(s)). + @param dw_returned_attr_num + On success returns the attribute number, such as DW_AT_name + @param dw_returned_form + On success returns the attribute FORM, such as DW_FORM_udata + @param dw_returned_implicit_const + On success, if the dw_returned_form is DW_FORM_implicit_const + then dw_returned_implicit_const is the implicit const value, + but if not implicit const the return value is zero.. + @param dw_offset + On success returns the offset of the start of this attr/form + pair in the abbreviation section. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + If the abbreviation code for this Dwarf_Abbrev is 0 + it is a null abbreviation, the dw_indx is ignored, + and the function returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_abbrev_entry_b(Dwarf_Abbrev dw_abbrev, + Dwarf_Unsigned dw_indx, + Dwarf_Bool dw_filter_outliers, + Dwarf_Unsigned * dw_returned_attr_num, + Dwarf_Unsigned * dw_returned_form, + Dwarf_Signed * dw_returned_implicit_const, + Dwarf_Off * dw_offset, + Dwarf_Error * dw_error); + +/*! @} */ +/*! @defgroup string String Section .debug_str Details + + @{ + Shows just the section content in detail +*/ +/*! @brief Reading From a String Section + + @link dwsec_independentsec Reading The String Section @endlink + + @param dw_dbg + The Dwarf_Debug whose .debug_str section we want to access. + @param dw_offset + Pass in a a string offset. Start at 0, and + for the next call pass in dw_offset + plus dw_strlen_of_string plus 1. + @param dw_string + On success returns a pointer to a string from offset + dw_offset. Never dealloc or free this string. + @param dw_strlen_of_string + On success returns the strlen() of the string. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + If there is no such section or if dw_offset is >= + the section size it returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_str(Dwarf_Debug dw_dbg, + Dwarf_Off dw_offset, + char** dw_string, + Dwarf_Signed * dw_strlen_of_string, + Dwarf_Error* dw_error); + +/*! @} */ +/*! @defgroup str_offsets Str_Offsets section details + + @{ + Shows just the section content in detail. + Most library users will never call these, + as references to this is handled by the code + accessing some Dwarf_Attribute. + @link dwsec_independentsec Reading The Str_Offsets @endlink +*/ +/* Allows applications to print the .debug_str_offsets + section. + Beginning at starting_offset zero, + returns data about the first table found. + The value *next_table_offset is the value + of the next table (if any), one byte past + the end of the table whose data is returned.. + Returns DW_DLV_NO_ENTRY if the starting offset + is past the end of valid data. + + There is no guarantee that there are no non-0 nonsense + bytes in the section outside of useful tables, + so this can fail and return nonsense or + DW_DLV_ERROR if such garbage exists. +*/ + +/*! @brief Creates access to a .debug_str_offsets table + + @see examplestrngoffsets + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + @param dw_table_data + On success returns a pointer to an opaque structure + for use in further calls. + @param dw_error + On error dw_error is set to point to the error details. + @return + DW_DLV_OK etc. + If there is no .debug_str_offsets section it returns + DW_DLV_NO_ENTRY +*/ +DW_API int dwarf_open_str_offsets_table_access(Dwarf_Debug dw_dbg, + Dwarf_Str_Offsets_Table * dw_table_data, + Dwarf_Error * dw_error); + +/*! @brief Close str_offsets access, free table_data. + + @see examplestrngoffsets + + @param dw_table_data + @param dw_error + On error dw_error is set to point to the error details. + @return + DW_DLV_OK etc. + If there is no .debug_str_offsets section it returns + DW_DLV_NO_ENTRY + If it returns DW_DLV_ERROR there is nothing you can do + except report the error and, optionally, + call dwarf_dealloc_error to dealloc the error content + (and then set the dw_error to NULL as after the dealloc + the pointer is stale).. +*/ +DW_API int dwarf_close_str_offsets_table_access( + Dwarf_Str_Offsets_Table dw_table_data, + Dwarf_Error * dw_error); + +/*! @brief Iterate through the offsets tables + + @see examplestrngoffsets + + Access to the tables starts at offset zero. + The library progresses through the next table + automatically, keeping track internally to + know where it is. + + @param dw_table_data + Pass in an open Dwarf_Str_Offsets_Table. + @param dw_unit_length + On success returns a table unit_length field + @param dw_unit_length_offset + On success returns the section offset of the unit_length field. + @param dw_table_start_offset + On success returns the section offset of the array + of table entries. + @param dw_entry_size + On success returns the entry size (4 or 8) + @param dw_version + On success returns the value in the version field 5. + @param dw_padding + On success returns the zero value in the padding field. + @param dw_table_value_count + On success returns the number of table entries, each + of size dw_entry_size, in the table. + @param dw_error + On error dw_error is set to point to the error details. + @return + DW_DLV_OK + Returns DW_DLV_NO_ENTRY if there are no more entries. +*/ +DW_API int dwarf_next_str_offsets_table( + Dwarf_Str_Offsets_Table dw_table_data, + Dwarf_Unsigned * dw_unit_length, + Dwarf_Unsigned * dw_unit_length_offset, + Dwarf_Unsigned * dw_table_start_offset, + Dwarf_Half * dw_entry_size, + Dwarf_Half * dw_version, + Dwarf_Half * dw_padding, + Dwarf_Unsigned * dw_table_value_count, + Dwarf_Error * dw_error); + +/*! @brief Access to an individual str offsets table entry + + @see examplestrngoffsets + + @param dw_table_data + Pass in the open table pointer. + @param dw_index_to_entry + Pass in the entry number, 0 through dw_table_value_count-1 + for the active table + @param dw_entry_value + On success returns the value in that table entry, + an offset into a string table. + @param dw_error + On error dw_error is set to point to the error details. + @return + DW_DLV_OK + Returns DW_DLV_ERROR if dw_index_to_entry is + out of the correct range. +*/ +DW_API int dwarf_str_offsets_value_by_index( + Dwarf_Str_Offsets_Table dw_table_data, + Dwarf_Unsigned dw_index_to_entry, + Dwarf_Unsigned * dw_entry_value, + Dwarf_Error * dw_error); + +/*! @brief Reports final wasted-bytes count + + Reports the number of tables seen so far. + Not very interesting. + + @param dw_table_data + Pass in the open table pointer. + @param dw_wasted_byte_count + Always returns 0 at present. + @param dw_table_count + On success returns the total number of tables seen + so far in the section. + @param dw_error + On error dw_error is set to point to the error details. + @return + DW_DLV_OK etc. +*/ +DW_API int dwarf_str_offsets_statistics( + Dwarf_Str_Offsets_Table dw_table_data, + Dwarf_Unsigned * dw_wasted_byte_count, + Dwarf_Unsigned * dw_table_count, + Dwarf_Error * dw_error); + +/*! @} */ +/*! @defgroup dwarferror Dwarf_Error Functions + @{ + These functions aid in understanding handling. +*/ +/*! @brief What DW_DLE code does the error have? + @param dw_error + The dw_error should be non-null and a valid Dwarf_Error. + @return + A DW_DLE value of some kind. For example: DW_DLE_DIE_NULL. +*/ +DW_API Dwarf_Unsigned dwarf_errno(Dwarf_Error dw_error); +/*! @brief What message string is in the error? + @param dw_error + The dw_error should be non-null and a valid Dwarf_Error. + @return + A string with a message related to the error. +*/ +DW_API char* dwarf_errmsg(Dwarf_Error dw_error); +/*! @brief What message string is associated with the error number. + @param dw_errornum + The dw_error should be an integer from the DW_DLE set. + For example, DW_DLE_DIE_NULL. + @return + The generic string describing that error number. +*/ +DW_API char* dwarf_errmsg_by_number(Dwarf_Unsigned dw_errornum); + +/*! @brief Creating an error. + This is very rarely helpful. It lets the library + user create a Dwarf_Error and associate any string + with that error. Your code could then return + DW_DLV_ERROR to your caller when your intent + is to let your caller clean up whatever seems wrong. + @param dw_dbg + The relevant Dwarf_Debug. + @param dw_error + a Dwarf_Error is returned through this pointer. + @param dw_errmsg + The message string you provide. +*/ +DW_API void dwarf_error_creation(Dwarf_Debug dw_dbg , + Dwarf_Error * dw_error, char * dw_errmsg); + +/*! @brief Free (dealloc) an Dwarf_Error something created. + @param dw_dbg + The relevant Dwarf_Debug pointer. + @param dw_error + A pointer to a Dwarf_Error. The pointer is then stale + so you should immediately zero that pointer passed + in. +*/ +DW_API void dwarf_dealloc_error(Dwarf_Debug dw_dbg, + Dwarf_Error dw_error); +/*! @} */ + +/*! @defgroup dwarfdealloc Generic dwarf_dealloc Function + @{ + + Works for most dealloc needed. + + For easier to use versions see the following + @see dwarf_dealloc_attribute @see dwarf_dealloc_die + @see dwarf_dealloc_dnames @see dwarf_dealloc_error + @see dwarf_dealloc_fde_cie_list + @see dwarf_dealloc_frame_instr_head + @see dwarf_dealloc_macro_context @see dwarf_dealloc_ranges + @see dwarf_dealloc_rnglists_head + @see dwarf_dealloc_uncompressed_block + @see dwarf_globals_dealloc + @see dwarf_gnu_index_dealloc @see dwarf_loc_head_c_dealloc + @see dwarf_srclines_dealloc_b + +*/ +/*! @brief The generic dealloc (free) function. + It requires you know the correct DW_DLA value + to pass in, and in a few cases such is + not provided. The functions doing allocations + tell you which dealloc to use. + + @param dw_dbg + Must be a valid open Dwarf_Debug. + and must be the dw_dbg that the error + was created on. + If it is not the dealloc will do nothing. + @param dw_space + Must be an address returned directly + by a libdwarf call that the + call specifies as requiring + dealloc/free. If it is not + a segfault or address fault is possible. + @param dw_type + Must be a correct naming of the DW_DLA type. + If it is not the dealloc will do nothing. +*/ +DW_API void dwarf_dealloc(Dwarf_Debug dw_dbg, + void* dw_space, Dwarf_Unsigned dw_type); +/*! @} */ +/*! @defgroup debugsup Access to Section .debug_sup + @{ +*/ +/*! @brief Return basic .debug_sup section header data + + This returns basic data from the header + of a .debug_sup section. + See DWARF5 Section 7.3.6, + "DWARF Supplementary Object Files" + + Other sections present should be normal + DWARF5, so normal libdwarf calls should work. + We have no existing examples on hand, so + it is hard to know what really works. + + If there is no such section it returns + DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_get_debug_sup(Dwarf_Debug dw_dbg, + Dwarf_Half * dw_version, + Dwarf_Small * dw_is_supplementary, + char ** dw_filename, + Dwarf_Unsigned * dw_checksum_len, + Dwarf_Small ** dw_checksum, + Dwarf_Error * dw_error); +/*! @} */ + +/*! @defgroup debugnames Fast Access to .debug_names DWARF5 + @{ + + The section is new in DWARF5 supersedes .debug_pubnames and + .debug_pubtypes in DWARF2, DWARF3, and DWARF4. + + The functions provide a detailed reporting + of the content and structure of the table (so one + can build one's own search table) but they + are not particularly helpful for searching. + + A new function (more than one?) would be needed for convenient + searching. +*/ +/*! @brief Open access to a .debug_names table + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_starting_offset + Read this section starting at offset zero. + @param dw_dn + On success returns a pointer to a set of data + allowing access to the table. + @param dw_offset_of_next_table + On success returns + Offset just past the end of the the opened table. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + If there is no such table or if dw_starting_offset + is past the end of the section it returns + DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_dnames_header(Dwarf_Debug dw_dbg, + Dwarf_Off dw_starting_offset, + Dwarf_Dnames_Head * dw_dn, + Dwarf_Off * dw_offset_of_next_table, + Dwarf_Error * dw_error); + +/*! @brief Frees all the malloc data associated with dw_dn + @param dw_dn + A Dwarf_Dnames_Head pointer. + Callers should zero the pointer passed in + as soon as possible after this returns + as the pointer is then stale. +*/ +DW_API void dwarf_dealloc_dnames(Dwarf_Dnames_Head dw_dn); + +/*! @brief Access to the abbrevs table content + + Of interest mainly to debugging issues with compilers + or debuggers. + + @param dw_dn + A Dwarf_Dnames_Head pointer. + @param dw_index + An index (starting at zero) into a table + constructed of abbrev data. + These indexes are derived from abbrev data and + are not in the abbrev data itself. + @param dw_abbrev_offset + Returns the offset of the abbrev table entry for this names table + entry. + @param dw_abbrev_code + Returns the abbrev code for the abbrev at offset dw_abbrev_offset. + @param dw_abbrev_tag + Returns the tag for the abbrev at offset dw_abbrev_offset. + @param dw_array_size + The size you allocated in each of the following two arrays. + @param dw_idxattr_array + Pass in an array you allocated where the function + returns and array of + index attributes (DW_IDX) for this dw_abbrev_code. + The last attribute code in the array is zero. + @param dw_form_array + Pass in an array you allocated where the + function returns and array of + forms for this dw_abbrev_code (paralled to dw_idxattr_array). + The last form code in the array is zero. + @param dw_idxattr_count + Returns the actual idxattribute/form count (including the + terminating 0,0 pair. If the array_size passed in is less + than this value the array returned is incomplete. + Array entries needed. Might be larger than + dw_array_size, meaning not all entries could + be returned in your arrays. + @return + Returns DW_DLV_OK on success. + If the offset does not refer to a known + part of the abbrev table it returns DW_DLV_NO_ENTRY. + Never returns DW_DLV_ERROR. +*/ +DW_API int dwarf_dnames_abbrevtable(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned dw_index, + Dwarf_Unsigned *dw_abbrev_offset, + Dwarf_Unsigned *dw_abbrev_code, + Dwarf_Unsigned *dw_abbrev_tag, + Dwarf_Unsigned dw_array_size, + Dwarf_Half *dw_idxattr_array, + Dwarf_Half *dw_form_array, + Dwarf_Unsigned *dw_idxattr_count); + +/*! @brief Sizes and counts from the debug names table + + We do not describe these returned values. + Other than for dw_dn and dw_error + passing pointers you do not care about as NULL + is fine. Of course no value can be + returned through those passed as NULL. + + Any program referencing a names table will + need at least a few of these values. + + See DWARF5 section 6.1.1 "Lookup By Name" + particularly the graph page 139. + dw_comp_unit_count is K(k), + dw_local_type_unit_count is T(t), and + dw_foreign_type_unit_count is F(f). +*/ +DW_API int dwarf_dnames_sizes(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned * dw_comp_unit_count, + Dwarf_Unsigned * dw_local_type_unit_count, + Dwarf_Unsigned * dw_foreign_type_unit_count, + Dwarf_Unsigned * dw_bucket_count, + Dwarf_Unsigned * dw_name_count, + /* The following are counted in bytes */ + Dwarf_Unsigned * dw_abbrev_table_size, + Dwarf_Unsigned * dw_entry_pool_size, + Dwarf_Unsigned * dw_augmentation_string_size, + char ** dw_augmentation_string, + Dwarf_Unsigned * dw_section_size, + Dwarf_Half * dw_table_version, + Dwarf_Half * dw_offset_size, + Dwarf_Error * dw_error); + +/*! @brief Offsets from the debug names table + + We do not describe these returned values, which + refer to the .debug_names section. + + The header offset is a section offset. + The rest are offsets from the header. + + See DWARF5 section 6.1.1 "Lookup By Name" +*/ +DW_API int dwarf_dnames_offsets(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned * dw_header_offset, + Dwarf_Unsigned * dw_cu_table_offset, + Dwarf_Unsigned * dw_tu_local_offset, + Dwarf_Unsigned * dw_foreign_tu_offset, + Dwarf_Unsigned * dw_bucket_offset, + Dwarf_Unsigned * dw_hashes_offset, + Dwarf_Unsigned * dw_stringoffsets_offset, + Dwarf_Unsigned * dw_entryoffsets_offset, + Dwarf_Unsigned * dw_abbrev_table_offset, + Dwarf_Unsigned * dw_entry_pool_offset, + Dwarf_Error * dw_error); + +/*! @brief Each debug names cu list entry one at a time + + Indexes to the cu/tu/ tables start at 0. + + Some values in dw_offset are actually offsets, + such as for DW_IDX_die_offset. DW_IDX_compile_unit + and DW_IDX_type_unit are indexes into + the table specified by dw_type and are returned + through dw_offset field; + + @param dw_dn + The table of interest. + @param dw_type + Pass in the type, "cu" or "tu" + @param dw_index_number + For "cu" index range is 0 through K-1 + For "tu" index range is 0 through T+F-1 + @param dw_offset + Zero if it cannot be determined. + (check the return value!). + @param dw_sig + the Dwarf_Sig8 is filled in with a signature + if the TU index is T through T+F-1 + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_dnames_cu_table(Dwarf_Dnames_Head dw_dn, + const char * dw_type, + Dwarf_Unsigned dw_index_number, + Dwarf_Unsigned * dw_offset, + Dwarf_Sig8 * dw_sig, + Dwarf_Error * dw_error); + +/*! @brief Access to bucket contents. + @param dw_dn + The Dwarf_Dnames_Head of interest. + @param dw_bucket_number + Pass in a bucket number + Bucket numbers start at 0. + @param dw_index + On success returns the index of + the appropriate name entry. + Name entry indexes start at one, a zero + index means the bucket is unused. + @param dw_indexcount + On success returns the number of + name entries in the bucket. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + An out of range dw_index_number gets a return + if DW_DLV_NO_ENTRY +*/ +DW_API int dwarf_dnames_bucket(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned dw_bucket_number, + Dwarf_Unsigned * dw_index, + Dwarf_Unsigned * dw_indexcount, + Dwarf_Error * dw_error); + +/*! @brief Retrieve a name table entry + + Retrieve the name and other data + from a single name table entry. + + @param dw_dn + The table of interest. + @param dw_name_index + Pass in the desired index, start at one. + @param dw_bucket_number + On success returns a bucket number, zero + if no buckets present. + @param dw_hash_value + The hash value, all zeros if no hashes present + @param dw_offset_to_debug_str + The offset to the .debug_str section string. + @param dw_ptrtostr + if dw_ptrtostr non-null returns a pointer to + the applicable string here. + @param dw_offset_in_entrypool + Returns the offset in the entrypool + @param dw_abbrev_number + Returned from entrypool. + @param dw_abbrev_tag + Returned from entrypool abbrev data. + @param dw_array_size + Size of array you provide + to hold DW_IDX index attribute and + form numbers. + Possibly 10 suffices for practical purposes. + @param dw_idxattr_array + Array space you provide, for idx attribute numbers + (function will initialize it). + The final entry in the array will be 0. + @param dw_form_array + Array you provide, for form numbers + (function will initialize it). + The final entry in the array will be 0. + @param dw_idxattr_count + Array entries needed. Might be larger than + dw_array_size, meaning not all entries could + be returned in your array. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + If the index passed in is outside the valid range + returns DW_DLV_NO_ENTRY. +*/ +DW_API int dwarf_dnames_name(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned dw_name_index, + Dwarf_Unsigned * dw_bucket_number, + Dwarf_Unsigned * dw_hash_value, + Dwarf_Unsigned * dw_offset_to_debug_str, + char * * dw_ptrtostr, + Dwarf_Unsigned * dw_offset_in_entrypool, + Dwarf_Unsigned * dw_abbrev_number, + Dwarf_Half * dw_abbrev_tag, + Dwarf_Unsigned dw_array_size, + Dwarf_Half * dw_idxattr_array, + Dwarf_Half * dw_form_array, + Dwarf_Unsigned * dw_idxattr_count, + Dwarf_Error * dw_error); + +/*! @brief Return a the set of values from an entrypool entry + + Returns the basic data about an entrypool record + and enables correct calling of + dwarf_dnames_entrypool_values + (see below). The two-stage approach makes it + simple for callers to prepare for the number of + values that will be returned by + dwarf_dnames_entrypool_values() + + @param dw_dn + Pass in the debug names table of interest. + @param dw_offset_in_entrypool + The record offset (in the entry pool table) + of the first record of IDX attributes. Starts at zero. + @param dw_abbrev_code + On success returns the abbrev code of the idx attributes + for the pool entry. + @param dw_tag + On success returns the TAG of the DIE referred to + by this entrypool entry. + @param dw_value_count + On success returns the number of distinct + values imply by this entry. + @param dw_index_of_abbrev + On success returns the index of the abbrev index/form + pairs in the abbreviation table. + @param dw_offset_of_initial_value + On success returns the entry pool offset of the + sequence of bytes containing values, such as + a CU index or a DIE offset. + @param dw_error + The usual error detail record + @return + DW_DLV_OK is returned if the specified name + entry exists. + DW_DLV_NO_ENTRY is returned if the specified offset + is outside the size of the table. + DW_DLV_ERROR is returned in case of an internal error + or corrupt section content. +*/ +DW_API int dwarf_dnames_entrypool(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned dw_offset_in_entrypool, + Dwarf_Unsigned * dw_abbrev_code, + Dwarf_Half * dw_tag, + Dwarf_Unsigned * dw_value_count, + Dwarf_Unsigned * dw_index_of_abbrev, + Dwarf_Unsigned * dw_offset_of_initial_value, + Dwarf_Error * dw_error); + +/*! @brief Return the value set defined by this entry + + Call here after calling dwarf_dnames_entrypool + to provide data to call this function correctly. + + This retrieves the index attribute values + that identify a names table name. + + The caller allocates a set of arrays and the function fills + them in. If dw_array_idx_number[n] + is DW_IDX_type_hash then dw_array_of_signatures[n] + contains the hash. For other IDX values + dw_array_of_offsets[n] contains the value being returned. + + @param dw_dn + Pass in the debug names table of interest. + @param dw_index_of_abbrev + Pass in the abbreviation index. + @param dw_offset_in_entrypool_of_values + Pass in the offset of the values returned + by dw_offset_of_initial_value above. + @param dw_arrays_length + Pass in the array length of each of the following + four fields. The dw_value_count returned above + is what you need to use. + @param dw_array_idx_number + Create an array of Dwarf_Half values, dw_arrays_length + long, and pass a pointer to the first entry here. + @param dw_array_form + Create an array of Dwarf_Half values, dw_arrays_length + long, and pass a pointer to the first entry here. + @param dw_array_of_offsets + Create an array of Dwarf_Unsigned values, dw_arrays_length + long, and pass a pointer to the first entry here. + @param dw_array_of_signatures + Create an array of Dwarf_Sig8 structs, dw_arrays_length + long, and pass a pointer to the first entry here. + @param dw_offset_of_next_entrypool + On success returns the offset of the next entrypool. + A value here is usable in the next call to + dwarf_dnames_entrypool. + @param dw_single_cu + On success, if it is a single-cu name table there is + likely no DW_IDX_compile_unit. So we return TRUE + via this flag in such a case. + @param dw_cu_offset + On success, for a single-cu name table with no + DW_IDX_compile_unit this is set + to the CU offset from that single CU-table entry. + @param dw_error + The usual error detail record + @return + DW_DLV_OK is returned if the specified name + entry exists. + DW_DLV_NO_ENTRY is returned if the specified offset + is outside the size of the table. + DW_DLV_ERROR is returned in case of an internal error + or corrupt section content. +*/ +DW_API int dwarf_dnames_entrypool_values(Dwarf_Dnames_Head dw_dn, + Dwarf_Unsigned dw_index_of_abbrev, + Dwarf_Unsigned dw_offset_in_entrypool_of_values, + Dwarf_Unsigned dw_arrays_length, + Dwarf_Half *dw_array_idx_number, + Dwarf_Half *dw_array_form, + Dwarf_Unsigned *dw_array_of_offsets, + Dwarf_Sig8 *dw_array_of_signatures, + Dwarf_Bool *dw_single_cu, + Dwarf_Unsigned *dw_cu_offset, + Dwarf_Unsigned *dw_offset_of_next_entrypool, + Dwarf_Error *dw_error); + +/*! @} */ + +/*! @defgroup aranges Fast Access to a CU given a code address + @{ +*/ +/*! @brief Get access to CUs given code addresses + + This intended as a fast-access to tie code addresses + to CU dies. The data is in the .debug_aranges section. + which may appear in DWARF2,3,4, or DWARF5. + + @see exampleu + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_aranges + On success returns a pointer to an array + of Dwarf_Arange pointers. + @param dw_arange_count + On success returns a count of the length of the array. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if there is no such section. +*/ +DW_API int dwarf_get_aranges(Dwarf_Debug dw_dbg, + Dwarf_Arange** dw_aranges, + Dwarf_Signed * dw_arange_count, + Dwarf_Error* dw_error); + +/*! @brief Find a range given a code address + + @param dw_aranges + Pass in a pointer to the first entry in the aranges array + of pointers. + @param dw_arange_count + Pass in the dw_arange_count, the count for the array. + @param dw_address + Pass in the code address of interest. + @param dw_returned_arange + On success, returns the particular arange that + holds that address. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if there is no such code + address present in the section. +*/ +DW_API int dwarf_get_arange(Dwarf_Arange* dw_aranges, + Dwarf_Unsigned dw_arange_count, + Dwarf_Addr dw_address, + Dwarf_Arange * dw_returned_arange, + Dwarf_Error* dw_error); + +/*! @brief Given an arange return its CU DIE offset. + + @param dw_arange + The specific arange of interest. + @param dw_return_offset + The CU DIE offset (in .debug_info) applicable + to this arange.. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_cu_die_offset(Dwarf_Arange dw_arange, + Dwarf_Off * dw_return_offset, + Dwarf_Error* dw_error); + +/*! @brief Given an arange return its CU header offset. + + @param dw_arange + The specific arange of interest. + @param dw_return_cu_header_offset + The CU header offset (in .debug_info) applicable + to this arange. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_arange_cu_header_offset(Dwarf_Arange dw_arange, + Dwarf_Off * dw_return_cu_header_offset, + Dwarf_Error* dw_error); + +/*! @brief Get the data in an arange entry. + + @param dw_arange + The specific arange of interest. + @param dw_segment + On success and if segment_entry_size is non-zero + this returns the segment number + from the arange. + @param dw_segment_entry_size + On success returns the segment entry size + from the arange. + @param dw_start + On success returns the low address this arange + refers to. + @param dw_length + On success returns the length, in bytes of the + code area this arange refers to. + @param dw_cu_die_offset + On success returns the .debug_info section offset + the arange refers to. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_get_arange_info_b(Dwarf_Arange dw_arange, + Dwarf_Unsigned* dw_segment, + Dwarf_Unsigned* dw_segment_entry_size, + Dwarf_Addr * dw_start, + Dwarf_Unsigned* dw_length, + Dwarf_Off * dw_cu_die_offset, + Dwarf_Error * dw_error ); +/*! @} */ + +/*! @defgroup pubnames Fast Access to .debug_pubnames and more. + + @{ + @link dwsec_pubnames Pubnames and Pubtypes overview @endlink + + These functions each read one of a set of sections designed + for fast access by name, but they are not always emitted as + they each have somewhat limited and inflexible + capabilities. So you may not see many of these. + + All have the same set of functions with a name + reflecting the specific object section involved. + Only the first, of type Dwarf_Global, is documented + here in full detail as the others do the same jobs + just each for their applicable object section.. + +*/ + +/*! @brief Global name space operations, .debug_pubnames access + + This accesses .debug_pubnames and .debug_names sections. + Section .debug_pubnames is defined in DWARF2, DWARF3, + and DWARF4. + Section .debug_names is defined in DWARF5. + + The code here, as of 0.4.3, September 3 2022, + returns data from either section. + + @see examplef + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_globals + On success returns an array of pointers to opaque + structs.. + @param dw_number_of_globals + On success returns the number of entries in the array. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if the section is not present. +*/ +DW_API int dwarf_get_globals(Dwarf_Debug dw_dbg, + Dwarf_Global** dw_globals, + Dwarf_Signed * dw_number_of_globals, + Dwarf_Error * dw_error); + +#define DW_GL_GLOBALS 0 /* .debug_pubnames and .debug_names */ +#define DW_GL_PUBTYPES 1 /* .debug_pubtypes */ +/* the following are IRIX ONLY */ +#define DW_GL_FUNCS 2 /* .debug_funcnames */ +#define DW_GL_TYPES 3 /* .debug_typenames */ +#define DW_GL_VARS 4 /* .debug_varnames */ +#define DW_GL_WEAKS 5 /* .debug_weaknames */ + +/* Same function name as 0.5.0 and earlier, but + the data type changes to Dwarf_Global */ +DW_API int dwarf_get_pubtypes(Dwarf_Debug dw_dbg, + Dwarf_Global** dw_pubtypes, + Dwarf_Signed * dw_number_of_pubtypes, + Dwarf_Error * dw_error); + +/*! @brief Allocate Any Fast Access DWARF2-DWARF4 + + This interface new in 0.6.0. Simplfies access + by replace dwarf_get_pubtypes, dwarf_get_funcs, + dwarf_get_types, dwarfget_vars, and dwarf_get_weaks + with a single set of types. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_requested_section + Pass in one of the values DW_GL_GLOBALS through + DW_GL_WEAKS to select the section to extract + data from. + @param dw_contents + On success returns an array of pointers to opaque + structs. + @param dw_count + On success returns the number of entries in the array. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if the section is not present. + +*/ +DW_API int dwarf_globals_by_type(Dwarf_Debug dw_dbg, + int dw_requested_section, + Dwarf_Global **dw_contents, + Dwarf_Signed *dw_count, + Dwarf_Error *dw_error); + +/*! @brief Dealloc the Dwarf_Global data + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_global_like + The array of globals/types/etc data to dealloc (free). + @param dw_count + The number of entries in the array. +*/ + +DW_API void dwarf_globals_dealloc(Dwarf_Debug dw_dbg, + Dwarf_Global* dw_global_like, + Dwarf_Signed dw_count); + +/*! @brief Return the name of a global-like data item + + @param dw_global + The Dwarf_Global of interest. + @param dw_returned_name + On success a pointer to the name (a null-terminated + string) is returned. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_globname(Dwarf_Global dw_global, + char ** dw_returned_name, + Dwarf_Error* dw_error); + +/*! @brief Return the DIE offset of a global data item + + @param dw_global + The Dwarf_Global of interest. + @param dw_die_offset + On success a the section-global DIE offset of a + data item is returned. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_global_die_offset(Dwarf_Global dw_global, + Dwarf_Off * dw_die_offset, + Dwarf_Error * dw_error); + +/*! @brief Return the CU header data of a global data item + + A CU header offset is rarely useful. + + @param dw_global + The Dwarf_Global of interest. + @param dw_cu_header_offset + On success a the section-global offset of + a CU header is returned. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_global_cu_offset(Dwarf_Global dw_global, + Dwarf_Off* dw_cu_header_offset, + Dwarf_Error* dw_error); + +/*! @brief Return the name and offsets of a global entry. + + @param dw_global + The Dwarf_Global of interest. + @param dw_returned_name + On success a pointer to the name (a null-terminated + string) is returned. + @param dw_die_offset + On success a the section-global DIE offset of + the global with the name. + @param dw_cu_die_offset + On success a the section-global offset of + the relevant CU DIE is returned. + @param dw_error + On error dw_error is set to point to the error details. + @return + The usual value: DW_DLV_OK etc. +*/ +DW_API int dwarf_global_name_offsets(Dwarf_Global dw_global, + char ** dw_returned_name, + Dwarf_Off* dw_die_offset, + Dwarf_Off* dw_cu_die_offset, + Dwarf_Error* dw_error); + +/*! @brief Return the DW_TAG number of a global entry. + + @param dw_global + The Dwarf_Global of interest. + @return + If the Dwarf_Global refers to a global from + the .debug_names section the return value is the + DW_TAG for the DIE in the global entry, for + example DW_TAG_subprogram. + In case of error or if the section for this global + was not .debug_names zero is returned. +*/ +DW_API Dwarf_Half dwarf_global_tag_number(Dwarf_Global dw_global); + +/*! @brief For more complete globals printing. + + For each CU represented in .debug_pubnames, etc, + there is a .debug_pubnames header. For any given + Dwarf_Global this returns the content of the applicable + header. This does not include header information + from any .debug_names headers. + + The function declaration changed at version 0.6.0. +*/ +DW_API int dwarf_get_globals_header(Dwarf_Global dw_global, + int * dw_category, /* DW_GL_GLOBAL for example */ + Dwarf_Off * dw_offset_pub_header, + Dwarf_Unsigned * dw_length_size, + Dwarf_Unsigned * dw_length_pub, + Dwarf_Unsigned * dw_version, + Dwarf_Unsigned * dw_header_info_offset, + Dwarf_Unsigned * dw_info_length, + Dwarf_Error * dw_error); + +/*! @brief A flag for dwarfdump on pubnames, pubtypes etc. + + Sets a flag in the dbg. Always returns DW_DLV_OK. + Applies to all the sections of this kind: + pubnames, pubtypes, funcs, typenames,vars, weaks. + Ensures empty content (meaning no + offset/name tuples, but with a header) + for a CU shows up rather than + being suppressed. + + Primarily useful if one wants to note any pointless + header data in the section. + + @link dwsec_pubnames Pubnames and Pubtypes overview @endlink + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_flag + Must be the value one. + @return + Returns DW_DLV_OK. Always. +*/ +DW_API int dwarf_return_empty_pubnames(Dwarf_Debug dw_dbg, + int dw_flag); + +/*! @} */ + +/*! @defgroup gnupubnames Fast Access to GNU .debug_gnu_pubnames + @{ + Section .debug_gnu_pubnames or .debug_gnu_pubtypes. + + This is a section created for and used by the GNU gdb + debugger to access DWARF information. + + Not part of standard DWARF. + +*/ +/*! @brief Access to .debug_gnu_pubnames or .debug_gnu_pubtypes + + Call this to get access. + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + @param dw_which_section + Pass in TRUE to access .debug_gnu_pubnames. + Pass in FALSE to access .debug_gnu_typenames. + @param dw_head + On success, set to a pointer to a head record + allowing access to all the content of the section. + @param dw_index_block_count_out + On success, set to a count of the number of blocks + of data available. + @param dw_error + @return + Returns DW_DLV_OK, DW_DLV_NO_ENTRY (if the section does + not exist or is empty), or, in case of + an error reading the section, DW_DLV_ERROR. +*/ +DW_API int dwarf_get_gnu_index_head(Dwarf_Debug dw_dbg, + Dwarf_Bool dw_which_section, + Dwarf_Gnu_Index_Head *dw_head, + Dwarf_Unsigned *dw_index_block_count_out, + Dwarf_Error *dw_error); +/*! @brief Free resources of .debug_gnu_pubnames .debug_gnu_pubtypes + + Call this to deallocate all memory used by dw_head. + + @param dw_head + Pass in the Dwarf_Gnu_Index_head whose data is to be deallocated. +*/ +DW_API void dwarf_gnu_index_dealloc(Dwarf_Gnu_Index_Head dw_head); +/*! @brief Access a particular block. + @param dw_head + Pass in the Dwarf_Gnu_Index_head interest. + @param dw_number + Pass in the block number of the block of interest. + 0 through dw_index_block_count_out-1. + @param dw_block_length + On success set to the length of the data in this block, + in bytes. + @param dw_version + On success set to the version number of the block. + @param dw_offset_into_debug_info + On success set to the offset, in .debug_info, of + the data for this block. + The returned offset may be outside the bounds + of the actual .debug_info section, sucn a possibility + does not cause the function to return DW_DLV_ERROR. + @param dw_size_of_debug_info_area + On success set to the size in bytes, in .debug_info, of + the area this block refers to. + The returned dw_ dw_size_of_debug_info_are + plus dw_offset_into_debug_info may be outside the bounds + of the actual .debug_info section, sucn a possibility + does not cause the function to return DW_DLV_ERROR. + Use dwarf_get_section_max_offsets_d() + to learn the size of .debug_info and optionally other + sections as well. + @param dw_count_of_index_entries + On success set to the count of index entries in + this particlular block number. + @param dw_error + On error dw_error is set to point to the error details. + @return + Returns DW_DLV_OK, DW_DLV_NO_ENTRY (if the section does + not exist or is empty), or, in case of + an error reading the section, DW_DLV_ERROR. +*/ + +DW_API int dwarf_get_gnu_index_block(Dwarf_Gnu_Index_Head dw_head, + Dwarf_Unsigned dw_number, + Dwarf_Unsigned *dw_block_length, + Dwarf_Half *dw_version, + Dwarf_Unsigned *dw_offset_into_debug_info, + Dwarf_Unsigned *dw_size_of_debug_info_area, + Dwarf_Unsigned *dw_count_of_index_entries, + Dwarf_Error *dw_error); + +/*! @brief Access a particular entry of a block. + + Access to a single entry in a block. + + @param dw_head + Pass in the Dwarf_Gnu_Index_head interest. + @param dw_number + Pass in the block number of the block of interest. + 0 through dw_index_block_count_out-1. + @param dw_entrynumber + Pass in the entry number of the entry of interest. + 0 through dw_count_of_index_entries-1. + @param dw_offset_in_debug_info + On success set to the offset in .debug_info + relevant to this entry. + @param dw_name_string + On success set to the size in bytes, in .debug_info, of + the area this block refersto. + @param dw_flagbyte + On success set to the entry flag byte content. + @param dw_staticorglobal + On success set to the entry static/global letter. + @param dw_typeofentry + On success set to the type of entry. + @param dw_error + On error dw_error is set to point to the error details. + @return + Returns DW_DLV_OK, DW_DLV_NO_ENTRY (if the section does + not exist or is empty), or, in case of + an error reading the section, DW_DLV_ERROR. +*/ +DW_API int dwarf_get_gnu_index_block_entry( + Dwarf_Gnu_Index_Head dw_head, + Dwarf_Unsigned dw_blocknumber, + Dwarf_Unsigned dw_entrynumber, + Dwarf_Unsigned *dw_offset_in_debug_info, + const char **dw_name_string, + unsigned char *dw_flagbyte, + unsigned char *dw_staticorglobal, + unsigned char *dw_typeofentry, + Dwarf_Error *dw_error); + +/*! @} */ + +/*! @defgroup gdbindex Fast Access to Gdb Index + + @{ + Section .gdb_index + + This is a section created for and used by the GNU gdb + debugger to access DWARF information. + + Not part of standard DWARF. + + @see https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html#Index-Section-Format + + Version 8 built by gdb, so type entries are ok as is. + Version 7 built by the 'gold' linker and type index + entries for a CU must be derived otherwise, the + type index is not correct... Earlier versions + cannot be read correctly by the functions here. + + The functions here make it possible to + print the section content in detail, there + is no search function here. + +*/ +/*! @brief Open access to the .gdb_index section. + + The section is a single table one thinks. + + @see examplew + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_gdbindexptr + On success returns a pointer to make access + to table details possible. + @param dw_version + On success returns the table version. + @param dw_cu_list_offset + On success returns the offset of the cu_list + in the section. + @param dw_types_cu_list_offset + On success returns the offset of the types cu_list + in the section. + @param dw_address_area_offset + On success returns the area pool offset. + @param dw_symbol_table_offset + On success returns the symbol table offset. + @param dw_constant_pool_offset + On success returns the constant pool offset. + @param dw_section_size + On success returns section size. + @param dw_section_name + On success returns section name. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if the section is absent. +*/ +DW_API int dwarf_gdbindex_header(Dwarf_Debug dw_dbg, + Dwarf_Gdbindex * dw_gdbindexptr, + Dwarf_Unsigned * dw_version, + Dwarf_Unsigned * dw_cu_list_offset, + Dwarf_Unsigned * dw_types_cu_list_offset, + Dwarf_Unsigned * dw_address_area_offset, + Dwarf_Unsigned * dw_symbol_table_offset, + Dwarf_Unsigned * dw_constant_pool_offset, + Dwarf_Unsigned * dw_section_size, + const char ** dw_section_name, + Dwarf_Error * dw_error); + +/*! @brief Free (dealloc) all allocated Dwarf_Gdbindex memory + It should named dwarf_dealloc_gdbindex + + @param dw_gdbindexptr + Pass in a valid dw_gdbindexptr and + on return assign zero to dw_gdbindexptr as it is stale. +*/ +DW_API void dwarf_dealloc_gdbindex(Dwarf_Gdbindex dw_gdbindexptr); + +/*! @brief Return the culist array length + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_list_length + On success returns the array length of the cu list. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_culist_array( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned * dw_list_length, + Dwarf_Error * dw_error); + +/*! @brief For a CU entry in the list return the offset and length + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_entryindex + Pass in a number from 0 through dw_list_length-1. + If dw_entryindex is too large for the array + the function returns DW_DLV_NO_ENTRY. + @param dw_cu_offset + On success returns the CU offet for this list entry. + @param dw_cu_length + On success returns the CU length(in bytes) + for this list entry. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_culist_entry( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_entryindex, + Dwarf_Unsigned * dw_cu_offset, + Dwarf_Unsigned * dw_cu_length, + Dwarf_Error * dw_error); + +/*! @brief Return the types culist array length + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_types_list_length + On success returns the array length of the + types cu list. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_types_culist_array( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned * dw_types_list_length, + Dwarf_Error * dw_error); + +/* entryindex: 0 to types_list_length -1 */ +/*! @brief For a types CU entry in the list + returns the offset and length + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_types_entryindex + Pass in a number from 0 through dw_list_length-1. + If the value is greater than dw_list_length-1 + the function returns DW_DLV_NO_ENTRY. + @param dw_cu_offset + On success returns the types CU offet for this list entry. + @param dw_tu_offset + On success returns the tu offet for this list entry. + @param dw_type_signature + On success returns the type unit offset for this + entry if the type has a signature. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_types_culist_entry( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_types_entryindex, + Dwarf_Unsigned * dw_cu_offset, + Dwarf_Unsigned * dw_tu_offset, + Dwarf_Unsigned * dw_type_signature, + Dwarf_Error * dw_error); + +/*! @brief Get access to gdbindex address area + + @see examplewgdbindex + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_addressarea_list_length + On success returns the number of entries in the + addressarea. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_addressarea( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned * dw_addressarea_list_length, + Dwarf_Error * dw_error); + +/*! @brief Get an address area value + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_entryindex + Pass in an index, 0 through dw_addressarea_list_length-1. + addressarea. + @param dw_low_address + On success returns the low address for the entry. + @param dw_high_address + On success returns the high address for the entry. + @param dw_cu_index + On success returns the index to the cu for the entry. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_addressarea_entry( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_entryindex, + Dwarf_Unsigned * dw_low_address, + Dwarf_Unsigned * dw_high_address, + Dwarf_Unsigned * dw_cu_index, + Dwarf_Error * dw_error); + +/*! @brief Get access to the symboltable array + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_symtab_list_length + On success returns the number of entries in the + symbol table + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_symboltable_array( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned * dw_symtab_list_length, + Dwarf_Error * dw_error); + +/*! @brief Access individual symtab entry + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_entryindex + Pass in a valid index in the range 0 through + dw_symtab_list_length-1 + If the value is greater than dw_symtab_list_length-1 + the function returns DW_DLV_NO_ENTRY; + @param dw_string_offset + On success returns the string offset in the + appropriate string section. + @param dw_cu_vector_offset + On success returns the CU vector offset. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_symboltable_entry( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_entryindex, + Dwarf_Unsigned * dw_string_offset, + Dwarf_Unsigned * dw_cu_vector_offset, + Dwarf_Error * dw_error); + +/*! @brief Get access to a cuvector + + @see examplex + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_cuvector_offset + Pass in the offset, dw_cu_vector_offset. + @param dw_innercount + On success returns the number of CUs in + the cuvector instance array. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. + +*/ +DW_API int dwarf_gdbindex_cuvector_length( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_cuvector_offset, + Dwarf_Unsigned * dw_innercount, + Dwarf_Error * dw_error); + +/*! @brief Get access to a cuvector + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_cuvector_offset_in + Pass in the value of dw_cuvector_offset + @param dw_innerindex + Pass in the index of the CU vector in, from 0 + through dw_innercount-1. + @param dw_field_value + On success returns a field of bits. To expand the bits + call dwarf_gdbindex_cuvector_instance_expand_value. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_cuvector_inner_attributes( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_cuvector_offset_in, + Dwarf_Unsigned dw_innerindex, + Dwarf_Unsigned * dw_field_value, + Dwarf_Error * dw_error); + +/*! @brief Expand the bit fields in a cuvector entry + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_field_value + Pass in the dw_field_value returned by + dwarf_gdbindex_cuvector_inner_attributes. + @param dw_cu_index + On success returns the CU index from the dw_field_value + @param dw_symbol_kind + On success returns the symbol kind (see + the sourceware page. Kinds are TYPE, VARIABLE, + or FUNCTION. + @param dw_is_static + On success returns non-zero if the entry is a static + symbol (file-local, as in C or C++), otherwise + it returns non-zero and the symbol is global. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_cuvector_instance_expand_value( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_field_value, + Dwarf_Unsigned * dw_cu_index, + Dwarf_Unsigned * dw_symbol_kind, + Dwarf_Unsigned * dw_is_static, + Dwarf_Error * dw_error); + +/*! @brief Retrieve a symbol name from the index data. + + @param dw_gdbindexptr + Pass in the Dwarf_Gdbindex pointer of interest. + @param dw_stringoffset + Pass in the string offset returned by + dwarf_gdbindex_symboltable_entry + @param dw_string_ptr + On success returns a a pointer to the null-terminated + string. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gdbindex_string_by_offset( + Dwarf_Gdbindex dw_gdbindexptr, + Dwarf_Unsigned dw_stringoffset, + const char ** dw_string_ptr, + Dwarf_Error * dw_error); +/*! @} */ + +/*! @defgroup splitdwarf Fast Access to Split Dwarf (Debug Fission) + @{ +*/ +/*! @brief Access a .debug_cu_index or dw_tu_index section + + These sections are in a DWARF5 package file, a file normally + named with the .dwo or .dwp extension.. + See DWARF5 section 7.3.5.3 Format of the CU and TU + Index Sections. + + @param dw_dbg + Pass in the Dwarf_Debug of interest + @param dw_section_type + Pass in a pointer to either "cu" or "tu". + @param dw_xuhdr + On success, returns a pointer usable in further + calls. + @param dw_version_number + On success returns five. + @param dw_section_count + On success returns the number of entries + in the table of section counts. Referred to as @b N. + @param dw_units_count + On success returns the number of compilation units or + type units in the index. Referred to as @b U. + @param dw_hash_slots_count + On success returns the number of slots in the hash table. + Referred to as @b S. + @param dw_sect_name + On success returns a pointer to the name of the section. + Do not free/dealloc the returned pointer. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. + Returns DW_DLV_NO_ENTRY if the section requested + is not present. +*/ +DW_API int dwarf_get_xu_index_header(Dwarf_Debug dw_dbg, + const char * dw_section_type, /* "tu" or "cu" */ + Dwarf_Xu_Index_Header * dw_xuhdr, + Dwarf_Unsigned * dw_version_number, + Dwarf_Unsigned * dw_section_count, + Dwarf_Unsigned * dw_units_count, + Dwarf_Unsigned * dw_hash_slots_count, + const char ** dw_sect_name, + Dwarf_Error * dw_error); + +/*! @brief Dealloc (free) memory associated with dw_xuhdr. + + Should be named dwarf_dealloc_xuhdr instead. + @param dw_xuhdr + Dealloc (free) all associated memory. + The caller should zero the passed in value + on return as it is then a stale value. +*/ +DW_API void dwarf_dealloc_xu_header(Dwarf_Xu_Index_Header dw_xuhdr); + +/*! @brief Return basic information about a Dwarf_Xu_Index_Header + @param dw_xuhdr + Pass in an open header pointer. + @param dw_typename + On success returns a pointer to + the immutable string "tu" or "cu". Do not free. + @param dw_sectionname + On success returns a pointer to the section name + in the object file. Do not free. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_xu_index_section_type( + Dwarf_Xu_Index_Header dw_xuhdr, + const char ** dw_typename, + const char ** dw_sectionname, + Dwarf_Error * dw_error); + +/*! @brief Get a Hash Entry + + @see examplez/x + + @param dw_xuhdr + Pass in an open header pointer. + @param dw_index + Pass in the index of the entry you wish. + Valid index values are 0 through @b S-1. + If the dw_index passed in is outside the valid range + the functionj + @param dw_hash_value + Pass in a pointer to a Dwarf_Sig8. + On success the hash struct is filled in with + the 8 byte hash value. + @param dw_index_to_sections + On success returns the offset/size table + index for this hash entry. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK on success. + If the dw_index passed in is outside the valid range + the function it returns DW_DLV_NO_ENTRY + (before version 0.7.0 it returned DW_DLV_ERROR, + though nothing mentioned that). + In case of error it returns DW_DLV_ERROR. + If dw_error is non-null returns error details through + dw_error (the usual error behavior). + +*/ +DW_API int dwarf_get_xu_hash_entry(Dwarf_Xu_Index_Header dw_xuhdr, + Dwarf_Unsigned dw_index, + Dwarf_Sig8 * dw_hash_value, + Dwarf_Unsigned * dw_index_to_sections, + Dwarf_Error * dw_error); + +/* Columns 0 to L-1, valid. */ +/*! @brief get DW_SECT value for a column. + + @see exampleza + + @param dw_xuhdr + Pass in an open header pointer. + @param dw_column_index + The section names are in row zero of the + table so we do not mention the row number at all. + Pass in the column of the entry you wish. + Valid dw_column_index values are 0 through @b N-1. + @param dw_SECT_number + On success returns DW_SECT_INFO or other section + id as appears in dw_column_index. + @param dw_SECT_name + On success returns a pointer to the string for + with the section name. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_xu_section_names(Dwarf_Xu_Index_Header dw_xuhdr, + Dwarf_Unsigned dw_column_index, + Dwarf_Unsigned* dw_SECT_number, + const char ** dw_SECT_name, + Dwarf_Error * dw_error); + +/*! @brief Get row data (section data) for a row and column + + @param dw_xuhdr + Pass in an open header pointer. + @param dw_row_index + Pass in a row number , 1 through @b U + @param dw_column_index + Pass in a column number , 0 through @b N-1 + @param dw_sec_offset + On success returns the section offset of + the section whose name dwarf_get_xu_section_names + returns. + @param dw_sec_size + On success returns the section size of + the section whose name dwarf_get_xu_section_names + returns. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_xu_section_offset( + Dwarf_Xu_Index_Header dw_xuhdr, + Dwarf_Unsigned dw_row_index, + Dwarf_Unsigned dw_column_index, + Dwarf_Unsigned* dw_sec_offset, + Dwarf_Unsigned* dw_sec_size, + Dwarf_Error * dw_error); + +/*! @brief Get debugfission data for a Dwarf_Die + + For any Dwarf_Die in a compilation unit, return + the debug fission table data through dw_percu_out. + Usually applications + will pass in the CU die. + Calling code should zero all of the + struct Dwarf_Debug_Fission_Per_CU_s before calling this. + If there is no debugfission data this returns + DW_DLV_NO_ENTRY (only .dwp objects have debugfission data) + @param dw_die + Pass in a Dwarf_Die pointer, Usually pass in a CU DIE + pointer. + @param dw_percu_out + Pass in a pointer to a zeroed structure. + On success the function fills in the structure. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_debugfission_for_die(Dwarf_Die dw_die, + Dwarf_Debug_Fission_Per_CU * dw_percu_out, + Dwarf_Error * dw_error); + +/*! @brief Given a hash signature find per-cu Fission data + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + @param dw_hash_sig + Pass in a pointer to a Dwarf_Sig8 containing + a hash value of interest. + @param dw_cu_type + Pass in the type, a string. Either "cu" or "tu". + @param dw_percu_out + Pass in a pointer to a zeroed structure. + On success the function fills in the structure. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_debugfission_for_key(Dwarf_Debug dw_dbg, + Dwarf_Sig8 * dw_hash_sig, + const char * dw_cu_type, + Dwarf_Debug_Fission_Per_CU * dw_percu_out, + Dwarf_Error * dw_error); + +/* END debugfission dwp .debug_cu_index + and .debug_tu_indexmeaningfumeaningfu operations. */ + +/*! @} */ + +/*! @defgroup gnudebuglink Access GNU .gnu_debuglink, build-id. + + @{ + When DWARF is separate from a normal shared object. + Has nothing to do with split-dwarf/debug-fission. +*/ + +/*! @brief Find a separated DWARF object file + + .gnu_debuglink and/or the section .note.gnu.build-id. + + Unless something is odd and you want to know details + of the two sections you will not need this function. + + @see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html + + @see exampledebuglink + + If no debuglink then name_returned,crc_returned and + debuglink_path_returned will get set 0 through the pointers. + + If no .note.gnu.build-id then buildid_length_returned, + and buildid_returned will be set 0 through the pointers. + + In most cases output arguments can be passed as zero + and the function will simply not return data through + such arguments. Useful if you only care about some + of the data potentially returned. + + Caller frees space returned by debuglink_fullpath_returned. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_debuglink_path_returned + On success returns a pointer to + a path in the debuglink section. Do not free! + @param dw_crc_returned + On success returns a pointer to a 4 byte area + through the pointer. + @param dw_debuglink_fullpath_returned + On success returns a pointer to a full path + computed from debuglink data of + a correct path to a file with DWARF sections. Free this string + when no longer of interest. + @param dw_debuglink_path_length_returned + On success returns the strlen() of + dw_debuglink_fullpath_returned . + + @param dw_buildid_type_returned + On success returns a pointer to integer with + a type code. See the buildid definition. + @param dw_buildid_owner_name_returned + On success returns a pointer to the owner + name from the buildid section. Do not free this. + @param dw_buildid_returned + On success returns a pointer to a sequence of bytes + containing the buildid. + @param dw_buildid_length_returned + On success this is set to the length of the + set of bytes pointed to by dw_buildid_returned . + @param dw_paths_returned + On success returns a pointer to an array of + pointers to strings, each with a global path. + It actually points to an array of pointers + followed by a blob of strings, and freeing + all of that just means calling free(dw_paths_returned). + @param dw_paths_length_returned + On success returns the length of the array of string + pointers dw_paths_returned points at. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_gnu_debuglink(Dwarf_Debug dw_dbg, + char ** dw_debuglink_path_returned, + unsigned char ** dw_crc_returned, + char ** dw_debuglink_fullpath_returned, + unsigned int * dw_debuglink_path_length_returned, + unsigned int * dw_buildid_type_returned, + char ** dw_buildid_owner_name_returned, + unsigned char ** dw_buildid_returned, + unsigned int * dw_buildid_length_returned, + char *** dw_paths_returned, + unsigned int * dw_paths_length_returned, + Dwarf_Error* dw_error); + +/*! @brief Suppressing crc calculations + + The .gnu_debuglink section contains a compilation-system + created crc (4 byte) value. If dwarf_init_path[_dl]() + is called such a section can result in the reader/consumer + calculating the crc value of a different object file. + Which on a large object file could seem slow. + See https://en.wikipedia.org/wiki/Cyclic_redundancy_check + + When one is confident that any debug_link file found + is the appropriate one one can call dwarf_suppress_debuglink_crc + with a non-zero argument and any dwarf_init_path[_dl] call + will skip debuglink crc calculations and just assume + the crc would match whenever it applies. + This is a global flag, applies to all Dwarf_Debug opened + after the call in the program execution. + + Does not apply to the .note.gnu.buildid section as + that section never implies the reader/consumer needs + to do a crc calculation. + + @param dw_suppress + Pass in 1 to suppress future calculation of crc values + to verify a debuglink target is correct. So use + only when you know this is safe. + Pass in 0 to ensure future dwarf_init_path_dl calls + compute debuglink CRC values as required. + @return + Returns the previous value of the global flag. + + @link dwsec_separatedebug Details on separate DWARF object access @endlink +*/ +DW_API int dwarf_suppress_debuglink_crc(int dw_suppress); + +/*! @brief Adding debuglink global paths + + Only really inside dwarfexample/dwdebuglink.c + so we can show all that is going on. + The following has the explanation for how debuglink + and global paths interact. + @see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + @param dw_pathname + Pass in a pathname to add to the list of global paths + used by debuglink. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_add_debuglink_global_path(Dwarf_Debug dw_dbg, + const char * dw_pathname, + Dwarf_Error* dw_error); + +/*! @brief Crc32 used for debuglink crc calculation. + + Caller passes pointer to array of 4 unsigned char + provided by the caller and if this returns DW_DLV_OK + that is filled in. + + @param dw_dbg + Pass in an open dw_dbg. When you attempted + to open it, and it succeeded then pass the + it via the Dwarf_Debug + The function reads the file into memory + and performs a crc calculation. + @param dw_crcbuf + Pass in a pointer to a 4 byte area to hold + the returned crc, on success the function + puts the 4 bytes there. + @param dw_error + The usual pointer to return error details. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_crc32(Dwarf_Debug dw_dbg, + unsigned char * dw_crcbuf, + Dwarf_Error * dw_error); + +/*! @brief Public interface to the real crc calculation + + It is unlikely this is useful. The calculation will + not produce a return matching that of Linux/Macos if + the compiler implements unsigned int or signed int as + 16 bits long. + + @param dw_buf + Pass in a pointer to some bytes on which the + crc calculation as done in debuglink is to be done. + @param dw_len + Pass in the length in bytes of dw_buf. + @param dw_init + Pass in the initial 32 bit value, zero is the right choice. + @return + Returns an int (assumed 32 bits int!) + with the calculated crc. +*/ +DW_API unsigned int dwarf_basic_crc32(const unsigned char * dw_buf, + unsigned long dw_len, + unsigned int dw_init); +/*! @} */ + +/*! @defgroup harmless Harmless Error recording + + @{ + The harmless error list is a circular buffer of + errors we note but which do not stop us from processing + the object. Created so dwarfdump or other tools + can report such inconsequential errors without causing + anything to stop early. +*/ +/*! @brief Default size of the libdwarf-internal circular list */ +#define DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE 4 + +/*! @brief Get the harmless error count and content + + User code supplies size of array of pointers dw_errmsg_ptrs_array + in count and the array of pointers (the pointers themselves + need not be initialized). + The pointers returned in the array of pointers + are invalidated by ANY call to libdwarf. + Use them before making another libdwarf call! + The array of string pointers passed in always has + a final null pointer, so if there are N pointers the + and M actual strings, then MIN(M,N-1) pointers are + set to point to error strings. The array of pointers + to strings always terminates with a NULL pointer. + Do not free the strings. Every string is null-terminated. + + Each call empties the error list (discarding all current entries). + and fills in your array + + @param dw_dbg + The applicable Dwarf_Debug. + @param dw_count + The number of string buffers. + If count is passed as zero no elements of the array are touched. + @param dw_errmsg_ptrs_array + A pointer to a user-created array of + pointer to const char. + @param dw_newerr_count + If non-NULL the count of harmless errors + pointers since the last call is returned through the pointer. + If dw_count is greater than zero the first dw_count + of the pointers in the user-created array point + to null-terminated strings. Do not free the strings. + print or copy the strings before any other libdwarf call. + + @return + Returns DW_DLV_NO_ENTRY if no harmless errors + were noted so far. Returns DW_DLV_OK if there are + harmless errors. Never returns DW_DLV_ERROR. + + If DW_DLV_NO_ENTRY is returned none of the arguments + other than dw_dbg are touched or used. + */ +DW_API int dwarf_get_harmless_error_list(Dwarf_Debug dw_dbg, + unsigned int dw_count, + const char ** dw_errmsg_ptrs_array, + unsigned int * dw_newerr_count); + +/*! @brief The size of the circular list of strings + libdwarf holds internally may be set + and reset as needed. If it is shortened excess + messages are simply dropped. It returns the previous + size. If zero passed in the size is unchanged + and it simply returns the current size. + + @param dw_dbg + The applicable Dwarf_Debug. + @param dw_maxcount + Set the new internal buffer count to a number greater + than zero. + @return + returns the current size of the internal circular + buffer if dw_maxcount is zero. + If dw_maxcount is greater than zero the internal + array is adjusted to hold that many and the + previous number of harmless errors possible in + the circular buffer is returned. + */ +DW_API unsigned int dwarf_set_harmless_error_list_size( + Dwarf_Debug dw_dbg, + unsigned int dw_maxcount); + +/*! @brief Harmless Error Insertion is only for testing + + Useful for testing the harmless error mechanism. + + @param dw_dbg + Pass in an open Dwarf_Debug + @param dw_newerror + Pass in a string whose content the function + inserts as a harmless error (which + dwarf_get_harmless_error_list will retrieve. +*/ +DW_API void dwarf_insert_harmless_error(Dwarf_Debug dw_dbg, + char * dw_newerror); +/*! @} */ + +/*! @defgroup Naming Names DW_TAG_member etc as strings + + @{ + Given a value you know is one of a particular + name category in DWARF2 or later, call the + appropriate function and on finding the name it + returns DW_DLV_OK and sets the + identifier for the value through a pointer. + On success + these functions return the string corresponding + to @b dw_val_in passed in + through the pointer @b dw_s_out and the value + returned is DW_DLV_OK. + + The strings are in static storage and must not be freed. + + If DW_DLV_NO_ENTRY is returned the @b dw_val_in is not known and + @b *s_out is not set. This is unusual. + + DW_DLV_ERROR is never returned. + + @see examplezb + +*/ +/*! @brief dwarf_get_ACCESS_name +*/ +DW_API int dwarf_get_ACCESS_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_ADDR_name +*/ +DW_API int dwarf_get_ADDR_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_AT_name +*/ +DW_API int dwarf_get_AT_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_AT_name +*/ +DW_API int dwarf_get_ATCF_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_ATE_name +*/ +DW_API int dwarf_get_ATE_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_CC_name +*/ +DW_API int dwarf_get_CC_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_CFA_name +*/ +DW_API int dwarf_get_CFA_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_children_namea - historic misspelling. +*/ +DW_API int dwarf_get_children_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_CHILDREN_name +*/ +DW_API int dwarf_get_CHILDREN_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_DEFAULTED_name +*/ +DW_API int dwarf_get_DEFAULTED_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_DS_name +*/ +DW_API int dwarf_get_DS_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_DSC_name +*/ +DW_API int dwarf_get_DSC_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_GNUIKIND_name - libdwarf invention + + So we can report things GNU extensions sensibly. +*/ +DW_API int dwarf_get_GNUIKIND_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_EH_name + + So we can report this GNU extension sensibly. +*/ +DW_API int dwarf_get_EH_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_END_name +*/ +DW_API int dwarf_get_END_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_FORM_name +*/ +DW_API int dwarf_get_FORM_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief This is a set of register names + + The set of register names is unlikely + to match your register set, but perhaps + this is better than no name. +*/ +DW_API int dwarf_get_FRAME_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_GNUIVIS_name - a libdwarf invention + + So we report a GNU extension sensibly. +*/ +DW_API int dwarf_get_GNUIVIS_name(unsigned int dw_val_in, + const char ** dw_s_out); + +/*! @brief dwarf_get_ID_name +*/ +DW_API int dwarf_get_ID_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_IDX_name +*/ +DW_API int dwarf_get_IDX_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_INL_name +*/ +DW_API int dwarf_get_INL_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_ISA_name +*/ +DW_API int dwarf_get_ISA_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_LANG_name +*/ +DW_API int dwarf_get_LANG_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_LLE_name +*/ +DW_API int dwarf_get_LLE_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_LLEX_name - a GNU extension. + + The name is a libdwarf invention for the GNU extension. + So we report a GNU extension sensibly. +*/ +DW_API int dwarf_get_LLEX_name(unsigned int dw_val_in, + const char ** dw_s_out ); + +/*! @brief dwarf_get_LNCT_name +*/ +DW_API int dwarf_get_LNCT_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_LNE_name +*/ +DW_API int dwarf_get_LNE_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_LNS_name +*/ +DW_API int dwarf_get_LNS_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_MACINFO_name + + Used in DWARF2-DWARF4 +*/ +DW_API int dwarf_get_MACINFO_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_MACRO_name + + Used in DWARF5 +*/ +DW_API int dwarf_get_MACRO_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_OP_name +*/ +DW_API int dwarf_get_OP_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_ORD_name +*/ +DW_API int dwarf_get_ORD_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_RLE_name +*/ +DW_API int dwarf_get_RLE_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_SECT_name +*/ +DW_API int dwarf_get_SECT_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_TAG_name +*/ +DW_API int dwarf_get_TAG_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_UT_name +*/ +DW_API int dwarf_get_UT_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_VIRTUALITY_name +*/ +DW_API int dwarf_get_VIRTUALITY_name(unsigned int dw_val_in, + const char ** dw_s_out); +/*! @brief dwarf_get_VIS_name +*/ +DW_API int dwarf_get_VIS_name(unsigned int dw_val_in, + const char ** dw_s_out); + +/*! @brief dwarf_get_FORM_CLASS_name is for a libdwarf + extension. + Not defined by the DWARF standard + though the concept is defined in the standard. + It seemed essential to invent it for libdwarf + to report correctly. + + See DWARF5 Table 2.3, Classes of Attribute Value page 23. + Earlier DWARF versions have a similar table. +*/ +DW_API int dwarf_get_FORM_CLASS_name(enum Dwarf_Form_Class dw_fc, + const char ** dw_s_out); +/*! @} */ + +/*! @defgroup objectsections Object Sections Data + @{ + + Section name access. Because names sections + such as .debug_info might + end with .dwo or be .zdebug or might not. + + String pointers returned via these functions + must not be freed, the strings are statically + declared. + + For non-Elf the name reported will be as if + it were Elf sections. For example, not the names + MacOS puts in its object sections (which + the MacOS reader translates). + + The simple calls will not be documented in full detail here. + +*/ +/*! @brief Get the real name a DIE section. + + @b dw_is_info + + @param dw_dbg + The Dwarf_Debug of interest + @param dw_is_info + We do not pass in a DIE, so we have to + pass in TRUE for for .debug_info, or if + DWARF4 .debug_types pass in FALSE. + @param dw_sec_name + On success returns a pointer to the actual + section name in the object file. + Do not free the string. + @param dw_error + The usual error argument to report error details. + @return + DW_DLV_OK etc. +*/ +DW_API int dwarf_get_die_section_name(Dwarf_Debug dw_dbg, + Dwarf_Bool dw_is_info, + const char **dw_sec_name, + Dwarf_Error *dw_error); + +/*! @brief Get the real name of a DIE section. + + The same as @b dwarf_get_die_section_name + except we have a DIE so do not need @b dw_is_info + as a argument. +*/ +DW_API int dwarf_get_die_section_name_b(Dwarf_Die dw_die, + const char ** dw_sec_name, + Dwarf_Error * dw_error); + +/*! @brief Get the real name of a .debug_macro section. +*/ +DW_API int dwarf_get_macro_section_name(Dwarf_Debug dw_dbg, + const char ** dw_sec_name_out, + Dwarf_Error * dw_err); + +/*! @brief Get the real name of a section. + + If the object has section groups only the + sections in the group in dw_dbg will be + found. + + Whether .zdebug or ZLIB or SHF_COMPRESSED + is the marker there is just one uncompress + algorithm (zlib) for all three cases. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_std_section_name + Pass in a standard section name, such as + .debug_info or .debug_info.dwo . + @param dw_actual_sec_name_out + On success returns the actual section name + from the object file. + @param dw_marked_zcompressed + On success returns TRUE if the original section name + ends in .zdebug + @param dw_marked_zlib_compressed + On success returns TRUE if the section has the ZLIB + string at the front of the section. + @param dw_marked_shf_compressed + On success returns TRUE if the section flag + (Elf SHF_COMPRESSED) is marked as compressed. + @param dw_compressed_length + On success if the section was compressed + it returns the original section length + in the object file. + @param dw_uncompressed_length + On success if the section was compressed this + returns the uncompressed length of the object section. + @param dw_error + On error returns the error usual details. + @return + The usual DW_DLV_OK etc. + If the section is not relevant to this Dwarf_Debug + or is not in the object file at all, returns + DW_DLV_NO_ENTRY +*/ +DW_API int dwarf_get_real_section_name(Dwarf_Debug dw_dbg, + const char * dw_std_section_name, + const char ** dw_actual_sec_name_out, + Dwarf_Small * dw_marked_zcompressed, + Dwarf_Small * dw_marked_zlib_compressed, + Dwarf_Small * dw_marked_shf_compressed, + Dwarf_Unsigned * dw_compressed_length, + Dwarf_Unsigned * dw_uncompressed_length, + Dwarf_Error * dw_error); + +/*! @brief Get .debug_frame section name + @return + returns DW_DLV_OK if the .debug_frame exists +*/ +DW_API int dwarf_get_frame_section_name(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Get GNU .eh_frame section name + @return + Returns DW_DLV_OK if the .debug_frame is present + Returns DW_DLV_NO_ENTRY if it is not present. +*/ +DW_API int dwarf_get_frame_section_name_eh_gnu(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Get .debug_aranges section name + The usual arguments. +*/ +DW_API int dwarf_get_aranges_section_name(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Get .debug_ranges section name + The usual arguments and return values. +*/ +DW_API int dwarf_get_ranges_section_name(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/* These two get the offset or address size as defined + by the object format (not by DWARF). */ +/*! @brief Get offset size as defined by the object + + This is not from DWARF information, it is + from object file headers. +*/ +DW_API int dwarf_get_offset_size(Dwarf_Debug /*dbg*/, + Dwarf_Half * dw_offset_size, + Dwarf_Error * dw_error); +/*! @brief Get the address size as defined by the object + + This is not from DWARF information, it is + from object file headers. +*/ +DW_API int dwarf_get_address_size(Dwarf_Debug /*dbg*/, + Dwarf_Half * dw_addr_size, + Dwarf_Error * dw_error); + +/*! @brief Get the string table section name + The usual arguments and return values. +*/ +DW_API int dwarf_get_string_section_name(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Get the line table section name + The usual arguments and return values. +*/ +DW_API int dwarf_get_line_section_name(Dwarf_Debug dw_dbg, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Get the line table section name + + @param dw_die + Pass in a Dwarf_Die pointer. + @param dw_section_name_out + On success returns the section name, usually + some .debug_info* name but in DWARF4 could be + a .debug_types* name. + @param dw_error + On error returns the usual error pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_line_section_name_from_die(Dwarf_Die dw_die, + const char ** dw_section_name_out, + Dwarf_Error * dw_error); + +/*! @brief Given a section name, get its size and address + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_section_name + Pass in a pointer to a section name. It + must be an exact match to the real section name. + @param dw_section_addr + On success returns the section address as defined + by an object header. + @param dw_section_size + On success returns the section size as defined + by an object header. + @param dw_error + On error returns the usual error pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_section_info_by_name(Dwarf_Debug dw_dbg, + const char * dw_section_name, + Dwarf_Addr * dw_section_addr, + Dwarf_Unsigned* dw_section_size, + Dwarf_Error * dw_error); + +/*! @brief Given a section index, get its size and address + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_section_index + Pass in an index, 0 through N-1 where + N is the count returned from dwarf_get_section_count . + @param dw_section_name + On success returns a pointer to the section name + as it appears in the object file. + @param dw_section_addr + On success returns the section address as defined + by an object header. + @param dw_section_size + On success returns the section size as defined + by an object header. + @param dw_error + On error returns the usual error pointer. + @return + Returns DW_DLV_OK etc. +*/ +DW_API int dwarf_get_section_info_by_index(Dwarf_Debug dw_dbg, + int dw_section_index, + const char ** dw_section_name, + Dwarf_Addr* dw_section_addr, + Dwarf_Unsigned* dw_section_size, + Dwarf_Error* dw_error); + +/*! @brief Get section count (of object file sections). +*/ +DW_API int dwarf_get_section_count(Dwarf_Debug dw_dbg); + +/*! @brief Get section sizes for many sections. + + The list of sections is incomplete and the argument list + is ... too long ... making this an unusual function + + Originally a hack so clients could verify offsets. + Added so that one can detect broken offsets + (which happened in an IRIX executable larger than 2GB + with MIPSpro 7.3.1.3 toolchain.). + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + + @return + Always returns DW_DLV_OK. +*/ +DW_API int dwarf_get_section_max_offsets_d(Dwarf_Debug dw_dbg, + Dwarf_Unsigned * dw_debug_info_size, + Dwarf_Unsigned * dw_debug_abbrev_size, + Dwarf_Unsigned * dw_debug_line_size, + Dwarf_Unsigned * dw_debug_loc_size, + Dwarf_Unsigned * dw_debug_aranges_size, + + Dwarf_Unsigned * dw_debug_macinfo_size, + Dwarf_Unsigned * dw_debug_pubnames_size, + Dwarf_Unsigned * dw_debug_str_size, + Dwarf_Unsigned * dw_debug_frame_size, + Dwarf_Unsigned * dw_debug_ranges_size, + + Dwarf_Unsigned * dw_debug_pubtypes_size, + Dwarf_Unsigned * dw_debug_types_size, + Dwarf_Unsigned * dw_debug_macro_size, + Dwarf_Unsigned * dw_debug_str_offsets_size, + Dwarf_Unsigned * dw_debug_sup_size, + + Dwarf_Unsigned * dw_debug_cu_index_size, + Dwarf_Unsigned * dw_debug_tu_index_size, + Dwarf_Unsigned * dw_debug_names_size, + Dwarf_Unsigned * dw_debug_loclists_size, + Dwarf_Unsigned * dw_debug_rnglists_size); +/*! @} */ + +/*! @defgroup secgroups Section Groups Objectfile Data + + @{ + @link dwsec_sectiongroup Section Groups Overview @endlink + +*/ +/*! @brief Get Section Groups data counts + + Allows callers to find out what groups (dwo or COMDAT) + are in the object and how much to allocate so one can get the + group-section map data. + + This is relevant for Debug Fission. + If an object file has both .dwo sections + and non-dwo sections or it has Elf COMDAT + GROUP sections this becomes important. + + @link dwsec_sectiongroup Section Groups Overview @endlink + + @param dw_dbg + Pass in the Dwarf_Debug of interest. + @param dw_section_count_out + On success returns the number of DWARF sections + in the object file. Can sometimes be many more + than are of interest. + @param dw_group_count_out + On success returns the number of groups. + Though usually one, it can be much larger. + @param dw_selected_group_out + On success returns the groupnumber that applies + to this specific open Dwarf_Debug. + @param dw_map_entry_count_out + On success returns the count of record allocations needed + to call dwarf_sec_group_map successfully. + dw_map_entry_count_out will be less than or equal to + dw_section_count_out. + @param dw_error + The usual error details pointer. + @return + On success returns DW_DLV_OK +*/ +DW_API int dwarf_sec_group_sizes(Dwarf_Debug dw_dbg, + Dwarf_Unsigned *dw_section_count_out, + Dwarf_Unsigned *dw_group_count_out, + Dwarf_Unsigned *dw_selected_group_out, + Dwarf_Unsigned *dw_map_entry_count_out, + Dwarf_Error *dw_error); + +/*! @brief Return a map between group numbers and section numbers + + This map shows all the groups in the object file + and shows which object sections go with which group. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_map_entry_count + Pass in the dw_map_entry_count_out from + dwarf_sec_group_sizes + @param dw_group_numbers_array + Pass in an array of Dwarf_Unsigned + with dw_map_entry_count entries. + Zero the data before the call here. + On success returns a list of group numbers. + @param dw_sec_numbers_array + Pass in an array of Dwarf_Unsigned + with dw_map_entry_count entries. + Zero the data before the call here. + On success returns a list of section numbers. + @param dw_sec_names_array + Pass in an array of const char * + with dw_map_entry_count entries. + Zero the data before the call here. + On success returns a list of section names. + @param dw_error + The usual error details pointer. + @return + On success returns DW_DLV_OK +*/ +DW_API int dwarf_sec_group_map(Dwarf_Debug dw_dbg, + Dwarf_Unsigned dw_map_entry_count, + Dwarf_Unsigned *dw_group_numbers_array, + Dwarf_Unsigned *dw_sec_numbers_array, + const char **dw_sec_names_array, + Dwarf_Error *dw_error); +/*! @} */ + +/*! @defgroup leb LEB Encode and Decode + @{ + + These are LEB/ULEB reading and writing + functions heavily used inside libdwarf. + + While the DWARF Standard does not mention + allowing extra insignificant trailing bytes + in a ULEB these functions allow a few such + for compilers using extras for alignment + in DWARF. +*/ +DW_API int dwarf_encode_leb128(Dwarf_Unsigned dw_val, + int *dw_nbytes, + char *dw_space, + int dw_splen); +DW_API int dwarf_encode_signed_leb128(Dwarf_Signed dw_val, + int *dw_nbytes, + char *dw_space, + int dw_splen); +/* Same for LEB decoding routines. + caller sets endptr to an address one past the last valid + address the library should be allowed to + access. */ +DW_API int dwarf_decode_leb128(char *dw_leb, + Dwarf_Unsigned *dw_leblen, + Dwarf_Unsigned *dw_outval, + char *dw_endptr); +DW_API int dwarf_decode_signed_leb128(char *dw_leb, + Dwarf_Unsigned *dw_leblen, + Dwarf_Signed *dw_outval, + char *dw_endptr); +/*! @} */ + +/*! @defgroup miscellaneous Miscellaneous Functions + @{ +*/ +/*! @brief Return the version string in the library. + + An example: "0.3.0" which is a Semantic Version identifier. + Before September 2021 the version string was + a date, for example "20210528", + which is in ISO date format. + See DW_LIBDWARF_VERSION DW_LIBDWARF_VERSION_MAJOR + DW_LIBDWARF_VERSION_MINOR DW_LIBDWARF_VERSION_MICRO + @return + The Package Version built into libdwarf.so or libdwarf.a +*/ +DW_API const char * dwarf_package_version(void); + +/*! @brief Turn off libdwarf checks of strings. + + Zero is the default and means do all + string length validity checks. + It applies to all Dwarf_Debug open and + all opened later in this library instance. + + @param dw_stringcheck + Pass in a small non-zero value to turn off + all libdwarf string validity checks. It speeds + up libdwarf, but...is dangerous and voids + all promises the library will not segfault. + @return + Returns the previous value of this flag. +*/ +DW_API int dwarf_set_stringcheck(int dw_stringcheck); + +/*! @brief Set libdwarf response to *.rela relocations + + dw_apply defaults to 1 and means apply all + '.rela' relocations on reading in a dwarf object + section of such relocations. + Best to just ignore this function + It applies to all Dwarf_Debug open and + all opened later in this library instance. + + @param dw_apply + Pass in a zero to turn off reading and applying of + *.rela relocations, which will likely break reading + of .o object files but probably will not break reading + executables or shared objects. + Pass in non zero (it is really just an 8 bit value, + so use a small value) to turn off inspecting .rela + sections. + @return + Returns the previous value of the apply flag. + +*/ +DW_API int dwarf_set_reloc_application(int dw_apply); + +/*! @brief Get a pointer to the applicable swap/noswap function + + the function pointer returned enables libdwarf users + to use the same 64bit/32bit/16bit word copy + as libdwarf does internally for the Dwarf_Debug + passed in. The function makes it possible for + libdwarf to read either endianness. + + @param dw_dbg + Pass in a pointer to the applicable Dwarf_Debug. + + @returns a pointer to a copy function. + If the object file referred to and the libdwarf + reading that file are the same endianness the function + returned will, when called, do a simple memcpy, + effectively, while otherwise + it would do a byte-swapping copy. It seems unlikely + this will be useful to most library users. + To call the copy function returned the first argument + must be a pointer to the target word and the second + must be a pointer to the input word. The third argument + is the length to be copied and it must be 2,4,or 8. +*/ + +DW_API void (*dwarf_get_endian_copy_function(Dwarf_Debug dw_dbg)) + (void *, const void *, unsigned long); + +/* A global flag in libdwarf. Applies to all Dwarf_Debug */ +DW_API extern Dwarf_Cmdline_Options dwarf_cmdline_options; + +/*! @brief Tell libdwarf to add verbosity to Line Header errors + By default the flag in the struct argument + is zero. + dwarfdump uses this when -v used on dwarfdump. + + @see dwarf_register_printf_callback + + @param dw_dd_options + The structure has one flag, and if + the flag is nonzero and there is an error + in reading a line table header + the function passes back detail error messages + via dwarf_register_printf_callback. +*/ +DW_API void dwarf_record_cmdline_options( + Dwarf_Cmdline_Options dw_dd_options); + +/*! @brief Eliminate libdwarf tracking of allocations + Independent of any Dwarf_Debug and applicable + to all whenever the setting is changed. + Defaults to non-zero. + + @param dw_v + If zero passed in libdwarf will run somewhat faster + and library memory allocations + will not all be tracked and dwarf_finish() will + be unable to free/dealloc some things. + User code can do the necessary deallocs + (as documented), but the normal guarantee + that libdwarf will clean up is revoked. + If non-zero passed in libdwarf will resume or + continue tracking allocations + @return + Returns the previous version of the flag. +*/ +DW_API int dwarf_set_de_alloc_flag(int dw_v); + +/*! @brief Set the address size on a Dwarf_Debug + + DWARF information CUs and other + section DWARF headers define a CU-specific + address size, but this Dwarf_Debug value + is used when other address size information + does not exist, for example in a DWARF2 + CIE or FDE. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_value + Sets the address size for the Dwarf_Debug to a + non-zero value. The default address size + is derived from headers in the object file. + Values larger than the size of Dwarf_Addr + are not set. + If zero passed the default is not changed. + @return + Returns the last set address size. +*/ +DW_API Dwarf_Small dwarf_set_default_address_size( + Dwarf_Debug dw_dbg, + Dwarf_Small dw_value); + +/*! @brief Retrieve universal binary index + + For Mach-O universal binaries this returns + relevant information. + + For non-universal binaries (Mach-O, Elf, + or PE) the values are not meaningful, so + the function returns DW_DLV_NO_ENTRY.. + + @param dw_dbg + The Dwarf_Debug of interest. + @param dw_current_index + If dw_current_index is passed in non-null the function + returns the universal-binary index of the current + object (which came from a universal binary). + @param dw_available_count + If dw_current_index is passed in non-null the function + returns the count of binaries in + the universal binary. + @return + Returns DW_DLV_NO_ENTRY if the object file is + not from a Mach-O universal binary. + Returns DW_DLV_NO_ENTRY if dw_dbg is passed in NULL. + Never returns DW_DLV_ERROR. +*/ +DW_API int dwarf_get_universalbinary_count( + Dwarf_Debug dw_dbg, + Dwarf_Unsigned *dw_current_index, + Dwarf_Unsigned *dw_available_count); + +/*! @} +*/ + +/*! @defgroup objectdetector Determine Object Type of a File + @{ + + This group of functions are unlikely to be called + by your code unless your code needs to know + the basic data about an object file without + actually opening a Dwarf_Debug. + + These are crucial for libdwarf itself. + +*/ +DW_API int dwarf_object_detector_path_b(const char * dw_path, + char *dw_outpath_buffer, + unsigned long dw_outpathlen, + char ** dw_gl_pathnames, + unsigned int dw_gl_pathcount, + unsigned int *dw_ftype, + unsigned int *dw_endian, + unsigned int *dw_offsetsize, + Dwarf_Unsigned *dw_filesize, + unsigned char *dw_pathsource, + int * dw_errcode); + +/* Solely looks for dSYM */ +DW_API int dwarf_object_detector_path_dSYM(const char * dw_path, + char * dw_outpath, + unsigned long dw_outpath_len, + char ** dw_gl_pathnames, + unsigned int dw_gl_pathcount, + unsigned int *dw_ftype, + unsigned int *dw_endian, + unsigned int *dw_offsetsize, + Dwarf_Unsigned *dw_filesize, + unsigned char *dw_pathsource, + int * dw_errcode); + +DW_API int dwarf_object_detector_fd(int dw_fd, + unsigned int *dw_ftype, + unsigned int *dw_endian, + unsigned int *dw_offsetsize, + Dwarf_Unsigned *dw_filesize, + int *dw_errcode); + +/*! @} +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _LIBDWARF_H */ diff --git a/src/lib/libdwarf/libdwarf.pc.cmake b/src/lib/libdwarf/libdwarf.pc.cmake new file mode 100644 index 0000000..6b18c77 --- /dev/null +++ b/src/lib/libdwarf/libdwarf.pc.cmake @@ -0,0 +1,12 @@ + +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix="${prefix}" +libdir="${prefix}/lib" +includedir="${prefix}/include" + +Name: libdwarf +Description: DWARF debug symbols library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldwarf +Cflags: -I${includedir} + diff --git a/src/lib/libdwarf/libdwarf_private.h b/src/lib/libdwarf/libdwarf_private.h new file mode 100644 index 0000000..b37ae99 --- /dev/null +++ b/src/lib/libdwarf/libdwarf_private.h @@ -0,0 +1,113 @@ +/* Copyright 2022, David Anderson + This trivial set of defines is hereby placed in the public domain + for all to use without restriction. +*/ +/* To enable printing with printf regardless of the + actual underlying data type, we define the DW_PR_xxx macros. + To ensure uses of DW_PR_DUx or DW_PR_DSx look the way you want + ensure the DW_PR_XZEROS define as you want it. +*/ +#ifndef LIBDWARF_PRIVATE_H +#define LIBDWARF_PRIVATE_H +#define DW_PR_XZEROS "08" + +#ifdef _WIN32 +#define DW_PR_DUx "I64x" +#define DW_PR_DSx "I64x" +#define DW_PR_DUu "I64u" +#define DW_PR_DSd "I64d" +#else +#define DW_PR_DUx "llx" +#define DW_PR_DSx "llx" +#define DW_PR_DUu "llu" +#define DW_PR_DSd "lld" +#endif /* DW_PR defines */ + +#ifdef _MSC_VER /* Macro to select VS compiler */ +#include +typedef SSIZE_T ssize_t; +#ifdef _WIN64 +typedef long long off_t; +#else +typedef long off_t; +#endif +#endif /* _MSC_VER */ + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#define DWARF_HALF_SIZE 2 +#define SIZEOFT16 2 +#define SIZEOFT32 4 +#define SIZEOFT64 8 + +#ifdef WORDS_BIGENDIAN +#define ASNAR(func,t,s) \ + do { \ + unsigned tbyte = sizeof(t) - sizeof(s); \ + (t) = 0; \ + (func)(((char *)&(t))+tbyte ,&(s)[0],sizeof(s)); \ + } while (0) +#else /* LITTLE ENDIAN */ +#define ASNAR(func,t,s) \ + do { \ + (t) = 0; \ + (func)(&(t),&(s)[0],sizeof(s)); \ + } while (0) +#endif /* end LITTLE- BIG-ENDIAN */ + +/* The following actually assumes (as used here) + that t is 8 bytes (integer) while s is + also 8 bytes (Dwarf_Sig8 struct). + Just slightly different from the ASNAR generally + used in libdwarf. Unusable in + libdwarfp because of _dwarf_error() here. */ +#ifdef WORDS_BIGENDIAN +#define ASNARL(t,s,l) \ + do { \ + unsigned tbyte = sizeof(t) - (l); \ + if (sizeof(t) < (l)) { \ + _dwarf_error(dbg,error,DW_DLE_XU_HASH_INDEX_ERROR); \ + return DW_DLV_ERROR; \ + } \ + (t) = 0; \ + dbg->de_copy_word(((char *)&(t))+tbyte ,&(s)[0],(l));\ + } while (0) +#else /* LITTLE ENDIAN */ +#define ASNARL(t,s,l) \ + do { \ + (t) = 0; \ + if (sizeof(t) < (l)) { \ + _dwarf_error(dbg,error,DW_DLE_XU_HASH_INDEX_ERROR); \ + return DW_DLV_ERROR; \ + } \ + dbg->de_copy_word(&(t),&(s)[0],(l)); \ + } while (0) +#endif /* end LITTLE- BIG-ENDIAN */ + +#ifdef WORDS_BIGENDIAN +#define SIGN_EXTEND(dest, length) \ + do { \ + if (*(Dwarf_Sbyte *)((char *)&(dest) + \ + sizeof(dest) - (length)) < 0) { \ + memcpy((char *)&(dest), \ + "\xff\xff\xff\xff\xff\xff\xff\xff", \ + sizeof(dest) - (length)); \ + } \ + } while (0) +#else /* LITTLE ENDIAN */ +#define SIGN_EXTEND(dest, length) \ + do { \ + if (*(Dwarf_Sbyte *)((char *)&(dest)+ ((length)-1)) < 0) { \ + memcpy((char *)&(dest)+(length), \ + "\xff\xff\xff\xff\xff\xff\xff\xff", \ + sizeof(dest) - (length)); \ + } \ + } while (0) +#endif /* LITTLE ENDIAN */ + +#endif /* LIBDWARF_PRIVATE_H */ diff --git a/src/lib/libdwarf/meson.build b/src/lib/libdwarf/meson.build new file mode 100644 index 0000000..ac4c273 --- /dev/null +++ b/src/lib/libdwarf/meson.build @@ -0,0 +1,102 @@ + +libdwarf_header_src = [ 'libdwarf.h', 'dwarf.h' ] + +libdwarf_src = [ + 'dwarf_abbrev.c', + 'dwarf_alloc.c', + 'dwarf_arange.c', + 'dwarf_crc.c', + 'dwarf_crc32.c', + 'dwarf_debugaddr.c', + 'dwarf_debuglink.c', + 'dwarf_die_deliv.c', + 'dwarf_debugnames.c', + 'dwarf_debug_sup.c', + 'dwarf_dsc.c', + 'dwarf_elf_load_headers.c', + 'dwarf_elfread.c', + 'dwarf_elf_rel_detector.c', + 'dwarf_error.c', + 'dwarf_fill_in_attr_form.c', + 'dwarf_find_sigref.c', + 'dwarf_fission_to_cu.c', + 'dwarf_form.c', + 'dwarf_form_class_names.c', + 'dwarf_frame.c', + 'dwarf_frame2.c', + 'dwarf_gdbindex.c', + 'dwarf_generic_init.c', + 'dwarf_global.c', + 'dwarf_gnu_index.c', + 'dwarf_groups.c', + 'dwarf_harmless.c', + 'dwarf_init_finish.c', + 'dwarf_leb.c', + 'dwarf_line.c', + 'dwarf_loc.c', + 'dwarf_locationop_read.c', + 'dwarf_loclists.c', + 'dwarf_machoread.c', + 'dwarf_macro.c', + 'dwarf_macro5.c', + 'dwarf_memcpy_swap.c', + 'dwarf_names.c', + 'dwarf_object_detector.c', + 'dwarf_object_read_common.c', + 'dwarf_peread.c', + 'dwarf_print_lines.c', + 'dwarf_query.c', + 'dwarf_safe_arithmetic.c', + 'dwarf_safe_strcpy.c', + 'dwarf_secname_ck.c', + 'dwarf_setup_sections.c', + 'dwarf_ranges.c', + 'dwarf_rnglists.c', + 'dwarf_str_offsets.c', + 'dwarf_string.c', + 'dwarf_stringsection.c', + 'dwarf_tied.c', + 'dwarf_tsearchhash.c', + 'dwarf_util.c', + 'dwarf_xu_index.c', +] + +zlib_deps = dependency('zlib', method: 'pkg-config', required: false) +libzstd_deps = dependency('libzstd', method: 'pkg-config', required: false) + +if zlib_deps.found() == true + # set10 means set to 1 or 0. Ref man, see cfg_data.set10 + # A variation on set(). + config_h.set10('HAVE_ZLIB', true) + config_h.set10('HAVE_ZLIB_H', true) +endif +if libzstd_deps.found() == true + config_h.set10('HAVE_ZSTD', true) + config_h.set10('HAVE_ZSTD_H', true) +endif + +if (lib_type == 'shared') + compiler_flags = ['-DLIBDWARF_BUILD'] +else + compiler_flags = ['-DLIBDWARF_STATIC'] +endif + +libdwarf_lib = library('dwarf', libdwarf_src, + c_args : [ dev_cflags, libdwarf_args, compiler_flags ], + dependencies : [ zlib_deps, libzstd_deps ], + gnu_symbol_visibility: 'hidden', + include_directories : config_dir, + install : true, + pic : true, + version : meson.project_version() +) + +libdwarf = declare_dependency( + include_directories : [ include_directories('.')], + link_with : libdwarf_lib, + dependencies : [zlib_deps, libzstd_deps] +) + +install_headers(libdwarf_header_src, + install_dir : dir_pkginclude + '-' + v_maj +)