Skip to content

Commit 27ec904

Browse files
Break up large linux impl
1 parent 73898d0 commit 27ec904

File tree

12 files changed

+480
-369
lines changed

12 files changed

+480
-369
lines changed

libcxx/include/__stacktrace/base.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ struct _LIBCPP_HIDE_FROM_ABI alloc final {
6969

7070
template <typename _A2>
7171
bool operator==(_A2 const& __rhs) const {
72-
return &__rhs == this;
72+
return std::addressof(__rhs) == this;
7373
}
7474
};
7575

libcxx/include/__stacktrace/basic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class _LIBCPP_EXPORTED_FROM_ABI basic_stacktrace {
5555

5656
[[no_unique_address]] _Allocator __alloc_;
5757

58-
using __entry_vec = vector<stacktrace_entry, _Allocator>;
58+
using __entry_vec _LIBCPP_NODEBUG = vector<stacktrace_entry, _Allocator>;
5959
__entry_vec __entries_;
6060

6161
public:

libcxx/include/__stacktrace/hash.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <__config>
1414
#include <__functional/hash.h>
15+
#include <cstddef>
1516
#include <cstdint>
1617

1718
#include <__stacktrace/base.h>

libcxx/include/module.modulemap.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,9 @@ module std [system] {
20212021
// TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108
20222022
export std.cstddef.byte
20232023
export std.cstddef.size_t
2024+
export std.format.escaped_output_table
20242025
export std.format.formatter
2026+
export std.format.width_estimation_table
20252027
export std.functional.function
20262028
export std.functional.hash
20272029
export std.iterator.iterator

libcxx/src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ set(LIBCXX_SOURCES
4141
ryu/d2s.cpp
4242
ryu/f2s.cpp
4343
stacktrace/builder.cpp
44+
stacktrace/linux/elf.cpp
45+
stacktrace/linux/images.cpp
4446
stacktrace/linux/impl.cpp
4547
stacktrace/macos/impl.cpp
4648
stacktrace/to_string.cpp

libcxx/src/stacktrace/linux/elf.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#if defined(__linux__)
10+
11+
# include "stacktrace/linux/elf.h"
12+
13+
# include <__stacktrace/base.h>
14+
# include <cassert>
15+
# include <cstddef>
16+
# include <cstdlib>
17+
# include <functional>
18+
# include <unistd.h>
19+
20+
_LIBCPP_BEGIN_NAMESPACE_STD
21+
namespace __stacktrace::elf {
22+
23+
ELF::ELF(std::byte const* image) {
24+
auto* p = (uint8_t const*)image;
25+
// Bytes 0..3: magic bytes: 0x7F, 'E', 'L', 'F'
26+
if (*p++ == 0x7f && *p++ == 0x45 && *p++ == 0x4c && *p++ == 0x46) {
27+
auto klass = *p++; // Byte 4 (EI_CLASS): ELF class, 32- or 64-bit (0x01 or 0x02)
28+
auto dataFormat = *p++; // Byte 5 (EI_DATA): (0x01) little- or (0x02) big-endian
29+
auto fileVersion = *p++; // Byte 6 (EI_VERSION): ELF version: expect 1 (latest ELF version)
30+
constexpr static uint16_t kEndianTestWord{0x0201};
31+
auto hostEndianness = *(uint8_t const*)&kEndianTestWord;
32+
if (dataFormat == hostEndianness && fileVersion == 1) {
33+
if (klass == 0x01) {
34+
header_ = Header((Header32 const*)image);
35+
makeSection_ = makeSection32;
36+
makeSymbol_ = makeSymbol32;
37+
secSize_ = sizeof(Section32);
38+
symSize_ = sizeof(Symbol32);
39+
} else if (klass == 0x02) {
40+
header_ = Header((Header64 const*)image);
41+
makeSection_ = makeSection64;
42+
makeSymbol_ = makeSymbol64;
43+
secSize_ = sizeof(Section64);
44+
symSize_ = sizeof(Symbol64);
45+
}
46+
}
47+
}
48+
if (*this) {
49+
nametab_ = section(header_.shstrndx_);
50+
eachSection([&](auto& sec) mutable -> bool {
51+
if (sec.type_ == Section::kSymTab && sec.name() == ".symtab") {
52+
symtab_ = sec;
53+
} else if (sec.type_ == Section::kStrTab && sec.name() == ".strtab") {
54+
strtab_ = sec;
55+
}
56+
return !symtab_ || !strtab_;
57+
});
58+
}
59+
if (symtab_) {
60+
symCount_ = symtab_.size_ / symSize_;
61+
}
62+
}
63+
64+
Section ELF::section(size_t index) {
65+
auto* addr = header_.ptr_ + header_.shoff_ + (index * secSize_);
66+
return makeSection_(this, addr);
67+
}
68+
69+
Symbol ELF::symbol(size_t index) {
70+
auto* addr = symtab_.data() + (index * symSize_);
71+
return makeSymbol_(this, addr);
72+
}
73+
74+
void ELF::eachSection(CB<Section> cb) {
75+
for (size_t i = 0; i < header_.shnum_ && cb(section(i)); i++)
76+
;
77+
}
78+
79+
void ELF::eachSymbol(CB<Symbol> cb) {
80+
for (size_t i = 0; i < symCount_ && cb(symbol(i)); i++)
81+
;
82+
}
83+
84+
Symbol ELF::getSym(uintptr_t addr) {
85+
Symbol ret{};
86+
eachSymbol([&](auto& sym) -> bool {
87+
if (sym.value_ <= addr && sym.value_ > ret.value_) {
88+
ret = sym;
89+
}
90+
return true;
91+
});
92+
return ret;
93+
}
94+
95+
} // namespace __stacktrace::elf
96+
_LIBCPP_END_NAMESPACE_STD
97+
98+
#endif // defined(__linux__)

libcxx/src/stacktrace/linux/elf.h

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP_STACKTRACE_LINUX_ELF
10+
#define _LIBCPP_STACKTRACE_LINUX_ELF
11+
12+
#include <__stacktrace/base.h>
13+
#include <cassert>
14+
#include <cstddef>
15+
#include <cstdlib>
16+
#include <functional>
17+
#include <string_view>
18+
#include <unistd.h>
19+
20+
_LIBCPP_BEGIN_NAMESPACE_STD
21+
namespace __stacktrace::elf {
22+
23+
// Includes ELF constants and structs copied from <elf.h>, with a few changes.
24+
25+
struct Header32 final {
26+
uint8_t ident[16]; /* Magic number and other info */
27+
uint16_t type; /* Object file type */
28+
uint16_t machine; /* Architecture */
29+
uint32_t version; /* Object file version */
30+
uint32_t entry; /* Entry point virtual address */
31+
uint32_t phoff; /* Program header table file offset */
32+
uint32_t shoff; /* Section header table file offset */
33+
uint32_t flags; /* Processor-specific flags */
34+
uint16_t ehsize; /* ELF header size in bytes */
35+
uint16_t phentsize; /* Program header table entry size */
36+
uint16_t phnum; /* Program header table entry count */
37+
uint16_t shentsize; /* Section header table entry size */
38+
uint16_t shnum; /* Section header table entry count */
39+
uint16_t shstrndx; /* Section header string table index */
40+
};
41+
42+
struct Section32 final {
43+
uint32_t name; /* Section name (string tbl index) */
44+
uint32_t type; /* Section type */
45+
uint32_t flags; /* Section flags */
46+
uint32_t addr; /* Section virtual addr at execution */
47+
uint32_t offset; /* Section file offset */
48+
uint32_t size; /* Section size in bytes */
49+
uint32_t link; /* Link to another section */
50+
uint32_t info; /* Additional section information */
51+
uint32_t addralign; /* Section alignment */
52+
uint32_t entsize; /* Entry size if section holds table */
53+
};
54+
55+
struct Symbol32 final {
56+
uint32_t name; /* Symbol name (string tbl index) */
57+
uint32_t value; /* Symbol value */
58+
uint32_t size; /* Symbol size */
59+
uint8_t info; /* Symbol type and binding */
60+
uint8_t other; /* Symbol visibility */
61+
uint16_t shndx; /* Section index */
62+
};
63+
64+
struct Header64 final {
65+
uint8_t ident[16]; /* Magic number and other info */
66+
uint16_t type; /* Object file type */
67+
uint16_t machine; /* Architecture */
68+
uint32_t version; /* Object file version */
69+
uint64_t entry; /* Entry point virtual address */
70+
uint64_t phoff; /* Program header table file offset */
71+
uint64_t shoff; /* Section header table file offset */
72+
uint32_t flags; /* Processor-specific flags */
73+
uint16_t ehsize; /* ELF header size in bytes */
74+
uint16_t phentsize; /* Program header table entry size */
75+
uint16_t phnum; /* Program header table entry count */
76+
uint16_t shentsize; /* Section header table entry size */
77+
uint16_t shnum; /* Section header table entry count */
78+
uint16_t shstrndx; /* Section header string table index */
79+
};
80+
81+
struct Section64 final {
82+
uint32_t name; /* Section name (string tbl index) */
83+
uint32_t type; /* Section type */
84+
uint64_t flags; /* Section flags */
85+
uint64_t addr; /* Section virtual addr at execution */
86+
uint64_t offset; /* Section file offset */
87+
uint64_t size; /* Section size in bytes */
88+
uint32_t link; /* Link to another section */
89+
uint32_t info; /* Additional section information */
90+
uint64_t addralign; /* Section alignment */
91+
uint64_t entsize; /* Entry size if section holds table */
92+
};
93+
94+
struct Symbol64 final {
95+
uint32_t name; /* Symbol name (string tbl index) */
96+
uint8_t info; /* Symbol type and binding */
97+
uint8_t other; /* Symbol visibility */
98+
uint16_t shndx; /* Section index */
99+
uint64_t value; /* Symbol value */
100+
uint64_t size; /* Symbol size */
101+
};
102+
103+
/** Represents an ELF header. Supports the minimum needed to navigate an ELF file's sections and get at the symbol and
104+
* string tables. */
105+
struct Header final {
106+
std::byte const* ptr_{};
107+
uintptr_t shoff_{};
108+
size_t shnum_{};
109+
size_t shstrndx_{};
110+
111+
Header() = default;
112+
Header(Header const&) = default;
113+
Header& operator=(Header const& rhs) { return *new (this) Header(rhs); }
114+
115+
operator bool() { return ptr_; }
116+
117+
template <class H>
118+
explicit Header(H* h)
119+
: ptr_((std::byte const*)h),
120+
shoff_(uintptr_t(h->shoff)),
121+
shnum_(size_t(h->shnum)),
122+
shstrndx_(size_t(h->shstrndx)) {}
123+
};
124+
125+
struct ELF;
126+
struct StringTable;
127+
128+
struct Section final {
129+
constexpr static uint32_t kSymTab = 2; // symbol table
130+
constexpr static uint32_t kStrTab = 3; // name table for symbols or sections
131+
132+
ELF* elf_{};
133+
std::byte const* ptr_{};
134+
uintptr_t nameIndex_{};
135+
uint32_t type_{};
136+
uintptr_t offset_{};
137+
size_t size_{};
138+
139+
Section() = default;
140+
141+
template <class S>
142+
Section(ELF* elf, S* sec)
143+
: elf_(elf),
144+
ptr_((std::byte const*)sec),
145+
nameIndex_(sec->name),
146+
type_(sec->type),
147+
offset_(sec->offset),
148+
size_(sec->size) {}
149+
150+
operator bool() const { return ptr_; }
151+
152+
template <class T = std::byte>
153+
T const* data() const {
154+
return (T const*)(elfBase() + offset_);
155+
}
156+
157+
std::byte const* elfBase() const;
158+
std::string_view name() const;
159+
};
160+
161+
struct Symbol final {
162+
constexpr static uint8_t kFunc = 0x02; // STT_FUNC (code object)
163+
164+
ELF* elf_{};
165+
std::byte const* ptr_{};
166+
uintptr_t nameIndex_{};
167+
uint32_t type_{};
168+
uintptr_t value_{};
169+
170+
Symbol() = default;
171+
Symbol(Symbol const&) = default;
172+
Symbol& operator=(Symbol const& rhs) { return *new (this) Symbol(rhs); }
173+
174+
operator bool() { return ptr_; }
175+
176+
bool isCode() const { return type_ == kFunc; }
177+
178+
template <class S>
179+
Symbol(ELF* elf, S* sym)
180+
: elf_(elf), ptr_((std::byte const*)sym), nameIndex_(sym->name), type_(0x0f & sym->info), value_(sym->value) {}
181+
182+
std::byte const* elfBase() const;
183+
std::string_view name() const;
184+
};
185+
186+
/** Represents one of the ELF's `strtab`s. This is a block of string data, with strings appended one after another, and
187+
* NUL-terminated. Strings are indexed according to their starting offset. At offset 0 is typically an empty string.
188+
*/
189+
struct StringTable {
190+
std::string_view data_{};
191+
192+
StringTable() = default;
193+
194+
/* implicit */ StringTable(Section const& sec) : data_(sec.data<char>(), sec.size_) {}
195+
196+
operator bool() { return data_.size(); }
197+
198+
std::string_view at(size_t index) {
199+
auto* ret = data_.data() + index;
200+
return {ret, strlen(ret)};
201+
}
202+
};
203+
204+
/** Encapsulates an ELF image specified by byte-address (e.g. from an mmapped file or a program image or shared object
205+
* in memory). If given a supported ELF image, this will test true with `operator bool` to indicate it is supported and
206+
* was able to parse some basic information from the header. */
207+
struct ELF {
208+
Header header_{};
209+
Section (*makeSection_)(ELF*, std::byte const*){};
210+
Symbol (*makeSymbol_)(ELF*, std::byte const*){};
211+
size_t secSize_{};
212+
size_t symSize_{};
213+
StringTable nametab_{};
214+
Section symtab_{};
215+
StringTable strtab_{};
216+
size_t symCount_{};
217+
218+
static Section makeSection32(ELF* elf, std::byte const* ptr) { return Section(elf, (Section32 const*)ptr); }
219+
static Section makeSection64(ELF* elf, std::byte const* ptr) { return Section(elf, (Section64 const*)ptr); }
220+
static Symbol makeSymbol32(ELF* elf, std::byte const* ptr) { return Symbol(elf, (Symbol32 const*)ptr); }
221+
static Symbol makeSymbol64(ELF* elf, std::byte const* ptr) { return Symbol(elf, (Symbol64 const*)ptr); }
222+
223+
operator bool() { return header_; }
224+
225+
explicit ELF(std::byte const* image);
226+
227+
Section section(size_t index);
228+
Symbol symbol(size_t index);
229+
230+
template <class T>
231+
using CB = std::function<bool(T const&)>;
232+
233+
void eachSection(CB<Section> cb);
234+
void eachSymbol(CB<Symbol> cb);
235+
236+
Symbol getSym(uintptr_t addr);
237+
};
238+
239+
inline std::byte const* Section::elfBase() const { return elf_->header_.ptr_; }
240+
inline std::byte const* Symbol::elfBase() const { return elf_->header_.ptr_; }
241+
242+
inline std::string_view Section::name() const { return elf_->nametab_.at(nameIndex_); }
243+
inline std::string_view Symbol::name() const { return elf_->strtab_.at(nameIndex_); }
244+
245+
} // namespace __stacktrace::elf
246+
_LIBCPP_END_NAMESPACE_STD
247+
248+
#endif // _LIBCPP_STACKTRACE_LINUX_ELF

0 commit comments

Comments
 (0)