Skip to content

Commit 8416bac

Browse files
authored
[lldb-dap] In DAP unit tests, add helpers for loading a CoreFile. (#140738)
This allows us to have a SBTarget and SBProcess for creating unit tests.
1 parent 9a77af3 commit 8416bac

File tree

9 files changed

+337
-2
lines changed

9 files changed

+337
-2
lines changed

lldb/tools/lldb-dap/Protocol/ProtocolBase.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ using Message = std::variant<Request, Response, Event>;
141141
bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
142142
llvm::json::Value toJSON(const Message &);
143143

144+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Message &V) {
145+
OS << toJSON(V);
146+
return OS;
147+
}
148+
144149
/// On error (whenever `success` is false), the body can provide more details.
145150
struct ErrorResponseBody {
146151
/// A structured error message.

lldb/unittests/DAP/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ add_lldb_unittest(DAPTests
1111
VariablesTest.cpp
1212

1313
LINK_LIBS
14+
liblldb
1415
lldbDAP
16+
lldbUtilityHelpers
1517
LLVMTestingSupport
1618
LINK_COMPONENTS
1719
Support
1820
)
21+
22+
set(test_inputs
23+
linux-x86_64.out.yaml
24+
linux-x86_64.core.yaml
25+
)
26+
add_unittest_inputs(DAPTests "${test_inputs}")

lldb/unittests/DAP/Handler/DisconnectTest.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
#include "Handler/RequestHandler.h"
1111
#include "Protocol/ProtocolBase.h"
1212
#include "TestBase.h"
13+
#include "lldb/API/SBDefines.h"
14+
#include "lldb/lldb-enumerations.h"
1315
#include "llvm/Testing/Support/Error.h"
16+
#include "gmock/gmock.h"
1417
#include "gtest/gtest.h"
1518
#include <memory>
1619
#include <optional>
@@ -23,13 +26,38 @@ using namespace lldb_dap::protocol;
2326

2427
class DisconnectRequestHandlerTest : public DAPTestBase {};
2528

26-
TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) {
29+
TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminated) {
2730
DisconnectRequestHandler handler(*dap);
2831
EXPECT_FALSE(dap->disconnecting);
2932
ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded());
3033
EXPECT_TRUE(dap->disconnecting);
3134
std::vector<Message> messages = DrainOutput();
3235
EXPECT_THAT(messages,
3336
testing::Contains(testing::VariantWith<Event>(testing::FieldsAre(
34-
/*event=*/"terminated", /*body=*/std::nullopt))));
37+
/*event=*/"terminated", /*body=*/testing::_))));
38+
}
39+
40+
TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminateCommands) {
41+
CreateDebugger();
42+
43+
if (!GetDebuggerSupportsTarget("X86"))
44+
GTEST_SKIP() << "Unsupported platform";
45+
46+
LoadCore();
47+
48+
DisconnectRequestHandler handler(*dap);
49+
50+
EXPECT_FALSE(dap->disconnecting);
51+
dap->configuration.terminateCommands = {"?script print(1)",
52+
"script print(2)"};
53+
EXPECT_EQ(dap->target.GetProcess().GetState(), lldb::eStateStopped);
54+
ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded());
55+
EXPECT_TRUE(dap->disconnecting);
56+
std::vector<Message> messages = DrainOutput();
57+
EXPECT_THAT(messages, testing::ElementsAre(
58+
OutputMatcher("Running terminateCommands:\n"),
59+
OutputMatcher("(lldb) script print(2)\n"),
60+
OutputMatcher("2\n"),
61+
testing::VariantWith<Event>(testing::FieldsAre(
62+
/*event=*/"terminated", /*body=*/testing::_))));
3563
}

lldb/unittests/DAP/Inputs/linux-x86_64.core.yaml

