void offset(int new_offset)
{
- Dwarf_Op op;
+ DwarfInstruction op;
op.atom = DW_OP_plus_uconst;
op.number = new_offset;
this->location_expression = { op };
#include <mc/mc.h>
#include "mc_snapshot.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_mmu.h"
#include "mc_unw.h"
#include "mc_protocol.h"
#include <xbt/sysdep.h>
#include "internal_config.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_safety.h"
#include "mc_liveness.h"
#include "mc_private.h"
#include "xbt/str.h"
#include "mc/mc.h"
#include "xbt/mmalloc.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc/datatypes.h"
#include "mc/mc_private.h"
#include "mc/mc_snapshot.h"
* under the terms of the license (GNU LGPL) which comes with this package. */
#include <cinttypes>
+#include <cstdint>
#include <algorithm>
#include <memory>
#include <stdlib.h>
#define DW_LANG_Objc DW_LANG_ObjC /* fix spelling error in older dwarf.h */
-#include <dwarf.h>
-#include <elfutils/libdw.h>
-#include <simgrid_config.h>
#include <simgrid/util.hpp>
#include <xbt/log.h>
#include <xbt/sysdep.h>
#include <simgrid/util.hpp>
-#include "mc_object_info.h"
-#include "mc_private.h"
-#include "mc_process.h"
+#include "mc/mc_dwarf.hpp"
+#include "mc/mc_dwarf.hpp"
+#include "mc/mc_private.h"
+#include "mc/mc_process.h"
#include "mc/ObjectInformation.hpp"
#include "mc/Variable.hpp"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing");
-/** \brief The default DW_TAG_lower_bound for a given DW_AT_language.
- *
- * The default for a given language is defined in the DWARF spec.
- *
- * \param language consant as defined by the DWARf spec
- */
-static uint64_t MC_dwarf_default_lower_bound(int lang);
-
-/** \brief Computes the the element_count of a DW_TAG_enumeration_type DIE
- *
- * This is the number of elements in a given array dimension.
- *
- * A reference of the compilation unit (DW_TAG_compile_unit) is
- * needed because the default lower bound (when there is no DW_AT_lower_bound)
- * depends of the language of the compilation unit (DW_AT_language).
- *
- * \param die DIE for the DW_TAG_enumeration_type or DW_TAG_subrange_type
- * \param unit DIE of the DW_TAG_compile_unit
- */
-static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die * die,
- Dwarf_Die * unit);
-
-/** \brief Computes the number of elements of a given DW_TAG_array_type.
- *
- * \param die DIE for the DW_TAG_array_type
- */
-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 die the current DIE
- * \param unit the DIE of the compile unit of the current DIE
- * \param frame containg frame if any
- */
-static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns);
-
-/** \brief Process a type DIE
- */
-static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns);
-
-/** \brief Calls MC_dwarf_handle_die on all childrend of the given die
- *
- * \param info the resulting object fot the library/binary file (output)
- * \param die the current DIE
- * \param unit the DIE of the compile unit of the current DIE
- * \param frame containg frame if any
- */
-static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns);
-
-/** \brief Handle a variable (DW_TAG_variable or other)
- *
- * \param info the resulting object fot the library/binary file (output)
- * \param die the current DIE
- * \param unit the DIE of the compile unit of the current DIE
- * \param frame containg frame if any
- */
-static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns);
-
-/** \brief Get the DW_TAG_type of the DIE
- *
- * \param die DIE
- * \return DW_TAG_type attribute as a new string (NULL if none)
- */
-static std::uint64_t MC_dwarf_at_type(Dwarf_Die * die);
-
-/** \brief A class of DWARF tags (DW_TAG_*)
- */
-typedef enum mc_tag_class {
- mc_tag_unknown,
- mc_tag_type,
- mc_tag_subprogram,
- mc_tag_variable,
- mc_tag_scope,
- mc_tag_namespace
-} mc_tag_class;
-
-static mc_tag_class MC_dwarf_tag_classify(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 mc_tag_type;
-
- case DW_TAG_subprogram:
- return mc_tag_subprogram;
-
- case DW_TAG_variable:
- case DW_TAG_formal_parameter:
- return mc_tag_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 mc_tag_scope;
-
- case DW_TAG_namespace:
- return mc_tag_namespace;
-
- default:
- return mc_tag_unknown;
-
- }
-}
-
-#define MC_DW_CLASS_UNKNOWN 0
-#define MC_DW_CLASS_ADDRESS 1 // Location in the address space of the program
-#define MC_DW_CLASS_BLOCK 2 // Arbitrary block of bytes
-#define MC_DW_CLASS_CONSTANT 3
-#define MC_DW_CLASS_STRING 3 // String
-#define MC_DW_CLASS_FLAG 4 // Boolean
-#define MC_DW_CLASS_REFERENCE 5 // Reference to another DIE
-#define MC_DW_CLASS_EXPRLOC 6 // DWARF expression/location description
-#define MC_DW_CLASS_LINEPTR 7
-#define MC_DW_CLASS_LOCLISTPTR 8
-#define MC_DW_CLASS_MACPTR 9
-#define MC_DW_CLASS_RANGELISTPTR 10
-
-/** \brief Find the DWARF data class for a given DWARF data form
- *
- * This mapping is defined in the DWARF spec.
- *
- * \param form The form (values taken from the DWARF spec)
- * \return An internal representation for the corresponding class
- * */
-static int MC_dwarf_form_get_class(int form)
-{
- switch (form) {
- case DW_FORM_addr:
- return MC_DW_CLASS_ADDRESS;
- case DW_FORM_block2:
- case DW_FORM_block4:
- case DW_FORM_block:
- case DW_FORM_block1:
- return MC_DW_CLASS_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 MC_DW_CLASS_CONSTANT;
- case DW_FORM_string:
- case DW_FORM_strp:
- return MC_DW_CLASS_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 MC_DW_CLASS_REFERENCE;
- case DW_FORM_flag:
- case DW_FORM_flag_present:
- return MC_DW_CLASS_FLAG;
- case DW_FORM_exprloc:
- return MC_DW_CLASS_EXPRLOC;
- // TODO sec offset
- // TODO indirect
- default:
- return MC_DW_CLASS_UNKNOWN;
- }
-}
-
-/** \brief Get the name of the tag of a given DIE
- *
- * \param die DIE
- * \return name of the tag of this DIE
- */
-static inline const char *MC_dwarf_die_tagname(Dwarf_Die * die)
-{
- return MC_dwarf_tagname(dwarf_tag(die));
-}
-
-// ***** Attributes
-
-/** \brief Get an attribute of a given DIE as a string
- *
- * \param die the DIE
- * \param attribute attribute
- * \return value of the given attribute of the given DIE
- */
-static const char *MC_dwarf_attr_integrate_string(Dwarf_Die * die,
- int attribute)
-{
- Dwarf_Attribute attr;
- if (!dwarf_attr_integrate(die, attribute, &attr)) {
- return NULL;
- } else {
- return dwarf_formstring(&attr);
- }
-}
-
-/** \brief Get the linkage name of a DIE.
- *
- * Use either DW_AT_linkage_name or DW_AT_MIPS_linkage_name.
- * DW_AT_linkage_name is standardized since DWARF 4.
- * Before this version of DWARF, the MIPS extensions
- * DW_AT_MIPS_linkage_name is used (at least by GCC).
- *
- * \param the DIE
- * \return linkage name of the given DIE (or NULL)
- * */
-static const char *MC_dwarf_at_linkage_name(Dwarf_Die * die)
-{
- const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_linkage_name);
- if (!name)
- name = MC_dwarf_attr_integrate_string(die, DW_AT_MIPS_linkage_name);
- return name;
-}
-
-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) == NULL)
- 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_Die subtype_die;
- if (dwarf_formref_die(&attr, &subtype_die) == NULL)
- xbt_die("Could not find DIE");
- return dwarf_dieoffset(&subtype_die);
-}
-
-/** \brief Find the type/subtype (DW_AT_type) for a DIE
- *
- * \param dit the DIE
- * \return DW_AT_type reference as a global offset in hexadecimal (or NULL)
- */
-static
-std::uint64_t MC_dwarf_at_type(Dwarf_Die * die)
-{
- return MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
-}
-
-static uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die * die, int attribute)
-{
- Dwarf_Attribute attr;
- if (dwarf_attr_integrate(die, attribute, &attr) == NULL)
- return 0;
- Dwarf_Addr value;
- if (dwarf_formaddr(&attr, &value) == 0)
- return (uint64_t) value;
- else
- return 0;
-}
-
-static uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die * die, int attribute,
- uint64_t default_value)
-{
- Dwarf_Attribute attr;
- if (dwarf_attr_integrate(die, attribute, &attr) == NULL)
- return default_value;
- Dwarf_Word value;
- return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr),
- &value) == 0 ? (uint64_t) value : default_value;
-}
-
-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)
- return false;
-
- bool result;
- if (dwarf_formflag(&attr, &result))
- xbt_die("Unexpected form for attribute %s", MC_dwarf_attrname(attribute));
- return result;
-}
-
-/** \brief Find the default lower bound for a given language
- *
- * The default lower bound of an array (when DW_TAG_lower_bound
- * is missing) depends on the language of the compilation unit.
- *
- * \param lang Language of the compilation unit (values defined in the DWARF spec)
- * \return Default lower bound of an array in this compilation unit
- * */
-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;
- }
-}
-
-/** \brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE
- *
- * \param die the DIE
- * \param unit DIE of the compilation unit
- * \return number of elements in the range
- * */
-static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die * die,
- Dwarf_Die * unit)
-{
- xbt_assert(dwarf_tag(die) == DW_TAG_enumeration_type
- || dwarf_tag(die) == DW_TAG_subrange_type,
- "MC_dwarf_subrange_element_count called with DIE of type %s",
- MC_dwarf_die_tagname(die));
-
- // Use DW_TAG_count if present:
- if (dwarf_hasattr_integrate(die, DW_AT_count))
- return MC_dwarf_attr_integrate_uint(die, DW_AT_count, 0);
- // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound + 1:
-
- if (!dwarf_hasattr_integrate(die, DW_AT_upper_bound))
- // This is not really 0, but the code expects this (we do not know):
- return 0;
-
- uint64_t upper_bound =
- MC_dwarf_attr_integrate_uint(die, DW_AT_upper_bound, -1);
-
- uint64_t lower_bound = 0;
- if (dwarf_hasattr_integrate(die, DW_AT_lower_bound))
- lower_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_lower_bound, -1);
- else
- lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
- return upper_bound - lower_bound + 1;
-}
-
-/** \brief Finds the number of elements in a 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.
- *
- * \param die the DIE of the DW_TAG_array_type
- * \param unit the DIE of the compilation unit
- * \return number of elements in this array type
- * */
-static uint64_t MC_dwarf_array_element_count(Dwarf_Die * die, Dwarf_Die * unit)
-{
- xbt_assert(dwarf_tag(die) == DW_TAG_array_type,
- "MC_dwarf_array_element_count called with DIE of type %s",
- MC_dwarf_die_tagname(die));
-
- int result = 1;
- Dwarf_Die child;
- int res;
- for (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);
- }
- return result;
-}
-
-// ***** Variable
-
-/** Sort the variable by name and address.
- *
- * We could use boost::container::flat_set instead.
- */
-static bool MC_compare_variable(
- simgrid::mc::Variable const& a, simgrid::mc::Variable const& b)
-{
- int cmp = strcmp(a.name.c_str(), b.name.c_str());
- if (cmp < 0)
- return true;
- else if (cmp > 0)
- return false;
- else
- return a.address < b.address;
-}
-
-// ***** simgrid::mc::Type*
-
-/** \brief Initialize the location of a member of a type
- * (DW_AT_data_member_location of a DW_TAG_member).
- *
- * \param type a type (struct, class)
- * \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::Type* member,
- Dwarf_Die * child)
-{
- if (dwarf_hasattr(child, DW_AT_data_bit_offset))
- xbt_die("Can't groke DW_AT_data_bit_offset.");
-
- if (!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());
- }
-
- Dwarf_Attribute attr;
- dwarf_attr_integrate(child, DW_AT_data_member_location, &attr);
- int form = dwarf_whatform(&attr);
- int klass = MC_dwarf_form_get_class(form);
- switch (klass) {
- case MC_DW_CLASS_EXPRLOC:
- case MC_DW_CLASS_BLOCK:
- // Location expression:
- {
- 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());
- simgrid::mc::DwarfExpression(expr, expr+len);
- break;
- }
- case MC_DW_CLASS_CONSTANT:
- // Offset from the base address of the object:
- {
- Dwarf_Word offset;
- if (!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());
- break;
- }
- case MC_DW_CLASS_LOCLISTPTR:
- // Reference to a location list:
- // TODO
- case MC_DW_CLASS_REFERENCE:
- // It's supposed to be possible in DWARF2 but I couldn't find its semantic
- // in the spec.
- default:
- xbt_die("Can't handle form class (%i) / form 0x%x as DW_AT_member_location",
- klass, form);
- }
-
-}
-
-/** \brief Populate the list of members of a type
- *
- * \param info ELF object containing the type DIE
- * \param die DIE of the type
- * \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)
-{
- int res;
- Dwarf_Die child;
- xbt_assert(type->members.empty());
- for (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;
-
- // Skip compile time constants:
- if (dwarf_hasattr(&child, DW_AT_const_value))
- continue;
-
- // TODO, we should use another type (because is is not a type but a member)
- simgrid::mc::Type member;
- member.type = tag;
-
- // Global Offset:
- member.id = dwarf_dieoffset(&child);
-
- const char *name = MC_dwarf_attr_integrate_string(&child, DW_AT_name);
- if (name)
- member.name = name;
- member.byte_size =
- MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0);
- member.element_count = -1;
- 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.");
-
- MC_dwarf_fill_member_location(type, &member, &child);
-
- if (!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());
-
- type->members.push_back(std::move(member));
- }
- }
-}
-
-/** \brief Create a MC type object from a DIE
- *
- * \param info current object info object
- * \param DIE (for a given type);
- * \param unit compilation unit of the current DIE
- * \return MC representation of the type
- */
-static simgrid::mc::Type MC_dwarf_die_to_type(
- simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- simgrid::mc::Type type;
- type.type = dwarf_tag(die);
- type.name = std::string();
- type.element_count = -1;
-
- // Global Offset
- type.id = dwarf_dieoffset(die);
-
- const char *prefix = "";
- switch (type.type) {
- case DW_TAG_structure_type:
- prefix = "struct ";
- break;
- case DW_TAG_union_type:
- prefix = "union ";
- break;
- case DW_TAG_class_type:
- prefix = "class ";
- break;
- default:
- prefix = "";
- }
-
- const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
- if (name != NULL) {
- char* full_name = ns ? bprintf("%s%s::%s", prefix, ns, name) :
- bprintf("%s%s", prefix, name);
- type.name = std::string(full_name);
- free(full_name);
- }
-
- type.type_id = MC_dwarf_at_type(die);
-
- // Some compilers do not emit DW_AT_byte_size for pointer_type,
- // so we fill this. We currently assume that the model-checked process is in
- // the same architecture..
- if (type.type == DW_TAG_pointer_type)
- type.byte_size = sizeof(void*);
-
- // Computation of the byte_size;
- if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
- type.byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
- else if (type.type == DW_TAG_array_type
- || type.type == DW_TAG_structure_type
- || type.type == DW_TAG_class_type) {
- Dwarf_Word size;
- if (dwarf_aggregate_size(die, &size) == 0)
- type.byte_size = size;
- }
-
- switch (type.type) {
- case DW_TAG_array_type:
- type.element_count = MC_dwarf_array_element_count(die, unit);
- // TODO, handle DW_byte_stride and (not) DW_bit_stride
- break;
-
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_rvalue_reference_type:
- type.is_pointer_type = 1;
- break;
-
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
- MC_dwarf_add_members(info, die, unit, &type);
- char *new_ns = ns == NULL ? xbt_strdup(type.name.c_str())
- : bprintf("%s::%s", ns, name);
- MC_dwarf_handle_children(info, die, unit, frame, new_ns);
- free(new_ns);
- break;
- }
-
- return std::move(type);
-}
-
-static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- simgrid::mc::Type type = MC_dwarf_die_to_type(info, die, unit, frame, ns);
- auto& t = (info->types[type.id] = std::move(type));
- if (!t.name.empty() && type.byte_size != 0)
- info->full_types_by_name[t.name] = &t;
-}
-
-static int mc_anonymous_variable_index = 0;
-
-static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable(
- simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- // Skip declarations:
- if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
- return nullptr;
-
- // Skip compile time constants:
- if (dwarf_hasattr(die, DW_AT_const_value))
- return nullptr;
-
- Dwarf_Attribute attr_location;
- if (dwarf_attr(die, DW_AT_location, &attr_location) == NULL)
- // No location: do not add it ?
- return nullptr;
-
- std::unique_ptr<simgrid::mc::Variable> variable =
- std::unique_ptr<simgrid::mc::Variable>(new simgrid::mc::Variable());
- variable->dwarf_offset = dwarf_dieoffset(die);
- variable->global = frame == NULL; // 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)
- variable->name = name;
- variable->type_id = MC_dwarf_at_type(die);
-
- int form = dwarf_whatform(&attr_location);
- int klass =
- form ==
- DW_FORM_sec_offset ? MC_DW_CLASS_CONSTANT : MC_dwarf_form_get_class(form);
- switch (klass) {
- case MC_DW_CLASS_EXPRLOC:
- case MC_DW_CLASS_BLOCK:
- // Location expression:
- {
- 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->dwarf_offset,
- variable->name.c_str());
- }
-
- if (len == 1 && expr[0].atom == DW_OP_addr) {
- variable->global = 1;
- uintptr_t offset = (uintptr_t) expr[0].number;
- uintptr_t base = (uintptr_t) info->base_address();
- variable->address = (void *) (base + offset);
- } else {
- simgrid::mc::LocationListEntry entry;
- entry.expression = {expr, expr + len};
- variable->location_list = { std::move(entry) };
- }
-
- break;
- }
- case MC_DW_CLASS_LOCLISTPTR:
- case MC_DW_CLASS_CONSTANT:
- // Reference to location list:
- mc_dwarf_location_list_init(
- &variable->location_list, info, die,
- &attr_location);
- break;
- default:
- xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location "
- "in <%" PRIx64 ">%s",
- form, form, klass, klass,
- (uint64_t) variable->dwarf_offset,
- variable->name.c_str());
- }
-
- // Handle start_scope:
- if (dwarf_hasattr(die, DW_AT_start_scope)) {
- Dwarf_Attribute attr;
- dwarf_attr(die, DW_AT_start_scope, &attr);
- int form = dwarf_whatform(&attr);
- int klass = MC_dwarf_form_get_class(form);
- switch (klass) {
- case MC_DW_CLASS_CONSTANT:
- {
- Dwarf_Word value;
- variable->start_scope =
- dwarf_formudata(&attr, &value) == 0 ? (size_t) value : 0;
- break;
- }
- case MC_DW_CLASS_RANGELISTPTR: // TODO
- default:
- xbt_die
- ("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s",
- form, klass, name == NULL ? "?" : name);
- }
- }
-
- if (ns && variable->global)
- variable->name =
- std::string(ns) + "::" + variable->name;
-
- // The current code needs a variable name,
- // generate a fake one:
- if (variable->name.empty())
- variable->name =
- "@anonymous#" + std::to_string(mc_anonymous_variable_index++);
-
- return std::move(variable);
-}
-
-static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- std::unique_ptr<simgrid::mc::Variable> variable =
- MC_die_to_variable(info, die, unit, frame, ns);
- if (!variable)
- return;
- // Those arrays are sorted later:
- else if (variable->global)
- info->global_variables.push_back(std::move(*variable));
- else if (frame != nullptr)
- frame->variables.push_back(std::move(*variable));
- else
- xbt_die("No frame for this local variable");
-}
-
-static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* parent_frame,
- const char *ns)
-{
- // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt
- int tag = dwarf_tag(die);
- mc_tag_class klass = MC_dwarf_tag_classify(tag);
-
- // (Template) Subprogram declaration:
- if (klass == mc_tag_subprogram
- && MC_dwarf_attr_flag(die, DW_AT_declaration, false))
- return;
-
- if (klass == mc_tag_scope)
- xbt_assert(parent_frame, "No parent scope for this scope");
-
- simgrid::mc::Frame frame;
-
- frame.tag = tag;
- frame.id = dwarf_dieoffset(die);
- frame.object_info = info;
-
- if (klass == mc_tag_subprogram) {
- const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
- if(ns)
- frame.name = std::string(ns) + "::" + name;
- else if (name)
- frame.name = name;
- else
- frame.name.clear();
- }
-
- frame.abstract_origin_id =
- MC_dwarf_attr_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
- void *base = info->base_address();
-
- // TODO, support DW_AT_ranges
- uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc);
- frame.low_pc = low_pc ? ((char *) base) + low_pc : 0;
- if (low_pc) {
- // DW_AT_high_pc:
- Dwarf_Attribute attr;
- if (!dwarf_attr_integrate(die, DW_AT_high_pc, &attr)) {
- xbt_die("Missing DW_AT_high_pc matching with DW_AT_low_pc");
- }
-
- Dwarf_Sword offset;
- Dwarf_Addr high_pc;
-
- switch (MC_dwarf_form_get_class(dwarf_whatform(&attr))) {
-
- // DW_AT_high_pc if an offset from the low_pc:
- case MC_DW_CLASS_CONSTANT:
-
- if (dwarf_formsdata(&attr, &offset) != 0)
- xbt_die("Could not read constant");
- frame.high_pc = (void *) ((char *) frame.low_pc + offset);
- break;
-
- // DW_AT_high_pc is a relocatable address:
- case MC_DW_CLASS_ADDRESS:
- if (dwarf_formaddr(&attr, &high_pc) != 0)
- xbt_die("Could not read address");
- frame.high_pc = ((char *) base) + high_pc;
- break;
-
- default:
- xbt_die("Unexpected class for DW_AT_high_pc");
-
- }
- }
-
- if (klass == mc_tag_subprogram) {
- Dwarf_Attribute attr_frame_base;
- if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
- mc_dwarf_location_list_init(&frame.frame_base, info, die,
- &attr_frame_base);
- }
-
- // Handle children:
- MC_dwarf_handle_children(info, die, unit, &frame, ns);
-
- // Someone needs this to be sorted but who?
- std::sort(frame.variables.begin(), frame.variables.end(),
- MC_compare_variable);
-
- // Register it:
- if (klass == mc_tag_subprogram)
- info->subprograms[frame.id] = frame;
- else if (klass == mc_tag_scope)
- parent_frame->scopes.push_back(std::move(frame));
-}
-
-static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info,
- Dwarf_Die * die, Dwarf_Die * unit,
- 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");
- char *new_ns = ns == NULL ? xbt_strdup(name)
- : bprintf("%s::%s", ns, name);
- MC_dwarf_handle_children(info, die, unit, frame, new_ns);
- xbt_free(new_ns);
-}
-
-static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- // For each child DIE:
- Dwarf_Die child;
- int res;
- for (res = dwarf_child(die, &child); res == 0;
- res = dwarf_siblingof(&child, &child)) {
- MC_dwarf_handle_die(info, &child, unit, frame, ns);
- }
-}
-
-static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
- Dwarf_Die * unit, simgrid::mc::Frame* frame,
- const char *ns)
-{
- int tag = dwarf_tag(die);
- mc_tag_class klass = MC_dwarf_tag_classify(tag);
- switch (klass) {
-
- // Type:
- case mc_tag_type:
- MC_dwarf_handle_type_die(info, die, unit, frame, ns);
- break;
-
- // Subprogram or scope:
- case mc_tag_subprogram:
- case mc_tag_scope:
- MC_dwarf_handle_scope_die(info, die, unit, frame, ns);
- return;
-
- // Variable:
- case mc_tag_variable:
- MC_dwarf_handle_variable_die(info, die, unit, frame, ns);
- break;
-
- case mc_tag_namespace:
- mc_dwarf_handle_namespace_die(info, die, unit, frame, ns);
- break;
-
- default:
- break;
-
- }
-}
-
-/** \brief Populate the debugging informations of the given ELF object
- *
- * Read the DWARf information of the EFFL object and populate the
- * lists of types, variables, functions.
- */
-void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info)
-{
- 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());
- Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
- if (dwarf == NULL)
- xbt_die("Missing debugging information in %s\n"
- "Your program and its dependencies must have debugging information.\n"
- "You might want to recompile with -g or install the suitable debugging package.\n",
- info->file_name.c_str());
- // For each compilation unit:
- Dwarf_Off offset = 0;
- Dwarf_Off next_offset = 0;
- size_t length;
-
- while (dwarf_nextcu(dwarf, offset, &next_offset, &length, NULL, NULL, NULL) ==
- 0) {
- Dwarf_Die unit_die;
- if (dwarf_offdie(dwarf, offset + length, &unit_die) != NULL)
- MC_dwarf_handle_children(info, &unit_die, &unit_die, NULL, NULL);
- offset = next_offset;
- }
-
- dwarf_end(dwarf);
- close(fd);
-}
-
// ***** Functions index
static int MC_compare_frame_index_items(simgrid::mc::FunctionIndexEntry* a,
info->types, variable.type_id);
}
-static void mc_post_process_scope(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope)
+static void mc_post_process_scope(
+ simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope)
{
if (scope->tag == DW_TAG_inlined_subroutine) {
auto i = info->subprograms.find(scope->abstract_origin_id);
xbt_assert(i != info->subprograms.end(),
"Could not lookup abstract origin %" PRIx64,
- (uint64_t) scope->abstract_origin_id);
+ (std::uint64_t) scope->abstract_origin_id);
scope->name = i->second.name;
}
/** \brief Fill/lookup the "subtype" field.
*/
-static void MC_resolve_subtype(simgrid::mc::ObjectInformation* info, simgrid::mc::Type* type)
+static void MC_resolve_subtype(
+ simgrid::mc::ObjectInformation* info, simgrid::mc::Type* type)
{
if (!type->type_id)
return;
--- /dev/null
+/* Copyright (c) 2008-2015. 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. */
+
+#if !defined(SIMGRID_MC_DWARF_HPP)
+#define SIMGRID_MC_DWARF_HPP
+
+#include <memory>
+
+#include <string.h>
+
+#include <xbt/sysdep.h>
+
+#define DW_LANG_Objc DW_LANG_ObjC /* fix spelling error in older dwarf.h */
+#include <dwarf.h>
+
+#include "mc/Variable.hpp"
+#include "mc/mc_memory_map.h"
+
+/** \brief A class of DWARF tags (DW_TAG_*)
+ */
+typedef enum mc_tag_class {
+ mc_tag_unknown,
+ mc_tag_type,
+ mc_tag_subprogram,
+ mc_tag_variable,
+ mc_tag_scope,
+ mc_tag_namespace
+} mc_tag_class;
+
+static mc_tag_class MC_dwarf_tag_classify(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 mc_tag_type;
+
+ case DW_TAG_subprogram:
+ return mc_tag_subprogram;
+
+ case DW_TAG_variable:
+ case DW_TAG_formal_parameter:
+ return mc_tag_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 mc_tag_scope;
+
+ case DW_TAG_namespace:
+ return mc_tag_namespace;
+
+ default:
+ return mc_tag_unknown;
+
+ }
+}
+
+#define MC_DW_CLASS_UNKNOWN 0
+#define MC_DW_CLASS_ADDRESS 1 // Location in the address space of the program
+#define MC_DW_CLASS_BLOCK 2 // Arbitrary block of bytes
+#define MC_DW_CLASS_CONSTANT 3
+#define MC_DW_CLASS_STRING 3 // String
+#define MC_DW_CLASS_FLAG 4 // Boolean
+#define MC_DW_CLASS_REFERENCE 5 // Reference to another DIE
+#define MC_DW_CLASS_EXPRLOC 6 // DWARF expression/location description
+#define MC_DW_CLASS_LINEPTR 7
+#define MC_DW_CLASS_LOCLISTPTR 8
+#define MC_DW_CLASS_MACPTR 9
+#define MC_DW_CLASS_RANGELISTPTR 10
+
+/** \brief Find the DWARF data class for a given DWARF data form
+ *
+ * This mapping is defined in the DWARF spec.
+ *
+ * \param form The form (values taken from the DWARF spec)
+ * \return An internal representation for the corresponding class
+ * */
+static int MC_dwarf_form_get_class(int form)
+{
+ switch (form) {
+ case DW_FORM_addr:
+ return MC_DW_CLASS_ADDRESS;
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ return MC_DW_CLASS_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 MC_DW_CLASS_CONSTANT;
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ return MC_DW_CLASS_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 MC_DW_CLASS_REFERENCE;
+ case DW_FORM_flag:
+ case DW_FORM_flag_present:
+ return MC_DW_CLASS_FLAG;
+ case DW_FORM_exprloc:
+ return MC_DW_CLASS_EXPRLOC;
+ // TODO sec offset
+ // TODO indirect
+ default:
+ return MC_DW_CLASS_UNKNOWN;
+ }
+}
+
+/** \brief Find the default lower bound for a given language
+ *
+ * The default lower bound of an array (when DW_TAG_lower_bound
+ * is missing) depends on the language of the compilation unit.
+ *
+ * \param lang Language of the compilation unit (values defined in the DWARF spec)
+ * \return Default lower bound of an array in this compilation unit
+ * */
+static inline
+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;
+ }
+}
+
+/** Sort the variable by name and address.
+ *
+ * We could use boost::container::flat_set instead.
+ */
+static inline
+bool MC_compare_variable(
+ simgrid::mc::Variable const& a, simgrid::mc::Variable const& b)
+{
+ int cmp = a.name.compare(b.name);
+ if (cmp < 0)
+ return true;
+ else if (cmp > 0)
+ return false;
+ else
+ return a.address < b.address;
+}
+
+XBT_INTERNAL std::shared_ptr<simgrid::mc::ObjectInformation> MC_find_object_info(
+ std::vector<simgrid::mc::VmMap> const& maps, const char* name, int executable);
+XBT_INTERNAL void MC_post_process_object_info(simgrid::mc::Process* process, simgrid::mc::ObjectInformation* info);
+
+XBT_INTERNAL void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info);
+XBT_INTERNAL void MC_dwarf_get_variables_libdw(simgrid::mc::ObjectInformation* info);
+
+XBT_INTERNAL const char* MC_dwarf_attrname(int attr);
+XBT_INTERNAL const char* MC_dwarf_tagname(int tag);
+
+XBT_INTERNAL void* mc_member_resolve(
+ const void* base, simgrid::mc::Type* type, simgrid::mc::Type* member,
+ simgrid::mc::AddressSpace* snapshot, int process_index);
+
+#endif
#include <xbt/base.h>
#include <dwarf.h>
-#include "mc_object_info.h"
-
/** \brief Get the name of an attribute (DW_AT_*) from its code
*
* \param attr attribute code (see the DWARF specification)
/* 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. */
+#include <cstdint>
+
#include <stdint.h>
#include <stdarg.h>
#include <dwarf.h>
-#include <elfutils/libdw.h>
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_private.h"
#include "mc_location.h"
#include "mc/AddressSpace.hpp"
extern "C" {
-static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
+static int mc_dwarf_push_value(mc_expression_state_t state, std::uint64_t value)
{
if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
return MC_EXPRESSION_E_STACK_OVERFLOW;
#endif
}
-int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
+int mc_dwarf_execute_expression(size_t n, const simgrid::mc::DwarfInstruction* ops,
mc_expression_state_t state)
{
for (size_t i = 0; i != n; ++i) {
int error = 0;
- const Dwarf_Op *op = ops + i;
+ const simgrid::mc::DwarfInstruction *op = ops + i;
uint8_t atom = op->atom;
switch (atom) {
return MC_EXPRESSION_E_NO_BASE_ADDRESS;
if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
return MC_EXPRESSION_E_STACK_OVERFLOW;
- Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
+ std::uint64_t addr = (std::uint64_t) (uintptr_t)
state->object_info->base_address() + op->number;
error = mc_dwarf_push_value(state, addr);
break;
}
}
-void mc_dwarf_location_list_init(
- simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
- Dwarf_Die * die, Dwarf_Attribute * attr)
-{
- list->clear();
-
- ptrdiff_t offset = 0;
- Dwarf_Addr base, start, end;
- Dwarf_Op *ops;
- size_t len;
-
- while (1) {
-
- offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
- if (offset == 0)
- return;
- else if (offset == -1)
- xbt_die("Error while loading location list");
-
- simgrid::mc::LocationListEntry entry;
- entry.expression = simgrid::mc::DwarfExpression(ops, ops + len);
-
- void *base = info->base_address();
- // If start == 0, this is not a location list:
- entry.lowpc = start == 0 ? NULL : (char *) base + start;
- entry.highpc = start == 0 ? NULL : (char *) base + end;
-
- list->push_back(std::move(entry));
- }
-
-}
-
}
/* Warning: autogenerated, do not edit! */
#include <dwarf.h>
-#include <elfutils/libdw.h>
#include <xbt/base.h>
-#include "mc_object_info.h"
/** \brief Get the name of a dwarf tag (DW_TAG_*) from its code
*
case 0x4109: return "DW_TAG_GNU_call_site";
case 0x410a: return "DW_TAG_GNU_call_site_parameter";
case 0xffff: return "DW_TAG_hi_user";
- case DW_TAG_invalid:
- return "DW_TAG_invalid";
default:
return "DW_TAG_unknown";
}
#include <libunwind.h>
#include <xbt/mmalloc.h>
#include "../xbt/mmalloc/mmprivate.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_comm_pattern.h"
#include "mc_request.h"
#include "mc_safety.h"
* under the terms of the license (GNU LGPL) which comes with this package. */
#include "internal_config.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_private.h"
#include "smpi/private.h"
#include "mc/mc_snapshot.h"
--- /dev/null
+/* Copyright (c) 2008-2015. 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. */
+
+#include <cstdint>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+
+#include <xbt/log.h>
+
+#include "mc/Frame.hpp"
+#include "mc/ObjectInformation.hpp"
+#include "mc/Variable.hpp"
+
+#include "mc/mc_dwarf.hpp"
+#include "mc/mc_libdw.hpp"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_libdw, mc, "DWARF processing");
+
+/** \brief Get the name of the tag of a given DIE
+ *
+ * \param die DIE
+ * \return name of the tag of this DIE
+ */
+static inline const char *MC_dwarf_die_tagname(Dwarf_Die * die)
+{
+ return MC_dwarf_tagname(dwarf_tag(die));
+}
+
+static
+simgrid::mc::DwarfExpression MC_dwarf_expression(Dwarf_Op* ops, std::size_t len)
+{
+ simgrid::mc::DwarfExpression expression(len);
+ for (std::size_t i = 0; i != len; ++i) {
+ expression[i].atom = ops[i].atom;
+ expression[i].number = ops[i].number;
+ expression[i].number2 = ops[i].number2;
+ expression[i].offset = ops[i].offset;
+ }
+ return std::move(expression);
+}
+
+static void mc_dwarf_location_list_init_libdw(
+ simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
+ Dwarf_Die * die, Dwarf_Attribute * attr)
+{
+ list->clear();
+
+ ptrdiff_t offset = 0;
+ Dwarf_Addr base, start, end;
+ Dwarf_Op *ops;
+ size_t len;
+
+ while (1) {
+
+ offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
+ if (offset == 0)
+ return;
+ else if (offset == -1)
+ xbt_die("Error while loading location list");
+
+ simgrid::mc::LocationListEntry entry;
+ entry.expression = MC_dwarf_expression(ops, len);
+
+ void *base = info->base_address();
+ // If start == 0, this is not a location list:
+ entry.lowpc = start == 0 ? NULL : (char *) base + start;
+ entry.highpc = start == 0 ? NULL : (char *) base + end;
+
+ list->push_back(std::move(entry));
+ }
+
+}
+
+// ***** Attributes
+
+/** \brief Get an attribute of a given DIE as a string
+ *
+ * \param die the DIE
+ * \param attribute attribute
+ * \return value of the given attribute of the given DIE
+ */
+static const char *MC_dwarf_attr_integrate_string(Dwarf_Die * die,
+ int attribute)
+{
+ Dwarf_Attribute attr;
+ if (!dwarf_attr_integrate(die, attribute, &attr)) {
+ return NULL;
+ } else {
+ return dwarf_formstring(&attr);
+ }
+}
+
+/** \brief Get the linkage name of a DIE.
+ *
+ * Use either DW_AT_linkage_name or DW_AT_MIPS_linkage_name.
+ * DW_AT_linkage_name is standardized since DWARF 4.
+ * Before this version of DWARF, the MIPS extensions
+ * DW_AT_MIPS_linkage_name is used (at least by GCC).
+ *
+ * \param the DIE
+ * \return linkage name of the given DIE (or NULL)
+ * */
+static const char *MC_dwarf_at_linkage_name(Dwarf_Die * die)
+{
+ const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_linkage_name);
+ if (!name)
+ name = MC_dwarf_attr_integrate_string(die, DW_AT_MIPS_linkage_name);
+ return name;
+}
+
+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) == NULL)
+ 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_Die subtype_die;
+ if (dwarf_formref_die(&attr, &subtype_die) == NULL)
+ xbt_die("Could not find DIE");
+ return dwarf_dieoffset(&subtype_die);
+}
+
+/** \brief Find the type/subtype (DW_AT_type) for a DIE
+ *
+ * \param dit the DIE
+ * \return DW_AT_type reference as a global offset in hexadecimal (or NULL)
+ */
+static
+std::uint64_t MC_dwarf_at_type(Dwarf_Die * die)
+{
+ return MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
+}
+
+static std::uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die * die, int attribute)
+{
+ Dwarf_Attribute attr;
+ if (dwarf_attr_integrate(die, attribute, &attr) == NULL)
+ return 0;
+ Dwarf_Addr value;
+ if (dwarf_formaddr(&attr, &value) == 0)
+ return (std::uint64_t) value;
+ else
+ return 0;
+}
+
+static std::uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die * die, int attribute,
+ std::uint64_t default_value)
+{
+ Dwarf_Attribute attr;
+ if (dwarf_attr_integrate(die, attribute, &attr) == NULL)
+ return default_value;
+ Dwarf_Word value;
+ return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr),
+ &value) == 0 ? (std::uint64_t) value : default_value;
+}
+
+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)
+ return false;
+
+ bool result;
+ if (dwarf_formflag(&attr, &result))
+ xbt_die("Unexpected form for attribute %s", MC_dwarf_attrname(attribute));
+ return result;
+}
+
+/** \brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE
+ *
+ * \param die the DIE
+ * \param unit DIE of the compilation unit
+ * \return number of elements in the range
+ * */
+static std::uint64_t MC_dwarf_subrange_element_count(Dwarf_Die * die,
+ Dwarf_Die * unit)
+{
+ xbt_assert(dwarf_tag(die) == DW_TAG_enumeration_type
+ || dwarf_tag(die) == DW_TAG_subrange_type,
+ "MC_dwarf_subrange_element_count called with DIE of type %s",
+ MC_dwarf_die_tagname(die));
+
+ // Use DW_TAG_count if present:
+ if (dwarf_hasattr_integrate(die, DW_AT_count))
+ return MC_dwarf_attr_integrate_uint(die, DW_AT_count, 0);
+ // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound + 1:
+
+ if (!dwarf_hasattr_integrate(die, DW_AT_upper_bound))
+ // This is not really 0, but the code expects this (we do not know):
+ return 0;
+
+ std::uint64_t upper_bound =
+ MC_dwarf_attr_integrate_uint(die, DW_AT_upper_bound, -1);
+
+ std::uint64_t lower_bound = 0;
+ if (dwarf_hasattr_integrate(die, DW_AT_lower_bound))
+ lower_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_lower_bound, -1);
+ else
+ lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
+ return upper_bound - lower_bound + 1;
+}
+
+/** \brief Finds the number of elements in a 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.
+ *
+ * \param die the DIE of the DW_TAG_array_type
+ * \param unit the DIE of the compilation unit
+ * \return number of elements in this array type
+ * */
+static
+std::uint64_t MC_dwarf_array_element_count(Dwarf_Die * die, Dwarf_Die * unit)
+{
+ xbt_assert(dwarf_tag(die) == DW_TAG_array_type,
+ "MC_dwarf_array_element_count called with DIE of type %s",
+ MC_dwarf_die_tagname(die));
+
+ int result = 1;
+ Dwarf_Die child;
+ int res;
+ for (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);
+ }
+ return result;
+}
+
+// ***** simgrid::mc::Type*
+
+/** \brief Initialize the location of a member of a type
+ * (DW_AT_data_member_location of a DW_TAG_member).
+ *
+ * \param type a type (struct, class)
+ * \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::Type* member,
+ Dwarf_Die * child)
+{
+ if (dwarf_hasattr(child, DW_AT_data_bit_offset))
+ xbt_die("Can't groke DW_AT_data_bit_offset.");
+
+ if (!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(),
+ (std::uint64_t) type->id, type->name.c_str());
+ }
+
+ Dwarf_Attribute attr;
+ dwarf_attr_integrate(child, DW_AT_data_member_location, &attr);
+ int form = dwarf_whatform(&attr);
+ int klass = MC_dwarf_form_get_class(form);
+ switch (klass) {
+ case MC_DW_CLASS_EXPRLOC:
+ case MC_DW_CLASS_BLOCK:
+ // Location expression:
+ {
+ 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),
+ (std::uint64_t) type->id, type->name.c_str());
+ member->location_expression = MC_dwarf_expression(expr, len);
+ break;
+ }
+ case MC_DW_CLASS_CONSTANT:
+ // Offset from the base address of the object:
+ {
+ Dwarf_Word offset;
+ if (!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),
+ (std::uint64_t) type->id, type->name.c_str());
+ break;
+ }
+ case MC_DW_CLASS_LOCLISTPTR:
+ // Reference to a location list:
+ // TODO
+ case MC_DW_CLASS_REFERENCE:
+ // It's supposed to be possible in DWARF2 but I couldn't find its semantic
+ // in the spec.
+ default:
+ xbt_die("Can't handle form class (%i) / form 0x%x as DW_AT_member_location",
+ klass, form);
+ }
+
+}
+
+/** \brief Populate the list of members of a type
+ *
+ * \param info ELF object containing the type DIE
+ * \param die DIE of the type
+ * \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)
+{
+ int res;
+ Dwarf_Die child;
+ xbt_assert(type->members.empty());
+ for (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;
+
+ // Skip compile time constants:
+ if (dwarf_hasattr(&child, DW_AT_const_value))
+ continue;
+
+ // TODO, we should use another type (because is is not a type but a member)
+ simgrid::mc::Type member;
+ member.type = tag;
+
+ // Global Offset:
+ member.id = dwarf_dieoffset(&child);
+
+ const char *name = MC_dwarf_attr_integrate_string(&child, DW_AT_name);
+ if (name)
+ member.name = name;
+ member.byte_size =
+ MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0);
+ member.element_count = -1;
+ 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.");
+
+ MC_dwarf_fill_member_location(type, &member, &child);
+
+ if (!member.type_id)
+ xbt_die("Missing type for member %s of <%" PRIx64 ">%s",
+ member.name.c_str(),
+ (std::uint64_t) type->id, type->name.c_str());
+
+ type->members.push_back(std::move(member));
+ }
+ }
+}
+
+/** \brief Create a MC type object from a DIE
+ *
+ * \param info current object info object
+ * \param DIE (for a given type);
+ * \param unit compilation unit of the current DIE
+ * \return MC representation of the type
+ */
+static simgrid::mc::Type MC_dwarf_die_to_type(
+ simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ simgrid::mc::Type type;
+ type.type = dwarf_tag(die);
+ type.name = std::string();
+ type.element_count = -1;
+
+ // Global Offset
+ type.id = dwarf_dieoffset(die);
+
+ const char *prefix = "";
+ switch (type.type) {
+ case DW_TAG_structure_type:
+ prefix = "struct ";
+ break;
+ case DW_TAG_union_type:
+ prefix = "union ";
+ break;
+ case DW_TAG_class_type:
+ prefix = "class ";
+ break;
+ default:
+ prefix = "";
+ }
+
+ const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
+ if (name != NULL) {
+ char* full_name = ns ? bprintf("%s%s::%s", prefix, ns, name) :
+ bprintf("%s%s", prefix, name);
+ type.name = std::string(full_name);
+ free(full_name);
+ }
+
+ type.type_id = MC_dwarf_at_type(die);
+
+ // Some compilers do not emit DW_AT_byte_size for pointer_type,
+ // so we fill this. We currently assume that the model-checked process is in
+ // the same architecture..
+ if (type.type == DW_TAG_pointer_type)
+ type.byte_size = sizeof(void*);
+
+ // Computation of the byte_size;
+ if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
+ type.byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
+ else if (type.type == DW_TAG_array_type
+ || type.type == DW_TAG_structure_type
+ || type.type == DW_TAG_class_type) {
+ Dwarf_Word size;
+ if (dwarf_aggregate_size(die, &size) == 0)
+ type.byte_size = size;
+ }
+
+ switch (type.type) {
+ case DW_TAG_array_type:
+ type.element_count = MC_dwarf_array_element_count(die, unit);
+ // TODO, handle DW_byte_stride and (not) DW_bit_stride
+ break;
+
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ type.is_pointer_type = 1;
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ MC_dwarf_add_members(info, die, unit, &type);
+ char *new_ns = ns == NULL ? xbt_strdup(type.name.c_str())
+ : bprintf("%s::%s", ns, name);
+ MC_dwarf_handle_children(info, die, unit, frame, new_ns);
+ free(new_ns);
+ break;
+ }
+
+ return std::move(type);
+}
+
+static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ simgrid::mc::Type type = MC_dwarf_die_to_type(info, die, unit, frame, ns);
+ auto& t = (info->types[type.id] = std::move(type));
+ if (!t.name.empty() && type.byte_size != 0)
+ info->full_types_by_name[t.name] = &t;
+}
+
+static int mc_anonymous_variable_index = 0;
+
+static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable(
+ simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ // Skip declarations:
+ if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
+ return nullptr;
+
+ // Skip compile time constants:
+ if (dwarf_hasattr(die, DW_AT_const_value))
+ return nullptr;
+
+ Dwarf_Attribute attr_location;
+ if (dwarf_attr(die, DW_AT_location, &attr_location) == NULL)
+ // No location: do not add it ?
+ return nullptr;
+
+ std::unique_ptr<simgrid::mc::Variable> variable =
+ std::unique_ptr<simgrid::mc::Variable>(new simgrid::mc::Variable());
+ variable->dwarf_offset = dwarf_dieoffset(die);
+ variable->global = frame == NULL; // 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)
+ variable->name = name;
+ variable->type_id = MC_dwarf_at_type(die);
+
+ int form = dwarf_whatform(&attr_location);
+ int klass =
+ form ==
+ DW_FORM_sec_offset ? MC_DW_CLASS_CONSTANT : MC_dwarf_form_get_class(form);
+ switch (klass) {
+ case MC_DW_CLASS_EXPRLOC:
+ case MC_DW_CLASS_BLOCK:
+ // Location expression:
+ {
+ 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",
+ (std::uint64_t) variable->dwarf_offset,
+ variable->name.c_str());
+ }
+
+ if (len == 1 && expr[0].atom == DW_OP_addr) {
+ variable->global = 1;
+ uintptr_t offset = (uintptr_t) expr[0].number;
+ uintptr_t base = (uintptr_t) info->base_address();
+ variable->address = (void *) (base + offset);
+ } else {
+ simgrid::mc::LocationListEntry entry;
+ entry.expression = MC_dwarf_expression(expr, len);
+ variable->location_list = { std::move(entry) };
+ }
+
+ break;
+ }
+ case MC_DW_CLASS_LOCLISTPTR:
+ case MC_DW_CLASS_CONSTANT:
+ // Reference to location list:
+ mc_dwarf_location_list_init_libdw(
+ &variable->location_list, info, die,
+ &attr_location);
+ break;
+ default:
+ xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location "
+ "in <%" PRIx64 ">%s",
+ form, form, klass, klass,
+ (std::uint64_t) variable->dwarf_offset,
+ variable->name.c_str());
+ }
+
+ // Handle start_scope:
+ if (dwarf_hasattr(die, DW_AT_start_scope)) {
+ Dwarf_Attribute attr;
+ dwarf_attr(die, DW_AT_start_scope, &attr);
+ int form = dwarf_whatform(&attr);
+ int klass = MC_dwarf_form_get_class(form);
+ switch (klass) {
+ case MC_DW_CLASS_CONSTANT:
+ {
+ Dwarf_Word value;
+ variable->start_scope =
+ dwarf_formudata(&attr, &value) == 0 ? (size_t) value : 0;
+ break;
+ }
+ case MC_DW_CLASS_RANGELISTPTR: // TODO
+ default:
+ xbt_die
+ ("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s",
+ form, klass, name == NULL ? "?" : name);
+ }
+ }
+
+ if (ns && variable->global)
+ variable->name =
+ std::string(ns) + "::" + variable->name;
+
+ // The current code needs a variable name,
+ // generate a fake one:
+ if (variable->name.empty())
+ variable->name =
+ "@anonymous#" + std::to_string(mc_anonymous_variable_index++);
+
+ return std::move(variable);
+}
+
+static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ std::unique_ptr<simgrid::mc::Variable> variable =
+ MC_die_to_variable(info, die, unit, frame, ns);
+ if (!variable)
+ return;
+ // Those arrays are sorted later:
+ else if (variable->global)
+ info->global_variables.push_back(std::move(*variable));
+ else if (frame != nullptr)
+ frame->variables.push_back(std::move(*variable));
+ else
+ xbt_die("No frame for this local variable");
+}
+
+static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* parent_frame,
+ const char *ns)
+{
+ // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt
+ int tag = dwarf_tag(die);
+ mc_tag_class klass = MC_dwarf_tag_classify(tag);
+
+ // (Template) Subprogram declaration:
+ if (klass == mc_tag_subprogram
+ && MC_dwarf_attr_flag(die, DW_AT_declaration, false))
+ return;
+
+ if (klass == mc_tag_scope)
+ xbt_assert(parent_frame, "No parent scope for this scope");
+
+ simgrid::mc::Frame frame;
+
+ frame.tag = tag;
+ frame.id = dwarf_dieoffset(die);
+ frame.object_info = info;
+
+ if (klass == mc_tag_subprogram) {
+ const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
+ if(ns)
+ frame.name = std::string(ns) + "::" + name;
+ else if (name)
+ frame.name = name;
+ else
+ frame.name.clear();
+ }
+
+ frame.abstract_origin_id =
+ MC_dwarf_attr_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
+ void *base = info->base_address();
+
+ // TODO, support DW_AT_ranges
+ std::uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc);
+ frame.low_pc = low_pc ? ((char *) base) + low_pc : 0;
+ if (low_pc) {
+ // DW_AT_high_pc:
+ Dwarf_Attribute attr;
+ if (!dwarf_attr_integrate(die, DW_AT_high_pc, &attr)) {
+ xbt_die("Missing DW_AT_high_pc matching with DW_AT_low_pc");
+ }
+
+ Dwarf_Sword offset;
+ Dwarf_Addr high_pc;
+
+ switch (MC_dwarf_form_get_class(dwarf_whatform(&attr))) {
+
+ // DW_AT_high_pc if an offset from the low_pc:
+ case MC_DW_CLASS_CONSTANT:
+
+ if (dwarf_formsdata(&attr, &offset) != 0)
+ xbt_die("Could not read constant");
+ frame.high_pc = (void *) ((char *) frame.low_pc + offset);
+ break;
+
+ // DW_AT_high_pc is a relocatable address:
+ case MC_DW_CLASS_ADDRESS:
+ if (dwarf_formaddr(&attr, &high_pc) != 0)
+ xbt_die("Could not read address");
+ frame.high_pc = ((char *) base) + high_pc;
+ break;
+
+ default:
+ xbt_die("Unexpected class for DW_AT_high_pc");
+
+ }
+ }
+
+ if (klass == mc_tag_subprogram) {
+ Dwarf_Attribute attr_frame_base;
+ if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
+ mc_dwarf_location_list_init_libdw(&frame.frame_base, info, die,
+ &attr_frame_base);
+ }
+
+ // Handle children:
+ MC_dwarf_handle_children(info, die, unit, &frame, ns);
+
+ // Someone needs this to be sorted but who?
+ std::sort(frame.variables.begin(), frame.variables.end(),
+ MC_compare_variable);
+
+ // Register it:
+ if (klass == mc_tag_subprogram)
+ info->subprograms[frame.id] = frame;
+ else if (klass == mc_tag_scope)
+ parent_frame->scopes.push_back(std::move(frame));
+}
+
+static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info,
+ Dwarf_Die * die, Dwarf_Die * unit,
+ 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");
+ char *new_ns = ns == NULL ? xbt_strdup(name)
+ : bprintf("%s::%s", ns, name);
+ MC_dwarf_handle_children(info, die, unit, frame, new_ns);
+ xbt_free(new_ns);
+}
+
+static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ // For each child DIE:
+ Dwarf_Die child;
+ int res;
+ for (res = dwarf_child(die, &child); res == 0;
+ res = dwarf_siblingof(&child, &child)) {
+ MC_dwarf_handle_die(info, &child, unit, frame, ns);
+ }
+}
+
+static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns)
+{
+ int tag = dwarf_tag(die);
+ mc_tag_class klass = MC_dwarf_tag_classify(tag);
+ switch (klass) {
+
+ // Type:
+ case mc_tag_type:
+ MC_dwarf_handle_type_die(info, die, unit, frame, ns);
+ break;
+
+ // Subprogram or scope:
+ case mc_tag_subprogram:
+ case mc_tag_scope:
+ MC_dwarf_handle_scope_die(info, die, unit, frame, ns);
+ return;
+
+ // Variable:
+ case mc_tag_variable:
+ MC_dwarf_handle_variable_die(info, die, unit, frame, ns);
+ break;
+
+ case mc_tag_namespace:
+ mc_dwarf_handle_namespace_die(info, die, unit, frame, ns);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+/** \brief Populate the debugging informations of the given ELF object
+ *
+ * Read the DWARf information of the EFFL object and populate the
+ * lists of types, variables, functions.
+ */
+void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info)
+{
+ 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());
+ Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
+ if (dwarf == NULL)
+ xbt_die("Missing debugging information in %s\n"
+ "Your program and its dependencies must have debugging information.\n"
+ "You might want to recompile with -g or install the suitable debugging package.\n",
+ info->file_name.c_str());
+ // For each compilation unit:
+ Dwarf_Off offset = 0;
+ Dwarf_Off next_offset = 0;
+ size_t length;
+
+ while (dwarf_nextcu(dwarf, offset, &next_offset, &length, NULL, NULL, NULL) ==
+ 0) {
+ Dwarf_Die unit_die;
+ if (dwarf_offdie(dwarf, offset + length, &unit_die) != NULL)
+ MC_dwarf_handle_children(info, &unit_die, &unit_die, NULL, NULL);
+ offset = next_offset;
+ }
+
+ dwarf_end(dwarf);
+ close(fd);
+}
--- /dev/null
+/* Copyright (c) 2008-2015. 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. */
+
+#if !defined(SIMGRID_MC_LIBDW_HPP)
+#define SIMGRID_MC_LIBDW_HPP
+
+#include <stdint.h>
+
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+
+#include "mc/Frame.hpp"
+#include "mc/ObjectInformation.hpp"
+#include "mc/Variable.hpp"
+
+/** \brief Computes the the element_count of a DW_TAG_enumeration_type DIE
+ *
+ * This is the number of elements in a given array dimension.
+ *
+ * A reference of the compilation unit (DW_TAG_compile_unit) is
+ * needed because the default lower bound (when there is no DW_AT_lower_bound)
+ * depends of the language of the compilation unit (DW_AT_language).
+ *
+ * \param die DIE for the DW_TAG_enumeration_type or DW_TAG_subrange_type
+ * \param unit DIE of the DW_TAG_compile_unit
+ */
+static std::uint64_t MC_dwarf_subrange_element_count(Dwarf_Die * die,
+ Dwarf_Die * unit);
+
+/** \brief Computes the number of elements of a given DW_TAG_array_type.
+ *
+ * \param die DIE for the DW_TAG_array_type
+ */
+static std::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 die the current DIE
+ * \param unit the DIE of the compile unit of the current DIE
+ * \param frame containg frame if any
+ */
+static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns);
+
+/** \brief Process a type DIE
+ */
+static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns);
+
+/** \brief Calls MC_dwarf_handle_die on all childrend of the given die
+ *
+ * \param info the resulting object fot the library/binary file (output)
+ * \param die the current DIE
+ * \param unit the DIE of the compile unit of the current DIE
+ * \param frame containg frame if any
+ */
+static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns);
+
+/** \brief Handle a variable (DW_TAG_variable or other)
+ *
+ * \param info the resulting object fot the library/binary file (output)
+ * \param die the current DIE
+ * \param unit the DIE of the compile unit of the current DIE
+ * \param frame containg frame if any
+ */
+static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+ Dwarf_Die * unit, simgrid::mc::Frame* frame,
+ const char *ns);
+
+/** \brief Get the DW_TAG_type of the DIE
+ *
+ * \param die DIE
+ * \return DW_TAG_type attribute as a new string (NULL if none)
+ */
+static std::uint64_t MC_dwarf_at_type(Dwarf_Die * die);
+
+#endif
#include <libunwind.h>
#include <dwarf.h>
-#include <elfutils/libdw.h>
#include <simgrid_config.h>
#include "mc_base.h"
namespace simgrid {
namespace mc {
-typedef std::vector<Dwarf_Op> DwarfExpression;
+typedef struct
+{
+ uint8_t atom;
+ std::uint64_t number;
+ std::uint64_t number2;
+ std::uint64_t offset;
+} DwarfInstruction;
+typedef std::vector<DwarfInstruction> DwarfExpression;
/** \brief A DWARF expression with optional validity contraints */
class LocationListEntry {
void* frame_pointer_address, simgrid::mc::AddressSpace* address_space,
int process_index);
-XBT_INTERNAL void mc_dwarf_location_list_init(
- simgrid::mc::LocationList*, simgrid::mc::ObjectInformation* info, Dwarf_Die* die,
- Dwarf_Attribute* attr);
-
#define MC_EXPRESSION_STACK_SIZE 64
#define MC_EXPRESSION_OK 0
} s_mc_expression_state_t, *mc_expression_state_t;
MC_SHOULD_BE_INTERNAL int mc_dwarf_execute_expression(
- size_t n, const Dwarf_Op* ops, mc_expression_state_t state);
+ size_t n, const simgrid::mc::DwarfInstruction* ops, mc_expression_state_t state);
MC_SHOULD_BE_INTERNAL void* mc_find_frame_base(
simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info, unw_cursor_t* unw_cursor);
#include <xbt/misc.h>
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_private.h"
#include "mc/Type.hpp"
#include "xbt/virtu.h"
#include "mc/mc.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_private.h"
extern "C" {
+++ /dev/null
-/* Copyright (c) 2007-2015. 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. */
-
-#ifndef SIMGRID_MC_OBJECT_INFO_H
-#define SIMGRID_MC_OBJECT_INFO_H
-
-#include <vector>
-#include <memory>
-
-#include <xbt/base.h>
-
-#include "mc_forward.hpp"
-#include "mc_memory_map.h"
-
-XBT_INTERNAL std::shared_ptr<simgrid::mc::ObjectInformation> MC_find_object_info(
- std::vector<simgrid::mc::VmMap> const& maps, const char* name, int executable);
-XBT_INTERNAL void MC_post_process_object_info(simgrid::mc::Process* process, simgrid::mc::ObjectInformation* info);
-
-XBT_INTERNAL void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info);
-XBT_INTERNAL void MC_dwarf_get_variables_libdw(simgrid::mc::ObjectInformation* info);
-
-XBT_INTERNAL const char* MC_dwarf_attrname(int attr);
-XBT_INTERNAL const char* MC_dwarf_tagname(int tag);
-
-XBT_INTERNAL void* mc_member_resolve(
- const void* base, simgrid::mc::Type* type, simgrid::mc::Type* member,
- simgrid::mc::AddressSpace* snapshot, int process_index);
-
-#endif
#ifndef WIN32
#include <sys/mman.h>
#endif
-#include <elfutils/libdw.h>
#include "mc/mc.h"
#include "mc_base.h"
#include <xbt/mmalloc.h>
#include "mc_process.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_unw.h"
#include "mc_snapshot.h"
#include "mc_ignore.h"
#include <libunwind.h>
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc_process.h"
#include "mc_unw.h"
#include "mc/Frame.hpp"
* under the terms of the license (GNU LGPL) which comes with this package. */
#include "internal_config.h"
-#include "mc_object_info.h"
+#include "mc_dwarf.hpp"
#include "mc/mc_private.h"
#include "smpi/private.h"
#include "mc/mc_snapshot.h"
while (start <= end) {
unsigned int cursor = (start + end) / 2;
simgrid::mc::Variable* current_var = &info->global_variables[cursor];
- int cmp = strcmp(current_var->name.c_str(), name);
+ int cmp = current_var->name.compare(name);
if (cmp == 0) {
info->global_variables.erase(
info->global_variables.begin() + cursor);
int cursor = (start + end) / 2;
simgrid::mc::Variable* current_var = &scope->variables[cursor];
- int compare = strcmp(current_var->name.c_str(), var_name);
+ int compare = current_var->name.compare(var_name);
if (compare == 0) {
// Variable found, remove it:
scope->variables.erase(scope->variables.begin() + cursor);
void CpuTi::modified(bool modified){
CpuTiList *modifiedCpu = static_cast<CpuTiModel*>(getModel())->p_modifiedCpu;
if (modified) {
- if (!is_linked()) {
+ if (!cpu_ti_hook.is_linked()) {
modifiedCpu->push_back(*this);
}
} else {
- if (is_linked()) {
+ if (cpu_ti_hook.is_linked()) {
modifiedCpu->erase(modifiedCpu->iterator_to(*this));
}
}
{
m_refcount--;
if (!m_refcount) {
- if (actionHook::is_linked())
+ if (action_hook.is_linked())
getStateSet()->erase(getStateSet()->iterator_to(*this));
/* remove from action_set */
- if (actionTiHook::is_linked())
+ if (action_ti_hook.is_linked())
p_cpu->p_actionSet->erase(p_cpu->p_actionSet->iterator_to(*this));
/* remove from heap */
xbt_heap_remove(static_cast<CpuTiModel*>(getModel())->p_tiActionHeap, this->m_indexHeap);
class CpuTi;
class CpuTiAction;
-typedef boost::intrusive::list<CpuTi> CpuTiList;
-typedef boost::intrusive::list_base_hook<> cpuTiHook;
-
struct tiTag;
-typedef boost::intrusive::list<CpuTiAction, boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::tag<tiTag> > > > ActionTiList;
-typedef boost::intrusive::list_base_hook<boost::intrusive::tag<tiTag> > actionTiHook;
/*********
* Trace *
tmgr_trace_t p_powerTrace;
};
-/*********
- * Model *
- *********/
-class CpuTiModel : public CpuModel {
-public:
- CpuTiModel();
- ~CpuTiModel();
- Cpu *createCpu(const char *name, xbt_dynar_t powerPeak,
- int pstate, double power_scale,
- tmgr_trace_t power_trace, int core,
- e_surf_resource_state_t state_initial,
- tmgr_trace_t state_trace,
- xbt_dict_t cpu_properties);
- double shareResources(double now);
- void updateActionsState(double now, double delta);
- void addTraces();
+/**********
+ * Action *
+ **********/
- ActionList *p_runningActionSetThatDoesNotNeedBeingChecked;
- CpuTiList *p_modifiedCpu;
- xbt_heap_t p_tiActionHeap;
+class CpuTiAction: public CpuAction {
+ friend class CpuTi;
+ // friend CpuAction *CpuTi::execute(double size);
+ // friend CpuAction *CpuTi::sleep(double duration);
+ // friend void CpuTi::updateActionsFinishTime(double now);//FIXME
+ // friend void CpuTi::updateRemainingAmount(double now);//FIXME
+public:
+ CpuTiAction(CpuTiModel *model, double cost, bool failed,
+ CpuTi *cpu);
-protected:
- void NotifyResourceTurnedOn(Resource*){};
- void NotifyResourceTurnedOff(Resource*){};
+ void setState(e_surf_action_state_t state);
+ int unref();
+ void cancel();
+ void updateIndexHeap(int i);
+ void suspend();
+ void resume();
+ bool isSuspended();
+ void setMaxDuration(double duration);
+ void setPriority(double priority);
+ double getRemains();
+ void setAffinity(Cpu * /*cpu*/, unsigned long /*mask*/) {};
- void NotifyActionCancel(Action*){};
- void NotifyActionResume(Action*){};
- void NotifyActionSuspend(Action*){};
+ CpuTi *p_cpu;
+ int m_indexHeap;
+ int m_suspended;
+public:
+ boost::intrusive::list_member_hook<> action_ti_hook;
};
+typedef boost::intrusive::member_hook<
+ CpuTiAction, boost::intrusive::list_member_hook<>, &CpuTiAction::action_ti_hook> ActionTiListOptions;
+typedef boost::intrusive::list<
+ CpuTiAction, ActionTiListOptions > ActionTiList;
+
/************
* Resource *
************/
-class CpuTi : public cpuTiHook, public Cpu {
+class CpuTi : public Cpu {
public:
CpuTi() {};
CpuTi(CpuTiModel *model, const char *name, xbt_dynar_t powerPeak,
double current_frequency;
void updateRemainingAmount(double now);
+public:
+ boost::intrusive::list_member_hook<> cpu_ti_hook;
};
-/**********
- * Action *
- **********/
-
-class CpuTiAction: public actionTiHook, public CpuAction {
- friend CpuAction *CpuTi::execute(double size);
- friend CpuAction *CpuTi::sleep(double duration);
- friend void CpuTi::updateActionsFinishTime(double now);//FIXME
- friend void CpuTi::updateRemainingAmount(double now);//FIXME
+typedef boost::intrusive::member_hook<
+ CpuTi, boost::intrusive::list_member_hook<>, &CpuTi::cpu_ti_hook> CpuTiListOptions;
+typedef boost::intrusive::list<CpuTi, CpuTiListOptions> CpuTiList;
+/*********
+ * Model *
+ *********/
+class CpuTiModel : public CpuModel {
public:
- CpuTiAction(CpuTiModel *model, double cost, bool failed,
- CpuTi *cpu);
+ CpuTiModel();
+ ~CpuTiModel();
+ Cpu *createCpu(const char *name, xbt_dynar_t powerPeak,
+ int pstate, double power_scale,
+ tmgr_trace_t power_trace, int core,
+ e_surf_resource_state_t state_initial,
+ tmgr_trace_t state_trace,
+ xbt_dict_t cpu_properties);
+ double shareResources(double now);
+ void updateActionsState(double now, double delta);
+ void addTraces();
- void setState(e_surf_action_state_t state);
- int unref();
- void cancel();
- void updateIndexHeap(int i);
- void suspend();
- void resume();
- bool isSuspended();
- void setMaxDuration(double duration);
- void setPriority(double priority);
- double getRemains();
- void setAffinity(Cpu * /*cpu*/, unsigned long /*mask*/) {};
+ ActionList *p_runningActionSetThatDoesNotNeedBeingChecked;
+ CpuTiList *p_modifiedCpu;
+ xbt_heap_t p_tiActionHeap;
- CpuTi *p_cpu;
- int m_indexHeap;
- int m_suspended;
-private:
+protected:
+ void NotifyResourceTurnedOn(Resource*){};
+ void NotifyResourceTurnedOff(Resource*){};
+
+ void NotifyActionCancel(Action*){};
+ void NotifyActionResume(Action*){};
+ void NotifyActionSuspend(Action*){};
};
{
m_refcount--;
if (!m_refcount) {
- if (actionHook::is_linked())
+ if (action_hook.is_linked())
p_stateSet->erase(p_stateSet->iterator_to(*this));
if (getVariable())
lmm_variable_free(ptask_maxmin_system, getVariable());
{
m_refcount--;
if (!m_refcount) {
- if (actionHook::is_linked())
+ if (action_hook.is_linked())
p_stateSet->erase(p_stateSet->iterator_to(*this));
delete this;
return 1;
{
m_refcount--;
if (!m_refcount) {
- if (actionHook::is_linked())
+ if (action_hook.is_linked())
p_stateSet->erase(p_stateSet->iterator_to(*this));
if (getVariable())
lmm_variable_free(getModel()->getMaxminSystem(), getVariable());
void Action::cancel(){
setState(SURF_ACTION_FAILED);
if (getModel()->getUpdateMechanism() == UM_LAZY) {
- if (actionLmmHook::is_linked())
+ if (action_lmm_hook.is_linked())
getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
heapRemove(getModel()->getActionHeap());
}
int Action::unref(){
m_refcount--;
if (!m_refcount) {
- if (actionHook::is_linked())
+ if (action_hook.is_linked())
p_stateSet->erase(p_stateSet->iterator_to(*this));
if (getVariable())
lmm_variable_free(getModel()->getMaxminSystem(), getVariable());
if (getModel()->getUpdateMechanism() == UM_LAZY) {
/* remove from heap */
heapRemove(getModel()->getActionHeap());
- if (actionLmmHook::is_linked())
+ if (action_lmm_hook.is_linked())
getModel()->getModifiedSet()->erase(getModel()->getModifiedSet()->iterator_to(*this));
}
delete this;
/***********
* Classes *
***********/
-typedef boost::intrusive::list<Action> ActionList;
-typedef ActionList* ActionListPtr;
-typedef boost::intrusive::list_base_hook<> actionHook;
-
-struct lmmTag;
-typedef boost::intrusive::list<Action, boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::tag<lmmTag> > > > ActionLmmList;
-typedef ActionLmmList* ActionLmmListPtr;
-typedef boost::intrusive::list_base_hook<boost::intrusive::tag<lmmTag> > actionLmmHook;
-
enum heap_action_type{
LATENCY = 100,
XBT_PUBLIC_DATA(xbt_dict_t) trace_connect_list_bandwidth;
XBT_PUBLIC_DATA(xbt_dict_t) trace_connect_list_latency;
+/**********
+ * Action *
+ **********/
+void surf_action_lmm_update_index_heap(void *action, int i);
+
+/** @ingroup SURF_interface
+ * @brief SURF action interface class
+ * @details An action is an event generated by a resource (e.g.: a communication for the network)
+ */
+XBT_PUBLIC_CLASS Action {
+public:
+ boost::intrusive::list_member_hook<> action_hook;
+ boost::intrusive::list_member_hook<> action_lmm_hook;
+ typedef boost::intrusive::member_hook<
+ Action, boost::intrusive::list_member_hook<>, &Action::action_hook> ActionOptions;
+ typedef boost::intrusive::list<Action, ActionOptions> ActionList;
+private:
+ /**
+ * @brief Common initializations for the constructors
+ */
+ void initialize(Model *model, double cost, bool failed,
+ lmm_variable_t var = NULL);
+
+public:
+ /**
+ * @brief Action constructor
+ *
+ * @param model The Model associated to this Action
+ * @param cost The cost of the Action
+ * @param failed If the action is impossible (e.g.: execute something on a switched off host)
+ */
+ Action(Model *model, double cost, bool failed);
+
+ /**
+ * @brief Action constructor
+ *
+ * @param model The Model associated to this Action
+ * @param cost The cost of the Action
+ * @param failed If the action is impossible (e.g.: execute something on a switched off host)
+ * @param var The lmm variable associated to this Action if it is part of a LMM component
+ */
+ Action(Model *model, double cost, bool failed, lmm_variable_t var);
+
+ /** @brief Destructor */
+ virtual ~Action();
+
+ /** @brief Mark that the action is now finished */
+ void finish();
+
+ /** @brief Get the [state](\ref e_surf_action_state_t) of the current Action */
+ e_surf_action_state_t getState(); /**< get the state*/
+ /** @brief Set the [state](\ref e_surf_action_state_t) of the current Action */
+ virtual void setState(e_surf_action_state_t state);
+
+ /** @brief Get the bound of the current Action */
+ double getBound();
+ /** @brief Set the bound of the current Action */
+ void setBound(double bound);
+
+ /** @brief Get the start time of the current action */
+ double getStartTime();
+ /** @brief Get the finish time of the current action */
+ double getFinishTime();
+
+ /** @brief Get the user data associated to the current action */
+ void *getData() {return p_data;}
+ /** @brief Set the user data associated to the current action */
+ void setData(void* data);
+
+ /** @brief Get the cost of the current action */
+ double getCost() {return m_cost;}
+ /** @brief Set the cost of the current action */
+ void setCost(double cost) {m_cost = cost;}
+
+ /** @brief Update the maximum duration of the current action
+ * @param delta Amount to remove from the MaxDuration */
+ void updateMaxDuration(double delta) {double_update(&m_maxDuration, delta,sg_surf_precision);}
+
+ /** @brief Update the remaining time of the current action
+ * @param delta Amount to remove from the remaining time */
+ void updateRemains(double delta) {double_update(&m_remains, delta, sg_maxmin_precision*sg_surf_precision);}
+
+ /** @brief Set the remaining time of the current action */
+ void setRemains(double value) {m_remains = value;}
+ /** @brief Get the remaining time of the current action after updating the resource */
+ virtual double getRemains();
+ /** @brief Get the remaining time of the current action without updating the resource */
+ double getRemainsNoUpdate();
+
+ /** @brief Set the finish time of the current action */
+ void setFinishTime(double value) {m_finish = value;}
+
+ /**@brief Add a reference to the current action (refcounting) */
+ void ref();
+ /** @brief Unref that action (and destroy it if refcount reaches 0)
+ * @return true if the action was destroyed and false if someone still has references on it
+ */
+ virtual int unref();
+
+ /** @brief Cancel the current Action if running */
+ virtual void cancel();
+
+ /** @brief Suspend the current Action */
+ virtual void suspend();
+
+ /** @brief Resume the current Action */
+ virtual void resume();
+
+ /** @brief Returns true if the current action is running */
+ virtual bool isSuspended();
+
+ /** @brief Get the maximum duration of the current action */
+ double getMaxDuration() {return m_maxDuration;}
+ /** @brief Set the maximum duration of the current Action */
+ virtual void setMaxDuration(double duration);
+
+ /** @brief Get the tracing category associated to the current action */
+ char *getCategory() {return p_category;}
+ /** @brief Set the tracing category of the current Action */
+ void setCategory(const char *category);
+
+ /** @brief Get the priority of the current Action */
+ double getPriority() {return m_priority;};
+ /** @brief Set the priority of the current Action */
+ virtual void setPriority(double priority);
+
+ /** @brief Get the state set in which the action is */
+ ActionList* getStateSet() {return p_stateSet;};
+
+ s_xbt_swag_hookup_t p_stateHookup;
+
+ Model *getModel() {return p_model;}
+
+protected:
+ ActionList* p_stateSet;
+ double m_priority; /**< priority (1.0 by default) */
+ int m_refcount;
+ double m_remains; /**< How much of that cost remains to be done in the currently running task */
+ double m_maxDuration; /*< max_duration (may fluctuate until the task is completed) */
+ double m_finish; /**< finish time : this is modified during the run and fluctuates until the task is completed */
+
+private:
+ double m_start; /**< start time */
+ char *p_category; /**< tracing category for categorized resource utilization monitoring */
+
+ #ifdef HAVE_LATENCY_BOUND_TRACKING
+ int m_latencyLimited; /**< Set to 1 if is limited by latency, 0 otherwise */
+ #endif
+ double m_cost;
+ Model *p_model;
+ void *p_data; /**< for your convenience */
+
+ /* LMM */
+public:
+ virtual void updateRemainingLazy(double now);
+ void heapInsert(xbt_heap_t heap, double key, enum heap_action_type hat);
+ void heapRemove(xbt_heap_t heap);
+ void heapUpdate(xbt_heap_t heap, double key, enum heap_action_type hat);
+ void updateIndexHeap(int i);
+ lmm_variable_t getVariable() {return p_variable;}
+ double getLastUpdate() {return m_lastUpdate;}
+ void refreshLastUpdate() {m_lastUpdate = surf_get_clock();}
+ enum heap_action_type getHat() {return m_hat;}
+ bool is_linked() {return action_lmm_hook.is_linked();}
+ void gapRemove();
+
+protected:
+ lmm_variable_t p_variable;
+ double m_lastValue;
+ double m_lastUpdate;
+ int m_suspended;
+ int m_indexHeap;
+ enum heap_action_type m_hat;
+};
+
+typedef Action::ActionList ActionList;
+
+typedef boost::intrusive::member_hook<
+ Action, boost::intrusive::list_member_hook<>, &Action::action_lmm_hook> ActionLmmOptions;
+typedef boost::intrusive::list<Action, ActionLmmOptions> ActionLmmList;
+typedef ActionLmmList* ActionLmmListPtr;
+
/*********
* Model *
*********/
*
* @return The set of [actions](@ref Action) in *ready* state
*/
- virtual ActionListPtr getReadyActionSet() {return p_readyActionSet;}
+ virtual ActionList* getReadyActionSet() {return p_readyActionSet;}
/**
* @brief Get the set of [actions](@ref Action) in *running* state
*
* @return The set of [actions](@ref Action) in *running* state
*/
- virtual ActionListPtr getRunningActionSet() {return p_runningActionSet;}
+ virtual ActionList* getRunningActionSet() {return p_runningActionSet;}
/**
* @brief Get the set of [actions](@ref Action) in *failed* state
*
* @return The set of [actions](@ref Action) in *failed* state
*/
- virtual ActionListPtr getFailedActionSet() {return p_failedActionSet;}
+ virtual ActionList* getFailedActionSet() {return p_failedActionSet;}
/**
* @brief Get the set of [actions](@ref Action) in *done* state
*
* @return The set of [actions](@ref Action) in *done* state
*/
- virtual ActionListPtr getDoneActionSet() {return p_doneActionSet;}
+ virtual ActionList* getDoneActionSet() {return p_doneActionSet;}
/**
* @brief Get the set of modified [actions](@ref Action)
virtual double shareResources(double now);
virtual double shareResourcesLazy(double now);
virtual double shareResourcesFull(double now);
- double shareResourcesMaxMin(ActionListPtr running_actions,
+ double shareResourcesMaxMin(ActionList* running_actions,
lmm_system_t sys,
void (*solve) (lmm_system_t));
xbt_heap_t p_actionHeap;
private:
- ActionListPtr p_readyActionSet; /**< Actions in state SURF_ACTION_READY */
- ActionListPtr p_runningActionSet; /**< Actions in state SURF_ACTION_RUNNING */
- ActionListPtr p_failedActionSet; /**< Actions in state SURF_ACTION_FAILED */
- ActionListPtr p_doneActionSet; /**< Actions in state SURF_ACTION_DONE */
+ ActionList* p_readyActionSet; /**< Actions in state SURF_ACTION_READY */
+ ActionList* p_runningActionSet; /**< Actions in state SURF_ACTION_RUNNING */
+ ActionList* p_failedActionSet; /**< Actions in state SURF_ACTION_FAILED */
+ ActionList* p_doneActionSet; /**< Actions in state SURF_ACTION_DONE */
};
/************
lmm_constraint_t p_constraint;
};
-/**********
- * Action *
- **********/
-void surf_action_lmm_update_index_heap(void *action, int i);
-
-/** @ingroup SURF_interface
- * @brief SURF action interface class
- * @details An action is an event generated by a resource (e.g.: a communication for the network)
- */
-XBT_PUBLIC_CLASS Action : public actionHook, public actionLmmHook {
-private:
- /**
- * @brief Common initializations for the constructors
- */
- void initialize(Model *model, double cost, bool failed,
- lmm_variable_t var = NULL);
-
-public:
- /**
- * @brief Action constructor
- *
- * @param model The Model associated to this Action
- * @param cost The cost of the Action
- * @param failed If the action is impossible (e.g.: execute something on a switched off host)
- */
- Action(Model *model, double cost, bool failed);
-
- /**
- * @brief Action constructor
- *
- * @param model The Model associated to this Action
- * @param cost The cost of the Action
- * @param failed If the action is impossible (e.g.: execute something on a switched off host)
- * @param var The lmm variable associated to this Action if it is part of a LMM component
- */
- Action(Model *model, double cost, bool failed, lmm_variable_t var);
-
- /** @brief Destructor */
- virtual ~Action();
-
- /** @brief Mark that the action is now finished */
- void finish();
-
- /** @brief Get the [state](\ref e_surf_action_state_t) of the current Action */
- e_surf_action_state_t getState(); /**< get the state*/
- /** @brief Set the [state](\ref e_surf_action_state_t) of the current Action */
- virtual void setState(e_surf_action_state_t state);
-
- /** @brief Get the bound of the current Action */
- double getBound();
- /** @brief Set the bound of the current Action */
- void setBound(double bound);
-
- /** @brief Get the start time of the current action */
- double getStartTime();
- /** @brief Get the finish time of the current action */
- double getFinishTime();
-
- /** @brief Get the user data associated to the current action */
- void *getData() {return p_data;}
- /** @brief Set the user data associated to the current action */
- void setData(void* data);
-
- /** @brief Get the cost of the current action */
- double getCost() {return m_cost;}
- /** @brief Set the cost of the current action */
- void setCost(double cost) {m_cost = cost;}
-
- /** @brief Update the maximum duration of the current action
- * @param delta Amount to remove from the MaxDuration */
- void updateMaxDuration(double delta) {double_update(&m_maxDuration, delta,sg_surf_precision);}
-
- /** @brief Update the remaining time of the current action
- * @param delta Amount to remove from the remaining time */
- void updateRemains(double delta) {double_update(&m_remains, delta, sg_maxmin_precision*sg_surf_precision);}
-
- /** @brief Set the remaining time of the current action */
- void setRemains(double value) {m_remains = value;}
- /** @brief Get the remaining time of the current action after updating the resource */
- virtual double getRemains();
- /** @brief Get the remaining time of the current action without updating the resource */
- double getRemainsNoUpdate();
-
- /** @brief Set the finish time of the current action */
- void setFinishTime(double value) {m_finish = value;}
-
- /**@brief Add a reference to the current action (refcounting) */
- void ref();
- /** @brief Unref that action (and destroy it if refcount reaches 0)
- * @return true if the action was destroyed and false if someone still has references on it
- */
- virtual int unref();
-
- /** @brief Cancel the current Action if running */
- virtual void cancel();
-
- /** @brief Suspend the current Action */
- virtual void suspend();
-
- /** @brief Resume the current Action */
- virtual void resume();
-
- /** @brief Returns true if the current action is running */
- virtual bool isSuspended();
-
- /** @brief Get the maximum duration of the current action */
- double getMaxDuration() {return m_maxDuration;}
- /** @brief Set the maximum duration of the current Action */
- virtual void setMaxDuration(double duration);
-
- /** @brief Get the tracing category associated to the current action */
- char *getCategory() {return p_category;}
- /** @brief Set the tracing category of the current Action */
- void setCategory(const char *category);
-
- /** @brief Get the priority of the current Action */
- double getPriority() {return m_priority;};
- /** @brief Set the priority of the current Action */
- virtual void setPriority(double priority);
-
- /** @brief Get the state set in which the action is */
- ActionListPtr getStateSet() {return p_stateSet;};
-
- s_xbt_swag_hookup_t p_stateHookup;
-
- Model *getModel() {return p_model;}
-
-protected:
- ActionListPtr p_stateSet;
- double m_priority; /**< priority (1.0 by default) */
- int m_refcount;
- double m_remains; /**< How much of that cost remains to be done in the currently running task */
- double m_maxDuration; /*< max_duration (may fluctuate until the task is completed) */
- double m_finish; /**< finish time : this is modified during the run and fluctuates until the task is completed */
-
-private:
- double m_start; /**< start time */
- char *p_category; /**< tracing category for categorized resource utilization monitoring */
-
- #ifdef HAVE_LATENCY_BOUND_TRACKING
- int m_latencyLimited; /**< Set to 1 if is limited by latency, 0 otherwise */
- #endif
- double m_cost;
- Model *p_model;
- void *p_data; /**< for your convenience */
-
- /* LMM */
-public:
- virtual void updateRemainingLazy(double now);
- void heapInsert(xbt_heap_t heap, double key, enum heap_action_type hat);
- void heapRemove(xbt_heap_t heap);
- void heapUpdate(xbt_heap_t heap, double key, enum heap_action_type hat);
- void updateIndexHeap(int i);
- lmm_variable_t getVariable() {return p_variable;}
- double getLastUpdate() {return m_lastUpdate;}
- void refreshLastUpdate() {m_lastUpdate = surf_get_clock();}
- enum heap_action_type getHat() {return m_hat;}
- bool is_linked() {return actionLmmHook::is_linked();}
- void gapRemove();
-
-protected:
- lmm_variable_t p_variable;
- double m_lastValue;
- double m_lastUpdate;
- int m_suspended;
- int m_indexHeap;
- enum heap_action_type m_hat;
-};
-
#endif /* SURF_MODEL_H_ */
*/
extern surf_callback(void, VM*) VMStateChangedCallbacks;
-/*********
- * Model *
- *********/
-/** @ingroup SURF_vm_interface
- * @brief SURF VM model interface class
- * @details A model is an object which handle the interactions between its Resources and its Actions
- */
-class VMModel : public HostModel {
-public:
- VMModel() :HostModel(){}
- ~VMModel(){};
-
- Host *createHost(const char *name){DIE_IMPOSSIBLE;}
-
- /**
- * @brief Create a new VM
- *
- * @param name The name of the new VM
- * @param host_PM The real machine hosting the VM
- *
- */
- virtual VM *createVM(const char *name, surf_resource_t host_PM)=0;
- void adjustWeightOfDummyCpuActions() {};
-
- typedef boost::intrusive::list<VM, boost::intrusive::constant_time_size<false> > vm_list_t;
- static vm_list_t ws_vms;
-};
-
/************
* Resource *
************/
* @brief SURF VM interface class
* @details A VM represent a virtual machine
*/
-class VM : public Host,
- public boost::intrusive::list_base_hook<> {
+class VM : public Host {
public:
/**
* @brief Constructor
CpuAction *p_action;
Host *p_subWs; // Pointer to the ''host'' OS
e_surf_vm_state_t p_currentState;
+public:
+ boost::intrusive::list_member_hook<> vm_hook;
+};
+
+/*********
+ * Model *
+ *********/
+/** @ingroup SURF_vm_interface
+ * @brief SURF VM model interface class
+ * @details A model is an object which handle the interactions between its Resources and its Actions
+ */
+class VMModel : public HostModel {
+public:
+ VMModel() :HostModel(){}
+ ~VMModel(){};
+
+ Host *createHost(const char *name){DIE_IMPOSSIBLE;}
+
+ /**
+ * @brief Create a new VM
+ *
+ * @param name The name of the new VM
+ * @param host_PM The real machine hosting the VM
+ *
+ */
+ virtual VM *createVM(const char *name, surf_resource_t host_PM)=0;
+ void adjustWeightOfDummyCpuActions() {};
+
+ typedef boost::intrusive::member_hook<
+ VM, boost::intrusive::list_member_hook<>, &VM::vm_hook> VmOptions;
+ typedef boost::intrusive::list<VM, VmOptions, boost::intrusive::constant_time_size<false> > vm_list_t;
+ static vm_list_t ws_vms;
};
/**********
#include <mc/mc.h>
#include "mc/datatypes.h"
-#include "mc/mc_object_info.h"
+#include "mc/mc_dwarf.hpp"
#include "mc/mc_private.h"
#include "mc/mc_process.h"
#include "mc/mc_process.h"
#include "mc/mc_private.h"
-#include "mc/mc_object_info.h"
+#include "mc/mc_dwarf.hpp"
#include "mc/Type.hpp"
#include "mc/ObjectInformation.hpp"
uintptr_t eval_binary_operation(mc_expression_state_t state, int op, uintptr_t a, uintptr_t b) {
state->stack_size = 0;
- Dwarf_Op ops[15];
+ simgrid::mc::DwarfInstruction ops[15];
ops[0].atom = DW_OP_const8u;
ops[0].number = a;
ops[1].atom = DW_OP_const8u;
static
void basic_test(mc_expression_state_t state) {
- Dwarf_Op ops[60];
+ simgrid::mc::DwarfInstruction ops[60];
uintptr_t a = rand();
uintptr_t b = rand();
void test_deref(mc_expression_state_t state) {
uintptr_t foo = 42;
- Dwarf_Op ops[60];
+ simgrid::mc::DwarfInstruction ops[60];
ops[0].atom = DW_OP_const8u;
ops[0].number = (uintptr_t) &foo;
ops[1].atom = DW_OP_deref;
src/mc/mc_unw.cpp
src/mc/mc_unw_vmread.cpp
src/mc/mc_mmalloc.h
- src/mc/mc_object_info.h
+ src/mc/mc_dwarf.hpp
src/mc/mc_checkpoint.cpp
src/mc/mc_snapshot.h
src/mc/mc_snapshot.cpp
src/mc/mc_compare.cpp
src/mc/mc_diff.cpp
src/mc/mc_dwarf.cpp
+ src/mc/mc_dwarf.hpp
+ src/mc/mc_libdw.cpp
+ src/mc/mc_libdw.hpp
src/mc/mc_dwarf_attrnames.cpp
src/mc/mc_dwarf_expression.cpp
src/mc/mc_dwarf_tagnames.cpp
# Usage: tools/generate-dwarf-functions /usr/include/dwarf.h
cat - > src/mc/mc_dwarf_tagnames.cpp <<EOF
-/* Copyright (c) 2014. The SimGrid Team.
+/* Copyright (c) 2014-2015. The SimGrid Team.
* All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
/* Warning: autogenerated, do not edit! */
#include <dwarf.h>
-#include <elfutils/libdw.h>
#include <xbt/base.h>
-#include "mc_object_info.h"
/** \brief Get the name of a dwarf tag (DW_TAG_*) from its code
*
{
switch (tag) {
$(cat "$1" | grep DW_TAG_ | sed 's/.*\(DW_TAG_[^ ]*\) = \(0x[0-9a-f]*\).*/ case \2: return "\1";/')
- case DW_TAG_invalid:
- return "DW_TAG_invalid";
default:
return "DW_TAG_unknown";
}
EOF
cat - > src/mc/mc_dwarf_attrnames.cpp << EOF
-/* Copyright (c) 2014. The SimGrid Team.
+/* Copyright (c) 2014-2015. The SimGrid Team.
* All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
#include <xbt/base.h>
#include <dwarf.h>
-#include "mc_object_info.h"
-
/** \brief Get the name of an attribute (DW_AT_*) from its code
*
* \param attr attribute code (see the DWARF specification)