Skip to content

Commit

Permalink
[Expression] Add PersistentExpressionState::GetCompilerTypeFromPersis…
Browse files Browse the repository at this point in the history
…tentDecl

Summary:
PersistentStateExpressions (e.g. ClangPersistentVariables) have the
ability to define types using expressions that persist throughout the
debugging session. GetCompilerTypeFromPersistentDecl is a useful
operation to have if you need to use any of those persistently declared types,
like in CommandObjectMemory.

This decouples clang from CommandObjectMemory and decouples Plugins from
Commands in general.

Differential Revision: https://reviews.llvm.org/D62797

llvm-svn: 363183
  • Loading branch information
bulbazord committed Jun 12, 2019
1 parent 8f4973f commit 5b99928
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 36 deletions.
3 changes: 3 additions & 0 deletions lldb/include/lldb/Expression/ExpressionVariable.h
Expand Up @@ -232,6 +232,9 @@ class PersistentExpressionState : public ExpressionVariableList {
virtual void
RemovePersistentVariable(lldb::ExpressionVariableSP variable) = 0;

virtual llvm::Optional<CompilerType>
GetCompilerTypeFromPersistentDecl(ConstString type_name) = 0;

virtual lldb::addr_t LookupSymbol(ConstString name);

void RegisterExecutionUnit(lldb::IRExecutionUnitSP &execution_unit_sp);
Expand Down
Expand Up @@ -55,6 +55,16 @@ def test_persistent_types(self):
"c = 'l'",
"d = 'l'"]) # persistent types are OK to use for memory read

self.expect(
"memory read foo -t $foobar -x c",
substrs=[
'($foobar) 0x',
' = ',
"a = 'H'",
"b = 'e'",
"c = 'l'",
"d = 'l'"]) # persistent types are OK to use for memory read

