Skip to content

Commit c02fe32

Browse files
committed
Try additional gz support
1 parent 50e4298 commit c02fe32

2 files changed

Lines changed: 122 additions & 14 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
365365
URL "${CPPTRACE_ZSTD_URL}"
366366
)
367367
FetchContent_MakeAvailable(zstd)
368+
target_include_directories(${target_name} PRIVATE ${zstd_SOURCE_DIR}/lib)
368369
endif()
369370
# Libdwarf itself
370371
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)

‎src/symbols/dwarf/dwarf_resolver.cpp‎

Lines changed: 121 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#endif
2424
#if IS_LINUX
2525
#include <elf.h>
26+
#include <zlib.h>
27+
#include <zstd.h>
2628
#endif
2729

2830
#include <algorithm>
@@ -37,6 +39,15 @@
3739
#include <unordered_map>
3840
#include <vector>
3941

42+
#if IS_LINUX
43+
#ifndef ELFCOMPRESS_ZLIB
44+
#define ELFCOMPRESS_ZLIB 1
45+
#endif
46+
#ifndef ELFCOMPRESS_ZSTD
47+
#define ELFCOMPRESS_ZSTD 2
48+
#endif
49+
#endif
50+
4051
// It's been tricky to piece together how to handle all this dwarf stuff. Some resources I've used are
4152
// https://www.prevanders.net/libdwarf.pdf
4253
// https://github.com/davea42/libdwarf-addr2line
@@ -67,7 +78,9 @@ namespace libdwarf {
6778
explicit in_memory_dwarf_object(elf::object_data&& object_data_)
6879
: object_data(std::move(object_data_)),
6980
relocated_sections(object_data.sections.size(), false),
70-
interface{this, &methods} {}
81+
interface{this, &methods} {
82+
decompress_compressed_sections();
83+
}
7184

7285
template<typename T>
7386
T byteswap_if_needed(T value) const {
@@ -80,7 +93,7 @@ namespace libdwarf {
8093
template<typename T>
8194
T load_value(const std::vector<char>& data, std::size_t offset) const {
8295
T value{};
83-
if(offset + sizeof(T) > data.size()) {
96+
if(offset > data.size() || sizeof(T) > data.size() - offset) {
8497
return value;
8598
}
8699
std::memcpy(&value, data.data() + offset, sizeof(T));
@@ -93,6 +106,100 @@ namespace libdwarf {
93106
std::memcpy(data.data() + offset, &value, sizeof(T));
94107
}
95108

109+
void decompress_compressed_sections() {
110+
for(auto& section : object_data.sections) {
111+
if((section.flags & SHF_COMPRESSED) == 0) {
112+
continue;
113+
}
114+
115+
std::size_t header_size{};
116+
std::uint32_t compression_type{};
117+
std::uint64_t uncompressed_size{};
118+
if(object_data.is_64_bit) {
119+
if(section.data.size() < sizeof(Elf64_Chdr)) {
120+
throw internal_error(
121+
"Compressed DWARF section {} is shorter than its ELF compression header.",
122+
section.name
123+
);
124+
}
125+
header_size = sizeof(Elf64_Chdr);
126+
compression_type = load_value<Elf32_Word>(section.data, 0);
127+
uncompressed_size = load_value<Elf64_Xword>(section.data, 8);
128+
} else {
129+
if(section.data.size() < sizeof(Elf32_Chdr)) {
130+
throw internal_error(
131+
"Compressed DWARF section {} is shorter than its ELF compression header.",
132+
section.name
133+
);
134+
}
135+
header_size = sizeof(Elf32_Chdr);
136+
compression_type = load_value<Elf32_Word>(section.data, 0);
137+
uncompressed_size = load_value<Elf32_Word>(section.data, 4);
138+
}
139+
140+
if(compression_type != ELFCOMPRESS_ZLIB && compression_type != ELFCOMPRESS_ZSTD) {
141+
throw internal_error(
142+
"Compressed DWARF section {} uses unsupported compression type {}.",
143+
section.name,
144+
compression_type
145+
);
146+
}
147+
if(
148+
uncompressed_size > std::numeric_limits<std::size_t>::max()
149+
|| uncompressed_size > std::numeric_limits<uLongf>::max()
150+
|| section.data.size() - header_size > std::numeric_limits<uLong>::max()
151+
) {
152+
throw internal_error(
153+
"Compressed DWARF section {} has an invalid uncompressed size.",
154+
section.name
155+
);
156+
}
157+
158+
std::vector<char> decompressed(static_cast<std::size_t>(uncompressed_size));
159+
if(compression_type == ELFCOMPRESS_ZLIB) {
160+
auto decompressed_size{ static_cast<uLongf>(decompressed.size()) };
161+
auto const compression_result{
162+
::uncompress(
163+
reinterpret_cast<Bytef*>(decompressed.data()),
164+
&decompressed_size,
165+
reinterpret_cast<const Bytef*>(section.data.data() + header_size),
166+
static_cast<uLong>(section.data.size() - header_size)
167+
)
168+
};
169+
if(
170+
compression_result != Z_OK
171+
|| decompressed_size != static_cast<uLongf>(uncompressed_size)
172+
) {
173+
throw internal_error(
174+
"Unable to decompress DWARF section {} with zlib (error {}).",
175+
section.name,
176+
compression_result
177+
);
178+
}
179+
} else if(compression_type == ELFCOMPRESS_ZSTD) {
180+
auto const decompressed_size{
181+
ZSTD_decompress(
182+
decompressed.data(),
183+
decompressed.size(),
184+
section.data.data() + header_size,
185+
section.data.size() - header_size
186+
)
187+
};
188+
if(ZSTD_isError(decompressed_size) || decompressed_size != decompressed.size()) {
189+
throw internal_error(
190+
"Unable to decompress DWARF section {} with zstd ({}).",
191+
section.name,
192+
ZSTD_getErrorName(decompressed_size)
193+
);
194+
}
195+
}
196+
197+
section.data = std::move(decompressed);
198+
section.size = section.data.size();
199+
section.flags &= ~static_cast<std::uint64_t>(SHF_COMPRESSED);
200+
}
201+
}
202+
96203
template<typename Sym>
97204
Dwarf_Addr normalized_symbol_value(const Sym& sym) const {
98205
auto value = byteswap_if_needed(sym.st_value);
@@ -124,8 +231,8 @@ namespace libdwarf {
124231
Dwarf_Unsigned value,
125232
int* error
126233
) {
127-
if(offset + sizeof(T) > target.size()) {
128-
*error = 0;
234+
if(offset > target.size() || sizeof(T) > target.size() - offset) {
235+
*error = DW_DLE_RELOC_INVALID;
129236
return DW_DLV_ERROR;
130237
}
131238
store_value(target, offset, static_cast<T>(value));
@@ -152,7 +259,7 @@ namespace libdwarf {
152259
case R_X86_64_PC32:
153260
return apply_relocation_value<std::uint32_t>(target, offset, symbol + addend - place, error);
154261
default:
155-
*error = 0;
262+
*error = DW_DLE_RELOC_INVALID;
156263
return DW_DLV_ERROR;
157264
}
158265
}
@@ -165,13 +272,13 @@ namespace libdwarf {
165272
) {
166273
const auto& reloc_section = object_data.sections[reloc_section_index];
167274
auto& target = object_data.sections[target_section_index].data;
168-
if(reloc_section.entsize == 0) {
169-
*error = 0;
275+
if(reloc_section.entsize < sizeof(Rela) || reloc_section.data.size() % reloc_section.entsize != 0) {
276+
*error = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
170277
return DW_DLV_ERROR;
171278
}
172279
auto symtab_index = reloc_section.link;
173280
if(symtab_index >= object_data.sections.size()) {
174-
*error = 0;
281+
*error = DW_DLE_RELOC_SECTION_MISSING_INDEX;
175282
return DW_DLV_ERROR;
176283
}
177284
for(std::size_t offset = 0; offset + sizeof(Rela) <= reloc_section.data.size(); offset += reloc_section.entsize) {
@@ -197,7 +304,7 @@ namespace libdwarf {
197304
return ret;
198305
}
199306
} else {
200-
*error = 0;
307+
*error = DW_DLE_RELOC_INVALID;
201308
return DW_DLV_ERROR;
202309
}
203310
}
@@ -212,13 +319,13 @@ namespace libdwarf {
212319
) {
213320
const auto& reloc_section = object_data.sections[reloc_section_index];
214321
auto& target = object_data.sections[target_section_index].data;
215-
if(reloc_section.entsize == 0) {
216-
*error = 0;
322+
if(reloc_section.entsize < sizeof(Rel) || reloc_section.data.size() % reloc_section.entsize != 0) {
323+
*error = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
217324
return DW_DLV_ERROR;
218325
}
219326
auto symtab_index = reloc_section.link;
220327
if(symtab_index >= object_data.sections.size()) {
221-
*error = 0;
328+
*error = DW_DLE_RELOC_SECTION_MISSING_INDEX;
222329
return DW_DLV_ERROR;
223330
}
224331
for(std::size_t offset = 0; offset + sizeof(Rel) <= reloc_section.data.size(); offset += reloc_section.entsize) {
@@ -246,7 +353,7 @@ namespace libdwarf {
246353
return ret;
247354
}
248355
} else {
249-
*error = 0;
356+
*error = DW_DLE_RELOC_INVALID;
250357
return DW_DLV_ERROR;
251358
}
252359
}
@@ -255,7 +362,7 @@ namespace libdwarf {
255362

256363
int relocate_section(Dwarf_Unsigned section_index, int* error) {
257364
if(section_index >= object_data.sections.size()) {
258-
*error = 0;
365+
*error = DW_DLE_RELOC_SECTION_MISMATCH;
259366
return DW_DLV_ERROR;
260367
}
261368
if(relocated_sections[section_index]) {

0 commit comments

Comments
 (0)