aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mentovai <mark@chromium.org>2016-09-23 14:22:42 -0400
committerMark Mentovai <mark@chromium.org>2016-09-23 14:22:42 -0400
commit7398ce15b79daf038cd07fbae4e37e183e99788d (patch)
treec6baf6108bf8de9d23f9f574a8102196621b98fd
parentgenerate a repo manifest from the DEPS file (diff)
downloadbreakpad-7398ce15b79daf038cd07fbae4e37e183e99788d.tar.xz
Initial support for dumping DWARF corresponding to Swift code
The DWARF data for Swift code has a top-level DW_TAG_module DIE as the child of the DW_TAG_compile_unit DIE and the parent of the DW_TAG_subprogram DIEs that dump_syms uses to locate functions. dump_syms needs to process DW_TAG_module DIEs as introducing nested scopes to make it work with Swift. This also reworks demangling to be language-specific, so that the C++ demangler isn't invoked when processing Swift code. The DWARF data for Swift code presents its mangled names in the same form as used for C++ (DW_AT_MIPS_linkage_name or DW_AT_linkage_name) but the mangling is Swift-specific (beginning with _T instead of _Z). There is no programmatic interface to a Swift name demangler as an analogue to C++'s __cxa_demangle(), so mangled Swift names are exposed as-is. Xcode's "xcrun swift-demangle" can be used to post-process these mangled Swift names on macOS. Support for mangled names presented in a DW_AT_linkage_name attribute, as used by DWARF 4, is added. This supersedes the earlier use of DW_AT_MIPS_linkage_name. BUG=google-breakpad:702,google-breakpad:715 R=ted.mielczarek@gmail.com Review URL: https://codereview.chromium.org/2147523005 .
-rw-r--r--src/common/dwarf/dwarf2enums.h7
-rw-r--r--src/common/dwarf_cu_to_module.cc45
-rw-r--r--src/common/dwarf_cu_to_module.h2
-rw-r--r--src/common/dwarf_cu_to_module_unittest.cc2
-rw-r--r--src/common/language.cc91
-rw-r--r--src/common/language.h16
6 files changed, 130 insertions, 33 deletions
diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h
index 6b8a7245..09567555 100644
--- a/src/common/dwarf/dwarf2enums.h
+++ b/src/common/dwarf/dwarf2enums.h
@@ -232,6 +232,8 @@ enum DwarfAttribute {
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
+ // DWARF 4
+ DW_AT_linkage_name = 0x6e,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
@@ -499,7 +501,7 @@ enum DwarfOpcode {
DW_OP_call_frame_cfa =0x9c,
DW_OP_bit_piece =0x9d,
DW_OP_lo_user =0xe0,
- DW_OP_hi_user =0xff,
+ DW_OP_hi_user =0xff,
// GNU extensions
DW_OP_GNU_push_tls_address =0xe0,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
@@ -542,6 +544,7 @@ enum DwarfLanguage
DW_LANG_ObjC_plus_plus =0x0011,
DW_LANG_UPC =0x0012,
DW_LANG_D =0x0013,
+ DW_LANG_Swift =0x001e,
// Implementation-defined language code range.
DW_LANG_lo_user = 0x8000,
DW_LANG_hi_user = 0xffff,
@@ -668,7 +671,7 @@ enum DwarfPointerEncoding
// encoding (except DW_EH_PE_aligned), and indicates that the
// encoded value represents the address at which the true address
// is stored, not the true address itself.
- DW_EH_PE_indirect = 0x80
+ DW_EH_PE_indirect = 0x80
};
} // namespace dwarf2reader
diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
index 479e39b2..100f3962 100644
--- a/src/common/dwarf_cu_to_module.cc
+++ b/src/common/dwarf_cu_to_module.cc
@@ -39,9 +39,6 @@
#include "common/dwarf_cu_to_module.h"
#include <assert.h>
-#if !defined(__ANDROID__)
-#include <cxxabi.h>
-#endif
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
@@ -350,20 +347,22 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
case dwarf2reader::DW_AT_name:
name_attribute_ = AddStringToPool(data);
break;
- case dwarf2reader::DW_AT_MIPS_linkage_name: {
- char* demangled = NULL;
- int status = -1;
-#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
- demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status);
-#endif
- if (status != 0) {
- cu_context_->reporter->DemangleError(data, status);
- demangled_name_ = "";
- break;
- }
- if (demangled) {
- demangled_name_ = AddStringToPool(demangled);
- free(reinterpret_cast<void*>(demangled));
+ case dwarf2reader::DW_AT_MIPS_linkage_name:
+ case dwarf2reader::DW_AT_linkage_name: {
+ string demangled;
+ Language::DemangleResult result =
+ cu_context_->language->DemangleName(data, &demangled);
+ switch (result) {
+ case Language::kDemangleSuccess:
+ demangled_name_ = AddStringToPool(demangled);
+ break;
+
+ case Language::kDemangleFailure:
+ cu_context_->reporter->DemangleError(data);
+ // fallthrough
+ case Language::kDontDemangle:
+ demangled_name_.clear();
+ break;
}
break;
}
@@ -676,11 +675,10 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
filename_.c_str(), offset);
}
-void DwarfCUToModule::WarningReporter::DemangleError(
- const string &input, int error) {
+void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
CUHeading();
- fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n",
- filename_.c_str(), input.c_str(), error);
+ fprintf(stderr, "%s: warning: failed to demangle %s\n",
+ filename_.c_str(), input.c_str());
}
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
@@ -761,6 +759,7 @@ dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
case dwarf2reader::DW_TAG_class_type:
case dwarf2reader::DW_TAG_structure_type:
case dwarf2reader::DW_TAG_union_type:
+ case dwarf2reader::DW_TAG_module:
return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
offset);
default:
@@ -774,6 +773,10 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
cu_context_->language = Language::Java;
break;
+ case dwarf2reader::DW_LANG_Swift:
+ cu_context_->language = Language::Swift;
+ break;
+
// DWARF has no generic language code for assembly language; this is
// what the GNU toolchain uses.
case dwarf2reader::DW_LANG_Mips_Assembler:
diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h
index fca92710..a36b82b0 100644
--- a/src/common/dwarf_cu_to_module.h
+++ b/src/common/dwarf_cu_to_module.h
@@ -202,7 +202,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
virtual void UnnamedFunction(uint64 offset);
// __cxa_demangle() failed to demangle INPUT.
- virtual void DemangleError(const string &input, int error);
+ virtual void DemangleError(const string &input);
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
// FilePrivate did not retain the inter-CU specification data.
diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc
index 619e90a2..e789f9da 100644
--- a/src/common/dwarf_cu_to_module_unittest.cc
+++ b/src/common/dwarf_cu_to_module_unittest.cc
@@ -83,7 +83,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
- MOCK_METHOD2(DemangleError, void(const string &input, int error));
+ MOCK_METHOD1(DemangleError, void(const string &input));
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
};
diff --git a/src/common/language.cc b/src/common/language.cc
index c2fd81f6..3a598f69 100644
--- a/src/common/language.cc
+++ b/src/common/language.cc
@@ -34,18 +34,66 @@
#include "common/language.h"
+#include <stdlib.h>
+
+#if !defined(__ANDROID__)
+#include <cxxabi.h>
+#endif
+
+#include <limits>
+
+namespace {
+
+string MakeQualifiedNameWithSeparator(const string& parent_name,
+ const char* separator,
+ const string& name) {
+ if (parent_name.empty()) {
+ return name;
+ }
+
+ return parent_name + separator + name;
+}
+
+} // namespace
+
namespace google_breakpad {
// C++ language-specific operations.
class CPPLanguage: public Language {
public:
CPPLanguage() {}
+
string MakeQualifiedName(const string &parent_name,
const string &name) const {
- if (parent_name.empty())
- return name;
- else
- return parent_name + "::" + name;
+ return MakeQualifiedNameWithSeparator(parent_name, "::", name);
+ }
+
+ virtual DemangleResult DemangleName(const string& mangled,
+ std::string* demangled) const {
+#if defined(__ANDROID__)
+ // Android NDK doesn't provide abi::__cxa_demangle.
+ demangled->clear();
+ return kDontDemangle;
+#else
+ int status;
+ char* demangled_c =
+ abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
+
+ DemangleResult result;
+ if (status == 0) {
+ result = kDemangleSuccess;
+ demangled->clear();
+ } else {
+ result = kDemangleFailure;
+ demangled->assign(demangled_c);
+ }
+
+ if (demangled_c) {
+ free(reinterpret_cast<void*>(demangled_c));
+ }
+
+ return result;
+#endif
}
};
@@ -54,19 +102,45 @@ CPPLanguage CPPLanguageSingleton;
// Java language-specific operations.
class JavaLanguage: public Language {
public:
+ JavaLanguage() {}
+
string MakeQualifiedName(const string &parent_name,
const string &name) const {
- if (parent_name.empty())
- return name;
- else
- return parent_name + "." + name;
+ return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
};
JavaLanguage JavaLanguageSingleton;
+// Swift language-specific operations.
+class SwiftLanguage: public Language {
+ public:
+ SwiftLanguage() {}
+
+ string MakeQualifiedName(const string &parent_name,
+ const string &name) const {
+ return MakeQualifiedNameWithSeparator(parent_name, ".", name);
+ }
+
+ virtual DemangleResult DemangleName(const string& mangled,
+ std::string* demangled) const {
+ // There is no programmatic interface to a Swift demangler. Pass through the
+ // mangled form because it encodes more information than the qualified name
+ // that would have been built by MakeQualifiedName(). The output can be
+ // post-processed by xcrun swift-demangle to transform mangled Swift names
+ // into something more readable.
+ demangled->assign(mangled);
+ return kDemangleSuccess;
+ }
+};
+
+SwiftLanguage SwiftLanguageSingleton;
+
// Assembler language-specific operations.
class AssemblerLanguage: public Language {
+ public:
+ AssemblerLanguage() {}
+
bool HasFunctions() const { return false; }
string MakeQualifiedName(const string &parent_name,
const string &name) const {
@@ -78,6 +152,7 @@ AssemblerLanguage AssemblerLanguageSingleton;
const Language * const Language::CPlusPlus = &CPPLanguageSingleton;
const Language * const Language::Java = &JavaLanguageSingleton;
+const Language * const Language::Swift = &SwiftLanguageSingleton;
const Language * const Language::Assembler = &AssemblerLanguageSingleton;
} // namespace google_breakpad
diff --git a/src/common/language.h b/src/common/language.h
index bbe30334..05786199 100644
--- a/src/common/language.h
+++ b/src/common/language.h
@@ -77,9 +77,25 @@ class Language {
virtual string MakeQualifiedName (const string &parent_name,
const string &name) const = 0;
+ enum DemangleResult {
+ // Demangling was not performed because it’s not appropriate to attempt.
+ kDontDemangle = -1,
+
+ kDemangleSuccess,
+ kDemangleFailure,
+ };
+
+ // Wraps abi::__cxa_demangle() or similar for languages where appropriate.
+ virtual DemangleResult DemangleName(const string& mangled,
+ std::string* demangled) const {
+ demangled->clear();
+ return kDontDemangle;
+ }
+
// Instances for specific languages.
static const Language * const CPlusPlus,
* const Java,
+ * const Swift,
* const Assembler;
};