Skip to content

Commit 270de57

Browse files
1 parent d6d66de commit 270de57

26 files changed

+743
-105
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ scratch
99
tmp/
1010
bazel-*/
1111
cmake-build-*/
12+
13+
test/jank/data

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ target_sources(
127127
src/demangle/demangle_with_cxxabi.cpp
128128
src/demangle/demangle_with_nothing.cpp
129129
src/demangle/demangle_with_winapi.cpp
130+
src/jit/jit_objects.cpp
130131
src/snippets/snippet.cpp
131132
src/symbols/dwarf/debug_map_resolver.cpp
132133
src/symbols/dwarf/dwarf_options.cpp
@@ -144,6 +145,8 @@ target_sources(
144145
src/unwind/unwind_with_nothing.cpp
145146
src/unwind/unwind_with_unwind.cpp
146147
src/unwind/unwind_with_winapi.cpp
148+
src/utils/io/file.cpp
149+
src/utils/io/memory_file_view.cpp
147150
src/utils/error.cpp
148151
src/utils/microfmt.cpp
149152
src/utils/string_view.cpp

include/cpptrace/basic.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ namespace cpptrace {
236236
CPPTRACE_EXPORT void get_safe_object_frame(frame_ptr address, safe_object_frame* out);
237237
CPPTRACE_EXPORT bool can_signal_safe_unwind();
238238
CPPTRACE_EXPORT bool can_get_safe_object_frame();
239+
240+
// JIT API
241+
CPPTRACE_EXPORT void register_jit_object(const char*, std::size_t);
242+
CPPTRACE_EXPORT void unregister_jit_object(const char*);
243+
CPPTRACE_EXPORT void clear_all_jit_objects();
239244
}
240245

241246
#ifdef _MSC_VER

include/cpptrace/gdb_jit.hpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#ifndef CPPTRACE_GDB_JIT_HPP
2+
#define CPPTRACE_GDB_JIT_HPP
3+
4+
#include <cpptrace/basic.hpp>
5+
6+
#include <cstdint>
7+
8+
namespace cpptrace {
9+
namespace detail {
10+
// https://sourceware.org/gdb/current/onlinedocs/gdb.html/JIT-Interface.html
11+
extern "C" {
12+
typedef enum
13+
{
14+
JIT_NOACTION = 0,
15+
JIT_REGISTER_FN,
16+
JIT_UNREGISTER_FN
17+
} jit_actions_t;
18+
19+
struct jit_code_entry
20+
{
21+
struct jit_code_entry *next_entry;
22+
struct jit_code_entry *prev_entry;
23+
const char *symfile_addr;
24+
uint64_t symfile_size;
25+
};
26+
27+
struct jit_descriptor
28+
{
29+
uint32_t version;
30+
/* This type should be jit_actions_t, but we use uint32_t
31+
to be explicit about the bitwidth. */
32+
uint32_t action_flag;
33+
struct jit_code_entry *relevant_entry;
34+
struct jit_code_entry *first_entry;
35+
};
36+
37+
extern struct jit_descriptor __jit_debug_descriptor;
38+
}
39+
}
40+
41+
inline void register_jit_objects_from_gdb_jit_interface() {
42+
clear_all_jit_objects();
43+
detail::jit_code_entry* entry = detail::__jit_debug_descriptor.first_entry;
44+
while(entry) {
45+
register_jit_object(entry->symfile_addr, entry->symfile_size);
46+
entry = entry->next_entry;
47+
}
48+
}
49+
}
50+
51+
#endif

src/binary/elf.cpp

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#include "binary/elf.hpp"
2+
3+
#include "utils/error.hpp"
4+
#include "utils/io/base_file.hpp"
5+
#include "utils/io/memory_file_view.hpp"
26
#include "utils/optional.hpp"
7+
#include "utils/io/file.hpp"
8+
#include "utils/string_view.hpp"
39

410
#if IS_LINUX
511

@@ -16,43 +22,51 @@
1622
namespace cpptrace {
1723
namespace detail {
1824
elf::elf(
19-
file_wrapper file,
20-
cstring_view object_path,
25+
std::unique_ptr<base_file> file,
2126
bool is_little_endian,
2227
bool is_64
23-
) : file(std::move(file)), object_path(object_path), is_little_endian(is_little_endian), is_64(is_64) {}
28+
) : file(std::move(file)), is_little_endian(is_little_endian), is_64(is_64) {}
2429

25-
Result<elf, internal_error> elf::open_elf(cstring_view object_path) {
26-
auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
27-
if(file == nullptr) {
28-
return internal_error("Unable to read object file {}", object_path);
29-
}
30+
Result<elf, internal_error> elf::open(std::unique_ptr<base_file> file) {
3031
// Initial checks/metadata
31-
auto magic = load_bytes<std::array<char, 4>>(file, 0);
32+
auto magic = file->read<std::array<char, 4>>(0);
3233
if(magic.is_error()) {
3334
return std::move(magic).unwrap_error();
3435
}
3536
if(magic.unwrap_value() != (std::array<char, 4>{0x7F, 'E', 'L', 'F'})) {
36-
return internal_error("File is not ELF {}", object_path);
37+
return internal_error("File is not ELF {}", file->path());
3738
}
38-
auto ei_class = load_bytes<std::uint8_t>(file, 4);
39+
auto ei_class = file->read<std::uint8_t>(4);
3940
if(ei_class.is_error()) {
4041
return std::move(ei_class).unwrap_error();
4142
}
4243
bool is_64 = ei_class.unwrap_value() == 2;
43-
auto ei_data = load_bytes<std::uint8_t>(file, 5);
44+
auto ei_data = file->read<std::uint8_t>(5);
4445
if(ei_data.is_error()) {
4546
return std::move(ei_data).unwrap_error();
4647
}
4748
bool is_little_endian = ei_data.unwrap_value() == 1;
48-
auto ei_version = load_bytes<std::uint8_t>(file, 6);
49+
auto ei_version = file->read<std::uint8_t>(6);
4950
if(ei_version.is_error()) {
5051
return std::move(ei_version).unwrap_error();
5152
}
5253
if(ei_version.unwrap_value() != 1) {
53-
return internal_error("Unexpected ELF version {}", object_path);
54+
return internal_error("Unexpected ELF version {}", file->path());
5455
}
55-
return elf(std::move(file), object_path, is_little_endian, is_64);
56+
return elf(std::move(file), is_little_endian, is_64);
57+
}
58+
59+
Result<elf, internal_error> elf::open(cstring_view object_path) {
60+
auto file_res = file::open(object_path);
61+
if(!file_res) {
62+
return internal_error("Unable to read object file {}", object_path);
63+
}
64+
auto& file = file_res.unwrap_value();
65+
return open(make_unique(std::move(file)));
66+
}
67+
68+
Result<elf, internal_error> elf::open(cbspan object) {
69+
return open(make_unique<memory_file_view>(object));
5670
}
5771

5872
Result<std::uintptr_t, internal_error> elf::get_module_image_base() {
@@ -77,7 +91,7 @@ namespace detail {
7791
// Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
7892
// It should occur at the beginning but may as well loop just in case
7993
for(unsigned i = 0; i < header_info.e_phnum; i++) {
80-
auto loaded_ph = load_bytes<PHeader>(file, header_info.e_phoff + header_info.e_phentsize * i);
94+
auto loaded_ph = file->read<PHeader>(header_info.e_phoff + header_info.e_phentsize * i);
8195
if(loaded_ph.is_error()) {
8296
return std::move(loaded_ph).unwrap_error();
8397
}
@@ -135,6 +149,31 @@ namespace detail {
135149
return nullopt;
136150
}
137151

152+
Result<std::vector<elf::pc_range>, internal_error> elf::get_pc_ranges() {
153+
std::vector<pc_range> vec;
154+
auto header_info_ = get_header_info();
155+
if(header_info_.is_error()) {
156+
return header_info_.unwrap_error();
157+
}
158+
auto& header_info = header_info_.unwrap_value();
159+
auto strtab_ = get_strtab(header_info.e_shstrndx);
160+
if(strtab_.is_error()) {
161+
return strtab_.unwrap_error();
162+
}
163+
auto& strtab = strtab_.unwrap_value();
164+
auto sections_res = get_sections();
165+
if(!sections_res) {
166+
return sections_res.unwrap_error();
167+
}
168+
const auto& sections = sections_res.unwrap_value();
169+
for(const auto& section : sections) {
170+
if(string_view(strtab.data() + section.sh_name) == ".text") {
171+
vec.push_back(pc_range{section.sh_addr, section.sh_addr + section.sh_size});
172+
}
173+
}
174+
return vec;
175+
}
176+
138177
Result<optional<std::vector<elf::symbol_entry>>, internal_error> elf::get_symtab_entries() {
139178
return resolve_symtab_entries(get_symtab());
140179
}
@@ -187,7 +226,7 @@ namespace detail {
187226
return std::ref(header.unwrap());
188227
}
189228
if(tried_to_load_header) {
190-
return internal_error("previous header load failed " + object_path);
229+
return internal_error("previous header load failed {}", file->path());
191230
}
192231
tried_to_load_header = true;
193232
if(is_64) {
@@ -201,13 +240,13 @@ namespace detail {
201240
Result<const elf::header_info&, internal_error> elf::get_header_info_impl() {
202241
static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument");
203242
using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type;
204-
auto loaded_header = load_bytes<Header>(file, 0);
243+
auto loaded_header = file->read<Header>(0);
205244
if(loaded_header.is_error()) {
206245
return std::move(loaded_header).unwrap_error();
207246
}
208247
const Header& file_header = loaded_header.unwrap_value();
209248
if(file_header.e_ehsize != sizeof(Header)) {
210-
return internal_error("ELF file header size mismatch" + object_path);
249+
return internal_error("ELF file header size mismatch {}", file->path());
211250
}
212251
header_info info;
213252
info.e_phoff = byteswap_if_needed(file_header.e_phoff);
@@ -216,6 +255,7 @@ namespace detail {
216255
info.e_shoff = byteswap_if_needed(file_header.e_shoff);
217256
info.e_shnum = byteswap_if_needed(file_header.e_shnum);
218257
info.e_shentsize = byteswap_if_needed(file_header.e_shentsize);
258+
info.e_shstrndx = byteswap_if_needed(file_header.e_shstrndx);
219259
header = info;
220260
return header.unwrap();
221261
}
@@ -225,7 +265,7 @@ namespace detail {
225265
return sections;
226266
}
227267
if(tried_to_load_sections) {
228-
return internal_error("previous sections load failed " + object_path);
268+
return internal_error("previous sections load failed {}", file->path());
229269
}
230270
tried_to_load_sections = true;
231271
if(is_64) {
@@ -245,12 +285,13 @@ namespace detail {
245285
}
246286
const auto& header_info = header.unwrap_value();
247287
for(unsigned i = 0; i < header_info.e_shnum; i++) {
248-
auto loaded_sh = load_bytes<SHeader>(file, header_info.e_shoff + header_info.e_shentsize * i);
288+
auto loaded_sh = file->read<SHeader>(header_info.e_shoff + header_info.e_shentsize * i);
249289
if(loaded_sh.is_error()) {
250290
return std::move(loaded_sh).unwrap_error();
251291
}
252292
const SHeader& section_header = loaded_sh.unwrap_value();
253293
section_info info;
294+
info.sh_name = byteswap_if_needed(section_header.sh_name);
254295
info.sh_type = byteswap_if_needed(section_header.sh_type);
255296
info.sh_addr = byteswap_if_needed(section_header.sh_addr);
256297
info.sh_offset = byteswap_if_needed(section_header.sh_offset);
@@ -273,7 +314,7 @@ namespace detail {
273314
return entry.data;
274315
}
275316
if(entry.tried_to_load_strtab) {
276-
return internal_error("previous strtab load failed {}", object_path);
317+
return internal_error("previous strtab load failed {}", file->path());
277318
}
278319
}
279320
entry.tried_to_load_strtab = true;
@@ -287,14 +328,12 @@ namespace detail {
287328
}
288329
const auto& section = sections[index];
289330
if(section.sh_type != SHT_STRTAB) {
290-
return internal_error("requested strtab section not a strtab (requested {} of {})", index, object_path);
331+
return internal_error("requested strtab section not a strtab (requested {} of {})", index, file->path());
291332
}
292333
entry.data.resize(section.sh_size + 1);
293-
if(std::fseek(file, section.sh_offset, SEEK_SET) != 0) {
294-
return internal_error("fseek error while loading elf string table");
295-
}
296-
if(std::fread(entry.data.data(), sizeof(char), section.sh_size, file) != section.sh_size) {
297-
return internal_error("fread error while loading elf string table");
334+
auto read_res = file->read_bytes(span<char>{entry.data.data(), section.sh_size}, section.sh_offset);
335+
if(!read_res) {
336+
return read_res.unwrap_error();
298337
}
299338
entry.data[section.sh_size] = 0; // just out of an abundance of caution
300339
entry.did_load_strtab = true;
@@ -306,7 +345,7 @@ namespace detail {
306345
return symtab;
307346
}
308347
if(tried_to_load_symtab) {
309-
return internal_error("previous symtab load failed {}", object_path);
348+
return internal_error("previous symtab load failed {}", file->path());
310349
}
311350
tried_to_load_symtab = true;
312351
if(is_64) {
@@ -335,7 +374,7 @@ namespace detail {
335374
return dynamic_symtab;
336375
}
337376
if(tried_to_load_dynamic_symtab) {
338-
return internal_error("previous dynamic symtab load failed {}", object_path);
377+
return internal_error("previous dynamic symtab load failed {}", file->path());
339378
}
340379
tried_to_load_dynamic_symtab = true;
341380
if(is_64) {
@@ -375,17 +414,15 @@ namespace detail {
375414
for(const auto& section : sections) {
376415
if(section.sh_type == (dynamic ? SHT_DYNSYM : SHT_SYMTAB)) {
377416
if(section.sh_entsize != sizeof(SymEntry)) {
378-
return internal_error("elf seems corrupted, sym entry mismatch {}", object_path);
417+
return internal_error("elf seems corrupted, sym entry mismatch {}", file->path());
379418
}
380419
if(section.sh_size % section.sh_entsize != 0) {
381-
return internal_error("elf seems corrupted, sym entry vs section size mismatch {}", object_path);
420+
return internal_error("elf seems corrupted, sym entry vs section size mismatch {}", file->path());
382421
}
383422
std::vector<SymEntry> buffer(section.sh_size / section.sh_entsize);
384-
if(std::fseek(file, section.sh_offset, SEEK_SET) != 0) {
385-
return internal_error("fseek error while loading elf symbol table");
386-
}
387-
if(std::fread(buffer.data(), section.sh_entsize, buffer.size(), file) != buffer.size()) {
388-
return internal_error("fread error while loading elf symbol table");
423+
auto res = file->read_span(make_span(buffer.begin(), buffer.end()), section.sh_offset);
424+
if(!res) {
425+
return res.unwrap_error();
389426
}
390427
symbol_table = symtab_info{};
391428
symbol_table.unwrap().entries.reserve(buffer.size());
@@ -414,8 +451,11 @@ namespace detail {
414451
}
415452

416453
Result<maybe_owned<elf>, internal_error> open_elf_cached(const std::string& object_path) {
454+
if(object_path.empty()) {
455+
return internal_error{"empty object_path"};
456+
}
417457
if(get_cache_mode() == cache_mode::prioritize_memory) {
418-
return elf::open_elf(object_path)
458+
return elf::open(object_path)
419459
.transform([](elf&& obj) { return maybe_owned<elf>{detail::make_unique<elf>(std::move(obj))}; });
420460
} else {
421461
std::mutex m;
@@ -424,7 +464,7 @@ namespace detail {
424464
static std::unordered_map<std::string, Result<elf, internal_error>> cache;
425465
auto it = cache.find(object_path);
426466
if(it == cache.end()) {
427-
auto res = cache.emplace(object_path, elf::open_elf(object_path));
467+
auto res = cache.emplace(object_path, elf::open(object_path));
428468
VERIFY(res.second);
429469
it = res.first;
430470
}

0 commit comments

Comments
 (0)