mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 05:55:36 +00:00
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 .
This commit is contained in:
parent
138886803c
commit
7398ce15b7
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue