Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ class TargetProperties : public Properties {

bool GetSwiftAutoImportFrameworks() const;

bool GetSwiftUseContextFreePrintObject() const;

bool GetEnableAutoImportClangModules() const;

bool GetUseAllCompilerFlags() const;
Expand Down Expand Up @@ -566,6 +568,14 @@ class EvaluateExpressionOptions {

bool GetPreparePlaygroundStubFunctions() const { return m_prepare_playground_stub_functions; }

void SetUseContextFreeSwiftPrintObject(bool enable = true) {
m_use_context_free_swift_print_object = enable;
}

bool GetUseContextFreeSwiftPrintObject() const {
return m_use_context_free_swift_print_object;
}

private:
ExecutionPolicy m_execution_policy = default_execution_policy;
SourceLanguage m_language;
Expand Down Expand Up @@ -607,6 +617,11 @@ class EvaluateExpressionOptions {
mutable uint32_t m_pound_line_line = 0;
bool m_prepare_playground_stub_functions = true;

/// An evaluation mode that for swift. Has the following effects:
/// 1. Disables implicit module loading
/// 2. Disables compiler availability checking
bool m_use_context_free_swift_print_object = false;

/// During expression evaluation, any SymbolContext in this list will be
/// used for symbol/function lookup before any other context (except for
/// the module corresponding to the current frame).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1317,13 +1317,14 @@ SwiftExpressionParser::ParseAndImport(
if (lldb::StackFrameSP this_frame_sp = m_stack_frame_wp.lock())
process_sp = this_frame_sp->CalculateProcess();
m_swift_ast_ctx.LoadImplicitModules(m_sc.target_sp, process_sp, *m_exe_scope);
if (!m_swift_ast_ctx.GetImplicitImports(m_sc, process_sp, additional_imports,
implicit_import_error)) {
const char *msg = implicit_import_error.AsCString();
if (!msg)
msg = "error status positive, but import still failed";
return make_error<ModuleImportError>(msg);
}
if (!m_options.GetUseContextFreeSwiftPrintObject())
if (!m_swift_ast_ctx.GetImplicitImports(
m_sc, process_sp, additional_imports, implicit_import_error)) {
Comment on lines +1320 to +1322
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrian-prantl I've introduced this change to the PR. This prevents module loading when the expression is running the new po.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM, assuming m_options.GetUseContextFreeSwiftPrintObject() is only true in a po!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is only true in a po.

const char *msg = implicit_import_error.AsCString();
if (!msg)
msg = "error status positive, but import still failed";
return make_error<ModuleImportError>(msg);
}

swift::ImplicitImportInfo importInfo;
importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,15 +640,22 @@ Status SwiftExpressionSourceCode::GetText(
if (triple.isOSDarwin()) {
if (auto process_sp = exe_ctx.GetProcessSP()) {
os_vers << getAvailabilityName(triple) << " ";
auto platform = target->GetPlatform();
bool is_simulator = platform->GetPluginName().ends_with("-simulator");
if (is_simulator) {
// The simulators look like the host OS to Process, but Platform
// can the version out of an environment variable.
os_vers << platform->GetOSVersion(process_sp.get()).getAsString();
if (options.GetUseContextFreeSwiftPrintObject()) {
// Disable availability by setting the OS version to 9999. This
// placeholder OS version used for future OS versions when building
// the Swift standard library locally.
os_vers << "9999";
} else {
llvm::VersionTuple version = process_sp->GetHostOSVersion();
os_vers << version.getAsString();
auto platform = target->GetPlatform();
bool is_simulator = platform->GetPluginName().ends_with("-simulator");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really not have a nicer way to tell if a Platform is a simulator?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's Triple::isSimulatorEnvironment but it's unclear if that applies here, based on the comment:

// The simulators look like the host OS to Process, but Platform
// can get the version out of an environment variable.

if (is_simulator) {
// The simulators look like the host OS to Process, but Platform
// can get the version out of an environment variable.
os_vers << platform->GetOSVersion(process_sp.get()).getAsString();
} else {
llvm::VersionTuple version = process_sp->GetHostOSVersion();
os_vers << version.getAsString();
}
}
}
}
Expand Down
104 changes: 95 additions & 9 deletions lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/OptionParsing.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/Timer.h"
#include "lldb/ValueObject/ValueObject.h"
Expand Down Expand Up @@ -835,7 +836,7 @@ SwiftLanguageRuntime::GetObjectDescriptionExpr_Ref(ValueObject &object) {
object.GetValueAsUnsigned(0)).str();

if (log)
log->Printf("[GetObjectDescriptionExpr_Result] expression: %s",
log->Printf("[GetObjectDescriptionExpr_Ref] expression: %s",
expr_string.GetData());
return expr_str;
}
Expand Down Expand Up @@ -911,25 +912,27 @@ std::string SwiftLanguageRuntime::GetObjectDescriptionExpr_Copy(
return expr_string;
}

llvm::Error SwiftLanguageRuntime::RunObjectDescriptionExpr(
ValueObject &object, std::string &expr_string, Stream &result) {
static llvm::Expected<ValueObjectSP>
RunObjectDescription(ValueObject &object, std::string &expr_string,
Process &process, bool context_free = false) {
Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions));
ValueObjectSP result_sp;
EvaluateExpressionOptions eval_options;
eval_options.SetUnwindOnError(true);
eval_options.SetLanguage(lldb::eLanguageTypeSwift);
eval_options.SetSuppressPersistentResult(true);
eval_options.SetIgnoreBreakpoints(true);
eval_options.SetTimeout(GetProcess().GetUtilityExpressionTimeout());
eval_options.SetTimeout(process.GetUtilityExpressionTimeout());
if (context_free)
eval_options.SetUseContextFreeSwiftPrintObject();

StackFrameSP frame_sp = object.GetFrameSP();
if (!frame_sp)
frame_sp =
GetProcess().GetThreadList().GetSelectedThread()->GetSelectedFrame(
DoNoSelectMostRelevantFrame);
frame_sp = process.GetThreadList().GetSelectedThread()->GetSelectedFrame(
DoNoSelectMostRelevantFrame);
if (!frame_sp)
return llvm::createStringError("no execution context to run expression in");
auto eval_result = GetProcess().GetTarget().EvaluateExpression(
auto eval_result = process.GetTarget().EvaluateExpression(
expr_string, frame_sp.get(), result_sp, eval_options);

LLDB_LOG(log, "[RunObjectDescriptionExpr] {0}", toString(eval_result));
Expand All @@ -952,12 +955,17 @@ llvm::Error SwiftLanguageRuntime::RunObjectDescriptionExpr(
return llvm::createStringError("expression produced invalid result type");
}

return result_sp;
}

static llvm::Error DumpString(ValueObjectSP result_sp, Stream &strm) {
Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions));
formatters::StringPrinter::ReadStringAndDumpToStreamOptions dump_options;
dump_options.SetEscapeNonPrintables(false);
dump_options.SetQuote('\0');
dump_options.SetPrefixToken(nullptr);
if (formatters::swift::String_SummaryProvider(
*result_sp.get(), result,
*result_sp, strm,
TypeSummaryOptions()
.SetLanguage(lldb::eLanguageTypeSwift)
.SetCapping(eTypeSummaryUncapped),
Expand All @@ -973,6 +981,15 @@ llvm::Error SwiftLanguageRuntime::RunObjectDescriptionExpr(
return llvm::createStringError("expression produced unprintable string");
}

llvm::Error SwiftLanguageRuntime::RunObjectDescriptionExpr(
ValueObject &object, std::string &expr_string, Stream &strm) {
auto result_or_err = RunObjectDescription(object, expr_string, GetProcess());
if (!result_or_err)
return result_or_err.takeError();

return DumpString(*result_or_err, strm);
}

static bool IsVariable(ValueObject &object) {
if (object.IsSynthetic())
return IsVariable(*object.GetNonSyntheticValue());
Expand Down Expand Up @@ -1002,11 +1019,80 @@ static bool IsSwiftReferenceType(ValueObject &object) {
return false;
}

static llvm::Error PrintObjectViaPointer(Stream &strm, ValueObject &object,
Process &process) {
Flags flags(object.GetCompilerType().GetTypeInfo());
addr_t addr = LLDB_INVALID_ADDRESS;
if (flags.Test(eTypeInstanceIsPointer)) {
// Objects are pointers.
addr = object.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use GetValueAsAddress.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetValueAsAddress is on SBValue, I don't see an equivalent on ValueObject.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised we don't have a little wrapper for this in ValueObject, but you can do what GetValueAsAddress does, and call FixDataAddress of the addr you get back.

@jasonmolenda will know for sure whether that's the right thing to do.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah if it's guaranteed to be an address it's safe to run it through Process::FixAnyAddress() (the method to use when you don't know if it's an address of code or data). With MTE managed heap, if the value might get put into a jitted expression (so used in code running in the inferior, with MTE) you need to retain the MTE nibble in the top byte. It's an edge case but something to mention, @felipepiovezan dealt with a tricky case where we needed to maintain metadata bits through to the point where we looked it up/use it, just recently, for something that ended up in a jitted expression.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasonmolenda thanks, this address is data, and will be used in a jitted expression.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a call to FixDataAddress.

addr = process.FixDataAddress(addr);
} else {
// Get the address of non-object values (structs, enums).
auto addr_and_type = object.GetAddressOf(false);
if (addr_and_type.type != eAddressTypeLoad) {
return llvm::createStringError("address-of value object failed");
}
addr = addr_and_type.address;
}

if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
return llvm::createStringError("invalid address 0x%x", addr);

StringRef mangled_type_name = object.GetMangledTypeName();
// Swift APIs that receive mangled names require the prefix removed.
mangled_type_name.consume_front("$s");
mangled_type_name.consume_front("$e"); // Embedded Swift prefix

std::string expr_string =
llvm::formatv(
"Swift._DebuggerSupport.stringForPrintObject(UnsafeRawPointer("
"bitPattern: {0}), mangledTypeName: \"{1}\")",
addr, mangled_type_name)
.str();

auto result_or_err = RunObjectDescription(object, expr_string, process, true);
if (!result_or_err)
return result_or_err.takeError();

// A `(Bool, String)` tuple, where the bool indicates success/failure.
auto result_sp = *result_or_err;
auto success_sp = result_sp->GetChildAtIndex(0);
auto description_sp = result_sp->GetChildAtIndex(1);

StreamString string_result;
auto err = DumpString(description_sp, string_result);
if (err) {
return llvm::joinErrors(
std::move(err),
llvm::createStringError("decoding of description String failed"));
}

Status status;
if (!success_sp->IsLogicalTrue(status))
// The Bool is false, which means the String is an error message.
return llvm::createStringError(string_result.GetData());

strm.PutCString(string_result.GetString());
return llvm::Error::success();
}

llvm::Error SwiftLanguageRuntime::GetObjectDescription(Stream &str,
ValueObject &object) {
if (object.IsUninitializedReference())
return llvm::createStringError("<uninitialized>");

Log *log = GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions);
if (GetProcess().GetTarget().GetSwiftUseContextFreePrintObject()) {
if (auto err = PrintObjectViaPointer(str, object, GetProcess())) {
LLDB_LOG_ERROR(log, std::move(err),
"stringForPrintObject(_:mangledTypeName) failed: {0}");
} else {
LLDB_LOG(log, "stringForPrintObject(_:mangledTypeName:) succeeded");
return llvm::Error::success();
}
}

std::string expr_string;

if (::IsVariable(object) || ::IsSwiftResultVariable(object.GetName())) {
Expand Down
12 changes: 12 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4705,6 +4705,18 @@ bool TargetProperties::GetSwiftAutoImportFrameworks() const {
idx, g_target_properties[idx].default_uint_value != 0);
}

bool TargetProperties::GetSwiftUseContextFreePrintObject() const {
const Property *exp_property =
m_collection_sp->GetPropertyAtIndex(ePropertyExperimental);
OptionValueProperties *exp_values =
exp_property->GetValue()->GetAsProperties();
if (exp_values)
return exp_values
->GetPropertyAtIndexAs<bool>(ePropertySwiftUseContextFreePrintObject)
.value_or(false);
return false;
}

void TargetProperties::SetUseDIL(ExecutionContext *exe_ctx, bool b) {
const Property *exp_property =
m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx);
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ let Definition = "target_experimental" in {
def SwiftCacheTaskPointerLocation: Property<"swift-cache-task-pointer-location", "Boolean">,
DefaultTrue,
Desc<"Enables caching of task pointers inside the swift tasks plugin">;
def SwiftUseContextFreePrintObject: Property<"swift-use-context-free-po", "Boolean">,
DefaultFalse,
Desc<"If true, use the context-free po implementation for Swift.">;
def UseDIL : Property<"use-DIL", "Boolean">,
Global, DefaultTrue,
Desc<"If true, use the DIL implementation for frame variable evaluation.">;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def test_missing_type(self):
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
self, 'break here', lldb.SBFileSpec('main.swift'))

self.runCmd("settings set target.experimental.swift-use-context-free-po true")

options = lldb.SBExpressionOptions()
value = self.frame().EvaluateExpression("strct", options)
def check(value):
Expand All @@ -81,12 +83,14 @@ def check(value):

check(value)

# This succeeds using stringForPrintObject(_:mangledTypeName:), which
# doesn't require the type to be available.
# Note: (?s)^(?!.*<pattern>) checks that the pattern is not found.
self.expect(
"dwim-print -O -- strct",
substrs=["error: Missing type", "properties = true"],
patterns=["(?s)^(?!.*error: Missing type)", "properties : true"],
)

process.Continue()
self.expect('expression -O -- number', error=True,
substrs=['self', 'not', 'found'])

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SWIFT_SOURCES := main.swift
SWIFTFLAGS_EXTRAS := -parse-as-library
include Makefile.rules
Loading