Rewrite and extend type paths from offset
Tests and extends deriving paths into types at a given offset in the following ways: - Parameter for limiting the depth of the path - Array support, e.g. `.member[5].anothermember` - Typedef support - Paths can be taken from arbitrary RzTypes, not only RzBaseType - Removed the typename in the beginning of paths, which can be added by the caller if needed
This commit is contained in:
parent
ff778e7507
commit
3e75e1f6c7
6 changed files with 704 additions and 137 deletions
|
|
@ -107,55 +107,6 @@ struct TListMeta {
|
|||
ut64 offset;
|
||||
};
|
||||
|
||||
// TODO: Also resolve pointers and arrays
|
||||
static bool type_paths_collect_by_offset_cb(void *user, ut64 k, const void *v) {
|
||||
rz_return_val_if_fail(user && v, false);
|
||||
struct TListMeta *tl = (struct TListMeta *)user;
|
||||
RzType *t = (RzType *)v;
|
||||
// Handle only identifiers here
|
||||
if (t->kind != RZ_TYPE_KIND_IDENTIFIER) {
|
||||
return true;
|
||||
}
|
||||
if (!t->identifier.name) {
|
||||
return true;
|
||||
}
|
||||
// Get the base type
|
||||
RzBaseType *btype = rz_type_db_get_base_type(tl->typedb, t->identifier.name);
|
||||
if (!btype) {
|
||||
return true;
|
||||
}
|
||||
if (btype->kind == RZ_BASE_TYPE_KIND_STRUCT || btype->kind == RZ_BASE_TYPE_KIND_UNION) {
|
||||
RzList *list = rz_type_path_by_offset(tl->typedb, btype, tl->offset);
|
||||
if (list) {
|
||||
rz_list_join(tl->l, list);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the list of all structured types that are linked and have members matching the offset
|
||||
*
|
||||
* \param analysis RzAnalysis instance
|
||||
* \param offset The offset of the member to match against
|
||||
*/
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_analysis_type_links_by_offset(RzAnalysis *analysis, ut64 offset) {
|
||||
rz_return_val_if_fail(analysis, NULL);
|
||||
if (offset == UT64_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
RzList *typepaths = rz_list_new();
|
||||
struct TListMeta tl = {
|
||||
.typedb = analysis->typedb,
|
||||
.l = typepaths,
|
||||
.addr = 0,
|
||||
.offset = offset
|
||||
};
|
||||
ht_up_foreach(analysis->type_links, type_paths_collect_by_offset_cb, &tl);
|
||||
return typepaths;
|
||||
}
|
||||
|
||||
// TODO: Also resolve pointers and arrays
|
||||
static bool type_paths_collect_by_address_cb(void *user, ut64 k, const void *v) {
|
||||
rz_return_val_if_fail(user && v, false);
|
||||
struct TListMeta *tl = (struct TListMeta *)user;
|
||||
|
|
@ -184,26 +135,60 @@ static bool type_paths_collect_by_address_cb(void *user, ut64 k, const void *v)
|
|||
return true;
|
||||
}
|
||||
if (btype->kind == RZ_BASE_TYPE_KIND_STRUCT || btype->kind == RZ_BASE_TYPE_KIND_UNION) {
|
||||
RzList *list = rz_type_path_by_offset(tl->typedb, btype, offset);
|
||||
RzList *list = rz_base_type_path_by_offset(tl->typedb, btype, offset, 1);
|
||||
if (list) {
|
||||
rz_list_join(tl->l, list);
|
||||
RzListIter *iter;
|
||||
RzTypePath *path;
|
||||
list->free = NULL;
|
||||
rz_list_foreach (list, iter, path) {
|
||||
if (!path->path) {
|
||||
rz_type_path_free(path);
|
||||
continue;
|
||||
}
|
||||
char *s = rz_str_newf("%s%s", btype->name, path->path);
|
||||
if (!s) {
|
||||
rz_type_path_free(path);
|
||||
continue;
|
||||
}
|
||||
free(path->path);
|
||||
path->path = s;
|
||||
RzTypePathTuple *tpl = RZ_NEW(RzTypePathTuple);
|
||||
if (!tpl) {
|
||||
rz_type_path_free(path);
|
||||
continue;
|
||||
}
|
||||
tpl->path = path;
|
||||
tpl->root = rz_type_identifier_of_base_type(tl->typedb, btype, false);
|
||||
rz_list_append(tl->l, tpl);
|
||||
}
|
||||
rz_list_free(list);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void type_path_tuple_free(void *p) {
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
RzTypePathTuple *tuple = p;
|
||||
rz_type_path_free(tuple->path);
|
||||
rz_type_free(tuple->root);
|
||||
free(tuple);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the list of all type paths that are linked to some address and have suitable offset
|
||||
*
|
||||
* \param analysis RzAnalysis instance
|
||||
* \param addr The address to check against possible matches
|
||||
*/
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_analysis_type_paths_by_address(RzAnalysis *analysis, ut64 addr) {
|
||||
RZ_API RZ_OWN RzList /*<RzTypePathTuple *>*/ *rz_analysis_type_paths_by_address(RzAnalysis *analysis, ut64 addr) {
|
||||
rz_return_val_if_fail(analysis, NULL);
|
||||
if (addr == UT64_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
RzList *typepaths = rz_list_new();
|
||||
RzList *typepaths = rz_list_newf(type_path_tuple_free);
|
||||
struct TListMeta tl = {
|
||||
.typedb = analysis->typedb,
|
||||
.l = typepaths,
|
||||
|
|
|
|||
|
|
@ -647,21 +647,22 @@ beach:
|
|||
return;
|
||||
}
|
||||
|
||||
static void set_offset_hint(RzCore *core, RzAnalysisOp *op, RZ_BORROW RzTypePath *tpath, ut64 laddr, ut64 at, int offimm) {
|
||||
static void set_offset_hint(RzCore *core, RzAnalysisOp *op, RZ_BORROW RzTypePathTuple *tpath, ut64 laddr, ut64 at, int offimm) {
|
||||
rz_return_if_fail(core && op && tpath);
|
||||
if (tpath->typ->kind != RZ_TYPE_KIND_IDENTIFIER) {
|
||||
if (tpath->root->kind != RZ_TYPE_KIND_IDENTIFIER) {
|
||||
return;
|
||||
}
|
||||
char *cmt = (offimm == 0) ? strdup(tpath->path) : rz_type_as_string(core->analysis->typedb, tpath->typ);
|
||||
char *cmt = (offimm == 0) ? strdup(tpath->path->path) : rz_type_as_string(core->analysis->typedb, tpath->root);
|
||||
if (offimm > 0) {
|
||||
// Set only the type path as the analysis hint
|
||||
// only and only if the types are the exact match between
|
||||
// possible member offset and the type linked to the laddr
|
||||
RzList *paths = rz_analysis_type_paths_by_address(core->analysis, laddr + offimm);
|
||||
if (paths && rz_list_length(paths)) {
|
||||
RzTypePath *link = rz_list_get_top(paths);
|
||||
rz_analysis_hint_set_offset(core->analysis, at, link->path);
|
||||
RzTypePathTuple *link = rz_list_get_top(paths);
|
||||
rz_analysis_hint_set_offset(core->analysis, at, link->path->path);
|
||||
}
|
||||
rz_list_free(paths);
|
||||
} else if (cmt && rz_analysis_op_ismemref(op->type)) {
|
||||
rz_meta_set_string(core->analysis, RZ_META_TYPE_VARTYPE, at, cmt);
|
||||
}
|
||||
|
|
@ -685,33 +686,37 @@ static void resolve_type_links(RzCore *core, ut64 at, struct TLAnalysisContext *
|
|||
RzList *vlinks = rz_analysis_type_paths_by_address(core->analysis, ctx->src_addr + ctx->src_imm);
|
||||
// TODO: Handle register based arg for struct offset propgation
|
||||
if (vlinks && rz_list_length(vlinks) && ctx->var && ctx->var->kind != 'r') {
|
||||
RzTypePath *vlink = rz_list_get_top(vlinks);
|
||||
RzTypePathTuple *vlink = rz_list_get_top(vlinks);
|
||||
// FIXME: For now we only propagate simple type identifiers,
|
||||
// no pointers or arrays
|
||||
if (vlink->typ->kind == RZ_TYPE_KIND_IDENTIFIER) {
|
||||
if (!vlink->typ->identifier.name) {
|
||||
if (vlink->root->kind == RZ_TYPE_KIND_IDENTIFIER) {
|
||||
if (!vlink->root->identifier.name) {
|
||||
rz_warn_if_reached();
|
||||
return;
|
||||
}
|
||||
RzBaseType *varbtype = rz_type_db_get_base_type(core->analysis->typedb, vlink->typ->identifier.name);
|
||||
RzBaseType *varbtype = rz_type_db_get_base_type(core->analysis->typedb, vlink->root->identifier.name);
|
||||
if (varbtype) {
|
||||
// if a var addr matches with struct , change it's type and name
|
||||
// var int local_e0h --> var struct foo
|
||||
// if (strcmp(var->name, vlink) && !*resolved) {
|
||||
if (!*resolved) {
|
||||
*resolved = true;
|
||||
rz_analysis_var_set_type(ctx->var, vlink->typ, true);
|
||||
rz_analysis_var_rename(ctx->var, vlink->typ->identifier.name, false);
|
||||
rz_analysis_var_set_type(ctx->var, vlink->root, true);
|
||||
rz_analysis_var_rename(ctx->var, vlink->root->identifier.name, false);
|
||||
vlink->root = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (slinks && rz_list_length(slinks)) {
|
||||
RzTypePath *slink = rz_list_get_top(slinks);
|
||||
RzTypePathTuple *slink = rz_list_get_top(slinks);
|
||||
set_offset_hint(core, ctx->aop, slink, ctx->src_addr, at - ret, ctx->src_imm);
|
||||
} else if (dlinks && rz_list_length(dlinks)) {
|
||||
RzTypePath *dlink = rz_list_get_top(dlinks);
|
||||
RzTypePathTuple *dlink = rz_list_get_top(dlinks);
|
||||
set_offset_hint(core, ctx->aop, dlink, ctx->dst_addr, at - ret, ctx->dst_imm);
|
||||
}
|
||||
rz_list_free(slinks);
|
||||
rz_list_free(dlinks);
|
||||
rz_list_free(vlinks);
|
||||
}
|
||||
|
||||
RZ_API void rz_core_link_stroff(RzCore *core, RzAnalysisFunction *fcn) {
|
||||
|
|
|
|||
|
|
@ -1629,8 +1629,7 @@ RZ_API bool rz_analysis_type_set_link(RzAnalysis *analysis, RZ_OWN RzType *type,
|
|||
RZ_API bool rz_analysis_type_unlink(RzAnalysis *analysis, ut64 addr);
|
||||
RZ_API bool rz_analysis_type_unlink_all(RzAnalysis *analysis);
|
||||
RZ_API RZ_OWN RzList /*<RzType *>*/ *rz_analysis_type_links(RzAnalysis *analysis);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_analysis_type_links_by_offset(RzAnalysis *analysis, ut64 offset);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_analysis_type_paths_by_address(RzAnalysis *analysis, ut64 addr);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePathTuple *>*/ *rz_analysis_type_paths_by_address(RzAnalysis *analysis, ut64 addr);
|
||||
|
||||
/* project */
|
||||
RZ_API bool rz_analysis_xrefs_init(RzAnalysis *analysis);
|
||||
|
|
|
|||
|
|
@ -172,10 +172,16 @@ struct rz_type_t {
|
|||
};
|
||||
|
||||
typedef struct rz_type_path_t {
|
||||
RzType *typ;
|
||||
RzType *typ; ///< type at the leaf
|
||||
char *path;
|
||||
} RzTypePath;
|
||||
|
||||
/// A path and the type that the path came from
|
||||
typedef struct rz_type_path_tuple_t {
|
||||
RzTypePath *path;
|
||||
RzType *root;
|
||||
} RzTypePathTuple;
|
||||
|
||||
/**
|
||||
* \brief Type Conditions
|
||||
*/
|
||||
|
|
@ -304,7 +310,8 @@ RZ_API RZ_OWN RzBaseType *rz_type_typeclass_get_default_sized(const RzTypeDB *ty
|
|||
RZ_API RZ_OWN RzTypePath *rz_type_path_new(RZ_BORROW RZ_NONNULL RzType *type, RZ_OWN RZ_NONNULL char *path);
|
||||
RZ_API void rz_type_path_free(RZ_NULLABLE RzTypePath *tpath);
|
||||
RZ_API st64 rz_type_offset_by_path(const RzTypeDB *typedb, RZ_NONNULL const char *path);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_path_by_offset(const RzTypeDB *typedb, RzBaseType *btype, ut64 offset);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_base_type_path_by_offset(const RzTypeDB *typedb, const RzBaseType *btype, ut64 offset, unsigned int max_depth);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_path_by_offset(const RzTypeDB *typedb, const RzType *type, ut64 offset, unsigned int max_depth);
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_db_get_by_offset(const RzTypeDB *typedb, ut64 offset);
|
||||
RZ_API ut64 rz_type_db_struct_member_packed_offset(RZ_NONNULL const RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_NONNULL const char *member);
|
||||
RZ_API ut64 rz_type_db_struct_member_offset(RZ_NONNULL const RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_NONNULL const char *member);
|
||||
|
|
|
|||
|
|
@ -122,91 +122,140 @@ RZ_API st64 rz_type_offset_by_path(const RzTypeDB *typedb, RZ_NONNULL const char
|
|||
return path_walker(typedb, path);
|
||||
}
|
||||
|
||||
// TODO: Handle arrays
|
||||
static bool structured_member_walker(const RzTypeDB *typedb, RzList /*<RzTypePath *>*/ *list, RzType *parent, RzType *type, char *path, ut64 offset) {
|
||||
rz_return_val_if_fail(list && type, false);
|
||||
if (type->kind != RZ_TYPE_KIND_IDENTIFIER) {
|
||||
return false;
|
||||
static void collect_type_paths(const RzTypeDB *typedb, RzList /*<RzTypePath *>*/ *list, const RzType *type, char *prefix, ut64 offset, unsigned int depth);
|
||||
|
||||
static void collect_base_type_paths(const RzTypeDB *typedb, RzList /*<RzTypePath *>*/ *list, const RzBaseType *btype, char *prefix, ut64 offset, unsigned int depth) {
|
||||
rz_return_if_fail(typedb && list && btype && prefix);
|
||||
if (!depth) {
|
||||
return;
|
||||
}
|
||||
rz_return_val_if_fail(type->identifier.name, false);
|
||||
bool result = true;
|
||||
if (type->identifier.kind == RZ_TYPE_IDENTIFIER_KIND_STRUCT) {
|
||||
// Get the base type
|
||||
RzBaseType *btype = rz_type_db_get_base_type(typedb, type->identifier.name);
|
||||
if (!btype) {
|
||||
return false;
|
||||
}
|
||||
switch (btype->kind) {
|
||||
case RZ_BASE_TYPE_KIND_STRUCT: {
|
||||
RzTypeStructMember *memb;
|
||||
ut64 memb_offset = 0;
|
||||
rz_vector_foreach(&btype->struct_data.members, memb) {
|
||||
if (memb_offset == offset) {
|
||||
RzTypePath *tpath = rz_type_path_new(parent, rz_str_newf("%s.%s.%s", path, btype->name, memb->name));
|
||||
RzTypePath *tpath = rz_type_path_new(memb->type, rz_str_newf("%s.%s", prefix, memb->name));
|
||||
if (tpath) {
|
||||
rz_list_append(list, tpath);
|
||||
}
|
||||
}
|
||||
char *newpath = rz_str_newf("%s.%s", path, memb->name);
|
||||
result &= structured_member_walker(typedb, list, parent, memb->type, newpath, memb_offset + offset);
|
||||
memb_offset += rz_type_db_get_bitsize(typedb, memb->type) / 8;
|
||||
free(newpath);
|
||||
}
|
||||
} else if (type->identifier.kind == RZ_TYPE_IDENTIFIER_KIND_UNION) {
|
||||
// Get the base type
|
||||
RzBaseType *btype = rz_type_db_get_base_type(typedb, type->identifier.name);
|
||||
if (!btype) {
|
||||
return false;
|
||||
ut64 bytesz = rz_type_db_get_bitsize(typedb, memb->type) / 8;
|
||||
if (memb_offset + bytesz > offset) {
|
||||
char *newpath = rz_str_newf("%s.%s", prefix, memb->name);
|
||||
collect_type_paths(typedb, list, memb->type, newpath, offset - memb_offset, depth - 1);
|
||||
free(newpath);
|
||||
break;
|
||||
}
|
||||
memb_offset += bytesz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RZ_BASE_TYPE_KIND_UNION: {
|
||||
RzTypeUnionMember *memb;
|
||||
rz_vector_foreach(&btype->union_data.members, memb) {
|
||||
char *newpath = rz_str_newf("%s.%s", path, memb->name);
|
||||
result &= structured_member_walker(typedb, list, parent, memb->type, path, offset);
|
||||
char *newpath = rz_str_newf("%s.%s", prefix, memb->name);
|
||||
if (offset == 0) {
|
||||
RzTypePath *tpath = rz_type_path_new(memb->type, newpath);
|
||||
if (tpath) {
|
||||
rz_list_append(list, tpath);
|
||||
}
|
||||
}
|
||||
collect_type_paths(typedb, list, memb->type, newpath, offset, depth - 1);
|
||||
if (offset != 0) {
|
||||
free(newpath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RZ_BASE_TYPE_KIND_TYPEDEF: {
|
||||
RzType *ttype = rz_type_db_base_type_unwrap_typedef(typedb, btype);
|
||||
if (!ttype) {
|
||||
return;
|
||||
}
|
||||
collect_type_paths(typedb, list, ttype, prefix, offset, depth); // depth not decreased because this is not a visible step in the path
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void collect_type_paths(const RzTypeDB *typedb, RzList /*<RzTypePath *>*/ *list, const RzType *type, char *prefix, ut64 offset, unsigned int depth) {
|
||||
rz_return_if_fail(typedb && list && type && prefix);
|
||||
if (!depth) {
|
||||
return;
|
||||
}
|
||||
switch (type->kind) {
|
||||
case RZ_TYPE_KIND_IDENTIFIER: {
|
||||
rz_return_if_fail(type->identifier.name);
|
||||
RzBaseType *btype = rz_type_db_get_base_type(typedb, type->identifier.name);
|
||||
if (!btype) {
|
||||
return;
|
||||
}
|
||||
collect_base_type_paths(typedb, list, btype, prefix, offset, depth); // depth not decreased because this is not a visible step in the path
|
||||
break;
|
||||
}
|
||||
case RZ_TYPE_KIND_ARRAY: {
|
||||
rz_return_if_fail(type->array.type);
|
||||
ut64 stride = rz_type_db_get_bitsize(typedb, type->array.type) / 8;
|
||||
if (!stride) {
|
||||
break;
|
||||
}
|
||||
ut64 idx = offset / stride;
|
||||
if (idx >= type->array.count) {
|
||||
break;
|
||||
}
|
||||
ut64 idx_offset = offset - idx * stride;
|
||||
char *newpath = rz_str_newf("%s[%" PFMT64u "]", prefix, idx);
|
||||
if (idx_offset == 0) {
|
||||
RzTypePath *tpath = rz_type_path_new(type->array.type, newpath);
|
||||
if (tpath) {
|
||||
rz_list_append(list, tpath);
|
||||
}
|
||||
}
|
||||
collect_type_paths(typedb, list, type->array.type, newpath, idx_offset, depth - 1);
|
||||
if (idx_offset != 0) {
|
||||
free(newpath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the list of all type paths matching the offset
|
||||
* \brief Returns the list of all paths into the base type matching the offset
|
||||
*
|
||||
* \param typedb Types Database instance
|
||||
* \param btype The base type
|
||||
* \param offset The offset of the path to match against
|
||||
* \param btype The root type from which paths are searched
|
||||
* \param offset The offset into \p btype to match against
|
||||
* \param max_depth Maximum number of components a path may have
|
||||
*/
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_path_by_offset(const RzTypeDB *typedb, RzBaseType *btype, ut64 offset) {
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_base_type_path_by_offset(const RzTypeDB *typedb, const RzBaseType *btype, ut64 offset, unsigned int max_depth) {
|
||||
rz_return_val_if_fail(typedb && btype && btype->name, NULL);
|
||||
RzList *list = rz_list_newf((RzListFree)rz_type_path_free);
|
||||
if (btype->kind == RZ_BASE_TYPE_KIND_STRUCT) {
|
||||
RzType *t = rz_type_identifier_of_base_type(typedb, btype, false);
|
||||
RzTypeStructMember *memb;
|
||||
ut64 memb_offset = 0;
|
||||
rz_vector_foreach(&btype->struct_data.members, memb) {
|
||||
if (memb_offset == offset) {
|
||||
RzTypePath *tpath = rz_type_path_new(t, rz_str_newf("%s.%s", btype->name, memb->name));
|
||||
if (tpath) {
|
||||
rz_list_append(list, tpath);
|
||||
}
|
||||
}
|
||||
// We go into the nested structures/unions if they are members of the structure
|
||||
char *path = rz_str_newf("%s.%s", btype->name, memb->name);
|
||||
structured_member_walker(typedb, list, t, memb->type, path, memb_offset + offset);
|
||||
memb_offset += rz_type_db_get_bitsize(typedb, memb->type) / 8;
|
||||
free(path);
|
||||
}
|
||||
} else if (btype->kind == RZ_BASE_TYPE_KIND_UNION) {
|
||||
// This function makes sense only for structures since union
|
||||
// members have exact same offset
|
||||
// But if the union has compound members, e.g. structures, their
|
||||
// internal offsets can be different
|
||||
RzType *t = rz_type_identifier_of_base_type(typedb, btype, false);
|
||||
RzTypeUnionMember *memb;
|
||||
rz_vector_foreach(&btype->union_data.members, memb) {
|
||||
char *path = rz_str_newf("%s.%s", btype->name, memb->name);
|
||||
structured_member_walker(typedb, list, t, memb->type, path, offset);
|
||||
free(path);
|
||||
}
|
||||
} else {
|
||||
rz_warn_if_reached();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
collect_base_type_paths(typedb, list, btype, "", offset, max_depth);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the list of all paths into the type matching the offset
|
||||
*
|
||||
* \param type The root type from which paths are searched
|
||||
* \param offset The offset into \p btype to match against
|
||||
* \param max_depth Maximum number of components a path may have
|
||||
*/
|
||||
RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_path_by_offset(const RzTypeDB *typedb, const RzType *type, ut64 offset, unsigned int max_depth) {
|
||||
rz_return_val_if_fail(typedb && type, NULL);
|
||||
RzList *list = rz_list_newf((RzListFree)rz_type_path_free);
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
collect_type_paths(typedb, list, type, "", offset, max_depth);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
@ -224,10 +273,7 @@ RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_db_get_by_offset(const RzTypeDB
|
|||
RzBaseType *t;
|
||||
rz_list_foreach (types, iter, t) {
|
||||
if (t->kind == RZ_BASE_TYPE_KIND_STRUCT || t->kind == RZ_BASE_TYPE_KIND_UNION) {
|
||||
RzList *list = rz_type_path_by_offset(typedb, t, offset);
|
||||
if (list) {
|
||||
rz_list_join(result, list);
|
||||
}
|
||||
collect_base_type_paths(typedb, result, t, t->name, offset, 1);
|
||||
}
|
||||
}
|
||||
rz_list_free(types);
|
||||
|
|
|
|||
|
|
@ -1077,6 +1077,527 @@ bool test_typedef_loop(void) {
|
|||
str = rz_base_type_as_format(typedb, btype);
|
||||
mu_assert_streq_free(str, "", "format");
|
||||
|
||||
RzList *paths = rz_type_path_by_offset(typedb, ttype, 0, INT_MAX);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
rz_type_db_free(typedb);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_path_by_offset_struct(void) {
|
||||
RzTypeDB *typedb = rz_type_db_new();
|
||||
const char *types_dir = TEST_BUILD_TYPES_DIR;
|
||||
rz_type_db_init(typedb, types_dir, "x86", 64, "linux");
|
||||
|
||||
// -- simple
|
||||
|
||||
char *error_msg = NULL;
|
||||
RzType *ttype = rz_type_parse_string_single(typedb->parser, "struct Hello { int a; uint32_t b; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "Hello", "parsed type");
|
||||
|
||||
RzList *paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
RzTypePath *path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 2, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".b", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
// -- recursive
|
||||
|
||||
ttype = rz_type_parse_string_single(typedb->parser, "struct World { uint64_t ulu; Hello mulu; int32_t urshak; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "World", "parsed type");
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 8, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 10, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 12, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu.b", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 8, 2);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 8, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 8, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
// -- base type
|
||||
|
||||
RzBaseType *btype = rz_type_db_get_base_type(typedb, "World");
|
||||
mu_assert_notnull(btype, "get base type");
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 8, 2);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 8, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 8, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_db_free(typedb);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_path_by_offset_union(void) {
|
||||
RzTypeDB *typedb = rz_type_db_new();
|
||||
const char *types_dir = TEST_BUILD_TYPES_DIR;
|
||||
rz_type_db_init(typedb, types_dir, "x86", 64, "linux");
|
||||
|
||||
// -- simple
|
||||
|
||||
char *error_msg = NULL;
|
||||
RzType *ttype = rz_type_parse_string_single(typedb->parser, "union Card { int fish; uint32_t senf; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "Card", "parsed type");
|
||||
|
||||
RzList *paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
RzTypePath *path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".fish", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".senf", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 2, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
// -- recursive
|
||||
|
||||
ttype = rz_type_parse_string_single(typedb->parser, "struct Hello { int a; uint32_t b; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "Hello", "parsed type");
|
||||
rz_type_free(ttype);
|
||||
ttype = rz_type_parse_string_single(typedb->parser, "union World { uint64_t ulu; Hello mulu; int32_t urshak; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "World", "parsed type");
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 4, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 2);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
path = rz_list_get_n(paths, 3);
|
||||
mu_assert_streq(path->path, ".urshak", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 8, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".mulu.b", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 2);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 4, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 2);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
path = rz_list_get_n(paths, 3);
|
||||
mu_assert_streq(path->path, ".urshak", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 3, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 2);
|
||||
mu_assert_streq(path->path, ".urshak", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
// -- base type
|
||||
|
||||
RzBaseType *btype = rz_type_db_get_base_type(typedb, "World");
|
||||
mu_assert_notnull(btype, "get base type");
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 0, 2);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 4, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 2);
|
||||
mu_assert_streq(path->path, ".mulu.a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
path = rz_list_get_n(paths, 3);
|
||||
mu_assert_streq(path->path, ".urshak", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 0, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 3, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".ulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint64_t", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, ".mulu", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 2);
|
||||
mu_assert_streq(path->path, ".urshak", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_base_type_path_by_offset(typedb, btype, 0, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_db_free(typedb);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_path_by_offset_array(void) {
|
||||
RzTypeDB *typedb = rz_type_db_new();
|
||||
const char *types_dir = TEST_BUILD_TYPES_DIR;
|
||||
rz_type_db_init(typedb, types_dir, "x86", 64, "linux");
|
||||
|
||||
// -- simple
|
||||
|
||||
char *error_msg = NULL;
|
||||
RzType *ttype = rz_type_parse_string_single(typedb->parser, "int [5]", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_ARRAY, "parsed type");
|
||||
|
||||
RzList *paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
RzTypePath *path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[0]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 1, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[1]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 16, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[4]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 19, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 20, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
// -- recursive
|
||||
|
||||
ttype = rz_type_parse_string_single(typedb->parser, "struct Hello { int a; uint32_t b; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "Hello", "parsed type");
|
||||
rz_type_free(ttype);
|
||||
|
||||
ttype = rz_type_parse_string_single(typedb->parser, "Hello [5]", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_ARRAY, "parsed type");
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[0]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, "[0].a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 12, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[1].b", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 2);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 2, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[0]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
path = rz_list_get_n(paths, 1);
|
||||
mu_assert_streq(path->path, "[0].a", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, "[0]", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "Hello", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 0, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
rz_type_db_free(typedb);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_path_by_offset_typedef(void) {
|
||||
RzTypeDB *typedb = rz_type_db_new();
|
||||
const char *types_dir = TEST_BUILD_TYPES_DIR;
|
||||
rz_type_db_init(typedb, types_dir, "x86", 64, "linux");
|
||||
|
||||
char *error_msg = NULL;
|
||||
RzType *ttype = rz_type_parse_string_single(typedb->parser, "struct Card { int fish; uint32_t senf; };", &error_msg);
|
||||
mu_assert_notnull(ttype, "type parse successful");
|
||||
mu_assert_eq(ttype->kind, RZ_TYPE_KIND_IDENTIFIER, "parsed type");
|
||||
mu_assert_streq(ttype->identifier.name, "Card", "parsed type");
|
||||
|
||||
RzBaseType *btype = rz_type_base_type_new(RZ_BASE_TYPE_KIND_TYPEDEF);
|
||||
btype->name = strdup("Alias");
|
||||
btype->type = RZ_NEW0(RzType);
|
||||
btype->type->kind = RZ_TYPE_KIND_IDENTIFIER;
|
||||
btype->type->identifier.name = strdup("Card");
|
||||
rz_type_db_save_base_type(typedb, btype);
|
||||
|
||||
RzList *paths = rz_type_path_by_offset(typedb, ttype, 0, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
RzTypePath *path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".fish", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "int", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 1, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 5);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".senf", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
// Resolving a typedef should not count as a depth step as we
|
||||
// can't observe it in the path.
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 1);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 1, "paths");
|
||||
path = rz_list_get_n(paths, 0);
|
||||
mu_assert_streq(path->path, ".senf", "paths");
|
||||
mu_assert_eq(path->typ->kind, RZ_TYPE_KIND_IDENTIFIER, "paths");
|
||||
mu_assert_streq(path->typ->identifier.name, "uint32_t", "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
paths = rz_type_path_by_offset(typedb, ttype, 4, 0);
|
||||
mu_assert_notnull(paths, "paths");
|
||||
mu_assert_eq(rz_list_length(paths), 0, "paths");
|
||||
rz_list_free(paths);
|
||||
|
||||
rz_type_free(ttype);
|
||||
|
||||
rz_type_db_free(typedb);
|
||||
mu_end;
|
||||
}
|
||||
|
|
@ -1103,6 +1624,10 @@ int all_tests() {
|
|||
mu_run_test(test_references);
|
||||
mu_run_test(test_addr_bits);
|
||||
mu_run_test(test_typedef_loop);
|
||||
mu_run_test(test_path_by_offset_struct);
|
||||
mu_run_test(test_path_by_offset_union);
|
||||
mu_run_test(test_path_by_offset_array);
|
||||
mu_run_test(test_path_by_offset_typedef);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue