/src/brpc/src/butil/third_party/symbolize/demangle.cc
Line | Count | Source |
1 | | // Copyright (c) 2006, Google Inc. |
2 | | // All rights reserved. |
3 | | // |
4 | | // Redistribution and use in source and binary forms, with or without |
5 | | // modification, are permitted provided that the following conditions are |
6 | | // met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright |
9 | | // notice, this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above |
11 | | // copyright notice, this list of conditions and the following disclaimer |
12 | | // in the documentation and/or other materials provided with the |
13 | | // distribution. |
14 | | // * Neither the name of Google Inc. nor the names of its |
15 | | // contributors may be used to endorse or promote products derived from |
16 | | // this software without specific prior written permission. |
17 | | // |
18 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | | // |
30 | | // Author: Satoru Takabayashi |
31 | | // |
32 | | // For reference check out: |
33 | | // http://www.codesourcery.com/public/cxx-abi/abi.html#mangling |
34 | | // |
35 | | // Note that we only have partial C++0x support yet. |
36 | | |
37 | | #include <stdio.h> // for NULL |
38 | | #include "demangle.h" |
39 | | |
40 | | _START_GOOGLE_NAMESPACE_ |
41 | | |
42 | | typedef struct { |
43 | | const char *abbrev; |
44 | | const char *real_name; |
45 | | } AbbrevPair; |
46 | | |
47 | | // List of operators from Itanium C++ ABI. |
48 | | static const AbbrevPair kOperatorList[] = { |
49 | | { "nw", "new" }, |
50 | | { "na", "new[]" }, |
51 | | { "dl", "delete" }, |
52 | | { "da", "delete[]" }, |
53 | | { "ps", "+" }, |
54 | | { "ng", "-" }, |
55 | | { "ad", "&" }, |
56 | | { "de", "*" }, |
57 | | { "co", "~" }, |
58 | | { "pl", "+" }, |
59 | | { "mi", "-" }, |
60 | | { "ml", "*" }, |
61 | | { "dv", "/" }, |
62 | | { "rm", "%" }, |
63 | | { "an", "&" }, |
64 | | { "or", "|" }, |
65 | | { "eo", "^" }, |
66 | | { "aS", "=" }, |
67 | | { "pL", "+=" }, |
68 | | { "mI", "-=" }, |
69 | | { "mL", "*=" }, |
70 | | { "dV", "/=" }, |
71 | | { "rM", "%=" }, |
72 | | { "aN", "&=" }, |
73 | | { "oR", "|=" }, |
74 | | { "eO", "^=" }, |
75 | | { "ls", "<<" }, |
76 | | { "rs", ">>" }, |
77 | | { "lS", "<<=" }, |
78 | | { "rS", ">>=" }, |
79 | | { "eq", "==" }, |
80 | | { "ne", "!=" }, |
81 | | { "lt", "<" }, |
82 | | { "gt", ">" }, |
83 | | { "le", "<=" }, |
84 | | { "ge", ">=" }, |
85 | | { "nt", "!" }, |
86 | | { "aa", "&&" }, |
87 | | { "oo", "||" }, |
88 | | { "pp", "++" }, |
89 | | { "mm", "--" }, |
90 | | { "cm", "," }, |
91 | | { "pm", "->*" }, |
92 | | { "pt", "->" }, |
93 | | { "cl", "()" }, |
94 | | { "ix", "[]" }, |
95 | | { "qu", "?" }, |
96 | | { "st", "sizeof" }, |
97 | | { "sz", "sizeof" }, |
98 | | { NULL, NULL }, |
99 | | }; |
100 | | |
101 | | // List of builtin types from Itanium C++ ABI. |
102 | | static const AbbrevPair kBuiltinTypeList[] = { |
103 | | { "v", "void" }, |
104 | | { "w", "wchar_t" }, |
105 | | { "b", "bool" }, |
106 | | { "c", "char" }, |
107 | | { "a", "signed char" }, |
108 | | { "h", "unsigned char" }, |
109 | | { "s", "short" }, |
110 | | { "t", "unsigned short" }, |
111 | | { "i", "int" }, |
112 | | { "j", "unsigned int" }, |
113 | | { "l", "long" }, |
114 | | { "m", "unsigned long" }, |
115 | | { "x", "long long" }, |
116 | | { "y", "unsigned long long" }, |
117 | | { "n", "__int128" }, |
118 | | { "o", "unsigned __int128" }, |
119 | | { "f", "float" }, |
120 | | { "d", "double" }, |
121 | | { "e", "long double" }, |
122 | | { "g", "__float128" }, |
123 | | { "z", "ellipsis" }, |
124 | | { NULL, NULL } |
125 | | }; |
126 | | |
127 | | // List of substitutions Itanium C++ ABI. |
128 | | static const AbbrevPair kSubstitutionList[] = { |
129 | | { "St", "" }, |
130 | | { "Sa", "allocator" }, |
131 | | { "Sb", "basic_string" }, |
132 | | // std::basic_string<char, std::char_traits<char>,std::allocator<char> > |
133 | | { "Ss", "string"}, |
134 | | // std::basic_istream<char, std::char_traits<char> > |
135 | | { "Si", "istream" }, |
136 | | // std::basic_ostream<char, std::char_traits<char> > |
137 | | { "So", "ostream" }, |
138 | | // std::basic_iostream<char, std::char_traits<char> > |
139 | | { "Sd", "iostream" }, |
140 | | { NULL, NULL } |
141 | | }; |
142 | | |
143 | | // State needed for demangling. |
144 | | typedef struct { |
145 | | const char *mangled_cur; // Cursor of mangled name. |
146 | | char *out_cur; // Cursor of output string. |
147 | | const char *out_begin; // Beginning of output string. |
148 | | const char *out_end; // End of output string. |
149 | | const char *prev_name; // For constructors/destructors. |
150 | | int prev_name_length; // For constructors/destructors. |
151 | | short nest_level; // For nested names. |
152 | | bool append; // Append flag. |
153 | | bool overflowed; // True if output gets overflowed. |
154 | | } State; |
155 | | |
156 | | // We don't use strlen() in libc since it's not guaranteed to be async |
157 | | // signal safe. |
158 | 24.8k | static size_t StrLen(const char *str) { |
159 | 24.8k | size_t len = 0; |
160 | 78.0k | while (*str != '\0') { |
161 | 53.2k | ++str; |
162 | 53.2k | ++len; |
163 | 53.2k | } |
164 | 24.8k | return len; |
165 | 24.8k | } |
166 | | |
167 | | // Returns true if "str" has at least "n" characters remaining. |
168 | 54.7k | static bool AtLeastNumCharsRemaining(const char *str, int n) { |
169 | 205k | for (int i = 0; i < n; ++i) { |
170 | 157k | if (str[i] == '\0') { |
171 | 7.06k | return false; |
172 | 7.06k | } |
173 | 157k | } |
174 | 47.6k | return true; |
175 | 54.7k | } |
176 | | |
177 | | // Returns true if "str" has "prefix" as a prefix. |
178 | 230 | static bool StrPrefix(const char *str, const char *prefix) { |
179 | 230 | size_t i = 0; |
180 | 230 | while (str[i] != '\0' && prefix[i] != '\0' && |
181 | 230 | str[i] == prefix[i]) { |
182 | 0 | ++i; |
183 | 0 | } |
184 | 230 | return prefix[i] == '\0'; // Consumed everything in "prefix". |
185 | 230 | } |
186 | | |
187 | | static void InitState(State *state, const char *mangled, |
188 | 4.76k | char *out, int out_size) { |
189 | 4.76k | state->mangled_cur = mangled; |
190 | 4.76k | state->out_cur = out; |
191 | 4.76k | state->out_begin = out; |
192 | 4.76k | state->out_end = out + out_size; |
193 | 4.76k | state->prev_name = NULL; |
194 | 4.76k | state->prev_name_length = -1; |
195 | 4.76k | state->nest_level = -1; |
196 | 4.76k | state->append = true; |
197 | 4.76k | state->overflowed = false; |
198 | 4.76k | } |
199 | | |
200 | | // Returns true and advances "mangled_cur" if we find "one_char_token" |
201 | | // at "mangled_cur" position. It is assumed that "one_char_token" does |
202 | | // not contain '\0'. |
203 | 571k | static bool ParseOneCharToken(State *state, const char one_char_token) { |
204 | 571k | if (state->mangled_cur[0] == one_char_token) { |
205 | 53.2k | ++state->mangled_cur; |
206 | 53.2k | return true; |
207 | 53.2k | } |
208 | 518k | return false; |
209 | 571k | } |
210 | | |
211 | | // Returns true and advances "mangled_cur" if we find "two_char_token" |
212 | | // at "mangled_cur" position. It is assumed that "two_char_token" does |
213 | | // not contain '\0'. |
214 | 173k | static bool ParseTwoCharToken(State *state, const char *two_char_token) { |
215 | 173k | if (state->mangled_cur[0] == two_char_token[0] && |
216 | 37.5k | state->mangled_cur[1] == two_char_token[1]) { |
217 | 4.45k | state->mangled_cur += 2; |
218 | 4.45k | return true; |
219 | 4.45k | } |
220 | 169k | return false; |
221 | 173k | } |
222 | | |
223 | | // Returns true and advances "mangled_cur" if we find any character in |
224 | | // "char_class" at "mangled_cur" position. |
225 | 25.2k | static bool ParseCharClass(State *state, const char *char_class) { |
226 | 25.2k | const char *p = char_class; |
227 | 122k | for (; *p != '\0'; ++p) { |
228 | 104k | if (state->mangled_cur[0] == *p) { |
229 | 7.40k | ++state->mangled_cur; |
230 | 7.40k | return true; |
231 | 7.40k | } |
232 | 104k | } |
233 | 17.8k | return false; |
234 | 25.2k | } |
235 | | |
236 | | // This function is used for handling an optional non-terminal. |
237 | 4.45k | static bool Optional(bool) { |
238 | 4.45k | return true; |
239 | 4.45k | } |
240 | | |
241 | | // This function is used for handling <non-terminal>+ syntax. |
242 | | typedef bool (*ParseFunc)(State *); |
243 | 4.45k | static bool OneOrMore(ParseFunc parse_func, State *state) { |
244 | 4.45k | if (parse_func(state)) { |
245 | 13.3k | while (parse_func(state)) { |
246 | 8.91k | } |
247 | 4.45k | return true; |
248 | 4.45k | } |
249 | 0 | return false; |
250 | 4.45k | } |
251 | | |
252 | | // This function is used for handling <non-terminal>* syntax. The function |
253 | | // always returns true and must be followed by a termination token or a |
254 | | // terminating sequence not handled by parse_func (e.g. |
255 | | // ParseOneCharToken(state, 'E')). |
256 | 0 | static bool ZeroOrMore(ParseFunc parse_func, State *state) { |
257 | 0 | while (parse_func(state)) { |
258 | 0 | } |
259 | 0 | return true; |
260 | 0 | } |
261 | | |
262 | | // Append "str" at "out_cur". If there is an overflow, "overflowed" |
263 | | // is set to true for later use. The output string is ensured to |
264 | | // always terminate with '\0' as long as there is no overflow. |
265 | 38.6k | static void Append(State *state, const char * const str, const int length) { |
266 | 38.6k | int i; |
267 | 176k | for (i = 0; i < length; ++i) { |
268 | 137k | if (state->out_cur + 1 < state->out_end) { // +1 for '\0' |
269 | 137k | *state->out_cur = str[i]; |
270 | 137k | ++state->out_cur; |
271 | 137k | } else { |
272 | 0 | state->overflowed = true; |
273 | 0 | break; |
274 | 0 | } |
275 | 137k | } |
276 | 38.6k | if (!state->overflowed) { |
277 | 38.6k | *state->out_cur = '\0'; // Terminate it with '\0' |
278 | 38.6k | } |
279 | 38.6k | } |
280 | | |
281 | | // We don't use equivalents in libc to avoid locale issues. |
282 | 36.1k | static bool IsLower(char c) { |
283 | 36.1k | return c >= 'a' && c <= 'z'; |
284 | 36.1k | } |
285 | | |
286 | 38.6k | static bool IsAlpha(char c) { |
287 | 38.6k | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); |
288 | 38.6k | } |
289 | | |
290 | 76.9k | static bool IsDigit(char c) { |
291 | 76.9k | return c >= '0' && c <= '9'; |
292 | 76.9k | } |
293 | | |
294 | | // Returns true if "str" is a function clone suffix. These suffixes are used |
295 | | // by GCC 4.5.x and later versions to indicate functions which have been |
296 | | // cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as |
297 | | // a function clone suffix. |
298 | 0 | static bool IsFunctionCloneSuffix(const char *str) { |
299 | 0 | size_t i = 0; |
300 | 0 | while (str[i] != '\0') { |
301 | | // Consume a single .<alpha>+.<digit>+ sequence. |
302 | 0 | if (str[i] != '.' || !IsAlpha(str[i + 1])) { |
303 | 0 | return false; |
304 | 0 | } |
305 | 0 | i += 2; |
306 | 0 | while (IsAlpha(str[i])) { |
307 | 0 | ++i; |
308 | 0 | } |
309 | 0 | if (str[i] != '.' || !IsDigit(str[i + 1])) { |
310 | 0 | return false; |
311 | 0 | } |
312 | 0 | i += 2; |
313 | 0 | while (IsDigit(str[i])) { |
314 | 0 | ++i; |
315 | 0 | } |
316 | 0 | } |
317 | 0 | return true; // Consumed everything in "str". |
318 | 0 | } |
319 | | |
320 | | // Append "str" with some tweaks, iff "append" state is true. |
321 | | // Returns true so that it can be placed in "if" conditions. |
322 | | static void MaybeAppendWithLength(State *state, const char * const str, |
323 | 39.6k | const int length) { |
324 | 39.6k | if (state->append && length > 0) { |
325 | | // Append a space if the output buffer ends with '<' and "str" |
326 | | // starts with '<' to avoid <<<. |
327 | 38.6k | if (str[0] == '<' && state->out_begin < state->out_cur && |
328 | 230 | state->out_cur[-1] == '<') { |
329 | 0 | Append(state, " ", 1); |
330 | 0 | } |
331 | | // Remember the last identifier name for ctors/dtors. |
332 | 38.6k | if (IsAlpha(str[0]) || str[0] == '_') { |
333 | 17.3k | state->prev_name = state->out_cur; |
334 | 17.3k | state->prev_name_length = length; |
335 | 17.3k | } |
336 | 38.6k | Append(state, str, length); |
337 | 38.6k | } |
338 | 39.6k | } |
339 | | |
340 | | // A convenient wrapper arount MaybeAppendWithLength(). |
341 | 48.6k | static bool MaybeAppend(State *state, const char * const str) { |
342 | 48.6k | if (state->append) { |
343 | 24.8k | int length = StrLen(str); |
344 | 24.8k | MaybeAppendWithLength(state, str, length); |
345 | 24.8k | } |
346 | 48.6k | return true; |
347 | 48.6k | } |
348 | | |
349 | | // This function is used for handling nested names. |
350 | 4.45k | static bool EnterNestedName(State *state) { |
351 | 4.45k | state->nest_level = 0; |
352 | 4.45k | return true; |
353 | 4.45k | } |
354 | | |
355 | | // This function is used for handling nested names. |
356 | 4.45k | static bool LeaveNestedName(State *state, short prev_value) { |
357 | 4.45k | state->nest_level = prev_value; |
358 | 4.45k | return true; |
359 | 4.45k | } |
360 | | |
361 | | // Disable the append mode not to print function parameters, etc. |
362 | 15.2k | static bool DisableAppend(State *state) { |
363 | 15.2k | state->append = false; |
364 | 15.2k | return true; |
365 | 15.2k | } |
366 | | |
367 | | // Restore the append mode to the previous state. |
368 | 4.45k | static bool RestoreAppend(State *state, bool prev_value) { |
369 | 4.45k | state->append = prev_value; |
370 | 4.45k | return true; |
371 | 4.45k | } |
372 | | |
373 | | // Increase the nest level for nested names. |
374 | 19.2k | static void MaybeIncreaseNestLevel(State *state) { |
375 | 19.2k | if (state->nest_level > -1) { |
376 | 19.2k | ++state->nest_level; |
377 | 19.2k | } |
378 | 19.2k | } |
379 | | |
380 | | // Appends :: for nested names if necessary. |
381 | 24.6k | static void MaybeAppendSeparator(State *state) { |
382 | 24.6k | if (state->nest_level >= 1) { |
383 | 20.1k | MaybeAppend(state, "::"); |
384 | 20.1k | } |
385 | 24.6k | } |
386 | | |
387 | | // Cancel the last separator if necessary. |
388 | 5.37k | static void MaybeCancelLastSeparator(State *state) { |
389 | 5.37k | if (state->nest_level >= 1 && state->append && |
390 | 3.76k | state->out_begin <= state->out_cur - 2) { |
391 | 3.76k | state->out_cur -= 2; |
392 | 3.76k | *state->out_cur = '\0'; |
393 | 3.76k | } |
394 | 5.37k | } |
395 | | |
396 | | // Returns true if the identifier of the given length pointed to by |
397 | | // "mangled_cur" is anonymous namespace. |
398 | 11.5k | static bool IdentifierIsAnonymousNamespace(State *state, int length) { |
399 | 11.5k | static const char anon_prefix[] = "_GLOBAL__N_"; |
400 | 11.5k | return (length > (int)sizeof(anon_prefix) - 1 && // Should be longer. |
401 | 230 | StrPrefix(state->mangled_cur, anon_prefix)); |
402 | 11.5k | } |
403 | | |
404 | | // Forward declarations of our parsing functions. |
405 | | static bool ParseMangledName(State *state); |
406 | | static bool ParseEncoding(State *state); |
407 | | static bool ParseName(State *state); |
408 | | static bool ParseUnscopedName(State *state); |
409 | | static bool ParseUnscopedTemplateName(State *state); |
410 | | static bool ParseNestedName(State *state); |
411 | | static bool ParsePrefix(State *state); |
412 | | static bool ParseUnqualifiedName(State *state); |
413 | | static bool ParseSourceName(State *state); |
414 | | static bool ParseLocalSourceName(State *state); |
415 | | static bool ParseNumber(State *state, int *number_out); |
416 | | static bool ParseFloatNumber(State *state); |
417 | | static bool ParseSeqId(State *state); |
418 | | static bool ParseIdentifier(State *state, int length); |
419 | | static bool ParseOperatorName(State *state); |
420 | | static bool ParseSpecialName(State *state); |
421 | | static bool ParseCallOffset(State *state); |
422 | | static bool ParseNVOffset(State *state); |
423 | | static bool ParseVOffset(State *state); |
424 | | static bool ParseCtorDtorName(State *state); |
425 | | static bool ParseType(State *state); |
426 | | static bool ParseCVQualifiers(State *state); |
427 | | static bool ParseBuiltinType(State *state); |
428 | | static bool ParseFunctionType(State *state); |
429 | | static bool ParseBareFunctionType(State *state); |
430 | | static bool ParseClassEnumType(State *state); |
431 | | static bool ParseArrayType(State *state); |
432 | | static bool ParsePointerToMemberType(State *state); |
433 | | static bool ParseTemplateParam(State *state); |
434 | | static bool ParseTemplateTemplateParam(State *state); |
435 | | static bool ParseTemplateArgs(State *state); |
436 | | static bool ParseTemplateArg(State *state); |
437 | | static bool ParseExpression(State *state); |
438 | | static bool ParseExprPrimary(State *state); |
439 | | static bool ParseLocalName(State *state); |
440 | | static bool ParseDiscriminator(State *state); |
441 | | static bool ParseSubstitution(State *state); |
442 | | |
443 | | // Implementation note: the following code is a straightforward |
444 | | // translation of the Itanium C++ ABI defined in BNF with a couple of |
445 | | // exceptions. |
446 | | // |
447 | | // - Support GNU extensions not defined in the Itanium C++ ABI |
448 | | // - <prefix> and <template-prefix> are combined to avoid infinite loop |
449 | | // - Reorder patterns to shorten the code |
450 | | // - Reorder patterns to give greedier functions precedence |
451 | | // We'll mark "Less greedy than" for these cases in the code |
452 | | // |
453 | | // Each parsing function changes the state and returns true on |
454 | | // success. Otherwise, don't change the state and returns false. To |
455 | | // ensure that the state isn't changed in the latter case, we save the |
456 | | // original state before we call more than one parsing functions |
457 | | // consecutively with &&, and restore the state if unsuccessful. See |
458 | | // ParseEncoding() as an example of this convention. We follow the |
459 | | // convention throughout the code. |
460 | | // |
461 | | // Originally we tried to do demangling without following the full ABI |
462 | | // syntax but it turned out we needed to follow the full syntax to |
463 | | // parse complicated cases like nested template arguments. Note that |
464 | | // implementing a full-fledged demangler isn't trivial (libiberty's |
465 | | // cp-demangle.c has +4300 lines). |
466 | | // |
467 | | // Note that (foo) in <(foo) ...> is a modifier to be ignored. |
468 | | // |
469 | | // Reference: |
470 | | // - Itanium C++ ABI |
471 | | // <http://www.codesourcery.com/cxx-abi/abi.html#mangling> |
472 | | |
473 | | // <mangled-name> ::= _Z <encoding> |
474 | 4.76k | static bool ParseMangledName(State *state) { |
475 | 4.76k | return ParseTwoCharToken(state, "_Z") && ParseEncoding(state); |
476 | 4.76k | } |
477 | | |
478 | | // <encoding> ::= <(function) name> <bare-function-type> |
479 | | // ::= <(data) name> |
480 | | // ::= <special-name> |
481 | 3.53k | static bool ParseEncoding(State *state) { |
482 | 3.53k | State copy = *state; |
483 | 3.53k | if (ParseName(state) && ParseBareFunctionType(state)) { |
484 | 3.53k | return true; |
485 | 3.53k | } |
486 | 0 | *state = copy; |
487 | |
|
488 | 0 | if (ParseName(state) || ParseSpecialName(state)) { |
489 | 0 | return true; |
490 | 0 | } |
491 | 0 | return false; |
492 | 0 | } |
493 | | |
494 | | // <name> ::= <nested-name> |
495 | | // ::= <unscoped-template-name> <template-args> |
496 | | // ::= <unscoped-name> |
497 | | // ::= <local-name> |
498 | 15.9k | static bool ParseName(State *state) { |
499 | 15.9k | if (ParseNestedName(state) || ParseLocalName(state)) { |
500 | 4.45k | return true; |
501 | 4.45k | } |
502 | | |
503 | 11.5k | State copy = *state; |
504 | 11.5k | if (ParseUnscopedTemplateName(state) && |
505 | 7.07k | ParseTemplateArgs(state)) { |
506 | 0 | return true; |
507 | 0 | } |
508 | 11.5k | *state = copy; |
509 | | |
510 | | // Less greedy than <unscoped-template-name> <template-args>. |
511 | 11.5k | if (ParseUnscopedName(state)) { |
512 | 0 | return true; |
513 | 0 | } |
514 | 11.5k | return false; |
515 | 11.5k | } |
516 | | |
517 | | // <unscoped-name> ::= <unqualified-name> |
518 | | // ::= St <unqualified-name> |
519 | 43.2k | static bool ParseUnscopedName(State *state) { |
520 | 43.2k | if (ParseUnqualifiedName(state)) { |
521 | 14.8k | return true; |
522 | 14.8k | } |
523 | | |
524 | 28.4k | State copy = *state; |
525 | 28.4k | if (ParseTwoCharToken(state, "St") && |
526 | 0 | MaybeAppend(state, "std::") && |
527 | 0 | ParseUnqualifiedName(state)) { |
528 | 0 | return true; |
529 | 0 | } |
530 | 28.4k | *state = copy; |
531 | 28.4k | return false; |
532 | 28.4k | } |
533 | | |
534 | | // <unscoped-template-name> ::= <unscoped-name> |
535 | | // ::= <substitution> |
536 | 11.5k | static bool ParseUnscopedTemplateName(State *state) { |
537 | 11.5k | return ParseUnscopedName(state) || ParseSubstitution(state); |
538 | 11.5k | } |
539 | | |
540 | | // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E |
541 | | // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E |
542 | 15.9k | static bool ParseNestedName(State *state) { |
543 | 15.9k | State copy = *state; |
544 | 15.9k | if (ParseOneCharToken(state, 'N') && |
545 | 4.45k | EnterNestedName(state) && |
546 | 4.45k | Optional(ParseCVQualifiers(state)) && |
547 | 4.45k | ParsePrefix(state) && |
548 | 4.45k | LeaveNestedName(state, copy.nest_level) && |
549 | 4.45k | ParseOneCharToken(state, 'E')) { |
550 | 4.45k | return true; |
551 | 4.45k | } |
552 | 11.5k | *state = copy; |
553 | 11.5k | return false; |
554 | 15.9k | } |
555 | | |
556 | | // This part is tricky. If we literally translate them to code, we'll |
557 | | // end up infinite loop. Hence we merge them to avoid the case. |
558 | | // |
559 | | // <prefix> ::= <prefix> <unqualified-name> |
560 | | // ::= <template-prefix> <template-args> |
561 | | // ::= <template-param> |
562 | | // ::= <substitution> |
563 | | // ::= # empty |
564 | | // <template-prefix> ::= <prefix> <(template) unqualified-name> |
565 | | // ::= <template-param> |
566 | | // ::= <substitution> |
567 | 5.37k | static bool ParsePrefix(State *state) { |
568 | 5.37k | bool has_something = false; |
569 | 24.6k | while (true) { |
570 | 24.6k | MaybeAppendSeparator(state); |
571 | 24.6k | if (ParseTemplateParam(state) || |
572 | 24.6k | ParseSubstitution(state) || |
573 | 20.1k | ParseUnscopedName(state)) { |
574 | 19.2k | has_something = true; |
575 | 19.2k | MaybeIncreaseNestLevel(state); |
576 | 19.2k | continue; |
577 | 19.2k | } |
578 | 5.37k | MaybeCancelLastSeparator(state); |
579 | 5.37k | if (has_something && ParseTemplateArgs(state)) { |
580 | 920 | return ParsePrefix(state); |
581 | 4.45k | } else { |
582 | 4.45k | break; |
583 | 4.45k | } |
584 | 5.37k | } |
585 | 4.45k | return true; |
586 | 5.37k | } |
587 | | |
588 | | // <unqualified-name> ::= <operator-name> |
589 | | // ::= <ctor-dtor-name> |
590 | | // ::= <source-name> |
591 | | // ::= <local-source-name> |
592 | 43.2k | static bool ParseUnqualifiedName(State *state) { |
593 | 43.2k | return (ParseOperatorName(state) || |
594 | 43.2k | ParseCtorDtorName(state) || |
595 | 39.9k | ParseSourceName(state) || |
596 | 28.4k | ParseLocalSourceName(state)); |
597 | 43.2k | } |
598 | | |
599 | | // <source-name> ::= <positive length number> <identifier> |
600 | 39.9k | static bool ParseSourceName(State *state) { |
601 | 39.9k | State copy = *state; |
602 | 39.9k | int length = -1; |
603 | 39.9k | if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { |
604 | 11.5k | return true; |
605 | 11.5k | } |
606 | 28.4k | *state = copy; |
607 | 28.4k | return false; |
608 | 39.9k | } |
609 | | |
610 | | // <local-source-name> ::= L <source-name> [<discriminator>] |
611 | | // |
612 | | // References: |
613 | | // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 |
614 | | // http://gcc.gnu.org/viewcvs?view=rev&revision=124467 |
615 | 28.4k | static bool ParseLocalSourceName(State *state) { |
616 | 28.4k | State copy = *state; |
617 | 28.4k | if (ParseOneCharToken(state, 'L') && ParseSourceName(state) && |
618 | 0 | Optional(ParseDiscriminator(state))) { |
619 | 0 | return true; |
620 | 0 | } |
621 | 28.4k | *state = copy; |
622 | 28.4k | return false; |
623 | 28.4k | } |
624 | | |
625 | | // <number> ::= [n] <non-negative decimal integer> |
626 | | // If "number_out" is non-null, then *number_out is set to the value of the |
627 | | // parsed number on success. |
628 | 39.9k | static bool ParseNumber(State *state, int *number_out) { |
629 | 39.9k | int sign = 1; |
630 | 39.9k | if (ParseOneCharToken(state, 'n')) { |
631 | 0 | sign = -1; |
632 | 0 | } |
633 | 39.9k | const char *p = state->mangled_cur; |
634 | 39.9k | int number = 0; |
635 | 52.1k | for (;*p != '\0'; ++p) { |
636 | 45.0k | if (IsDigit(*p)) { |
637 | 12.2k | number = number * 10 + (*p - '0'); |
638 | 32.8k | } else { |
639 | 32.8k | break; |
640 | 32.8k | } |
641 | 45.0k | } |
642 | 39.9k | if (p != state->mangled_cur) { // Conversion succeeded. |
643 | 11.5k | state->mangled_cur = p; |
644 | 11.5k | if (number_out != NULL) { |
645 | 11.5k | *number_out = number * sign; |
646 | 11.5k | } |
647 | 11.5k | return true; |
648 | 11.5k | } |
649 | 28.4k | return false; |
650 | 39.9k | } |
651 | | |
652 | | // Floating-point literals are encoded using a fixed-length lowercase |
653 | | // hexadecimal string. |
654 | 0 | static bool ParseFloatNumber(State *state) { |
655 | 0 | const char *p = state->mangled_cur; |
656 | 0 | for (;*p != '\0'; ++p) { |
657 | 0 | if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) { |
658 | 0 | break; |
659 | 0 | } |
660 | 0 | } |
661 | 0 | if (p != state->mangled_cur) { // Conversion succeeded. |
662 | 0 | state->mangled_cur = p; |
663 | 0 | return true; |
664 | 0 | } |
665 | 0 | return false; |
666 | 0 | } |
667 | | |
668 | | // The <seq-id> is a sequence number in base 36, |
669 | | // using digits and upper case letters |
670 | 17.6k | static bool ParseSeqId(State *state) { |
671 | 17.6k | const char *p = state->mangled_cur; |
672 | 31.8k | for (;*p != '\0'; ++p) { |
673 | 31.8k | if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) { |
674 | 17.6k | break; |
675 | 17.6k | } |
676 | 31.8k | } |
677 | 17.6k | if (p != state->mangled_cur) { // Conversion succeeded. |
678 | 14.1k | state->mangled_cur = p; |
679 | 14.1k | return true; |
680 | 14.1k | } |
681 | 3.53k | return false; |
682 | 17.6k | } |
683 | | |
684 | | // <identifier> ::= <unqualified source code identifier> (of given length) |
685 | 11.5k | static bool ParseIdentifier(State *state, int length) { |
686 | 11.5k | if (length == -1 || |
687 | 11.5k | !AtLeastNumCharsRemaining(state->mangled_cur, length)) { |
688 | 0 | return false; |
689 | 0 | } |
690 | 11.5k | if (IdentifierIsAnonymousNamespace(state, length)) { |
691 | 0 | MaybeAppend(state, "(anonymous namespace)"); |
692 | 11.5k | } else { |
693 | 11.5k | MaybeAppendWithLength(state, state->mangled_cur, length); |
694 | 11.5k | } |
695 | 11.5k | state->mangled_cur += length; |
696 | 11.5k | return true; |
697 | 11.5k | } |
698 | | |
699 | | // <operator-name> ::= nw, and other two letters cases |
700 | | // ::= cv <type> # (cast) |
701 | | // ::= v <digit> <source-name> # vendor extended operator |
702 | 43.2k | static bool ParseOperatorName(State *state) { |
703 | 43.2k | if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) { |
704 | 7.06k | return false; |
705 | 7.06k | } |
706 | | // First check with "cv" (cast) case. |
707 | 36.1k | State copy = *state; |
708 | 36.1k | if (ParseTwoCharToken(state, "cv") && |
709 | 0 | MaybeAppend(state, "operator ") && |
710 | 0 | EnterNestedName(state) && |
711 | 0 | ParseType(state) && |
712 | 0 | LeaveNestedName(state, copy.nest_level)) { |
713 | 0 | return true; |
714 | 0 | } |
715 | 36.1k | *state = copy; |
716 | | |
717 | | // Then vendor extended operators. |
718 | 36.1k | if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") && |
719 | 0 | ParseSourceName(state)) { |
720 | 0 | return true; |
721 | 0 | } |
722 | 36.1k | *state = copy; |
723 | | |
724 | | // Other operator names should start with a lower alphabet followed |
725 | | // by a lower/upper alphabet. |
726 | 36.1k | if (!(IsLower(state->mangled_cur[0]) && |
727 | 36.1k | IsAlpha(state->mangled_cur[1]))) { |
728 | 36.1k | return false; |
729 | 36.1k | } |
730 | | // We may want to perform a binary search if we really need speed. |
731 | 0 | const AbbrevPair *p; |
732 | 0 | for (p = kOperatorList; p->abbrev != NULL; ++p) { |
733 | 0 | if (state->mangled_cur[0] == p->abbrev[0] && |
734 | 0 | state->mangled_cur[1] == p->abbrev[1]) { |
735 | 0 | MaybeAppend(state, "operator"); |
736 | 0 | if (IsLower(*p->real_name)) { // new, delete, etc. |
737 | 0 | MaybeAppend(state, " "); |
738 | 0 | } |
739 | 0 | MaybeAppend(state, p->real_name); |
740 | 0 | state->mangled_cur += 2; |
741 | 0 | return true; |
742 | 0 | } |
743 | 0 | } |
744 | 0 | return false; |
745 | 0 | } |
746 | | |
747 | | // <special-name> ::= TV <type> |
748 | | // ::= TT <type> |
749 | | // ::= TI <type> |
750 | | // ::= TS <type> |
751 | | // ::= Tc <call-offset> <call-offset> <(base) encoding> |
752 | | // ::= GV <(object) name> |
753 | | // ::= T <call-offset> <(base) encoding> |
754 | | // G++ extensions: |
755 | | // ::= TC <type> <(offset) number> _ <(base) type> |
756 | | // ::= TF <type> |
757 | | // ::= TJ <type> |
758 | | // ::= GR <name> |
759 | | // ::= GA <encoding> |
760 | | // ::= Th <call-offset> <(base) encoding> |
761 | | // ::= Tv <call-offset> <(base) encoding> |
762 | | // |
763 | | // Note: we don't care much about them since they don't appear in |
764 | | // stack traces. The are special data. |
765 | 0 | static bool ParseSpecialName(State *state) { |
766 | 0 | State copy = *state; |
767 | 0 | if (ParseOneCharToken(state, 'T') && |
768 | 0 | ParseCharClass(state, "VTIS") && |
769 | 0 | ParseType(state)) { |
770 | 0 | return true; |
771 | 0 | } |
772 | 0 | *state = copy; |
773 | |
|
774 | 0 | if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) && |
775 | 0 | ParseCallOffset(state) && ParseEncoding(state)) { |
776 | 0 | return true; |
777 | 0 | } |
778 | 0 | *state = copy; |
779 | |
|
780 | 0 | if (ParseTwoCharToken(state, "GV") && |
781 | 0 | ParseName(state)) { |
782 | 0 | return true; |
783 | 0 | } |
784 | 0 | *state = copy; |
785 | |
|
786 | 0 | if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) && |
787 | 0 | ParseEncoding(state)) { |
788 | 0 | return true; |
789 | 0 | } |
790 | 0 | *state = copy; |
791 | | |
792 | | // G++ extensions |
793 | 0 | if (ParseTwoCharToken(state, "TC") && ParseType(state) && |
794 | 0 | ParseNumber(state, NULL) && ParseOneCharToken(state, '_') && |
795 | 0 | DisableAppend(state) && |
796 | 0 | ParseType(state)) { |
797 | 0 | RestoreAppend(state, copy.append); |
798 | 0 | return true; |
799 | 0 | } |
800 | 0 | *state = copy; |
801 | |
|
802 | 0 | if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") && |
803 | 0 | ParseType(state)) { |
804 | 0 | return true; |
805 | 0 | } |
806 | 0 | *state = copy; |
807 | |
|
808 | 0 | if (ParseTwoCharToken(state, "GR") && ParseName(state)) { |
809 | 0 | return true; |
810 | 0 | } |
811 | 0 | *state = copy; |
812 | |
|
813 | 0 | if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) { |
814 | 0 | return true; |
815 | 0 | } |
816 | 0 | *state = copy; |
817 | |
|
818 | 0 | if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") && |
819 | 0 | ParseCallOffset(state) && ParseEncoding(state)) { |
820 | 0 | return true; |
821 | 0 | } |
822 | 0 | *state = copy; |
823 | 0 | return false; |
824 | 0 | } |
825 | | |
826 | | // <call-offset> ::= h <nv-offset> _ |
827 | | // ::= v <v-offset> _ |
828 | 0 | static bool ParseCallOffset(State *state) { |
829 | 0 | State copy = *state; |
830 | 0 | if (ParseOneCharToken(state, 'h') && |
831 | 0 | ParseNVOffset(state) && ParseOneCharToken(state, '_')) { |
832 | 0 | return true; |
833 | 0 | } |
834 | 0 | *state = copy; |
835 | |
|
836 | 0 | if (ParseOneCharToken(state, 'v') && |
837 | 0 | ParseVOffset(state) && ParseOneCharToken(state, '_')) { |
838 | 0 | return true; |
839 | 0 | } |
840 | 0 | *state = copy; |
841 | |
|
842 | 0 | return false; |
843 | 0 | } |
844 | | |
845 | | // <nv-offset> ::= <(offset) number> |
846 | 0 | static bool ParseNVOffset(State *state) { |
847 | 0 | return ParseNumber(state, NULL); |
848 | 0 | } |
849 | | |
850 | | // <v-offset> ::= <(offset) number> _ <(virtual offset) number> |
851 | 0 | static bool ParseVOffset(State *state) { |
852 | 0 | State copy = *state; |
853 | 0 | if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') && |
854 | 0 | ParseNumber(state, NULL)) { |
855 | 0 | return true; |
856 | 0 | } |
857 | 0 | *state = copy; |
858 | 0 | return false; |
859 | 0 | } |
860 | | |
861 | | // <ctor-dtor-name> ::= C1 | C2 | C3 |
862 | | // ::= D0 | D1 | D2 |
863 | 43.2k | static bool ParseCtorDtorName(State *state) { |
864 | 43.2k | State copy = *state; |
865 | 43.2k | if (ParseOneCharToken(state, 'C') && |
866 | 3.30k | ParseCharClass(state, "123")) { |
867 | 3.30k | const char * const prev_name = state->prev_name; |
868 | 3.30k | const int prev_name_length = state->prev_name_length; |
869 | 3.30k | MaybeAppendWithLength(state, prev_name, prev_name_length); |
870 | 3.30k | return true; |
871 | 3.30k | } |
872 | 39.9k | *state = copy; |
873 | | |
874 | 39.9k | if (ParseOneCharToken(state, 'D') && |
875 | 0 | ParseCharClass(state, "012")) { |
876 | 0 | const char * const prev_name = state->prev_name; |
877 | 0 | const int prev_name_length = state->prev_name_length; |
878 | 0 | MaybeAppend(state, "~"); |
879 | 0 | MaybeAppendWithLength(state, prev_name, prev_name_length); |
880 | 0 | return true; |
881 | 0 | } |
882 | 39.9k | *state = copy; |
883 | 39.9k | return false; |
884 | 39.9k | } |
885 | | |
886 | | // <type> ::= <CV-qualifiers> <type> |
887 | | // ::= P <type> # pointer-to |
888 | | // ::= R <type> # reference-to |
889 | | // ::= O <type> # rvalue reference-to (C++0x) |
890 | | // ::= C <type> # complex pair (C 2000) |
891 | | // ::= G <type> # imaginary (C 2000) |
892 | | // ::= U <source-name> <type> # vendor extended type qualifier |
893 | | // ::= <builtin-type> |
894 | | // ::= <function-type> |
895 | | // ::= <class-enum-type> |
896 | | // ::= <array-type> |
897 | | // ::= <pointer-to-member-type> |
898 | | // ::= <template-template-param> <template-args> |
899 | | // ::= <template-param> |
900 | | // ::= <substitution> |
901 | | // ::= Dp <type> # pack expansion of (C++0x) |
902 | | // ::= Dt <expression> E # decltype of an id-expression or class |
903 | | // # member access (C++0x) |
904 | | // ::= DT <expression> E # decltype of an expression (C++0x) |
905 | | // |
906 | 25.6k | static bool ParseType(State *state) { |
907 | | // We should check CV-qualifers, and PRGC things first. |
908 | 25.6k | State copy = *state; |
909 | 25.6k | if (ParseCVQualifiers(state) && ParseType(state)) { |
910 | 3.76k | return true; |
911 | 3.76k | } |
912 | 21.9k | *state = copy; |
913 | | |
914 | 21.9k | if (ParseCharClass(state, "OPRCG") && ParseType(state)) { |
915 | 4.10k | return true; |
916 | 4.10k | } |
917 | 17.8k | *state = copy; |
918 | | |
919 | 17.8k | if (ParseTwoCharToken(state, "Dp") && ParseType(state)) { |
920 | 0 | return true; |
921 | 0 | } |
922 | 17.8k | *state = copy; |
923 | | |
924 | 17.8k | if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") && |
925 | 0 | ParseExpression(state) && ParseOneCharToken(state, 'E')) { |
926 | 0 | return true; |
927 | 0 | } |
928 | 17.8k | *state = copy; |
929 | | |
930 | 17.8k | if (ParseOneCharToken(state, 'U') && ParseSourceName(state) && |
931 | 0 | ParseType(state)) { |
932 | 0 | return true; |
933 | 0 | } |
934 | 17.8k | *state = copy; |
935 | | |
936 | 17.8k | if (ParseBuiltinType(state) || |
937 | 12.4k | ParseFunctionType(state) || |
938 | 12.4k | ParseClassEnumType(state) || |
939 | 11.5k | ParseArrayType(state) || |
940 | 11.5k | ParsePointerToMemberType(state) || |
941 | 13.3k | ParseSubstitution(state)) { |
942 | 13.3k | return true; |
943 | 13.3k | } |
944 | | |
945 | 4.45k | if (ParseTemplateTemplateParam(state) && |
946 | 0 | ParseTemplateArgs(state)) { |
947 | 0 | return true; |
948 | 0 | } |
949 | 4.45k | *state = copy; |
950 | | |
951 | | // Less greedy than <template-template-param> <template-args>. |
952 | 4.45k | if (ParseTemplateParam(state)) { |
953 | 0 | return true; |
954 | 0 | } |
955 | | |
956 | 4.45k | return false; |
957 | 4.45k | } |
958 | | |
959 | | // <CV-qualifiers> ::= [r] [V] [K] |
960 | | // We don't allow empty <CV-qualifiers> to avoid infinite loop in |
961 | | // ParseType(). |
962 | 30.1k | static bool ParseCVQualifiers(State *state) { |
963 | 30.1k | int num_cv_qualifiers = 0; |
964 | 30.1k | num_cv_qualifiers += ParseOneCharToken(state, 'r'); |
965 | 30.1k | num_cv_qualifiers += ParseOneCharToken(state, 'V'); |
966 | 30.1k | num_cv_qualifiers += ParseOneCharToken(state, 'K'); |
967 | 30.1k | return num_cv_qualifiers > 0; |
968 | 30.1k | } |
969 | | |
970 | | // <builtin-type> ::= v, etc. |
971 | | // ::= u <source-name> |
972 | 17.8k | static bool ParseBuiltinType(State *state) { |
973 | 17.8k | const AbbrevPair *p; |
974 | 313k | for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) { |
975 | 300k | if (state->mangled_cur[0] == p->abbrev[0]) { |
976 | 5.37k | MaybeAppend(state, p->real_name); |
977 | 5.37k | ++state->mangled_cur; |
978 | 5.37k | return true; |
979 | 5.37k | } |
980 | 300k | } |
981 | | |
982 | 12.4k | State copy = *state; |
983 | 12.4k | if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) { |
984 | 0 | return true; |
985 | 0 | } |
986 | 12.4k | *state = copy; |
987 | 12.4k | return false; |
988 | 12.4k | } |
989 | | |
990 | | // <function-type> ::= F [Y] <bare-function-type> E |
991 | 12.4k | static bool ParseFunctionType(State *state) { |
992 | 12.4k | State copy = *state; |
993 | 12.4k | if (ParseOneCharToken(state, 'F') && |
994 | 0 | Optional(ParseOneCharToken(state, 'Y')) && |
995 | 0 | ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) { |
996 | 0 | return true; |
997 | 0 | } |
998 | 12.4k | *state = copy; |
999 | 12.4k | return false; |
1000 | 12.4k | } |
1001 | | |
1002 | | // <bare-function-type> ::= <(signature) type>+ |
1003 | 3.53k | static bool ParseBareFunctionType(State *state) { |
1004 | 3.53k | State copy = *state; |
1005 | 3.53k | DisableAppend(state); |
1006 | 3.53k | if (OneOrMore(ParseType, state)) { |
1007 | 3.53k | RestoreAppend(state, copy.append); |
1008 | 3.53k | MaybeAppend(state, "()"); |
1009 | 3.53k | return true; |
1010 | 3.53k | } |
1011 | 0 | *state = copy; |
1012 | 0 | return false; |
1013 | 3.53k | } |
1014 | | |
1015 | | // <class-enum-type> ::= <name> |
1016 | 12.4k | static bool ParseClassEnumType(State *state) { |
1017 | 12.4k | return ParseName(state); |
1018 | 12.4k | } |
1019 | | |
1020 | | // <array-type> ::= A <(positive dimension) number> _ <(element) type> |
1021 | | // ::= A [<(dimension) expression>] _ <(element) type> |
1022 | 11.5k | static bool ParseArrayType(State *state) { |
1023 | 11.5k | State copy = *state; |
1024 | 11.5k | if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) && |
1025 | 0 | ParseOneCharToken(state, '_') && ParseType(state)) { |
1026 | 0 | return true; |
1027 | 0 | } |
1028 | 11.5k | *state = copy; |
1029 | | |
1030 | 11.5k | if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) && |
1031 | 0 | ParseOneCharToken(state, '_') && ParseType(state)) { |
1032 | 0 | return true; |
1033 | 0 | } |
1034 | 11.5k | *state = copy; |
1035 | 11.5k | return false; |
1036 | 11.5k | } |
1037 | | |
1038 | | // <pointer-to-member-type> ::= M <(class) type> <(member) type> |
1039 | 11.5k | static bool ParsePointerToMemberType(State *state) { |
1040 | 11.5k | State copy = *state; |
1041 | 11.5k | if (ParseOneCharToken(state, 'M') && ParseType(state) && |
1042 | 0 | ParseType(state)) { |
1043 | 0 | return true; |
1044 | 0 | } |
1045 | 11.5k | *state = copy; |
1046 | 11.5k | return false; |
1047 | 11.5k | } |
1048 | | |
1049 | | // <template-param> ::= T_ |
1050 | | // ::= T <parameter-2 non-negative number> _ |
1051 | 33.5k | static bool ParseTemplateParam(State *state) { |
1052 | 33.5k | if (ParseTwoCharToken(state, "T_")) { |
1053 | 0 | MaybeAppend(state, "?"); // We don't support template substitutions. |
1054 | 0 | return true; |
1055 | 0 | } |
1056 | | |
1057 | 33.5k | State copy = *state; |
1058 | 33.5k | if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) && |
1059 | 0 | ParseOneCharToken(state, '_')) { |
1060 | 0 | MaybeAppend(state, "?"); // We don't support template substitutions. |
1061 | 0 | return true; |
1062 | 0 | } |
1063 | 33.5k | *state = copy; |
1064 | 33.5k | return false; |
1065 | 33.5k | } |
1066 | | |
1067 | | |
1068 | | // <template-template-param> ::= <template-param> |
1069 | | // ::= <substitution> |
1070 | 4.45k | static bool ParseTemplateTemplateParam(State *state) { |
1071 | 4.45k | return (ParseTemplateParam(state) || |
1072 | 4.45k | ParseSubstitution(state)); |
1073 | 4.45k | } |
1074 | | |
1075 | | // <template-args> ::= I <template-arg>+ E |
1076 | 11.7k | static bool ParseTemplateArgs(State *state) { |
1077 | 11.7k | State copy = *state; |
1078 | 11.7k | DisableAppend(state); |
1079 | 11.7k | if (ParseOneCharToken(state, 'I') && |
1080 | 920 | OneOrMore(ParseTemplateArg, state) && |
1081 | 920 | ParseOneCharToken(state, 'E')) { |
1082 | 920 | RestoreAppend(state, copy.append); |
1083 | 920 | MaybeAppend(state, "<>"); |
1084 | 920 | return true; |
1085 | 920 | } |
1086 | 10.8k | *state = copy; |
1087 | 10.8k | return false; |
1088 | 11.7k | } |
1089 | | |
1090 | | // <template-arg> ::= <type> |
1091 | | // ::= <expr-primary> |
1092 | | // ::= I <template-arg>* E # argument pack |
1093 | | // ::= X <expression> E |
1094 | 2.30k | static bool ParseTemplateArg(State *state) { |
1095 | 2.30k | State copy = *state; |
1096 | 2.30k | if (ParseOneCharToken(state, 'I') && |
1097 | 0 | ZeroOrMore(ParseTemplateArg, state) && |
1098 | 0 | ParseOneCharToken(state, 'E')) { |
1099 | 0 | return true; |
1100 | 0 | } |
1101 | 2.30k | *state = copy; |
1102 | | |
1103 | 2.30k | if (ParseType(state) || |
1104 | 1.38k | ParseExprPrimary(state)) { |
1105 | 1.38k | return true; |
1106 | 1.38k | } |
1107 | 920 | *state = copy; |
1108 | | |
1109 | 920 | if (ParseOneCharToken(state, 'X') && ParseExpression(state) && |
1110 | 0 | ParseOneCharToken(state, 'E')) { |
1111 | 0 | return true; |
1112 | 0 | } |
1113 | 920 | *state = copy; |
1114 | 920 | return false; |
1115 | 920 | } |
1116 | | |
1117 | | // <expression> ::= <template-param> |
1118 | | // ::= <expr-primary> |
1119 | | // ::= <unary operator-name> <expression> |
1120 | | // ::= <binary operator-name> <expression> <expression> |
1121 | | // ::= <trinary operator-name> <expression> <expression> |
1122 | | // <expression> |
1123 | | // ::= st <type> |
1124 | | // ::= sr <type> <unqualified-name> <template-args> |
1125 | | // ::= sr <type> <unqualified-name> |
1126 | 0 | static bool ParseExpression(State *state) { |
1127 | 0 | if (ParseTemplateParam(state) || ParseExprPrimary(state)) { |
1128 | 0 | return true; |
1129 | 0 | } |
1130 | | |
1131 | 0 | State copy = *state; |
1132 | 0 | if (ParseOperatorName(state) && |
1133 | 0 | ParseExpression(state) && |
1134 | 0 | ParseExpression(state) && |
1135 | 0 | ParseExpression(state)) { |
1136 | 0 | return true; |
1137 | 0 | } |
1138 | 0 | *state = copy; |
1139 | |
|
1140 | 0 | if (ParseOperatorName(state) && |
1141 | 0 | ParseExpression(state) && |
1142 | 0 | ParseExpression(state)) { |
1143 | 0 | return true; |
1144 | 0 | } |
1145 | 0 | *state = copy; |
1146 | |
|
1147 | 0 | if (ParseOperatorName(state) && |
1148 | 0 | ParseExpression(state)) { |
1149 | 0 | return true; |
1150 | 0 | } |
1151 | 0 | *state = copy; |
1152 | |
|
1153 | 0 | if (ParseTwoCharToken(state, "st") && ParseType(state)) { |
1154 | 0 | return true; |
1155 | 0 | } |
1156 | 0 | *state = copy; |
1157 | |
|
1158 | 0 | if (ParseTwoCharToken(state, "sr") && ParseType(state) && |
1159 | 0 | ParseUnqualifiedName(state) && |
1160 | 0 | ParseTemplateArgs(state)) { |
1161 | 0 | return true; |
1162 | 0 | } |
1163 | 0 | *state = copy; |
1164 | |
|
1165 | 0 | if (ParseTwoCharToken(state, "sr") && ParseType(state) && |
1166 | 0 | ParseUnqualifiedName(state)) { |
1167 | 0 | return true; |
1168 | 0 | } |
1169 | 0 | *state = copy; |
1170 | 0 | return false; |
1171 | 0 | } |
1172 | | |
1173 | | // <expr-primary> ::= L <type> <(value) number> E |
1174 | | // ::= L <type> <(value) float> E |
1175 | | // ::= L <mangled-name> E |
1176 | | // // A bug in g++'s C++ ABI version 2 (-fabi-version=2). |
1177 | | // ::= LZ <encoding> E |
1178 | 920 | static bool ParseExprPrimary(State *state) { |
1179 | 920 | State copy = *state; |
1180 | 920 | if (ParseOneCharToken(state, 'L') && ParseType(state) && |
1181 | 0 | ParseNumber(state, NULL) && |
1182 | 0 | ParseOneCharToken(state, 'E')) { |
1183 | 0 | return true; |
1184 | 0 | } |
1185 | 920 | *state = copy; |
1186 | | |
1187 | 920 | if (ParseOneCharToken(state, 'L') && ParseType(state) && |
1188 | 0 | ParseFloatNumber(state) && |
1189 | 0 | ParseOneCharToken(state, 'E')) { |
1190 | 0 | return true; |
1191 | 0 | } |
1192 | 920 | *state = copy; |
1193 | | |
1194 | 920 | if (ParseOneCharToken(state, 'L') && ParseMangledName(state) && |
1195 | 0 | ParseOneCharToken(state, 'E')) { |
1196 | 0 | return true; |
1197 | 0 | } |
1198 | 920 | *state = copy; |
1199 | | |
1200 | 920 | if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) && |
1201 | 0 | ParseOneCharToken(state, 'E')) { |
1202 | 0 | return true; |
1203 | 0 | } |
1204 | 920 | *state = copy; |
1205 | | |
1206 | 920 | return false; |
1207 | 920 | } |
1208 | | |
1209 | | // <local-name> := Z <(function) encoding> E <(entity) name> |
1210 | | // [<discriminator>] |
1211 | | // := Z <(function) encoding> E s [<discriminator>] |
1212 | 11.5k | static bool ParseLocalName(State *state) { |
1213 | 11.5k | State copy = *state; |
1214 | 11.5k | if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && |
1215 | 0 | ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") && |
1216 | 0 | ParseName(state) && Optional(ParseDiscriminator(state))) { |
1217 | 0 | return true; |
1218 | 0 | } |
1219 | 11.5k | *state = copy; |
1220 | | |
1221 | 11.5k | if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && |
1222 | 0 | ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) { |
1223 | 0 | return true; |
1224 | 0 | } |
1225 | 11.5k | *state = copy; |
1226 | 11.5k | return false; |
1227 | 11.5k | } |
1228 | | |
1229 | | // <discriminator> := _ <(non-negative) number> |
1230 | 0 | static bool ParseDiscriminator(State *state) { |
1231 | 0 | State copy = *state; |
1232 | 0 | if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) { |
1233 | 0 | return true; |
1234 | 0 | } |
1235 | 0 | *state = copy; |
1236 | 0 | return false; |
1237 | 0 | } |
1238 | | |
1239 | | // <substitution> ::= S_ |
1240 | | // ::= S <seq-id> _ |
1241 | | // ::= St, etc. |
1242 | 52.1k | static bool ParseSubstitution(State *state) { |
1243 | 52.1k | if (ParseTwoCharToken(state, "S_")) { |
1244 | 920 | MaybeAppend(state, "?"); // We don't support substitutions. |
1245 | 920 | return true; |
1246 | 920 | } |
1247 | | |
1248 | 51.2k | State copy = *state; |
1249 | 51.2k | if (ParseOneCharToken(state, 'S') && ParseSeqId(state) && |
1250 | 14.1k | ParseOneCharToken(state, '_')) { |
1251 | 14.1k | MaybeAppend(state, "?"); // We don't support substitutions. |
1252 | 14.1k | return true; |
1253 | 14.1k | } |
1254 | 37.0k | *state = copy; |
1255 | | |
1256 | | // Expand abbreviations like "St" => "std". |
1257 | 37.0k | if (ParseOneCharToken(state, 'S')) { |
1258 | 3.53k | const AbbrevPair *p; |
1259 | 3.53k | for (p = kSubstitutionList; p->abbrev != NULL; ++p) { |
1260 | 3.53k | if (state->mangled_cur[0] == p->abbrev[1]) { |
1261 | 3.53k | MaybeAppend(state, "std"); |
1262 | 3.53k | if (p->real_name[0] != '\0') { |
1263 | 0 | MaybeAppend(state, "::"); |
1264 | 0 | MaybeAppend(state, p->real_name); |
1265 | 0 | } |
1266 | 3.53k | ++state->mangled_cur; |
1267 | 3.53k | return true; |
1268 | 3.53k | } |
1269 | 3.53k | } |
1270 | 3.53k | } |
1271 | 33.5k | *state = copy; |
1272 | 33.5k | return false; |
1273 | 37.0k | } |
1274 | | |
1275 | | // Parse <mangled-name>, optionally followed by either a function-clone suffix |
1276 | | // or version suffix. Returns true only if all of "mangled_cur" was consumed. |
1277 | 4.76k | static bool ParseTopLevelMangledName(State *state) { |
1278 | 4.76k | if (ParseMangledName(state)) { |
1279 | 3.53k | if (state->mangled_cur[0] != '\0') { |
1280 | | // Drop trailing function clone suffix, if any. |
1281 | 0 | if (IsFunctionCloneSuffix(state->mangled_cur)) { |
1282 | 0 | return true; |
1283 | 0 | } |
1284 | | // Append trailing version suffix if any. |
1285 | | // ex. _Z3foo@@GLIBCXX_3.4 |
1286 | 0 | if (state->mangled_cur[0] == '@') { |
1287 | 0 | MaybeAppend(state, state->mangled_cur); |
1288 | 0 | return true; |
1289 | 0 | } |
1290 | 0 | return false; // Unconsumed suffix. |
1291 | 0 | } |
1292 | 3.53k | return true; |
1293 | 3.53k | } |
1294 | 1.23k | return false; |
1295 | 4.76k | } |
1296 | | |
1297 | | // The demangler entry point. |
1298 | 4.76k | bool Demangle(const char *mangled, char *out, int out_size) { |
1299 | 4.76k | State state; |
1300 | 4.76k | InitState(&state, mangled, out, out_size); |
1301 | 4.76k | return ParseTopLevelMangledName(&state) && !state.overflowed; |
1302 | 4.76k | } |
1303 | | |
1304 | | _END_GOOGLE_NAMESPACE_ |