Skip to content

Commit 810b74e

Browse files
committed
Refactor symbols_with_libdwarf indo separate files
1 parent 5171e87 commit 810b74e

File tree

6 files changed

+1219
-1136
lines changed

6 files changed

+1219
-1136
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ target_sources(
218218
src/demangle/demangle_with_nothing.cpp
219219
src/demangle/demangle_with_winapi.cpp
220220
src/snippets/snippet.cpp
221+
src/symbols/dwarf/debug_map_resolver.cpp
222+
src/symbols/dwarf/dwarf_resolver.cpp
221223
src/symbols/symbols_core.cpp
222224
src/symbols/symbols_with_addr2line.cpp
223225
src/symbols/symbols_with_dbghelp.cpp
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
2+
3+
#include "resolver.hpp"
4+
5+
#include <cpptrace/cpptrace.hpp>
6+
#include "../symbols.hpp"
7+
#include "../../utils/common.hpp"
8+
#include "../../utils/error.hpp"
9+
#include "../../binary/object.hpp"
10+
#include "../../binary/mach-o.hpp"
11+
#include "../../utils/utils.hpp"
12+
13+
#include <algorithm>
14+
#include <cstdint>
15+
#include <cstdio>
16+
#include <memory>
17+
#include <string>
18+
#include <unordered_map>
19+
#include <vector>
20+
21+
namespace cpptrace {
22+
namespace detail {
23+
namespace libdwarf {
24+
#if IS_APPLE
25+
struct target_object {
26+
std::string object_path;
27+
bool path_ok = true;
28+
optional<std::unordered_map<std::string, uint64_t>> symbols;
29+
std::unique_ptr<symbol_resolver> resolver;
30+
31+
target_object(std::string object_path) : object_path(std::move(object_path)) {}
32+
33+
std::unique_ptr<symbol_resolver>& get_resolver() {
34+
if(!resolver) {
35+
// this seems silly but it's an attempt to not repeatedly try to initialize new dwarf_resolvers if
36+
// exceptions are thrown, e.g. if the path doesn't exist
37+
resolver = std::unique_ptr<null_resolver>(new null_resolver);
38+
resolver = make_dwarf_resolver(object_path);
39+
}
40+
return resolver;
41+
}
42+
43+
std::unordered_map<std::string, uint64_t>& get_symbols() {
44+
if(!symbols) {
45+
// this is an attempt to not repeatedly try to reprocess mach-o files if exceptions are thrown, e.g. if
46+
// the path doesn't exist
47+
std::unordered_map<std::string, uint64_t> symbols;
48+
this->symbols = symbols;
49+
auto obj = mach_o::open_mach_o(object_path);
50+
if(!obj) {
51+
return this->symbols.unwrap();
52+
}
53+
auto symbol_table = obj.unwrap_value().symbol_table();
54+
if(!symbol_table) {
55+
return this->symbols.unwrap();
56+
}
57+
for(const auto& symbol : symbol_table.unwrap_value()) {
58+
symbols[symbol.name] = symbol.address;
59+
}
60+
this->symbols = std::move(symbols);
61+
}
62+
return symbols.unwrap();
63+
}
64+
65+
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
66+
frame_with_inlines resolve_frame(
67+
const object_frame& frame_info,
68+
const std::string& symbol_name,
69+
std::size_t offset
70+
) {
71+
const auto& symbol_table = get_symbols();
72+
auto it = symbol_table.find(symbol_name);
73+
if(it != symbol_table.end()) {
74+
auto frame = frame_info;
75+
frame.object_address = it->second + offset;
76+
return get_resolver()->resolve_frame(frame);
77+
} else {
78+
return {
79+
{
80+
frame_info.raw_address,
81+
frame_info.object_address,
82+
nullable<std::uint32_t>::null(),
83+
nullable<std::uint32_t>::null(),
84+
frame_info.object_path,
85+
symbol_name,
86+
false
87+
},
88+
{}
89+
};
90+
}
91+
}
92+
};
93+
94+
struct debug_map_symbol_info {
95+
uint64_t source_address;
96+
uint64_t size;
97+
std::string name;
98+
nullable<uint64_t> target_address; // T(-1) is used as a sentinel
99+
std::size_t object_index;
100+
};
101+
102+
class debug_map_resolver : public symbol_resolver {
103+
std::vector<target_object> target_objects;
104+
std::vector<debug_map_symbol_info> symbols;
105+
public:
106+
debug_map_resolver(const std::string& source_object_path) {
107+
// load mach-o
108+
// TODO: Cache somehow?
109+
auto obj = mach_o::open_mach_o(source_object_path);
110+
if(!obj) {
111+
return;
112+
}
113+
mach_o& source_mach = obj.unwrap_value();
114+
auto source_debug_map = source_mach.get_debug_map();
115+
if(!source_debug_map) {
116+
return;
117+
}
118+
// get symbol entries from debug map, as well as the various object files used to make this binary
119+
for(auto& entry : source_debug_map.unwrap_value()) {
120+
// object it came from
121+
target_objects.push_back({entry.first});
122+
// push the symbols
123+
auto& map_entry_symbols = entry.second;
124+
symbols.reserve(symbols.size() + map_entry_symbols.size());
125+
for(auto& symbol : map_entry_symbols) {
126+
symbols.push_back({
127+
symbol.source_address,
128+
symbol.size,
129+
std::move(symbol.name),
130+
nullable<uint64_t>::null(),
131+
target_objects.size() - 1
132+
});
133+
}
134+
}
135+
// sort for binary lookup later
136+
std::sort(
137+
symbols.begin(),
138+
symbols.end(),
139+
[] (
140+
const debug_map_symbol_info& a,
141+
const debug_map_symbol_info& b
142+
) {
143+
return a.source_address < b.source_address;
144+
}
145+
);
146+
}
147+
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
148+
frame_with_inlines resolve_frame(const object_frame& frame_info) override {
149+
// resolve object frame:
150+
// find the symbol in this executable corresponding to the object address
151+
// resolve the symbol in the object it came from, based on the symbol name
152+
auto closest_symbol_it = first_less_than_or_equal(
153+
symbols.begin(),
154+
symbols.end(),
155+
frame_info.object_address,
156+
[] (
157+
Dwarf_Addr pc,
158+
const debug_map_symbol_info& symbol
159+
) {
160+
return pc < symbol.source_address;
161+
}
162+
);
163+
if(closest_symbol_it != symbols.end()) {
164+
if(frame_info.object_address <= closest_symbol_it->source_address + closest_symbol_it->size) {
165+
return target_objects[closest_symbol_it->object_index].resolve_frame(
166+
{
167+
frame_info.raw_address,
168+
// the resolver doesn't care about the object address here, only the offset from the start
169+
// of the symbol and it'll lookup the symbol's base-address
170+
0,
171+
frame_info.object_path
172+
},
173+
closest_symbol_it->name,
174+
frame_info.object_address - closest_symbol_it->source_address
175+
);
176+
}
177+
}
178+
// There was either no closest symbol or the closest symbol didn't end up containing the address we're
179+
// looking for, so just return a blank frame
180+
return {
181+
{
182+
frame_info.raw_address,
183+
frame_info.object_address,
184+
nullable<std::uint32_t>::null(),
185+
nullable<std::uint32_t>::null(),
186+
frame_info.object_path,
187+
"",
188+
false
189+
},
190+
{}
191+
};
192+
};
193+
};
194+
195+
std::unique_ptr<symbol_resolver> make_debug_map_resolver(const std::string& object_path) {
196+
return std::unique_ptr<debug_map_resolver>(new debug_map_resolver(object_path));
197+
}
198+
#endif
199+
}
200+
}
201+
}
202+
203+
#endif

0 commit comments

Comments
 (0)