Files
llvm-project/lldb/unittests/DataFormatter/FormatterSectionTest.cpp
Adrian Prantl 94819cc7b1 [LLDB] Modify CreateValueObjectFrom* to take an ExecutionContext (#185547)
Currently these functions take a target pointer. In Cross-language
projects this means it's down to chance what typesystem the resulting
value will be in, since the implementation returns the first scratch
type system in the target, which depends on the order of images and
their implementation language.

By passing in an execution context the selected frame is used to
determine the typesystem, which is usually the expected outcome when
using DIL.

This should be entirely NFC for Clang-only LLDBs, but is a necessity for
LLDBs with additional type system plugins such as the Swift plugin.

Assisted by Claude to patch the call sites.
2026-03-12 16:08:04 -07:00

145 lines
4.7 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/FormatterSection.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/ValueObject/ValueObjectConstResult.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
namespace {
struct MockProcess : Process {
MockProcess(TargetSP target_sp, ListenerSP listener_sp)
: Process(target_sp, listener_sp) {}
llvm::StringRef GetPluginName() override { return "mock process"; }
bool CanDebug(TargetSP target, bool plugin_specified_by_name) override {
return false;
};
Status DoDestroy() override { return {}; }
void RefreshStateAfterStop() override {}
bool DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override {
return false;
};
size_t DoReadMemory(addr_t vm_addr, void *buf, size_t size,
Status &error) override {
return 0;
}
};
class FormatterSectionTest : public ::testing::Test {
public:
void SetUp() override {
ArchSpec arch("x86_64-pc-linux");
Platform::SetHostPlatform(
platform_linux::PlatformLinux::CreateInstance(true, &arch));
m_debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(m_debugger_sp);
m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
eLoadDependentsNo,
m_platform_sp, m_target_sp);
ASSERT_TRUE(m_target_sp);
ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
ASSERT_TRUE(m_platform_sp);
m_listener_sp = Listener::MakeListener("dummy");
m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
ASSERT_TRUE(m_process_sp);
m_exe_ctx = ExecutionContext(m_process_sp);
}
ExecutionContext m_exe_ctx;
TypeSystemClang *m_type_system;
lldb::TargetSP m_target_sp;
private:
SubsystemRAII<FileSystem, HostInfo, ObjectFileELF,
platform_linux::PlatformLinux, SymbolFileSymtab>
m_subsystems;
lldb::DebuggerSP m_debugger_sp;
lldb::PlatformSP m_platform_sp;
lldb::ListenerSP m_listener_sp;
lldb::ProcessSP m_process_sp;
};
} // namespace
/// Test that multiple formatters can be loaded
TEST_F(FormatterSectionTest, LoadFormattersForModule) {
auto ExpectedFile = TestFile::fromYaml(R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .lldbformatters
Type: SHT_PROGBITS
Flags: [ ]
Address: 0x2010
AddressAlign: 0x10
# Two summaries for "Point" and "Rect" that return "AAAAA" and "BBBBB" respectively
Content: 011205506F696E74000009012205414141414113000000000111045265637400000901220542424242421300000000
Size: 256
...
)");
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
LoadFormattersForModule(module_sp);
TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(ConstString("default"), category);
ASSERT_TRUE(category != nullptr);
ASSERT_EQ(category->GetCount(), 2u);
TypeSummaryImplSP point_summary_sp =
category->GetSummaryForType(std::make_shared<TypeNameSpecifierImpl>(
"Point", lldb::eFormatterMatchExact));
ASSERT_TRUE(point_summary_sp != nullptr);
TypeSummaryImplSP rect_summary_sp =
category->GetSummaryForType(std::make_shared<TypeNameSpecifierImpl>(
"Rect", lldb::eFormatterMatchExact));
ASSERT_TRUE(rect_summary_sp != nullptr);
std::string dest;
Scalar val;
ValueObjectSP valobj = ValueObjectConstResult::CreateValueObjectFromScalar(
ExecutionContext(m_target_sp.get(), false), val, CompilerType(), "mock");
ASSERT_TRUE(
point_summary_sp->FormatObject(valobj.get(), dest, TypeSummaryOptions()));
ASSERT_EQ(dest, "AAAAA");
dest.clear();
ASSERT_TRUE(
rect_summary_sp->FormatObject(valobj.get(), dest, TypeSummaryOptions()));
ASSERT_EQ(dest, "BBBBB");
}