Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Rewrite PDB parser #1498

Closed
wants to merge 17 commits into from
Closed
497 changes: 259 additions & 238 deletions librz/analysis/type_pdb.c

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions librz/bin/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,10 @@ rz_bin_sources = [
'mangling/swift.c',

'pdb/dbi.c',
'pdb/fpo.c',
'pdb/gdata.c',
'pdb/omap.c',
'pdb/pdb.c',
'pdb/pdb_downloader.c',
'pdb/stream_file.c',
'pdb/stream_pe.c',
'pdb/tpi.c'
]
Expand All @@ -176,6 +174,7 @@ rz_bin = library('rz_bin', rz_bin_sources,
rz_syscall_dep,
rz_cons_dep,
rz_io_dep,
rz_type_dep,
],
install: true,
implicit_include_directories: false,
Expand All @@ -196,7 +195,8 @@ pkgconfig_mod.generate(rz_bin,
'rz_util',
'rz_io',
'rz_socket',
'rz_syscall'
'rz_syscall',
'rz_type'
],
description: 'rizin foundation libraries'
)
284 changes: 141 additions & 143 deletions librz/bin/pdb/dbi.c
Original file line number Diff line number Diff line change
@@ -1,164 +1,162 @@
// SPDX-FileCopyrightText: 2014-2020 inisider <[email protected]>
// SPDX-FileCopyrightText: 2021 Basstorm <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

#include "types.h"
#include "dbi.h"
#include "stream_file.h"
#include "tpi.h"
#include "pdb.h"

#define PDB_ALIGN 4

static void free_dbi_stream(void *stream) {
SDbiStream *t = (SDbiStream *)stream;
SDBIExHeader *dbi_ex_header = 0;

RzListIter *it = rz_list_iterator(t->dbiexhdrs);
while (rz_list_iter_next(it)) {
dbi_ex_header = (SDBIExHeader *)rz_list_iter_get(it);
free(dbi_ex_header->modName.name);
free(dbi_ex_header->objName.name);
free(dbi_ex_header);
RZ_IPI void free_dbi_stream(DbiStream *stream) {
DbiStreamExHdr *ex_hdr;
RzListIter *it;
rz_list_foreach (stream->ex_hdrs, it, ex_hdr) {
RZ_FREE(ex_hdr->ModuleName);
RZ_FREE(ex_hdr->ObjFileName);
RZ_FREE(ex_hdr);
}
rz_list_free(t->dbiexhdrs);
rz_list_free(stream->ex_hdrs);
}

static void parse_dbi_header(SDBIHeader *dbi_header, RZ_STREAM_FILE *stream_file) {
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->magic);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->version);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->age);
stream_file_read(stream_file, sizeof(ut16), (char *)&dbi_header->gssymStream);
stream_file_read(stream_file, sizeof(ut16), (char *)&dbi_header->vers);
stream_file_read(stream_file, sizeof(st16), (char *)&dbi_header->pssymStream);
stream_file_read(stream_file, sizeof(ut16), (char *)&dbi_header->pdbver);
stream_file_read(stream_file, sizeof(st16), (char *)&dbi_header->symrecStream);
stream_file_read(stream_file, sizeof(ut16), (char *)&dbi_header->pdbver2);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->module_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->seccon_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->secmap_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->filinf_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->tsmap_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->mfc_index);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->dbghdr_size);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->ecinfo_size);
stream_file_read(stream_file, sizeof(ut16), (char *)&dbi_header->flags);
stream_file_read(stream_file, 2, (char *)&dbi_header->machine);
stream_file_read(stream_file, sizeof(ut32), (char *)&dbi_header->resvd);
static bool parse_dbi_stream_header(DbiStream *s, RzBuffer *buf) {
return rz_buf_read_le32(buf, (ut32 *)&s->hdr.version_signature) &&
rz_buf_read_le32(buf, &s->hdr.version_header) &&
rz_buf_read_le32(buf, &s->hdr.age) &&
rz_buf_read_le16(buf, &s->hdr.global_stream_index) &&
rz_buf_read_le16(buf, &s->hdr.build_number) &&
rz_buf_read_le16(buf, &s->hdr.public_stream_index) &&
rz_buf_read_le16(buf, &s->hdr.pdb_dll_version) &&
rz_buf_read_le16(buf, &s->hdr.sym_record_stream) &&
rz_buf_read_le16(buf, &s->hdr.pdb_dll_rbld) &&
rz_buf_read_le32(buf, &s->hdr.mod_info_size) &&
rz_buf_read_le32(buf, &s->hdr.section_contribution_size) &&
rz_buf_read_le32(buf, &s->hdr.section_map_size) &&
rz_buf_read_le32(buf, &s->hdr.source_info_size) &&
rz_buf_read_le32(buf, &s->hdr.type_server_map_size) &&
rz_buf_read_le32(buf, &s->hdr.mfc_type_server_index) &&
rz_buf_read_le32(buf, &s->hdr.optional_dbg_header_size) &&
rz_buf_read_le32(buf, &s->hdr.ec_substream_size) &&
rz_buf_read_le16(buf, &s->hdr.flags) &&
rz_buf_read_le16(buf, &s->hdr.machine) &&
rz_buf_read_le32(buf, &s->hdr.padding);
}

