1//===-- BreakpadRecordsTest.cpp -------------------------------------------===//
2//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
11#include "gtest/gtest.h"
12
13using namespace lldb_private;
14using namespace lldb_private::breakpad;
15
16TEST(Record, classify) {
17 EXPECT_EQ(Record::Module, Record::classify("MODULE"));
18 EXPECT_EQ(Record::Info, Record::classify("INFO"));
19 EXPECT_EQ(Record::File, Record::classify("FILE"));
20 EXPECT_EQ(Record::Func, Record::classify("FUNC"));
21 EXPECT_EQ(Record::Inline, Record::classify("INLINE"));
22 EXPECT_EQ(Record::InlineOrigin, Record::classify("INLINE_ORIGIN"));
23 EXPECT_EQ(Record::Public, Record::classify("PUBLIC"));
24 EXPECT_EQ(Record::StackCFI, Record::classify("STACK CFI"));
25 EXPECT_EQ(Record::StackWin, Record::classify("STACK WIN"));
26
27 // Any obviously incorrect lines will be classified as such.
28 EXPECT_EQ(std::nullopt, Record::classify("STACK"));
29 EXPECT_EQ(std::nullopt, Record::classify("STACK CODE_ID"));
30 EXPECT_EQ(std::nullopt, Record::classify("CODE_ID"));
31
32 // Any line which does not start with a known keyword will be classified as a
33 // line record, as those are the only ones that start without a keyword.
34 EXPECT_EQ(Record::Line, Record::classify("deadbeef"));
35 EXPECT_EQ(Record::Line, Record::classify("12"));
36}
37
38TEST(ModuleRecord, parse) {
39 EXPECT_EQ(ModuleRecord(llvm::Triple::Linux, llvm::Triple::x86_64,
40 UUID("@ABCDEFGHIJKLMNO", 16)),
41 ModuleRecord::parse(
42 "MODULE Linux x86_64 404142434445464748494a4b4c4d4e4f0 a.out"));
43
44 EXPECT_EQ(std::nullopt, ModuleRecord::parse("MODULE"));
45 EXPECT_EQ(std::nullopt, ModuleRecord::parse("MODULE Linux"));
46 EXPECT_EQ(std::nullopt, ModuleRecord::parse("MODULE Linux x86_64"));
47 EXPECT_EQ(std::nullopt,
48 ModuleRecord::parse("MODULE Linux x86_64 deadbeefbaadf00d"));
49}
50
51TEST(InfoRecord, parse) {
52 EXPECT_EQ(InfoRecord(UUID("@ABCDEFGHIJKLMNO", 16)),
53 InfoRecord::parse("INFO CODE_ID 404142434445464748494a4b4c4d4e4f"));
54 EXPECT_EQ(InfoRecord(UUID()), InfoRecord::parse("INFO CODE_ID 47 a.exe"));
55
56 EXPECT_EQ(std::nullopt, InfoRecord::parse("INFO"));
57 EXPECT_EQ(std::nullopt, InfoRecord::parse("INFO CODE_ID"));
58}
59
60TEST(FileRecord, parse) {
61 EXPECT_EQ(FileRecord(47, "foo"), FileRecord::parse("FILE 47 foo"));
62 EXPECT_EQ(std::nullopt, FileRecord::parse("FILE 47"));
63 EXPECT_EQ(std::nullopt, FileRecord::parse("FILE"));
64 EXPECT_EQ(std::nullopt, FileRecord::parse(""));
65}
66
67TEST(FuncRecord, parse) {
68 EXPECT_EQ(FuncRecord(true, 0x47, 0x7, 0x8, "foo"),
69 FuncRecord::parse("FUNC m 47 7 8 foo"));
70 EXPECT_EQ(FuncRecord(false, 0x47, 0x7, 0x8, "foo"),
71 FuncRecord::parse("FUNC 47 7 8 foo"));
72
73 EXPECT_EQ(std::nullopt, FuncRecord::parse("PUBLIC 47 7 8 foo"));
74 EXPECT_EQ(std::nullopt, FuncRecord::parse("FUNC 47 7 8"));
75 EXPECT_EQ(std::nullopt, FuncRecord::parse("FUNC 47 7"));
76 EXPECT_EQ(std::nullopt, FuncRecord::parse("FUNC 47"));
77 EXPECT_EQ(std::nullopt, FuncRecord::parse("FUNC m"));
78 EXPECT_EQ(std::nullopt, FuncRecord::parse("FUNC"));
79}
80
81TEST(InlineOriginRecord, parse) {
82 EXPECT_EQ(InlineOriginRecord(47, "foo"),
83 InlineOriginRecord::parse("INLINE_ORIGIN 47 foo"));
84 EXPECT_EQ(std::nullopt, InlineOriginRecord::parse("INLINE_ORIGIN 47"));
85 EXPECT_EQ(std::nullopt, InlineOriginRecord::parse("INLINE_ORIGIN"));
86 EXPECT_EQ(std::nullopt, InlineOriginRecord::parse(""));
87}
88
89TEST(InlineRecord, parse) {
90 InlineRecord record1 = InlineRecord(0, 1, 2, 3);
91 record1.Ranges.emplace_back(args: 4, args: 5);
92 EXPECT_EQ(record1, InlineRecord::parse("INLINE 0 1 2 3 4 5"));
93 record1.Ranges.emplace_back(args: 6, args: 7);
94 EXPECT_EQ(record1, InlineRecord::parse("INLINE 0 1 2 3 4 5 6 7"));
95 EXPECT_EQ(std::nullopt, InlineRecord::parse("INLINE 0 1 2 3"));
96 EXPECT_EQ(std::nullopt, InlineRecord::parse("INLINE 0 1 2 3 4 5 6"));
97 EXPECT_EQ(std::nullopt, InlineRecord::parse("INLNIE 0"));
98 EXPECT_EQ(std::nullopt, InlineRecord::parse(""));
99 EXPECT_EQ(std::nullopt, InlineRecord::parse("FUNC"));
100}
101
102TEST(LineRecord, parse) {
103 EXPECT_EQ(LineRecord(0x47, 0x74, 47, 74), LineRecord::parse("47 74 47 74"));
104 EXPECT_EQ(std::nullopt, LineRecord::parse("47 74 47"));
105 EXPECT_EQ(std::nullopt, LineRecord::parse("47 74"));
106 EXPECT_EQ(std::nullopt, LineRecord::parse("47"));
107 EXPECT_EQ(std::nullopt, LineRecord::parse(""));
108 EXPECT_EQ(std::nullopt, LineRecord::parse("FUNC"));
109}
110
111TEST(PublicRecord, parse) {
112 EXPECT_EQ(PublicRecord(true, 0x47, 0x8, "foo"),
113 PublicRecord::parse("PUBLIC m 47 8 foo"));
114 EXPECT_EQ(PublicRecord(false, 0x47, 0x8, "foo"),
115 PublicRecord::parse("PUBLIC 47 8 foo"));
116
117 EXPECT_EQ(std::nullopt, PublicRecord::parse("FUNC 47 8 foo"));
118 EXPECT_EQ(std::nullopt, PublicRecord::parse("PUBLIC 47 8"));
119 EXPECT_EQ(std::nullopt, PublicRecord::parse("PUBLIC 47"));
120 EXPECT_EQ(std::nullopt, PublicRecord::parse("PUBLIC m"));
121 EXPECT_EQ(std::nullopt, PublicRecord::parse("PUBLIC"));
122}
123
124TEST(StackCFIRecord, parse) {
125 EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 + $eip: .cfa 4 - ^"),
126 StackCFIRecord::parse(
127 "STACK CFI INIT 47 8 .cfa: $esp 4 + $eip: .cfa 4 - ^"));
128
129 EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 +"),
130 StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: $esp 4 + "));
131
132 EXPECT_EQ(StackCFIRecord(0x47, std::nullopt, ".cfa: $esp 4 +"),
133 StackCFIRecord::parse("STACK CFI 47 .cfa: $esp 4 +"));
134
135 // The validity of the register value expressions is not checked
136 EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: ^ ^ ^"),
137 StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: ^ ^ ^"));
138
139 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("STACK CFI INIT 47"));
140 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("STACK CFI INIT"));
141 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("STACK CFI"));
142 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("STACK"));
143 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("FILE 47 foo"));
144 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("42 47"));
145}
146
147TEST(StackWinRecord, parse) {
148 EXPECT_EQ(
149 StackWinRecord(0x47, 0x8, 3, 4, 5, llvm::StringRef("$eip $esp ^ =")),
150 StackWinRecord::parse("STACK WIN 4 47 8 1 2 3 4 5 6 1 $eip $esp ^ ="));
151
152 EXPECT_EQ(std::nullopt, StackWinRecord::parse(
153 "STACK WIN 0 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
154 EXPECT_EQ(std::nullopt,
155 StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0 0 1"));
156 EXPECT_EQ(std::nullopt, StackWinRecord::parse(
157 "STACK WIN 3 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
158 EXPECT_EQ(std::nullopt,
159 StackWinRecord::parse("STACK WIN 3 47 8 1 0 0 0 0 0 0 1"));
160 EXPECT_EQ(std::nullopt, StackWinRecord::parse(
161 "STACK WIN 4 47 8 1 0 0 0 0 1 $eip $esp ^ ="));
162 EXPECT_EQ(std::nullopt,
163 StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0"));
164 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0"));
165 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0"));
166 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0"));
167 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8 1 0"));
168 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8 1"));
169 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47 8"));
170 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4 47"));
171 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN 4"));
172 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK WIN"));
173 EXPECT_EQ(std::nullopt, StackWinRecord::parse("STACK"));
174 EXPECT_EQ(std::nullopt, StackWinRecord::parse(""));
175 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("FILE 47 foo"));
176 EXPECT_EQ(std::nullopt, StackCFIRecord::parse("42 47"));
177}
178

source code of lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp