[lldb] Store the return SBValueList in the CommandReturnObject (#127566)
There are a lot of lldb commands whose result is really one or more ValueObjects that we then print with the ValueObjectPrinter. Now that we have the ability to access the SBCommandReturnObject through a callback (#125006), we can store the resultant ValueObjects in the return object, allowing an IDE to access the SBValues and do its own rich formatting. rdar://143965453
This commit is contained in:
parent
b0e24d17f2
commit
f62f13d5db
@ -136,6 +136,8 @@ public:
|
||||
|
||||
void SetError(const char *error_cstr);
|
||||
|
||||
lldb::SBValueList GetValues(lldb::DynamicValueType use_dynamic);
|
||||
|
||||
protected:
|
||||
friend class SBCommandInterpreter;
|
||||
friend class SBOptions;
|
||||
|
@ -442,6 +442,7 @@ public:
|
||||
|
||||
protected:
|
||||
friend class SBBlock;
|
||||
friend class SBCommandReturnObject;
|
||||
friend class SBFrame;
|
||||
friend class SBModule;
|
||||
friend class SBTarget;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "lldb/Utility/StreamString.h"
|
||||
#include "lldb/Utility/StreamTee.h"
|
||||
#include "lldb/Utility/StructuredData.h"
|
||||
#include "lldb/ValueObject/ValueObjectList.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@ -134,7 +135,7 @@ public:
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
template <typename... Args>
|
||||
void AppendMessageWithFormatv(const char *format, Args &&... args) {
|
||||
void AppendMessageWithFormatv(const char *format, Args &&...args) {
|
||||
AppendMessage(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
@ -144,12 +145,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void AppendWarningWithFormatv(const char *format, Args &&... args) {
|
||||
void AppendWarningWithFormatv(const char *format, Args &&...args) {
|
||||
AppendWarning(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void AppendErrorWithFormatv(const char *format, Args &&... args) {
|
||||
void AppendErrorWithFormatv(const char *format, Args &&...args) {
|
||||
AppendError(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
@ -165,6 +166,10 @@ public:
|
||||
return m_diagnostic_indent;
|
||||
}
|
||||
|
||||
const ValueObjectList &GetValueObjectList() const { return m_value_objects; }
|
||||
|
||||
ValueObjectList &GetValueObjectList() { return m_value_objects; }
|
||||
|
||||
lldb::ReturnStatus GetStatus() const;
|
||||
|
||||
void SetStatus(lldb::ReturnStatus status);
|
||||
@ -197,6 +202,9 @@ private:
|
||||
|
||||
lldb::ReturnStatus m_status = lldb::eReturnStatusStarted;
|
||||
|
||||
/// An optionally empty list of values produced by this command.
|
||||
ValueObjectList m_value_objects;
|
||||
|
||||
bool m_did_change_process_state = false;
|
||||
bool m_suppress_immediate_output = false;
|
||||
|
||||
|
@ -22,8 +22,6 @@ class ValueObject;
|
||||
/// A collection of ValueObject values that.
|
||||
class ValueObjectList {
|
||||
public:
|
||||
const ValueObjectList &operator=(const ValueObjectList &rhs);
|
||||
|
||||
void Append(const lldb::ValueObjectSP &val_obj_sp);
|
||||
|
||||
void Append(const ValueObjectList &valobj_list);
|
||||
|
@ -12,11 +12,14 @@
|
||||
#include "lldb/API/SBFile.h"
|
||||
#include "lldb/API/SBStream.h"
|
||||
#include "lldb/API/SBStructuredData.h"
|
||||
#include "lldb/API/SBValue.h"
|
||||
#include "lldb/API/SBValueList.h"
|
||||
#include "lldb/Core/StructuredDataImpl.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Utility/ConstString.h"
|
||||
#include "lldb/Utility/Instrumentation.h"
|
||||
#include "lldb/Utility/Status.h"
|
||||
#include "lldb/lldb-forward.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
@ -356,3 +359,18 @@ void SBCommandReturnObject::SetError(const char *error_cstr) {
|
||||
if (error_cstr)
|
||||
ref().AppendError(error_cstr);
|
||||
}
|
||||
|
||||
SBValueList
|
||||
SBCommandReturnObject::GetValues(lldb::DynamicValueType use_dynamic) {
|
||||
LLDB_INSTRUMENT_VA(this, use_dynamic);
|
||||
|
||||
SBValueList value_list;
|
||||
for (ValueObjectSP value_object_sp :
|
||||
ref().GetValueObjectList().GetObjects()) {
|
||||
SBValue value_sb;
|
||||
value_sb.SetSP(value_object_sp, use_dynamic);
|
||||
value_list.Append(value_sb);
|
||||
}
|
||||
|
||||
return value_list;
|
||||
}
|
||||
|
@ -205,6 +205,9 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
|
||||
ExpressionResults expr_result = target.EvaluateExpression(
|
||||
expr, exe_scope, valobj_sp, eval_options, &fixed_expression);
|
||||
|
||||
if (valobj_sp)
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
|
||||
// Record the position of the expression in the command.
|
||||
std::optional<uint16_t> indent;
|
||||
if (fixed_expression.empty()) {
|
||||
|
@ -434,6 +434,8 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
|
||||
}
|
||||
|
||||
if (result_valobj_sp) {
|
||||
result.GetValueObjectList().Append(result_valobj_sp);
|
||||
|
||||
Format format = m_format_options.GetFormat();
|
||||
|
||||
if (result_valobj_sp->GetError().Success()) {
|
||||
|
@ -152,6 +152,7 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
DumpValueObjectOptions::DeclPrintingHelper helper =
|
||||
[&valobj_sp](ConstString type, ConstString var,
|
||||
const DumpValueObjectOptions &opts,
|
||||
@ -317,10 +318,10 @@ protected:
|
||||
} else if (*m_options.relative_frame_offset > 0) {
|
||||
// I don't want "up 20" where "20" takes you past the top of the stack
|
||||
// to produce an error, but rather to just go to the top. OTOH, start
|
||||
// by seeing if the requested frame exists, in which case we can avoid
|
||||
// by seeing if the requested frame exists, in which case we can avoid
|
||||
// counting the stack here...
|
||||
const uint32_t frame_requested = frame_idx
|
||||
+ *m_options.relative_frame_offset;
|
||||
const uint32_t frame_requested =
|
||||
frame_idx + *m_options.relative_frame_offset;
|
||||
StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
|
||||
if (frame_sp)
|
||||
frame_idx = frame_requested;
|
||||
@ -515,8 +516,8 @@ protected:
|
||||
|
||||
if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
|
||||
result.AppendError(error.AsCString());
|
||||
|
||||
}
|
||||
|
||||
ValueObjectSP valobj_sp;
|
||||
|
||||
TypeSummaryImplSP summary_format_sp;
|
||||
@ -564,6 +565,8 @@ protected:
|
||||
valobj_sp = frame->GetValueObjectForFrameVariable(
|
||||
var_sp, m_varobj_options.use_dynamic);
|
||||
if (valobj_sp) {
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
|
||||
std::string scope_string;
|
||||
if (m_option_variable.show_scope)
|
||||
scope_string = GetScopeString(var_sp).str();
|
||||
@ -604,6 +607,8 @@ protected:
|
||||
entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
|
||||
var_sp, error);
|
||||
if (valobj_sp) {
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
|
||||
std::string scope_string;
|
||||
if (m_option_variable.show_scope)
|
||||
scope_string = GetScopeString(var_sp).str();
|
||||
@ -653,6 +658,8 @@ protected:
|
||||
valobj_sp = frame->GetValueObjectForFrameVariable(
|
||||
var_sp, m_varobj_options.use_dynamic);
|
||||
if (valobj_sp) {
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
|
||||
// When dumping all variables, don't print any variables that are
|
||||
// not in scope to avoid extra unneeded output
|
||||
if (valobj_sp->IsInScope()) {
|
||||
@ -694,6 +701,7 @@ protected:
|
||||
recognized_frame->GetRecognizedArguments();
|
||||
if (recognized_arg_list) {
|
||||
for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
|
||||
result.GetValueObjectList().Append(rec_value_sp);
|
||||
options.SetFormat(m_option_format.GetFormat());
|
||||
options.SetVariableFormatDisplayLanguage(
|
||||
rec_value_sp->GetPreferredDisplayLanguage());
|
||||
|
@ -803,7 +803,9 @@ public:
|
||||
protected:
|
||||
void DumpGlobalVariableList(const ExecutionContext &exe_ctx,
|
||||
const SymbolContext &sc,
|
||||
const VariableList &variable_list, Stream &s) {
|
||||
const VariableList &variable_list,
|
||||
CommandReturnObject &result) {
|
||||
Stream &s = result.GetOutputStream();
|
||||
if (variable_list.Empty())
|
||||
return;
|
||||
if (sc.module_sp) {
|
||||
@ -824,15 +826,16 @@ protected:
|
||||
ValueObjectSP valobj_sp(ValueObjectVariable::Create(
|
||||
exe_ctx.GetBestExecutionContextScope(), var_sp));
|
||||
|
||||
if (valobj_sp)
|
||||
if (valobj_sp) {
|
||||
result.GetValueObjectList().Append(valobj_sp);
|
||||
DumpValueObject(s, var_sp, valobj_sp, var_sp->GetName().GetCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoExecute(Args &args, CommandReturnObject &result) override {
|
||||
Target *target = m_exe_ctx.GetTargetPtr();
|
||||
const size_t argc = args.GetArgumentCount();
|
||||
Stream &s = result.GetOutputStream();
|
||||
|
||||
if (argc > 0) {
|
||||
for (const Args::ArgEntry &arg : args) {
|
||||
@ -874,7 +877,7 @@ protected:
|
||||
m_exe_ctx.GetBestExecutionContextScope(), var_sp);
|
||||
|
||||
if (valobj_sp)
|
||||
DumpValueObject(s, var_sp, valobj_sp,
|
||||
DumpValueObject(result.GetOutputStream(), var_sp, valobj_sp,
|
||||
use_var_name ? var_sp->GetName().GetCString()
|
||||
: arg.c_str());
|
||||
}
|
||||
@ -903,7 +906,8 @@ protected:
|
||||
if (comp_unit_varlist_sp) {
|
||||
size_t count = comp_unit_varlist_sp->GetSize();
|
||||
if (count > 0) {
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp,
|
||||
result);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
@ -964,7 +968,8 @@ protected:
|
||||
VariableListSP comp_unit_varlist_sp(
|
||||
sc.comp_unit->GetVariableList(can_create));
|
||||
if (comp_unit_varlist_sp)
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp,
|
||||
result);
|
||||
} else if (sc.module_sp) {
|
||||
// Get all global variables for this module
|
||||
lldb_private::RegularExpression all_globals_regex(
|
||||
@ -972,7 +977,7 @@ protected:
|
||||
VariableList variable_list;
|
||||
sc.module_sp->FindGlobalVariables(all_globals_regex, UINT32_MAX,
|
||||
variable_list);
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, variable_list, s);
|
||||
DumpGlobalVariableList(m_exe_ctx, sc, variable_list, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,6 @@
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
const ValueObjectList &ValueObjectList::operator=(const ValueObjectList &rhs) {
|
||||
if (this != &rhs)
|
||||
m_value_objects = rhs.m_value_objects;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ValueObjectList::Append(const ValueObjectSP &val_obj_sp) {
|
||||
m_value_objects.push_back(val_obj_sp);
|
||||
}
|
||||
|
@ -33,3 +33,16 @@ class TestSBCommandReturnObject(TestBase):
|
||||
ci.HandleCommand("help help", res)
|
||||
self.assertTrue(res.Succeeded())
|
||||
self.assertEqual(res.GetCommand(), "help help")
|
||||
|
||||
value_list = res.GetValues(lldb.eNoDynamicValues)
|
||||
self.assertEqual(value_list.GetSize(), 0)
|
||||
|
||||
def test_get_value(self):
|
||||
res = lldb.SBCommandReturnObject()
|
||||
ci = self.dbg.GetCommandInterpreter()
|
||||
ci.HandleCommand("p 1 + 1", res)
|
||||
self.assertTrue(res.Succeeded())
|
||||
|
||||
value_list = res.GetValues(lldb.eNoDynamicValues)
|
||||
self.assertEqual(value_list.GetSize(), 1)
|
||||
self.assertEqual(value_list.GetValueAtIndex(0).GetValue(), "2")
|
||||
|
@ -2,7 +2,6 @@
|
||||
Make sure the frame variable -g, -a, and -l flags work.
|
||||
"""
|
||||
|
||||
|
||||
import lldb
|
||||
import lldbsuite.test.lldbutil as lldbutil
|
||||
from lldbsuite.test.decorators import *
|
||||
@ -79,6 +78,14 @@ class TestFrameVar(TestBase):
|
||||
self.assertNotIn("test_var", output, "Args found a local")
|
||||
self.assertNotIn("g_var", output, "Args found a global")
|
||||
|
||||
value_list = command_result.GetValues(lldb.eNoDynamicValues)
|
||||
self.assertGreaterEqual(value_list.GetSize(), 2)
|
||||
value_names = []
|
||||
for value in value_list:
|
||||
value_names.append(value.GetName())
|
||||
self.assertIn("argc", value_names)
|
||||
self.assertIn("argv", value_names)
|
||||
|
||||
# Just get locals:
|
||||
result = interp.HandleCommand("frame var -a", command_result)
|
||||
self.assertEqual(
|
||||
|
@ -34,3 +34,12 @@ class targetCommandTestCase(TestBase):
|
||||
error=True,
|
||||
substrs=["can't find global variable 'var[0]'"],
|
||||
)
|
||||
|
||||
command_result = lldb.SBCommandReturnObject()
|
||||
result = self.ci.HandleCommand("target var", command_result)
|
||||
value_list = command_result.GetValues(lldb.eNoDynamicValues)
|
||||
self.assertGreaterEqual(value_list.GetSize(), 2)
|
||||
value_names = []
|
||||
for value in value_list:
|
||||
value_names.append(value.GetName())
|
||||
self.assertIn("i", value_names)
|
||||
|
Loading…
x
Reference in New Issue
Block a user