Properly handle dwarf errors (#43)

This commit is contained in:
Jeremy Rifkin 2023-09-22 19:54:56 -04:00 committed by GitHub
parent f69448f781
commit 76fc93639e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 285 additions and 195 deletions

View File

@ -34,7 +34,7 @@ namespace detail {
using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type; using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type;
using PHeader = typename std::conditional<Bits == 32, Elf32_Phdr, Elf64_Phdr>::type; using PHeader = typename std::conditional<Bits == 32, Elf32_Phdr, Elf64_Phdr>::type;
Header file_header = load_bytes<Header>(file, 0); Header file_header = load_bytes<Header>(file, 0);
CPPTRACE_VERIFY(file_header.e_ehsize == sizeof(Header), "ELF file header size mismatch" + obj_path); VERIFY(file_header.e_ehsize == sizeof(Header), "ELF file header size mismatch" + obj_path);
// PT_PHDR will occur at most once // PT_PHDR will occur at most once
// Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011 // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
// It should occur at the beginning but may as well loop just in case // It should occur at the beginning but may as well loop just in case
@ -56,10 +56,10 @@ namespace detail {
} }
// Initial checks/metadata // Initial checks/metadata
auto magic = load_bytes<std::array<char, 4>>(file, 0); auto magic = load_bytes<std::array<char, 4>>(file, 0);
CPPTRACE_VERIFY(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}), "File is not ELF " + obj_path); VERIFY(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}), "File is not ELF " + obj_path);
bool is_64 = load_bytes<uint8_t>(file, 4) == 2; bool is_64 = load_bytes<uint8_t>(file, 4) == 2;
bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1; bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1;
CPPTRACE_VERIFY(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF endianness " + obj_path); VERIFY(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF endianness " + obj_path);
// get image base // get image base
if(is_64) { if(is_64) {
return elf_get_module_image_base_from_program_table<64>(obj_path, file, is_little_endian); return elf_get_module_image_base_from_program_table<64>(obj_path, file, is_little_endian);

View File

@ -5,6 +5,7 @@
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <utility>
#include "common.hpp" #include "common.hpp"
@ -37,37 +38,65 @@ namespace detail {
) : file(_file), /*function(_function),*/ line(_line) {} ) : file(_file), /*function(_function),*/ line(_line) {}
}; };
inline void primitive_assert_impl( enum class assert_type {
bool condition, assert,
bool verify, verify,
panic,
};
constexpr const char* assert_actions[] = {"assertion", "verification", "panic"};
constexpr const char* assert_names[] = {"ASSERT", "VERIFY", "PANIC"};
inline void assert_fail(
assert_type type,
const char* expression, const char* expression,
const char* signature, const char* signature,
source_location location, source_location location,
const std::string& message = "" const std::string& message = ""
) { ) {
if(!condition) { const char* action = assert_actions[static_cast<std::underlying_type<assert_type>::type>(type)];
const char* action = verify ? "verification" : "assertion"; const char* name = assert_names[static_cast<std::underlying_type<assert_type>::type>(type)];
const char* name = verify ? "VERIFY" : "ASSERT";
if(message == "") { if(message == "") {
throw std::runtime_error( throw std::logic_error(
stringf( stringf(
"Cpptrace %s failed at %s:%d: %s\n" "Cpptrace %s failed at %s:%d: %s\n"
" CPPTRACE_%s(%s);\n", " %s(%s);\n",
action, location.file, location.line, signature, action, location.file, location.line, signature,
name, expression name, expression
) )
); );
} else { } else {
throw std::runtime_error( throw std::logic_error(
stringf( stringf(
"Cpptrace %s failed at %s:%d: %s: %s\n" "Cpptrace %s failed at %s:%d: %s: %s\n"
" CPPTRACE_%s(%s);\n", " %s(%s);\n",
action, location.file, location.line, signature, message.c_str(), action, location.file, location.line, signature, message.c_str(),
name, expression name, expression
) )
); );
} }
} }
[[noreturn]] inline void panic(
const char* signature,
source_location location,
const std::string& message = ""
) {
if(message == "") {
throw std::logic_error(
stringf(
"Cpptrace panic %s:%d: %s\n",
location.file, location.line, signature
)
);
} else {
throw std::logic_error(
stringf(
"Cpptrace panic %s:%d: %s: %s\n",
location.file, location.line, signature, message.c_str()
)
);
}
} }
template<typename T> template<typename T>
@ -75,25 +104,43 @@ namespace detail {
#define PHONY_USE(E) (nullfn<decltype(E)>()) #define PHONY_USE(E) (nullfn<decltype(E)>())
// Workaround a compiler warning
template<typename T>
bool as_bool(T&& value) {
return static_cast<bool>(std::forward<T>(value));
}
// Check condition in both debug and release. std::runtime_error on failure. // Check condition in both debug and release. std::runtime_error on failure.
#define CPPTRACE_VERIFY(c, ...) ( \ #define VERIFY(c, ...) ( \
::cpptrace::detail::primitive_assert_impl(c, true, #c, CPPTRACE_PFUNC, {}, ##__VA_ARGS__) \ (::cpptrace::detail::as_bool(c)) \
? static_cast<void>(0) \
: (::cpptrace::detail::assert_fail)( \
::cpptrace::detail::assert_type::verify, \
#c, \
CPPTRACE_PFUNC, \
{}, \
##__VA_ARGS__) \
) )
// Check condition in both debug and release. std::runtime_error on failure.
#define PANIC(...) ((::cpptrace::detail::panic)(CPPTRACE_PFUNC, {}, std::string(__VA_ARGS__)))
#ifndef NDEBUG #ifndef NDEBUG
// Check condition in both debug. std::runtime_error on failure. // Check condition in both debug. std::runtime_error on failure.
#define CPPTRACE_ASSERT(c, ...) ( \ #define ASSERT(c, ...) ( \
::cpptrace::detail::primitive_assert_impl(c, false, #c, CPPTRACE_PFUNC, {}, ##__VA_ARGS__) \ (::cpptrace::detail::as_bool(c)) \
? static_cast<void>(0) \
: (::cpptrace::detail::assert_fail)( \
::cpptrace::detail::assert_type::assert, \
#c, \
CPPTRACE_PFUNC, \
{}, \
##__VA_ARGS__) \
) )
#else #else
// Check condition in both debug. std::runtime_error on failure. // Check condition in both debug. std::runtime_error on failure.
#define CPPTRACE_ASSERT(c, ...) PHONY_USE(c) #define ASSERT(c, ...) PHONY_USE(c)
#endif #endif
// TODO: Setting to silence these or make them fatal
inline void nonfatal_error(const std::string& message) {
fprintf(stderr, "Non-fatal cpptrace error: %s\n", message.c_str());
}
} }
} }

