forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild_id.cc
82 lines (66 loc) · 1.93 KB
/
build_id.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
* Copyright (C) 2019-present ScyllaDB
*/
#include "utils/assert.hh"
#include "build_id.hh"
#include <fmt/ostream.h>
#include <link.h>
#include <seastar/core/align.hh>
#include <sstream>
#include <cassert>
using namespace seastar;
static const Elf64_Nhdr* get_nt_build_id(dl_phdr_info* info) {
auto base = info->dlpi_addr;
const auto* h = info->dlpi_phdr;
auto num_headers = info->dlpi_phnum;
for (int i = 0; i != num_headers; ++i, ++h) {
if (h->p_type != PT_NOTE) {
continue;
}
auto* p = reinterpret_cast<const char*>(base + h->p_vaddr);
auto* e = p + h->p_memsz;
while (p != e) {
const auto* n = reinterpret_cast<const Elf64_Nhdr*>(p);
if (n->n_type == NT_GNU_BUILD_ID) {
return n;
}
p += sizeof(Elf64_Nhdr);
p += n->n_namesz;
p = align_up(p, 4);
p += n->n_descsz;
p = align_up(p, 4);
}
}
SCYLLA_ASSERT(0 && "no NT_GNU_BUILD_ID note");
}
static int callback(dl_phdr_info* info, size_t size, void* data) {
std::string& ret = *(std::string*)data;
std::ostringstream os;
// The first DSO is always the main program, which has an empty name.
SCYLLA_ASSERT(strlen(info->dlpi_name) == 0);
auto* n = get_nt_build_id(info);
auto* p = reinterpret_cast<const unsigned char*>(n);
p += sizeof(Elf64_Nhdr);
p += n->n_namesz;
p = align_up(p, 4);
auto* desc = p;
auto* desc_end = p + n->n_descsz;
while (desc < desc_end) {
fmt::print(os, "{:02x}", *desc++);
}
ret = os.str();
return 1;
}
static std::string really_get_build_id() {
std::string ret;
int r = dl_iterate_phdr(callback, &ret);
SCYLLA_ASSERT(r == 1);
return ret;
}
std::string get_build_id() {
static thread_local std::string cache;
if (cache.empty()) {
cache = really_get_build_id();
}
return cache;
}