rust-demangle.c revision 1.1.1.6 1 1.1 mrg /* Demangler for the Rust programming language
2 1.1.1.6 mrg Copyright (C) 2016-2020 Free Software Foundation, Inc.
3 1.1 mrg Written by David Tolnay (dtolnay (at) gmail.com).
4 1.1 mrg
5 1.1 mrg This file is part of the libiberty library.
6 1.1 mrg Libiberty is free software; you can redistribute it and/or
7 1.1 mrg modify it under the terms of the GNU Library General Public
8 1.1 mrg License as published by the Free Software Foundation; either
9 1.1 mrg version 2 of the License, or (at your option) any later version.
10 1.1 mrg
11 1.1 mrg In addition to the permissions in the GNU Library General Public
12 1.1 mrg License, the Free Software Foundation gives you unlimited permission
13 1.1 mrg to link the compiled version of this file into combinations with other
14 1.1 mrg programs, and to distribute those combinations without any restriction
15 1.1 mrg coming from the use of this file. (The Library Public License
16 1.1 mrg restrictions do apply in other respects; for example, they cover
17 1.1 mrg modification of the file, and distribution when not linked into a
18 1.1 mrg combined executable.)
19 1.1 mrg
20 1.1 mrg Libiberty is distributed in the hope that it will be useful,
21 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
22 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 1.1 mrg Library General Public License for more details.
24 1.1 mrg
25 1.1 mrg You should have received a copy of the GNU Library General Public
26 1.1 mrg License along with libiberty; see the file COPYING.LIB.
27 1.1 mrg If not, see <http://www.gnu.org/licenses/>. */
28 1.1 mrg
29 1.1 mrg
30 1.1 mrg #ifdef HAVE_CONFIG_H
31 1.1 mrg #include "config.h"
32 1.1 mrg #endif
33 1.1 mrg
34 1.1 mrg #include "safe-ctype.h"
35 1.1 mrg
36 1.1.1.6 mrg #include <inttypes.h>
37 1.1 mrg #include <sys/types.h>
38 1.1 mrg #include <string.h>
39 1.1 mrg #include <stdio.h>
40 1.1.1.6 mrg #include <stdlib.h>
41 1.1 mrg
42 1.1 mrg #ifdef HAVE_STRING_H
43 1.1 mrg #include <string.h>
44 1.1 mrg #else
45 1.1 mrg extern size_t strlen(const char *s);
46 1.1 mrg extern int strncmp(const char *s1, const char *s2, size_t n);
47 1.1 mrg extern void *memset(void *s, int c, size_t n);
48 1.1 mrg #endif
49 1.1 mrg
50 1.1 mrg #include <demangle.h>
51 1.1 mrg #include "libiberty.h"
52 1.1 mrg
53 1.1.1.6 mrg struct rust_demangler
54 1.1.1.6 mrg {
55 1.1.1.6 mrg const char *sym;
56 1.1.1.6 mrg size_t sym_len;
57 1.1 mrg
58 1.1.1.6 mrg void *callback_opaque;
59 1.1.1.6 mrg demangle_callbackref callback;
60 1.1 mrg
61 1.1.1.6 mrg /* Position of the next character to read from the symbol. */
62 1.1.1.6 mrg size_t next;
63 1.1 mrg
64 1.1.1.6 mrg /* Non-zero if any error occurred. */
65 1.1.1.6 mrg int errored;
66 1.1 mrg
67 1.1.1.6 mrg /* Non-zero if printing should be verbose (e.g. include hashes). */
68 1.1.1.6 mrg int verbose;
69 1.1 mrg
70 1.1.1.6 mrg /* Rust mangling version, with legacy mangling being -1. */
71 1.1.1.6 mrg int version;
72 1.1.1.6 mrg };
73 1.1 mrg
74 1.1.1.6 mrg /* Parsing functions. */
75 1.1 mrg
76 1.1.1.6 mrg static char
77 1.1.1.6 mrg peek (const struct rust_demangler *rdm)
78 1.1 mrg {
79 1.1.1.6 mrg if (rdm->next < rdm->sym_len)
80 1.1.1.6 mrg return rdm->sym[rdm->next];
81 1.1.1.6 mrg return 0;
82 1.1.1.6 mrg }
83 1.1 mrg
84 1.1.1.6 mrg static char
85 1.1.1.6 mrg next (struct rust_demangler *rdm)
86 1.1.1.6 mrg {
87 1.1.1.6 mrg char c = peek (rdm);
88 1.1.1.6 mrg if (!c)
89 1.1.1.6 mrg rdm->errored = 1;
90 1.1.1.6 mrg else
91 1.1.1.6 mrg rdm->next++;
92 1.1.1.6 mrg return c;
93 1.1.1.6 mrg }
94 1.1.1.6 mrg
95 1.1.1.6 mrg struct rust_mangled_ident
96 1.1.1.6 mrg {
97 1.1.1.6 mrg /* ASCII part of the identifier. */
98 1.1.1.6 mrg const char *ascii;
99 1.1.1.6 mrg size_t ascii_len;
100 1.1.1.6 mrg };
101 1.1.1.6 mrg
102 1.1.1.6 mrg static struct rust_mangled_ident
103 1.1.1.6 mrg parse_ident (struct rust_demangler *rdm)
104 1.1.1.6 mrg {
105 1.1.1.6 mrg char c;
106 1.1.1.6 mrg size_t start, len;
107 1.1.1.6 mrg struct rust_mangled_ident ident;
108 1.1.1.6 mrg
109 1.1.1.6 mrg ident.ascii = NULL;
110 1.1.1.6 mrg ident.ascii_len = 0;
111 1.1.1.6 mrg
112 1.1.1.6 mrg c = next (rdm);
113 1.1.1.6 mrg if (!ISDIGIT (c))
114 1.1.1.6 mrg {
115 1.1.1.6 mrg rdm->errored = 1;
116 1.1.1.6 mrg return ident;
117 1.1.1.6 mrg }
118 1.1.1.6 mrg len = c - '0';
119 1.1.1.6 mrg
120 1.1.1.6 mrg if (c != '0')
121 1.1.1.6 mrg while (ISDIGIT (peek (rdm)))
122 1.1.1.6 mrg len = len * 10 + (next (rdm) - '0');
123 1.1.1.6 mrg
124 1.1.1.6 mrg start = rdm->next;
125 1.1.1.6 mrg rdm->next += len;
126 1.1.1.6 mrg /* Check for overflows. */
127 1.1.1.6 mrg if ((start > rdm->next) || (rdm->next > rdm->sym_len))
128 1.1.1.6 mrg {
129 1.1.1.6 mrg rdm->errored = 1;
130 1.1.1.6 mrg return ident;
131 1.1.1.6 mrg }
132 1.1.1.6 mrg
133 1.1.1.6 mrg ident.ascii = rdm->sym + start;
134 1.1.1.6 mrg ident.ascii_len = len;
135 1.1.1.6 mrg
136 1.1.1.6 mrg if (ident.ascii_len == 0)
137 1.1.1.6 mrg ident.ascii = NULL;
138 1.1.1.6 mrg
139 1.1.1.6 mrg return ident;
140 1.1.1.6 mrg }
141 1.1.1.6 mrg
142 1.1.1.6 mrg /* Printing functions. */
143 1.1.1.6 mrg
144 1.1.1.6 mrg static void
145 1.1.1.6 mrg print_str (struct rust_demangler *rdm, const char *data, size_t len)
146 1.1.1.6 mrg {
147 1.1.1.6 mrg if (!rdm->errored)
148 1.1.1.6 mrg rdm->callback (data, len, rdm->callback_opaque);
149 1.1.1.6 mrg }
150 1.1.1.6 mrg
151 1.1.1.6 mrg #define PRINT(s) print_str (rdm, s, strlen (s))
152 1.1.1.6 mrg
153 1.1.1.6 mrg /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */
154 1.1.1.6 mrg static int
155 1.1.1.6 mrg decode_lower_hex_nibble (char nibble)
156 1.1.1.6 mrg {
157 1.1.1.6 mrg if ('0' <= nibble && nibble <= '9')
158 1.1.1.6 mrg return nibble - '0';
159 1.1.1.6 mrg if ('a' <= nibble && nibble <= 'f')
160 1.1.1.6 mrg return 0xa + (nibble - 'a');
161 1.1.1.6 mrg return -1;
162 1.1.1.6 mrg }
163 1.1.1.6 mrg
164 1.1.1.6 mrg /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */
165 1.1.1.6 mrg static char
166 1.1.1.6 mrg decode_legacy_escape (const char *e, size_t len, size_t *out_len)
167 1.1.1.6 mrg {
168 1.1.1.6 mrg char c = 0;
169 1.1.1.6 mrg size_t escape_len = 0;
170 1.1.1.6 mrg int lo_nibble = -1, hi_nibble = -1;
171 1.1 mrg
172 1.1.1.6 mrg if (len < 3 || e[0] != '$')
173 1.1 mrg return 0;
174 1.1 mrg
175 1.1.1.6 mrg e++;
176 1.1.1.6 mrg len--;
177 1.1.1.6 mrg
178 1.1.1.6 mrg if (e[0] == 'C')
179 1.1.1.6 mrg {
180 1.1.1.6 mrg escape_len = 1;
181 1.1.1.6 mrg
182 1.1.1.6 mrg c = ',';
183 1.1.1.6 mrg }
184 1.1.1.6 mrg else if (len > 2)
185 1.1.1.6 mrg {
186 1.1.1.6 mrg escape_len = 2;
187 1.1.1.6 mrg
188 1.1.1.6 mrg if (e[0] == 'S' && e[1] == 'P')
189 1.1.1.6 mrg c = '@';
190 1.1.1.6 mrg else if (e[0] == 'B' && e[1] == 'P')
191 1.1.1.6 mrg c = '*';
192 1.1.1.6 mrg else if (e[0] == 'R' && e[1] == 'F')
193 1.1.1.6 mrg c = '&';
194 1.1.1.6 mrg else if (e[0] == 'L' && e[1] == 'T')
195 1.1.1.6 mrg c = '<';
196 1.1.1.6 mrg else if (e[0] == 'G' && e[1] == 'T')
197 1.1.1.6 mrg c = '>';
198 1.1.1.6 mrg else if (e[0] == 'L' && e[1] == 'P')
199 1.1.1.6 mrg c = '(';
200 1.1.1.6 mrg else if (e[0] == 'R' && e[1] == 'P')
201 1.1.1.6 mrg c = ')';
202 1.1.1.6 mrg else if (e[0] == 'u' && len > 3)
203 1.1.1.6 mrg {
204 1.1.1.6 mrg escape_len = 3;
205 1.1.1.6 mrg
206 1.1.1.6 mrg hi_nibble = decode_lower_hex_nibble (e[1]);
207 1.1.1.6 mrg if (hi_nibble < 0)
208 1.1.1.6 mrg return 0;
209 1.1.1.6 mrg lo_nibble = decode_lower_hex_nibble (e[2]);
210 1.1.1.6 mrg if (lo_nibble < 0)
211 1.1.1.6 mrg return 0;
212 1.1.1.6 mrg
213 1.1.1.6 mrg /* Only allow non-control ASCII characters. */
214 1.1.1.6 mrg if (hi_nibble > 7)
215 1.1.1.6 mrg return 0;
216 1.1.1.6 mrg c = (hi_nibble << 4) | lo_nibble;
217 1.1.1.6 mrg if (c < 0x20)
218 1.1.1.6 mrg return 0;
219 1.1.1.6 mrg }
220 1.1.1.6 mrg }
221 1.1.1.6 mrg
222 1.1.1.6 mrg if (!c || len <= escape_len || e[escape_len] != '$')
223 1.1 mrg return 0;
224 1.1 mrg
225 1.1.1.6 mrg *out_len = 2 + escape_len;
226 1.1.1.6 mrg return c;
227 1.1 mrg }
228 1.1 mrg
229 1.1.1.6 mrg static void
230 1.1.1.6 mrg print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident)
231 1.1.1.6 mrg {
232 1.1.1.6 mrg char unescaped;
233 1.1.1.6 mrg size_t len;
234 1.1.1.6 mrg
235 1.1.1.6 mrg if (rdm->errored)
236 1.1.1.6 mrg return;
237 1.1.1.6 mrg
238 1.1.1.6 mrg if (rdm->version == -1)
239 1.1.1.6 mrg {
240 1.1.1.6 mrg /* Ignore leading underscores preceding escape sequences.
241 1.1.1.6 mrg The mangler inserts an underscore to make sure the
242 1.1.1.6 mrg identifier begins with a XID_Start character. */
243 1.1.1.6 mrg if (ident.ascii_len >= 2 && ident.ascii[0] == '_'
244 1.1.1.6 mrg && ident.ascii[1] == '$')
245 1.1.1.6 mrg {
246 1.1.1.6 mrg ident.ascii++;
247 1.1.1.6 mrg ident.ascii_len--;
248 1.1.1.6 mrg }
249 1.1.1.6 mrg
250 1.1.1.6 mrg while (ident.ascii_len > 0)
251 1.1.1.6 mrg {
252 1.1.1.6 mrg /* Handle legacy escape sequences ("$...$", ".." or "."). */
253 1.1.1.6 mrg if (ident.ascii[0] == '$')
254 1.1.1.6 mrg {
255 1.1.1.6 mrg unescaped
256 1.1.1.6 mrg = decode_legacy_escape (ident.ascii, ident.ascii_len, &len);
257 1.1.1.6 mrg if (unescaped)
258 1.1.1.6 mrg print_str (rdm, &unescaped, 1);
259 1.1.1.6 mrg else
260 1.1.1.6 mrg {
261 1.1.1.6 mrg /* Unexpected escape sequence, print the rest verbatim. */
262 1.1.1.6 mrg print_str (rdm, ident.ascii, ident.ascii_len);
263 1.1.1.6 mrg return;
264 1.1.1.6 mrg }
265 1.1.1.6 mrg }
266 1.1.1.6 mrg else if (ident.ascii[0] == '.')
267 1.1.1.6 mrg {
268 1.1.1.6 mrg if (ident.ascii_len >= 2 && ident.ascii[1] == '.')
269 1.1.1.6 mrg {
270 1.1.1.6 mrg /* ".." becomes "::" */
271 1.1.1.6 mrg PRINT ("::");
272 1.1.1.6 mrg len = 2;
273 1.1.1.6 mrg }
274 1.1.1.6 mrg else
275 1.1.1.6 mrg {
276 1.1.1.6 mrg /* "." becomes "-" */
277 1.1.1.6 mrg PRINT ("-");
278 1.1.1.6 mrg len = 1;
279 1.1.1.6 mrg }
280 1.1.1.6 mrg }
281 1.1.1.6 mrg else
282 1.1.1.6 mrg {
283 1.1.1.6 mrg /* Print everything before the next escape sequence, at once. */
284 1.1.1.6 mrg for (len = 0; len < ident.ascii_len; len++)
285 1.1.1.6 mrg if (ident.ascii[len] == '$' || ident.ascii[len] == '.')
286 1.1.1.6 mrg break;
287 1.1.1.6 mrg
288 1.1.1.6 mrg print_str (rdm, ident.ascii, len);
289 1.1.1.6 mrg }
290 1.1.1.6 mrg
291 1.1.1.6 mrg ident.ascii += len;
292 1.1.1.6 mrg ident.ascii_len -= len;
293 1.1.1.6 mrg }
294 1.1 mrg
295 1.1.1.6 mrg return;
296 1.1.1.6 mrg }
297 1.1.1.6 mrg }
298 1.1.1.6 mrg
299 1.1.1.6 mrg /* A legacy hash is the prefix "h" followed by 16 lowercase hex digits.
300 1.1.1.6 mrg The hex digits must contain at least 5 distinct digits. */
301 1.1 mrg static int
302 1.1.1.6 mrg is_legacy_prefixed_hash (struct rust_mangled_ident ident)
303 1.1 mrg {
304 1.1.1.6 mrg uint16_t seen;
305 1.1.1.6 mrg int nibble;
306 1.1.1.6 mrg size_t i, count;
307 1.1 mrg
308 1.1.1.6 mrg if (ident.ascii_len != 17 || ident.ascii[0] != 'h')
309 1.1 mrg return 0;
310 1.1 mrg
311 1.1.1.6 mrg seen = 0;
312 1.1.1.6 mrg for (i = 0; i < 16; i++)
313 1.1.1.6 mrg {
314 1.1.1.6 mrg nibble = decode_lower_hex_nibble (ident.ascii[1 + i]);
315 1.1.1.6 mrg if (nibble < 0)
316 1.1.1.6 mrg return 0;
317 1.1.1.6 mrg seen |= (uint16_t)1 << nibble;
318 1.1.1.6 mrg }
319 1.1 mrg
320 1.1.1.6 mrg /* Count how many distinct digits were seen. */
321 1.1 mrg count = 0;
322 1.1.1.6 mrg while (seen)
323 1.1.1.6 mrg {
324 1.1.1.6 mrg if (seen & 1)
325 1.1.1.6 mrg count++;
326 1.1.1.6 mrg seen >>= 1;
327 1.1.1.6 mrg }
328 1.1 mrg
329 1.1.1.6 mrg return count >= 5;
330 1.1 mrg }
331 1.1 mrg
332 1.1.1.6 mrg int
333 1.1.1.6 mrg rust_demangle_callback (const char *mangled, int options,
334 1.1.1.6 mrg demangle_callbackref callback, void *opaque)
335 1.1 mrg {
336 1.1.1.6 mrg const char *p;
337 1.1.1.6 mrg struct rust_demangler rdm;
338 1.1.1.6 mrg struct rust_mangled_ident ident;
339 1.1.1.6 mrg
340 1.1.1.6 mrg rdm.sym = mangled;
341 1.1.1.6 mrg rdm.sym_len = 0;
342 1.1.1.6 mrg
343 1.1.1.6 mrg rdm.callback_opaque = opaque;
344 1.1.1.6 mrg rdm.callback = callback;
345 1.1.1.6 mrg
346 1.1.1.6 mrg rdm.next = 0;
347 1.1.1.6 mrg rdm.errored = 0;
348 1.1.1.6 mrg rdm.verbose = (options & DMGL_VERBOSE) != 0;
349 1.1.1.6 mrg rdm.version = 0;
350 1.1.1.6 mrg
351 1.1.1.6 mrg /* Rust symbols always start with _ZN (legacy). */
352 1.1.1.6 mrg if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N')
353 1.1.1.6 mrg {
354 1.1.1.6 mrg rdm.sym += 3;
355 1.1.1.6 mrg rdm.version = -1;
356 1.1.1.6 mrg }
357 1.1.1.6 mrg else
358 1.1.1.6 mrg return 0;
359 1.1.1.6 mrg
360 1.1.1.6 mrg /* Legacy Rust symbols use only [_0-9a-zA-Z.:$] characters. */
361 1.1.1.6 mrg for (p = rdm.sym; *p; p++)
362 1.1.1.6 mrg {
363 1.1.1.6 mrg rdm.sym_len++;
364 1.1 mrg
365 1.1.1.6 mrg if (*p == '_' || ISALNUM (*p))
366 1.1.1.6 mrg continue;
367 1.1 mrg
368 1.1.1.6 mrg if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':'))
369 1.1.1.6 mrg continue;
370 1.1.1.6 mrg
371 1.1.1.6 mrg return 0;
372 1.1.1.6 mrg }
373 1.1.1.6 mrg
374 1.1.1.6 mrg /* Legacy Rust symbols need to be handled separately. */
375 1.1.1.6 mrg if (rdm.version == -1)
376 1.1.1.6 mrg {
377 1.1.1.6 mrg /* Legacy Rust symbols always end with E. */
378 1.1.1.6 mrg if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E'))
379 1.1.1.6 mrg return 0;
380 1.1.1.6 mrg rdm.sym_len--;
381 1.1.1.6 mrg
382 1.1.1.6 mrg /* Legacy Rust symbols also always end with a path segment
383 1.1.1.6 mrg that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
384 1.1.1.6 mrg This early check, before any parse_ident calls, should
385 1.1.1.6 mrg quickly filter out most C++ symbols unrelated to Rust. */
386 1.1.1.6 mrg if (!(rdm.sym_len > 19
387 1.1.1.6 mrg && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3)))
388 1.1.1.6 mrg return 0;
389 1.1.1.6 mrg
390 1.1.1.6 mrg do
391 1.1.1.6 mrg {
392 1.1.1.6 mrg ident = parse_ident (&rdm);
393 1.1.1.6 mrg if (rdm.errored || !ident.ascii)
394 1.1.1.6 mrg return 0;
395 1.1.1.6 mrg }
396 1.1.1.6 mrg while (rdm.next < rdm.sym_len);
397 1.1.1.6 mrg
398 1.1.1.6 mrg /* The last path segment should be the hash. */
399 1.1.1.6 mrg if (!is_legacy_prefixed_hash (ident))
400 1.1.1.6 mrg return 0;
401 1.1.1.6 mrg
402 1.1.1.6 mrg /* Reset the state for a second pass, to print the symbol. */
403 1.1.1.6 mrg rdm.next = 0;
404 1.1.1.6 mrg if (!rdm.verbose && rdm.sym_len > 19)
405 1.1.1.6 mrg {
406 1.1.1.6 mrg /* Hide the last segment, containing the hash, if not verbose. */
407 1.1.1.6 mrg rdm.sym_len -= 19;
408 1.1.1.6 mrg }
409 1.1.1.6 mrg
410 1.1.1.6 mrg do
411 1.1.1.6 mrg {
412 1.1.1.6 mrg if (rdm.next > 0)
413 1.1.1.6 mrg print_str (&rdm, "::", 2);
414 1.1.1.6 mrg
415 1.1.1.6 mrg ident = parse_ident (&rdm);
416 1.1.1.6 mrg print_ident (&rdm, ident);
417 1.1.1.6 mrg }
418 1.1.1.6 mrg while (rdm.next < rdm.sym_len);
419 1.1.1.6 mrg }
420 1.1.1.6 mrg else
421 1.1.1.6 mrg return 0;
422 1.1.1.6 mrg
423 1.1.1.6 mrg return !rdm.errored;
424 1.1.1.6 mrg }
425 1.1.1.6 mrg
426 1.1.1.6 mrg /* Growable string buffers. */
427 1.1.1.6 mrg struct str_buf
428 1.1.1.6 mrg {
429 1.1.1.6 mrg char *ptr;
430 1.1.1.6 mrg size_t len;
431 1.1.1.6 mrg size_t cap;
432 1.1.1.6 mrg int errored;
433 1.1.1.6 mrg };
434 1.1.1.6 mrg
435 1.1.1.6 mrg static void
436 1.1.1.6 mrg str_buf_reserve (struct str_buf *buf, size_t extra)
437 1.1.1.6 mrg {
438 1.1.1.6 mrg size_t available, min_new_cap, new_cap;
439 1.1.1.6 mrg char *new_ptr;
440 1.1.1.6 mrg
441 1.1.1.6 mrg /* Allocation failed before. */
442 1.1.1.6 mrg if (buf->errored)
443 1.1.1.6 mrg return;
444 1.1.1.6 mrg
445 1.1.1.6 mrg available = buf->cap - buf->len;
446 1.1.1.6 mrg
447 1.1.1.6 mrg if (extra <= available)
448 1.1 mrg return;
449 1.1 mrg
450 1.1.1.6 mrg min_new_cap = buf->cap + (extra - available);
451 1.1.1.6 mrg
452 1.1.1.6 mrg /* Check for overflows. */
453 1.1.1.6 mrg if (min_new_cap < buf->cap)
454 1.1.1.6 mrg {
455 1.1.1.6 mrg buf->errored = 1;
456 1.1.1.6 mrg return;
457 1.1.1.6 mrg }
458 1.1.1.6 mrg
459 1.1.1.6 mrg new_cap = buf->cap;
460 1.1.1.6 mrg
461 1.1.1.6 mrg if (new_cap == 0)
462 1.1.1.6 mrg new_cap = 4;
463 1.1.1.6 mrg
464 1.1.1.6 mrg /* Double capacity until sufficiently large. */
465 1.1.1.6 mrg while (new_cap < min_new_cap)
466 1.1.1.6 mrg {
467 1.1.1.6 mrg new_cap *= 2;
468 1.1.1.6 mrg
469 1.1.1.6 mrg /* Check for overflows. */
470 1.1.1.6 mrg if (new_cap < buf->cap)
471 1.1.1.6 mrg {
472 1.1.1.6 mrg buf->errored = 1;
473 1.1.1.6 mrg return;
474 1.1.1.6 mrg }
475 1.1.1.6 mrg }
476 1.1.1.6 mrg
477 1.1.1.6 mrg new_ptr = (char *)realloc (buf->ptr, new_cap);
478 1.1.1.6 mrg if (new_ptr == NULL)
479 1.1.1.6 mrg {
480 1.1.1.6 mrg free (buf->ptr);
481 1.1.1.6 mrg buf->ptr = NULL;
482 1.1.1.6 mrg buf->len = 0;
483 1.1.1.6 mrg buf->cap = 0;
484 1.1.1.6 mrg buf->errored = 1;
485 1.1.1.6 mrg }
486 1.1.1.6 mrg else
487 1.1.1.6 mrg {
488 1.1.1.6 mrg buf->ptr = new_ptr;
489 1.1.1.6 mrg buf->cap = new_cap;
490 1.1.1.6 mrg }
491 1.1 mrg }
492 1.1 mrg
493 1.1.1.6 mrg static void
494 1.1.1.6 mrg str_buf_append (struct str_buf *buf, const char *data, size_t len)
495 1.1 mrg {
496 1.1.1.6 mrg str_buf_reserve (buf, len);
497 1.1.1.6 mrg if (buf->errored)
498 1.1.1.6 mrg return;
499 1.1 mrg
500 1.1.1.6 mrg memcpy (buf->ptr + buf->len, data, len);
501 1.1.1.6 mrg buf->len += len;
502 1.1.1.6 mrg }
503 1.1 mrg
504 1.1.1.6 mrg static void
505 1.1.1.6 mrg str_buf_demangle_callback (const char *data, size_t len, void *opaque)
506 1.1.1.6 mrg {
507 1.1.1.6 mrg str_buf_append ((struct str_buf *)opaque, data, len);
508 1.1.1.6 mrg }
509 1.1.1.6 mrg
510 1.1.1.6 mrg char *
511 1.1.1.6 mrg rust_demangle (const char *mangled, int options)
512 1.1.1.6 mrg {
513 1.1.1.6 mrg struct str_buf out;
514 1.1.1.6 mrg int success;
515 1.1 mrg
516 1.1.1.6 mrg out.ptr = NULL;
517 1.1.1.6 mrg out.len = 0;
518 1.1.1.6 mrg out.cap = 0;
519 1.1.1.6 mrg out.errored = 0;
520 1.1.1.6 mrg
521 1.1.1.6 mrg success = rust_demangle_callback (mangled, options,
522 1.1.1.6 mrg str_buf_demangle_callback, &out);
523 1.1.1.6 mrg
524 1.1.1.6 mrg if (!success)
525 1.1.1.6 mrg {
526 1.1.1.6 mrg free (out.ptr);
527 1.1.1.6 mrg return NULL;
528 1.1.1.6 mrg }
529 1.1 mrg
530 1.1.1.6 mrg str_buf_append (&out, "\0", 1);
531 1.1.1.6 mrg return out.ptr;
532 1.1 mrg }
533