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

Rewrite PDB parser #1517

Merged
merged 9 commits into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
504 changes: 265 additions & 239 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 @@ -145,12 +145,10 @@ rz_bin_sources = [
'format/zimg/zimg.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 @@ -171,6 +169,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 @@ -191,7 +190,8 @@ pkgconfig_mod.generate(rz_bin,
'rz_util',
'rz_io',
'rz_socket',
'rz_syscall'
'rz_syscall',
'rz_type'
],
description: 'rizin foundation libraries'
)
281 changes: 138 additions & 143 deletions librz/bin/pdb/dbi.c
Original file line number Diff line number Diff line change
@@ -1,164 +1,159 @@
// SPDX-FileCopyrightText: 2014-2020 inisider <inisider@gmail.com>
// SPDX-FileCopyrightText: 2021 Basstorm <basstorm@nyist.edu.cn>
// 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(RzPdbDbiStream *stream) {
RzPdbDbiStreamExHdr *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(RzPdbDbiStream *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(RzPdbDbiStreamExHdr *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(RzPdbDbiStream *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) {
Basstorm marked this conversation as resolved.
Show resolved Hide resolved
ut32 initial_seek = rz_buf_tell(buf);
RzPdbDbiStreamExHdr *hdr = RZ_NEW0(RzPdbDbiStreamExHdr);
if (!hdr) {
return false;
}
if (!rz_buf_read_le32(buf, &hdr->unknown)) {
return false;
}
if (!parse_dbi_stream_section_entry(hdr, buf)) {
return false;
}
if (!rz_buf_read_le16(buf, &hdr->Flags) ||
!rz_buf_read_le16(buf, &hdr->ModuleSymStream)) {
return false;
}
if (!rz_buf_read_le32(buf, &hdr->SymByteSize) ||
!rz_buf_read_le32(buf, &hdr->C11ByteSize) ||
!rz_buf_read_le32(buf, &hdr->C13ByteSize)) {
return false;
}
if (!rz_buf_read_le16(buf, &hdr->SourceFileCount) ||
!rz_buf_read_le16(buf, (ut16 *)&hdr->Padding)) {
return false;
}
if (!rz_buf_read_le32(buf, &hdr->Unused2) ||
!rz_buf_read_le32(buf, &hdr->SourceFileNameIndex) ||
!rz_buf_read_le32(buf, &hdr->PdbFilePathNameIndex)) {
return false;
}

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, str_length, RZ_BUF_CUR);
}

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, str_length, RZ_BUF_CUR);
}
read_len += rz_buf_tell(buf) - initial_seek;
if ((read_len % 4)) {
ut16 remain = 4 - (read_len % 4);
rz_buf_seek(buf, remain, RZ_BUF_CUR);
read_len += remain;
Basstorm marked this conversation as resolved.
Show resolved Hide resolved
}
rz_list_append(s->ex_hdrs, hdr);
}
if (read_len != ex_size) {
return false;
}
return true;
}

void init_dbi_stream(SDbiStream *dbi_stream) {
dbi_stream->free_ = free_dbi_stream;
static bool parse_dbi_dbg_header(RzPdbDbiStream *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, RzPdbMsfStream *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(RzPdbDbiStream);
RzPdbDbiStream *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, seek, RZ_BUF_CUR);
if (!parse_dbi_dbg_header(s, buf)) {
return false;
}
return true;
}
48 changes: 42 additions & 6 deletions librz/bin/pdb/dbi.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
// SPDX-FileCopyrightText: 2014 inisider <inisider@gmail.com>
// SPDX-FileCopyrightText: 2021 Basstorm <basstorm@nyist.edu.cn>
// SPDX-License-Identifier: LGPL-3.0-only

#ifndef DBI_H
#define DBI_H
#ifndef PDB_DBI_H
#define PDB_DBI_H

void init_dbi_stream(SDbiStream *dbi_stream);
void parse_dbi_stream(void *parsed_pdb_stream, RZ_STREAM_FILE *stream_file);
#include <rz_util.h>

#endif // DBI_H
enum dbi_stream_version {
DSV_VC41 = 930803,
DSV_V50 = 19960307,
DSV_V60 = 19970606,
DSV_V70 = 19990903,
DSV_V110 = 20091201
};

typedef struct SectionContribEntry {
ut16 Section;
char Padding1[2];
st32 Offset;
st32 Size;
ut32 Characteristics;
ut16 ModuleIndex;
char Padding2[2];
ut32 DataCrc;
ut32 RelocCrc;
} SectionContr;

typedef struct dbi_stream_ex_header_t {
ut32 unknown;
SectionContr sec_con;
ut16 Flags;
ut16 ModuleSymStream;
ut32 SymByteSize;
ut32 C11ByteSize;
ut32 C13ByteSize;
ut16 SourceFileCount;
char Padding[2];
ut32 Unused2;
ut32 SourceFileNameIndex;
ut32 PdbFilePathNameIndex;
char *ModuleName;
char *ObjFileName;
} RzPdbDbiStreamExHdr;

#endif
Loading