Rizin
unix-like reverse engineering framework and cli tools
path.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Anton Kochkov <anton.kochkov@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_util.h>
5 #include <rz_type.h>
6 
15  RzTypePath *tpath = RZ_NEW0(RzTypePath);
16  if (!tpath) {
17  return NULL;
18  }
19  tpath->typ = type;
20  tpath->path = path;
21  return tpath;
22 }
23 
32  if (!tpath) {
33  return;
34  }
35  free(tpath->path);
36  free(tpath);
37 }
38 
39 static st64 path_walker(const RzTypeDB *typedb, const char *path) {
40  rz_return_val_if_fail(typedb && path, -1);
41  const char *member;
42  size_t membsize;
43  ut64 index;
44  st64 offset = 0;
45  RzType *parent = NULL;
46  const char *path_begin = path;
47  while (*path) {
48  switch (*path++) {
49  case '\0':
50  break;
51  case '[':
52  member = path;
53  index = (ut64)strtoull(member, (char **)&path, 10);
54  if (member == path || *path != ']') {
55  eprintf("Type path: expected ] (\"%s\")", path - 1);
56  return -1;
57  }
58  ++path;
59  if (!parent || parent->kind != RZ_TYPE_KIND_ARRAY) {
60  return -1;
61  }
62  offset += rz_type_db_get_bitsize(typedb, parent) * index;
63  break;
64  case '.':
65  member = path;
66  for (membsize = 0; member[membsize]; ++membsize) {
67  if (strchr(".[", member[membsize])) {
68  break;
69  }
70  }
71  if (membsize == 0) {
72  eprintf("Type path: expected member (\"%s\")", path - 1);
73  return -1;
74  }
75  if (!parent) {
76  if (member <= path) {
77  return -1;
78  }
79  size_t typenamesize = member - path_begin;
80  char *typename = malloc(typenamesize + 1);
81  if (!typename) {
82  return -1;
83  }
84  strncpy(typename, path_begin, typenamesize);
85  typename[typenamesize] = '\0';
86  parent = rz_type_identifier_of_base_type_str(typedb, typename);
87  free(typename);
88  if (!parent) {
89  return -1;
90  }
91  } else {
92  if (parent->kind != RZ_TYPE_KIND_IDENTIFIER) {
93  return -1;
94  }
96  return -1;
97  }
98  }
99  offset += rz_type_db_struct_member_packed_offset(typedb, parent->identifier.name, member);
100  path = member + membsize;
101  break;
102  default:
103  eprintf("Type path: unexpected char (\"%s\")", path - 1);
104  return -1;
105  }
106  }
107  return offset;
108 }
109 
121  rz_return_val_if_fail(typedb && path, -1);
122  return path_walker(typedb, path);
123 }
124 
125 // TODO: Handle arrays
126 static bool structured_member_walker(const RzTypeDB *typedb, RzList /*<RzTypePath *>*/ *list, RzType *parent, RzType *type, char *path, ut64 offset) {
127  rz_return_val_if_fail(list && type, false);
128  if (type->kind != RZ_TYPE_KIND_IDENTIFIER) {
129  return false;
130  }
131  rz_return_val_if_fail(type->identifier.name, false);
132  bool result = true;
133  if (type->identifier.kind == RZ_TYPE_IDENTIFIER_KIND_STRUCT) {
134  // Get the base type
135  RzBaseType *btype = rz_type_db_get_base_type(typedb, type->identifier.name);
136  if (!btype) {
137  return false;
138  }
139  RzTypeStructMember *memb;
140  ut64 memb_offset = 0;
141  rz_vector_foreach(&btype->struct_data.members, memb) {
142  if (memb_offset == offset) {
143  RzTypePath *tpath = rz_type_path_new(parent, rz_str_newf("%s.%s.%s", path, btype->name, memb->name));
144  if (tpath) {
145  rz_list_append(list, tpath);
146  }
147  }
148  char *newpath = rz_str_newf("%s.%s", path, memb->name);
149  result &= structured_member_walker(typedb, list, parent, memb->type, newpath, memb_offset + offset);
150  memb_offset += rz_type_db_get_bitsize(typedb, memb->type) / 8;
151  free(newpath);
152  }
153  } else if (type->identifier.kind == RZ_TYPE_IDENTIFIER_KIND_UNION) {
154  // Get the base type
155  RzBaseType *btype = rz_type_db_get_base_type(typedb, type->identifier.name);
156  if (!btype) {
157  return false;
158  }
159  RzTypeUnionMember *memb;
160  rz_vector_foreach(&btype->union_data.members, memb) {
161  char *newpath = rz_str_newf("%s.%s", path, memb->name);
162  result &= structured_member_walker(typedb, list, parent, memb->type, path, offset);
163  free(newpath);
164  }
165  }
166  return result;
167 }
168 
176 RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_path_by_offset(const RzTypeDB *typedb, RzBaseType *btype, ut64 offset) {
178  if (btype->kind == RZ_BASE_TYPE_KIND_STRUCT) {
179  RzType *t = rz_type_identifier_of_base_type(typedb, btype, false);
180  RzTypeStructMember *memb;
181  ut64 memb_offset = 0;
182  rz_vector_foreach(&btype->struct_data.members, memb) {
183  if (memb_offset == offset) {
184  RzTypePath *tpath = rz_type_path_new(t, rz_str_newf("%s.%s", btype->name, memb->name));
185  if (tpath) {
186  rz_list_append(list, tpath);
187  }
188  }
189  // We go into the nested structures/unions if they are members of the structure
190  char *path = rz_str_newf("%s.%s", btype->name, memb->name);
191  structured_member_walker(typedb, list, t, memb->type, path, memb_offset + offset);
192  memb_offset += rz_type_db_get_bitsize(typedb, memb->type) / 8;
193  free(path);
194  }
195  } else if (btype->kind == RZ_BASE_TYPE_KIND_UNION) {
196  // This function makes sense only for structures since union
197  // members have exact same offset
198  // But if the union has compound members, e.g. structures, their
199  // internal offsets can be different
200  RzType *t = rz_type_identifier_of_base_type(typedb, btype, false);
201  RzTypeUnionMember *memb;
202  rz_vector_foreach(&btype->union_data.members, memb) {
203  char *path = rz_str_newf("%s.%s", btype->name, memb->name);
204  structured_member_walker(typedb, list, t, memb->type, path, offset);
205  free(path);
206  }
207  } else {
209  }
210  return list;
211 }
212 
219 RZ_API RZ_OWN RzList /*<RzTypePath *>*/ *rz_type_db_get_by_offset(const RzTypeDB *typedb, ut64 offset) {
220  rz_return_val_if_fail(typedb, NULL);
223  RzListIter *iter;
224  RzBaseType *t;
225  rz_list_foreach (types, iter, t) {
227  RzList *list = rz_type_path_by_offset(typedb, t, offset);
228  if (list) {
229  rz_list_join(result, list);
230  }
231  }
232  }
234  return result;
235 }
236 
245  rz_return_val_if_fail(typedb && name && member, 0);
246  RzBaseType *btype = rz_type_db_get_base_type(typedb, name);
247  if (!btype || btype->kind != RZ_BASE_TYPE_KIND_STRUCT) {
248  return 0;
249  }
250  RzTypeStructMember *memb;
251  ut64 result = 0;
252  rz_vector_foreach(&btype->struct_data.members, memb) {
253  if (!strcmp(memb->name, member)) {
254  return result;
255  break;
256  }
257  result += rz_type_db_get_bitsize(typedb, memb->type);
258  }
259  return result;
260 }
261 
269 RZ_API ut64 rz_type_db_struct_member_offset(RZ_NONNULL const RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_NONNULL const char *member) {
270  rz_return_val_if_fail(typedb && name && member, 0);
271  RzBaseType *btype = rz_type_db_get_base_type(typedb, name);
272  if (!btype || btype->kind != RZ_BASE_TYPE_KIND_STRUCT) {
273  return 0;
274  }
275  RzTypeStructMember *memb;
276  rz_vector_foreach(&btype->struct_data.members, memb) {
277  if (!strcmp(memb->name, member)) {
278  return memb->offset;
279  }
280  }
281  return 0;
282 }
RZ_API RZ_OWN RzList * rz_type_db_get_base_types(const RzTypeDB *typedb)
Returns the list of all basic types.
Definition: base.c:120
RZ_API RZ_BORROW RzBaseType * rz_type_db_get_base_type(const RzTypeDB *typedb, RZ_NONNULL const char *name)
Searches for the RzBaseType in the types database given the name.
Definition: base.c:57
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
RZ_API RZ_OWN RzType * rz_type_identifier_of_base_type(const RzTypeDB *typedb, RZ_NONNULL const RzBaseType *btype, bool is_const)
Creates a new RzType indentifier from the given RzBaseType.
Definition: helpers.c:15
RZ_API RZ_OWN RzType * rz_type_identifier_of_base_type_str(const RzTypeDB *typedb, RZ_NONNULL const char *name)
Creates a new RzType indentifier from the given RzBaseType name.
Definition: helpers.c:47
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API bool rz_list_join(RZ_NONNULL RzList *list1, RZ_NONNULL RzList *list2)
Joins 2 list into one (list2 pointer needs to be freed by the user)
Definition: list.c:209
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * malloc(size_t size)
Definition: malloc.c:123
int type
Definition: mipsasm.c:17
insn_type_descr_t types[]
Definition: or1k_disas.c:7
#define eprintf(x, y...)
Definition: rlcc.c:7
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
@ RZ_BASE_TYPE_KIND_UNION
Definition: rz_type.h:74
@ RZ_BASE_TYPE_KIND_STRUCT
Definition: rz_type.h:73
@ RZ_TYPE_IDENTIFIER_KIND_STRUCT
Definition: rz_type.h:136
@ RZ_TYPE_IDENTIFIER_KIND_UNION
Definition: rz_type.h:137
@ RZ_TYPE_KIND_ARRAY
Definition: rz_type.h:130
@ RZ_TYPE_KIND_IDENTIFIER
Definition: rz_type.h:128
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_BORROW
Definition: rz_types.h:63
#define st64
Definition: rz_types_base.h:10
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
Definition: z80asm.h:102
RzBaseTypeStruct struct_data
Definition: rz_type.h:118
char * name
Definition: rz_type.h:112
RzBaseTypeUnion union_data
Definition: rz_type.h:120
RzBaseTypeKind kind
Definition: rz_type.h:115
RzVector members
Definition: rz_type.h:104
RzType * typ
Definition: rz_type.h:175
char * path
Definition: rz_type.h:176
RzTypeKind kind
Definition: rz_type.h:155
struct rz_type_t::@292::@294 identifier
RZ_API ut64 rz_type_db_struct_member_offset(RZ_NONNULL const RzTypeDB *typedb, RZ_NONNULL const char *name, RZ_NONNULL const char *member)
Returns the offset in bytes of the structure member if there is a match.
Definition: path.c:269
RZ_API st64 rz_type_offset_by_path(const RzTypeDB *typedb, RZ_NONNULL const char *path)
Returns the offset of the member given path.
Definition: path.c:120
static st64 path_walker(const RzTypeDB *typedb, const char *path)
Definition: path.c:39
static bool structured_member_walker(const RzTypeDB *typedb, RzList *list, RzType *parent, RzType *type, char *path, ut64 offset)
Definition: path.c:126
RZ_API RZ_OWN RzTypePath * rz_type_path_new(RZ_BORROW RZ_NONNULL RzType *type, RZ_OWN RZ_NONNULL char *path)
Creates a new instance of RzTypePath.
Definition: path.c:13
RZ_API RZ_OWN RzList * rz_type_db_get_by_offset(const RzTypeDB *typedb, ut64 offset)
Returns the list of all structured types that have members matching the offset.
Definition: path.c:219
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)
Returns the packed offset in bits of the structure member if there is a match.
Definition: path.c:244
RZ_API RZ_OWN RzList * rz_type_path_by_offset(const RzTypeDB *typedb, RzBaseType *btype, ut64 offset)
Returns the list of all type paths matching the offset.
Definition: path.c:176
RZ_API void rz_type_path_free(RZ_NULLABLE RzTypePath *tpath)
Frees the RzTypePath.
Definition: path.c:31
RZ_API ut64 rz_type_db_get_bitsize(const RzTypeDB *typedb, RZ_NONNULL RzType *type)
Returns the type size in bits (target dependent)
Definition: type.c:779
ut64(WINAPI *w32_GetEnabledXStateFeatures)()