static int parse_ssymbol_range(char *data, int max_len, SSymbolRange *symbol_range) {
int read_bytes = 0;

READ2(read_bytes, max_len, symbol_range->section, data, st16);
READ2(read_bytes, max_len, symbol_range->padding1, data, st16);
READ4(read_bytes, max_len, symbol_range->offset, data, st32);
READ4(read_bytes, max_len, symbol_range->size, data, st32);
READ4(read_bytes, max_len, symbol_range->flags, data, ut32);
READ4(read_bytes, max_len, symbol_range->module, data, st32);

// TODO: why not need to read this padding?
// READ2(read_bytes, max_len, symbol_range->padding2, data, short);
READ4(read_bytes, max_len, symbol_range->data_crc, data, ut32);
READ4(read_bytes, max_len, symbol_range->reloc_crc, data, ut32);

return read_bytes;
static bool parse_dbi_stream_section_entry(DbiStreamExHdr *hdr, RzBuffer *buf) {
return rz_buf_read_le16(buf, &hdr->sec_con.Section) &&
rz_buf_read_le16(buf, (ut16 *)&hdr->sec_con.Padding1) &&
rz_buf_read_le32(buf, (ut32 *)&hdr->sec_con.Offset) &&
rz_buf_read_le32(buf, (ut32 *)&hdr->sec_con.Size) &&
rz_buf_read_le32(buf, &hdr->sec_con.Characteristics) &&
rz_buf_read_le16(buf, &hdr->sec_con.ModuleIndex) &&
rz_buf_read_le16(buf, (ut16 *)&hdr->sec_con.Padding2) &&
rz_buf_read_le32(buf, &hdr->sec_con.DataCrc) &&
rz_buf_read_le32(buf, &hdr->sec_con.RelocCrc);
}

static int parse_dbi_ex_header(char *data, int max_len, SDBIExHeader *dbi_ex_header) {
ut32 read_bytes = 0, before_read_bytes = 0;

READ4(read_bytes, max_len, dbi_ex_header->opened, data, ut32);

before_read_bytes = read_bytes;
read_bytes += parse_ssymbol_range(data, max_len, &dbi_ex_header->range);
data += (read_bytes - before_read_bytes);

READ2(read_bytes, max_len, dbi_ex_header->flags, data, ut16);
READ2(read_bytes, max_len, dbi_ex_header->stream, data, st16);
READ4(read_bytes, max_len, dbi_ex_header->symSize, data, ut32);
READ4(read_bytes, max_len, dbi_ex_header->oldLineSize, data, ut32);
READ4(read_bytes, max_len, dbi_ex_header->lineSize, data, ut32);
READ2(read_bytes, max_len, dbi_ex_header->nSrcFiles, data, st16);
READ2(read_bytes, max_len, dbi_ex_header->padding1, data, st16);
READ4(read_bytes, max_len, dbi_ex_header->offsets, data, ut32);
READ4(read_bytes, max_len, dbi_ex_header->niSource, data, ut32);
READ4(read_bytes, max_len, dbi_ex_header->niCompiler, data, ut32);

before_read_bytes = read_bytes;
parse_scstring(&dbi_ex_header->modName, (unsigned char *)data, &read_bytes, max_len);
data += (read_bytes - before_read_bytes);

parse_scstring(&dbi_ex_header->objName, (unsigned char *)data, &read_bytes, max_len);
static bool parse_dbi_stream_ex_header(DbiStream *s, RzBuffer *buf) {
s->ex_hdrs = rz_list_new();
if (!s->ex_hdrs) {
// free s-dbi
return false;
}
ut32 ex_size = s->hdr.mod_info_size;
ut32 read_len = 0;
while (read_len < ex_size) {
DbiStreamExHdr *hdr = RZ_NEW0(DbiStreamExHdr);
if (!hdr) {
return false;
}
if (!rz_buf_read_le32(buf, &hdr->unknown)) {
return false;
}
read_len += sizeof(ut32);
if (!parse_dbi_stream_section_entry(hdr, buf)) {
return false;
}
read_len += sizeof(SectionContr);
if (!rz_buf_read_le16(buf, &hdr->Flags) ||
!rz_buf_read_le16(buf, &hdr->ModuleSymStream)) {
return false;
}
read_len += sizeof(ut16) * 2;
if (!rz_buf_read_le32(buf, &hdr->SymByteSize) ||
!rz_buf_read_le32(buf, &hdr->C11ByteSize) ||
!rz_buf_read_le32(buf, &hdr->C13ByteSize)) {
return false;
}
read_len += sizeof(ut32) * 3;
if (!rz_buf_read_le16(buf, &hdr->SourceFileCount) ||
!rz_buf_read_le16(buf, (ut16 *)&hdr->Padding)) {
return false;
}
read_len += sizeof(ut16) * 2;
if (!rz_buf_read_le32(buf, &hdr->Unused2) ||
!rz_buf_read_le32(buf, &hdr->SourceFileNameIndex) ||
!rz_buf_read_le32(buf, &hdr->PdbFilePathNameIndex)) {
return false;
}
read_len += sizeof(ut32) * 3;

return read_bytes;
}
hdr->ModuleName = rz_buf_get_string(buf, rz_buf_tell(buf));
ut32 str_length = strlen(hdr->ModuleName) + 1;
if (str_length) {
rz_buf_seek(buf, rz_buf_tell(buf) + str_length, RZ_BUF_SET);
read_len += str_length;
}

static void parse_dbg_header(SDbiDbgHeader *dbg_header, RZ_STREAM_FILE *stream_file) {
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_fpo);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_exception);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_fixup);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_omap_to_src);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_omap_from_src);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_section_hdr);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_token_rid_map);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_xdata);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_pdata);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_new_fpo);
stream_file_read(stream_file, sizeof(short), (char *)&dbg_header->sn_section_hdr_orig);
hdr->ObjFileName = rz_buf_get_string(buf, rz_buf_tell(buf));
str_length = strlen(hdr->ObjFileName) + 1;
if (str_length) {
rz_buf_seek(buf, rz_buf_tell(buf) + str_length, RZ_BUF_SET);
read_len += str_length;
}
if ((read_len % 4)) {
ut16 remain = 4 - (read_len % 4);
rz_buf_seek(buf, rz_buf_tell(buf) + remain, RZ_BUF_SET);
read_len += remain;
}
rz_list_append(s->ex_hdrs, hdr);
}
return true;
}

