Rizin
unix-like reverse engineering framework and cli tools
swift.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: MIT
3 /* work-in-progress reverse engineered swift-demangler in C */
4 #include "demangler_util.h"
5 #include <rz_libdemangle.h>
6 
7 struct Type {
8  const char *code;
9  const char *name;
10 };
11 
12 static struct Type types[] = {
13  /* basic types */
14  { "Sb", "Bool" },
15  { "SS", "String" },
16  { "FS", "String" },
17  { "GV", "mutableAddressor" }, // C_ARGC
18  { "Ss", "generic" }, // C_ARGC
19  { "S_", "Generic" }, // C_ARGC
20  { "TF", "GenericSpec" }, // C_ARGC
21  { "Ts", "String" }, // C_ARGC
22  { "Sa", "Array" },
23  { "Si", "Swift.Int" },
24  { "Sf", "Float" },
25  { "Sb", "Bool" },
26  { "Su", "UInt" },
27  { "SQ", "ImplicitlyUnwrappedOptional" },
28  { "Sc", "UnicodeScalar" },
29  { "Sd", "Double" },
30  { "SS", "String" }, // Swift.String
31  /* builtin */
32  { "Bi1", "Builtin.Int1" },
33  { "Bp", "Builtin.RawPointer" },
34  { "Bw", "Builtin.Word" }, // isASCII ?
35  /* eol */
36  { NULL, NULL }
37 };
38 
39 static struct Type metas[] = {
40  /* attributes */
41  { "FC", "ClassFunc" },
42  { "S0_FT", "?" },
43  { "RxC", ".." },
44  { "S0", "self" },
45  { "U__FQ_T_", "<A>(A)" },
46  { "ToFC", "@objc class func" },
47  { "ToF", "@objc func" },
48  /* eol */
49  { NULL, NULL }
50 };
51 
52 static struct Type flags[] = {
53  //{ "f", "function" }, // this is not an accessor
54  { "s", "setter" },
55  { "g", "getter" },
56  { "m", "method" }, // field?
57  { "d", "destructor" },
58  { "D", "deallocator" },
59  { "c", "constructor" },
60  { "C", "allocator" },
61  { NULL, NULL }
62 };
63 
64 static const char *getnum(const char *n, int *num) {
65  if (num && *n) {
66  *num = atoi(n);
67  }
68  while (*n && *n >= '0' && *n <= '9') {
69  n++;
70  }
71  return n;
72 }
73 
74 static const char *numpos(const char *n) {
75  while (*n && (*n < '0' || *n > '9')) {
76  n++;
77  }
78  return n;
79 }
80 
81 static char *getstring(const char *s, int len) {
82  if (len < 1) {
83  return strdup("");
84  }
85  char *buf = malloc(len + 1);
86  memcpy(buf, s, len);
87  buf[len] = 0;
88  return buf;
89 }
90 
91 static const char *resolve(struct Type *t, const char *foo, const char **bar) {
92  if (!t || !foo || !*foo) {
93  return NULL;
94  }
95  for (; t[0].code; t++) {
96  int len = strlen(t[0].code);
97  if (!strncmp(foo, t[0].code, len)) {
98  if (bar) {
99  *bar = t[0].name;
100  }
101  return foo + len;
102  }
103  }
104  return NULL;
105 }
106 
107 char *libdemangle_handler_swift(const char *s) {
108 #define STRCAT_BOUNDS(x) \
109  if (((x) + 2 + strlen(out)) > sizeof(out)) \
110  break;
111  char out[1024];
112  int i, len, is_generic = 0;
113  int is_first = 1;
114  int is_last = 0;
115  int retmode = 0;
116  if (!strncmp(s, "imp.", 4)) {
117  s = s + 4;
118  }
119  if (!strncmp(s, "reloc.", 6)) {
120  s = s + 6;
121  }
122 
123  if (*s != 'T' && strncmp(s, "_T", 2) && strncmp(s, "__T", 3)) {
124  // modern swift symbols
125  if (strncmp(s, "$s", 2)) {
126  return NULL;
127  }
128  }
129 
130  if (!strncmp(s, "__", 2)) {
131  s = s + 2;
132  }
133 
134  const char *attr = NULL;
135  const char *attr2 = NULL;
136  const char *q, *p = s;
137  const char *q_end = p + strlen(p);
138  const char *q_start = p;
139 
140  if (strchr(s, '\'') || strchr(s, ' ')) {
141  return NULL;
142  }
143 
144  out[0] = 0;
145 
146  const char *tail = NULL;
147  if (p[0]) {
148  switch (p[1]) {
149  case 'W':
150  switch (p[2]) {
151  case 'a':
152  tail = "..protocol";
153  break;
154  }
155  break;
156  case 'F':
157  switch (p[2]) {
158  case 'e':
159  tail = "..extension";
160  p += 2;
161  break;
162  }
163  break;
164  case 'M':
165  switch (p[2]) {
166  case 'a':
167  tail = "..accessor.metadata";
168  break;
169  case 'e':
170  tail = "..override";
171  break;
172  case 'm':
173  tail = "..metaclass";
174  break;
175  case 'L':
176  tail = "..lazy.metadata";
177  break;
178  default:
179  tail = "..metadata";
180  break;
181  }
182  break;
183  case 'I': // interfaces
184  // TODO
185  return NULL;
186  }
187  }
188  if (tail) {
189  if (*p) {
190  p++;
191  }
192  } else {
193  if (*p && p[1]) {
194  p += 2;
195  }
196  }
197 
198  // XXX
199  q = getnum(p, NULL);
200 
201  // _TF or __TW
202  if (IS_DIGIT(*p) || *p == 'v' || *p == 'I' || *p == 'o' || *p == 'T' || *p == 'V' || *p == 'M' || *p == 'C' || *p == 'F' || *p == 'W') {
203  if (!strncmp(p + 1, "SS", 2)) {
204  strcat(out, "Swift.String.init (");
205  p += 3;
206  }
207  if (!strncmp(p, "vdv", 3)) {
208  tail = "..field";
209  p += 3;
210  }
211  if (!strncmp(p, "oFC", 3)) {
212  tail = "..init.witnesstable";
213  p += 4;
214  }
215  getnum(q, &len);
216  q = numpos(p);
217  for (i = 0, len = 1; len && q < q_end; q += len, i++) {
218  if (*q == 'P') {
219  q++;
220  }
221  q = getnum(q, &len);
222  if (!len) {
223  break;
224  }
225  char *str = getstring(q, len);
226  if (len == 2 && !strcmp(str, "ee")) {
227  strcat(out, "Swift");
228  } else {
229  RZ_FREE(str);
230  // push string
231  if (i && *out) {
232  strcat(out, ".");
233  }
235  len = RZ_MIN(len, strlen(q));
236  str = getstring(q, len);
237  strcat(out, str);
238  }
239  free(str);
240  }
241  if (q > q_end) {
242  return 0;
243  }
244  p = resolve(flags, q, &attr);
245  if (!p && ((*q == 'U') || (*q == 'R'))) {
246  p = resolve(metas, q, &attr);
247  if (attr && *q == 'R') {
248  attr = NULL;
249  q += 3;
250  }
251  }
252  /* parse accessors */
253  if (attr) {
254  int len = 0;
255  char *name = NULL;
256  /* get field name and then type */
257  resolve(types, q, &attr);
258 
259  q = getnum(q + 1, &len);
260  if (len < strlen(q)) {
261  resolve(types, q + len, &attr2);
262  } else {
263  resolve(types, q, &attr2);
264  }
265  name = getstring(q, len);
266  do {
267  if (name && *name) {
268  strcat(out, ".");
269  STRCAT_BOUNDS(strlen(name));
270  strcat(out, name);
271  }
272  if (attr && *attr) {
273  strcat(out, ".");
274  STRCAT_BOUNDS(strlen(attr));
275  strcat(out, attr);
276  }
277  if (attr2 && *attr2) {
278  strcat(out, "__");
279  STRCAT_BOUNDS(strlen(attr2));
280  strcat(out, attr2);
281  }
282  } while (0);
283  free(name);
284  if (*q == '_') {
285  strcat(out, " -> ()");
286  }
287  } else {
288  /* parse function parameters here */
289  // type len value/
290  for (i = 0; q && q < q_end && q >= q_start; i++) {
291  if (*q == 'f') {
292  q++;
293  }
294  switch (*q) {
295  case 's': {
296  int n = 0;
297  const char *Q = getnum(q + 1, &n);
298  char *res = getstring(Q, n);
299  strcat(out, res);
300  free(res);
301  q = Q + n + 1;
302  continue;
303  } break;
304  case 'u':
305  if (!strncmp(q, "uRxs", 4)) {
306  strcat(out, "..");
307  int n = 0;
308  const char *Q = getnum(q + 4, &n);
309  char *res = getstring(Q, n);
310  strcat(out, res);
311  free(res);
312  q = Q + n + 1;
313  continue;
314  }
315  break;
316  case 'S': // "S0"
317  if (q[1] == '1') {
318  q++;
319  }
320  switch (q[1]) {
321  case '0':
322  strcat(out, " (self) -> ()");
323  if (attr) {
324  strcat(out, attr);
325  }
326  q = p = q + 1;
327  attr = "";
328  break;
329  case 'S':
330  // swift string
331  strcat(out, "__String");
332  break;
333  case '_':
334  // swift string
335  if (q[0] && q[1] && q[2]) {
336  strcat(out, "..");
337  int n = 0;
338  const char *Q = getnum(q + 2, &n);
339  char *res = getstring(Q, n);
340  strcat(out, res);
341  free(res);
342  q = Q + n + 1;
343  continue;
344  }
345  break;
346  }
347  break;
348  case 'B':
349  case 'T':
350  case 'I':
351  p = resolve(types, q + 0, &attr); // type
352  if (p && *p && IS_DIGIT(p[1])) {
353  p--;
354  }
355  break;
356  case 'F':
357  strcat(out, " ()");
358  p = resolve(types, (strlen(q) > 2) ? q + 3 : "", &attr); // type
359  break;
360  case 'G':
361  q += 2;
362  if (!strncmp(q, "_V", 2)) {
363  q += 2;
364  }
365  p = resolve(types, q, &attr); // type
366  break;
367  case 'V':
368  p = resolve(types, q + 1, &attr); // type
369  break;
370  case '_':
371  // it's return value time!
372  p = resolve(types, q + 1, &attr); // type
373  break;
374  default:
375  p = resolve(types, q, &attr); // type
376  }
377 
378  if (p) {
379  q = getnum(p, &len);
380  if (attr && !strcmp(attr, "generic")) {
381  is_generic = 1;
382  }
383  if (!len) {
384  if (retmode) {
385  if (q + 1 > q_end) {
386  if (attr) {
387  strcat(out, " -> ");
388  STRCAT_BOUNDS(strlen(attr));
389  strcat(out, attr);
390  }
391  break;
392  }
393  resolve(types, *q ? q + 1 : q, &attr); // type
394  if (attr) {
395  strcat(out, " -> ");
396  STRCAT_BOUNDS(strlen(attr));
397  strcat(out, attr);
398  }
399  break;
400  }
401  retmode = 1;
402  len++;
403  }
404  if (len < 0 || len > 256) {
405  // invalid length
406  break;
407  }
408  if (len <= (q_end - q) && q[len]) {
409  char *s = getstring(q, len);
410  if (s && *s) {
411  if (is_first) {
412  strcat(out, is_generic ? "<" : "(");
413  is_first = 0;
414  }
415  is_last = q[len];
416  if (attr) {
417  STRCAT_BOUNDS(strlen(attr));
418  strcat(out, attr);
419  strcat(out, " ");
420  }
421  STRCAT_BOUNDS(strlen(s));
422  strcat(out, s);
423  if (is_last) {
424  strcat(out, is_generic ? ">" : ")");
425  is_first = (*s != '_');
426  if (is_generic && !is_first) {
427  break;
428  }
429  } else {
430  strcat(out, ", ");
431  }
432  } else {
433  if (attr) {
434  strcat(out, " -> ");
435  STRCAT_BOUNDS(strlen(attr));
436  strcat(out, attr);
437  }
438  }
439  free(s);
440  } else {
441  if (attr) {
442  strcat(out, " -> ");
443  STRCAT_BOUNDS(strlen(attr));
444  strcat(out, attr);
445  }
446  }
447  q += len;
448  p = q;
449  } else {
450  if (q && *q) {
451  q++;
452  } else {
453  break;
454  }
455  char *n = strstr(q, "__");
456  if (n) {
457  q = n + 1;
458  } else {
459  n = strchr(q, '_');
460  if (n) {
461  q = n + 1;
462  } else {
463  break;
464  }
465  }
466  }
467  }
468  }
469  }
470  if (*out) {
471  if (tail) {
472  strcat(out, tail);
473  }
474 #if 1
475  char *p, *outstr = strdup(out);
476  p = outstr;
477  for (;;) {
478  p = strstr(p, ")(");
479  if (p) {
480  p[0] = '_';
481  p[1] = '_';
482  p += 2;
483  } else {
484  break;
485  }
486  }
487  return outstr;
488 #endif
489  }
490  return NULL;
491 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
#define Q(x)
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static RzMain foo[]
Definition: main.c:11
void * malloc(size_t size)
Definition: malloc.c:123
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void static offset const char static length static mode static who const char struct statfs static buf unsigned unsigned num
Definition: sflib.h:126
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
int n
Definition: mipsasm.c:19
static RzSocket * s
Definition: rtr.c:28
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MIN(x, y)
Definition: swift.c:7
const char * name
Definition: swift.c:9
const char * code
Definition: swift.c:8
Definition: inftree9.h:24
Definition: z80asm.h:102
static struct Type types[]
Definition: swift.c:12
static struct Type flags[]
Definition: swift.c:52
#define STRCAT_BOUNDS(x)
static const char * numpos(const char *n)
Definition: swift.c:74
static char * getstring(const char *s, int len)
Definition: swift.c:81
char * libdemangle_handler_swift(const char *s)
Definition: swift.c:107
static const char * getnum(const char *n, int *num)
Definition: swift.c:64
static const char * resolve(struct Type *t, const char *foo, const char **bar)
Definition: swift.c:91
static struct Type metas[]
Definition: swift.c:39