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