void init_dbi_stream(SDbiStream *dbi_stream) {
dbi_stream->free_ = free_dbi_stream;
static bool parse_dbi_dbg_header(DbiStream *s, RzBuffer *buf) {
if (!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_fpo) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_exception) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_fixup) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_omap_to_src) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_omap_from_src) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_section_hdr) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_token_rid_map) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_xdata) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_pdata) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_new_fpo) ||
!rz_buf_read_le16(buf, (ut16 *)&s->dbg_hdr.sn_section_hdr_orig)) {
return false;
}
return true;
}

void parse_dbi_stream(void *parsed_pdb_stream, RZ_STREAM_FILE *stream_file) {
SDbiStream *dbi_stream = (SDbiStream *)parsed_pdb_stream;
SDBIExHeader *dbi_ex_header = 0;
int pos = 0;
char *dbiexhdr_data = 0, *p_tmp = 0;
int size = 0, sz = 0;
int i = 0;

parse_dbi_header(&dbi_stream->dbi_header, stream_file);
pos += sizeof(SDBIHeader) - 2; // 2 because enum in C equal to 4, but
// to read just 2;
stream_file_seek(stream_file, pos, 0);

size = dbi_stream->dbi_header.module_size;
dbiexhdr_data = (char *)malloc(size);
if (!dbiexhdr_data) {
return;
RZ_IPI bool parse_dbi_stream(RzPdb *pdb, MsfStream *stream) {
if (!pdb || !stream) {
return false;
}
stream_file_read(stream_file, size, dbiexhdr_data);

dbi_stream->dbiexhdrs = rz_list_new();
p_tmp = dbiexhdr_data;
while (i < size) {
dbi_ex_header = (SDBIExHeader *)malloc(sizeof(SDBIExHeader));
if (!dbi_ex_header) {
break;
}
// TODO: rewrite for signature where can to do chech CAN_READ true?
sz = parse_dbi_ex_header(p_tmp, size, dbi_ex_header);
if ((sz % PDB_ALIGN)) {
sz = sz + (PDB_ALIGN - (sz % PDB_ALIGN));
}
i += sz;
p_tmp += sz;
rz_list_append(dbi_stream->dbiexhdrs, dbi_ex_header);
pdb->s_dbi = RZ_NEW0(DbiStream);
Basstorm marked this conversation as resolved.
Show resolved Hide resolved
DbiStream *s = pdb->s_dbi;
if (!s) {
RZ_LOG_ERROR("Error allocating memory.\n");
return false;
}
RzBuffer *buf = stream->stream_data;
// parse header
if (!parse_dbi_stream_header(s, buf) || !parse_dbi_stream_ex_header(s, buf)) {
return false;
}

free(dbiexhdr_data);

// "Section Contribution"
stream_file_seek(stream_file, dbi_stream->dbi_header.seccon_size, 1);
// "Section Map"
stream_file_seek(stream_file, dbi_stream->dbi_header.secmap_size, 1);
// "File Info"
stream_file_seek(stream_file, dbi_stream->dbi_header.filinf_size, 1);
// "TSM"
stream_file_seek(stream_file, dbi_stream->dbi_header.tsmap_size, 1);
// "EC"
stream_file_seek(stream_file, dbi_stream->dbi_header.ecinfo_size, 1);

parse_dbg_header(&dbi_stream->dbg_header, stream_file);
// skip these streams
ut64 seek = s->hdr.section_contribution_size + s->hdr.section_map_size +
s->hdr.source_info_size + s->hdr.type_server_map_size +
s->hdr.ec_substream_size;
rz_buf_seek(buf, rz_buf_tell(buf) + seek, RZ_BUF_SET);
if (!parse_dbi_dbg_header(s, buf)) {
return false;
}
return true;
}
Loading