summaryrefslogtreecommitdiffstats
path: root/base/third_party
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-25 10:52:28 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-25 10:52:28 +0000
commitb84167f708bc75d06bb175850d292778426d701c (patch)
tree396662faf225ce79b3159437f600f824282bb113 /base/third_party
parent5e9e3685204f9307b0b724a5064a31558e1455d5 (diff)
downloadchromium_src-b84167f708bc75d06bb175850d292778426d701c.zip
chromium_src-b84167f708bc75d06bb175850d292778426d701c.tar.gz
chromium_src-b84167f708bc75d06bb175850d292778426d701c.tar.bz2
Import google-glog's Symbolize() and use it in debug_util_posix.cc.
Unlike glibc's backtrace_symbols(), google-glog's Symbolize() can resolve symbols in binaries built with -fvisibility=hidden. This is because Symbolize() uses both dynamic and regular symbols, while backtrace_symbols() only uses dynamic symbols. As shown below, the new backtrace is slightly less informative as it does not have the binary name like out/Debug/base_unittests and the distance information like +0x20, but it should be ok. BUG=32762 TEST=out/Debug/base_unittests --gtest_filter='StackTrace*' --gtest_also_run_disabled_tests; and manually: BEFORE out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x81d38f6] out/Debug/base_unittests(StackTrace_DISABLED_DebugOutputToStream_Test::TestBody()+0x17) [0x806633d] out/Debug/base_unittests(testing::Test::Run()+0x7a) [0x8242f96] out/Debug/base_unittests(testing::internal::TestInfoImpl::Run()+0xb9) [0x824347b] out/Debug/base_unittests(testing::TestCase::Run()+0xb7) [0x8243a7f] out/Debug/base_unittests(testing::internal::UnitTestImpl::RunAllTests()+0x256) [0x824777e] out/Debug/base_unittests(testing::UnitTest::Run()+0x14) [0x824680a] out/Debug/base_unittests [0x8048cc5] out/Debug/base_unittests(main+0x50) [0x80482a4] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0xb6b41b56] out/Debug/base_unittests [0x80481c1] AFTER % out/Debug/base_unittests --gtest_filter='*DebugOutputToStream' --gtest_also_run_disabled_tests StackTrace::StackTrace() [0x81d3910] StackTrace_DISABLED_DebugOutputToStream_Test::TestBody() [0x806633d] testing::Test::Run() [0x8242f66] testing::internal::TestInfoImpl::Run() [0x824344b] testing::TestCase::Run() [0x8243a4f] testing::internal::UnitTestImpl::RunAllTests() [0x824774e] testing::UnitTest::Run() [0x82467da] TestSuite::Run() [0x8048cc5] main [0x80482a4] 0xb6c0db56 0x80481c1 Review URL: http://codereview.chromium.org/545148 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36997 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/third_party')
-rw-r--r--base/third_party/symbolize/README.chromium17
-rw-r--r--base/third_party/symbolize/config.h7
-rw-r--r--base/third_party/symbolize/demangle.cc1231
-rw-r--r--base/third_party/symbolize/demangle.h84
-rw-r--r--base/third_party/symbolize/glog/logging.h5
-rw-r--r--base/third_party/symbolize/glog/raw_logging.h6
-rw-r--r--base/third_party/symbolize/symbolize.cc681
-rw-r--r--base/third_party/symbolize/symbolize.h116
-rw-r--r--base/third_party/symbolize/utilities.h11
9 files changed, 2158 insertions, 0 deletions
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
new file mode 100644
index 0000000..5b3ba0e
--- /dev/null
+++ b/base/third_party/symbolize/README.chromium
@@ -0,0 +1,17 @@
+The directory contains google-glog's symbolization library.
+License can be found in symbolize.cc.
+
+The following files are copied AS-IS from:
+http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r76)
+
+- demangle.cc
+- demangle.h
+- symbolize.cc
+- symbolize.h
+
+The following files are minimal stubs created for use in Chromium:
+
+- config.h
+- glog/logging.h
+- glog/raw_logging.h
+- utilities.h
diff --git a/base/third_party/symbolize/config.h b/base/third_party/symbolize/config.h
new file mode 100644
index 0000000..945f5a6
--- /dev/null
+++ b/base/third_party/symbolize/config.h
@@ -0,0 +1,7 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define GOOGLE_NAMESPACE google
+#define _END_GOOGLE_NAMESPACE_ }
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
new file mode 100644
index 0000000..46556bf
--- /dev/null
+++ b/base/third_party/symbolize/demangle.cc
@@ -0,0 +1,1231 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+
+#include <stdio.h> // for NULL
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+ const char *abbrev;
+ const char *real_name;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+ { "nw", "new" },
+ { "na", "new[]" },
+ { "dl", "delete" },
+ { "da", "delete[]" },
+ { "ps", "+" },
+ { "ng", "-" },
+ { "ad", "&" },
+ { "de", "*" },
+ { "co", "~" },
+ { "pl", "+" },
+ { "mi", "-" },
+ { "ml", "*" },
+ { "dv", "/" },
+ { "rm", "%" },
+ { "an", "&" },
+ { "or", "|" },
+ { "eo", "^" },
+ { "aS", "=" },
+ { "pL", "+=" },
+ { "mI", "-=" },
+ { "mL", "*=" },
+ { "dV", "/=" },
+ { "rM", "%=" },
+ { "aN", "&=" },
+ { "oR", "|=" },
+ { "eO", "^=" },
+ { "ls", "<<" },
+ { "rs", ">>" },
+ { "lS", "<<=" },
+ { "rS", ">>=" },
+ { "eq", "==" },
+ { "ne", "!=" },
+ { "lt", "<" },
+ { "gt", ">" },
+ { "le", "<=" },
+ { "ge", ">=" },
+ { "nt", "!" },
+ { "aa", "&&" },
+ { "oo", "||" },
+ { "pp", "++" },
+ { "mm", "--" },
+ { "cm", "," },
+ { "pm", "->*" },
+ { "pt", "->" },
+ { "cl", "()" },
+ { "ix", "[]" },
+ { "qu", "?" },
+ { "st", "sizeof" },
+ { "sz", "sizeof" },
+ { NULL, NULL },
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+ { "v", "void" },
+ { "w", "wchar_t" },
+ { "b", "bool" },
+ { "c", "char" },
+ { "a", "signed char" },
+ { "h", "unsigned char" },
+ { "s", "short" },
+ { "t", "unsigned short" },
+ { "i", "int" },
+ { "j", "unsigned int" },
+ { "l", "long" },
+ { "m", "unsigned long" },
+ { "x", "long long" },
+ { "y", "unsigned long long" },
+ { "n", "__int128" },
+ { "o", "unsigned __int128" },
+ { "f", "float" },
+ { "d", "double" },
+ { "e", "long double" },
+ { "g", "__float128" },
+ { "z", "ellipsis" },
+ { NULL, NULL }
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+ { "St", "" },
+ { "Sa", "allocator" },
+ { "Sb", "basic_string" },
+ // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+ { "Ss", "string"},
+ // std::basic_istream<char, std::char_traits<char> >
+ { "Si", "istream" },
+ // std::basic_ostream<char, std::char_traits<char> >
+ { "So", "ostream" },
+ // std::basic_iostream<char, std::char_traits<char> >
+ { "Sd", "iostream" },
+ { NULL, NULL }
+};
+
+// 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.
+ bool append; // Append flag.
+ bool overflowed; // True if output gets overflowed.
+} State;
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+ size_t len = 0;
+ while (*str != '\0') {
+ ++str;
+ ++len;
+ }
+ return len;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+ size_t i = 0;
+ while (str[i] != '\0' && prefix[i] != '\0' &&
+ str[i] == prefix[i]) {
+ ++i;
+ }
+ return prefix[i] == '\0'; // Consumed everything in "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) {
+ ++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]) {
+ state->mangled_cur += 2;
+ return true;
+ }
+ return false;
+}
+
+// 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;
+ return true;
+ }
+ }
+ return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool status) {
+ return true;
+}
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+ if (parse_func(state)) {
+ while (parse_func(state)) {
+ }
+ return true;
+ }
+ return false;
+}
+
+// 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.
+static void Append(State *state, const char * const str, const int length) {
+ int i;
+ for (i = 0; i < length; ++i) {
+ if (state->out_cur + 1 < state->out_end) { // +1 for '\0'
+ *state->out_cur = str[i];
+ ++state->out_cur;
+ } else {
+ state->overflowed = true;
+ break;
+ }
+ }
+ if (!state->overflowed) {
+ *state->out_cur = '\0'; // Terminate it with '\0'
+ }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) {
+ return c >= 'a' && c <= 'z';
+}
+
+static bool IsAlpha(char c) {
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+// 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,
+ const int length) {
+ if (state->append && length > 0) {
+ // Append a space if the output buffer ends with '<' and "str"
+ // starts with '<' to avoid <<<.
+ if (str[0] == '<' && state->out_begin < state->out_cur &&
+ state->out_cur[-1] == '<') {
+ Append(state, " ", 1);
+ }
+ // Remember the last identifier name for ctors/dtors.
+ if (IsAlpha(str[0]) || str[0] == '_') {
+ state->prev_name = state->out_cur;
+ state->prev_name_length = length;
+ }
+ Append(state, str, length);
+ }
+}
+
+// A convenient wrapper arount MaybeAppendWithLength().
+static bool MaybeAppend(State *state, const char * const str) {
+ if (state->append) {
+ int length = StrLen(str);
+ MaybeAppendWithLength(state, str, length);
+ }
+ return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+ state->nest_level = 0;
+ return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, int prev_value) {
+ state->nest_level = prev_value;
+ return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+ state->append = false;
+ return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+ state->append = prev_value;
+ return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+ if (state->nest_level > -1) {
+ ++state->nest_level;
+ }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+ if (state->nest_level >= 1) {
+ MaybeAppend(state, "::");
+ }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+ if (state->nest_level >= 1 && state->append &&
+ state->out_begin <= state->out_cur - 2) {
+ state->out_cur -= 2;
+ *state->out_cur = '\0';
+ }
+}
+
+// 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.
+ StrPrefix(state->mangled_cur, anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseUnscopedTemplateName(State *state);
+static bool ParseNestedName(State *state);
+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 ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state);
+static bool ParseOperatorName(State *state);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+// We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the state and returns true on
+// success. Otherwise, don't change the state and returns false. To
+// ensure that the state isn't changed in the latter case, we save the
+// original state before we call more than one parsing functions
+// consecutively with &&, and restore the state if unsuccessful. See
+// ParseEncoding() as an example of this convention. We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments. Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+// <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
+
+// <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;
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+// ::= <(data) name>
+// ::= <special-name>
+static bool ParseEncoding(State *state) {
+ State copy = *state;
+ if (ParseName(state) && ParseBareFunctionType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseName(state) || ParseSpecialName(state)) {
+ return true;
+ }
+ return false;
+}
+
+// <name> ::= <nested-name>
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+// ::= <local-name>
+static bool ParseName(State *state) {
+ if (ParseNestedName(state) || ParseLocalName(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseUnscopedTemplateName(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Less greedy than <unscoped-template-name> <template-args>.
+ if (ParseUnscopedName(state)) {
+ return true;
+ }
+ return false;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+ if (ParseUnqualifiedName(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseTwoChar(state, "St") &&
+ MaybeAppend(state, "std::") &&
+ ParseUnqualifiedName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+static bool ParseUnscopedTemplateName(State *state) {
+ return ParseUnscopedName(state) || ParseSubstitution(state);
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+static bool ParseNestedName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'N') &&
+ EnterNestedName(state) &&
+ Optional(ParseCVQualifiers(state)) &&
+ ParsePrefix(state) &&
+ LeaveNestedName(state, copy.nest_level) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// This part is tricky. If we literally translate them to code, we'll
+// end up infinite loop. Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <substitution>
+// ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+static bool ParsePrefix(State *state) {
+ bool has_something = false;
+ while (true) {
+ MaybeAppendSeparator(state);
+ if (ParseTemplateParam(state) ||
+ ParseSubstitution(state) ||
+ ParseUnscopedName(state)) {
+ has_something = true;
+ MaybeIncreaseNestLevel(state);
+ continue;
+ }
+ MaybeCancelLastSeparator(state);
+ if (has_something && ParseTemplateArgs(state)) {
+ return ParsePrefix(state);
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <local-source-name>
+static bool ParseUnqualifiedName(State *state) {
+ return (ParseOperatorName(state) ||
+ ParseCtorDtorName(state) ||
+ ParseSourceName(state) ||
+ ParseLocalSourceName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+ State copy = *state;
+ if (ParseNumber(state) && ParseIdentifier(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'L') && ParseSourceName(state) &&
+ Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+static bool ParseNumber(State *state) {
+ int sign = 1;
+ if (ParseChar(state, 'n')) {
+ sign = -1;
+ }
+ const char *p = state->mangled_cur;
+ int number = 0;
+ for (;p < state->mangled_end; ++p) {
+ if ((*p >= '0' && *p <= '9')) {
+ number = number * 10 + (*p - '0');
+ } else {
+ break;
+ }
+ }
+ if (p != state->mangled_cur) { // Conversion succeeded.
+ state->mangled_cur = p;
+ state->number = number * sign;
+ return true;
+ }
+ return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// 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 {
+ break;
+ }
+ }
+ if (p != state->mangled_cur) { // Conversion succeeded.
+ state->mangled_cur = p;
+ state->number = number;
+ return true;
+ }
+ return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// 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 {
+ 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) {
+ return false;
+ }
+ if (IdentifierIsAnonymousNamespace(state)) {
+ MaybeAppend(state, "(anonymous namespace)");
+ } else {
+ MaybeAppendWithLength(state, state->mangled_cur, state->number);
+ }
+ state->mangled_cur += state->number;
+ state->number = -1; // Reset the number.
+ return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+// ::= cv <type> # (cast)
+// ::= v <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state) {
+ if (RemainingLength(state) < 2) {
+ return false;
+ }
+ // First check with "cv" (cast) case.
+ State copy = *state;
+ if (ParseTwoChar(state, "cv") &&
+ MaybeAppend(state, "operator ") &&
+ EnterNestedName(state) &&
+ ParseType(state) &&
+ LeaveNestedName(state, copy.nest_level)) {
+ return true;
+ }
+ *state = copy;
+
+ // Then vendor extended operators.
+ if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") &&
+ ParseSourceName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Other operator names should start with a lower alphabet followed
+ // by a lower/upper alphabet.
+ if (!(IsLower(state->mangled_cur[0]) &&
+ IsAlpha(state->mangled_cur[1]))) {
+ return false;
+ }
+ // We may want to perform a binary search if we really need speed.
+ const AbbrevPair *p;
+ for (p = kOperatorList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[0] &&
+ state->mangled_cur[1] == p->abbrev[1]) {
+ MaybeAppend(state, "operator");
+ if (IsLower(*p->real_name)) { // new, delete, etc.
+ MaybeAppend(state, " ");
+ }
+ MaybeAppend(state, p->real_name);
+ state->mangled_cur += 2;
+ return true;
+ }
+ }
+ return false;
+}
+
+// <special-name> ::= TV <type>
+// ::= TT <type>
+// ::= TI <type>
+// ::= TS <type>
+// ::= Tc <call-offset> <call-offset> <(base) encoding>
+// ::= GV <(object) name>
+// ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+// ::= TC <type> <(offset) number> _ <(base) type>
+// ::= TF <type>
+// ::= TJ <type>
+// ::= GR <name>
+// ::= GA <encoding>
+// ::= Th <call-offset> <(base) encoding>
+// ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces. The are special data.
+static bool ParseSpecialName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'T') &&
+ ParseCharClass(state, "VTIS") &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) &&
+ ParseCallOffset(state) && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GV") &&
+ ParseName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCallOffset(state) &&
+ ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // G++ extensions
+ if (ParseTwoChar(state, "TC") && ParseType(state) &&
+ ParseNumber(state) && ParseChar(state, '_') &&
+ DisableAppend(state) &&
+ ParseType(state)) {
+ RestoreAppend(state, copy.append);
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GR") && ParseName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GA") && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCharClass(state, "hv") &&
+ ParseCallOffset(state) && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'h') &&
+ ParseNVOffset(state) && ParseChar(state, '_')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'v') &&
+ ParseVOffset(state) && ParseChar(state, '_')) {
+ return true;
+ }
+ *state = copy;
+
+ return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+ return ParseNumber(state);
+}
+
+// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+ State copy = *state;
+ if (ParseNumber(state) && ParseChar(state, '_') &&
+ ParseNumber(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+// ::= D0 | D1 | D2
+static bool ParseCtorDtorName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'C') &&
+ ParseCharClass(state, "123")) {
+ const char * const prev_name = state->prev_name;
+ const int prev_name_length = state->prev_name_length;
+ MaybeAppendWithLength(state, prev_name, prev_name_length);
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'D') &&
+ ParseCharClass(state, "012")) {
+ const char * const prev_name = state->prev_name;
+ const int prev_name_length = state->prev_name_length;
+ MaybeAppend(state, "~");
+ MaybeAppendWithLength(state, prev_name, prev_name_length);
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+// ::= P <type>
+// ::= R <type>
+// ::= C <type>
+// ::= G <type>
+// ::= U <source-name> <type>
+// ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-template-param> <template-args>
+// ::= <template-param>
+// ::= <substitution>
+static bool ParseType(State *state) {
+ // We should check CV-qualifers, and PRGC things first.
+ State copy = *state;
+ if (ParseCVQualifiers(state) && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseCharClass(state, "PRCG") && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'U') && ParseSourceName(state) &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseBuiltinType(state) ||
+ ParseFunctionType(state) ||
+ ParseClassEnumType(state) ||
+ ParseArrayType(state) ||
+ ParsePointerToMemberType(state) ||
+ ParseSubstitution(state)) {
+ return true;
+ }
+
+ if (ParseTemplateTemplateParam(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Less greedy than <template-template-param> <template-args>.
+ if (ParseTemplateParam(state)) {
+ return true;
+ }
+
+ return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// 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');
+ return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+// ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+ const AbbrevPair *p;
+ for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[0]) {
+ MaybeAppend(state, p->real_name);
+ ++state->mangled_cur;
+ return true;
+ }
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'u') && ParseSourceName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <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')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+ State copy = *state;
+ DisableAppend(state);
+ if (OneOrMore(ParseType, state)) {
+ RestoreAppend(state, copy.append);
+ MaybeAppend(state, "()");
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+ return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+// ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'A') && ParseNumber(state) &&
+ ParseChar(state, '_') && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'A') && Optional(ParseExpression(state)) &&
+ ParseChar(state, '_') && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'M') && ParseType(state) &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <template-param> ::= T_
+// ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+ if (ParseTwoChar(state, "T_")) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'T') && ParseNumber(state) &&
+ ParseChar(state, '_')) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+
+// <template-template-param> ::= <template-param>
+// ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+ return (ParseTemplateParam(state) ||
+ ParseSubstitution(state));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+ State copy = *state;
+ DisableAppend(state);
+ if (ParseChar(state, 'I') &&
+ OneOrMore(ParseTemplateArg, state) &&
+ ParseChar(state, 'E')) {
+ RestoreAppend(state, copy.append);
+ MaybeAppend(state, "<>");
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <template-arg> ::= <type>
+// ::= <expr-primary>
+// ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+ if (ParseType(state) ||
+ ParseExprPrimary(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'X') && ParseExpression(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <expression> ::= <template-param>
+// ::= <expr-primary>
+// ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <trinary operator-name> <expression> <expression>
+// <expression>
+// ::= st <type>
+// ::= sr <type> <unqualified-name> <template-args>
+// ::= sr <type> <unqualified-name>
+static bool ParseExpression(State *state) {
+ if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseOperatorName(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOperatorName(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOperatorName(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "st") && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ ParseUnqualifiedName(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ ParseUnqualifiedName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+// ::= L <type> <(value) float> E
+// ::= L <mangled-name> E
+// // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+// ::= LZ <encoding> E
+static bool ParseExprPrimary(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'L') && ParseType(state) &&
+ ParseNumber(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'L') && ParseType(state) &&
+ ParseFloatNumber(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'L') && ParseMangledName(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "LZ") && ParseEncoding(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ return false;
+}
+
+// <local-name> := Z <(function) encoding> E <(entity) name>
+// [<discriminator>]
+// := 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, "::") &&
+ ParseName(state) && Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'Z') && ParseEncoding(state) &&
+ ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+ State copy = *state;
+ if (ParseChar(state, '_') && ParseNumber(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <substitution> ::= S_
+// ::= S <seq-id> _
+// ::= St, etc.
+static bool ParseSubstitution(State *state) {
+ if (ParseTwoChar(state, "S_")) {
+ MaybeAppend(state, "?"); // We don't support substitutions.
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'S') && ParseSeqId(state) &&
+ ParseChar(state, '_')) {
+ MaybeAppend(state, "?"); // We don't support substitutions.
+ return true;
+ }
+ *state = copy;
+
+ // Expand abbreviations like "St" => "std".
+ if (ParseChar(state, 'S')) {
+ const AbbrevPair *p;
+ for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[1]) {
+ MaybeAppend(state, "std");
+ if (p->real_name[0] != '\0') {
+ MaybeAppend(state, "::");
+ MaybeAppend(state, p->real_name);
+ }
+ state->mangled_cur += 1;
+ return true;
+ }
+ }
+ }
+ *state = copy;
+ 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);
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/demangle.h b/base/third_party/symbolize/demangle.h
new file mode 100644
index 0000000..9c75915
--- /dev/null
+++ b/base/third_party/symbolize/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces. We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling. More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments. It just skips them. However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv | f() | f()
+// | _Z1fi | f() | f(int)
+// | _Z3foo3bar | foo() | foo(bar)
+// | _Z1fIiEvi | f<>() | void f<int>(int)
+// | _ZN1N1fE | N::f | N::f
+// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
+// | _Zrm1XS_" | operator%() | operator%(X, X)
+// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
+// | _Z1fSs | f() | f(std::basic_string<char,
+// | | | std::char_traits<char>,
+// | | | std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled". On success, return true and write the
+// demangled symbol name to "out". Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_DEMANGLE_H_
diff --git a/base/third_party/symbolize/glog/logging.h b/base/third_party/symbolize/glog/logging.h
new file mode 100644
index 0000000..a42c306
--- /dev/null
+++ b/base/third_party/symbolize/glog/logging.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Empty.
diff --git a/base/third_party/symbolize/glog/raw_logging.h b/base/third_party/symbolize/glog/raw_logging.h
new file mode 100644
index 0000000..f5515c4
--- /dev/null
+++ b/base/third_party/symbolize/glog/raw_logging.h
@@ -0,0 +1,6 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define WARNING 1;
+#define RAW_LOG(severity, ...); // Do nothing.
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
new file mode 100644
index 0000000..3465de6
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.cc
@@ -0,0 +1,681 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks. We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym) = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym) = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove(). We assume they are async-signal-safe.
+//
+
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe. Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+ abort();
+ return 0; // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+ g_symbolize_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
+// get inlined.
+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'.
+ SAFE_ASSERT(len < sizeof(demangled));
+ memmove(out, demangled, len + 1);
+ }
+ }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <link.h> // For ElfW() macro.
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR. On
+// success, return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+ SAFE_ASSERT(fd >= 0);
+ SAFE_ASSERT(count >= 0 && count <= std::numeric_limits<ssize_t>::max());
+ char *buf0 = reinterpret_cast<char *>(buf);
+ ssize_t num_bytes = 0;
+ while (num_bytes < count) {
+ ssize_t len;
+ NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+ if (len < 0) { // There was an error other than EINTR.
+ return -1;
+ }
+ if (len == 0) { // Reached EOF.
+ break;
+ }
+ num_bytes += len;
+ }
+ SAFE_ASSERT(num_bytes <= count);
+ return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf". On success,
+// return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ off_t off = lseek(fd, offset, SEEK_SET);
+ if (off == (off_t)-1) {
+ return -1;
+ }
+ return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR. On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ ssize_t len = ReadFromOffset(fd, buf, count, offset);
+ return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return -1;
+ }
+ if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+ return -1;
+ }
+ return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+ ElfW(Word) type, ElfW(Shdr) *out) {
+ // Read at most 16 section headers at a time to save read calls.
+ ElfW(Shdr) buf[16];
+ for (int i = 0; i < sh_num;) {
+ const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+ const ssize_t num_bytes_to_read =
+ (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+ const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+ sh_offset + i * sizeof(buf[0]));
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+ for (int j = 0; j < num_headers_in_buf; ++j) {
+ if (buf[j].sh_type == type) {
+ *out = buf[j];
+ return true;
+ }
+ }
+ i += num_headers_in_buf;
+ }
+ return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+ ElfW(Shdr) *out) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ ElfW(Shdr) shstrtab;
+ off_t shstrtab_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * elf_header.e_shstrndx);
+ if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+ return false;
+ }
+
+ for (int i = 0; i < elf_header.e_shnum; ++i) {
+ off_t section_header_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * i);
+ if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+ return false;
+ }
+ char header_name[kMaxSectionNameLen];
+ if (sizeof(header_name) < name_len) {
+ RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
+ "section will not be found (even if present).", name, name_len);
+ // No point in even trying.
+ return false;
+ }
+ off_t name_offset = shstrtab.sh_offset + out->sh_name;
+ ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+ if (n_read == -1) {
+ return false;
+ } else if (n_read != name_len) {
+ // Short read -- name could be at end of file.
+ continue;
+ }
+ if (memcmp(header_name, name, name_len) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc". On success, return true and write the symbol name
+// to out. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+ uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+ const ElfW(Shdr) *symtab) {
+ if (symtab == NULL) {
+ return false;
+ }
+ const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+ for (int i = 0; i < num_symbols;) {
+ off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+ // If we are reading Elf64_Sym's, we want to limit this array to
+ // 32 elements (to keep stack consumption low), otherwise we can
+ // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+ // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+ ElfW(Sym) buf[NUM_SYMBOLS];
+ const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+ for (int j = 0; j < num_symbols_in_buf; ++j) {
+ const ElfW(Sym)& symbol = buf[j];
+ uint64_t start_address = symbol.st_value;
+ start_address += symbol_offset;
+ uint64_t end_address = start_address + symbol.st_size;
+ if (symbol.st_value != 0 && // Skip null value symbols.
+ symbol.st_shndx != 0 && // Skip undefined symbols.
+ start_address <= pc && pc < end_address) {
+ ssize_t len1 = ReadFromOffset(fd, out, out_size,
+ strtab->sh_offset + symbol.st_name);
+ if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+ return false;
+ }
+ return true; // Obtained the symbol name.
+ }
+ }
+ i += num_symbols_in_buf;
+ }
+ return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd". Process
+// both regular and dynamic symbol tables if necessary. On success,
+// write the symbol name to "out" and return true. Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+ char *out, int out_size,
+ uint64_t map_start_address) {
+ // Read the ELF header.
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ uint64_t symbol_offset = 0;
+ if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
+ symbol_offset = map_start_address;
+ }
+
+ ElfW(Shdr) symtab, strtab;
+
+ // Consult a regular symbol table first.
+ if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_SYMTAB, &symtab)) {
+ return false;
+ }
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a regular symbol table.
+ }
+
+ // If the symbol is not found, then consult a dynamic symbol table.
+ if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_DYNSYM, &symtab)) {
+ return false;
+ }
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a dynamic symbol table.
+ }
+
+ return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+ const int fd_;
+ explicit FileDescriptor(int fd) : fd_(fd) {}
+ ~FileDescriptor() {
+ if (fd_ >= 0) {
+ NO_INTR(close(fd_));
+ }
+ }
+ int get() { return fd_; }
+
+ private:
+ explicit FileDescriptor(const FileDescriptor&);
+ void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+ explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+ buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+ }
+
+ // Read '\n'-terminated line from file. On success, modify "bol"
+ // and "eol", then return true. Otherwise, return false.
+ //
+ // Note: if the last line doesn't end with '\n', the line will be
+ // dropped. It's an intentional behavior to make the code simple.
+ bool ReadLine(const char **bol, const char **eol) {
+ if (BufferIsEmpty()) { // First time.
+ const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = buf_ + num_bytes;
+ bol_ = buf_;
+ } else {
+ bol_ = eol_ + 1; // Advance to the next line in the buffer.
+ SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
+ if (!HasCompleteLine()) {
+ const int incomplete_line_length = eod_ - bol_;
+ // Move the trailing incomplete line to the beginning.
+ memmove(buf_, bol_, incomplete_line_length);
+ // Read text from file and append it.
+ char * const append_pos = buf_ + incomplete_line_length;
+ const int capacity_left = buf_len_ - incomplete_line_length;
+ const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+ capacity_left);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = append_pos + num_bytes;
+ bol_ = buf_;
+ }
+ }
+ eol_ = FindLineFeed();
+ if (eol_ == NULL) { // '\n' not found. Malformed line.
+ return false;
+ }
+ *eol_ = '\0'; // Replace '\n' with '\0'.
+
+ *bol = bol_;
+ *eol = eol_;
+ return true;
+ }
+
+ // Beginning of line.
+ const char *bol() {
+ return bol_;
+ }
+
+ // End of line.
+ const char *eol() {
+ return eol_;
+ }
+
+ private:
+ explicit LineReader(const LineReader&);
+ void operator=(const LineReader&);
+
+ char *FindLineFeed() {
+ return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+ }
+
+ bool BufferIsEmpty() {
+ return buf_ == eod_;
+ }
+
+ bool HasCompleteLine() {
+ return !BufferIsEmpty() && FindLineFeed() != NULL;
+ }
+
+ const int fd_;
+ char * const buf_;
+ const int buf_len_;
+ char *bol_;
+ char *eol_;
+ const char *eod_; // End of data in "buf_".
+};
+} // namespace
+
+// Place the hex number read from "start" into "*hex". The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+ *hex = 0;
+ const char *p;
+ for (p = start; p < end; ++p) {
+ int ch = *p;
+ if ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+ *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+ } else { // Encountered the first non-hex character.
+ break;
+ }
+ }
+ SAFE_ASSERT(p <= end);
+ 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.
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+ uint64_t &start_address) {
+ int object_fd;
+
+ // Open /proc/self/maps.
+ int maps_fd;
+ NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+ FileDescriptor wrapped_maps_fd(maps_fd);
+ if (wrapped_maps_fd.get() < 0) {
+ return -1;
+ }
+
+ // 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
+ LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+ while (true) {
+ const char *cursor;
+ const char *eol;
+ if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
+ return -1;
+ }
+
+ // Start parsing line in /proc/self/maps. Here is an example:
+ //
+ // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
+ //
+ // We want start address (08048000), end address (0804c000), flags
+ // (r-xp) and file name (/bin/cat).
+
+ // Read start address.
+ cursor = GetHex(cursor, eol, &start_address);
+ if (cursor == eol || *cursor != '-') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip '-'.
+
+ // Read end address.
+ uint64_t end_address;
+ cursor = GetHex(cursor, eol, &end_address);
+ if (cursor == eol || *cursor != ' ') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip ' '.
+
+ // Check start and end addresses.
+ if (!(start_address <= pc && pc < end_address)) {
+ continue; // We skip this map. PC isn't in this map.
+ }
+
+ // Read flags. Skip flags until we encounter a space or eol.
+ const char * const flags_start = cursor;
+ while (cursor < eol && *cursor != ' ') {
+ ++cursor;
+ }
+ // We expect at least four letters for flags (ex. "r-xp").
+ if (cursor == eol || cursor < flags_start + 4) {
+ return -1; // Malformed line.
+ }
+
+ // Check flags. We are only interested in "r-x" maps.
+ if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
+ continue; // We skip this map.
+ }
+ ++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.
+ 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
+ // is the beginning of the file name.
+ break;
+ }
+ ++cursor;
+ }
+ if (cursor == eol) {
+ return -1; // Malformed line.
+ }
+
+ // Finally, "cursor" now points to file name of our interest.
+ NO_INTR(object_fd = open(cursor, O_RDONLY));
+ if (object_fd < 0) {
+ return -1;
+ }
+ return object_fd;
+ }
+}
+
+// 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".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+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;
+
+ int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
+ start_address);
+ if (object_fd == -1) {
+ return false;
+ }
+ FileDescriptor wrapped_object_fd(object_fd);
+ int elf_type = FileGetElfType(wrapped_object_fd.get());
+ if (elf_type == -1) {
+ return false;
+ }
+ if (g_symbolize_callback) {
+ // Run the call back if it's installed.
+ // Note: relocation (and much of the rest of this code) will be
+ // wrong for prelinked shared libraries and PIE executables.
+ uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+ int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+ pc, out, out_size,
+ relocation);
+ if (num_bytes_written > 0) {
+ out += num_bytes_written;
+ out_size -= num_bytes_written;
+ }
+ }
+ if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+ out, out_size, start_address)) {
+ return false;
+ }
+
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+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) {
+ strcpy(out, info.dli_sname);
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+ }
+ }
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+ SAFE_ASSERT(out_size >= 0);
+ return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+ assert(0);
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
new file mode 100644
index 0000000..1ebe4dd
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+// 1. Go through a list of maps in /proc/self/maps and find the map
+// containing the program counter.
+//
+// 2. Open the mapped file and find a regular symbol table inside.
+// Iterate over symbols in the symbol table and look for the symbol
+// containing the program counter. If such a symbol is found,
+// obtain the symbol name, and demangle the symbol if possible.
+// If the symbol isn't found in the regular symbol table (binary is
+// stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// FailureSignalHandler() in base/google.cc. Hence it doesn't use
+// malloc() and other unsafe operations. It should be both
+// thread-safe and async-signal-safe.
+
+#ifndef BASE_SYMBOLIZE_H_
+#define BASE_SYMBOLIZE_H_
+
+#include "utilities.h"
+#include "config.h"
+#include "glog/logging.h"
+
+#ifdef HAVE_SYMBOLIZE
+
+#if defined(__ELF__) // defined by gcc on Linux
+#include <elf.h>
+#include <link.h> // For ElfW() macro.
+
+// If there is no ElfW macro, let's define it by ourself.
+#ifndef ElfW
+# if SIZEOF_VOID_P == 4
+# define ElfW(type) Elf32_##type
+# elif SIZEOF_VOID_P == 8
+# define ElfW(type) Elf64_##type
+# else
+# error "Unknown sizeof(void *)"
+# endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+ ElfW(Shdr) *out);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* __ELF__ */
+
+_START_GOOGLE_NAMESPACE_
+
+// 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.
+// "fd" is a file descriptor of the object file containing the program
+// counter "pc". The callback function should write output to "out"
+// and return the size of the output written. On error, the callback
+// function should return -1.
+typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
+ uint64 relocation);
+void InstallSymbolizeCallback(SymbolizeCallback callback);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Symbolizes a program counter. On success, returns true and write the
+// symbol name to "out". The symbol name is demangled if possible
+// (supports symbols generated by GCC 3.x or newer). Otherwise,
+// returns false.
+bool Symbolize(void *pc, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_SYMBOLIZE_H_
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
new file mode 100644
index 0000000..0bed526
--- /dev/null
+++ b/base/third_party/symbolize/utilities.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+typedef uint64_t uint64;
+#define HAVE_SYMBOLIZE 1
+#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))