Implement symbol table lookup for mach-o and fix mingw build
This commit is contained in:
parent
68c9d33e94
commit
08306c12a5
@ -219,7 +219,7 @@ namespace detail {
|
||||
|
||||
void mach_o::print_symbol_table_entry(
|
||||
const nlist_64& entry,
|
||||
const std::unique_ptr<char[]>& stringtab,
|
||||
const char* stringtab,
|
||||
std::size_t stringsize,
|
||||
std::size_t j
|
||||
) const {
|
||||
@ -248,7 +248,7 @@ namespace detail {
|
||||
stringtab == nullptr
|
||||
? "Stringtab error"
|
||||
: entry.n_un.n_strx < stringsize
|
||||
? stringtab.get() + entry.n_un.n_strx
|
||||
? stringtab + entry.n_un.n_strx
|
||||
: "String index out of bounds"
|
||||
);
|
||||
}
|
||||
@ -286,7 +286,7 @@ namespace detail {
|
||||
}
|
||||
print_symbol_table_entry(
|
||||
entry.unwrap_value(),
|
||||
std::move(stringtab).value_or(std::unique_ptr<char[]>(nullptr)),
|
||||
stringtab ? stringtab.unwrap_value().get() : nullptr,
|
||||
symtab.strsize,
|
||||
j
|
||||
);
|
||||
@ -364,10 +364,17 @@ namespace detail {
|
||||
return debug_map;
|
||||
}
|
||||
|
||||
Result<std::vector<mach_o::symbol_entry>, internal_error> mach_o::symbol_table() {
|
||||
Result<const std::vector<mach_o::symbol_entry>&, internal_error> mach_o::symbol_table() {
|
||||
if(symbols) {
|
||||
return symbols.unwrap();
|
||||
}
|
||||
if(tried_to_load_symbols) {
|
||||
return internal_error("previous symbol table load failed");
|
||||
}
|
||||
tried_to_load_symbols = true;
|
||||
std::vector<symbol_entry> symbol_table;
|
||||
// we have a bunch of symbols in our binary we need to pair up with symbols from various .o files
|
||||
// first collect symbols and the objects they come from
|
||||
std::vector<symbol_entry> symbols;
|
||||
auto symtab_info_res = get_symtab_info();
|
||||
if(!symtab_info_res) {
|
||||
return std::move(symtab_info_res).unwrap_error();
|
||||
@ -394,13 +401,42 @@ namespace detail {
|
||||
if(!str) {
|
||||
return std::move(str).unwrap_error();
|
||||
}
|
||||
symbols.push_back({
|
||||
symbol_table.push_back({
|
||||
entry.n_value,
|
||||
str.unwrap_value()
|
||||
});
|
||||
}
|
||||
}
|
||||
return symbols;
|
||||
std::sort(
|
||||
symbol_table.begin(),
|
||||
symbol_table.end(),
|
||||
[] (const symbol_entry& a, const symbol_entry& b) { return a.address < b.address; }
|
||||
);
|
||||
symbols = std::move(symbol_table);
|
||||
return symbols.unwrap();
|
||||
}
|
||||
|
||||
std::string mach_o::lookup_symbol(frame_ptr pc) {
|
||||
auto symtab_ = symbol_table();
|
||||
if(!symtab_) {
|
||||
return "";
|
||||
}
|
||||
const auto& symtab = symtab_.unwrap_value();;
|
||||
auto it = first_less_than_or_equal(
|
||||
symtab.begin(),
|
||||
symtab.end(),
|
||||
pc,
|
||||
[] (frame_ptr pc, const symbol_entry& entry) {
|
||||
return pc < entry.address;
|
||||
}
|
||||
);
|
||||
if(it == symtab.end()) {
|
||||
return "";
|
||||
}
|
||||
ASSERT(pc >= it->address);
|
||||
// TODO: We subtracted one from the address so name + diff won't show up in the objdump, decide if desirable
|
||||
// to have an easier offset to lookup
|
||||
return microfmt::format("{} + {}", it->name, pc - it->address);
|
||||
}
|
||||
|
||||
// produce information similar to dsymutil -dump-debug-map
|
||||
|
||||
@ -28,6 +28,23 @@ namespace detail {
|
||||
};
|
||||
|
||||
class mach_o {
|
||||
public:
|
||||
struct debug_map_entry {
|
||||
uint64_t source_address;
|
||||
uint64_t size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct symbol_entry {
|
||||
uint64_t address;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// map from object file to a vector of symbols to resolve
|
||||
using debug_map = std::unordered_map<std::string, std::vector<debug_map_entry>>;
|
||||
|
||||
private:
|
||||
|
||||
file_wrapper file;
|
||||
std::string object_path;
|
||||
std::uint32_t magic;
|
||||
@ -53,6 +70,9 @@ namespace detail {
|
||||
bool tried_to_load_symtab = false;
|
||||
optional<symtab_info_data> symtab_info;
|
||||
|
||||
bool tried_to_load_symbols = false;
|
||||
optional<std::vector<symbol_entry>> symbols;
|
||||
|
||||
mach_o(
|
||||
file_wrapper file,
|
||||
const std::string& object_path,
|
||||
@ -80,31 +100,19 @@ namespace detail {
|
||||
|
||||
void print_symbol_table_entry(
|
||||
const nlist_64& entry,
|
||||
const std::unique_ptr<char[]>& stringtab,
|
||||
const char* stringtab,
|
||||
std::size_t stringsize,
|
||||
std::size_t j
|
||||
) const;
|
||||
|
||||
void print_symbol_table();
|
||||
|
||||
struct debug_map_entry {
|
||||
uint64_t source_address;
|
||||
uint64_t size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct symbol_entry {
|
||||
uint64_t address;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// map from object file to a vector of symbols to resolve
|
||||
using debug_map = std::unordered_map<std::string, std::vector<debug_map_entry>>;
|
||||
|
||||
// produce information similar to dsymutil -dump-debug-map
|
||||
Result<debug_map, internal_error> get_debug_map();
|
||||
|
||||
Result<std::vector<symbol_entry>, internal_error> symbol_table();
|
||||
Result<const std::vector<symbol_entry>&, internal_error> symbol_table();
|
||||
|
||||
std::string lookup_symbol(frame_ptr pc);
|
||||
|
||||
// produce information similar to dsymutil -dump-debug-map
|
||||
static void print_debug_map(const debug_map& debug_map);
|
||||
|
||||
@ -50,7 +50,7 @@ namespace libdwarf {
|
||||
if(!obj) {
|
||||
return this->symbols.unwrap();
|
||||
}
|
||||
auto symbol_table = obj.unwrap_value().symbol_table();
|
||||
const auto& symbol_table = obj.unwrap_value().symbol_table();
|
||||
if(!symbol_table) {
|
||||
return this->symbols.unwrap();
|
||||
}
|
||||
@ -100,7 +100,7 @@ namespace libdwarf {
|
||||
uint64_t size;
|
||||
std::string name;
|
||||
nullable<uint64_t> target_address; // T(-1) is used as a sentinel
|
||||
std::size_t object_index;
|
||||
std::size_t object_index; // index into target_objects
|
||||
};
|
||||
|
||||
class debug_map_resolver : public symbol_resolver {
|
||||
@ -137,6 +137,7 @@ namespace libdwarf {
|
||||
}
|
||||
}
|
||||
// sort for binary lookup later
|
||||
// TODO: Redundant?
|
||||
std::sort(
|
||||
symbols.begin(),
|
||||
symbols.end(),
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "binary/elf.hpp"
|
||||
#include "binary/mach-o.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
@ -93,9 +94,12 @@ namespace libdwarf {
|
||||
for(const auto& group : collate_frames(frames, trace)) {
|
||||
try {
|
||||
const auto& object_name = group.first;
|
||||
// TODO PERF: Potentially a duplicate elf open and parse with module base stuff
|
||||
// TODO: What about mach-o
|
||||
// TODO PERF: Potentially a duplicate open and parse with module base stuff (and debug map resolver)
|
||||
#if IS_LINUX
|
||||
auto object = elf::open_elf(object_name);
|
||||
#elif IS_APPLE
|
||||
auto object = mach_o::open_mach_o(object_name);
|
||||
#endif
|
||||
auto resolver = get_resolver(object_name);
|
||||
for(const auto& entry : group.second) {
|
||||
const auto& dlframe = entry.first.get();
|
||||
@ -110,9 +114,11 @@ namespace libdwarf {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#if IS_LINUX || IS_APPLE
|
||||
if(frame.frame.symbol.empty() && object.has_value()) {
|
||||
frame.frame.symbol = object.unwrap_value().lookup_symbol(dlframe.object_address);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} catch(...) { // NOSONAR
|
||||
if(!should_absorb_trace_exceptions()) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user