[Lldb-commits] [lldb] [lldb] Add LineTable::{upper, lower}_bound (PR #127519)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Mon Feb 17 14:25:39 PST 2025
================
@@ -0,0 +1,285 @@
+//===-- LineTableTest.cpp -------------------------------------------------===//
+//
+// 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 "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace lldb;
+using namespace llvm;
+using namespace lldb_private;
+
+namespace {
+
+// A fake symbol file class to allow us to create the line table "the right
+// way". Pretty much all methods except for GetCompileUnitAtIndex and
+// GetNumCompileUnits are stubbed out.
+class FakeSymbolFile : public SymbolFile {
+public:
+ /// LLVM RTTI support.
+ /// \{
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || SymbolFile::isA(ClassID);
+ }
+ static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
+ /// \}
+
+ static void Initialize() {
+ PluginManager::RegisterPlugin("FakeSymbolFile", "", CreateInstance,
+ DebuggerInitialize);
+ }
+ static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
+
+ void InjectCompileUnit(std::unique_ptr<CompileUnit> cu_up) {
+ m_cu_sp = std::move(cu_up);
+ }
+
+private:
+ /// LLVM RTTI support.
+ static char ID;
+
+ static SymbolFile *CreateInstance(ObjectFileSP objfile_sp) {
+ return new FakeSymbolFile(std::move(objfile_sp));
+ }
+ static void DebuggerInitialize(Debugger &) {}
+
+ StringRef GetPluginName() override { return "FakeSymbolFile"; }
+ uint32_t GetAbilities() override { return UINT32_MAX; }
+ uint32_t CalculateAbilities() override { return UINT32_MAX; }
+ uint32_t GetNumCompileUnits() override { return 1; }
+ CompUnitSP GetCompileUnitAtIndex(uint32_t) override { return m_cu_sp; }
+ Symtab *GetSymtab() override { return nullptr; }
+ LanguageType ParseLanguage(CompileUnit &) override { return eLanguageTypeC; }
+ size_t ParseFunctions(CompileUnit &) override { return 0; }
+ bool ParseLineTable(CompileUnit &) override { return true; }
+ bool ParseDebugMacros(CompileUnit &) override { return true; }
+ bool ParseSupportFiles(CompileUnit &, SupportFileList &) override {
+ return true;
+ }
+ size_t ParseTypes(CompileUnit &) override { return 0; }
+ bool ParseImportedModules(const SymbolContext &,
+ std::vector<SourceModule> &) override {
+ return false;
+ }
+ size_t ParseBlocksRecursive(Function &) override { return 0; }
+ size_t ParseVariablesForContext(const SymbolContext &) override { return 0; }
+ Type *ResolveTypeUID(user_id_t) override { return nullptr; }
+ std::optional<ArrayInfo>
+ GetDynamicArrayInfoForUID(user_id_t, const ExecutionContext *) override {
+ return std::nullopt;
+ }
+ bool CompleteType(CompilerType &) override { return true; }
+ uint32_t ResolveSymbolContext(const Address &, SymbolContextItem,
+ SymbolContext &) override {
+ return 0;
+ }
+ void GetTypes(SymbolContextScope *, TypeClass, TypeList &) override {}
+ Expected<TypeSystemSP> GetTypeSystemForLanguage(LanguageType) override {
+ return createStringError(std::errc::not_supported, "");
+ }
+ const ObjectFile *GetObjectFile() const override {
+ return m_objfile_sp.get();
+ }
+ ObjectFile *GetObjectFile() override { return m_objfile_sp.get(); }
+ ObjectFile *GetMainObjectFile() override { return m_objfile_sp.get(); }
+ void SectionFileAddressesChanged() override {}
+ void Dump(Stream &) override {}
+ uint64_t GetDebugInfoSize(bool) override { return 0; }
+ bool GetDebugInfoIndexWasLoadedFromCache() const override { return false; }
+ void SetDebugInfoIndexWasLoadedFromCache() override {}
+ bool GetDebugInfoIndexWasSavedToCache() const override { return false; }
+ void SetDebugInfoIndexWasSavedToCache() override {}
+ bool GetDebugInfoHadFrameVariableErrors() const override { return false; }
+ void SetDebugInfoHadFrameVariableErrors() override {}
+ TypeSP MakeType(user_id_t, ConstString, std::optional<uint64_t>,
+ SymbolContextScope *, user_id_t, Type::EncodingDataType,
+ const Declaration &, const CompilerType &, Type::ResolveState,
+ uint32_t) override {
+ return nullptr;
+ }
+ TypeSP CopyType(const TypeSP &) override { return nullptr; }
+
+ FakeSymbolFile(ObjectFileSP objfile_sp)
+ : m_objfile_sp(std::move(objfile_sp)) {}
+
+ ObjectFileSP m_objfile_sp;
+ CompUnitSP m_cu_sp;
+};
+
+struct FakeModuleFixture {
+ TestFile file;
+ ModuleSP module_sp;
+ SectionSP text_sp;
+ LineTable *line_table;
+};
+
+class LineTableTest : public testing::Test {
+ SubsystemRAII<ObjectFileELF, FakeSymbolFile> subsystems;
+};
+
+class LineSequenceBuilder {
+public:
+ std::vector<std::unique_ptr<LineSequence>> Build() {
+ return std::move(m_sequences);
+ }
+
+ void Entry(addr_t addr, bool terminal) {
+ LineTable::AppendLineEntryToSequence(
+ m_seq_up.get(), addr, /*line=*/1, /*column=*/0,
+ /*file_idx=*/0,
+ /*is_start_of_statement=*/false, /*is_start_of_basic_block=*/false,
+ /*is_prologue_end=*/false, /*is_epilogue_begin=*/false, terminal);
+ if (terminal) {
+ m_sequences.push_back(std::move(m_seq_up));
+ m_seq_up = LineTable::CreateLineSequenceContainer();
+ }
+ }
+
+private:
+ std::vector<std::unique_ptr<LineSequence>> m_sequences;
+ std::unique_ptr<LineSequence> m_seq_up =
+ LineTable::CreateLineSequenceContainer();
+};
+
+} // namespace
+
+char FakeSymbolFile::ID;
+
+static llvm::Expected<FakeModuleFixture>
+CreateFakeModule(std::vector<std::unique_ptr<LineSequence>> line_sequences) {
+ Expected<TestFile> file = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_386
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0010
+ Address: 0x0000
+ Size: 0x1000
+)");
+ if (!file)
+ return file.takeError();
+
+ auto module_sp = std::make_shared<Module>(file->moduleSpec());
+ SectionSP text_sp =
+ module_sp->GetSectionList()->FindSectionByName(ConstString(".text"));
+ if (!text_sp)
+ return createStringError("No .text");
+
+ auto cu_up = std::make_unique<CompileUnit>(module_sp, /*user_data=*/nullptr,
+ /*support_file_sp=*/nullptr,
+ /*uid=*/0, eLanguageTypeC,
+ /*is_optimized=*/eLazyBoolNo);
+ LineTable *line_table = new LineTable(cu_up.get(), std::move(line_sequences));
+ cu_up->SetLineTable(line_table);
+ cast<FakeSymbolFile>(module_sp->GetSymbolFile())
+ ->InjectCompileUnit(std::move(cu_up));
+
+ return FakeModuleFixture{std::move(*file), std::move(module_sp),
+ std::move(text_sp), line_table};
+}
+
+TEST_F(LineTableTest, LowerAndUpperBound) {
+ LineSequenceBuilder builder;
+ builder.Entry(0, false);
+ builder.Entry(10, false);
+ builder.Entry(20, true);
+ builder.Entry(20, false); // Starts right after the previous sequence.
+ builder.Entry(30, true);
+ builder.Entry(40, false); // Gap after the previous sequence.
+ builder.Entry(50, true);
----------------
JDevlieghere wrote:
```suggestion
builder.Entry(0);
builder.Entry(10);
builder.Entry(20, Terminal);
builder.Entry(20); // Starts right after the previous sequence.
builder.Entry(30, Terminal);
builder.Entry(40); // Gap after the previous sequence.
builder.Entry(50, Terminal);
```
https://github.com/llvm/llvm-project/pull/127519
More information about the lldb-commits
mailing list