Improving PDB type information parsing and saving types into SDB (#17226)

This commit is contained in:
HoundThe 2020-07-24 19:40:55 +02:00 committed by GitHub
parent f338c2b2bb
commit eac93216ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2791 additions and 1158 deletions

View File

@ -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

17
libr/anal/base_types.h Normal file
View File

@ -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

View File

@ -33,6 +33,7 @@ r_anal_sources = [
'sign.c',
'switch.c',
'type.c',
'type_pdb.c',
'type_dwarf.c',
'value.c',
'var.c',

View File

@ -3,6 +3,7 @@
#include <r_anal.h>
#include <string.h>
#include <sdb.h>
#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;

View File

@ -1,7 +1,8 @@
#include <r_anal.h>
#include "base_types.h"
#include <sdb.h>
#include <string.h>
#include <r_anal.h>
#include <r_bin_dwarf.h>
#include <string.h>
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;
}
}

277
libr/anal/type_pdb.c Normal file
View File

@ -0,0 +1,277 @@
#include <r_bin.h>
#include <r_core.h>
#include <r_anal.h>
#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);
}
}
}

View File

@ -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[] =
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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
}

View File

@ -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=<<EOF
long
int32_t
EOF
RUN
NAME=member2 type of structure R2_TEST_STRUCT
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep r2_struct_var_2 | grep -ao short
CMDS=!rabin2 -P ${R2_FILE} | grep r2_struct_var_2 | grep -ao uint16_t
EXPECT=<<EOF
short
uint16_t
EOF
RUN
@ -90,22 +90,6 @@ EXPECT=<<EOF
EOF
RUN
NAME=member1 offset of union R2_TEST_UNION
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep r2_union_var_1 | grep -ao 0x0
EXPECT=<<EOF
0x0
EOF
RUN
NAME=member2 offset of union R2_TEST_UNION
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep r2_union_var_2 | grep -ao 0x0
EXPECT=<<EOF
0x0
EOF
RUN
NAME=member1 name of union R2_TEST_UNION
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep -ao r2_union_var_1
@ -124,9 +108,9 @@ RUN
NAME=member1 type of union R2_TEST_UNION
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep r2_union_var_1 | grep -ao long
CMDS=!rabin2 -P ${R2_FILE} | grep r2_union_var_1 | grep -ao int32_t
EXPECT=<<EOF
long
int32_t
EOF
RUN
@ -146,97 +130,6 @@ EXPECT=<<EOF
EOF
RUN
NAME=member1 value of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep eENUM1_R2 | grep -ao 0x10
EXPECT=<<EOF
0x10
EOF
RUN
NAME=member2 value of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep eENUM2_R2 | grep -ao 0x20
EXPECT=<<EOF
0x20
EOF
RUN
NAME=member3 vlue of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep eENUM_R2_MAX | grep -ao 0x21
EXPECT=<<EOF
0x21
EOF
RUN
NAME=member1 name of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep -ao eENUM1_R2
EXPECT=<<EOF
eENUM1_R2
eENUM1_R2
EOF
RUN
NAME=member2 name of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep -ao eENUM2_R2
EXPECT=<<EOF
eENUM2_R2
eENUM2_R2
EOF
RUN
NAME=member3 name of enum R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep -ao eENUM_R2_MAX
EXPECT=<<EOF
eENUM_R2_MAX
eENUM_R2_MAX
EOF
RUN
NAME=check size of union R2_TEST_ENUM
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -P ${R2_FILE} | grep R2_TEST_ENUM | grep -ao 0x0
EXPECT=<<EOF
0x0
EOF
RUN
NAME=enumerate export test
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep -ao R2_TEST_ENUM
EXPECT=<<EOF
R2_TEST_ENUM
EOF
RUN
NAME=enumerate value1 export test
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep -ao eENUM1_R2=0x10
EXPECT=<<EOF
eENUM1_R2=0x10
EOF
RUN
NAME=enumerate value2 export test
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep -ao eENUM2_R2=0x20
EXPECT=<<EOF
eENUM2_R2=0x20
EOF
RUN
NAME=enumerate value3 export test
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep -ao eENUM_R2_MAX=0x21
EXPECT=<<EOF
eENUM_R2_MAX=0x21
EOF
RUN
NAME=redirection test
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep -ao _unnamed_tag_ | head -n1
@ -263,9 +156,9 @@ RUN
NAME=struct export types
FILE=bins/pdb/Project1.pdb
CMDS=!rabin2 -Pr ${R2_FILE} | grep R2_TEST_STRUCT | grep -ao iw
CMDS=!rabin2 -Pr ${R2_FILE} | grep R2_TEST_STRUCT | grep -ao n4n2
EXPECT=<<EOF
iw
n4n2
EOF
RUN

517
test/unit/test_pdb.c Normal file
View File

@ -0,0 +1,517 @@
#include <r_util.h>
#include "minunit.h"
#include <r_bin.h>
#include <r_core.h>
#include <r_bin_dwarf.h>
#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<core::cell::Cell<core::option::Option<core::ptr::non_null::NonNull<core::task::wake::Context>>>>", "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 ();
}