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(
|
void mach_o::print_symbol_table_entry(
|
||||||
const nlist_64& entry,
|
const nlist_64& entry,
|
||||||
const std::unique_ptr<char[]>& stringtab,
|
const char* stringtab,
|
||||||
std::size_t stringsize,
|
std::size_t stringsize,
|
||||||
std::size_t j
|
std::size_t j
|
||||||
) const {
|
) const {
|
||||||
@ -248,7 +248,7 @@ namespace detail {
|
|||||||
stringtab == nullptr
|
stringtab == nullptr
|
||||||
? "Stringtab error"
|
? "Stringtab error"
|
||||||
: entry.n_un.n_strx < stringsize
|
: entry.n_un.n_strx < stringsize
|
||||||
? stringtab.get() + entry.n_un.n_strx
|
? stringtab + entry.n_un.n_strx
|
||||||
: "String index out of bounds"
|
: "String index out of bounds"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
print_symbol_table_entry(
|
print_symbol_table_entry(
|
||||||
entry.unwrap_value(),
|
entry.unwrap_value(),
|
||||||
std::move(stringtab).value_or(std::unique_ptr<char[]>(nullptr)),
|
stringtab ? stringtab.unwrap_value().get() : nullptr,
|
||||||
symtab.strsize,
|
symtab.strsize,
|
||||||
j
|
j
|
||||||
);
|
);
|
||||||
@ -364,10 +364,17 @@ namespace detail {
|
|||||||
return debug_map;
|
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
|
// 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
|
// first collect symbols and the objects they come from
|
||||||
std::vector<symbol_entry> symbols;
|
|
||||||
auto symtab_info_res = get_symtab_info();
|
auto symtab_info_res = get_symtab_info();
|
||||||
if(!symtab_info_res) {
|
if(!symtab_info_res) {
|
||||||
return std::move(symtab_info_res).unwrap_error();
|
return std::move(symtab_info_res).unwrap_error();
|
||||||
@ -394,13 +401,42 @@ namespace detail {
|
|||||||
if(!str) {
|
if(!str) {
|
||||||
return std::move(str).unwrap_error();
|
return std::move(str).unwrap_error();
|
||||||
}
|
}
|
||||||
symbols.push_back({
|
symbol_table.push_back({
|
||||||
entry.n_value,
|
entry.n_value,
|
||||||
str.unwrap_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
|
// produce information similar to dsymutil -dump-debug-map
|
||||||
|
|||||||
@ -28,6 +28,23 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class mach_o {
|
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;
|
file_wrapper file;
|
||||||
std::string object_path;
|
std::string object_path;
|
||||||
std::uint32_t magic;
|
std::uint32_t magic;
|
||||||
@ -53,6 +70,9 @@ namespace detail {
|
|||||||
bool tried_to_load_symtab = false;
|
bool tried_to_load_symtab = false;
|
||||||
optional<symtab_info_data> symtab_info;
|
optional<symtab_info_data> symtab_info;
|
||||||
|
|
||||||
|
bool tried_to_load_symbols = false;
|
||||||
|
optional<std::vector<symbol_entry>> symbols;
|
||||||
|
|
||||||
mach_o(
|
mach_o(
|
||||||
file_wrapper file,
|
file_wrapper file,
|
||||||
const std::string& object_path,
|
const std::string& object_path,
|
||||||
@ -80,31 +100,19 @@ namespace detail {
|
|||||||
|
|
||||||
void print_symbol_table_entry(
|
void print_symbol_table_entry(
|
||||||
const nlist_64& entry,
|
const nlist_64& entry,
|
||||||
const std::unique_ptr<char[]>& stringtab,
|
const char* stringtab,
|
||||||
std::size_t stringsize,
|
std::size_t stringsize,
|
||||||
std::size_t j
|
std::size_t j
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
void print_symbol_table();
|
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
|
// produce information similar to dsymutil -dump-debug-map
|
||||||
Result<debug_map, internal_error> get_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
|
// produce information similar to dsymutil -dump-debug-map
|
||||||
static void print_debug_map(const debug_map& debug_map);
|
static void print_debug_map(const debug_map& debug_map);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ namespace libdwarf {
|
|||||||
if(!obj) {
|
if(!obj) {
|
||||||
return this->symbols.unwrap();
|
return this->symbols.unwrap();
|
||||||
}
|
}
|
||||||
auto symbol_table = obj.unwrap_value().symbol_table();
|
const auto& symbol_table = obj.unwrap_value().symbol_table();
|
||||||
if(!symbol_table) {
|
if(!symbol_table) {
|
||||||
return this->symbols.unwrap();
|
return this->symbols.unwrap();
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ namespace libdwarf {
|
|||||||
uint64_t size;
|
uint64_t size;
|
||||||
std::string name;
|
std::string name;
|
||||||
nullable<uint64_t> target_address; // T(-1) is used as a sentinel
|
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 {
|
class debug_map_resolver : public symbol_resolver {
|
||||||
@ -137,6 +137,7 @@ namespace libdwarf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sort for binary lookup later
|
// sort for binary lookup later
|
||||||
|
// TODO: Redundant?
|
||||||
std::sort(
|
std::sort(
|
||||||
symbols.begin(),
|
symbols.begin(),
|
||||||
symbols.end(),
|
symbols.end(),
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
#include "binary/elf.hpp"
|
#include "binary/elf.hpp"
|
||||||
|
#include "binary/mach-o.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -93,9 +94,12 @@ namespace libdwarf {
|
|||||||
for(const auto& group : collate_frames(frames, trace)) {
|
for(const auto& group : collate_frames(frames, trace)) {
|
||||||
try {
|
try {
|
||||||
const auto& object_name = group.first;
|
const auto& object_name = group.first;
|
||||||
// TODO PERF: Potentially a duplicate elf open and parse with module base stuff
|
// TODO PERF: Potentially a duplicate open and parse with module base stuff (and debug map resolver)
|
||||||
// TODO: What about mach-o
|
#if IS_LINUX
|
||||||
auto object = elf::open_elf(object_name);
|
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);
|
auto resolver = get_resolver(object_name);
|
||||||
for(const auto& entry : group.second) {
|
for(const auto& entry : group.second) {
|
||||||
const auto& dlframe = entry.first.get();
|
const auto& dlframe = entry.first.get();
|
||||||
@ -110,9 +114,11 @@ namespace libdwarf {
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if IS_LINUX || IS_APPLE
|
||||||
if(frame.frame.symbol.empty() && object.has_value()) {
|
if(frame.frame.symbol.empty() && object.has_value()) {
|
||||||
frame.frame.symbol = object.unwrap_value().lookup_symbol(dlframe.object_address);
|
frame.frame.symbol = object.unwrap_value().lookup_symbol(dlframe.object_address);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} catch(...) { // NOSONAR
|
} catch(...) { // NOSONAR
|
||||||
if(!should_absorb_trace_exceptions()) {
|
if(!should_absorb_trace_exceptions()) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user