diff options
author | <hlsyounes@gmail.com> | 2011-02-07 14:43:05 +0000 |
---|---|---|
committer | <hlsyounes@gmail.com> | 2011-02-07 14:43:05 +0000 |
commit | 0b4dcd23acba2bd0e6fd538bbbee8bde37285e8e (patch) | |
tree | 1f09462b3f83d48235978766dc0d4c0a636208dd /src | |
parent | 1e86eecaf61271b225af6916f016376c34631602 (diff) | |
download | glog-0b4dcd23acba2bd0e6fd538bbbee8bde37285e8e.tar.gz glog-0b4dcd23acba2bd0e6fd538bbbee8bde37285e8e.tar.bz2 glog-0b4dcd23acba2bd0e6fd538bbbee8bde37285e8e.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/demangle.cc | 94 | ||||
-rw-r--r-- | src/demangle_unittest.cc | 26 | ||||
-rwxr-xr-x | src/demangle_unittest.sh | 5 |
3 files changed, 114 insertions, 11 deletions
diff --git a/src/demangle.cc b/src/demangle.cc index 46556bf..cc7cebb 100644 --- a/src/demangle.cc +++ b/src/demangle.cc @@ -28,6 +28,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // 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 "demangle.h" @@ -245,6 +250,15 @@ static bool OneOrMore(ParseFunc parse_func, State *state) { 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" // is set to true for later use. The output string is ensured to // 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')); } +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. // Returns true so that it can be placed in "if" conditions. static void MaybeAppendWithLength(State *state, const char * const str, @@ -429,6 +473,10 @@ static bool ParseSubstitution(State *state); // <mangled-name> ::= _Z <encoding> static bool ParseMangledName(State *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. // ex. _Z3foo@@GLIBCXX_3.4 if (state->mangled_cur < state->mangled_end && @@ -596,7 +644,7 @@ static bool ParseNumber(State *state) { const char *p = state->mangled_cur; int number = 0; for (;p < state->mangled_end; ++p) { - if ((*p >= '0' && *p <= '9')) { + if (IsDigit(*p)) { number = number * 10 + (*p - '0'); } else { break; @@ -616,7 +664,7 @@ static bool ParseFloatNumber(State *state) { const char *p = state->mangled_cur; int number = 0; for (;p < state->mangled_end; ++p) { - if ((*p >= '0' && *p <= '9')) { + if (IsDigit(*p)) { number = number * 16 + (*p - '0'); } else if (*p >= 'a' && *p <= 'f') { number = number * 16 + (*p - 'a' + 10); @@ -638,7 +686,7 @@ static bool ParseSeqId(State *state) { const char *p = state->mangled_cur; int number = 0; for (;p < state->mangled_end; ++p) { - if ((*p >= '0' && *p <= '9')) { + if (IsDigit(*p)) { number = number * 36 + (*p - '0'); } else if (*p >= 'A' && *p <= 'Z') { number = number * 36 + (*p - 'A' + 10); @@ -858,11 +906,12 @@ static bool ParseCtorDtorName(State *state) { } // <type> ::= <CV-qualifiers> <type> -// ::= P <type> -// ::= R <type> -// ::= C <type> -// ::= G <type> -// ::= U <source-name> <type> +// ::= P <type> # pointer-to +// ::= R <type> # reference-to +// ::= O <type> # rvalue reference-to (C++0x) +// ::= C <type> # complex pair (C 2000) +// ::= G <type> # imaginary (C 2000) +// ::= U <source-name> <type> # vendor extended type qualifier // ::= <builtin-type> // ::= <function-type> // ::= <class-enum-type> @@ -871,6 +920,11 @@ static bool ParseCtorDtorName(State *state) { // ::= <template-template-param> <template-args> // ::= <template-param> // ::= <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) { // We should check CV-qualifers, and PRGC things first. State copy = *state; @@ -879,7 +933,18 @@ static bool ParseType(State *state) { } *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; } *state = copy; @@ -1045,14 +1110,23 @@ static bool ParseTemplateArgs(State *state) { // <template-arg> ::= <type> // ::= <expr-primary> +// ::= I <template-arg>* E # argument pack // ::= X <expression> E 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) || ParseExprPrimary(state)) { return true; } + *state = copy; - State copy = *state; if (ParseChar(state, 'X') && ParseExpression(state) && ParseChar(state, 'E')) { return true; diff --git a/src/demangle_unittest.cc b/src/demangle_unittest.cc index c07332a..9d219e6 100644 --- a/src/demangle_unittest.cc +++ b/src/demangle_unittest.cc @@ -71,6 +71,32 @@ TEST(Demangle, CornerCases) { 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) { string test_file = FLAGS_test_srcdir + "/src/demangle_unittest.txt"; ifstream f(test_file.c_str()); // The file should exist. diff --git a/src/demangle_unittest.sh b/src/demangle_unittest.sh index 4e79538..91deee2 100755 --- a/src/demangle_unittest.sh +++ b/src/demangle_unittest.sh @@ -84,7 +84,10 @@ fi # Check if mangled symbols exist. They must not exist. 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 # All C++ symbols are demangled successfully. |