X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/7d28d93b90eedd2a49da8b9b990296669e46d05c..85861efad8a0c75dfc4cca06c3f8adcf86d49495:/src/mc/inspect/mc_dwarf.cpp diff --git a/src/mc/inspect/mc_dwarf.cpp b/src/mc/inspect/mc_dwarf.cpp index 83444e45b6..372b01340a 100644 --- a/src/mc/inspect/mc_dwarf.cpp +++ b/src/mc/inspect/mc_dwarf.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2020. The SimGrid Team. All rights reserved. */ +/* Copyright (c) 2008-2021. The SimGrid Team. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it * under the terms of the license (GNU LGPL) which comes with this package. */ @@ -13,22 +13,24 @@ #include "src/mc/inspect/Variable.hpp" #include "src/mc/inspect/mc_dwarf.hpp" #include "src/mc/mc_private.hpp" -#include "src/mc/remote/RemoteSimulation.hpp" +#include "src/mc/remote/RemoteProcess.hpp" #include #include +#include #include #include #include +#include #include #include +#include #include #include #include - -#include +#include XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing"); @@ -124,52 +126,32 @@ enum class FormClass { static TagClass classify_tag(int tag) { - switch (tag) { - case DW_TAG_array_type: - case DW_TAG_class_type: - case DW_TAG_enumeration_type: - case DW_TAG_typedef: - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_string_type: - case DW_TAG_structure_type: - case DW_TAG_subroutine_type: - case DW_TAG_union_type: - case DW_TAG_ptr_to_member_type: - case DW_TAG_set_type: - case DW_TAG_subrange_type: - case DW_TAG_base_type: - case DW_TAG_const_type: - case DW_TAG_file_type: - case DW_TAG_packed_type: - case DW_TAG_volatile_type: - case DW_TAG_restrict_type: - case DW_TAG_interface_type: - case DW_TAG_unspecified_type: - case DW_TAG_shared_type: - return TagClass::Type; - - case DW_TAG_subprogram: - return TagClass::Subprogram; - - case DW_TAG_variable: - case DW_TAG_formal_parameter: - return TagClass::Variable; - - case DW_TAG_lexical_block: - case DW_TAG_try_block: - case DW_TAG_catch_block: - case DW_TAG_inlined_subroutine: - case DW_TAG_with_stmt: - return TagClass::Scope; - - case DW_TAG_namespace: - return TagClass::Namespace; - - default: - return TagClass::Unknown; - } + static const std::unordered_map map = { + {DW_TAG_array_type, TagClass::Type}, {DW_TAG_class_type, TagClass::Type}, + {DW_TAG_enumeration_type, TagClass::Type}, {DW_TAG_typedef, TagClass::Type}, + {DW_TAG_pointer_type, TagClass::Type}, {DW_TAG_reference_type, TagClass::Type}, + {DW_TAG_rvalue_reference_type, TagClass::Type}, {DW_TAG_string_type, TagClass::Type}, + {DW_TAG_structure_type, TagClass::Type}, {DW_TAG_subroutine_type, TagClass::Type}, + {DW_TAG_union_type, TagClass::Type}, {DW_TAG_ptr_to_member_type, TagClass::Type}, + {DW_TAG_set_type, TagClass::Type}, {DW_TAG_subrange_type, TagClass::Type}, + {DW_TAG_base_type, TagClass::Type}, {DW_TAG_const_type, TagClass::Type}, + {DW_TAG_file_type, TagClass::Type}, {DW_TAG_packed_type, TagClass::Type}, + {DW_TAG_volatile_type, TagClass::Type}, {DW_TAG_restrict_type, TagClass::Type}, + {DW_TAG_interface_type, TagClass::Type}, {DW_TAG_unspecified_type, TagClass::Type}, + {DW_TAG_shared_type, TagClass::Type}, + + {DW_TAG_subprogram, TagClass::Subprogram}, + + {DW_TAG_variable, TagClass::Variable}, {DW_TAG_formal_parameter, TagClass::Variable}, + + {DW_TAG_lexical_block, TagClass::Scope}, {DW_TAG_try_block, TagClass::Scope}, + {DW_TAG_catch_block, TagClass::Scope}, {DW_TAG_inlined_subroutine, TagClass::Scope}, + {DW_TAG_with_stmt, TagClass::Scope}, + + {DW_TAG_namespace, TagClass::Namespace}}; + + auto res = map.find(tag); + return res != map.end() ? res->second : TagClass::Unknown; } /** @brief Find the DWARF data class for a given DWARF data form @@ -181,41 +163,35 @@ static TagClass classify_tag(int tag) * */ static FormClass classify_form(int form) { - switch (form) { - case DW_FORM_addr: - return FormClass::Address; - case DW_FORM_block2: - case DW_FORM_block4: - case DW_FORM_block: - case DW_FORM_block1: - return FormClass::Block; - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_udata: - case DW_FORM_sdata: - return FormClass::Constant; - case DW_FORM_string: - case DW_FORM_strp: - return FormClass::String; - case DW_FORM_ref_addr: - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: - return FormClass::Reference; - case DW_FORM_flag: - case DW_FORM_flag_present: - return FormClass::Flag; - case DW_FORM_exprloc: - return FormClass::ExprLoc; + static const std::unordered_map map = { + {DW_FORM_addr, FormClass::Address}, + + {DW_FORM_block2, FormClass::Block}, {DW_FORM_block4, FormClass::Block}, + {DW_FORM_block, FormClass::Block}, {DW_FORM_block1, FormClass::Block}, + + {DW_FORM_data1, FormClass::Constant}, {DW_FORM_data2, FormClass::Constant}, + {DW_FORM_data4, FormClass::Constant}, {DW_FORM_data8, FormClass::Constant}, + {DW_FORM_udata, FormClass::Constant}, {DW_FORM_sdata, FormClass::Constant}, +#if _ELFUTILS_PREREQ(0, 171) + {DW_FORM_implicit_const, FormClass::Constant}, +#endif + + {DW_FORM_string, FormClass::String}, {DW_FORM_strp, FormClass::String}, + + {DW_FORM_ref_addr, FormClass::Reference}, {DW_FORM_ref1, FormClass::Reference}, + {DW_FORM_ref2, FormClass::Reference}, {DW_FORM_ref4, FormClass::Reference}, + {DW_FORM_ref8, FormClass::Reference}, {DW_FORM_ref_udata, FormClass::Reference}, + + {DW_FORM_flag, FormClass::Flag}, {DW_FORM_flag_present, FormClass::Flag}, + + {DW_FORM_exprloc, FormClass::ExprLoc} + // TODO sec offset // TODO indirect - default: - return FormClass::Unknown; - } + }; + + auto res = map.find(form); + return res != map.end() ? res->second : FormClass::Unknown; } /** @brief Get the name of the tag of a given DIE @@ -323,33 +299,19 @@ static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, bool integrate) * */ static uint64_t MC_dwarf_default_lower_bound(int lang) { - switch (lang) { - case DW_LANG_C: - case DW_LANG_C89: - case DW_LANG_C99: - case DW_LANG_C_plus_plus: - case DW_LANG_D: - case DW_LANG_Java: - case DW_LANG_ObjC: - case DW_LANG_ObjC_plus_plus: - case DW_LANG_Python: - case DW_LANG_UPC: - return 0; - case DW_LANG_Ada83: - case DW_LANG_Ada95: - case DW_LANG_Fortran77: - case DW_LANG_Fortran90: - case DW_LANG_Fortran95: - case DW_LANG_Modula2: - case DW_LANG_Pascal83: - case DW_LANG_PL1: - case DW_LANG_Cobol74: - case DW_LANG_Cobol85: - return 1; - default: - xbt_die("No default DW_TAG_lower_bound for language %i and none given", lang); - return 0; - } + const std::unordered_map map = { + {DW_LANG_C, 0}, {DW_LANG_C89, 0}, {DW_LANG_C99, 0}, {DW_LANG_C11, 0}, + {DW_LANG_C_plus_plus, 0}, {DW_LANG_C_plus_plus_11, 0}, {DW_LANG_C_plus_plus_14, 0}, {DW_LANG_D, 0}, + {DW_LANG_Java, 0}, {DW_LANG_ObjC, 0}, {DW_LANG_ObjC_plus_plus, 0}, {DW_LANG_Python, 0}, + {DW_LANG_UPC, 0}, + + {DW_LANG_Ada83, 1}, {DW_LANG_Ada95, 1}, {DW_LANG_Fortran77, 1}, {DW_LANG_Fortran90, 1}, + {DW_LANG_Fortran95, 1}, {DW_LANG_Fortran03, 1}, {DW_LANG_Fortran08, 1}, {DW_LANG_Modula2, 1}, + {DW_LANG_Pascal83, 1}, {DW_LANG_PL1, 1}, {DW_LANG_Cobol74, 1}, {DW_LANG_Cobol85, 1}}; + + auto res = map.find(lang); + xbt_assert(res != map.end(), "No default DW_TAG_lower_bound for language %i and none given", lang); + return res->second; } /** @brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE @@ -437,10 +399,10 @@ static void MC_dwarf_fill_member_location(const simgrid::mc::Type* type, simgrid xbt_assert(not dwarf_hasattr(child, DW_AT_data_bit_offset), "Can't groke DW_AT_data_bit_offset."); if (not dwarf_hasattr_integrate(child, DW_AT_data_member_location)) { - if (type->type == DW_TAG_union_type) - return; - xbt_die("Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%" PRIx64 ">%s", - member->name.c_str(), (uint64_t)type->id, type->name.c_str()); + xbt_assert(type->type == DW_TAG_union_type, + "Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%" PRIx64 ">%s", + member->name.c_str(), (uint64_t)type->id, type->name.c_str()); + return; } Dwarf_Attribute attr; @@ -511,8 +473,7 @@ static void MC_dwarf_add_members(const simgrid::mc::ObjectInformation* /*info*/, member.name = name; // Those base names are used by GCC and clang for virtual table pointers // respectively ("__vptr$ClassName", "__vptr.ClassName"): - if (boost::algorithm::starts_with(member.name, "__vptr$") || - boost::algorithm::starts_with(member.name, "__vptr.")) + if (member.name.rfind("__vptr$", 0) == 0 || member.name.rfind("__vptr.", 0) == 0) member.flags |= simgrid::mc::Member::VIRTUAL_POINTER_FLAG; // A cleaner solution would be to check against the type: // --- @@ -641,8 +602,6 @@ static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf info->full_types_by_name[t.name] = &t; } -static int mc_anonymous_variable_index = 0; - static std::unique_ptr MC_die_to_variable(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* /*unit*/, const simgrid::mc::Frame* frame, const char* ns) @@ -732,6 +691,7 @@ static std::unique_ptr MC_die_to_variable(simgrid::mc::Ob // The current code needs a variable name, // generate a fake one: + static int mc_anonymous_variable_index = 0; if (variable->name.empty()) { variable->name = "@anonymous#" + std::to_string(mc_anonymous_variable_index); mc_anonymous_variable_index++; @@ -1002,7 +962,7 @@ static constexpr auto debug_paths = { */ // Example: // /usr/lib/debug/.build-id/0b/dc77f1c29aea2b14ff5acd9a19ab3175ffdeae.debug -static std::string find_by_build_id(std::vector id) +static int find_by_build_id(std::vector id) { std::string filename; std::string hex = to_hex(id); @@ -1011,13 +971,15 @@ static std::string find_by_build_id(std::vector id) filename = std::string(debug_path) + ".build-id/" + to_hex(id.data(), 1) + '/' + to_hex(id.data() + 1, id.size() - 1) + ".debug"; XBT_DEBUG("Checking debug file: %s", filename.c_str()); - if (access(filename.c_str(), F_OK) == 0) { + int fd = open(filename.c_str(), O_RDONLY); + if (fd != -1) { XBT_DEBUG("Found debug file: %s\n", hex.c_str()); - return filename; + return fd; } + xbt_assert(errno != ENOENT, "Could not open file: %s", strerror(errno)); } XBT_DEBUG("No debug info found for build ID %s\n", hex.data()); - return std::string(); + return -1; } /** @brief Populate the debugging information of the given ELF object @@ -1033,9 +995,7 @@ static void MC_load_dwarf(simgrid::mc::ObjectInformation* info) int fd = open(info->file_name.c_str(), O_RDONLY); xbt_assert(fd >= 0, "Could not open file %s", info->file_name.c_str()); Elf* elf = elf_begin(fd, ELF_C_READ, nullptr); - xbt_assert(elf != nullptr, "Not an ELF file"); - Elf_Kind kind = elf_kind(elf); - xbt_assert(kind == ELF_K_ELF, "Not an ELF file"); + xbt_assert(elf != nullptr && elf_kind(elf) == ELF_K_ELF, "%s is not an ELF file", info->file_name.c_str()); // Remember if this is a `ET_EXEC` (fixed location) or `ET_DYN`: Elf64_Half type = get_type(elf); @@ -1068,18 +1028,16 @@ static void MC_load_dwarf(simgrid::mc::ObjectInformation* info) close(fd); // Find the debug file using the build id: - std::string debug_file = find_by_build_id(build_id); - xbt_assert(not debug_file.empty(), + fd = find_by_build_id(build_id); + xbt_assert(fd != -1, "Missing debug info for %s with build-id %s\n" "You might want to install the suitable debugging package.\n", info->file_name.c_str(), to_hex(build_id).c_str()); // Load the DWARF info from this file: - XBT_DEBUG("Load DWARF for %s from %s", info->file_name.c_str(), debug_file.c_str()); - fd = open(debug_file.c_str(), O_RDONLY); - xbt_assert(fd >= 0, "Could not open file %s", debug_file.c_str()); + XBT_DEBUG("Load DWARF for %s", info->file_name.c_str()); dwarf = dwarf_begin(fd, DWARF_C_READ); - xbt_assert(dwarf != nullptr, "No DWARF info in %s for %s", debug_file.c_str(), info->file_name.c_str()); + xbt_assert(dwarf != nullptr, "No DWARF info for %s", info->file_name.c_str()); read_dwarf_info(info, dwarf); dwarf_end(dwarf); close(fd); @@ -1186,24 +1144,32 @@ static void MC_post_process_types(simgrid::mc::ObjectInformation* info) namespace simgrid { namespace mc { +void ObjectInformation::ensure_dwarf_loaded() +{ + if (dwarf_loaded) + return; + dwarf_loaded = true; + + MC_load_dwarf(this); + MC_post_process_variables(this); + MC_post_process_types(this); + for (auto& entry : this->subprograms) + mc_post_process_scope(this, &entry.second); + MC_make_functions_index(this); +} + /** @brief Finds information about a given shared object/executable */ std::shared_ptr createObjectInformation(std::vector const& maps, const char* name) { auto result = std::make_shared(); result->file_name = name; simgrid::mc::find_object_address(maps, result.get()); - MC_load_dwarf(result.get()); - MC_post_process_variables(result.get()); - MC_post_process_types(result.get()); - for (auto& entry : result.get()->subprograms) - mc_post_process_scope(result.get(), &entry.second); - MC_make_functions_index(result.get()); return result; } /*************************************************************************/ -void postProcessObjectInformation(const RemoteSimulation* process, ObjectInformation* info) +void postProcessObjectInformation(const RemoteProcess* process, ObjectInformation* info) { for (auto& t : info->types) { Type* type = &(t.second); @@ -1249,58 +1215,14 @@ int dwarf_register_to_libunwind(int dwarf_register) #elif defined(__i386__) // Couldn't find the authoritative source of information for this. // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517. - switch (dwarf_register) { - case 0: - return UNW_X86_EAX; - case 1: - return UNW_X86_ECX; - case 2: - return UNW_X86_EDX; - case 3: - return UNW_X86_EBX; - case 4: - return UNW_X86_ESP; - case 5: - return UNW_X86_EBP; - case 6: - return UNW_X86_ESI; - case 7: - return UNW_X86_EDI; - case 8: - return UNW_X86_EIP; - case 9: - return UNW_X86_EFLAGS; - case 10: - return UNW_X86_CS; - case 11: - return UNW_X86_SS; - case 12: - return UNW_X86_DS; - case 13: - return UNW_X86_ES; - case 14: - return UNW_X86_FS; - case 15: - return UNW_X86_GS; - case 16: - return UNW_X86_ST0; - case 17: - return UNW_X86_ST1; - case 18: - return UNW_X86_ST2; - case 19: - return UNW_X86_ST3; - case 20: - return UNW_X86_ST4; - case 21: - return UNW_X86_ST5; - case 22: - return UNW_X86_ST6; - case 23: - return UNW_X86_ST7; - default: - xbt_die("Bad/unknown register number."); - } + constexpr std::array regs{ + {/* 0 */ UNW_X86_EAX, /* 1 */ UNW_X86_ECX, /* 2 */ UNW_X86_EDX, /* 3 */ UNW_X86_EBX, + /* 4 */ UNW_X86_ESP, /* 5 */ UNW_X86_EBP, /* 6 */ UNW_X86_ESI, /* 7 */ UNW_X86_EDI, + /* 8 */ UNW_X86_EIP, /* 9 */ UNW_X86_EFLAGS, /* 10 */ UNW_X86_CS, /* 11 */ UNW_X86_SS, + /* 12 */ UNW_X86_DS, /* 13 */ UNW_X86_ES, /* 14 */ UNW_X86_FS, /* 15 */ UNW_X86_GS, + /* 16 */ UNW_X86_ST0, /* 17 */ UNW_X86_ST1, /* 18 */ UNW_X86_ST2, /* 19 */ UNW_X86_ST3, + /* 20 */ UNW_X86_ST4, /* 21 */ UNW_X86_ST5, /* 22 */ UNW_X86_ST6, /* 23 */ UNW_X86_ST7}}; + return regs.at(dwarf_register); #else #error This architecture is not supported yet for DWARF expression evaluation. #endif