198 lines · cpp
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-exception6//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 23using namespace lldb;24using namespace lldb_private;25 26struct 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 52class ValueObjectMockProcessTest : public ::testing::Test {53public: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::eEncodingSint101 : 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 120private: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 133TEST_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 146TEST_F(ValueObjectMockProcessTest, Enum) {147 // This is not a bitfield-like enum, so values are printed as decimal by148 // default. Also we only show the enumerator name if the value is an149 // 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 169TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {170 // These enumerators set individual bits in the value, as if it were a flag171 // set. lldb treats this as a "bitfield like enum". This means we show values172 // as hex, and values without exact matches are shown as a combination of173 // 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