📄 demangle.h
字号:
// implicitely contained in <T> instead of explicitly part of the M format.
// I am convinced that this is a bug in the ABI. Unfortunately, this is
// how we have to demangle things as it has a direct impact on the order
// in which substitutions are stored. This ill-formed design results in
// rather ill-formed demangler code too however :/
//
// <Q2> is now explicitely part of the M format.
// For some weird reason, g++ (3.2.1) does not add substitutions for
// qualified member function pointers. I think that is another bug.
//
// In the case of
// <Q>A<I>
// where <Q> ends on [K|V|r]+ then that part should be processed as
// if it was behind the A<I> instead of in front of it. This is
// because a constant array of ints is normally always mangled as
// an array of constant ints. KVr qualifiers can end up in front
// of an array when the array is part of a substitution or template
// parameter, but the demangling should still result in the same
// syntax; thus KA2_i (const array of ints) must result in the same
// demangling as A2_Ki (array of const ints). As a result we must
// demangle ...[...[[KVr]+A<I0>][KVr]+A<I1>]...[KVr]+A<In>[KVr]+
// as A<I0>A<I1>...A<In>[KVr]+ where each K, V and r in the series
// collapses to a single character at the right of the string.
// For example:
// VA9_KrA6_KVi --> A9_A6_KVri --> int volatile const restrict [9][6]
// Note that substitutions are still added as usual (the translation
// to A9_A6_KVri does not really happen).
//
// This decoding is achieved by delaying the decoding of any sequence
// of [KVrA]'s and processing them together in the order: first the
// short-circuited KVr part and then the arrays.
static int const cvq_K = 1; // Saw at least one K
static int const cvq_V = 2; // Saw at least one V
static int const cvq_r = 4; // Saw at least one r
static int const cvq_A = 8; // Saw at least one A
static int const cvq_last = 16; // No remaining qualifiers.
static int const cvq_A_cnt = 32; // Bit 5 and higher represent the
// number of A's in the series.
// In the function below, iter_array points to the first (right most)
// A in the series, if any.
template<typename Tp, typename Allocator>
void
qualifier_list<Tp, Allocator>::decode_KVrA(
string_type& prefix, string_type& postfix, int cvq,
typename qual_vector::const_reverse_iterator const& iter_array) const
{
_GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_KVrA");
if ((cvq & cvq_K))
prefix += " const";
if ((cvq & cvq_V))
prefix += " volatile";
if ((cvq & cvq_r))
prefix += " restrict";
if ((cvq & cvq_A))
{
int n = cvq >> 5;
for (typename qual_vector::
const_reverse_iterator iter = iter_array;
iter != M_qualifier_starts.rend(); ++iter)
{
switch((*iter).first_qualifier())
{
case 'K':
case 'V':
case 'r':
break;
case 'A':
{
string_type index = (*iter).get_optional_type();
if (--n == 0 && (cvq & cvq_last))
postfix = " [" + index + "]" + postfix;
else if (n > 0)
postfix = "[" + index + "]" + postfix;
else
{
prefix += " (";
postfix = ") [" + index + "]" + postfix;
}
break;
}
default:
_GLIBCXX_DEMANGLER_RETURN3;
}
}
}
_GLIBCXX_DEMANGLER_RETURN3;
}
template<typename Tp, typename Allocator>
void
qualifier_list<Tp, Allocator>::decode_qualifiers(
string_type& prefix,
string_type& postfix,
bool member_function_pointer_qualifiers = false) const
{
_GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_qualifiers");
int cvq = 0;
typename qual_vector::const_reverse_iterator iter_array;
for(typename qual_vector::
const_reverse_iterator iter = M_qualifier_starts.rbegin();
iter != M_qualifier_starts.rend(); ++iter)
{
if (!member_function_pointer_qualifiers
&& !(*iter).part_of_substitution())
{
int saved_inside_substitution = M_demangler.M_inside_substitution;
M_demangler.M_inside_substitution = 0;
M_demangler.add_substitution((*iter).get_start_pos(), type);
M_demangler.M_inside_substitution = saved_inside_substitution;
}
char qualifier_char = (*iter).first_qualifier();
for(; qualifier_char; qualifier_char = (*iter).next_qualifier())
{
switch(qualifier_char)
{
case 'P':
if (cvq)
{
decode_KVrA(prefix, postfix, cvq, iter_array);
cvq = 0;
}
prefix += "*";
break;
case 'R':
if (cvq)
{
decode_KVrA(prefix, postfix, cvq, iter_array);
cvq = 0;
}
prefix += "&";
break;
case 'K':
cvq |= cvq_K;
continue;
case 'V':
cvq |= cvq_V;
continue;
case 'r':
cvq |= cvq_r;
continue;
case 'A':
if (!(cvq & cvq_A))
{
cvq |= cvq_A;
iter_array = iter;
}
cvq += cvq_A_cnt;
break;
case 'M':
if (cvq)
{
decode_KVrA(prefix, postfix, cvq, iter_array);
cvq = 0;
}
prefix += " ";
prefix += (*iter).get_optional_type();
prefix += "::*";
break;
case 'U':
if (cvq)
{
decode_KVrA(prefix, postfix, cvq, iter_array);
cvq = 0;
}
prefix += " ";
prefix += (*iter).get_optional_type();
break;
case 'G': // Only here so we added a substitution.
break;
}
break;
}
}
if (cvq)
decode_KVrA(prefix, postfix, cvq|cvq_last, iter_array);
M_printing_suppressed = false;
_GLIBCXX_DEMANGLER_RETURN3;
}
//
template<typename Tp, typename Allocator>
bool
session<Tp, Allocator>::decode_type_with_postfix(
string_type& prefix, string_type& postfix,
qualifier_list<Tp, Allocator>* qualifiers)
{
_GLIBCXX_DEMANGLER_DOUT_ENTERING2("decode_type");
++M_inside_type;
bool recursive_template_param_or_substitution_call;
if (!(recursive_template_param_or_substitution_call = qualifiers))
{
qualifier_list<Allocator>* raw_qualifiers = M_qualifier_list_alloc.allocate(1);
qualifiers = new (raw_qualifiers) qualifier_list<Allocator>(*this);
}
// First eat all qualifiers.
bool failure = false;
for(;;) // So we can use 'continue' to eat the next qualifier.
{
int start_pos = M_pos;
switch(current())
{
case 'P':
qualifiers->add_qualifier_start(pointer, start_pos,
M_inside_substitution);
eat_current();
continue;
case 'R':
qualifiers->add_qualifier_start(reference, start_pos,
M_inside_substitution);
eat_current();
continue;
case 'K':
case 'V':
case 'r':
{
char c;
int count = 0;
do
{
++count;
c = next();
}
while(c == 'K' || c == 'V' || c == 'r');
qualifiers->add_qualifier_start(cv_qualifier, start_pos, count,
M_inside_substitution);
continue;
}
case 'U':
{
eat_current();
string_type source_name;
if (!decode_source_name(source_name))
{
failure = true;
break;
}
qualifiers->add_qualifier_start(vendor_extension, start_pos,
source_name, M_inside_substitution);
continue;
}
case 'A':
{
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
//
string_type index;
int saved_pos;
store(saved_pos);
if (next() == 'n' || !decode_number(index))
{
restore(saved_pos);
if (next() != '_' && !decode_expression(index))
{
failure = true;
break;
}
}
if (eat_current() != '_')
{
failure = true;
break;
}
qualifiers->add_qualifier_start(array, start_pos, index,
M_inside_substitution);
continue;
}
case 'M':
{
// <pointer-to-member-type> ::= M <class type> <member type>
// <Q>M<C> or <Q>M<C><Q2>F<R><B>E
eat_current();
string_type class_type;
if (!decode_type(class_type)) // Substitution: "<C>".
{
failure = true;
break;
}
char c = current();
if (c == 'F' || c == 'K' || c == 'V' || c == 'r')
// Must be CV-qualifiers and a member function pointer.
{
// <Q>M<C><Q2>F<R><B>E ==> R (C::*Q)B Q2
// substitutions: "<C>", "F<R><B>E" (<R> and <B>
// recursive), "M<C><Q2>F<R><B>E".
int count = 0;
int Q2_start_pos = M_pos;
while(c == 'K' || c == 'V' || c == 'r') // Decode <Q2>.
{
++count;
c = next();
}
qualifier_list<Tp, Allocator> class_type_qualifiers(*this);
if (count)
class_type_qualifiers.
add_qualifier_start(cv_qualifier, Q2_start_pos,
count, M_inside_substitution);
string_type member_function_qualifiers;
// It is unclear why g++ doesn't add a substitution for
// "<Q2>F<R><B>E" as it should I think.
string_type member_function_qualifiers_postfix;
class_type_qualifiers.
decode_qualifiers(member_function_qualifiers,
member_function_qualifiers_postfix, true);
member_function_qualifiers +=
member_function_qualifiers_postfix;
// I don't think this substitution is actually ever used.
int function_pos = M_pos;
if (eat_current() != 'F')
{
failure = true;
break;
}
// Return type.
// Constructors, destructors and conversion operators don't
// have a return type, but seem to never get here.
string_type return_type_postfix;
if (!decode_type_with_postfix(prefix, return_type_postfix))
// substitution: <R> recursive
{
failure = true;
break;
}
prefix += " (";
prefix += class_type;
prefix += "::*";
string_type bare_function_type;
if (!decode_bare_function_type(bare_function_type)
|| eat_current() != 'E') // Substitution: <B> recursive.
{
failure = true;
break;
}
// substitution: "F<R><B>E".
add_substitution(function_pos, type);
// substitution: "M<C><Q2>F<R><B>E".
add_substitution(start_pos, type);
// substitution: all qualified types if any.
qualifiers->decode_qualifiers(prefix, postfix);
postfix += ")";
postfix += bare_function_type;
postfix += member_function_qualifiers;
postfix += return_type_postfix;
goto decode_type_exit;
}
qualifiers->add_qualifier_start(pointer_to_member, start_pos,
class_type, M_inside_substitution);
continue;
}
default:
break;
}
break;
}
if (!failure)
{
// <Q>G<T> ==> imaginary T Q
// substitutions: "<T>", "G<T>" (<T> recursive).
// <Q>C<T> ==> complex T Q
// substitutions: "<T>", "C<T>" (<T> recursive).
if (current() == 'C' || current() == 'G')
{
prefix += current() == 'C' ? "complex " : "imaginary ";
qualifiers->add_qualifier_start(complex_or_imaginary, M_pos,
M_inside_substitution);
eat_current();
}
int start_pos = M_pos;
switch(current())
{
case 'F':
{
// <function-type> ::= F [Y] <bare-function-type> E
//
// Note that g++ never generates the 'Y', but we try to
// demangle it anyway.
bool extern_C = (next() == 'Y');
if (extern_C)
eat_current();
// <Q>F<R><B>E ==> R (Q)B
// substitution: "<R>", "<B>" (<B> recursive) and "F<R><B>E".
// Return type.
string_type return_type_postfix;
if (!decode_type_with_postfix(prefix, return_type_postfix))
// Substitution: "<R>".
{
failure = true;
break;
}
// Only array and function (pointer) types have a postfix.
// In that case we don't want the space but expect something
// like prefix is "int (*" and postfix is ") [1]".
// We do want the space if this pointer is qualified.
if (return_type_postfix.size() == 0 ||
(prefix.size() > 0 && *prefix.rbegin() != '*'))
prefix += ' ';
prefix += '(';
string_type bare_function_type;
if (!decode_bare_function_type(bare_function_type)
// substitution: "<B>" (<B> recursive).
|| eat_current() != 'E')
{
failure = true;
break;
}
add_substitution(start_pos, type); // Substitution: "F<R><B>E".
qualifiers->decode_qualifiers(prefix, postfix);
// substitution: all qualified types, if any.
postfix += ")";
if (extern_C)
postfix += " [extern \"C\"] ";
postfix += bare_function_type;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -