1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <string.h> |
3 | #include <stdlib.h> |
4 | #include "util/string2.h" |
5 | |
6 | #include "demangle-ocaml.h" |
7 | |
8 | #include <linux/ctype.h> |
9 | |
10 | static const char *caml_prefix = "caml" ; |
11 | static const size_t caml_prefix_len = 4; |
12 | |
13 | /* mangled OCaml symbols start with "caml" followed by an upper-case letter */ |
14 | static bool |
15 | ocaml_is_mangled(const char *sym) |
16 | { |
17 | return 0 == strncmp(sym, caml_prefix, caml_prefix_len) |
18 | && isupper(sym[caml_prefix_len]); |
19 | } |
20 | |
21 | /* |
22 | * input: |
23 | * sym: a symbol which may have been mangled by the OCaml compiler |
24 | * return: |
25 | * if the input doesn't look like a mangled OCaml symbol, NULL is returned |
26 | * otherwise, a newly allocated string containing the demangled symbol is returned |
27 | */ |
28 | char * |
29 | ocaml_demangle_sym(const char *sym) |
30 | { |
31 | char *result; |
32 | int j = 0; |
33 | int i; |
34 | int len; |
35 | |
36 | if (!ocaml_is_mangled(sym)) { |
37 | return NULL; |
38 | } |
39 | |
40 | len = strlen(sym); |
41 | |
42 | /* the demangled symbol is always smaller than the mangled symbol */ |
43 | result = malloc(len + 1); |
44 | if (!result) |
45 | return NULL; |
46 | |
47 | /* skip "caml" prefix */ |
48 | i = caml_prefix_len; |
49 | |
50 | while (i < len) { |
51 | if (sym[i] == '_' && sym[i + 1] == '_') { |
52 | /* "__" -> "." */ |
53 | result[j++] = '.'; |
54 | i += 2; |
55 | } |
56 | else if (sym[i] == '$' && isxdigit(sym[i + 1]) && isxdigit(sym[i + 2])) { |
57 | /* "$xx" is a hex-encoded character */ |
58 | result[j++] = (hex(sym[i + 1]) << 4) | hex(sym[i + 2]); |
59 | i += 3; |
60 | } |
61 | else { |
62 | result[j++] = sym[i++]; |
63 | } |
64 | } |
65 | result[j] = '\0'; |
66 | |
67 | return result; |
68 | } |
69 | |