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 /* scan backwards to remove an "_" followed by decimal digits */ 68 if (j != 0 && isdigit(result[j - 1])) { 69 while (--j) { 70 if (!isdigit(result[j])) { 71 break; 72 } 73 } 74 if (result[j] == '_') { 75 result[j] = '\0'; 76 } 77 } 78 79 return result; 80 } 81