blob: 5f332506e58bd9320fe9a6028e086656559c7866 [file] [log] [blame]
//===-- SwiftLanguageRuntime.cpp --------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/SwiftLanguageRuntime.h"
#include <string.h>
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/ABI/System.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/Types.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Remote/MemoryReader.h"
#include "swift/RemoteAST/RemoteAST.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Utility/Status.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/SwiftASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
#include "lldb/Target/ThreadPlanStepInRange.h"
#include "lldb/Target/ThreadPlanStepOverRange.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StringLexer.h"
// FIXME: we should not need this
#include "Plugins/Language/Swift/SwiftFormatters.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
SwiftLanguageRuntime::~SwiftLanguageRuntime() {}
SwiftLanguageRuntime::SwiftLanguageRuntime(Process *process)
: LanguageRuntime(process), m_negative_cache_mutex(),
m_SwiftNativeNSErrorISA(), m_memory_reader_sp(), m_promises_map(),
m_resolvers_map(), m_bridged_synthetics_map(), m_box_metadata_type() {
SetupSwiftError();
SetupExclusivity();
}
static llvm::Optional<lldb::addr_t>
FindSymbolForSwiftObject(Target &target, const ConstString &object,
const SymbolType sym_type) {
llvm::Optional<lldb::addr_t> retval;
SymbolContextList sc_list;
if (target.GetImages().FindSymbolsWithNameAndType(object, sym_type,
sc_list)) {
SymbolContext SwiftObject_Class;
if (sc_list.GetSize() == 1 &&
sc_list.GetContextAtIndex(0, SwiftObject_Class)) {
if (SwiftObject_Class.symbol) {
lldb::addr_t SwiftObject_class_addr =
SwiftObject_Class.symbol->GetAddress().GetLoadAddress(&target);
if (SwiftObject_class_addr &&
SwiftObject_class_addr != LLDB_INVALID_ADDRESS)
retval = SwiftObject_class_addr;
}
}
}
return retval;
}
AppleObjCRuntimeV2 *SwiftLanguageRuntime::GetObjCRuntime() {
if (auto objc_runtime = GetProcess()->GetObjCLanguageRuntime()) {
if (objc_runtime->GetPluginName() ==
AppleObjCRuntimeV2::GetPluginNameStatic())
return (AppleObjCRuntimeV2 *)objc_runtime;
}
return nullptr;
}
void SwiftLanguageRuntime::SetupSwiftError() {
Target &target(m_process->GetTarget());
if (m_SwiftNativeNSErrorISA.hasValue())
return;
ConstString g_SwiftNativeNSError("_SwiftNativeNSError");
m_SwiftNativeNSErrorISA = FindSymbolForSwiftObject(
target, g_SwiftNativeNSError, eSymbolTypeObjCClass);
}
void SwiftLanguageRuntime::SetupExclusivity() {
Target &target(m_process->GetTarget());
ConstString g_disableExclusivityChecking("_swift_disableExclusivityChecking");
m_dynamic_exclusivity_flag_addr = FindSymbolForSwiftObject(
target, g_disableExclusivityChecking, eSymbolTypeData);
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
if (log)
log->Printf("SwiftLanguageRuntime: _swift_disableExclusivityChecking = %llu",
m_dynamic_exclusivity_flag_addr ?
*m_dynamic_exclusivity_flag_addr : 0);
}
void SwiftLanguageRuntime::ModulesDidLoad(const ModuleList &module_list) {}
static bool GetObjectDescription_ResultVariable(Process *process, Stream &str,
ValueObject &object) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
StreamString expr_string;
expr_string.Printf("Swift._DebuggerSupport.stringForPrintObject(%s)",
object.GetName().GetCString());
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression: %s",
expr_string.GetData());
ValueObjectSP result_sp;
EvaluateExpressionOptions eval_options;
eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetResultIsInternal(true);
eval_options.SetGenerateDebugInfo(true);
auto eval_result = process->GetTarget().EvaluateExpression(
expr_string.GetData(),
process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(),
result_sp, eval_options);
if (log) {
switch (eval_result) {
case eExpressionCompleted:
log->Printf("[GetObjectDescription_ResultVariable] eExpressionCompleted");
break;
case eExpressionSetupError:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionSetupError");
break;
case eExpressionParseError:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionParseError");
break;
case eExpressionDiscarded:
log->Printf("[GetObjectDescription_ResultVariable] eExpressionDiscarded");
break;
case eExpressionInterrupted:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionInterrupted");
break;
case eExpressionHitBreakpoint:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionHitBreakpoint");
break;
case eExpressionTimedOut:
log->Printf("[GetObjectDescription_ResultVariable] eExpressionTimedOut");
break;
case eExpressionResultUnavailable:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionResultUnavailable");
break;
case eExpressionStoppedForDebug:
log->Printf(
"[GetObjectDescription_ResultVariable] eExpressionStoppedForDebug");
break;
}
}
// sanitize the result of the expression before moving forward
if (!result_sp) {
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression generated "
"no result");
return false;
}
if (result_sp->GetError().Fail()) {
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression generated "
"error: %s",
result_sp->GetError().AsCString());
return false;
}
if (false == result_sp->GetCompilerType().IsValid()) {
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression generated "
"invalid type");
return false;
}
lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions
dump_options;
dump_options.SetEscapeNonPrintables(false).SetQuote('\0').SetPrefixToken(
nullptr);
if (lldb_private::formatters::swift::String_SummaryProvider(
*result_sp.get(), str, TypeSummaryOptions()
.SetLanguage(lldb::eLanguageTypeSwift)
.SetCapping(eTypeSummaryUncapped),
dump_options)) {
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression completed "
"successfully");
return true;
} else {
if (log)
log->Printf("[GetObjectDescription_ResultVariable] expression generated "
"invalid string data");
return false;
}
}
static bool GetObjectDescription_ObjectReference(Process *process, Stream &str,
ValueObject &object) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
StreamString expr_string;
expr_string.Printf("Swift._DebuggerSupport.stringForPrintObject(Swift."
"unsafeBitCast(0x%" PRIx64 ", to: AnyObject.self))",
object.GetValueAsUnsigned(0));
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression: %s",
expr_string.GetData());
ValueObjectSP result_sp;
EvaluateExpressionOptions eval_options;
eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetResultIsInternal(true);
eval_options.SetGenerateDebugInfo(true);
auto eval_result = process->GetTarget().EvaluateExpression(
expr_string.GetData(),
process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(),
result_sp, eval_options);
if (log) {
switch (eval_result) {
case eExpressionCompleted:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionCompleted");
break;
case eExpressionSetupError:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionSetupError");
break;
case eExpressionParseError:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionParseError");
break;
case eExpressionDiscarded:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionDiscarded");
break;
case eExpressionInterrupted:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionInterrupted");
break;
case eExpressionHitBreakpoint:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionHitBreakpoint");
break;
case eExpressionTimedOut:
log->Printf("[GetObjectDescription_ObjectReference] eExpressionTimedOut");
break;
case eExpressionResultUnavailable:
log->Printf("[GetObjectDescription_ObjectReference] "
"eExpressionResultUnavailable");
break;
case eExpressionStoppedForDebug:
log->Printf(
"[GetObjectDescription_ObjectReference] eExpressionStoppedForDebug");
break;
}
}
// sanitize the result of the expression before moving forward
if (!result_sp) {
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression generated "
"no result");
return false;
}
if (result_sp->GetError().Fail()) {
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression generated "
"error: %s",
result_sp->GetError().AsCString());
return false;
}
if (false == result_sp->GetCompilerType().IsValid()) {
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression generated "
"invalid type");
return false;
}
lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions
dump_options;
dump_options.SetEscapeNonPrintables(false).SetQuote('\0').SetPrefixToken(
nullptr);
if (lldb_private::formatters::swift::String_SummaryProvider(
*result_sp.get(), str, TypeSummaryOptions()
.SetLanguage(lldb::eLanguageTypeSwift)
.SetCapping(eTypeSummaryUncapped),
dump_options)) {
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression completed "
"successfully");
return true;
} else {
if (log)
log->Printf("[GetObjectDescription_ObjectReference] expression generated "
"invalid string data");
return false;
}
}
static bool GetObjectDescription_ObjectCopy(Process *process, Stream &str,
ValueObject &object) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
ValueObjectSP static_sp(object.GetStaticValue());
CompilerType static_type(static_sp->GetCompilerType());
if (auto non_reference_type = static_type.GetNonReferenceType())
static_type = non_reference_type;
Status error;
lldb::addr_t copy_location = process->AllocateMemory(
static_type.GetByteStride(), ePermissionsReadable | ePermissionsWritable,
error);
if (copy_location == LLDB_INVALID_ADDRESS) {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] copy_location invalid");
return false;
}
CleanUp cleanup(
[process, copy_location] { process->DeallocateMemory(copy_location); });
DataExtractor data_extractor;
if (0 == static_sp->GetData(data_extractor, error)) {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] data extraction failed");
return false;
}
if (0 ==
process->WriteMemory(copy_location, data_extractor.GetDataStart(),
data_extractor.GetByteSize(), error)) {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] memory copy failed");
return false;
}
StreamString expr_string;
expr_string.Printf("Swift._DebuggerSupport.stringForPrintObject(Swift."
"UnsafePointer<%s>(bitPattern: 0x%" PRIx64 ")!.pointee)",
static_type.GetTypeName().GetCString(), copy_location);
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] expression: %s",
expr_string.GetData());
ValueObjectSP result_sp;
EvaluateExpressionOptions eval_options;
eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetResultIsInternal(true);
eval_options.SetGenerateDebugInfo(true);
auto eval_result = process->GetTarget().EvaluateExpression(
expr_string.GetData(),
process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(),
result_sp, eval_options);
if (log) {
switch (eval_result) {
case eExpressionCompleted:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionCompleted");
break;
case eExpressionSetupError:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionSetupError");
break;
case eExpressionParseError:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionParseError");
break;
case eExpressionDiscarded:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionDiscarded");
break;
case eExpressionInterrupted:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionInterrupted");
break;
case eExpressionHitBreakpoint:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionHitBreakpoint");
break;
case eExpressionTimedOut:
log->Printf("[GetObjectDescription_ObjectCopy] eExpressionTimedOut");
break;
case eExpressionResultUnavailable:
log->Printf(
"[GetObjectDescription_ObjectCopy] eExpressionResultUnavailable");
break;
case eExpressionStoppedForDebug:
log->Printf(
"[GetObjectDescription_ObjectCopy] eExpressionStoppedForDebug");
break;
}
}
// sanitize the result of the expression before moving forward
if (!result_sp) {
if (log)
log->Printf(
"[GetObjectDescription_ObjectCopy] expression generated no result");
str.Printf("expression produced no result");
return true;
}
if (result_sp->GetError().Fail()) {
if (log)
log->Printf(
"[GetObjectDescription_ObjectCopy] expression generated error: %s",
result_sp->GetError().AsCString());
str.Printf("expression produced error: %s",
result_sp->GetError().AsCString());
return true;
}
if (false == result_sp->GetCompilerType().IsValid()) {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] expression generated "
"invalid type");
str.Printf("expression produced invalid result type");
return true;
}
lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions
dump_options;
dump_options.SetEscapeNonPrintables(false).SetQuote('\0').SetPrefixToken(
nullptr);
if (lldb_private::formatters::swift::String_SummaryProvider(
*result_sp.get(), str, TypeSummaryOptions()
.SetLanguage(lldb::eLanguageTypeSwift)
.SetCapping(eTypeSummaryUncapped),
dump_options)) {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] expression completed "
"successfully");
} else {
if (log)
log->Printf("[GetObjectDescription_ObjectCopy] expression generated "
"invalid string data");
str.Printf("expression produced unprintable string");
}
return true;
}
static bool IsSwiftResultVariable(const ConstString &name) {
if (name) {
llvm::StringRef name_sr(name.GetStringRef());
if (name_sr.size() > 2 &&
(name_sr.startswith("$R") || name_sr.startswith("$E")) &&
::isdigit(name_sr[2]))
return true;
}
return false;
}
static bool IsSwiftReferenceType(ValueObject &object) {
CompilerType object_type(object.GetCompilerType());
if (llvm::dyn_cast_or_null<SwiftASTContext>(object_type.GetTypeSystem())) {
Flags type_flags(object_type.GetTypeInfo());
if (type_flags.AllSet(eTypeIsClass | eTypeHasValue |
eTypeInstanceIsPointer))
return true;
}
return false;
}
bool SwiftLanguageRuntime::GetObjectDescription(Stream &str,
ValueObject &object) {
if (object.IsUninitializedReference()) {
str.Printf("<uninitialized>");
return true;
}
if (::IsSwiftResultVariable(object.GetName())) {
// if this thing is a Swift expression result variable, it has two
// properties:
// a) its name is something we can refer to in expressions for free
// b) its type may be something we can't actually talk about in expressions
// so, just use the result variable's name in the expression and be done
// with it
StreamString probe_stream;
if (GetObjectDescription_ResultVariable(m_process, probe_stream, object)) {
str.Printf("%s", probe_stream.GetData());
return true;
}
} else if (::IsSwiftReferenceType(object)) {
// if this is a Swift class, it has two properties:
// a) we do not need its type name, AnyObject is just as good
// b) its value is something we can directly use to refer to it
// so, just use the ValueObject's pointer-value and be done with it
StreamString probe_stream;
if (GetObjectDescription_ObjectReference(m_process, probe_stream, object)) {
str.Printf("%s", probe_stream.GetData());
return true;
}
}
// in general, don't try to use the name of the ValueObject as it might end up
// referring to the wrong thing
return GetObjectDescription_ObjectCopy(m_process, str, object);
}
bool SwiftLanguageRuntime::GetObjectDescription(
Stream &str, Value &value, ExecutionContextScope *exe_scope) {
// This is only interesting to do with a ValueObject for Swift
return false;
}
bool SwiftLanguageRuntime::IsSwiftMangledName(const char *name) {
return swift::Demangle::isSwiftSymbol(name);
}
std::string SwiftLanguageRuntime::DemangleSymbolAsString (const char *symbol,
bool simplified) {
if (simplified) {
swift::Demangle::DemangleOptions options(swift::Demangle::DemangleOptions::
SimplifiedUIDemangleOptions());
return swift::Demangle::demangleSymbolAsString(
symbol, strlen(symbol), options);
} else
return swift::Demangle::demangleSymbolAsString(symbol, strlen(symbol));
}
std::string SwiftLanguageRuntime::DemangleSymbolAsString (const ConstString &symbol,
bool simplified) {
if (simplified) {
swift::Demangle::DemangleOptions options(swift::Demangle::DemangleOptions::
SimplifiedUIDemangleOptions());
return swift::Demangle::demangleSymbolAsString(
symbol.GetStringRef(), options);
} else
return swift::Demangle::demangleSymbolAsString(symbol.GetStringRef());
}
bool SwiftLanguageRuntime::IsSwiftClassName(const char *name)
{
return swift::Demangle::isClass(name);
}
const std::string SwiftLanguageRuntime::GetCurrentMangledName(const char *mangled_name)
{
#ifndef USE_NEW_MANGLING
return std::string(mangled_name);
#else
//FIXME: Check if we need to cache these lookups...
swift::Demangle::Context demangle_ctx;
swift::Demangle::NodePointer node_ptr = demangle_ctx.demangleSymbolAsNode(mangled_name);
if (!node_ptr)
{
// Sometimes this gets passed the prefix of a name, in which case we
// won't be able to demangle it. In that case return what was passed in.
printf ("Couldn't get mangled name for %s.\n", mangled_name);
return mangled_name;
}
else
return swift::Demangle::mangleNode(node_ptr);
#endif
}
void SwiftLanguageRuntime::MethodName::Clear() {
m_full.Clear();
m_basename = llvm::StringRef();
m_context = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
m_template_args = llvm::StringRef();
m_metatype_ref = llvm::StringRef();
m_return_type = llvm::StringRef();
m_type = eTypeInvalid;
m_parsed = false;
m_parse_error = false;
}
static bool StringHasAllOf(const llvm::StringRef &s, const char *which) {
for (const char *c = which; *c != 0; c++) {
if (s.find(*c) == llvm::StringRef::npos)
return false;
}
return true;
}
static bool StringHasAnyOf(const llvm::StringRef &s,
std::initializer_list<const char *> which,
size_t &where) {
for (const char *item : which) {
size_t where_item = s.find(item);
if (where_item != llvm::StringRef::npos) {
where = where_item;
return true;
}
}
where = llvm::StringRef::npos;
return false;
}
bool StringHasAnyOf(const llvm::StringRef &s, const char *which,
size_t &where) {
for (const char *c = which; *c != 0; c++) {
size_t where_item = s.find(*c);
if (where_item != llvm::StringRef::npos) {
where = where_item;
return true;
}
}
where = llvm::StringRef::npos;
return false;
}
static bool UnpackTerminatedSubstring(const llvm::StringRef &s,
const char start, const char stop,
llvm::StringRef &dest) {
size_t pos_of_start = s.find(start);
if (pos_of_start == llvm::StringRef::npos)
return false;
size_t pos_of_stop = s.rfind(stop);
if (pos_of_stop == llvm::StringRef::npos)
return false;
size_t token_count = 1;
size_t idx = pos_of_start + 1;
while (idx < s.size()) {
if (s[idx] == start)
++token_count;
if (s[idx] == stop) {
if (token_count == 1) {
dest = s.slice(pos_of_start, idx + 1);
return true;
}
}
idx++;
}
return false;
}
static bool UnpackQualifiedName(const llvm::StringRef &s, llvm::StringRef &decl,
llvm::StringRef &basename, bool &was_operator) {
size_t pos_of_dot = s.rfind('.');
if (pos_of_dot == llvm::StringRef::npos)
return false;
decl = s.substr(0, pos_of_dot);
basename = s.substr(pos_of_dot + 1);
size_t idx_of_operator;
was_operator = StringHasAnyOf(basename, {"@infix", "@prefix", "@postfix"},
idx_of_operator);
if (was_operator)
basename = basename.substr(0, idx_of_operator - 1);
return !decl.empty() && !basename.empty();
}
static bool ParseLocalDeclName(const swift::Demangle::NodePointer &node,
StreamString &identifier,
swift::Demangle::Node::Kind &parent_kind,
swift::Demangle::Node::Kind &kind) {
swift::Demangle::Node::iterator end = node->end();
for (swift::Demangle::Node::iterator pos = node->begin(); pos != end; ++pos) {
swift::Demangle::NodePointer child = *pos;
swift::Demangle::Node::Kind child_kind = child->getKind();
switch (child_kind) {
case swift::Demangle::Node::Kind::Number:
break;
default:
if (child->hasText()) {
identifier.PutCString(child->getText());
return true;
}
break;
}
}
return false;
}
static bool ParseFunction(const swift::Demangle::NodePointer &node,
StreamString &identifier,
swift::Demangle::Node::Kind &parent_kind,
swift::Demangle::Node::Kind &kind) {
swift::Demangle::Node::iterator end = node->end();
swift::Demangle::Node::iterator pos = node->begin();
// First child is the function's scope
parent_kind = (*pos)->getKind();
++pos;
// Second child is either the type (no identifier)
if (pos != end) {
switch ((*pos)->getKind()) {
case swift::Demangle::Node::Kind::Type:
break;
case swift::Demangle::Node::Kind::LocalDeclName:
if (ParseLocalDeclName(*pos, identifier, parent_kind, kind))
return true;
else
return false;
break;
default:
case swift::Demangle::Node::Kind::InfixOperator:
case swift::Demangle::Node::Kind::PostfixOperator:
case swift::Demangle::Node::Kind::PrefixOperator:
case swift::Demangle::Node::Kind::Identifier:
if ((*pos)->hasText())
identifier.PutCString((*pos)->getText());
return true;
}
}
return false;
}
static bool ParseGlobal(const swift::Demangle::NodePointer &node,
StreamString &identifier,
swift::Demangle::Node::Kind &parent_kind,
swift::Demangle::Node::Kind &kind) {
swift::Demangle::Node::iterator end = node->end();
for (swift::Demangle::Node::iterator pos = node->begin(); pos != end; ++pos) {
swift::Demangle::NodePointer child = *pos;
if (child) {
kind = child->getKind();
switch (child->getKind()) {
case swift::Demangle::Node::Kind::Allocator:
identifier.PutCString("__allocating_init");
ParseFunction(child, identifier, parent_kind, kind);
return true;
case swift::Demangle::Node::Kind::Constructor:
identifier.PutCString("init");
ParseFunction(child, identifier, parent_kind, kind);
return true;
case swift::Demangle::Node::Kind::Deallocator:
identifier.PutCString("__deallocating_deinit");
ParseFunction(child, identifier, parent_kind, kind);
return true;
case swift::Demangle::Node::Kind::Destructor:
identifier.PutCString("deinit");
ParseFunction(child, identifier, parent_kind, kind);
return true;
case swift::Demangle::Node::Kind::Getter:
case swift::Demangle::Node::Kind::Setter:
case swift::Demangle::Node::Kind::Function:
return ParseFunction(child, identifier, parent_kind, kind);
// Ignore these, they decorate a function at the same level, but don't
// contain any text
case swift::Demangle::Node::Kind::ObjCAttribute:
break;
default:
return false;
}
}
}
return false;
}
bool SwiftLanguageRuntime::MethodName::ExtractFunctionBasenameFromMangled(
const ConstString &mangled, ConstString &basename, bool &is_method) {
bool success = false;
swift::Demangle::Node::Kind kind = swift::Demangle::Node::Kind::Global;
swift::Demangle::Node::Kind parent_kind = swift::Demangle::Node::Kind::Global;
if (mangled) {
const char *mangled_cstr = mangled.GetCString();
const size_t mangled_cstr_len = mangled.GetLength();
if (mangled_cstr_len > 3) {
llvm::StringRef mangled_ref(mangled_cstr, mangled_cstr_len);
// Only demangle swift functions
// This is a no-op right now for the new mangling, because you
// have to demangle the whole name to figure this out anyway.
// I'm leaving the test here in case we actually need to do this
// only to functions.
swift::Demangle::Context demangle_ctx;
swift::Demangle::NodePointer node =
demangle_ctx.demangleSymbolAsNode(mangled_ref);
StreamString identifier;
if (node) {
switch (node->getKind()) {
case swift::Demangle::Node::Kind::Global:
success = ParseGlobal(node, identifier, parent_kind, kind);
break;
default:
break;
}
if (!identifier.GetString().empty()) {
basename = ConstString(identifier.GetString());
}
}
}
}
if (success) {
switch (kind) {
case swift::Demangle::Node::Kind::Allocator:
case swift::Demangle::Node::Kind::Constructor:
case swift::Demangle::Node::Kind::Deallocator:
case swift::Demangle::Node::Kind::Destructor:
is_method = true;
break;
case swift::Demangle::Node::Kind::Getter:
case swift::Demangle::Node::Kind::Setter:
// don't handle getters and setters right now...
return false;
case swift::Demangle::Node::Kind::Function:
switch (parent_kind) {
case swift::Demangle::Node::Kind::BoundGenericClass:
case swift::Demangle::Node::Kind::BoundGenericEnum:
case swift::Demangle::Node::Kind::BoundGenericStructure:
case swift::Demangle::Node::Kind::Class:
case swift::Demangle::Node::Kind::Enum:
case swift::Demangle::Node::Kind::Structure:
is_method = true;
break;
default:
break;
}
break;
default:
break;
}
}
return success;
}
void SwiftLanguageRuntime::MethodName::Parse() {
if (!m_parsed && m_full) {
// ConstString mangled;
// m_full.GetMangledCounterpart(mangled);
// printf ("\n parsing = '%s'\n", m_full.GetCString());
// if (mangled)
// printf (" mangled = '%s'\n", mangled.GetCString());
m_parse_error = false;
m_parsed = true;
llvm::StringRef full(m_full.GetCString());
bool was_operator = false;
if (full.find("::") != llvm::StringRef::npos) {
// :: is not an allowed operator in Swift (func ::(...) { fails to
// compile)
// but it's a very legitimate token in C++ - as a defense, reject anything
// with a :: in it as invalid Swift
m_parse_error = true;
return;
}
if (StringHasAllOf(full, ".:()")) {
const size_t open_paren = full.find(" (");
llvm::StringRef funcname = full.substr(0, open_paren);
UnpackQualifiedName(funcname, m_context, m_basename, was_operator);
if (was_operator)
m_type = eTypeOperator;
// check for obvious constructor/destructor cases
else if (m_basename.equals("__deallocating_destructor"))
m_type = eTypeDeallocator;
else if (m_basename.equals("__allocating_constructor"))
m_type = eTypeAllocator;
else if (m_basename.equals("init"))
m_type = eTypeConstructor;
else if (m_basename.equals("destructor"))
m_type = eTypeDestructor;
else
m_type = eTypeUnknownMethod;
const size_t idx_of_colon =
full.find(':', open_paren == llvm::StringRef::npos ? 0 : open_paren);
full = full.substr(idx_of_colon + 2);
if (full.empty())
return;
if (full[0] == '<') {
if (UnpackTerminatedSubstring(full, '<', '>', m_template_args)) {
full = full.substr(m_template_args.size());
} else {
m_parse_error = true;
return;
}
}
if (full.empty())
return;
if (full[0] == '(') {
if (UnpackTerminatedSubstring(full, '(', ')', m_metatype_ref)) {
full = full.substr(m_template_args.size());
if (full[0] == '<') {
if (UnpackTerminatedSubstring(full, '<', '>', m_template_args)) {
full = full.substr(m_template_args.size());
} else {
m_parse_error = true;
return;
}
}
} else {
m_parse_error = true;
return;
}
}
if (full.empty())
return;
if (full[0] == '(') {
if (UnpackTerminatedSubstring(full, '(', ')', m_arguments)) {
full = full.substr(m_template_args.size());
} else {
m_parse_error = true;
return;
}
}
if (full.empty())
return;
size_t idx_of_ret = full.find("->");
if (idx_of_ret == llvm::StringRef::npos) {
full = full.substr(idx_of_ret);
if (full.empty()) {
m_parse_error = true;
return;
}
if (full[0] == ' ')
full = full.substr(1);
m_return_type = full;
}
} else if (full.find('.') != llvm::StringRef::npos) {
// this is probably just a full name (module.type.func)
UnpackQualifiedName(full, m_context, m_basename, was_operator);
if (was_operator)
m_type = eTypeOperator;
else
m_type = eTypeUnknownMethod;
} else {
// this is most probably just a basename
m_basename = full;
m_type = eTypeUnknownMethod;
}
}
}
llvm::StringRef SwiftLanguageRuntime::MethodName::GetBasename() {
if (!m_parsed)
Parse();
return m_basename;
}
const CompilerType &SwiftLanguageRuntime::GetBoxMetadataType() {
if (m_box_metadata_type.IsValid())
return m_box_metadata_type;
static ConstString g_type_name("__lldb_autogen_boxmetadata");
const bool is_packed = false;
if (ClangASTContext *ast_ctx =
GetProcess()->GetTarget().GetScratchClangASTContext()) {
CompilerType voidstar =
ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
CompilerType uint32 = ClangASTContext::GetIntTypeFromBitSize(
ast_ctx->getASTContext(), 32, false);
m_box_metadata_type = ast_ctx->GetOrCreateStructForIdentifier(
g_type_name, {{"kind", voidstar}, {"offset", uint32}}, is_packed);
}
return m_box_metadata_type;
}
std::shared_ptr<swift::remote::MemoryReader>
SwiftLanguageRuntime::GetMemoryReader() {
class MemoryReader : public swift::remote::MemoryReader {
public:
MemoryReader(Process *p, size_t max_read_amount = 50 * 1024)
: m_process(p) {
lldbassert(m_process && "MemoryReader requires a valid Process");
m_max_read_amount = max_read_amount;
}
virtual ~MemoryReader() = default;
uint8_t getPointerSize() override {
return m_process->GetAddressByteSize();
}
uint8_t getSizeSize() override {
return getPointerSize(); // FIXME: sizeof(size_t)
}
swift::remote::RemoteAddress
getSymbolAddress(const std::string &name) override {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (name.empty())
return swift::remote::RemoteAddress(nullptr);
if (log)
log->Printf("[MemoryReader] asked to retrieve address of symbol %s",
name.c_str());
ConstString name_cs(name.c_str(), name.size());
SymbolContextList sc_list;
if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType(
name_cs, lldb::eSymbolTypeAny, sc_list)) {
SymbolContext sym_ctx;
// Remove undefined symbols from the list:
size_t num_sc_matches = sc_list.GetSize();
if (num_sc_matches > 1) {
SymbolContextList tmp_sc_list(sc_list);
sc_list.Clear();
for (size_t idx = 0; idx < num_sc_matches; idx++) {
tmp_sc_list.GetContextAtIndex(idx, sym_ctx);
if (sym_ctx.symbol &&
sym_ctx.symbol->GetType() != lldb::eSymbolTypeUndefined) {
sc_list.Append(sym_ctx);
}
}
}
if (sc_list.GetSize() == 1 && sc_list.GetContextAtIndex(0, sym_ctx)) {
if (sym_ctx.symbol) {
auto load_addr =
sym_ctx.symbol->GetLoadAddress(&m_process->GetTarget());
if (log)
log->Printf("[MemoryReader] symbol resolved to 0x%" PRIx64,
load_addr);
return swift::remote::RemoteAddress(load_addr);
}
}
}
if (log)
log->Printf("[MemoryReader] symbol resolution failed");
return swift::remote::RemoteAddress(nullptr);
}
bool readBytes(swift::remote::RemoteAddress address, uint8_t *dest,
uint64_t size) override {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (log)
log->Printf("[MemoryReader] asked to read %" PRIu64
" bytes at address 0x%" PRIx64,
size, address.getAddressData());
if (size > m_max_read_amount) {
if (log)
log->Printf(
"[MemoryReader] memory read exceeds maximum allowed size");
return false;
}
Target &target(m_process->GetTarget());
Address addr(address.getAddressData());
Status error;
if (size > target.ReadMemory(addr, false, dest, size, error)) {
if (log)
log->Printf(
"[MemoryReader] memory read returned fewer bytes than asked for");
return false;
}
if (error.Fail()) {
if (log)
log->Printf("[MemoryReader] memory read returned error: %s",
error.AsCString());
return false;
}
if (log) {
StreamString stream;
for (uint64_t i = 0; i < size; i++) {
stream.PutHex8(dest[i]);
stream.PutChar(' ');
}
log->Printf("[MemoryReader] memory read returned data: %s",
stream.GetData());
}
return true;
}
bool readString(swift::remote::RemoteAddress address,
std::string &dest) override {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (log)
log->Printf(
"[MemoryReader] asked to read string data at address 0x%" PRIx64,
address.getAddressData());
std::vector<char> storage(m_max_read_amount, 0);
Target &target(m_process->GetTarget());
Address addr(address.getAddressData());
Status error;
target.ReadCStringFromMemory(addr, &storage[0], storage.size(), error);
if (error.Success()) {
dest.assign(&storage[0]);
if (log)
log->Printf("[MemoryReader] memory read returned data: %s",
dest.c_str());
return true;
} else {
if (log)
log->Printf("[MemoryReader] memory read returned error: %s",
error.AsCString());
return false;
}
}
private:
Process *m_process;
size_t m_max_read_amount;
};
if (!m_memory_reader_sp)
m_memory_reader_sp.reset(new MemoryReader(GetProcess()));
return m_memory_reader_sp;
}
SwiftASTContext *SwiftLanguageRuntime::GetScratchSwiftASTContext() {
Status error;
return m_process->GetTarget().GetScratchSwiftASTContext(error);
}
SwiftLanguageRuntime::MemberVariableOffsetResolver::
MemberVariableOffsetResolver(swift::ASTContext *ast_ctx,
SwiftLanguageRuntime *runtime,
swift::TypeBase *type)
: m_swift_ast(ast_ctx), m_swift_runtime(runtime), m_offsets() {
lldbassert(m_swift_ast &&
"MemberVariableOffsetResolver requires a swift::ASTContext");
lldbassert(m_swift_runtime &&
"MemberVariableOffsetResolver requires a SwiftLanguageRuntime");
lldbassert(type && "MemberVariableOffsetResolver requires a swift::Type");
m_swift_type = type;
m_remote_ast.reset(new swift::remoteAST::RemoteASTContext(
*ast_ctx, m_swift_runtime->GetMemoryReader()));
}
llvm::Optional<uint64_t>
SwiftLanguageRuntime::MemberVariableOffsetResolver::ResolveOffset(
ValueObject *valobj, ConstString ivar_name, Status *error) {
if (error)
error->Clear();
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (log)
log->Printf(
"[MemberVariableOffsetResolver] asked to resolve offset for ivar %s",
ivar_name.AsCString());
auto iter = m_offsets.find(ivar_name.AsCString()), end = m_offsets.end();
if (iter != end)
return iter->second;
auto optmeta = swift::remote::RemoteAddress(nullptr);
const swift::TypeKind type_kind = m_swift_type->getKind();
switch (type_kind) {
case swift::TypeKind::Class:
case swift::TypeKind::BoundGenericClass: {
if (log)
log->Printf("[MemberVariableOffsetResolver] type is a class - trying to "
"get metadata for valueobject %s",
(valobj ? valobj->GetName().AsCString() : "<null>"));
// retrieve the metadata for class types as this is where we get the maximum
// benefit
if (valobj) {
lldb::addr_t value = valobj->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (value == 0 || value == LLDB_INVALID_ADDRESS)
break;
Status error;
lldb::addr_t meta_ptr =
m_swift_runtime->GetProcess()->ReadPointerFromMemory(value, error);
if (error.Fail() || meta_ptr == 0 || meta_ptr == LLDB_INVALID_ADDRESS)
break;
if (auto objc_runtime = m_swift_runtime->GetObjCRuntime()) {
if (objc_runtime->GetRuntimeVersion() ==
ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) {
meta_ptr =
((AppleObjCRuntimeV2 *)objc_runtime)->GetPointerISA(meta_ptr);
}
}
optmeta = swift::remote::RemoteAddress(meta_ptr);
}
if (log)
log->Printf("[MemberVariableOffsetResolver] optmeta = 0x%" PRIx64,
optmeta.getAddressData());
} break;
default: {
if (log)
log->Printf("[MemberVariableOffsetResolver] type is not a class - no "
"metadata needed");
} break;
}
swift::remoteAST::Result<uint64_t> result = m_remote_ast->getOffsetOfMember(
m_swift_type, optmeta, ivar_name.GetStringRef());
if (result) {
if (log)
log->Printf("[MemberVariableOffsetResolver] offset discovered = %" PRIu64,
(uint64_t)result.getValue());
m_offsets.emplace(ivar_name.AsCString(), result.getValue());
return result.getValue();
} else {
const auto &failure = result.getFailure();
if (error)
error->SetErrorStringWithFormat("error in resolving type offset: %s",
failure.render().c_str());
if (log)
log->Printf("[MemberVariableOffsetResolver] failure: %s",
failure.render().c_str());
return llvm::Optional<uint64_t>();
}
}
SwiftLanguageRuntime::MetadataPromise::MetadataPromise(
swift::ASTContext *ast_ctx, SwiftLanguageRuntime *runtime,
lldb::addr_t location)
: m_swift_ast(ast_ctx), m_swift_runtime(runtime),
m_metadata_location(location) {
lldbassert(m_swift_ast && "MetadataPromise requires a swift::ASTContext");
lldbassert(m_swift_runtime &&
"MetadataPromise requires a SwiftLanguageRuntime");
m_remote_ast.reset(new swift::remoteAST::RemoteASTContext(
*ast_ctx, m_swift_runtime->GetMemoryReader()));
}
CompilerType
SwiftLanguageRuntime::MetadataPromise::FulfillTypePromise(Status *error) {
if (error)
error->Clear();
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (log)
log->Printf("[MetadataPromise] asked to fulfill type promise at location "
"0x%" PRIx64,
m_metadata_location);
if (m_compiler_type.hasValue())
return m_compiler_type.getValue();
swift::remoteAST::Result<swift::Type> result =
m_remote_ast->getTypeForRemoteTypeMetadata(
swift::remote::RemoteAddress(m_metadata_location));
if (result) {
m_compiler_type = CompilerType(m_swift_ast, result.getValue().getPointer());
if (log)
log->Printf("[MetadataPromise] result is type %s",
m_compiler_type->GetTypeName().AsCString());
return m_compiler_type.getValue();
} else {
const auto &failure = result.getFailure();
if (error)
error->SetErrorStringWithFormat("error in resolving type: %s",
failure.render().c_str());
if (log)
log->Printf("[MetadataPromise] failure: %s", failure.render().c_str());
return (m_compiler_type = CompilerType()).getValue();
}
}
llvm::Optional<swift::MetadataKind>
SwiftLanguageRuntime::MetadataPromise::FulfillKindPromise(Status *error) {
if (error)
error->Clear();
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
if (log)
log->Printf("[MetadataPromise] asked to fulfill kind promise at location "
"0x%" PRIx64,
m_metadata_location);
if (m_metadata_kind.hasValue())
return m_metadata_kind;
swift::remoteAST::Result<swift::MetadataKind> result =
m_remote_ast->getKindForRemoteTypeMetadata(
swift::remote::RemoteAddress(m_metadata_location));
if (result) {
m_metadata_kind = result.getValue();
if (log)
log->Printf("[MetadataPromise] result is kind %u", result.getValue());
return m_metadata_kind;
} else {
const auto &failure = result.getFailure();
if (error)
error->SetErrorStringWithFormat("error in resolving type: %s",
failure.render().c_str());
if (log)
log->Printf("[MetadataPromise] failure: %s", failure.render().c_str());
return m_metadata_kind;
}
}
bool SwiftLanguageRuntime::MetadataPromise::IsStaticallyDetermined() {
if (llvm::Optional<swift::MetadataKind> kind_promise = FulfillKindPromise()) {
switch (kind_promise.getValue()) {
case swift::MetadataKind::Class:
case swift::MetadataKind::Existential:
case swift::MetadataKind::ObjCClassWrapper:
return false;
default:
return true;
}
}
return true;
}
static inline swift::Type GetSwiftType(const CompilerType &type) {
return swift::Type(
reinterpret_cast<swift::TypeBase *>(type.GetOpaqueQualType()));
}
SwiftLanguageRuntime::MetadataPromiseSP
SwiftLanguageRuntime::GetMetadataPromise(lldb::addr_t addr,
SwiftASTContext *swift_ast_ctx) {
if (!swift_ast_ctx)
swift_ast_ctx = GetScratchSwiftASTContext();
if (!swift_ast_ctx || swift_ast_ctx->HasFatalErrors())
return nullptr;
if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
return nullptr;
if (auto objc_runtime = GetObjCRuntime()) {
if (objc_runtime->GetRuntimeVersion() ==
ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) {
addr = ((AppleObjCRuntimeV2 *)objc_runtime)->GetPointerISA(addr);
}
}
typename decltype(m_promises_map)::key_type key{
swift_ast_ctx->GetASTContext(), addr};
auto iter = m_promises_map.find(key), end = m_promises_map.end();
if (iter != end)
return iter->second;
MetadataPromiseSP promise_sp(
new MetadataPromise(std::get<0>(key), this, std::get<1>(key)));
m_promises_map.emplace(key, promise_sp);
return promise_sp;
}
SwiftLanguageRuntime::MemberVariableOffsetResolverSP
SwiftLanguageRuntime::GetMemberVariableOffsetResolver(
CompilerType compiler_type) {
if (!compiler_type.IsValid())
return nullptr;
SwiftASTContext *swift_ast_ctx =
llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem());
if (!swift_ast_ctx || swift_ast_ctx->HasFatalErrors())
return nullptr;
swift::TypeBase *swift_type = reinterpret_cast<swift::TypeBase *>(
compiler_type.GetCanonicalType().GetOpaqueQualType());
typename decltype(m_resolvers_map)::key_type key{
swift_ast_ctx->GetASTContext(), swift_type};
auto iter = m_resolvers_map.find(key), end = m_resolvers_map.end();
if (iter != end)
return iter->second;
MemberVariableOffsetResolverSP resolver_sp(new MemberVariableOffsetResolver(
std::get<0>(key), this, std::get<1>(key)));
m_resolvers_map.emplace(key, resolver_sp);
return resolver_sp;
}
static size_t BaseClassDepth(ValueObject &in_value) {
ValueObject *ptr = &in_value;
size_t depth = 0;
while (ptr->IsBaseClass()) {
depth++;
ptr = ptr->GetParent();
}
return depth;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
CompilerType value_type(in_value.GetCompilerType());
AddressType address_type;
lldb::addr_t class_metadata_ptr = in_value.GetPointerValue(&address_type);
if (auto objc_runtime = GetObjCRuntime()) {
if (objc_runtime->IsTaggedPointer(class_metadata_ptr)) {
Value::ValueType value_type;
return objc_runtime->GetDynamicTypeAndAddress(
in_value, use_dynamic, class_type_or_name, address, value_type,
/* allow_swift = */ true);
}
}
if (class_metadata_ptr == LLDB_INVALID_ADDRESS || class_metadata_ptr == 0)
return false;
address.SetRawAddress(class_metadata_ptr);
size_t base_depth = BaseClassDepth(in_value);
lldb::addr_t class_instance_location;
if (in_value.IsBaseClass())
class_instance_location = in_value.GetPointerValue();
else
class_instance_location = in_value.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (class_instance_location == LLDB_INVALID_ADDRESS)
return false;
Status error;
lldb::addr_t class_metadata_location =
m_process->ReadPointerFromMemory(class_instance_location, error);
if (error.Fail() || class_metadata_location == 0 ||
class_metadata_location == LLDB_INVALID_ADDRESS)
return false;
SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null<SwiftASTContext>(
in_value.GetCompilerType().GetTypeSystem());
MetadataPromiseSP promise_sp(
GetMetadataPromise(class_metadata_location, swift_ast_ctx));
if (!promise_sp)
return false;
CompilerType class_type(promise_sp->FulfillTypePromise());
if (!class_type)
return false;
while (base_depth > 0) {
class_type = class_type.GetDirectBaseClassAtIndex(0, nullptr);
assert(class_type && "failed to get base class");
base_depth--;
}
class_type_or_name.SetCompilerType(class_type);
if (error.Fail())
return false;
return class_type_or_name.GetCompilerType().IsValid();
}
SwiftLanguageRuntime::SwiftErrorDescriptor::SwiftErrorDescriptor()
: m_kind(Kind::eNotAnError) {}
bool SwiftLanguageRuntime::IsValidErrorValue(
ValueObject &in_value, SwiftErrorDescriptor *out_error_descriptor) {
// see GetDynamicTypeAndAddress_ErrorType for details
CompilerType var_type(in_value.GetStaticValue()->GetCompilerType());
SwiftASTContext::ProtocolInfo protocol_info;
if (!SwiftASTContext::GetProtocolTypeInfo(var_type, protocol_info))
return false;
if (!protocol_info.m_is_errortype)
return false;
static ConstString g_instance_type_child_name("instance_type");
ValueObjectSP instance_type_sp(
in_value.GetStaticValue()->GetChildMemberWithName(
g_instance_type_child_name, true));
if (!instance_type_sp)
return false;
lldb::addr_t metadata_location = instance_type_sp->GetValueAsUnsigned(0);
if (metadata_location == 0 || metadata_location == LLDB_INVALID_ADDRESS)
return false;
SetupSwiftError();
if (m_SwiftNativeNSErrorISA.hasValue()) {
if (auto objc_runtime = GetObjCRuntime()) {
if (auto descriptor =
objc_runtime->GetClassDescriptor(*instance_type_sp)) {
if (descriptor->GetISA() != m_SwiftNativeNSErrorISA.getValue()) {
// not a _SwiftNativeNSError - but statically typed as ErrorType
// return true here
if (out_error_descriptor) {
*out_error_descriptor = SwiftErrorDescriptor();
out_error_descriptor->m_kind = SwiftErrorDescriptor::Kind::eBridged;
out_error_descriptor->m_bridged.instance_ptr_value =
instance_type_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
}
return true;
}
}
}
}
if (GetObjCRuntime()) {
// this is a swift native error but it can be bridged to ObjC
// so it needs to be layout compatible
size_t ptr_size = m_process->GetAddressByteSize();
size_t metadata_offset =
ptr_size + 4 + (ptr_size == 8 ? 4 : 0); // CFRuntimeBase
metadata_offset += ptr_size + ptr_size + ptr_size; // CFIndex + 2*CFRef
metadata_location += metadata_offset;
Status error;
lldb::addr_t metadata_ptr_value =
m_process->ReadPointerFromMemory(metadata_location, error);
if (metadata_ptr_value == 0 || metadata_ptr_value == LLDB_INVALID_ADDRESS ||
error.Fail())
return false;
if (out_error_descriptor) {
*out_error_descriptor = SwiftErrorDescriptor();
out_error_descriptor->m_kind =
SwiftErrorDescriptor::Kind::eSwiftBridgeableNative;
out_error_descriptor->m_bridgeable_native.metadata_location =
metadata_location;
out_error_descriptor->m_bridgeable_native.metadata_ptr_value =
metadata_ptr_value;
}
} else {
// this is a swift native error and it has no way to be bridged to ObjC
// so it adopts a more compact layout
Status error;
size_t ptr_size = m_process->GetAddressByteSize();
size_t metadata_offset = 2 * ptr_size;
metadata_location += metadata_offset;
lldb::addr_t metadata_ptr_value =
m_process->ReadPointerFromMemory(metadata_location, error);
if (metadata_ptr_value == 0 || metadata_ptr_value == LLDB_INVALID_ADDRESS ||
error.Fail())
return false;
lldb::addr_t witness_table_location = metadata_location + ptr_size;
lldb::addr_t witness_table_ptr_value =
m_process->ReadPointerFromMemory(witness_table_location, error);
if (witness_table_ptr_value == 0 ||
witness_table_ptr_value == LLDB_INVALID_ADDRESS || error.Fail())
return false;
lldb::addr_t payload_location = witness_table_location + ptr_size;
if (out_error_descriptor) {
*out_error_descriptor = SwiftErrorDescriptor();
out_error_descriptor->m_kind =
SwiftErrorDescriptor::Kind::eSwiftPureNative;
out_error_descriptor->m_pure_native.metadata_location =
metadata_ptr_value;
out_error_descriptor->m_pure_native.witness_table_location =
witness_table_ptr_value;
out_error_descriptor->m_pure_native.payload_ptr = payload_location;
}
}
return true;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_ErrorType(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
// layout of error type
// pointer to -------> SwiftError {
// --------------
// CFRuntimeBase
// CFIndex
// CFStringRef
// CFDictionaryRef
// --------------
// Metadata
// WitnessTable
// hashable Metadata
// hashable WitnessTable
// --------------
// tail allocated actual object data *
// }
// * for a struct, it's the inline data
// * for a class, it's the inline pointer-to-the-data (aka, the swift class
// instance)
SwiftErrorDescriptor error_descriptor;
if (!IsValidErrorValue(in_value, &error_descriptor))
return false;
Status error;
CompilerType var_type(in_value.GetStaticValue()->GetCompilerType());
size_t ptr_size = m_process->GetAddressByteSize();
SwiftASTContext *swift_ast_ctx =
llvm::dyn_cast_or_null<SwiftASTContext>(var_type.GetTypeSystem());
if (!swift_ast_ctx)
return false;
switch (error_descriptor.m_kind) {
case SwiftErrorDescriptor::Kind::eNotAnError:
return false;
case SwiftErrorDescriptor::Kind::eSwiftBridgeableNative: {
MetadataPromiseSP promise_sp(GetMetadataPromise(
error_descriptor.m_bridgeable_native.metadata_ptr_value,
swift_ast_ctx));
if (!promise_sp)
return false;
error_descriptor.m_bridgeable_native.metadata_location += 4 * ptr_size;
if (!promise_sp->IsStaticallyDetermined()) {
// figure out the actual dynamic type via the metadata at the "isa"
// pointer
error_descriptor.m_bridgeable_native.metadata_location =
m_process->ReadPointerFromMemory(
error_descriptor.m_bridgeable_native.metadata_location, error);
if (error_descriptor.m_bridgeable_native.metadata_location == 0 ||
error_descriptor.m_bridgeable_native.metadata_location ==
LLDB_INVALID_ADDRESS ||
error.Fail())
return false;
error_descriptor.m_bridgeable_native.metadata_ptr_value =
m_process->ReadPointerFromMemory(
error_descriptor.m_bridgeable_native.metadata_location, error);
if (error_descriptor.m_bridgeable_native.metadata_ptr_value == 0 ||
error_descriptor.m_bridgeable_native.metadata_ptr_value ==
LLDB_INVALID_ADDRESS ||
error.Fail())
return false;
promise_sp = GetMetadataPromise(
error_descriptor.m_bridgeable_native.metadata_ptr_value,
swift_ast_ctx);
if (!promise_sp || !promise_sp->FulfillTypePromise()) {
// this could still be a random ObjC object
if (auto objc_runtime = GetObjCRuntime()) {
DataExtractor extractor(
&error_descriptor.m_bridgeable_native.metadata_location,
sizeof(error_descriptor.m_bridgeable_native.metadata_location),
GetProcess()->GetByteOrder(), GetProcess()->GetAddressByteSize());
ExecutionContext exe_ctx(GetProcess());
auto scratch_ast =
GetProcess()->GetTarget().GetScratchClangASTContext();
if (scratch_ast) {
auto valobj_sp = ValueObject::CreateValueObjectFromData(
in_value.GetName().AsCString(), extractor, exe_ctx,
scratch_ast->GetBasicType(eBasicTypeObjCID));
if (valobj_sp) {
Value::ValueType value_type;
if (objc_runtime->GetDynamicTypeAndAddress(
*valobj_sp, use_dynamic, class_type_or_name, address,
value_type)) {
address.SetLoadAddress(
error_descriptor.m_bridgeable_native.metadata_location,
&GetProcess()->GetTarget());
if (!class_type_or_name.GetCompilerType().IsPointerType()) {
// the language runtimes do not return pointer-to-types when
// doing dynamic type resolution
// what usually happens is that the static type has
// pointer-like traits that ValueObjectDynamic
// then preserves in the dynamic value - since the static type
// here is a Swift protocol object
// the dynamic type won't know to pointerize. But we truly
// need an ObjCObjectPointer here or else
// type printing WILL be confused. Hence, make the pointer
// type ourselves if we didn't get one already
class_type_or_name.SetCompilerType(
class_type_or_name.GetCompilerType().GetPointerType());
}
return true;
}
}
}
}
return false;
}
}
if (!promise_sp)
return false;
address.SetLoadAddress(
error_descriptor.m_bridgeable_native.metadata_location,
&m_process->GetTarget());
CompilerType metadata_type(promise_sp->FulfillTypePromise());
if (metadata_type.IsValid() && error.Success()) {
class_type_or_name.SetCompilerType(metadata_type);
return true;
}
} break;
case SwiftErrorDescriptor::Kind::eBridged: {
if (error_descriptor.m_bridged.instance_ptr_value != 0 &&
error_descriptor.m_bridged.instance_ptr_value != LLDB_INVALID_ADDRESS) {
Status error_type_lookup_error;
if (CompilerType error_type =
swift_ast_ctx->GetNSErrorType(error_type_lookup_error)) {
class_type_or_name.SetCompilerType(error_type);
address.SetRawAddress(error_descriptor.m_bridged.instance_ptr_value);
return true;
}
}
} break;
case SwiftErrorDescriptor::Kind::eSwiftPureNative: {
Status error;
if (MetadataPromiseSP promise_sp = GetMetadataPromise(
error_descriptor.m_pure_native.metadata_location, swift_ast_ctx)) {
if (promise_sp->IsStaticallyDetermined()) {
if (CompilerType compiler_type = promise_sp->FulfillTypePromise()) {
class_type_or_name.SetCompilerType(compiler_type);
address.SetRawAddress(error_descriptor.m_pure_native.payload_ptr);
return true;
}
} else {
error_descriptor.m_pure_native.metadata_location =
m_process->ReadPointerFromMemory(
error_descriptor.m_pure_native.payload_ptr, error);
if (error_descriptor.m_pure_native.metadata_location == 0 ||
error_descriptor.m_pure_native.metadata_location ==
LLDB_INVALID_ADDRESS ||
error.Fail())
return false;
error_descriptor.m_pure_native.payload_ptr =
error_descriptor.m_pure_native.metadata_location;
error_descriptor.m_pure_native.metadata_location =
m_process->ReadPointerFromMemory(
error_descriptor.m_pure_native.payload_ptr, error);
if (MetadataPromiseSP promise_sp = GetMetadataPromise(
error_descriptor.m_pure_native.metadata_location,
swift_ast_ctx)) {
if (CompilerType compiler_type = promise_sp->FulfillTypePromise()) {
class_type_or_name.SetCompilerType(compiler_type);
address.SetRawAddress(error_descriptor.m_pure_native.payload_ptr);
return true;
}
}
}
}
} break;
}
return false;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Protocol(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
CompilerType var_type(in_value.GetCompilerType());
SwiftASTContext::ProtocolInfo protocol_info;
if (!SwiftASTContext::GetProtocolTypeInfo(var_type, protocol_info))
return false;
if (protocol_info.m_is_errortype)
return GetDynamicTypeAndAddress_ErrorType(in_value, use_dynamic,
class_type_or_name, address);
MetadataPromiseSP promise_sp;
static ConstString g_instance_type_child_name("instance_type");
ValueObjectSP instance_type_sp(
in_value.GetStaticValue()->GetChildMemberWithName(
g_instance_type_child_name, true));
if (!instance_type_sp)
return false;
ValueObjectSP payload0_sp(
in_value.GetStaticValue()->GetChildAtIndex(0, true));
if (!payload0_sp)
return false;
// @objc protocols are automatically class-only, and there is no
// static/dynamic to deal with
bool is_class = protocol_info.m_is_objc || protocol_info.m_is_class_only ||
protocol_info.m_is_anyobject;
if (!is_class) {
promise_sp = GetMetadataPromise(instance_type_sp->GetValueAsUnsigned(0));
if (!promise_sp)
return false;
if (promise_sp->FulfillKindPromise().hasValue() &&
promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Class)
is_class = true;
}
if (is_class) {
if (GetDynamicTypeAndAddress_Class(*payload0_sp, use_dynamic,
class_type_or_name, address))
return true;
// only for @objc protocols, try to fallback to the ObjC runtime as a source
// of type information
// this is not exactly a great solution and we need to be careful with how
// we use the results of this
// computation, but assuming some care, at least data formatters will work
if (!protocol_info.m_is_objc)
return false;
auto objc_runtime = GetObjCRuntime();
if (!objc_runtime)
return false;
auto descriptor_sp = objc_runtime->GetClassDescriptor(*payload0_sp);
if (!descriptor_sp)
return false;
std::vector<clang::NamedDecl *> decls;
DeclVendor *vendor = objc_runtime->GetDeclVendor();
if (!vendor)
return false;
vendor->FindDecls(descriptor_sp->GetClassName(), true, 1, decls);
if (decls.size() == 0)
return false;
CompilerType type = ClangASTContext::GetTypeForDecl(decls[0]);
if (!type.IsValid())
return false;
lldb::addr_t class_metadata_ptr = payload0_sp->GetAddressOf();
if (class_metadata_ptr == LLDB_INVALID_ADDRESS || class_metadata_ptr == 0)
return false;
address.SetRawAddress(class_metadata_ptr);
class_type_or_name.SetCompilerType(type.GetPointerType());
return class_type_or_name.GetCompilerType().IsValid();
}
if (promise_sp->FulfillKindPromise().hasValue() &&
(promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Struct ||
promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Enum ||
promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Tuple)) {
Status error;
class_type_or_name.SetCompilerType(promise_sp->FulfillTypePromise());
if (error.Fail())
return false;
// the choices made here affect dynamic type resolution
// for an inline protocol object, e.g.:
// (P) $R1 = {
// (Builtin.RawPointer) payload_data_0 = 0x0000000000000001
// (Builtin.RawPointer) payload_data_1 = 0x0000000000000002
// (Builtin.RawPointer) payload_data_2 = 0x0000000000000000
// (Builtin.RawPointer) instance_type = 0x000000010054c2f8
// (Builtin.RawPointer) protocol_witness_0 = 0x000000010054c100
// }
// pick &payload_data_0
// for a pointed-to protocol object, e.g.:
// (Q) $R2 = {
// (Builtin.RawPointer) payload_data_0 = 0x00000001006079b0
// (Builtin.RawPointer) payload_data_1 = 0x0000000000000000
// (Builtin.RawPointer) payload_data_2 = 0x0000000000000000
// (Builtin.RawPointer) instance_type = 0x000000010054c648
// (Builtin.RawPointer) protocol_witness_0 = 0x000000010054c7b0
// }
// pick the value of payload_data_0
switch (SwiftASTContext::GetAllocationStrategy(
class_type_or_name.GetCompilerType())) {
case SwiftASTContext::TypeAllocationStrategy::eInline:
// FIXME: we should not have to do this - but we are getting confused
// w.r.t.
// frozen-dried vs. live versions of objects, so hack around it for now
if (in_value.GetValue().GetValueAddressType() == eAddressTypeHost)
address.SetRawAddress(in_value.GetValue().GetScalar().ULongLong());
else
address.SetRawAddress(in_value.GetAddressOf());
return true;
case SwiftASTContext::TypeAllocationStrategy::ePointer:
address.SetRawAddress(payload0_sp->GetValueAsUnsigned(0));
return true;
default:
// TODO we don't know how to deal with the dynamic case quite yet
return false;
}
}
return false;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Promise(
ValueObject &in_value, MetadataPromiseSP promise_sp,
lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name,
Address &address) {
if (!promise_sp)
return false;
CompilerType var_type(in_value.GetCompilerType());
Status error;
if (!promise_sp->FulfillKindPromise())
return false;
switch (promise_sp->FulfillKindPromise().getValue()) {
case swift::MetadataKind::Class: {
CompilerType dyn_type(promise_sp->FulfillTypePromise());
if (!dyn_type.IsValid())
return false;
class_type_or_name.SetCompilerType(dyn_type);
lldb::addr_t val_ptr_addr = in_value.GetPointerValue();
val_ptr_addr = GetProcess()->ReadPointerFromMemory(val_ptr_addr, error);
address.SetLoadAddress(val_ptr_addr, &m_process->GetTarget());
return true;
} break;
case swift::MetadataKind::Struct:
case swift::MetadataKind::Tuple: {
CompilerType dyn_type(promise_sp->FulfillTypePromise());
if (!dyn_type.IsValid())
return false;
class_type_or_name.SetCompilerType(dyn_type);
lldb::addr_t val_ptr_addr = in_value.GetPointerValue();
address.SetLoadAddress(val_ptr_addr, &m_process->GetTarget());
return true;
} break;
case swift::MetadataKind::Enum: {
CompilerType dyn_type(promise_sp->FulfillTypePromise());
if (!dyn_type.IsValid())
return false;
class_type_or_name.SetCompilerType(dyn_type);
lldb::addr_t val_ptr_addr = in_value.GetPointerValue();
{
auto swift_type = GetSwiftType(dyn_type);
if (swift_type->getOptionalObjectType())
val_ptr_addr = GetProcess()->ReadPointerFromMemory(val_ptr_addr, error);
}
address.SetLoadAddress(val_ptr_addr, &m_process->GetTarget());
return true;
} break;
case swift::MetadataKind::Existential: {
SwiftASTContext *swift_ast_ctx =
llvm::dyn_cast_or_null<SwiftASTContext>(var_type.GetTypeSystem());
CompilerType protocol_type(promise_sp->FulfillTypePromise());
if (swift_ast_ctx->IsErrorType(protocol_type)) {
if (swift_ast_ctx) {
Status error;
// the offset
size_t ptr_size = m_process->GetAddressByteSize();
size_t metadata_offset = ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
metadata_offset += ptr_size + ptr_size + ptr_size;
lldb::addr_t archetype_ptr_value = in_value.GetValueAsUnsigned(0);
lldb::addr_t base_errortype_ptr =
m_process->ReadPointerFromMemory(archetype_ptr_value, error);
lldb::addr_t static_metadata_ptrptr =
base_errortype_ptr + metadata_offset;
lldb::addr_t static_metadata_ptr =
m_process->ReadPointerFromMemory(static_metadata_ptrptr, error);
MetadataPromiseSP promise_sp(
GetMetadataPromise(static_metadata_ptr, swift_ast_ctx));
if (promise_sp) {
lldb::addr_t load_addr = static_metadata_ptrptr + 2 * ptr_size;
if (promise_sp->FulfillKindPromise() &&
promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Class) {
load_addr = m_process->ReadPointerFromMemory(load_addr, error);
lldb::addr_t dynamic_metadata_location =
m_process->ReadPointerFromMemory(load_addr, error);
promise_sp =
GetMetadataPromise(dynamic_metadata_location, swift_ast_ctx);
}
CompilerType clang_type(promise_sp->FulfillTypePromise());
if (clang_type.IsValid() && load_addr != 0 &&
load_addr != LLDB_INVALID_ADDRESS) {
class_type_or_name.SetCompilerType(clang_type);
address.SetLoadAddress(load_addr, &m_process->GetTarget());
return true;
}
}
}
} else {
Status error;
lldb::addr_t ptr_to_instance_type = in_value.GetValueAsUnsigned(0) +
(3 * m_process->GetAddressByteSize());
lldb::addr_t metadata_of_impl_addr =
m_process->ReadPointerFromMemory(ptr_to_instance_type, error);
if (error.Fail() || metadata_of_impl_addr == 0 ||
metadata_of_impl_addr == LLDB_INVALID_ADDRESS)
return false;
MetadataPromiseSP promise_of_impl_sp(
GetMetadataPromise(metadata_of_impl_addr, swift_ast_ctx));
if (GetDynamicTypeAndAddress_Promise(in_value, promise_of_impl_sp,
use_dynamic, class_type_or_name,
address)) {
lldb::addr_t load_addr = in_value.GetValueAsUnsigned(0);
if (promise_of_impl_sp->FulfillKindPromise() &&
promise_of_impl_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Class) {
load_addr = m_process->ReadPointerFromMemory(load_addr, error);
if (error.Fail() || load_addr == 0 ||
load_addr == LLDB_INVALID_ADDRESS)
return false;
} else if (promise_of_impl_sp->FulfillKindPromise() &&
(promise_of_impl_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Enum ||
promise_of_impl_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Struct)) {
} else
lldbassert(false && "class, enum and struct are the only protocol "
"implementor types I know about");
address.SetLoadAddress(load_addr, &m_process->GetTarget());
return true;
}
}
} break;
default:
break;
}
return false;
}
SwiftLanguageRuntime::MetadataPromiseSP
SwiftLanguageRuntime::GetPromiseForTypeNameAndFrame(const char *type_name,
StackFrame *frame) {
if (!frame || !type_name || !type_name[0])
return nullptr;
SwiftASTContext *swift_ast_ctx = nullptr;
const SymbolContext &sc(frame->GetSymbolContext(eSymbolContextFunction));
if (sc.function)
swift_ast_ctx = llvm::dyn_cast_or_null<SwiftASTContext>(
sc.function->GetCompilerType().GetTypeSystem());
StreamString type_metadata_ptr_var_name;
type_metadata_ptr_var_name.Printf("$swift.type.%s", type_name);
VariableList *var_list = frame->GetVariableList(false);
if (!var_list)
return nullptr;
VariableSP var_sp(var_list->FindVariable(
ConstString(type_metadata_ptr_var_name.GetData())));
if (!var_sp)
return nullptr;
ValueObjectSP metadata_ptr_var_sp(
frame->GetValueObjectForFrameVariable(var_sp, lldb::eNoDynamicValues));
if (!metadata_ptr_var_sp ||
metadata_ptr_var_sp->UpdateValueIfNeeded() == false)
return nullptr;
lldb::addr_t metadata_location(metadata_ptr_var_sp->GetValueAsUnsigned(0));
if (metadata_location == 0 || metadata_location == LLDB_INVALID_ADDRESS)
return nullptr;
return GetMetadataPromise(metadata_location, swift_ast_ctx);
}
CompilerType
SwiftLanguageRuntime::DoArchetypeBindingForType(StackFrame &stack_frame,
CompilerType base_type) {
SwiftASTContext *ast_context =
llvm::dyn_cast_or_null<SwiftASTContext>(base_type.GetTypeSystem());
lldbassert(ast_context && "null AST Context");
if (!ast_context)
return base_type;
if (base_type.GetTypeInfo() & lldb::eTypeIsSwift) {
swift::Type target_swift_type(GetSwiftType(base_type));
target_swift_type = target_swift_type.transform(
[this, &stack_frame,
ast_context](swift::Type candidate_type) -> swift::Type {
if (swift::ArchetypeType *candidate_archetype =
llvm::dyn_cast_or_null<swift::ArchetypeType>(
candidate_type.getPointer())) {
ConstString candidate_name(candidate_archetype->getFullName());
CompilerType concrete_type = this->GetConcreteType(
&stack_frame, candidate_name);
Status import_error;
CompilerType target_concrete_type =
ast_context->ImportType(concrete_type, import_error);
if (target_concrete_type.IsValid())
return swift::Type(GetSwiftType(target_concrete_type));
else
return candidate_type;
} else
return candidate_type;
});
return CompilerType(ast_context->GetASTContext(),
target_swift_type.getPointer());
}
return base_type;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Archetype(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
const char *type_name(in_value.GetTypeName().GetCString());
StackFrame *frame(in_value.GetFrameSP().get());
MetadataPromiseSP promise_sp(GetPromiseForTypeNameAndFrame(type_name, frame));
if (!promise_sp)
return false;
if (!GetDynamicTypeAndAddress_Promise(in_value, promise_sp, use_dynamic,
class_type_or_name, address))
return false;
if (promise_sp->FulfillKindPromise() &&
promise_sp->FulfillKindPromise().getValue() ==
swift::MetadataKind::Class) {
// when an archetype represents a class, it will represent the static type
// of the class
// but the dynamic type might be different
Status error;
lldb::addr_t addr_of_meta = address.GetLoadAddress(&m_process->GetTarget());
addr_of_meta = m_process->ReadPointerFromMemory(addr_of_meta, error);
if (addr_of_meta == LLDB_INVALID_ADDRESS || addr_of_meta == 0 ||
error.Fail())
return true; // my gut says we should fail here, but we seemed to be on a
// good track before..
MetadataPromiseSP actual_type_promise(GetMetadataPromise(addr_of_meta));
if (actual_type_promise && actual_type_promise.get() != promise_sp.get()) {
CompilerType static_type(class_type_or_name.GetCompilerType());
class_type_or_name.SetCompilerType(
actual_type_promise->FulfillTypePromise());
if (error.Fail() ||
class_type_or_name.GetCompilerType().IsValid() == false)
class_type_or_name.SetCompilerType(static_type);
}
}
return true;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Tuple(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
std::vector<CompilerType> dyn_types;
for (size_t idx = 0; idx < in_value.GetNumChildren(); idx++) {
ValueObjectSP child_sp(in_value.GetChildAtIndex(idx, true));
TypeAndOrName type_and_or_name;
Address address;
Value::ValueType value_type;
if (GetDynamicTypeAndAddress(*child_sp.get(), use_dynamic, type_and_or_name,
address, value_type) == false)
dyn_types.push_back(child_sp->GetCompilerType());
else
dyn_types.push_back(type_and_or_name.GetCompilerType());
}
SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null<SwiftASTContext>(
in_value.GetCompilerType().GetTypeSystem());
CompilerType dyn_tuple_type(swift_ast_ctx->CreateTupleType(dyn_types));
class_type_or_name.SetCompilerType(dyn_tuple_type);
lldb::addr_t tuple_address = in_value.GetPointerValue();
Status error;
tuple_address = m_process->ReadPointerFromMemory(tuple_address, error);
if (error.Fail() || tuple_address == 0 ||
tuple_address == LLDB_INVALID_ADDRESS)
return false;
address.SetLoadAddress(tuple_address, in_value.GetTargetSP().get());
return true;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Struct(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
// struct can't inherit from each other, but they can be generic, in which
// case
// we need to turn MyStruct<U> into MyStruct<$swift.type.U>
std::vector<CompilerType> generic_args;
lldb_private::StackFrame *frame =
in_value.GetExecutionContextRef().GetFrameSP().get();
if (!frame)
return false;
// this will be a BoundGenericStruct, bound to archetypes
CompilerType struct_type(in_value.GetCompilerType());
CompilerType resolved_type(DoArchetypeBindingForType(*frame, struct_type));
if (!resolved_type)
return false;
class_type_or_name.SetCompilerType(resolved_type);
lldb::addr_t struct_address = in_value.GetPointerValue();
if (0 == struct_address || LLDB_INVALID_ADDRESS == struct_address)
struct_address = in_value.GetAddressOf(true, nullptr);
if (0 == struct_address || LLDB_INVALID_ADDRESS == struct_address) {
if (false == SwiftASTContext::IsPossibleZeroSizeType(
class_type_or_name.GetCompilerType()))
return false;
}
address.SetLoadAddress(struct_address, in_value.GetTargetSP().get());
return true;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Enum(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
// enums can't inherit from each other, but they can be generic, in which case
// we need to turn MyEnum<U> into MyEnum<$swift.type.U>
std::vector<CompilerType> generic_args;
lldb_private::StackFrame *frame =
in_value.GetExecutionContextRef().GetFrameSP().get();
if (!frame)
return false;
// this will be a BoundGenericEnum, bound to archetypes
CompilerType enum_type(in_value.GetCompilerType());
CompilerType resolved_type(DoArchetypeBindingForType(*frame, enum_type));
if (!resolved_type)
return false;
class_type_or_name.SetCompilerType(resolved_type);
lldb::addr_t enum_address = in_value.GetPointerValue();
if (0 == enum_address || LLDB_INVALID_ADDRESS == enum_address)
enum_address = in_value.GetAddressOf(true, nullptr);
if (0 == enum_address || LLDB_INVALID_ADDRESS == enum_address) {
if (false == SwiftASTContext::IsPossibleZeroSizeType(
class_type_or_name.GetCompilerType()))
return false;
}
address.SetLoadAddress(enum_address, in_value.GetTargetSP().get());
return true;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_IndirectEnumCase(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address) {
static ConstString g_offset("offset");
DataExtractor data;
Status error;
if (in_value.GetParent() && in_value.GetParent()->GetData(data, error) &&
error.Success()) {
bool has_payload;
bool is_indirect;
CompilerType payload_type;
if (SwiftASTContext::GetSelectedEnumCase(
in_value.GetParent()->GetCompilerType(), data, nullptr,
&has_payload, &payload_type, &is_indirect)) {
if (has_payload && is_indirect && payload_type)
class_type_or_name.SetCompilerType(payload_type);
lldb::addr_t box_addr = in_value.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (box_addr != LLDB_INVALID_ADDRESS) {
box_addr = MaskMaybeBridgedPointer(box_addr);
lldb::addr_t box_location =
m_process->ReadPointerFromMemory(box_addr, error);
if (box_location != LLDB_INVALID_ADDRESS) {
box_location = MaskMaybeBridgedPointer(box_location);
ProcessStructReader reader(m_process, box_location,
GetBoxMetadataType());
uint32_t offset = reader.GetField<uint32_t>(g_offset);
lldb::addr_t box_value = box_addr + offset;
// try to read one byte at the box value
m_process->ReadUnsignedIntegerFromMemory(box_value, 1, 0, error);
if (error
.Fail()) // and if that fails, then we're off in no man's land
return false;
Flags type_info(payload_type.GetTypeInfo());
if (type_info.AllSet(eTypeIsSwift | eTypeIsClass)) {
lldb::addr_t old_box_value = box_value;
box_value = m_process->ReadPointerFromMemory(box_value, error);
if (box_value != LLDB_INVALID_ADDRESS) {
DataExtractor data(&box_value, m_process->GetAddressByteSize(),
m_process->GetByteOrder(),
m_process->GetAddressByteSize());
ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromData(
"_", data, *m_process, payload_type));
if (valobj_sp) {
Value::ValueType value_type;
if (GetDynamicTypeAndAddress(*valobj_sp, use_dynamic,
class_type_or_name, address,
value_type)) {
address.SetRawAddress(old_box_value);
return true;
}
}
}
} else if (type_info.AllSet(eTypeIsSwift | eTypeIsProtocol)) {
SwiftASTContext::ProtocolInfo protocol_info;
if (SwiftASTContext::GetProtocolTypeInfo(payload_type,
protocol_info)) {
auto ptr_size = m_process->GetAddressByteSize();
std::vector<uint8_t> buffer(
ptr_size * protocol_info.m_num_storage_words, 0);
for (uint32_t idx = 0; idx < protocol_info.m_num_storage_words;
idx++) {
lldb::addr_t word = m_process->ReadUnsignedIntegerFromMemory(
box_value + idx * ptr_size, ptr_size, 0, error);
if (error.Fail())
return false;
memcpy(&buffer[idx * ptr_size], &word, ptr_size);
}
DataExtractor data(&buffer[0], buffer.size(),
m_process->GetByteOrder(),
m_process->GetAddressByteSize());
ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromData(
"_", data, *m_process, payload_type));
if (valobj_sp) {
Value::ValueType value_type;
if (GetDynamicTypeAndAddress(*valobj_sp, use_dynamic,
class_type_or_name, address,
value_type)) {
address.SetRawAddress(box_value);
return true;
}
}
}
} else {
// this is most likely a statically known type
address.SetLoadAddress(box_value, &m_process->GetTarget());
return true;
}
}
}
}
}
return false;
}
// Dynamic type resolution tends to want to generate scalar data - but there are
// caveats
// Per original comment here
// "Our address is the location of the dynamic type stored in memory. It isn't
// a load address,
// because we aren't pointing to the LOCATION that stores the pointer to us,
// we're pointing to us..."
// See inlined comments for exceptions to this general rule.
Value::ValueType SwiftLanguageRuntime::GetValueType(
Value::ValueType static_value_type, const CompilerType &static_type,
const CompilerType &dynamic_type, bool is_indirect_enum_case) {
Flags static_type_flags(static_type.GetTypeInfo());
Flags dynamic_type_flags(dynamic_type.GetTypeInfo());
if (dynamic_type_flags.AllSet(eTypeIsSwift)) {
// for a protocol object where does the dynamic data live if the target
// object is a struct? (for a class, it's easy)
if (static_type_flags.AllSet(eTypeIsSwift | eTypeIsProtocol) &&
dynamic_type_flags.AnySet(eTypeIsStructUnion | eTypeIsEnumeration)) {
SwiftASTContext *swift_ast_ctx =
llvm::dyn_cast_or_null<SwiftASTContext>(static_type.GetTypeSystem());
if (swift_ast_ctx && swift_ast_ctx->IsErrorType(static_type)) {
// ErrorType values are always a pointer
return Value::eValueTypeLoadAddress;
}
switch (SwiftASTContext::GetAllocationStrategy(dynamic_type)) {
case SwiftASTContext::TypeAllocationStrategy::eDynamic:
case SwiftASTContext::TypeAllocationStrategy::eUnknown:
break;
case SwiftASTContext::TypeAllocationStrategy::eInline: // inline data;
// same as the
// static data
return static_value_type;
case SwiftASTContext::TypeAllocationStrategy::ePointer: // pointed-to; in
// the target
return Value::eValueTypeLoadAddress;
}
}
if (static_type_flags.AllSet(eTypeIsSwift | eTypeIsArchetype)) {
// if I am handling a non-pointer Swift type obtained from an archetype,
// then the runtime vends the location
// of the object, not the object per se (since the object is not a pointer
// itself, this is way easier to achieve)
// hence, it's a load address, not a scalar containing a pointer as for
// ObjC classes
if (dynamic_type_flags.AllClear(eTypeIsPointer | eTypeIsReference |
eTypeInstanceIsPointer))
return Value::eValueTypeLoadAddress;
}
if (static_type_flags.AllSet(eTypeIsSwift | eTypeIsPointer) &&
static_type_flags.AllClear(eTypeIsArchetype)) {
if (is_indirect_enum_case || static_type_flags.AllClear(eTypeIsBuiltIn))
return Value::eValueTypeLoadAddress;
}
}
if (static_type_flags.AllSet(eTypeIsSwift) &&
dynamic_type_flags.AllSet(eTypeIsSwift) &&
dynamic_type_flags.AllClear(eTypeIsPointer | eTypeInstanceIsPointer))
return static_value_type;
else
return Value::eValueTypeScalar;
}
static bool IsIndirectEnumCase(ValueObject &valobj) {
return (valobj.GetLanguageFlags() &
SwiftASTContext::LanguageFlags::eIsIndirectEnumCase) ==
SwiftASTContext::LanguageFlags::eIsIndirectEnumCase;
}
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
class_type_or_name.Clear();
if (SwiftASTContext *swift_ast = llvm::dyn_cast_or_null<SwiftASTContext>(
in_value.GetCompilerType().GetTypeSystem())) {
if (swift_ast->HasFatalErrors() || !swift_ast->GetClangImporter()) {
return false;
}
} else {
return false;
}
if (use_dynamic == lldb::eNoDynamicValues || !CouldHaveDynamicValue(in_value))
return false;
bool success = false;
const bool is_indirect_enum_case = IsIndirectEnumCase(in_value);
if (is_indirect_enum_case)
success = GetDynamicTypeAndAddress_IndirectEnumCase(
in_value, use_dynamic, class_type_or_name, address);
else {
CompilerType var_type(in_value.GetCompilerType());
Flags type_info(var_type.GetTypeInfo());
if (type_info.AnySet(eTypeIsSwift)) {
if (type_info.AnySet(eTypeIsClass))
success = GetDynamicTypeAndAddress_Class(in_value, use_dynamic,
class_type_or_name, address);
else if (type_info.AnySet(eTypeIsEnumeration))
success = GetDynamicTypeAndAddress_Enum(in_value, use_dynamic,
class_type_or_name, address);
else if (type_info.AnySet(eTypeIsProtocol))
success = GetDynamicTypeAndAddress_Protocol(
in_value, use_dynamic, class_type_or_name, address);
else if (type_info.AnySet(eTypeIsArchetype))
success = GetDynamicTypeAndAddress_Archetype(
in_value, use_dynamic, class_type_or_name, address);
else if (type_info.AnySet(eTypeIsTuple))
success = GetDynamicTypeAndAddress_Tuple(in_value, use_dynamic,
class_type_or_name, address);
else if (type_info.AnySet(eTypeIsStructUnion))
success = GetDynamicTypeAndAddress_Struct(in_value, use_dynamic,
class_type_or_name, address);
else if (type_info.AllSet(eTypeIsBuiltIn | eTypeIsPointer |
eTypeHasValue))
success = GetDynamicTypeAndAddress_Class(in_value, use_dynamic,
class_type_or_name, address);
}
}
if (success) {
value_type = GetValueType(
in_value.GetValue().GetValueType(), in_value.GetCompilerType(),
class_type_or_name.GetCompilerType(), is_indirect_enum_case);
}
return success;
}
TypeAndOrName
SwiftLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) {
TypeAndOrName ret(type_and_or_name);
bool should_be_made_into_ref = false;
bool should_be_made_into_ptr = false;
Flags type_flags(static_value.GetCompilerType().GetTypeInfo());
Flags type_andor_name_flags(type_and_or_name.GetCompilerType().GetTypeInfo());
// if the static type is a pointer or reference, so should the dynamic type
// caveat: if the static type is a Swift class instance, the dynamic type
// could either be a Swift type (no need to change anything), or an ObjC type
// in which case it needs to be made into a pointer
if (type_flags.AnySet(eTypeIsPointer))
should_be_made_into_ptr =
(type_flags.AllClear(eTypeIsArchetype | eTypeIsBuiltIn) &&
!IsIndirectEnumCase(static_value));
else if (type_flags.AnySet(eTypeInstanceIsPointer))
should_be_made_into_ptr = !type_andor_name_flags.AllSet(eTypeIsSwift);
else if (type_flags.AnySet(eTypeIsReference))
should_be_made_into_ref = true;
else if (type_flags.AllSet(eTypeIsSwift | eTypeIsProtocol))
should_be_made_into_ptr =
type_and_or_name.GetCompilerType().IsRuntimeGeneratedType() &&
!type_and_or_name.GetCompilerType().IsPointerType();
if (type_and_or_name.HasType()) {
// The type will always be the type of the dynamic object. If our parent's
// type was a pointer,
// then our type should be a pointer to the type of the dynamic object. If
// a reference, then the original type
// should be okay...
CompilerType orig_type = type_and_or_name.GetCompilerType();
CompilerType corrected_type = orig_type;
if (should_be_made_into_ptr)
corrected_type = orig_type.GetPointerType();
else if (should_be_made_into_ref)
corrected_type = orig_type.GetLValueReferenceType();
ret.SetCompilerType(corrected_type);
} else /*if (m_dynamic_type_info.HasName())*/
{
// If we are here we need to adjust our dynamic type name to include the
// correct & or * symbol
std::string corrected_name(type_and_or_name.GetName().GetCString());
if (should_be_made_into_ptr)
corrected_name.append(" *");
else if (should_be_made_into_ref)
corrected_name.append(" &");
// the parent type should be a correctly pointer'ed or referenc'ed type
ret.SetCompilerType(static_value.GetCompilerType());
ret.SetName(corrected_name.c_str());
}
return ret;
}
bool SwiftLanguageRuntime::IsRuntimeSupportValue(ValueObject &valobj) {
static llvm::StringRef g_dollar_swift_type("$swift.type.");
ConstString valobj_name(valobj.GetName());
llvm::StringRef valobj_name_sr(valobj_name.GetStringRef());
if (valobj_name_sr.startswith(g_dollar_swift_type))
return true;
static llvm::StringRef g_globalinit("globalinit_");
static ConstString g_builtin_word("Builtin.Word");
static ConstString g__argc("_argc");
static ConstString g__unsafeArgv("_unsafeArgv");
static ConstString g_dollar_error("$error");
static ConstString g_tmp_closure("$tmpClosure");
ConstString valobj_type_name(valobj.GetTypeName());
if (valobj_name_sr.startswith(g_globalinit) &&
valobj_type_name == g_builtin_word)
return true;
if (valobj_name == g__argc || valobj_name == g__unsafeArgv ||
valobj_name == g_dollar_error || valobj_name == g_tmp_closure)
return true;
return false;
}
bool SwiftLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
// if (in_value.IsDynamic())
// return false;
if (IsIndirectEnumCase(in_value))
return true;
CompilerType var_type(in_value.GetCompilerType());
Flags var_type_flags(var_type.GetTypeInfo());
if (var_type_flags.AllSet(eTypeIsSwift | eTypeInstanceIsPointer)) {
// Swift class instances are actually pointers, but base class instances
// are inlined at offset 0 in the class data. If we just let base classes
// be dynamic, it would cause an infinite recursion. So we would usually
// disable it
// But if the base class is a generic type we still need to bind it, and
// that is
// a good job for dynamic types to perform
if (in_value.IsBaseClass()) {
CompilerType base_type(in_value.GetCompilerType());
if (SwiftASTContext::IsFullyRealized(base_type))
return false;
}
return true;
}
return var_type.IsPossibleDynamicType(nullptr, false, false, true);
}
CompilerType
SwiftLanguageRuntime::GetConcreteType(ExecutionContextScope *exe_scope,
ConstString abstract_type_name) {
if (!exe_scope)
return CompilerType();
StackFrame *frame(exe_scope->CalculateStackFrame().get());
if (!frame)
return CompilerType();
MetadataPromiseSP promise_sp(
GetPromiseForTypeNameAndFrame(abstract_type_name.GetCString(), frame));
if (!promise_sp)
return CompilerType();
return promise_sp->FulfillTypePromise();
}
namespace {
enum class ThunkKind
{
Unknown = 0,
AllocatingInit,
PartialApply,
ObjCAttribute,
Reabstraction,
ProtocolConformance,
};
enum class ThunkAction
{
Unknown = 0,
GetThunkTarget,
StepIntoConformance,
StepThrough
};
}
static ThunkKind
GetThunkKind(llvm::StringRef symbol_name)
{
swift::Demangle::Node::Kind kind;
swift::Demangle::Context demangle_ctx;
if (!demangle_ctx.isThunkSymbol(symbol_name))
return ThunkKind::Unknown;
swift::Demangle::NodePointer nodes = demangle_ctx.demangleSymbolAsNode(symbol_name);
size_t num_global_children = nodes->getNumChildren();
if (num_global_children == 0)
return ThunkKind::Unknown;
if (nodes->getKind() != swift::Demangle::Node::Kind::Global)
return ThunkKind::Unknown;
if (nodes->getNumChildren() == 0)
return ThunkKind::Unknown;
swift::Demangle::NodePointer node_ptr = nodes->getFirstChild();
kind = node_ptr->getKind();
switch (kind)
{
case swift::Demangle::Node::Kind::ObjCAttribute:
return ThunkKind::ObjCAttribute;
break;
case swift::Demangle::Node::Kind::ProtocolWitness:
if (node_ptr->getNumChildren() == 0)
return ThunkKind::Unknown;
if (node_ptr->getFirstChild()->getKind()
== swift::Demangle::Node::Kind::ProtocolConformance)
return ThunkKind::ProtocolConformance;
break;
case swift::Demangle::Node::Kind::ReabstractionThunkHelper:
return ThunkKind::Reabstraction;
case swift::Demangle::Node::Kind::PartialApplyForwarder:
return ThunkKind::PartialApply;
case swift::Demangle::Node::Kind::Allocator:
if (node_ptr->getNumChildren() == 0)
return ThunkKind::Unknown;
if (node_ptr->getFirstChild()->getKind()
== swift::Demangle::Node::Kind::Class)
return ThunkKind::AllocatingInit;
break;
default:
break;
}
return ThunkKind::Unknown;
}
static const char *GetThunkKindName (ThunkKind kind)
{
switch (kind)
{
case ThunkKind::Unknown:
return "Unknown";
case ThunkKind::AllocatingInit:
return "StepThrough";
case ThunkKind::PartialApply:
return "GetThunkTarget";
case ThunkKind::ObjCAttribute:
return "GetThunkTarget";
case ThunkKind::Reabstraction:
return "GetThunkTarget";
case ThunkKind::ProtocolConformance:
return "StepIntoConformance";
}
}
static ThunkAction
GetThunkAction (ThunkKind kind)
{
switch (kind)
{
case ThunkKind::Unknown:
return ThunkAction::Unknown;
case ThunkKind::AllocatingInit:
return ThunkAction::StepThrough;
case ThunkKind::PartialApply:
return ThunkAction::GetThunkTarget;
case ThunkKind::ObjCAttribute:
return ThunkAction::GetThunkTarget;
case ThunkKind::Reabstraction:
return ThunkAction::StepThrough;
case ThunkKind::ProtocolConformance:
return ThunkAction::StepIntoConformance;
}
}
bool SwiftLanguageRuntime::GetTargetOfPartialApply(SymbolContext &curr_sc,
ConstString &apply_name,
SymbolContext &sc) {
if (!curr_sc.module_sp)
return false;
SymbolContextList sc_list;
swift::Demangle::Context demangle_ctx;
// Make sure this is a partial apply:
std::string apply_target = demangle_ctx.getThunkTarget(apply_name.GetStringRef());
if (!apply_target.empty()) {
size_t num_symbols = curr_sc.module_sp->FindFunctions(
ConstString(apply_target), NULL, eFunctionNameTypeFull, true, false, false, sc_list);
if (num_symbols == 0)
return false;
CompileUnit *curr_cu = curr_sc.comp_unit;
size_t num_found = 0;
for (size_t i = 0; i < num_symbols; i++) {
SymbolContext tmp_sc;
if (sc_list.GetContextAtIndex(i, tmp_sc)) {
if (tmp_sc.comp_unit && curr_cu && tmp_sc.comp_unit == curr_cu) {
sc = tmp_sc;
num_found++;
} else if (curr_sc.module_sp == tmp_sc.module_sp) {
sc = tmp_sc;
num_found++;
}
}
}
if (num_found == 1)
return true;
else {
sc.Clear(false);
return false;
}
} else {
return false;
}
}
bool SwiftLanguageRuntime::IsSymbolARuntimeThunk(const Symbol &symbol) {
llvm::StringRef symbol_name = symbol.GetMangled().GetMangledName().GetStringRef();
if (symbol_name.empty())
return false;
swift::Demangle::Context demangle_ctx;
return demangle_ctx.isThunkSymbol(symbol_name);
}
lldb::ThreadPlanSP
SwiftLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
bool stop_others) {
// Here are the trampolines we have at present.
// 1) The thunks from protocol invocations to the call in the actual object
// implementing the protocol.
// 2) Thunks for going from Swift ObjC classes to their actual method
// invocations
// 3) Thunks that retain captured objects in closure invocations.
ThreadPlanSP new_thread_plan_sp;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0);
if (!stack_sp)
return new_thread_plan_sp;
SymbolContext sc = stack_sp->GetSymbolContext(eSymbolContextEverything);
Symbol *symbol = sc.symbol;
// Note, I don't really need to consult IsSymbolARuntimeThunk here, but it
// is fast to do and
// keeps this list and the one in IsSymbolARuntimeThunk in sync.
if (!symbol || !IsSymbolARuntimeThunk(*symbol))
return new_thread_plan_sp;
// Only do this if you are at the beginning of the thunk function:
lldb::addr_t cur_addr = thread.GetRegisterContext()->GetPC();
lldb::addr_t symbol_addr = symbol->GetAddress().GetLoadAddress(
&thread.GetProcess()->GetTarget());
if (symbol_addr != cur_addr)
return new_thread_plan_sp;
Address target_address;
ConstString symbol_mangled_name = symbol->GetMangled().GetMangledName();
const char *symbol_name = symbol_mangled_name.AsCString();
ThunkKind thunk_kind = GetThunkKind(symbol_mangled_name.GetStringRef());
ThunkAction thunk_action = GetThunkAction(thunk_kind);
switch (thunk_action)
{
case ThunkAction::Unknown:
return new_thread_plan_sp;
case ThunkAction::GetThunkTarget:
{
swift::Demangle::Context demangle_ctx;
std::string thunk_target = demangle_ctx.getThunkTarget(symbol_name);
if (thunk_target.empty())
{
if (log)
log->Printf("Stepped to thunk \"%s\" (kind: %s) but could not "
"find the thunk target. ",
symbol_name,
GetThunkKindName(thunk_kind));
return new_thread_plan_sp;
}
if (log)
log->Printf("Stepped to thunk \"%s\" (kind: %s) stepping to target: \"%s\".",
symbol_name, GetThunkKindName(thunk_kind), thunk_target.c_str());
ModuleList modules = thread.GetProcess()->GetTarget().GetImages();
SymbolContextList sc_list;
modules.FindFunctionSymbols(ConstString(thunk_target),
eFunctionNameTypeFull, sc_list);
if (sc_list.GetSize() == 1) {
SymbolContext sc;
sc_list.GetContextAtIndex(0, sc);
if (sc.symbol)
target_address = sc.symbol->GetAddress();
}
}
break;
case ThunkAction::StepIntoConformance:
{
// The TTW symbols encode the protocol conformance requirements and it
// is possible to go to
// the AST and get it to replay the logic that it used to determine
// what to dispatch to.
// But that ties us too closely to the logic of the compiler, and
// these thunks are quite
// simple, they just do a little retaining, and then call the correct
// function.
// So for simplicity's sake, I'm just going to get the base name of
// the function
// this protocol thunk is preparing to call, then step into through
// the thunk, stopping if I end up
// in a frame with that function name.
swift::Demangle::Context demangle_ctx;
swift::Demangle::NodePointer demangled_nodes =
demangle_ctx.demangleSymbolAsNode(symbol_mangled_name.GetStringRef());
// Now find the ProtocolWitness node in the demangled result.
swift::Demangle::NodePointer witness_node = demangled_nodes;
bool found_witness_node = false;
while (witness_node) {
if (witness_node->getKind() ==
swift::Demangle::Node::Kind::ProtocolWitness) {
found_witness_node = true;
break;
}
witness_node = witness_node->getFirstChild();
}
if (!found_witness_node) {
if (log)
log->Printf("Stepped into witness thunk \"%s\" but could not "
"find the ProtocolWitness node in the demangled "
"nodes.",
symbol_name);
return new_thread_plan_sp;
}
size_t num_children = witness_node->getNumChildren();
if (num_children < 2) {
if (log)
log->Printf("Stepped into witness thunk \"%s\" but the "
"ProtocolWitness node doesn't have enough nodes.",
symbol_name);
return new_thread_plan_sp;
}
swift::Demangle::NodePointer function_node =
witness_node->getChild(1);
if (function_node == nullptr ||
function_node->getKind() !=
swift::Demangle::Node::Kind::Function) {
if (log)
log->Printf("Stepped into witness thunk \"%s\" but could not "
"find the function in the ProtocolWitness node.",
symbol_name);
return new_thread_plan_sp;
}
// Okay, now find the name of this function.
num_children = function_node->getNumChildren();
swift::Demangle::NodePointer name_node(nullptr);
for (size_t i = 0; i < num_children; i++) {
if (function_node->getChild(i)->getKind() ==
swift::Demangle::Node::Kind::Identifier) {
name_node = function_node->getChild(i);
break;
}
}
if (!name_node) {
if (log)
log->Printf("Stepped into witness thunk \"%s\" but could not "
"find the Function name in the function node.",
symbol_name);
return new_thread_plan_sp;
}
std::string function_name(name_node->getText());
if (function_name.empty()) {
if (log)
log->Printf("Stepped into witness thunk \"%s\" but the Function "
"name was empty.",
symbol_name);
return new_thread_plan_sp;
}
// We have to get the address range of the thunk symbol, and make a
// "step through range stepping in"
AddressRange sym_addr_range(sc.symbol->GetAddress(),
sc.symbol->GetByteSize());
new_thread_plan_sp.reset(new ThreadPlanStepInRange(
thread, sym_addr_range, sc, function_name.c_str(),
eOnlyDuringStepping, eLazyBoolNo, eLazyBoolNo));
return new_thread_plan_sp;
}
break;
case ThunkAction::StepThrough:
{
if (log)
log->Printf("Stepping through thunk: %s kind: %s",
symbol_name, GetThunkKindName(thunk_kind));
AddressRange sym_addr_range(sc.symbol->GetAddress(),
sc.symbol->GetByteSize());
new_thread_plan_sp.reset(new ThreadPlanStepInRange(
thread, sym_addr_range, sc, nullptr, eOnlyDuringStepping,
eLazyBoolNo, eLazyBoolNo));
return new_thread_plan_sp;
}
break;
}
if (target_address.IsValid()) {
new_thread_plan_sp.reset(
new ThreadPlanRunToAddress(thread, target_address, stop_others));
}
return new_thread_plan_sp;
}
void SwiftLanguageRuntime::FindFunctionPointersInCall(
StackFrame &frame, std::vector<Address> &addresses, bool debug_only,
bool resolve_thunks) {
// Extract the mangled name from the stack frame, and realize the function
// type in the Target's SwiftASTContext.
// Then walk the arguments looking for function pointers. If we find one in
// the FIRST argument, we can fetch
// the pointer value and return that.
// FIXME: when we can ask swift/llvm for the location of function arguments,
// then we can do this for all the
// function pointer arguments we find.
SymbolContext sc = frame.GetSymbolContext(eSymbolContextSymbol);
if (sc.symbol) {
Mangled mangled_name = sc.symbol->GetMangled();
if (mangled_name.GuessLanguage() == lldb::eLanguageTypeSwift) {
Status error;
Target &target = frame.GetThread()->GetProcess()->GetTarget();
SwiftASTContext *swift_ast = target.GetScratchSwiftASTContext(error);
if (swift_ast) {
CompilerType function_type = swift_ast->GetTypeFromMangledTypename(
mangled_name.GetMangledName().AsCString(), error);
if (error.Success()) {
if (function_type.IsFunctionType()) {
// FIXME: For now we only check the first argument since we don't
// know how to find the values
// of arguments further in the argument list.
// int num_arguments = function_type.GetFunctionArgumentCount();
// for (int i = 0; i < num_arguments; i++)
for (int i = 0; i < 1; i++) {
CompilerType argument_type =
function_type.GetFunctionArgumentTypeAtIndex(i);
if (argument_type.IsFunctionPointerType()) {
// We found a function pointer argument. Try to track down its
// value. This is a hack
// for now, we really should ask swift/llvm how to find the
// argument(s) given the
// Swift decl for this function, and then look those up in the
// frame.
ABISP abi_sp(frame.GetThread()->GetProcess()->GetABI());
ValueList argument_values;
Value input_value;
CompilerType clang_void_ptr_type =
target.GetScratchClangASTContext()
->GetBasicType(eBasicTypeVoid)
.GetPointerType();
input_value.SetValueType(Value::eValueTypeScalar);
input_value.SetCompilerType(clang_void_ptr_type);
argument_values.PushValue(input_value);
bool success = abi_sp->GetArgumentValues(
*(frame.GetThread().get()), argument_values);
if (success) {
// Now get a pointer value from the zeroth argument.
Status error;
DataExtractor data;
ExecutionContext exe_ctx;
frame.CalculateExecutionContext(exe_ctx);
error = argument_values.GetValueAtIndex(0)->GetValueAsData(
&exe_ctx, data, 0, NULL);
lldb::offset_t offset = 0;
lldb::addr_t fn_ptr_addr = data.GetPointer(&offset);
Address fn_ptr_address;
fn_ptr_address.SetLoadAddress(fn_ptr_addr, &target);
// Now check to see if this has debug info:
bool add_it = true;
if (resolve_thunks) {
SymbolContext sc;
fn_ptr_address.CalculateSymbolContext(
&sc, eSymbolContextEverything);
if (sc.comp_unit && sc.symbol) {
ConstString symbol_name =
sc.symbol->GetMangled().GetMangledName();
if (symbol_name) {
SymbolContext target_context;
if (GetTargetOfPartialApply(sc, symbol_name,
target_context)) {
if (target_context.symbol)
fn_ptr_address =
target_context.symbol->GetAddress();
else if (target_context.function)
fn_ptr_address =
target_context.function->GetAddressRange()
.GetBaseAddress();
}
}
}
}
if (debug_only) {
LineEntry line_entry;
fn_ptr_address.CalculateSymbolContextLineEntry(line_entry);
if (!line_entry.IsValid())
add_it = false;
}
if (add_it)
addresses.push_back(fn_ptr_address);
}
}
}
}
}
}
}
}
}
//------------------------------------------------------------------
// Exception breakpoint Precondition class for Swift:
//------------------------------------------------------------------
void SwiftLanguageRuntime::SwiftExceptionPrecondition::AddTypeName(
const char *class_name) {
m_type_names.insert(class_name);
}
void SwiftLanguageRuntime::SwiftExceptionPrecondition::AddEnumSpec(
const char *enum_name, const char *element_name) {
std::unordered_map<std::string, std::vector<std::string>>::value_type
new_value(enum_name, std::vector<std::string>());
auto result = m_enum_spec.emplace(new_value);
result.first->second.push_back(element_name);
}
SwiftLanguageRuntime::SwiftExceptionPrecondition::SwiftExceptionPrecondition() {
}
ValueObjectSP
SwiftLanguageRuntime::CalculateErrorValueObjectFromValue(
Value &value, ConstString name, bool persistent)
{
ValueObjectSP error_valobj_sp;
Status error;
SwiftASTContext *ast_context =
m_process->GetTarget().GetScratchSwiftASTContext(error);
if (!ast_context || error.Fail())
return error_valobj_sp;
CompilerType swift_error_proto_type = ast_context->GetErrorType();
value.SetCompilerType(swift_error_proto_type);
error_valobj_sp = ValueObjectConstResult::Create(
m_process, value, name);
if (error_valobj_sp && error_valobj_sp->GetError().Success()) {
error_valobj_sp = error_valobj_sp->GetQualifiedRepresentationIfAvailable(
lldb::eDynamicCanRunTarget, true);
if (!IsValidErrorValue(*(error_valobj_sp.get()))) {
error_valobj_sp.reset();
}
}
if (persistent && error_valobj_sp) {
PersistentExpressionState *persistent_state =
m_process->GetTarget().GetPersistentExpressionStateForLanguage(
eLanguageTypeSwift);
ConstString persistent_variable_name(
persistent_state->GetNextPersistentVariableName(true));
lldb::ValueObjectSP const_valobj_sp;
// Check in case our value is already a constant value
if (error_valobj_sp->GetIsConstant()) {
const_valobj_sp = error_valobj_sp;
const_valobj_sp->SetName(persistent_variable_name);
} else
const_valobj_sp =
error_valobj_sp->CreateConstantValue(persistent_variable_name);
lldb::ValueObjectSP live_valobj_sp = error_valobj_sp;
error_valobj_sp = const_valobj_sp;
ExpressionVariableSP clang_expr_variable_sp(
persistent_state->CreatePersistentVariable(error_valobj_sp));
clang_expr_variable_sp->m_live_sp = live_valobj_sp;
clang_expr_variable_sp->m_flags |=
ClangExpressionVariable::EVIsProgramReference;
error_valobj_sp = clang_expr_variable_sp->GetValueObject();
}
return error_valobj_sp;
}
ValueObjectSP SwiftLanguageRuntime::CalculateErrorValueFromFirstArgument(
StackFrameSP frame_sp, ConstString variable_name) {
ProcessSP process_sp(frame_sp->GetThread()->GetProcess());
ABISP abi_sp(process_sp->GetABI());
ValueList argument_values;
Value input_value;
Status error;
Target *target = frame_sp->CalculateTarget().get();
ValueObjectSP error_valobj_sp;
ClangASTContext *clang_ast_context = target->GetScratchClangASTContext();
CompilerType clang_void_ptr_type =
clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
input_value.SetValueType(Value::eValueTypeScalar);
input_value.SetCompilerType(clang_void_ptr_type);
argument_values.PushValue(input_value);
bool success = abi_sp->GetArgumentValues(*(frame_sp->GetThread().get()),
argument_values);
if (success) {
ExecutionContext exe_ctx;
frame_sp->CalculateExecutionContext(exe_ctx);
DataExtractor data;
SwiftASTContext *ast_context = target->GetScratchSwiftASTContext(error);
if (!ast_context || error.Fail())
return error_valobj_sp;
CompilerType swift_error_proto_type = ast_context->GetErrorType();
if (swift_error_proto_type.IsValid()) {
Value *arg0 = argument_values.GetValueAtIndex(0);
Status extract_error = arg0->GetValueAsData(&exe_ctx, data, 0, nullptr);
if (extract_error.Success()) {
error_valobj_sp = ValueObjectConstResult::Create(
frame_sp.get(), swift_error_proto_type, variable_name, data);
if (error_valobj_sp->GetError().Fail()) {
// If we couldn't make the error ValueObject, then we will always
// stop.
// FIXME: Some logging here would be good.
return error_valobj_sp;
}
error_valobj_sp =
error_valobj_sp->GetQualifiedRepresentationIfAvailable(
lldb::eDynamicCanRunTarget, true);
}
}
}
return error_valobj_sp;
}
void SwiftLanguageRuntime::RegisterGlobalError(Target &target, ConstString name,
lldb::addr_t addr) {
Status ast_context_error;
SwiftASTContext *ast_context =
target.GetScratchSwiftASTContext(ast_context_error);
if (ast_context_error.Success() && ast_context &&
!ast_context->HasFatalErrors()) {
SwiftPersistentExpressionState *persistent_state =
llvm::cast<SwiftPersistentExpressionState>(
target.GetPersistentExpressionStateForLanguage(
lldb::eLanguageTypeSwift));
std::string module_name = "$__lldb_module_for_";
module_name.append(&name.GetCString()[1]);
Status module_creation_error;
swift::ModuleDecl *module_decl = ast_context->CreateModule(
ConstString(module_name), module_creation_error);
if (module_creation_error.Success() && module_decl) {
const bool is_static = false;
const auto specifier = swift::VarDecl::Specifier::Let;
const bool is_capture_list = false;
swift::VarDecl *var_decl = new (*ast_context->GetASTContext())
swift::VarDecl(is_static, specifier, is_capture_list, swift::SourceLoc(),
ast_context->GetIdentifier(name.GetCString()),
GetSwiftType(ast_context->GetErrorType()),
module_decl);
var_decl->setInterfaceType(var_decl->getType());
var_decl->setDebuggerVar(true);
persistent_state->RegisterSwiftPersistentDecl(var_decl);
ConstString mangled_name;
{
swift::Mangle::ASTMangler mangler(true);
mangled_name = ConstString(mangler.mangleGlobalVariableFull(var_decl));
}
lldb::addr_t symbol_addr;
{
ProcessSP process_sp(target.GetProcessSP());
Status alloc_error;
symbol_addr = process_sp->AllocateMemory(
process_sp->GetAddressByteSize(),
lldb::ePermissionsWritable | lldb::ePermissionsReadable,
alloc_error);
if (alloc_error.Success() && symbol_addr != LLDB_INVALID_ADDRESS) {
Status write_error;
process_sp->WritePointerToMemory(symbol_addr, addr, write_error);
if (write_error.Success()) {
persistent_state->RegisterSymbol(mangled_name, symbol_addr);
}
}
}
}
}
}
bool SwiftLanguageRuntime::SwiftExceptionPrecondition::EvaluatePrecondition(
StoppointCallbackContext &context) {
if (!m_type_names.empty()) {
StackFrameSP frame_sp = context.exe_ctx_ref.GetFrameSP();
if (!frame_sp)
return true;
ValueObjectSP error_valobj_sp = CalculateErrorValueFromFirstArgument(
frame_sp, ConstString("__swift_error_var"));
if (!error_valobj_sp || error_valobj_sp->GetError().Fail())
return true;
// This shouldn't fail, since at worst it will return me the object I just
// successfully got.
std::string full_error_name(
error_valobj_sp->GetCompilerType().GetTypeName().AsCString());
size_t last_dot_pos = full_error_name.rfind('.');
std::string type_name_base;
if (last_dot_pos == std::string::npos)
type_name_base = full_error_name;
else {
if (last_dot_pos + 1 <= full_error_name.size())
type_name_base =
full_error_name.substr(last_dot_pos + 1, full_error_name.size());
}
// The type name will be the module and then the type. If the match name
// has a dot, we require a complete
// match against the type, if the type name has no dot, we match it against
// the base.
for (std::string name : m_type_names) {
if (name.rfind('.') != std::string::npos) {
if (name == full_error_name)
return true;
} else {
if (name == type_name_base)
return true;
}
}
return false;
}
return true;
}
void SwiftLanguageRuntime::SwiftExceptionPrecondition::GetDescription(
Stream &stream, lldb::DescriptionLevel level) {
if (level == eDescriptionLevelFull || level == eDescriptionLevelVerbose) {
if (m_type_names.size() > 0) {
stream.Printf("\nType Filters:");
for (std::string name : m_type_names) {
stream.Printf(" %s", name.c_str());
}
stream.Printf("\n");
}
}
}
Status SwiftLanguageRuntime::SwiftExceptionPrecondition::ConfigurePrecondition(
Args &args) {
Status error;
std::vector<std::string> object_typenames;
args.GetOptionValuesAsStrings("exception-typename", object_typenames);
for (auto type_name : object_typenames)
AddTypeName(type_name.c_str());
return error;
}
void SwiftLanguageRuntime::AddToLibraryNegativeCache(const char *library_name) {
std::lock_guard<std::mutex> locker(m_negative_cache_mutex);
m_library_negative_cache.insert(library_name);
}
bool SwiftLanguageRuntime::IsInLibraryNegativeCache(const char *library_name) {
std::lock_guard<std::mutex> locker(m_negative_cache_mutex);
return m_library_negative_cache.count(library_name) == 1;
}
lldb::addr_t
SwiftLanguageRuntime::MaskMaybeBridgedPointer(lldb::addr_t addr,
lldb::addr_t *masked_bits) {
if (!m_process)
return addr;
const ArchSpec &arch_spec(m_process->GetTarget().GetArchitecture());
ArchSpec::Core core_kind = arch_spec.GetCore();
bool is_arm = false;
bool is_intel = false;
bool is_32 = false;
bool is_64 = false;
if (core_kind == ArchSpec::Core::eCore_arm_arm64) {
is_arm = is_64 = true;
} else if (core_kind >= ArchSpec::Core::kCore_arm_first &&
core_kind <= ArchSpec::Core::kCore_arm_last) {
is_arm = true;
} else if (core_kind >= ArchSpec::Core::kCore_x86_64_first &&
core_kind <= ArchSpec::Core::kCore_x86_64_last) {
is_intel = true;
} else if (core_kind >= ArchSpec::Core::kCore_x86_32_first &&
core_kind <= ArchSpec::Core::kCore_x86_32_last) {
is_intel = true;
} else {
// this is a really random CPU core to be running on - just get out fast
return addr;
}
switch (arch_spec.GetAddressByteSize()) {
case 4:
is_32 = true;
break;
case 8:
is_64 = true;
break;
default:
// this is a really random pointer size to be running on - just get out fast
return addr;
}
lldb::addr_t mask = 0;
if (is_arm && is_64)
mask = SWIFT_ABI_ARM64_SWIFT_SPARE_BITS_MASK;
if (is_arm && is_32)
mask = SWIFT_ABI_ARM_SWIFT_SPARE_BITS_MASK;
if (is_intel && is_64)
mask = SWIFT_ABI_X86_64_SWIFT_SPARE_BITS_MASK;
if (is_intel && is_32)
mask = SWIFT_ABI_I386_SWIFT_SPARE_BITS_MASK;
if (masked_bits)
*masked_bits = addr & mask;
return addr & ~mask;
}
lldb::addr_t
SwiftLanguageRuntime::MaybeMaskNonTrivialReferencePointer(
lldb::addr_t addr,
SwiftASTContext::NonTriviallyManagedReferenceStrategy strategy) {
if (addr == 0)
return addr;
AppleObjCRuntime *objc_runtime = GetObjCRuntime();
if (objc_runtime) {
// tagged pointers don't perform any masking
if (objc_runtime->IsTaggedPointer(addr))
return addr;
}
if (!m_process)
return addr;
const ArchSpec &arch_spec(m_process->GetTarget().GetArchitecture());
ArchSpec::Core core_kind = arch_spec.GetCore();
bool is_arm = false;
bool is_intel = false;
bool is_32 = false;
bool is_64 = false;
if (core_kind == ArchSpec::Core::eCore_arm_arm64) {
is_arm = is_64 = true;
} else if (core_kind >= ArchSpec::Core::kCore_arm_first &&
core_kind <= ArchSpec::Core::kCore_arm_last) {
is_arm = true;
} else if (core_kind >= ArchSpec::Core::kCore_x86_64_first &&
core_kind <= ArchSpec::Core::kCore_x86_64_last) {
is_intel = true;
} else if (core_kind >= ArchSpec::Core::kCore_x86_32_first &&
core_kind <= ArchSpec::Core::kCore_x86_32_last) {
is_intel = true;
} else {
// this is a really random CPU core to be running on - just get out fast
return addr;
}
switch (arch_spec.GetAddressByteSize()) {
case 4:
is_32 = true;
break;
case 8:
is_64 = true;
break;
default:
// this is a really random pointer size to be running on - just get out fast
return addr;
}
lldb::addr_t mask = 0;
if (strategy == SwiftASTContext::NonTriviallyManagedReferenceStrategy::eWeak) {
bool is_indirect = true;
// On non-objc platforms, the weak reference pointer always pointed to a
// runtime structure.
// For ObjC platforms, the masked value determines whether it is indirect.
uint32_t value = 0;
if (objc_runtime)
{
if (is_intel) {
if (is_64) {
mask = SWIFT_ABI_X86_64_OBJC_WEAK_REFERENCE_MARKER_MASK;
value = SWIFT_ABI_X86_64_OBJC_WEAK_REFERENCE_MARKER_VALUE;
} else {
mask = SWIFT_ABI_I386_OBJC_WEAK_REFERENCE_MARKER_MASK;
value = SWIFT_ABI_I386_OBJC_WEAK_REFERENCE_MARKER_VALUE;
}
} else if (is_arm) {
if (is_64) {
mask = SWIFT_ABI_ARM64_OBJC_WEAK_REFERENCE_MARKER_MASK;
value = SWIFT_ABI_ARM64_OBJC_WEAK_REFERENCE_MARKER_VALUE;
} else {
mask = SWIFT_ABI_ARM_OBJC_WEAK_REFERENCE_MARKER_MASK;
value = SWIFT_ABI_ARM_OBJC_WEAK_REFERENCE_MARKER_VALUE;
}
}
} else {
// This name is a little confusing. The "DEFAULT" marking in System.h
// is supposed to mean: the value for non-ObjC platforms. So
// DEFAULT_OBJC here actually means "non-ObjC".
mask = SWIFT_ABI_DEFAULT_OBJC_WEAK_REFERENCE_MARKER_MASK;
value = SWIFT_ABI_DEFAULT_OBJC_WEAK_REFERENCE_MARKER_VALUE;
}
is_indirect = ((addr & mask) == value);
if (!is_indirect)
return addr;
// The masked value of address is a pointer to the runtime structure.
// The first field of the structure is the actual pointer.
Process *process = GetProcess();
Status error;
lldb::addr_t masked_addr = addr & ~mask;
lldb::addr_t isa_addr = process->ReadPointerFromMemory(masked_addr, error);
if (error.Fail())
{
// FIXME: do some logging here.
return addr;
}
return isa_addr;
} else {
if (is_arm && is_64)
mask = SWIFT_ABI_ARM64_OBJC_NUM_RESERVED_LOW_BITS;
else if (is_intel && is_64)
mask = SWIFT_ABI_X86_64_OBJC_NUM_RESERVED_LOW_BITS;
else
mask = SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS;
mask = (1 << mask) | (1 << (mask + 1));
return addr & ~mask;
}
return addr;
}
ConstString SwiftLanguageRuntime::GetErrorBackstopName() {
return ConstString("swift_errorInMain");
}
ConstString SwiftLanguageRuntime::GetStandardLibraryBaseName() {
static ConstString g_swiftCore("swiftCore");
return g_swiftCore;
}
ConstString SwiftLanguageRuntime::GetStandardLibraryName() {
PlatformSP platform_sp(m_process->GetTarget().GetPlatform());
if (platform_sp)
return platform_sp->GetFullNameForDylib(GetStandardLibraryBaseName());
return GetStandardLibraryBaseName();
}
bool SwiftLanguageRuntime::GetReferenceCounts(ValueObject &valobj,
size_t &strong, size_t &weak) {
CompilerType compiler_type(valobj.GetCompilerType());
Flags type_flags(compiler_type.GetTypeInfo());
if (llvm::isa<SwiftASTContext>(compiler_type.GetTypeSystem()) &&
type_flags.AllSet(eTypeInstanceIsPointer)) {
lldb::addr_t ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
if (ptr_value == LLDB_INVALID_ADDRESS)
return false;
ptr_value += GetProcess()->GetAddressByteSize();
Status error;
strong =
GetProcess()->ReadUnsignedIntegerFromMemory(ptr_value, 4, 0, error) >>
2;
if (error.Fail())
return false;
weak = GetProcess()->ReadUnsignedIntegerFromMemory(ptr_value + 4, 4, 0,
error) >>
2;
if (error.Fail())
return false;
return true;
}
return false;
}
class ProjectionSyntheticChildren : public SyntheticChildren {
public:
struct FieldProjection {
ConstString name;
CompilerType type;
int32_t byte_offset;
FieldProjection(CompilerType parent_type, ExecutionContext *exe_ctx,
size_t idx) {
const bool transparent_pointers = false;
const bool omit_empty_base_classes = true;
const bool ignore_array_bounds = false;
bool child_is_base_class = false;
bool child_is_deref_of_parent = false;
std::string child_name;
uint32_t child_byte_size;
uint32_t child_bitfield_bit_size;
uint32_t child_bitfield_bit_offset;
uint64_t language_flags;
type = parent_type.GetChildCompilerTypeAtIndex(
exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
ignore_array_bounds, child_name, child_byte_size, byte_offset,
child_bitfield_bit_size, child_bitfield_bit_offset,
child_is_base_class, child_is_deref_of_parent, nullptr,
language_flags);
if (child_is_base_class)
type.Clear(); // invalidate - base classes are dealt with outside of the
// projection
else
name.SetCStringWithLength(child_name.c_str(), child_name.size());
}
bool IsValid() { return !name.IsEmpty() && type.IsValid(); }
explicit operator bool() { return IsValid(); }
};
struct TypeProjection {
std::vector<FieldProjection> field_projections;
ConstString type_name;
};
typedef std::unique_ptr<TypeProjection> TypeProjectionUP;
bool IsScripted() { return false; }
std::string GetDescription() { return "projection synthetic children"; }
ProjectionSyntheticChildren(const Flags &flags, TypeProjectionUP &&projection)
: SyntheticChildren(flags), m_projection(std::move(projection)) {}
protected:
TypeProjectionUP m_projection;
class ProjectionFrontEndProvider : public SyntheticChildrenFrontEnd {
public:
ProjectionFrontEndProvider(ValueObject &backend,
TypeProjectionUP &projection)
: SyntheticChildrenFrontEnd(backend), m_num_bases(0),
m_projection(projection.get()) {
lldbassert(m_projection && "need a valid projection");
CompilerType type(backend.GetCompilerType());
m_num_bases = type.GetNumDirectBaseClasses();
}
size_t CalculateNumChildren() override {
return m_projection->field_projections.size() + m_num_bases;
}
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
if (idx < m_num_bases) {
if (ValueObjectSP base_object_sp =
m_backend.GetChildAtIndex(idx, true)) {
CompilerType base_type(base_object_sp->GetCompilerType());
ConstString base_type_name(base_type.GetTypeName());
if (base_type_name.IsEmpty() ||
!SwiftLanguageRuntime::IsSwiftClassName(base_type_name.GetCString()))
return base_object_sp;
base_object_sp = m_backend.GetSyntheticBase(
0, base_type, true,
Mangled(base_type_name, true)
.GetDemangledName(lldb::eLanguageTypeSwift));
return base_object_sp;
} else
return nullptr;
}
idx -= m_num_bases;
if (idx < m_projection->field_projections.size()) {
auto &projection(m_projection->field_projections.at(idx));
return m_backend.GetSyntheticChildAtOffset(
projection.byte_offset, projection.type, true, projection.name);
}
return nullptr;
}
size_t GetIndexOfChildWithName(const ConstString &name) override {
for (size_t idx = 0; idx < m_projection->field_projections.size();
idx++) {
if (m_projection->field_projections.at(idx).name == name)
return idx;
}
return UINT32_MAX;
}
bool Update() override { return false; }
bool MightHaveChildren() override { return true; }
ConstString GetSyntheticTypeName() override {
return m_projection->type_name;
}
private:
size_t m_num_bases;
TypeProjectionUP::element_type *m_projection;
};
public:
SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject &backend) {
return SyntheticChildrenFrontEnd::AutoPointer(
new ProjectionFrontEndProvider(backend, m_projection));
}
};
lldb::SyntheticChildrenSP
SwiftLanguageRuntime::GetBridgedSyntheticChildProvider(ValueObject &valobj) {
const char *type_name(valobj.GetCompilerType().GetTypeName().AsCString());
if (type_name && *type_name) {
auto iter = m_bridged_synthetics_map.find(type_name),
end = m_bridged_synthetics_map.end();
if (iter != end)
return iter->second;
}
ProjectionSyntheticChildren::TypeProjectionUP type_projection(
new ProjectionSyntheticChildren::TypeProjectionUP::element_type());
if (SwiftASTContext *swift_ast_ctx = GetScratchSwiftASTContext()) {
Status error;
CompilerType swift_type =
swift_ast_ctx->GetTypeFromMangledTypename(type_name, error);
if (swift_type.IsValid()) {
ExecutionContext exe_ctx(GetProcess());
bool any_projected = false;
for (size_t idx = 0; idx < swift_type.GetNumChildren(true); idx++) {
// if a projection fails, keep going - we have offsets here, so it
// should be OK to skip some members
if (auto projection = ProjectionSyntheticChildren::FieldProjection(
swift_type, &exe_ctx, idx)) {
any_projected = true;
type_projection->field_projections.push_back(projection);
}
}
if (any_projected) {
type_projection->type_name = swift_type.GetDisplayTypeName();
SyntheticChildrenSP synth_sp =
SyntheticChildrenSP(new ProjectionSyntheticChildren(
SyntheticChildren::Flags(), std::move(type_projection)));
return (m_bridged_synthetics_map[type_name] = synth_sp);
}
}
}
return nullptr;
}
void SwiftLanguageRuntime::WillStartExecutingUserExpression() {
std::lock_guard<std::mutex> lock(m_active_user_expr_mutex);
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
if (m_active_user_expr_count == 0 &&
m_dynamic_exclusivity_flag_addr) {
// We're executing the first user expression. Toggle the flag.
Status error;
TypeSystem *type_system =
m_process->GetTarget().GetScratchTypeSystemForLanguage(
&error,
eLanguageTypeC_plus_plus);
if (error.Fail()) {
if (log)
log->Printf("SwiftLanguageRuntime: Unable to get pointer to type "
"system: %s", error.AsCString());
return;
}
ConstString BoolName("bool");
size_t bool_size =
type_system->GetBuiltinTypeByName(BoolName).GetByteSize(nullptr);
Scalar original_value;
m_process->ReadScalarIntegerFromMemory(*m_dynamic_exclusivity_flag_addr,
bool_size, false, original_value,
error);
m_original_dynamic_exclusivity_flag_state = original_value.UInt() != 0;
if (error.Fail()) {
if (log)
log->Printf("SwiftLanguageRuntime: Unable to read "
"disableExclusivityChecking flag state: %s",
error.AsCString());
} else {
Scalar new_value(1U);
m_process->WriteScalarToMemory(*m_dynamic_exclusivity_flag_addr,
new_value, bool_size, error);
if (error.Fail()) {
if (log)
log->Printf("SwiftLanguageRuntime: Unable to set "
"disableExclusivityChecking flag state: %s",
error.AsCString());
} else {
if (log)
log->Printf("SwiftLanguageRuntime: Changed "
"disableExclusivityChecking flag state from %u to 1",
m_original_dynamic_exclusivity_flag_state);
}
}
}
++m_active_user_expr_count;
if (log)
log->Printf("SwiftLanguageRuntime: starting user expression. "
"Number active: %u", m_active_user_expr_count);
}
void SwiftLanguageRuntime::DidFinishExecutingUserExpression() {
std::lock_guard<std::mutex> lock(m_active_user_expr_mutex);
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
--m_active_user_expr_count;
if (log)
log->Printf("SwiftLanguageRuntime: finished user expression. "
"Number active: %u", m_active_user_expr_count);
if (m_active_user_expr_count == 0 &&
m_dynamic_exclusivity_flag_addr) {
Status error;
TypeSystem *type_system =
m_process->GetTarget().GetScratchTypeSystemForLanguage(
&error,
eLanguageTypeC_plus_plus);
if (error.Fail()) {
if (log)
log->Printf("SwiftLanguageRuntime: Unable to get pointer to type "
"system: %s", error.AsCString());
return;
}
ConstString BoolName("bool");
size_t bool_size =
type_system->GetBuiltinTypeByName(BoolName).GetByteSize(nullptr);
Scalar original_value(m_original_dynamic_exclusivity_flag_state ? 1U : 0U);
m_process->WriteScalarToMemory(*m_dynamic_exclusivity_flag_addr,
original_value, bool_size, error);
if (error.Fail()) {
if (log)
log->Printf("SwiftLanguageRuntime: Unable to reset "
"disableExclusivityChecking flag state: %s",
error.AsCString());
} else {
if (log)
log->Printf("SwiftLanguageRuntime: Changed "
"disableExclusivityChecking flag state back to %u",
m_original_dynamic_exclusivity_flag_state);
}
}
}
llvm::Optional<Value> SwiftLanguageRuntime::GetErrorReturnLocationAfterReturn(
lldb::StackFrameSP frame_sp)
{
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
llvm::Optional<Value> error_val;
llvm::StringRef error_reg_name;
ArchSpec arch_spec(GetTargetRef().GetArchitecture());
switch (arch_spec.GetMachine()) {
case llvm::Triple::ArchType::arm:
error_reg_name = "r6";
break;
case llvm::Triple::ArchType::aarch64:
error_reg_name = "x19";
break;
case llvm::Triple::ArchType::x86_64:
error_reg_name = "r12";
break;
default:
break;
}
if (error_reg_name.empty())
return error_val;
RegisterContextSP reg_ctx = frame_sp->GetRegisterContext();
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(error_reg_name);
lldbassert(reg_info && "didn't get the right register name for swift error register");
if (!reg_info)
return error_val;
RegisterValue reg_value;
if (!reg_ctx->ReadRegister(reg_info, reg_value))
{
// Do some logging here.
return error_val;
}
lldb::addr_t error_addr = reg_value.GetAsUInt64();
if (error_addr == 0)
return error_val;
Value val;
if (reg_value.GetScalarValue(val.GetScalar())) {
val.SetValueType(Value::eValueTypeScalar);
val.SetContext(Value::eContextTypeRegisterInfo,
const_cast<RegisterInfo *>(reg_info));
error_val = val;
}
// if (log)
// log->Printf("Found return address: 0x%" PRIu64 " from register %s.",
// return_addr,
// error_reg_name.str().c_str());
return error_val;
}
llvm::Optional<Value> SwiftLanguageRuntime::GetErrorReturnLocationBeforeReturn(
lldb::StackFrameSP frame_sp, bool &need_to_check_after_return) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
llvm::Optional<Value> error_val;
if (!frame_sp)
{
need_to_check_after_return = false;
return error_val;
}
// For Architectures where the error isn't returned in a register,
// there's a magic variable that points to the value. Check that first:
ConstString error_location_name("$error");
VariableListSP variables_sp = frame_sp->GetInScopeVariableList(false);
VariableSP error_loc_var_sp = variables_sp->FindVariable(
error_location_name, eValueTypeVariableArgument);
if (error_loc_var_sp) {
need_to_check_after_return = false;
ValueObjectSP error_loc_val_sp = frame_sp->GetValueObjectForFrameVariable(
error_loc_var_sp, eNoDynamicValues);
if (error_loc_val_sp && error_loc_val_sp->GetError().Success())
error_val = error_loc_val_sp->GetValue();
// if (log)
// log->Printf("Found return address: 0x%" PRIu64 " from error variable.", return_addr);
return error_val;
}
// Otherwise, see if we know which register it lives in from the calling convention.
// This should probably go in the ABI plugin not here, but the Swift ABI can change with
// swiftlang versions and that would make it awkward in the ABI.
Function *func = frame_sp->GetSymbolContext(eSymbolContextFunction).function;
if (!func)
{
need_to_check_after_return = false;
return error_val;
}
need_to_check_after_return = func->CanThrow();
return error_val;
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
LanguageRuntime *
SwiftLanguageRuntime::CreateInstance(Process *process,
lldb::LanguageType language) {
if (language == eLanguageTypeSwift)
return new SwiftLanguageRuntime(process);
else
return NULL;
}
lldb::BreakpointResolverSP
SwiftLanguageRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp,
bool throw_bp) {
BreakpointResolverSP resolver_sp;
if (throw_bp)
resolver_sp.reset(new BreakpointResolverName(
bkpt, "swift_willThrow", eFunctionNameTypeBase, eLanguageTypeUnknown,
Breakpoint::Exact, 0, eLazyBoolNo));
// FIXME: We don't do catch breakpoints for ObjC yet.
// Should there be some way for the runtime to specify what it can do in this
// regard?
return resolver_sp;
}
static const char *
SwiftDemangleNodeKindToCString(const swift::Demangle::Node::Kind node_kind) {
#define NODE(e) \
case swift::Demangle::Node::Kind::e: \
return #e;
switch (node_kind) {
#include "swift/Demangling/DemangleNodes.def"
}
return "swift::Demangle::Node::Kind::???";
#undef NODE
}
static OptionDefinition g_swift_demangle_options[] = {
// clang-format off
{LLDB_OPT_SET_1, false, "expand", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Whether LLDB should print the demangled tree"},
// clang-format on
};
class CommandObjectSwift_Demangle : public CommandObjectParsed {
public:
CommandObjectSwift_Demangle(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "demangle",
"Demangle a Swift mangled name",
"language swift demangle"),
m_options() {}
~CommandObjectSwift_Demangle() {}
virtual Options *GetOptions() { return &m_options; }
class CommandOptions : public Options {
public:
CommandOptions() : Options(), m_expand(false, false) {
OptionParsingStarting(nullptr);
}
virtual ~CommandOptions() {}
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) override {
Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'e':
m_expand.SetCurrentValue(true);
break;
default:
error.SetErrorStringWithFormat("invalid short option character '%c'",
short_option);
break;
}
return error;
}
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_expand.Clear();
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
return llvm::makeArrayRef(g_swift_demangle_options);
}
// Options table: Required for subclasses of Options.
OptionValueBoolean m_expand;
};
protected:
void PrintNode(swift::Demangle::NodePointer node_ptr, Stream &stream,
int depth = 0) {
if (!node_ptr)
return;
std::string indent(2 * depth, ' ');
stream.Printf("%s", indent.c_str());
stream.Printf("kind=%s",
SwiftDemangleNodeKindToCString(node_ptr->getKind()));
if (node_ptr->hasText()) {
std::string Text = node_ptr->getText();
stream.Printf(", text=\"%s\"", Text.c_str());
}
if (node_ptr->hasIndex())
stream.Printf(", index=%" PRIu64, node_ptr->getIndex());
stream.Printf("\n");
for (auto &&child : *node_ptr) {
PrintNode(child, stream, depth + 1);
}
}
bool DoExecute(Args &command, CommandReturnObject &result) {
for (size_t i = 0; i < command.GetArgumentCount(); i++) {
const char *arg = command.GetArgumentAtIndex(i);
if (arg && *arg) {
swift::Demangle::Context demangle_ctx;
auto node_ptr = demangle_ctx.demangleSymbolAsNode(llvm::StringRef(arg));
if (node_ptr) {
if (m_options.m_expand) {
PrintNode(node_ptr, result.GetOutputStream());
}
result.GetOutputStream().Printf(
"%s ---> %s\n", arg,
swift::Demangle::nodeToString(node_ptr).c_str());
}
}
}
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
return true;
}
CommandOptions m_options;
};
class CommandObjectSwift_RefCount : public CommandObjectRaw {
public:
CommandObjectSwift_RefCount(CommandInterpreter &interpreter)
: CommandObjectRaw(interpreter, "refcount",
"Inspect the reference count data for a Swift object",
"language swift refcount",
eCommandProcessMustBePaused | eCommandRequiresFrame) {}
~CommandObjectSwift_RefCount() {}
virtual Options *GetOptions() { return nullptr; }
protected:
bool DoExecute(const char *command, CommandReturnObject &result) {
ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
StackFrameSP frame_sp(exe_ctx.GetFrameSP());
EvaluateExpressionOptions options;
options.SetLanguage(lldb::eLanguageTypeSwift);
options.SetResultIsInternal(true);
options.SetUseDynamic();
ValueObjectSP result_valobj_sp;
if (exe_ctx.GetTargetSP()->EvaluateExpression(command, frame_sp.get(),
result_valobj_sp) ==
eExpressionCompleted) {
if (result_valobj_sp) {
if (result_valobj_sp->GetError().Fail()) {
result.SetStatus(lldb::eReturnStatusFailed);
result.AppendError(result_valobj_sp->GetError().AsCString());
return false;
}
result_valobj_sp =
result_valobj_sp->GetQualifiedRepresentationIfAvailable(
lldb::eDynamicCanRunTarget, true);
CompilerType result_type(result_valobj_sp->GetCompilerType());
if (result_type.GetTypeInfo() & lldb::eTypeInstanceIsPointer) {
size_t strong = 0, weak = 0;
if (!exe_ctx.GetProcessSP()
->GetSwiftLanguageRuntime()
->GetReferenceCounts(*result_valobj_sp.get(), strong,
weak)) {
result.AppendError("refcount not available");
result.SetStatus(lldb::eReturnStatusFailed);
return false;
} else {
result.AppendMessageWithFormat(
"refcount data: (strong = %zu, weak = %zu)\n", strong, weak);
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
return true;
}
} else {
result.AppendError("refcount only available for class types");
result.SetStatus(lldb::eReturnStatusFailed);
return false;
}
}
}
result.SetStatus(lldb::eReturnStatusFailed);
if (result_valobj_sp && result_valobj_sp->GetError().Fail())
result.AppendError(result_valobj_sp->GetError().AsCString());
return false;
}
};
class CommandObjectMultiwordSwift : public CommandObjectMultiword {
public:
CommandObjectMultiwordSwift(CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "swift",
"A set of commands for operating on the Swift Language Runtime.",
"swift <subcommand> [<subcommand-options>]") {
LoadSubCommand("demangle", CommandObjectSP(new CommandObjectSwift_Demangle(
interpreter)));
LoadSubCommand("refcount", CommandObjectSP(new CommandObjectSwift_RefCount(
interpreter)));
}
virtual ~CommandObjectMultiwordSwift() {}
};
void SwiftLanguageRuntime::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), "Language runtime for the Swift language",
CreateInstance,
[](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
return CommandObjectSP(new CommandObjectMultiwordSwift(interpreter));
});
}
void SwiftLanguageRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString SwiftLanguageRuntime::GetPluginNameStatic() {
static ConstString g_name("swift");
return g_name;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString SwiftLanguageRuntime::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t SwiftLanguageRuntime::GetPluginVersion() { return 1; }