Lines changed: 49 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_EXEC
6+
Machine: EM_X86_64
7+
Entry: 0x400144
8+
ProgramHeaders:
9+
- Type: PT_LOAD
10+
Flags: [ PF_X, PF_R ]
11+
FirstSec: .note.gnu.build-id
12+
LastSec: .eh_frame
13+
VAddr: 0x400000
14+
Align: 0x200000
15+
Offset: 0x0
16+
- Type: PT_NOTE
17+
Flags: [ PF_R ]
18+
FirstSec: .note.gnu.build-id
19+
LastSec: .note.gnu.build-id
20+
VAddr: 0x4000E8
21+
Align: 0x4
22+
Offset: 0xE8
23+
- Type: PT_GNU_STACK
24+
Flags: [ PF_W, PF_R ]
25+
Align: 0x10
26+
Offset: 0x0
27+
Sections:
28+
- Name: .note.gnu.build-id
29+
Type: SHT_NOTE
30+
Flags: [ SHF_ALLOC ]
31+
Address: 0x4000E8
32+
AddressAlign: 0x4
33+
Notes:
34+
- Name: GNU
35+
Desc: 01DF54A6045E657D3F8FFB9CE111878914F8BD6D
36+
Type: NT_PRPSINFO
37+
- Name: .text
38+
Type: SHT_PROGBITS
39+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
40+
Address: 0x40010C
41+
AddressAlign: 0x1
42+
Content: 554889E548897DE8C645FF62488B45E8C6002F5DC3554889E54883EC2048897DE8488975E0C645FF66488B55E8488B45E04889D7FFD0C9C3554889E54883EC10C645FF5FBE0C014000BF00000000E8C2FFFFFFC9C3
43+
- Name: .eh_frame
44+
Type: SHT_PROGBITS
45+
Flags: [ SHF_ALLOC ]
46+
Address: 0x400168
47+
AddressAlign: 0x8
48+
Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C00000084FFFFFF1500000000410E108602430D06500C07080000001C0000003C00000079FFFFFF2300000000410E108602430D065E0C07080000001C0000005C0000007CFFFFFF1D00000000410E108602430D06580C0708000000
49+
- Name: .comment
50+
Type: SHT_PROGBITS
51+
Flags: [ SHF_MERGE, SHF_STRINGS ]
52+
AddressAlign: 0x1
53+
EntSize: 0x1
54+
Content: 4743433A20285562756E747520342E382E342D327562756E7475317E31342E30342920342E382E3400
55+
- Name: .debug_info
56+
Type: SHT_PROGBITS
57+
AddressAlign: 0x1
58+
Content: EC00000004000000000008011300000001070000003F0000000C01400000000000550000000000000000000000026261720001010C014000000000001500000000000000019C65000000030E00000001016500000002915804460001036B00000002916F0005086B0000000601065800000007666F6F00010721014000000000002300000000000000019CB8000000030E00000001076500000002915803000000000107C300000002915004460001096B00000002916F0008C30000000965000000000508B80000000A51000000010D44014000000000001D00000000000000019C044600010F6B00000002916F0000
59+
- Name: .debug_abbrev
60+
Type: SHT_PROGBITS
61+
AddressAlign: 0x1
62+
Content: 011101250E130B030E1B0E1101120710170000022E0103083A0B3B0B271911011207401897421901130000030500030E3A0B3B0B49130218000004340003083A0B3B0B491302180000050F000B0B491300000624000B0B3E0B030E0000072E0103083A0B3B0B271911011207401896421901130000081501271901130000090500491300000A2E013F19030E3A0B3B0B2719110112074018964219000000
63+
- Name: .debug_line
64+
Type: SHT_PROGBITS
65+
AddressAlign: 0x1
66+
Content: 3F00000002001D0000000101FB0E0D000101010100000001000001006D61696E2E6300000000000009020C0140000000000013834B7531F34BC931834BE50202000101
67+
Symbols:
68+
- Name: .note.gnu.build-id
69+
Type: STT_SECTION
70+
Section: .note.gnu.build-id
71+
Value: 0x4000E8
72+
- Name: .text
73+
Type: STT_SECTION
74+
Section: .text
75+
Value: 0x40010C
76+
- Name: .eh_frame
77+
Type: STT_SECTION
78+
Section: .eh_frame
79+
Value: 0x400168
80+
- Name: .comment
81+
Type: STT_SECTION
82+
Section: .comment
83+
- Name: .debug_aranges
84+
Type: STT_SECTION
85+
Section: .debug_aranges
86+
- Name: .debug_info
87+
Type: STT_SECTION
88+
Section: .debug_info
89+
- Name: .debug_abbrev
90+
Type: STT_SECTION
91+
Section: .debug_abbrev
92+
- Name: .debug_line
93+
Type: STT_SECTION
94+
Section: .debug_line
95+
- Name: .debug_str
96+
Type: STT_SECTION
97+
Section: .debug_str
98+
- Name: main.c
99+
Type: STT_FILE
100+
Index: SHN_ABS
101+
- Name: bar
102+
Type: STT_FUNC
103+
Section: .text
104+
Value: 0x40010C
105+
Size: 0x15
106+
- Name: foo
107+
Type: STT_FUNC
108+
Section: .text
109+
Value: 0x400121
110+
Size: 0x23
111+
- Type: STT_FILE
112+
Index: SHN_ABS
113+
- Name: _start
114+
Type: STT_FUNC
115+
Section: .text
116+
Binding: STB_GLOBAL
117+
Value: 0x400144
118+
Size: 0x1D
119+
- Name: __bss_start
120+
Section: .eh_frame
121+
Binding: STB_GLOBAL
122+
Value: 0x601000
123+
- Name: _edata
124+
Section: .eh_frame
125+
Binding: STB_GLOBAL
126+
Value: 0x601000
127+
- Name: _end
128+
Section: .eh_frame
129+
Binding: STB_GLOBAL
130+
Value: 0x601000
131+
DWARF:
132+
debug_str:
133+
- boomer
134+
- main.c
135+
- boom
136+
- 'GNU C 4.8.4 -mtune=generic -march=x86-64 -g'
137+
- '/home/labath/test'
138+
- _start
139+
- char
140+
debug_aranges:
141+
- Length: 0x2C
142+
Version: 2
143+
CuOffset: 0x0
144+
AddressSize: 0x8
145+
Descriptors:
146+
- Address: 0x40010C
147+
Length: 0x55
148+
...

