Add partial C++0x support and recognition of GCC function clone suffixes to
demangle.cc. Fixes issue 80. Make svn ignore autom4te.cache. git-svn-id: https://google-glog.googlecode.com/svn/trunk@91 eb4d4688-79bd-11dd-afb4-1d65580434c0
This commit is contained in:
parent
1e86eecaf6
commit
0b4dcd23ac
@ -28,6 +28,11 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Author: Satoru Takabayashi
|
// Author: Satoru Takabayashi
|
||||||
|
//
|
||||||
|
// For reference check out:
|
||||||
|
// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
|
||||||
|
//
|
||||||
|
// Note that we only have partial C++0x support yet.
|
||||||
|
|
||||||
#include <stdio.h> // for NULL
|
#include <stdio.h> // for NULL
|
||||||
#include "demangle.h"
|
#include "demangle.h"
|
||||||
@ -245,6 +250,15 @@ static bool OneOrMore(ParseFunc parse_func, State *state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is used for handling <non-terminal>* syntax. The function
|
||||||
|
// always returns true and must be followed by a termination symbol or a
|
||||||
|
// terminating sequence not handled by parse_func (e.g. ParseChar(state, 'E')).
|
||||||
|
static bool ZeroOrMore(ParseFunc parse_func, State *state) {
|
||||||
|
while (parse_func(state)) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Append "str" at "out_cur". If there is an overflow, "overflowed"
|
// Append "str" at "out_cur". If there is an overflow, "overflowed"
|
||||||
// is set to true for later use. The output string is ensured to
|
// is set to true for later use. The output string is ensured to
|
||||||
// always terminate with '\0' as long as there is no overflow.
|
// always terminate with '\0' as long as there is no overflow.
|
||||||
@ -273,6 +287,36 @@ static bool IsAlpha(char c) {
|
|||||||
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
|
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsDigit(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if "str" is a function clone suffix. These suffixes are used
|
||||||
|
// by GCC 4.5.x and later versions to indicate functions which have been
|
||||||
|
// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
|
||||||
|
// a function clone suffix.
|
||||||
|
static bool IsFunctionCloneSuffix(const char *str) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (str[i] != '\0') {
|
||||||
|
// Consume a single .<alpha>+.<digit>+ sequence.
|
||||||
|
if (str[i] != '.' || !IsAlpha(str[i + 1])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i += 2;
|
||||||
|
while (IsAlpha(str[i])) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (str[i] != '.' || !IsDigit(str[i + 1])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i += 2;
|
||||||
|
while (IsDigit(str[i])) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; // Consumed everything in "str".
|
||||||
|
}
|
||||||
|
|
||||||
// Append "str" with some tweaks, iff "append" state is true.
|
// Append "str" with some tweaks, iff "append" state is true.
|
||||||
// Returns true so that it can be placed in "if" conditions.
|
// Returns true so that it can be placed in "if" conditions.
|
||||||
static void MaybeAppendWithLength(State *state, const char * const str,
|
static void MaybeAppendWithLength(State *state, const char * const str,
|
||||||
@ -429,6 +473,10 @@ static bool ParseSubstitution(State *state);
|
|||||||
// <mangled-name> ::= _Z <encoding>
|
// <mangled-name> ::= _Z <encoding>
|
||||||
static bool ParseMangledName(State *state) {
|
static bool ParseMangledName(State *state) {
|
||||||
if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
|
if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
|
||||||
|
// Drop trailing function clone suffix, if any.
|
||||||
|
if (IsFunctionCloneSuffix(state->mangled_cur)) {
|
||||||
|
state->mangled_cur = state->mangled_end;
|
||||||
|
}
|
||||||
// Append trailing version suffix if any.
|
// Append trailing version suffix if any.
|
||||||
// ex. _Z3foo@@GLIBCXX_3.4
|
// ex. _Z3foo@@GLIBCXX_3.4
|
||||||
if (state->mangled_cur < state->mangled_end &&
|
if (state->mangled_cur < state->mangled_end &&
|
||||||
@ -596,7 +644,7 @@ static bool ParseNumber(State *state) {
|
|||||||
const char *p = state->mangled_cur;
|
const char *p = state->mangled_cur;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
for (;p < state->mangled_end; ++p) {
|
for (;p < state->mangled_end; ++p) {
|
||||||
if ((*p >= '0' && *p <= '9')) {
|
if (IsDigit(*p)) {
|
||||||
number = number * 10 + (*p - '0');
|
number = number * 10 + (*p - '0');
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -616,7 +664,7 @@ static bool ParseFloatNumber(State *state) {
|
|||||||
const char *p = state->mangled_cur;
|
const char *p = state->mangled_cur;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
for (;p < state->mangled_end; ++p) {
|
for (;p < state->mangled_end; ++p) {
|
||||||
if ((*p >= '0' && *p <= '9')) {
|
if (IsDigit(*p)) {
|
||||||
number = number * 16 + (*p - '0');
|
number = number * 16 + (*p - '0');
|
||||||
} else if (*p >= 'a' && *p <= 'f') {
|
} else if (*p >= 'a' && *p <= 'f') {
|
||||||
number = number * 16 + (*p - 'a' + 10);
|
number = number * 16 + (*p - 'a' + 10);
|
||||||
@ -638,7 +686,7 @@ static bool ParseSeqId(State *state) {
|
|||||||
const char *p = state->mangled_cur;
|
const char *p = state->mangled_cur;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
for (;p < state->mangled_end; ++p) {
|
for (;p < state->mangled_end; ++p) {
|
||||||
if ((*p >= '0' && *p <= '9')) {
|
if (IsDigit(*p)) {
|
||||||
number = number * 36 + (*p - '0');
|
number = number * 36 + (*p - '0');
|
||||||
} else if (*p >= 'A' && *p <= 'Z') {
|
} else if (*p >= 'A' && *p <= 'Z') {
|
||||||
number = number * 36 + (*p - 'A' + 10);
|
number = number * 36 + (*p - 'A' + 10);
|
||||||
@ -858,11 +906,12 @@ static bool ParseCtorDtorName(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <type> ::= <CV-qualifiers> <type>
|
// <type> ::= <CV-qualifiers> <type>
|
||||||
// ::= P <type>
|
// ::= P <type> # pointer-to
|
||||||
// ::= R <type>
|
// ::= R <type> # reference-to
|
||||||
// ::= C <type>
|
// ::= O <type> # rvalue reference-to (C++0x)
|
||||||
// ::= G <type>
|
// ::= C <type> # complex pair (C 2000)
|
||||||
// ::= U <source-name> <type>
|
// ::= G <type> # imaginary (C 2000)
|
||||||
|
// ::= U <source-name> <type> # vendor extended type qualifier
|
||||||
// ::= <builtin-type>
|
// ::= <builtin-type>
|
||||||
// ::= <function-type>
|
// ::= <function-type>
|
||||||
// ::= <class-enum-type>
|
// ::= <class-enum-type>
|
||||||
@ -871,6 +920,11 @@ static bool ParseCtorDtorName(State *state) {
|
|||||||
// ::= <template-template-param> <template-args>
|
// ::= <template-template-param> <template-args>
|
||||||
// ::= <template-param>
|
// ::= <template-param>
|
||||||
// ::= <substitution>
|
// ::= <substitution>
|
||||||
|
// ::= Dp <type> # pack expansion of (C++0x)
|
||||||
|
// ::= Dt <expression> E # decltype of an id-expression or class
|
||||||
|
// # member access (C++0x)
|
||||||
|
// ::= DT <expression> E # decltype of an expression (C++0x)
|
||||||
|
//
|
||||||
static bool ParseType(State *state) {
|
static bool ParseType(State *state) {
|
||||||
// We should check CV-qualifers, and PRGC things first.
|
// We should check CV-qualifers, and PRGC things first.
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
@ -879,7 +933,18 @@ static bool ParseType(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseCharClass(state, "PRCG") && ParseType(state)) {
|
if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
|
if (ParseTwoChar(state, "Dp") && ParseType(state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
|
if (ParseChar(state, 'D') && ParseCharClass(state, "tT") &&
|
||||||
|
ParseExpression(state) && ParseChar(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1045,14 +1110,23 @@ static bool ParseTemplateArgs(State *state) {
|
|||||||
|
|
||||||
// <template-arg> ::= <type>
|
// <template-arg> ::= <type>
|
||||||
// ::= <expr-primary>
|
// ::= <expr-primary>
|
||||||
|
// ::= I <template-arg>* E # argument pack
|
||||||
// ::= X <expression> E
|
// ::= X <expression> E
|
||||||
static bool ParseTemplateArg(State *state) {
|
static bool ParseTemplateArg(State *state) {
|
||||||
|
State copy = *state;
|
||||||
|
if (ParseChar(state, 'I') &&
|
||||||
|
ZeroOrMore(ParseTemplateArg, state) &&
|
||||||
|
ParseChar(state, 'E')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
if (ParseType(state) ||
|
if (ParseType(state) ||
|
||||||
ParseExprPrimary(state)) {
|
ParseExprPrimary(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
State copy = *state;
|
|
||||||
if (ParseChar(state, 'X') && ParseExpression(state) &&
|
if (ParseChar(state, 'X') && ParseExpression(state) &&
|
||||||
ParseChar(state, 'E')) {
|
ParseChar(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -71,6 +71,32 @@ TEST(Demangle, CornerCases) {
|
|||||||
EXPECT_FALSE(Demangle("_Z6foobarv", NULL, 0)); // Should not cause SEGV.
|
EXPECT_FALSE(Demangle("_Z6foobarv", NULL, 0)); // Should not cause SEGV.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test handling of functions suffixed with .clone.N, which is used by GCC
|
||||||
|
// 4.5.x, and .constprop.N and .isra.N, which are used by GCC 4.6.x. These
|
||||||
|
// suffixes are used to indicate functions which have been cloned during
|
||||||
|
// optimization. We ignore these suffixes.
|
||||||
|
TEST(Demangle, Clones) {
|
||||||
|
char tmp[20];
|
||||||
|
EXPECT_TRUE(Demangle("_ZL3Foov", tmp, sizeof(tmp)));
|
||||||
|
EXPECT_STREQ("Foo()", tmp);
|
||||||
|
EXPECT_TRUE(Demangle("_ZL3Foov.clone.3", tmp, sizeof(tmp)));
|
||||||
|
EXPECT_STREQ("Foo()", tmp);
|
||||||
|
EXPECT_TRUE(Demangle("_ZL3Foov.constprop.80", tmp, sizeof(tmp)));
|
||||||
|
EXPECT_STREQ("Foo()", tmp);
|
||||||
|
EXPECT_TRUE(Demangle("_ZL3Foov.isra.18", tmp, sizeof(tmp)));
|
||||||
|
EXPECT_STREQ("Foo()", tmp);
|
||||||
|
EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
|
||||||
|
EXPECT_STREQ("Foo()", tmp);
|
||||||
|
// Invalid (truncated), should not demangle.
|
||||||
|
EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
|
||||||
|
// Invalid (.clone. not followed by number), should not demangle.
|
||||||
|
EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
|
||||||
|
// Invalid (.clone. followed by non-number), should not demangle.
|
||||||
|
EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
|
||||||
|
// Invalid (.constprop. not followed by number), should not demangle.
|
||||||
|
EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Demangle, FromFile) {
|
TEST(Demangle, FromFile) {
|
||||||
string test_file = FLAGS_test_srcdir + "/src/demangle_unittest.txt";
|
string test_file = FLAGS_test_srcdir + "/src/demangle_unittest.txt";
|
||||||
ifstream f(test_file.c_str()); // The file should exist.
|
ifstream f(test_file.c_str()); // The file should exist.
|
||||||
|
|||||||
@ -84,7 +84,10 @@ fi
|
|||||||
|
|
||||||
# Check if mangled symbols exist. They must not exist.
|
# Check if mangled symbols exist. They must not exist.
|
||||||
if grep --quiet '^_Z' "$DM_OUTPUT"; then
|
if grep --quiet '^_Z' "$DM_OUTPUT"; then
|
||||||
die "Mangled symbols found in $DM_OUTPUT"
|
MANGLED=`grep '^_Z' "$DM_OUTPUT" | wc -l | awk '{ print \$1 }'`
|
||||||
|
echo "Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT:"
|
||||||
|
grep '^_Z' "$DM_OUTPUT"
|
||||||
|
die "Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# All C++ symbols are demangled successfully.
|
# All C++ symbols are demangled successfully.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user