From d5d29fcb37cbb563ff0d1fae6ccfde1c8e8c4653 Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 10 Dec 2023 14:14:14 +0800 Subject: [PATCH] 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` --- librz/analysis/pdb_process.c | 416 +++---- librz/bin/format/pe/pe_security.c | 2 +- librz/bin/meson.build | 1 + librz/bin/pdb/dbi.c | 191 ++- librz/bin/pdb/dbi.h | 57 +- librz/bin/pdb/gdata.c | 29 +- librz/bin/pdb/modi.c | 52 + librz/bin/pdb/modi.h | 19 + librz/bin/pdb/omap.c | 10 +- librz/bin/pdb/pdb.c | 127 +- librz/bin/pdb/pdb.h | 91 +- librz/bin/pdb/stream_pe.c | 4 +- librz/bin/pdb/symbol.c | 105 +- librz/bin/pdb/symbol.h | 72 +- librz/bin/pdb/tpi.c | 1881 +++++++++++++---------------- librz/bin/pdb/tpi.h | 132 +- librz/core/cpdb.c | 301 +++-- librz/core/windows_heap.c | 92 +- librz/include/rz_core.h | 2 +- librz/include/rz_pdb.h | 125 +- librz/util/buf.c | 4 +- test/db/cmd/cmd_idp | 16 + test/db/formats/pdb | 191 ++- test/db/tools/rz_bin | 16 + test/integration/test_pdb.c | 33 +- 25 files changed, 2071 insertions(+), 1898 deletions(-) create mode 100644 librz/bin/pdb/modi.c create mode 100644 librz/bin/pdb/modi.h diff --git a/librz/analysis/pdb_process.c b/librz/analysis/pdb_process.c index af3e1b10a4..9fb3b727c4 100644 --- a/librz/analysis/pdb_process.c +++ b/librz/analysis/pdb_process.c @@ -9,31 +9,29 @@ #include #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 /**/ *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 /**/ *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 /**/ *vec) { +static void arglist_parse(const RzTypeDB *typedb, RzPdbTpiStream *stream, RzPdbTpiType *arglist, RzPVector /**/ *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); } } diff --git a/librz/bin/format/pe/pe_security.c b/librz/bin/format/pe/pe_security.c index ba9d77b387..5bd96c6d5f 100644 --- a/librz/bin/format/pe/pe_security.c +++ b/librz/bin/format/pe/pe_security.c @@ -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; } diff --git a/librz/bin/meson.build b/librz/bin/meson.build index aa03a7389c..7cc1a1c6f5 100644 --- a/librz/bin/meson.build +++ b/librz/bin/meson.build @@ -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', diff --git a/librz/bin/pdb/dbi.c b/librz/bin/pdb/dbi.c index 7280f1169c..d7efea3e5e 100644 --- a/librz/bin/pdb/dbi.c +++ b/librz/bin/pdb/dbi.c @@ -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; } diff --git a/librz/bin/pdb/dbi.h b/librz/bin/pdb/dbi.h index 6da5ef5cad..0b537ffb38 100644 --- a/librz/bin/pdb/dbi.h +++ b/librz/bin/pdb/dbi.h @@ -4,7 +4,10 @@ #ifndef PDB_DBI_H #define PDB_DBI_H -#include +#include + +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 \ No newline at end of file diff --git a/librz/bin/pdb/gdata.c b/librz/bin/pdb/gdata.c index 63a4c350be..17c0a6f9af 100644 --- a/librz/bin/pdb/gdata.c +++ b/librz/bin/pdb/gdata.c @@ -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; } diff --git a/librz/bin/pdb/modi.c b/librz/bin/pdb/modi.c new file mode 100644 index 0000000000..d87dc4c8d6 --- /dev/null +++ b/librz/bin/pdb/modi.c @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2023 billow +// 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; +} diff --git a/librz/bin/pdb/modi.h b/librz/bin/pdb/modi.h new file mode 100644 index 0000000000..ddebf41123 --- /dev/null +++ b/librz/bin/pdb/modi.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 billow +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef MODI_H +#define MODI_H + +#include +#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 diff --git a/librz/bin/pdb/omap.c b/librz/bin/pdb/omap.c index 7db2b263e3..65b50458f9 100644 --- a/librz/bin/pdb/omap.c +++ b/librz/bin/pdb/omap.c @@ -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; diff --git a/librz/bin/pdb/pdb.c b/librz/bin/pdb/pdb.c index 135f9b246f..6583d44e81 100644 --- a/librz/bin/pdb/pdb.c +++ b/librz/bin/pdb/pdb.c @@ -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 /**/ *pdb7_extract_streams(RzPdb *pdb, RzPdbMsfStreamDirectory *msd) { - RzList *streams = rz_list_newf(msf_stream_free); +static RzPVector /**/ *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 /**/ *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 /**/ *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); } diff --git a/librz/bin/pdb/pdb.h b/librz/bin/pdb/pdb.h index a7c8f6a0d1..9d8ec3ac6e 100644 --- a/librz/bin/pdb/pdb.h +++ b/librz/bin/pdb/pdb.h @@ -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 \ No newline at end of file +#endif diff --git a/librz/bin/pdb/stream_pe.c b/librz/bin/pdb/stream_pe.c index 8409bd1e3f..7034e4d0b7 100644 --- a/librz/bin/pdb/stream_pe.c +++ b/librz/bin/pdb/stream_pe.c @@ -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; } diff --git a/librz/bin/pdb/symbol.c b/librz/bin/pdb/symbol.c index 492196b80b..ce34c16a22 100644 --- a/librz/bin/pdb/symbol.c +++ b/librz/bin/pdb/symbol.c @@ -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 /**/ **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; +} diff --git a/librz/bin/pdb/symbol.h b/librz/bin/pdb/symbol.h index 89d380b70b..051462ab31 100644 --- a/librz/bin/pdb/symbol.h +++ b/librz/bin/pdb/symbol.h @@ -8,79 +8,8 @@ #include #include -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 /**/ **psymbols); #endif // RIZIN_SYMBOL_H diff --git a/librz/bin/pdb/tpi.c b/librz/bin/pdb/tpi.c index b3cd9511b1..65766b83a2 100644 --- a/librz/bin/pdb/tpi.c +++ b/librz/bin/pdb/tpi.c @@ -4,57 +4,26 @@ #include "pdb.h" +#define conditional(X, T, F) (X ? T : F) + +static bool buf_read_string(RzBuffer *b, ut16 leaf, char **result) { + if (leaf < LF_ST_MAX) { + return buf_read_u8_pascal_string(b, result); + } else { + return rz_buf_read_string(b, result) > 0; + } + return false; +} + static RzPdbTpiType *RzPdbTpiType_from_buf(RzBuffer *b, ut32 index, ut16 length); -static RzBuffer *buf_take(RzBuffer *b, ut32 len) { - 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 bool buf_empty(RzBuffer *b) { - if (!b) { - return true; - } - return rz_buf_tell(b) >= rz_buf_size(b); -} - -static 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 bool is_simple_type(RzPdbTpiStream *stream, ut32 idx) { - /* https://llvm.org/docs/PDB/TpiStream.html#type-indices - .---------------------------.------.----------. - | Unused | Mode | Kind | - '---------------------------'------'----------' - |+32 |+12 |+8 |+0 - */ - return idx < stream->header.TypeIndexBegin; - // return ((value & 0x00000000FFF00) <= 0x700 && (value & 0x00000000000FF) < - // 0x80); -} - int tpi_type_node_cmp(const void *incoming, const RBNode *in_tree, void *user) { ut32 ia = *(ut32 *)incoming; ut32 ta = container_of(in_tree, const RzPdbTpiType, rb)->index; if (ia < ta) { return -1; - } else if (ia > ta) { + } + if (ia > ta) { return 1; } return 0; @@ -91,28 +60,17 @@ RZ_API RZ_OWN char *rz_bin_pdb_calling_convention_as_string(RZ_NONNULL RzPdbTpiC } } -static TpiSimpleTypeMode get_simple_type_mode(ut32 type) { - /* https://llvm.org/docs/PDB/RzPdbTpiStream.html#type-indices - .---------------------------.------.----------. - | Unused | Mode | Kind | - '---------------------------'------'----------' - |+32 |+12 |+8 |+0 - */ - // because mode is only number between 0-7, 1 byte is enough - return (type & 0x0000000000F00) >> 8; -} +#define GEN_PARSER(T, S, U, F) \ + static bool T##_parse(RzBuffer *b, T *p) { \ + U value; \ + if (!F(b, &value)) { \ + return false; \ + } \ + S(p, value); \ + return true; \ + } -static TpiSimpleTypeKind get_simple_type_kind(ut32 type) { - /* https://llvm.org/docs/PDB/RzPdbTpiStream.html#type-indices - .---------------------------.------.----------. - | Unused | Mode | Kind | - '---------------------------'------'----------' - |+32 |+12 |+8 |+0 - */ - return (type & 0x00000000000FF); -} - -static void parse_codeview_property(TpiCVProperty *p, ut16 value) { +static void set_property(TpiCVProperty *p, ut32 const value) { p->packed = GET_BF(value, 0, 1); p->ctor = GET_BF(value, 1, 1); p->ovlops = GET_BF(value, 2, 1); @@ -129,7 +87,21 @@ static void parse_codeview_property(TpiCVProperty *p, ut16 value) { p->mocom = GET_BF(value, 14, 2); } -static void parse_codeview_fld_attribute(TpiCVFldattr *f, ut16 value) { +GEN_PARSER(TpiCVProperty, set_property, ut16, rz_buf_read_le16); +static bool TpiCVProperty_parse_opt(RzBuffer *b, TpiCVProperty *p, const bool is32) { + if (is32) { + ut32 value; + if (!rz_buf_read_le32(b, &value)) { + return false; + } + set_property(p, value); + } else { + return TpiCVProperty_parse(b, p); + } + return true; +} + +static void set_fldattr(TpiCVFldattr *f, ut16 value) { f->access = GET_BF(value, 0, 2); f->mprop = GET_BF(value, 2, 3); f->pseudo = GET_BF(value, 5, 1); @@ -138,14 +110,21 @@ static void parse_codeview_fld_attribute(TpiCVFldattr *f, ut16 value) { f->compgenx = GET_BF(value, 8, 1); f->sealed = GET_BF(value, 9, 1); } +GEN_PARSER(TpiCVFldattr, set_fldattr, ut16, rz_buf_read_le16); -static void parse_codeview_func_attribute(TpiCVFuncattr *f, ut8 value) { +RZ_IPI bool TpiCVFldattr_is_intro_virtual(TpiCVFldattr *x) { + return x && (x->mprop == MTintro || x->mprop == MTpureintro); +} + +static void set_func_attribute(TpiCVFuncattr *f, ut16 value) { + f->calling_convention = value & 0xff; f->cxxreturnudt = GET_BF(value, 0, 1); f->ctor = GET_BF(value, 1, 1); f->ctorvbase = GET_BF(value, 2, 1); } +GEN_PARSER(TpiCVFuncattr, set_func_attribute, ut16, rz_buf_read_le16); -static void parse_codeview_pointer_attribute(TpiCVPointerAttr *p, ut32 value) { +static void set_pointer_attribute(TpiCVPointerAttr *p, ut32 value) { p->ptrtype = GET_BF(value, 0, 5); p->ptrmode = GET_BF(value, 5, 3); p->flat32 = GET_BF(value, 8, 1); @@ -159,12 +138,51 @@ static void parse_codeview_pointer_attribute(TpiCVPointerAttr *p, ut32 value) { p->rref = GET_BF(value, 21, 1); p->unused = GET_BF(value, 22, 10); } +GEN_PARSER(TpiCVPointerAttr, set_pointer_attribute, ut32, rz_buf_read_le32); -static void parse_codeview_modifier(TpiCVModifier *m, ut16 value) { +RZ_IPI bool TpiCVPointerAttr_pointer_to_member(TpiCVPointerAttr *x) { + return x && (x->ptrmode == PTR_MODE_PMFUNC || x->ptrmode == PTR_MODE_PMEM); +} + +static void set_modifier(TpiCVModifier *m, ut16 value) { m->const_ = GET_BF(value, 0, 1); m->volatile_ = GET_BF(value, 1, 1); m->unaligned = GET_BF(value, 2, 1); } +GEN_PARSER(TpiCVModifier, set_modifier, ut16, rz_buf_read_le16); + +static bool simple_type_check(RzPdbTpiStream *stream, ut32 idx) { + /* https://llvm.org/docs/PDB/TpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + return idx < stream->header.TypeIndexBegin; + // return ((value & 0x00000000FFF00) <= 0x700 && (value & 0x00000000000FF) < + // 0x80); +} + +static TpiSimpleTypeMode simple_type_mode(ut32 type) { + /* https://llvm.org/docs/PDB/RzPdbTpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + // because mode is only number between 0-7, 1 byte is enough + return (type & 0x0000000000F00) >> 8; +} + +static TpiSimpleTypeKind simple_type_kind(ut32 type) { + /* https://llvm.org/docs/PDB/RzPdbTpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + return (type & 0x00000000000FF); +} /** * \brief Parses simple type if the idx represents one @@ -172,13 +190,14 @@ static void parse_codeview_modifier(TpiCVModifier *m, ut16 value) { * \param idx leaf index * \return RzPdbTpiType, leaf = 0 -> error */ -RZ_IPI RzPdbTpiType *parse_simple_type(RzPdbTpiStream *stream, ut32 idx) { +RZ_IPI RzPdbTpiType *simple_type_parse(RzPdbTpiStream *stream, ut32 idx) { RzPdbTpiType *type = RZ_NEW0(RzPdbTpiType); if (!type) { RZ_LOG_ERROR("Error allocating memory.\n"); return NULL; } type->leaf = LF_SIMPLE_TYPE; + type->kind = TpiKind_SIMPLE_TYPE; type->index = idx; // For simple type we don't set length type->length = 0; @@ -189,164 +208,164 @@ RZ_IPI RzPdbTpiType *parse_simple_type(RzPdbTpiStream *stream, ut32 idx) { return NULL; } type->data = simple_type; - RzStrBuf *buf; - TpiSimpleTypeKind kind = get_simple_type_kind(idx); + RzStrBuf *b; + TpiSimpleTypeKind kind = simple_type_kind(idx); switch (kind) { case PDB_NONE: simple_type->size = 0; - buf = rz_strbuf_new("notype_t"); + b = rz_strbuf_new("notype_t"); break; case PDB_VOID: simple_type->size = 0; - buf = rz_strbuf_new("void"); + b = rz_strbuf_new("void"); break; case PDB_SIGNED_CHAR: case PDB_NARROW_CHAR: simple_type->size = 1; - buf = rz_strbuf_new("char"); + b = rz_strbuf_new("char"); break; case PDB_UNSIGNED_CHAR: simple_type->size = 1; - buf = rz_strbuf_new("unsigned char"); + b = rz_strbuf_new("unsigned char"); break; case PDB_WIDE_CHAR: simple_type->size = 4; - buf = rz_strbuf_new("wchar_t"); + b = rz_strbuf_new("wchar_t"); break; case PDB_CHAR16: simple_type->size = 2; - buf = rz_strbuf_new("char16_t"); + b = rz_strbuf_new("char16_t"); break; case PDB_CHAR32: simple_type->size = 4; - buf = rz_strbuf_new("char32_t"); + b = rz_strbuf_new("char32_t"); break; case PDB_BYTE: simple_type->size = 1; - buf = rz_strbuf_new("uint8_t"); + b = rz_strbuf_new("uint8_t"); break; case PDB_SBYTE: simple_type->size = 1; - buf = rz_strbuf_new("int8_t"); + b = rz_strbuf_new("int8_t"); break; case PDB_INT16: case PDB_INT16_SHORT: simple_type->size = 2; - buf = rz_strbuf_new("int16_t"); + b = rz_strbuf_new("int16_t"); break; case PDB_UINT16: case PDB_UINT16_SHORT: simple_type->size = 2; - buf = rz_strbuf_new("uint16_t"); + b = rz_strbuf_new("uint16_t"); break; case PDB_INT32: case PDB_INT32_LONG: simple_type->size = 4; - buf = rz_strbuf_new("int32_t"); + b = rz_strbuf_new("int32_t"); break; case PDB_UINT32: case PDB_UINT32_LONG: simple_type->size = 4; - buf = rz_strbuf_new("uint32_t"); + b = rz_strbuf_new("uint32_t"); break; case PDB_INT64: case PDB_INT64_QUAD: simple_type->size = 8; - buf = rz_strbuf_new("int64_t"); + b = rz_strbuf_new("int64_t"); break; case PDB_UINT64: case PDB_UINT64_QUAD: simple_type->size = 8; - buf = rz_strbuf_new("uint64_t"); + b = rz_strbuf_new("uint64_t"); break; case PDB_INT128: case PDB_INT128_OCT: simple_type->size = 16; - buf = rz_strbuf_new("int128_t"); + b = rz_strbuf_new("int128_t"); break; case PDB_UINT128: case PDB_UINT128_OCT: simple_type->size = 16; - buf = rz_strbuf_new("uint128_t"); + b = rz_strbuf_new("uint128_t"); break; case PDB_FLOAT16: simple_type->size = 2; - buf = rz_strbuf_new("float"); + b = rz_strbuf_new("float"); break; case PDB_FLOAT32: case PDB_FLOAT32_PP: simple_type->size = 4; - buf = rz_strbuf_new("float"); + b = rz_strbuf_new("float"); break; case PDB_FLOAT48: simple_type->size = 6; - buf = rz_strbuf_new("float"); + b = rz_strbuf_new("float"); break; case PDB_FLOAT64: simple_type->size = 8; - buf = rz_strbuf_new("double"); + b = rz_strbuf_new("double"); break; case PDB_FLOAT80: simple_type->size = 10; - buf = rz_strbuf_new("long double"); + b = rz_strbuf_new("long double"); break; case PDB_FLOAT128: simple_type->size = 16; - buf = rz_strbuf_new("long double"); + b = rz_strbuf_new("long double"); break; case PDB_COMPLEX16: simple_type->size = 2; - buf = rz_strbuf_new("float _Complex"); + b = rz_strbuf_new("float _Complex"); break; case PDB_COMPLEX32: case PDB_COMPLEX32_PP: simple_type->size = 4; - buf = rz_strbuf_new("float _Complex"); + b = rz_strbuf_new("float _Complex"); break; case PDB_COMPLEX48: simple_type->size = 6; - buf = rz_strbuf_new("float _Complex"); + b = rz_strbuf_new("float _Complex"); break; case PDB_COMPLEX64: simple_type->size = 8; - buf = rz_strbuf_new("double _Complex"); + b = rz_strbuf_new("double _Complex"); break; case PDB_COMPLEX80: simple_type->size = 10; - buf = rz_strbuf_new("long double _Complex"); + b = rz_strbuf_new("long double _Complex"); break; case PDB_COMPLEX128: simple_type->size = 16; - buf = rz_strbuf_new("long double _Complex"); + b = rz_strbuf_new("long double _Complex"); break; case PDB_BOOL8: simple_type->size = 1; - buf = rz_strbuf_new("bool"); + b = rz_strbuf_new("bool"); break; case PDB_BOOL16: simple_type->size = 2; - buf = rz_strbuf_new("bool"); + b = rz_strbuf_new("bool"); break; case PDB_BOOL32: simple_type->size = 4; - buf = rz_strbuf_new("bool"); + b = rz_strbuf_new("bool"); break; case PDB_BOOL64: simple_type->size = 8; - buf = rz_strbuf_new("bool"); + b = rz_strbuf_new("bool"); break; case PDB_BOOL128: simple_type->size = 16; - buf = rz_strbuf_new("bool"); + b = rz_strbuf_new("bool"); break; default: simple_type->size = 0; - buf = rz_strbuf_new("unknown_t"); + b = rz_strbuf_new("unknown_t"); break; } - TpiSimpleTypeMode mode = get_simple_type_mode(idx); + TpiSimpleTypeMode mode = simple_type_mode(idx); if (mode) { - rz_strbuf_append(buf, " *"); + rz_strbuf_append(b, " *"); } switch (mode) { case NEAR_POINTER: @@ -367,43 +386,138 @@ RZ_IPI RzPdbTpiType *parse_simple_type(RzPdbTpiStream *stream, ut32 idx) { default: break; } - simple_type->type = rz_strbuf_drain(buf); + simple_type->type = rz_strbuf_drain(b); // We just insert once rz_rbtree_insert(&stream->types, &type->index, &type->rb, tpi_type_node_cmp, NULL); return type; } -static void simple_type_free(Tpi_LF_SimpleType *t) { - if (!t) { - return; - } +static void simple_type_fini(Tpi_LF_SimpleType *t) { free(t->type); - free(t); } -static ut64 get_numeric_val(Tpi_Type_Numeric *numeric) { - switch (numeric->type_index) { - case LF_CHAR: - return *(st8 *)(numeric->data); - case LF_SHORT: - return *(st16 *)(numeric->data); - case LF_USHORT: - return *(ut16 *)(numeric->data); - case LF_LONG: - return *(st32 *)(numeric->data); - case LF_ULONG: - return *(ut32 *)(numeric->data); - case LF_QUADWORD: - return *(st64 *)(numeric->data); - case LF_UQUADWORD: - return *(ut64 *)(numeric->data); - default: - if (numeric->type_index >= 0x8000) { - return 0; - } - return *(ut16 *)(numeric->data); +static bool buf_read_unsigned(RzBuffer *b, ut64 *x) { + ut16 leaf; + if (!rz_buf_read_le16(b, &leaf)) { + return false; } + if (leaf < LF_NUMERIC) { + *x = leaf; + return true; + } + switch (leaf) { + case LF_CHAR: { + ut8 tmp; + if (!rz_buf_read8(b, &tmp)) { + return false; + } + *x = tmp; + break; + } + case LF_USHORT: { + ut16 tmp; + if (!rz_buf_read_le16(b, &tmp)) { + return false; + } + *x = tmp; + break; + } + case LF_ULONG: { + ut32 tmp; + if (!rz_buf_read_le32(b, &tmp)) { + return false; + } + *x = tmp; + break; + } + case LF_UQUADWORD: { + ut64 tmp; + if (!rz_buf_read_le64(b, &tmp)) { + return false; + } + *x = tmp; + break; + } + default: + return false; + } + return true; } + +static bool TpiVariant_parse(RzBuffer *b, TpiVariant *x) { + ut16 leaf = 0; + if (!rz_buf_read_le16(b, &leaf)) { + return false; + } + if (leaf < LF_NUMERIC) { + x->tag = TpiVariant_U16; + x->u16v = leaf; + return true; + } + switch (leaf) { + case LF_CHAR: { + ut8 tmp; + if (!rz_buf_read8(b, &tmp)) { + return false; + } + x->tag = TpiVariant_I8; + x->i8v = (st8)tmp; + break; + } + case LF_SHORT: { + ut16 tmp; + if (!rz_buf_read_le16(b, &tmp)) { + return false; + } + x->tag = TpiVariant_I16; + x->i16v = (st16)tmp; + break; + } + case LF_LONG: { + ut32 tmp; + if (!rz_buf_read_le32(b, &tmp)) { + return false; + } + x->tag = TpiVariant_I32; + x->i32v = (st32)tmp; + break; + } + case LF_QUADWORD: { + ut64 tmp; + if (!rz_buf_read_le64(b, &tmp)) { + return false; + } + x->tag = TpiVariant_I64; + x->i64v = (st64)tmp; + break; + } + case LF_USHORT: { + x->tag = TpiVariant_U16; + if (!rz_buf_read_le16(b, &x->u16v)) { + return false; + } + break; + } + case LF_ULONG: { + x->tag = TpiVariant_U32; + if (!rz_buf_read_le32(b, &x->u32v)) { + return false; + } + break; + } + case LF_UQUADWORD: { + x->tag = TpiVariant_U64; + if (!rz_buf_read_le64(b, &x->u64v)) { + return false; + } + break; + } + default: + return false; + } + return true; +} + /** * \brief Return true if type is forward definition * @@ -412,23 +526,17 @@ static ut64 get_numeric_val(Tpi_Type_Numeric *numeric) { */ RZ_API bool rz_bin_pdb_type_is_fwdref(RZ_NONNULL RzPdbTpiType *t) { rz_return_val_if_fail(t, false); // return val stands for we do nothing for it - switch (t->leaf) { - case LF_UNION: { - Tpi_LF_Union *lf = (Tpi_LF_Union *)t->data; + switch (t->kind) { + case TpiKind_UNION: { + Tpi_LF_Union *lf = t->data; return lf->prop.fwdref ? true : false; } - case LF_STRUCTURE: - case LF_CLASS: { - Tpi_LF_Structure *lf = (Tpi_LF_Structure *)t->data; + case TpiKind_CLASS: { + Tpi_LF_Class *lf = t->data; return lf->prop.fwdref ? true : false; } - case LF_STRUCTURE_19: - case LF_CLASS_19: { - Tpi_LF_Structure_19 *lf = (Tpi_LF_Structure_19 *)t->data; - return lf->prop.fwdref ? true : false; - } - case LF_ENUM: { - Tpi_LF_Enum *lf = (Tpi_LF_Enum *)t->data; + case TpiKind_ENUM: { + Tpi_LF_Enum *lf = t->data; return lf->prop.fwdref ? true : false; } default: @@ -447,37 +555,30 @@ RZ_API bool rz_bin_pdb_type_is_fwdref(RZ_NONNULL RzPdbTpiType *t) { RZ_API RZ_BORROW RzPVector /**/ *rz_bin_pdb_get_type_members( RZ_NONNULL RzPdbTpiStream *stream, RzPdbTpiType *t) { rz_return_val_if_fail(t, NULL); - RzPdbTpiType *tmp; - switch (t->leaf) { - case LF_FIELDLIST: { - Tpi_LF_FieldList *lf = t->data; - return lf->substructs; + const RzPdbTpiType *fieldlist = NULL; + switch (t->kind) { + case TpiKind_FILEDLIST: { + fieldlist = t; + break; } - case LF_UNION: { - tmp = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Union *)t->data)->field_list); - Tpi_LF_FieldList *lf_union = tmp ? tmp->data : NULL; - return lf_union ? lf_union->substructs : NULL; + case TpiKind_UNION: { + fieldlist = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Union *)t->data)->field_list); + break; } - case LF_STRUCTURE: - case LF_CLASS: { - tmp = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Structure *)t->data)->field_list); - Tpi_LF_FieldList *lf_struct = tmp ? tmp->data : NULL; - return lf_struct ? lf_struct->substructs : NULL; + case TpiKind_CLASS: { + fieldlist = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Class *)t->data)->field_list); + break; } - case LF_STRUCTURE_19: - case LF_CLASS_19: { - tmp = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Structure_19 *)t->data)->field_list); - Tpi_LF_FieldList *lf_struct19 = tmp ? tmp->data : NULL; - return lf_struct19 ? lf_struct19->substructs : NULL; - } - case LF_ENUM: { - tmp = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Enum *)t->data)->field_list); - Tpi_LF_FieldList *lf_enum = tmp ? tmp->data : NULL; - return lf_enum ? lf_enum->substructs : NULL; + case TpiKind_ENUM: { + fieldlist = rz_bin_pdb_get_type_by_index(stream, ((Tpi_LF_Enum *)t->data)->field_list); + break; } default: + err: return NULL; } + map_err(fieldlist && fieldlist->data); + return ((Tpi_LF_FieldList *)fieldlist->data)->substructs; } /** @@ -488,52 +589,49 @@ RZ_API RZ_BORROW RzPVector /**/ *rz_bin_pdb_get_type_members( */ RZ_API RZ_BORROW char *rz_bin_pdb_get_type_name(RZ_NONNULL RzPdbTpiType *type) { rz_return_val_if_fail(type, NULL); - switch (type->leaf) { - case LF_MEMBER: { + if (!type->data) { + return NULL; + } + switch (type->kind) { + case TpiKind_MEMBER: { Tpi_LF_Member *lf_member = type->data; - return lf_member->name.name; + return lf_member->name; } - case LF_STMEMBER: { + case TpiKind_STMEMBER: { Tpi_LF_StaticMember *lf_stmember = type->data; - return lf_stmember->name.name; + return lf_stmember->name; } - case LF_ONEMETHOD: { + case TpiKind_ONEMETHOD: { Tpi_LF_OneMethod *lf_onemethod = type->data; - return lf_onemethod->name.name; + return lf_onemethod->name; } - case LF_METHOD: { + case TpiKind_METHOD: { Tpi_LF_Method *lf_method = type->data; - return lf_method->name.name; + return lf_method->name; } - case LF_NESTTYPE: { + case TpiKind_NESTTYPE: { Tpi_LF_NestType *lf_nesttype = type->data; - return lf_nesttype->name.name; + return lf_nesttype->name; } - case LF_ENUM: { + case TpiKind_ENUM: { Tpi_LF_Enum *lf_enum = type->data; - return lf_enum->name.name; + return lf_enum->name; } - case LF_ENUMERATE: { + case TpiKind_ENUMERATE: { Tpi_LF_Enumerate *lf_enumerate = type->data; - return lf_enumerate->name.name; + return lf_enumerate->name; } - case LF_CLASS: - case LF_STRUCTURE: { - Tpi_LF_Structure *lf_struct = type->data; - return lf_struct->name.name; + case TpiKind_CLASS: { + Tpi_LF_Class *lf_struct = type->data; + return lf_struct->name; } - case LF_CLASS_19: - case LF_STRUCTURE_19: { - Tpi_LF_Structure_19 *lf_struct_19 = type->data; - return lf_struct_19->name.name; - } - case LF_ARRAY: { - Tpi_LF_Array *lf_array = type->data; - return lf_array->name.name; - } - case LF_UNION: { + case TpiKind_UNION: { Tpi_LF_Union *lf_union = type->data; - return lf_union->name.name; + return lf_union->name; + } + case TpiKind_SIMPLE_TYPE: { + Tpi_LF_SimpleType *st = type->data; + return st->type; } default: return NULL; @@ -548,1049 +646,723 @@ 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) { rz_return_val_if_fail(type, -1); - switch (type->leaf) { - case LF_ONEMETHOD: { + switch (type->kind) { + case TpiKind_ONEMETHOD: { Tpi_LF_OneMethod *lf_onemethod = type->data; return lf_onemethod->offset_in_vtable; } - case LF_MEMBER: { + case TpiKind_MEMBER: { Tpi_LF_Member *lf_member = type->data; - return get_numeric_val(&lf_member->offset); + return lf_member->offset; } - case LF_ENUMERATE: { + case TpiKind_ENUMERATE: { Tpi_LF_Enumerate *lf_enumerate = type->data; - return get_numeric_val(&lf_enumerate->enum_value); + TpiVariant *x = &lf_enumerate->value; + switch (x->tag) { + case TpiVariant_U64: return x->u64v; + case TpiVariant_U32: return x->u32v; + case TpiVariant_U16: return x->u16v; + case TpiVariant_U8: return x->u8v; + case TpiVariant_I64: return x->i64v; + case TpiVariant_I32: return x->i32v; + case TpiVariant_I16: return x->i16v; + case TpiVariant_I8: return x->i8v; + } + break; } - case LF_CLASS: - case LF_STRUCTURE: { - Tpi_LF_Structure *lf_struct = type->data; - return get_numeric_val(&lf_struct->size); + case TpiKind_CLASS: { + Tpi_LF_Class *lf_struct = type->data; + return lf_struct->size; } - case LF_CLASS_19: - case LF_STRUCTURE_19: { - Tpi_LF_Structure_19 *lf_struct_19 = type->data; - return get_numeric_val(&lf_struct_19->size); - } - case LF_ARRAY: { - Tpi_LF_Array *lf_array = type->data; - return get_numeric_val(&lf_array->size); - } - case LF_UNION: { + case TpiKind_UNION: { Tpi_LF_Union *lf_union = type->data; - return get_numeric_val(&lf_union->size); + return lf_union->size; } - case LF_INDEX: { + case TpiKind_INDEX: { Tpi_LF_Index *lf_index = type->data; return lf_index->index; } + case TpiKind_ARRAY: { + Tpi_LF_Array *a = type->data; + ut64 y = 0; + ut32 *x; + rz_vector_foreach(&a->dimensions, x) { + y = y == 0 ? *x : (*x * y); + } + return y; + } default: + rz_warn_if_reached(); return 0; } + return -1; } -static void free_snumeric(Tpi_Type_Numeric *numeric) { - switch (numeric->type_index) { - case LF_CHAR: - case LF_SHORT: - case LF_USHORT: - case LF_LONG: - case LF_ULONG: - case LF_QUADWORD: - case LF_UQUADWORD: - RZ_FREE(numeric->data); - break; - default: - if (numeric->type_index >= 0x8000) { - eprintf("%s::not supproted type\n", __FUNCTION__); - break; - } - RZ_FREE(numeric->data); +static void tpi_data_free_with_kind(void *data, RzPDBTpiKind k) { + if (!data) { + return; } -} - -static void free_tpi_type(void *type_info) { - rz_return_if_fail(type_info); - RzPdbTpiType *type = (RzPdbTpiType *)type_info; - switch (type->leaf) { - case LF_ENUMERATE: { - Tpi_LF_Enumerate *lf_en = (Tpi_LF_Enumerate *)type->data; - free_snumeric(&(lf_en->enum_value)); - RZ_FREE(lf_en->name.name); + switch (k) { + case TpiKind_ENUMERATE: { + Tpi_LF_Enumerate *lf_en = data; + free(lf_en->name); break; } - case LF_NESTTYPE: { - Tpi_LF_NestType *lf_nest = (Tpi_LF_NestType *)type->data; - RZ_FREE(lf_nest->name.name); + case TpiKind_NESTTYPE: { + Tpi_LF_NestType *lf_nest = data; + free(lf_nest->name); break; } - case LF_METHOD: { - Tpi_LF_Method *lf_meth = (Tpi_LF_Method *)type->data; - RZ_FREE(lf_meth->name.name); + case TpiKind_METHOD: { + Tpi_LF_Method *lf_meth = data; + free(lf_meth->name); break; } - case LF_MEMBER: { - Tpi_LF_Member *lf_mem = (Tpi_LF_Member *)type->data; - free_snumeric(&lf_mem->offset); - RZ_FREE(lf_mem->name.name); + case TpiKind_MEMBER: { + Tpi_LF_Member *lf_mem = data; + free(lf_mem->name); break; } - case LF_STMEMBER: { - Tpi_LF_StaticMember *lf_stmem = (Tpi_LF_StaticMember *)type->data; - RZ_FREE(lf_stmem->name.name); + case TpiKind_STMEMBER: { + Tpi_LF_StaticMember *lf_stmem = data; + free(lf_stmem->name); break; } - case LF_FIELDLIST: { - Tpi_LF_FieldList *lf_fieldlist = (Tpi_LF_FieldList *)type->data; + case TpiKind_FILEDLIST: { + Tpi_LF_FieldList *lf_fieldlist = data; rz_pvector_free(lf_fieldlist->substructs); break; } - case LF_CLASS: - case LF_STRUCTURE: { - Tpi_LF_Structure *lf_class = (Tpi_LF_Structure *)type->data; - free_snumeric(&lf_class->size); - RZ_FREE(lf_class->name.name); - RZ_FREE(lf_class->mangled_name.name); + case TpiKind_CLASS: { + Tpi_LF_Class *lf_class = data; + free(lf_class->name); + free(lf_class->mangled_name); break; } - case LF_CLASS_19: - case LF_STRUCTURE_19: { - Tpi_LF_Structure_19 *lf_class_19 = (Tpi_LF_Structure_19 *)type->data; - free_snumeric(&lf_class_19->size); - RZ_FREE(lf_class_19->name.name); - RZ_FREE(lf_class_19->mangled_name.name); + case TpiKind_UNION: { + Tpi_LF_Union *lf_union = data; + free(lf_union->name); + free(lf_union->mangled_name); break; } - case LF_UNION: { - Tpi_LF_Union *lf_union = (Tpi_LF_Union *)type->data; - free_snumeric(&lf_union->size); - RZ_FREE(lf_union->name.name); - RZ_FREE(lf_union->mangled_name.name); + case TpiKind_ONEMETHOD: { + Tpi_LF_OneMethod *lf_onemethod = data; + free(lf_onemethod->name); break; } - case LF_ONEMETHOD: { - Tpi_LF_OneMethod *lf_onemethod = (Tpi_LF_OneMethod *)type->data; - RZ_FREE(lf_onemethod->name.name); + case TpiKind_ENUM: { + Tpi_LF_Enum *lf_enum = data; + free(lf_enum->name); + free(lf_enum->mangled_name); break; } - case LF_BCLASS: { - Tpi_LF_BClass *lf_bclass = (Tpi_LF_BClass *)type->data; - free_snumeric(&lf_bclass->offset); + case TpiKind_ARRAY: { + Tpi_LF_Array *lf_array = data; + rz_vector_fini(&lf_array->dimensions); break; } - case LF_VBCLASS: - case LF_IVBCLASS: { - Tpi_LF_VBClass *lf_vbclass = (Tpi_LF_VBClass *)type->data; - free_snumeric(&lf_vbclass->vb_pointer_offset); - free_snumeric(&lf_vbclass->vb_offset_from_vbtable); + case TpiKind_ARGLIST: { + Tpi_LF_Arglist *lf_arglist = data; + free(lf_arglist->arg_type); break; } - case LF_ENUM: { - Tpi_LF_Enum *lf_enum = (Tpi_LF_Enum *)type->data; - RZ_FREE(lf_enum->name.name); - RZ_FREE(lf_enum->mangled_name.name); + case TpiKind_VTSHAPE: { + Tpi_LF_Vtshape *lf_vtshape = data; + rz_vector_fini(&lf_vtshape->descriptors); break; } - case LF_ARRAY: { - Tpi_LF_Array *lf_array = (Tpi_LF_Array *)type->data; - free_snumeric(&lf_array->size); - RZ_FREE(lf_array->name.name); + case TpiKind_METHODLIST: { + Tpi_LF_MethodList *lf_mlist = data; + rz_pvector_fini(&lf_mlist->members); break; } - case LF_ARGLIST: { - Tpi_LF_Arglist *lf_arglist = (Tpi_LF_Arglist *)type->data; - RZ_FREE(lf_arglist->arg_type); - break; - } - case LF_VTSHAPE: { - Tpi_LF_Vtshape *lf_vtshape = (Tpi_LF_Vtshape *)type->data; - RZ_FREE(lf_vtshape->vt_descriptors); - break; - } - case LF_SIMPLE_TYPE: { - Tpi_LF_SimpleType *lf_simple = (Tpi_LF_SimpleType *)type->data; - RZ_FREE(lf_simple->type); - break; - } - case LF_METHODLIST: { - Tpi_LF_MethodList *lf_mlist = (Tpi_LF_MethodList *)type->data; - rz_list_free(lf_mlist->members); - break; - } - case LF_VFTABLE: { - Tpi_LF_Vftable *vft = type->data; + case TpiKind_VFTABLE: { + Tpi_LF_Vftable *vft = data; rz_pvector_fini(&vft->method_names); break; } - case LF_POINTER: - case LF_PROCEDURE: - case LF_MODIFIER: - case LF_MFUNCTION: - case LF_BITFIELD: - case LF_INDEX: - case LF_VFUNCTAB: - case LF_LABEL: - break; - case 0: - if (type->index < 0x1000) { - simple_type_free(type->data); - } - break; + case TpiKind_SIMPLE_TYPE: { + simple_type_fini(data); + } default: - if (type->data) { - rz_warn_if_reached(); - } break; } - free(type->data); + free(data); +} + +static void tpi_type_free(void *type_info) { + if (!type_info) { + return; + } + RzPdbTpiType *type = type_info; + tpi_data_free_with_kind(type->data, type->kind); free(type); } -static void free_tpi_rbtree(RBNode *node, void *user) { - rz_return_if_fail(node); +static void tpi_rbtree_free(RBNode *node, void *user) { + if (!node) { + return; + } RzPdbTpiType *type = container_of(node, RzPdbTpiType, rb); - free_tpi_type(type); + tpi_type_free(type); } -RZ_IPI void free_tpi_stream(RzPdbTpiStream *stream) { +RZ_IPI void tpi_stream_free(RzPdbTpiStream *stream) { if (!stream) { return; } - rz_rbtree_free(stream->types, free_tpi_rbtree, NULL); + rz_rbtree_free(stream->types, tpi_rbtree_free, NULL); rz_list_free(stream->print_type); free(stream); } -static bool parse_type_numeric(RzBuffer *buf, Tpi_Type_Numeric *numeric) { - numeric->data = 0; - numeric->is_integer = true; - if (!rz_buf_read_le16(buf, &numeric->type_index)) { - return false; - } - switch (numeric->type_index) { - case LF_CHAR: - numeric->data = RZ_NEW0(st8); - if (!rz_buf_read8(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_SHORT: - numeric->data = RZ_NEW0(st16); - if (!rz_buf_read_le16(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_USHORT: - numeric->data = RZ_NEW0(ut16); - if (!rz_buf_read_le16(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_LONG: - numeric->data = RZ_NEW0(st32); - if (!rz_buf_read_le32(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_ULONG: - numeric->data = RZ_NEW0(ut32); - if (!rz_buf_read_le32(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_QUADWORD: - numeric->data = RZ_NEW0(st64); - if (!rz_buf_read_le64(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - case LF_UQUADWORD: - numeric->data = RZ_NEW0(ut64); - if (!rz_buf_read_le64(buf, numeric->data)) { - RZ_FREE(numeric->data); - return false; - } - break; - default: - if (numeric->type_index >= 0x8000) { - numeric->is_integer = false; - RZ_LOG_ERROR("%s: Skipping unsupported type (%d)\n", __FUNCTION__, - numeric->type_index); - return false; - } - numeric->data = RZ_NEW0(ut16); - *(ut16 *)(numeric->data) = numeric->type_index; - return true; - } - return true; -} - -static void parse_type_string(RzBuffer *buf, Tpi_Type_String *str) { - str->size = rz_buf_read_string(buf, &str->name); -} - -static Tpi_LF_Enumerate *parse_type_enumerate(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Enumerate *enumerate_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Enumerate *enumerate = RZ_NEW0(Tpi_LF_Enumerate); if (!enumerate) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(enumerate); - return NULL; - } - parse_codeview_fld_attribute(&enumerate->fldattr, fldattr); - if (!parse_type_numeric(buf, &enumerate->enum_value)) { - RZ_FREE(enumerate); - return NULL; - } - if (!enumerate->enum_value.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&enumerate->enum_value); - RZ_FREE(enumerate); - return NULL; - } - parse_type_string(buf, &enumerate->name); + map_err(TpiCVFldattr_parse(b, &enumerate->fldattr) && + TpiVariant_parse(b, &enumerate->value) && + buf_read_string(b, leaf, &enumerate->name)); return enumerate; +err: + rz_warn_if_reached(); + free(enumerate); + return NULL; } -static Tpi_LF_Index *parse_type_index(RzBuffer *b) { +static Tpi_LF_Index *index_parse(RzBuffer *b) { rz_return_val_if_fail(b, NULL); Tpi_LF_Index *index = RZ_NEW0(Tpi_LF_Index); if (!index) { return NULL; } - if (!(rz_buf_read_le16(b, &index->pad0) && - rz_buf_read_le32(b, &index->index))) { - goto err; - } - if (index->pad0 != 0) { - RZ_LOG_ERROR("LF_Index pad0 must be 0\n"); - goto err; - } + map_err(rz_buf_read_le16(b, &index->pad0) && + rz_buf_read_le32(b, &index->index)); + rz_warn_if_fail(index->pad0 == 0); index->leaf = LF_INDEX; return index; err: + rz_warn_if_reached(); free(index); return NULL; } -static Tpi_LF_NestType *parse_type_nesttype(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_NestType *nesttype_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_NestType *nest = RZ_NEW0(Tpi_LF_NestType); if (!nest) { return NULL; } - if (!rz_buf_read_le16(buf, &nest->pad)) { - RZ_FREE(nest); - return NULL; - } - if (!rz_buf_read_le32(buf, &nest->index)) { - RZ_FREE(nest); - return NULL; - } - parse_type_string(buf, &nest->name); + ut16 pad; + map_err(conditional((leaf == LF_NESTTYPEEX || leaf == LF_NESTTYPEEX_ST), + TpiCVFldattr_parse(b, &nest->fldattr), + rz_buf_read_le16(b, &pad)) && + rz_buf_read_le32(b, &nest->index) && + buf_read_string(b, leaf, &nest->name)); return nest; +err: + rz_warn_if_reached(); + free(nest->name); + free(nest); + return NULL; } -static Tpi_LF_VFuncTab *parse_type_vfunctab(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_VFuncTab *vfunctab_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_VFuncTab *vftab = RZ_NEW0(Tpi_LF_VFuncTab); if (!vftab) { return NULL; } - if (!rz_buf_read_le16(buf, &vftab->pad)) { - RZ_FREE(vftab); - return NULL; - } - if (!rz_buf_read_le32(buf, &vftab->index)) { - RZ_FREE(vftab); - return NULL; - } + map_err(rz_buf_read_le16(b, &vftab->pad) && + rz_buf_read_le32(b, &vftab->index)); + rz_warn_if_fail(vftab->pad == 0); return vftab; +err: + rz_warn_if_reached(); + free(vftab); + return NULL; } -static Tpi_LF_Method *parse_type_method(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Method *method_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Method *method = RZ_NEW0(Tpi_LF_Method); if (!method) { return NULL; } - if (!rz_buf_read_le16(buf, &method->count)) { - RZ_FREE(method); - return NULL; - } - if (!rz_buf_read_le32(buf, &method->mlist)) { - RZ_FREE(method); - return NULL; - } - parse_type_string(buf, &method->name); + map_err(rz_buf_read_le16(b, &method->count) && + rz_buf_read_le32(b, &method->mlist) && + buf_read_string(b, leaf, &method->name)); return method; +err: + rz_warn_if_reached(); + free(method->name); + free(method); + return NULL; } -static Tpi_LF_Member *parse_type_member(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Member *member_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Member *member = RZ_NEW0(Tpi_LF_Member); if (!member) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(member); - return NULL; - } - parse_codeview_fld_attribute(&member->fldattr, fldattr); - if (!rz_buf_read_le32(buf, &member->index)) { - RZ_FREE(member); - return NULL; - } - if (!parse_type_numeric(buf, &member->offset)) { - RZ_FREE(member); - return NULL; - } - if (!member->offset.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&member->offset); - RZ_FREE(member); - return NULL; - } - parse_type_string(buf, &member->name); + map_err(TpiCVFldattr_parse(b, &member->fldattr) && + rz_buf_read_le32(b, &member->field_type) && + buf_read_unsigned(b, &member->offset) && + buf_read_string(b, leaf, &member->name)); return member; +err: + rz_warn_if_reached(); + free(member); + return NULL; } -static Tpi_LF_StaticMember *parse_type_staticmember(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_StaticMember *staticmember_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_StaticMember *member = RZ_NEW0(Tpi_LF_StaticMember); if (!member) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(member); - return NULL; - } - parse_codeview_fld_attribute(&member->fldattr, fldattr); - if (!rz_buf_read_le32(buf, &member->index)) { - RZ_FREE(member); - return NULL; - } - parse_type_string(buf, &member->name); + map_err(TpiCVFldattr_parse(b, &member->fldattr) && + rz_buf_read_le32(b, &member->field_type) && + buf_read_string(b, leaf, &member->name)); return member; +err: + rz_warn_if_reached(); + free(member->name); + free(member); + return NULL; } -static Tpi_LF_OneMethod *parse_type_onemethod(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_OneMethod *onemethod_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_OneMethod *onemethod = RZ_NEW0(Tpi_LF_OneMethod); if (!onemethod) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(onemethod); - return NULL; - } - parse_codeview_fld_attribute(&onemethod->fldattr, fldattr); - if (!rz_buf_read_le32(buf, &onemethod->index)) { - RZ_FREE(onemethod); - return NULL; - } - onemethod->offset_in_vtable = 0; - if (onemethod->fldattr.mprop == MTintro || - onemethod->fldattr.mprop == MTpureintro) { - if (!rz_buf_read_le32(buf, &onemethod->offset_in_vtable)) { - RZ_FREE(onemethod); - } - } - parse_type_string(buf, &onemethod->name); + map_err(TpiCVFldattr_parse(b, &onemethod->fldattr) && + rz_buf_read_le32(b, &onemethod->index) && + conditional(TpiCVFldattr_is_intro_virtual(&onemethod->fldattr), + rz_buf_read_le32(b, &onemethod->offset_in_vtable), + true) && + buf_read_string(b, leaf, &onemethod->name)); return onemethod; +err: + rz_warn_if_reached(); + free(onemethod->name); + free(onemethod); + return NULL; } -static Tpi_LF_BClass *parse_type_bclass(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_BClass *bclass_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_BClass *bclass = RZ_NEW0(Tpi_LF_BClass); if (!bclass) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(bclass); - return NULL; - } - parse_codeview_fld_attribute(&bclass->fldattr, fldattr); - if (!rz_buf_read_le32(buf, &bclass->index)) { - RZ_FREE(bclass); - return NULL; - } - if (!parse_type_numeric(buf, &bclass->offset)) { - RZ_FREE(bclass); - return NULL; - } - if (!bclass->offset.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&bclass->offset); - RZ_FREE(bclass); - return NULL; + if (leaf == LF_BCLASS) { + bclass->kind = ClassKind_Class; + } else if (leaf == LF_BINTERFACE) { + bclass->kind = ClassKind_Interface; } + map_err(TpiCVFldattr_parse(b, &bclass->fldattr) && + rz_buf_read_le32(b, &bclass->index) && + buf_read_unsigned(b, &bclass->offset)); return bclass; +err: + rz_warn_if_reached(); + free(bclass); + return NULL; } -static Tpi_LF_VBClass *parse_type_vbclass(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_VBClass *vbclass_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_VBClass *bclass = RZ_NEW0(Tpi_LF_VBClass); if (!bclass) { return NULL; } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(bclass); - return NULL; - } - parse_codeview_fld_attribute(&bclass->fldattr, fldattr); - if (!rz_buf_read_le32(buf, &bclass->direct_vbclass_idx)) { - RZ_FREE(bclass); - return NULL; - } - if (!rz_buf_read_le32(buf, &bclass->vb_pointer_idx)) { - RZ_FREE(bclass); - return NULL; - } - parse_type_numeric(buf, &bclass->vb_pointer_offset); - if (!bclass->vb_pointer_offset.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&bclass->vb_pointer_offset); - RZ_FREE(bclass); - return NULL; - } - parse_type_numeric(buf, &bclass->vb_offset_from_vbtable); - if (!bclass->vb_offset_from_vbtable.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&bclass->vb_offset_from_vbtable); - RZ_FREE(bclass); - return NULL; - } + map_err(TpiCVFldattr_parse(b, &bclass->fldattr) && + rz_buf_read_le32(b, &bclass->direct_vbclass_idx) && + rz_buf_read_le32(b, &bclass->vb_pointer_idx) && + buf_read_unsigned(b, &bclass->vb_pointer_offset) && + buf_read_unsigned(b, &bclass->vb_offset_from_vbtable)); return bclass; +err: + rz_warn_if_reached(); + free(bclass); + return NULL; } -static Tpi_LF_FieldList *parse_type_fieldlist(RzBuffer *b) { +static Tpi_LF_FieldList *fieldlist_parse(RzBuffer *b) { rz_return_val_if_fail(b, NULL); Tpi_LF_FieldList *fieldlist = RZ_NEW0(Tpi_LF_FieldList); if (!fieldlist) { return NULL; } - fieldlist->substructs = rz_pvector_new(free_tpi_type); - if (!fieldlist->substructs) { - goto error; - } + fieldlist->substructs = rz_pvector_new(tpi_type_free); + map_err(fieldlist->substructs); while (!buf_empty(b)) { RzPdbTpiType *t = RzPdbTpiType_from_buf(b, 0, 0); - if (!t) { - continue; - } + map_err(t); buf_read_padding(b); - rz_pvector_push(fieldlist->substructs, t); + map_err(rz_pvector_push(fieldlist->substructs, t)); } return fieldlist; -error: - RZ_LOG_ERROR("failed type_fieldlist\n"); +err: + rz_warn_if_reached(); rz_pvector_free(fieldlist->substructs); - RZ_FREE(fieldlist); + free(fieldlist); return NULL; } -static Tpi_LF_Enum *parse_type_enum(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Enum *enum_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Enum *_enum = RZ_NEW0(Tpi_LF_Enum); if (!_enum) { return NULL; } - if (!rz_buf_read_le16(buf, &_enum->count)) { - RZ_FREE(_enum); - return NULL; - } - ut16 prop; - if (!rz_buf_read_le16(buf, &prop)) { - RZ_FREE(_enum); - return NULL; - } - parse_codeview_property(&_enum->prop, prop); - if (!rz_buf_read_le32(buf, &_enum->utype)) { - RZ_FREE(_enum); - return NULL; - } - if (!rz_buf_read_le32(buf, &_enum->field_list)) { - RZ_FREE(_enum); - return NULL; - } - parse_type_string(buf, &_enum->name); - if (_enum->prop.has_uniquename) { - parse_type_string(buf, &_enum->mangled_name); - } + map_err(rz_buf_read_le16(b, &_enum->count) && + TpiCVProperty_parse(b, &_enum->prop) && + rz_buf_read_le32(b, &_enum->utype) && + rz_buf_read_le32(b, &_enum->field_list) && + buf_read_string(b, leaf, &_enum->name) && + conditional(_enum->prop.has_uniquename, + buf_read_string(b, leaf, &_enum->mangled_name), true)); return _enum; +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(_enum, TpiKind_ENUM); + return NULL; } -static Tpi_LF_Structure *parse_type_struct(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); - Tpi_LF_Structure *structure = RZ_NEW0(Tpi_LF_Structure); +static Tpi_LF_Class *class_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); + Tpi_LF_Class *structure = RZ_NEW0(Tpi_LF_Class); if (!structure) { return NULL; } - if (!rz_buf_read_le16(buf, &structure->count)) { - RZ_FREE(structure); - return NULL; + bool is_32bit_property = false; + switch (leaf) { + case LF_CLASS: + case LF_CLASS_ST: + structure->kind = ClassKind_Class; + break; + case LF_STRUCTURE: + case LF_STRUCTURE_ST: + structure->kind = ClassKind_Struct; + break; + case LF_INTERFACE: + structure->kind = ClassKind_Interface; + break; + case LF_CLASS_19: + structure->kind = ClassKind_Class; + is_32bit_property = true; + break; + case LF_STRUCTURE_19: + structure->kind = ClassKind_Struct; + is_32bit_property = true; + break; + case LF_INTERFACE_19: + structure->kind = ClassKind_Interface; + is_32bit_property = true; + break; + default: + rz_warn_if_reached(); + goto err; } - ut16 prop; - if (!rz_buf_read_le16(buf, &prop)) { - RZ_FREE(structure); - return NULL; + if (!is_32bit_property) { + map_err(rz_buf_read_le16(b, &structure->count) && + TpiCVProperty_parse_opt(b, &structure->prop, is_32bit_property) && + rz_buf_read_le32(b, &structure->field_list) && + rz_buf_read_le32(b, &structure->derived) && + rz_buf_read_le32(b, &structure->vshape) && + buf_read_unsigned(b, &structure->size) && + buf_read_string(b, leaf, &structure->name) && + conditional(structure->prop.has_uniquename, + buf_read_string(b, leaf, &structure->mangled_name), true)); + } else { + map_err(TpiCVProperty_parse_opt(b, &structure->prop, is_32bit_property) && + rz_buf_read_le32(b, &structure->field_list) && + rz_buf_read_le32(b, &structure->derived) && + rz_buf_read_le32(b, &structure->vshape) && + rz_buf_read_le16(b, &structure->count) && + buf_read_unsigned(b, &structure->size) && + buf_read_string(b, leaf, &structure->name) && + conditional(structure->prop.has_uniquename, + buf_read_string(b, leaf, &structure->mangled_name), true)); } - parse_codeview_property(&structure->prop, prop); - if (!rz_buf_read_le32(buf, &structure->field_list)) { - RZ_FREE(structure); - return NULL; - } - if (!rz_buf_read_le32(buf, &structure->derived)) { - RZ_FREE(structure); - return NULL; - } - if (!rz_buf_read_le32(buf, &structure->vshape)) { - RZ_FREE(structure); - return NULL; - } - if (!parse_type_numeric(buf, &structure->size)) { - RZ_FREE(structure); - return NULL; - } - if (!structure->size.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&structure->size); - RZ_FREE(structure); - return NULL; - } - parse_type_string(buf, &structure->name); - parse_type_string(buf, &structure->mangled_name); return structure; +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(structure, TpiKind_CLASS); + return NULL; } -static Tpi_LF_Structure_19 *parse_type_struct_19(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); - Tpi_LF_Structure_19 *structure = RZ_NEW0(Tpi_LF_Structure_19); - if (!structure) { - return NULL; - } - ut16 prop; - if (!rz_buf_read_le16(buf, &prop)) { - RZ_FREE(structure); - return NULL; - } - parse_codeview_property(&structure->prop, prop); - if (!rz_buf_read_le16(buf, &structure->unknown)) { - RZ_FREE(structure); - return NULL; - } - if (!rz_buf_read_le32(buf, &structure->field_list)) { - RZ_FREE(structure); - return NULL; - } - if (!rz_buf_read_le32(buf, &structure->derived)) { - RZ_FREE(structure); - return NULL; - } - if (!rz_buf_read_le32(buf, &structure->vshape)) { - RZ_FREE(structure); - return NULL; - } - if (!parse_type_numeric(buf, &structure->unknown1)) { - RZ_FREE(structure); - return NULL; - } - if (!parse_type_numeric(buf, &structure->size)) { - RZ_FREE(structure); - return NULL; - } - if (!structure->size.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&structure->size); - RZ_FREE(structure); - return NULL; - } - parse_type_string(buf, &structure->name); - parse_type_string(buf, &structure->mangled_name); - return structure; -} - -static Tpi_LF_Pointer *parse_type_pointer(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Pointer *pointer_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Pointer *pointer = RZ_NEW0(Tpi_LF_Pointer); if (!pointer) { return NULL; } - if (!rz_buf_read_le32(buf, &pointer->utype)) { - RZ_FREE(pointer); - return NULL; - } - ut32 ptrattr; - if (!rz_buf_read_le32(buf, &ptrattr)) { - RZ_FREE(pointer); - return NULL; - } - parse_codeview_pointer_attribute(&pointer->ptr_attr, ptrattr); - if (pointer->ptr_attr.ptrmode == PTR_MODE_PMFUNC || - pointer->ptr_attr.ptrmode == PTR_MODE_PMEM) { - if (!rz_buf_read_le32(buf, &pointer->pmember.pmclass)) { - RZ_FREE(pointer); - return NULL; - } - if (!rz_buf_read_le16(buf, &pointer->pmember.pmtype)) { - RZ_FREE(pointer); - return NULL; - } - } else if (pointer->ptr_attr.ptrtype == PTR_BASE_TYPE) { - if (!rz_buf_read_le32(buf, &pointer->pbase.index)) { - RZ_FREE(pointer); - return NULL; - } - } + map_err(rz_buf_read_le32(b, &pointer->utype) && + TpiCVPointerAttr_parse(b, &pointer->ptr_attr) && + conditional(TpiCVPointerAttr_pointer_to_member(&pointer->ptr_attr), + rz_buf_read_le32(b, &pointer->containing_class), true)); return pointer; +err: + rz_warn_if_reached(); + free(pointer); + return NULL; } -static Tpi_LF_Array *parse_type_array(RzBuffer *buf, TpiLeafType leaf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Array *array_parse(RzBuffer *b, TpiLeafType leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Array *array = RZ_NEW0(Tpi_LF_Array); if (!array) { return NULL; } - if (!rz_buf_read_le32(buf, &array->element_type)) { - goto err; - } - if (!rz_buf_read_le32(buf, &array->index_type)) { - goto err; - } - if (leaf == LF_STRIDED_ARRAY) { - if (!rz_buf_read_le32(buf, &array->stride)) { - goto err; + map_err(rz_buf_read_le32(b, &array->element_type) && + rz_buf_read_le32(b, &array->index_type) && + conditional(leaf == LF_STRIDED_ARRAY, rz_buf_read_le32(b, &array->stride), true)); + + rz_vector_init(&array->dimensions, sizeof(ut32), NULL, NULL); + while (true) { + ut64 dim = { 0 }; + map_err(buf_read_unsigned(b, &dim)); + rz_warn_if_fail(dim <= UT32_MAX); + + ut32 v = dim; + rz_vector_push(&array->dimensions, &v); + rz_warn_if_fail(!buf_empty(b)); + if (rz_buf_peek(b) == 0x00) { + rz_buf_seek(b, 1, RZ_BUF_CUR); + break; } } - if (!parse_type_numeric(buf, &array->size)) { - goto err; - } - if (!array->size.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&array->size); - goto err; - } - parse_type_string(buf, &array->name); + buf_read_padding(b); + rz_warn_if_fail(buf_empty(b)); + return array; err: - RZ_FREE(array); + rz_warn_if_reached(); + tpi_data_free_with_kind(array, TpiKind_ARRAY); return NULL; } -static Tpi_LF_Modifier *parse_type_modifier(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Modifier *modifier_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Modifier *modifier = RZ_NEW0(Tpi_LF_Modifier); if (!modifier) { return NULL; } - if (!rz_buf_read_le32(buf, &modifier->modified_type)) { - RZ_FREE(modifier); - return NULL; - } - ut16 umodifier; - if (!rz_buf_read_le16(buf, &umodifier)) { - RZ_FREE(modifier); - return NULL; - } - parse_codeview_modifier(&modifier->umodifier, umodifier); + map_err(rz_buf_read_le32(b, &modifier->modified_type) && + TpiCVModifier_parse(b, &modifier->umodifier)); return modifier; +err: + rz_warn_if_reached(); + free(modifier); + return NULL; } -static Tpi_LF_Arglist *parse_type_arglist(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Arglist *arglist_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Arglist *arglist = RZ_NEW0(Tpi_LF_Arglist); if (!arglist) { return NULL; } - if (!rz_buf_read_le32(buf, &arglist->count)) { - RZ_FREE(arglist); - return NULL; + map_err(rz_buf_read_le32(b, &arglist->count)); + if (arglist->count == 0) { + return arglist; } arglist->arg_type = (ut32 *)malloc(sizeof(ut32) * arglist->count); - if (!arglist->arg_type) { - RZ_LOG_ERROR("Error allocating memory.\n"); - RZ_FREE(arglist); - return NULL; - } - for (size_t i = 0; i < arglist->count; i++) { - if (!rz_buf_read_le32(buf, &arglist->arg_type[i])) { - RZ_FREE(arglist->arg_type); - RZ_FREE(arglist); - return NULL; - } + map_err(arglist->arg_type); + for (ut32 i = 0; i < arglist->count; i++) { + map_err(rz_buf_read_le32(b, &arglist->arg_type[i])); } return arglist; +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(arglist, TpiKind_ARGLIST); + return NULL; } -static Tpi_LF_MFcuntion *parse_type_mfunction(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_MFcuntion *mfunction_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_MFcuntion *mfunc = RZ_NEW0(Tpi_LF_MFcuntion); if (!mfunc) { return NULL; } - if (!rz_buf_read_le32(buf, &mfunc->return_type)) { - RZ_FREE(mfunc); - return NULL; - } - if (!rz_buf_read_le32(buf, &mfunc->class_type)) { - RZ_FREE(mfunc); - return NULL; - } - if (!rz_buf_read_le32(buf, &mfunc->this_type)) { - RZ_FREE(mfunc); - return NULL; - } - if (!rz_buf_read8(buf, (ut8 *)&mfunc->call_conv)) { - RZ_FREE(mfunc); - return NULL; - } - ut8 funcattr; - if (!rz_buf_read8(buf, &funcattr)) { - RZ_FREE(mfunc); - return NULL; - } - parse_codeview_func_attribute(&mfunc->func_attr, funcattr); - if (!rz_buf_read_le16(buf, &mfunc->parm_count)) { - RZ_FREE(mfunc); - return NULL; - } - if (!rz_buf_read_le32(buf, &mfunc->arglist)) { - RZ_FREE(mfunc); - return NULL; - } - if (!rz_buf_read_le32(buf, (ut32 *)&mfunc->this_adjust)) { - RZ_FREE(mfunc); - return NULL; - } + map_err(rz_buf_read_le32(b, &mfunc->return_type) && + rz_buf_read_le32(b, &mfunc->class_type) && + rz_buf_read_le32(b, &mfunc->this_type) && + TpiCVFuncattr_parse(b, &mfunc->func_attr) && + rz_buf_read_le16(b, &mfunc->parm_count) && + rz_buf_read_le32(b, &mfunc->arglist) && + rz_buf_read_le32(b, (ut32 *)&mfunc->this_adjust)); return mfunc; +err: + rz_warn_if_reached(); + free(mfunc); + return NULL; } -static Tpi_LF_MethodList *parse_type_methodlist(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_MethodList *methodlist_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_MethodList *mlist = RZ_NEW0(Tpi_LF_MethodList); if (!mlist) { return NULL; } - mlist->members = rz_list_newf(free); - if (!mlist->members) { - RZ_LOG_ERROR("Error allocating memory.\n"); - goto error; - } - while (!buf_empty(buf)) { - Tpi_Type_MethodListMember *member = RZ_NEW0(Tpi_Type_MethodListMember); - if (!member) { - continue; - } - ut16 fldattr; - if (!rz_buf_read_le16(buf, &fldattr)) { - RZ_FREE(member); - rz_list_free(mlist->members); - RZ_FREE(mlist); - return NULL; - } - parse_codeview_fld_attribute(&member->fldattr, fldattr); - if (!rz_buf_read_le16(buf, &member->pad)) { - RZ_FREE(member); - rz_list_free(mlist->members); - RZ_FREE(mlist); - return NULL; - } - if (!rz_buf_read_le32(buf, &member->type)) { - RZ_FREE(member); - rz_list_free(mlist->members); - RZ_FREE(mlist); - return NULL; - } - member->optional_offset = 0; - if (member->fldattr.mprop == MTintro || - member->fldattr.mprop == MTpureintro) { - if (!rz_buf_read_le32(buf, &member->optional_offset)) { - RZ_FREE(member); - rz_list_free(mlist->members); - RZ_FREE(mlist); - return NULL; - } - } - rz_list_append(mlist->members, member); + rz_pvector_init(&mlist->members, free); + + Tpi_Type_MethodListMember *member = NULL; + while (!buf_empty(b)) { + member = RZ_NEW0(Tpi_Type_MethodListMember); + map_err(member && + TpiCVFldattr_parse(b, &member->fldattr) && + rz_buf_read_le16(b, &member->pad) && + rz_buf_read_le32(b, &member->type) && + conditional(member->fldattr.mprop == MTintro || + member->fldattr.mprop == MTpureintro, + rz_buf_read_le32(b, &member->optional_offset), true) && + rz_pvector_push(&mlist->members, member)); } return mlist; - -error: - RZ_FREE(mlist); +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(member, TpiKind_METHODLIST); return NULL; } -static Tpi_LF_Procedure *parse_type_procedure(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Procedure *procedure_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Procedure *proc = RZ_NEW0(Tpi_LF_Procedure); if (!proc) { return NULL; } - if (!rz_buf_read_le32(buf, &proc->return_type)) { - RZ_FREE(proc); - return NULL; - } - if (!rz_buf_read8(buf, (ut8 *)&proc->call_conv)) { - RZ_FREE(proc); - return NULL; - } - ut8 funcattr; - if (!rz_buf_read8(buf, &funcattr)) { - RZ_FREE(proc); - return NULL; - } - parse_codeview_func_attribute(&proc->func_attr, funcattr); - if (!rz_buf_read_le16(buf, &proc->parm_count)) { - RZ_FREE(proc); - return NULL; - } - if (!rz_buf_read_le32(buf, &proc->arg_list)) { - RZ_FREE(proc); - return NULL; - } + map_err(rz_buf_read_le32(b, &proc->return_type) && + TpiCVFuncattr_parse(b, &proc->func_attr) && + rz_buf_read_le16(b, &proc->parm_count) && + rz_buf_read_le32(b, &proc->arg_list)); return proc; +err: + rz_warn_if_reached(); + free(proc); + return NULL; } -static Tpi_LF_Union *parse_type_union(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Union *union_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Union *unin = RZ_NEW0(Tpi_LF_Union); if (!unin) { return NULL; } - if (!rz_buf_read_le16(buf, &unin->count)) { - RZ_FREE(unin); - return NULL; + if (leaf != LF_UNION_19) { + map_err(rz_buf_read_le16(b, &unin->count) && + TpiCVProperty_parse_opt(b, &unin->prop, leaf == LF_UNION_19) && + rz_buf_read_le32(b, &unin->field_list) && + buf_read_unsigned(b, &unin->size) && + buf_read_string(b, leaf, &unin->name) && + conditional(unin->prop.has_uniquename, + buf_read_string(b, leaf, &unin->mangled_name), true)); + } else { + map_err(TpiCVProperty_parse_opt(b, &unin->prop, leaf == LF_UNION_19) && + rz_buf_read_le32(b, &unin->field_list) && + rz_buf_read_le16(b, &unin->count) && + buf_read_unsigned(b, &unin->size) && + buf_read_string(b, leaf, &unin->name) && + conditional(unin->prop.has_uniquename, + buf_read_string(b, leaf, &unin->mangled_name), true)); } - ut16 prop; - if (!rz_buf_read_le16(buf, &prop)) { - RZ_FREE(unin); - return NULL; - } - parse_codeview_property(&unin->prop, prop); - if (!rz_buf_read_le32(buf, &unin->field_list)) { - RZ_FREE(unin); - return NULL; - } - if (!parse_type_numeric(buf, &unin->size)) { - RZ_FREE(unin); - } - if (!unin->size.is_integer) { - RZ_LOG_ERROR("Integer expected!\n"); - free_snumeric(&unin->size); - RZ_FREE(unin); - return NULL; - } - parse_type_string(buf, &unin->name); - parse_type_string(buf, &unin->mangled_name); return unin; +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(unin, TpiKind_UNION); + return NULL; } -static Tpi_LF_Bitfield *parse_type_bitfield(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Bitfield *bitfield_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Bitfield *bf = RZ_NEW0(Tpi_LF_Bitfield); if (!bf) { return NULL; } - if (!rz_buf_read_le32(buf, &bf->base_type)) { - RZ_FREE(bf); - return NULL; - } - if (!rz_buf_read8(buf, &bf->length)) { - RZ_FREE(bf); - return NULL; - } - if (!rz_buf_read8(buf, &bf->position)) { - RZ_FREE(bf); - return NULL; - } + map_err(rz_buf_read_le32(b, &bf->base_type) && + rz_buf_read8(b, &bf->length) && + rz_buf_read8(b, &bf->position)); return bf; +err: + rz_warn_if_reached(); + free(bf); + return NULL; } -static Tpi_LF_Vtshape *parse_type_vtshape(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Vtshape *vtshape_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Vtshape *vt = RZ_NEW0(Tpi_LF_Vtshape); if (!vt) { return NULL; } - if (!rz_buf_read_le16(buf, &vt->count)) { - RZ_FREE(vt); - return NULL; + map_err(rz_buf_read_le16(b, &vt->count)); + rz_vector_init(&vt->descriptors, sizeof(ut8), NULL, NULL); + for (int i = 0; i < (vt->count + 1) / 2; ++i) { + ut8 desc = 0; + map_err(rz_buf_read8(b, &desc)); + ut8 x = desc & 0xF; + map_err(rz_vector_push(&vt->descriptors, &x)); + if (rz_vector_len(&vt->descriptors) < vt->count) { + x = desc >> 4; + map_err(rz_vector_push(&vt->descriptors, &x)); + } } - ut16 size = (4 * vt->count + (vt->count % 2) * 4) / 8; - vt->vt_descriptors = (char *)malloc(size); - if (!vt->vt_descriptors) { - RZ_LOG_ERROR("Error allocating memory.\n"); - RZ_FREE(vt); - return NULL; - } - rz_buf_read(buf, (ut8 *)vt->vt_descriptors, size); return vt; +err: + rz_warn_if_reached(); + tpi_data_free_with_kind(vt, TpiKind_VTSHAPE); + return NULL; } -static Tpi_LF_Vftable *vftable_parse(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Vftable *vftable_parse(RzBuffer *b, ut16 leaf) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Vftable *vft = RZ_NEW0(Tpi_LF_Vftable); if (!vft) { return NULL; } + ut64 len; + map_err(rz_buf_read_le32(b, (ut32 *)&vft->complete_class) && + rz_buf_read_le32(b, (ut32 *)&vft->override_vftable) && + rz_buf_read_le32(b, (ut32 *)&vft->vfptr_offset) && + buf_read_unsigned(b, &len)); - if (!rz_buf_read_le32(buf, (ut32 *)&vft->complete_class)) { - goto err; - } - if (!rz_buf_read_le32(buf, (ut32 *)&vft->override_vftable)) { - goto err; - } - if (!rz_buf_read_le32(buf, (ut32 *)&vft->vfptr_offset)) { - goto err; - } - ut32 names_len = 0; - if (!rz_buf_read_le32(buf, &names_len)) { - goto err; - } rz_pvector_init(&vft->method_names, free); - - while (rz_buf_peek(buf) < LF_PAD0) { + while (!buf_empty(b) && rz_buf_peek(b) < LF_PAD0) { char *name = NULL; - ut64 nlen = rz_buf_read_string(buf, &name); + const ut64 nlen = buf_read_string(b, leaf, &name); if (nlen <= 0) { continue; } - rz_pvector_push(&vft->method_names, name); + map_err(rz_pvector_push(&vft->method_names, name)); } return vft; err: - rz_pvector_fini(&vft->method_names); - RZ_FREE(vft); + rz_warn_if_reached(); + tpi_data_free_with_kind(vft, TpiKind_VFTABLE); return NULL; } -static Tpi_LF_Label *labal_parse(RzBuffer *buf) { - rz_return_val_if_fail(buf, NULL); +static Tpi_LF_Label *labal_parse(RzBuffer *b) { + rz_return_val_if_fail(b, NULL); Tpi_LF_Label *record = RZ_NEW0(Tpi_LF_Label); if (!record) { return NULL; } - if (!rz_buf_read_le32(buf, (ut32 *)&record->mode)) { - goto err; - } + map_err(rz_buf_read_le32(b, (ut32 *)&record->mode)); return record; err: - RZ_FREE(record); + rz_warn_if_reached(); + free(record); return NULL; } @@ -1603,90 +1375,130 @@ static RzPdbTpiType *RzPdbTpiType_from_buf(RzBuffer *b, ut32 index, ut16 length) return NULL; } + RzPDBTpiKind k = 0; void *data = NULL; switch (leaf) { case LF_FIELDLIST: - data = parse_type_fieldlist(b); + k = TpiKind_FILEDLIST; + data = fieldlist_parse(b); break; case LF_ENUM: - data = parse_type_enum(b); + case LF_ENUM_ST: + k = TpiKind_ENUM; + data = enum_parse(b, leaf); + break; + case LF_ENUMERATE: + case LF_ENUMERATE_ST: + k = TpiKind_ENUMERATE; + data = enumerate_parse(b, leaf); break; case LF_CLASS: + case LF_CLASS_ST: case LF_STRUCTURE: - data = parse_type_struct(b); - break; + case LF_STRUCTURE_ST: + case LF_INTERFACE: case LF_CLASS_19: case LF_STRUCTURE_19: - data = parse_type_struct_19(b); + case LF_INTERFACE_19: + k = TpiKind_CLASS; + data = class_parse(b, leaf); break; case LF_POINTER: - data = parse_type_pointer(b); + k = TpiKind_POINTER; + data = pointer_parse(b); break; case LF_ARRAY: case LF_ARRAY_ST: case LF_STRIDED_ARRAY: - data = parse_type_array(b, leaf); + k = TpiKind_ARRAY; + data = array_parse(b, leaf); break; case LF_MODIFIER: - data = parse_type_modifier(b); + k = TpiKind_MODIFIER; + data = modifier_parse(b); break; case LF_ARGLIST: - data = parse_type_arglist(b); + k = TpiKind_ARGLIST; + data = arglist_parse(b); break; case LF_MFUNCTION: - data = parse_type_mfunction(b); + k = TpiKind_MFUNCTION; + data = mfunction_parse(b); break; case LF_METHODLIST: - data = parse_type_methodlist(b); + k = TpiKind_METHODLIST; + data = methodlist_parse(b); break; case LF_PROCEDURE: - data = parse_type_procedure(b); + k = TpiKind_PROCEDURE; + data = procedure_parse(b); break; case LF_UNION: - data = parse_type_union(b); + case LF_UNION_ST: + case LF_UNION_19: + k = TpiKind_UNION; + data = union_parse(b, leaf); break; case LF_BITFIELD: - data = parse_type_bitfield(b); + k = TpiKind_BITFIELD; + data = bitfield_parse(b); break; case LF_VTSHAPE: - data = parse_type_vtshape(b); + k = TpiKind_VTSHAPE; + data = vtshape_parse(b); break; case LF_VFTABLE: - data = vftable_parse(b); + k = TpiKind_VFTABLE; + data = vftable_parse(b, leaf); break; case LF_LABEL: + k = TpiKind_LABEL; data = labal_parse(b); break; - case LF_ENUMERATE: - data = parse_type_enumerate(b); - break; case LF_NESTTYPE: - data = parse_type_nesttype(b); - break; - case LF_VFUNCTAB: - data = parse_type_vfunctab(b); - break; - case LF_METHOD: - data = parse_type_method(b); + case LF_NESTTYPE_ST: + case LF_NESTTYPEEX: + case LF_NESTTYPEEX_ST: + k = TpiKind_NESTTYPE; + data = nesttype_parse(b, leaf); break; case LF_MEMBER: - data = parse_type_member(b); + case LF_MEMBER_ST: + k = TpiKind_MEMBER; + data = member_parse(b, leaf); + break; + case LF_METHOD: + case LF_METHOD_ST: + k = TpiKind_METHOD; + data = method_parse(b, leaf); break; case LF_ONEMETHOD: - data = parse_type_onemethod(b); + case LF_ONEMETHOD_ST: + k = TpiKind_ONEMETHOD; + data = onemethod_parse(b, leaf); break; case LF_BCLASS: - data = parse_type_bclass(b); + case LF_BINTERFACE: + k = TpiKind_BCLASS; + data = bclass_parse(b, leaf); + break; + case LF_VFUNCTAB: + k = TpiKind_VFUNCTAB; + data = vfunctab_parse(b); + break; + case LF_STMEMBER: + case LF_STMEMBER_ST: + k = TpiKind_STMEMBER; + data = staticmember_parse(b, leaf); break; case LF_VBCLASS: case LF_IVBCLASS: - data = parse_type_vbclass(b); - break; - case LF_STMEMBER: - data = parse_type_staticmember(b); + k = TpiKind_VBCLASS; + data = vbclass_parse(b); break; case LF_INDEX: - data = parse_type_index(b); + k = TpiKind_INDEX; + data = index_parse(b); break; default: RZ_LOG_DEBUG("%s: 0x%" PFMT32x ": unsupported leaf type: 0x%" PFMT32x "\n", __FUNCTION__, index, leaf); @@ -1694,44 +1506,47 @@ static RzPdbTpiType *RzPdbTpiType_from_buf(RzBuffer *b, ut32 index, ut16 length) } if (!data && !length && !index) { + rz_warn_if_reached(); return NULL; } RzPdbTpiType *type = RZ_NEW0(RzPdbTpiType); if (!type) { + rz_warn_if_reached(); free(data); return NULL; } type->index = index; type->length = length; type->leaf = leaf; + type->kind = k; type->data = data; return type; } -static bool parse_tpi_stream_header(RzPdbTpiStream *s, RzBuffer *buf) { - return rz_buf_read_le32(buf, (ut32 *)&s->header.Version) && - rz_buf_read_le32(buf, &s->header.HeaderSize) && - rz_buf_read_le32(buf, &s->header.TypeIndexBegin) && - rz_buf_read_le32(buf, &s->header.TypeIndexEnd) && - rz_buf_read_le32(buf, &s->header.TypeRecordBytes) && +static bool tpi_stream_header_parse(RzBuffer *b, RzPdbTpiStreamHeader *h) { + return rz_buf_read_le32(b, (ut32 *)&h->Version) && + rz_buf_read_le32(b, &h->HeaderSize) && + rz_buf_read_le32(b, &h->TypeIndexBegin) && + rz_buf_read_le32(b, &h->TypeIndexEnd) && + rz_buf_read_le32(b, &h->TypeRecordBytes) && - rz_buf_read_le16(buf, &s->header.HashStreamIndex) && - rz_buf_read_le16(buf, &s->header.HashAuxStreamIndex) && - rz_buf_read_le32(buf, &s->header.HashKeySize) && - rz_buf_read_le32(buf, &s->header.NumHashBuckets) && + rz_buf_read_le16(b, &h->HashStreamIndex) && + rz_buf_read_le16(b, &h->HashAuxStreamIndex) && + rz_buf_read_le32(b, &h->HashKeySize) && + rz_buf_read_le32(b, &h->NumHashBuckets) && - rz_buf_read_le32(buf, (ut32 *)&s->header.HashValueBufferOffset) && - rz_buf_read_le32(buf, &s->header.HashValueBufferLength) && + rz_buf_read_le32(b, (ut32 *)&h->HashValueBufferOffset) && + rz_buf_read_le32(b, &h->HashValueBufferLength) && - rz_buf_read_le32(buf, (ut32 *)&s->header.IndexOffsetBufferOffset) && - rz_buf_read_le32(buf, &s->header.IndexOffsetBufferLength) && + rz_buf_read_le32(b, (ut32 *)&h->IndexOffsetBufferOffset) && + rz_buf_read_le32(b, &h->IndexOffsetBufferLength) && - rz_buf_read_le32(buf, (ut32 *)&s->header.HashAdjBufferOffset) && - rz_buf_read_le32(buf, &s->header.HashAdjBufferLength); + rz_buf_read_le32(b, (ut32 *)&h->HashAdjBufferOffset) && + rz_buf_read_le32(b, &h->HashAdjBufferLength); } -RZ_IPI bool parse_tpi_stream(RzPdb *pdb, RzPdbMsfStream *stream) { +RZ_IPI bool tpi_stream_parse(RzPdb *pdb, RzPdbMsfStream *stream) { if (!pdb || !stream) { return false; } @@ -1747,24 +1562,28 @@ RZ_IPI bool parse_tpi_stream(RzPdb *pdb, RzPdbMsfStream *stream) { } s->types = NULL; RzBuffer *steam_buffer = stream->stream_data; - if (!parse_tpi_stream_header(s, steam_buffer)) { + if (!tpi_stream_header_parse(steam_buffer, &s->header)) { return false; } if (s->header.HeaderSize != sizeof(RzPdbTpiStreamHeader)) { RZ_LOG_ERROR("Corrupted TPI stream.\n"); return false; } + RzPdbTpiType *type = NULL; + RzBuffer *b = NULL; for (ut32 index = s->header.TypeIndexBegin; index < s->header.TypeIndexEnd; index++) { ut16 length = 0; if (!rz_buf_read_le16(steam_buffer, &length)) { - return false; + goto err; } - RzBuffer *b = buf_take(steam_buffer, length); + b = NULL; + b = buf_take(steam_buffer, length); if (!b) { - return false; + goto err; } - RzPdbTpiType *type = RzPdbTpiType_from_buf(b, index, length); + type = NULL; + type = RzPdbTpiType_from_buf(b, index, length); if (!type) { goto err; } @@ -1772,8 +1591,9 @@ RZ_IPI bool parse_tpi_stream(RzPdb *pdb, RzPdbMsfStream *stream) { rz_rbtree_insert(&s->types, &type->index, &type->rb, tpi_type_node_cmp, NULL); continue; err: + rz_warn_if_reached(); rz_buf_free(b); - free(type); + tpi_type_free(type); return false; } return true; @@ -1793,11 +1613,10 @@ RZ_API RZ_BORROW RzPdbTpiType *rz_bin_pdb_get_type_by_index( RBNode *node = rz_rbtree_find(stream->types, &index, tpi_type_node_cmp, NULL); if (!node) { - if (is_simple_type(stream, index)) { - return parse_simple_type(stream, index); + if (simple_type_check(stream, index)) { + return simple_type_parse(stream, index); } return NULL; } - RzPdbTpiType *type = container_of(node, RzPdbTpiType, rb); - return type; + return container_of(node, RzPdbTpiType, rb); } diff --git a/librz/bin/pdb/tpi.h b/librz/bin/pdb/tpi.h index 4027fc5f07..12c7ae6a9c 100644 --- a/librz/bin/pdb/tpi.h +++ b/librz/bin/pdb/tpi.h @@ -6,6 +6,10 @@ #include +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 /**/ 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 /**/ 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 /**/ *members; + RzPVector /**/ 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 { diff --git a/librz/core/cpdb.c b/librz/core/cpdb.c index 733fd3db32..424df6a300 100644 --- a/librz/core/cpdb.c +++ b/librz/core/cpdb.c @@ -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); diff --git a/librz/core/windows_heap.c b/librz/core/windows_heap.c index 178456c8df..4fb59da895 100644 --- a/librz/core/windows_heap.c +++ b/librz/core/windows_heap.c @@ -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; -} \ No newline at end of file +} diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index c0e71f46b0..0af3e196bc 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -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); diff --git a/librz/include/rz_pdb.h b/librz/include/rz_pdb.h index a4983692e6..2b9c5aedc5 100644 --- a/librz/include/rz_pdb.h +++ b/librz/include/rz_pdb.h @@ -58,9 +58,9 @@ typedef struct { typedef struct dbi_stream_t { RzPdbRzPdbDbiStreamHdr hdr; - RzList /**/ *ex_hdrs; + ut64 hdr_size; + RzPVector /**/ *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 /**/ *symbols; +} PDBModuleInfo; + typedef struct rz_pdb_t { RzBuffer *buf; // mmap of file RzPdbMsfSuperBlock *super_block; - RzList /**/ *streams; + RzPdbMsfStreamDirectory *msd; + RzPVector /**/ *streams; RzPdbStream *s_pdb; RzPdbDbiStream *s_dbi; RzPdbTpiStream *s_tpi; RzPdbGDataStream *s_gdata; RzPdbOmapStream *s_omap; RzPdbPeStream *s_pe; + RzPVector /**/ *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 } diff --git a/librz/util/buf.c b/librz/util/buf.c index 5252f98c96..a0655a55bf 100644 --- a/librz/util/buf.c +++ b/librz/util/buf.c @@ -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; } diff --git a/test/db/cmd/cmd_idp b/test/db/cmd/cmd_idp index 374ffa595a..603e63ee3a 100644 --- a/test/db/cmd/cmd_idp +++ b/test/db/cmd/cmd_idp @@ -31,6 +31,22 @@ FILE== CMDS=idpij bins/pdb/minimal.pdb~{} EXPECT=<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");