X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/a57327d86b9fb16acacc71a3359817acd2a2816b..5a006fa396cfcc8a91a8284f0d625b2a9a2565c9:/src/mc/inspect/mc_dwarf.cpp diff --git a/src/mc/inspect/mc_dwarf.cpp b/src/mc/inspect/mc_dwarf.cpp index 9fbe7255cc..93ff5f8c36 100644 --- a/src/mc/inspect/mc_dwarf.cpp +++ b/src/mc/inspect/mc_dwarf.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019. The SimGrid Team. All rights reserved. */ +/* Copyright (c) 2008-2023. 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,20 +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/RemoteClient.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"); @@ -59,7 +63,7 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit); /** @brief Process a DIE * - * @param info the resulting object fot the library/binary file (output) + * @param info the resulting object for the library/binary file (output) * @param die the current DIE * @param unit the DIE of the compile unit of the current DIE * @param frame containing frame if any @@ -74,7 +78,7 @@ static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf /** @brief Calls MC_dwarf_handle_die on all children of the given die * - * @param info the resulting object fot the library/binary file (output) + * @param info the resulting object for the library/binary file (output) * @param die the current DIE * @param unit the DIE of the compile unit of the current DIE * @param frame containing frame if any @@ -84,12 +88,12 @@ static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf /** @brief Handle a variable (DW_TAG_variable or other) * - * @param info the resulting object fot the library/binary file (output) + * @param info the resulting object for the library/binary file (output) * @param die the current DIE * @param unit the DIE of the compile unit of the current DIE * @param frame containing frame if any */ -static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, +static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit, simgrid::mc::Frame* frame, const char* ns); /** @brief Get the DW_TAG_type of the DIE @@ -99,8 +103,7 @@ static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, D */ static std::uint64_t MC_dwarf_at_type(Dwarf_Die* die); -namespace simgrid { -namespace dwarf { +namespace simgrid::dwarf { enum class TagClass { Unknown, Type, Subprogram, Variable, Scope, Namespace }; @@ -122,53 +125,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 @@ -180,41 +162,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 @@ -224,11 +200,10 @@ static FormClass classify_form(int form) */ inline XBT_PRIVATE const char* tagname(Dwarf_Die* die) { - return simgrid::dwarf::tagname(dwarf_tag(die)); + return tagname(dwarf_tag(die)); } -} // namespace dwarf -} // namespace simgrid +} // namespace simgrid::dwarf // ***** Attributes @@ -247,27 +222,14 @@ static const char* MC_dwarf_attr_integrate_string(Dwarf_Die* die, int attribute) return dwarf_formstring(&attr); } -static Dwarf_Off MC_dwarf_attr_dieoffset(Dwarf_Die* die, int attribute) -{ - Dwarf_Attribute attr; - if (dwarf_hasattr_integrate(die, attribute) == 0) - return 0; - dwarf_attr_integrate(die, attribute, &attr); - Dwarf_Die subtype_die; - if (dwarf_formref_die(&attr, &subtype_die) == nullptr) - xbt_die("Could not find DIE"); - return dwarf_dieoffset(&subtype_die); -} - static Dwarf_Off MC_dwarf_attr_integrate_dieoffset(Dwarf_Die* die, int attribute) { Dwarf_Attribute attr; if (dwarf_hasattr_integrate(die, attribute) == 0) return 0; - dwarf_attr_integrate(die, DW_AT_type, &attr); + dwarf_attr_integrate(die, attribute, &attr); Dwarf_Die subtype_die; - if (dwarf_formref_die(&attr, &subtype_die) == nullptr) - xbt_die("Could not find DIE"); + xbt_assert(dwarf_formref_die(&attr, &subtype_die) != nullptr, "Could not find DIE"); return dwarf_dieoffset(&subtype_die); } @@ -305,12 +267,12 @@ static uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die* die, int attribute, uint static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, bool integrate) { Dwarf_Attribute attr; - if ((integrate ? dwarf_attr_integrate(die, attribute, &attr) : dwarf_attr(die, attribute, &attr)) == 0) + if ((integrate ? dwarf_attr_integrate(die, attribute, &attr) : dwarf_attr(die, attribute, &attr)) == nullptr) return false; bool result; - if (dwarf_formflag(&attr, &result)) - xbt_die("Unexpected form for attribute %s", simgrid::dwarf::attrname(attribute)); + xbt_assert(not dwarf_formflag(&attr, &result), "Unexpected form for attribute %s", + simgrid::dwarf::attrname(attribute)); return result; } @@ -324,33 +286,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 @@ -383,7 +331,7 @@ static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit) return upper_bound - lower_bound + 1; } -/** @brief Finds the number of elements in a array type (DW_TAG_array_type) +/** @brief Finds the number of elements in an array type (DW_TAG_array_type) * * The compilation unit might be needed because the default lower * bound depends on the language of the compilation unit. @@ -399,8 +347,7 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit) int result = 1; Dwarf_Die child; - int res; - for (res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { + for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { int child_tag = dwarf_tag(&child); if (child_tag == DW_TAG_subrange_type || child_tag == DW_TAG_enumeration_type) result *= MC_dwarf_subrange_element_count(&child, unit); @@ -434,16 +381,15 @@ static bool MC_compare_variable(simgrid::mc::Variable const& a, simgrid::mc::Var * @param member the member of the type * @param child DIE of the member (DW_TAG_member) */ -static void MC_dwarf_fill_member_location(simgrid::mc::Type* type, simgrid::mc::Member* member, Dwarf_Die* child) +static void MC_dwarf_fill_member_location(const simgrid::mc::Type* type, simgrid::mc::Member* member, Dwarf_Die* child) { - if (dwarf_hasattr(child, DW_AT_data_bit_offset)) - xbt_die("Can't groke DW_AT_data_bit_offset."); + 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; @@ -457,10 +403,10 @@ static void MC_dwarf_fill_member_location(simgrid::mc::Type* type, simgrid::mc:: { Dwarf_Op* expr; size_t len; - if (dwarf_getlocation(&attr, &expr, &len)) - xbt_die("Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%" PRIx64 - ">%s", - MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str()); + xbt_assert(not dwarf_getlocation(&attr, &expr, &len), + "Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%" PRIx64 + ">%s", + MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str()); member->location_expression = simgrid::dwarf::DwarfExpression(expr, expr + len); break; } @@ -468,11 +414,9 @@ static void MC_dwarf_fill_member_location(simgrid::mc::Type* type, simgrid::mc:: // Offset from the base address of the object: { Dwarf_Word offset; - if (not dwarf_formudata(&attr, &offset)) - member->offset(offset); - else - xbt_die("Cannot get %s location <%" PRIx64 ">%s", MC_dwarf_attr_integrate_string(child, DW_AT_name), - (uint64_t)type->id, type->name.c_str()); + xbt_assert(not dwarf_formudata(&attr, &offset), "Cannot get %s location <%" PRIx64 ">%s", + MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t)type->id, type->name.c_str()); + member->offset(offset); break; } @@ -490,16 +434,14 @@ static void MC_dwarf_fill_member_location(simgrid::mc::Type* type, simgrid::mc:: * @param unit DIE of the compilation unit containing the type DIE * @param type the type */ -static void MC_dwarf_add_members(simgrid::mc::ObjectInformation* /*info*/, Dwarf_Die* die, Dwarf_Die* /*unit*/, - simgrid::mc::Type* type) +static void MC_dwarf_add_members(const simgrid::mc::ObjectInformation* /*info*/, Dwarf_Die* die, + const Dwarf_Die* /*unit*/, simgrid::mc::Type* type) { - int res; Dwarf_Die child; xbt_assert(type->members.empty()); - for (res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { + for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) { int tag = dwarf_tag(&child); if (tag == DW_TAG_member || tag == DW_TAG_inheritance) { - // Skip declarations: if (MC_dwarf_attr_flag(&child, DW_AT_declaration, false)) continue; @@ -518,8 +460,7 @@ static void MC_dwarf_add_members(simgrid::mc::ObjectInformation* /*info*/, Dwarf 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: // --- @@ -542,14 +483,15 @@ static void MC_dwarf_add_members(simgrid::mc::ObjectInformation* /*info*/, Dwarf member.byte_size = MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0); member.type_id = MC_dwarf_at_type(&child); - if (dwarf_hasattr(&child, DW_AT_data_bit_offset)) - xbt_die("Can't groke DW_AT_data_bit_offset."); + if (dwarf_hasattr(&child, DW_AT_data_bit_offset)) { + XBT_WARN("Can't groke DW_AT_data_bit_offset for %s", name); + continue; + } MC_dwarf_fill_member_location(type, &member, &child); - if (not member.type_id) - xbt_die("Missing type for member %s of <%" PRIx64 ">%s", member.name.c_str(), (uint64_t)type->id, - type->name.c_str()); + xbt_assert(member.type_id, "Missing type for member %s of <%" PRIx64 ">%s", member.name.c_str(), + (uint64_t)type->id, type->name.c_str()); type->members.push_back(std::move(member)); } @@ -568,13 +510,13 @@ static simgrid::mc::Type MC_dwarf_die_to_type(simgrid::mc::ObjectInformation* in { simgrid::mc::Type type; type.type = dwarf_tag(die); - type.name = std::string(); + type.name = ""; type.element_count = -1; // Global Offset type.id = dwarf_dieoffset(die); - const char* prefix = ""; + const char* prefix; switch (type.type) { case DW_TAG_structure_type: prefix = "struct "; @@ -650,11 +592,9 @@ 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, - Dwarf_Die* /*unit*/, simgrid::mc::Frame* frame, - const char* ns) + const Dwarf_Die* /*unit*/, + const simgrid::mc::Frame* frame, const char* ns) { // Skip declarations: if (MC_dwarf_attr_flag(die, DW_AT_declaration, false)) @@ -669,10 +609,10 @@ static std::unique_ptr MC_die_to_variable(simgrid::mc::Ob // No location: do not add it ? return nullptr; - std::unique_ptr variable = std::unique_ptr(new simgrid::mc::Variable()); - variable->id = dwarf_dieoffset(die); - variable->global = frame == nullptr; // Can be override base on DW_AT_location - variable->object_info = info; + auto variable = std::make_unique(); + variable->id = dwarf_dieoffset(die); + variable->global = frame == nullptr; // Can be override base on DW_AT_location + variable->object_info = info; const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); if (name) @@ -692,17 +632,16 @@ static std::unique_ptr MC_die_to_variable(simgrid::mc::Ob { Dwarf_Op* expr; size_t len; - if (dwarf_getlocation(&attr_location, &expr, &len)) { - xbt_die("Could not read location expression in DW_AT_location " - "of variable <%" PRIx64 ">%s", - (uint64_t)variable->id, variable->name.c_str()); - } + xbt_assert(not dwarf_getlocation(&attr_location, &expr, &len), + "Could not read location expression in DW_AT_location " + "of variable <%" PRIx64 ">%s", + (uint64_t)variable->id, variable->name.c_str()); if (len == 1 && expr[0].atom == DW_OP_addr) { variable->global = true; - uintptr_t offset = (uintptr_t)expr[0].number; - uintptr_t base = (uintptr_t)info->base_address(); - variable->address = (void*)(base + offset); + auto offset = static_cast(expr[0].number); + auto base = reinterpret_cast(info->base_address()); + variable->address = reinterpret_cast(base + offset); } else variable->location_list = { simgrid::dwarf::LocationListEntry(simgrid::dwarf::DwarfExpression(expr, expr + len))}; @@ -738,10 +677,11 @@ static std::unique_ptr MC_die_to_variable(simgrid::mc::Ob } if (ns && variable->global) - variable->name = std::string(ns) + "::" + variable->name; + variable->name.insert(0, std::string(ns) + "::"); // 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++; @@ -749,7 +689,7 @@ static std::unique_ptr MC_die_to_variable(simgrid::mc::Ob return variable; } -static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, Dwarf_Die* unit, +static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* die, const Dwarf_Die* unit, simgrid::mc::Frame* frame, const char* ns) { std::unique_ptr variable = MC_die_to_variable(info, die, unit, frame, ns); @@ -791,39 +731,35 @@ static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwar frame.name = name; } - frame.abstract_origin_id = MC_dwarf_attr_dieoffset(die, DW_AT_abstract_origin); + frame.abstract_origin_id = MC_dwarf_attr_integrate_dieoffset(die, DW_AT_abstract_origin); // This is the base address for DWARF addresses. // Relocated addresses are offset from this base address. // See DWARF4 spec 7.5 - std::uint64_t base = (std::uint64_t)info->base_address(); + auto base = reinterpret_cast(info->base_address()); // TODO, support DW_AT_ranges uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc); - frame.range.begin() = low_pc ? (std::uint64_t)base + low_pc : 0; + frame.range.begin() = low_pc ? base + low_pc : 0; if (low_pc) { // DW_AT_high_pc: Dwarf_Attribute attr; - if (not dwarf_attr_integrate(die, DW_AT_high_pc, &attr)) - xbt_die("Missing DW_AT_high_pc matching with DW_AT_low_pc"); + xbt_assert(dwarf_attr_integrate(die, DW_AT_high_pc, &attr), "Missing DW_AT_high_pc matching with DW_AT_low_pc"); Dwarf_Sword offset; Dwarf_Addr high_pc; switch (simgrid::dwarf::classify_form(dwarf_whatform(&attr))) { - - // DW_AT_high_pc if an offset from the low_pc: + // DW_AT_high_pc if an offset from the low_pc: case simgrid::dwarf::FormClass::Constant: - if (dwarf_formsdata(&attr, &offset) != 0) - xbt_die("Could not read constant"); + xbt_assert(dwarf_formsdata(&attr, &offset) == 0, "Could not read constant"); frame.range.end() = frame.range.begin() + offset; break; // DW_AT_high_pc is a relocatable address: case simgrid::dwarf::FormClass::Address: - if (dwarf_formaddr(&attr, &high_pc) != 0) - xbt_die("Could not read address"); + xbt_assert(dwarf_formaddr(&attr, &high_pc) == 0, "Could not read address"); frame.range.end() = base + high_pc; break; @@ -856,8 +792,7 @@ static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* frame, const char* ns) { const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name); - if (frame) - xbt_die("Unexpected namespace in a subprogram"); + xbt_assert(not frame, "Unexpected namespace in a subprogram"); char* new_ns = ns == nullptr ? xbt_strdup(name) : bprintf("%s::%s", ns, name); MC_dwarf_handle_children(info, die, unit, frame, new_ns); xbt_free(new_ns); @@ -868,8 +803,7 @@ static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf { // For each child DIE: Dwarf_Die child; - int res; - for (res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) + for (int res = dwarf_child(die, &child); res == 0; res = dwarf_siblingof(&child, &child)) MC_dwarf_handle_die(info, &child, unit, frame, ns); } @@ -879,8 +813,7 @@ static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* int tag = dwarf_tag(die); simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag); switch (klass) { - - // Type: + // Type: case simgrid::dwarf::TagClass::Type: MC_dwarf_handle_type_die(info, die, unit, frame, ns); break; @@ -907,11 +840,9 @@ static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die* static Elf64_Half get_type(Elf* elf) { - Elf64_Ehdr* ehdr64 = elf64_getehdr(elf); - if (ehdr64) + if (const Elf64_Ehdr* ehdr64 = elf64_getehdr(elf)) return ehdr64->e_type; - Elf32_Ehdr* ehdr32 = elf32_getehdr(elf); - if (ehdr32) + if (const Elf32_Ehdr* ehdr32 = elf32_getehdr(elf)) return ehdr32->e_type; xbt_die("Could not get ELF heeader"); } @@ -924,8 +855,7 @@ static void read_dwarf_info(simgrid::mc::ObjectInformation* info, Dwarf* dwarf) size_t length; while (dwarf_nextcu(dwarf, offset, &next_offset, &length, nullptr, nullptr, nullptr) == 0) { - Dwarf_Die unit_die; - if (dwarf_offdie(dwarf, offset + length, &unit_die) != nullptr) + if (Dwarf_Die unit_die; dwarf_offdie(dwarf, offset + length, &unit_die) != nullptr) MC_dwarf_handle_children(info, &unit_die, &unit_die, nullptr, nullptr); offset = next_offset; } @@ -939,20 +869,19 @@ static void read_dwarf_info(simgrid::mc::ObjectInformation* info, Dwarf* dwarf) * @param elf libelf handle for an ELF file * @return build-id for this ELF file (or an empty vector if none is found) */ -static std::vector get_build_id(Elf* elf) +static std::vector get_build_id(Elf* elf) { #ifdef __linux // Summary: the GNU build ID is stored in a ("GNU, NT_GNU_BUILD_ID) note // found in a PT_NOTE entry in the program header table. size_t phnum; - if (elf_getphdrnum(elf, &phnum) != 0) - xbt_die("Could not read program headers"); + xbt_assert(elf_getphdrnum(elf, &phnum) == 0, "Could not read program headers"); // Iterate over the program headers and find the PT_NOTE ones: for (size_t i = 0; i < phnum; ++i) { GElf_Phdr phdr_temp; - GElf_Phdr* phdr = gelf_getphdr(elf, i, &phdr_temp); + const GElf_Phdr* phdr = gelf_getphdr(elf, i, &phdr_temp); if (phdr->p_type != PT_NOTE) continue; @@ -969,49 +898,44 @@ static std::vector get_build_id(Elf* elf) // A build ID note is identified by the pair ("GNU", NT_GNU_BUILD_ID) // (a namespace and a type within this namespace): if (nhdr.n_type == NT_GNU_BUILD_ID && nhdr.n_namesz == sizeof("GNU") && - memcmp((char*)data->d_buf + name_pos, "GNU", sizeof("GNU")) == 0) { + memcmp(static_cast(data->d_buf) + name_pos, "GNU", sizeof("GNU")) == 0) { XBT_DEBUG("Found GNU/NT_GNU_BUILD_ID note"); - char* start = (char*)data->d_buf + desc_pos; - char* end = (char*)start + nhdr.n_descsz; - return std::vector(start, end); + std::byte* start = static_cast(data->d_buf) + desc_pos; + std::byte* end = start + nhdr.n_descsz; + return std::vector(start, end); } } } #endif - return std::vector(); + return std::vector(); } -static char hexdigits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - /** Binary data to hexadecimal */ -static inline std::array to_hex(std::uint8_t byte) +static inline std::array to_hex(std::byte byte) { - // Horrid double braces! - // Apparently, this is needed in C++11 (not in C++14). - return {{hexdigits[byte >> 4], hexdigits[byte & 0xF]}}; + constexpr std::array hexdigits{ + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}}; + return {hexdigits[std::to_integer(byte >> 4)], hexdigits[std::to_integer(byte & std::byte{0xF})]}; } /** Binary data to hexadecimal */ -static std::string to_hex(const char* data, std::size_t count) +static std::string to_hex(const std::byte* data, std::size_t count) { std::string res; res.resize(2 * count); - for (std::size_t i = 0; i < count; i++) { - std::array hex_byte = to_hex(data[i]); - for (int j = 0; j < 2; ++j) - res[2 * i + j] = hex_byte[j]; - } + for (std::size_t i = 0; i < count; i++) + std::copy_n(cbegin(to_hex(data[i])), 2, &res[2 * i]); return res; } /** Binary data to hexadecimal */ -static std::string to_hex(std::vector const& data) +static std::string to_hex(std::vector const& data) { return to_hex(data.data(), data.size()); } /** Base directories for external debug files */ -static const char* debug_paths[] = { +static constexpr auto debug_paths = { "/usr/lib/debug/", "/usr/local/lib/debug/", }; @@ -1023,7 +947,7 @@ static const char* 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); @@ -1032,54 +956,46 @@ 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) { + if (int fd = open(filename.c_str(), O_RDONLY); 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("Not debuf info found for build ID %s\n", hex.data()); - return std::string(); + XBT_DEBUG("No debug info found for build ID %s\n", hex.data()); + return -1; } -/** @brief Populate the debugging informations of the given ELF object +/** @brief Populate the debugging information of the given ELF object * - * Read the DWARf information of the EFFL object and populate the + * Read the DWARF information of the ELF object and populate the * lists of types, variables, functions. */ static void MC_load_dwarf(simgrid::mc::ObjectInformation* info) { - if (elf_version(EV_CURRENT) == EV_NONE) - xbt_die("libelf initialization error"); + xbt_assert(elf_version(EV_CURRENT) != EV_NONE, "libelf initialization error"); // Open the ELF file: int fd = open(info->file_name.c_str(), O_RDONLY); - if (fd < 0) - xbt_die("Could not open file %s", info->file_name.c_str()); + xbt_assert(fd >= 0, "Could not open file %s", info->file_name.c_str()); Elf* elf = elf_begin(fd, ELF_C_READ, nullptr); - if (elf == nullptr) - xbt_die("Not an ELF file"); - Elf_Kind kind = elf_kind(elf); - if (kind != ELF_K_ELF) - xbt_die("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); - if (type == ET_EXEC) + if (get_type(elf) == ET_EXEC) info->flags |= simgrid::mc::ObjectInformation::Executable; // Read DWARF debug information in the file: - Dwarf* dwarf = dwarf_begin_elf(elf, DWARF_C_READ, nullptr); - if (dwarf != nullptr) { + if (Dwarf* dwarf = dwarf_begin_elf(elf, DWARF_C_READ, nullptr)) { read_dwarf_info(info, dwarf); dwarf_end(dwarf); elf_end(elf); close(fd); return; } - dwarf_end(dwarf); // If there was no DWARF in the file, try to find it in a separate file. - // Different methods might be used to store the DWARF informations: + // Different methods might be used to store the DWARF information: // * GNU NT_GNU_BUILD_ID // * .gnu_debuglink // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html @@ -1087,28 +1003,21 @@ static void MC_load_dwarf(simgrid::mc::ObjectInformation* info) // Try with NT_GNU_BUILD_ID: we find the build ID in the ELF file and then // use this ID to find the file in some known locations in the filesystem. - std::vector build_id = get_build_id(elf); - if (not build_id.empty()) { + if (std::vector build_id = get_build_id(elf); not build_id.empty()) { elf_end(elf); close(fd); // Find the debug file using the build id: - std::string debug_file = find_by_build_id(build_id); - if (debug_file.empty()) { - std::string hex = to_hex(build_id); - xbt_die("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(), hex.c_str()); - } + 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); - if (fd < 0) - xbt_die("Could not open file %s", debug_file.c_str()); - dwarf = dwarf_begin(fd, DWARF_C_READ); - if (dwarf == nullptr) - xbt_die("No DWARF info in %s for %s", debug_file.c_str(), info->file_name.c_str()); + XBT_DEBUG("Load DWARF for %s", info->file_name.c_str()); + Dwarf* dwarf = dwarf_begin(fd, DWARF_C_READ); + xbt_assert(dwarf != nullptr, "No DWARF info for %s", info->file_name.c_str()); read_dwarf_info(info, dwarf); dwarf_end(dwarf); close(fd); @@ -1130,12 +1039,12 @@ static void MC_make_functions_index(simgrid::mc::ObjectInformation* info) { info->functions_index.clear(); - for (auto& e : info->subprograms) { - if (e.second.range.begin() == 0) + for (auto& [_, e] : info->subprograms) { + if (e.range.begin() == 0) continue; simgrid::mc::FunctionIndexEntry entry; - entry.low_pc = (void*)e.second.range.begin(); - entry.function = &e.second; + entry.low_pc = (void*)e.range.begin(); + entry.function = &e; info->functions_index.push_back(entry); } @@ -1160,7 +1069,6 @@ static void MC_post_process_variables(simgrid::mc::ObjectInformation* info) static void mc_post_process_scope(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope) { - if (scope->tag == DW_TAG_inlined_subroutine) { // Attach correct namespaced name in inlined subroutine: auto i = info->subprograms.find(scope->abstract_origin_id); @@ -1197,8 +1105,7 @@ static simgrid::mc::Type* MC_resolve_type(simgrid::mc::ObjectInformation* info, // Try to find a more complete description of the type: // We need to fix in order to support C++. - simgrid::mc::Type** subtype = simgrid::util::find_map_ptr(info->full_types_by_name, type->name); - if (subtype) + if (simgrid::mc::Type** subtype = simgrid::util::find_map_ptr(info->full_types_by_name, type->name)) type = *subtype; return type; } @@ -1206,40 +1113,45 @@ static simgrid::mc::Type* MC_resolve_type(simgrid::mc::ObjectInformation* info, static void MC_post_process_types(simgrid::mc::ObjectInformation* info) { // Lookup "subtype" field: - for (auto& i : info->types) { - i.second.subtype = MC_resolve_type(info, i.second.type_id); - for (simgrid::mc::Member& member : i.second.members) + for (auto& [_, i] : info->types) { + i.subtype = MC_resolve_type(info, i.type_id); + for (simgrid::mc::Member& member : i.members) member.type = MC_resolve_type(info, member.type_id); } } -namespace simgrid { -namespace mc { +namespace simgrid::mc { -/** @brief Finds informations about a given shared object/executable */ -std::shared_ptr createObjectInformation(std::vector const& maps, - const char* name) +void ObjectInformation::ensure_dwarf_loaded() { - std::shared_ptr result = std::make_shared(); - result->file_name = name; + 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); + 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(simgrid::mc::RemoteClient* process, simgrid::mc::ObjectInformation* info) +void postProcessObjectInformation(const RemoteProcess* process, ObjectInformation* info) { - for (auto& t : info->types) { - - simgrid::mc::Type* type = &(t.second); - simgrid::mc::Type* subtype = type; + for (auto& [_, t] : info->types) { + Type* type = &t; + Type* subtype = type; while (subtype->type == DW_TAG_typedef || subtype->type == DW_TAG_volatile_type || subtype->type == DW_TAG_const_type) if (subtype->subtype) @@ -1261,11 +1173,9 @@ void postProcessObjectInformation(simgrid::mc::RemoteClient* process, simgrid::m } } -} // namespace mc -} // namespace simgrid +} // namespace simgrid::mc -namespace simgrid { -namespace dwarf { +namespace simgrid::dwarf { /** Convert a DWARF register into a libunwind register * @@ -1275,68 +1185,23 @@ namespace dwarf { */ int dwarf_register_to_libunwind(int dwarf_register) { -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__aarch64__) // It seems for this arch, DWARF and libunwind agree in the numbering: return 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 } -} // namespace dwarf -} // namespace simgrid +} // namespace simgrid::dwarf