Skip to content

Commit

Permalink
Load split DWARF (#3833)
Browse files Browse the repository at this point in the history
- Add `read_debuglink` and `read_build_id`
- Fix `*.dwo` loading
- Try process DW_UT_skeleton
- Fix dwo_id
- Check buffer size
- Add `bin.dbginfo.debug_file_directory`
- Add test "Debugging Information in Separate Files"
  • Loading branch information
imbillow authored Oct 21, 2023
1 parent febfdd5 commit 7982454
Show file tree
Hide file tree
Showing 19 changed files with 1,043 additions and 164 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);
}
209 changes: 197 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,223 @@ 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(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(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;
}

static inline RzBinDWARF *dwarf_from_debuglink(
const char *file_directory,
RzList /*<const char *>*/ *debug_file_directorys,
const char *debuglink_path) {
RzBinDWARF *dw = NULL;
char *dir = NULL;
char *path = NULL;
char *file_dir = NULL;

path = rz_file_path_join(file_directory, debuglink_path);
if (rz_file_exists(path)) {
goto ok;
}
free(path);

dir = rz_file_path_join(file_directory, ".debug");
path = rz_file_path_join(dir, debuglink_path);
if (rz_file_exists(path)) {
goto ok;
}
free(dir);
free(path);

if (RZ_STR_ISNOTEMPTY(file_directory) && strlen(file_directory) >= 2 && file_directory[1] == ':') {
file_dir = rz_str_newf("/%c%s", file_directory[0], file_directory + 2);
} else {
file_dir = rz_str_new(file_directory);
}
RzListIter *it = NULL;
const char *debug_file_directory = NULL;
rz_list_foreach (debug_file_directorys, it, debug_file_directory) {
dir = rz_file_path_join(debug_file_directory, file_dir);
path = rz_file_path_join(dir, debuglink_path);
if (rz_file_exists(path)) {
goto ok;
}
free(dir);
free(path);
}

return NULL;
ok:
dw = rz_bin_dwarf_from_path(path, false);
free(dir);
free(path);
free(file_dir);
return dw;
}

static inline RzBinDWARF *dwarf_from_build_id(
RzList /*<const char *>*/ *debug_file_directorys,
const char *build_id_path) {
RzListIter *it = NULL;
const char *debug_file_directory = NULL;
rz_list_foreach (debug_file_directorys, it, debug_file_directory) {
char *dir = rz_file_path_join(debug_file_directory, ".build-id");
char *path = rz_file_path_join(dir, build_id_path);
if (rz_file_exists(path)) {
RzBinDWARF *dw = rz_bin_dwarf_from_path(path, false);
free(dir);
free(path);
return dw;
}
free(dir);
free(path);
}
return NULL;
}

RZ_API RZ_OWN RzBinDWARF *rz_bin_dwarf_search_debug_file_directory(
RZ_BORROW RZ_NONNULL RzBinFile *bf,
RZ_BORROW RZ_NONNULL RzList /*<const char *>*/ *debug_file_directorys) {
rz_return_val_if_fail(bf && debug_file_directorys, NULL);

RzBinDWARF *dw = NULL;
char *build_id = read_build_id(bf);
if (build_id) {
char *build_id_path = rz_str_newf("%c%c/%s", build_id[0], build_id[1], build_id + 2);
dw = dwarf_from_build_id(debug_file_directorys, build_id_path);
free(build_id);
free(build_id_path);
if (dw) {
return dw;
}
}
char *debuglink = read_debuglink(bf);
if (debuglink) {
char *file_abspath = rz_file_abspath(bf->file);
char *file_dir = file_abspath ? rz_file_dirname(file_abspath) : NULL;
if (file_dir) {
dw = dwarf_from_debuglink(file_dir, debug_file_directorys, debuglink);
}
free(debuglink);
free(file_dir);
if (dw) {
return dw;
}
}
return NULL;
}

/**
* \brief Load DWARF from split DWARF file
* \param filepath The file path
* \return RzBinDWARF pointer or NULL if failed
*/
RZ_API RZ_OWN RzBinDWARF *rz_bin_dwarf_from_path(
RZ_BORROW RZ_NONNULL const char *filepath, bool is_dwo) {
rz_return_val_if_fail(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, is_dwo);

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->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
Loading

0 comments on commit 7982454

Please sign in to comment.