diff --git a/libr/anal/Makefile b/libr/anal/Makefile index 403f8016a2..503d09737e 100644 --- a/libr/anal/Makefile +++ b/libr/anal/Makefile @@ -29,7 +29,7 @@ include ${STATIC_ANAL_PLUGINS} STATIC_OBJS=$(addprefix $(LTOP)/anal/p/,$(STATIC_OBJ)) OBJLIBS=meta.o reflines.o op.o fcn.o bb.o var.o block.o -OBJLIBS+=cond.o value.o cc.o class.o diff.o type.o type_dwarf.o +OBJLIBS+=cond.o value.o cc.o class.o diff.o type.o type_pdb.o type_dwarf.o OBJLIBS+=hint.o anal.o data.o xrefs.o esil.o sign.o OBJLIBS+=switch.o cycles.o esil_dfg.o OBJLIBS+=esil_sources.o esil_interrupt.o esil_cfg.o diff --git a/libr/anal/base_types.h b/libr/anal/base_types.h new file mode 100644 index 0000000000..6767077261 --- /dev/null +++ b/libr/anal/base_types.h @@ -0,0 +1,17 @@ +#ifndef R_BASE_TYPES_H +#define R_BASE_TYPES_H + +#include "r_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +R_IPI void enum_type_case_free(void *e, void *user); +R_IPI void struct_type_member_free(void *e, void *user); +R_IPI void union_type_member_free(void *e, void *user); + +#ifdef __cplusplus +} +#endif +#endif R_BASE_TYPES_H \ No newline at end of file diff --git a/libr/anal/meson.build b/libr/anal/meson.build index cb28914c64..bea183aef4 100644 --- a/libr/anal/meson.build +++ b/libr/anal/meson.build @@ -33,6 +33,7 @@ r_anal_sources = [ 'sign.c', 'switch.c', 'type.c', + 'type_pdb.c', 'type_dwarf.c', 'value.c', 'var.c', diff --git a/libr/anal/type.c b/libr/anal/type.c index 0dba8c13fb..368d250276 100644 --- a/libr/anal/type.c +++ b/libr/anal/type.c @@ -3,6 +3,7 @@ #include #include #include +#include "base_types.h" static char *is_type(char *type) { char *name = NULL; @@ -146,20 +147,20 @@ R_API RList *r_anal_types_from_fcn(RAnal *anal, RAnalFunction *fcn) { return uniq; } -static void enum_type_fini(void *e, void *user) { +R_IPI void enum_type_case_free(void *e, void *user) { (void)user; RAnalEnumCase *cas = e; free ((char *)cas->name); } -static void struct_type_fini(void *e, void *user) { +R_IPI void struct_type_member_free(void *e, void *user) { (void)user; RAnalStructMember *member = e; free ((char *)member->name); free ((char *)member->type); } -static void union_type_fini(void *e, void *user) { +R_IPI void union_type_member_free(void *e, void *user) { (void)user; RAnalUnionMember *member = e; free ((char *)member->name); @@ -183,7 +184,7 @@ static RAnalBaseType *get_enum_type(RAnal *anal, const char *sname) { } RVector cases; - r_vector_init (&cases, sizeof (RAnalEnumCase), enum_type_fini, NULL); + r_vector_init (&cases, sizeof (RAnalEnumCase), enum_type_case_free, NULL); if (!r_vector_reserve (&cases, (size_t)sdb_alen (members))) { goto error; @@ -241,7 +242,7 @@ static RAnalBaseType *get_struct_type(RAnal *anal, const char *sname) { } RVector members; - r_vector_init (&members, sizeof (RAnalStructMember), struct_type_fini, NULL); + r_vector_init (&members, sizeof (RAnalStructMember), struct_type_member_free, NULL); if (!r_vector_reserve (&members, (size_t)sdb_alen (sdb_members))) { goto error; @@ -311,7 +312,7 @@ static RAnalBaseType *get_union_type(RAnal *anal, const char *sname) { } RVector members; - r_vector_init (&members, sizeof (RAnalUnionMember), union_type_fini, NULL); + r_vector_init (&members, sizeof (RAnalUnionMember), union_type_member_free, NULL); if (!r_vector_reserve (&members, (size_t)sdb_alen (sdb_members))) { goto error; diff --git a/libr/anal/type_dwarf.c b/libr/anal/type_dwarf.c index a728de3109..12cd4b52bd 100644 --- a/libr/anal/type_dwarf.c +++ b/libr/anal/type_dwarf.c @@ -1,7 +1,8 @@ -#include +#include "base_types.h" #include -#include +#include #include +#include static int die_tag_cmp(const void *a, const void *b) { const RBinDwarfDie *first = a; @@ -24,19 +25,6 @@ static inline bool is_type_tag(ut64 tag_code) { tag_code == DW_TAG_base_type || tag_code == DW_TAG_typedef); } - -static void struct_type_fini(void *e, void *user) { - (void)user; - RAnalStructMember *member = e; - free ((char *)member->name); - free ((char *)member->type); -} - -static void enum_type_fini(void *e, void *user) { - (void)user; - RAnalEnumCase *cas = e; - free ((char *)cas->name); -} /** * @brief Finds index of a particular attribute of a DIE @@ -532,7 +520,7 @@ static void parse_structure_type(const RAnal *anal, const RBinDwarfDie *all_dies base_type->size = get_die_size (die); r_vector_init (&base_type->struct_data.members, - sizeof (RAnalStructMember), struct_type_fini, NULL); + sizeof (RAnalStructMember), struct_type_member_free, NULL); RAnalStructMember member = { 0 }; // Parse out all members, can this in someway be extracted to a function? if (die->has_children) { @@ -603,7 +591,7 @@ static void parse_enum_type(const RAnal *anal, const RBinDwarfDie *all_dies, } r_vector_init (&base_type->enum_data.cases, - sizeof (RAnalEnumCase), enum_type_fini, NULL); + sizeof (RAnalEnumCase), enum_type_case_free, NULL); RAnalEnumCase cas; if (die->has_children) { int child_depth = 1; // Direct children of the node @@ -619,7 +607,7 @@ static void parse_enum_type(const RAnal *anal, const RBinDwarfDie *all_dies, } else { void *element = r_vector_push (&base_type->enum_data.cases, &cas); if (!element) { - enum_type_fini (result, NULL); + enum_type_case_free (result, NULL); goto cleanup; } } diff --git a/libr/anal/type_pdb.c b/libr/anal/type_pdb.c new file mode 100644 index 0000000000..f8ddfd29dd --- /dev/null +++ b/libr/anal/type_pdb.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include "../bin/pdb/types.h" +#include "base_types.h" + +static bool is_parsable_type(const ELeafType type) { + return (type == eLF_STRUCTURE || + type == eLF_UNION || + type == eLF_ENUM || + type == eLF_CLASS); +} + +/** + * @brief Create a type name from offset + * + * @param offset + * @return char* Name or NULL if error + */ +static char *create_type_name_from_offset(ut64 offset) { + int offset_length = snprintf (NULL, 0, "type_0x%" PFMT64x, offset); + char *str = malloc (offset_length + 1); + snprintf (str, offset_length + 1, "type_0x%" PFMT64x, offset); + return str; +} + +/** + * @brief Parses class/struct/union member + * + * @param type_info Current type info (member) + * @param types List of all types + * @return RAnalStructMember* parsed member, NULL if fail + */ +static RAnalStructMember *parse_member(STypeInfo *type_info, RList *types) { + r_return_val_if_fail (type_info && types, NULL); + if (type_info->leaf_type != eLF_MEMBER) { + return NULL; + } + r_return_val_if_fail (type_info->get_name && + type_info->get_print_type && type_info->get_val, NULL); + char *name = NULL; + char *type = NULL; + int offset = 0; + + type_info->get_val (type_info, &offset); // gets offset + type_info->get_name (type_info, &name); + type_info->get_print_type (type_info, &type); + RAnalStructMember *member = R_NEW0 (RAnalStructMember); + if (!member) { + goto cleanup; + } + char *sname = r_str_sanitize_sdb_key (name); + member->name = sname; + member->type = strdup (type); // we assume it's sanitized + member->offset = offset; + return member; +cleanup: + return NULL; +} + +/** + * @brief Parse enum case + * + * @param type_info Current type info (enum case) + * @param types List of all types + * @return RAnalEnumCase* parsed enum case, NULL if fail + */ +static RAnalEnumCase *parse_enumerate(STypeInfo *type_info, RList *types) { + r_return_val_if_fail (type_info && types && type_info->leaf_type == eLF_ENUMERATE, NULL); + r_return_val_if_fail (type_info->get_val && type_info->get_name, NULL); + + char *name = NULL; + int value = 0; + // sometimes, the type doesn't have get_val for some reason + type_info->get_val (type_info, &value); + type_info->get_name (type_info, &name); + RAnalEnumCase *cas = R_NEW0 (RAnalEnumCase); + if (!cas) { + goto cleanup; + } + char *sname = r_str_sanitize_sdb_key (name); + cas->name = sname; + cas->val = value; + return cas; +cleanup: + return NULL; +} + +/** + * @brief Parses enum into BaseType and saves it into SDB + * + * @param anal + * @param type Current type + * @param types List of all types + */ +static void parse_enum(const RAnal *anal, SType *type, RList *types) { + r_return_if_fail (anal && type && types); + STypeInfo *type_info = &type->type_data; + // assert all member functions we need info from + r_return_if_fail (type_info->get_members && + type_info->get_name && + type_info->get_utype); + + RAnalBaseType *base_type = r_anal_new_base_type (R_ANAL_BASE_TYPE_KIND_ENUM); + if (!base_type) { + return; + } + + char *name = NULL; + type_info->get_name (type_info, &name); + bool to_free_name = false; + if (!name) { + name = create_type_name_from_offset (type->tpi_idx); + to_free_name = true; + } + type_info->get_utype (type_info, (void **)&type); + int size = 0; + char *type_name = NULL; + if (type && type->type_data.type_info) { + SLF_SIMPLE_TYPE *base_type = type->type_data.type_info; + type_name = base_type->type; + size = base_type->size; + } + RList *members; + type_info->get_members (type_info, &members); + + r_vector_init (&base_type->enum_data.cases, + sizeof (RAnalEnumCase), enum_type_case_free, NULL); + + RListIter *it = r_list_iterator (members); + while (r_list_iter_next (it)) { + STypeInfo *member_info = r_list_iter_get (it); + RAnalEnumCase *enum_case = parse_enumerate (member_info, types); + if (!enum_case) { + continue; // skip it, move forward + } + void *element = r_vector_push (&base_type->struct_data.members, enum_case); + if (!element) { + goto cleanup; + } + } + char *sname = r_str_sanitize_sdb_key (name); + base_type->name = sname; + base_type->size = size; + base_type->type = strdup (type_name); // we assume it's sanitized + + r_anal_save_base_type (anal, base_type); +cleanup: + if (to_free_name) { + R_FREE (name); + } + r_anal_free_base_type (base_type); + return; +} + +/** + * @brief Parses classes, unions and structures into BaseType and saves them into SDB + * + * @param anal + * @param type Current type + * @param types List of all types + */ +static void parse_structure(const RAnal *anal, SType *type, RList *types) { + r_return_if_fail (anal && type && types); + STypeInfo *type_info = &type->type_data; + // assert all member functions we need info from + r_return_if_fail (type_info->get_members && + type_info->is_fwdref && + type_info->get_name && + type_info->get_val); + + RAnalBaseType *base_type = r_anal_new_base_type (R_ANAL_BASE_TYPE_KIND_STRUCT); + if (!base_type) { + return; + } + r_vector_init (&base_type->struct_data.members, + sizeof (RAnalStructMember), struct_type_member_free, NULL); + + char *name = NULL; + type_info->get_name (type_info, &name); + bool to_free_name = false; + if (!name) { + name = create_type_name_from_offset (type->tpi_idx); + to_free_name = true; + } + int size; + type_info->get_val (type_info, &size); // gets size + + RList *members; + type_info->get_members (type_info, &members); + + RListIter *it = r_list_iterator (members); + while (r_list_iter_next (it)) { + STypeInfo *member_info = r_list_iter_get (it); + RAnalStructMember *struct_member = parse_member (member_info, types); + if (!struct_member) { + continue; // skip the failure + } + void *element = r_vector_push (&base_type->struct_data.members, struct_member); + if (!element) { + goto cleanup; + } + } + if (type_info->leaf_type == eLF_STRUCTURE || type_info->leaf_type == eLF_CLASS) { + base_type->kind = R_ANAL_BASE_TYPE_KIND_STRUCT; + } else { // union + base_type->kind = R_ANAL_BASE_TYPE_KIND_UNION; + } + char *sname = r_str_sanitize_sdb_key (name); + base_type->name = sname; + base_type->size = size; + r_anal_save_base_type (anal, base_type); +cleanup: + if (to_free_name) { + R_FREE (name); + } + r_anal_free_base_type (base_type); + return; +} + +/** + * @brief Delegate the type parsing to appropriate function + * + * @param anal + * @param type Current type + * @param types List of all types + */ +static void parse_type (const RAnal *anal, SType *type, RList *types) { + r_return_if_fail (anal && type && types); + + int is_forward_decl; + if (type->type_data.is_fwdref) { + type->type_data.is_fwdref (&type->type_data, &is_forward_decl); + if (is_forward_decl) { // we skip those, atleast for now + return; + } + } + switch (type->type_data.leaf_type) { + case eLF_CLASS: + case eLF_STRUCTURE: + case eLF_UNION: + parse_structure (anal, type, types); + break; + case eLF_ENUM: + parse_enum (anal, type, types); + break; + default: + // shouldn't happen, happens when someone modifies leafs that get here + // but not how they should be parsed + eprintf ("Unknown type record"); + break; + } +} + +/** + * @brief Saves PDB types from TPI stream into the SDB + * + * @param anal + * @param pdb PDB information + */ +R_API void r_parse_pdb_types(const RAnal *anal, const RPdb *pdb) { + r_return_if_fail (anal && pdb); + RList *plist = pdb->pdb_streams; + // getting the TPI stream from the streams list + STpiStream *tpi_stream = r_list_get_n (plist, ePDB_STREAM_TPI); + if (!tpi_stream) { // no TPI stream found + return; + } + // Types should be DAC - only references previous records + RListIter *iter = r_list_iterator (tpi_stream->types); + while (r_list_iter_next (iter)) { // iterate all types + SType *type = r_list_iter_get (iter); + if (is_parsable_type (type->type_data.leaf_type)) { + parse_type (anal, type, tpi_stream->types); + } + } +} \ No newline at end of file diff --git a/libr/bin/pdb/main.c b/libr/bin/pdb/main.c index 0b8f06b295..a73a8e32a8 100644 --- a/libr/bin/pdb/main.c +++ b/libr/bin/pdb/main.c @@ -15,7 +15,7 @@ static void print_usage(void) { /////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { - R_PDB pdb; + RPdb pdb; static struct option long_options[] = { diff --git a/libr/bin/pdb/pdb.c b/libr/bin/pdb/pdb.c index 8c773f5b6b..85067656eb 100644 --- a/libr/bin/pdb/pdb.c +++ b/libr/bin/pdb/pdb.c @@ -41,6 +41,19 @@ static void free_pdb_stream(void *stream) { } } +/** + * @brief Create a type name from offset + * + * @param offset + * @return char* Name or NULL if error + */ +static char *create_type_name_from_offset(ut64 offset) { + int offset_length = snprintf (NULL, 0, "type_0x%" PFMT64x, offset); + char *str = malloc (offset_length + 1); + snprintf (str, offset_length + 1, "type_0x%" PFMT64x, offset); + return str; +} + // static void pdb_stream_get_data(R_PDB_STREAM *pdb_stream, char *data) // { // int pos = stream_file_tell(&pdb_stream->stream_file); @@ -72,7 +85,7 @@ static int init_r_pdb_stream(R_PDB_STREAM *pdb_stream, RBuffer *buf /*FILE *fp*/ } /////////////////////////////////////////////////////////////////////////////// -static int read_int_var(char *var_name, int *var, R_PDB *pdb) { +static int read_int_var(char *var_name, int *var, RPdb *pdb) { if (var) { *var = 0; } @@ -97,7 +110,7 @@ static int count_pages(int length, int page_size) { } /////////////////////////////////////////////////////////////////////////////// -static int init_pdb7_root_stream(R_PDB *pdb, int *root_page_list, int pages_amount, +static int init_pdb7_root_stream(RPdb *pdb, int *root_page_list, int pages_amount, EStream indx, int root_size, int page_size) { R_PDB_STREAM *pdb_stream = 0; int tmp_data_max_size = 0; @@ -320,7 +333,7 @@ static void find_indx_in_list(RList *l, int index, SStreamParseFunc **res) { } /////////////////////////////////////////////////////////////////////////////// -static int pdb_read_root(R_PDB *pdb) { +static int pdb_read_root(RPdb *pdb) { int i = 0; RList *pList = pdb->pdb_streams; R_PDB7_ROOT_STREAM *root_stream = pdb->root_stream; @@ -406,7 +419,7 @@ static int pdb_read_root(R_PDB *pdb) { return 1; } -static bool pdb7_parse(R_PDB *pdb) { +static bool pdb7_parse(RPdb *pdb) { char signature[PDB7_SIGNATURE_LEN + 1]; int num_root_index_pages = 0; int *root_index_pages = 0; @@ -511,7 +524,7 @@ error: return false; } -static void finish_pdb_parse(R_PDB *pdb) { +static void finish_pdb_parse(RPdb *pdb) { R_PDB7_ROOT_STREAM *p = pdb->root_stream; RListIter *it; SPage *page = 0; @@ -604,471 +617,705 @@ static void finish_pdb_parse(R_PDB *pdb) { // printf("finish_pdb_parse()\n"); } -typedef enum EStates { - ePointerState, - eUnionState, - eStructState, - eMemberState, - eUnsignedState, - eTypeNameState, - eShortState, - eLongState, - eCharState, - eModifierState, - eEnumState, - eArrayState, - eOneMethodState, - eVoidState, - eDoubleState, - eBitfieldState, - eStateMax -} EStates; - -/////////////////////////////////////////////////////////////////////////////// -static EStates convert_to_state(char *cstate) { - EStates state = eStateMax; - - if (strstr (cstate, "member")) { - state = eMemberState; - } else if (strstr (cstate, "pointer")) { - state = ePointerState; - } else if (strstr (cstate, "union")) { - state = eUnionState; - } else if (strstr (cstate, "struct")) { - state = eStructState; - } else if (strstr (cstate, "unsigned")) { - state = eUnsignedState; - } else if (strstr (cstate, "short")) { - state = eShortState; - } else if (strstr (cstate, "long")) { - state = eLongState; - } else if (strstr (cstate, "char")) { - state = eCharState; - } else if (strstr (cstate, "modifier")) { - state = eModifierState; - } else if (strstr (cstate, "enum")) { - state = eEnumState; - } else if (strstr (cstate, "array")) { - state = eArrayState; - } else if (strstr (cstate, "onemethod")) { - state = eOneMethodState; - } else if (strstr (cstate, "void")) { - state = eVoidState; - } else if (strstr (cstate, "double")) { - state = eDoubleState; - } else if (strstr (cstate, "bitfield")) { - state = eBitfieldState; - } - - return state; +static SimpleTypeMode get_simple_type_mode (PDB_SIMPLE_TYPES type) { + ut32 value = type; // cast to unsigned for defined bitwise operations + /* https://llvm.org/docs/PDB/TpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + // because mode is only number between 0-7, 1 byte is enough + return (value & 0x00000000F0000); } -/////////////////////////////////////////////////////////////////////////////// -/// TODO: rewrite this ?! -static int build_format_flags(R_PDB *pdb, char *type, int pos, char *res_field, char **name_field) { - EStates curr_state; - char *tmp = 0; - char *name = 0; +static SimpleTypeKind get_simple_type_kind (PDB_SIMPLE_TYPES type) { + ut32 value = type; // cast to unsigned for defined bitwise operations + /* https://llvm.org/docs/PDB/TpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + return (value & 0x00000000000FF); +} - tmp = strtok (type, " "); - while (tmp != NULL) { - curr_state = convert_to_state (tmp); - switch (curr_state) { - case eMemberState: +/** + * @brief Maps simple type into a format string for `pf` + * + * @param simple_type + * @param member_format pointer to assert member format to + * @return int -1 if it's unparsable, -2 if it should be skipped, 0 if all is correct + */ +static int simple_type_to_format (const SLF_SIMPLE_TYPE *simple_type, char **member_format) { + SimpleTypeMode mode = get_simple_type_mode (simple_type->simple_type); + switch (mode) { + case DIRECT: { + SimpleTypeKind kind = get_simple_type_kind (simple_type->simple_type); + switch (kind) { + case PDB_NONE: + case PDB_VOID: + case PDB_NOT_TRANSLATED: + case PDB_HRESULT: + return -1; break; - case ePointerState: - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'p'; + case PDB_SIGNED_CHAR: + case PDB_NARROW_CHAR: + *member_format = "c"; break; - case eUnionState: - case eStructState: - res_field[pos] = '?'; - tmp = strtok (NULL, " "); - name = (char *) malloc (strlen (tmp) + strlen (*name_field) + 1 + 2); - if (!name) { - return 0; - } - r_name_filter (tmp, -1); - r_name_filter (*name_field, -1); - strcpy (name, tmp); + case PDB_UNSIGNED_CHAR: + *member_format = "b"; + break; + case PDB_SBYTE: + *member_format = "n1"; + break; + case PDB_BOOL8: + case PDB_BYTE: + *member_format = "N1"; + break; + case PDB_INT16_SHORT: + case PDB_INT16: + *member_format = "n2"; + break; + case PDB_UINT16_SHORT: + case PDB_UINT16: + case PDB_WIDE_CHAR: // TODO what ideal format for wchar? + case PDB_CHAR16: + case PDB_BOOL16: + *member_format = "N2"; + break; + case PDB_INT32_LONG: + case PDB_INT32: + *member_format = "n4"; + break; + case PDB_UINT32_LONG: + case PDB_UINT32: + case PDB_CHAR32: + case PDB_BOOL32: + *member_format = "N4"; + break; + case PDB_INT64_QUAD: + case PDB_INT64: + *member_format = "n8"; + break; + case PDB_UINT64_QUAD: + case PDB_UINT64: + case PDB_BOOL64: + *member_format = "N8"; + break; + // TODO these when formatting for them will exist + case PDB_INT128_OCT: + case PDB_UINT128_OCT: + case PDB_INT128: + case PDB_UINT128: + case PDB_BOOL128: + *member_format = "::::"; + return -2; + //////////////////////////////////// + // TODO these when formatting for them will exist + // I assume complex are made up by 2 floats + case PDB_COMPLEX16: + *member_format = ".."; + return -2; + case PDB_COMPLEX32: + case PDB_COMPLEX32_PP: + *member_format = ":"; + return -2; + case PDB_COMPLEX48: + *member_format = ":."; + return -2; + case PDB_COMPLEX64: + *member_format = "::"; + return -2; + case PDB_COMPLEX80: + *member_format = "::.."; + return -2; + case PDB_COMPLEX128: + *member_format = "::::"; + return -2; - sprintf (name, "(%s)%s", tmp, *name_field); - free (*name_field); - *name_field = name; - - return 1; - case eUnsignedState: - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'u'; + case PDB_FLOAT32: + case PDB_FLOAT32_PP: + *member_format = "f"; break; - case eShortState: - // TODO: where is short?? - // where is unsigned not in hex?? - // w word (2 bytes unsigned short in hex) - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'w'; - return 1; - case eCharState: - if (res_field[pos] == 'p') { - return 1; - } - if (res_field[pos] == 'u') { - res_field[pos] = 'b'; - } else { - res_field[pos] = 'c'; - } - return 1; - case eLongState: - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'i'; - return 1; - case eModifierState: - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'w'; + case PDB_FLOAT64: + *member_format = "F"; break; - case eEnumState: - if (res_field[pos] == 'p') { - return 1; - } - res_field[pos] = 'E'; - tmp = strtok (NULL, " "); - name = (char *) malloc (strlen (tmp) + strlen (*name_field) + 1 + 2); - if (!name) { - return 0; - } - strcpy (name, tmp); - sprintf (name, "(%s)%s", tmp, *name_field); - free (*name_field); - *name_field = name; - return 1; -// case eDoubleState: -//// TODO: what is the flag for double in pf?? -// res_field[pos] = 'q'; -// return 1; - case eBitfieldState: - res_field[pos] = 'B'; - tmp = strtok (NULL, " "); - name = (char *) malloc (strlen (tmp) + strlen (*name_field) + 1 + 2); - if (!name) { - return 0; - } - strcpy (name, tmp); - sprintf (name, "(%s)%s", tmp, *name_field); - free (*name_field); - *name_field = name; - return 1; - case eVoidState: - case eArrayState: - case eOneMethodState: - res_field[pos] = 'p'; - return 1; + //////////////////////////////////// + // TODO these when formatting for them will exist + case PDB_FLOAT16: + *member_format = ".."; + return -2; + case PDB_FLOAT48: + *member_format = ":."; + return -2; + case PDB_FLOAT80: + *member_format = "::.."; + return -2; + case PDB_FLOAT128: + *member_format = "::::"; + return -2; default: - if (((!strcmp (tmp, "to"))) || - (!strcmp (tmp, "nesttype")) || - (!strcmp (tmp, "mfunction")) || - (!strcmp (tmp, "proc")) || - (!strcmp (tmp, "arglist"))) { - break; - } else { - //eprintf ("There is no support for type \"%s\" in PF structs\n", tmp); - res_field[pos] = 'A'; - return 0; + r_warn_if_reached (); + break; + } + } break; + case NEAR_POINTER: + *member_format = "p2"; + break; + case FAR_POINTER: + *member_format = "p4"; + break; + case HUGE_POINTER: + *member_format = "p4"; + break; + case NEAR_POINTER32: + *member_format = "p4"; + break; + case FAR_POINTER32: + *member_format = "p4"; + break; + case NEAR_POINTER64: + *member_format = "p8"; + break; + case NEAR_POINTER128: + *member_format = "p8::"; // TODO fix when support for 16 bytes + break; + default: + // unknown mode ?? + r_warn_if_reached (); + return -1; + } + return 0; +} + +/** + * @brief Creates the format string and puts it into format + * + * @param type_info Information about the member type + * @param format buffer for the formatting string + * @param names buffer for the member names + * @return int -1 if it can't build the format + */ +static int build_member_format(STypeInfo *type_info, RStrBuf *format, RStrBuf *names) { + r_return_val_if_fail (type_info && format && names && type_info->type_info, -1); + // THOUGHT: instead of not doing anything for unknown types I can just skip the bytes + // format is 2 chars tops + null terminator + + char *name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &name); + } + if (!name) { // name should never be null, but malformed PDB exists + return -1; + } + name = r_str_sanitize_sdb_key (name); + + SType *under_type = NULL; + if (type_info->leaf_type == eLF_MEMBER || + type_info->leaf_type == eLF_NESTTYPE) { + if (type_info->get_index) { + type_info->get_index (type_info, (void **)&under_type); + } else { + r_warn_if_reached (); + } + } else if (type_info->leaf_type == eLF_METHOD || + type_info->leaf_type == eLF_ONEMETHOD) { + return 0; // skip method member + } else { + r_warn_if_reached (); + return -1; + } + type_info = &under_type->type_data; + + char *member_format = NULL; + char tmp_format[5] = { 0 }; // used as writable format buffer + + switch (type_info->leaf_type) { + case eLF_SIMPLE_TYPE: { + int map_result = 0; + if ((map_result = simple_type_to_format (type_info->type_info, &member_format)) != 0) { + if (map_result == -1) { // unparsable + goto error; + } else if (map_result == -2) { // skip + goto skip; } } + r_strbuf_append (names, name); + } break; + case eLF_POINTER: { + int size = 4; + if (type_info->get_val) { + type_info->get_val (type_info, &size); + } + snprintf (tmp_format, 5, "p%d", size); + member_format = tmp_format; + r_strbuf_appendf (names, name); + } break; + case eLF_CLASS: + case eLF_UNION: + case eLF_STRUCTURE: { + member_format = "?"; + char *field_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &field_name); + } + if (!field_name) { + field_name = create_type_name_from_offset (under_type->tpi_idx); + } else { + field_name = r_str_sanitize_sdb_key (field_name); + } + r_strbuf_appendf (names, "(%s)%s", field_name, name); + free (field_name); + } break; + // TODO complete the type with additional info + case eLF_BITFIELD: { + member_format = "B"; + r_strbuf_appendf (names, "(uint)%s", name); + } break; + // TODO complete the type with additional info + case eLF_ENUM: { + member_format = "E"; + r_strbuf_appendf (names, "(int)%s", name); + } break; + case eLF_ARRAY: { + int size = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &size); + } + snprintf (tmp_format, 5, "[%d]", size); + member_format = tmp_format; + r_strbuf_append (names, name); // TODO complete the type with additional info + } break; - tmp = strtok (NULL, " "); + default: + r_warn_if_reached (); // Unhandled type format + goto error; } - return 1; + if (!member_format) { + r_warn_if_reached (); // Unhandled type format + goto error; + } + r_strbuf_appendf (format, "%s", member_format); +skip: // shortcut for unknown types where we only skip the bytes + free (name); + return 0; +error: + free (name); + return -1; } -/////////////////////////////////////////////////////////////////////////////// -void build_command_field(ELeafType lt, char **command_field) { - switch (lt) { - case eLF_STRUCTURE: - case eLF_UNION: - *command_field = (char *) malloc (strlen ("\"pf.") + 1); - if (!(*command_field)) { +static inline bool is_printable_type(ELeafType type) { + return (type == eLF_STRUCTURE || + type == eLF_UNION || + type == eLF_ENUM || + type == eLF_CLASS); +} + +/** + * @brief Gets the name of the enum base type + * + * @param type_info Enum TypeInfo + * @return char* name of the base type + */ +static char *get_enum_base_type_name(STypeInfo *type_info) { + char *base_type_name = NULL; + if (type_info->get_utype) { + SType *base_type = NULL; + type_info->get_utype (type_info, (void **)&base_type); + if (base_type && base_type->type_data.leaf_type == eLF_SIMPLE_TYPE) { + SLF_SIMPLE_TYPE *tmp = base_type->type_data.type_info; + base_type_name = tmp->type; + } + } + if (!base_type_name) { + base_type_name = "unknown_t"; + } + return base_type_name; +} + +/** + * @brief Prints out structure and class leaf types + * + * @param name Name of the structure/class + * @param size Size of the structure/class + * @param members List of members + * @param printf Print function + */ +static void print_struct(const char *name, const int size, const RList *members, PrintfCallback printf) { + r_return_if_fail (name && printf); + printf ("struct %s { // size 0x%x\n", name, size); + + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + STypeInfo *type_info = r_list_iter_get (member_iter); + char *member_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &member_name); + } + int offset = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &offset); + } + char *type_name = NULL; + if (type_info->get_print_type) { + type_info->get_print_type (type_info, &type_name); + } + printf (" %s %s; // offset +0x%x\n", type_name, member_name, offset); + R_FREE (type_name); + } + printf ("};\n"); +} + +/** + * @brief Prints out union leaf type + * + * @param name Name of the union + * @param size Size of the union + * @param members List of members + * @param printf Print function + */ +static void print_union(const char *name, const int size, const RList *members, PrintfCallback printf) { + r_return_if_fail (name && printf); + printf ("union %s { // size 0x%x\n", name, size); + + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + STypeInfo *type_info = r_list_iter_get (member_iter); + char *member_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &member_name); + } + int offset = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &offset); + } + char *type_name = NULL; + if (type_info->get_print_type) { + type_info->get_print_type (type_info, &type_name); + } + printf (" %s %s;\n", type_name, member_name); + R_FREE (type_name); + } + printf ("};\n"); +} + +/** + * @brief Prints out enum leaf type + * + * @param name Name of the enum + * @param type type of the enum + * @param members List of cases + * @param printf Print function + */ +static void print_enum(const char *name, const char *type, const RList *members, PrintfCallback printf) { + r_return_if_fail (name && printf); + printf ("enum %s { // type: %s\n", name, type); + + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + STypeInfo *type_info = r_list_iter_get (member_iter); + char *member_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &member_name); + } + int value = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &value); + } + printf (" %s = %d,\n", member_name, value); + } + printf ("};\n"); +} + +/** + * @brief Prints out types in a default format "idpi" command + * + * @param pdb pdb structure for printing function + * @param types List of types + */ +static void print_types_regular(const RPdb *pdb, const RList *types) { + r_return_if_fail (pdb && types); + RListIter *it = r_list_iterator (types); + + while (r_list_iter_next (it)) { + SType *type = r_list_iter_get (it); + STypeInfo *type_info = &type->type_data; + // skip unprintable types + if (!is_printable_type (type_info->leaf_type)) { + continue; + } + // skip forward references + if (type_info->is_fwdref) { + int is_fwdref = 0; + type_info->is_fwdref (type_info, &is_fwdref); + if (is_fwdref == 1) { + continue; + } + } + char *name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &name); + } + int size = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &size); + } + RList *members = NULL; + if (type_info->get_members) { // do we wanna print empty types? + type_info->get_members (type_info, &members); + } + + switch (type_info->leaf_type) { + case eLF_CLASS: + case eLF_STRUCTURE: + print_struct (name, size, members, pdb->cb_printf); + break; + case eLF_UNION: + print_union (name, size, members, pdb->cb_printf); + break; + case eLF_ENUM:; + print_enum (name, get_enum_base_type_name (type_info), members, pdb->cb_printf); + break; + default: + // Unimplemented printing of printable type + r_warn_if_reached (); break; } - strcpy (*command_field, "\"pf."); - break; - case eLF_ENUM: - *command_field = (char *) malloc (strlen ("\"td enum ") + 1); - if (!(*command_field)) { + } +} + +/** + * @brief Prints out types in a json format - "idpij" command + * + * @param pdb pdb structure for printing function + * @param types List of types + */ +static void print_types_json(const RPdb *pdb, PJ *pj, const RList *types) { + r_return_if_fail (pdb && types && pj); + + RListIter *it = r_list_iterator (types); + pj_ka (pj, "types"); + + while (r_list_iter_next (it)) { + SType *type = r_list_iter_get (it); + STypeInfo *type_info = &type->type_data; + // skip unprintable types + if (!is_printable_type (type_info->leaf_type)) { + continue; + } + // skip forward references + if (type_info->is_fwdref) { + int is_fwdref = 0; + type_info->is_fwdref (type_info, &is_fwdref); + if (is_fwdref == 1) { + continue; + } + } + // get the necessary type information + char *name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &name); + } + int size = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &size); + } + RList *members = NULL; // Should we print empty structures/enums? + if (type_info->get_members) { + type_info->get_members (type_info, &members); + } + + // Maybe refactor these into their own functions aswell + switch (type_info->leaf_type) { + case eLF_CLASS: + case eLF_STRUCTURE: + case eLF_UNION: { + pj_o (pj); + pj_ks (pj, "type", "structure"); + pj_ks (pj, "name", name); + pj_kn (pj, "size", size); + pj_ka (pj, "members"); + + if (members) { + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + pj_o (pj); + STypeInfo *type_info = r_list_iter_get (member_iter); + char *member_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &member_name); + } + int offset = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &offset); + } + char *type_name = NULL; + if (type_info->get_print_type) { + type_info->get_print_type (type_info, &type_name); + } + pj_ks (pj, "member_type", type_name); + pj_ks (pj, "member_name", member_name); + pj_kN (pj, "offset", offset); + pj_end (pj); + R_FREE (type_name); + } + } + pj_end (pj); + pj_end (pj); break; } - strcpy (*command_field, "\"td enum "); - break; - default: - break; - } -} + case eLF_ENUM: { + pj_o (pj); + pj_ks (pj, "type", "enum"); + pj_ks (pj, "name", name); + pj_ks (pj, "base_type", get_enum_base_type_name (type_info)); + pj_ka (pj, "cases"); -/////////////////////////////////////////////////////////////////////////////// -void build_name_field(char *name, char **name_field) { - if (name_field) { - *name_field = name? strdup (name): NULL; - r_name_filter (*name_field, -1); - r_str_replace_char (*name_field, ':', '_'); - } -} - -/////////////////////////////////////////////////////////////////////////////// -int build_flags_format_and_members_field(R_PDB *pdb, ELeafType lt, char *name, char *type, - int i, int *pos, int offset, char *format_flags_field, char **members_field) { - switch (lt) { - case eLF_STRUCTURE: - case eLF_UNION: - members_field[i] = (char *) malloc (sizeof(char) * strlen (name) + 1); - if (!members_field[i]) { - return 0; + if (members) { + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + pj_o (pj); + STypeInfo *type_info = r_list_iter_get (member_iter); + char *member_name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &member_name); + } + int value = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &value); + } + pj_ks (pj, "enum_name", member_name); + pj_kn (pj, "enum_val", value); + pj_end (pj); + } + } + pj_end (pj); + pj_end (pj); + break; } - strcpy (members_field[i], name); - if (build_format_flags (pdb, type, *pos, format_flags_field, &members_field[i]) == 0) { - return 0; + default: + // Unimplemented printing of printable type + r_warn_if_reached (); + break; } - *pos = *pos + 1; - break; - case eLF_ENUM: - members_field[i] = r_str_newf ("%s=0x%"PFMT64x, name, offset); -#if 0 - members_field[i] = (char *) malloc (sizeof(char) * strlen (name) + 8 + 1 + 1); // 8 - hex int, 1 - = - if (!members_field[i]) { - return 0; - } - sprintf (members_field[i], "%s=%08X", name, offset); -#endif - break; - default: - return 0; } - - return 1; + pj_end (pj); } -int alloc_format_flag_and_member_fields(RList *ptmp, char **flags_format_field, int *members_amount, char ***members_name_field) { - int i = 0, size = 0; +/** + * @brief Creates pf commands from PDB types - "idpi*" command + * + * @param pdb pdb structure for printing function + * @param types List of types + */ +static void print_types_format(const RPdb *pdb, const RList *types) { + r_return_if_fail (pdb && types); + RListIter *it = r_list_iterator (types); + bool to_free_name = false; + while (r_list_iter_next (it)) { + SType *type = r_list_iter_get (it); + STypeInfo *type_info = &type->type_data; + // skip unprintable types and enums + if (!is_printable_type (type_info->leaf_type) || type_info->leaf_type == eLF_ENUM) { + continue; + } + // skip forward references + if (type_info->is_fwdref) { + int is_fwdref = 0; + type_info->is_fwdref (type_info, &is_fwdref); + if (is_fwdref == 1) { + continue; + } + } + char *name = NULL; + if (type_info->get_name) { + type_info->get_name (type_info, &name); + } + if (!name) { + name = create_type_name_from_offset (type->tpi_idx); + to_free_name = true; + } + int size = 0; + if (type_info->get_val) { + type_info->get_val (type_info, &size); + } + RList *members = NULL; + if (type_info->get_members) { + type_info->get_members (type_info, &members); + } + // pf.name + RStrBuf format; + r_strbuf_init (&format); + RStrBuf member_names; + r_strbuf_init (&member_names); - RListIter *it2 = r_list_iterator (ptmp); - while (r_list_iter_next (it2)) { - (void) r_list_iter_get (it2); - *members_amount = *members_amount + 1; - } - if (!*members_amount) { - return 0; - } - *flags_format_field = (char *) malloc (*members_amount + 1); - memset (*flags_format_field, 0, *members_amount + 1); + if (type_info->leaf_type == eLF_UNION) { + r_strbuf_append (&format, "0"); // every type start from the offset 0 + } - size = sizeof *members_name_field * (*members_amount); - *members_name_field = (char **) malloc (size); - for (i = 0; i < *members_amount; i++) { - (*members_name_field)[i] = 0; + RListIter *member_iter = r_list_iterator (members); + while (r_list_iter_next (member_iter)) { + STypeInfo *member_info = r_list_iter_get (member_iter); + switch (type_info->leaf_type) { + case eLF_STRUCTURE: + case eLF_CLASS: + case eLF_UNION: + if (build_member_format (member_info, &format, &member_names) == -1) { // if failed + goto fail; // skip to the next one, we can't build format from this + } + break; + default: + r_warn_if_reached (); + } + r_strbuf_append (&member_names, " "); + } + if (format.len == 0) { // if it has no members, it's useless for us then? + goto fail; + } + char *sanitized_name = r_str_sanitize_sdb_key (name); + pdb->cb_printf ("pf.%s %s %s\n", sanitized_name, r_strbuf_get (&format), r_strbuf_get (&member_names)); + + if (to_free_name) { // name can be generated or part of the PDB data + R_FREE (name); + } + R_FREE (sanitized_name); + r_strbuf_fini (&format); + r_strbuf_fini (&member_names); + + fail: // if we can't print whole type correctly, don't print at all + if (to_free_name) { + R_FREE (name); + } + r_strbuf_fini (&format); + r_strbuf_fini (&member_names); } - return 1; } -/////////////////////////////////////////////////////////////////////////////// -// TODO: need refactor -static void print_types(R_PDB *pdb, int mode) { - ELeafType lt = eLF_MAX; - char *command_field = 0; - char *name_field = 0; - char *flags_format_field = 0; // format for struct - char **members_name_field = 0; - char *type = 0; - int members_amount = 0; - int i = 0; - int pos = 0; - char sym = ' '; - int is_first = 1; - char *name = NULL; - int val = 0; - int offset = 0; - SType *t = 0; - STypeInfo *tf = 0; - RListIter *it = 0, *it2 = 0; - RList *plist = pdb->pdb_streams, *ptmp = NULL; +/** + * @brief Prints out all the type information in regular,json or pf format + * + * @param pdb PDB information + * @param mode printing mode + */ +static void print_types(const RPdb *pdb, PJ *pj, const int mode) { + RList *plist = pdb->pdb_streams; STpiStream *tpi_stream = r_list_get_n (plist, ePDB_STREAM_TPI); if (!tpi_stream) { eprintf ("There is no tpi stream in current pdb\n"); return; } - - if (mode == 'j') { - pdb->cb_printf ("{\"%s\":[", "types"); - } - - it = r_list_iterator (tpi_stream->types); - while (r_list_iter_next (it)) { - pos = 0; - i = 0; - members_amount = 0; - val = 0; - t = (SType *) r_list_iter_get (it); - tf = &t->type_data; - lt = tf->leaf_type; - if ((tf->leaf_type == eLF_STRUCTURE) || (tf->leaf_type == eLF_UNION) || (tf->leaf_type == eLF_ENUM)) { - if (tf->is_fwdref) { - tf->is_fwdref (tf, &val); - if (val == 1) { - continue; - } - } - if ((mode == 'j') && (is_first == 0)) { - pdb->cb_printf (","); - } - is_first = 0; - if (tf->get_name) { - tf->get_name (tf, &name); - } - // val for STRUCT or UNION mean size - if (tf->get_val) { - tf->get_val (tf, &val); - } - if (tf->get_members) { - tf->get_members (tf, &ptmp); - } - // pdb->cb_printf ("%s: size 0x%x\n", name, val); - switch (mode) { - case 'd': pdb->cb_printf ("%s: size 0x%x\n", name, val); break; - case 'r': - build_command_field (lt, &command_field); - build_name_field (name, &name_field); - if (!alloc_format_flag_and_member_fields (ptmp, &flags_format_field, - &members_amount, &members_name_field)) { - goto err; - } - break; - case 'j': - switch (lt) { - case eLF_ENUM: - pdb->cb_printf ("{\"type\":\"%s\", \"name\":\"%s\",\"%s\":[", - "enum", name, "enums"); - break; - case eLF_STRUCTURE: - case eLF_UNION: - pdb->cb_printf ("{\"type\":\"%s\",\"name\":\"%s\",\"size\":%d,\"%s\":[", - "structure", name, val, "members"); - break; - default: - continue; - } - - break; - } - - it2 = r_list_iterator (ptmp); - while (r_list_iter_next (it2)) { - if ((mode == 'j') && (i)) { - pdb->cb_printf (","); - } - tf = (STypeInfo *) r_list_iter_get (it2); - if (tf->get_name) { - tf->get_name (tf, &name); - } - if (tf->get_val) { - tf->get_val (tf, &offset); - } else { - offset = 0; - } - if (tf->get_print_type) { - tf->get_print_type (tf, &type); - } - switch (mode) { - case 'd': - pdb->cb_printf (" 0x%x: %s type:", offset, name); - pdb->cb_printf ("%s\n", type); - break; - case 'r': - if (!build_flags_format_and_members_field (pdb, lt, name, type, i, - &pos, offset, flags_format_field, members_name_field)) { - R_FREE (type); - goto err; - } - break; - case 'j': // JSON - switch (lt) { - case eLF_ENUM: - pdb->cb_printf ("{\"%s\":\"%s\",\"%s\":%d}", - "enum_name", name, "enum_val", offset); - break; - case eLF_STRUCTURE: - case eLF_UNION: - pdb->cb_printf ("{\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":%d}", - "member_type", type + strlen ("(member)") + 1, - "member_name", name, "offset", offset); - break; - default: - break; - } - break; - } - R_FREE (type); - i++; - } - - if (mode == 'r') { - r_name_filter (name_field, -1); - pdb->cb_printf ("%s%s ", command_field, name_field); - if (lt != eLF_ENUM) { - pdb->cb_printf ("%s ", flags_format_field); - } else { - pdb->cb_printf ("%c ", '{'); - } - sym = (lt == eLF_ENUM)? ',': ' '; - for (i = 0; i < members_amount; i++) { - char *eq = (lt == eLF_ENUM) ? strchr (members_name_field[i], '=') : NULL; - r_name_filter2 (members_name_field[i]); - if (eq) { - *eq = '='; - } - pdb->cb_printf ("%s", members_name_field[i]); - if ((i + 1) != members_amount) { - pdb->cb_printf ("%c", sym); - } - } - if (lt == eLF_ENUM) { - pdb->cb_printf (" };\"\n"); - } else { - pdb->cb_printf ("\"\n"); - } - } - if (mode == 'j') { - pdb->cb_printf ("]}"); - } -err: - if (mode == 'r') { - R_FREE (command_field); - R_FREE (name_field); - R_FREE (flags_format_field); - for (i = 0; i < members_amount; i++) { - R_FREE (members_name_field[i]); - } - R_FREE (members_name_field); - } - } - } - - if (mode == 'j') { - pdb->cb_printf ("]}"); + switch (mode) { + case 'd': print_types_regular (pdb, tpi_stream->types); return; + case 'j': print_types_json (pdb, pj, tpi_stream->types); return; + case 'r': print_types_format (pdb, tpi_stream->types); return; } } /////////////////////////////////////////////////////////////////////////////// -static void print_gvars(R_PDB *pdb, ut64 img_base, int format) { +static void print_gvars(RPdb *pdb, ut64 img_base, PJ *pj, int format) { SStreamParseFunc *omap = 0, *sctns = 0, *sctns_orig = 0, *gsym = 0, *tmp = 0; SIMAGE_SECTION_HEADER *sctn_header = 0; SGDATAStream *gsym_data_stream = 0; @@ -1077,7 +1324,6 @@ static void print_gvars(R_PDB *pdb, ut64 img_base, int format) { RListIter *it = 0; RList *l = 0; char *name; - int is_first = 1; l = pdb->pdb_streams2; it = r_list_iterator (l); @@ -1104,15 +1350,16 @@ static void print_gvars(R_PDB *pdb, ut64 img_base, int format) { eprintf ("There is no global symbols in current PDB.\n"); return; } + if (format == 'j') { - pdb->cb_printf ("{\"%s\":[", "gvars"); + pj_ka (pj, "gvars"); } - gsym_data_stream = (SGDATAStream *) gsym->stream; + gsym_data_stream = (SGDATAStream *)gsym->stream; if ((omap != 0) && (sctns_orig != 0)) { - pe_stream = (SPEStream *) sctns_orig->stream; + pe_stream = (SPEStream *)sctns_orig->stream; } else { if (sctns) { - pe_stream = (SPEStream *) sctns->stream; + pe_stream = (SPEStream *)sctns->stream; } } if (!pe_stream) { @@ -1120,11 +1367,11 @@ static void print_gvars(R_PDB *pdb, ut64 img_base, int format) { } it = r_list_iterator (gsym_data_stream->globals_list); while (r_list_iter_next (it)) { - gdata = (SGlobal *) r_list_iter_get (it); + gdata = (SGlobal *)r_list_iter_get (it); sctn_header = r_list_get_n (pe_stream->sections_hdrs, (gdata->segment - 1)); if (sctn_header) { name = r_bin_demangle_msvc (gdata->name.name); - name = (name)? name: strdup (gdata->name.name); + name = (name) ? name : strdup (gdata->name.name); if (name && format != 'd') { char *_name = name; name = r_name_filter2 (_name); @@ -1132,47 +1379,42 @@ static void print_gvars(R_PDB *pdb, ut64 img_base, int format) { } switch (format) { case 2: - case 'j': // JSON - if (!is_first) { - pdb->cb_printf (","); - } - pdb->cb_printf ("{\"%s\":%d,\"%s\":%d,\"%s\":\"%.*s\",\"%s\":\"%s\"}", - "address", (ut64) (img_base + omap_remap ((omap)? (omap->stream): 0, gdata->offset + sctn_header->virtual_address)), - "symtype", gdata->symtype, - "section_name", PDB_SIZEOF_SECTION_NAME, sctn_header->name, - "gdata_name", name); + case 'j': // JSON + pj_o (pj); + pj_kN (pj, "address", (img_base + omap_remap ((omap) ? (omap->stream) : 0, gdata->offset + sctn_header->virtual_address))); + pj_kN (pj, "symtype", gdata->symtype); + pj_ks (pj, "section_name", sctn_header->name); + pj_ks (pj, "gdata_name", name); + pj_end (pj); break; case 1: case '*': case 'r': - pdb->cb_printf ("f pdb.%s = 0x%"PFMT64x " # %d %.*s\n", + pdb->cb_printf ("f pdb.%s = 0x%" PFMT64x " # %d %.*s\n", name, - (ut64) (img_base + omap_remap ((omap)? (omap->stream): 0, - gdata->offset + sctn_header->virtual_address)), + (ut64) (img_base + omap_remap ((omap) ? (omap->stream) : 0, gdata->offset + sctn_header->virtual_address)), gdata->symtype, PDB_SIZEOF_SECTION_NAME, sctn_header->name); break; case 'd': default: - pdb->cb_printf ("0x%08"PFMT64x " %d %.*s %s\n", - (ut64) (img_base + omap_remap ((omap)? (omap->stream): 0, - gdata->offset + sctn_header->virtual_address)), + pdb->cb_printf ("0x%08" PFMT64x " %d %.*s %s\n", + (ut64) (img_base + omap_remap ((omap) ? (omap->stream) : 0, gdata->offset + sctn_header->virtual_address)), gdata->symtype, PDB_SIZEOF_SECTION_NAME, sctn_header->name, name); break; } free (name); } else { //eprintf ("Skipping %s, segment %d does not exist\n", - //gdata->name.name, (gdata->segment - 1)); + //gdata->name.name, (gdata->segment - 1)); } - is_first = 0; } if (format == 'j') { - pdb->cb_printf ("]}"); + pj_end (pj); } } /////////////////////////////////////////////////////////////////////////////// -R_API bool init_pdb_parser_with_buf(R_PDB *pdb, RBuffer* buf) { +R_API bool init_pdb_parser_with_buf(RPdb *pdb, RBuffer* buf) { char *signature = NULL; int bytes_read = 0; @@ -1222,7 +1464,7 @@ error: return false; } -R_API bool init_pdb_parser(R_PDB *pdb, const char *filename) { +R_API bool init_pdb_parser(RPdb *pdb, const char *filename) { RBuffer *buf = r_buf_new_slurp (filename); if (!buf) { eprintf ("%s: Error reading file \"%s\"\n", __func__, filename); diff --git a/libr/bin/pdb/tpi.c b/libr/bin/pdb/tpi.c index f0e00d5606..4f89ebf8cd 100644 --- a/libr/bin/pdb/tpi.c +++ b/libr/bin/pdb/tpi.c @@ -5,90 +5,681 @@ static unsigned int base_idx = 0; static RList *p_types_list; -static void print_base_type(EBASE_TYPES base_type, char **name) { - switch (base_type) { - case eT_32PINT4: - *name = "pointer to long"; +static bool is_simple_type(int idx) { + ut32 value = (ut32) idx; + /* https://llvm.org/docs/PDB/TpiStream.html#type-indices + .---------------------------.------.----------. + | Unused | Mode | Kind | + '---------------------------'------'----------' + |+32 |+12 |+8 |+0 + */ + return value < base_idx; + // return ((value & 0x00000000FFF00) <= 0x700 && (value & 0x00000000000FF) < 0x80); +} + +/** + * @brief Parses simple type if the idx represents one + * + * @param idx + * @return STypeInfo, leaf_type = 0 -> error + * This can be made smarter by using the masks + * and splitting it on 2 parts, 1 mode, 1 type + */ +static STypeInfo parse_simple_type(ut32 idx) { + STypeInfo type = { 0 }; + SLF_SIMPLE_TYPE *simple_type = R_NEW0 (SLF_SIMPLE_TYPE); + if (!simple_type) { + return type; + } + switch (idx) { + case eT_NOTYPE: // uncharacterized type (no type) + simple_type->size = 0; + simple_type->type = strdup ("notype_t"); break; - case eT_32PRCHAR: - *name = "pointer to unsigned char"; + case eT_VOID: // void + simple_type->size = 0; + simple_type->type = strdup ("void"); break; - case eT_32PUCHAR: - *name = "pointer to unsigned char"; - break; - case eT_32PULONG: - *name = "pointer to unsigned long"; - break; - case eT_32PLONG: - *name = "pointer to long"; - break; - case eT_32PUQUAD: - *name = "pointer to unsigned long long"; - break; - case eT_32PUSHORT: - *name = "pointer to unsigned short"; + case eT_PVOID: // near ptr to void (2 bytes?) + simple_type->size = 2; + simple_type->type = strdup ("void *"); break; + case eT_PFVOID: // far ptr to void (4 bytes) + case eT_PHVOID: // huge ptr to void (4 bytes) case eT_32PVOID: - *name = "pointer to void"; + case eT_32PFVOID: + simple_type->size = 4; + simple_type->type = strdup ("void *"); break; case eT_64PVOID: - *name = "pointer64 to void"; + simple_type->size = 8; + simple_type->type = strdup ("void *"); break; - case eT_INT4: - *name = "long"; + + case eT_CHAR: + simple_type->size = 1; + simple_type->type = strdup ("char"); break; - case eT_INT8: - *name = "long long"; + case eT_PCHAR: // near + simple_type->size = 2; + simple_type->type = strdup ("char *"); break; - case eT_LONG: - *name = "long"; + case eT_PFCHAR: + case eT_PHCHAR: + case eT_32PCHAR: + case eT_32PFCHAR: + simple_type->size = 4; + simple_type->type = strdup ("uint8_t *"); break; - case eT_QUAD: - *name = "long long"; + case eT_64PCHAR: + simple_type->size = 8; + simple_type->type = strdup ("uint8_t *"); break; + + case eT_UCHAR: + simple_type->size = 1; + simple_type->type = strdup ("uint8_t"); + break; + case eT_PUCHAR: + simple_type->size = 2; + simple_type->type = strdup ("uint8_t *"); + break; + case eT_PFUCHAR: + case eT_PHUCHAR: + case eT_32PUCHAR: + case eT_32PFUCHAR: + simple_type->size = 4; + simple_type->type = strdup ("uint8_t *"); + break; + case eT_64PUCHAR: + simple_type->size = 8; + simple_type->type = strdup ("uint8_t *"); + break; + + case eT_RCHAR: - *name = "unsigned char"; + simple_type->size = 1; + simple_type->type = strdup ("char"); + break; + case eT_PRCHAR: + simple_type->size = 2; + simple_type->type = strdup ("char *"); + break; + case eT_PFRCHAR: + case eT_PHRCHAR: + case eT_32PRCHAR: + case eT_32PFRCHAR: + simple_type->size = 4; + simple_type->type = strdup ("char *"); + break; + case eT_64PRCHAR: + simple_type->size = 8; + simple_type->type = strdup ("char *"); + break; + + case eT_WCHAR: + simple_type->size = 4; + simple_type->type = strdup ("wchar_t"); + break; + case eT_PWCHAR: + simple_type->size = 2; + simple_type->type = strdup ("wchar_t *"); + break; + case eT_PFWCHAR: + case eT_PHWCHAR: + case eT_32PWCHAR: + case eT_32PFWCHAR: + simple_type->size = 4; + simple_type->type = strdup ("wchar_t *"); + break; + case eT_64PWCHAR: + simple_type->size = 8; + simple_type->type = strdup ("wchar_t *"); + break; + + case eT_BYTE: + simple_type->size = 1; + simple_type->type = strdup ("char"); + break; + case eT_PBYTE: + simple_type->size = 2; + simple_type->type = strdup ("char *"); + break; + case eT_PFBYTE: + case eT_PHBYTE: + case eT_32PBYTE: + case eT_32PFBYTE: + simple_type->size = 4; + simple_type->type = strdup ("char *"); + break; + case eT_64PBYTE: + simple_type->size = 8; + simple_type->type = strdup ("char *"); + break; + + case eT_UBYTE: + simple_type->size = 1; + simple_type->type = strdup ("uint8_t"); + break; + case eT_PUBYTE: + simple_type->size = 2; + simple_type->type = strdup ("uint8_t *"); + break; + case eT_PFUBYTE: + case eT_PHUBYTE: + case eT_32PUBYTE: + case eT_32PFUBYTE: + simple_type->size = 4; + simple_type->type = strdup ("uint8_t *"); + break; + case eT_64PUBYTE: + simple_type->size = 8; + simple_type->type = strdup ("uint8_t*"); + break; + + + case eT_INT16: // 16 bit + case eT_SHORT: // 16 bit short + simple_type->size = 2; + simple_type->type = strdup ("uint16_t"); + break; + case eT_PINT16: + case eT_PSHORT: + simple_type->size = 2; + simple_type->type = strdup ("uint16_t *"); + break; + case eT_PFSHORT: + case eT_PHSHORT: + case eT_32PSHORT: + case eT_32PFSHORT: + case eT_PFINT16: + case eT_PHINT16: + case eT_32PINT16: + case eT_32PFINT16: + simple_type->size = 4; + simple_type->type = strdup ("uint16_t *"); + break; + case eT_64PINT16: + case eT_64PSHORT: + simple_type->size = 8; + simple_type->type = strdup ("uint16_t *"); + break; + + case eT_UINT16: // 16 bit + case eT_USHORT: // 16 bit short + simple_type->size = 2; + simple_type->type = strdup ("uint16_t"); + break; + case eT_PUINT16: + case eT_PUSHORT: + simple_type->size = 2; + simple_type->type = strdup ("uint16_t *"); + break; + case eT_PFUSHORT: + case eT_PHUSHORT: + case eT_32PUSHORT: + case eT_PFUINT16: + case eT_PHUINT16: + case eT_32PUINT16: + case eT_32PFUINT16: + case eT_32PFUSHORT: + simple_type->size = 4; + simple_type->type = strdup ("uint16_t *"); + break; + case eT_64PUINT16: + case eT_64PUSHORT: + simple_type->size =8; + simple_type->type = strdup ("uint16_t *"); + break; + + case eT_LONG: + case eT_INT4: + simple_type->size = 4; + simple_type->type = strdup ("int32_t"); + break; + case eT_PLONG: + case eT_PINT4: + simple_type->size = 2; + simple_type->type = strdup ("int32_t *"); + break; + case eT_PFLONG: + case eT_PHLONG: + case eT_32PLONG: + case eT_32PFLONG: + case eT_PFINT4: + case eT_PHINT4: + case eT_32PINT4: + case eT_32PFINT4: + simple_type->size = 4; + simple_type->type = strdup ("int32_t *"); + break; + case eT_64PLONG: + case eT_64PINT4: + simple_type->size = 8; + simple_type->type = strdup ("int32_t *"); + break; + + case eT_ULONG: + case eT_UINT4: + simple_type->size = 4; + simple_type->type = strdup ("uint32_t"); + break; + case eT_PULONG: + case eT_PUINT4: + simple_type->size = 2; + simple_type->type = strdup ("uint32_t *"); + break; + case eT_PFULONG: + case eT_PHULONG: + case eT_32PULONG: + case eT_32PFULONG: + case eT_PFUINT4: + case eT_PHUINT4: + case eT_32PUINT4: + case eT_32PFUINT4: + simple_type->size = 4; + simple_type->type = strdup ("uint32_t *"); + break; + case eT_64PULONG: + case eT_64PUINT4: + simple_type->size = 8; + simple_type->type = strdup ("uint32_t *"); + break; + + case eT_INT8: + case eT_QUAD: + simple_type->size = 8; + simple_type->type = strdup ("int64_t"); + break; + case eT_PQUAD: + case eT_PINT8: + simple_type->size = 2; + simple_type->type = strdup ("int64_t *"); + break; + case eT_PFQUAD: + case eT_PHQUAD: + case eT_32PQUAD: + case eT_32PFQUAD: + case eT_PFINT8: + case eT_PHINT8: + case eT_32PINT8: + case eT_32PFINT8: + simple_type->size = 4; + simple_type->type = strdup ("int64_t *"); + break; + case eT_64PQUAD: + case eT_64PINT8: + simple_type->size = 8; + simple_type->type = strdup ("int64_t *"); + break; + + + case eT_UQUAD: + case eT_UINT8: + simple_type->size = 8; + simple_type->type = strdup ("uint64_t"); + break; + + case eT_PUQUAD: + case eT_PUINT8: + simple_type->size = 2; + simple_type->type = strdup ("uint64_t *"); + break; + case eT_PFUQUAD: + case eT_PHUQUAD: + case eT_32PUQUAD: + case eT_32PFUQUAD: + case eT_PFUINT8: + case eT_PHUINT8: + case eT_32PUINT8: + case eT_32PFUINT8: + simple_type->size = 4; + simple_type->type = strdup ("uint64_t *"); + break; + case eT_64PUQUAD: + case eT_64PUINT8: + simple_type->size = 8; + simple_type->type = strdup ("uint64_t *"); + break; + case eT_INT128: + case eT_OCT: + simple_type->size = 16; + simple_type->type = strdup ("int128_t"); + break; + case eT_PINT128: + case eT_POCT: + simple_type->size = 2; + simple_type->type = strdup ("int128_t *"); + break; + case eT_PFINT128: + case eT_PHINT128: + case eT_32PINT128: + case eT_32PFINT128: + case eT_PFOCT: + case eT_PHOCT: + case eT_32POCT: + case eT_32PFOCT: + simple_type->size = 4; + simple_type->type = strdup ("int128_t *"); + break; + case eT_64PINT128: + case eT_64POCT: + simple_type->size = 8; + simple_type->type = strdup ("int128_t *"); + break; + + case eT_UINT128: + case eT_UOCT: + simple_type->size = 16; + simple_type->type = strdup ("uint128_t"); + break; + case eT_PUINT128: + case eT_PUOCT: + simple_type->size = 2; + simple_type->type = strdup ("uint128_t *"); + break; + case eT_PFUINT128: + case eT_PHUINT128: + case eT_32PUINT128: + case eT_32PFUINT128: + case eT_PFUOCT: + case eT_PHUOCT: + case eT_32PUOCT: + case eT_32PFUOCT: + simple_type->size = 4; + simple_type->type = strdup ("uint128_t *"); + break; + case eT_64PUINT128: + case eT_64PUOCT: + simple_type->size = 8; + simple_type->type = strdup ("uint128_t *"); break; case eT_REAL32: - *name = "float"; + simple_type->size = 4; + simple_type->type = strdup ("float"); + break; + case eT_PREAL32: + simple_type->size = 2; + simple_type->type = strdup ("float *"); + break; + case eT_PFREAL32: + case eT_PHREAL32: + case eT_32PREAL32: + case eT_32PFREAL32: + simple_type->size = 4; + simple_type->type = strdup ("float *"); + break; + case eT_64PREAL32: + simple_type->size = 8; + simple_type->type = strdup ("float *"); + break; + case eT_REAL48: + simple_type->size = 6; + simple_type->type = strdup ("float"); + break; + case eT_PREAL48: + simple_type->size = 2; + simple_type->type = strdup ("float *"); + break; + case eT_PFREAL48: + case eT_PHREAL48: + case eT_32PREAL48: + case eT_32PFREAL48: + simple_type->size = 4; + simple_type->type = strdup ("float *"); + break; + case eT_64PREAL48: + simple_type->size = 8; + simple_type->type = strdup ("float *"); break; case eT_REAL64: - *name = "double"; + simple_type->size = 8; + simple_type->type = strdup ("double"); break; + case eT_PREAL64: + simple_type->size = 2; + simple_type->type = strdup ("double *"); + break; + case eT_PFREAL64: + case eT_PHREAL64: + case eT_32PREAL64: + case eT_32PFREAL64: + simple_type->size = 4; + simple_type->type = strdup ("long double *"); + break; + case eT_64PREAL64: + simple_type->size = 8; + simple_type->type = strdup ("long double *"); + break; + case eT_REAL80: - *name = "long double"; + simple_type->size = 10; + simple_type->type = strdup ("long double"); break; - case eT_SHORT: - *name = "short"; + case eT_PREAL80: + simple_type->size = 2; + simple_type->type = strdup ("long double *"); break; - case eT_UCHAR: - *name = "unsigned char"; + case eT_PFREAL80: + case eT_PHREAL80: + case eT_32PREAL80: + case eT_32PFREAL80: + simple_type->size = 4; + simple_type->type = strdup ("long double *"); break; - case eT_UINT4: - *name = "unsigned long"; + case eT_64PREAL80: + simple_type->size = 8; + simple_type->type = strdup ("long double *"); break; - case eT_ULONG: - *name = "unsigned long"; + + case eT_REAL128: + simple_type->size = 16; + simple_type->type = strdup ("long double"); break; - case eT_UQUAD: - *name = "unsigned long long"; + case eT_PREAL128: + simple_type->size = 2; + simple_type->type = strdup ("long double *"); break; - case eT_USHORT: - *name = "unsigned short"; + case eT_PFREAL128: + case eT_PHREAL128: + case eT_32PREAL128: + case eT_32PFREAL128: + simple_type->size = 4; + simple_type->type = strdup ("long double *"); break; - case eT_WCHAR: - *name = "wchar"; + case eT_64PREAL128: + simple_type->size = 8; + simple_type->type = strdup ("long double *"); break; - case eT_VOID: - *name = "void"; + + case eT_CPLX32: + simple_type->size = 4; + simple_type->type = strdup ("float _Complex"); break; - case eT_32PWCHAR: - *name = "pointer to wchar"; + case eT_PCPLX32: + simple_type->size = 2; + simple_type->type = strdup ("float _Complex *"); + break; + case eT_PFCPLX32: + case eT_PHCPLX32: + case eT_32PCPLX32: + case eT_32PFCPLX32: + simple_type->size = 4; + simple_type->type = strdup ("float _Complex *"); + break; + case eT_64PCPLX32: + simple_type->size = 8; + simple_type->type = strdup ("float _Complex *"); + break; + + case eT_CPLX64: + simple_type->size = 8; + simple_type->type = strdup ("double _Complex"); + break; + case eT_PCPLX64: + simple_type->size = 2; + simple_type->type = strdup ("double _Complex *"); + break; + case eT_PFCPLX64: + case eT_PHCPLX64: + case eT_32PCPLX64: + case eT_32PFCPLX64: + simple_type->size = 4; + simple_type->type = strdup ("double _Complex *"); + break; + case eT_64PCPLX64: + simple_type->size = 8; + simple_type->type = strdup ("double _Complex *"); + break; + + case eT_CPLX80: + simple_type->size = 10; + simple_type->type = strdup ("long double _Complex"); + break; + case eT_PCPLX80: + simple_type->size = 2; + simple_type->type = strdup ("long double _Complex *"); + break; + case eT_PFCPLX80: + case eT_PHCPLX80: + case eT_32PCPLX80: + case eT_32PFCPLX80: + simple_type->size = 4; + simple_type->type = strdup ("long double _Complex *"); + break; + case eT_64PCPLX80: + simple_type->size = 8; + simple_type->type = strdup ("long double _Complex *"); + break; + + case eT_CPLX128: + simple_type->size = 16; + simple_type->type = strdup ("long double _Complex"); + break; + case eT_PCPLX128: + simple_type->size = 2; + simple_type->type = strdup ("long double _Complex *"); + break; + case eT_PFCPLX128: + case eT_PHCPLX128: + case eT_32PCPLX128: + case eT_32PFCPLX128: + simple_type->size = 4; + simple_type->type = strdup ("long double _Complex *"); + break; + case eT_64PCPLX128: + simple_type->size = 8; + simple_type->type = strdup ("long double _Complex *"); + break; + + case eT_BOOL08: // _Bool probably isn't ideal for bool > 08 + simple_type->size = 1; + simple_type->type = strdup ("_Bool"); + break; + case eT_PBOOL08: + simple_type->size = 2; + simple_type->type = strdup ("_Bool *"); + break; + case eT_PFBOOL08: + case eT_PHBOOL08: + case eT_32PBOOL08: + case eT_32PFBOOL08: + simple_type->size = 4; + simple_type->type = strdup ("_Bool *"); + break; + case eT_64PBOOL08: + simple_type->size = 8; + simple_type->type = strdup ("_Bool *"); + break; + + case eT_BOOL16: + simple_type->size = 2; + simple_type->type = strdup ("_Bool"); + break; + case eT_PBOOL16: + simple_type->size = 2; + simple_type->type = strdup ("_Bool *"); + break; + case eT_PFBOOL16: + case eT_PHBOOL16: + case eT_32PBOOL16: + case eT_32PFBOOL16: + simple_type->size = 4; + simple_type->type = strdup ("_Bool *"); + break; + case eT_64PBOOL16: + simple_type->size = 8; + simple_type->type = strdup ("_Bool *"); + break; + + case eT_BOOL32: + simple_type->size = 4; + simple_type->type = strdup ("_Bool"); + break; + case eT_PBOOL32: + simple_type->size = 2; + simple_type->type = strdup ("_Bool *"); + break; + case eT_PFBOOL32: + case eT_PHBOOL32: + case eT_32PBOOL32: + case eT_32PFBOOL32: + simple_type->size = 4; + simple_type->type = strdup ("_Bool *"); + break; + case eT_64PBOOL32: + simple_type->size = 8; + simple_type->type = strdup ("_Bool *"); + break; + + case eT_BOOL64: + simple_type->size = 8; + simple_type->type = strdup ("_Bool"); + break; + case eT_PBOOL64: + simple_type->size = 2; + simple_type->type = strdup ("_Bool *"); + break; + case eT_PFBOOL64: + case eT_PHBOOL64: + case eT_32PBOOL64: + case eT_32PFBOOL64: + simple_type->size = 4; + simple_type->type = strdup ("_Bool *"); + break; + case eT_64PBOOL64: + simple_type->size = 8; + simple_type->type = strdup ("_Bool *"); + break; + + case eT_BOOL128: + simple_type->size = 16; + simple_type->type = strdup ("_Bool"); + break; + case eT_PBOOL128: + simple_type->size = 2; + simple_type->type = strdup ("_Bool *"); + break; + case eT_PFBOOL128: + case eT_PHBOOL128: + case eT_32PBOOL128: + case eT_32PFBOOL128: + simple_type->size = 4; + simple_type->type = strdup ("_Bool *"); + break; + case eT_64PBOOL128: + simple_type->size = 8; + simple_type->type = strdup ("_Bool *"); break; default: - *name = "unsupported base type"; + simple_type->size = 0; + simple_type->type = strdup ("unknown_t"); break; } + simple_type->simple_type = idx; + type.type_info = simple_type; + type.leaf_type = eLF_SIMPLE_TYPE; + return type; } /////////////////////////////////////////////////////////////////////////////// @@ -190,26 +781,6 @@ static void get_sval_name(SVal *val, char **name) { } } -/////////////////////////////////////////////////////////////////////////////// -//static void get_arglist_type(void *type, void **arglist_type) -//{ -// STypeInfo *t = (STypeInfo *) type; -// SLF_ARGLIST *lf_arglist = (SLF_ARGLIST *) t->type_info; -// RList *l = (RList *) *arglist_type; -// int i = 0; -// int tmp = 0; - -// for (i = 0; i < lf_arglist->count; i++) { -// tmp = lf_arglist->arg_type[i]; -// if (tmp < base_idx) { -// // 0 - means NO_TYPE -// r_list_append(l, 0); -// } else { -// r_list_append(l, r_list_get_n(p_types_list, (tmp - base_idx))); -// } -// } -//} - /////////////////////////////////////////////////////////////////////////////// static void is_union_fwdref(void *type, int *is_fwdref) { STypeInfo *t = (STypeInfo *) type; @@ -219,10 +790,11 @@ static void is_union_fwdref(void *type, int *is_fwdref) { } /////////////////////////////////////////////////////////////////////////////// +// static void is_struct_class_fwdref(void *type, int *is_fwdref) { STypeInfo *t = (STypeInfo *) type; + // SLF_STRUCTURE and SLF_CLASS refer to the same struct so this is fine SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info; - *is_fwdref = lf->prop.bits.fwdref; } @@ -232,8 +804,18 @@ static int get_array_element_type(void *type, void **ret_type) { SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info; int curr_idx = lf_array->element_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -248,8 +830,18 @@ static int get_array_index_type(void *type, void **ret_type) { SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info; int curr_idx = lf_array->index_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -259,13 +851,24 @@ static int get_array_index_type(void *type, void **ret_type) { } /////////////////////////////////////////////////////////////////////////////// +// Again doesn't work for base types static int get_bitfield_base_type(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_BITFIELD *lf = (SLF_BITFIELD *) t->type_info; int curr_idx = lf->base_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -280,40 +883,48 @@ static int get_class_struct_derived(void *type, void **ret_type) { SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info; int curr_idx = lf->derived; - if (curr_idx < base_idx) { - *ret_type = 0; - } else { + if (curr_idx) { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); + } else { + *ret_type = NULL; } return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_class_struct_vshape(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info; int curr_idx = lf->vshape; - if (curr_idx < base_idx) { - *ret_type = 0; - } else { + if (curr_idx) { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); + } else { + *ret_type = NULL; } return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_mfunction_return_type(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info; int curr_idx = lf->return_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -322,33 +933,31 @@ static int get_mfunction_return_type(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_mfunction_class_type(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info; int curr_idx = lf->class_type; - if (curr_idx < base_idx) { - *ret_type = 0; - } else { + if (curr_idx) { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); + } else { + *ret_type = NULL; } return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_mfunction_this_type(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info; int curr_idx = lf->this_type; - if (curr_idx < base_idx) { - *ret_type = 0; - } else { + if (curr_idx) { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); + } else { + *ret_type = NULL; } return curr_idx; @@ -360,11 +969,11 @@ static int get_mfunction_arglist(void *type, void **ret_type) { SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info; int curr_idx = lf->arglist; - if (curr_idx < base_idx) { - *ret_type = 0; - } else { + if (curr_idx) { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); + } else { + *ret_type = NULL; } return curr_idx; @@ -376,8 +985,18 @@ static int get_modifier_modified_type(void *type, void **ret_type) { SLF_MODIFIER *lf = (SLF_MODIFIER *) t->type_info; int curr_idx = lf->modified_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -392,8 +1011,18 @@ static int get_pointer_utype(void *type, void **ret_type) { SLF_POINTER *lf = (SLF_POINTER *) t->type_info; int curr_idx = lf->utype; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -402,14 +1031,23 @@ static int get_pointer_utype(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_procedure_return_type(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_PROCEDURE *lf = (SLF_PROCEDURE *) t->type_info; int curr_idx = lf->return_type; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -418,14 +1056,23 @@ static int get_procedure_return_type(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_procedure_arglist(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_PROCEDURE *lf = (SLF_PROCEDURE *) t->type_info; int curr_idx = lf->arg_list; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -434,14 +1081,23 @@ static int get_procedure_arglist(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_member_index(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_MEMBER *lf = (SLF_MEMBER *) t->type_info; int curr_idx = lf->index; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -450,14 +1106,23 @@ static int get_member_index(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_nesttype_index(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_NESTTYPE *lf = (SLF_NESTTYPE *) t->type_info; int curr_idx = lf->index; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -466,14 +1131,23 @@ static int get_nesttype_index(void *type, void **ret_type) { return curr_idx; } -/////////////////////////////////////////////////////////////////////////////// static int get_onemethod_index(void *type, void **ret_type) { STypeInfo *t = (STypeInfo *) type; SLF_ONEMETHOD *lf = (SLF_ONEMETHOD *) t->type_info; int curr_idx = lf->index; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -487,8 +1161,18 @@ static int get_method_mlist(void *type, void **ret_type) { SLF_METHOD *lf = (SLF_METHOD *) t->type_info; int curr_idx = lf->mlist; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -502,8 +1186,18 @@ static int get_enum_utype(void *type, void **ret_type) { SLF_ENUM *lf = (SLF_ENUM *) t->type_info; int curr_idx = lf->utype; - if (curr_idx < base_idx) { - *ret_type = 0; + if (is_simple_type (curr_idx)) { + STypeInfo base_type = parse_simple_type (curr_idx); + SType *base_ret_type = R_NEW0 (SType); + if (!base_ret_type) { + *ret_type = 0; + return false; + } + base_ret_type->tpi_idx = 0; + base_ret_type->length = 0; + base_ret_type->type_data = base_type; + *ret_type = base_ret_type; + return true; // check what are the return values used for } else { curr_idx -= base_idx; *ret_type = r_list_get_n(p_types_list, curr_idx); @@ -802,26 +1496,6 @@ static void get_union_val(void *type, int *res) { get_sval_val(&lf_union->size, res); } -/////////////////////////////////////////////////////////////////////////////// -//static void printf_sval_name(SVal *val) -//{ -// int len = 0; -// char *name = 0; - -// get_sval_name_len(val, &len); -// name = (char *) malloc(len); -// get_sval_name(val, &name); -// printf("%s", name); - -// free(name); -//} - -//typedef struct { -// SParsedPDBStream *parsed_pdb_stream; -// SPDBInfoStreamD data; -//} SPDBInfoStream; - -/////////////////////////////////////////////////////////////////////////////// static void free_sval(SVal *val) { if (val->value_or_type < eLF_CHAR) { SCString *scstr; @@ -993,37 +1667,32 @@ static void free_tpi_stream(void *stream) { static void get_array_print_type(void *type, char **name) { STypeInfo *ti = (STypeInfo *) type; - SType *t = 0; char *tmp_name = NULL; - int name_len = 0; bool need_to_free = true; - int base_type = 0; - base_type = ti->get_element_type (ti, (void **)&t); - if (!t) { + SType *t = 0; + ti->get_element_type (ti, (void **)&t); + r_return_if_fail (t); // t == NULL indicates malformed PDB ? + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { need_to_free = false; - print_base_type (base_type, &tmp_name); + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); } - - name_len = strlen ("array: "); + int size = 0; + if (ti->get_val) { + ti->get_val (ti, &size); + } + RStrBuf buff; + r_strbuf_init (&buff); if (tmp_name) { - name_len += strlen (tmp_name); - } - *name = (char *) malloc (name_len + 1); - if (!(*name)) { - if (need_to_free) { - R_FREE (tmp_name); - } - return; - } - // name[name_len] = '\0'; - strcpy (*name, "array: "); - if (tmp_name) { - strcat (*name, tmp_name); + r_strbuf_append (&buff, tmp_name); } + r_strbuf_appendf (&buff, "[%d]", size); + *name = r_strbuf_drain_nofree (&buff); + r_strbuf_fini (&buff); if (need_to_free) { R_FREE (tmp_name); } @@ -1033,33 +1702,27 @@ static void get_pointer_print_type(void *type, char **name) { STypeInfo *ti = (STypeInfo *) type; SType *t = 0; char *tmp_name = NULL; - int name_len = 0; int need_to_free = 1; - int base_type = 0; - base_type = ti->get_utype (ti, (void **)&t); - if (!t) { - need_to_free = 0; - print_base_type (base_type, &tmp_name); + ti->get_utype (ti, (void **)&t); + r_return_if_fail (t); // t == NULL indicates malformed PDB ? + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { + need_to_free = false; + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); } - name_len = strlen ("pointer to "); + RStrBuf buff; + r_strbuf_init (&buff); if (tmp_name) { - name_len += strlen (tmp_name); - } - *name = (char *) malloc (name_len + 1); - if (!(*name)) { - // free (tmp_name); - return; - } - // name[name_len] = '\0'; - strcpy (*name, "pointer to "); - if (tmp_name) { - strcat (*name, tmp_name); + r_strbuf_append (&buff, tmp_name); } + r_strbuf_append (&buff, "*"); + *name = r_strbuf_drain_nofree (&buff); + r_strbuf_fini (&buff); if (need_to_free) { free (tmp_name); tmp_name = 0; @@ -1067,44 +1730,47 @@ static void get_pointer_print_type(void *type, char **name) { } static void get_modifier_print_type(void *type, char **name) { - STypeInfo *ti = (STypeInfo *) type; - SType *t = 0; - char *tmp_name = NULL; - int name_len = 0; + STypeInfo *stype_info = type; bool need_to_free = true; - int base_type = 0; + SType *stype = NULL; + char *tmp_name = NULL; - base_type = ti->get_modified_type (ti, (void **)&t); - if (!t) { + stype_info->get_modified_type (stype_info, (void **)&stype); + if (stype && stype->type_data.leaf_type == eLF_SIMPLE_TYPE) { need_to_free = false; - print_base_type (base_type, &tmp_name); + SLF_SIMPLE_TYPE *base_type = stype->type_data.type_info; + tmp_name = base_type->type; } else { - ti = &t->type_data; - ti->get_print_type (ti, &tmp_name); + STypeInfo *refered_type_info = NULL; + refered_type_info = &stype->type_data; + refered_type_info->get_print_type (refered_type_info, &tmp_name); } - name_len = strlen ("modifier "); + SLF_MODIFIER *modifier = stype_info->type_info; + RStrBuf buff; + r_strbuf_init (&buff); + if (modifier->umodifier.bits.const_) { + r_strbuf_append (&buff, "const "); + } + if (modifier->umodifier.bits.volatile_) { + r_strbuf_append (&buff, "volatile "); + } + if (modifier->umodifier.bits.unaligned) { + r_strbuf_append (&buff, "unaligned "); + } if (tmp_name) { - name_len += strlen (tmp_name); - } - *name = (char *) malloc (name_len + 1); - if (!(*name)) { - if (need_to_free) { - free (tmp_name); - } - return; - } - // name[name_len] = '\0'; - strcpy (*name, "modifier "); - if (tmp_name) { - strcat (*name, tmp_name); + r_strbuf_append (&buff, tmp_name); } + *name = r_strbuf_drain_nofree (&buff); + r_strbuf_fini (&buff); + if (need_to_free) { free (tmp_name); } } static void get_procedure_print_type(void *type, char **name) { + // TODO const int name_len = strlen ("proc "); *name = (char *) malloc (name_len + 1); if (!(*name)) { @@ -1120,13 +1786,13 @@ static void get_bitfield_print_type(void *type, char **name) { char *tmp_name = 0; int name_len = 0; int need_to_free = 1; - int base_type = 0; SLF_BITFIELD *bitfeild_info = (SLF_BITFIELD *)ti->type_info; - base_type = ti->get_base_type (ti, (void **)&t); - if (!t) { - need_to_free = 0; - print_base_type (base_type, &tmp_name); + ti->get_base_type (ti, (void **)&t); + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { + need_to_free = false; + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); @@ -1173,35 +1839,27 @@ static void get_enum_print_type(void *type, char **name) { STypeInfo *ti = (STypeInfo *) type; SType *t = 0; char *tmp_name = 0; - int name_len = 0; int need_to_free = 1; - int base_type = 0; - base_type = ti->get_utype (ti, (void **)&t); - if (!t) { + ti->get_utype (ti, (void **)&t); + r_return_if_fail (t); // This shouldn't happen?, TODO explore this situation + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { // BaseType need_to_free = 0; - print_base_type (base_type, &tmp_name); + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); } - name_len = strlen ("enum "); + RStrBuf buff; + r_strbuf_init (&buff); + r_strbuf_append (&buff, "enum "); if (tmp_name) { - name_len += strlen (tmp_name); - } - *name = (char *) malloc (name_len + 1); - if (!(*name)) { - if (need_to_free) { - free (tmp_name); - } - return; - } - // name[name_len] = '\0'; - strcpy (*name, "enum "); - if (tmp_name) { - strcat (*name, tmp_name); + r_strbuf_append (&buff, tmp_name); } + *name = r_strbuf_drain_nofree (&buff); + r_strbuf_fini (&buff); if (need_to_free) { free (tmp_name); @@ -1280,6 +1938,7 @@ static void get_arglist_print_type(void *type, char **name) { // free(tmp_name); } +// TODO, nothing is really being parsed here static void get_mfunction_print_type(void *type, char **name) { int name_len = 0; @@ -1367,12 +2026,12 @@ static void get_nesttype_print_type(void *type, char **name) { char *tmp_name = 0; int name_len = 0; int need_to_free = 1; - int base_type = 0; - base_type = ti->get_index (ti, (void **)&t); - if (!t) { - need_to_free = 0; - print_base_type (base_type, &tmp_name); + ti->get_index (ti, (void **)&t); + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { + need_to_free = false; + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; if (ti->get_print_type != NULL) { @@ -1438,36 +2097,17 @@ static void get_member_print_type(void *type, char **name) { STypeInfo *ti = (STypeInfo *) type; SType *t = 0; char *tmp_name = 0; - int name_len = 0; - int need_to_free = 1; - int base_type = 0; - base_type = ti->get_index (ti, (void **) &t); - if (!t) { - need_to_free = 0; - print_base_type (base_type, &tmp_name); + ti->get_index (ti, (void **) &t); + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); } - - name_len = strlen ("(member) "); if (tmp_name) { - name_len += strlen (tmp_name); - } - *name = (char *) malloc (name_len + 1); - if (!(*name)) { - if (need_to_free) R_FREE (tmp_name); - return; - } - // name[name_len] = '\0'; - strcpy(*name, "(member) "); - if (tmp_name) { - strcat (*name, tmp_name); - } - - if (need_to_free) { - R_FREE (tmp_name); + *name = tmp_name; } } @@ -1477,12 +2117,12 @@ static void get_onemethod_print_type(void *type, char **name) { char *tmp_name = 0; int name_len = 0; int need_to_free = 1; - int base_type = 0; - base_type = ti->get_index (ti, (void **)&t); - if (!t) { - need_to_free = 0; - print_base_type (base_type, &tmp_name); + ti->get_index (ti, (void **)&t); + if (t->type_data.leaf_type == eLF_SIMPLE_TYPE) { + need_to_free = false; + SLF_SIMPLE_TYPE *base_type = t->type_data.type_info; + tmp_name = base_type->type; } else { ti = &t->type_data; ti->get_print_type (ti, &tmp_name); @@ -1522,7 +2162,7 @@ void deinit_scstring(SCString *cstr) { } /////////////////////////////////////////////////////////////////////////////// -int parse_sctring(SCString *sctr, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) { +int parse_sctring(SCString *sctr, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int c = 0; sctr->name = NULL; sctr->size = 0; @@ -1540,7 +2180,7 @@ int parse_sctring(SCString *sctr, unsigned char *leaf_data, unsigned int *read_b } /////////////////////////////////////////////////////////////////////////////// -static int parse_sval(SVal *val, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_sval(SVal *val, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { val->name_or_val = 0; @@ -1657,7 +2297,7 @@ static int parse_sval(SVal *val, unsigned char *leaf_data, unsigned int *read_by } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_enumerate(SLF_ENUMERATE *lf_enumerate, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_enumerate(SLF_ENUMERATE *lf_enumerate, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int read_bytes_before = 0, tmp_read_bytes_before = 0; @@ -1673,15 +2313,11 @@ static int parse_lf_enumerate(SLF_ENUMERATE *lf_enumerate, unsigned char *leaf_d PEEK_READ1(*read_bytes, len, lf_enumerate->pad, leaf_data, ut8); PAD_ALIGN(lf_enumerate->pad, *read_bytes, leaf_data, len); -// printf("%s:", "parse_lf_enumerate()"); -// printf_sval_name(&lf_enumerate->enum_value); -// printf("\n"); - return (*read_bytes - read_bytes_before); } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_nesttype(SLF_NESTTYPE *lf_nesttype, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_nesttype(SLF_NESTTYPE *lf_nesttype, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int read_bytes_before = *read_bytes; @@ -1691,13 +2327,12 @@ static int parse_lf_nesttype(SLF_NESTTYPE *lf_nesttype, unsigned char *leaf_data READ4(*read_bytes, len, lf_nesttype->index, leaf_data, ut16); parse_sctring(&lf_nesttype->name, leaf_data, read_bytes, len); -// printf("parse_lf_nesttype(): name = %s\n", lf_nesttype->name.name); return *read_bytes - read_bytes_before; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_method(SLF_METHOD *lf_method, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_method(SLF_METHOD *lf_method, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int read_bytes_before = *read_bytes, tmp_read_bytes_before = 0; @@ -1713,13 +2348,11 @@ static int parse_lf_method(SLF_METHOD *lf_method, unsigned char *leaf_data, unsi PEEK_READ1(*read_bytes, len, lf_method->pad, leaf_data, ut8); PAD_ALIGN(lf_method->pad, *read_bytes, leaf_data, len); -// printf("parse_lf_method(): name = %s\n", lf_method->name.name); - return *read_bytes - read_bytes_before; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_member(SLF_MEMBER *lf_member, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_member(SLF_MEMBER *lf_member, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { int read_bytes_before = *read_bytes, tmp_read_bytes_before = 0; @@ -1735,15 +2368,11 @@ static int parse_lf_member(SLF_MEMBER *lf_member, unsigned char *leaf_data, unsi PEEK_READ1(*read_bytes, len, lf_member->pad, leaf_data, ut8); PAD_ALIGN(lf_member->pad, *read_bytes, leaf_data, len); -// printf("parse_lf_member(): name = "); -// printf_sval_name(&lf_member->offset); -// printf("\n"); - return (*read_bytes - read_bytes_before); } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_onemethod(SLF_ONEMETHOD *lf_onemethod, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_onemethod(SLF_ONEMETHOD *lf_onemethod, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { int read_bytes_before = *read_bytes, tmp_before_read_bytes = 0; @@ -1753,7 +2382,7 @@ static int parse_lf_onemethod(SLF_ONEMETHOD *lf_onemethod, unsigned char *leaf_d READ2(*read_bytes, len, lf_onemethod->fldattr.fldattr, leaf_data, ut16); READ4(*read_bytes, len, lf_onemethod->index, leaf_data, ut32); - lf_onemethod->fldattr.fldattr = SWAP_UINT16(lf_onemethod->fldattr.fldattr); + // lf_onemethod->fldattr.fldattr = SWAP_UINT16(lf_onemethod->fldattr.fldattr); if((lf_onemethod->fldattr.bits.mprop == eMTintro) || (lf_onemethod->fldattr.bits.mprop == eMTpureintro)) { @@ -1849,7 +2478,7 @@ static void init_stype_info(STypeInfo *type_info) type_info->get_arglist = get_mfunction_arglist; type_info->get_print_type = get_mfunction_print_type; break; - case eLF_METHODLIST: + case eLF_METHODLIST: // TODO missing stuff break; case eLF_PROCEDURE: type_info->get_return_type = get_procedure_return_type; @@ -1911,7 +2540,6 @@ static void init_stype_info(STypeInfo *type_info) type_info->get_print_type = get_onemethod_print_type; break; default: -// printf("init_stype_info(): unknown type for init\n"); type_info->get_name = 0; type_info->get_val = 0; type_info->get_name_len = 0; @@ -1950,11 +2578,11 @@ static void init_stype_info(STypeInfo *type_info) } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_fieldlist(SLF_FIELDLIST *lf_fieldlist, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_fieldlist(SLF_FIELDLIST *lf_fieldlist, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { ELeafType leaf_type; int curr_read_bytes = 0; - unsigned char *p = leaf_data; + uint8_t *p = leaf_data; lf_fieldlist->substructs = r_list_new (); @@ -1991,7 +2619,7 @@ static int parse_lf_fieldlist(SLF_FIELDLIST *lf_fieldlist, unsigned char *leaf_ } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_enum(SLF_ENUM *lf_enum, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_enum(SLF_ENUM *lf_enum, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; unsigned int before_read_bytes = 0; @@ -2003,7 +2631,7 @@ static int parse_lf_enum(SLF_ENUM *lf_enum, unsigned char *leaf_data, unsigned i READ4(*read_bytes, len, lf_enum->utype, leaf_data, ut32); READ4(*read_bytes, len, lf_enum->field_list, leaf_data, ut32); - lf_enum->prop.cv_property = SWAP_UINT16(lf_enum->prop.cv_property); + // lf_enum->prop.cv_property = SWAP_UINT16(lf_enum->prop.cv_property); before_read_bytes = *read_bytes; parse_sctring (&lf_enum->name, leaf_data, read_bytes, len); leaf_data += (*read_bytes - before_read_bytes); @@ -2011,14 +2639,12 @@ static int parse_lf_enum(SLF_ENUM *lf_enum, unsigned char *leaf_data, unsigned i PEEK_READ1(*read_bytes, len, lf_enum->pad, leaf_data, ut8); PAD_ALIGN(lf_enum->pad, *read_bytes, leaf_data, len); -// printf("parse_lf_enum(): name = %s\n", lf_enum->name.name); return *read_bytes - tmp_before_read_bytes; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_class(SLF_CLASS *lf_class, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_class(SLF_CLASS *lf_class, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { -// SLF_CLASS lf_class; unsigned int tmp_before_read_bytes = *read_bytes; unsigned int before_read_bytes = 0; @@ -2033,33 +2659,29 @@ static int parse_lf_class(SLF_CLASS *lf_class, unsigned char *leaf_data, unsigne before_read_bytes = *read_bytes; parse_sval(&lf_class->size, leaf_data, read_bytes, len); before_read_bytes = *read_bytes - before_read_bytes; - leaf_data = (unsigned char *)leaf_data + before_read_bytes; + leaf_data = (uint8_t *)leaf_data + before_read_bytes; PEEK_READ1(*read_bytes, len, lf_class->pad, leaf_data, ut8); PAD_ALIGN(lf_class->pad, *read_bytes, leaf_data, len); -// printf("%s:", "parse_lf_class()"); -// printf_sval_name(&lf_class->size); -// printf("\n"); return *read_bytes - tmp_before_read_bytes; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_structure(SLF_STRUCTURE *lf_structure, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_structure(SLF_STRUCTURE *lf_structure, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { // SLF_STRUCTURE lf_structure; unsigned int tmp_before_read_bytes = *read_bytes; unsigned int before_read_bytes = 0; lf_structure->size.name_or_val = 0; - READ2(*read_bytes, len, lf_structure->count, leaf_data, ut16); READ2(*read_bytes, len, lf_structure->prop.cv_property, leaf_data, ut16); READ4(*read_bytes, len, lf_structure->field_list, leaf_data, ut32); READ4(*read_bytes, len, lf_structure->derived, leaf_data, ut32); READ4(*read_bytes, len, lf_structure->vshape, leaf_data, ut32); - - lf_structure->prop.cv_property = SWAP_UINT16(lf_structure->prop.cv_property); + // Why flipping ?? Works just right without it + // lf_structure->prop.cv_property = SWAP_UINT16(lf_structure->prop.cv_property); before_read_bytes = *read_bytes; parse_sval(&lf_structure->size, leaf_data, read_bytes, len); @@ -2068,21 +2690,18 @@ static int parse_lf_structure(SLF_STRUCTURE *lf_structure, unsigned char *leaf_d PEEK_READ1(*read_bytes, len, lf_structure->pad, leaf_data, ut8); PAD_ALIGN(lf_structure->pad, *read_bytes, leaf_data, len); -// printf("parse_lf_structure(): name = "); -// printf_sval_name(&lf_structure->size); -// printf("\n"); return *read_bytes - tmp_before_read_bytes; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_pointer(SLF_POINTER *lf_pointer, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_pointer(SLF_POINTER *lf_pointer, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; READ4(*read_bytes, len, lf_pointer->utype, leaf_data, ut32); READ4(*read_bytes, len, lf_pointer->ptr_attr.ptr_attr, leaf_data, ut32); - lf_pointer->ptr_attr.ptr_attr = SWAP_UINT32(lf_pointer->ptr_attr.ptr_attr); + // lf_pointer->ptr_attr.ptr_attr = SWAP_UINT32(lf_pointer->ptr_attr.ptr_attr); PEEK_READ1(*read_bytes, len, lf_pointer->pad, leaf_data, ut8); PAD_ALIGN(lf_pointer->pad, *read_bytes, leaf_data, len); @@ -2091,7 +2710,7 @@ static int parse_lf_pointer(SLF_POINTER *lf_pointer, unsigned char *leaf_data, u } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_array(SLF_ARRAY *lf_array, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_array(SLF_ARRAY *lf_array, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; unsigned int before_read_bytes = 0; @@ -2108,20 +2727,19 @@ static int parse_lf_array(SLF_ARRAY *lf_array, unsigned char *leaf_data, unsigne PEEK_READ1(*read_bytes, len, lf_array->pad, leaf_data, ut8); PAD_ALIGN(lf_array->pad, *read_bytes, leaf_data, len); -// printf("parse_lf_array(): name = "); -// printf_sval_name(&lf_array->size); -// printf("\n"); return *read_bytes - tmp_before_read_bytes; } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_modifier(SLF_MODIFIER *lf_modifier, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_modifier(SLF_MODIFIER *lf_modifier, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; READ4(*read_bytes, len, lf_modifier->modified_type, leaf_data, ut32); READ2(*read_bytes, len, lf_modifier->umodifier.modifier, leaf_data, ut16); - lf_modifier->umodifier.modifier = SWAP_UINT16(lf_modifier->umodifier.modifier); + + // what is the reason for the swap vs modifying the bitfield so it is correct + // lf_modifier->umodifier.modifier = SWAP_UINT16(lf_modifier->umodifier.modifier); PEEK_READ1(*read_bytes, len, lf_modifier->pad, leaf_data, ut8); PAD_ALIGN(lf_modifier->pad, *read_bytes, leaf_data, len); @@ -2130,7 +2748,7 @@ static int parse_lf_modifier(SLF_MODIFIER *lf_modifier, unsigned char *leaf_data } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_arglist(SLF_ARGLIST *lf_arglist, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_arglist(SLF_ARGLIST *lf_arglist, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; @@ -2153,7 +2771,7 @@ static int parse_lf_arglist(SLF_ARGLIST *lf_arglist, unsigned char *leaf_data, u } /////////////////////////////////////////////////////////////////////////////// -static int parse_lf_mfunction(SLF_MFUNCTION *lf_mfunction, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) +static int parse_lf_mfunction(SLF_MFUNCTION *lf_mfunction, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; @@ -2172,7 +2790,7 @@ static int parse_lf_mfunction(SLF_MFUNCTION *lf_mfunction, unsigned char *leaf_d return *read_bytes - tmp_before_read_bytes; } -static int parse_lf_procedure(SLF_PROCEDURE *lf_procedure, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) { +static int parse_lf_procedure(SLF_PROCEDURE *lf_procedure, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; READ4(*read_bytes, len, lf_procedure->return_type, leaf_data, ut32); @@ -2187,7 +2805,7 @@ static int parse_lf_procedure(SLF_PROCEDURE *lf_procedure, unsigned char *leaf_d return *read_bytes - tmp_before_read_bytes; } -static int parse_lf_union(SLF_UNION *lf_union, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) { +static int parse_lf_union(SLF_UNION *lf_union, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; unsigned int before_read_bytes = 0; @@ -2200,18 +2818,15 @@ static int parse_lf_union(SLF_UNION *lf_union, unsigned char *leaf_data, unsigne before_read_bytes = *read_bytes; parse_sval(&lf_union->size, leaf_data, read_bytes, len); before_read_bytes = *read_bytes - before_read_bytes; - leaf_data = (unsigned char *)leaf_data + before_read_bytes; + leaf_data = (uint8_t *)leaf_data + before_read_bytes; PEEK_READ1(*read_bytes, len, lf_union->pad, leaf_data, ut8); PAD_ALIGN(lf_union->pad, *read_bytes, leaf_data, len); -// printf("%s:", "parse_lf_union()"); -// printf_sval_name(&lf_union->size); -// printf("\n"); return *read_bytes - tmp_before_read_bytes; } -static int parse_lf_bitfield(SLF_BITFIELD *lf_bitfield, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) { +static int parse_lf_bitfield(SLF_BITFIELD *lf_bitfield, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; READ4(*read_bytes, len, lf_bitfield->base_type, leaf_data, ut32); @@ -2224,7 +2839,7 @@ static int parse_lf_bitfield(SLF_BITFIELD *lf_bitfield, unsigned char *leaf_data return *read_bytes - tmp_before_read_bytes; } -static int parse_lf_vtshape(SLF_VTSHAPE *lf_vtshape, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len) { +static int parse_lf_vtshape(SLF_VTSHAPE *lf_vtshape, uint8_t *leaf_data, unsigned int *read_bytes, unsigned int len) { unsigned int tmp_before_read_bytes = *read_bytes; unsigned int size; // in bytes; @@ -2257,40 +2872,35 @@ static int parse_lf_vtshape(SLF_VTSHAPE *lf_vtshape, unsigned char *leaf_data, u /////////////////////////////////////////////////////////////////////////////// static int parse_tpi_stypes(R_STREAM_FILE *stream, SType *type) { - unsigned char *leaf_data; + uint8_t *leaf_data; unsigned int read_bytes = 0; stream_file_read(stream, 2, (char *)&type->length); if (type->length < 1) { return 0; } - leaf_data = (unsigned char *) malloc(type->length); + leaf_data = (uint8_t *) malloc(type->length); if (!leaf_data) { return 0; } stream_file_read (stream, type->length, (char *)leaf_data); - type->type_data.leaf_type = *(unsigned short *)leaf_data; + type->type_data.leaf_type = *(uint16_t *)leaf_data; read_bytes += 2; switch (type->type_data.leaf_type) { case eLF_FIELDLIST: -// printf("eLF_FIELDLIST\n"); PARSE_LF(SLF_FIELDLIST, lf_fieldlist); break; case eLF_ENUM: -// printf("eLF_ENUM\n"); PARSE_LF(SLF_ENUM, lf_enum); break; // TODO: combine with eLF_STRUCTURE case eLF_CLASS: -// printf("eLF_CLASS\n"); PARSE_LF(SLF_CLASS, lf_class); break; case eLF_STRUCTURE: -// printf("eLF_STRUCTURE\n"); PARSE_LF(SLF_STRUCTURE, lf_structure); break; case eLF_POINTER: -// printf("eLF_POINTER\n"); { SLF_POINTER *lf = (SLF_POINTER *) malloc(sizeof(SLF_POINTER)); \ if (!lf) { \ @@ -2304,38 +2914,29 @@ static int parse_tpi_stypes(R_STREAM_FILE *stream, SType *type) { // PARSE_LF(SLF_POINTER, lf_pointer); break; case eLF_ARRAY: -// printf("eLF_ARRAY\n"); PARSE_LF(SLF_ARRAY, lf_array); break; case eLF_MODIFIER: -// printf("eLF_MODIFIER\n"); PARSE_LF(SLF_MODIFIER, lf_modifier); break; case eLF_ARGLIST: -// printf("eLF_ARGLIST\n"); PARSE_LF(SLF_ARGLIST, lf_arglist); break; case eLF_MFUNCTION: -// printf("eLF_MFUNCTION\n"); PARSE_LF(SLF_MFUNCTION, lf_mfunction); break; case eLF_METHODLIST: -// printf("eLF_METHOD_LIST\n"); break; case eLF_PROCEDURE: -// printf("eLF_PROCEDURE\n"); PARSE_LF(SLF_PROCEDURE, lf_procedure); break; case eLF_UNION: -// printf("eLF_UNION\n"); PARSE_LF(SLF_UNION, lf_union); break; case eLF_BITFIELD: -// printf("eLF_BITFIELD\n"); PARSE_LF(SLF_BITFIELD, lf_bitfield); break; case eLF_VTSHAPE: -// printf("eLF_VTSHAPE\n"); PARSE_LF(SLF_VTSHAPE, lf_vtshape); break; default: @@ -2356,9 +2957,9 @@ int parse_tpi_stream(void *parsed_pdb_stream, R_STREAM_FILE *stream) { stream_file_read(stream, sizeof(STPIHeader), (char *)&tpi_stream->header); - base_idx = tpi_stream->header.ti_min; + base_idx = tpi_stream->header.idx_begin; - for (i = tpi_stream->header.ti_min; i < tpi_stream->header.ti_max; i++) { + for (i = tpi_stream->header.idx_begin; i < tpi_stream->header.idx_end; i++) { type = (SType *) malloc (sizeof (SType)); if (!type) { return 0; diff --git a/libr/bin/pdb/types.h b/libr/bin/pdb/types.h index 60558a256b..8bbcb7d37c 100644 --- a/libr/bin/pdb/types.h +++ b/libr/bin/pdb/types.h @@ -31,7 +31,7 @@ /////////////////////////////////////////////////////////////////////////////// #define CAN_READ(curr_read_bytes, bytes_for_read, max_len) { \ - if ((((curr_read_bytes) + (bytes_for_read)) >= (max_len))) { \ + if ((((curr_read_bytes) + (bytes_for_read)) > (max_len))) { \ return 0; \ } \ } @@ -125,19 +125,87 @@ typedef get_arg_type_ get_modified_type_; typedef get_value get_index_val; typedef get_value_name get_print_type_; +// start of refactoring the simple type to mode and kind typedef enum { - eT_NOTYPE = 0x00000000, + DIRECT = 0, // Not a pointer + NEAR_POINTER = 1, // Near pointer + FAR_POINTER = 2, // Far pointer + HUGE_POINTER = 3, // Huge pointer + NEAR_POINTER32 = 4, // 32 bit near pointer + FAR_POINTER32 = 5, // 32 bit far pointer + NEAR_POINTER64 = 6, // 64 bit near pointer + NEAR_POINTER128 = 7 // 128 bit near pointer +} SimpleTypeMode; + +typedef enum { + PDB_NONE = 0x0000, // uncharacterized type (no type) + PDB_VOID = 0x0003, // void + PDB_NOT_TRANSLATED = 0x0007, // type not translated by cvpack + PDB_HRESULT = 0x0008, // OLE/COM HRESULT + + PDB_SIGNED_CHAR = 0x0010, // 8 bit signed + PDB_UNSIGNED_CHAR = 0x0020, // 8 bit unsigned + PDB_NARROW_CHAR = 0x0070, // really a char + PDB_WIDE_CHAR = 0x0071, // wide char + PDB_CHAR16 = 0x007a, // char16_t + PDB_CHAR32 = 0x007b, // char32_t + + PDB_SBYTE = 0x0068, // 8 bit signed int + PDB_BYTE = 0x0069, // 8 bit unsigned int + PDB_INT16_SHORT = 0x0011, // 16 bit signed + PDB_UINT16_SHORT = 0x0021, // 16 bit unsigned + PDB_INT16 = 0x0072, // 16 bit signed int + PDB_UINT16 = 0x0073, // 16 bit unsigned int + PDB_INT32_LONG = 0x0012, // 32 bit signed + PDB_UINT32_LONG = 0x0022, // 32 bit unsigned + PDB_INT32 = 0x0074, // 32 bit signed int + PDB_UINT32 = 0x0075, // 32 bit unsigned int + PDB_INT64_QUAD = 0x0013, // 64 bit signed + PDB_UINT64_QUAD = 0x0023, // 64 bit unsigned + PDB_INT64 = 0x0076, // 64 bit signed int + PDB_UINT64 = 0x0077, // 64 bit unsigned int + PDB_INT128_OCT = 0x0014, // 128 bit signed int + PDB_UINT128_OCT = 0x0024, // 128 bit unsigned int + PDB_INT128 = 0x0078, // 128 bit signed int + PDB_UINT128 = 0x0079, // 128 bit unsigned int + + PDB_FLOAT16 = 0x0046, // 16 bit real + PDB_FLOAT32 = 0x0040, // 32 bit real + PDB_FLOAT32_PP = 0x0045, // 32 bit PP (partial precision) real + PDB_FLOAT48 = 0x0044, // 48 bit real + PDB_FLOAT64 = 0x0041, // 64 bit real + PDB_FLOAT80 = 0x0042, // 80 bit real + PDB_FLOAT128 = 0x0043, // 128 bit real + + PDB_COMPLEX16 = 0x0056, // 16 bit complex + PDB_COMPLEX32 = 0x0050, // 32 bit complex + PDB_COMPLEX32_PP = 0x0055, // 32 bit PP (partial precision) complex + PDB_COMPLEX48 = 0x0054, // 48 bit complex + PDB_COMPLEX64 = 0x0051, // 64 bit complex + PDB_COMPLEX80 = 0x0052, // 80 bit complex + PDB_COMPLEX128 = 0x0053, // 128 bit complex + + PDB_BOOL8 = 0x0030, // 8 bit boolean + PDB_BOOL16 = 0x0031, // 16 bit boolean + PDB_BOOL32 = 0x0032, // 32 bit boolean + PDB_BOOL64 = 0x0033, // 64 bit boolean + PDB_BOOL128 = 0x0034, // 128 bit boolean +} SimpleTypeKind; +// https://llvm.org/docs/PDB/TpiStream.html#type-indices +// This can be done smarter splitting it up on mode and kind +typedef enum { + eT_NOTYPE = 0x00000000, // uncharacterized type (no type) eT_ABS = 0x00000001, eT_SEGMENT = 0x00000002, - eT_VOID = 0x00000003, + eT_VOID = 0x00000003, // void - eT_HRESULT = 0x00000008, + eT_HRESULT = 0x00000008, // OLE/COM HRESULT eT_32PHRESULT = 0x00000408, eT_64PHRESULT = 0x00000608, - eT_PVOID = 0x00000103, - eT_PFVOID = 0x00000203, - eT_PHVOID = 0x00000303, + eT_PVOID = 0x00000103, // near ptr to void + eT_PFVOID = 0x00000203, // far ptr to void (4 bytes) + eT_PHVOID = 0x00000303, // huge ptr to void (4 bytes) eT_32PVOID = 0x00000403, eT_32PFVOID = 0x00000503, eT_64PVOID = 0x00000603, @@ -181,23 +249,23 @@ typedef enum { eT_32PFWCHAR = 0x00000571, eT_64PWCHAR = 0x00000671, - eT_INT1 = 0x00000068, - eT_PINT1 = 0x00000168, - eT_PFINT1 = 0x00000268, - eT_PHINT1 = 0x00000368, - eT_32PINT1 = 0x00000468, - eT_32PFINT1 = 0x00000568, - eT_64PINT1 = 0x00000668, + eT_BYTE = 0x00000068, + eT_PBYTE = 0x00000168, + eT_PFBYTE = 0x00000268, + eT_PHBYTE = 0x00000368, + eT_32PBYTE = 0x00000468, + eT_32PFBYTE = 0x00000568, + eT_64PBYTE = 0x00000668, - eT_UINT1 = 0x00000069, - eT_PUINT1 = 0x00000169, - eT_PFUINT1 = 0x00000269, - eT_PHUINT1 = 0x00000369, - eT_32PUINT1 = 0x00000469, - eT_32PFUINT1 = 0x00000569, - eT_64PUINT1 = 0x00000669, + eT_UBYTE = 0x00000069, + eT_PUBYTE = 0x00000169, + eT_PFUBYTE = 0x00000269, + eT_PHUBYTE = 0x00000369, + eT_32PUBYTE = 0x00000469, + eT_32PFUBYTE = 0x00000569, + eT_64PUBYTE = 0x00000669, - eT_SHORT = 0x00000011, + eT_SHORT = 0x00000011, // 16 bit short eT_PSHORT = 0x00000111, eT_PFSHORT = 0x00000211, eT_PHSHORT = 0x00000311, @@ -205,7 +273,7 @@ typedef enum { eT_32PFSHORT = 0x00000511, eT_64PSHORT = 0x00000611, - eT_USHORT = 0x00000021, + eT_USHORT = 0x00000021, // 16 bit short eT_PUSHORT = 0x00000121, eT_PFUSHORT = 0x00000221, eT_PHUSHORT = 0x00000321, @@ -213,23 +281,23 @@ typedef enum { eT_32PFUSHORT = 0x00000521, eT_64PUSHORT = 0x00000621, - eT_INT2 = 0x00000072, - eT_PINT2 = 0x00000172, - eT_PFINT2 = 0x00000272, - eT_PHINT2 = 0x00000372, - eT_32PINT2 = 0x00000472, - eT_32PFINT2 = 0x00000572, - eT_64PINT2 = 0x00000672, + eT_INT16 = 0x00000072, // 16 bit + eT_PINT16 = 0x00000172, + eT_PFINT16 = 0x00000272, + eT_PHINT16 = 0x00000372, + eT_32PINT16 = 0x00000472, + eT_32PFINT16 = 0x00000572, + eT_64PINT16 = 0x00000672, - eT_UINT2 = 0x00000073, - eT_PUINT2 = 0x00000173, - eT_PFUINT2 = 0x00000273, - eT_PHUINT2 = 0x00000373, - eT_32PUINT2 = 0x00000473, - eT_32PFUINT2 = 0x00000573, - eT_64PUINT2 = 0x00000673, + eT_UINT16 = 0x00000073, // 16 bit + eT_PUINT16 = 0x00000173, + eT_PFUINT16 = 0x00000273, + eT_PHUINT16 = 0x00000373, + eT_32PUINT16 = 0x00000473, + eT_32PFUINT16 = 0x00000573, + eT_64PUINT16 = 0x00000673, - eT_LONG = 0x00000012, + eT_LONG = 0x00000012, // 32 bit eT_PLONG = 0x00000112, eT_PFLONG = 0x00000212, eT_PHLONG = 0x00000312, @@ -261,7 +329,7 @@ typedef enum { eT_32PFUINT4 = 0x00000575, eT_64PUINT4 = 0x00000675, - eT_QUAD = 0x00000013, + eT_QUAD = 0x00000013, // 64 bit signed eT_PQUAD = 0x00000113, eT_PFQUAD = 0x00000213, eT_PHQUAD = 0x00000313, @@ -309,21 +377,21 @@ typedef enum { eT_32PFUOCT = 0x00000524, eT_64PUOCT = 0x00000624, - eT_INT16 = 0x00000078, - eT_PINT16 = 0x00000178, - eT_PFINT16 = 0x00000278, - eT_PHINT16 = 0x00000378, - eT_32PINT16 = 0x00000478, - eT_32PFINT16 = 0x00000578, - eT_64PINT16 = 0x00000678, + eT_INT128 = 0x00000078, + eT_PINT128 = 0x00000178, + eT_PFINT128 = 0x00000278, + eT_PHINT128 = 0x00000378, + eT_32PINT128 = 0x00000478, + eT_32PFINT128 = 0x00000578, + eT_64PINT128 = 0x00000678, - eT_UINT16 = 0x00000079, - eT_PUINT16 = 0x00000179, - eT_PFUINT16 = 0x00000279, - eT_PHUINT16 = 0x00000379, - eT_32PUINT16 = 0x00000479, - eT_32PFUINT16 = 0x00000579, - eT_64PUINT16 = 0x00000679, + eT_UINT128 = 0x00000079, + eT_PUINT128 = 0x00000179, + eT_PFUINT128 = 0x00000279, + eT_PHUINT128 = 0x00000379, + eT_32PUINT128 = 0x00000479, + eT_32PFUINT128 = 0x00000579, + eT_64PUINT128 = 0x00000679, eT_REAL32 = 0x00000040, eT_PREAL32 = 0x00000140, @@ -429,13 +497,21 @@ typedef enum { eT_32PFBOOL64 = 0x00000533, eT_64PBOOL64 = 0x00000633, + eT_BOOL128 = 0x00000034, + eT_PBOOL128 = 0x00000134, + eT_PFBOOL128 = 0x00000234, + eT_PHBOOL128 = 0x00000334, + eT_32PBOOL128 = 0x00000434, + eT_32PFBOOL128 = 0x00000534, + eT_64PBOOL128 = 0x00000634, + eT_NCVPTR = 0x000001F0, eT_FCVPTR = 0x000002F0, eT_HCVPTR = 0x000003F0, eT_32NCVPTR = 0x000004F0, eT_32FCVPTR = 0x000005F0, eT_64NCVPTR = 0x000006F0, -} EBASE_TYPES; +} PDB_SIMPLE_TYPES; typedef enum { eNEAR_C = 0x00000000, @@ -466,16 +542,20 @@ typedef enum { typedef union { struct { - ut8 scoped : 1; - ut8 reserved : 7; // swapped - ut8 packed : 1; - ut8 ctor : 1; - ut8 ovlops : 1; - ut8 isnested : 1; - ut8 cnested : 1; - ut8 opassign : 1; - ut8 opcast : 1; - ut8 fwdref : 1; + ut16 packed : 1; // true if structure is packed + ut16 ctor : 1; // true if constructors or destructors present + ut16 ovlops : 1; // true if overloaded operators present + ut16 isnested : 1; // true if this is a nested class + ut16 cnested : 1; // true if this class contains nested types + ut16 opassign : 1; // true if overloaded assignment (=) + ut16 opcast : 1; // true if casting methods + ut16 fwdref : 1; // true if forward reference (incomplete defn) + ut16 scoped : 1; // scoped definition + ut16 hasuniquename : 1; // true if there is a decorated name following the regular name + ut16 sealed : 1; // true if class cannot be used as a base class + ut16 hfa : 2; // CV_HFA_e + ut16 intrinsic : 1; // true if class is an intrinsic type (e.g. __m128d) + ut16 mocom : 2; // CV_MOCOM_UDT_e } bits; ut16 cv_property; } UCV_PROPERTY; @@ -498,25 +578,32 @@ typedef enum { eAccessMax } EACCESS; +// Struct to represent base types +typedef struct { + char *type; + ut32 size; + PDB_SIMPLE_TYPES simple_type; +} SLF_SIMPLE_TYPE; //### CodeView bitfields and enums //# NOTE: Construct assumes big-endian //# ordering for BitStructs typedef union { struct { - ut8 access : 2; - ut8 mprop : 3; - ut8 pseudo : 1; - ut8 noinherit : 1; - ut8 noconstruct : 1; - ut8 padding : 7; - ut8 compgenx : 1; + ut16 access : 2; // access protection CV_access_t + ut16 mprop : 3; // method properties CV_methodprop_t + ut16 pseudo : 1; // compiler generated fcn and does not exist + ut16 noinherit : 1; // true if class cannot be inherited + ut16 noconstruct : 1; // true if class cannot be constructed + ut16 compgenx : 1; // compiler generated fcn and does exist + ut16 sealed : 1; // true if method cannot be overridden + ut16 unused : 6; // unused } bits; ut16 fldattr; } UCV_fldattr; R_PACKED( typedef struct { - ut32 return_type; + ut16 return_type; ECV_CALL call_conv; ut8 reserved; ut16 parm_count; @@ -549,11 +636,10 @@ typedef struct { ut32 modified_type; union { struct { - ut8 pad2 : 8; - ut8 const_ : 1; - ut8 volatile_ : 1; - ut8 unaligned : 1; - ut8 pad1 : 5; + ut16 const_ : 1; + ut16 volatile_ : 1; + ut16 unaligned : 1; + ut16 unused : 13; } bits; ut16 modifier; } umodifier; @@ -590,15 +676,18 @@ typedef enum { R_PACKED( typedef union { struct { - ut8 pad[2]; - ut8 flat32 : 1; - ut8 volatile_ : 1; - ut8 const_ : 1; - ut8 unaligned : 1; - ut8 restrict_ : 1; - ut8 pad1 : 3; - ut8 type : 5; - ut8 mode : 3; + ut32 ptrtype : 5; // ordinal specifying pointer type + ut32 ptrmode : 3; // ordinal specifying pointer mode + ut32 flat32 : 1; // true if 0:32 pointer + ut32 volatile_ : 1; // TRUE if volatile pointer + ut32 const_ : 1; // TRUE if const pointer + ut32 unaligned : 1; // TRUE if unaligned pointer + ut32 restrict_ : 1; // TRUE if restricted pointer (allow agressive opts) + ut32 size : 6; // size of pointer (in bytes) + ut32 mocom : 1; // TRUE if it is a MoCOM pointer (^ or %) + ut32 lref : 1; // TRUE if it is this pointer of member function with & ref-qualifier + ut32 rref : 1; // TRUE if it is this pointer of member function with && ref-qualifier + ut32 unused : 10; // pad out to 32-bits for following cv_typ_t's } bits; ut32 ptr_attr; }) UPTR_ATTR; @@ -730,10 +819,10 @@ typedef struct { R_PACKED( typedef struct { ut16 count; - UCV_PROPERTY prop; - ut32 field_list; - ut32 derived; - ut32 vshape; + UCV_PROPERTY 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 SVal size; ut8 pad; }) SLF_STRUCTURE, SLF_CLASS; @@ -831,165 +920,172 @@ typedef struct { } SLF_FIELDLIST; typedef struct { - st32 off; - st32 cb; + st32 offset; + ut32 buff_len; } SOffCb; typedef struct { - st16 sn; - st16 padding; - st32 hash_key; + ut16 hash_stream_idx; + ut16 hash_aux_stream_idx; + st32 hash_key_size; st32 buckets; - SOffCb hash_vals; - SOffCb ti_off; + SOffCb hash_val; + SOffCb idx_off; SOffCb hash_adj; } STPI; typedef struct { ut32 version; - st32 hdr_size; - ut32 ti_min; - ut32 ti_max; + ut32 hdr_size; // should be ut32 + ut32 idx_begin; + ut32 idx_end; ut32 follow_size; STPI tpi; } STPIHeader; typedef enum { - eLF_MODIFIER_16t = 0x00000001, + eLF_MODIFIER_16t = 0x00000001, // type record for a generalized built-in type modifier eLF_POINTER_16t = 0x00000002, - eLF_ARRAY_16t = 0x00000003, + eLF_ARRAY_16t = 0x00000003, // type record for basic array eLF_CLASS_16t = 0x00000004, eLF_STRUCTURE_16t = 0x00000005, eLF_UNION_16t = 0x00000006, - eLF_ENUM_16t = 0x00000007, - eLF_PROCEDURE_16t = 0x00000008, - eLF_MFUNCTION_16t = 0x00000009, - eLF_VTSHAPE = 0x0000000A, - eLF_COBOL0_16t = 0x0000000B, - eLF_COBOL1 = 0x0000000C, - eLF_BARRAY_16t = 0x0000000D, + eLF_ENUM_16t = 0x00000007, // type record for LF_ENUM + eLF_PROCEDURE_16t = 0x00000008, // Type record for LF_PROCEDURE + eLF_MFUNCTION_16t = 0x00000009, // Type record for member function + eLF_VTSHAPE = 0x0000000A, // type record for virtual function table shape + eLF_COBOL0_16t = 0x0000000B, // type record for cobol0 + eLF_COBOL1 = 0x0000000C, // type record for cobol1 + eLF_BARRAY_16t = 0x0000000D, // type record for basic array eLF_LABEL = 0x0000000E, eLF_NULL = 0x0000000F, eLF_NOTTRAN = 0x00000010, - eLF_DIMARRAY_16t = 0x00000011, - eLF_VFTPATH_16t = 0x00000012, - eLF_PRECOMP_16t = 0x00000013, - eLF_ENDPRECOMP = 0x00000014, - eLF_OEM_16t = 0x00000015, - eLF_TYPESERVER_ST = 0x00000016, + eLF_DIMARRAY_16t = 0x00000011, // type record for dimensioned arrays + eLF_VFTPATH_16t = 0x00000012, // type record describing path to virtual function table + eLF_PRECOMP_16t = 0x00000013, // type record describing inclusion of precompiled types + eLF_ENDPRECOMP = 0x00000014, // type record describing end of precompiled types that can be + eLF_OEM_16t = 0x00000015, // type record for OEM definable type strings + eLF_TYPESERVER_ST = 0x00000016, // type record describing using of a type server eLF_SKIP_16t = 0x00000200, eLF_ARGLIST_16t = 0x00000201, eLF_DEFARG_16t = 0x00000202, eLF_LIST = 0x00000203, eLF_FIELDLIST_16t = 0x00000204, - eLF_DERIVED_16t = 0x00000205, - eLF_BITFIELD_16t = 0x00000206, - eLF_METHODLIST_16t = 0x00000207, - eLF_DIMCONU_16t = 0x00000208, - eLF_DIMCONLU_16t = 0x00000209, - eLF_DIMVARU_16t = 0x0000020A, - eLF_DIMVARLU_16t = 0x0000020B, - eLF_REFSYM = 0x0000020C, - eLF_BCLASS_16t = 0x00000400, - eLF_VBCLASS_16t = 0x00000401, + eLF_DERIVED_16t = 0x00000205, // derived class list leaf + eLF_BITFIELD_16t = 0x00000206, // type record for LF_BITFIELD + eLF_METHODLIST_16t = 0x00000207, // type record for non-static methods and friends in overloaded method list + eLF_DIMCONU_16t = 0x00000208, // type record for dimensioned array with constant bounds + eLF_DIMCONLU_16t = 0x00000209, // type record for dimensioned array with constant bounds + eLF_DIMVARU_16t = 0x0000020A, // type record for dimensioned array with variable bounds + eLF_DIMVARLU_16t = 0x0000020B, // type record for dimensioned array with variable bounds + eLF_REFSYM = 0x0000020C, // type record for referenced symbol + eLF_BCLASS_16t = 0x00000400, // subfield record for base class field + eLF_VBCLASS_16t = 0x00000401, // subfield record for direct and indirect virtual base class field eLF_IVBCLASS_16t = 0x00000402, - eLF_ENUMERATE_ST = 0x00000403, - eLF_FRIENDFCN_16t = 0x00000404, - eLF_INDEX_16t = 0x00000405, + eLF_ENUMERATE_ST = 0x00000403, // subfield record for enumerate + eLF_FRIENDFCN_16t = 0x00000404, // subfield record for friend function + eLF_INDEX_16t = 0x00000405, // index leaf - contains type index of another leaf eLF_MEMBER_16t = 0x00000406, eLF_STMEMBER_16t = 0x00000407, - eLF_METHOD_16t = 0x00000408, - eLF_NESTTYPE_16t = 0x00000409, - eLF_VFUNCTAB_16t = 0x0000040A, - eLF_FRIENDCLS_16t = 0x0000040B, - eLF_ONEMETHOD_16t = 0x0000040C, - eLF_VFUNCOFF_16t = 0x0000040D, + eLF_METHOD_16t = 0x00000408, // subfield record for overloaded method list + eLF_NESTTYPE_16t = 0x00000409, // type record for nested (scoped) type definition + eLF_VFUNCTAB_16t = 0x0000040A, // subfield record for virtual function table pointer + eLF_FRIENDCLS_16t = 0x0000040B, // subfield record for friend class + eLF_ONEMETHOD_16t = 0x0000040C, // subfield record for nonoverloaded method + eLF_VFUNCOFF_16t = 0x0000040D, // subfield record for virtual function table pointer with offset eLF_TI16_MAX = 0x00001000, - eLF_MODIFIER = 0x00001001, + eLF_MODIFIER = 0x00001001, // type record for a generalized built-in type modifier eLF_POINTER = 0x00001002, - eLF_ARRAY_ST = 0x00001003, + eLF_ARRAY_ST = 0x00001003, // type record for basic array eLF_CLASS_ST = 0x00001004, eLF_STRUCTURE_ST = 0x00001005, eLF_UNION_ST = 0x00001006, - eLF_ENUM_ST = 0x00001007, - eLF_PROCEDURE = 0x00001008, - eLF_MFUNCTION = 0x00001009, + eLF_ENUM_ST = 0x00001007, // type record for LF_ENUM + eLF_PROCEDURE = 0x00001008, // Type record for LF_PROCEDURE + eLF_MFUNCTION = 0x00001009, // Type record for member function eLF_COBOL0 = 0x0000100A, - eLF_BARRAY = 0x0000100B, - eLF_DIMARRAY_ST = 0x0000100C, - eLF_VFTPATH = 0x0000100D, - eLF_PRECOMP_ST = 0x0000100E, - eLF_OEM = 0x0000100F, + eLF_BARRAY = 0x0000100B, // type record for basic array + eLF_DIMARRAY_ST = 0x0000100C, // type record for dimensioned arrays + eLF_VFTPATH = 0x0000100D, // type record describing path to virtual function table + eLF_PRECOMP_ST = 0x0000100E, // type record describing inclusion of precompiled types + eLF_OEM = 0x0000100F, // type record for OEM definable type strings eLF_ALIAS_ST = 0x00001010, - eLF_OEM2 = 0x00001011, + eLF_OEM2 = 0x00001011, // type record for OEM definable type strings eLF_SKIP = 0x00001200, eLF_ARGLIST = 0x00001201, eLF_DEFARG_ST = 0x00001202, - eLF_FIELDLIST = 0x00001203, - eLF_DERIVED = 0x00001204, - eLF_BITFIELD = 0x00001205, - eLF_METHODLIST = 0x00001206, - eLF_DIMCONU = 0x00001207, - eLF_DIMCONLU = 0x00001208, - eLF_DIMVARU = 0x00001209, - eLF_DIMVARLU = 0x0000120A, - eLF_BCLASS = 0x00001400, - eLF_VBCLASS = 0x00001401, + eLF_FIELDLIST = 0x00001203, + eLF_DERIVED = 0x00001204, // derived class list leaf + eLF_BITFIELD = 0x00001205, // type record for LF_BITFIELD + eLF_METHODLIST = 0x00001206, // subfield record for overloaded method list + eLF_DIMCONU = 0x00001207, // type record for dimensioned array with constant bounds + eLF_DIMCONLU = 0x00001208, // type record for dimensioned array with constant bounds + eLF_DIMVARU = 0x00001209, // type record for dimensioned array with variable bounds + eLF_DIMVARLU = 0x0000120A, // type record for dimensioned array with variable bounds + eLF_BCLASS = 0x00001400, // subfield record for base class field + eLF_VBCLASS = 0x00001401, // subfield record for direct and indirect virtual base class field eLF_IVBCLASS = 0x00001402, - eLF_FRIENDFCN_ST = 0x00001403, + eLF_FRIENDFCN_ST = 0x00001403, // subfield record for friend function eLF_INDEX = 0x00001404, - eLF_MEMBER_ST = 0x00001405, + eLF_MEMBER_ST = 0x00001405, // subfield record for non-static data members eLF_STMEMBER_ST = 0x00001406, - eLF_METHOD_ST = 0x00001407, - eLF_NESTTYPE_ST = 0x00001408, - eLF_VFUNCTAB = 0x00001409, - eLF_FRIENDCLS = 0x0000140A, - eLF_ONEMETHOD_ST = 0x0000140B, - eLF_VFUNCOFF = 0x0000140C, - eLF_NESTTYPEEX_ST = 0x0000140D, - eLF_MEMBERMODIFY_ST = 0x0000140E, + eLF_METHOD_ST = 0x00001407, // subfield record for overloaded method list + eLF_NESTTYPE_ST = 0x00001408, // type record for nested (scoped) type definition + eLF_VFUNCTAB = 0x00001409, // subfield record for virtual function table pointer + eLF_FRIENDCLS = 0x0000140A, // subfield record for friend class + eLF_ONEMETHOD_ST = 0x0000140B, // subfield record for nonoverloaded method + eLF_VFUNCOFF = 0x0000140C, // subfield record for virtual function table pointer with offset + eLF_NESTTYPEEX_ST = 0x0000140D, // type record for nested (scoped) type definition, with attributes + eLF_MEMBERMODIFY_ST = 0x0000140E, // type record for modifications to members eLF_MANAGED_ST = 0x0000140F, eLF_ST_MAX = 0x00001500, - eLF_TYPESERVER = 0x00001501, - eLF_ENUMERATE = 0x00001502, - eLF_ARRAY = 0x00001503, + eLF_TYPESERVER = 0x00001501, // type record describing using of a type server + eLF_ENUMERATE = 0x00001502, // subfield record for enumerate + eLF_ARRAY = 0x00001503, // type record for basic array eLF_CLASS = 0x00001504, eLF_STRUCTURE = 0x00001505, eLF_UNION = 0x00001506, - eLF_ENUM = 0x00001507, - eLF_DIMARRAY = 0x00001508, - eLF_PRECOMP = 0x00001509, + eLF_ENUM = 0x00001507, // type record for LF_ENUM + eLF_DIMARRAY = 0x00001508, // type record for dimensioned arrays + eLF_PRECOMP = 0x00001509, // type record describing inclusion of precompiled types eLF_ALIAS = 0x0000150A, eLF_DEFARG = 0x0000150B, - eLF_FRIENDFCN = 0x0000150C, - eLF_MEMBER = 0x0000150D, + eLF_FRIENDFCN = 0x0000150C, // subfield record for friend function + eLF_MEMBER = 0x0000150D, // subfield record for non-static data members eLF_STMEMBER = 0x0000150E, - eLF_METHOD = 0x0000150F, - eLF_NESTTYPE = 0x00001510, - eLF_ONEMETHOD = 0x00001511, - eLF_NESTTYPEEX = 0x00001512, - eLF_MEMBERMODIFY = 0x00001513, + eLF_METHOD = 0x0000150F, // subfield record for overloaded method list + eLF_NESTTYPE = 0x00001510, // type record for nested (scoped) type definition + eLF_ONEMETHOD = 0x00001511, // subfield record for nonoverloaded method + eLF_NESTTYPEEX = 0x00001512, // type record for nested (scoped) type definition, with attributes + eLF_MEMBERMODIFY = 0x00001513, // type record for modifications to members eLF_MANAGED = 0x00001514, - eLF_TYPESERVER2 = 0x00001515, - eLF_CHAR = 0x00008000, - eLF_SHORT = 0x00008001, - eLF_USHORT = 0x00008002, - eLF_LONG = 0x00008003, - eLF_ULONG = 0x00008004, - eLF_REAL32 = 0x00008005, - eLF_REAL64 = 0x00008006, - eLF_REAL80 = 0x00008007, - eLF_REAL128 = 0x00008008, - eLF_QUADWORD = 0x00008009, - eLF_UQUADWORD = 0x0000800A, - eLF_REAL48 = 0x0000800B, - eLF_COMPLEX32 = 0x0000800C, - eLF_COMPLEX64 = 0x0000800D, - eLF_COMPLEX80 = 0x0000800E, - eLF_COMPLEX128 = 0x0000800F, - eLF_VARSTRING = 0x00008010, - eLF_OCTWORD = 0x00008017, - eLF_UOCTWORD = 0x00008018, + eLF_TYPESERVER2 = 0x00001515, // type record describing using of a type server with v7 (GUID) signatures + + /** the following are numeric leaves. They are used to indicate the + * size of the following variable length data. When the numeric + * data is a single byte less than 0x8000, then the data is output + * directly. If the data is more the 0x8000 or is a negative value, + * then the data is preceeded by the proper index. + */ + eLF_CHAR = 0x00008000, // signed character leaf + eLF_SHORT = 0x00008001, // signed short leaf + eLF_USHORT = 0x00008002, // unsigned short leaf + eLF_LONG = 0x00008003, // signed long leaf + eLF_ULONG = 0x00008004, // unsigned long leaf + eLF_REAL32 = 0x00008005, // real 32-bit leaf + eLF_REAL64 = 0x00008006, // real 64-bit leaf + eLF_REAL80 = 0x00008007, // real 80-bit leaf + eLF_REAL128 = 0x00008008, // real 128-bit leaf + eLF_QUADWORD = 0x00008009, // signed quad leaf + eLF_UQUADWORD = 0x0000800A, // unsigned quad leaf + eLF_REAL48 = 0x0000800B, // real 48-bit leaf + eLF_COMPLEX32 = 0x0000800C, // complex 32-bit leaf + eLF_COMPLEX64 = 0x0000800D, // complex 64-bit leaf + eLF_COMPLEX80 = 0x0000800E, // complex 80-bit leaf + eLF_COMPLEX128 = 0x0000800F, // complex 128-bit leaf + eLF_VARSTRING = 0x00008010, // variable length numeric field + eLF_OCTWORD = 0x00008017, // signed int128 leaf + eLF_UOCTWORD = 0x00008018, // unsigned int128 leaf eLF_DECIMAL = 0x00008019, eLF_DATE = 0x0000801A, eLF_UTF8STRING = 0x0000801B, @@ -1009,6 +1105,7 @@ typedef enum { eLF_PAD13 = 0x000000FD, eLF_PAD14 = 0x000000FE, eLF_PAD15 = 0x000000FF, + eLF_SIMPLE_TYPE = 0xEFFFFFFF, // Custom, hopefully it doesn't collide eLF_MAX = 0xFFFFFFFF } ELeafType; diff --git a/libr/core/cbin.c b/libr/core/cbin.c index d4ff20b31d..b16b13d7f1 100644 --- a/libr/core/cbin.c +++ b/libr/core/cbin.c @@ -1190,7 +1190,7 @@ static int bin_dwarf(RCore *core, int mode) { } R_API int r_core_pdb_info(RCore *core, const char *file, ut64 baddr, int mode) { - R_PDB pdb = R_EMPTY; + RPdb pdb = R_EMPTY; pdb.cb_printf = r_cons_printf; if (!init_pdb_parser (&pdb, file)) { @@ -1201,9 +1201,6 @@ R_API int r_core_pdb_info(RCore *core, const char *file, ut64 baddr, int mode) { pdb.finish_pdb_parse (&pdb); return false; } - if (mode == R_MODE_JSON) { - r_cons_printf ("["); - } switch (mode) { case R_MODE_SET: @@ -1221,17 +1218,18 @@ R_API int r_core_pdb_info(RCore *core, const char *file, ut64 baddr, int mode) { mode = 'd'; // default break; } + PJ *pj = pj_new (); - pdb.print_types (&pdb, mode); - if (mode == 'j') { - r_cons_printf (","); - } - pdb.print_gvars (&pdb, baddr, mode); - if (mode == 'j') { - r_cons_printf ("]"); - } + pdb.print_types (&pdb, pj, mode); + pdb.print_gvars (&pdb, baddr, pj, mode); + // Save compound types into SDB + r_parse_pdb_types (core->anal, &pdb); pdb.finish_pdb_parse (&pdb); + if (mode == 'j') { + r_cons_printf ("%s\n", pj_string (pj)); + } + pj_free (pj); return true; } diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 8768b221c9..7494503bb0 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -245,7 +245,7 @@ typedef struct r_anal_base_type_enum_t { typedef struct r_anal_base_type_t { char *name; - char *type; // Used by typedef, atomic type + char *type; // Used by typedef, atomic type, enum ut64 size; // size of the whole type in bits RAnalBaseTypeKind kind; union { @@ -2065,7 +2065,9 @@ R_API RAnalEsilDFG *r_anal_esil_dfg_expr(RAnal *anal, RAnalEsilDFG *dfg, const c R_API RStrBuf *r_anal_esil_dfg_filter(RAnalEsilDFG *dfg, const char *reg); R_API RStrBuf *r_anal_esil_dfg_filter_expr(RAnal *anal, const char *expr, const char *reg); R_API RList *r_anal_types_from_fcn(RAnal *anal, RAnalFunction *fcn); + R_API RAnalBaseType *r_anal_get_base_type(RAnal *anal, const char *name); +R_API void r_parse_pdb_types(const RAnal *anal, const RPdb *pdb); R_API void r_anal_save_base_type(const RAnal *anal, const RAnalBaseType *type); R_API void r_anal_free_base_type(RAnalBaseType *type); R_API RAnalBaseType *r_anal_new_base_type(RAnalBaseTypeKind kind); diff --git a/libr/include/r_pdb.h b/libr/include/r_pdb.h index 5f67b23fd4..254da9a8df 100644 --- a/libr/include/r_pdb.h +++ b/libr/include/r_pdb.h @@ -11,13 +11,12 @@ extern "C" { #define FILE_NAME_LEN 256 -struct R_PDB; struct R_PDB7_ROOT_STREAM; -typedef struct R_PDB { - bool (*pdb_parse)(struct R_PDB *pdb); - void (*finish_pdb_parse)(struct R_PDB *pdb); - void (*print_types)(struct R_PDB *pdb, int mode); +typedef struct r_pdb_t { + bool (*pdb_parse)(struct r_pdb_t *pdb); + void (*finish_pdb_parse)(struct r_pdb_t *pdb); + void (*print_types)(const struct r_pdb_t *pdb, PJ *pj, int mode); // FILE *fp; PrintfCallback cb_printf; struct R_PDB7_ROOT_STREAM *root_stream; @@ -27,11 +26,11 @@ typedef struct R_PDB { RBuffer *buf; // mmap of file // int curr; - void (*print_gvars)(struct R_PDB *pdb, ut64 img_base, int format); -} R_PDB; + void (*print_gvars)(struct r_pdb_t *pdb, ut64 img_base, PJ *pj, int format); +} RPdb; -R_API bool init_pdb_parser(R_PDB *pdb, const char *filename); -R_API bool init_pdb_parser_with_buf(R_PDB *pdb, RBuffer *buf); +R_API bool init_pdb_parser(RPdb *pdb, const char *filename); +R_API bool init_pdb_parser_with_buf(RPdb *pdb, RBuffer *buf); #ifdef __cplusplus } diff --git a/test/db/formats/pdb b/test/db/formats/pdb index d59431b811..f7dda5fb9e 100644 --- a/test/db/formats/pdb +++ b/test/db/formats/pdb @@ -68,17 +68,17 @@ RUN NAME=member1 type of structure R2_TEST_STRUCT FILE=bins/pdb/Project1.pdb -CMDS=!rabin2 -P ${R2_FILE} | grep r2_struct_var_1 | grep -ao long +CMDS=!rabin2 -P ${R2_FILE} | grep r2_struct_var_1 | grep -ao int32_t EXPECT=< +#include "minunit.h" +#include +#include +#include +#include "../../libr/bin/pdb/types.h" + +#define MODE 2 + +#define check_kv(k, v) \ + do { \ + char *value = sdb_get (anal->sdb_types, k, NULL); \ + mu_assert_nullable_streq (value, v, "Wrong key - value pair"); \ + } while (0) + +// copy from cbin.c modified to get pdb back +int pdb_info(const char *file, RPdb *pdb) { + pdb->cb_printf = r_cons_printf; + if (!init_pdb_parser (pdb, file)) { + return false; + } + if (!pdb->pdb_parse (pdb)) { + eprintf ("pdb was not parsed\n"); + pdb->finish_pdb_parse (pdb); + return false; + } + return true; +} + +int pdb_info_save_types(RAnal *anal, const char *file, RPdb *pdb) { + pdb->cb_printf = r_cons_printf; + if (!init_pdb_parser (pdb, file)) { + return false; + } + if (!pdb->pdb_parse (pdb)) { + eprintf ("pdb was not parsed\n"); + pdb->finish_pdb_parse (pdb); + return false; + } + r_parse_pdb_types (anal, pdb); + pdb->finish_pdb_parse (pdb); + return true; +} + +bool test_pdb_tpi_cpp(void) { + RPdb pdb = R_EMPTY; + mu_assert_true (pdb_info ("bins/pdb/Project1.pdb", &pdb), "pdb parsing failed"); + + RList *plist = pdb.pdb_streams; + mu_assert_notnull (plist, "PDB streams is NULL"); + + mu_assert_eq (pdb.root_stream->num_streams, 50, "Incorrect number of streams"); + + STpiStream *tpi_stream = r_list_get_n (plist, ePDB_STREAM_TPI); + mu_assert_notnull (tpi_stream, "TPIs stream not found in current PDB"); + mu_assert_eq (tpi_stream->header.hdr_size + tpi_stream->header.follow_size, 117156, "Wrong TPI size"); + mu_assert_eq (tpi_stream->header.idx_begin, 0x1000, "Wrong beginning index"); + + // tpi_stream->header. + mu_assert_eq (tpi_stream->types->length, 1148, "Incorrect number of types"); + RListIter *it = r_list_iterator (tpi_stream->types); + SType *type; + while (r_list_iter_next (it)) { + type = r_list_iter_get (it); + STypeInfo *type_info = &type->type_data; + if (type->tpi_idx == 0x1028) { + mu_assert_eq (type_info->leaf_type, eLF_PROCEDURE, "Incorrect data type"); + SType *arglist; + type_info->get_arglist (type_info, (void **)&arglist); + mu_assert_eq (arglist->tpi_idx, 0x1027, "Wrong type index"); + SType *return_type; + type_info->get_return_type (type_info, (void **)&return_type); + mu_assert_eq (return_type->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = return_type->type_data.type_info; + mu_assert_eq (simple_type->size, 4, "Incorrect return type"); + mu_assert_streq (simple_type->type, "int32_t", "Incorrect return type"); + } else if (type->tpi_idx == 0x1161) { + mu_assert_eq (type_info->leaf_type, eLF_POINTER, "Incorrect data type"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "struct _RTC_framedesc*", "Wrong pointer print type"); + } else if (type->tpi_idx == 0x1004) { + mu_assert_eq (type_info->leaf_type, eLF_STRUCTURE, "Incorrect data type"); + int forward_ref = 0; + type->type_data.is_fwdref (type_info, &forward_ref); + mu_assert_eq (forward_ref, 1, "Wrong fwdref"); + } else if (type->tpi_idx == 0x113F) { + mu_assert_eq (type_info->leaf_type, eLF_ARRAY, "Incorrect data type"); + char *type; + type_info->get_print_type (type_info, &type); + SType *dump; + type_info->get_index_type (type_info, (void **)&dump); + mu_assert_eq (dump->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = dump->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_ULONG, "Incorrect return type"); + mu_assert_eq (simple_type->size, 4, "Incorrect return type"); + mu_assert_streq (simple_type->type, "uint32_t", "Incorrect return type"); + type_info->get_element_type (type_info, (void **)&dump); + mu_assert_eq (dump->tpi_idx, 0x113E, "Wrong element type index"); + int size; + type_info->get_val (type_info, &size); + mu_assert_eq (size, 20, "Wrong array size"); + } else if (type->tpi_idx == 0x145A) { + mu_assert_eq (type_info->leaf_type, eLF_ENUM, "Incorrect data type"); + SType *dump; + RList *members; + char *name; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "EXCEPTION_DEBUGGER_ENUM", "wrong enum name"); + type_info->get_utype (type_info, (void **)&dump); + mu_assert_eq (dump->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = dump->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_INT4, "Incorrect return type"); + mu_assert_eq (simple_type->size, 4, "Incorrect return type"); + mu_assert_streq (simple_type->type, "int32_t", "Incorrect return type"); + type_info->get_members (type_info, &members); + mu_assert_eq (members->length, 6, "wrong enum members length"); + } else if (type->tpi_idx == 0x1414) { + mu_assert_eq (type_info->leaf_type, eLF_VTSHAPE, "Incorrect data type"); + } else if (type->tpi_idx == 0x1421) { + mu_assert_eq (type_info->leaf_type, eLF_MODIFIER, "Incorrect data type"); + SType *stype = NULL; + type_info->get_modified_type (type_info, (void **)&stype); + mu_assert_eq (stype->tpi_idx, 0x120F, "Incorrect modified type"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "const struct Stream", "Incorrect modifier print type"); + } else if (type->tpi_idx == 0x1003) { + mu_assert_eq (type_info->leaf_type, eLF_UNION, "Incorrect data type"); + char *name; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "R2_TEST_UNION", "wrong union name"); + RList *members; + type_info->get_members (type_info, &members); + mu_assert_eq (members->length, 2, "wrong union member count"); + } else if (type->tpi_idx == 0x100B) { + mu_assert_eq (type_info->leaf_type, eLF_CLASS, "Incorrect data type"); + char *name; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "TEST_CLASS", "wrong class name"); + RList *members; + type_info->get_members (type_info, &members); + mu_assert_eq (members->length, 2, "wrong class member count"); + SType *stype = NULL; + int result = type_info->get_vshape (type_info, (void **)&stype); + mu_assert_eq (result || stype, 0, "wrong class vshape"); + result = type_info->get_derived (type_info, (void **)&stype); + mu_assert_eq (result || stype, 0, "wrong class derived"); + } else if (type->tpi_idx == 0x1062) { + mu_assert_eq (type_info->leaf_type, eLF_BITFIELD, "Incorrect data type"); + SType *base_type = NULL; + type_info->get_base_type (type_info, (void **)&base_type); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "bitfield uint32_t : 1", "Incorrect bitfield print type"); + } else if (type->tpi_idx == 0x1258) { + mu_assert_eq (type_info->leaf_type, eLF_METHODLIST, "Incorrect data type"); + // Nothing from methodlist is currently being parsed + } else if (type->tpi_idx == 0x107A) { + mu_assert_eq (type_info->leaf_type, eLF_MFUNCTION, "Incorrect data type"); + SType *type; + type_info->get_return_type (type_info, (void **)&type); + mu_assert_eq (type->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = type->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_BOOL08, "Incorrect return type"); + mu_assert_eq (simple_type->size, 1, "Incorrect return type"); + mu_assert_streq (simple_type->type, "_Bool", "Incorrect return type"); + type_info->get_class_type (type_info, (void **)&type); + mu_assert_eq (type->tpi_idx, 0x1079, "incorrect mfunction class type"); + type_info->get_this_type (type_info, (void **)&type); + mu_assert_eq (type, 0, "incorrect mfunction this type"); + type_info->get_arglist (type_info, (void **)&type); + mu_assert_eq (type->tpi_idx, 0x1027, "incorrect mfunction arglist"); + } else if (type->tpi_idx == 0x113F) { + mu_assert_eq (type_info->leaf_type, eLF_FIELDLIST, "Incorrect data type"); + RList *members = r_list_new (); + type_info->get_members (&type->type_data, &members); + mu_assert_eq (members->length, 2725, "Incorrect members length"); + RListIter *it = r_list_iterator (members); + int i = 0; + while (r_list_iter_next (it)) { + STypeInfo *type_info = (STypeInfo *)r_list_iter_get (it); + mu_assert_eq (type_info->leaf_type, eLF_ENUMERATE, "Incorrect data type"); + if (i == 0) { + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "CV_ALLREG_ERR", "Wrong enum name"); + int value = 0; + type_info->get_val (type_info, &value); + mu_assert_eq (value, 30000, "Wrong enumerate value"); + } + if (i == 2724) { + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "CV_AMD64_YMM15D3", "Wrong enum name"); + int value = 0; + type_info->get_val (type_info, &value); + mu_assert_eq (value, 687, "Wrong enumerate value"); + } + i++; + } + } else if (type->tpi_idx == 0x1231) { + mu_assert_eq (type_info->leaf_type, eLF_ARGLIST, "Incorrect data type"); + } else if (type->tpi_idx == 0x101A) { + mu_assert_eq (type_info->leaf_type, eLF_STRUCTURE, "Incorrect data type"); + SType *return_type; + char *name; + int is_forward_ref; + type_info->get_name (&type->type_data, &name); + mu_assert_streq (name, "threadlocaleinfostruct", "Wrong name"); + type_info->is_fwdref (&type->type_data, &is_forward_ref); + mu_assert_eq (is_forward_ref, false, "Wrong is_fwdref"); + RList *members = r_list_new (); + type_info->get_members (&type->type_data, &members); + mu_assert_eq (members->length, 18, "Incorrect members count"); + RListIter *it = r_list_iterator (members); + int i = 0; + while (r_list_iter_next (it)) { + STypeInfo *type_info = (STypeInfo *)r_list_iter_get (it); + if (i == 0) { + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "refcount", "Wrong member name"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "int32_t", "Wrong member type"); + } + if (i == 1) { + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "lc_codepage", "Wrong member name"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "uint32_t", "Wrong member type"); + } + if (i == 17) { + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "locale_name", "Wrong method name"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "wchar_t *[24]", "Wrong method type"); + } + i++; + } + } + }; + pdb.finish_pdb_parse (&pdb); + mu_end; +} + +bool test_pdb_tpi_rust(void) { + RPdb pdb = R_EMPTY; + mu_assert_true (pdb_info ("bins/pdb/ghidra_rust_pdb_bug.pdb", &pdb), "pdb parsing failed"); + + RList *plist = pdb.pdb_streams; + mu_assert_notnull (plist, "PDB streams is NULL"); + + mu_assert_eq (pdb.root_stream->num_streams, 88, "Incorrect number of streams"); + + STpiStream *tpi_stream = r_list_get_n (plist, ePDB_STREAM_TPI); + mu_assert_notnull (tpi_stream, "TPIs stream not found in current PDB"); + mu_assert_eq (tpi_stream->header.hdr_size + tpi_stream->header.follow_size, 305632, "Wrong TPI size"); + mu_assert_eq (tpi_stream->header.idx_begin, 0x1000, "Wrong beginning index"); + + // tpi_stream->header. + mu_assert_eq (tpi_stream->types->length, 4031, "Incorrect number of types"); + RListIter *it = r_list_iterator (tpi_stream->types); + SType *type; + while (r_list_iter_next (it)) { + type = r_list_iter_get (it); + STypeInfo *type_info = &type->type_data; + if (type->tpi_idx == 0x101B) { + mu_assert_eq (type_info->leaf_type, eLF_PROCEDURE, "Incorrect data type"); + SType *arglist; + type_info->get_arglist (type_info, (void **)&arglist); + mu_assert_eq (arglist->tpi_idx, 0x101A, "Wrong type index"); + SType *return_type; + type_info->get_return_type (type_info, (void **)&return_type); + mu_assert_eq (return_type->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = return_type->type_data.type_info; + mu_assert_eq (simple_type->size, 4, "Incorrect return type"); + mu_assert_streq (simple_type->type, "int32_t", "Incorrect return type"); + } else if (type->tpi_idx == 0x1163) { + mu_assert_eq (type_info->leaf_type, eLF_POINTER, "Incorrect data type"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "struct core::fmt::Void*", "Wrong pointer print type"); + } else if (type->tpi_idx == 0x1005) { + mu_assert_eq (type_info->leaf_type, eLF_STRUCTURE, "Incorrect data type"); + int forward_ref = 0; + type->type_data.is_fwdref (type_info, &forward_ref); + mu_assert_eq (forward_ref, 1, "Wrong fwdref"); + } else if (type->tpi_idx == 0x114A) { + mu_assert_eq (type_info->leaf_type, eLF_ARRAY, "Incorrect data type"); + SType *dump; + + type_info->get_index_type (type_info, (void **)&dump); + mu_assert_eq (dump->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = dump->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_UQUAD, "Incorrect return type"); + mu_assert_eq (simple_type->size, 8, "Incorrect return type"); + mu_assert_streq (simple_type->type, "uint64_t", "Incorrect return type"); + type_info->get_element_type (type_info, (void **)&dump); + + mu_assert_eq (dump->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + simple_type = dump->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_UCHAR, "Incorrect return type"); + mu_assert_eq (simple_type->size, 1, "Incorrect return type"); + mu_assert_streq (simple_type->type, "uint8_t", "Incorrect return type"); + + int size; + type_info->get_val (type_info, &size); + mu_assert_eq (size, 16, "Wrong array size"); + } else if (type->tpi_idx == 0x1FB4) { + mu_assert_eq (type_info->leaf_type, eLF_ENUM, "Incorrect data type"); + SType *dump; + RList *members; + char *name; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "ISA_AVAILABILITY", "wrong enum name"); + type_info->get_utype (type_info, (void **)&dump); + mu_assert_eq (dump->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = dump->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_INT4, "Incorrect return type"); + mu_assert_eq (simple_type->size, 4, "Incorrect return type"); + mu_assert_streq (simple_type->type, "int32_t", "Incorrect return type"); + type_info->get_members (type_info, &members); + mu_assert_eq (members->length, 10, "wrong enum members length"); + } else if (type->tpi_idx == 0x1E31) { + mu_assert_eq (type_info->leaf_type, eLF_VTSHAPE, "Incorrect data type"); + } else if (type->tpi_idx == 0x1FB7) { + mu_assert_eq (type_info->leaf_type, eLF_MODIFIER, "Incorrect data type"); + SType *stype = NULL; + type_info->get_modified_type (type_info, (void **)&stype); + mu_assert_eq (stype->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect modified type"); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "const volatile uint64_t", "Incorrect modifier print type"); + // } else if (type->tpi_idx == 0x1F4E) { This whole thing isn't parsed correctly for some reason TODO + // mu_assert_eq (type_info->leaf_type, eLF_UNION, "Incorrect data type"); + // char *name; + // type_info->get_name (type_info, &name); + // mu_assert_streq (name, "_SLIST_HEADER", "wrong union name"); + // RList *members; + // type_info->get_members (type_info, &members); + // mu_assert_eq (members->length, 3, "wrong union member count"); + // // mu_assert_eq (members->length, 4, "wrong union member count"); // Doesn't work, missing one (last) member for some reason TODO + // int size = 0; + // type_info->get_val (type_info, &size); + // // mu_assert_eq (size, 48, " Wrong union size"); // parse wrong should be 48, is 16 + // mu_assert_eq (size, 16, " Wrong union size"); + } else if (type->tpi_idx == 0x1EA9) { + mu_assert_eq (type_info->leaf_type, eLF_CLASS, "Incorrect data type"); + char *name; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "std::bad_typeid", "wrong class name"); + RList *members; + type_info->get_members (type_info, &members); + // mu_assert_eq (members->length, 7, "wrong class member count"); // These members (fieldlist) isn't properly parsed? + SType *stype = NULL; + int result = type_info->get_vshape (type_info, (void **)&stype); + mu_assert_eq (result || stype, 1, "wrong class vshape"); + result = type_info->get_derived (type_info, (void **)&stype); + mu_assert_eq (result || stype, 0, "wrong class derived"); + } else if (type->tpi_idx == 0x1F50) { + mu_assert_eq (type_info->leaf_type, eLF_BITFIELD, "Incorrect data type"); + SType *base_type = NULL; + type_info->get_base_type (type_info, (void **)&base_type); + char *type; + type_info->get_print_type (type_info, &type); + mu_assert_streq (type, "bitfield uint64_t : 48", "Incorrect bitfield print type"); + } else if (type->tpi_idx == 0x1E27) { + mu_assert_eq (type_info->leaf_type, eLF_METHODLIST, "Incorrect data type"); + // Nothing from methodlist is currently being parsed + } else if (type->tpi_idx == 0x181C) { + mu_assert_eq (type_info->leaf_type, eLF_MFUNCTION, "Incorrect data type"); + SType *type; + type_info->get_return_type (type_info, (void **)&type); + mu_assert_eq (type->type_data.leaf_type, eLF_SIMPLE_TYPE, "Incorrect return type"); + SLF_SIMPLE_TYPE *simple_type = type->type_data.type_info; + mu_assert_eq (simple_type->simple_type, eT_VOID, "Incorrect return type"); + mu_assert_eq (simple_type->size, 0, "Incorrect return type"); + mu_assert_streq (simple_type->type, "void", "Incorrect return type"); + type_info->get_class_type (type_info, (void **)&type); + mu_assert_eq (type->tpi_idx, 0x107F, "incorrect mfunction class type"); + type_info->get_this_type (type_info, (void **)&type); + mu_assert_eq (type, 0, "incorrect mfunction this type"); + type_info->get_arglist (type_info, (void **)&type); + mu_assert_eq (type->tpi_idx, 0x1000, "incorrect mfunction arglist"); + } else if (type->tpi_idx == 0x13BF) { + mu_assert_eq (type_info->leaf_type, eLF_FIELDLIST, "Incorrect data type"); + // check size + RList *members = r_list_new (); + type_info->get_members (&type->type_data, &members); + mu_assert_eq (members->length, 3, "Incorrect members length"); + RListIter *it = r_list_iterator (members); + int i = 0; + while (r_list_iter_next (it)) { + STypeInfo *type_info = (STypeInfo *)r_list_iter_get (it); + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + if (i == 0) { + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "RUST$ENUM$DISR", "Wrong member name"); + // get type + } + if (i == 2) { + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "__0", "Wrong member name"); + // get type + } + i++; + } + } else if (type->tpi_idx == 0x1164) { + mu_assert_eq (type_info->leaf_type, eLF_ARGLIST, "Incorrect data type"); + } else if (type->tpi_idx == 0x1058) { + mu_assert_eq (type_info->leaf_type, eLF_STRUCTURE, "Incorrect data type"); + SType *return_type; + char *name; + type_info->get_name (&type->type_data, &name); + mu_assert_streq (name, "std::thread::local::fast::Key>>>", "Wrong name"); + + int is_forward_ref; + type_info->is_fwdref (&type->type_data, &is_forward_ref); + mu_assert_eq (is_forward_ref, false, "Wrong is_fwdref"); + + int size = 0; + type_info->get_val (type_info, &size); + mu_assert_eq (size, 24, "Wrong struct size"); + + RList *members = r_list_new (); + type_info->get_members (&type->type_data, &members); + mu_assert_eq (members->length, 2, "Incorrect members count"); + + RListIter *it = r_list_iterator (members); + int i = 0; + while (r_list_iter_next (it)) { + STypeInfo *type_info = (STypeInfo *)r_list_iter_get (it); + if (i == 0) { + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "inner", "Wrong member name"); + // todo add type idx + } + if (i == 1) { + mu_assert_eq (type_info->leaf_type, eLF_MEMBER, "Incorrect data type"); + char *name = NULL; + type_info->get_name (type_info, &name); + mu_assert_streq (name, "dtor_state", "Wrong member name"); + } + i++; + } + } + }; + pdb.finish_pdb_parse (&pdb); + mu_end; +} + +bool test_pdb_type_save(void) { + RPdb pdb = R_EMPTY; + RAnal *anal = r_anal_new (); + mu_assert_true (pdb_info_save_types (anal, "bins/pdb/Project1.pdb", &pdb), "pdb parsing failed"); + check_kv ("R2_TEST_ENUM", "enum"); + check_kv ("enum.R2_TEST_ENUM", "eENUM1_R2,eENUM2_R2,eENUM_R2_MAX"); + check_kv ("enum.R2_TEST_ENUM.0x10", "eENUM1_R2"); + check_kv ("enum.R2_TEST_ENUM.eENUM1_R2", "0x10"); + + check_kv ("R2_TEST_UNION", "union"); + check_kv ("union.R2_TEST_UNION", "r2_union_var_1,r2_union_var_2"); + check_kv ("union.R2_TEST_UNION.r2_union_var_1", "int32_t,0,0"); + check_kv ("union.R2_TEST_UNION.r2_union_var_2", "double,0,0"); + check_kv ("union.R2_TEST_UNION.!size", "8"); + + check_kv ("__m64", "union"); + check_kv ("union.__m64", "m64_u64,m64_f32,m64_i8,m64_i16,m64_i32,m64_i64,m64_u8,m64_u16,m64_u32"); + check_kv ("union.__m64.m64_u64", "uint64_t,0,0"); + check_kv ("union.__m64.m64_f32", "float[8],0,0"); + check_kv ("union.__m64.m64_i8", "char[8],0,0"); + check_kv ("union.__m64.m64_i16", "uint16_t[8],0,0"); + check_kv ("union.__m64.m64_i32", "int32_t[8],0,0"); + check_kv ("union.__m64.m64_i64", "int64_t,0,0"); + check_kv ("union.__m64.m64_u8", "uint8_t[8],0,0"); + check_kv ("union.__m64.m64_u16", "uint16_t[8],0,0"); + check_kv ("union.__m64.m64_u32", "uint32_t[8],0,0"); + check_kv ("union.__m64.!size", "8"); + + check_kv ("TEST_CLASS", "struct"); + check_kv ("struct.TEST_CLASS", "class_var1,calss_var2"); + check_kv ("struct.TEST_CLASS.class_var1", "int32_t,0,0"); + check_kv ("struct.TEST_CLASS.calss_var2", "uint16_t,4,0"); + check_kv ("union.__m64.!size", "8"); + + check_kv ("localeinfo_struct", "struct"); + check_kv ("struct.localeinfo_struct", "locinfo,mbcinfo"); + check_kv ("struct.localeinfo_struct.locinfo", "struct threadlocaleinfostruct*,0,0"); + check_kv ("struct.localeinfo_struct.mbcinfo", "struct threadmbcinfostruct*,4,0"); + check_kv ("union.__m64.!size", "8"); + r_anal_free (anal); + mu_end; +} + +bool all_tests() { + mu_run_test (test_pdb_tpi_cpp); + mu_run_test (test_pdb_tpi_rust); + mu_run_test (test_pdb_type_save); + return tests_passed != tests_run; +} + +int main(int argc, char **argv) { + return all_tests (); +} \ No newline at end of file