+ // Horrid double braces!
+ // Apparently, this is needed in C++11 (not in C++14).
+ return { { hexdigits[byte >> 4], hexdigits[byte & 0xF] } };
+}
+
+/** Binary data to hexadecimal */
+static
+std::string to_hex(const char* data, std::size_t count)
+{
+ std::string res;
+ res.resize(2*count);
+ for (std::size_t i = 0; i < count; i++) {
+ std::array<char, 2> hex_byte = to_hex(data[i]);
+ for (int j = 0; j < 2; ++j)
+ res[2 * i + j] = hex_byte[j];
+ }
+ return res;
+}
+
+/** Binary data to hexadecimal */
+static
+std::string to_hex(std::vector<char> const& data)
+{
+ return to_hex(data.data(), data.size());
+}
+
+/** Base directories for external debug files */
+static
+const char* debug_paths[] = {
+ "/usr/lib/debug/",
+ "/usr/local/lib/debug/",
+};
+
+/** Locate an external debug file from the NT_GNU_BUILD_ID
+ *
+ * This is one of the mechanisms used for
+ * [separate debug files](https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html).
+ */
+// Example:
+// /usr/lib/debug/.build-id/0b/dc77f1c29aea2b14ff5acd9a19ab3175ffdeae.debug
+static
+std::string find_by_build_id(std::vector<char> id)
+{
+ std::string filename;
+ std::string hex = to_hex(id);
+ for (const char* const& debug_path : debug_paths) {
+ // Example:
+ filename = std::string(debug_path) + ".build-id/"
+ + to_hex(id.data(), 1) + '/'
+ + to_hex(id.data() + 1, id.size() - 1) + ".debug";
+ XBT_DEBUG("Checking debug file: %s", filename.c_str());
+ if (access(filename.c_str(), F_OK) == 0) {
+ XBT_DEBUG("Found debug file: %s\n", hex.c_str());
+ return filename;
+ }
+ }
+ XBT_DEBUG("Not debuf info found for build ID %s\n", hex.data());
+ return std::string();
+}
+
+/** @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.
+ */
+static
+void MC_load_dwarf(simgrid::mc::ObjectInformation* info)
+{
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ xbt_die("libelf initialization error");
+
+ // Open the ELF file:
+ int fd = open(info->file_name.c_str(), O_RDONLY);
+ if (fd < 0)
+ xbt_die("Could not open file %s", info->file_name.c_str());
+ Elf* elf = elf_begin(fd, ELF_C_READ, nullptr);
+ if (elf == nullptr)
+ xbt_die("Not an ELF file");
+ Elf_Kind kind = elf_kind(elf);
+ if (kind != ELF_K_ELF)
+ xbt_die("Not an ELF file");
+
+ // Remember if this is a `ET_EXEC` (fixed location) or `ET_DYN`:
+ Elf64_Half type = get_type(elf);
+ if (type == ET_EXEC)
+ info->flags |= simgrid::mc::ObjectInformation::Executable;
+
+ // Read DWARF debug information in the file:
+ Dwarf* dwarf = dwarf_begin_elf (elf, DWARF_C_READ, nullptr);
+ if (dwarf != nullptr) {
+ read_dwarf_info(info, dwarf);
+ dwarf_end(dwarf);
+ elf_end(elf);
+ close(fd);
+ return;
+ }
+ dwarf_end(dwarf);
+
+ // If there was no DWARF in the file, try to find it in a separate file.
+ // Different methods might be used to store the DWARF informations:
+ // * GNU NT_GNU_BUILD_ID
+ // * .gnu_debuglink
+ // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
+ // for reference of what we are doing.
+
+ // Try with NT_GNU_BUILD_ID: we find the build ID in the ELF file and then
+ // use this ID to find the file in some known locations in the filesystem.
+ std::vector<char> build_id = get_build_id(elf);
+ if (not build_id.empty()) {
+ elf_end(elf);
+ close(fd);
+
+ // Find the debug file using the build id:
+ std::string debug_file = find_by_build_id(build_id);
+ if (debug_file.empty()) {
+ std::string hex = to_hex(build_id);
+ xbt_die("Missing debug info for %s with build-id %s\n"
+ "You might want to install the suitable debugging package.\n",
+ info->file_name.c_str(), hex.c_str());
+ }
+
+ // Load the DWARF info from this file:
+ XBT_DEBUG("Load DWARF for %s from %s",
+ info->file_name.c_str(), debug_file.c_str());
+ fd = open(debug_file.c_str(), O_RDONLY);
+ if (fd < 0)
+ xbt_die("Could not open file %s", debug_file.c_str());
+ dwarf = dwarf_begin(fd, DWARF_C_READ);
+ if (dwarf == nullptr)
+ xbt_die("No DWARF info in %s for %s",
+ debug_file.c_str(), info->file_name.c_str());
+ read_dwarf_info(info, dwarf);
+ dwarf_end(dwarf);
+ close(fd);
+ return;
+ }
+
+ // TODO, try to find DWARF info using .gnu_debuglink.
+
+ elf_end(elf);
+ close(fd);
+ xbt_die("Debugging information not found for %s\n"
+ "Try recompiling with -g\n",
+ info->file_name.c_str());