^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include "debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include "demangle-rust.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Mangled Rust symbols look like this:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * _$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * The original symbol is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * <std::sys::fd::FileDesc as core::ops::Drop>::drop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * The last component of the path is a 64-bit hash in lowercase hex, prefixed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * with "h". Rust does not have a global namespace between crates, an illusion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * which Rust maintains by using the hash to distinguish things that would
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * otherwise have the same symbol.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Any path component not starting with a XID_Start character is prefixed with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * "_".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * The following escape sequences are used:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * "," => $C$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * "@" => $SP$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * "*" => $BP$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * "&" => $RF$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * "<" => $LT$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * ">" => $GT$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * "(" => $LP$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * ")" => $RP$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * " " => $u20$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * "'" => $u27$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * "[" => $u5b$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * "]" => $u5d$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * "~" => $u7e$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * A double ".." means "::" and a single "." means "-".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static const char *hash_prefix = "::h";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static const size_t hash_prefix_len = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static const size_t hash_len = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static bool is_prefixed_hash(const char *start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static bool looks_like_rust(const char *sym, size_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static bool unescape(const char **in, char **out, const char *seq, char value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * INPUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * sym: symbol that has been through BFD-demangling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * This function looks for the following indicators:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * 1. The hash must consist of "h" followed by 16 lowercase hex digits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * 2. As a sanity check, the hash must use between 5 and 15 of the 16 possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * hex digits. This is true of 99.9998% of hashes so once in your life you
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * may see a false negative. The point is to notice path components that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * could be Rust hashes but are probably not, like "haaaaaaaaaaaaaaaa". In
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * this case a false positive (non-Rust symbol has an important path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * component removed because it looks like a Rust hash) is worse than a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * false negative (the rare Rust symbol is not demangled) so this sets the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * balance in favor of false negatives.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * 3. There must be no characters other than a-zA-Z0-9 and _.:$
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * 4. There must be no unrecognized $-sign sequences.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * 5. There must be no sequence of three or more dots in a row ("...").
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) rust_is_mangled(const char *sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) size_t len, len_without_hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) len = strlen(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (len <= hash_prefix_len + hash_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* Not long enough to contain "::h" + hash + something else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) len_without_hash = len - (hash_prefix_len + hash_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!is_prefixed_hash(sym + len_without_hash))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return looks_like_rust(sym, len_without_hash);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * A hash is the prefix "::h" followed by 16 lowercase hex digits. The hex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * digits must comprise between 5 and 15 (inclusive) distinct digits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static bool is_prefixed_hash(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) const char *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) bool seen[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (strncmp(str, hash_prefix, hash_prefix_len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) str += hash_prefix_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) memset(seen, false, sizeof(seen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) for (end = str + hash_len; str < end; str++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (*str >= '0' && *str <= '9')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) seen[*str - '0'] = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) else if (*str >= 'a' && *str <= 'f')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) seen[*str - 'a' + 10] = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Count how many distinct digits seen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (seen[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return count >= 5 && count <= 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static bool looks_like_rust(const char *str, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) const char *end = str + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) while (str < end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) switch (*str) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) case '$':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (!strncmp(str, "$C$", 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) str += 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) else if (!strncmp(str, "$SP$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) || !strncmp(str, "$BP$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) || !strncmp(str, "$RF$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) || !strncmp(str, "$LT$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) || !strncmp(str, "$GT$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) || !strncmp(str, "$LP$", 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) || !strncmp(str, "$RP$", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) str += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) else if (!strncmp(str, "$u20$", 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) || !strncmp(str, "$u27$", 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) || !strncmp(str, "$u5b$", 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) || !strncmp(str, "$u5d$", 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) || !strncmp(str, "$u7e$", 5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) str += 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case '.':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Do not allow three or more consecutive dots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (!strncmp(str, "...", 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Fall through */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case 'a' ... 'z':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) case 'A' ... 'Z':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case '0' ... '9':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case '_':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case ':':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * INPUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * sym: symbol for which rust_is_mangled(sym) returns true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * The input is demangled in-place because the mangled name is always longer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * than the demangled one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) rust_demangle_sym(char *sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) const char *in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) char *out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) const char *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (!sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) in = sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) out = sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) end = sym + strlen(sym) - (hash_prefix_len + hash_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) while (in < end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) switch (*in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) case '$':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (!(unescape(&in, &out, "$C$", ',')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) || unescape(&in, &out, "$SP$", '@')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) || unescape(&in, &out, "$BP$", '*')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) || unescape(&in, &out, "$RF$", '&')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) || unescape(&in, &out, "$LT$", '<')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) || unescape(&in, &out, "$GT$", '>')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) || unescape(&in, &out, "$LP$", '(')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) || unescape(&in, &out, "$RP$", ')')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) || unescape(&in, &out, "$u20$", ' ')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) || unescape(&in, &out, "$u27$", '\'')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) || unescape(&in, &out, "$u5b$", '[')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) || unescape(&in, &out, "$u5d$", ']')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) || unescape(&in, &out, "$u7e$", '~'))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pr_err("demangle-rust: unexpected escape sequence");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case '_':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * If this is the start of a path component and the next
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * character is an escape sequence, ignore the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * underscore. The mangler inserts an underscore to make
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * sure the path component begins with a XID_Start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * character.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if ((in == sym || in[-1] == ':') && in[1] == '$')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) in++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *out++ = *in++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) case '.':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (in[1] == '.') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* ".." becomes "::" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) *out++ = ':';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *out++ = ':';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) in += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* "." becomes "-" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) *out++ = '-';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) in++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) case 'a' ... 'z':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case 'A' ... 'Z':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case '0' ... '9':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) case ':':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) *out++ = *in++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) pr_err("demangle-rust: unexpected character '%c' in symbol\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) *out = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static bool unescape(const char **in, char **out, const char *seq, char value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) size_t len = strlen(seq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (strncmp(*in, seq, len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) **out = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) *in += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) *out += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }