summaryrefslogtreecommitdiffstats
path: root/base/third_party
diff options
context:
space:
mode:
authorivanpe@google.com <ivanpe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-05 10:16:03 +0000
committerivanpe@google.com <ivanpe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-05 10:16:03 +0000
commitdb024825de7b10be6382b216c11cda7c8aa16af4 (patch)
tree2486262b7faeda9630d6aca48ef396d2ca6406a6 /base/third_party
parent704a900dae24b39386940a88978a3b31fdd0a805 (diff)
downloadchromium_src-db024825de7b10be6382b216c11cda7c8aa16af4.zip
chromium_src-db024825de7b10be6382b216c11cda7c8aa16af4.tar.gz
chromium_src-db024825de7b10be6382b216c11cda7c8aa16af4.tar.bz2
Copying the following files AS-IS from google.glog r141:
- demangle.cc - demangle.h - symbolize.cc - symbolize.h The new functionality is a callback mechanism to allow users of google.glog to provide their own implementation of OpenObjectFileContainingPcAndGetStartAddress. BUG= Review URL: https://codereview.chromium.org/180163013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254996 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/third_party')
-rw-r--r--base/third_party/symbolize/README.chromium5
-rw-r--r--base/third_party/symbolize/demangle.cc379
-rw-r--r--base/third_party/symbolize/symbolize.cc197
-rw-r--r--base/third_party/symbolize/symbolize.h22
4 files changed, 430 insertions, 173 deletions
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
index 520a3db..de92794 100644
--- a/base/third_party/symbolize/README.chromium
+++ b/base/third_party/symbolize/README.chromium
@@ -3,16 +3,13 @@ URL: http://code.google.com/p/google-glog/
License: BSD
The following files are copied AS-IS from:
-http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r76)
+http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r141)
- demangle.cc
- demangle.h
- symbolize.cc
- symbolize.h
-r137 (https://code.google.com/p/google-glog/source/detail?r=137) was merged
-after that.
-
The following files are minimal stubs created for use in Chromium:
- config.h
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
index 46556bf..e858181 100644
--- a/base/third_party/symbolize/demangle.cc
+++ b/base/third_party/symbolize/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"
@@ -138,14 +143,12 @@ static const AbbrevPair kSubstitutionList[] = {
// State needed for demangling.
typedef struct {
const char *mangled_cur; // Cursor of mangled name.
- const char *mangled_end; // End of mangled name.
char *out_cur; // Cursor of output string.
const char *out_begin; // Beginning of output string.
const char *out_end; // End of output string.
const char *prev_name; // For constructors/destructors.
int prev_name_length; // For constructors/destructors.
- int nest_level; // For nested names.
- int number; // Remember the previous number.
+ short nest_level; // For nested names.
bool append; // Append flag.
bool overflowed; // True if output gets overflowed.
} State;
@@ -161,6 +164,16 @@ static size_t StrLen(const char *str) {
return len;
}
+// Returns true if "str" has at least "n" characters remaining.
+static bool AtLeastNumCharsRemaining(const char *str, int n) {
+ for (int i = 0; i < n; ++i) {
+ if (str[i] == '\0') {
+ return false;
+ }
+ }
+ return true;
+}
+
// Returns true if "str" has "prefix" as a prefix.
static bool StrPrefix(const char *str, const char *prefix) {
size_t i = 0;
@@ -174,39 +187,33 @@ static bool StrPrefix(const char *str, const char *prefix) {
static void InitState(State *state, const char *mangled,
char *out, int out_size) {
state->mangled_cur = mangled;
- state->mangled_end = mangled + StrLen(mangled);
state->out_cur = out;
state->out_begin = out;
state->out_end = out + out_size;
state->prev_name = NULL;
state->prev_name_length = -1;
state->nest_level = -1;
- state->number = -1;
state->append = true;
state->overflowed = false;
}
-// Calculates the remaining length of the mangled name.
-static int RemainingLength(State *state) {
- return state->mangled_end - state->mangled_cur;
-}
-
-// Returns true and advances "mangled_cur" if we find "c" at
-// "mangled_cur" position.
-static bool ParseChar(State *state, const char c) {
- if (RemainingLength(state) >= 1 && *state->mangled_cur == c) {
+// Returns true and advances "mangled_cur" if we find "one_char_token"
+// at "mangled_cur" position. It is assumed that "one_char_token" does
+// not contain '\0'.
+static bool ParseOneCharToken(State *state, const char one_char_token) {
+ if (state->mangled_cur[0] == one_char_token) {
++state->mangled_cur;
return true;
}
return false;
}
-// Returns true and advances "mangled_cur" if we find "two_chars" at
-// "mangled_cur" position.
-static bool ParseTwoChar(State *state, const char *two_chars) {
- if (RemainingLength(state) >= 2 &&
- state->mangled_cur[0] == two_chars[0] &&
- state->mangled_cur[1] == two_chars[1]) {
+// Returns true and advances "mangled_cur" if we find "two_char_token"
+// at "mangled_cur" position. It is assumed that "two_char_token" does
+// not contain '\0'.
+static bool ParseTwoCharToken(State *state, const char *two_char_token) {
+ if (state->mangled_cur[0] == two_char_token[0] &&
+ state->mangled_cur[1] == two_char_token[1]) {
state->mangled_cur += 2;
return true;
}
@@ -216,13 +223,10 @@ static bool ParseTwoChar(State *state, const char *two_chars) {
// Returns true and advances "mangled_cur" if we find any character in
// "char_class" at "mangled_cur" position.
static bool ParseCharClass(State *state, const char *char_class) {
- if (state->mangled_cur == state->mangled_end) {
- return false;
- }
const char *p = char_class;
for (; *p != '\0'; ++p) {
- if (*state->mangled_cur == *p) {
- state->mangled_cur += 1;
+ if (state->mangled_cur[0] == *p) {
+ ++state->mangled_cur;
return true;
}
}
@@ -230,7 +234,7 @@ static bool ParseCharClass(State *state, const char *char_class) {
}
// This function is used for handling an optional non-terminal.
-static bool Optional(bool status) {
+static bool Optional(bool) {
return true;
}
@@ -245,6 +249,16 @@ 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 token or a
+// terminating sequence not handled by parse_func (e.g.
+// ParseOneCharToken(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.
@@ -270,7 +284,37 @@ static bool IsLower(char c) {
}
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.
@@ -309,7 +353,7 @@ static bool EnterNestedName(State *state) {
}
// This function is used for handling nested names.
-static bool LeaveNestedName(State *state, int prev_value) {
+static bool LeaveNestedName(State *state, short prev_value) {
state->nest_level = prev_value;
return true;
}
@@ -349,11 +393,11 @@ static void MaybeCancelLastSeparator(State *state) {
}
}
-// Returns true if identifier pointed by "mangled_cur" is anonymous
-// namespace.
-static bool IdentifierIsAnonymousNamespace(State *state) {
- const char anon_prefix[] = "_GLOBAL__N_";
- return (state->number > sizeof(anon_prefix) - 1 && // Should be longer.
+// Returns true if the identifier of the given length pointed to by
+// "mangled_cur" is anonymous namespace.
+static bool IdentifierIsAnonymousNamespace(State *state, int length) {
+ static const char anon_prefix[] = "_GLOBAL__N_";
+ return (length > (int)sizeof(anon_prefix) - 1 && // Should be longer.
StrPrefix(state->mangled_cur, anon_prefix));
}
@@ -368,10 +412,10 @@ static bool ParsePrefix(State *state);
static bool ParseUnqualifiedName(State *state);
static bool ParseSourceName(State *state);
static bool ParseLocalSourceName(State *state);
-static bool ParseNumber(State *state);
+static bool ParseNumber(State *state, int *number_out);
static bool ParseFloatNumber(State *state);
static bool ParseSeqId(State *state);
-static bool ParseIdentifier(State *state);
+static bool ParseIdentifier(State *state, int length);
static bool ParseOperatorName(State *state);
static bool ParseSpecialName(State *state);
static bool ParseCallOffset(State *state);
@@ -428,17 +472,7 @@ static bool ParseSubstitution(State *state);
// <mangled-name> ::= _Z <encoding>
static bool ParseMangledName(State *state) {
- if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
- // Append trailing version suffix if any.
- // ex. _Z3foo@@GLIBCXX_3.4
- if (state->mangled_cur < state->mangled_end &&
- state->mangled_cur[0] == '@') {
- MaybeAppend(state, state->mangled_cur);
- state->mangled_cur = state->mangled_end;
- }
- return true;
- }
- return false;
+ return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
}
// <encoding> ::= <(function) name> <bare-function-type>
@@ -488,7 +522,7 @@ static bool ParseUnscopedName(State *state) {
}
State copy = *state;
- if (ParseTwoChar(state, "St") &&
+ if (ParseTwoCharToken(state, "St") &&
MaybeAppend(state, "std::") &&
ParseUnqualifiedName(state)) {
return true;
@@ -507,12 +541,12 @@ static bool ParseUnscopedTemplateName(State *state) {
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
static bool ParseNestedName(State *state) {
State copy = *state;
- if (ParseChar(state, 'N') &&
+ if (ParseOneCharToken(state, 'N') &&
EnterNestedName(state) &&
Optional(ParseCVQualifiers(state)) &&
ParsePrefix(state) &&
LeaveNestedName(state, copy.nest_level) &&
- ParseChar(state, 'E')) {
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
@@ -565,7 +599,8 @@ static bool ParseUnqualifiedName(State *state) {
// <source-name> ::= <positive length number> <identifier>
static bool ParseSourceName(State *state) {
State copy = *state;
- if (ParseNumber(state) && ParseIdentifier(state)) {
+ int length = -1;
+ if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
return true;
}
*state = copy;
@@ -579,7 +614,7 @@ static bool ParseSourceName(State *state) {
// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
static bool ParseLocalSourceName(State *state) {
State copy = *state;
- if (ParseChar(state, 'L') && ParseSourceName(state) &&
+ if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
Optional(ParseDiscriminator(state))) {
return true;
}
@@ -588,15 +623,17 @@ static bool ParseLocalSourceName(State *state) {
}
// <number> ::= [n] <non-negative decimal integer>
-static bool ParseNumber(State *state) {
+// If "number_out" is non-null, then *number_out is set to the value of the
+// parsed number on success.
+static bool ParseNumber(State *state, int *number_out) {
int sign = 1;
- if (ParseChar(state, 'n')) {
+ if (ParseOneCharToken(state, 'n')) {
sign = -1;
}
const char *p = state->mangled_cur;
int number = 0;
- for (;p < state->mangled_end; ++p) {
- if ((*p >= '0' && *p <= '9')) {
+ for (;*p != '\0'; ++p) {
+ if (IsDigit(*p)) {
number = number * 10 + (*p - '0');
} else {
break;
@@ -604,7 +641,9 @@ static bool ParseNumber(State *state) {
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
- state->number = number * sign;
+ if (number_out != NULL) {
+ *number_out = number * sign;
+ }
return true;
}
return false;
@@ -614,19 +653,13 @@ static bool ParseNumber(State *state) {
// hexadecimal string.
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')) {
- number = number * 16 + (*p - '0');
- } else if (*p >= 'a' && *p <= 'f') {
- number = number * 16 + (*p - 'a' + 10);
- } else {
+ for (;*p != '\0'; ++p) {
+ if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
break;
}
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
- state->number = number;
return true;
}
return false;
@@ -636,37 +669,30 @@ static bool ParseFloatNumber(State *state) {
// using digits and upper case letters
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')) {
- number = number * 36 + (*p - '0');
- } else if (*p >= 'A' && *p <= 'Z') {
- number = number * 36 + (*p - 'A' + 10);
- } else {
+ for (;*p != '\0'; ++p) {
+ if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
break;
}
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
- state->number = number;
return true;
}
return false;
}
-// <identifier> ::= <unqualified source code identifier>
-static bool ParseIdentifier(State *state) {
- if (state->number == -1 ||
- RemainingLength(state) < state->number) {
+// <identifier> ::= <unqualified source code identifier> (of given length)
+static bool ParseIdentifier(State *state, int length) {
+ if (length == -1 ||
+ !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
return false;
}
- if (IdentifierIsAnonymousNamespace(state)) {
+ if (IdentifierIsAnonymousNamespace(state, length)) {
MaybeAppend(state, "(anonymous namespace)");
} else {
- MaybeAppendWithLength(state, state->mangled_cur, state->number);
+ MaybeAppendWithLength(state, state->mangled_cur, length);
}
- state->mangled_cur += state->number;
- state->number = -1; // Reset the number.
+ state->mangled_cur += length;
return true;
}
@@ -674,12 +700,12 @@ static bool ParseIdentifier(State *state) {
// ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator
static bool ParseOperatorName(State *state) {
- if (RemainingLength(state) < 2) {
+ if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
return false;
}
// First check with "cv" (cast) case.
State copy = *state;
- if (ParseTwoChar(state, "cv") &&
+ if (ParseTwoCharToken(state, "cv") &&
MaybeAppend(state, "operator ") &&
EnterNestedName(state) &&
ParseType(state) &&
@@ -689,7 +715,7 @@ static bool ParseOperatorName(State *state) {
*state = copy;
// Then vendor extended operators.
- if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") &&
+ if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") &&
ParseSourceName(state)) {
return true;
}
@@ -738,34 +764,34 @@ static bool ParseOperatorName(State *state) {
// stack traces. The are special data.
static bool ParseSpecialName(State *state) {
State copy = *state;
- if (ParseChar(state, 'T') &&
+ if (ParseOneCharToken(state, 'T') &&
ParseCharClass(state, "VTIS") &&
ParseType(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) &&
+ if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
ParseCallOffset(state) && ParseEncoding(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "GV") &&
+ if (ParseTwoCharToken(state, "GV") &&
ParseName(state)) {
return true;
}
*state = copy;
- if (ParseChar(state, 'T') && ParseCallOffset(state) &&
+ if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
ParseEncoding(state)) {
return true;
}
*state = copy;
// G++ extensions
- if (ParseTwoChar(state, "TC") && ParseType(state) &&
- ParseNumber(state) && ParseChar(state, '_') &&
+ if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
+ ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
DisableAppend(state) &&
ParseType(state)) {
RestoreAppend(state, copy.append);
@@ -773,23 +799,23 @@ static bool ParseSpecialName(State *state) {
}
*state = copy;
- if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") &&
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
ParseType(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "GR") && ParseName(state)) {
+ if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "GA") && ParseEncoding(state)) {
+ if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
return true;
}
*state = copy;
- if (ParseChar(state, 'T') && ParseCharClass(state, "hv") &&
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
ParseCallOffset(state) && ParseEncoding(state)) {
return true;
}
@@ -801,14 +827,14 @@ static bool ParseSpecialName(State *state) {
// ::= v <v-offset> _
static bool ParseCallOffset(State *state) {
State copy = *state;
- if (ParseChar(state, 'h') &&
- ParseNVOffset(state) && ParseChar(state, '_')) {
+ if (ParseOneCharToken(state, 'h') &&
+ ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
return true;
}
*state = copy;
- if (ParseChar(state, 'v') &&
- ParseVOffset(state) && ParseChar(state, '_')) {
+ if (ParseOneCharToken(state, 'v') &&
+ ParseVOffset(state) && ParseOneCharToken(state, '_')) {
return true;
}
*state = copy;
@@ -818,14 +844,14 @@ static bool ParseCallOffset(State *state) {
// <nv-offset> ::= <(offset) number>
static bool ParseNVOffset(State *state) {
- return ParseNumber(state);
+ return ParseNumber(state, NULL);
}
// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
static bool ParseVOffset(State *state) {
State copy = *state;
- if (ParseNumber(state) && ParseChar(state, '_') &&
- ParseNumber(state)) {
+ if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
+ ParseNumber(state, NULL)) {
return true;
}
*state = copy;
@@ -836,7 +862,7 @@ static bool ParseVOffset(State *state) {
// ::= D0 | D1 | D2
static bool ParseCtorDtorName(State *state) {
State copy = *state;
- if (ParseChar(state, 'C') &&
+ if (ParseOneCharToken(state, 'C') &&
ParseCharClass(state, "123")) {
const char * const prev_name = state->prev_name;
const int prev_name_length = state->prev_name_length;
@@ -845,7 +871,7 @@ static bool ParseCtorDtorName(State *state) {
}
*state = copy;
- if (ParseChar(state, 'D') &&
+ if (ParseOneCharToken(state, 'D') &&
ParseCharClass(state, "012")) {
const char * const prev_name = state->prev_name;
const int prev_name_length = state->prev_name_length;
@@ -858,11 +884,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 +898,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,12 +911,23 @@ static bool ParseType(State *state) {
}
*state = copy;
- if (ParseCharClass(state, "PRCG") && ParseType(state)) {
+ if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
return true;
}
*state = copy;
- if (ParseChar(state, 'U') && ParseSourceName(state) &&
+ if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
+ ParseExpression(state) && ParseOneCharToken(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
}
@@ -918,9 +961,9 @@ static bool ParseType(State *state) {
// ParseType().
static bool ParseCVQualifiers(State *state) {
int num_cv_qualifiers = 0;
- num_cv_qualifiers += ParseChar(state, 'r');
- num_cv_qualifiers += ParseChar(state, 'V');
- num_cv_qualifiers += ParseChar(state, 'K');
+ num_cv_qualifiers += ParseOneCharToken(state, 'r');
+ num_cv_qualifiers += ParseOneCharToken(state, 'V');
+ num_cv_qualifiers += ParseOneCharToken(state, 'K');
return num_cv_qualifiers > 0;
}
@@ -937,7 +980,7 @@ static bool ParseBuiltinType(State *state) {
}
State copy = *state;
- if (ParseChar(state, 'u') && ParseSourceName(state)) {
+ if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
return true;
}
*state = copy;
@@ -947,8 +990,9 @@ static bool ParseBuiltinType(State *state) {
// <function-type> ::= F [Y] <bare-function-type> E
static bool ParseFunctionType(State *state) {
State copy = *state;
- if (ParseChar(state, 'F') && Optional(ParseChar(state, 'Y')) &&
- ParseBareFunctionType(state) && ParseChar(state, 'E')) {
+ if (ParseOneCharToken(state, 'F') &&
+ Optional(ParseOneCharToken(state, 'Y')) &&
+ ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
@@ -977,14 +1021,14 @@ static bool ParseClassEnumType(State *state) {
// ::= A [<(dimension) expression>] _ <(element) type>
static bool ParseArrayType(State *state) {
State copy = *state;
- if (ParseChar(state, 'A') && ParseNumber(state) &&
- ParseChar(state, '_') && ParseType(state)) {
+ if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) &&
+ ParseOneCharToken(state, '_') && ParseType(state)) {
return true;
}
*state = copy;
- if (ParseChar(state, 'A') && Optional(ParseExpression(state)) &&
- ParseChar(state, '_') && ParseType(state)) {
+ if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
+ ParseOneCharToken(state, '_') && ParseType(state)) {
return true;
}
*state = copy;
@@ -994,7 +1038,7 @@ static bool ParseArrayType(State *state) {
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
static bool ParsePointerToMemberType(State *state) {
State copy = *state;
- if (ParseChar(state, 'M') && ParseType(state) &&
+ if (ParseOneCharToken(state, 'M') && ParseType(state) &&
ParseType(state)) {
return true;
}
@@ -1005,14 +1049,14 @@ static bool ParsePointerToMemberType(State *state) {
// <template-param> ::= T_
// ::= T <parameter-2 non-negative number> _
static bool ParseTemplateParam(State *state) {
- if (ParseTwoChar(state, "T_")) {
+ if (ParseTwoCharToken(state, "T_")) {
MaybeAppend(state, "?"); // We don't support template substitutions.
return true;
}
State copy = *state;
- if (ParseChar(state, 'T') && ParseNumber(state) &&
- ParseChar(state, '_')) {
+ if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) &&
+ ParseOneCharToken(state, '_')) {
MaybeAppend(state, "?"); // We don't support template substitutions.
return true;
}
@@ -1032,9 +1076,9 @@ static bool ParseTemplateTemplateParam(State *state) {
static bool ParseTemplateArgs(State *state) {
State copy = *state;
DisableAppend(state);
- if (ParseChar(state, 'I') &&
+ if (ParseOneCharToken(state, 'I') &&
OneOrMore(ParseTemplateArg, state) &&
- ParseChar(state, 'E')) {
+ ParseOneCharToken(state, 'E')) {
RestoreAppend(state, copy.append);
MaybeAppend(state, "<>");
return true;
@@ -1045,16 +1089,25 @@ 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 (ParseOneCharToken(state, 'I') &&
+ ZeroOrMore(ParseTemplateArg, state) &&
+ ParseOneCharToken(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')) {
+ if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
@@ -1097,19 +1150,19 @@ static bool ParseExpression(State *state) {
}
*state = copy;
- if (ParseTwoChar(state, "st") && ParseType(state)) {
+ if (ParseTwoCharToken(state, "st") && ParseType(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
ParseUnqualifiedName(state) &&
ParseTemplateArgs(state)) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
ParseUnqualifiedName(state)) {
return true;
}
@@ -1124,28 +1177,28 @@ static bool ParseExpression(State *state) {
// ::= LZ <encoding> E
static bool ParseExprPrimary(State *state) {
State copy = *state;
- if (ParseChar(state, 'L') && ParseType(state) &&
- ParseNumber(state) &&
- ParseChar(state, 'E')) {
+ if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+ ParseNumber(state, NULL) &&
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
- if (ParseChar(state, 'L') && ParseType(state) &&
+ if (ParseOneCharToken(state, 'L') && ParseType(state) &&
ParseFloatNumber(state) &&
- ParseChar(state, 'E')) {
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
- if (ParseChar(state, 'L') && ParseMangledName(state) &&
- ParseChar(state, 'E')) {
+ if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
- if (ParseTwoChar(state, "LZ") && ParseEncoding(state) &&
- ParseChar(state, 'E')) {
+ if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) &&
+ ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
@@ -1158,15 +1211,15 @@ static bool ParseExprPrimary(State *state) {
// := Z <(function) encoding> E s [<discriminator>]
static bool ParseLocalName(State *state) {
State copy = *state;
- if (ParseChar(state, 'Z') && ParseEncoding(state) &&
- ParseChar(state, 'E') && MaybeAppend(state, "::") &&
+ if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+ ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") &&
ParseName(state) && Optional(ParseDiscriminator(state))) {
return true;
}
*state = copy;
- if (ParseChar(state, 'Z') && ParseEncoding(state) &&
- ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) {
+ if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+ ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) {
return true;
}
*state = copy;
@@ -1176,7 +1229,7 @@ static bool ParseLocalName(State *state) {
// <discriminator> := _ <(non-negative) number>
static bool ParseDiscriminator(State *state) {
State copy = *state;
- if (ParseChar(state, '_') && ParseNumber(state)) {
+ if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) {
return true;
}
*state = copy;
@@ -1187,21 +1240,21 @@ static bool ParseDiscriminator(State *state) {
// ::= S <seq-id> _
// ::= St, etc.
static bool ParseSubstitution(State *state) {
- if (ParseTwoChar(state, "S_")) {
+ if (ParseTwoCharToken(state, "S_")) {
MaybeAppend(state, "?"); // We don't support substitutions.
return true;
}
State copy = *state;
- if (ParseChar(state, 'S') && ParseSeqId(state) &&
- ParseChar(state, '_')) {
+ if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
+ ParseOneCharToken(state, '_')) {
MaybeAppend(state, "?"); // We don't support substitutions.
return true;
}
*state = copy;
// Expand abbreviations like "St" => "std".
- if (ParseChar(state, 'S')) {
+ if (ParseOneCharToken(state, 'S')) {
const AbbrevPair *p;
for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
if (state->mangled_cur[0] == p->abbrev[1]) {
@@ -1210,7 +1263,7 @@ static bool ParseSubstitution(State *state) {
MaybeAppend(state, "::");
MaybeAppend(state, p->real_name);
}
- state->mangled_cur += 1;
+ ++state->mangled_cur;
return true;
}
}
@@ -1219,13 +1272,33 @@ static bool ParseSubstitution(State *state) {
return false;
}
+// Parse <mangled-name>, optionally followed by either a function-clone suffix
+// or version suffix. Returns true only if all of "mangled_cur" was consumed.
+static bool ParseTopLevelMangledName(State *state) {
+ if (ParseMangledName(state)) {
+ if (state->mangled_cur[0] != '\0') {
+ // Drop trailing function clone suffix, if any.
+ if (IsFunctionCloneSuffix(state->mangled_cur)) {
+ return true;
+ }
+ // Append trailing version suffix if any.
+ // ex. _Z3foo@@GLIBCXX_3.4
+ if (state->mangled_cur[0] == '@') {
+ MaybeAppend(state, state->mangled_cur);
+ return true;
+ }
+ return false; // Unconsumed suffix.
+ }
+ return true;
+ }
+ return false;
+}
+
// The demangler entry point.
bool Demangle(const char *mangled, char *out, int out_size) {
State state;
InitState(&state, mangled, out, out_size);
- return (ParseMangledName(&state) &&
- state.overflowed == false &&
- RemainingLength(&state) == 0);
+ return ParseTopLevelMangledName(&state) && !state.overflowed;
}
_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
index 85976bb..b25f747 100644
--- a/base/third_party/symbolize/symbolize.cc
+++ b/base/third_party/symbolize/symbolize.cc
@@ -45,8 +45,13 @@
// some functions which are not guaranteed to be so, such as memchr()
// and memmove(). We assume they are async-signal-safe.
//
+// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
+// macro to add platform specific defines (e.g. OS_OPENBSD).
+
+#ifdef GLOG_BUILD_CONFIG_INCLUDE
+#include GLOG_BUILD_CONFIG_INCLUDE
+#endif // GLOG_BUILD_CONFIG_INCLUDE
-#include "build/build_config.h"
#include "utilities.h"
#if defined(HAVE_SYMBOLIZE)
@@ -75,6 +80,13 @@ void InstallSymbolizeCallback(SymbolizeCallback callback) {
g_symbolize_callback = callback;
}
+static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
+ NULL;
+void InstallSymbolizeOpenObjectFileCallback(
+ SymbolizeOpenObjectFileCallback callback) {
+ g_symbolize_open_object_file_callback = callback;
+}
+
// This function wraps the Demangle function to provide an interface
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
@@ -83,8 +95,8 @@ static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
char demangled[256]; // Big enough for sane demangled symbols.
if (Demangle(out, demangled, sizeof(demangled))) {
// Demangling succeeded. Copy to out if the space allows.
- int len = strlen(demangled);
- if (len + 1 <= out_size) { // +1 for '\0'.
+ size_t len = strlen(demangled);
+ if (len + 1 <= (size_t)out_size) { // +1 for '\0'.
SAFE_ASSERT(len < sizeof(demangled));
memmove(out, demangled, len + 1);
}
@@ -483,13 +495,20 @@ static char *GetHex(const char *start, const char *end, uint64_t *hex) {
return const_cast<char *>(p);
}
-// Search for the object file (from /proc/self/maps) that contains
-// the specified pc. If found, open this file and return the file handle,
-// and also set start_address to the start address of where this object
-// file is mapped to in memory. Otherwise, return -1.
+// Searches for the object file (from /proc/self/maps) that contains
+// the specified pc. If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file. If the object
+// file is opened successfully, returns the file descriptor. Otherwise,
+// returns -1. |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
static ATTRIBUTE_NOINLINE int
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
- uint64_t &start_address) {
+ uint64_t &start_address,
+ uint64_t &base_address,
+ char *out_file_name,
+ int out_file_name_size) {
int object_fd;
// Open /proc/self/maps.
@@ -503,8 +522,10 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside.
char buf[1024]; // Big enough for line of sane /proc/self/maps
+ int num_maps = 0;
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
while (true) {
+ num_maps++;
const char *cursor;
const char *eol;
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
@@ -554,14 +575,35 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
}
++cursor; // Skip ' '.
- // Skip to file name. "cursor" now points to file offset. We need to
- // skip at least three spaces for file offset, dev, and inode.
+ // Read file offset.
+ uint64_t file_offset;
+ cursor = GetHex(cursor, eol, &file_offset);
+ if (cursor == eol || *cursor != ' ') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip ' '.
+
+ // Don't subtract 'start_address' from the first entry:
+ // * If a binary is compiled w/o -pie, then the first entry in
+ // process maps is likely the binary itself (all dynamic libs
+ // are mapped higher in address space). For such a binary,
+ // instruction offset in binary coincides with the actual
+ // instruction address in virtual memory (as code section
+ // is mapped to a fixed memory range).
+ // * If a binary is compiled with -pie, all the modules are
+ // mapped high at address space (in particular, higher than
+ // shadow memory of the tool), so the module can't be the
+ // first entry.
+ base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
+
+ // Skip to file name. "cursor" now points to dev. We need to
+ // skip at least two spaces for dev and inode.
int num_spaces = 0;
while (cursor < eol) {
if (*cursor == ' ') {
++num_spaces;
- } else if (num_spaces >= 3) {
- // The first non-space character after skipping three spaces
+ } else if (num_spaces >= 2) {
+ // The first non-space character after skipping two spaces
// is the beginning of the file name.
break;
}
@@ -574,12 +616,105 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// Finally, "cursor" now points to file name of our interest.
NO_INTR(object_fd = open(cursor, O_RDONLY));
if (object_fd < 0) {
+ // Failed to open object file. Copy the object file name to
+ // |out_file_name|.
+ strncpy(out_file_name, cursor, out_file_name_size);
+ // Making sure |out_file_name| is always null-terminated.
+ out_file_name[out_file_name_size - 1] = '\0';
return -1;
}
return object_fd;
}
}
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+ // Make sure we can write at least one NUL byte.
+ size_t n = 1;
+ if (n > sz)
+ return NULL;
+
+ if (base < 2 || base > 16) {
+ buf[0] = '\000';
+ return NULL;
+ }
+
+ char *start = buf;
+
+ uintptr_t j = i;
+
+ // Handle negative numbers (only for base 10).
+ if (i < 0 && base == 10) {
+ j = -i;
+
+ // Make sure we can write the '-' character.
+ if (++n > sz) {
+ buf[0] = '\000';
+ return NULL;
+ }
+ *start++ = '-';
+ }
+
+ // Loop until we have converted the entire number. Output at least one
+ // character (i.e. '0').
+ char *ptr = start;
+ do {
+ // Make sure there is still enough space left in our output buffer.
+ if (++n > sz) {
+ buf[0] = '\000';
+ return NULL;
+ }
+
+ // Output the next digit.
+ *ptr++ = "0123456789abcdef"[j % base];
+ j /= base;
+
+ if (padding > 0)
+ padding--;
+ } while (j > 0 || padding > 0);
+
+ // Terminate the output with a NUL character.
+ *ptr = '\000';
+
+ // Conversion to ASCII actually resulted in the digits being in reverse
+ // order. We can't easily generate them in forward order, as we can't tell
+ // the number of characters needed until we are done converting.
+ // So, now, we reverse the string (except for the possible "-" sign).
+ while (--ptr > start) {
+ char ch = *ptr;
+ *ptr = *start;
+ *start++ = ch;
+ }
+ return buf;
+}
+
+// Safely appends string |source| to string |dest|. Never writes past the
+// buffer size |dest_size| and guarantees that |dest| is null-terminated.
+void SafeAppendString(const char* source, char* dest, int dest_size) {
+ int dest_string_length = strlen(dest);
+ SAFE_ASSERT(dest_string_length < dest_size);
+ dest += dest_string_length;
+ dest_size -= dest_string_length;
+ strncpy(dest, source, dest_size);
+ // Making sure |dest| is always null-terminated.
+ dest[dest_size - 1] = '\0';
+}
+
+// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
+// Never writes past the buffer size |dest_size| and guarantees that |dest| is
+// null-terminated.
+void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
+ // 64-bit numbers in hex can have up to 16 digits.
+ char buf[17] = {'\0'};
+ SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
+}
+
// The implementation of our symbolization routine. If it
// successfully finds the symbol containing "pc" and obtains the
// symbol name, returns true and write the symbol name to "out".
@@ -592,10 +727,40 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
int out_size) {
uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
uint64_t start_address = 0;
+ uint64_t base_address = 0;
+ int object_fd = -1;
- int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
- start_address);
- if (object_fd == -1) {
+ if (out_size < 1) {
+ return false;
+ }
+ out[0] = '\0';
+ SafeAppendString("(", out, out_size);
+
+ if (g_symbolize_open_object_file_callback) {
+ object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
+ base_address, out + 1,
+ out_size - 1);
+ } else {
+ object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
+ base_address,
+ out + 1,
+ out_size - 1);
+ }
+
+ // Check whether a file name was returned.
+ if (object_fd < 0) {
+ if (out[1]) {
+ // The object file containing PC was determined successfully however the
+ // object file was not opened successfully. This is still considered
+ // success because the object file name and offset are known and tools
+ // like asan_symbolize.py can be used for the symbolization.
+ out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
+ SafeAppendString("+0x", out, out_size);
+ SafeAppendHexNumber(pc0 - base_address, out, out_size);
+ SafeAppendString(")", out, out_size);
+ return true;
+ }
+ // Failed to determine the object file containing PC. Bail out.
return false;
}
FileDescriptor wrapped_object_fd(object_fd);
@@ -639,7 +804,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
int out_size) {
Dl_info info;
if (dladdr(pc, &info)) {
- if (strlen(info.dli_sname) < out_size) {
+ if ((int)strlen(info.dli_sname) < out_size) {
strcpy(out, info.dli_sname);
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size);
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
index 441e543..f617184 100644
--- a/base/third_party/symbolize/symbolize.h
+++ b/base/third_party/symbolize/symbolize.h
@@ -105,6 +105,10 @@ _END_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_
+// Restrictions on the callbacks that follow:
+// - The callbacks must not use heaps but only use stacks.
+// - The callbacks must be async-signal-safe.
+
// Installs a callback function, which will be called right before a symbol name
// is printed. The callback is intended to be used for showing a file name and a
// line number preceding a symbol name.
@@ -116,6 +120,24 @@ typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
uint64 relocation);
void InstallSymbolizeCallback(SymbolizeCallback callback);
+// Installs a callback function, which will be called instead of
+// OpenObjectFileContainingPcAndGetStartAddress. The callback is expected
+// to searches for the object file (from /proc/self/maps) that contains
+// the specified pc. If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file. If the object
+// file is opened successfully, returns the file descriptor. Otherwise,
+// returns -1. |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
+ uint64_t &start_address,
+ uint64_t &base_address,
+ char *out_file_name,
+ int out_file_name_size);
+void InstallSymbolizeOpenObjectFileCallback(
+ SymbolizeOpenObjectFileCallback callback);
+
_END_GOOGLE_NAMESPACE_
#endif