View File

@ -107,7 +107,7 @@ namespace detail {
if(allow_arch_mismatch) { if(allow_arch_mismatch) {
return nullopt; return nullopt;
} else { } else {
CPPTRACE_VERIFY(false, "Mach-O file cpu type and subtype do not match current machine " + obj_path); PANIC("Mach-O file cpu type and subtype do not match current machine " + obj_path);
} }
} }
ncmds = header.ncmds; ncmds = header.ncmds;
@ -130,7 +130,7 @@ namespace detail {
actual_offset += cmd.cmdsize; actual_offset += cmd.cmdsize;
} }
// somehow no __TEXT section was found... // somehow no __TEXT section was found...
CPPTRACE_VERIFY(false, "Couldn't find __TEXT section while parsing Mach-O object"); PANIC("Couldn't find __TEXT section while parsing Mach-O object");
return 0; return 0;
} }
@ -173,7 +173,7 @@ namespace detail {
} }
} }
// If this is reached... something went wrong. The cpu we're on wasn't found. // If this is reached... something went wrong. The cpu we're on wasn't found.
CPPTRACE_VERIFY(false, "Couldn't find appropriate architecture in fat Mach-O"); PANIC("Couldn't find appropriate architecture in fat Mach-O");
return 0; return 0;
} }
@ -184,7 +184,7 @@ namespace detail {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + obj_path);
} }
uint32_t magic = load_bytes<uint32_t>(file, 0); uint32_t magic = load_bytes<uint32_t>(file, 0);
CPPTRACE_VERIFY(is_mach_o(magic), "File is not Mach-O " + obj_path); VERIFY(is_mach_o(magic), "File is not Mach-O " + obj_path);
bool is_64 = is_magic_64(magic); bool is_64 = is_magic_64(magic);
bool should_swap = should_swap_bytes(magic); bool should_swap = should_swap_bytes(magic);
if(magic == FAT_MAGIC || magic == FAT_CIGAM) { if(magic == FAT_MAGIC || magic == FAT_CIGAM) {
@ -220,7 +220,7 @@ namespace detail {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + obj_path);
} }
uint32_t magic = load_bytes<uint32_t>(file, 0); uint32_t magic = load_bytes<uint32_t>(file, 0);
CPPTRACE_VERIFY(is_fat_magic(magic)); VERIFY(is_fat_magic(magic));
bool should_swap = should_swap_bytes(magic); bool should_swap = should_swap_bytes(magic);
size_t header_size = sizeof(fat_header); size_t header_size = sizeof(fat_header);
size_t arch_size = sizeof(fat_arch); size_t arch_size = sizeof(fat_arch);
@ -244,7 +244,7 @@ namespace detail {
} }
} }
// If this is reached... something went wrong. The cpu we're on wasn't found. // If this is reached... something went wrong. The cpu we're on wasn't found.
CPPTRACE_VERIFY(false, "Couldn't find appropriate architecture in fat Mach-O"); PANIC("Couldn't find appropriate architecture in fat Mach-O");
return { 0, 0 }; return { 0, 0 };
} }
} }

View File

@ -37,19 +37,19 @@ namespace detail {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + obj_path);
} }
auto magic = load_bytes<std::array<char, 2>>(file, 0); auto magic = load_bytes<std::array<char, 2>>(file, 0);
CPPTRACE_VERIFY(memcmp(magic.data(), "MZ", 2) == 0, "File is not a PE file " + obj_path); VERIFY(memcmp(magic.data(), "MZ", 2) == 0, "File is not a PE file " + obj_path);
DWORD e_lfanew = pe_byteswap_if_needed(load_bytes<DWORD>(file, 0x3c)); // dos header + 0x3c DWORD e_lfanew = pe_byteswap_if_needed(load_bytes<DWORD>(file, 0x3c)); // dos header + 0x3c
DWORD nt_header_offset = e_lfanew; DWORD nt_header_offset = e_lfanew;
auto signature = load_bytes<std::array<char, 4>>(file, nt_header_offset); // nt header + 0 auto signature = load_bytes<std::array<char, 4>>(file, nt_header_offset); // nt header + 0
CPPTRACE_VERIFY(memcmp(signature.data(), "PE\0\0", 4) == 0, "File is not a PE file " + obj_path); VERIFY(memcmp(signature.data(), "PE\0\0", 4) == 0, "File is not a PE file " + obj_path);
WORD size_of_optional_header = pe_byteswap_if_needed( WORD size_of_optional_header = pe_byteswap_if_needed(
load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10 load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10
); );
CPPTRACE_VERIFY(size_of_optional_header != 0); VERIFY(size_of_optional_header != 0);
WORD optional_header_magic = pe_byteswap_if_needed( WORD optional_header_magic = pe_byteswap_if_needed(
load_bytes<WORD>(file, nt_header_offset + 0x18) // optional header + 0x0 load_bytes<WORD>(file, nt_header_offset + 0x18) // optional header + 0x0
); );
CPPTRACE_VERIFY( VERIFY(
optional_header_magic == IMAGE_NT_OPTIONAL_HDR_MAGIC, optional_header_magic == IMAGE_NT_OPTIONAL_HDR_MAGIC,
"PE file does not match expected bit-mode " + obj_path "PE file does not match expected bit-mode " + obj_path
); );

View File

