diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index ec3c64ad9c3b2..adc89003cdd33 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -274,6 +274,215 @@ 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); + eval_options.SetTimeout(g_po_function_timeout); + 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); + eval_options.SetTimeout(g_po_function_timeout); + 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 const ExecutionContextRef *GetSwiftExeCtx(ValueObject &valobj) { return (valobj.GetPreferredDisplayLanguage() == eLanguageTypeSwift) ? &valobj.GetExecutionContextRef() @@ -440,12 +649,61 @@ static bool GetObjectDescription_ObjectCopy(SwiftLanguageRuntime *runtime, return true; } +static bool IsSwiftResultVariable(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(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(""); 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(this, m_process, str, object); }