1 //===-- FastDemangle.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Utility/FastDemangle.h"
12 #include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
20 //#define DEBUG_FAILURES 1
21 //#define DEBUG_SUBSTITUTIONS 1
22 //#define DEBUG_TEMPLATE_ARGS 1
23 //#define DEBUG_HIGHWATER 1
24 //#define DEBUG_REORDERING 1
28 /// @brief Represents the collection of qualifiers on a type
33 QualifierRestrict = 2,
34 QualifierVolatile = 4,
35 QualifierReference = 8,
36 QualifierRValueReference = 16,
40 /// @brief Categorizes the recognized operators
42 enum class OperatorKind {
53 /// @brief Represents one of the recognized two-character operator
54 /// abbreviations used when parsing operators as names and expressions
61 /// @brief Represents a range of characters in the output buffer, typically for
62 /// use with RewriteRange()
69 /// @brief Transient state required while parsing a name
72 bool parse_function_params;
74 bool has_no_return_type;
75 BufferRange last_name_range;
78 /// @brief LLDB's fast C++ demangler
80 /// This is an incomplete implementation designed to speed up the demangling
81 /// process that is often a bottleneck when LLDB stops a process for the first
82 /// time. Where the implementation doesn't know how to demangle a symbol it
83 /// fails gracefully to allow the caller to fall back to the existing demangler.
85 /// Over time the full mangling spec should be supported without compromising
86 /// performance for the most common cases.
88 class SymbolDemangler {
90 //----------------------------------------------------
92 //----------------------------------------------------
94 /// @brief Create a SymbolDemangler
96 /// The newly created demangler allocates and owns scratch memory sufficient
97 /// for demangling typical symbols. Additional memory will be allocated if
98 /// needed and managed by the demangler instance.
101 m_buffer = (char *)malloc(8192);
102 m_buffer_end = m_buffer + 8192;
103 m_owns_buffer = true;
105 m_rewrite_ranges = (BufferRange *)malloc(128 * sizeof(BufferRange));
106 m_rewrite_ranges_size = 128;
107 m_owns_m_rewrite_ranges = true;
110 /// @brief Create a SymbolDemangler that uses provided scratch memory
112 /// The provided memory is not owned by the demangler. It will be
113 /// overwritten during calls to GetDemangledCopy() but can be used for
114 /// other purposes between calls. The provided memory will not be freed
115 /// when this instance is destroyed.
117 /// If demangling a symbol requires additional space it will be allocated
118 /// and managed by the demangler instance.
120 /// @param storage_ptr Valid pointer to at least storage_size bytes of
121 /// space that the SymbolDemangler can use during demangling
123 /// @param storage_size Number of bytes of space available scratch memory
124 /// referenced by storage_ptr
126 SymbolDemangler(void *storage_ptr, size_t storage_size,
127 std::function<void(const char *)> builtins_hook = nullptr)
128 : m_builtins_hook(builtins_hook) {
129 // Use up to 1/8th of the provided space for rewrite ranges
130 m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
131 m_rewrite_ranges = (BufferRange *)storage_ptr;
132 m_owns_m_rewrite_ranges = false;
134 // Use the rest for the character buffer
136 (char *)storage_ptr + m_rewrite_ranges_size * sizeof(BufferRange);
137 m_buffer_end = (const char *)storage_ptr + storage_size;
138 m_owns_buffer = false;
141 /// @brief Destroys the SymbolDemangler and deallocates any scratch
142 /// memory that it owns
147 if (m_owns_m_rewrite_ranges)
148 free(m_rewrite_ranges);
151 #ifdef DEBUG_HIGHWATER
152 int highwater_store = 0;
153 int highwater_buffer = 0;
156 /// @brief Parses the provided mangled name and returns a newly allocated
159 /// @param mangled_name Valid null-terminated C++ mangled name following
160 /// the Itanium C++ ABI mangling specification as implemented by Clang
162 /// @result Newly allocated null-terminated demangled name when demangling
163 /// is successful, and nullptr when demangling fails. The caller is
164 /// responsible for freeing the allocated memory.
166 char *GetDemangledCopy(const char *mangled_name,
167 long mangled_name_length = 0) {
168 if (!ParseMangling(mangled_name, mangled_name_length))
171 #ifdef DEBUG_HIGHWATER
172 int rewrite_count = m_next_substitute_index +
173 (m_rewrite_ranges_size - 1 - m_next_template_arg_index);
174 int buffer_size = (int)(m_write_ptr - m_buffer);
175 if (rewrite_count > highwater_store)
176 highwater_store = rewrite_count;
177 if (buffer_size > highwater_buffer)
178 highwater_buffer = buffer_size;
181 int length = (int)(m_write_ptr - m_buffer);
182 char *copy = (char *)malloc(length + 1);
183 memcpy(copy, m_buffer, length);
189 //----------------------------------------------------
192 // Manage the storage used during demangling
193 //----------------------------------------------------
195 void GrowBuffer(long min_growth = 0) {
196 // By default, double the size of the buffer
197 long growth = m_buffer_end - m_buffer;
199 // Avoid growing by more than 1MB at a time
200 if (growth > 1 << 20)
203 // ... but never grow by less than requested,
204 // or 1K, whichever is greater
205 if (min_growth < 1024)
207 if (growth < min_growth)
210 // Allocate the new m_buffer and migrate content
211 long new_size = (m_buffer_end - m_buffer) + growth;
212 char *new_buffer = (char *)malloc(new_size);
213 memcpy(new_buffer, m_buffer, m_write_ptr - m_buffer);
216 m_owns_buffer = true;
218 // Update references to the new buffer
219 m_write_ptr = new_buffer + (m_write_ptr - m_buffer);
220 m_buffer = new_buffer;
221 m_buffer_end = m_buffer + new_size;
224 void GrowRewriteRanges() {
225 // By default, double the size of the array
226 int growth = m_rewrite_ranges_size;
228 // Apply reasonable minimum and maximum sizes for growth
234 // Allocate the new array and migrate content
235 int bytes = (m_rewrite_ranges_size + growth) * sizeof(BufferRange);
236 BufferRange *new_ranges = (BufferRange *)malloc(bytes);
237 for (int index = 0; index < m_next_substitute_index; index++) {
238 new_ranges[index] = m_rewrite_ranges[index];
240 for (int index = m_rewrite_ranges_size - 1;
241 index > m_next_template_arg_index; index--) {
242 new_ranges[index + growth] = m_rewrite_ranges[index];
244 if (m_owns_m_rewrite_ranges)
245 free(m_rewrite_ranges);
246 m_owns_m_rewrite_ranges = true;
248 // Update references to the new array
249 m_rewrite_ranges = new_ranges;
250 m_rewrite_ranges_size += growth;
251 m_next_template_arg_index += growth;
254 //----------------------------------------------------
255 // Range and state management
256 //----------------------------------------------------
258 int GetStartCookie() { return (int)(m_write_ptr - m_buffer); }
260 BufferRange EndRange(int start_cookie) {
261 return {start_cookie, (int)(m_write_ptr - (m_buffer + start_cookie))};
264 void ReorderRange(BufferRange source_range, int insertion_point_cookie) {
265 // Ensure there's room the preserve the source range
266 if (m_write_ptr + source_range.length > m_buffer_end) {
267 GrowBuffer(m_write_ptr + source_range.length - m_buffer_end);
270 // Reorder the content
271 memcpy(m_write_ptr, m_buffer + source_range.offset, source_range.length);
272 memmove(m_buffer + insertion_point_cookie + source_range.length,
273 m_buffer + insertion_point_cookie,
274 source_range.offset - insertion_point_cookie);
275 memcpy(m_buffer + insertion_point_cookie, m_write_ptr, source_range.length);
277 // Fix up rewritable ranges, covering both substitutions and templates
280 if (index == m_next_substitute_index)
281 index = m_next_template_arg_index + 1;
282 if (index == m_rewrite_ranges_size)
285 // Affected ranges are either shuffled forward when after the
286 // insertion but before the source, or backward when inside the
288 int candidate_offset = m_rewrite_ranges[index].offset;
289 if (candidate_offset >= insertion_point_cookie) {
290 if (candidate_offset < source_range.offset) {
291 m_rewrite_ranges[index].offset += source_range.length;
292 } else if (candidate_offset >= source_range.offset) {
293 m_rewrite_ranges[index].offset -=
294 (source_range.offset - insertion_point_cookie);
301 void EndSubstitution(int start_cookie) {
302 if (m_next_substitute_index == m_next_template_arg_index)
305 int index = m_next_substitute_index++;
306 m_rewrite_ranges[index] = EndRange(start_cookie);
307 #ifdef DEBUG_SUBSTITUTIONS
308 printf("Saved substitution # %d = %.*s\n", index,
309 m_rewrite_ranges[index].length, m_buffer + start_cookie);
313 void EndTemplateArg(int start_cookie) {
314 if (m_next_substitute_index == m_next_template_arg_index)
317 int index = m_next_template_arg_index--;
318 m_rewrite_ranges[index] = EndRange(start_cookie);
319 #ifdef DEBUG_TEMPLATE_ARGS
320 printf("Saved template arg # %d = %.*s\n",
321 m_rewrite_ranges_size - index - 1, m_rewrite_ranges[index].length,
322 m_buffer + start_cookie);
326 void ResetTemplateArgs() {
327 // TODO: this works, but is it the right thing to do?
328 // Should we push/pop somehow at the call sites?
329 m_next_template_arg_index = m_rewrite_ranges_size - 1;
332 //----------------------------------------------------
335 // Appends content to the existing output buffer
336 //----------------------------------------------------
338 void Write(char character) {
339 if (m_write_ptr == m_buffer_end)
341 *m_write_ptr++ = character;
344 void Write(const char *content) { Write(content, strlen(content)); }
346 void Write(const char *content, long content_length) {
347 char *end_m_write_ptr = m_write_ptr + content_length;
348 if (end_m_write_ptr > m_buffer_end) {
349 if (content >= m_buffer && content < m_buffer_end) {
350 long offset = content - m_buffer;
351 GrowBuffer(end_m_write_ptr - m_buffer_end);
352 content = m_buffer + offset;
354 GrowBuffer(end_m_write_ptr - m_buffer_end);
356 end_m_write_ptr = m_write_ptr + content_length;
358 memcpy(m_write_ptr, content, content_length);
359 m_write_ptr = end_m_write_ptr;
361 #define WRITE(x) Write(x, sizeof(x) - 1)
363 void WriteTemplateStart() { Write('<'); }
365 void WriteTemplateEnd() {
366 // Put a space between terminal > characters when nesting templates
367 if (m_write_ptr != m_buffer && *(m_write_ptr - 1) == '>')
373 void WriteCommaSpace() { WRITE(", "); }
375 void WriteNamespaceSeparator() { WRITE("::"); }
377 void WriteStdPrefix() { WRITE("std::"); }
379 void WriteQualifiers(int qualifiers, bool space_before_reference = true) {
380 if (qualifiers & QualifierPointer)
382 if (qualifiers & QualifierConst)
384 if (qualifiers & QualifierVolatile)
386 if (qualifiers & QualifierRestrict)
388 if (qualifiers & QualifierReference) {
389 if (space_before_reference)
394 if (qualifiers & QualifierRValueReference) {
395 if (space_before_reference)
402 //----------------------------------------------------
405 // Write another copy of content already present
406 // earlier in the output buffer
407 //----------------------------------------------------
409 void RewriteRange(BufferRange range) {
410 Write(m_buffer + range.offset, range.length);
413 bool RewriteSubstitution(int index) {
414 if (index < 0 || index >= m_next_substitute_index) {
415 #ifdef DEBUG_FAILURES
416 printf("*** Invalid substitution #%d\n", index);
420 RewriteRange(m_rewrite_ranges[index]);
424 bool RewriteTemplateArg(int template_index) {
425 int index = m_rewrite_ranges_size - 1 - template_index;
426 if (template_index < 0 || index <= m_next_template_arg_index) {
427 #ifdef DEBUG_FAILURES
428 printf("*** Invalid template arg reference #%d\n", template_index);
432 RewriteRange(m_rewrite_ranges[index]);
436 //----------------------------------------------------
439 // Provide information with return values instead of
440 // writing to the output buffer
442 // Values indicating failure guarantee that the pre-
443 // call m_read_ptr is unchanged
444 //----------------------------------------------------
446 int TryParseNumber() {
447 unsigned char digit = *m_read_ptr - '0';
453 digit = *++m_read_ptr - '0';
457 count = count * 10 + digit;
462 int TryParseBase36Number() {
463 char digit = *m_read_ptr;
465 if (digit >= '0' && digit <= '9')
466 count = digit -= '0';
467 else if (digit >= 'A' && digit <= 'Z')
468 count = digit -= ('A' - 10);
473 digit = *++m_read_ptr;
474 if (digit >= '0' && digit <= '9')
476 else if (digit >= 'A' && digit <= 'Z')
481 count = count * 36 + digit;
486 // <builtin-type> ::= v # void
490 // ::= a # signed char
491 // ::= h # unsigned char
493 // ::= t # unsigned short
495 // ::= j # unsigned int
497 // ::= m # unsigned long
498 // ::= x # long long, __int64
499 // ::= y # unsigned long long, __int64
501 // ::= o # unsigned __int128
504 // ::= e # long double, __float80
505 // ::= g # __float128
507 // ::= Dd # IEEE 754r decimal floating point (64 bits)
508 // ::= De # IEEE 754r decimal floating point (128 bits)
509 // ::= Df # IEEE 754r decimal floating point (32 bits)
510 // ::= Dh # IEEE 754r half-precision floating point (16 bits)
513 // ::= Da # auto (in dependent new-expressions)
514 // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
515 // ::= u <source-name> # vendor extended type
517 const char *TryParseBuiltinType() {
519 m_builtins_hook(m_read_ptr);
521 switch (*m_read_ptr++) {
531 return "signed char";
533 return "unsigned char";
537 return "unsigned short";
541 return "unsigned int";
545 return "unsigned long";
549 return "unsigned long long";
553 return "unsigned __int128";
559 return "long double";
565 switch (*m_read_ptr++) {
581 return "decltype(auto)";
583 return "std::nullptr_t";
595 // ::= ad # & (unary)
603 // ::= de # * (unary)
621 // ::= mm # -- (postfix in <expression> context)
624 // ::= ng # - (unary)
633 // ::= pp # ++ (postfix in <expression> context)
634 // ::= ps # + (unary)
641 // ::= cv <type> # (cast)
642 // ::= v <digit> <source-name> # vendor extended
645 Operator TryParseOperator() {
646 switch (*m_read_ptr++) {
648 switch (*m_read_ptr++) {
650 return {"&&", OperatorKind::Binary};
652 return {"&", OperatorKind::Unary};
654 return {"&", OperatorKind::Binary};
656 return {"&=", OperatorKind::Binary};
658 return {"=", OperatorKind::Binary};
663 switch (*m_read_ptr++) {
665 return {"()", OperatorKind::Other};
667 return {",", OperatorKind::Other};
669 return {"~", OperatorKind::Unary};
671 return {nullptr, OperatorKind::ConversionOperator};
676 switch (*m_read_ptr++) {
678 return {" delete[]", OperatorKind::Other};
680 return {"*", OperatorKind::Unary};
682 return {" delete", OperatorKind::Other};
684 return {"/", OperatorKind::Binary};
686 return {"/=", OperatorKind::Binary};
691 switch (*m_read_ptr++) {
693 return {"^", OperatorKind::Binary};
695 return {"^=", OperatorKind::Binary};
697 return {"==", OperatorKind::Binary};
702 switch (*m_read_ptr++) {
704 return {">=", OperatorKind::Binary};
706 return {">", OperatorKind::Binary};
711 switch (*m_read_ptr++) {
713 return {"[]", OperatorKind::Other};
718 switch (*m_read_ptr++) {
720 return {"<=", OperatorKind::Binary};
722 return {"<<", OperatorKind::Binary};
724 return {"<<=", OperatorKind::Binary};
726 return {"<", OperatorKind::Binary};
727 // case 'i': return { "?", OperatorKind::Binary };
732 switch (*m_read_ptr++) {
734 return {"-", OperatorKind::Binary};
736 return {"-=", OperatorKind::Binary};
738 return {"*", OperatorKind::Binary};
740 return {"*=", OperatorKind::Binary};
742 return {"--", OperatorKind::Postfix};
747 switch (*m_read_ptr++) {
749 return {" new[]", OperatorKind::Other};
751 return {"!=", OperatorKind::Binary};
753 return {"-", OperatorKind::Unary};
755 return {"!", OperatorKind::Unary};
757 return {" new", OperatorKind::Other};
762 switch (*m_read_ptr++) {
764 return {"||", OperatorKind::Binary};
766 return {"|", OperatorKind::Binary};
768 return {"|=", OperatorKind::Binary};
773 switch (*m_read_ptr++) {
775 return {"->*", OperatorKind::Binary};
777 return {"+", OperatorKind::Unary};
779 return {"+", OperatorKind::Binary};
781 return {"+=", OperatorKind::Binary};
783 return {"++", OperatorKind::Postfix};
785 return {"->", OperatorKind::Binary};
790 switch (*m_read_ptr++) {
792 return {"?", OperatorKind::Ternary};
797 switch (*m_read_ptr++) {
799 return {"%", OperatorKind::Binary};
801 return {"%=", OperatorKind::Binary};
803 return {">>", OperatorKind::Binary};
805 return {">=", OperatorKind::Binary};
810 char digit = *m_read_ptr;
811 if (digit >= '0' && digit <= '9') {
813 return {nullptr, OperatorKind::Vendor};
819 return {nullptr, OperatorKind::NoMatch};
822 // <CV-qualifiers> ::= [r] [V] [K]
823 // <ref-qualifier> ::= R # & ref-qualifier
824 // <ref-qualifier> ::= O # && ref-qualifier
826 int TryParseQualifiers(bool allow_cv, bool allow_ro) {
827 int qualifiers = QualifierNone;
828 char next = *m_read_ptr;
830 if (next == 'r') // restrict
832 qualifiers |= QualifierRestrict;
833 next = *++m_read_ptr;
835 if (next == 'V') // volatile
837 qualifiers |= QualifierVolatile;
838 next = *++m_read_ptr;
840 if (next == 'K') // const
842 qualifiers |= QualifierConst;
843 next = *++m_read_ptr;
849 qualifiers |= QualifierReference;
850 } else if (next == 'O') {
852 qualifiers |= QualifierRValueReference;
858 // <discriminator> := _ <non-negative number> # when number < 10
859 // := __ <non-negative number> _ # when number >= 10
860 // extension := decimal-digit+
862 int TryParseDiscriminator() {
863 const char *discriminator_start = m_read_ptr;
865 // Test the extension first, since it's what Clang uses
866 int discriminator_value = TryParseNumber();
867 if (discriminator_value != -1)
868 return discriminator_value;
870 char next = *m_read_ptr;
872 next = *++m_read_ptr;
875 discriminator_value = TryParseNumber();
876 if (discriminator_value != -1 && *m_read_ptr++ != '_') {
877 return discriminator_value;
879 } else if (next >= '0' && next <= '9') {
885 // Not a valid discriminator
886 m_read_ptr = discriminator_start;
890 //----------------------------------------------------
893 // Consume input starting from m_read_ptr and produce
894 // buffered output at m_write_ptr
896 // Failures return false and may leave m_read_ptr in an
897 // indeterminate state
898 //----------------------------------------------------
900 bool Parse(char character) {
901 if (*m_read_ptr++ == character)
903 #ifdef DEBUG_FAILURES
904 printf("*** Expected '%c'\n", character);
909 // <number> ::= [n] <non-negative decimal integer>
911 bool ParseNumber(bool allow_negative = false) {
912 if (allow_negative && *m_read_ptr == 'n') {
916 const char *before_digits = m_read_ptr;
918 unsigned char digit = *m_read_ptr - '0';
923 if (int digit_count = (int)(m_read_ptr - before_digits)) {
924 Write(before_digits, digit_count);
927 #ifdef DEBUG_FAILURES
928 printf("*** Expected number\n");
933 // <substitution> ::= S <seq-id> _
935 // <substitution> ::= Sa # ::std::allocator
936 // <substitution> ::= Sb # ::std::basic_string
937 // <substitution> ::= Ss # ::std::basic_string < char,
938 // ::std::char_traits<char>,
939 // ::std::allocator<char> >
940 // <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char>
942 // <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char>
944 // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char>
947 bool ParseSubstitution() {
948 const char *substitution;
949 switch (*m_read_ptr) {
951 substitution = "std::allocator";
954 substitution = "std::basic_string";
957 substitution = "std::string";
960 substitution = "std::istream";
963 substitution = "std::ostream";
966 substitution = "std::iostream";
969 // A failed attempt to parse a number will return -1 which turns out to be
970 // perfect here as S_ is the first substitution, S0_ the next and so forth
971 int substitution_index = TryParseBase36Number();
972 if (*m_read_ptr++ != '_') {
973 #ifdef DEBUG_FAILURES
974 printf("*** Expected terminal _ in substitution\n");
978 return RewriteSubstitution(substitution_index + 1);
985 // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
987 // <bare-function-type> ::= <signature type>+ # types are possible return
988 // type, then parameter types
990 bool ParseFunctionType(int inner_qualifiers = QualifierNone) {
991 #ifdef DEBUG_FAILURES
992 printf("*** Function types not supported\n");
994 // TODO: first steps toward an implementation follow, but they're far
995 // from complete. Function types tend to bracket other types eg:
996 // int (*)() when used as the type for "name" becomes int (*name)().
997 // This makes substitution et al ... interesting.
1001 if (*m_read_ptr == 'Y')
1004 int return_type_start_cookie = GetStartCookie();
1009 int insert_cookie = GetStartCookie();
1011 bool first_param = true;
1012 int qualifiers = QualifierNone;
1015 switch (*m_read_ptr)
1026 if (*(m_read_ptr + 1) == 'E')
1028 qualifiers = TryParseQualifiers (false, true);
1036 first_param = false;
1037 else WriteCommaSpace();
1049 WriteQualifiers (qualifiers);
1050 EndSubstitution (return_type_start_cookie);
1053 if (inner_qualifiers)
1055 int qualifier_start_cookie = GetStartCookie();
1057 WriteQualifiers (inner_qualifiers);
1059 ReorderRange (EndRange (qualifier_start_cookie), insert_cookie);
1065 // <array-type> ::= A <positive dimension number> _ <element type>
1066 // ::= A [<dimension expression>] _ <element type>
1068 bool ParseArrayType(int qualifiers = QualifierNone) {
1069 #ifdef DEBUG_FAILURES
1070 printf("*** Array type unsupported\n");
1072 // TODO: We fail horribly when recalling these as substitutions or
1073 // templates and trying to constify them eg:
1074 // _ZN4llvm2cl5applyIA28_cNS0_3optIbLb0ENS0_6parserIbEEEEEEvRKT_PT0_
1076 // TODO: Chances are we don't do any better with references and pointers
1077 // that should be type (&) [] instead of type & []
1082 if (*m_read_ptr == '_')
1088 WriteQualifiers(qualifiers);
1094 const char *before_digits = m_read_ptr;
1095 if (TryParseNumber() != -1)
1097 const char *after_digits = m_read_ptr;
1103 WriteQualifiers(qualifiers);
1106 Write(before_digits, after_digits - before_digits);
1110 int type_insertion_cookie = GetStartCookie();
1111 if (!ParseExpression())
1116 int type_start_cookie = GetStartCookie();
1120 WriteQualifiers(qualifiers);
1123 ReorderRange (EndRange (type_start_cookie), type_insertion_cookie);
1131 // <pointer-to-member-type> ::= M <class type> <member type>
1133 // TODO: Determine how to handle pointers to function members correctly,
1134 // currently not an issue because we don't have function types at all...
1135 bool ParsePointerToMemberType() {
1136 int insertion_cookie = GetStartCookie();
1142 int type_cookie = GetStartCookie();
1145 ReorderRange(EndRange(type_cookie), insertion_cookie);
1149 // <template-param> ::= T_ # first template parameter
1150 // ::= T <parameter-2 non-negative number> _
1152 bool ParseTemplateParam() {
1153 int count = TryParseNumber();
1157 // When no number is present we get -1, which is convenient since
1158 // T_ is the zeroth element T0_ is element 1, and so on
1159 return RewriteTemplateArg(count + 1);
1163 // Dv <dimension number> _ <vector type>
1164 bool TryParseVectorType() {
1165 const int dimension = TryParseNumber();
1166 if (dimension == -1)
1169 if (*m_read_ptr++ != '_')
1172 char vec_dimens[32] = {'\0'};
1173 ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension);
1179 // <type> ::= <builtin-type>
1180 // ::= <function-type>
1181 // ::= <class-enum-type>
1183 // ::= <pointer-to-member-type>
1184 // ::= <template-param>
1185 // ::= <template-template-param> <template-args>
1187 // ::= <substitution>
1188 // ::= <CV-qualifiers> <type>
1189 // ::= P <type> # pointer-to
1190 // ::= R <type> # reference-to
1191 // ::= O <type> # rvalue reference-to (C++0x)
1192 // ::= C <type> # complex pair (C 2000)
1193 // ::= G <type> # imaginary (C 2000)
1194 // ::= Dp <type> # pack expansion (C++0x)
1195 // ::= U <source-name> <type> # vendor extended type qualifier
1196 // extension := U <objc-name> <objc-type> # objc-type<identifier>
1197 // extension := <vector-type> # <vector-type> starts with Dv
1199 // <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 +
1200 // <number of digits in k1> + k1
1201 // <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name>
1202 // 11objc_object -> id<source-name>
1205 #ifdef DEBUG_FAILURES
1206 const char *failed_type = m_read_ptr;
1208 int type_start_cookie = GetStartCookie();
1209 bool suppress_substitution = false;
1211 int qualifiers = TryParseQualifiers(true, false);
1212 switch (*m_read_ptr) {
1215 switch (*m_read_ptr++) {
1221 if (!TryParseVectorType())
1227 #ifdef DEBUG_FAILURES
1228 printf("*** Unsupported type: %.3s\n", failed_type);
1235 if (!ParseTemplateParam())
1240 if (!ParsePointerToMemberType())
1245 if (!ParseArrayType())
1250 if (!ParseFunctionType())
1254 if (*++m_read_ptr == 't') {
1260 suppress_substitution = true;
1261 if (!ParseSubstitution())
1266 switch (*++m_read_ptr) {
1269 if (!ParseFunctionType(QualifierPointer))
1298 #ifdef DEBUG_FAILURES
1299 printf("*** Unsupported type: %.3s\n", failed_type);
1302 // Test for common cases to avoid TryParseBuiltinType() overhead
1310 if (const char *builtin = TryParseBuiltinType()) {
1312 suppress_substitution = true;
1320 // Allow base substitutions to be suppressed, but always record
1321 // substitutions for the qualified variant
1322 if (!suppress_substitution)
1323 EndSubstitution(type_start_cookie);
1325 WriteQualifiers(qualifiers, false);
1326 EndSubstitution(type_start_cookie);
1331 // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
1332 // ::= <closure-type-name>
1334 // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
1336 // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda
1337 // has no parameters
1339 bool ParseUnnamedTypeName(NameState &name_state) {
1340 switch (*m_read_ptr++) {
1342 int cookie = GetStartCookie();
1344 const char *before_digits = m_read_ptr;
1345 if (TryParseNumber() != -1)
1346 Write(before_digits, m_read_ptr - before_digits);
1350 name_state.last_name_range = EndRange(cookie);
1354 int cookie = GetStartCookie();
1356 const char *before_digits = m_read_ptr;
1357 if (TryParseNumber() != -1)
1358 Write(before_digits, m_read_ptr - before_digits);
1362 name_state.last_name_range = EndRange(cookie);
1366 #ifdef DEBUG_FAILURES
1367 printf("*** Lambda type names unsupported\n");
1371 #ifdef DEBUG_FAILURES
1372 printf("*** Unknown unnamed type %.3s\n", m_read_ptr - 2);
1377 // <ctor-dtor-name> ::= C1 # complete object constructor
1378 // ::= C2 # base object constructor
1379 // ::= C3 # complete object allocating constructor
1381 bool ParseCtor(NameState &name_state) {
1382 char next = *m_read_ptr;
1383 if (next == '1' || next == '2' || next == '3' || next == '5') {
1384 RewriteRange(name_state.last_name_range);
1385 name_state.has_no_return_type = true;
1389 #ifdef DEBUG_FAILURES
1390 printf("*** Broken constructor\n");
1395 // <ctor-dtor-name> ::= D0 # deleting destructor
1396 // ::= D1 # complete object destructor
1397 // ::= D2 # base object destructor
1399 bool ParseDtor(NameState &name_state) {
1400 char next = *m_read_ptr;
1401 if (next == '0' || next == '1' || next == '2' || next == '5') {
1403 RewriteRange(name_state.last_name_range);
1404 name_state.has_no_return_type = true;
1408 #ifdef DEBUG_FAILURES
1409 printf("*** Broken destructor\n");
1414 // See TryParseOperator()
1416 bool ParseOperatorName(NameState &name_state) {
1417 #ifdef DEBUG_FAILURES
1418 const char *operator_ptr = m_read_ptr;
1420 Operator parsed_operator = TryParseOperator();
1421 if (parsed_operator.name) {
1423 Write(parsed_operator.name);
1427 // Handle special operators
1428 switch (parsed_operator.kind) {
1429 case OperatorKind::Vendor:
1431 return ParseSourceName();
1432 case OperatorKind::ConversionOperator:
1433 ResetTemplateArgs();
1434 name_state.has_no_return_type = true;
1438 #ifdef DEBUG_FAILURES
1439 printf("*** Unknown operator: %.2s\n", operator_ptr);
1445 // <source-name> ::= <positive length number> <identifier>
1447 bool ParseSourceName() {
1448 int count = TryParseNumber();
1450 #ifdef DEBUG_FAILURES
1451 printf("*** Malformed source name, missing length count\n");
1456 const char *next_m_read_ptr = m_read_ptr + count;
1457 if (next_m_read_ptr > m_read_end) {
1458 #ifdef DEBUG_FAILURES
1459 printf("*** Malformed source name, premature termination\n");
1464 if (count >= 10 && strncmp(m_read_ptr, "_GLOBAL__N", 10) == 0)
1465 WRITE("(anonymous namespace)");
1467 Write(m_read_ptr, count);
1469 m_read_ptr = next_m_read_ptr;
1473 // <unqualified-name> ::= <operator-name>
1474 // ::= <ctor-dtor-name>
1475 // ::= <source-name>
1476 // ::= <unnamed-type-name>
1478 bool ParseUnqualifiedName(NameState &name_state) {
1479 // Note that these are detected directly in ParseNestedName for
1480 // performance rather than switching on the same options twice
1481 char next = *m_read_ptr;
1485 return ParseCtor(name_state);
1488 return ParseDtor(name_state);
1491 return ParseUnnamedTypeName(name_state);
1502 int name_start_cookie = GetStartCookie();
1503 if (!ParseSourceName())
1505 name_state.last_name_range = EndRange(name_start_cookie);
1509 return ParseOperatorName(name_state);
1513 // <unscoped-name> ::= <unqualified-name>
1514 // ::= St <unqualified-name> # ::std::
1515 // extension ::= StL<unqualified-name>
1517 bool ParseUnscopedName(NameState &name_state) {
1518 if (*m_read_ptr == 'S' && *(m_read_ptr + 1) == 't') {
1520 if (*(m_read_ptr += 2) == 'L')
1523 return ParseUnqualifiedName(name_state);
1526 bool ParseIntegerLiteral(const char *prefix, const char *suffix,
1527 bool allow_negative) {
1530 if (!ParseNumber(allow_negative))
1537 bool ParseBooleanLiteral() {
1538 switch (*m_read_ptr++) {
1546 #ifdef DEBUG_FAILURES
1547 printf("*** Boolean literal not 0 or 1\n");
1554 // <expr-primary> ::= L <type> <value number> E #
1556 // ::= L <type> <value float> E #
1558 // ::= L <string type> E #
1560 // ::= L <nullptr type> E #
1561 // nullptr literal (i.e., "LDnE")
1562 // ::= L <type> <real-part float> _ <imag-part float> E #
1563 // complex floating point literal (C 2000)
1564 // ::= L <mangled-name> E #
1567 bool ParseExpressionPrimary() {
1568 switch (*m_read_ptr++) {
1570 return ParseBooleanLiteral();
1572 return ParseIntegerLiteral(nullptr, "ll", true);
1574 return ParseIntegerLiteral(nullptr, "l", true);
1576 return ParseIntegerLiteral(nullptr, nullptr, true);
1578 return ParseIntegerLiteral("(__int128)", nullptr, true);
1580 return ParseIntegerLiteral(nullptr, "u", false);
1582 return ParseIntegerLiteral(nullptr, "ul", false);
1584 return ParseIntegerLiteral(nullptr, "ull", false);
1586 return ParseIntegerLiteral("(unsigned __int128)", nullptr, false);
1588 if (*m_read_ptr++ == 'Z') {
1589 if (!ParseEncoding())
1604 #ifdef DEBUG_FAILURES
1605 printf("*** Unsupported primary expression %.5s\n", m_read_ptr - 1);
1609 // Invalid mangled name per
1610 // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
1611 #ifdef DEBUG_FAILURES
1612 printf("*** Invalid primary expr encoding\n");
1627 // <unresolved-type> ::= <template-param>
1629 // ::= <substitution>
1631 bool ParseUnresolvedType() {
1632 int type_start_cookie = GetStartCookie();
1633 switch (*m_read_ptr++) {
1635 if (!ParseTemplateParam())
1637 EndSubstitution(type_start_cookie);
1640 if (*m_read_ptr != 't')
1641 return ParseSubstitution();
1645 NameState type_name = {};
1646 if (!ParseUnqualifiedName(type_name))
1648 EndSubstitution(type_start_cookie);
1653 #ifdef DEBUG_FAILURES
1654 printf("*** Unsupported unqualified type: %3s\n", m_read_ptr - 1);
1660 // <base-unresolved-name> ::= <simple-id> #
1662 // extension ::= <operator-name> #
1663 // unresolved operator-function-id
1664 // extension ::= <operator-name> <template-args> #
1665 // unresolved operator template-id
1666 // ::= on <operator-name> #
1667 // unresolved operator-function-id
1668 // ::= on <operator-name> <template-args> #
1669 // unresolved operator template-id
1670 // ::= dn <destructor-name> #
1671 // destructor or pseudo-destructor;
1678 bool ParseBaseUnresolvedName() {
1679 #ifdef DEBUG_FAILURES
1680 printf("*** Base unresolved name unsupported\n");
1685 // <unresolved-name>
1686 // extension ::= srN <unresolved-type> [<template-args>]
1687 // <unresolved-qualifier-level>* E <base-unresolved-name>
1688 // ::= [gs] <base-unresolved-name> # x
1689 // or (with "gs") ::x
1690 // ::= [gs] sr <unresolved-qualifier-level>+ E
1691 // <base-unresolved-name>
1700 // ::= sr <unresolved-type> <base-unresolved-name> #
1701 // T::x / decltype(p)::x
1702 // extension ::= sr <unresolved-type> <template-args>
1703 // <base-unresolved-name>
1706 // /decltype(p)::N::x
1707 // (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+
1708 // E <base-unresolved-name>
1710 bool ParseUnresolvedName() {
1711 #ifdef DEBUG_FAILURES
1712 printf("*** Unresolved names not supported\n");
1714 // TODO: grammar for all of this seems unclear...
1718 if (*m_read_ptr == 'g' && *(m_read_ptr + 1) == 's')
1721 WriteNamespaceSeparator();
1726 // <expression> ::= <unary operator-name> <expression>
1727 // ::= <binary operator-name> <expression> <expression>
1728 // ::= <ternary operator-name> <expression> <expression>
1730 // ::= cl <expression>+ E #
1732 // ::= cv <type> <expression> #
1733 // conversion with one argument
1734 // ::= cv <type> _ <expression>* E #
1735 // conversion with a different number of arguments
1736 // ::= [gs] nw <expression>* _ <type> E # new
1738 // ::= [gs] nw <expression>* _ <type> <initializer> # new
1739 // (expr-list) type (init)
1740 // ::= [gs] na <expression>* _ <type> E #
1741 // new[] (expr-list) type
1742 // ::= [gs] na <expression>* _ <type> <initializer> #
1743 // new[] (expr-list) type (init)
1744 // ::= [gs] dl <expression> #
1745 // delete expression
1746 // ::= [gs] da <expression> #
1747 // delete[] expression
1748 // ::= pp_ <expression> #
1750 // ::= mm_ <expression> #
1754 // ::= te <expression> #
1755 // typeid (expression)
1756 // ::= dc <type> <expression> #
1757 // dynamic_cast<type> (expression)
1758 // ::= sc <type> <expression> #
1759 // static_cast<type> (expression)
1760 // ::= cc <type> <expression> #
1761 // const_cast<type> (expression)
1762 // ::= rc <type> <expression> #
1763 // reinterpret_cast<type> (expression)
1766 // ::= sz <expression> #
1767 // sizeof (an expression)
1770 // ::= az <expression> #
1771 // alignof (an expression)
1772 // ::= nx <expression> #
1773 // noexcept (expression)
1774 // ::= <template-param>
1775 // ::= <function-param>
1776 // ::= dt <expression> <unresolved-name> #
1778 // ::= pt <expression> <unresolved-name> #
1780 // ::= ds <expression> <expression> #
1782 // ::= sZ <template-param> #
1783 // size of a parameter pack
1784 // ::= sZ <function-param> #
1785 // size of a function parameter pack
1786 // ::= sp <expression> #
1788 // ::= tw <expression> #
1791 // throw with no operand (rethrow)
1792 // ::= <unresolved-name> #
1793 // f(p), N::f(p), ::f(p),
1805 // ::= <expr-primary>
1807 bool ParseExpression() {
1808 Operator expression_operator = TryParseOperator();
1809 switch (expression_operator.kind) {
1810 case OperatorKind::Unary:
1811 Write(expression_operator.name);
1813 if (!ParseExpression())
1817 case OperatorKind::Binary:
1818 if (!ParseExpression())
1820 Write(expression_operator.name);
1821 return ParseExpression();
1822 case OperatorKind::Ternary:
1823 if (!ParseExpression())
1826 if (!ParseExpression())
1829 return ParseExpression();
1830 case OperatorKind::NoMatch:
1832 case OperatorKind::Other:
1834 #ifdef DEBUG_FAILURES
1835 printf("*** Unsupported operator: %s\n", expression_operator.name);
1840 switch (*m_read_ptr++) {
1842 return ParseTemplateParam();
1844 return ParseExpressionPrimary();
1846 if (*m_read_ptr++ == 'r')
1847 return ParseUnresolvedName();
1851 return ParseExpressionPrimary();
1855 // <template-arg> ::= <type> #
1857 // ::= X <expression> E #
1859 // ::= <expr-primary> #
1860 // simple expressions
1861 // ::= J <template-arg>* E #
1863 // ::= LZ <encoding> E #
1866 bool ParseTemplateArg() {
1867 switch (*m_read_ptr) {
1869 #ifdef DEBUG_FAILURES
1870 printf("*** Template argument packs unsupported\n");
1875 if (!ParseExpression())
1880 return ParseExpressionPrimary();
1886 // <template-args> ::= I <template-arg>* E
1887 // extension, the abi says <template-arg>+
1889 bool ParseTemplateArgs(bool record_template_args = false) {
1890 if (record_template_args)
1891 ResetTemplateArgs();
1893 bool first_arg = true;
1894 while (*m_read_ptr != 'E') {
1900 int template_start_cookie = GetStartCookie();
1901 if (!ParseTemplateArg())
1903 if (record_template_args)
1904 EndTemplateArg(template_start_cookie);
1910 // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix>
1911 // <unqualified-name> E
1912 // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
1913 // <template-args> E
1915 // <prefix> ::= <prefix> <unqualified-name>
1916 // ::= <template-prefix> <template-args>
1917 // ::= <template-param>
1920 // ::= <substitution>
1921 // ::= <prefix> <data-member-prefix>
1924 // <template-prefix> ::= <prefix> <template unqualified-name>
1925 // ::= <template-param>
1926 // ::= <substitution>
1928 // <unqualified-name> ::= <operator-name>
1929 // ::= <ctor-dtor-name>
1930 // ::= <source-name>
1931 // ::= <unnamed-type-name>
1933 bool ParseNestedName(NameState &name_state,
1934 bool parse_discriminator = false) {
1935 int qualifiers = TryParseQualifiers(true, true);
1936 bool first_part = true;
1937 bool suppress_substitution = true;
1938 int name_start_cookie = GetStartCookie();
1940 char next = *m_read_ptr;
1946 // Record a substitution candidate for all prefixes, but not the full name
1947 if (suppress_substitution)
1948 suppress_substitution = false;
1950 EndSubstitution(name_start_cookie);
1954 name_state.is_last_generic = true;
1955 WriteTemplateStart();
1956 if (!ParseTemplateArgs(name_state.parse_function_params))
1965 WriteNamespaceSeparator();
1967 name_state.is_last_generic = false;
1979 int name_start_cookie = GetStartCookie();
1980 if (!ParseSourceName())
1982 name_state.last_name_range = EndRange(name_start_cookie);
1986 if (*++m_read_ptr == 't') {
1989 if (!ParseUnqualifiedName(name_state))
1992 if (!ParseSubstitution())
1994 suppress_substitution = true;
1999 if (!ParseTemplateParam())
2004 if (!ParseCtor(name_state))
2008 switch (*(m_read_ptr + 1)) {
2011 #ifdef DEBUG_FAILURES
2012 printf("*** Decltype unsupported\n");
2017 if (!ParseDtor(name_state))
2023 if (!ParseUnnamedTypeName(name_state))
2028 if (!ParseUnqualifiedName(name_state))
2032 if (!ParseOperatorName(name_state))
2037 if (parse_discriminator)
2038 TryParseDiscriminator();
2039 if (name_state.parse_function_params &&
2040 !ParseFunctionArgs(name_state, name_start_cookie)) {
2044 WriteQualifiers(qualifiers);
2048 // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
2049 // := Z <function encoding> E s [<discriminator>]
2050 // := Z <function encoding> Ed [ <parameter number> ] _ <entity
2053 bool ParseLocalName(bool parse_function_params) {
2054 if (!ParseEncoding())
2059 switch (*m_read_ptr) {
2062 TryParseDiscriminator(); // Optional and ignored
2063 WRITE("::string literal");
2067 TryParseNumber(); // Optional and ignored
2070 WriteNamespaceSeparator();
2075 WriteNamespaceSeparator();
2076 if (!ParseName(parse_function_params, true))
2078 TryParseDiscriminator(); // Optional and ignored
2083 // <name> ::= <nested-name>
2085 // ::= <unscoped-template-name> <template-args>
2086 // ::= <unscoped-name>
2088 // <unscoped-template-name> ::= <unscoped-name>
2089 // ::= <substitution>
2091 bool ParseName(bool parse_function_params = false,
2092 bool parse_discriminator = false) {
2093 NameState name_state = {parse_function_params, false, false, {0, 0}};
2094 int name_start_cookie = GetStartCookie();
2096 switch (*m_read_ptr) {
2099 return ParseNestedName(name_state, parse_discriminator);
2102 if (!ParseLocalName(parse_function_params))
2110 if (!ParseUnscopedName(name_state))
2113 if (*m_read_ptr == 'I') {
2114 EndSubstitution(name_start_cookie);
2117 name_state.is_last_generic = true;
2118 WriteTemplateStart();
2119 if (!ParseTemplateArgs(parse_function_params))
2126 if (parse_discriminator)
2127 TryParseDiscriminator();
2128 if (parse_function_params &&
2129 !ParseFunctionArgs(name_state, name_start_cookie)) {
2135 // <call-offset> ::= h <nv-offset> _
2136 // ::= v <v-offset> _
2138 // <nv-offset> ::= <offset number>
2139 // # non-virtual base override
2141 // <v-offset> ::= <offset number> _ <virtual offset number>
2142 // # virtual base override, with vcall offset
2144 bool ParseCallOffset() {
2145 switch (*m_read_ptr++) {
2147 if (*m_read_ptr == 'n')
2149 if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
2153 if (*m_read_ptr == 'n')
2155 if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
2157 if (*m_read_ptr == 'n')
2159 if (TryParseNumber() == -1 || *m_read_ptr++ != '_')
2163 #ifdef DEBUG_FAILURES
2164 printf("*** Malformed call offset\n");
2169 // <special-name> ::= TV <type> # virtual table
2170 // ::= TT <type> # VTT structure (construction vtable index)
2171 // ::= TI <type> # typeinfo structure
2172 // ::= TS <type> # typeinfo name (null-terminated byte
2174 // ::= Tc <call-offset> <call-offset> <base encoding>
2175 // # base is the nominal target function of thunk
2176 // # first call-offset is 'this' adjustment
2177 // # second call-offset is result adjustment
2178 // ::= T <call-offset> <base encoding>
2179 // # base is the nominal target function of thunk
2180 // extension ::= TC <first type> <number> _ <second type> # construction
2181 // vtable for second-in-first
2183 bool ParseSpecialNameT() {
2184 switch (*m_read_ptr++) {
2186 WRITE("vtable for ");
2192 WRITE("typeinfo for ");
2195 WRITE("typeinfo name for ");
2199 #ifdef DEBUG_FAILURES
2200 printf("*** Unsupported thunk or construction vtable name: %.3s\n",
2205 if (*--m_read_ptr == 'v') {
2206 WRITE("virtual thunk to ");
2208 WRITE("non-virtual thunk to ");
2210 if (!ParseCallOffset())
2212 return ParseEncoding();
2216 // <special-name> ::= GV <object name> # Guard variable for one-time
2219 // extension ::= GR <object name> # reference temporary for object
2221 bool ParseSpecialNameG() {
2222 switch (*m_read_ptr++) {
2224 WRITE("guard variable for ");
2225 if (!ParseName(true))
2229 WRITE("reference temporary for ");
2230 if (!ParseName(true))
2234 #ifdef DEBUG_FAILURES
2235 printf("*** Unknown G encoding\n");
2242 // <bare-function-type> ::= <signature type>+ # types are possible
2243 // return type, then parameter types
2245 bool ParseFunctionArgs(NameState &name_state, int return_insert_cookie) {
2246 char next = *m_read_ptr;
2247 if (next == 'E' || next == '\0' || next == '.')
2250 // Clang has a bad habit of making unique manglings by just sticking numbers
2251 // on the end of a symbol,
2252 // which is ambiguous with malformed source name manglings
2253 const char *before_clang_uniquing_test = m_read_ptr;
2254 if (TryParseNumber()) {
2255 if (*m_read_ptr == '\0')
2257 m_read_ptr = before_clang_uniquing_test;
2260 if (name_state.is_last_generic && !name_state.has_no_return_type) {
2261 int return_type_start_cookie = GetStartCookie();
2265 ReorderRange(EndRange(return_type_start_cookie), return_insert_cookie);
2269 bool first_param = true;
2271 switch (*m_read_ptr) {
2280 // Not a formal part of the mangling specification, but clang emits
2281 // suffixes starting with _block_invoke
2282 if (strncmp(m_read_ptr, "_block_invoke", 13) == 0) {
2283 m_read_ptr += strlen(m_read_ptr);
2289 first_param = false;
2303 // <encoding> ::= <function name> <bare-function-type>
2305 // ::= <special-name>
2307 bool ParseEncoding() {
2308 switch (*m_read_ptr) {
2311 if (!ParseSpecialNameT())
2316 if (!ParseSpecialNameG())
2320 if (!ParseName(true))
2327 bool ParseMangling(const char *mangled_name, long mangled_name_length = 0) {
2328 if (!mangled_name_length)
2329 mangled_name_length = strlen(mangled_name);
2330 m_read_end = mangled_name + mangled_name_length;
2331 m_read_ptr = mangled_name;
2332 m_write_ptr = m_buffer;
2333 m_next_substitute_index = 0;
2334 m_next_template_arg_index = m_rewrite_ranges_size - 1;
2336 if (*m_read_ptr++ != '_' || *m_read_ptr++ != 'Z') {
2337 #ifdef DEBUG_FAILURES
2338 printf("*** Missing _Z prefix\n");
2342 if (!ParseEncoding())
2344 switch (*m_read_ptr) {
2348 Write(m_read_ptr, m_read_end - m_read_ptr);
2354 #ifdef DEBUG_FAILURES
2355 printf("*** Unparsed mangled content\n");
2362 // External scratch storage used during demanglings
2365 const char *m_buffer_end;
2366 BufferRange *m_rewrite_ranges;
2367 int m_rewrite_ranges_size;
2369 bool m_owns_m_rewrite_ranges;
2371 // Internal state used during demangling
2373 const char *m_read_ptr;
2374 const char *m_read_end;
2376 int m_next_template_arg_index;
2377 int m_next_substitute_index;
2378 std::function<void(const char *s)> m_builtins_hook;
2381 } // Anonymous namespace
2383 // Public entry points referenced from Mangled.cpp
2384 namespace lldb_private {
2385 char *FastDemangle(const char *mangled_name) {
2387 SymbolDemangler demangler(buffer, sizeof(buffer));
2388 return demangler.GetDemangledCopy(mangled_name);
2391 char *FastDemangle(const char *mangled_name, size_t mangled_name_length,
2392 std::function<void(const char *s)> builtins_hook) {
2394 SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook);
2395 return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
2397 } // lldb_private namespace