2323#endif
2424#if IS_LINUX
2525#include < elf.h>
26+ #include < zlib.h>
27+ #include < zstd.h>
2628#endif
2729
2830#include < algorithm>
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