/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.86M | size_t StrLen(const char* str) { |
129 | 3.86M | size_t len = 0; |
130 | 46.0M | while (*str != '\0') { |
131 | 42.1M | ++str; |
132 | 42.1M | ++len; |
133 | 42.1M | } |
134 | 3.86M | return len; |
135 | 3.86M | } |
136 | | |
137 | | // Returns true if "str" has at least "n" characters remaining. |
138 | 11.8M | bool AtLeastNumCharsRemaining(const char* str, ssize_t n) { |
139 | 34.5M | for (ssize_t i = 0; i < n; ++i) { |
140 | 23.1M | if (str[i] == '\0') { |
141 | 480k | return false; |
142 | 480k | } |
143 | 23.1M | } |
144 | 11.3M | return true; |
145 | 11.8M | } |
146 | | |
147 | | // Returns true if "str" has "prefix" as a prefix. |
148 | 910 | bool StrPrefix(const char* str, const char* prefix) { |
149 | 910 | size_t i = 0; |
150 | 7.79k | while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) { |
151 | 6.88k | ++i; |
152 | 6.88k | } |
153 | 910 | return prefix[i] == '\0'; // Consumed everything in "prefix". |
154 | 910 | } |
155 | | |
156 | 4.70k | void InitState(State* state, const char* mangled, char* out, size_t out_size) { |
157 | 4.70k | state->mangled_cur = mangled; |
158 | 4.70k | state->out_cur = out; |
159 | 4.70k | state->out_begin = out; |
160 | 4.70k | state->out_end = out + out_size; |
161 | 4.70k | state->prev_name = nullptr; |
162 | 4.70k | state->prev_name_length = -1; |
163 | 4.70k | state->nest_level = -1; |
164 | 4.70k | state->append = true; |
165 | 4.70k | state->overflowed = false; |
166 | 4.70k | state->local_level = 0; |
167 | 4.70k | state->expr_level = 0; |
168 | 4.70k | state->arg_level = 0; |
169 | 4.70k | } |
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 | 159M | bool ParseOneCharToken(State* state, const char one_char_token) { |
175 | 159M | if (state->mangled_cur[0] == one_char_token) { |
176 | 3.85M | ++state->mangled_cur; |
177 | 3.85M | return true; |
178 | 3.85M | } |
179 | 155M | return false; |
180 | 159M | } |
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 | 53.1M | bool ParseTwoCharToken(State* state, const char* two_char_token) { |
186 | 53.1M | if (state->mangled_cur[0] == two_char_token[0] && |
187 | 3.77M | state->mangled_cur[1] == two_char_token[1]) { |
188 | 3.71M | state->mangled_cur += 2; |
189 | 3.71M | return true; |
190 | 3.71M | } |
191 | 49.4M | return false; |
192 | 53.1M | } |
193 | | |
194 | | // Returns true and advances "mangled_cur" if we find any character in |
195 | | // "char_class" at "mangled_cur" position. |
196 | 3.83M | bool ParseCharClass(State* state, const char* char_class) { |
197 | 3.83M | const char* p = char_class; |
198 | 22.8M | for (; *p != '\0'; ++p) { |
199 | 19.0M | if (state->mangled_cur[0] == *p) { |
200 | 22.7k | ++state->mangled_cur; |
201 | 22.7k | return true; |
202 | 22.7k | } |
203 | 19.0M | } |
204 | 3.81M | return false; |
205 | 3.83M | } |
206 | | |
207 | | // This function is used for handling an optional non-terminal. |
208 | 3.69M | bool Optional(bool) { return true; } |
209 | | |
210 | | // This function is used for handling <non-terminal>+ syntax. |
211 | | using ParseFunc = bool (*)(State*); |
212 | 228k | bool OneOrMore(ParseFunc parse_func, State* state) { |
213 | 228k | if (parse_func(state)) { |
214 | 25.1k | while (parse_func(state)) { |
215 | 4.09k | } |
216 | 21.0k | return true; |
217 | 21.0k | } |
218 | 207k | return false; |
219 | 228k | } |
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 | 2.95k | bool ZeroOrMore(ParseFunc parse_func, State* state) { |
226 | 3.76k | while (parse_func(state)) { |
227 | 812 | } |
228 | 2.95k | return true; |
229 | 2.95k | } |
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.69M | void Append(State* state, const char* const str, ssize_t length) { |
235 | 3.69M | if (state->out_cur == nullptr) { |
236 | 0 | state->overflowed = true; |
237 | 0 | return; |
238 | 0 | } |
239 | 9.42M | for (ssize_t i = 0; i < length; ++i) { |
240 | 8.80M | if (state->out_cur + 1 < state->out_end) { // +1 for '\0' |
241 | 5.72M | *state->out_cur = str[i]; |
242 | 5.72M | ++state->out_cur; |
243 | 5.72M | } else { |
244 | 3.07M | state->overflowed = true; |
245 | 3.07M | break; |
246 | 3.07M | } |
247 | 8.80M | } |
248 | 3.69M | if (!state->overflowed) { |
249 | 618k | *state->out_cur = '\0'; // Terminate it with '\0' |
250 | 618k | } |
251 | 3.69M | } |
252 | | |
253 | | // We don't use equivalents in libc to avoid locale issues. |
254 | 11.2M | bool IsLower(char c) { return c >= 'a' && c <= 'z'; } |
255 | | |
256 | 7.39M | bool IsAlpha(char c) { |
257 | 7.39M | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); |
258 | 7.39M | } |
259 | | |
260 | 11.5M | 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.43k | bool IsFunctionCloneSuffix(const char* str) { |
267 | 1.43k | size_t i = 0; |
268 | 2.07k | while (str[i] != '\0') { |
269 | | // Consume a single .<alpha>+.<digit>+ sequence. |
270 | 2.04k | if (str[i] != '.' || !IsAlpha(str[i + 1])) { |
271 | 1.34k | return false; |
272 | 1.34k | } |
273 | 700 | i += 2; |
274 | 1.14k | while (IsAlpha(str[i])) { |
275 | 445 | ++i; |
276 | 445 | } |
277 | 700 | if (str[i] != '.' || !IsDigit(str[i + 1])) { |
278 | 62 | return false; |
279 | 62 | } |
280 | 638 | i += 2; |
281 | 838 | while (IsDigit(str[i])) { |
282 | 200 | ++i; |
283 | 200 | } |
284 | 638 | } |
285 | 23 | return true; // Consumed everything in "str". |
286 | 1.43k | } |
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.86M | ssize_t length) { |
292 | 3.86M | if (state->append && length > 0) { |
293 | | // Append a space if the output buffer ends with '<' and "str" |
294 | | // starts with '<' to avoid <<<. |
295 | 3.69M | if (str[0] == '<' && state->out_begin < state->out_cur && |
296 | 1.49k | state->out_cur[-1] == '<') { |
297 | 388 | Append(state, " ", 1); |
298 | 388 | } |
299 | | // Remember the last identifier name for ctors/dtors. |
300 | 3.69M | if (IsAlpha(str[0]) || str[0] == '_') { |
301 | 3.65M | state->prev_name = state->out_cur; |
302 | 3.65M | state->prev_name_length = length; |
303 | 3.65M | } |
304 | 3.69M | Append(state, str, length); |
305 | 3.69M | } |
306 | 3.86M | } |
307 | | |
308 | | // A convenient wrapper around MaybeAppendWithLength(). |
309 | 3.79M | bool MaybeAppend(State* state, const char* const str) { |
310 | 3.79M | if (state->append) { |
311 | 3.69M | size_t length = StrLen(str); |
312 | 3.69M | MaybeAppendWithLength(state, str, static_cast<ssize_t>(length)); |
313 | 3.69M | } |
314 | 3.79M | return true; |
315 | 3.79M | } |
316 | | |
317 | | // This function is used for handling nested names. |
318 | 7.18M | bool EnterNestedName(State* state) { |
319 | 7.18M | state->nest_level = 0; |
320 | 7.18M | return true; |
321 | 7.18M | } |
322 | | |
323 | | // This function is used for handling nested names. |
324 | 3.51M | bool LeaveNestedName(State* state, short prev_value) { |
325 | 3.51M | state->nest_level = prev_value; |
326 | 3.51M | return true; |
327 | 3.51M | } |
328 | | |
329 | | // Disable the append mode not to print function parameters, etc. |
330 | 294k | bool DisableAppend(State* state) { |
331 | 294k | state->append = false; |
332 | 294k | return true; |
333 | 294k | } |
334 | | |
335 | | // Restore the append mode to the previous state. |
336 | 13.3k | bool RestoreAppend(State* state, bool prev_value) { |
337 | 13.3k | state->append = prev_value; |
338 | 13.3k | return true; |
339 | 13.3k | } |
340 | | |
341 | | // Increase the nest level for nested names. |
342 | 19.6k | void MaybeIncreaseNestLevel(State* state) { |
343 | 19.6k | if (state->nest_level > -1) { |
344 | 19.6k | ++state->nest_level; |
345 | 19.6k | } |
346 | 19.6k | } |
347 | | |
348 | | // Appends :: for nested names if necessary. |
349 | 3.53M | void MaybeAppendSeparator(State* state) { |
350 | 3.53M | if (state->nest_level >= 1) { |
351 | 20.0k | MaybeAppend(state, "::"); |
352 | 20.0k | } |
353 | 3.53M | } |
354 | | |
355 | | // Cancel the last separator if necessary. |
356 | 3.51M | void MaybeCancelLastSeparator(State* state) { |
357 | 3.51M | if (state->nest_level >= 1 && state->append && |
358 | 2.78k | state->out_begin <= state->out_cur - 2) { |
359 | 2.78k | state->out_cur -= 2; |
360 | 2.78k | *state->out_cur = '\0'; |
361 | 2.78k | } |
362 | 3.51M | } |
363 | | |
364 | | // Returns true if the identifier of the given length pointed to by |
365 | | // "mangled_cur" is anonymous namespace. |
366 | 171k | bool IdentifierIsAnonymousNamespace(State* state, ssize_t length) { |
367 | 171k | const char anon_prefix[] = "_GLOBAL__N_"; |
368 | 171k | return (length > static_cast<ssize_t>(sizeof(anon_prefix)) - |
369 | 171k | 1 && // Should be longer. |
370 | 910 | StrPrefix(state->mangled_cur, anon_prefix)); |
371 | 171k | } |
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.10k | bool ParseMangledName(State* state) { |
446 | 9.10k | return ParseTwoCharToken(state, "_Z") && ParseEncoding(state); |
447 | 9.10k | } |
448 | | |
449 | | // <encoding> ::= <(function) name> <bare-function-type> |
450 | | // ::= <(data) name> |
451 | | // ::= <special-name> |
452 | 140k | bool ParseEncoding(State* state) { |
453 | 140k | State copy = *state; |
454 | 140k | if (ParseName(state) && ParseBareFunctionType(state)) { |
455 | 3.77k | return true; |
456 | 3.77k | } |
457 | 136k | *state = copy; |
458 | | |
459 | 136k | if (ParseName(state) || ParseSpecialName(state)) { |
460 | 40.9k | return true; |
461 | 40.9k | } |
462 | 95.9k | return false; |
463 | 136k | } |
464 | | |
465 | | // <name> ::= <nested-name> |
466 | | // ::= <unscoped-template-name> <template-args> |
467 | | // ::= <unscoped-name> |
468 | | // ::= <local-name> |
469 | 4.06M | bool ParseName(State* state) { |
470 | 4.06M | if (ParseNestedName(state) || ParseLocalName(state)) { |
471 | 5.67k | return true; |
472 | 5.67k | } |
473 | | |
474 | 4.05M | State copy = *state; |
475 | 4.05M | if (ParseUnscopedTemplateName(state) && ParseTemplateArgs(state)) { |
476 | 2.63k | return true; |
477 | 2.63k | } |
478 | 4.05M | *state = copy; |
479 | | |
480 | | // Less greedy than <unscoped-template-name> <template-args>. |
481 | 4.05M | if (ParseUnscopedName(state)) { |
482 | 77.6k | return true; |
483 | 77.6k | } |
484 | 3.97M | return false; |
485 | 4.05M | } |
486 | | |
487 | | // <unscoped-name> ::= <unqualified-name> |
488 | | // ::= St <unqualified-name> |
489 | 11.6M | bool ParseUnscopedName(State* state) { |
490 | 11.6M | if (ParseUnqualifiedName(state)) { |
491 | 162k | return true; |
492 | 162k | } |
493 | | |
494 | 11.4M | State copy = *state; |
495 | 11.4M | if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") && |
496 | 10.5k | ParseUnqualifiedName(state)) { |
497 | 6.58k | return true; |
498 | 6.58k | } |
499 | 11.4M | *state = copy; |
500 | 11.4M | return false; |
501 | 11.4M | } |
502 | | |
503 | | // <unscoped-template-name> ::= <unscoped-name> |
504 | | // ::= <substitution> |
505 | 4.05M | bool ParseUnscopedTemplateName(State* state) { |
506 | 4.05M | return ParseUnscopedName(state) || ParseSubstitution(state); |
507 | 4.05M | } |
508 | | |
509 | | // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E |
510 | | // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E |
511 | 4.06M | bool ParseNestedName(State* state) { |
512 | 4.06M | State copy = *state; |
513 | 4.06M | if (ParseOneCharToken(state, 'N') && EnterNestedName(state) && |
514 | 3.51M | Optional(ParseCVQualifiers(state)) && ParsePrefix(state) && |
515 | 3.51M | LeaveNestedName(state, copy.nest_level) && |
516 | 3.51M | ParseOneCharToken(state, 'E')) { |
517 | 1.14k | return true; |
518 | 1.14k | } |
519 | 4.06M | *state = copy; |
520 | 4.06M | return false; |
521 | 4.06M | } |
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.51M | bool ParsePrefix(State* state) { |
535 | 3.51M | bool has_something = false; |
536 | 3.53M | while (true) { |
537 | 3.53M | MaybeAppendSeparator(state); |
538 | 3.53M | if (ParseTemplateParam(state) || ParseSubstitution(state) || |
539 | 3.52M | ParseUnscopedName(state)) { |
540 | 19.6k | has_something = true; |
541 | 19.6k | MaybeIncreaseNestLevel(state); |
542 | 19.6k | continue; |
543 | 19.6k | } |
544 | 3.51M | MaybeCancelLastSeparator(state); |
545 | 3.51M | if (has_something && ParseTemplateArgs(state)) { |
546 | 428 | return ParsePrefix(state); |
547 | 3.51M | } else { |
548 | 3.51M | break; |
549 | 3.51M | } |
550 | 3.51M | } |
551 | 3.51M | return true; |
552 | 3.51M | } |
553 | | |
554 | | // <unqualified-name> ::= <operator-name> |
555 | | // ::= <ctor-dtor-name> |
556 | | // ::= <source-name> [<abi-tags>] |
557 | | // ::= <local-source-name> [<abi-tags>] |
558 | 11.6M | bool ParseUnqualifiedName(State* state) { |
559 | 11.6M | return (ParseOperatorName(state) || ParseCtorDtorName(state) || |
560 | 11.6M | (ParseSourceName(state) && Optional(ParseAbiTags(state))) || |
561 | 11.4M | (ParseLocalSourceName(state) && Optional(ParseAbiTags(state)))); |
562 | 11.6M | } |
563 | | |
564 | | // <source-name> ::= <positive length number> <identifier> |
565 | 11.6M | bool ParseSourceName(State* state) { |
566 | 11.6M | State copy = *state; |
567 | 11.6M | int length = -1; |
568 | 11.6M | if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { |
569 | 170k | return true; |
570 | 170k | } |
571 | 11.5M | *state = copy; |
572 | 11.5M | return false; |
573 | 11.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 | 11.4M | bool ParseLocalSourceName(State* state) { |
581 | 11.4M | State copy = *state; |
582 | 11.4M | if (ParseOneCharToken(state, 'L') && ParseSourceName(state) && |
583 | 6.02k | Optional(ParseDiscriminator(state))) { |
584 | 6.02k | return true; |
585 | 6.02k | } |
586 | 11.4M | *state = copy; |
587 | 11.4M | return false; |
588 | 11.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 | 11.6M | bool ParseNumber(State* state, int* number_out) { |
594 | 11.6M | int sign = 1; |
595 | 11.6M | if (ParseOneCharToken(state, 'n')) { |
596 | 3.91k | sign = -1; |
597 | 3.91k | } |
598 | 11.6M | const char* p = state->mangled_cur; |
599 | 11.6M | int number = 0; |
600 | 11.6M | constexpr int int_max_by_10 = std::numeric_limits<int>::max() / 10; |
601 | 11.9M | for (; *p != '\0'; ++p) { |
602 | 11.5M | if (IsDigit(*p)) { |
603 | | // Prevent signed integer overflow when multiplying |
604 | 247k | if (number > int_max_by_10) { |
605 | 2.51k | return false; |
606 | 2.51k | } |
607 | | |
608 | 244k | const int digit = *p - '0'; |
609 | 244k | const int shifted = number * 10; |
610 | | |
611 | | // Prevent signed integer overflow when summing |
612 | 244k | if (digit > std::numeric_limits<int>::max() - shifted) { |
613 | 2.68k | return false; |
614 | 2.68k | } |
615 | | |
616 | 242k | number = shifted + digit; |
617 | 11.2M | } else { |
618 | 11.2M | break; |
619 | 11.2M | } |
620 | 11.5M | } |
621 | 11.6M | if (p != state->mangled_cur) { // Conversion succeeded. |
622 | 183k | state->mangled_cur = p; |
623 | 183k | if (number_out != nullptr) { |
624 | 172k | *number_out = number * sign; |
625 | 172k | } |
626 | 183k | return true; |
627 | 183k | } |
628 | 11.5M | return false; |
629 | 11.6M | } |
630 | | |
631 | | // Floating-point literals are encoded using a fixed-length lowercase |
632 | | // hexadecimal string. |
633 | 2.05k | bool ParseFloatNumber(State* state) { |
634 | 2.05k | const char* p = state->mangled_cur; |
635 | 7.63k | for (; *p != '\0'; ++p) { |
636 | 6.55k | if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) { |
637 | 964 | break; |
638 | 964 | } |
639 | 6.55k | } |
640 | 2.05k | if (p != state->mangled_cur) { // Conversion succeeded. |
641 | 1.42k | state->mangled_cur = p; |
642 | 1.42k | return true; |
643 | 1.42k | } |
644 | 624 | return false; |
645 | 2.05k | } |
646 | | |
647 | | // The <seq-id> is a sequence number in base 36, |
648 | | // using digits and upper case letters |
649 | 14.2k | bool ParseSeqId(State* state) { |
650 | 14.2k | const char* p = state->mangled_cur; |
651 | 15.1k | for (; *p != '\0'; ++p) { |
652 | 12.9k | if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) { |
653 | 12.0k | break; |
654 | 12.0k | } |
655 | 12.9k | } |
656 | 14.2k | if (p != state->mangled_cur) { // Conversion succeeded. |
657 | 862 | state->mangled_cur = p; |
658 | 862 | return true; |
659 | 862 | } |
660 | 13.3k | return false; |
661 | 14.2k | } |
662 | | |
663 | | // <identifier> ::= <unqualified source code identifier> (of given length) |
664 | 172k | bool ParseIdentifier(State* state, ssize_t length) { |
665 | 172k | if (length == -1 || !AtLeastNumCharsRemaining(state->mangled_cur, length)) { |
666 | 1.11k | return false; |
667 | 1.11k | } |
668 | 171k | if (IdentifierIsAnonymousNamespace(state, length)) { |
669 | 589 | MaybeAppend(state, "(anonymous namespace)"); |
670 | 170k | } else { |
671 | 170k | MaybeAppendWithLength(state, state->mangled_cur, length); |
672 | 170k | } |
673 | 171k | if (length < 0 || |
674 | 170k | static_cast<std::size_t>(length) > StrLen(state->mangled_cur)) { |
675 | 659 | return false; |
676 | 659 | } |
677 | 170k | state->mangled_cur += length; |
678 | 170k | return true; |
679 | 171k | } |
680 | | |
681 | | // <abi-tags> ::= <abi-tag> [<abi-tags>] |
682 | 163k | bool ParseAbiTags(State* state) { |
683 | 163k | State copy = *state; |
684 | 163k | DisableAppend(state); |
685 | 163k | if (OneOrMore(ParseAbiTag, state)) { |
686 | 4.69k | RestoreAppend(state, copy.append); |
687 | 4.69k | return true; |
688 | 4.69k | } |
689 | 159k | *state = copy; |
690 | 159k | return false; |
691 | 163k | } |
692 | | |
693 | | // <abi-tag> ::= B <source-name> |
694 | 169k | bool ParseAbiTag(State* state) { |
695 | 169k | return ParseOneCharToken(state, 'B') && ParseSourceName(state); |
696 | 169k | } |
697 | | |
698 | | // <operator-name> ::= nw, and other two letters cases |
699 | | // ::= cv <type> # (cast) |
700 | | // ::= v <digit> <source-name> # vendor extended operator |
701 | 11.6M | bool ParseOperatorName(State* state) { |
702 | 11.6M | if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) { |
703 | 479k | return false; |
704 | 479k | } |
705 | | // First check with "cv" (cast) case. |
706 | 11.2M | State copy = *state; |
707 | 11.2M | if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") && |
708 | 3.67M | EnterNestedName(state) && ParseType(state) && |
709 | 1.94k | LeaveNestedName(state, copy.nest_level)) { |
710 | 1.94k | return true; |
711 | 1.94k | } |
712 | 11.2M | *state = copy; |
713 | | |
714 | | // Then vendor extended operators. |
715 | 11.2M | if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") && |
716 | 477 | ParseSourceName(state)) { |
717 | 229 | return true; |
718 | 229 | } |
719 | 11.2M | *state = copy; |
720 | | |
721 | | // Other operator names should start with a lower alphabet followed |
722 | | // by a lower/upper alphabet. |
723 | 11.2M | if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) { |
724 | 7.51M | return false; |
725 | 7.51M | } |
726 | | // We may want to perform a binary search if we really need speed. |
727 | 3.69M | const AbbrevPair* p; |
728 | 184M | for (p = kOperatorList; p->abbrev != nullptr; ++p) { |
729 | 180M | if (state->mangled_cur[0] == p->abbrev[0] && |
730 | 11.0M | state->mangled_cur[1] == p->abbrev[1]) { |
731 | 7.24k | MaybeAppend(state, "operator"); |
732 | 7.24k | if (IsLower(*p->real_name)) { // new, delete, etc. |
733 | 3.12k | MaybeAppend(state, " "); |
734 | 3.12k | } |
735 | 7.24k | MaybeAppend(state, p->real_name); |
736 | 7.24k | state->mangled_cur += 2; |
737 | 7.24k | return true; |
738 | 7.24k | } |
739 | 180M | } |
740 | 3.68M | return false; |
741 | 3.69M | } |
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 | 101k | bool ParseSpecialName(State* state) { |
762 | 101k | State copy = *state; |
763 | 101k | if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && |
764 | 502 | ParseType(state)) { |
765 | 252 | return true; |
766 | 252 | } |
767 | 101k | *state = copy; |
768 | | |
769 | 101k | if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) && |
770 | 678 | ParseCallOffset(state) && ParseEncoding(state)) { |
771 | 226 | return true; |
772 | 226 | } |
773 | 101k | *state = copy; |
774 | | |
775 | 101k | if (ParseTwoCharToken(state, "GV") && ParseName(state)) { |
776 | 2.12k | return true; |
777 | 2.12k | } |
778 | 99.2k | *state = copy; |
779 | | |
780 | 99.2k | if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) && |
781 | 678 | ParseEncoding(state)) { |
782 | 226 | return true; |
783 | 226 | } |
784 | 98.9k | *state = copy; |
785 | | |
786 | | // G++ extensions |
787 | 98.9k | if (ParseTwoCharToken(state, "TC") && ParseType(state) && |
788 | 2.22k | ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') && |
789 | 454 | DisableAppend(state) && ParseType(state)) { |
790 | 226 | RestoreAppend(state, copy.append); |
791 | 226 | return true; |
792 | 226 | } |
793 | 98.7k | *state = copy; |
794 | | |
795 | 98.7k | if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") && |
796 | 508 | ParseType(state)) { |
797 | 260 | return true; |
798 | 260 | } |
799 | 98.4k | *state = copy; |
800 | | |
801 | 98.4k | if (ParseTwoCharToken(state, "GR") && ParseName(state)) { |
802 | 2.07k | return true; |
803 | 2.07k | } |
804 | 96.4k | *state = copy; |
805 | | |
806 | 96.4k | if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) { |
807 | 265 | return true; |
808 | 265 | } |
809 | 96.1k | *state = copy; |
810 | | |
811 | 96.1k | if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") && |
812 | 6.24k | ParseCallOffset(state) && ParseEncoding(state)) { |
813 | 226 | return true; |
814 | 226 | } |
815 | 95.9k | *state = copy; |
816 | 95.9k | return false; |
817 | 96.1k | } |
818 | | |
819 | | // <call-offset> ::= h <nv-offset> _ |
820 | | // ::= v <v-offset> _ |
821 | 18.6k | bool ParseCallOffset(State* state) { |
822 | 18.6k | State copy = *state; |
823 | 18.6k | if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) && |
824 | 2.48k | ParseOneCharToken(state, '_')) { |
825 | 2.03k | return true; |
826 | 2.03k | } |
827 | 16.6k | *state = copy; |
828 | | |
829 | 16.6k | if (ParseOneCharToken(state, 'v') && ParseVOffset(state) && |
830 | 655 | ParseOneCharToken(state, '_')) { |
831 | 226 | return true; |
832 | 226 | } |
833 | 16.3k | *state = copy; |
834 | | |
835 | 16.3k | return false; |
836 | 16.6k | } |
837 | | |
838 | | // <nv-offset> ::= <(offset) number> |
839 | 4.25k | bool ParseNVOffset(State* state) { return ParseNumber(state, nullptr); } |
840 | | |
841 | | // <v-offset> ::= <(offset) number> _ <(virtual offset) number> |
842 | 4.17k | bool ParseVOffset(State* state) { |
843 | 4.17k | State copy = *state; |
844 | 4.17k | if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') && |
845 | 1.89k | ParseNumber(state, nullptr)) { |
846 | 655 | return true; |
847 | 655 | } |
848 | 3.51k | *state = copy; |
849 | 3.51k | return false; |
850 | 4.17k | } |
851 | | |
852 | | // <ctor-dtor-name> ::= C1 | C2 | C3 |
853 | | // ::= D0 | D1 | D2 |
854 | 11.6M | bool ParseCtorDtorName(State* state) { |
855 | 11.6M | State copy = *state; |
856 | 11.6M | if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "123")) { |
857 | 303 | const char* const prev_name = state->prev_name; |
858 | 303 | const ssize_t prev_name_length = state->prev_name_length; |
859 | 303 | MaybeAppendWithLength(state, prev_name, prev_name_length); |
860 | 303 | return true; |
861 | 303 | } |
862 | 11.6M | *state = copy; |
863 | | |
864 | 11.6M | if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "012")) { |
865 | 1.12k | const char* const prev_name = state->prev_name; |
866 | 1.12k | const ssize_t prev_name_length = state->prev_name_length; |
867 | 1.12k | MaybeAppend(state, "~"); |
868 | 1.12k | MaybeAppendWithLength(state, prev_name, prev_name_length); |
869 | 1.12k | return true; |
870 | 1.12k | } |
871 | 11.6M | *state = copy; |
872 | 11.6M | return false; |
873 | 11.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.79M | bool ParseType(State* state) { |
896 | | // We should check CV-qualifers, and PRGC things first. |
897 | 3.79M | State copy = *state; |
898 | 3.79M | if (ParseCVQualifiers(state) && ParseType(state)) { |
899 | 301 | return true; |
900 | 301 | } |
901 | 3.79M | *state = copy; |
902 | | |
903 | 3.79M | if (ParseCharClass(state, "OPRCG") && ParseType(state)) { |
904 | 276 | return true; |
905 | 276 | } |
906 | 3.79M | *state = copy; |
907 | | |
908 | 3.79M | if (ParseTwoCharToken(state, "Dp") && ParseType(state)) { |
909 | 226 | return true; |
910 | 226 | } |
911 | 3.79M | *state = copy; |
912 | | |
913 | 3.79M | if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") && |
914 | 847 | ParseExpression(state) && ParseOneCharToken(state, 'E')) { |
915 | 226 | return true; |
916 | 226 | } |
917 | 3.79M | *state = copy; |
918 | | |
919 | 3.79M | if (ParseOneCharToken(state, 'U') && ParseSourceName(state) && |
920 | 455 | ParseType(state)) { |
921 | 226 | return true; |
922 | 226 | } |
923 | 3.79M | *state = copy; |
924 | | |
925 | 3.79M | if (ParseBuiltinType(state) || ParseFunctionType(state) || |
926 | 3.77M | ParseClassEnumType(state) || ParseArrayType(state) || |
927 | 3.76M | ParsePointerToMemberType(state) || ParseSubstitution(state)) { |
928 | 28.9k | return true; |
929 | 28.9k | } |
930 | | |
931 | 3.76M | if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) { |
932 | 452 | return true; |
933 | 452 | } |
934 | 3.76M | *state = copy; |
935 | | |
936 | | // Less greedy than <template-template-param> <template-args>. |
937 | 3.76M | if (ParseTemplateParam(state)) { |
938 | 901 | return true; |
939 | 901 | } |
940 | | |
941 | 3.76M | return false; |
942 | 3.76M | } |
943 | | |
944 | | // <CV-qualifiers> ::= [r] [V] [K] |
945 | | // We don't allow empty <CV-qualifiers> to avoid infinite loop in |
946 | | // ParseType(). |
947 | 7.31M | bool ParseCVQualifiers(State* state) { |
948 | 7.31M | int num_cv_qualifiers = 0; |
949 | 7.31M | num_cv_qualifiers += ParseOneCharToken(state, 'r'); |
950 | 7.31M | num_cv_qualifiers += ParseOneCharToken(state, 'V'); |
951 | 7.31M | num_cv_qualifiers += ParseOneCharToken(state, 'K'); |
952 | 7.31M | return num_cv_qualifiers > 0; |
953 | 7.31M | } |
954 | | |
955 | | // <builtin-type> ::= v, etc. |
956 | | // ::= u <source-name> |
957 | 3.79M | bool ParseBuiltinType(State* state) { |
958 | 3.79M | const AbbrevPair* p; |
959 | 87.0M | for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) { |
960 | 83.2M | if (state->mangled_cur[0] == p->abbrev[0]) { |
961 | 21.1k | MaybeAppend(state, p->real_name); |
962 | 21.1k | ++state->mangled_cur; |
963 | 21.1k | return true; |
964 | 21.1k | } |
965 | 83.2M | } |
966 | | |
967 | 3.77M | State copy = *state; |
968 | 3.77M | if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) { |
969 | 234 | return true; |
970 | 234 | } |
971 | 3.77M | *state = copy; |
972 | 3.77M | return false; |
973 | 3.77M | } |
974 | | |
975 | | // <function-type> ::= F [Y] <bare-function-type> E |
976 | 3.77M | bool ParseFunctionType(State* state) { |
977 | 3.77M | State copy = *state; |
978 | 3.77M | if (ParseOneCharToken(state, 'F') && |
979 | 3.13k | Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) && |
980 | 989 | ParseOneCharToken(state, 'E')) { |
981 | 194 | return true; |
982 | 194 | } |
983 | 3.77M | *state = copy; |
984 | 3.77M | return false; |
985 | 3.77M | } |
986 | | |
987 | | // <bare-function-type> ::= <(signature) type>+ |
988 | 41.9k | bool ParseBareFunctionType(State* state) { |
989 | 41.9k | State copy = *state; |
990 | 41.9k | DisableAppend(state); |
991 | 41.9k | if (OneOrMore(ParseType, state)) { |
992 | 4.76k | RestoreAppend(state, copy.append); |
993 | 4.76k | MaybeAppend(state, "()"); |
994 | 4.76k | return true; |
995 | 4.76k | } |
996 | 37.1k | *state = copy; |
997 | 37.1k | return false; |
998 | 41.9k | } |
999 | | |
1000 | | // <class-enum-type> ::= <name> |
1001 | 3.77M | 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.76M | bool ParseArrayType(State* state) { |
1006 | 3.76M | State copy = *state; |
1007 | 3.76M | if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) && |
1008 | 892 | ParseOneCharToken(state, '_') && ParseType(state)) { |
1009 | 226 | return true; |
1010 | 226 | } |
1011 | 3.76M | *state = copy; |
1012 | | |
1013 | 3.76M | if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) && |
1014 | 5.46k | ParseOneCharToken(state, '_') && ParseType(state)) { |
1015 | 229 | return true; |
1016 | 229 | } |
1017 | 3.76M | *state = copy; |
1018 | 3.76M | return false; |
1019 | 3.76M | } |
1020 | | |
1021 | | // <pointer-to-member-type> ::= M <(class) type> <(member) type> |
1022 | 3.76M | bool ParsePointerToMemberType(State* state) { |
1023 | 3.76M | State copy = *state; |
1024 | 3.76M | if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) { |
1025 | 194 | return true; |
1026 | 194 | } |
1027 | 3.76M | *state = copy; |
1028 | 3.76M | return false; |
1029 | 3.76M | } |
1030 | | |
1031 | | // <template-param> ::= T_ |
1032 | | // ::= T <parameter-2 non-negative number> _ |
1033 | 11.0M | bool ParseTemplateParam(State* state) { |
1034 | 11.0M | if (ParseTwoCharToken(state, "T_")) { |
1035 | 5.26k | MaybeAppend(state, "?"); // We don't support template substitutions. |
1036 | 5.26k | return true; |
1037 | 5.26k | } |
1038 | | |
1039 | 11.0M | State copy = *state; |
1040 | 11.0M | if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) && |
1041 | 760 | ParseOneCharToken(state, '_')) { |
1042 | 389 | MaybeAppend(state, "?"); // We don't support template substitutions. |
1043 | 389 | return true; |
1044 | 389 | } |
1045 | 11.0M | *state = copy; |
1046 | 11.0M | return false; |
1047 | 11.0M | } |
1048 | | |
1049 | | // <template-template-param> ::= <template-param> |
1050 | | // ::= <substitution> |
1051 | 3.76M | bool ParseTemplateTemplateParam(State* state) { |
1052 | 3.76M | return (ParseTemplateParam(state) || ParseSubstitution(state)); |
1053 | 3.76M | } |
1054 | | |
1055 | | // <template-args> ::= I <template-arg>+ E |
1056 | 88.2k | bool ParseTemplateArgs(State* state) { |
1057 | 88.2k | State copy = *state; |
1058 | 88.2k | DisableAppend(state); |
1059 | 88.2k | if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) && |
1060 | 11.5k | ParseOneCharToken(state, 'E')) { |
1061 | 3.70k | RestoreAppend(state, copy.append); |
1062 | 3.70k | MaybeAppend(state, "<>"); |
1063 | 3.70k | return true; |
1064 | 3.70k | } |
1065 | 84.5k | *state = copy; |
1066 | 84.5k | return false; |
1067 | 88.2k | } |
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.6k | bool ParseTemplateArg(State* state) { |
1075 | | // Avoid recursion above max_levels |
1076 | 39.6k | constexpr uint32 max_levels = 6; |
1077 | | |
1078 | 39.6k | if (state->arg_level > max_levels) { |
1079 | 194 | return false; |
1080 | 194 | } |
1081 | 39.5k | ++state->arg_level; |
1082 | | |
1083 | 39.5k | State copy = *state; |
1084 | 39.5k | if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) && |
1085 | 2.95k | ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) { |
1086 | 197 | --state->arg_level; |
1087 | 197 | return true; |
1088 | 197 | } |
1089 | 39.3k | *state = copy; |
1090 | | |
1091 | 39.3k | if (ParseType(state) || ParseExprPrimary(state)) { |
1092 | 13.6k | --state->arg_level; |
1093 | 13.6k | return true; |
1094 | 13.6k | } |
1095 | 25.6k | *state = copy; |
1096 | | |
1097 | 25.6k | if (ParseOneCharToken(state, 'X') && ParseExpression(state) && |
1098 | 948 | ParseOneCharToken(state, 'E')) { |
1099 | 196 | --state->arg_level; |
1100 | 196 | return true; |
1101 | 196 | } |
1102 | 25.4k | *state = copy; |
1103 | 25.4k | return false; |
1104 | 25.6k | } |
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.5k | bool ParseExpression(State* state) { |
1116 | 14.5k | if (ParseTemplateParam(state) || ParseExprPrimary(state)) { |
1117 | 3.33k | return true; |
1118 | 3.33k | } |
1119 | | |
1120 | | // Avoid recursion above max_levels |
1121 | 11.2k | constexpr uint32 max_levels = 5; |
1122 | | |
1123 | 11.2k | if (state->expr_level > max_levels) { |
1124 | 856 | return false; |
1125 | 856 | } |
1126 | 10.3k | ++state->expr_level; |
1127 | | |
1128 | 10.3k | State copy = *state; |
1129 | 10.3k | if (ParseOperatorName(state) && ParseExpression(state) && |
1130 | 664 | ParseExpression(state) && ParseExpression(state)) { |
1131 | 226 | --state->expr_level; |
1132 | 226 | return true; |
1133 | 226 | } |
1134 | 10.1k | *state = copy; |
1135 | | |
1136 | 10.1k | if (ParseOperatorName(state) && ParseExpression(state) && |
1137 | 438 | ParseExpression(state)) { |
1138 | 194 | --state->expr_level; |
1139 | 194 | return true; |
1140 | 194 | } |
1141 | 9.94k | *state = copy; |
1142 | | |
1143 | 9.94k | if (ParseOperatorName(state) && ParseExpression(state)) { |
1144 | 244 | --state->expr_level; |
1145 | 244 | return true; |
1146 | 244 | } |
1147 | 9.70k | *state = copy; |
1148 | | |
1149 | 9.70k | if (ParseTwoCharToken(state, "st") && ParseType(state)) { |
1150 | 237 | return true; |
1151 | 0 | --state->expr_level; |
1152 | 0 | } |
1153 | 9.46k | *state = copy; |
1154 | | |
1155 | 9.46k | if (ParseTwoCharToken(state, "sr") && ParseType(state) && |
1156 | 646 | ParseUnqualifiedName(state) && ParseTemplateArgs(state)) { |
1157 | 194 | --state->expr_level; |
1158 | 194 | return true; |
1159 | 194 | } |
1160 | 9.27k | *state = copy; |
1161 | | |
1162 | 9.27k | if (ParseTwoCharToken(state, "sr") && ParseType(state) && |
1163 | 452 | ParseUnqualifiedName(state)) { |
1164 | 226 | --state->expr_level; |
1165 | 226 | return true; |
1166 | 226 | } |
1167 | 9.04k | *state = copy; |
1168 | | |
1169 | | // Pack expansion |
1170 | 9.04k | if (ParseTwoCharToken(state, "sp") && ParseType(state)) { |
1171 | 226 | --state->expr_level; |
1172 | 226 | return true; |
1173 | 226 | } |
1174 | 8.82k | *state = copy; |
1175 | | |
1176 | 8.82k | return false; |
1177 | 9.04k | } |
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.9k | bool ParseExprPrimary(State* state) { |
1185 | 37.9k | State copy = *state; |
1186 | 37.9k | if (ParseOneCharToken(state, 'L') && ParseType(state) && |
1187 | 2.32k | ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) { |
1188 | 271 | return true; |
1189 | 271 | } |
1190 | 37.6k | *state = copy; |
1191 | | |
1192 | 37.6k | if (ParseOneCharToken(state, 'L') && ParseType(state) && |
1193 | 2.05k | ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) { |
1194 | 346 | return true; |
1195 | 346 | } |
1196 | 37.2k | *state = copy; |
1197 | | |
1198 | 37.2k | if (ParseOneCharToken(state, 'L') && ParseMangledName(state) && |
1199 | 1.36k | ParseOneCharToken(state, 'E')) { |
1200 | 203 | return true; |
1201 | 203 | } |
1202 | 37.0k | *state = copy; |
1203 | | |
1204 | 37.0k | if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) && |
1205 | 420 | ParseOneCharToken(state, 'E')) { |
1206 | 208 | return true; |
1207 | 208 | } |
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 | 4.06M | bool ParseLocalName(State* state) { |
1217 | | // Avoid recursion above max_levels |
1218 | 4.06M | constexpr uint32 max_levels = 5; |
1219 | 4.06M | if (state->local_level > max_levels) { |
1220 | 2.27M | return false; |
1221 | 2.27M | } |
1222 | 1.79M | ++state->local_level; |
1223 | | |
1224 | 1.79M | State copy = *state; |
1225 | 1.79M | if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && |
1226 | 21.0k | ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") && |
1227 | 5.37k | ParseName(state) && Optional(ParseDiscriminator(state))) { |
1228 | 2.08k | --state->local_level; |
1229 | 2.08k | return true; |
1230 | 2.08k | } |
1231 | 1.79M | *state = copy; |
1232 | | |
1233 | 1.79M | if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && |
1234 | 18.9k | ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) { |
1235 | 2.45k | --state->local_level; |
1236 | 2.45k | return true; |
1237 | 2.45k | } |
1238 | 1.78M | *state = copy; |
1239 | 1.78M | return false; |
1240 | 1.79M | } |
1241 | | |
1242 | | // <discriminator> := _ <(non-negative) number> |
1243 | 10.5k | bool ParseDiscriminator(State* state) { |
1244 | 10.5k | State copy = *state; |
1245 | 10.5k | if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) { |
1246 | 1.72k | return true; |
1247 | 1.72k | } |
1248 | 8.83k | *state = copy; |
1249 | 8.83k | return false; |
1250 | 10.5k | } |
1251 | | |
1252 | | // <substitution> ::= S_ |
1253 | | // ::= S <seq-id> _ |
1254 | | // ::= St, etc. |
1255 | 15.0M | bool ParseSubstitution(State* state) { |
1256 | 15.0M | if (ParseTwoCharToken(state, "S_")) { |
1257 | 656 | MaybeAppend(state, "?"); // We don't support substitutions. |
1258 | 656 | return true; |
1259 | 656 | } |
1260 | | |
1261 | 15.0M | State copy = *state; |
1262 | 15.0M | if (ParseOneCharToken(state, 'S') && ParseSeqId(state) && |
1263 | 862 | ParseOneCharToken(state, '_')) { |
1264 | 415 | MaybeAppend(state, "?"); // We don't support substitutions. |
1265 | 415 | return true; |
1266 | 415 | } |
1267 | 15.0M | *state = copy; |
1268 | | |
1269 | | // Expand abbreviations like "St" => "std". |
1270 | 15.0M | if (ParseOneCharToken(state, 'S')) { |
1271 | 13.8k | const AbbrevPair* p; |
1272 | 49.6k | for (p = kSubstitutionList; p->abbrev != nullptr; ++p) { |
1273 | 47.0k | if (state->mangled_cur[0] == p->abbrev[1]) { |
1274 | 11.2k | MaybeAppend(state, "std"); |
1275 | 11.2k | if (p->real_name[0] != '\0') { |
1276 | 8.52k | MaybeAppend(state, "::"); |
1277 | 8.52k | MaybeAppend(state, p->real_name); |
1278 | 8.52k | } |
1279 | 11.2k | ++state->mangled_cur; |
1280 | 11.2k | return true; |
1281 | 11.2k | } |
1282 | 47.0k | } |
1283 | 13.8k | } |
1284 | 15.0M | *state = copy; |
1285 | 15.0M | return false; |
1286 | 15.0M | } |
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.70k | bool ParseTopLevelMangledName(State* state) { |
1291 | 4.70k | if (ParseMangledName(state)) { |
1292 | 1.91k | if (state->mangled_cur[0] != '\0') { |
1293 | | // Drop trailing function clone suffix, if any. |
1294 | 1.43k | if (IsFunctionCloneSuffix(state->mangled_cur)) { |
1295 | 23 | return true; |
1296 | 23 | } |
1297 | | // Append trailing version suffix if any. |
1298 | | // ex. _Z3foo@@GLIBCXX_3.4 |
1299 | 1.41k | if (state->mangled_cur[0] == '@') { |
1300 | 20 | MaybeAppend(state, state->mangled_cur); |
1301 | 20 | return true; |
1302 | 20 | } |
1303 | 1.39k | return ParseName(state); |
1304 | 1.41k | } |
1305 | 480 | return true; |
1306 | 1.91k | } |
1307 | 2.79k | return false; |
1308 | 4.70k | } |
1309 | | } // namespace |
1310 | | #endif |
1311 | | |
1312 | | // The demangler entry point. |
1313 | 4.70k | 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.70k | State state; |
1357 | 4.70k | InitState(&state, mangled, out, out_size); |
1358 | 4.70k | return ParseTopLevelMangledName(&state) && !state.overflowed; |
1359 | 4.70k | #endif |
1360 | 4.70k | } |
1361 | | |
1362 | | } // namespace glog_internal_namespace_ |
1363 | | } // namespace google |