Skip to content

Commit 441192a

Browse files
committed
add test
1 parent 854f74e commit 441192a

File tree

4 files changed

+260
-13
lines changed

4 files changed

+260
-13
lines changed

lldb/source/ValueObject/ValueObjectDynamicValue.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,16 @@ bool ValueObjectDynamicValue::UpdateValue() {
244244
// If we found a host address, and the dynamic type fits in the local buffer
245245
// that was found, point to thar buffer. Later on this function will copy
246246
// the buffer over.
247-
if (value_type == Value::ValueType::HostAddress && !local_buffer.empty() &&
248-
local_buffer.size() <=
249-
m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
247+
if (value_type == Value::ValueType::HostAddress) {
248+
// If we found a host address but it doesn't fit in the buffer, there's
249+
// nothing we can do.
250+
if (local_buffer.empty() ||
251+
local_buffer.size() <
252+
m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
253+
SetValueIsValid(false);
254+
return false;
255+
}
256+
250257
m_value.GetScalar() = (uint64_t)local_buffer.data();
251258
m_address = LLDB_INVALID_ADDRESS;
252259
} else {

lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@ inline clang::DeclarationName getDeclarationName(TypeSystemClang &ast,
2121
return ast.getASTContext().DeclarationNames.getIdentifier(&II);
2222
}
2323

24-
inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) {
24+
inline CompilerType
25+
createRecord(TypeSystemClang &ast, llvm::StringRef name,
26+
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
2527
return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(),
2628
OptionalClangModuleID(),
27-
lldb::AccessType::eAccessPublic, name, 0,
28-
lldb::LanguageType::eLanguageTypeC);
29+
lldb::AccessType::eAccessPublic, name, 0, lang);
2930
}
3031

3132
/// Create a record with the given name and a field with the given type
3233
/// and name.
33-
inline CompilerType createRecordWithField(TypeSystemClang &ast,
34-
llvm::StringRef record_name,
35-
CompilerType field_type,
36-
llvm::StringRef field_name) {
37-
CompilerType t = createRecord(ast, record_name);
34+
inline CompilerType createRecordWithField(
35+
TypeSystemClang &ast, llvm::StringRef record_name, CompilerType field_type,
36+
llvm::StringRef field_name,
37+
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
38+
CompilerType t = createRecord(ast, record_name, lang);
3839

3940
TypeSystemClang::StartTagDeclarationDefinition(t);
4041
ast.AddFieldToRecordType(t, field_name, field_type,
@@ -63,12 +64,13 @@ struct SourceASTWithRecord {
6364
CompilerType record_type;
6465
clang::RecordDecl *record_decl = nullptr;
6566
clang::FieldDecl *field_decl = nullptr;
66-
SourceASTWithRecord() {
67+
SourceASTWithRecord(
68+
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
6769
holder = std::make_unique<TypeSystemClangHolder>("test ASTContext");
6870
ast = holder->GetAST();
6971
record_type = createRecordWithField(
7072
*ast, "Source", ast->GetBasicType(lldb::BasicType::eBasicTypeChar),
71-
"a_field");
73+
"a_field", lang);
7274
record_decl =
7375
llvm::cast<clang::RecordDecl>(ClangUtil::GetAsTagDecl(record_type));
7476
field_decl = *record_decl->fields().begin();

lldb/unittests/ValueObject/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_lldb_unittest(LLDBValueObjectTests
22
DumpValueObjectOptionsTests.cpp
33
DILLexerTests.cpp
4+
ValueObjectLocalBuffer.cpp
45

56
LINK_LIBS
67
lldbValueObject
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
//===-- DumpValueObjectOptionsTests.cpp -----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "Plugins/Platform/Linux/PlatformLinux.h"
10+
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
11+
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12+
#include "TestingSupport/SubsystemRAII.h"
13+
#include "TestingSupport/Symbol/ClangTestUtils.h"
14+
#include "lldb/Core/Debugger.h"
15+
#include "lldb/Core/PluginManager.h"
16+
#include "lldb/Target/Language.h"
17+
#include "lldb/Target/LanguageRuntime.h"
18+
#include "lldb/ValueObject/ValueObject.h"
19+
#include "lldb/ValueObject/ValueObjectConstResult.h"
20+
21+
#include "gtest/gtest.h"
22+
23+
using namespace lldb;
24+
using namespace lldb_private;
25+
using namespace lldb_private::clang_utils;
26+
27+
// This entire class is boilerplate.
28+
struct MockLanguage : public Language {
29+
30+
llvm::StringRef GetPluginName() override { return "MockLanguage"; }
31+
lldb::LanguageType GetLanguageType() const override {
32+
return lldb::eLanguageTypeC_plus_plus;
33+
};
34+
35+
static Language *CreateInstance(lldb::LanguageType language) {
36+
return new MockLanguage();
37+
}
38+
static void Initialize() {
39+
PluginManager::RegisterPlugin("MockLanguage", "Mock Language",
40+
CreateInstance);
41+
};
42+
43+
static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
44+
bool IsSourceFile(llvm::StringRef file_path) const override { return true; }
45+
};
46+
LLDB_PLUGIN_DEFINE(MockLanguage)
47+
48+
struct MockLanguageRuntime : public LanguageRuntime {
49+
// This is the only method in this class that matters for this test.
50+
// This will unconditionally succeed and return a type with size 4,
51+
// a value_type of HostAddress, and a local buffer that points to the parent's
52+
// local buffer.
53+
// The tests will set that buffer to be either be larger or smaller than the
54+
// type we're returning.
55+
bool
56+
GetDynamicTypeAndAddress(ValueObject &in_value,
57+
lldb::DynamicValueType use_dynamic,
58+
TypeAndOrName &class_type_or_name, Address &address,
59+
Value::ValueType &value_type,
60+
llvm::ArrayRef<uint8_t> &local_buffer) override {
61+
auto ast = in_value.GetCompilerType()
62+
.GetTypeSystem()
63+
.dyn_cast_or_null<TypeSystemClang>();
64+
65+
auto int_type = createRecordWithField(
66+
*ast, "TypeWitInt", ast->GetBasicType(lldb::BasicType::eBasicTypeInt),
67+
"theIntField", LanguageType::eLanguageTypeC_plus_plus);
68+
class_type_or_name.SetCompilerType(int_type);
69+
local_buffer = {(uint8_t *)in_value.GetValue().GetScalar().ULongLong(
70+
LLDB_INVALID_ADDRESS),
71+
in_value.GetLocalBufferSize()};
72+
value_type = Value::ValueType::HostAddress;
73+
74+
return true;
75+
}
76+
77+
// All of this is boilerplate.
78+
MockLanguageRuntime(Process *process) : LanguageRuntime(process) {}
79+
llvm::StringRef GetPluginName() override { return "MockLanguageRuntime"; }
80+
lldb::LanguageType GetLanguageType() const override {
81+
return lldb::eLanguageTypeC_plus_plus;
82+
}
83+
84+
llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override {
85+
return llvm::Error::success();
86+
}
87+
88+
llvm::Error GetObjectDescription(Stream &str, Value &value,
89+
ExecutionContextScope *exe_scope) override {
90+
return llvm::Error::success();
91+
}
92+
93+
bool CouldHaveDynamicValue(ValueObject &in_value) override { return true; }
94+
95+
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
96+
ValueObject &static_value) override {
97+
return type_and_or_name;
98+
}
99+
100+
lldb::BreakpointResolverSP
101+
CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
102+
bool throw_bp) override {
103+
return lldb::BreakpointResolverSP();
104+
}
105+
106+
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
107+
bool stop_others) override {
108+
return {};
109+
}
110+
111+
static LanguageRuntime *CreateInstance(Process *process,
112+
LanguageType language) {
113+
return new MockLanguageRuntime(process);
114+
}
115+
116+
static void Initialize() {
117+
PluginManager::RegisterPlugin(
118+
"MockLanguageRuntime", "MockLanguageRuntime", CreateInstance,
119+
[](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
120+
return {};
121+
},
122+
[](lldb::LanguageType language,
123+
bool throw_bp) -> BreakpointPreconditionSP { return {}; });
124+
}
125+
126+
static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
127+
};
128+
LLDB_PLUGIN_DEFINE(MockLanguageRuntime)
129+
130+
// This entire class is boilerplate.
131+
struct MockProcess : Process {
132+
MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
133+
: Process(target_sp, listener_sp) {}
134+
135+
llvm::StringRef GetPluginName() override { return "mock process"; }
136+
137+
bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
138+
return false;
139+
};
140+
141+
Status DoDestroy() override { return {}; }
142+
143+
void RefreshStateAfterStop() override {}
144+
145+
bool DoUpdateThreadList(ThreadList &old_thread_list,
146+
ThreadList &new_thread_list) override {
147+
return false;
148+
};
149+
150+
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
151+
Status &error) override {
152+
// No need to read memory in these tests.
153+
return size;
154+
}
155+
};
156+
157+
class ValueObjectLocalBufferTest : public ::testing::Test {
158+
public:
159+
void SetUp() override {
160+
ArchSpec arch("i386-pc-linux");
161+
Platform::SetHostPlatform(
162+
platform_linux::PlatformLinux::CreateInstance(true, &arch));
163+
// std::call_once(TestUtilities::g_debugger_initialize_flag,
164+
// []() { Debugger::Initialize(nullptr); });
165+
m_debugger_sp = Debugger::CreateInstance();
166+
ASSERT_TRUE(m_debugger_sp);
167+
m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
168+
eLoadDependentsNo,
169+
m_platform_sp, m_target_sp);
170+
ASSERT_TRUE(m_target_sp);
171+
ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
172+
ASSERT_TRUE(m_platform_sp);
173+
m_listener_sp = Listener::MakeListener("dummy");
174+
m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
175+
ASSERT_TRUE(m_process_sp);
176+
m_exe_ctx = ExecutionContext(m_process_sp);
177+
178+
m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
179+
m_type_system = m_holder->GetAST();
180+
LLDB_PLUGIN_INITIALIZE(MockLanguage);
181+
LLDB_PLUGIN_INITIALIZE(MockLanguageRuntime);
182+
}
183+
void TearDown() override {
184+
LLDB_PLUGIN_TERMINATE(MockLanguage);
185+
LLDB_PLUGIN_TERMINATE(MockLanguageRuntime);
186+
}
187+
188+
void TestValueObjectWithLocalBuffer(DataExtractor &data_extractor,
189+
bool should_succeed) {
190+
std::unique_ptr<TypeSystemClangHolder> holder =
191+
std::make_unique<TypeSystemClangHolder>("test ASTContext");
192+
TypeSystemClang *ast = holder->GetAST();
193+
auto char_type = createRecordWithField(
194+
*ast, "TypeWithChar",
195+
ast->GetBasicType(lldb::BasicType::eBasicTypeChar), "theField");
196+
197+
ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
198+
ConstString var_name("test_var");
199+
auto valobj_sp = ValueObjectConstResult::Create(exe_scope, char_type,
200+
var_name, data_extractor);
201+
auto dyn_valobj = valobj_sp->GetDynamicValue(lldb::eDynamicCanRunTarget);
202+
ASSERT_TRUE(dyn_valobj->GetValueIsValid() == should_succeed);
203+
}
204+
205+
SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux,
206+
ScriptInterpreterNone>
207+
m_subsystems;
208+
std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
209+
lldb::DebuggerSP m_debugger_sp;
210+
lldb::TargetSP m_target_sp;
211+
lldb::PlatformSP m_platform_sp;
212+
lldb::ListenerSP m_listener_sp;
213+
lldb::ProcessSP m_process_sp;
214+
ExecutionContext m_exe_ctx;
215+
TypeSystemClang *m_type_system;
216+
};
217+
218+
TEST_F(ValueObjectLocalBufferTest, BufferTooSmall) {
219+
u_int8_t value = 1;
220+
ByteOrder endian = endian::InlHostByteOrder();
221+
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
222+
TestValueObjectWithLocalBuffer(data_extractor, false);
223+
}
224+
225+
TEST_F(ValueObjectLocalBufferTest, BufferTooBig) {
226+
uint64_t value = 1;
227+
ByteOrder endian = endian::InlHostByteOrder();
228+
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
229+
TestValueObjectWithLocalBuffer(data_extractor, true);
230+
}
231+
232+
TEST_F(ValueObjectLocalBufferTest, BufferExactlyRight) {
233+
uint32_t value = 1;
234+
ByteOrder endian = endian::InlHostByteOrder();
235+
DataExtractor data_extractor{&value, sizeof(value), endian, 4};
236+
TestValueObjectWithLocalBuffer(data_extractor, true);
237+
}

0 commit comments

Comments
 (0)