17cdd53daSDavid Spickett //===-- DumpValueObjectOptionsTests.cpp -----------------------------------===// 27cdd53daSDavid Spickett // 37cdd53daSDavid Spickett // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47cdd53daSDavid Spickett // See https://llvm.org/LICENSE.txt for license information. 57cdd53daSDavid Spickett // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67cdd53daSDavid Spickett // 77cdd53daSDavid Spickett //===----------------------------------------------------------------------===// 87cdd53daSDavid Spickett 97cdd53daSDavid Spickett #include "Plugins/Platform/Linux/PlatformLinux.h" 107cdd53daSDavid Spickett #include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h" 117cdd53daSDavid Spickett #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 127cdd53daSDavid Spickett #include "TestingSupport/SubsystemRAII.h" 137cdd53daSDavid Spickett #include "TestingSupport/Symbol/ClangTestUtils.h" 147cdd53daSDavid Spickett #include "lldb/Core/Debugger.h" 157cdd53daSDavid Spickett #include "lldb/DataFormatters/DumpValueObjectOptions.h" 16*b852fb1eSJonas Devlieghere #include "lldb/ValueObject/ValueObject.h" 17*b852fb1eSJonas Devlieghere #include "lldb/ValueObject/ValueObjectConstResult.h" 187cdd53daSDavid Spickett 197cdd53daSDavid Spickett #include "gtest/gtest.h" 207cdd53daSDavid Spickett 21328d9f62SDavid Spickett #include <type_traits> 22328d9f62SDavid Spickett 237cdd53daSDavid Spickett using namespace lldb; 247cdd53daSDavid Spickett using namespace lldb_private; 257cdd53daSDavid Spickett 267cdd53daSDavid Spickett struct MockProcess : Process { 277cdd53daSDavid Spickett MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp) 287cdd53daSDavid Spickett : Process(target_sp, listener_sp) {} 297cdd53daSDavid Spickett 307cdd53daSDavid Spickett llvm::StringRef GetPluginName() override { return "mock process"; } 317cdd53daSDavid Spickett 327cdd53daSDavid Spickett bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override { 337cdd53daSDavid Spickett return false; 347cdd53daSDavid Spickett }; 357cdd53daSDavid Spickett 367cdd53daSDavid Spickett Status DoDestroy() override { return {}; } 377cdd53daSDavid Spickett 387cdd53daSDavid Spickett void RefreshStateAfterStop() override {} 397cdd53daSDavid Spickett 407cdd53daSDavid Spickett bool DoUpdateThreadList(ThreadList &old_thread_list, 417cdd53daSDavid Spickett ThreadList &new_thread_list) override { 427cdd53daSDavid Spickett return false; 437cdd53daSDavid Spickett }; 447cdd53daSDavid Spickett 457cdd53daSDavid Spickett size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, 467cdd53daSDavid Spickett Status &error) override { 477cdd53daSDavid Spickett // No need to read memory in these tests. 487cdd53daSDavid Spickett return size; 497cdd53daSDavid Spickett } 507cdd53daSDavid Spickett }; 517cdd53daSDavid Spickett 527cdd53daSDavid Spickett class ValueObjectMockProcessTest : public ::testing::Test { 537cdd53daSDavid Spickett public: 547cdd53daSDavid Spickett void SetUp() override { 557cdd53daSDavid Spickett ArchSpec arch("i386-pc-linux"); 567cdd53daSDavid Spickett Platform::SetHostPlatform( 577cdd53daSDavid Spickett platform_linux::PlatformLinux::CreateInstance(true, &arch)); 587cdd53daSDavid Spickett m_debugger_sp = Debugger::CreateInstance(); 597cdd53daSDavid Spickett ASSERT_TRUE(m_debugger_sp); 607cdd53daSDavid Spickett m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch, 617cdd53daSDavid Spickett eLoadDependentsNo, 627cdd53daSDavid Spickett m_platform_sp, m_target_sp); 637cdd53daSDavid Spickett ASSERT_TRUE(m_target_sp); 647cdd53daSDavid Spickett ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid()); 657cdd53daSDavid Spickett ASSERT_TRUE(m_platform_sp); 667cdd53daSDavid Spickett m_listener_sp = Listener::MakeListener("dummy"); 677cdd53daSDavid Spickett m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp); 687cdd53daSDavid Spickett ASSERT_TRUE(m_process_sp); 697cdd53daSDavid Spickett m_exe_ctx = ExecutionContext(m_process_sp); 707cdd53daSDavid Spickett 717cdd53daSDavid Spickett m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test"); 727cdd53daSDavid Spickett m_type_system = m_holder->GetAST(); 737cdd53daSDavid Spickett } 747cdd53daSDavid Spickett 75328d9f62SDavid Spickett template <typename UnderlyingType> 76328d9f62SDavid Spickett void TestDumpEnum( 77328d9f62SDavid Spickett const std::vector<std::pair<const char *, UnderlyingType>> enumerators, 78328d9f62SDavid Spickett const std::vector<std::tuple<UnderlyingType, DumpValueObjectOptions, 79328d9f62SDavid Spickett const char *>> &tests) { 80328d9f62SDavid Spickett CompilerType enum_type = MakeEnumType(enumerators); 817cdd53daSDavid Spickett StreamString strm; 827cdd53daSDavid Spickett ConstString var_name("test_var"); 837cdd53daSDavid Spickett ByteOrder endian = endian::InlHostByteOrder(); 847cdd53daSDavid Spickett ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); 857cdd53daSDavid Spickett for (auto [value, options, expected] : tests) { 867cdd53daSDavid Spickett DataExtractor data_extractor{&value, sizeof(value), endian, 4}; 87d1bc75c0SAdrian Prantl auto valobj_sp = ValueObjectConstResult::Create(exe_scope, enum_type, 88d1bc75c0SAdrian Prantl var_name, data_extractor); 89d1bc75c0SAdrian Prantl if (llvm::Error error = valobj_sp->Dump(strm, options)) 90d1bc75c0SAdrian Prantl llvm::consumeError(std::move(error)); 917cdd53daSDavid Spickett ASSERT_STREQ(strm.GetString().str().c_str(), expected); 927cdd53daSDavid Spickett strm.Clear(); 937cdd53daSDavid Spickett } 947cdd53daSDavid Spickett } 957cdd53daSDavid Spickett 96328d9f62SDavid Spickett template <typename UnderlyingType> 97328d9f62SDavid Spickett CompilerType MakeEnumType( 98328d9f62SDavid Spickett const std::vector<std::pair<const char *, UnderlyingType>> enumerators) { 99328d9f62SDavid Spickett CompilerType int_type = m_type_system->GetBuiltinTypeForEncodingAndBitSize( 100328d9f62SDavid Spickett std::is_same<UnderlyingType, int>::value ? lldb::eEncodingSint 101328d9f62SDavid Spickett : lldb::eEncodingUint, 102328d9f62SDavid Spickett 32); 103328d9f62SDavid Spickett CompilerType enum_type = m_type_system->CreateEnumerationType( 104328d9f62SDavid Spickett "TestEnum", m_type_system->GetTranslationUnitDecl(), 105328d9f62SDavid Spickett OptionalClangModuleID(), Declaration(), int_type, false); 106328d9f62SDavid Spickett 107328d9f62SDavid Spickett m_type_system->StartTagDeclarationDefinition(enum_type); 108328d9f62SDavid Spickett Declaration decl; 109328d9f62SDavid Spickett for (auto [name, value] : enumerators) 110328d9f62SDavid Spickett m_type_system->AddEnumerationValueToEnumerationType(enum_type, decl, name, 111328d9f62SDavid Spickett value, 32); 112328d9f62SDavid Spickett m_type_system->CompleteTagDeclarationDefinition(enum_type); 113328d9f62SDavid Spickett 114328d9f62SDavid Spickett return enum_type; 115328d9f62SDavid Spickett } 116328d9f62SDavid Spickett 1177cdd53daSDavid Spickett ExecutionContext m_exe_ctx; 1187cdd53daSDavid Spickett TypeSystemClang *m_type_system; 1197cdd53daSDavid Spickett 1207cdd53daSDavid Spickett private: 1217cdd53daSDavid Spickett SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux, 1227cdd53daSDavid Spickett ScriptInterpreterNone> 1237cdd53daSDavid Spickett m_subsystems; 1247cdd53daSDavid Spickett 1257cdd53daSDavid Spickett std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder; 1267cdd53daSDavid Spickett lldb::DebuggerSP m_debugger_sp; 1277cdd53daSDavid Spickett lldb::TargetSP m_target_sp; 1287cdd53daSDavid Spickett lldb::PlatformSP m_platform_sp; 1297cdd53daSDavid Spickett lldb::ListenerSP m_listener_sp; 1307cdd53daSDavid Spickett lldb::ProcessSP m_process_sp; 1317cdd53daSDavid Spickett }; 1327cdd53daSDavid Spickett 133328d9f62SDavid Spickett TEST_F(ValueObjectMockProcessTest, EmptyEnum) { 134328d9f62SDavid Spickett // All values of an empty enum should be shown as plain numbers. 135328d9f62SDavid Spickett TestDumpEnum<unsigned>({}, {{0, {}, "(TestEnum) test_var = 0\n"}, 136328d9f62SDavid Spickett {1, {}, "(TestEnum) test_var = 1\n"}, 137328d9f62SDavid Spickett {2, {}, "(TestEnum) test_var = 2\n"}}); 138328d9f62SDavid Spickett 139328d9f62SDavid Spickett TestDumpEnum<int>({}, {{-2, {}, "(TestEnum) test_var = -2\n"}, 140328d9f62SDavid Spickett {-1, {}, "(TestEnum) test_var = -1\n"}, 141328d9f62SDavid Spickett {0, {}, "(TestEnum) test_var = 0\n"}, 142328d9f62SDavid Spickett {1, {}, "(TestEnum) test_var = 1\n"}, 143328d9f62SDavid Spickett {2, {}, "(TestEnum) test_var = 2\n"}}); 144328d9f62SDavid Spickett } 145328d9f62SDavid Spickett 1467cdd53daSDavid Spickett TEST_F(ValueObjectMockProcessTest, Enum) { 1477cdd53daSDavid Spickett // This is not a bitfield-like enum, so values are printed as decimal by 1487cdd53daSDavid Spickett // default. Also we only show the enumerator name if the value is an 1497cdd53daSDavid Spickett // exact match. 150328d9f62SDavid Spickett TestDumpEnum<unsigned>( 151328d9f62SDavid Spickett {{"test_2", 2}, {"test_3", 3}}, 1527cdd53daSDavid Spickett {{0, {}, "(TestEnum) test_var = 0\n"}, 1537cdd53daSDavid Spickett {1, {}, "(TestEnum) test_var = 1\n"}, 1547cdd53daSDavid Spickett {2, {}, "(TestEnum) test_var = test_2\n"}, 1557cdd53daSDavid Spickett {3, {}, "(TestEnum) test_var = test_3\n"}, 1567cdd53daSDavid Spickett {4, {}, "(TestEnum) test_var = 4\n"}, 1577cdd53daSDavid Spickett {5, {}, "(TestEnum) test_var = 5\n"}, 1587cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideRootName(true), "(TestEnum) 1\n"}, 1597cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideRootType(true), "test_var = 1\n"}, 1607cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true), 1617cdd53daSDavid Spickett "1\n"}, 1627cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 1\n"}, 1637cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideValue(true), 1647cdd53daSDavid Spickett "(TestEnum) test_var =\n"}, 1657cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true), 1667cdd53daSDavid Spickett "(TestEnum) \n"}}); 1677cdd53daSDavid Spickett } 1687cdd53daSDavid Spickett 1697cdd53daSDavid Spickett TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) { 1707cdd53daSDavid Spickett // These enumerators set individual bits in the value, as if it were a flag 1717cdd53daSDavid Spickett // set. lldb treats this as a "bitfield like enum". This means we show values 17231015240SDavid Spickett // as hex, and values without exact matches are shown as a combination of 17331015240SDavid Spickett // enumerators and any remaining value left over. 174328d9f62SDavid Spickett TestDumpEnum<unsigned>( 175328d9f62SDavid Spickett {{"test_2", 2}, {"test_4", 4}}, 1767cdd53daSDavid Spickett { 17731015240SDavid Spickett {0, {}, "(TestEnum) test_var = 0x0\n"}, 1787cdd53daSDavid Spickett {1, {}, "(TestEnum) test_var = 0x1\n"}, 1797cdd53daSDavid Spickett {2, {}, "(TestEnum) test_var = test_2\n"}, 1807cdd53daSDavid Spickett {4, {}, "(TestEnum) test_var = test_4\n"}, 1817cdd53daSDavid Spickett {6, {}, "(TestEnum) test_var = test_2 | test_4\n"}, 1827cdd53daSDavid Spickett {7, {}, "(TestEnum) test_var = test_2 | test_4 | 0x1\n"}, 1837cdd53daSDavid Spickett {8, {}, "(TestEnum) test_var = 0x8\n"}, 1847cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideRootName(true), 1857cdd53daSDavid Spickett "(TestEnum) 0x1\n"}, 1867cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideRootType(true), 1877cdd53daSDavid Spickett "test_var = 0x1\n"}, 1887cdd53daSDavid Spickett {1, 1897cdd53daSDavid Spickett DumpValueObjectOptions().SetHideRootName(true).SetHideRootType(true), 1907cdd53daSDavid Spickett "0x1\n"}, 1917cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 0x1\n"}, 1927cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideValue(true), 1937cdd53daSDavid Spickett "(TestEnum) test_var =\n"}, 1947cdd53daSDavid Spickett {1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true), 1957cdd53daSDavid Spickett "(TestEnum) \n"}, 1967cdd53daSDavid Spickett }); 1977cdd53daSDavid Spickett } 198