mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-26 22:50:48 +00:00
Improving PDB type information parsing and saving types into SDB (#17226)
This commit is contained in:
parent
f338c2b2bb
commit
eac93216ec
@ -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
17
libr/anal/base_types.h
Normal 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
|
@ -33,6 +33,7 @@ r_anal_sources = [
|
||||
'sign.c',
|
||||
'switch.c',
|
||||
'type.c',
|
||||
'type_pdb.c',
|
||||
'type_dwarf.c',
|
||||
'value.c',
|
||||
'var.c',
|
||||
|
@ -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;
|
||||
|
@ -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
277
libr/anal/type_pdb.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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[] =
|
||||
{
|
||||
|
1154
libr/bin/pdb/pdb.c
1154
libr/bin/pdb/pdb.c
File diff suppressed because it is too large
Load Diff
1283
libr/bin/pdb/tpi.c
1283
libr/bin/pdb/tpi.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
517
test/unit/test_pdb.c
Normal 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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user