-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LLDB] Add framework for Data Inspection Language (DIL) work. #115666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add the framework code for hooking up and calling the Data Inspection Language (DIL) implementation, as an alternate implementation for the 'frame variable' command. For now, this is an opt-in option, via a target setting 'target.experimental.use-DIL'. See https://discourse.llvm.org/t/rfc-data-inspection-language/69893 for more information about this project. This PR does not actually call any of the DIL code; instead the piece that will eventually call the DIL code (StackFrame::DILEvaluateVariableExpression) calls back into the original 'frame variable' implementation.
@llvm/pr-subscribers-lldb Author: None (cmtice) ChangesAdd the framework code for hooking up and calling the Data Inspection Language (DIL) implementation, as an alternate implementation for the 'frame variable' command. For now, this is an opt-in option, via a target setting 'target.experimental.use-DIL'. See This PR does not actually call any of the DIL code; instead the piece that will eventually call the DIL code (StackFrame::DILEvaluateVariableExpression) calls back into the original 'frame variable' implementation. Full diff: https://github.com/llvm/llvm-project/pull/115666.diff 10 Files Affected:
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index 3881137583b941..03128447b5d496 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -308,6 +308,35 @@ class StackFrame : public ExecutionContextScope,
llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
uint32_t options, lldb::VariableSP &var_sp, Status &error);
+ /// Create a ValueObject for a variable name / pathname, possibly including
+ /// simple dereference/child selection syntax.
+ ///
+ /// \param[in] var_expr
+ /// The string specifying a variable to base the VariableObject off
+ /// of.
+ ///
+ /// \param[in] use_dynamic
+ /// Whether the correct dynamic type of an object pointer should be
+ /// determined before creating the object, or if the static type is
+ /// sufficient. One of the DynamicValueType enumerated values.
+ ///
+ /// \param[in] options
+ /// An unsigned integer of flags, values from
+ /// StackFrame::ExpressionPathOption
+ /// enum.
+ /// \param[in] var_sp
+ /// A VariableSP that will be set to the variable described in the
+ /// var_expr path.
+ ///
+ /// \param[in] error
+ /// Record any errors encountered while evaluating var_expr.
+ ///
+ /// \return
+ /// A shared pointer to the ValueObject described by var_expr.
+ lldb::ValueObjectSP DILEvaluateVariableExpression(
+ llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
+ uint32_t options, lldb::VariableSP &var_sp, Status &error);
+
/// Determine whether this StackFrame has debug information available or not.
///
/// \return
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index cab21c29a7486f..b5becfb0e4fe17 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -252,6 +252,10 @@ class TargetProperties : public Properties {
bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const;
+ bool GetUseDIL(ExecutionContext *exe_ctx) const;
+
+ void SetUseDIL(ExecutionContext *exe_ctx, bool b);
+
void SetRequireHardwareBreakpoints(bool b);
bool GetRequireHardwareBreakpoints() const;
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index dc41e80b457d7d..4e3e47b7a5f60b 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -472,6 +472,7 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
StackFrame *frame = nullptr;
Target *target = exe_ctx.GetTargetPtr();
Process *process = exe_ctx.GetProcessPtr();
+ bool use_DIL = target->GetUseDIL(&exe_ctx);
if (target && process) {
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&process->GetRunLock())) {
@@ -479,11 +480,22 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
if (frame) {
VariableSP var_sp;
Status error;
- ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
- var_path, eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember |
- StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
- var_sp, error));
+ ValueObjectSP value_sp;
+ if (use_DIL) {
+ // Use DIL parser/evaluator.
+ value_sp = frame->DILEvaluateVariableExpression(
+ var_path, eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+ var_sp, error);
+ } else {
+ // Use original frame function.
+ value_sp = frame->GetValueForVariableExpressionPath(
+ var_path, eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+ var_sp, error);
+ }
sb_value.SetSP(value_sp, use_dynamic);
}
}
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index a5709b36f52ee2..7e0651657482bb 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -517,7 +517,10 @@ may even involve JITing and running code in the target program.)");
result.AppendError(error.AsCString());
}
+ VariableSP var_sp;
ValueObjectSP valobj_sp;
+ TargetSP target_sp = frame->CalculateTarget();
+ bool use_DIL = target_sp->GetUseDIL(&m_exe_ctx);
TypeSummaryImplSP summary_format_sp;
if (!m_option_variable.summary.IsCurrentValueEmpty())
@@ -600,9 +603,17 @@ may even involve JITing and running code in the target program.)");
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
lldb::VariableSP var_sp;
- valobj_sp = frame->GetValueForVariableExpressionPath(
- entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
- var_sp, error);
+ if (use_DIL) {
+ // Use the DIL parser/evaluator.
+ valobj_sp = frame->DILEvaluateVariableExpression(
+ entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
+ var_sp, error);
+ } else {
+ // Original 'frame variable' execution path
+ valobj_sp = frame->GetValueForVariableExpressionPath(
+ entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
+ var_sp, error);
+ }
if (valobj_sp) {
std::string scope_string;
if (m_option_variable.show_scope)
@@ -641,7 +652,7 @@ may even involve JITing and running code in the target program.)");
const size_t num_variables = variable_list->GetSize();
if (num_variables > 0) {
for (size_t i = 0; i < num_variables; i++) {
- VariableSP var_sp = variable_list->GetVariableAtIndex(i);
+ var_sp = variable_list->GetVariableAtIndex(i);
if (!ScopeRequested(var_sp->GetScope()))
continue;
std::string scope_string;
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index 766d650a2ca070..6eaefcef4398f4 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -806,6 +806,7 @@ corresponding to the byte size of the data type.");
void DoExecute(Args &command, CommandReturnObject &result) override {
Target &target = GetTarget();
StackFrame *frame = m_exe_ctx.GetFramePtr();
+ bool use_DIL = target.GetUseDIL(&m_exe_ctx);
// If no argument is present, issue an error message. There's no way to
// set a watchpoint.
@@ -840,9 +841,16 @@ corresponding to the byte size of the data type.");
uint32_t expr_path_options =
StackFrame::eExpressionPathOptionCheckPtrVsMember |
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
- valobj_sp = frame->GetValueForVariableExpressionPath(
- command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
- var_sp, error);
+ if (use_DIL)
+ // Use the DIL parser/evaluator.
+ valobj_sp = frame->DILEvaluateVariableExpression(
+ command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
+ var_sp, error);
+ else
+ // Use the original frame function.
+ valobj_sp = frame->GetValueForVariableExpressionPath(
+ command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
+ var_sp, error);
if (!valobj_sp) {
// Not in the frame; let's check the globals.
diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp
index ed3734cbb943f6..bcfc25ff40b537 100644
--- a/lldb/source/Expression/UserExpression.cpp
+++ b/lldb/source/Expression/UserExpression.cpp
@@ -110,13 +110,28 @@ lldb::ValueObjectSP UserExpression::GetObjectPointerValueObject(
lldb::VariableSP var_sp;
lldb::ValueObjectSP valobj_sp;
- return frame_sp->GetValueForVariableExpressionPath(
- object_name, lldb::eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember |
- StackFrame::eExpressionPathOptionsNoFragileObjcIvar |
- StackFrame::eExpressionPathOptionsNoSyntheticChildren |
- StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
- var_sp, err);
+ lldb::TargetSP target_sp = frame_sp->CalculateTarget();
+ ExecutionContext exe_ctx;
+ frame_sp->CalculateExecutionContext(exe_ctx);
+ bool use_DIL = target_sp->GetUseDIL(&exe_ctx);
+
+ if (use_DIL) {
+ return frame_sp->DILEvaluateVariableExpression(
+ object_name, lldb::eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar |
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren |
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var_sp, err);
+ } else {
+ return frame_sp->GetValueForVariableExpressionPath(
+ object_name, lldb::eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar |
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren |
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var_sp, err);
+ }
}
lldb::addr_t UserExpression::GetObjectPointer(lldb::StackFrameSP frame_sp,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
index e53e930665a602..270aa1481994c8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
@@ -56,8 +56,19 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die,
if (auto frame = exe_ctx->GetFrameSP()) {
Status error;
lldb::VariableSP var_sp;
- auto valobj_sp = frame->GetValueForVariableExpressionPath(
- var_die.GetName(), eNoDynamicValues, 0, var_sp, error);
+ lldb::TargetSP target_sp = frame->CalculateTarget();
+ bool use_DIL = target_sp->GetUseDIL(
+ (lldb_private::ExecutionContext *)exe_ctx);
+ lldb::ValueObjectSP valobj_sp;
+ if (use_DIL) {
+ // Use the DIL parser/evaluator.
+ valobj_sp = frame->DILEvaluateVariableExpression(
+ var_die.GetName(), eNoDynamicValues, 0, var_sp, error);
+ } else {
+ // Use the original frame function.
+ valobj_sp = frame->GetValueForVariableExpressionPath(
+ var_die.GetName(), eNoDynamicValues, 0, var_sp, error);
+ }
if (valobj_sp) {
num_elements = valobj_sp->GetValueAsUnsigned(0);
break;
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 3761b867452c99..83d8cbb440ad9d 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -505,6 +505,15 @@ StackFrame::GetInScopeVariableList(bool get_file_globals,
return var_list_sp;
}
+ValueObjectSP StackFrame::DILEvaluateVariableExpression(
+ llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
+ uint32_t options, lldb::VariableSP &var_sp, Status &error) {
+ // This is a place-holder for the calls into the DIL parser and
+ // evaluator. For now, just call the "real" frame variable implementation.
+ return GetValueForVariableExpressionPath(var_expr, use_dynamic, options,
+ var_sp, error);
+}
+
ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options,
VariableSP &var_sp, Status &error) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 242d2eaec2a15a..57ecbbc29bce64 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -4385,6 +4385,27 @@ bool TargetProperties::GetInjectLocalVariables(
.value_or(true);
}
+bool TargetProperties::GetUseDIL(ExecutionContext *exe_ctx) const {
+ const Property *exp_property =
+ m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx);
+ OptionValueProperties *exp_values =
+ exp_property->GetValue()->GetAsProperties();
+ if (exp_values)
+ return exp_values->GetPropertyAtIndexAs<bool>(ePropertyUseDIL, exe_ctx)
+ .value_or(false);
+ else
+ return true;
+}
+
+void TargetProperties::SetUseDIL(ExecutionContext *exe_ctx, bool b) {
+ const Property *exp_property =
+ m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx);
+ OptionValueProperties *exp_values =
+ exp_property->GetValue()->GetAsProperties();
+ if (exp_values)
+ exp_values->SetPropertyAtIndex(ePropertyUseDIL, true, exe_ctx);
+}
+
ArchSpec TargetProperties::GetDefaultArchitecture() const {
const uint32_t idx = ePropertyDefaultArch;
return GetPropertyAtIndexAs<ArchSpec>(idx, {});
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index 00ad8dd2a9f7f9..8978a4a143b6f7 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -4,6 +4,9 @@ let Definition = "target_experimental" in {
def InjectLocalVars : Property<"inject-local-vars", "Boolean">,
Global, DefaultTrue,
Desc<"If true, inject local variables explicitly into the expression text. This will fix symbol resolution when there are name collisions between ivars and local variables. But it can make expressions run much more slowly.">;
+ def UseDIL : Property<"use-DIL", "Boolean">,
+ Global, DefaultFalse,
+ Desc<"If true, use the alternative DIL implementation for frame variable evaluation.">;
}
let Definition = "target" in {
|
IIUC, the goal is that In the end, DIL will win and there will only be one VariableExpressionPath interface in lldb. So it seems inefficient for the interim stage to introduce another function and switch between them with UseDIL all over the code. Why not leave GetValueForVariableExpressionPath for now, and move the That will make the diff much smaller, and in the end mean that pulling the switch to use only the DIL will be less disruptive. |
var_die.GetName(), eNoDynamicValues, 0, var_sp, error); | ||
lldb::TargetSP target_sp = frame->CalculateTarget(); | ||
bool use_DIL = target_sp->GetUseDIL( | ||
(lldb_private::ExecutionContext *)exe_ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this cast wouldn't be required if you changed GetExperimentalPropertyValue
to take a const execution context (all of the functions below it already take a const argument)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code & cast are gone now.
+1 to what Jim said. You could keep |
Remove redundant calculations of 'use_DIL'. Make StackFrame::GetValueForVariableExpressionPath the gating function that dispatches to either DILGetValueForVariableExpressionPath or LegacyGetValueForVariableExpressionPath.
I've updated the code as Jim and Pavel suggested. :-) |
lldb::ValueObjectSP LegacyGetValueForVariableExpressionPath( | ||
llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, | ||
uint32_t options, lldb::VariableSP &var_sp, Status &error); | ||
|
||
/// Create a ValueObject for a variable name / pathname, possibly including | ||
/// simple dereference/child selection syntax. | ||
/// | ||
/// \param[in] var_expr | ||
/// The string specifying a variable to base the VariableObject off | ||
/// of. | ||
/// | ||
/// \param[in] use_dynamic | ||
/// Whether the correct dynamic type of an object pointer should be | ||
/// determined before creating the object, or if the static type is | ||
/// sufficient. One of the DynamicValueType enumerated values. | ||
/// | ||
/// \param[in] options | ||
/// An unsigned integer of flags, values from | ||
/// StackFrame::ExpressionPathOption | ||
/// enum. | ||
/// \param[in] var_sp | ||
/// A VariableSP that will be set to the variable described in the | ||
/// var_expr path. | ||
/// | ||
/// \param[in] error | ||
/// Record any errors encountered while evaluating var_expr. | ||
/// | ||
/// \return | ||
/// A shared pointer to the ValueObject described by var_expr. | ||
lldb::ValueObjectSP DILGetValueForVariableExpressionPath( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these be private (they should only be called from the dispatcher function, right)?
(You can attach the doxygen comment to the public function, there's no need to repeat it everywhere)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
lldb/source/Target/StackFrame.cpp
Outdated
if (use_DIL) | ||
return DILGetValueForVariableExpressionPath(var_expr, use_dynamic, options, | ||
var_sp, error); | ||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return
(I also think the comments in this method don't tell us anything that's not immediately obvious from the code. I'd just remove them.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
lldb/source/Target/StackFrame.cpp
Outdated
lldb::TargetSP target_sp = CalculateTarget(); | ||
ExecutionContext exe_ctx; | ||
CalculateExecutionContext(exe_ctx); | ||
bool use_DIL = target_sp->GetUseDIL(&exe_ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lldb::TargetSP target_sp = CalculateTarget(); | |
ExecutionContext exe_ctx; | |
CalculateExecutionContext(exe_ctx); | |
bool use_DIL = target_sp->GetUseDIL(&exe_ctx); | |
ExecutionContext exe_ctx; | |
CalculateExecutionContext(exe_ctx); | |
bool use_DIL = exe_ctx.GetTargetRef().GetUseDIL(&exe_ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return exp_values->GetPropertyAtIndexAs<bool>(ePropertyUseDIL, exe_ctx) | ||
.value_or(false); | ||
else | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be false
as well? Otherwise DIL will be enabled if exp_values
is not available (not sure when this happens though).
- Make LegacyGetValueForVariableExpressionPath and DILGetValueForVariableExpressionPath private. - Remove redundant or useless comments. - Clean up definition of use_DIL slightly.
Add the framework code for hooking up and calling the Data Inspection Language (DIL) implementation, as an alternate implementation for the 'frame variable' command. For now, this is an opt-in option, via a target setting 'target.experimental.use-DIL'. See
https://discourse.llvm.org/t/rfc-data-inspection-language/69893 for more information about this project.
This PR does not actually call any of the DIL code; instead the piece that will eventually call the DIL code (StackFrame::DILEvaluateVariableExpression) calls back into the original 'frame variable' implementation.