mirror of
https://github.com/rizinorg/rizin.git
synced 2026-10-12 02:21:57 +00:00
Load symbols in modules from PDB (#4025)
* PDB: add module info parsing * Refactor PDB component * Refactor PDB/tpi * Fix read_pascal_string * Fix memory leaks * Add test `Modules from PDB`
This commit is contained in:
+199
-217
@@ -9,31 +9,29 @@
|
||||
#include <rz_analysis.h>
|
||||
#include "../bin/pdb/pdb.h"
|
||||
|
||||
static RzType *parse_type(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *parse_regular_type(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *parse_type_modifier(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzType *parse_type_pointer(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *parse_type_procedure(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *parse_type_array(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static void parse_type_arglist(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *arglist, RzPVector /*<RzCallableArg *>*/ *vec);
|
||||
static RzType *parse_type_mfunction(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name);
|
||||
static RzType *parse_type_onemethod(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *parse_type_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name);
|
||||
static RzType *parse_type_nest(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *parse_union(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeUnionMember *parse_union_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *parse_structure(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeStructMember *parse_struct_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *parse_enum(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeEnumCase *parse_enumerate(RzPdbTpiType *type);
|
||||
static RzType *pdb_type_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *modifier_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzType *pointer_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *procedure_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name);
|
||||
static RzType *array_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static void arglist_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *arglist, RzPVector /*<RzCallableArg *>*/ *vec);
|
||||
static RzType *mfunction_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name);
|
||||
static RzType *onemethod_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name);
|
||||
static RzType *nest_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *t, char *name);
|
||||
static RzType *union_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeUnionMember *union_member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info);
|
||||
static RzType *class_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeStructMember *class_member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *t);
|
||||
static RzType *enum_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type);
|
||||
static RzTypeEnumCase *enumerate_parse(RzPdbTpiType *type);
|
||||
static RzType *pdb_simple_type_parse(const RzTypeDB *typedb, const RzPdbTpiType *type);
|
||||
|
||||
static bool is_parsable_type(const TpiLeafType type) {
|
||||
return (type == LF_STRUCTURE ||
|
||||
type == LF_UNION ||
|
||||
type == LF_ENUM ||
|
||||
type == LF_CLASS ||
|
||||
type == LF_CLASS_19 ||
|
||||
type == LF_STRUCTURE_19);
|
||||
static bool is_parsable_type(const RzPdbTpiType *t) {
|
||||
const RzPDBTpiKind k = t->kind;
|
||||
return k == TpiKind_CLASS ||
|
||||
k == TpiKind_UNION ||
|
||||
k == TpiKind_ENUM;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,14 +47,27 @@ static char *create_type_name_from_offset(ut64 offset) {
|
||||
return str;
|
||||
}
|
||||
|
||||
static RzType *parse_type_array(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
static RzType *pdb_simple_type_parse(const RzTypeDB *typedb, const RzPdbTpiType *type) {
|
||||
rz_warn_if_fail(type->kind == TpiKind_SIMPLE_TYPE);
|
||||
const Tpi_LF_SimpleType *simple_type = type->data;
|
||||
char *error_msg = NULL;
|
||||
RzType *typ = rz_type_parse_string_single(typedb->parser, simple_type->type, &error_msg);
|
||||
if (error_msg) {
|
||||
RZ_LOG_ERROR("%s : Error parsing complex type member \"%s\" type:\n%s\n",
|
||||
__FUNCTION__, simple_type->type, error_msg);
|
||||
RZ_FREE(error_msg);
|
||||
}
|
||||
return typ;
|
||||
}
|
||||
|
||||
static RzType *array_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(type && stream && typedb, NULL);
|
||||
Tpi_LF_Array *lf_array = type->data;
|
||||
RzPdbTpiType *element = rz_bin_pdb_get_type_by_index(stream, lf_array->element_type);
|
||||
if (!element) {
|
||||
return NULL;
|
||||
}
|
||||
RzType *element_type = parse_type(typedb, stream, element, NULL);
|
||||
RzType *element_type = pdb_type_parse(typedb, stream, element, NULL);
|
||||
if (!element_type) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -70,46 +81,12 @@ static RzType *parse_type_array(const RzTypeDB *typedb, RzPdbTpiStream *stream,
|
||||
return typ;
|
||||
}
|
||||
|
||||
static RzType *parse_regular_type(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
rz_return_val_if_fail(type && stream && typedb, NULL);
|
||||
switch (type->leaf) {
|
||||
case LF_CLASS:
|
||||
case LF_CLASS_19:
|
||||
// TODO: https://github.com/rizinorg/rizin/issues/1205
|
||||
RZ_LOG_INFO("%s : LF_CLASS is not handled for now.\n", __FUNCTION__);
|
||||
break;
|
||||
case LF_STRUCTURE:
|
||||
case LF_STRUCTURE_19:
|
||||
return parse_structure(typedb, stream, type);
|
||||
case LF_MODIFIER:
|
||||
return parse_type_modifier(typedb, stream, type);
|
||||
case LF_ARRAY:
|
||||
return parse_type_array(typedb, stream, type);
|
||||
case LF_BITFIELD:
|
||||
// TODO: we don't have BITFIELD type for now https://github.com/rizinorg/rizin/issues/1240
|
||||
RZ_LOG_INFO("%s : LF_BITFIELD is not handled for now.\n", __FUNCTION__);
|
||||
break;
|
||||
case LF_POINTER:
|
||||
return parse_type_pointer(typedb, stream, type, name);
|
||||
case LF_PROCEDURE:
|
||||
return parse_type_procedure(typedb, stream, type, name);
|
||||
case LF_UNION:
|
||||
return parse_union(typedb, stream, type);
|
||||
case LF_ENUM:
|
||||
return parse_enum(typedb, stream, type);
|
||||
default:
|
||||
RZ_LOG_INFO("%s : unsupported leaf type 0x%x\n", __FUNCTION__, type->leaf);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzType *parse_type_modifier(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
static RzType *modifier_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(type && stream && typedb, NULL);
|
||||
Tpi_LF_Modifier *lf_modifier = type->data;
|
||||
RzPdbTpiType *m_utype = rz_bin_pdb_get_type_by_index(stream, lf_modifier->modified_type);
|
||||
if (m_utype) {
|
||||
RzType *typ = parse_type(typedb, stream, m_utype, NULL);
|
||||
RzType *typ = pdb_type_parse(typedb, stream, m_utype, NULL);
|
||||
if (typ && lf_modifier->umodifier.const_) {
|
||||
switch (typ->kind) {
|
||||
case RZ_TYPE_KIND_IDENTIFIER:
|
||||
@@ -127,7 +104,8 @@ static RzType *parse_type_modifier(const RzTypeDB *typedb, RzPdbTpiStream *strea
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzType *parse_type_pointer(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
static RzType *pointer_parse(
|
||||
const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
rz_return_val_if_fail(type && typedb, NULL);
|
||||
Tpi_LF_Pointer *lf_pointer = type->data;
|
||||
RzType *typ = RZ_NEW0(RzType);
|
||||
@@ -137,7 +115,7 @@ static RzType *parse_type_pointer(const RzTypeDB *typedb, RzPdbTpiStream *stream
|
||||
typ->kind = RZ_TYPE_KIND_POINTER;
|
||||
RzPdbTpiType *p_utype = rz_bin_pdb_get_type_by_index(stream, lf_pointer->utype);
|
||||
if (p_utype) {
|
||||
RzType *tmp = parse_type(typedb, stream, p_utype, name);
|
||||
RzType *tmp = pdb_type_parse(typedb, stream, p_utype, name);
|
||||
if (!tmp) {
|
||||
goto error;
|
||||
}
|
||||
@@ -149,40 +127,16 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzType *parse_type(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
rz_return_val_if_fail(type && typedb, NULL);
|
||||
RzType *typ;
|
||||
if (type->leaf == LF_SIMPLE_TYPE) {
|
||||
Tpi_LF_SimpleType *simple_type = type->data;
|
||||
char *error_msg = NULL;
|
||||
typ = rz_type_parse_string_single(typedb->parser, simple_type->type, &error_msg);
|
||||
if (error_msg) {
|
||||
RZ_LOG_ERROR("%s : Error parsing complex type member \"%s\" type:\n%s\n", __FUNCTION__, simple_type->type, error_msg);
|
||||
RZ_FREE(error_msg);
|
||||
}
|
||||
return typ;
|
||||
} else {
|
||||
if (type->leaf == LF_POINTER) {
|
||||
return parse_type_pointer(typedb, stream, type, name);
|
||||
} else {
|
||||
return parse_regular_type(typedb, stream, type, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_type_arglist(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *arglist, RzPVector /*<RzCallableArg *>*/ *vec) {
|
||||
static void arglist_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *arglist, RzPVector /*<RzCallableArg *>*/ *vec) {
|
||||
rz_return_if_fail(arglist && typedb && vec);
|
||||
Tpi_LF_Arglist *lf_arglist = arglist->data;
|
||||
if (!vec) {
|
||||
return;
|
||||
}
|
||||
ut32 *ptr_types = lf_arglist->arg_type;
|
||||
for (int i = 0; i < lf_arglist->count; i++) {
|
||||
RzPdbTpiType *stype = rz_bin_pdb_get_type_by_index(stream, *ptr_types++);
|
||||
if (!stype) {
|
||||
continue;
|
||||
}
|
||||
RzType *type = parse_type(typedb, stream, stype, NULL);
|
||||
RzType *type = pdb_type_parse(typedb, stream, stype, NULL);
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
@@ -193,7 +147,8 @@ static void parse_type_arglist(const RzTypeDB *typedb, RzPdbTpiStream *stream, R
|
||||
}
|
||||
}
|
||||
|
||||
static RzType *parse_type_procedure(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
static RzType *procedure_parse(
|
||||
const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
rz_return_val_if_fail(type && stream && typedb, NULL);
|
||||
Tpi_LF_Procedure *lf_procedure = type->data;
|
||||
RzType *typ = RZ_NEW0(RzType);
|
||||
@@ -211,11 +166,11 @@ static RzType *parse_type_procedure(const RzTypeDB *typedb, RzPdbTpiStream *stre
|
||||
typ->callable->name = strdup(name);
|
||||
}
|
||||
|
||||
typ->callable->cc = rz_bin_pdb_calling_convention_as_string(lf_procedure->call_conv);
|
||||
typ->callable->cc = rz_bin_pdb_calling_convention_as_string(lf_procedure->func_attr.calling_convention);
|
||||
// parse return type
|
||||
RzPdbTpiType *ret_type = rz_bin_pdb_get_type_by_index(stream, lf_procedure->return_type);
|
||||
if (ret_type) {
|
||||
typ->callable->ret = parse_type(typedb, stream, ret_type, name);
|
||||
typ->callable->ret = pdb_type_parse(typedb, stream, ret_type, name);
|
||||
if (!typ->callable->ret) {
|
||||
typ->callable->noret = true;
|
||||
}
|
||||
@@ -228,13 +183,13 @@ static RzType *parse_type_procedure(const RzTypeDB *typedb, RzPdbTpiStream *stre
|
||||
}
|
||||
RzPdbTpiType *arglist = rz_bin_pdb_get_type_by_index(stream, lf_procedure->arg_list);
|
||||
if (arglist) {
|
||||
parse_type_arglist(typedb, stream, arglist, typ->callable->args);
|
||||
arglist_parse(typedb, stream, arglist, typ->callable->args);
|
||||
}
|
||||
rz_type_func_save((RzTypeDB *)typedb, callable);
|
||||
return typ;
|
||||
}
|
||||
|
||||
static RzType *parse_type_mfunction(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
static RzType *mfunction_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
rz_return_val_if_fail(type_info && stream && typedb, NULL);
|
||||
Tpi_LF_MFcuntion *lf_mfunction = type_info->data;
|
||||
RzType *type = RZ_NEW0(RzType);
|
||||
@@ -247,11 +202,11 @@ static RzType *parse_type_mfunction(const RzTypeDB *typedb, RzPdbTpiStream *stre
|
||||
type->kind = RZ_TYPE_KIND_CALLABLE;
|
||||
type->callable = callable;
|
||||
type->callable->name = strdup(name);
|
||||
type->callable->cc = rz_bin_pdb_calling_convention_as_string(lf_mfunction->call_conv);
|
||||
type->callable->cc = rz_bin_pdb_calling_convention_as_string(lf_mfunction->func_attr.calling_convention);
|
||||
// parse return type
|
||||
RzPdbTpiType *ret_type = rz_bin_pdb_get_type_by_index(stream, lf_mfunction->return_type);
|
||||
if (ret_type) {
|
||||
type->callable->ret = parse_type(typedb, stream, ret_type, name);
|
||||
type->callable->ret = pdb_type_parse(typedb, stream, ret_type, name);
|
||||
if (!type->callable->ret) {
|
||||
type->callable->noret = true;
|
||||
}
|
||||
@@ -264,13 +219,14 @@ static RzType *parse_type_mfunction(const RzTypeDB *typedb, RzPdbTpiStream *stre
|
||||
}
|
||||
RzPdbTpiType *arglist = rz_bin_pdb_get_type_by_index(stream, lf_mfunction->arglist);
|
||||
if (arglist) {
|
||||
parse_type_arglist(typedb, stream, arglist, type->callable->args);
|
||||
arglist_parse(typedb, stream, arglist, type->callable->args);
|
||||
}
|
||||
rz_type_func_save((RzTypeDB *)typedb, callable);
|
||||
return type;
|
||||
}
|
||||
|
||||
static RzType *parse_type_onemethod(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
static RzType *onemethod_parse(
|
||||
const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
rz_return_val_if_fail(type_info && typedb, NULL);
|
||||
Tpi_LF_OneMethod *lf_onemethod = type_info->data;
|
||||
char *name = rz_bin_pdb_get_type_name(type_info);
|
||||
@@ -278,68 +234,78 @@ static RzType *parse_type_onemethod(const RzTypeDB *typedb, RzPdbTpiStream *stre
|
||||
if (!utype) {
|
||||
return NULL;
|
||||
}
|
||||
if (utype->leaf == LF_MFUNCTION) {
|
||||
return parse_type_mfunction(typedb, stream, utype, name);
|
||||
if (utype->kind == TpiKind_MFUNCTION) {
|
||||
return mfunction_parse(typedb, stream, utype, name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RzType *parse_type_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
static RzType *member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
rz_return_val_if_fail(type_info && typedb, NULL);
|
||||
Tpi_LF_Member *lf_member = type_info->data;
|
||||
|
||||
RzPdbTpiType *utype = rz_bin_pdb_get_type_by_index(stream, lf_member->index);
|
||||
RzPdbTpiType *utype = rz_bin_pdb_get_type_by_index(stream, lf_member->field_type);
|
||||
if (!utype) {
|
||||
return NULL;
|
||||
}
|
||||
return parse_type(typedb, stream, utype, name);
|
||||
return pdb_type_parse(typedb, stream, utype, name);
|
||||
}
|
||||
|
||||
static RzType *parse_type_static_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
static RzType *static_member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
rz_return_val_if_fail(type_info && typedb, NULL);
|
||||
Tpi_LF_StaticMember *lf_stmember = type_info->data;
|
||||
RzPdbTpiType *utype = rz_bin_pdb_get_type_by_index(stream, lf_stmember->index);
|
||||
RzPdbTpiType *utype = rz_bin_pdb_get_type_by_index(stream, lf_stmember->field_type);
|
||||
if (!utype) {
|
||||
return NULL;
|
||||
}
|
||||
return parse_type(typedb, stream, utype, name);
|
||||
return pdb_type_parse(typedb, stream, utype, name);
|
||||
}
|
||||
|
||||
static RzType *parse_type_nest(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
static RzType *type_new_identify(const char *name, RzTypeIdentifierKind k) {
|
||||
if (RZ_STR_ISEMPTY(name)) {
|
||||
return NULL;
|
||||
}
|
||||
RzType *t = RZ_NEW0(RzType);
|
||||
if (!t) {
|
||||
return NULL;
|
||||
}
|
||||
t->kind = RZ_TYPE_KIND_IDENTIFIER;
|
||||
t->identifier.name = rz_str_new(name);
|
||||
t->identifier.kind = k;
|
||||
return t;
|
||||
}
|
||||
|
||||
static RzTypeIdentifierKind iKind_from_bKind(RzBaseTypeKind k) {
|
||||
switch (k) {
|
||||
case RZ_BASE_TYPE_KIND_STRUCT: return RZ_TYPE_IDENTIFIER_KIND_STRUCT;
|
||||
case RZ_BASE_TYPE_KIND_UNION: return RZ_TYPE_IDENTIFIER_KIND_UNION;
|
||||
case RZ_BASE_TYPE_KIND_ENUM: return RZ_TYPE_IDENTIFIER_KIND_ENUM;
|
||||
case RZ_BASE_TYPE_KIND_TYPEDEF:
|
||||
case RZ_BASE_TYPE_KIND_ATOMIC: return RZ_TYPE_IDENTIFIER_KIND_UNSPECIFIED;
|
||||
}
|
||||
return RZ_TYPE_IDENTIFIER_KIND_UNSPECIFIED;
|
||||
}
|
||||
|
||||
static RzType *nest_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info, char *name) {
|
||||
rz_return_val_if_fail(type_info && stream && typedb, NULL);
|
||||
Tpi_LF_NestType *lf_nest = type_info->data;
|
||||
RzPdbTpiType *utype = rz_bin_pdb_get_type_by_index(stream, lf_nest->index);
|
||||
RzPdbTpiType *utpi = rz_bin_pdb_get_type_by_index(stream, lf_nest->index);
|
||||
if (!utpi) {
|
||||
return NULL;
|
||||
}
|
||||
const char *uname = rz_bin_pdb_get_type_name(utpi);
|
||||
if (uname) {
|
||||
const RzBaseType *bt = rz_type_db_get_base_type(typedb, uname);
|
||||
if (bt) {
|
||||
return type_new_identify(bt->name, iKind_from_bKind(bt->kind));
|
||||
}
|
||||
}
|
||||
|
||||
RzType *utype = pdb_type_parse(typedb, stream, utpi, NULL);
|
||||
if (!utype) {
|
||||
return NULL;
|
||||
}
|
||||
const char *name = rz_bin_pdb_get_type_name(utype);
|
||||
if (name) {
|
||||
RzBaseType *b_type = rz_type_db_get_base_type(typedb, name);
|
||||
if (b_type && b_type->type) {
|
||||
if (b_type->type->kind == RZ_TYPE_KIND_IDENTIFIER) {
|
||||
return rz_type_clone(b_type->type);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RzType *n_type = parse_type(typedb, stream, utype, NULL);
|
||||
if (!n_type) {
|
||||
return NULL;
|
||||
}
|
||||
RzBaseType *btype = rz_type_base_type_new(RZ_BASE_TYPE_KIND_TYPEDEF);
|
||||
if (!btype) {
|
||||
return NULL;
|
||||
}
|
||||
btype->name = name ? strdup(name) : create_type_name_from_offset(lf_nest->index);
|
||||
btype->type = n_type;
|
||||
if (!rz_type_db_save_base_type(typedb, btype)) {
|
||||
return NULL;
|
||||
}
|
||||
if (n_type->kind == RZ_TYPE_KIND_IDENTIFIER) {
|
||||
return rz_type_clone(n_type);
|
||||
}
|
||||
return NULL;
|
||||
return rz_type_clone(utype);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -347,47 +313,50 @@ static RzType *parse_type_nest(const RzTypeDB *typedb, RzPdbTpiStream *stream, R
|
||||
*
|
||||
* \param typedb Types DB instance
|
||||
* \param stream TPI Stream
|
||||
* \param type_info Current RzPdbTpiType (member)
|
||||
* \param t Current RzPdbTpiType (member)
|
||||
* \return RzTypeStructMember* parsed member, NULL if fail
|
||||
*/
|
||||
static RzTypeStructMember *parse_struct_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
rz_return_val_if_fail(type_info, NULL);
|
||||
static RzTypeStructMember *class_member_parse(
|
||||
const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *t) {
|
||||
rz_return_val_if_fail(t, NULL);
|
||||
char *name = NULL;
|
||||
ut64 offset = 0;
|
||||
RzType *type = NULL;
|
||||
switch (type_info->leaf) {
|
||||
case LF_ONEMETHOD: {
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_onemethod(typedb, stream, type_info);
|
||||
switch (t->kind) {
|
||||
case TpiKind_ONEMETHOD: {
|
||||
name = rz_bin_pdb_get_type_name(t);
|
||||
type = onemethod_parse(typedb, stream, t);
|
||||
break;
|
||||
}
|
||||
case LF_MEMBER: {
|
||||
offset = rz_bin_pdb_get_type_val(type_info);
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_member(typedb, stream, type_info, name);
|
||||
case TpiKind_MEMBER: {
|
||||
offset = rz_bin_pdb_get_type_val(t);
|
||||
name = rz_bin_pdb_get_type_name(t);
|
||||
type = member_parse(typedb, stream, t, name);
|
||||
break;
|
||||
}
|
||||
case LF_STMEMBER: {
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_static_member(typedb, stream, type_info, name);
|
||||
case TpiKind_STMEMBER: {
|
||||
name = rz_bin_pdb_get_type_name(t);
|
||||
type = static_member_parse(typedb, stream, t, name);
|
||||
break;
|
||||
}
|
||||
case LF_NESTTYPE: {
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_nest(typedb, stream, type_info);
|
||||
case TpiKind_NESTTYPE: {
|
||||
name = rz_bin_pdb_get_type_name(t);
|
||||
type = nest_parse(typedb, stream, t, rz_str_new(name));
|
||||
break;
|
||||
}
|
||||
case LF_BCLASS:
|
||||
case TpiKind_VBCLASS:
|
||||
case TpiKind_BCLASS:
|
||||
// For structure, we don't need base class for now
|
||||
goto cleanup;
|
||||
case LF_METHOD:
|
||||
case TpiKind_METHOD:
|
||||
// TODO: need to handle overloaded methods here
|
||||
goto cleanup;
|
||||
case LF_VFUNCTAB:
|
||||
case TpiKind_VFUNCTAB:
|
||||
// For structure, we don't need vtable for now
|
||||
goto cleanup;
|
||||
default:
|
||||
RZ_LOG_ERROR("%s : unsupported leaf type 0x%x\n", __FUNCTION__, type_info->leaf);
|
||||
rz_warn_if_reached();
|
||||
RZ_LOG_ERROR("%s : unsupported leaf type 0x%x\n", __FUNCTION__, t->leaf);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!type) {
|
||||
@@ -436,7 +405,7 @@ static RzType *create_rztype(RzPdbTpiType *type, RzTypeIdentifierKind kind, cons
|
||||
}
|
||||
|
||||
#define PDB_PROCESS_LF_INDEX \
|
||||
if (member_info->leaf == LF_INDEX) { \
|
||||
if (member_info->kind == TpiKind_INDEX) { \
|
||||
ut32 index = rz_bin_pdb_get_type_val(member_info); \
|
||||
if (index == type->index) { \
|
||||
break; \
|
||||
@@ -460,7 +429,7 @@ static RzType *create_rztype(RzPdbTpiType *type, RzTypeIdentifierKind kind, cons
|
||||
* \param stream TPI Stream
|
||||
* \param type Current type
|
||||
*/
|
||||
static RzType *parse_structure(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
static RzType *class_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(typedb && stream && type, NULL);
|
||||
|
||||
RzBaseType *base_type = NULL;
|
||||
@@ -510,12 +479,13 @@ foreach_members:
|
||||
rz_pvector_foreach (members, it) {
|
||||
RzPdbTpiType *member_info = *it;
|
||||
PDB_PROCESS_LF_INDEX;
|
||||
RzTypeStructMember *struct_member = parse_struct_member(typedb, stream, member_info);
|
||||
RzTypeStructMember *struct_member = class_member_parse(typedb, stream, member_info);
|
||||
if (!struct_member) {
|
||||
continue; // skip the failure
|
||||
}
|
||||
void *element = rz_vector_push(&base_type->struct_data.members, struct_member);
|
||||
if (!element) {
|
||||
rz_warn_if_reached();
|
||||
rz_type_base_struct_member_free(struct_member, NULL);
|
||||
return NULL;
|
||||
}
|
||||
@@ -538,29 +508,30 @@ foreach_members:
|
||||
* \param type_info Current RzPdbTpiType (member)
|
||||
* \return RzTypeUnionMember* parsed member, NULL if fail
|
||||
*/
|
||||
static RzTypeUnionMember *parse_union_member(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
static RzTypeUnionMember *union_member_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type_info) {
|
||||
rz_return_val_if_fail(type_info && stream && typedb, NULL);
|
||||
char *name = NULL;
|
||||
ut64 offset = 0;
|
||||
RzType *type = NULL;
|
||||
switch (type_info->leaf) {
|
||||
case LF_ONEMETHOD: {
|
||||
switch (type_info->kind) {
|
||||
case TpiKind_ONEMETHOD: {
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_onemethod(typedb, stream, type_info);
|
||||
type = onemethod_parse(typedb, stream, type_info);
|
||||
break;
|
||||
}
|
||||
case LF_MEMBER: {
|
||||
case TpiKind_MEMBER: {
|
||||
offset = rz_bin_pdb_get_type_val(type_info);
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_member(typedb, stream, type_info, name);
|
||||
type = member_parse(typedb, stream, type_info, name);
|
||||
break;
|
||||
}
|
||||
case LF_NESTTYPE: {
|
||||
case TpiKind_NESTTYPE: {
|
||||
name = rz_bin_pdb_get_type_name(type_info);
|
||||
type = parse_type_nest(typedb, stream, type_info);
|
||||
type = nest_parse(typedb, stream, type_info, rz_str_new(name));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rz_warn_if_reached();
|
||||
RZ_LOG_ERROR("%s : unsupported leaf type 0x%x\n", __FUNCTION__, type_info->leaf);
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -588,7 +559,7 @@ cleanup:
|
||||
* \param stream TPI Stream
|
||||
* \param type_info Current RzPdbTpiType (enum case)
|
||||
*/
|
||||
static RzType *parse_union(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
static RzType *union_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(typedb && stream && type, NULL);
|
||||
|
||||
RzBaseType *base_type = NULL;
|
||||
@@ -638,7 +609,7 @@ foreach_members:
|
||||
rz_pvector_foreach (members, it) {
|
||||
RzPdbTpiType *member_info = *it;
|
||||
PDB_PROCESS_LF_INDEX;
|
||||
RzTypeUnionMember *union_member = parse_union_member(typedb, stream, member_info);
|
||||
RzTypeUnionMember *union_member = union_member_parse(typedb, stream, member_info);
|
||||
if (!union_member) {
|
||||
continue; // skip the failure
|
||||
}
|
||||
@@ -660,17 +631,15 @@ foreach_members:
|
||||
|
||||
/**
|
||||
* \brief Parse enum case
|
||||
* \param type_info Current type info (enum case)
|
||||
* \param type Current type info (enum case)
|
||||
* \return RzTypeEnumCase* parsed enum case, NULL if fail
|
||||
*/
|
||||
static RzTypeEnumCase *parse_enumerate(RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(type && type->leaf == LF_ENUMERATE, NULL);
|
||||
static RzTypeEnumCase *enumerate_parse(RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(type && type->kind == TpiKind_ENUMERATE, NULL);
|
||||
|
||||
char *name = NULL;
|
||||
ut64 value = 0;
|
||||
// sometimes, the type doesn't have get_val for some reason
|
||||
value = rz_bin_pdb_get_type_val(type);
|
||||
name = rz_bin_pdb_get_type_name(type);
|
||||
ut64 value = rz_bin_pdb_get_type_val(type);
|
||||
char *name = rz_bin_pdb_get_type_name(type);
|
||||
RzTypeEnumCase *cas = RZ_NEW0(RzTypeEnumCase);
|
||||
if (!cas) {
|
||||
goto cleanup;
|
||||
@@ -689,7 +658,7 @@ cleanup:
|
||||
* \param stream TPI Stream
|
||||
* \param type Current type
|
||||
*/
|
||||
static RzType *parse_enum(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
static RzType *enum_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(typedb && type, NULL);
|
||||
Tpi_LF_Enum *lf_enum = type->data;
|
||||
// assert all member functions we need info from
|
||||
@@ -722,7 +691,7 @@ static RzType *parse_enum(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbT
|
||||
rz_type_base_type_free(base_type);
|
||||
return NULL;
|
||||
}
|
||||
RzType *btype = parse_type(typedb, stream, utype, NULL);
|
||||
RzType *btype = pdb_type_parse(typedb, stream, utype, NULL);
|
||||
if (!btype) {
|
||||
rz_type_base_type_free(base_type);
|
||||
return NULL;
|
||||
@@ -746,7 +715,7 @@ foreach_members:
|
||||
rz_pvector_foreach (members, it) {
|
||||
RzPdbTpiType *member_info = *it;
|
||||
PDB_PROCESS_LF_INDEX;
|
||||
RzTypeEnumCase *enum_case = parse_enumerate(member_info);
|
||||
RzTypeEnumCase *enum_case = enumerate_parse(member_info);
|
||||
if (!enum_case) {
|
||||
continue; // skip it, move forward
|
||||
}
|
||||
@@ -765,6 +734,53 @@ foreach_members:
|
||||
return base_type->type ? rz_type_clone(base_type->type) : NULL;
|
||||
}
|
||||
|
||||
static RzType *pdb_type_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type, char *name) {
|
||||
switch (type->kind) {
|
||||
case TpiKind_SIMPLE_TYPE:
|
||||
return pdb_simple_type_parse(typedb, type);
|
||||
case TpiKind_CLASS:
|
||||
return class_parse(typedb, stream, type);
|
||||
case TpiKind_UNION:
|
||||
return union_parse(typedb, stream, type);
|
||||
case TpiKind_ENUM:
|
||||
return enum_parse(typedb, stream, type);
|
||||
case TpiKind_MODIFIER:
|
||||
return modifier_parse(typedb, stream, type);
|
||||
case TpiKind_ARRAY:
|
||||
return array_parse(typedb, stream, type);
|
||||
case TpiKind_POINTER:
|
||||
return pointer_parse(typedb, stream, type, name);
|
||||
case TpiKind_PROCEDURE:
|
||||
return procedure_parse(typedb, stream, type, name);
|
||||
case TpiKind_MFUNCTION:
|
||||
return mfunction_parse(typedb, stream, type, name);
|
||||
case TpiKind_BITFIELD:
|
||||
case TpiKind_BCLASS:
|
||||
case TpiKind_FILEDLIST:
|
||||
case TpiKind_ENUMERATE:
|
||||
case TpiKind_ARGLIST:
|
||||
case TpiKind_METHODLIST:
|
||||
case TpiKind_VTSHAPE:
|
||||
case TpiKind_VFTABLE:
|
||||
case TpiKind_LABEL:
|
||||
case TpiKind_NESTTYPE:
|
||||
case TpiKind_MEMBER:
|
||||
case TpiKind_METHOD:
|
||||
case TpiKind_ONEMETHOD:
|
||||
case TpiKind_VFUNCTAB:
|
||||
case TpiKind_STMEMBER:
|
||||
case TpiKind_VBCLASS:
|
||||
case TpiKind_INDEX:
|
||||
return NULL;
|
||||
default:
|
||||
rz_warn_if_reached();
|
||||
RZ_LOG_DEBUG("Unknown type record: #0x%" PFMT32x ": leaf=0x%" PFMT32x "\n",
|
||||
type->index, type->leaf);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Delegate the type parsing to appropriate function
|
||||
*
|
||||
@@ -774,41 +790,7 @@ foreach_members:
|
||||
*/
|
||||
RZ_API RzType *rz_type_db_pdb_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *type) {
|
||||
rz_return_val_if_fail(typedb && type, NULL);
|
||||
|
||||
switch (type->leaf) {
|
||||
case LF_SIMPLE_TYPE: {
|
||||
Tpi_LF_SimpleType *simple_type = type->data;
|
||||
char *error_msg = NULL;
|
||||
RzType *typ = rz_type_parse_string_single(typedb->parser, simple_type->type, &error_msg);
|
||||
if (error_msg) {
|
||||
RZ_LOG_ERROR("%s : Error parsing complex type member \"%s\" type:\n%s\n", __FUNCTION__, simple_type->type, error_msg);
|
||||
RZ_FREE(error_msg);
|
||||
}
|
||||
return typ;
|
||||
}
|
||||
case LF_CLASS:
|
||||
case LF_CLASS_19:
|
||||
case LF_STRUCTURE:
|
||||
case LF_STRUCTURE_19:
|
||||
return parse_structure(typedb, stream, type);
|
||||
case LF_UNION:
|
||||
return parse_union(typedb, stream, type);
|
||||
case LF_ENUM:
|
||||
return parse_enum(typedb, stream, type);
|
||||
case LF_MODIFIER:
|
||||
return parse_type_modifier(typedb, stream, type);
|
||||
case LF_ARRAY:
|
||||
return parse_type_array(typedb, stream, type);
|
||||
case LF_POINTER:
|
||||
return parse_type_pointer(typedb, stream, type, NULL);
|
||||
case LF_PROCEDURE:
|
||||
return parse_type_procedure(typedb, stream, type, NULL);
|
||||
default:
|
||||
RZ_LOG_DEBUG("Unknown type record: #0x%" PFMT32x ": leaf=0x%" PFMT32x "\n",
|
||||
type->index, type->leaf);
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
return pdb_type_parse(typedb, stream, type, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -832,7 +814,7 @@ RZ_API void rz_type_db_pdb_load(const RzTypeDB *typedb, const RzPdb *pdb) {
|
||||
RBIter it;
|
||||
RzPdbTpiType *type;
|
||||
rz_rbtree_foreach (stream->types, it, type, RzPdbTpiType, rb) {
|
||||
if (type && is_parsable_type(type->leaf)) {
|
||||
if (type && is_parsable_type(type)) {
|
||||
rz_type_db_pdb_parse(typedb, stream, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ int PE_(bin_pe_init_security)(RzBinPEObj *bin) {
|
||||
PE_DWord paddr = data_dir_security->VirtualAddress;
|
||||
ut32 size = data_dir_security->Size;
|
||||
if (size < 8 || paddr > bin->size || paddr + size > bin->size) {
|
||||
RZ_LOG_INFO("Invalid certificate table");
|
||||
RZ_LOG_INFO("Invalid certificate table\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@ rz_bin_sources = [
|
||||
'pdb/stream_pe.c',
|
||||
'pdb/tpi.c',
|
||||
'pdb/symbol.c',
|
||||
'pdb/modi.c',
|
||||
|
||||
'dwarf/abbrev.c',
|
||||
'dwarf/addr.c',
|
||||
|
||||
+79
-112
@@ -4,18 +4,18 @@
|
||||
|
||||
#include "pdb.h"
|
||||
|
||||
RZ_IPI void free_dbi_stream(RzPdbDbiStream *stream) {
|
||||
RZ_IPI void dbi_stream_free(RzPdbDbiStream *stream) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
void **it;
|
||||
rz_pvector_foreach (stream->modules, it) {
|
||||
PDB_DBIModule *m = *it;
|
||||
RZ_FREE(m->module_name);
|
||||
RZ_FREE(m->object_file_name);
|
||||
RZ_FREE(m);
|
||||
}
|
||||
rz_list_free(stream->ex_hdrs);
|
||||
rz_pvector_free(stream->modules);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
@@ -42,113 +42,77 @@ static bool parse_dbi_stream_header(RzPdbDbiStream *s, RzBuffer *buf) {
|
||||
rz_buf_read_le32(buf, &s->hdr.padding);
|
||||
}
|
||||
|
||||
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 bool PDB_DBISectionContrbution_parse(RzBuffer *buf, PDB_DBISectionContrbution *section) {
|
||||
ut16 pad = 0;
|
||||
return rz_buf_read_le16(buf, §ion->offset.section_index) &&
|
||||
rz_buf_read_le16(buf, &pad) &&
|
||||
rz_buf_read_le32(buf, §ion->offset.offset) &&
|
||||
rz_buf_read_le32(buf, §ion->size) &&
|
||||
rz_buf_read_le32(buf, §ion->characteristics) &&
|
||||
rz_buf_read_le16(buf, §ion->module) &&
|
||||
rz_buf_read_le16(buf, §ion->pad) &&
|
||||
rz_buf_read_le32(buf, §ion->data_crc) &&
|
||||
rz_buf_read_le32(buf, §ion->reloc_crc);
|
||||
}
|
||||
|
||||
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;
|
||||
bool result = true;
|
||||
while (read_len < ex_size) {
|
||||
ut32 initial_seek = rz_buf_tell(buf);
|
||||
RzPdbDbiStreamExHdr *hdr = RZ_NEW0(RzPdbDbiStreamExHdr);
|
||||
if (!hdr) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!rz_buf_read_le32(buf, &hdr->unknown)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!parse_dbi_stream_section_entry(hdr, buf)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!rz_buf_read_le16(buf, &hdr->Flags) ||
|
||||
!rz_buf_read_le16(buf, &hdr->ModuleSymStream)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!rz_buf_read_le32(buf, &hdr->SymByteSize) ||
|
||||
!rz_buf_read_le32(buf, &hdr->C11ByteSize) ||
|
||||
!rz_buf_read_le32(buf, &hdr->C13ByteSize)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!rz_buf_read_le16(buf, &hdr->SourceFileCount) ||
|
||||
!rz_buf_read_le16(buf, (ut16 *)&hdr->Padding)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
if (!rz_buf_read_le32(buf, &hdr->Unused2) ||
|
||||
!rz_buf_read_le32(buf, &hdr->SourceFileNameIndex) ||
|
||||
!rz_buf_read_le32(buf, &hdr->PdbFilePathNameIndex)) {
|
||||
result = false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
rz_list_append(s->ex_hdrs, hdr);
|
||||
err:
|
||||
if (!result) {
|
||||
free(hdr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (read_len != ex_size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
static bool PDB_DBIModule_parse(RzBuffer *b, PDB_DBIModule *m) {
|
||||
return rz_buf_read_le32(b, &m->opened) &&
|
||||
PDB_DBISectionContrbution_parse(b, &m->section) &&
|
||||
rz_buf_read_le16(b, &m->flags) &&
|
||||
rz_buf_read_le16(b, &m->stream) &&
|
||||
rz_buf_read_le32(b, &m->symbols_size) &&
|
||||
rz_buf_read_le32(b, &m->line_size) &&
|
||||
rz_buf_read_le32(b, &m->c13_line_size) &&
|
||||
rz_buf_read_le16(b, &m->files) &&
|
||||
rz_buf_read_le16(b, &m->pad) &&
|
||||
rz_buf_read_le32(b, &m->filename_offsets) &&
|
||||
rz_buf_read_le32(b, &m->source) &&
|
||||
rz_buf_read_le32(b, &m->compiler) &&
|
||||
rz_buf_read_string(b, &m->module_name) > 0 &&
|
||||
rz_buf_read_string(b, &m->object_file_name) > 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return 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);
|
||||
}
|
||||
|
||||
RZ_IPI bool parse_dbi_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
static bool modules_parse(RzPdbDbiStream *s, RzBuffer *stream_buffer) {
|
||||
s->modules = rz_pvector_new(NULL);
|
||||
if (!s->modules) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RzBuffer *b = rz_buf_new_slice(stream_buffer, s->hdr_size, s->hdr.mod_info_size);
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
while (!buf_empty(b)) {
|
||||
PDB_DBIModule *m = RZ_NEW0(PDB_DBIModule);
|
||||
if (!(m && PDB_DBIModule_parse(b, m) &&
|
||||
buf_align(b, 4))) {
|
||||
free(m);
|
||||
goto err;
|
||||
}
|
||||
rz_pvector_push(s->modules, m);
|
||||
}
|
||||
rz_buf_free(b);
|
||||
return true;
|
||||
err:
|
||||
rz_buf_free(b);
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_IPI bool dbi_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
if (!pdb || !stream) {
|
||||
return false;
|
||||
}
|
||||
@@ -159,16 +123,19 @@ RZ_IPI bool parse_dbi_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
return false;
|
||||
}
|
||||
RzBuffer *buf = stream->stream_data;
|
||||
// parse header
|
||||
if (!parse_dbi_stream_header(s, buf) || !parse_dbi_stream_ex_header(s, buf)) {
|
||||
if (!parse_dbi_stream_header(s, buf)) {
|
||||
return false;
|
||||
}
|
||||
s->hdr_size = rz_buf_tell(buf);
|
||||
if (!modules_parse(s, buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip these streams
|
||||
ut64 seek = s->hdr.section_contribution_size + s->hdr.section_map_size +
|
||||
ut64 pos = s->hdr_size + s->hdr.mod_info_size + 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);
|
||||
rz_buf_seek(buf, pos, RZ_BUF_SET);
|
||||
if (!parse_dbi_dbg_header(s, buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+29
-28
@@ -4,7 +4,10 @@
|
||||
#ifndef PDB_DBI_H
|
||||
#define PDB_DBI_H
|
||||
|
||||
#include <rz_util.h>
|
||||
#include <rz_pdb.h>
|
||||
|
||||
RZ_IPI bool dbi_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void dbi_stream_free(RzPdbDbiStream *stream);
|
||||
|
||||
enum dbi_stream_version {
|
||||
DSV_VC41 = 930803,
|
||||
@@ -14,33 +17,31 @@ enum dbi_stream_version {
|
||||
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 {
|
||||
PDBSectionOffset offset;
|
||||
ut32 size;
|
||||
ut32 characteristics;
|
||||
ut16 module;
|
||||
ut16 pad;
|
||||
ut32 data_crc;
|
||||
ut32 reloc_crc;
|
||||
} PDB_DBISectionContrbution;
|
||||
|
||||
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;
|
||||
typedef struct {
|
||||
ut32 opened;
|
||||
PDB_DBISectionContrbution section;
|
||||
ut16 flags;
|
||||
ut16 stream;
|
||||
ut32 symbols_size;
|
||||
ut32 line_size;
|
||||
ut32 c13_line_size;
|
||||
ut16 files;
|
||||
ut16 pad;
|
||||
ut32 filename_offsets;
|
||||
ut32 source;
|
||||
ut32 compiler;
|
||||
char *module_name;
|
||||
char *object_file_name;
|
||||
} PDB_DBIModule;
|
||||
|
||||
#endif
|
||||
+7
-22
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "pdb.h"
|
||||
|
||||
RZ_IPI bool parse_gdata_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
RZ_IPI bool gdata_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
rz_return_val_if_fail(pdb && stream, false);
|
||||
PDBSymbolTable *syms = pdb_global_symbols(pdb);
|
||||
if (!syms) {
|
||||
@@ -16,37 +16,22 @@ RZ_IPI bool parse_gdata_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
RzPdbGDataStream *s = pdb->s_gdata;
|
||||
if (!s) {
|
||||
RZ_LOG_ERROR("Error allocating memory.\n");
|
||||
return false;
|
||||
}
|
||||
s->global_symbols = rz_pvector_new(free);
|
||||
if (!s->global_symbols) {
|
||||
return false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
PDBSymbolIter iter = { 0 };
|
||||
PDBSymbolTable_iter(syms, &iter);
|
||||
while (true) {
|
||||
PDBSymbol *symbol = RZ_NEW0(PDBSymbol);
|
||||
if (!symbol) {
|
||||
goto err;
|
||||
}
|
||||
if (!PDBSymbolIter_next(&iter, symbol)) {
|
||||
free(symbol);
|
||||
break;
|
||||
}
|
||||
if (!symbol->data) {
|
||||
free(symbol);
|
||||
continue;
|
||||
}
|
||||
rz_pvector_push(s->global_symbols, symbol);
|
||||
if (!PDBSymbolIter_collect(&iter, &s->global_symbols)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
free(syms);
|
||||
return true;
|
||||
err:
|
||||
free(syms);
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_IPI void free_gdata_stream(RzPdbGDataStream *stream) {
|
||||
RZ_IPI void gdata_stream_free(RzPdbGDataStream *stream) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: 2023 billow <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "modi.h"
|
||||
|
||||
static bool PDBModuleInfo_symbols(const PDBModuleInfo *modi, PDBSymbolIter *iter) {
|
||||
RzBuffer *b = rz_buf_new_slice(modi->stream, 0, modi->symbols_size);
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
if (modi->symbols_size > 0) {
|
||||
ut32 sig = 0;
|
||||
if (!rz_buf_read_le32(b, &sig)) {
|
||||
goto err;
|
||||
}
|
||||
if (sig != CV_SIGNATURE_C13) {
|
||||
RZ_LOG_ERROR("Unsupported symbol data format: 0x%" PFMT32x "\n", sig);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
iter->b = b;
|
||||
return true;
|
||||
err:
|
||||
rz_buf_free(b);
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_IPI bool PDBModuleInfo_parse(const RzPdb *pdb, const PDB_DBIModule *m, PDBModuleInfo *modi) {
|
||||
if (!(pdb && m && modi)) {
|
||||
return false;
|
||||
}
|
||||
modi->stream_index = m->stream;
|
||||
modi->symbols_size = m->symbols_size;
|
||||
if (modi->symbols_size == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const RzPdbMsfStream *stream = pdb_raw_steam(pdb, modi->stream_index);
|
||||
if (!stream) {
|
||||
return false;
|
||||
}
|
||||
modi->stream = stream->stream_data;
|
||||
|
||||
PDBSymbolIter iter = { 0 };
|
||||
if (!PDBModuleInfo_symbols(modi, &iter)) {
|
||||
return false;
|
||||
}
|
||||
if (!PDBSymbolIter_collect(&iter, &modi->symbols)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-FileCopyrightText: 2023 billow <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#ifndef MODI_H
|
||||
#define MODI_H
|
||||
|
||||
#include <rz_util/rz_buf.h>
|
||||
#include "dbi.h"
|
||||
#include "pdb.h"
|
||||
|
||||
#define CV_SIGNATURE_C6 0L // Actual signature is >64K
|
||||
#define CV_SIGNATURE_C7 1L // First explicit signature
|
||||
#define CV_SIGNATURE_C11 2L // C11 (vc5.x) 32-bit types
|
||||
#define CV_SIGNATURE_C13 4L // C13 (vc7.x) zero terminated names
|
||||
#define CV_SIGNATURE_RESERVED 5L // All signatures from 5 to 64K are reserved
|
||||
|
||||
RZ_IPI bool PDBModuleInfo_parse(const RzPdb *pdb, const PDB_DBIModule *m, PDBModuleInfo *modi);
|
||||
|
||||
#endif // MODI_H
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "pdb.h"
|
||||
|
||||
RZ_IPI bool parse_omap_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
RZ_IPI bool omap_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
rz_return_val_if_fail(pdb && stream, false);
|
||||
if (!pdb->s_omap) {
|
||||
pdb->s_omap = RZ_NEW0(RzPdbOmapStream);
|
||||
@@ -39,7 +39,7 @@ RZ_IPI bool parse_omap_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_IPI void free_omap_stream(RzPdbOmapStream *stream) {
|
||||
RZ_IPI void omap_stream_free(RzPdbOmapStream *stream) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
@@ -117,9 +117,11 @@ static ut64 pdb_omap_remap(RZ_NONNULL RzPdbOmapStream *omap_stream, ut64 address
|
||||
* \param section_offset The section offset
|
||||
* \return The relative virtual address
|
||||
*/
|
||||
RZ_API ut64 rz_bin_pdb_to_rva(RZ_NONNULL const RzPdb *pdb, const PDBSectionOffset *section_offset) {
|
||||
RZ_API ut64 rz_bin_pdb_to_rva(
|
||||
RZ_BORROW RZ_NONNULL const RzPdb *pdb,
|
||||
RZ_BORROW RZ_NONNULL const PDBSectionOffset *section_offset) {
|
||||
static const ut64 DEFAULT = UT64_MAX;
|
||||
rz_return_val_if_fail(pdb && pdb->s_pe, DEFAULT);
|
||||
rz_return_val_if_fail(pdb && pdb->s_pe && section_offset, DEFAULT);
|
||||
PeImageSectionHeader *section_hdr = pdb_section_hdr_by_index(pdb->s_pe, section_offset->section_index);
|
||||
if (!section_hdr) {
|
||||
return DEFAULT;
|
||||
|
||||
+55
-72
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "pdb.h"
|
||||
|
||||
static bool parse_pdb_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
static bool pdb_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
if (!pdb || !stream) {
|
||||
return false;
|
||||
}
|
||||
@@ -35,75 +35,58 @@ static bool parse_pdb_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_stream(
|
||||
RzPdb *pdb, ut32 index, bool (*f)(RzPdb *, RzPdbMsfStream *), bool try) {
|
||||
RzPdbMsfStream *stream = pdb_raw_steam(pdb, index);
|
||||
if (!stream) {
|
||||
return try;
|
||||
}
|
||||
return f(pdb, stream);
|
||||
}
|
||||
|
||||
static bool parse_streams(RzPdb *pdb) {
|
||||
RzListIter *it;
|
||||
RzPdbMsfStream *ms;
|
||||
rz_list_foreach (pdb->streams, it, ms) {
|
||||
switch (ms->stream_idx) {
|
||||
case PDB_STREAM_ROOT:
|
||||
break;
|
||||
case PDB_STREAM_PDB:
|
||||
if (!parse_pdb_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse pdb stream failed.\n");
|
||||
if (!(parse_stream(pdb, PDB_STREAM_PDB, pdb_stream_parse, false) &&
|
||||
parse_stream(pdb, PDB_STREAM_TPI, tpi_stream_parse, false) &&
|
||||
parse_stream(pdb, PDB_STREAM_DBI, dbi_stream_parse, false))) {
|
||||
return false;
|
||||
}
|
||||
if (!(parse_stream(pdb, pdb->s_dbi->hdr.sym_record_stream, gdata_stream_parse, true) &&
|
||||
parse_stream(pdb, pdb->s_dbi->dbg_hdr.sn_section_hdr, pe_stream_parse, true) &&
|
||||
parse_stream(pdb, pdb->s_dbi->dbg_hdr.sn_section_hdr_orig, pe_stream_parse, true) &&
|
||||
parse_stream(pdb, pdb->s_dbi->dbg_hdr.sn_omap_to_src, omap_stream_parse, true) &&
|
||||
parse_stream(pdb, pdb->s_dbi->dbg_hdr.sn_omap_from_src, omap_stream_parse, true))) {
|
||||
return false;
|
||||
}
|
||||
if (pdb->s_dbi->modules) {
|
||||
pdb->module_infos = rz_pvector_new(NULL);
|
||||
void **modit;
|
||||
rz_pvector_foreach (pdb->s_dbi->modules, modit) {
|
||||
const PDB_DBIModule *m = *modit;
|
||||
PDBModuleInfo *modi = RZ_NEW0(PDBModuleInfo);
|
||||
if (!modi) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PDB_STREAM_TPI:
|
||||
if (!parse_tpi_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse tpi stream failed.\n");
|
||||
if (!PDBModuleInfo_parse(pdb, m, modi)) {
|
||||
free(modi);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PDB_STREAM_DBI:
|
||||
if (!parse_dbi_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse dbi stream failed.\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
if (!pdb->s_dbi) {
|
||||
break;
|
||||
}
|
||||
if (ms->stream_idx == pdb->s_dbi->hdr.sym_record_stream) {
|
||||
if (!parse_gdata_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse gdata stream failed.\n");
|
||||
return false;
|
||||
}
|
||||
} else if (ms->stream_idx == pdb->s_dbi->dbg_hdr.sn_section_hdr ||
|
||||
ms->stream_idx == pdb->s_dbi->dbg_hdr.sn_section_hdr_orig) {
|
||||
if (!parse_pe_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse pe stream failed.\n");
|
||||
return false;
|
||||
}
|
||||
} else if (ms->stream_idx == pdb->s_dbi->dbg_hdr.sn_omap_to_src ||
|
||||
ms->stream_idx == pdb->s_dbi->dbg_hdr.sn_omap_from_src) {
|
||||
if (!parse_omap_stream(pdb, ms)) {
|
||||
RZ_LOG_ERROR("Parse omap stream failed.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
rz_pvector_push(pdb->module_infos, modi);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_IPI RzPdbMsfStream *pdb_raw_steam(RzPdb *pdb, ut16 index) {
|
||||
if (!(pdb && pdb->streams)) {
|
||||
RZ_IPI RzPdbMsfStream *pdb_raw_steam(const RzPdb *pdb, ut16 index) {
|
||||
if (!(pdb && pdb->streams && pdb->msd)) {
|
||||
return NULL;
|
||||
}
|
||||
RzListIter *it;
|
||||
RzPdbMsfStream *ms;
|
||||
rz_list_foreach (pdb->streams, it, ms) {
|
||||
if (ms->stream_idx == index) {
|
||||
return ms;
|
||||
}
|
||||
if (index >= pdb->msd->NumStreams) {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
return rz_pvector_at(pdb->streams, index);
|
||||
}
|
||||
|
||||
RZ_IPI PDBSymbolTable *pdb_global_symbols(RzPdb *pdb) {
|
||||
RZ_IPI PDBSymbolTable *pdb_global_symbols(const RzPdb *pdb) {
|
||||
if (!(pdb && pdb->s_dbi)) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -143,29 +126,28 @@ static ut64 count_blocks(ut64 length, ut64 block_size) {
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
static RzList /*<RzPdbMsfStream *>*/ *pdb7_extract_streams(RzPdb *pdb, RzPdbMsfStreamDirectory *msd) {
|
||||
RzList *streams = rz_list_newf(msf_stream_free);
|
||||
static RzPVector /*<RzPdbMsfStream *>*/ *pdb7_extract_streams(RzPdb *pdb, RzPdbMsfStreamDirectory *msd) {
|
||||
RzPVector *streams = rz_pvector_new_with_len(msf_stream_free, msd->NumStreams);
|
||||
if (!streams) {
|
||||
goto error_memory;
|
||||
}
|
||||
for (size_t i = 0; i < msd->NumStreams; i++) {
|
||||
RzPdbMsfStream *stream = RZ_NEW0(RzPdbMsfStream);
|
||||
if (!stream) {
|
||||
rz_list_free(streams);
|
||||
rz_pvector_free(streams);
|
||||
goto error_memory;
|
||||
}
|
||||
stream->stream_idx = i;
|
||||
stream->stream_size = msd->StreamSizes[i];
|
||||
stream->blocks_num = count_blocks(stream->stream_size, pdb->super_block->block_size);
|
||||
if (!stream->stream_size) {
|
||||
stream->stream_data = NULL;
|
||||
rz_list_append(streams, stream);
|
||||
rz_pvector_set(streams, stream->stream_idx, stream);
|
||||
continue;
|
||||
}
|
||||
ut8 *stream_data = (ut8 *)malloc((size_t)stream->blocks_num * pdb->super_block->block_size);
|
||||
if (!stream_data) {
|
||||
RZ_FREE(stream);
|
||||
rz_list_free(streams);
|
||||
rz_pvector_free(streams);
|
||||
RZ_LOG_ERROR("Error allocating memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
@@ -174,7 +156,7 @@ static RzList /*<RzPdbMsfStream *>*/ *pdb7_extract_streams(RzPdb *pdb, RzPdbMsfS
|
||||
if (!rz_buf_read_le32(msd->sd, &block_idx)) {
|
||||
RZ_FREE(stream);
|
||||
RZ_FREE(stream_data);
|
||||
rz_list_free(streams);
|
||||
rz_pvector_free(streams);
|
||||
return NULL;
|
||||
}
|
||||
rz_buf_seek(pdb->buf, (long long)block_idx * pdb->super_block->block_size, RZ_BUF_SET);
|
||||
@@ -184,12 +166,11 @@ static RzList /*<RzPdbMsfStream *>*/ *pdb7_extract_streams(RzPdb *pdb, RzPdbMsfS
|
||||
if (!stream->stream_data) {
|
||||
RZ_FREE(stream);
|
||||
RZ_FREE(stream_data);
|
||||
rz_list_free(streams);
|
||||
rz_pvector_free(streams);
|
||||
goto error_memory;
|
||||
}
|
||||
rz_list_append(streams, stream);
|
||||
rz_pvector_set(streams, stream->stream_idx, stream);
|
||||
}
|
||||
msf_stream_directory_free(msd);
|
||||
return streams;
|
||||
|
||||
error_memory:
|
||||
@@ -291,9 +272,9 @@ static bool pdb7_parse(RzPdb *pdb) {
|
||||
RZ_LOG_ERROR("Error extracting stream directory.\n");
|
||||
goto error;
|
||||
}
|
||||
pdb->msd = msd;
|
||||
pdb->streams = pdb7_extract_streams(pdb, msd);
|
||||
if (!pdb->streams) {
|
||||
msf_stream_directory_free(msd);
|
||||
RZ_LOG_ERROR("Error extracting streams.\n");
|
||||
goto error;
|
||||
}
|
||||
@@ -399,12 +380,14 @@ RZ_API void rz_bin_pdb_free(RzPdb *pdb) {
|
||||
}
|
||||
rz_buf_free(pdb->buf);
|
||||
free(pdb->super_block);
|
||||
rz_list_free(pdb->streams);
|
||||
msf_stream_directory_free(pdb->msd);
|
||||
rz_pvector_free(pdb->streams);
|
||||
rz_pvector_free(pdb->module_infos);
|
||||
free(pdb->s_pdb);
|
||||
free_dbi_stream(pdb->s_dbi);
|
||||
free_gdata_stream(pdb->s_gdata);
|
||||
free_omap_stream(pdb->s_omap);
|
||||
free_tpi_stream(pdb->s_tpi);
|
||||
free_pe_stream(pdb->s_pe);
|
||||
dbi_stream_free(pdb->s_dbi);
|
||||
gdata_stream_free(pdb->s_gdata);
|
||||
omap_stream_free(pdb->s_omap);
|
||||
tpi_stream_free(pdb->s_tpi);
|
||||
pe_stream_free(pdb->s_pe);
|
||||
free(pdb);
|
||||
}
|
||||
|
||||
+73
-18
@@ -10,30 +10,85 @@
|
||||
#include "stream_pe.h"
|
||||
#include "tpi.h"
|
||||
#include "symbol.h"
|
||||
#include "modi.h"
|
||||
|
||||
RZ_IPI RzPdbMsfStream *pdb_raw_steam(RzPdb *pdb, ut16 index);
|
||||
RZ_IPI PDBSymbolTable *pdb_global_symbols(RzPdb *pdb);
|
||||
#define map_err(x) \
|
||||
if (!(x)) { \
|
||||
goto err; \
|
||||
}
|
||||
|
||||
static inline RzBuffer *buf_take(RzBuffer *b, ut32 len) {
|
||||
if (!(b && len)) {
|
||||
return NULL;
|
||||
}
|
||||
RzBuffer *type_buffer = rz_buf_new_slice(b, rz_buf_tell(b), len);
|
||||
if (!type_buffer) {
|
||||
return NULL;
|
||||
}
|
||||
rz_buf_seek(b, len, RZ_BUF_CUR);
|
||||
return type_buffer;
|
||||
}
|
||||
|
||||
static inline bool buf_empty(RzBuffer *b) {
|
||||
if (!b) {
|
||||
return true;
|
||||
}
|
||||
return rz_buf_tell(b) >= rz_buf_size(b);
|
||||
}
|
||||
|
||||
static inline void buf_read_padding(RzBuffer *b) {
|
||||
if (!b) {
|
||||
return;
|
||||
}
|
||||
while (!buf_empty(b) && rz_buf_peek(b) > 0xf0) {
|
||||
ut8 padding = 0;
|
||||
if (!rz_buf_read8(b, &padding)) {
|
||||
return;
|
||||
}
|
||||
if (padding > 0xf0) {
|
||||
rz_buf_seek(b, (padding & 0x0f) - 1, RZ_BUF_CUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool buf_read_u8_pascal_string(RzBuffer *b, char **result) {
|
||||
ut8 length = 0;
|
||||
if (!rz_buf_read8(b, &length)) {
|
||||
return false;
|
||||
}
|
||||
*result = RZ_NEWS0(char, length);
|
||||
if (!*result) {
|
||||
return false;
|
||||
}
|
||||
return rz_buf_read(b, (ut8 *)*result, length);
|
||||
}
|
||||
|
||||
static inline bool buf_align(RzBuffer *b, ut64 alignment) {
|
||||
const ut64 diff = rz_buf_tell(b) % alignment;
|
||||
if (diff <= 0) {
|
||||
return true;
|
||||
}
|
||||
ut64 off = rz_buf_tell(b);
|
||||
if (rz_buf_size(b) - off < alignment - diff) {
|
||||
return false;
|
||||
}
|
||||
return rz_buf_seek(b, alignment - diff, RZ_BUF_CUR) == off + alignment - diff;
|
||||
}
|
||||
|
||||
RZ_IPI RzPdbMsfStream *pdb_raw_steam(const RzPdb *pdb, ut16 index);
|
||||
RZ_IPI PDBSymbolTable *pdb_global_symbols(const RzPdb *pdb);
|
||||
|
||||
// OMAP
|
||||
RZ_IPI bool parse_omap_stream(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void free_omap_stream(RzPdbOmapStream *stream);
|
||||
RZ_IPI bool omap_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void omap_stream_free(RzPdbOmapStream *stream);
|
||||
RZ_IPI int omap_remap(void *stream, int address);
|
||||
|
||||
// GDATA
|
||||
RZ_IPI bool parse_gdata_stream(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void free_gdata_stream(RzPdbGDataStream *stream);
|
||||
|
||||
// DBI
|
||||
RZ_IPI bool parse_dbi_stream(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void free_dbi_stream(RzPdbDbiStream *stream);
|
||||
RZ_IPI bool gdata_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void gdata_stream_free(RzPdbGDataStream *stream);
|
||||
|
||||
// PE
|
||||
RZ_IPI bool parse_pe_stream(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void free_pe_stream(RzPdbPeStream *stream);
|
||||
RZ_IPI bool pe_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI void pe_stream_free(RzPdbPeStream *stream);
|
||||
|
||||
// TPI
|
||||
RZ_IPI bool parse_tpi_stream(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI RzPdbTpiType *parse_simple_type(RzPdbTpiStream *stream, ut32 idx);
|
||||
RZ_IPI void free_tpi_stream(RzPdbTpiStream *stream);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@ static bool parse_image_header(PeImageSectionHeader *hdr, RzBuffer *buf) {
|
||||
rz_buf_read_le32(buf, &hdr->charactestics);
|
||||
}
|
||||
|
||||
RZ_IPI bool parse_pe_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
RZ_IPI bool pe_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
rz_return_val_if_fail(pdb && stream, false);
|
||||
if (!pdb->s_pe) {
|
||||
pdb->s_pe = RZ_NEW0(RzPdbPeStream);
|
||||
@@ -50,7 +50,7 @@ RZ_IPI bool parse_pe_stream(RzPdb *pdb, RzPdbMsfStream *stream) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
RZ_IPI void free_pe_stream(RzPdbPeStream *stream) {
|
||||
RZ_IPI void pe_stream_free(RzPdbPeStream *stream) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
+93
-12
@@ -3,10 +3,7 @@
|
||||
|
||||
#include "symbol.h"
|
||||
|
||||
#define map_err(x) \
|
||||
if (!(x)) { \
|
||||
goto err; \
|
||||
}
|
||||
#include "pdb.h"
|
||||
|
||||
RZ_IPI bool PDBSectionOffset_parse(RzBuffer *b, PDBSectionOffset *section_offset) {
|
||||
if (!section_offset) {
|
||||
@@ -25,7 +22,7 @@ RZ_IPI bool PDBSectionOffset_parse(RzBuffer *b, PDBSectionOffset *section_offset
|
||||
|
||||
static bool symbol_name_parse(RzBuffer *b, PDBSymbolKind kind, char **result) {
|
||||
if (kind < S_ST_MAX) {
|
||||
// TODO: pascal
|
||||
return buf_read_u8_pascal_string(b, result);
|
||||
} else {
|
||||
return rz_buf_read_string(b, result) > 0;
|
||||
}
|
||||
@@ -124,14 +121,16 @@ err:
|
||||
|
||||
RZ_IPI PDBSymbol *PDBSymbolTable_symbol_by_index(PDBSymbolTable *symbol_table, PDBSymbolIndex index) {
|
||||
PDBSymbolIter iter = { 0 };
|
||||
PDBSymbol *symbol = NULL;
|
||||
map_err(PDBSymbolTable_iter(symbol_table, &iter));
|
||||
map_err(PDBSymbolIter_seek(&iter, index));
|
||||
PDBSymbol *symbol = RZ_NEW0(PDBSymbol);
|
||||
symbol = RZ_NEW0(PDBSymbol);
|
||||
map_err(symbol);
|
||||
map_err(PDBSymbolIter_next(&iter, symbol));
|
||||
|
||||
return symbol;
|
||||
err:
|
||||
free(symbol);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -148,14 +147,14 @@ RZ_IPI bool PDBSymbolIter_next(PDBSymbolIter *iter, PDBSymbol *symbol) {
|
||||
if (length < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
b = rz_buf_new_slice(iter->b, rz_buf_tell(iter->b), length);
|
||||
map_err(b);
|
||||
const ut64 begin = rz_buf_tell(iter->b);
|
||||
rz_buf_seek(iter->b, length, RZ_BUF_CUR);
|
||||
|
||||
if (!symbol) {
|
||||
continue;
|
||||
goto loop_continue;
|
||||
}
|
||||
|
||||
b = rz_buf_new_slice(iter->b, begin, length);
|
||||
map_err(b);
|
||||
symbol->index = index;
|
||||
symbol->length = length;
|
||||
map_err(PDBSymbol_parse(b, symbol));
|
||||
@@ -163,10 +162,16 @@ RZ_IPI bool PDBSymbolIter_next(PDBSymbolIter *iter, PDBSymbol *symbol) {
|
||||
switch (symbol->raw_kind) {
|
||||
case S_ALIGN:
|
||||
case S_SKIP:
|
||||
continue;
|
||||
goto loop_continue;
|
||||
default:
|
||||
if (!symbol->data) {
|
||||
goto loop_continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
loop_continue:
|
||||
rz_buf_free(b);
|
||||
b = NULL;
|
||||
}
|
||||
err:
|
||||
rz_buf_free(b);
|
||||
@@ -180,3 +185,79 @@ RZ_IPI bool PDBSymbolIter_seek(PDBSymbolIter *iter, PDBSymbolIndex index) {
|
||||
err:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void PDBSymbol_free(void *x) {
|
||||
if (!x) {
|
||||
return;
|
||||
}
|
||||
PDBSymbol *symbol = x;
|
||||
if (symbol->data) {
|
||||
switch (symbol->kind) {
|
||||
case PDB_Public: {
|
||||
PDBSPublic *d = symbol->data;
|
||||
free(d->name);
|
||||
break;
|
||||
}
|
||||
case PDB_Data: {
|
||||
PDBSData *d = symbol->data;
|
||||
free(d->name);
|
||||
break;
|
||||
}
|
||||
default: rz_warn_if_reached(); break;
|
||||
}
|
||||
free(symbol->data);
|
||||
}
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
RZ_IPI bool PDBSymbolIter_collect(PDBSymbolIter *iter, RzPVector /*<PDBSymbol *>*/ **psymbols) {
|
||||
RzPVector *symbols = *psymbols = rz_pvector_new(PDBSymbol_free);
|
||||
if (!symbols) {
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
PDBSymbol *symbol = RZ_NEW0(PDBSymbol);
|
||||
if (!symbol) {
|
||||
rz_pvector_free(symbols);
|
||||
psymbols = NULL;
|
||||
return false;
|
||||
}
|
||||
if (!PDBSymbolIter_next(iter, symbol)) {
|
||||
break;
|
||||
}
|
||||
rz_pvector_push(symbols, symbol);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API bool rz_pdb_all_symbols_foreach(
|
||||
RZ_BORROW RZ_NONNULL const RzPdb *pdb,
|
||||
RZ_BORROW RZ_NONNULL bool (*f)(const RzPdb *, const PDBSymbol *, void *),
|
||||
RZ_BORROW RZ_NULLABLE void *u) {
|
||||
rz_return_val_if_fail(pdb && f, false);
|
||||
if (!(pdb->s_gdata && pdb->s_gdata->global_symbols)) {
|
||||
return true;
|
||||
}
|
||||
void **it;
|
||||
rz_pvector_foreach (pdb->s_gdata->global_symbols, it) {
|
||||
if (!f(pdb, *it, u)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!pdb->module_infos) {
|
||||
return true;
|
||||
}
|
||||
void **modit;
|
||||
rz_pvector_foreach (pdb->module_infos, modit) {
|
||||
PDBModuleInfo *modi = *modit;
|
||||
if (!modi->symbols) {
|
||||
continue;
|
||||
}
|
||||
rz_pvector_foreach (modi->symbols, it) {
|
||||
if (!f(pdb, *it, u)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-71
@@ -8,79 +8,8 @@
|
||||
#include <rz_util/rz_buf.h>
|
||||
#include <rz_pdb.h>
|
||||
|
||||
typedef ut16 PDBSymbolKind;
|
||||
typedef ut32 PDBTypeIndex;
|
||||
typedef ut32 PDBSymbolIndex;
|
||||
|
||||
RZ_IPI bool PDBSectionOffset_parse(RzBuffer *b, PDBSectionOffset *section_offset);
|
||||
|
||||
typedef struct {
|
||||
bool global : 1;
|
||||
bool managed : 1;
|
||||
PDBTypeIndex type_index;
|
||||
PDBSectionOffset offset;
|
||||
char *name;
|
||||
} PDBSData;
|
||||
|
||||
RZ_IPI bool PDBSData_parse(RzBuffer *b, PDBSymbolKind kind, PDBSData *sdata);
|
||||
|
||||
typedef struct {
|
||||
bool code : 1;
|
||||
bool function : 1;
|
||||
bool managed : 1;
|
||||
bool msil : 1;
|
||||
PDBSectionOffset offset;
|
||||
char *name;
|
||||
} PDBSPublic;
|
||||
|
||||
RZ_IPI bool PDBSPublic_parse(RzBuffer *b, PDBSymbolKind kind, PDBSPublic *s);
|
||||
|
||||
typedef struct {
|
||||
PDBSymbolIndex index;
|
||||
PDBSymbolKind raw_kind;
|
||||
ut16 length;
|
||||
enum {
|
||||
PDB_ScopeEnd, /// End of a scope, such as a procedure.
|
||||
PDB_ObjName, /// Name of the object file of this module.
|
||||
PDB_RegisterVariable, /// A Register variable.
|
||||
PDB_Constant, /// A constant value.
|
||||
PDB_UserDefinedType, /// A user defined type.
|
||||
PDB_MultiRegisterVariable, /// A Register variable spanning multiple registers.
|
||||
PDB_Data, /// Static data, such as a global variable.
|
||||
PDB_Public, /// A public symbol with a mangled name.
|
||||
PDB_Procedure, /// A procedure, such as a function or method.
|
||||
PDB_ThreadStorage, /// A thread local variable.
|
||||
PDB_CompileFlags, /// Flags used to compile a module.
|
||||
PDB_UsingNamespace, /// A using namespace directive.
|
||||
PDB_ProcedureReference, /// Reference to a [`ProcedureSymbol`].
|
||||
PDB_DataReference, /// Reference to an imported variable.
|
||||
PDB_AnnotationReference, /// Reference to an annotation.
|
||||
PDB_Trampoline, /// Trampoline thunk.
|
||||
PDB_Export, /// An exported symbol.
|
||||
PDB_Local, /// A local symbol in optimized code.
|
||||
PDB_BuildInfo, /// Reference to build information.
|
||||
PDB_InlineSite, /// The callsite of an inlined function.
|
||||
PDB_InlineSiteEnd, /// End of an inline callsite.
|
||||
PDB_ProcedureEnd, /// End of a procedure.
|
||||
PDB_Label, /// A label.
|
||||
PDB_Block, /// A block.
|
||||
PDB_RegisterRelative, /// Data allocated relative to a register.
|
||||
PDB_Thunk, /// A thunk.
|
||||
PDB_SeparatedCode, /// A block of separated code.
|
||||
PDB_DefRange, /// A live range of a variable.
|
||||
PDB_DefRangeSubField, /// A live range of a sub field of a variable.
|
||||
PDB_DefRangeRegister, /// A live range of a register variable.
|
||||
PDB_DefRangeFramePointerRelative, /// A live range of a frame pointer-relative variable.
|
||||
PDB_DefRangeFramePointerRelativeFullScope, /// A frame-pointer variable which is valid in the full scope of the function.
|
||||
PDB_DefRangeSubFieldRegister, /// A live range of a sub field of a register variable.
|
||||
PDB_DefRangeRegisterRelative, /// A live range of a variable related to a register.
|
||||
PDB_BasePointerRelative, /// A base pointer-relative variable.
|
||||
PDB_FrameProcedure, /// Extra frame and proc information.
|
||||
PDB_CallSiteInfo, /// Indirect call site information.
|
||||
} kind;
|
||||
void *data;
|
||||
} PDBSymbol;
|
||||
|
||||
RZ_IPI bool PDBSymbol_parse(RzBuffer *b, PDBSymbol *symbol);
|
||||
|
||||
typedef struct {
|
||||
@@ -96,5 +25,6 @@ RZ_IPI PDBSymbol *PDBSymbolTable_symbol_by_index(PDBSymbolTable *symbol_table, P
|
||||
|
||||
RZ_IPI bool PDBSymbolIter_next(PDBSymbolIter *iter, PDBSymbol *symbol);
|
||||
RZ_IPI bool PDBSymbolIter_seek(PDBSymbolIter *iter, PDBSymbolIndex index);
|
||||
RZ_IPI bool PDBSymbolIter_collect(PDBSymbolIter *iter, RzPVector /*<PDBSymbol *>*/ **psymbols);
|
||||
|
||||
#endif // RIZIN_SYMBOL_H
|
||||
|
||||
+850
-1031
File diff suppressed because it is too large
Load Diff
+68
-64
@@ -6,6 +6,10 @@
|
||||
|
||||
#include <rz_util.h>
|
||||
|
||||
RZ_IPI bool tpi_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream);
|
||||
RZ_IPI RzPdbTpiType *simple_type_parse(RzPdbTpiStream *stream, ut32 idx);
|
||||
RZ_IPI void tpi_stream_free(RzPdbTpiStream *stream);
|
||||
|
||||
/// enumeration for virtual shape table entries
|
||||
typedef enum {
|
||||
VTS_near = 0x00,
|
||||
@@ -250,6 +254,8 @@ typedef enum {
|
||||
LF_USER_DEFINED_TYPE_MODULE_SOURCE_AND_LINE = 0x1607,
|
||||
LF_CLASS_19 = 0x1608,
|
||||
LF_STRUCTURE_19 = 0x1609,
|
||||
LF_UNION_19 = 0x160A,
|
||||
LF_INTERFACE_19 = 0x160B,
|
||||
LF_ID_LAST, // one greater than the last ID record
|
||||
LF_ID_MAX = LF_ID_LAST - 1,
|
||||
|
||||
@@ -259,6 +265,7 @@ typedef enum {
|
||||
* directly. If the data is more the 0x8000 or is a negative value,
|
||||
* then the data is preceeded by the proper index.
|
||||
*/
|
||||
LF_NUMERIC = 0x8000,
|
||||
LF_CHAR = 0x8000, // signed character leaf
|
||||
LF_SHORT = 0x8001, // signed short leaf
|
||||
LF_USHORT = 0x8002, // unsigned short leaf
|
||||
@@ -350,15 +357,15 @@ typedef struct {
|
||||
} TpiCVFldattr;
|
||||
|
||||
typedef struct cv_funcattr {
|
||||
unsigned char cxxreturnudt : 1; // true if C++ style ReturnUDT
|
||||
unsigned char ctor : 1; // true if func is an instance constructor
|
||||
unsigned char ctorvbase : 1; // true if func is an instance constructor of a class with virtual bases
|
||||
unsigned char unused : 5; // unused
|
||||
RzPdbTpiCallingConvention calling_convention;
|
||||
ut8 cxxreturnudt : 1; // true if C++ style ReturnUDT
|
||||
ut8 ctor : 1; // true if func is an instance constructor
|
||||
ut8 ctorvbase : 1; // true if func is an instance constructor of a class with virtual bases
|
||||
ut8 unused : 5; // unused
|
||||
} TpiCVFuncattr;
|
||||
|
||||
typedef struct {
|
||||
ut32 return_type;
|
||||
RzPdbTpiCallingConvention call_conv;
|
||||
TpiCVFuncattr func_attr;
|
||||
ut16 parm_count;
|
||||
ut32 arg_list;
|
||||
@@ -369,7 +376,6 @@ typedef struct {
|
||||
ut32 return_type;
|
||||
ut32 class_type;
|
||||
ut32 this_type;
|
||||
RzPdbTpiCallingConvention call_conv; // 1 byte
|
||||
TpiCVFuncattr func_attr;
|
||||
ut16 parm_count;
|
||||
ut32 arglist;
|
||||
@@ -454,70 +460,67 @@ typedef struct {
|
||||
typedef struct {
|
||||
ut32 utype;
|
||||
TpiCVPointerAttr ptr_attr;
|
||||
union {
|
||||
struct {
|
||||
ut32 pmclass; // index of containing class for pointer to member
|
||||
ut16 pmtype; // TpiCVPmType
|
||||
} pmember;
|
||||
struct {
|
||||
ut32 index; // type index if PTR_BASE_TYPE
|
||||
} pbase;
|
||||
};
|
||||
PDBTypeIndex containing_class;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Pointer;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
ut32 size;
|
||||
} Tpi_Type_String;
|
||||
|
||||
typedef struct {
|
||||
ut16 type_index;
|
||||
void *data;
|
||||
bool is_integer;
|
||||
} Tpi_Type_Numeric;
|
||||
enum {
|
||||
TpiVariant_U64,
|
||||
TpiVariant_U32,
|
||||
TpiVariant_U16,
|
||||
TpiVariant_U8,
|
||||
TpiVariant_I64,
|
||||
TpiVariant_I32,
|
||||
TpiVariant_I16,
|
||||
TpiVariant_I8,
|
||||
} tag;
|
||||
union {
|
||||
ut64 u64v;
|
||||
ut32 u32v;
|
||||
ut16 u16v;
|
||||
ut8 u8v;
|
||||
st64 i64v;
|
||||
st32 i32v;
|
||||
st16 i16v;
|
||||
st8 i8v;
|
||||
};
|
||||
} TpiVariant;
|
||||
|
||||
typedef struct {
|
||||
ut32 element_type;
|
||||
ut32 index_type;
|
||||
ut32 stride;
|
||||
Tpi_Type_Numeric size;
|
||||
Tpi_Type_String name;
|
||||
RzVector /*<ut32>*/ dimensions;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Array;
|
||||
|
||||
typedef struct {
|
||||
ut16 count;
|
||||
TpiCVProperty prop; // property attribute field
|
||||
ut32 field_list; // type index of LF_FIELD descriptor list
|
||||
ut32 derived; // type index of derived from list if not zero
|
||||
ut32 vshape; // type index of vshape table for this class
|
||||
Tpi_Type_Numeric size;
|
||||
Tpi_Type_String name;
|
||||
Tpi_Type_String mangled_name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Structure, Tpi_LF_Class;
|
||||
typedef enum {
|
||||
ClassKind_Class,
|
||||
ClassKind_Struct,
|
||||
ClassKind_Interface
|
||||
} ClassKind;
|
||||
|
||||
typedef struct {
|
||||
ut16 count;
|
||||
ClassKind kind;
|
||||
TpiCVProperty prop; // property attribute field
|
||||
ut16 unknown;
|
||||
ut32 field_list; // type index of LF_FIELD descriptor list
|
||||
ut32 derived; // type index of derived from list if not zero
|
||||
ut32 vshape; // type index of vshape table for this class
|
||||
Tpi_Type_Numeric unknown1;
|
||||
Tpi_Type_Numeric size;
|
||||
Tpi_Type_String name;
|
||||
Tpi_Type_String mangled_name;
|
||||
ut64 size;
|
||||
char *name;
|
||||
char *mangled_name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Structure_19, Tpi_LF_Class_19;
|
||||
} Tpi_LF_Structure, Tpi_LF_Class;
|
||||
|
||||
typedef struct {
|
||||
ut16 count;
|
||||
TpiCVProperty prop;
|
||||
ut32 field_list;
|
||||
Tpi_Type_Numeric size;
|
||||
Tpi_Type_String name;
|
||||
Tpi_Type_String mangled_name;
|
||||
ut64 size;
|
||||
char *name;
|
||||
char *mangled_name;
|
||||
ut32 pad;
|
||||
} Tpi_LF_Union;
|
||||
|
||||
@@ -530,7 +533,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
ut16 count;
|
||||
char *vt_descriptors;
|
||||
RzVector /*<ut8>*/ descriptors;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Vtshape;
|
||||
|
||||
@@ -555,22 +558,22 @@ typedef struct {
|
||||
TpiCVProperty prop;
|
||||
ut32 utype;
|
||||
ut32 field_list;
|
||||
Tpi_Type_String name;
|
||||
Tpi_Type_String mangled_name;
|
||||
char *name;
|
||||
char *mangled_name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Enum;
|
||||
|
||||
typedef struct {
|
||||
TpiCVFldattr fldattr;
|
||||
Tpi_Type_Numeric enum_value;
|
||||
Tpi_Type_String name;
|
||||
TpiVariant value;
|
||||
char *name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Enumerate;
|
||||
|
||||
typedef struct {
|
||||
ut16 pad;
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 index;
|
||||
Tpi_Type_String name;
|
||||
char *name;
|
||||
} Tpi_LF_NestType;
|
||||
|
||||
typedef struct {
|
||||
@@ -581,7 +584,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
ut16 count;
|
||||
ut32 mlist;
|
||||
Tpi_Type_String name;
|
||||
char *name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Method;
|
||||
|
||||
@@ -593,21 +596,21 @@ typedef struct {
|
||||
} Tpi_Type_MethodListMember;
|
||||
|
||||
typedef struct {
|
||||
RzList /*<Tpi_Type_MethodListMember *>*/ *members;
|
||||
RzPVector /*<Tpi_Type_MethodListMember *>*/ members;
|
||||
} Tpi_LF_MethodList;
|
||||
|
||||
typedef struct {
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 index;
|
||||
Tpi_Type_Numeric offset;
|
||||
Tpi_Type_String name;
|
||||
ut32 field_type;
|
||||
ut64 offset;
|
||||
char *name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_Member;
|
||||
|
||||
typedef struct {
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 index;
|
||||
Tpi_Type_String name;
|
||||
ut32 field_type;
|
||||
char *name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_StaticMember;
|
||||
|
||||
@@ -621,14 +624,15 @@ typedef struct {
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 index;
|
||||
ut32 offset_in_vtable;
|
||||
Tpi_Type_String name;
|
||||
char *name;
|
||||
ut8 pad;
|
||||
} Tpi_LF_OneMethod;
|
||||
|
||||
typedef struct {
|
||||
ClassKind kind;
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 index;
|
||||
Tpi_Type_Numeric offset;
|
||||
ut64 offset;
|
||||
ut8 pad;
|
||||
} Tpi_LF_BClass;
|
||||
|
||||
@@ -636,8 +640,8 @@ typedef struct {
|
||||
TpiCVFldattr fldattr;
|
||||
ut32 direct_vbclass_idx;
|
||||
ut32 vb_pointer_idx;
|
||||
Tpi_Type_Numeric vb_pointer_offset;
|
||||
Tpi_Type_Numeric vb_offset_from_vbtable;
|
||||
ut64 vb_pointer_offset;
|
||||
ut64 vb_offset_from_vbtable;
|
||||
} Tpi_LF_VBClass, Tpi_LF_IVBClass;
|
||||
|
||||
typedef struct {
|
||||
|
||||
+185
-116
@@ -114,87 +114,96 @@ static void rz_core_bin_pdb_types_print(const RzTypeDB *db, const RzPdb *pdb, co
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
RzStrBuf *buf;
|
||||
const ut64 baddr;
|
||||
RzCmdStateOutput *state;
|
||||
} PDBDumpContext;
|
||||
|
||||
static bool symbol_dump(const RzPdb *pdb, const PDBSymbol *symbol, void *u) {
|
||||
PDBDumpContext *ctx = u;
|
||||
PJ *pj = ctx->state->d.pj;
|
||||
if (symbol->kind == PDB_Public) {
|
||||
const PDBSPublic *public = symbol->data;
|
||||
PeImageSectionHeader *sctn_header = pdb_section_hdr_by_index(pdb->s_pe, public->offset.section_index);
|
||||
if (!sctn_header) {
|
||||
return true;
|
||||
}
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &public->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
return true;
|
||||
}
|
||||
if (ctx->baddr != UT64_MAX) {
|
||||
addr += ctx->baddr;
|
||||
}
|
||||
|
||||
char *name = rz_demangler_msvc(public->name, RZ_DEMANGLER_FLAG_BASE);
|
||||
name = (name) ? name : strdup(public->name);
|
||||
|
||||
switch (ctx->state->mode) {
|
||||
case RZ_OUTPUT_MODE_JSON: // JSON
|
||||
pj_o(pj);
|
||||
pj_kn(pj, "address", addr);
|
||||
pj_kN(pj, "symtype", symbol->raw_kind);
|
||||
pj_ks(pj, "section_name", sctn_header->name);
|
||||
pj_ks(pj, "gdata_name", name);
|
||||
pj_end(pj);
|
||||
break;
|
||||
case RZ_OUTPUT_MODE_STANDARD:
|
||||
rz_strbuf_appendf(ctx->buf, "0x%08" PFMT64x " %d %.*s %s\n",
|
||||
addr,
|
||||
symbol->raw_kind, PDB_SIZEOF_SECTION_NAME, sctn_header->name, name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the PDB global vars string
|
||||
*
|
||||
* \param pdb PDB instance
|
||||
* \param img_base image base addr
|
||||
* \param pj JSON instance
|
||||
* \param mode RzOutputMode
|
||||
* \param baddr image base addr
|
||||
* \param state The RzCmdStateOutput instance
|
||||
* \return char *
|
||||
*/
|
||||
RZ_API char *rz_core_bin_pdb_gvars_as_string(RZ_NONNULL const RzPdb *pdb, const ut64 img_base, PJ *pj, const RzOutputMode mode) {
|
||||
rz_return_val_if_fail(pdb, NULL);
|
||||
RzPdbGDataStream *gsym_data_stream = 0;
|
||||
RzPdbPeStream *pe_stream = 0;
|
||||
RZ_API char *rz_core_bin_pdb_gvars_as_string(
|
||||
RZ_NONNULL const RzPdb *pdb, const ut64 baddr, RzCmdStateOutput *state) {
|
||||
rz_return_val_if_fail(pdb && state, NULL);
|
||||
RzStrBuf *buf = rz_strbuf_new(NULL);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
if (mode == RZ_OUTPUT_MODE_JSON) {
|
||||
PJ *pj = state->d.pj;
|
||||
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
||||
pj_o(pj);
|
||||
pj_ka(pj, "gvars");
|
||||
}
|
||||
gsym_data_stream = pdb->s_gdata;
|
||||
pe_stream = pdb->s_pe;
|
||||
if (!pe_stream) {
|
||||
if (!pdb->s_pe) {
|
||||
rz_strbuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
void **it;
|
||||
rz_pvector_foreach (gsym_data_stream->global_symbols, it) {
|
||||
PDBSymbol *symbol = *it;
|
||||
if (symbol->kind == PDB_Public) {
|
||||
PDBSPublic *public = symbol->data;
|
||||
PeImageSectionHeader *sctn_header = pdb_section_hdr_by_index(pdb->s_pe, public->offset.section_index);
|
||||
if (!sctn_header) {
|
||||
continue;
|
||||
}
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &public->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
continue;
|
||||
}
|
||||
if (img_base != UT64_MAX) {
|
||||
addr += img_base;
|
||||
}
|
||||
|
||||
char *name = rz_demangler_msvc(public->name, RZ_DEMANGLER_FLAG_BASE);
|
||||
name = (name) ? name : strdup(public->name);
|
||||
|
||||
switch (mode) {
|
||||
case RZ_OUTPUT_MODE_JSON: // JSON
|
||||
pj_o(pj);
|
||||
pj_kn(pj, "address", addr);
|
||||
pj_kN(pj, "symtype", symbol->raw_kind);
|
||||
pj_ks(pj, "section_name", sctn_header->name);
|
||||
pj_ks(pj, "gdata_name", name);
|
||||
pj_end(pj);
|
||||
break;
|
||||
case RZ_OUTPUT_MODE_STANDARD:
|
||||
rz_strbuf_appendf(buf, "0x%08" PFMT64x " %d %.*s %s\n",
|
||||
addr,
|
||||
symbol->raw_kind, PDB_SIZEOF_SECTION_NAME, sctn_header->name, name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
if (mode == RZ_OUTPUT_MODE_JSON) {
|
||||
PDBDumpContext ctx = {
|
||||
.buf = buf,
|
||||
.baddr = baddr,
|
||||
.state = state,
|
||||
};
|
||||
rz_pdb_all_symbols_foreach(pdb, symbol_dump, &ctx);
|
||||
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
||||
pj_end(pj);
|
||||
pj_end(pj);
|
||||
// We will need this for Windows Heap.
|
||||
rz_strbuf_append(buf, pj_string(pj));
|
||||
}
|
||||
char *str = strdup(rz_strbuf_get(buf));
|
||||
rz_strbuf_free(buf);
|
||||
return str;
|
||||
return rz_strbuf_drain(buf);
|
||||
}
|
||||
|
||||
static void rz_core_bin_pdb_gvars_print(const RzPdb *pdb, const ut64 img_base, const RzCmdStateOutput *state) {
|
||||
static void rz_core_bin_pdb_gvars_print(const RzPdb *pdb, const ut64 baddr, RzCmdStateOutput *state) {
|
||||
rz_return_if_fail(pdb && state);
|
||||
char *str = rz_core_bin_pdb_gvars_as_string(pdb, img_base, state->d.pj, state->mode);
|
||||
char *str = rz_core_bin_pdb_gvars_as_string(pdb, baddr, state);
|
||||
// We don't need to print the output of JSON because the RzCmdStateOutput will handle it.
|
||||
if (state->mode == RZ_OUTPUT_MODE_STANDARD) {
|
||||
rz_cons_print(str);
|
||||
@@ -202,65 +211,91 @@ static void rz_core_bin_pdb_gvars_print(const RzPdb *pdb, const ut64 img_base, c
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void pdb_set_symbols(
|
||||
const RzCore *core, const RzPdb *pdb, const ut64 img_base, const char *pdbfile) {
|
||||
typedef struct {
|
||||
const RzCore *core;
|
||||
const ut64 baddr;
|
||||
const char *file;
|
||||
} PDBLoadContext;
|
||||
|
||||
static bool symbol_load(const RzPdb *pdb, const PDBSymbol *symbol, void *u) {
|
||||
if (!symbol) {
|
||||
return true;
|
||||
}
|
||||
PDBLoadContext *ctx = u;
|
||||
const RzDemanglerFlag dflags = rz_demangler_get_flags(ctx->core->bin->demangler);
|
||||
if (symbol->kind == PDB_Public) {
|
||||
const PDBSPublic *public = symbol->data;
|
||||
if (RZ_STR_ISEMPTY(public->name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char *name = rz_demangler_msvc(public->name, dflags);
|
||||
name = (name) ? name : strdup(public->name);
|
||||
char *filtered_name = rz_name_filter2(name, true);
|
||||
char *fname = rz_str_newf("pdb.%s.%s", ctx->file, filtered_name);
|
||||
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &public->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
return true;
|
||||
}
|
||||
if (ctx->baddr != UT64_MAX) {
|
||||
addr += ctx->baddr;
|
||||
}
|
||||
|
||||
RzFlagItem *item = rz_flag_set(ctx->core->flags, fname, addr, 0);
|
||||
if (item) {
|
||||
rz_flag_item_set_realname(item, name);
|
||||
}
|
||||
free(filtered_name);
|
||||
free(fname);
|
||||
free(name);
|
||||
} else if (symbol->kind == PDB_Data) {
|
||||
const PDBSData *data = symbol->data;
|
||||
if (RZ_STR_ISEMPTY(data->name)) {
|
||||
return true;
|
||||
}
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &data->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
return true;
|
||||
}
|
||||
if (ctx->baddr != UT64_MAX) {
|
||||
addr += ctx->baddr;
|
||||
}
|
||||
|
||||
RzPdbTpiType *t = rz_bin_pdb_get_type_by_index(pdb->s_tpi, data->type_index);
|
||||
if (!t) {
|
||||
return true;
|
||||
}
|
||||
RzType *rt = rz_type_db_pdb_parse(ctx->core->analysis->typedb, pdb->s_tpi, t);
|
||||
if (!rt) {
|
||||
return true;
|
||||
}
|
||||
rz_analysis_var_global_create(ctx->core->analysis, data->name, rt, addr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pdb_symbols_load(
|
||||
const RzCore *core, const RzPdb *pdb, const char *pdbfile) {
|
||||
rz_return_if_fail(core && pdb);
|
||||
if (!(pdb->s_pe && pdb->s_gdata)) {
|
||||
return;
|
||||
}
|
||||
RzDemanglerFlag dflags = rz_demangler_get_flags(core->bin->demangler);
|
||||
ut64 baddr = rz_bin_get_baddr(core->bin);
|
||||
if (!baddr || baddr == UT64_MAX) {
|
||||
baddr = rz_config_get_i(core->config, "bin.baddr");
|
||||
RZ_LOG_WARN("core: cannot find base address, flags will probably be misplaced\n");
|
||||
}
|
||||
char *file = rz_str_replace(strdup(pdbfile), ".pdb", "", 0);
|
||||
rz_flag_space_push(core->flags, RZ_FLAGS_FS_SYMBOLS);
|
||||
|
||||
void **it;
|
||||
rz_pvector_foreach (pdb->s_gdata->global_symbols, it) {
|
||||
PDBSymbol *symbol = *it;
|
||||
if (symbol->kind == PDB_Public) {
|
||||
PDBSPublic *public = symbol->data;
|
||||
PDBLoadContext ctx = {
|
||||
.core = core,
|
||||
.baddr = baddr,
|
||||
.file = file,
|
||||
};
|
||||
rz_pdb_all_symbols_foreach(pdb, symbol_load, &ctx);
|
||||
|
||||
char *name = rz_demangler_msvc(public->name, dflags);
|
||||
name = (name) ? name : strdup(public->name);
|
||||
char *filtered_name = rz_name_filter2(name, true);
|
||||
char *fname = rz_str_newf("pdb.%s.%s", file, filtered_name);
|
||||
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &public->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
continue;
|
||||
}
|
||||
if (img_base != UT64_MAX) {
|
||||
addr += img_base;
|
||||
}
|
||||
|
||||
RzFlagItem *item = rz_flag_set(core->flags, fname, addr, 0);
|
||||
if (item) {
|
||||
rz_flag_item_set_realname(item, name);
|
||||
}
|
||||
free(filtered_name);
|
||||
free(name);
|
||||
} else if (symbol->kind == PDB_Data) {
|
||||
const PDBSData *data = symbol->data;
|
||||
if (!data->global) {
|
||||
continue;
|
||||
}
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &data->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
continue;
|
||||
}
|
||||
if (img_base != UT64_MAX) {
|
||||
addr += img_base;
|
||||
}
|
||||
|
||||
RzPdbTpiType *t = rz_bin_pdb_get_type_by_index(pdb->s_tpi, data->type_index);
|
||||
if (!t) {
|
||||
continue;
|
||||
}
|
||||
RzType *rt = rz_type_db_pdb_parse(core->analysis->typedb, pdb->s_tpi, t);
|
||||
if (!rt) {
|
||||
continue;
|
||||
}
|
||||
rz_analysis_var_global_create(core->analysis, data->name, rt, addr);
|
||||
}
|
||||
}
|
||||
rz_flag_space_pop(core->flags);
|
||||
free(file);
|
||||
}
|
||||
@@ -274,13 +309,6 @@ static void pdb_set_symbols(
|
||||
*/
|
||||
RZ_API RzPdb *rz_core_pdb_load_info(RZ_NONNULL RzCore *core, RZ_NONNULL const char *file) {
|
||||
rz_return_val_if_fail(core && file, NULL);
|
||||
|
||||
ut64 baddr = rz_bin_get_baddr(core->bin);
|
||||
if (!baddr || baddr == UT64_MAX) {
|
||||
baddr = rz_config_get_i(core->config, "bin.baddr");
|
||||
RZ_LOG_WARN("core: cannot find base address, flags will probably be misplaced\n");
|
||||
}
|
||||
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file(file);
|
||||
if (!pdb) {
|
||||
return NULL;
|
||||
@@ -288,10 +316,50 @@ RZ_API RzPdb *rz_core_pdb_load_info(RZ_NONNULL RzCore *core, RZ_NONNULL const ch
|
||||
|
||||
// Save compound types into types database
|
||||
rz_type_db_pdb_load(core->analysis->typedb, pdb);
|
||||
pdb_set_symbols(core, pdb, baddr, rz_file_basename(file));
|
||||
pdb_symbols_load(core, pdb, rz_file_basename(file));
|
||||
return pdb;
|
||||
}
|
||||
|
||||
static void pdb_modules_print(RZ_NONNULL RzPdb *pdb, RZ_NONNULL RzCmdStateOutput *state) {
|
||||
if (!(pdb->s_dbi && pdb->s_dbi->modules)) {
|
||||
return;
|
||||
}
|
||||
PJ *j = state->d.pj;
|
||||
switch (state->mode) {
|
||||
case RZ_OUTPUT_MODE_JSON:
|
||||
pj_o(j);
|
||||
pj_ka(j, "modules");
|
||||
break;
|
||||
case RZ_OUTPUT_MODE_STANDARD: {
|
||||
rz_cons_println("modules:");
|
||||
break;
|
||||
}
|
||||
default: rz_warn_if_reached();
|
||||
}
|
||||
void **it;
|
||||
rz_pvector_foreach (pdb->s_dbi->modules, it) {
|
||||
PDB_DBIModule *module = *it;
|
||||
switch (state->mode) {
|
||||
case RZ_OUTPUT_MODE_JSON: {
|
||||
pj_o(j);
|
||||
pj_ks(j, "module_name", module->module_name);
|
||||
pj_ks(j, "object_file_name", module->object_file_name);
|
||||
pj_end(j);
|
||||
break;
|
||||
}
|
||||
case RZ_OUTPUT_MODE_STANDARD: {
|
||||
rz_cons_println(module->module_name);
|
||||
break;
|
||||
}
|
||||
default: rz_warn_if_reached();
|
||||
}
|
||||
}
|
||||
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
||||
pj_end(j);
|
||||
pj_end(j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print parsed PDB file info
|
||||
*
|
||||
@@ -311,6 +379,7 @@ RZ_API void rz_core_pdb_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzTypeDB
|
||||
}
|
||||
|
||||
rz_cmd_state_output_array_start(state);
|
||||
pdb_modules_print(pdb, state);
|
||||
rz_core_bin_pdb_types_print(core->analysis->typedb, pdb, state);
|
||||
rz_core_bin_pdb_gvars_print(pdb, baddr, state);
|
||||
rz_cmd_state_output_array_end(state);
|
||||
|
||||
+48
-44
@@ -268,6 +268,38 @@ static inline bool has_heap_globals(void) {
|
||||
return RtlpHpHeapGlobalsOffset && RtlpLFHKeyOffset;
|
||||
}
|
||||
|
||||
static bool symbol_do(const RzPdb *pdb, const PDBSymbol *symbol, void *u) {
|
||||
if (has_heap_globals()) {
|
||||
return false;
|
||||
}
|
||||
if (symbol->kind != PDB_Public) {
|
||||
return true;
|
||||
}
|
||||
ut64 baddr = (ut64)u;
|
||||
const PDBSPublic *data = symbol->data;
|
||||
if (!(data && data->name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ut64 addr = rz_bin_pdb_to_rva(pdb, &data->offset);
|
||||
if (addr == UT64_MAX) {
|
||||
return true;
|
||||
}
|
||||
if (baddr != UT64_MAX) {
|
||||
addr += baddr;
|
||||
}
|
||||
|
||||
char *name = rz_demangler_msvc(data->name, RZ_DEMANGLER_FLAG_BASE);
|
||||
if (RZ_STR_EQ(name, "RtlpHpHeapGlobals")) {
|
||||
RtlpHpHeapGlobalsOffset = addr;
|
||||
}
|
||||
if (RZ_STR_EQ(name, "RtlpLFHKey")) {
|
||||
RtlpLFHKeyOffset = addr;
|
||||
}
|
||||
free(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
|
||||
if (has_heap_globals()) {
|
||||
return true;
|
||||
@@ -311,11 +343,13 @@ static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
|
||||
rz_io_fd_close(core->io, fd);
|
||||
return false;
|
||||
}
|
||||
char *pdb_path = NULL;
|
||||
RzPdb *pdb = NULL;
|
||||
RzBinInfo *info = rz_bin_get_info(core->bin);
|
||||
if (!info) {
|
||||
goto fail;
|
||||
}
|
||||
char *pdb_path = rz_str_newf("%s\\ntdll.pdb\\%s\\ntdll.pdb",
|
||||
pdb_path = rz_str_newf("%s\\ntdll.pdb\\%s\\ntdll.pdb",
|
||||
rz_config_get(core->config, "pdb.symstore"), info->guid);
|
||||
if (!pdb_path) {
|
||||
goto fail;
|
||||
@@ -328,62 +362,28 @@ static bool GetHeapGlobalsOffset(RzDebug *dbg, HANDLE h_proc) {
|
||||
opts.symbol_server = rz_config_get(core->config, "pdb.server");
|
||||
if (rz_bin_pdb_download(core->bin, NULL, false, &opts)) {
|
||||
RZ_LOG_ERROR("core: Failed to download ntdll.pdb file\n");
|
||||
free(pdb_path);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// Get ntdll.dll PDB info and parse json output
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file(pdb_path);
|
||||
pdb = rz_bin_pdb_parse_from_file(pdb_path);
|
||||
if (!pdb) {
|
||||
free(pdb_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(pdb_path);
|
||||
ut64 baddr = rz_config_get_i(core->config, "bin.baddr");
|
||||
if (core->bin->cur && core->bin->cur->o && core->bin->cur->o->opts.baseaddr) {
|
||||
baddr = core->bin->cur->o->opts.baseaddr;
|
||||
} else {
|
||||
RZ_LOG_WARN("core: Cannot find base address, flags will probably be misplaced\n");
|
||||
}
|
||||
PJ *pj = pj_new();
|
||||
if (!pj) {
|
||||
rz_bin_pdb_free(pdb);
|
||||
goto fail;
|
||||
}
|
||||
char *j = rz_core_bin_pdb_gvars_as_string(pdb, baddr, pj, RZ_OUTPUT_MODE_JSON);
|
||||
if (!j) {
|
||||
rz_bin_pdb_free(pdb);
|
||||
pj_free(pj);
|
||||
goto fail;
|
||||
}
|
||||
pj_free(pj);
|
||||
rz_bin_pdb_free(pdb);
|
||||
RzJson *json = rz_json_parse(j);
|
||||
if (!json) {
|
||||
RZ_LOG_ERROR("core: rz_core_pdb_info returned invalid JSON");
|
||||
free(j);
|
||||
goto fail;
|
||||
}
|
||||
free(j);
|
||||
|
||||
// Go through gvars array and search for the heap globals symbols
|
||||
const RzJson *gvars = rz_json_get(json, "gvars");
|
||||
gvars = gvars->children.first;
|
||||
do {
|
||||
const RzJson *gdata_name = rz_json_get(gvars, "gdata_name");
|
||||
if (!strcmp(gdata_name->str_value, "RtlpHpHeapGlobals")) {
|
||||
const RzJson *address = rz_json_get(gvars, "address");
|
||||
RtlpHpHeapGlobalsOffset = address->num.u_value;
|
||||
} else if (!strcmp(gdata_name->str_value, "RtlpLFHKey")) {
|
||||
const RzJson *address = rz_json_get(gvars, "address");
|
||||
RtlpLFHKeyOffset = address->num.u_value;
|
||||
}
|
||||
} while ((gvars = gvars->next) && !has_heap_globals());
|
||||
rz_pdb_all_symbols_foreach(pdb, symbol_do, (void *)baddr);
|
||||
|
||||
free(json);
|
||||
fail:
|
||||
rz_bin_pdb_free(pdb);
|
||||
free(pdb_path);
|
||||
rz_bin_file_delete(core->bin, bf);
|
||||
rz_bin_file_set_cur_binfile(core->bin, obf);
|
||||
rz_io_fd_close(core->io, fd);
|
||||
@@ -685,7 +685,8 @@ static bool GetSegmentHeapBlocks(RzDebug *dbg, HANDLE h_proc, PVOID heapBase, PH
|
||||
PRTL_BALANCED_NODE node = malloc(sizeof(RTL_BALANCED_NODE));
|
||||
RzStack *s = rz_stack_new(segheapHeader.LargeReservedPages);
|
||||
PRTL_BALANCED_NODE curr = segheapHeader.LargeAllocMetadata.Root;
|
||||
do { // while (!rz_stack_is_empty(s));
|
||||
do {
|
||||
// while (!rz_stack_is_empty(s));
|
||||
GROW_PBLOCKS();
|
||||
while (curr) {
|
||||
rz_stack_push(s, curr);
|
||||
@@ -870,7 +871,8 @@ static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RzDebug *dbg) {
|
||||
curEntry = lfhHeader.SubSegmentZones.Flink;
|
||||
|
||||
// Loops through all _HEAP_SUBSEGMENTs
|
||||
do { // (curEntry != firstEntry)
|
||||
do {
|
||||
// (curEntry != firstEntry)
|
||||
HEAP_LOCAL_SEGMENT_INFO info;
|
||||
HEAP_LOCAL_DATA localData;
|
||||
HEAP_SUBSEGMENT subsegment;
|
||||
@@ -879,7 +881,8 @@ static PDEBUG_BUFFER GetHeapBlocks(DWORD pid, RzDebug *dbg) {
|
||||
|
||||
WPARAM curSubsegment = (WPARAM)(curEntry + 2);
|
||||
int next = 0;
|
||||
do { // (next < blockZone.NextIndex)
|
||||
do {
|
||||
// (next < blockZone.NextIndex)
|
||||
if (!ReadProcessMemory(h_proc, (PVOID)curSubsegment, &subsegment, sizeof(HEAP_SUBSEGMENT), &bytesRead) || !subsegment.BlockSize || !ReadProcessMemory(h_proc, subsegment.LocalInfo, &info, sizeof(HEAP_LOCAL_SEGMENT_INFO), &bytesRead) || !ReadProcessMemory(h_proc, info.LocalData, &localData, sizeof(HEAP_LOCAL_DATA), &bytesRead) || !ReadProcessMemory(h_proc, localData.CrtZone, &blockZone, sizeof(LFH_BLOCK_ZONE), &bytesRead)) {
|
||||
break;
|
||||
}
|
||||
@@ -1032,7 +1035,8 @@ static PHeapBlock GetSingleSegmentBlock(RzDebug *dbg, HANDLE h_proc, PSEGMENT_HE
|
||||
WPARAM segSignature;
|
||||
ReadProcessMemory(h_proc, (PVOID)(pgSegOff + sizeof(LIST_ENTRY)), &segSignature, sizeof(WPARAM), NULL); // HEAP_PAGE_SEGMENT.Signature
|
||||
WPARAM test = RtlpHpHeapGlobal ^ pgSegOff ^ segSignature ^ ((WPARAM)heapBase + offsetof(SEGMENT_HEAP, SegContexts));
|
||||
if (test == 0xa2e64eada2e64ead) { // Hardcoded in ntdll
|
||||
if (test == 0xa2e64eada2e64ead) {
|
||||
// Hardcoded in ntdll
|
||||
HEAP_PAGE_SEGMENT segment;
|
||||
ReadProcessMemory(h_proc, (PVOID)pgSegOff, &segment, sizeof(HEAP_PAGE_SEGMENT), NULL);
|
||||
WPARAM pgRangeDescOff = ((headerOff - pgSegOff) >> heap.SegContexts[0].UnitShift) << 5;
|
||||
@@ -1508,4 +1512,4 @@ RZ_IPI RzList *rz_heap_list(RzCore *core) {
|
||||
|
||||
RtlDestroyQueryDebugBuffer(db);
|
||||
return heaps_list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,7 +994,7 @@ RZ_API RZ_OWN char *rz_core_bin_pdb_get_filename(RZ_NONNULL RzCore *core);
|
||||
RZ_API bool rz_core_bin_pdb_load(RZ_NONNULL RzCore *core, RZ_NONNULL const char *filename);
|
||||
RZ_API RzPdb *rz_core_pdb_load_info(RZ_NONNULL RzCore *core, RZ_NONNULL const char *file);
|
||||
RZ_API void rz_core_pdb_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzTypeDB *db, RZ_NONNULL RzPdb *pdb, RZ_NONNULL RzCmdStateOutput *state);
|
||||
RZ_API char *rz_core_bin_pdb_gvars_as_string(RZ_NONNULL const RzPdb *pdb, const ut64 img_base, PJ *pj, const RzOutputMode mode);
|
||||
RZ_API char *rz_core_bin_pdb_gvars_as_string(RZ_NONNULL const RzPdb *pdb, const ut64 img_base, RzCmdStateOutput *state);
|
||||
RZ_API RzCmdStatus rz_core_bin_plugins_print(RzBin *bin, RzCmdStateOutput *state);
|
||||
|
||||
RZ_API bool rz_core_bin_archs_print(RZ_NONNULL RzBin *bin, RZ_NONNULL RzCmdStateOutput *state);
|
||||
|
||||
+121
-4
@@ -58,9 +58,9 @@ typedef struct {
|
||||
|
||||
typedef struct dbi_stream_t {
|
||||
RzPdbRzPdbDbiStreamHdr hdr;
|
||||
RzList /*<RzPdbDbiStreamExHdr *>*/ *ex_hdrs;
|
||||
ut64 hdr_size;
|
||||
RzPVector /*<PDB_DBIModule *>*/ *modules;
|
||||
RzPdbRzPdbDbiStreamDbgHeader dbg_hdr;
|
||||
|
||||
} RzPdbDbiStream;
|
||||
|
||||
// GDATA
|
||||
@@ -141,11 +141,42 @@ typedef struct tpi_stream_header_t {
|
||||
ut32 HashAdjBufferLength;
|
||||
} RzPdbTpiStreamHeader;
|
||||
|
||||
typedef enum {
|
||||
TpiKind_INVALID,
|
||||
TpiKind_FILEDLIST,
|
||||
TpiKind_ENUM,
|
||||
TpiKind_ENUMERATE,
|
||||
TpiKind_CLASS,
|
||||
TpiKind_UNION,
|
||||
TpiKind_BITFIELD,
|
||||
TpiKind_POINTER,
|
||||
TpiKind_ARRAY,
|
||||
TpiKind_MODIFIER,
|
||||
TpiKind_ARGLIST,
|
||||
TpiKind_MFUNCTION,
|
||||
TpiKind_METHODLIST,
|
||||
TpiKind_PROCEDURE,
|
||||
TpiKind_VTSHAPE,
|
||||
TpiKind_VFTABLE,
|
||||
TpiKind_LABEL,
|
||||
TpiKind_NESTTYPE,
|
||||
TpiKind_MEMBER,
|
||||
TpiKind_METHOD,
|
||||
TpiKind_ONEMETHOD,
|
||||
TpiKind_BCLASS,
|
||||
TpiKind_VFUNCTAB,
|
||||
TpiKind_STMEMBER,
|
||||
TpiKind_VBCLASS,
|
||||
TpiKind_INDEX,
|
||||
TpiKind_SIMPLE_TYPE,
|
||||
} RzPDBTpiKind;
|
||||
|
||||
typedef struct tpi_types {
|
||||
RBNode rb;
|
||||
ut32 index;
|
||||
ut16 leaf;
|
||||
ut16 length;
|
||||
RzPDBTpiKind kind;
|
||||
void *data;
|
||||
bool parsed;
|
||||
} RzPdbTpiType;
|
||||
@@ -238,16 +269,25 @@ typedef struct {
|
||||
RzBuffer *sd;
|
||||
} RzPdbMsfStreamDirectory;
|
||||
|
||||
typedef struct {
|
||||
RzBuffer *stream;
|
||||
ut32 symbols_size;
|
||||
ut16 stream_index;
|
||||
RzPVector /*<PDBSymbol *>*/ *symbols;
|
||||
} PDBModuleInfo;
|
||||
|
||||
typedef struct rz_pdb_t {
|
||||
RzBuffer *buf; // mmap of file
|
||||
RzPdbMsfSuperBlock *super_block;
|
||||
RzList /*<RzPdbMsfStream *>*/ *streams;
|
||||
RzPdbMsfStreamDirectory *msd;
|
||||
RzPVector /*<RzPdbMsfStream *>*/ *streams;
|
||||
RzPdbStream *s_pdb;
|
||||
RzPdbDbiStream *s_dbi;
|
||||
RzPdbTpiStream *s_tpi;
|
||||
RzPdbGDataStream *s_gdata;
|
||||
RzPdbOmapStream *s_omap;
|
||||
RzPdbPeStream *s_pe;
|
||||
RzPVector /*<PDBModuleInfo *>*/ *module_infos;
|
||||
} RzPdb;
|
||||
|
||||
typedef struct {
|
||||
@@ -255,11 +295,86 @@ typedef struct {
|
||||
ut16 section_index;
|
||||
} PDBSectionOffset;
|
||||
|
||||
typedef ut16 PDBSymbolKind;
|
||||
typedef ut32 PDBTypeIndex;
|
||||
typedef ut32 PDBSymbolIndex;
|
||||
|
||||
typedef struct {
|
||||
bool global : 1;
|
||||
bool managed : 1;
|
||||
PDBTypeIndex type_index;
|
||||
PDBSectionOffset offset;
|
||||
char *name;
|
||||
} PDBSData;
|
||||
|
||||
RZ_IPI bool PDBSData_parse(RzBuffer *b, PDBSymbolKind kind, PDBSData *sdata);
|
||||
|
||||
typedef struct {
|
||||
bool code : 1;
|
||||
bool function : 1;
|
||||
bool managed : 1;
|
||||
bool msil : 1;
|
||||
PDBSectionOffset offset;
|
||||
char *name;
|
||||
} PDBSPublic;
|
||||
|
||||
RZ_IPI bool PDBSPublic_parse(RzBuffer *b, PDBSymbolKind kind, PDBSPublic *s);
|
||||
|
||||
typedef struct {
|
||||
PDBSymbolIndex index;
|
||||
PDBSymbolKind raw_kind;
|
||||
ut16 length;
|
||||
enum {
|
||||
PDB_ScopeEnd, /// End of a scope, such as a procedure.
|
||||
PDB_ObjName, /// Name of the object file of this module.
|
||||
PDB_RegisterVariable, /// A Register variable.
|
||||
PDB_Constant, /// A constant value.
|
||||
PDB_UserDefinedType, /// A user defined type.
|
||||
PDB_MultiRegisterVariable, /// A Register variable spanning multiple registers.
|
||||
PDB_Data, /// Static data, such as a global variable.
|
||||
PDB_Public, /// A public symbol with a mangled name.
|
||||
PDB_Procedure, /// A procedure, such as a function or method.
|
||||
PDB_ThreadStorage, /// A thread local variable.
|
||||
PDB_CompileFlags, /// Flags used to compile a module.
|
||||
PDB_UsingNamespace, /// A using namespace directive.
|
||||
PDB_ProcedureReference, /// Reference to a [`ProcedureSymbol`].
|
||||
PDB_DataReference, /// Reference to an imported variable.
|
||||
PDB_AnnotationReference, /// Reference to an annotation.
|
||||
PDB_Trampoline, /// Trampoline thunk.
|
||||
PDB_Export, /// An exported symbol.
|
||||
PDB_Local, /// A local symbol in optimized code.
|
||||
PDB_BuildInfo, /// Reference to build information.
|
||||
PDB_InlineSite, /// The callsite of an inlined function.
|
||||
PDB_InlineSiteEnd, /// End of an inline callsite.
|
||||
PDB_ProcedureEnd, /// End of a procedure.
|
||||
PDB_Label, /// A label.
|
||||
PDB_Block, /// A block.
|
||||
PDB_RegisterRelative, /// Data allocated relative to a register.
|
||||
PDB_Thunk, /// A thunk.
|
||||
PDB_SeparatedCode, /// A block of separated code.
|
||||
PDB_DefRange, /// A live range of a variable.
|
||||
PDB_DefRangeSubField, /// A live range of a sub field of a variable.
|
||||
PDB_DefRangeRegister, /// A live range of a register variable.
|
||||
PDB_DefRangeFramePointerRelative, /// A live range of a frame pointer-relative variable.
|
||||
PDB_DefRangeFramePointerRelativeFullScope, /// A frame-pointer variable which is valid in the full scope of the function.
|
||||
PDB_DefRangeSubFieldRegister, /// A live range of a sub field of a register variable.
|
||||
PDB_DefRangeRegisterRelative, /// A live range of a variable related to a register.
|
||||
PDB_BasePointerRelative, /// A base pointer-relative variable.
|
||||
PDB_FrameProcedure, /// Extra frame and proc information.
|
||||
PDB_CallSiteInfo, /// Indirect call site information.
|
||||
} kind;
|
||||
void *data;
|
||||
} PDBSymbol;
|
||||
|
||||
// PDB
|
||||
RZ_API bool rz_bin_pdb_extract_in_folder(RZ_NONNULL const char *file_cab, RZ_NONNULL const char *output_dir);
|
||||
RZ_API RZ_OWN RzPdb *rz_bin_pdb_parse_from_file(RZ_NONNULL const char *filename);
|
||||
RZ_API RZ_OWN RzPdb *rz_bin_pdb_parse_from_buf(RZ_NONNULL const RzBuffer *buf);
|
||||
RZ_API void rz_bin_pdb_free(RzPdb *pdb);
|
||||
RZ_API bool rz_pdb_all_symbols_foreach(
|
||||
RZ_BORROW RZ_NONNULL const RzPdb *pdb,
|
||||
RZ_BORROW RZ_NONNULL bool (*f)(const RzPdb *, const PDBSymbol *, void *),
|
||||
RZ_BORROW RZ_NULLABLE void *u);
|
||||
|
||||
// TPI
|
||||
RZ_API RZ_BORROW RzPdbTpiType *rz_bin_pdb_get_type_by_index(RZ_NONNULL RzPdbTpiStream *stream, ut32 index);
|
||||
@@ -270,7 +385,9 @@ RZ_API RZ_BORROW char *rz_bin_pdb_get_type_name(RZ_NONNULL RzPdbTpiType *type);
|
||||
RZ_API ut64 rz_bin_pdb_get_type_val(RZ_NONNULL RzPdbTpiType *type);
|
||||
|
||||
// OMAP
|
||||
RZ_API ut64 rz_bin_pdb_to_rva(RZ_NONNULL const RzPdb *pdb, const PDBSectionOffset *section_offset);
|
||||
RZ_API ut64 rz_bin_pdb_to_rva(
|
||||
RZ_BORROW RZ_NONNULL const RzPdb *pdb,
|
||||
RZ_BORROW RZ_NONNULL const PDBSectionOffset *section_offset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+3
-1
@@ -643,10 +643,12 @@ RZ_API ut64 rz_buf_read_string(RZ_NONNULL RzBuffer *b, RZ_BORROW RZ_NULLABLE cha
|
||||
if (!tmp) {
|
||||
return 0;
|
||||
}
|
||||
ut64 string_len = strlen(tmp) + 1;
|
||||
const ut64 string_len = strlen(tmp) + 1;
|
||||
rz_buf_seek(b, string_len, RZ_BUF_CUR);
|
||||
if (s) {
|
||||
*s = tmp;
|
||||
} else {
|
||||
free(tmp);
|
||||
}
|
||||
return string_len;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,22 @@ FILE==
|
||||
CMDS=idpij bins/pdb/minimal.pdb~{}
|
||||
EXPECT=<<EOF
|
||||
[
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"module_name": "* Linker Generated Manifest RES *",
|
||||
"object_file_name": ""
|
||||
},
|
||||
{
|
||||
"module_name": "C:\\Users\\emuresan\\source\\repos\\minimal\\Release\\main.obj",
|
||||
"object_file_name": "C:\\Users\\emuresan\\source\\repos\\minimal\\Release\\main.obj"
|
||||
},
|
||||
{
|
||||
"module_name": "* Linker *",
|
||||
"object_file_name": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"types": [
|
||||
{
|
||||
|
||||
+136
-55
@@ -1,3 +1,42 @@
|
||||
NAME=Modules from PDB
|
||||
FILE=
|
||||
CMDS=<<EOF
|
||||
idpi bins/pdb/Project1.pdb~:..30
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
modules:
|
||||
* Linker Generated Manifest RES *
|
||||
C:\Users\inisider\documents\visual studio 2012\Projects\Project1\Project1\Debug\Source.obj
|
||||
KERNEL32.dll
|
||||
Import:KERNEL32.dll
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\xdll_lib\unhandld.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\atonexit.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\cinitexe.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\crtexe.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\dllargv.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\gs_cookie.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\gs_report.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\gs_support.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\merr.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\natstart.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\pesect.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\wildcard.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\asm\dllsupp.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\xdll_lib\chandler4gs.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\fp8.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\loadcfg.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\secchk.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\_newmode.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\xncommod.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\xtxtmode.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\src\build\INTEL\xdll_obj\nativec\xthdloc.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\prebuild\build\INTEL\xdll_obj\rtc\nativecpp\\userapi.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\prebuild\build\INTEL\xdll_obj\rtc\nativecpp\\stack.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\prebuild\build\INTEL\xdll_obj\rtc\nativecpp\\pdblkup.obj
|
||||
F:\dd\vctools\crt_bld\SELF_X86\crt\prebuild\build\INTEL\xdll_obj\rtc\nativecpp\\initsect.obj
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=Load global variables from PDB
|
||||
FILE=
|
||||
CMDS=<<EOF
|
||||
@@ -5,33 +44,53 @@ idp bins/pdb/Project1.pdb
|
||||
avg
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
global int32_t (*type_0x1028)() (*type_0x1097)(int32_t (*type_0x1028)()) _imp___onexit @ 0x19248
|
||||
global void * __native_startup_lock @ 0x18548
|
||||
global int32_t __native_startup_state @ 0x18558
|
||||
global struct IMAGE_LOAD_CONFIG_DIRECTORY32_2 _load_config_used @ 0x165b0
|
||||
global int32_t (*type_0x1450)(char *arg0, const char *arg1) wsprintffp @ 0x1815c
|
||||
global void (*type_0x1093)() [4] __rtc_izz @ 0x16ae8
|
||||
global wchar_t [26] mspdbName @ 0x1640c
|
||||
global char ** argv @ 0x18140
|
||||
global void (**type_0x1093)() __onexitbegin @ 0x1856c
|
||||
global uint32_t __security_cookie @ 0x18024
|
||||
global void (*type_0x1093)() [4] __rtc_iaa @ 0x168e0
|
||||
global int32_t __defaultmatherr @ 0x18018
|
||||
global void * __native_startup_lock @ 0x18548
|
||||
global int32_t has_cctor @ 0x18138
|
||||
global int32_t __native_startup_state @ 0x18558
|
||||
global uint32_t __native_dllmain_reason @ 0x18020
|
||||
global int32_t _dowildcard @ 0x18170
|
||||
global struct _EXCEPTION_RECORD GS_ExceptionRecord @ 0x18188
|
||||
global void (*type_0x1093)() [4] __xc_a @ 0x15000
|
||||
global void (*type_0x1093)() [4] __xi_a @ 0x1530c
|
||||
global bool init @ 0x18130
|
||||
global int32_t argret @ 0x18148
|
||||
global int32_t argc @ 0x1813c
|
||||
global int32_t (*type_0x1028)() pinit @ 0x15514
|
||||
global wchar_t [8] dllExt @ 0x1654c
|
||||
global int32_t managedapp @ 0x1814c
|
||||
global struct HINSTANCE__ * mspdb @ 0x1817c
|
||||
global void (*type_0x1093)() [4] __xi_z @ 0x1571c
|
||||
global struct _EXCEPTION_POINTERS GS_ExceptionPointers @ 0x165a0
|
||||
global int32_t __globallocalestatus @ 0x1801c
|
||||
global int32_t _commode @ 0x1816c
|
||||
global int32_t DebuggerWasPresent @ 0x184a4
|
||||
global void (*type_0x1093)() pcppinit @ 0x15104
|
||||
global int32_t _newmode @ 0x18174
|
||||
global int32_t mainret @ 0x18134
|
||||
global void (*type_0x1093)() [4] __xc_z @ 0x15208
|
||||
global int32_t [20] _RTC_ErrorLevels @ 0x18000
|
||||
global int32_t (*type_0x1028)() (*type_0x1097)(int32_t (*type_0x1028)()) _imp___onexit @ 0x19248
|
||||
global int32_t (*type_0x1028)() pcinit @ 0x15410
|
||||
global const char *[20] _RTC_errlist @ 0x16034
|
||||
global int32_t * _imp___commode @ 0x1927c
|
||||
global uint32_t __security_cookie_complement @ 0x18028
|
||||
global int32_t _fmode @ 0x18178
|
||||
global struct _startupinfo startinfo @ 0x18150
|
||||
global int32_t (*type_0x1141)(int32_t arg0, const char *arg1, int32_t arg2, const char *arg3, const char *arg4) _RTC_ErrorReportFunc @ 0x18160
|
||||
global const char *[24] _RTC_ErrorMessages @ 0x1594c
|
||||
global int32_t * _imp___fmode @ 0x19280
|
||||
global void (*type_0x1093)() [4] __rtc_tzz @ 0x16df4
|
||||
global void (**type_0x1093)() __onexitend @ 0x1855c
|
||||
global int32_t [20] _RTC_ErrorLevels @ 0x18000
|
||||
global void (*type_0x1093)() [4] __rtc_taa @ 0x16bec
|
||||
global int32_t _commode @ 0x1816c
|
||||
global int32_t __globallocalestatus @ 0x1801c
|
||||
global void (*type_0x1093)() [4] __xi_z @ 0x1571c
|
||||
global uint32_t __security_cookie @ 0x18024
|
||||
global int32_t (*type_0x1450)(char *arg0, const char *arg1) wsprintffp @ 0x1815c
|
||||
global int32_t * _imp___fmode @ 0x19280
|
||||
global void (*type_0x1093)() [4] __rtc_izz @ 0x16ae8
|
||||
global void (*type_0x1093)() [4] __xc_z @ 0x15208
|
||||
global void (**type_0x1093)() __onexitbegin @ 0x1856c
|
||||
global int32_t _fmode @ 0x18178
|
||||
global void (*type_0x1093)() [4] __xc_a @ 0x15000
|
||||
global int32_t * _imp___commode @ 0x1927c
|
||||
global uint32_t __native_dllmain_reason @ 0x18020
|
||||
global void (*type_0x1093)() [4] __rtc_iaa @ 0x168e0
|
||||
global int32_t _newmode @ 0x18174
|
||||
global int32_t _dowildcard @ 0x18170
|
||||
global uint32_t __security_cookie_complement @ 0x18028
|
||||
EOF
|
||||
RUN
|
||||
|
||||
@@ -50,47 +109,69 @@ avgx __dyn_tls_init_callback
|
||||
pdr @ fcn.140001316
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
global void * __guard_check_icall_fptr @ 0x140015000
|
||||
global int32_t __favor @ 0x140011bc4
|
||||
global void (*type_0x1079)(void *arg0) __castguard_check_failure_os_handled_fptr @ 0x140011ba8
|
||||
global int32_t __scrt_debugger_hook_flag @ 0x140011ba4
|
||||
global void (*type_0x1001)() [8] __rtc_iaa @ 0x14000ed88
|
||||
global struct _RS5_IMAGE_LOAD_CONFIG_DIRECTORY64 _load_config_used @ 0x14000e2d0
|
||||
global struct __type_info_node __type_info_root_node @ 0x140011b80
|
||||
global void (*type_0x1001)() [8] __rtc_taa @ 0x14000f0b8
|
||||
global void (*type_0x1de8)(void *arg0, uint32_t arg1, void *arg2) __dyn_tls_init_callback @ 0x140011be0
|
||||
global void (*type_0x1001)() [24] std::runtime_error::`vftable' @ 0x14000d808
|
||||
global void (*type_0x1001)() [8] __rtc_izz @ 0x14000efa8
|
||||
global int32_t __scrt_current_native_startup_state @ 0x140011b28
|
||||
global void * __guard_xfg_check_icall_fptr @ 0x140015010
|
||||
global const unsigned char _guard_dispatch_icall_nop @ 0x140009a80
|
||||
global void (*type_0x1001)() [8] __rtc_tzz @ 0x14000f2d8
|
||||
global const int32_t __scrt_ucrt_dll_is_in_use @ 0x140011060
|
||||
global void * __guard_dispatch_icall_fptr @ 0x140015020
|
||||
global void * __guard_xfg_dispatch_icall_fptr @ 0x140015030
|
||||
global int32_t (*type_0x1d02)(int32_t arg0, wchar_t *arg1, int32_t arg2, wchar_t *arg3, wchar_t *arg4) _RTC_ErrorReportFuncW @ 0x140011490
|
||||
global int32_t __isa_available @ 0x140011038
|
||||
global int32_t (*type_0x1015)() [8] __xi_a @ 0x14000c330
|
||||
global void (*type_0x1001)() [8] __xc_z @ 0x14000c220
|
||||
global int32_t [20] _RTC_ErrorLevels @ 0x140011018
|
||||
global int32_t (*type_0x1015)() [8] __xi_z @ 0x14000c660
|
||||
global unsigned char $xdatasym @ 0x14000ff40
|
||||
global const unsigned char _guard_xfg_dispatch_icall_nop @ 0x140009aa0
|
||||
global struct _EXCEPTION_POINTERS GS_ExceptionPointers @ 0x14000e060
|
||||
global bool module_local_atexit_table_initialized @ 0x140011b39
|
||||
global uint64_t __security_cookie @ 0x140011008
|
||||
global void * __CastGuardVftablesEnd @ 0x14000e710
|
||||
global void * __guard_dispatch_icall_fptr @ 0x140015020
|
||||
global void (*type_0x1001)() [24] std::runtime_error::`vftable' @ 0x14000d808
|
||||
global const int32_t __scrt_ucrt_dll_is_in_use @ 0x140011060
|
||||
global void (*type_0x1001)() [24] std::exception::`vftable' @ 0x14000d530
|
||||
global void (*type_0x1de8)(void *arg0, uint32_t arg1, void *arg2) __dyn_tls_dtor_callback @ 0x140011bc8
|
||||
global void * __CastGuardVftablesStart @ 0x14000e600
|
||||
global void (*type_0x1001)() [8] __xt_z @ 0x14000caa0
|
||||
global int64_t __memset_nt_iters @ 0x140011048
|
||||
global int32_t (*type_0x1015)() pre_c_initializer @ 0x14000c440
|
||||
global void (*type_0x1001)() [8] __xp_z @ 0x14000c880
|
||||
global const unsigned char _guard_xfg_dispatch_icall_nop @ 0x140009aa0
|
||||
global void * __guard_xfg_table_dispatch_icall_fptr @ 0x140015040
|
||||
global void (*type_0x1001)() [8] __xc_a @ 0x14000c000
|
||||
global struct _onexit_table_t module_local_at_quick_exit_table @ 0x140011b58
|
||||
global int32_t __isa_enabled @ 0x14001103c
|
||||
global int32_t __scrt_default_matherr @ 0x140011034
|
||||
global void (*type_0x1001)() [8] __xt_a @ 0x14000c990
|
||||
global int64_t __memset_nt_iters @ 0x140011048
|
||||
global struct HINSTANCE__ * mspdb @ 0x140011bb8
|
||||
global void * __scrt_native_startup_lock @ 0x140011b30
|
||||
global void (*type_0x1001)() [8] __xc_a @ 0x14000c000
|
||||
global uint64_t __security_cookie_complement @ 0x140011000
|
||||
global int64_t __memcpy_nt_iters @ 0x140011040
|
||||
global void (*type_0x1001)() [8] __xp_a @ 0x14000c770
|
||||
global void (*type_0x1001)() [8] __rtc_taa @ 0x14000f0b8
|
||||
global const char [15] uninit_premsg @ 0x14000d8d0
|
||||
global const char [43] uninit_postmsg @ 0x14000d8e0
|
||||
global bool PDBOK @ 0x140011bc2
|
||||
global int64_t __memcpy_nt_iters @ 0x140011040
|
||||
global int32_t [20] _RTC_ErrorLevels @ 0x140011018
|
||||
global void (*type_0x1001)() [8] __rtc_tzz @ 0x14000f2d8
|
||||
global const char *[40] _RTC_errlist @ 0x14000df58
|
||||
global void * __guard_xfg_dispatch_icall_fptr @ 0x140015030
|
||||
global bool is_initialized_as_dll @ 0x140011b38
|
||||
global void * __guard_xfg_table_dispatch_icall_fptr @ 0x140015040
|
||||
global void (*type_0x1001)() [8] __rtc_iaa @ 0x14000ed88
|
||||
global struct _onexit_table_t module_local_atexit_table @ 0x140011b40
|
||||
global wchar_t [46] mspdbName @ 0x14000e078
|
||||
global bool init @ 0x140011470
|
||||
global void (*type_0x1001)() [8] __xt_z @ 0x14000caa0
|
||||
global void (*type_0x1001)() pre_cpp_initializer @ 0x14000c110
|
||||
global struct _RS5_IMAGE_LOAD_CONFIG_DIRECTORY64 _load_config_used @ 0x14000e2d0
|
||||
global struct __type_info_node __type_info_root_node @ 0x140011b80
|
||||
global void * __guard_check_icall_fptr @ 0x140015000
|
||||
global void (*type_0x1001)() [8] __xc_z @ 0x14000c220
|
||||
global bool alreadyTried @ 0x140011bc1
|
||||
global void (*type_0x1001)() [8] __rtc_izz @ 0x14000efa8
|
||||
global void (*type_0x1079)(void *arg0) __castguard_check_failure_os_handled_fptr @ 0x140011ba8
|
||||
global struct _EXCEPTION_RECORD GS_ExceptionRecord @ 0x1400114a0
|
||||
global int32_t (*type_0x1015)() [8] __xi_a @ 0x14000c330
|
||||
global void (*type_0x1001)() [8] __xt_a @ 0x14000c990
|
||||
global const unsigned char _guard_dispatch_icall_nop @ 0x140009a80
|
||||
global int32_t __scrt_debugger_hook_flag @ 0x140011ba4
|
||||
global int32_t (*type_0x1015)() [8] __xi_z @ 0x14000c660
|
||||
global int32_t __scrt_current_native_startup_state @ 0x140011b28
|
||||
global void (*type_0x1de8)(void *arg0, uint32_t arg1, void *arg2) __dyn_tls_init_callback @ 0x140011be0
|
||||
global uint64_t _OptionsStorage @ 0x140011478
|
||||
global wchar_t [8] dllExt @ 0x14000e240
|
||||
global int32_t (*type_0x1d1a)(int32_t arg0, const char *arg1, int32_t arg2, const char *arg3, const char *arg4) _RTC_ErrorReportFunc @ 0x140011488
|
||||
global int32_t (*type_0x1015)() post_pgo_initializer @ 0x14000c550
|
||||
global void * __CastGuardVftablesStart @ 0x14000e600
|
||||
global int32_t __favor @ 0x140011bc4
|
||||
global void * __CastGuardVftablesEnd @ 0x14000e710
|
||||
global uint64_t __security_cookie_complement @ 0x140011000
|
||||
global void * __guard_xfg_check_icall_fptr @ 0x140015010
|
||||
---
|
||||
(nofunc) 0x140007344 [DATA] lea rcx, pdb.exceptions_test.__guard_check_icall_fptr
|
||||
0x140007344 lea rcx, pdb.exceptions_test.__guard_check_icall_fptr ; 0x140015000
|
||||
@@ -180,10 +261,10 @@ FILE==
|
||||
CMDS=<<EOF
|
||||
e bin.baddr=0
|
||||
idp bins/pdb/Project1.pdb
|
||||
fl~pdb:1
|
||||
fl~__enc_textbss_end
|
||||
e bin.baddr=0x800000
|
||||
idp bins/pdb/Project1.pdb
|
||||
fl~pdb:1
|
||||
fl~__enc_textbss_end
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00011000 0 pdb.Project1.__enc_textbss_end
|
||||
|
||||
@@ -1068,6 +1068,22 @@ EOF
|
||||
EXPECT=<<EOF
|
||||
{
|
||||
"pdb": [
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"module_name": "* Linker Generated Manifest RES *",
|
||||
"object_file_name": ""
|
||||
},
|
||||
{
|
||||
"module_name": "C:\\Users\\emuresan\\source\\repos\\minimal\\Release\\main.obj",
|
||||
"object_file_name": "C:\\Users\\emuresan\\source\\repos\\minimal\\Release\\main.obj"
|
||||
},
|
||||
{
|
||||
"module_name": "* Linker *",
|
||||
"object_file_name": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"types": [
|
||||
{
|
||||
|
||||
+10
-23
@@ -21,6 +21,10 @@ bool pdb_info_save_types(RzAnalysis *analysis, const char *file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#define STREAMS_CHECK(x) \
|
||||
mu_assert_notnull(pdb->streams, "NULL streams"); \
|
||||
mu_assert_eq(rz_pvector_len(pdb->streams), (x), "Incorrect number of streams");
|
||||
|
||||
#define MEMBER_INIT_AND_CHECK_LEN(x) \
|
||||
RzPVector *members = rz_bin_pdb_get_type_members(stream, type); \
|
||||
mu_assert_notnull(members, "NULL members"); \
|
||||
@@ -30,11 +34,7 @@ bool test_pdb_tpi_cpp(void) {
|
||||
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file("bins/pdb/Project1.pdb");
|
||||
mu_assert_notnull(pdb, "PDB parse failed.");
|
||||
|
||||
RzList *plist = pdb->streams;
|
||||
mu_assert_notnull(plist, "PDB streams is NULL");
|
||||
|
||||
mu_assert_eq(pdb->streams->length, 50, "Incorrect number of streams");
|
||||
STREAMS_CHECK(50);
|
||||
|
||||
RzPdbTpiStream *stream = pdb->s_tpi;
|
||||
mu_assert_notnull(stream, "TPIs stream not found in current PDB");
|
||||
@@ -42,13 +42,13 @@ bool test_pdb_tpi_cpp(void) {
|
||||
mu_assert_eq(stream->header.TypeIndexBegin, 0x1000, "Wrong beginning index");
|
||||
RBIter it;
|
||||
RzPdbTpiType *type;
|
||||
|
||||
rz_rbtree_foreach (stream->types, it, type, RzPdbTpiType, rb) {
|
||||
mu_assert_notnull(type, "RzPdbTpiType is null in RBTree.");
|
||||
if (type->index == 0x1028) {
|
||||
mu_assert_eq(type->leaf, LF_PROCEDURE, "Incorrect data type");
|
||||
Tpi_LF_Procedure *procedure = type->data;
|
||||
RzPdbTpiType *arglist;
|
||||
arglist = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Procedure *)(type->data))->arg_list);
|
||||
arglist = rz_bin_pdb_get_type_by_index(stream, procedure->arg_list);
|
||||
mu_assert_eq(arglist->index, 0x1027, "Wrong type index");
|
||||
RzPdbTpiType *return_type;
|
||||
return_type = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Procedure *)(type->data))->return_type);
|
||||
@@ -195,11 +195,7 @@ bool test_pdb_tpi_rust(void) {
|
||||
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file("bins/pdb/ghidra_rust_pdb_bug.pdb");
|
||||
mu_assert_notnull(pdb, "PDB parse failed.");
|
||||
|
||||
RzList *plist = pdb->streams;
|
||||
mu_assert_notnull(plist, "PDB streams is NULL");
|
||||
|
||||
mu_assert_eq(pdb->streams->length, 88, "Incorrect number of streams");
|
||||
STREAMS_CHECK(88);
|
||||
|
||||
RzPdbTpiStream *stream = pdb->s_tpi;
|
||||
mu_assert_notnull(stream, "TPIs stream not found in current PDB");
|
||||
@@ -434,11 +430,7 @@ bool test_pdb_type_save(void) {
|
||||
bool test_pdb_tpi_cpp_vs2019(void) {
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file("bins/pdb/vs2019_cpp_override.pdb");
|
||||
mu_assert_notnull(pdb, "PDB parse failed.");
|
||||
|
||||
RzList *plist = pdb->streams;
|
||||
mu_assert_notnull(plist, "PDB streams is NULL");
|
||||
|
||||
mu_assert_eq(pdb->streams->length, 75, "Incorrect number of streams");
|
||||
STREAMS_CHECK(75);
|
||||
|
||||
RzPdbTpiStream *stream = pdb->s_tpi;
|
||||
mu_assert_notnull(stream, "TPIs stream not found in current PDB");
|
||||
@@ -673,11 +665,7 @@ bool test_pdb_tpi_cpp_vs2019(void) {
|
||||
bool test_pdb_tpi_arm(void) {
|
||||
RzPdb *pdb = rz_bin_pdb_parse_from_file("bins/pe/hello_world_arm/hello_world_arm_ZiZoO2.pdb");
|
||||
mu_assert_notnull(pdb, "PDB parse failed.");
|
||||
|
||||
RzList *plist = pdb->streams;
|
||||
mu_assert_notnull(plist, "PDB streams is NULL");
|
||||
|
||||
mu_assert_eq(pdb->streams->length, 399, "Incorrect number of streams");
|
||||
STREAMS_CHECK(399);
|
||||
|
||||
RzPdbTpiStream *stream = pdb->s_tpi;
|
||||
mu_assert_notnull(stream, "TPIs stream not found in current PDB");
|
||||
@@ -685,7 +673,6 @@ bool test_pdb_tpi_arm(void) {
|
||||
mu_assert_eq(stream->header.TypeIndexBegin, 0x1000, "Wrong beginning index");
|
||||
RBIter it;
|
||||
RzPdbTpiType *type;
|
||||
|
||||
rz_rbtree_foreach (stream->types, it, type, RzPdbTpiType, rb) {
|
||||
if (type->index == 0x1A56) {
|
||||
mu_assert_eq(type->leaf, LF_PROCEDURE, "Incorrect data type");
|
||||
|
||||
Reference in New Issue
Block a user