1 | //===- llvm/unittest/MC/DwarfLineTables.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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ADT/STLExtras.h" |
10 | #include "llvm/ADT/StringExtras.h" |
11 | #include "llvm/BinaryFormat/Dwarf.h" |
12 | #include "llvm/MC/MCAsmInfo.h" |
13 | #include "llvm/MC/MCContext.h" |
14 | #include "llvm/MC/MCDwarf.h" |
15 | #include "llvm/MC/MCRegisterInfo.h" |
16 | #include "llvm/MC/MCTargetOptions.h" |
17 | #include "llvm/MC/TargetRegistry.h" |
18 | #include "llvm/Support/TargetSelect.h" |
19 | #include "gtest/gtest.h" |
20 | |
21 | using namespace llvm; |
22 | |
23 | namespace { |
24 | struct Context { |
25 | const char *TripleName = "x86_64-pc-linux" ; |
26 | std::unique_ptr<MCRegisterInfo> MRI; |
27 | std::unique_ptr<MCAsmInfo> MAI; |
28 | std::unique_ptr<MCContext> Ctx; |
29 | |
30 | Context() { |
31 | llvm::InitializeAllTargetInfos(); |
32 | llvm::InitializeAllTargetMCs(); |
33 | llvm::InitializeAllDisassemblers(); |
34 | |
35 | // If we didn't build x86, do not run the test. |
36 | std::string Error; |
37 | const Target *TheTarget = TargetRegistry::lookupTarget(Triple: TripleName, Error); |
38 | if (!TheTarget) |
39 | return; |
40 | |
41 | MRI.reset(p: TheTarget->createMCRegInfo(TT: TripleName)); |
42 | MCTargetOptions MCOptions; |
43 | MAI.reset(p: TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple: TripleName, Options: MCOptions)); |
44 | Ctx = std::make_unique<MCContext>(args: Triple(TripleName), args: MAI.get(), args: MRI.get(), |
45 | /*MSTI=*/args: nullptr); |
46 | } |
47 | |
48 | operator bool() { return Ctx.get(); } |
49 | operator MCContext &() { return *Ctx; }; |
50 | }; |
51 | |
52 | Context &getContext() { |
53 | static Context Ctxt; |
54 | return Ctxt; |
55 | } |
56 | } |
57 | |
58 | void verifyEncoding(MCDwarfLineTableParams Params, int LineDelta, int AddrDelta, |
59 | ArrayRef<uint8_t> ExpectedEncoding) { |
60 | SmallString<16> Buffer; |
61 | MCDwarfLineAddr::encode(Context&: getContext(), Params, LineDelta, AddrDelta, |
62 | OS&: Buffer); |
63 | EXPECT_EQ(ExpectedEncoding, arrayRefFromStringRef(Buffer)); |
64 | } |
65 | |
66 | TEST(DwarfLineTables, TestDefaultParams) { |
67 | if (!getContext()) |
68 | GTEST_SKIP(); |
69 | |
70 | MCDwarfLineTableParams Params; |
71 | |
72 | // Minimal line offset expressible through extended opcode, 0 addr delta |
73 | const uint8_t Encoding0[] = {13}; // Special opcode Addr += 0, Line += -5 |
74 | verifyEncoding(Params, LineDelta: -5, AddrDelta: 0, ExpectedEncoding: Encoding0); |
75 | |
76 | // Maximal line offset expressible through extended opcode, |
77 | const uint8_t Encoding1[] = {26}; // Special opcode Addr += 0, Line += +8 |
78 | verifyEncoding(Params, LineDelta: 8, AddrDelta: 0, ExpectedEncoding: Encoding1); |
79 | |
80 | // Random value in the middle of the special ocode range |
81 | const uint8_t Encoding2[] = {146}; // Special opcode Addr += 9, Line += 2 |
82 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 9, ExpectedEncoding: Encoding2); |
83 | |
84 | // Minimal line offset expressible through extended opcode, max addr delta |
85 | const uint8_t Encoding3[] = {251}; // Special opcode Addr += 17, Line += -5 |
86 | verifyEncoding(Params, LineDelta: -5, AddrDelta: 17, ExpectedEncoding: Encoding3); |
87 | |
88 | // Biggest special opcode |
89 | const uint8_t Encoding4[] = {255}; // Special opcode Addr += 17, Line += -1 |
90 | verifyEncoding(Params, LineDelta: -1, AddrDelta: 17, ExpectedEncoding: Encoding4); |
91 | |
92 | // Line delta outside of the special opcode range, address delta in range |
93 | const uint8_t Encoding5[] = {dwarf::DW_LNS_advance_line, 9, |
94 | 158}; // Special opcode Addr += 10, Line += 0 |
95 | verifyEncoding(Params, LineDelta: 9, AddrDelta: 10, ExpectedEncoding: Encoding5); |
96 | |
97 | // Address delta outside of the special opcode range, but small |
98 | // enough to do DW_LNS_const_add_pc + special opcode. |
99 | const uint8_t Encoding6[] = {dwarf::DW_LNS_const_add_pc, // pc += 17 |
100 | 62}; // Special opcode Addr += 3, Line += 2 |
101 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 20, ExpectedEncoding: Encoding6); |
102 | |
103 | // Address delta big enough to require the use of DW_LNS_advance_pc |
104 | // Line delta in special opcode range |
105 | const uint8_t Encoding7[] = {dwarf::DW_LNS_advance_pc, 100, |
106 | 20}; // Special opcode Addr += 0, Line += 2 |
107 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 100, ExpectedEncoding: Encoding7); |
108 | |
109 | // No special opcode possible. |
110 | const uint8_t Encoding8[] = {dwarf::DW_LNS_advance_line, 20, |
111 | dwarf::DW_LNS_advance_pc, 100, |
112 | dwarf::DW_LNS_copy}; |
113 | verifyEncoding(Params, LineDelta: 20, AddrDelta: 100, ExpectedEncoding: Encoding8); |
114 | } |
115 | |
116 | TEST(DwarfLineTables, TestCustomParams) { |
117 | if (!getContext()) |
118 | GTEST_SKIP(); |
119 | |
120 | // Some tests against the example values given in the standard. |
121 | MCDwarfLineTableParams Params; |
122 | Params.DWARF2LineOpcodeBase = 13; |
123 | Params.DWARF2LineBase = -3; |
124 | Params.DWARF2LineRange = 12; |
125 | |
126 | // Minimal line offset expressible through extended opcode, 0 addr delta |
127 | const uint8_t Encoding0[] = {13}; // Special opcode Addr += 0, Line += -5 |
128 | verifyEncoding(Params, LineDelta: -3, AddrDelta: 0, ExpectedEncoding: Encoding0); |
129 | |
130 | // Maximal line offset expressible through extended opcode, |
131 | const uint8_t Encoding1[] = {24}; // Special opcode Addr += 0, Line += +8 |
132 | verifyEncoding(Params, LineDelta: 8, AddrDelta: 0, ExpectedEncoding: Encoding1); |
133 | |
134 | // Random value in the middle of the special ocode range |
135 | const uint8_t Encoding2[] = {126}; // Special opcode Addr += 9, Line += 2 |
136 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 9, ExpectedEncoding: Encoding2); |
137 | |
138 | // Minimal line offset expressible through extended opcode, max addr delta |
139 | const uint8_t Encoding3[] = {253}; // Special opcode Addr += 20, Line += -3 |
140 | verifyEncoding(Params, LineDelta: -3, AddrDelta: 20, ExpectedEncoding: Encoding3); |
141 | |
142 | // Biggest special opcode |
143 | const uint8_t Encoding4[] = {255}; // Special opcode Addr += 17, Line += -1 |
144 | verifyEncoding(Params, LineDelta: -1, AddrDelta: 20, ExpectedEncoding: Encoding4); |
145 | |
146 | // Line delta outside of the special opcode range, address delta in range |
147 | const uint8_t Encoding5[] = {dwarf::DW_LNS_advance_line, 9, |
148 | 136}; // Special opcode Addr += 10, Line += 0 |
149 | verifyEncoding(Params, LineDelta: 9, AddrDelta: 10, ExpectedEncoding: Encoding5); |
150 | |
151 | // Address delta outside of the special opcode range, but small |
152 | // enough to do DW_LNS_const_add_pc + special opcode. |
153 | const uint8_t Encoding6[] = {dwarf::DW_LNS_const_add_pc, // pc += 20 |
154 | 138}; // Special opcode Addr += 10, Line += 2 |
155 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 30, ExpectedEncoding: Encoding6); |
156 | |
157 | // Address delta big enough to require the use of DW_LNS_advance_pc |
158 | // Line delta in special opcode range |
159 | const uint8_t Encoding7[] = {dwarf::DW_LNS_advance_pc, 100, |
160 | 18}; // Special opcode Addr += 0, Line += 2 |
161 | verifyEncoding(Params, LineDelta: 2, AddrDelta: 100, ExpectedEncoding: Encoding7); |
162 | |
163 | // No special opcode possible. |
164 | const uint8_t Encoding8[] = {dwarf::DW_LNS_advance_line, 20, |
165 | dwarf::DW_LNS_advance_pc, 100, |
166 | dwarf::DW_LNS_copy}; |
167 | verifyEncoding(Params, LineDelta: 20, AddrDelta: 100, ExpectedEncoding: Encoding8); |
168 | } |
169 | |
170 | TEST(DwarfLineTables, TestCustomParams2) { |
171 | if (!getContext()) |
172 | GTEST_SKIP(); |
173 | |
174 | // Corner case param values. |
175 | MCDwarfLineTableParams Params; |
176 | Params.DWARF2LineOpcodeBase = 13; |
177 | Params.DWARF2LineBase = 1; |
178 | Params.DWARF2LineRange = 255; |
179 | |
180 | const uint8_t Encoding0[] = {dwarf::DW_LNS_advance_line, 248, 1, |
181 | dwarf::DW_LNS_copy}; |
182 | verifyEncoding(Params, LineDelta: 248, AddrDelta: 0, ExpectedEncoding: Encoding0); |
183 | } |
184 | |