lldb/unittests/DAP/TestBase.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,16 @@
88

99
#include "TestBase.h"
1010
#include "Protocol/ProtocolBase.h"
11+
#include "TestingSupport/TestUtilities.h"
12+
#include "lldb/API/SBDefines.h"
13+
#include "lldb/API/SBStructuredData.h"
1114
#include "lldb/Host/File.h"
1215
#include "lldb/Host/Pipe.h"
16+
#include "lldb/lldb-forward.h"
17+
#include "llvm/ADT/StringRef.h"
1318
#include "llvm/Testing/Support/Error.h"
19+
#include "gtest/gtest.h"
20+
#include <memory>
1421

1522
using namespace llvm;
1623
using namespace lldb;
@@ -55,6 +62,62 @@ void DAPTestBase::SetUp() {
5562
/*transport=*/*to_dap);
5663
}
5764

65+
void DAPTestBase::TearDown() {
66+
if (core)
67+
ASSERT_THAT_ERROR(core->discard(), Succeeded());
68+
if (binary)
69+
ASSERT_THAT_ERROR(binary->discard(), Succeeded());
70+
}
71+
72+
void DAPTestBase::SetUpTestSuite() {
73+
lldb::SBError error = SBDebugger::InitializeWithErrorHandling();
74+
EXPECT_TRUE(error.Success());
75+
}
76+
void DAPTestBase::TeatUpTestSuite() { SBDebugger::Terminate(); }
77+
78+
bool DAPTestBase::GetDebuggerSupportsTarget(llvm::StringRef platform) {
79+
EXPECT_TRUE(dap->debugger);
80+
81+
lldb::SBStructuredData data = dap->debugger.GetBuildConfiguration()
82+
.GetValueForKey("targets")
83+
.GetValueForKey("value");
84+
for (size_t i = 0; i < data.GetSize(); i++) {
85+
char buf[100] = {0};
86+
size_t size = data.GetItemAtIndex(i).GetStringValue(buf, sizeof(buf));
87+
if (llvm::StringRef(buf, size) == platform)
88+
return true;
89+
}
90+
91+
return false;
92+
}
93+
94+
void DAPTestBase::CreateDebugger() {
95+
dap->debugger = lldb::SBDebugger::Create();
96+
ASSERT_TRUE(dap->debugger);
97+
}
98+
99+
void DAPTestBase::LoadCore() {
100+
ASSERT_TRUE(dap->debugger);
101+
llvm::Expected<lldb_private::TestFile> binary_yaml =
102+
lldb_private::TestFile::fromYamlFile(k_linux_binary);
103+
ASSERT_THAT_EXPECTED(binary_yaml, Succeeded());
104+
llvm::Expected<llvm::sys::fs::TempFile> binary_file =
105+
binary_yaml->writeToTemporaryFile();
106+
ASSERT_THAT_EXPECTED(binary_file, Succeeded());
107+
binary = std::move(*binary_file);
108+
dap->target = dap->debugger.CreateTarget(binary->TmpName.data());
109+
ASSERT_TRUE(dap->target);
110+
llvm::Expected<lldb_private::TestFile> core_yaml =
111+
lldb_private::TestFile::fromYamlFile(k_linux_core);
112+
ASSERT_THAT_EXPECTED(core_yaml, Succeeded());
113+
llvm::Expected<llvm::sys::fs::TempFile> core_file =
114+
core_yaml->writeToTemporaryFile();
115+
ASSERT_THAT_EXPECTED(core_file, Succeeded());
116+
this->core = std::move(*core_file);
117+
SBProcess process = dap->target.LoadCore(this->core->TmpName.data());
118+
ASSERT_TRUE(process);
119+
}
120+
58121
std::vector<Message> DAPTestBase::DrainOutput() {
59122
std::vector<Message> msgs;
60123
output.CloseWriteFileDescriptor();

lldb/unittests/DAP/TestBase.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "Protocol/ProtocolBase.h"
1111
#include "Transport.h"
1212
#include "lldb/Host/Pipe.h"
13+
#include "llvm/ADT/StringRef.h"
14+
#include "gmock/gmock.h"
1315
#include "gtest/gtest.h"
1416

1517
namespace lldb_dap_tests {
@@ -33,12 +35,32 @@ class TransportBase : public PipeBase {
3335
void SetUp() override;
3436
};
3537

38+
/// Matches an "output" event.
39+
inline auto OutputMatcher(const llvm::StringRef output,
40+
const llvm::StringRef category = "console") {
41+
return testing::VariantWith<lldb_dap::protocol::Event>(testing::FieldsAre(
42+
/*event=*/"output", /*body=*/testing::Optional<llvm::json::Value>(
43+
llvm::json::Object{{"category", category}, {"output", output}})));
44+
}
45+
3646
/// A base class for tests that interact with a `lldb_dap::DAP` instance.
3747
class DAPTestBase : public TransportBase {
3848
protected:
3949
std::unique_ptr<lldb_dap::DAP> dap;
50+
std::optional<llvm::sys::fs::TempFile> core;
51+
std::optional<llvm::sys::fs::TempFile> binary;
52+
53+
static constexpr llvm::StringLiteral k_linux_binary = "linux-x86_64.out.yaml";
54+
static constexpr llvm::StringLiteral k_linux_core = "linux-x86_64.core.yaml";
4055

56+
static void SetUpTestSuite();
57+
static void TeatUpTestSuite();
4158
void SetUp() override;
59+
void TearDown() override;
60+
61+
bool GetDebuggerSupportsTarget(llvm::StringRef platform);
62+
void CreateDebugger();
63+
void LoadCore();
4264

4365
/// Closes the DAP output pipe and returns the remaining protocol messages in
4466
/// the buffer.

lldb/unittests/TestingSupport/TestUtilities.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,12 @@ llvm::Expected<TestFile> TestFile::fromYamlFile(const llvm::Twine &Name) {
4747
return llvm::errorCodeToError(BufferOrError.getError());
4848
return fromYaml(BufferOrError.get()->getBuffer());
4949
}
50+
51+
llvm::Expected<llvm::sys::fs::TempFile> TestFile::writeToTemporaryFile() {
52+
llvm::Expected<llvm::sys::fs::TempFile> Temp =
53+
llvm::sys::fs::TempFile::create("temp%%%%%%%%%%%%%%%%");
54+
if (!Temp)
55+
return Temp.takeError();
56+
llvm::raw_fd_ostream(Temp->FD, /*shouldClose=*/false) << Buffer;
57+
return std::move(*Temp);
58+
}

lldb/unittests/TestingSupport/TestUtilities.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/SmallString.h"
1515
#include "llvm/ADT/Twine.h"
1616
#include "llvm/Support/Error.h"
17+
#include "llvm/Support/FileSystem.h"
1718
#include "llvm/Support/FileUtilities.h"
1819
#include <string>
1920

@@ -45,6 +46,8 @@ class TestFile {
4546
return ModuleSpec(FileSpec(), UUID(), dataBuffer());
4647
}
4748

49+
llvm::Expected<llvm::sys::fs::TempFile> writeToTemporaryFile();
50+
4851
private:
4952
TestFile(std::string &&Buffer) : Buffer(std::move(Buffer)) {}
5053

0 commit comments

Comments
 (0)