self.expect(
"memory read foo -t foobar",
substrs=[
Expand Down
1 change: 0 additions & 1 deletion lldb/source/Commands/CMakeLists.txt
Expand Up @@ -41,7 +41,6 @@ add_lldb_library(lldbCommands
lldbSymbol
lldbTarget
lldbUtility
lldbPluginExpressionParserClang

LINK_COMPONENTS
Support
Expand Down
96 changes: 61 additions & 35 deletions lldb/source/Commands/CommandObjectMemory.cpp
Expand Up @@ -6,32 +6,32 @@
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Decl.h"

#include "CommandObjectMemory.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionGroupOutputFile.h"
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Interpreter/OptionValueLanguage.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/MemoryHistory.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/DataBufferHeap.h"
Expand All @@ -51,7 +51,9 @@ static constexpr OptionDefinition g_read_memory_options[] = {
{LLDB_OPT_SET_1, false, "num-per-line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNumberPerLine, "The number of items per line to display." },
{LLDB_OPT_SET_2, false, "binary", 'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that "
"uses the format, size, count and number per line settings." },
{LLDB_OPT_SET_3, true , "type", 't', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone, "The name of a type to view memory as." },
{LLDB_OPT_SET_3 |
LLDB_OPT_SET_4, true , "type", 't', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeName, "The name of a type to view memory as." },
{LLDB_OPT_SET_4, false, "language", 'x', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLanguage, "The language of the type to view memory as."},
{LLDB_OPT_SET_3, false, "offset", 'E', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount, "How many elements of the specified type to skip before starting to display data." },
{LLDB_OPT_SET_1 |
LLDB_OPT_SET_2 |
Expand All @@ -63,7 +65,7 @@ class OptionGroupReadMemory : public OptionGroup {
public:
OptionGroupReadMemory()
: m_num_per_line(1, 1), m_output_as_binary(false), m_view_as_type(),
m_offset(0, 0) {}
m_offset(0, 0), m_language_for_type(eLanguageTypeUnknown) {}

~OptionGroupReadMemory() override = default;

Expand Down Expand Up @@ -97,6 +99,10 @@ class OptionGroupReadMemory : public OptionGroup {
m_force = true;
break;

case 'x':
error = m_language_for_type.SetValueFromString(option_value);
break;

case 'E':
error = m_offset.SetValueFromString(option_value);
break;
Expand All @@ -115,6 +121,7 @@ class OptionGroupReadMemory : public OptionGroup {
m_view_as_type.Clear();
m_force = false;
m_offset.Clear();
m_language_for_type.Clear();
}

Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
Expand Down Expand Up @@ -277,14 +284,16 @@ class OptionGroupReadMemory : public OptionGroup {

bool AnyOptionWasSet() const {
return m_num_per_line.OptionWasSet() || m_output_as_binary ||
m_view_as_type.OptionWasSet() || m_offset.OptionWasSet();
m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||
m_language_for_type.OptionWasSet();
}

OptionValueUInt64 m_num_per_line;
bool m_output_as_binary;
OptionValueString m_view_as_type;
bool m_force;
OptionValueUInt64 m_offset;
OptionValueLanguage m_language_for_type;
};

// Read memory from the inferior process
Expand Down Expand Up @@ -372,7 +381,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
return false;
}

CompilerType clang_ast_type;
CompilerType compiler_type;
Status error;

const char *view_as_type_cstr =
Expand Down Expand Up @@ -472,26 +481,43 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
exact_match, 1, searched_symbol_files,
type_list);

if (type_list.GetSize() == 0 && lookup_type_name.GetCString() &&
*lookup_type_name.GetCString() == '$') {
if (ClangPersistentVariables *persistent_vars =
llvm::dyn_cast_or_null<ClangPersistentVariables>(
target->GetPersistentExpressionStateForLanguage(
lldb::eLanguageTypeC))) {
clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>(
persistent_vars->GetPersistentDecl(
ConstString(lookup_type_name)));

if (tdecl) {
clang_ast_type.SetCompilerType(
ClangASTContext::GetASTContext(&tdecl->getASTContext()),
reinterpret_cast<lldb::opaque_compiler_type_t>(
const_cast<clang::Type *>(tdecl->getTypeForDecl())));
if (type_list.GetSize() == 0 && lookup_type_name.GetCString()) {
LanguageType language_for_type =
m_memory_options.m_language_for_type.GetCurrentValue();
std::set<LanguageType> languages_to_check;
if (language_for_type != eLanguageTypeUnknown) {
languages_to_check.insert(language_for_type);
} else {
languages_to_check = Language::GetSupportedLanguages();
}

std::set<CompilerType> user_defined_types;
for (auto lang : languages_to_check) {
if (auto *persistent_vars =
target->GetPersistentExpressionStateForLanguage(lang)) {
if (llvm::Optional<CompilerType> type =
persistent_vars->GetCompilerTypeFromPersistentDecl(
lookup_type_name)) {
user_defined_types.emplace(*type);
}
}
}

if (user_defined_types.size() > 1) {
result.AppendErrorWithFormat(
"Mutiple types found matching raw type '%s', please disambiguate "
"by specifying the language with -x",
lookup_type_name.GetCString());
result.SetStatus(eReturnStatusFailed);
return false;
}

if (user_defined_types.size() == 1) {
compiler_type = *user_defined_types.begin();
}
}

if (!clang_ast_type.IsValid()) {
if (!compiler_type.IsValid()) {
if (type_list.GetSize() == 0) {
result.AppendErrorWithFormat("unable to find any types that match "
"the raw type '%s' for full type '%s'\n",
Expand All @@ -501,14 +527,14 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
return false;
} else {
TypeSP type_sp(type_list.GetTypeAtIndex(0));
clang_ast_type = type_sp->GetFullCompilerType();
compiler_type = type_sp->GetFullCompilerType();
}
}

while (pointer_count > 0) {
CompilerType pointer_type = clang_ast_type.GetPointerType();
CompilerType pointer_type = compiler_type.GetPointerType();
if (pointer_type.IsValid())
clang_ast_type = pointer_type;
compiler_type = pointer_type;
else {
result.AppendError("unable make a pointer type\n");
result.SetStatus(eReturnStatusFailed);
Expand All @@ -517,7 +543,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
--pointer_count;
}

llvm::Optional<uint64_t> size = clang_ast_type.GetByteSize(nullptr);
llvm::Optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
if (!size) {
result.AppendErrorWithFormat(
"unable to get the byte size of the type '%s'\n",
Expand Down Expand Up @@ -547,7 +573,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
// options have been set
addr = m_next_addr;
total_byte_size = m_prev_byte_size;
clang_ast_type = m_prev_clang_ast_type;
compiler_type = m_prev_compiler_type;
if (!m_format_options.AnyOptionWasSet() &&
!m_memory_options.AnyOptionWasSet() &&
!m_outfile_options.AnyOptionWasSet() &&
Expand Down Expand Up @@ -634,13 +660,13 @@ class CommandObjectMemoryRead : public CommandObjectParsed {

DataBufferSP data_sp;
size_t bytes_read = 0;
if (clang_ast_type.GetOpaqueQualType()) {
if (compiler_type.GetOpaqueQualType()) {
// Make sure we don't display our type as ASCII bytes like the default
// memory read
if (!m_format_options.GetFormatValue().OptionWasSet())
m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);

llvm::Optional<uint64_t> size = clang_ast_type.GetByteSize(nullptr);
llvm::Optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
if (!size) {
result.AppendError("can't get size of type");
return false;
Expand Down Expand Up @@ -750,7 +776,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
m_prev_memory_options = m_memory_options;
m_prev_outfile_options = m_outfile_options;
m_prev_varobj_options = m_varobj_options;
m_prev_clang_ast_type = clang_ast_type;
m_prev_compiler_type = compiler_type;

StreamFile outfile_stream;
Stream *output_stream = nullptr;
Expand Down Expand Up @@ -800,14 +826,14 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
}

ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
if (clang_ast_type.GetOpaqueQualType()) {
if (compiler_type.GetOpaqueQualType()) {
for (uint32_t i = 0; i < item_count; ++i) {
addr_t item_addr = addr + (i * item_byte_size);
Address address(item_addr);
StreamString name_strm;
name_strm.Printf("0x%" PRIx64, item_addr);
ValueObjectSP valobj_sp(ValueObjectMemory::Create(
exe_scope, name_strm.GetString(), address, clang_ast_type));
exe_scope, name_strm.GetString(), address, compiler_type));
if (valobj_sp) {
Format format = m_format_options.GetFormat();
if (format != eFormatDefault)
Expand Down Expand Up @@ -877,7 +903,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
OptionGroupReadMemory m_prev_memory_options;
OptionGroupOutputFile m_prev_outfile_options;
OptionGroupValueObjectDisplay m_prev_varobj_options;
CompilerType m_prev_clang_ast_type;
CompilerType m_prev_compiler_type;
};

static constexpr OptionDefinition g_memory_find_option_table[] = {
Expand Down
Expand Up @@ -9,6 +9,7 @@
#include "ClangPersistentVariables.h"

#include "lldb/Core/Value.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Log.h"
Expand Down Expand Up @@ -52,6 +53,21 @@ void ClangPersistentVariables::RemovePersistentVariable(
m_next_persistent_variable_id--;
}

llvm::Optional<CompilerType>
ClangPersistentVariables::GetCompilerTypeFromPersistentDecl(
ConstString type_name) {
CompilerType compiler_type;
if (clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>(
GetPersistentDecl(type_name))) {
compiler_type.SetCompilerType(
ClangASTContext::GetASTContext(&tdecl->getASTContext()),
reinterpret_cast<lldb::opaque_compiler_type_t>(
const_cast<clang::Type *>(tdecl->getTypeForDecl())));
return compiler_type;
}
return llvm::None;
}

void ClangPersistentVariables::RegisterPersistentDecl(ConstString name,
clang::NamedDecl *decl) {
m_persistent_decls.insert(
Expand Down
Expand Up @@ -50,6 +50,9 @@ class ClangPersistentVariables : public PersistentExpressionState {
return "$";
}

llvm::Optional<CompilerType>
GetCompilerTypeFromPersistentDecl(ConstString type_name) override;

void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl);

clang::NamedDecl *GetPersistentDecl(ConstString name);
Expand Down

0 comments on commit 5b99928

Please sign in to comment.