Skip to content

Commit

Permalink
[skip ci] Try load split DWARF file
Browse files Browse the repository at this point in the history
Add `read_debuglink` and `read_build_id`

Fix dwo loading

add is_dwo

Fix DW_LNCT_MD5

- Try process DW_UT_skeleton
- Fix dwo_id
- Check buffer size
  • Loading branch information
imbillow committed Oct 20, 2023
1 parent 24bfd59 commit 2d02625
Show file tree
Hide file tree
Showing 18 changed files with 269 additions and 158 deletions.
8 changes: 6 additions & 2 deletions librz/bin/dwarf/abbrev.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ RZ_API RZ_OWN RzBinDwarfAbbrev *rz_bin_dwarf_abbrev_new(RZ_OWN RZ_NONNULL RzBinE
* \param bf Binfile to parse
* \return RzBinDwarfAbbrevs object
*/
RZ_API RZ_OWN RzBinDwarfAbbrev *rz_bin_dwarf_abbrev_from_file(RZ_BORROW RZ_NONNULL RzBinFile *bf) {
RZ_API RZ_OWN RzBinDwarfAbbrev *rz_bin_dwarf_abbrev_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf, bool is_dwo) {
rz_return_val_if_fail(bf, NULL);
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_abbrev");
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_abbrev", is_dwo);
RET_NULL_IF_FAIL(r);
return rz_bin_dwarf_abbrev_new(r);
}
Expand All @@ -201,6 +202,9 @@ RZ_API size_t rz_bin_dwarf_abbrev_count(RZ_BORROW RZ_NONNULL const RzBinDwarfAbb
*/
RZ_API RZ_BORROW RzBinDwarfAbbrevDecl *rz_bin_dwarf_abbrev_get(RZ_BORROW RZ_NONNULL const RzBinDwarfAbbrevTable *tbl, size_t idx) {
rz_return_val_if_fail(tbl, NULL);
if (idx > rz_vector_len(&tbl->abbrevs)) {
return NULL;
}
return rz_vector_index_ptr(&tbl->abbrevs, idx - 1);
}

Expand Down
2 changes: 1 addition & 1 deletion librz/bin/dwarf/addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ RZ_IPI RzBinDwarfAddr *DebugAddr_new(RzBinEndianReader *reader) {

RZ_IPI RzBinDwarfAddr *DebugAddr_from_file(RzBinFile *bf) {
rz_return_val_if_fail(bf, NULL);
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_addr");
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_addr", false);
RET_NULL_IF_FAIL(r);
return DebugAddr_new(r);
}
2 changes: 1 addition & 1 deletion librz/bin/dwarf/aranges.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ RZ_API RZ_OWN RzBinDwarfARanges *rz_bin_dwarf_aranges_new(RZ_NONNULL RZ_OWN RzBi
*/
RZ_API RZ_OWN RzBinDwarfARanges *rz_bin_dwarf_aranges_from_file(RZ_BORROW RZ_NONNULL RzBinFile *bf) {
rz_return_val_if_fail(bf, NULL);
RzBinEndianReader *reader = RzBinEndianReader_from_file(bf, ".debug_aranges");
RzBinEndianReader *reader = RzBinEndianReader_from_file(bf, ".debug_aranges", false);
RET_NULL_IF_FAIL(reader);
return rz_bin_dwarf_aranges_new(reader);
}
111 changes: 99 additions & 12 deletions librz/bin/dwarf/dwarf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <rz_bin_dwarf.h>
#include "dwarf_private.h"
#include "../format/elf/elf.h"

RZ_IPI bool RzBinDwarfEncoding_from_file(RzBinDwarfEncoding *encoding, RzBinFile *bf) {
if (!(encoding && bf)) {
Expand All @@ -15,39 +16,125 @@ RZ_IPI bool RzBinDwarfEncoding_from_file(RzBinDwarfEncoding *encoding, RzBinFile
return true;
}

RZ_API RZ_OWN RzBinDWARF *rz_bin_dwarf_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf) {
static inline RZ_OWN RzBinDWARF *dwarf_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf, bool is_dwo) {
rz_return_val_if_fail(bf, NULL);
RzBinDWARF *dw = RZ_NEW0(RzBinDWARF);
RET_NULL_IF_FAIL(dw);

dw->addr = DebugAddr_from_file(bf);
dw->str = RzBinDwarfStr_from_file(bf);
dw->str_offsets = RzBinDwarfStrOffsets_from_file(bf);
dw->line_str = rz_bin_dwarf_line_str_from_file(bf);
dw->abbrev = rz_bin_dwarf_abbrev_from_file(bf);
dw->aranges = rz_bin_dwarf_aranges_from_file(bf);

dw->str = rz_bin_dwarf_str_from_file(bf, is_dwo);
dw->str_offsets = rz_bin_dwarf_str_offsets_from_file(bf, is_dwo);
dw->loclists = rz_bin_dwarf_loclists_new_from_file(bf, is_dwo);
dw->rnglists = rz_bin_dwarf_rnglists_new_from_file(bf, is_dwo);
dw->abbrev = rz_bin_dwarf_abbrev_from_file(bf, is_dwo);

if (dw->abbrev) {
dw->info = rz_bin_dwarf_info_from_file(bf, dw);
dw->info = rz_bin_dwarf_info_from_file(bf, dw, is_dwo);
}
dw->loclists = rz_bin_dwarf_loclists_new_from_file(bf);
dw->rnglists = rz_bin_dwarf_rnglists_new_from_file(bf);
if (dw->info) {
dw->line = rz_bin_dwarf_line_from_file(bf, dw);
dw->line = rz_bin_dwarf_line_from_file(bf, dw, is_dwo);
}
return dw;
}

static inline char *read_debuglink(RzCore *core, RzBinFile *binfile) {
RzBinSection *sect = rz_bin_dwarf_section_by_name(binfile, ".gnu_debuglink", false);
RET_NULL_IF_FAIL(sect);
RzBuffer *buffer = rz_bin_dwarf_section_buf(binfile, sect);
RET_NULL_IF_FAIL(buffer);
char *name = rz_buf_get_string(buffer, 0);
// TODO: Verification the CRC
rz_buf_free(buffer);
return name;
}

static inline char *read_build_id(RzCore *core, RzBinFile *binfile) {
RzBinSection *sect = rz_bin_dwarf_section_by_name(binfile, ".note.gnu.build-id", false);
RET_NULL_IF_FAIL(sect);
RzBuffer *buffer = rz_bin_dwarf_section_buf(binfile, sect);
RET_NULL_IF_FAIL(buffer);

char *build_id = NULL;
/**
* struct build_id_note {
* Elf_Nhdr nhdr;
* char name[4];
* uint8_t buf[0];
* };
*/
size_t nhdr_sz = binfile->o->info->bits == 64 ? sizeof(Elf64_Nhdr) : sizeof(Elf32_Nhdr);
size_t begin = nhdr_sz + 4;
size_t sz = rz_buf_size(buffer) - begin;
ut8 *buf = RZ_NEWS0(ut8, sz);
if (!buf) {
goto beach;
}
if (rz_buf_read_at(buffer, begin, buf, sz) != sz) {
goto beach;
}
build_id = rz_hex_bin2strdup(buf, (int)sz);

beach:
rz_buf_free(buffer);
free(buf);
return build_id;
}

/**
* \brief Load DWARF from split DWARF file
* \param bin The RzBin instance
* \param opt The RzBinDWARFOption reference
* \param filepath The file path
* \return RzBinDWARF pointer or NULL if failed
*/
RZ_API RZ_OWN RzBinDWARF *rz_bin_dwarf_dwo_from_file(
RZ_BORROW RZ_NONNULL RzBin *bin,
RZ_BORROW RZ_NONNULL const char *filepath) {
rz_return_val_if_fail(bin && filepath, NULL);

RzBinDWARF *dwo = NULL;
RzIO *io_tmp = rz_io_new();
RzBin *bin_tmp = rz_bin_new();
rz_io_bind(io_tmp, &bin_tmp->iob);

RzBinOptions bopt = { 0 };
rz_bin_options_init(&bopt, 0, 0, 0, false);
RzBinFile *bf = rz_bin_open(bin_tmp, filepath, &bopt);
if (!bf) {
goto beach;
}
dwo = dwarf_from_file(bf, true);

beach:
rz_bin_free(bin_tmp);
rz_io_free(io_tmp);
return dwo;
}

RZ_API RZ_OWN RzBinDWARF *rz_bin_dwarf_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf) {
return dwarf_from_file(bf, false);
}

RZ_API void rz_bin_dwarf_free(RZ_OWN RZ_NULLABLE RzBinDWARF *dw) {
if (!dw) {
return;
}
rz_bin_dwarf_free(dw->dwo_parent);

DebugRngLists_free(dw->rnglists);
DebugAddr_free(dw->addr);
rz_bin_dwarf_str_free(dw->str);
rz_bin_dwarf_str_offsets_free(dw->str_offsets);

rz_bin_dwarf_abbrev_free(dw->abbrev);
rz_bin_dwarf_info_free(dw->info);
rz_bin_dwarf_line_free(dw->line);
rz_bin_dwarf_loclists_free(dw->loclists);
DebugRngLists_free(dw->rnglists);
rz_bin_dwarf_aranges_free(dw->aranges);
DebugAddr_free(dw->addr);
RzBinDwarfStr_free(dw->str);
free(dw);
}
22 changes: 5 additions & 17 deletions librz/bin/dwarf/dwarf_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ RZ_IPI RzBinEndianReader *RzBinDwarfBlock_as_reader(const RzBinDwarfBlock *self)
RZ_IPI void RzBinDwarfBlock_fini(RzBinDwarfBlock *self);
RZ_IPI void RzBinDwarfBlock_free(RzBinDwarfBlock *self);

RZ_IPI RzBinSection *rz_bin_dwarf_section_by_name(RzBinFile *binfile, const char *sn, bool is_dwo);
RZ_IPI RzBuffer *rz_bin_dwarf_section_buf(RzBinFile *binfile, RzBinSection *section);

RZ_IPI bool read_initial_length(RzBinEndianReader *reader, RZ_OUT bool *is_64bit, ut64 *out);
RZ_IPI bool read_offset(RzBinEndianReader *reader, ut64 *out, bool is_64bit);
RZ_IPI bool read_address(RzBinEndianReader *reader, ut64 *out, ut8 address_size);
Expand All @@ -40,9 +43,9 @@ RZ_IPI RzBinEndianReader *RzBinEndianReader_clone(RzBinEndianReader *x);

RZ_IPI bool RzBinDwarfAttr_parse(RzBinEndianReader *reader, RzBinDwarfAttr *attr, AttrOption *opt);
RZ_IPI void RzBinDwarfAttr_fini(RzBinDwarfAttr *attr);
RZ_IPI char *RzBinDwarfAttr_to_string(RzBinDwarfAttr *attr);

RZ_IPI RzBinEndianReader *RzBinEndianReader_from_file(RzBinFile *binfile, const char *sect_name);
RZ_IPI RzBinEndianReader *RzBinEndianReader_from_file(
RzBinFile *binfile, const char *sect_name, bool is_dwo);

static inline bool bf_bigendian(RzBinFile *bf) {
return bf->o && bf->o->info && bf->o->info->big_endian;
Expand Down Expand Up @@ -124,19 +127,4 @@ RZ_IPI void Value_dump(

#include "op.h"

///

/// debug_str
RZ_IPI void RzBinDwarfStr_free(RzBinDwarfStr *str);
RZ_IPI char *RzBinDwarfStr_get(RzBinDwarfStr *str, ut64 offset);
RZ_IPI void RzBinDwarfStr_read_all(RzBinDwarfStr *str);
RZ_IPI RzBinDwarfStr *RzBinDwarfStr_new(RZ_NONNULL RZ_OWN RzBinEndianReader *reader);
RZ_IPI RzBinDwarfStr *RzBinDwarfStr_from_file(RZ_NONNULL RZ_BORROW RzBinFile *bf);

/// debug_str_offsets
RZ_IPI void RzBinDwarfStrOffsets_free(RzBinDwarfStrOffsets *str_offsets);
RZ_IPI char *RzBinDwarfStrOffsets_get(RzBinDwarfStr *str, RzBinDwarfStrOffsets *str_offsets, ut64 base, ut64 index);
RZ_IPI RzBinDwarfStrOffsets *RzBinDwarfStrOffsets_new(RzBinEndianReader *reader);
RZ_IPI RzBinDwarfStrOffsets *RzBinDwarfStrOffsets_from_file(RZ_NONNULL RZ_BORROW RzBinFile *bf);

#endif
31 changes: 19 additions & 12 deletions librz/bin/dwarf/endian_reader.c
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
// SPDX-FileCopyrightText: 2023 billow <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include <zstd.h>
#include <rz_bin_dwarf.h>
#include "dwarf_private.h"
#include <zstd.h>
#include "../format/elf/elf.h"

RZ_IPI RzBinSection *get_section(RzBinFile *binfile, const char *sn) {
RZ_IPI RzBinSection *rz_bin_dwarf_section_by_name(RzBinFile *binfile, const char *sn, bool is_dwo) {
rz_return_val_if_fail(binfile && sn, NULL);
RzListIter *iter;
RzListIter *iter = NULL;
RzBinSection *section = NULL;
RzBinSection *result_section = NULL;
RzBinObject *o = binfile->o;
if (!o || !o->sections || RZ_STR_ISEMPTY(sn)) {
return NULL;
}
char *name = is_dwo ? rz_str_newf("%s.dwo", sn) : rz_str_new(sn);
if (!name) {
return NULL;
}
rz_list_foreach (o->sections, iter, section) {
if (!section->name) {
continue;
}
if (RZ_STR_EQ(section->name, sn) ||
rz_str_endswith(section->name, sn + 1)) {
return section;
if (RZ_STR_EQ(section->name, name) ||
rz_str_endswith(section->name, name + 1)) {
result_section = section;
break;
}
}
return NULL;
free(name);
return result_section;
}

typedef struct {
ut8 gch_magic[4]; /* [ 'Z', 'L', 'I', 'B'] */
ut8 gch_size[8]; /* unaligned 64-bit ELFDATAMSB integer */
} Chdr_GNU;

RZ_IPI RzBuffer *get_section_buf(RzBinFile *binfile, RzBinSection *section) {
RZ_IPI RzBuffer *rz_bin_dwarf_section_buf(RzBinFile *binfile, RzBinSection *section) {
rz_return_val_if_fail(binfile && section, NULL);
if (section->paddr >= binfile->size) {
return NULL;
Expand Down Expand Up @@ -106,7 +113,7 @@ RZ_IPI RzBuffer *get_section_buf(RzBinFile *binfile, RzBinSection *section) {
return NULL;
}

void add_relocations(
static inline void add_relocations(
RzBinFile *bf,
HtUP *relocations,
RzBinSection *section) {
Expand All @@ -121,11 +128,11 @@ void add_relocations(
}
}

RZ_IPI RzBinEndianReader *RzBinEndianReader_from_file(RzBinFile *binfile, const char *sect_name) {
RZ_IPI RzBinEndianReader *RzBinEndianReader_from_file(RzBinFile *binfile, const char *sect_name, bool is_dwo) {
rz_return_val_if_fail(binfile && sect_name, NULL);
RzBinSection *section = get_section(binfile, sect_name);
RzBinSection *section = rz_bin_dwarf_section_by_name(binfile, sect_name, is_dwo);
OK_OR(section, return NULL);
RzBuffer *buf = get_section_buf(binfile, section);
RzBuffer *buf = rz_bin_dwarf_section_buf(binfile, section);
OK_OR(buf, return NULL);

HtUP *relocations = ht_up_new0();
Expand Down
10 changes: 6 additions & 4 deletions librz/bin/dwarf/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ static RzBinDwarfFileEntry *FileEntry_parse_v5(
entry->size = rz_bin_dwarf_attr_udata(&attr);
break;
case DW_LNCT_MD5: {
const RzBinDwarfBlock *b = rz_bin_dwarf_attr_block(&attr);
memcpy(entry->md5, rz_bin_dwarf_block_data(b), 16);
rz_warn_if_fail(attr.form == DW_FORM_data16);
const ut128 data = attr.value.u128;
memcpy(entry->md5, &data, 16);
break;
}
default: rz_warn_if_reached(); break;
Expand Down Expand Up @@ -737,14 +738,15 @@ RZ_API RZ_OWN RzBinDwarfLine *rz_bin_dwarf_line_new(
*/
RZ_API RZ_OWN RzBinDwarfLine *rz_bin_dwarf_line_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf,
RZ_BORROW RZ_NULLABLE RzBinDWARF *dw) {
RZ_BORROW RZ_NULLABLE RzBinDWARF *dw,
bool is_dwo) {
rz_return_val_if_fail(bf, NULL);
RzBinDwarfEncoding encoding_bf = { 0 };
if (!RzBinDwarfEncoding_from_file(&encoding_bf, bf)) {
return NULL;
}

RzBinEndianReader *reader = RzBinEndianReader_from_file(bf, ".debug_line");
RzBinEndianReader *reader = RzBinEndianReader_from_file(bf, ".debug_line", is_dwo);
RET_NULL_IF_FAIL(reader);
return Line_parse(reader, &encoding_bf, dw);
}
10 changes: 5 additions & 5 deletions librz/bin/dwarf/line_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
#include "dwarf_private.h"

RZ_API RZ_OWN RzBinDwarfLineStr *rz_bin_dwarf_line_str_new(RZ_NONNULL RZ_OWN RzBinEndianReader *reader) {
return RzBinDwarfStr_new(reader);
return rz_bin_dwarf_str_new(reader);
}
RZ_API RZ_OWN RzBinDwarfLineStr *rz_bin_dwarf_line_str_from_file(RZ_NONNULL RZ_BORROW RzBinFile *bf) {
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_line_str");
RzBinEndianReader *r = RzBinEndianReader_from_file(bf, ".debug_line_str", false);
RET_NULL_IF_FAIL(r);
return RzBinDwarfStr_new(r);
return rz_bin_dwarf_str_new(r);
}
RZ_API void rz_bin_dwarf_line_str_free(RzBinDwarfLineStr *str) {
RzBinDwarfStr_free(str);
rz_bin_dwarf_str_free(str);
}
RZ_API RZ_BORROW const char *rz_bin_dwarf_line_str_get(RZ_NONNULL RZ_BORROW RzBinDwarfLineStr *str, ut64 offset) {
return RzBinDwarfStr_get(str, offset);
return rz_bin_dwarf_str_get(str, offset);
}
7 changes: 4 additions & 3 deletions librz/bin/dwarf/loclists.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,11 @@ RZ_API RZ_OWN RzBinDwarfLocLists *rz_bin_dwarf_loclists_new(RzBinEndianReader *l
* \param dw RzBinDwarf instance
* \return RzBinDwarfLocListTable instance on success, NULL otherwise
*/
RZ_API RZ_OWN RzBinDwarfLocLists *rz_bin_dwarf_loclists_new_from_file(RZ_BORROW RZ_NONNULL RzBinFile *bf) {
RZ_API RZ_OWN RzBinDwarfLocLists *rz_bin_dwarf_loclists_new_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf, bool is_dwo) {
RET_NULL_IF_FAIL(bf);
RzBinEndianReader *loclists = RzBinEndianReader_from_file(bf, ".debug_loclists");
RzBinEndianReader *loc = RzBinEndianReader_from_file(bf, ".debug_loc");
RzBinEndianReader *loclists = RzBinEndianReader_from_file(bf, ".debug_loclists", is_dwo);
RzBinEndianReader *loc = RzBinEndianReader_from_file(bf, ".debug_loc", is_dwo);
if (!(loclists || loc)) {
RzBinEndianReader_free(loclists);
RzBinEndianReader_free(loc);
Expand Down
6 changes: 3 additions & 3 deletions librz/bin/dwarf/rnglists.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,10 @@ RZ_API RZ_OWN RzBinDwarfRngLists *rz_bin_dwarf_rnglists_new(
* \return the RzBinDwarfRngListTable instance on success, NULL otherwise
*/
RZ_API RZ_OWN RzBinDwarfRngLists *rz_bin_dwarf_rnglists_new_from_file(
RZ_BORROW RZ_NONNULL RzBinFile *bf) {
RZ_BORROW RZ_NONNULL RzBinFile *bf, bool is_dwo) {
RET_NULL_IF_FAIL(bf);
RzBinEndianReader *rnglists = RzBinEndianReader_from_file(bf, ".debug_rnglists");
RzBinEndianReader *ranges = RzBinEndianReader_from_file(bf, ".debug_ranges");
RzBinEndianReader *rnglists = RzBinEndianReader_from_file(bf, ".debug_rnglists", is_dwo);
RzBinEndianReader *ranges = RzBinEndianReader_from_file(bf, ".debug_ranges", is_dwo);
if (!(rnglists || ranges)) {
RzBinEndianReader_free(rnglists);
RzBinEndianReader_free(ranges);
Expand Down
Loading

0 comments on commit 2d02625

Please sign in to comment.