xref: /llvm-project/lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp (revision b852fb1ec5fa15f0b913cc4988cbd09239b19904)
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/DataFormatters/DumpValueObjectOptions.h"
16 #include "lldb/ValueObject/ValueObject.h"
17 #include "lldb/ValueObject/ValueObjectConstResult.h"
18 
19 #include "gtest/gtest.h"
20 
21 #include <type_traits>
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 struct MockProcess : Process {
27   MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
28       : Process(target_sp, listener_sp) {}
29 
30   llvm::StringRef GetPluginName() override { return "mock process"; }
31 
32   bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
33     return false;
34   };
35 
36   Status DoDestroy() override { return {}; }
37 
38   void RefreshStateAfterStop() override {}
39 
40   bool DoUpdateThreadList(ThreadList &old_thread_list,
41                           ThreadList &new_thread_list) override {
42     return false;
43   };
44 
45   size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
46                       Status &error) override {
47     // No need to read memory in these tests.
48     return size;
49   }
50 };
51 
52 class ValueObjectMockProcessTest : public ::testing::Test {
53 public:
54   void SetUp() override {
55     ArchSpec arch("i386-pc-linux");
56     Platform::SetHostPlatform(
57         platform_linux::PlatformLinux::CreateInstance(true, &arch));
58     m_debugger_sp = Debugger::CreateInstance();
59     ASSERT_TRUE(m_debugger_sp);
60     m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
61                                                 eLoadDependentsNo,
62                                                 m_platform_sp, m_target_sp);
63     ASSERT_TRUE(m_target_sp);
64     ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
65     ASSERT_TRUE(m_platform_sp);
66     m_listener_sp = Listener::MakeListener("dummy");
67     m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
68     ASSERT_TRUE(m_process_sp);
69     m_exe_ctx = ExecutionContext(m_process_sp);
70 
71     m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
72     m_type_system = m_holder->GetAST();
73   }
74 
75   template <typename UnderlyingType>
76   void TestDumpEnum(
77       const std::vector<std::pair<const char *, UnderlyingType>> enumerators,
78       const std::vector<std::tuple<UnderlyingType, DumpValueObjectOptions,
79                                    const char *>> &tests) {
80     CompilerType enum_type = MakeEnumType(enumerators);
81     StreamString strm;
82     ConstString var_name("test_var");
83     ByteOrder endian = endian::InlHostByteOrder();
84     ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
85     for (auto [value, options, expected] : tests) {
86       DataExtractor data_extractor{&value, sizeof(value), endian, 4};
87       auto valobj_sp = ValueObjectConstResult::Create(exe_scope, enum_type,
88                                                       var_name, data_extractor);
89       if (llvm::Error error = valobj_sp->Dump(strm, options))
90         llvm::consumeError(std::move(error));
91       ASSERT_STREQ(strm.GetString().str().c_str(), expected);
92       strm.Clear();
93     }
94   }
95 
96   template <typename UnderlyingType>
97   CompilerType MakeEnumType(
98       const std::vector<std::pair<const char *, UnderlyingType>> enumerators) {
99     CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize(
100         std::is_same<UnderlyingType, int>::value ? lldb::eEncodingSint
101                                                  : lldb::eEncodingUint,
102         32);
103     CompilerType enum_type = m_type_system->CreateEnumerationType(
104         "TestEnum", m_type_system->GetTranslationUnitDecl(),
105         OptionalClangModuleID(), Declaration(), int_type, false);
106 
107     m_type_system->StartTagDeclarationDefinition(enum_type);
108     Declaration decl;
109     for (auto [name, value] : enumerators)
110       m_type_system->AddEnumerationValueToEnumerationType(enum_type, decl, name,
111                                                           value, 32);
112     m_type_system->CompleteTagDeclarationDefinition(enum_type);
113 
114     return enum_type;
115   }
116 
117   ExecutionContext m_exe_ctx;
118   TypeSystemClang *m_type_system;
119 
120 private:
121   SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux,
122                 ScriptInterpreterNone>
123       m_subsystems;
124 
125   std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
126   lldb::DebuggerSP m_debugger_sp;
127   lldb::TargetSP m_target_sp;
128   lldb::PlatformSP m_platform_sp;
129   lldb::ListenerSP m_listener_sp;
130   lldb::ProcessSP m_process_sp;
131 };
132 
133 TEST_F(ValueObjectMockProcessTest, EmptyEnum) {
134   // All values of an empty enum should be shown as plain numbers.
135   TestDumpEnum<unsigned>({}, {{0, {}, "(TestEnum) test_var = 0\n"},
136                               {1, {}, "(TestEnum) test_var = 1\n"},
137                               {2, {}, "(TestEnum) test_var = 2\n"}});
138 
139   TestDumpEnum<int>({}, {{-2, {}, "(TestEnum) test_var = -2\n"},
140                          {-1, {}, "(TestEnum) test_var = -1\n"},
141                          {0, {}, "(TestEnum) test_var = 0\n"},
142                          {1, {}, "(TestEnum) test_var = 1\n"},
143                          {2, {}, "(TestEnum) test_var = 2\n"}});
144 }
145 
146 TEST_F(ValueObjectMockProcessTest, Enum) {
147   // This is not a bitfield-like enum, so values are printed as decimal by
148   // default. Also we only show the enumerator name if the value is an
149   // exact match.
150   TestDumpEnum<unsigned>(
151       {{"test_2", 2}, {"test_3", 3}},
152       {{0, {}, "(TestEnum) test_var = 0\n"},
153        {1, {}, "(TestEnum) test_var = 1\n"},
154        {2, {}, "(TestEnum) test_var = test_2\n"},
155        {3, {}, "(TestEnum) test_var = test_3\n"},
156        {4, {}, "(TestEnum) test_var = 4\n"},
157        {5, {}, "(TestEnum) test_var = 5\n"},
158        {1, DumpValueObjectOptions().SetHideRootName(true), "(TestEnum) 1\n"},
159        {1, DumpValueObjectOptions().SetHideRootType(true), "test_var = 1\n"},
160        {1, DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
161         "1\n"},
162        {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 1\n"},
163        {1, DumpValueObjectOptions().SetHideValue(true),
164         "(TestEnum) test_var =\n"},
165        {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
166         "(TestEnum) \n"}});
167 }
168 
169 TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {
170   // These enumerators set individual bits in the value, as if it were a flag
171   // set. lldb treats this as a "bitfield like enum". This means we show values
172   // as hex, and values without exact matches are shown as a combination of
173   // enumerators and any remaining value left over.
174   TestDumpEnum<unsigned>(
175       {{"test_2", 2}, {"test_4", 4}},
176       {
177           {0, {}, "(TestEnum) test_var = 0x0\n"},
178           {1, {}, "(TestEnum) test_var = 0x1\n"},
179           {2, {}, "(TestEnum) test_var = test_2\n"},
180           {4, {}, "(TestEnum) test_var = test_4\n"},
181           {6, {}, "(TestEnum) test_var = test_2 | test_4\n"},
182           {7, {}, "(TestEnum) test_var = test_2 | test_4 | 0x1\n"},
183           {8, {}, "(TestEnum) test_var = 0x8\n"},
184           {1, DumpValueObjectOptions().SetHideRootName(true),
185            "(TestEnum) 0x1\n"},
186           {1, DumpValueObjectOptions().SetHideRootType(true),
187            "test_var = 0x1\n"},
188           {1,
189            DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true),
190            "0x1\n"},
191           {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 0x1\n"},
192           {1, DumpValueObjectOptions().SetHideValue(true),
193            "(TestEnum) test_var =\n"},
194           {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
195            "(TestEnum) \n"},
196       });
197 }
198