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