@ -155,8 +155,8 @@ namespace detail {
template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0>
T load_bytes(FILE* obj_file, off_t offset) { T load_bytes(FILE* obj_file, off_t offset) {
T object; T object;
CPPTRACE_VERIFY(fseek(obj_file, offset, SEEK_SET) == 0, "fseek error"); VERIFY(fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
CPPTRACE_VERIFY(fread(&object, sizeof(T), 1, obj_file) == 1, "fread error"); VERIFY(fread(&object, sizeof(T), 1, obj_file) == 1, "fread error");
return object; return object;
} }

View File

@ -75,8 +75,8 @@ namespace addr2line {
std::string resolve_addresses(const std::string& addresses, const std::string& executable) { std::string resolve_addresses(const std::string& addresses, const std::string& executable) {
pipe_t output_pipe; pipe_t output_pipe;
pipe_t input_pipe; pipe_t input_pipe;
CPPTRACE_VERIFY(pipe(output_pipe.data) == 0); VERIFY(pipe(output_pipe.data) == 0);
CPPTRACE_VERIFY(pipe(input_pipe.data) == 0); VERIFY(pipe(input_pipe.data) == 0);
const pid_t pid = fork(); const pid_t pid = fork();
if(pid == -1) { return ""; } // error? TODO: Diagnostic if(pid == -1) { return ""; } // error? TODO: Diagnostic
if(pid == 0) { // child if(pid == 0) { // child
@ -120,7 +120,7 @@ namespace addr2line {
#endif #endif
_exit(1); // TODO: Diagnostic? _exit(1); // TODO: Diagnostic?
} }
CPPTRACE_VERIFY(write(input_pipe.write_end, addresses.data(), addresses.size()) != -1); VERIFY(write(input_pipe.write_end, addresses.data(), addresses.size()) != -1);
close(input_pipe.read_end); close(input_pipe.read_end);
close(input_pipe.write_end); close(input_pipe.write_end);
close(output_pipe.write_end); close(output_pipe.write_end);
@ -200,14 +200,14 @@ namespace addr2line {
symbol_end = at_location; symbol_end = at_location;
filename_start = at_location + 4; filename_start = at_location + 4;
} else { } else {
CPPTRACE_VERIFY(line.find("?? ") == 0, "Unexpected edge case while processing addr2line output"); VERIFY(line.find("?? ") == 0, "Unexpected edge case while processing addr2line output");
symbol_end = 2; symbol_end = 2;
filename_start = 3; filename_start = 3;
} }
auto symbol = line.substr(0, symbol_end); auto symbol = line.substr(0, symbol_end);
auto colon = line.rfind(':'); auto colon = line.rfind(':');
CPPTRACE_VERIFY(colon != std::string::npos); VERIFY(colon != std::string::npos);
CPPTRACE_VERIFY(colon >= filename_start); // :? to deal with "symbol :?" edge case VERIFY(colon >= filename_start); // :? to deal with "symbol :?" edge case
auto filename = line.substr(filename_start, colon - filename_start); auto filename = line.substr(filename_start, colon - filename_start);
auto line_number = line.substr(colon + 1); auto line_number = line.substr(colon + 1);
if(line_number != "?") { if(line_number != "?") {
@ -237,7 +237,7 @@ namespace addr2line {
const std::size_t symbol_end = in_location; const std::size_t symbol_end = in_location;
entries_vec[entry_index].second.get().symbol = line.substr(0, symbol_end); entries_vec[entry_index].second.get().symbol = line.substr(0, symbol_end);
const std::size_t obj_end = line.find(")", in_location); const std::size_t obj_end = line.find(")", in_location);
CPPTRACE_VERIFY( VERIFY(
obj_end != std::string::npos, obj_end != std::string::npos,
"Unexpected edge case while processing addr2line/atos output" "Unexpected edge case while processing addr2line/atos output"
); );
@ -247,7 +247,7 @@ namespace addr2line {
return; return;
} }
const std::size_t filename_end = line.find(":", filename_start); const std::size_t filename_end = line.find(":", filename_start);
CPPTRACE_VERIFY( VERIFY(
filename_end != std::string::npos, filename_end != std::string::npos,
"Unexpected edge case while processing addr2line/atos output" "Unexpected edge case while processing addr2line/atos output"
); );
@ -257,7 +257,7 @@ namespace addr2line {
); );
const std::size_t line_start = filename_end + 1; const std::size_t line_start = filename_end + 1;
const std::size_t line_end = line.find(")", filename_end); const std::size_t line_end = line.find(")", filename_end);
CPPTRACE_VERIFY( VERIFY(
line_end == line.size() - 1, line_end == line.size() - 1,
"Unexpected edge case while processing addr2line/atos output" "Unexpected edge case while processing addr2line/atos output"
); );
@ -296,7 +296,7 @@ namespace addr2line {
#endif #endif
} }
auto output = split(trim(resolve_addresses(address_input, object_name)), "\n"); auto output = split(trim(resolve_addresses(address_input, object_name)), "\n");
CPPTRACE_VERIFY(output.size() == entries_vec.size()); VERIFY(output.size() == entries_vec.size());
for(size_t i = 0; i < output.size(); i++) { for(size_t i = 0; i < output.size(); i++) {
update_trace(output[i], i, entries_vec); update_trace(output[i], i, entries_vec);
} }

View File

@ -14,6 +14,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <stdexcept>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
@ -42,23 +43,48 @@ namespace libdwarf {
constexpr bool dump_dwarf = false; constexpr bool dump_dwarf = false;
constexpr bool trace_dwarf = false; constexpr bool trace_dwarf = false;
static void err_handler(Dwarf_Error err, Dwarf_Ptr errarg) {
printf("libdwarf error reading %s: %llu %s\n", "xx", to_ull(dwarf_errno(err)), dwarf_errmsg(err));
if(errarg) {
printf("Error: errarg is nonnull but it should be null\n");
}
printf("Giving up");
exit(1);
}
static_assert(std::is_pointer<Dwarf_Die>::value, "Dwarf_Die not a pointer"); static_assert(std::is_pointer<Dwarf_Die>::value, "Dwarf_Die not a pointer");
static_assert(std::is_pointer<Dwarf_Debug>::value, "Dwarf_Debug not a pointer"); static_assert(std::is_pointer<Dwarf_Debug>::value, "Dwarf_Debug not a pointer");
void handle_error(Dwarf_Debug dbg, Dwarf_Error error) {
int ev = dwarf_errno(error);
char* msg = dwarf_errmsg(error);
dwarf_dealloc_error(dbg, error);
throw std::runtime_error(stringf("Cpptrace dwarf error %d %s\n", ev, msg));
}
struct die_object { struct die_object {
Dwarf_Debug dbg = nullptr; Dwarf_Debug dbg = nullptr;
Dwarf_Die die = nullptr; Dwarf_Die die = nullptr;
die_object(Dwarf_Debug dbg, Dwarf_Die die) : dbg(dbg), die(die) {} // Error handling helper
// For some reason R (*f)(Args..., void*)-style deduction isn't possible, seems like a bug in all compilers
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56190
template<
typename... Args,
typename... Args2,
typename std::enable_if<
std::is_same<
decltype(
(void)std::declval<int(Args...)>()(std::forward<Args2>(std::declval<Args2>())..., nullptr)
),
void
>::value,
int
>::type = 0
>
int wrap(int (*f)(Args...), Args2&&... args) const {
Dwarf_Error error = 0;
int ret = f(std::forward<Args2>(args)..., &error);
if(ret == DW_DLV_ERROR) {
handle_error(dbg, error);
}
return ret;
}
die_object(Dwarf_Debug dbg, Dwarf_Die die) : dbg(dbg), die(die) {
ASSERT(dbg != nullptr);
}
~die_object() { ~die_object() {
if(die) { if(die) {
@ -88,37 +114,31 @@ namespace libdwarf {
Dwarf_Off off = get_global_offset(); Dwarf_Off off = get_global_offset();
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die); Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
Dwarf_Die die_copy = 0; Dwarf_Die die_copy = 0;
CPPTRACE_VERIFY(dwarf_offdie_b(dbg, off, is_info, &die_copy, nullptr) == DW_DLV_OK); VERIFY(wrap(dwarf_offdie_b, dbg, off, is_info, &die_copy) == DW_DLV_OK);
return {dbg, die_copy}; return {dbg, die_copy};
} }
die_object get_child() const { die_object get_child() const {
Dwarf_Die child = nullptr; Dwarf_Die child = nullptr;
int ret = dwarf_child( int ret = wrap(dwarf_child, die, &child);
die,
&child,
nullptr
);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
return die_object(dbg, child); return die_object(dbg, child);
} else if(ret == DW_DLV_NO_ENTRY) { } else if(ret == DW_DLV_NO_ENTRY) {
return die_object(dbg, 0); return die_object(dbg, 0);
} else { } else {
fprintf(stderr, "Error\n"); PANIC();
exit(1);
} }
} }
die_object get_sibling() const { die_object get_sibling() const {
Dwarf_Die sibling = 0; Dwarf_Die sibling = 0;
int ret = dwarf_siblingof_b(dbg, die, true, &sibling, nullptr); int ret = wrap(dwarf_siblingof_b, dbg, die, true, &sibling);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
return die_object(dbg, sibling); return die_object(dbg, sibling);
} else if(ret == DW_DLV_NO_ENTRY) { } else if(ret == DW_DLV_NO_ENTRY) {
return die_object(dbg, 0); return die_object(dbg, 0);
} else { } else {
fprintf(stderr, "Error\n"); PANIC();
exit(1);
} }
} }
@ -133,7 +153,7 @@ namespace libdwarf {
std::string get_name() const { std::string get_name() const {
char empty[] = ""; char empty[] = "";
char* name = empty; char* name = empty;
int ret = dwarf_diename(die, &name, nullptr); int ret = wrap(dwarf_diename, die, &name);
std::string str; std::string str;
if(ret != DW_DLV_NO_ENTRY) { if(ret != DW_DLV_NO_ENTRY) {
str = name; str = name;
@ -144,12 +164,10 @@ namespace libdwarf {
optional<std::string> get_string_attribute(Dwarf_Half dw_attrnum) const { optional<std::string> get_string_attribute(Dwarf_Half dw_attrnum) const {
Dwarf_Attribute attr; Dwarf_Attribute attr;
int ret = dwarf_attr(die, dw_attrnum, &attr, nullptr); if(wrap(dwarf_attr, die, dw_attrnum, &attr) == DW_DLV_OK) {
if(ret == DW_DLV_OK) {
char* raw_str; char* raw_str;
std::string str; std::string str;
ret = dwarf_formstring(attr, &raw_str, nullptr); VERIFY(wrap(dwarf_formstring, attr, &raw_str) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
str = raw_str; str = raw_str;
dwarf_dealloc(dbg, raw_str, DW_DLA_STRING); dwarf_dealloc(dbg, raw_str, DW_DLA_STRING);
dwarf_dealloc_attribute(attr); dwarf_dealloc_attribute(attr);
@ -161,34 +179,36 @@ namespace libdwarf {
bool has_attr(Dwarf_Half dw_attrnum) const { bool has_attr(Dwarf_Half dw_attrnum) const {
Dwarf_Bool present = false; Dwarf_Bool present = false;
CPPTRACE_VERIFY(dwarf_hasattr(die, dw_attrnum, &present, nullptr) == DW_DLV_OK); VERIFY(wrap(dwarf_hasattr, die, dw_attrnum, &present) == DW_DLV_OK);
return present; return present;
} }
Dwarf_Half get_tag() const { Dwarf_Half get_tag() const {
Dwarf_Half tag = 0; Dwarf_Half tag = 0;
dwarf_tag(die, &tag, nullptr); VERIFY(wrap(dwarf_tag, die, &tag) == DW_DLV_OK);
return tag; return tag;
} }
const char* get_tag_name() const { const char* get_tag_name() const {
const char* tag_name; const char* tag_name;
dwarf_get_TAG_name(get_tag(), &tag_name); if(dwarf_get_TAG_name(get_tag(), &tag_name) == DW_DLV_OK) {
return tag_name; return tag_name;
} else {
return "<unknown tag name>";
}
} }
Dwarf_Off get_global_offset() const { Dwarf_Off get_global_offset() const {
Dwarf_Off off; Dwarf_Off off;
int ret = dwarf_dieoffset(die, &off, nullptr); VERIFY(wrap(dwarf_dieoffset, die, &off) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
return off; return off;
} }
die_object resolve_reference_attribute(Dwarf_Half dw_attrnum) const { die_object resolve_reference_attribute(Dwarf_Half dw_attrnum) const {
Dwarf_Attribute attr; Dwarf_Attribute attr;
int ret = dwarf_attr(die, dw_attrnum, &attr, nullptr); VERIFY(dwarf_attr(die, dw_attrnum, &attr, nullptr) == DW_DLV_OK);
Dwarf_Half form = 0; Dwarf_Half form = 0;
ret = dwarf_whatform(attr, &form, nullptr); VERIFY(wrap(dwarf_whatform, attr, &form) == DW_DLV_OK);
switch(form) { switch(form) {
case DW_FORM_ref1: case DW_FORM_ref1:
case DW_FORM_ref2: case DW_FORM_ref2:
@ -198,37 +218,31 @@ namespace libdwarf {
{ {
Dwarf_Off off = 0; Dwarf_Off off = 0;
Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die); Dwarf_Bool is_info = dwarf_get_die_infotypes_flag(die);
ret = dwarf_formref(attr, &off, &is_info, nullptr); VERIFY(wrap(dwarf_formref, attr, &off, &is_info) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
Dwarf_Off goff = 0; Dwarf_Off goff = 0;
ret = dwarf_convert_to_global_offset(attr, off, &goff, nullptr); VERIFY(wrap(dwarf_convert_to_global_offset, attr, off, &goff) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
Dwarf_Die targ_die_a = 0; Dwarf_Die targ_die_a = 0;
ret = dwarf_offdie_b(dbg, goff, is_info, &targ_die_a, nullptr); VERIFY(wrap(dwarf_offdie_b, dbg, goff, is_info, &targ_die_a) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
dwarf_dealloc_attribute(attr); dwarf_dealloc_attribute(attr);
return die_object(dbg, targ_die_a); return die_object(dbg, targ_die_a);
} }
case DW_FORM_ref_addr: case DW_FORM_ref_addr:
{ {
Dwarf_Off off; Dwarf_Off off;
ret = dwarf_global_formref(attr, &off, nullptr); VERIFY(wrap(dwarf_global_formref, attr, &off) == DW_DLV_OK);
int is_info_a = dwarf_get_die_infotypes_flag(die); int is_info_a = dwarf_get_die_infotypes_flag(die);
Dwarf_Die targ_die_a = 0; Dwarf_Die targ_die_a = 0;
ret = dwarf_offdie_b(dbg, off, is_info_a, &targ_die_a, nullptr); VERIFY(wrap(dwarf_offdie_b, dbg, off, is_info_a, &targ_die_a) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
dwarf_dealloc_attribute(attr); dwarf_dealloc_attribute(attr);
return die_object(dbg, targ_die_a); return die_object(dbg, targ_die_a);
} }
case DW_FORM_ref_sig8: case DW_FORM_ref_sig8:
{ {
Dwarf_Sig8 signature; Dwarf_Sig8 signature;
ret = dwarf_formsig8(attr, &signature, nullptr); VERIFY(wrap(dwarf_formsig8, attr, &signature) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
Dwarf_Die targdie = 0; Dwarf_Die targdie = 0;
Dwarf_Bool targ_is_info = false; Dwarf_Bool targ_is_info = false;
ret = dwarf_find_die_given_sig8(dbg, &signature, &targdie, &targ_is_info, nullptr); VERIFY(wrap(dwarf_find_die_given_sig8, dbg, &signature, &targdie, &targ_is_info) == DW_DLV_OK);
CPPTRACE_VERIFY(ret == DW_DLV_OK);
dwarf_dealloc_attribute(attr); dwarf_dealloc_attribute(attr);
return die_object(dbg, targdie); return die_object(dbg, targdie);
} }
@ -241,13 +255,11 @@ namespace libdwarf {
Dwarf_Unsigned get_ranges_offset(Dwarf_Attribute attr) const { Dwarf_Unsigned get_ranges_offset(Dwarf_Attribute attr) const {
Dwarf_Unsigned off = 0; Dwarf_Unsigned off = 0;
Dwarf_Half attrform = 0; Dwarf_Half attrform = 0;
dwarf_whatform(attr, &attrform, nullptr); VERIFY(wrap(dwarf_whatform, attr, &attrform) == DW_DLV_OK);
if (attrform == DW_FORM_rnglistx) { if (attrform == DW_FORM_rnglistx) {
int fres = dwarf_formudata(attr, &off, nullptr); VERIFY(wrap(dwarf_formudata, attr, &off) == DW_DLV_OK);
CPPTRACE_VERIFY(fres == DW_DLV_OK);
} else { } else {
int fres = dwarf_global_formref(attr, &off, nullptr); VERIFY(wrap(dwarf_global_formref, attr, &off) == DW_DLV_OK);
CPPTRACE_VERIFY(fres == DW_DLV_OK);
} }
return off; return off;
} }
@ -265,7 +277,7 @@ namespace libdwarf {
Dwarf_Unsigned i = 0; Dwarf_Unsigned i = 0;
int res = 0; int res = 0;
res = dwarf_attr(cu_die, DW_AT_ranges, &attr, nullptr); res = wrap(dwarf_attr, cu_die, DW_AT_ranges, &attr);
if(res != DW_DLV_OK) { if(res != DW_DLV_OK) {
return res; return res;
} }
@ -275,18 +287,18 @@ namespace libdwarf {
Dwarf_Unsigned rnglists_count = 0; Dwarf_Unsigned rnglists_count = 0;
Dwarf_Rnglists_Head head = 0; Dwarf_Rnglists_Head head = 0;
dwarf_whatform(attr, &attrform, nullptr); VERIFY(wrap(dwarf_whatform, attr, &attrform) == DW_DLV_OK);
/* offset is in .debug_rnglists */ // offset is in .debug_rnglists
res = dwarf_rnglists_get_rle_head( res = wrap(
dwarf_rnglists_get_rle_head,
attr, attr,
attrform, attrform,
offset, offset,
&head, &head,
&rnglists_count, &rnglists_count,
&rlesetoffset, &rlesetoffset
nullptr
); );
CPPTRACE_VERIFY(res == DW_DLV_OK); VERIFY(res == DW_DLV_OK);
if(res != DW_DLV_OK) { if(res != DW_DLV_OK) {
/* ASSERT: is DW_DLV_NO_ENTRY */ /* ASSERT: is DW_DLV_NO_ENTRY */
dwarf_dealloc_attribute(attr); dwarf_dealloc_attribute(attr);
@ -301,7 +313,8 @@ namespace libdwarf {
Dwarf_Unsigned cooked1 = 0; Dwarf_Unsigned cooked1 = 0;
Dwarf_Unsigned cooked2 = 0; Dwarf_Unsigned cooked2 = 0;
res = dwarf_get_rnglists_entry_fields_a( res = wrap(
dwarf_get_rnglists_entry_fields_a,
head, head,
i, i,
&entrylen, &entrylen,
@ -310,11 +323,10 @@ namespace libdwarf {
&raw2, &raw2,
&unavail, &unavail,
&cooked1, &cooked1,
&cooked2, &cooked2
nullptr
); );
if(res != DW_DLV_OK) { if(res != DW_DLV_OK) {
/* ASSERT: is DW_DLV_NO_ENTRY */ ASSERT(res == DW_DLV_NO_ENTRY);
continue; continue;
} }
if(unavail) { if(unavail) {
@ -342,8 +354,7 @@ namespace libdwarf {
} }
break; break;
default: default:
CPPTRACE_VERIFY(false); PANIC("Something is wrong");
/* Something is wrong. */
break; break;
} }
} }
@ -365,26 +376,28 @@ namespace libdwarf {
Dwarf_Attribute attr = 0; Dwarf_Attribute attr = 0;
int res = 0; int res = 0;
res = dwarf_attr(cu_die, DW_AT_ranges, &attr, nullptr); res = wrap(dwarf_attr, cu_die, DW_AT_ranges, &attr);
if(res != DW_DLV_OK) { if(res != DW_DLV_OK) {
return res; return res;
} }
if(dwarf_global_formref(attr, &offset, nullptr) == DW_DLV_OK) { if(wrap(dwarf_global_formref, attr, &offset) == DW_DLV_OK) {
Dwarf_Signed count = 0; Dwarf_Signed count = 0;
Dwarf_Ranges *ranges = 0; Dwarf_Ranges *ranges = 0;
Dwarf_Addr baseaddr = 0; Dwarf_Addr baseaddr = 0;
if(cu_lowpc != 0xffffffffffffffff) { if(cu_lowpc != 0xffffffffffffffff) {
baseaddr = cu_lowpc; baseaddr = cu_lowpc;
} }
res = dwarf_get_ranges_b( VERIFY(
wrap(
dwarf_get_ranges_b,
dbg, dbg,
offset, offset,
cu_die, cu_die,
nullptr, nullptr,
&ranges, &ranges,
&count, &count,
nullptr,
nullptr nullptr
) == DW_DLV_OK
); );
for(int i = 0; i < count; i++) { for(int i = 0; i < count; i++) {
Dwarf_Ranges *cur = ranges + i; Dwarf_Ranges *cur = ranges + i;
@ -425,10 +438,9 @@ namespace libdwarf {
Dwarf_Addr lowest = 0xffffffffffffffff; Dwarf_Addr lowest = 0xffffffffffffffff;
Dwarf_Addr highest = 0; Dwarf_Addr highest = 0;
ret = dwarf_lowpc(die, &cu_lowpc, nullptr); ret = wrap(dwarf_lowpc, die, &cu_lowpc);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
ret = dwarf_highpc_b(die, &cu_highpc, ret = wrap(dwarf_highpc_b, die, &cu_highpc, nullptr, &highpc_cls);
nullptr, &highpc_cls, nullptr);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
if(highpc_cls == DW_FORM_CLASS_CONSTANT) { if(highpc_cls == DW_FORM_CLASS_CONSTANT) {
cu_highpc += cu_lowpc; cu_highpc += cu_lowpc;
@ -455,13 +467,12 @@ namespace libdwarf {
Dwarf_Addr lowest = 0xffffffffffffffff; Dwarf_Addr lowest = 0xffffffffffffffff;
Dwarf_Addr highest = 0; Dwarf_Addr highest = 0;
ret = dwarf_lowpc(die, &cu_lowpc, nullptr); ret = wrap(dwarf_lowpc, die, &cu_lowpc);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
if(pc == cu_lowpc) { if(pc == cu_lowpc) {
return true; return true;
} }
ret = dwarf_highpc_b(die, &cu_highpc, ret = wrap(dwarf_highpc_b, die, &cu_highpc, nullptr, &highpc_cls);
nullptr, &highpc_cls, nullptr);
if(ret == DW_DLV_OK) { if(ret == DW_DLV_OK) {
if(highpc_cls == DW_FORM_CLASS_CONSTANT) { if(highpc_cls == DW_FORM_CLASS_CONSTANT) {
cu_highpc += cu_lowpc; cu_highpc += cu_lowpc;
@ -512,12 +523,38 @@ namespace libdwarf {
struct dwarf_resolver { struct dwarf_resolver {
std::string obj_path; std::string obj_path;
Dwarf_Debug dbg; Dwarf_Debug dbg;
bool ok = false;
std::unordered_map<Dwarf_Off, line_context> line_contexts; std::unordered_map<Dwarf_Off, line_context> line_contexts;
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache; std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
// Exists only for cleaning up an awful mach-o hack // Exists only for cleaning up an awful mach-o hack
std::string tmp_object_path; std::string tmp_object_path;
// Error handling helper
// For some reason R (*f)(Args..., void*)-style deduction isn't possible, seems like a bug in all compilers
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56190
template<
typename... Args,
typename... Args2,
typename std::enable_if<
std::is_same<
decltype(
(void)std::declval<int(Args...)>()(std::forward<Args2>(std::declval<Args2>())..., nullptr)
),
void
>::value,
int
>::type = 0
>
int wrap(int (*f)(Args...), Args2&&... args) const {
Dwarf_Error error = 0;
int ret = f(std::forward<Args2>(args)..., &error);
if(ret == DW_DLV_ERROR) {
handle_error(dbg, error);
}
return ret;
}
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
dwarf_resolver(const std::string& object_path) { dwarf_resolver(const std::string& object_path) {
obj_path = object_path; obj_path = object_path;
@ -532,17 +569,17 @@ namespace libdwarf {
char tmp_template[] = "/tmp/tmp.cpptrace.XXXXXX"; char tmp_template[] = "/tmp/tmp.cpptrace.XXXXXX";
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
CPPTRACE_VERIFY(mktemp(tmp_template) != nullptr); VERIFY(mktemp(tmp_template) != nullptr);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
std::string tmp_path = tmp_template; std::string tmp_path = tmp_template;
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter); auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
auto tmp = raii_wrap(fopen(tmp_path.c_str(), "wb"), file_deleter); auto tmp = raii_wrap(fopen(tmp_path.c_str(), "wb"), file_deleter);
CPPTRACE_VERIFY(file != nullptr); VERIFY(file != nullptr);
CPPTRACE_VERIFY(tmp != nullptr); VERIFY(tmp != nullptr);
std::unique_ptr<char[]> buffer(new char[sub_object.size]); std::unique_ptr<char[]> buffer(new char[sub_object.size]);
CPPTRACE_VERIFY(fseek(file, sub_object.offset, SEEK_SET) == 0); VERIFY(fseek(file, sub_object.offset, SEEK_SET) == 0);
CPPTRACE_VERIFY(fread(buffer.get(), 1, sub_object.size, file) == sub_object.size); VERIFY(fread(buffer.get(), 1, sub_object.size, file) == sub_object.size);
CPPTRACE_VERIFY(fwrite(buffer.get(), 1, sub_object.size, tmp) == sub_object.size); VERIFY(fwrite(buffer.get(), 1, sub_object.size, tmp) == sub_object.size);
obj_path = tmp_path; obj_path = tmp_path;
tmp_object_path = std::move(tmp_path); tmp_object_path = std::move(tmp_path);
} }
@ -551,21 +588,24 @@ namespace libdwarf {
// Giving libdwarf a buffer for a true output path is needed for its automatic resolution of debuglink and // Giving libdwarf a buffer for a true output path is needed for its automatic resolution of debuglink and
// dSYM files. We don't utilize the dSYM logic here, we just care about debuglink. // dSYM files. We don't utilize the dSYM logic here, we just care about debuglink.
std::unique_ptr<char[]> buffer(new char[CPPTRACE_MAX_PATH]); std::unique_ptr<char[]> buffer(new char[CPPTRACE_MAX_PATH]);
Dwarf_Ptr errarg = 0; auto ret = wrap(
auto ret = dwarf_init_path( dwarf_init_path,
obj_path.c_str(), obj_path.c_str(),
buffer.get(), buffer.get(),
CPPTRACE_MAX_PATH, CPPTRACE_MAX_PATH,
DW_GROUPNUMBER_ANY, DW_GROUPNUMBER_ANY,
err_handler, nullptr,
errarg, nullptr,
&dbg, &dbg
nullptr
); );
if(ret == DW_DLV_NO_ENTRY) { if(ret == DW_DLV_OK) {
ok = true;
} else if(ret == DW_DLV_NO_ENTRY) {
// fail, no debug info // fail, no debug info
} else if(ret != DW_DLV_OK) { ok = false;
fprintf(stderr, "Error\n"); } else {
ok = false;
PANIC("Unknown return code from dwarf_init_path");
} }
} }
@ -637,7 +677,7 @@ namespace libdwarf {
Dwarf_Half dwversion, Dwarf_Half dwversion,
stacktrace_frame& frame stacktrace_frame& frame
) { ) {
CPPTRACE_ASSERT(die.get_tag() == DW_TAG_subprogram); ASSERT(die.get_tag() == DW_TAG_subprogram);
optional<std::string> name; optional<std::string> name;
if(auto linkage_name = die.get_string_attribute(DW_AT_linkage_name)) { if(auto linkage_name = die.get_string_attribute(DW_AT_linkage_name)) {
name = std::move(linkage_name); name = std::move(linkage_name);
@ -827,7 +867,7 @@ namespace libdwarf {
retrieve_symbol_for_subprogram(vec_it->die, pc, dwversion, frame); retrieve_symbol_for_subprogram(vec_it->die, pc, dwversion, frame);
} }
} else { } else {
CPPTRACE_ASSERT(vec.size() == 0, "Vec should be empty?"); ASSERT(vec.size() == 0, "Vec should be empty?");
} }
} }
@ -837,9 +877,8 @@ namespace libdwarf {
Dwarf_Unsigned lineno = 0; Dwarf_Unsigned lineno = 0;
if(line) { if(line) {
/* These never return DW_DLV_NO_ENTRY */ VERIFY(wrap(dwarf_linesrc, line, &linesrc) == DW_DLV_OK);
dwarf_linesrc(line, &linesrc, nullptr); VERIFY(wrap(dwarf_lineno, line, &lineno) == DW_DLV_OK);
dwarf_lineno(line, &lineno, nullptr);
} }
if(dump_dwarf) { if(dump_dwarf) {
printf("%s:%u\n", linesrc, to<unsigned>(lineno)); printf("%s:%u\n", linesrc, to<unsigned>(lineno));
@ -871,41 +910,42 @@ namespace libdwarf {
table_count = entry.table_count; table_count = entry.table_count;
ctxt = entry.ctx; ctxt = entry.ctx;
} else { } else {
int ret = dwarf_srclines_b( int ret = wrap(
dwarf_srclines_b,
die.get(), die.get(),
&version, &version,
&table_count, &table_count,
&ctxt, &ctxt
nullptr
); );
line_contexts.insert({off, {version, table_count, ctxt}});
if(ret == DW_DLV_NO_ENTRY) { if(ret == DW_DLV_NO_ENTRY) {
fprintf(stderr, "dwarf_srclines_b error\n"); // TODO: Failing silently for now
return; return;
} }
line_contexts.insert({off, {version, table_count, ctxt}});
} }
if(table_count == 1) { if(table_count == 1) {
Dwarf_Line* linebuf = 0; Dwarf_Line* linebuf = 0;
Dwarf_Signed linecount = 0; Dwarf_Signed linecount = 0;
Dwarf_Addr prev_lineaddr = 0; Dwarf_Addr prev_lineaddr = 0;
VERIFY(
dwarf_srclines_from_linecontext(ctxt, &linebuf, wrap(
&linecount, nullptr); dwarf_srclines_from_linecontext,
ctxt,
&linebuf,
&linecount
) == DW_DLV_OK
);
Dwarf_Line prev_line = 0; Dwarf_Line prev_line = 0;
for(int i = 0; i < linecount; i++) { for(int i = 0; i < linecount; i++) {
Dwarf_Line line = linebuf[i]; Dwarf_Line line = linebuf[i];
Dwarf_Addr lineaddr = 0; Dwarf_Addr lineaddr = 0;
VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK);
dwarf_lineaddr(line, &lineaddr, nullptr);
if(pc == lineaddr) { if(pc == lineaddr) {
/* Print the last line entry containing current pc. */ // Find the last line entry containing current pc
Dwarf_Line last_pc_line = line; Dwarf_Line last_pc_line = line;
for(int j = i + 1; j < linecount; j++) { for(int j = i + 1; j < linecount; j++) {
Dwarf_Line j_line = linebuf[j]; Dwarf_Line j_line = linebuf[j];
dwarf_lineaddr(j_line, &lineaddr, nullptr); VERIFY(wrap(dwarf_lineaddr, j_line, &lineaddr) == DW_DLV_OK);
if(pc == lineaddr) { if(pc == lineaddr) {
last_pc_line = j_line; last_pc_line = j_line;
} }
@ -917,7 +957,7 @@ namespace libdwarf {
break; break;
} }
Dwarf_Bool is_lne; Dwarf_Bool is_lne;
dwarf_lineendsequence(line, &is_lne, nullptr); VERIFY(wrap(dwarf_lineendsequence, line, &is_lne) == DW_DLV_OK);
if(is_lne) { if(is_lne) {
prev_line = 0; prev_line = 0;
} else { } else {
@ -978,7 +1018,8 @@ namespace libdwarf {
Dwarf_Half header_cu_type; Dwarf_Half header_cu_type;
//fprintf(stderr, "-----------------\n"); //fprintf(stderr, "-----------------\n");
while(true) { while(true) {
int ret = dwarf_next_cu_header_d( int ret = wrap(
dwarf_next_cu_header_d,
dbg, dbg,
true, true,
nullptr, nullptr,
@ -990,8 +1031,7 @@ namespace libdwarf {
nullptr, nullptr,
nullptr, nullptr,
&next_cu_header, &next_cu_header,
&header_cu_type, &header_cu_type
nullptr
); );
if(ret == DW_DLV_NO_ENTRY) { if(ret == DW_DLV_NO_ENTRY) {
if(dump_dwarf) { if(dump_dwarf) {
@ -1000,7 +1040,7 @@ namespace libdwarf {
return; return;
} }
if(ret != DW_DLV_OK) { if(ret != DW_DLV_OK) {
fprintf(stderr, "Error\n"); PANIC("Unexpected return code from dwarf_next_cu_header_d");
return; return;
} }
walk_compilation_units(pc, frame); walk_compilation_units(pc, frame);
@ -1019,20 +1059,20 @@ namespace libdwarf {
// Check for .debug_aranges for fast lookup // Check for .debug_aranges for fast lookup
Dwarf_Arange *aranges; Dwarf_Arange *aranges;
Dwarf_Signed arange_count; Dwarf_Signed arange_count;
if(dwarf_get_aranges(dbg, &aranges, &arange_count, nullptr) == DW_DLV_OK) { if(wrap(dwarf_get_aranges, dbg, &aranges, &arange_count) == DW_DLV_OK) {
// Try to find pc in aranges // Try to find pc in aranges
Dwarf_Arange arange; Dwarf_Arange arange;
if(dwarf_get_arange(aranges, arange_count, pc, &arange, nullptr) == DW_DLV_OK) { if(wrap(dwarf_get_arange, aranges, arange_count, pc, &arange) == DW_DLV_OK) {
// Address in table, load CU die // Address in table, load CU die
Dwarf_Off cu_die_offset; Dwarf_Off cu_die_offset;
CPPTRACE_VERIFY(dwarf_get_cu_die_offset(arange, &cu_die_offset, nullptr) == DW_DLV_OK); VERIFY(wrap(dwarf_get_cu_die_offset, arange, &cu_die_offset) == DW_DLV_OK);
Dwarf_Die raw_die; Dwarf_Die raw_die;
// Setting is_info = true for now, assuming in .debug_info rather than .debug_types // Setting is_info = true for now, assuming in .debug_info rather than .debug_types
CPPTRACE_VERIFY(dwarf_offdie_b(dbg, cu_die_offset, true, &raw_die, nullptr) == DW_DLV_OK); VERIFY(wrap(dwarf_offdie_b, dbg, cu_die_offset, true, &raw_die) == DW_DLV_OK);
die_object cu_die(dbg, raw_die); die_object cu_die(dbg, raw_die);
Dwarf_Half offset_size = 0; Dwarf_Half offset_size = 0;
Dwarf_Half dwversion = 0; Dwarf_Half dwversion = 0;
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size); VERIFY(dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size) == DW_DLV_OK);
if(trace_dwarf) { if(trace_dwarf) {
fprintf(stderr, "Found CU in aranges\n"); fprintf(stderr, "Found CU in aranges\n");
cu_die.print(); cu_die.print();
@ -1079,12 +1119,15 @@ namespace libdwarf {
for(const auto& obj_entry : collate_frames(frames, trace)) { for(const auto& obj_entry : collate_frames(frames, trace)) {
const auto& obj_name = obj_entry.first; const auto& obj_name = obj_entry.first;
dwarf_resolver resolver(obj_name); dwarf_resolver resolver(obj_name);
// If there's no debug information it'll mark itself as not ok
if(resolver.ok) {
for(const auto& entry : obj_entry.second) { for(const auto& entry : obj_entry.second) {
const auto& dlframe = entry.first.get(); const auto& dlframe = entry.first.get();
auto& frame = entry.second.get(); auto& frame = entry.second.get();
frame = resolver.resolve_frame(dlframe); frame = resolver.resolve_frame(dlframe);
} }
} }
}
return trace; return trace;
} }
@ -1182,7 +1225,7 @@ namespace libdwarf {
std::string resolve_type(Dwarf_Debug dbg, const die_object& die, std::string build = ""); std::string resolve_type(Dwarf_Debug dbg, const die_object& die, std::string build = "");
std::string get_array_extents(Dwarf_Debug dbg, const die_object& die) { std::string get_array_extents(Dwarf_Debug dbg, const die_object& die) {
CPPTRACE_VERIFY(die.get_tag() == DW_TAG_array_type); VERIFY(die.get_tag() == DW_TAG_array_type);
std::string extents = ""; std::string extents = "";
walk_die_list(dbg, die.get_child(), [&extents](Dwarf_Debug dbg, const die_object& subrange) { walk_die_list(dbg, die.get_child(), [&extents](Dwarf_Debug dbg, const die_object& subrange) {
if(subrange.get_tag() == DW_TAG_subrange_type) { if(subrange.get_tag() == DW_TAG_subrange_type) {
@ -1216,7 +1259,7 @@ namespace libdwarf {
} }
std::string get_parameters(Dwarf_Debug dbg, const die_object& die) { std::string get_parameters(Dwarf_Debug dbg, const die_object& die) {
CPPTRACE_VERIFY(die.get_tag() == DW_TAG_subroutine_type); VERIFY(die.get_tag() == DW_TAG_subroutine_type);
std::vector<std::string> params; std::vector<std::string> params;
walk_die_list(dbg, die.get_child(), [&params](Dwarf_Debug dbg, const die_object& die) { walk_die_list(dbg, die.get_child(), [&params](Dwarf_Debug dbg, const die_object& die) {
if(die.get_tag() == DW_TAG_formal_parameter) { if(die.get_tag() == DW_TAG_formal_parameter) {

View File

@ -31,7 +31,7 @@ namespace detail {
} }
} }
CPPTRACE_VERIFY( VERIFY(
state.count < state.vec.size(), state.count < state.vec.size(),
"Somehow cpptrace::detail::unwind_callback is overflowing a vector" "Somehow cpptrace::detail::unwind_callback is overflowing a vector"
); );