+ }
+#endif
+ return std::vector<char>();
+}
+
+static char hexdigits[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+/** Binary data to hexadecimal */
+static inline
+std::array<char, 2> to_hex(std::uint8_t byte)
+{
+ // 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* 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;