Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/eh-frame.h"
6 : #include "test/unittests/test-utils.h"
7 :
8 : namespace v8 {
9 : namespace internal {
10 :
11 : // Test enabled only on supported architectures.
12 : #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM) || \
13 : defined(V8_TARGET_ARCH_ARM64)
14 :
15 : namespace {
16 :
17 38 : class EhFrameWriterTest : public TestWithZone {
18 : protected:
19 : // Being a 7bit positive integer, this also serves as its ULEB128 encoding.
20 : static const int kTestRegisterCode = 0;
21 :
22 : static EhFrameIterator MakeIterator(EhFrameWriter* writer) {
23 19 : CodeDesc desc;
24 19 : writer->GetEhFrame(&desc);
25 : DCHECK_GT(desc.unwinding_info_size, 0);
26 : return EhFrameIterator(desc.unwinding_info,
27 19 : desc.unwinding_info + desc.unwinding_info_size);
28 : }
29 : };
30 :
31 : const int EhFrameWriterTest::kTestRegisterCode;
32 :
33 : } // namespace
34 :
35 15444 : TEST_F(EhFrameWriterTest, Alignment) {
36 1 : EhFrameWriter writer(zone());
37 1 : writer.Initialize();
38 1 : writer.AdvanceLocation(42 * EhFrameConstants::kCodeAlignmentFactor);
39 1 : writer.Finish(100);
40 :
41 : EhFrameIterator iterator = MakeIterator(&writer);
42 2 : ASSERT_EQ(0, EhFrameConstants::kEhFrameHdrSize % 4);
43 2 : ASSERT_EQ(0, EhFrameConstants::kEhFrameTerminatorSize % 4);
44 2 : EXPECT_EQ(0, (iterator.GetBufferSize() - EhFrameConstants::kEhFrameHdrSize -
45 : EhFrameConstants::kEhFrameTerminatorSize) %
46 0 : kSystemPointerSize);
47 : }
48 :
49 15444 : TEST_F(EhFrameWriterTest, FDEHeader) {
50 : static const int kProcedureSize = 0x5678ABCD;
51 :
52 1 : EhFrameWriter writer(zone());
53 1 : writer.Initialize();
54 1 : writer.Finish(kProcedureSize);
55 :
56 : EhFrameIterator iterator = MakeIterator(&writer);
57 1 : int cie_size = iterator.GetNextUInt32();
58 : iterator.Skip(cie_size);
59 :
60 1 : int fde_size = iterator.GetNextUInt32();
61 3 : EXPECT_EQ(iterator.GetBufferSize(),
62 : fde_size + cie_size + EhFrameConstants::kEhFrameTerminatorSize +
63 0 : EhFrameConstants::kEhFrameHdrSize + 2 * kInt32Size);
64 :
65 1 : int backwards_offset_to_cie_offset = iterator.GetCurrentOffset();
66 1 : int backwards_offset_to_cie = iterator.GetNextUInt32();
67 1 : EXPECT_EQ(backwards_offset_to_cie_offset, backwards_offset_to_cie);
68 :
69 : int procedure_address_offset = iterator.GetCurrentOffset();
70 1 : int procedure_address = iterator.GetNextUInt32();
71 2 : EXPECT_EQ(-(procedure_address_offset + RoundUp(kProcedureSize, 8)),
72 0 : procedure_address);
73 :
74 1 : int procedure_size = iterator.GetNextUInt32();
75 1 : EXPECT_EQ(kProcedureSize, procedure_size);
76 1 : }
77 :
78 15444 : TEST_F(EhFrameWriterTest, SetOffset) {
79 : static const uint32_t kOffset = 0x0BADC0DE;
80 :
81 1 : EhFrameWriter writer(zone());
82 1 : writer.Initialize();
83 1 : writer.SetBaseAddressOffset(kOffset);
84 1 : writer.Finish(100);
85 :
86 : EhFrameIterator iterator = MakeIterator(&writer);
87 : iterator.SkipToFdeDirectives();
88 :
89 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kDefCfaOffset,
90 0 : iterator.GetNextOpcode());
91 2 : EXPECT_EQ(kOffset, iterator.GetNextULeb128());
92 1 : }
93 :
94 15444 : TEST_F(EhFrameWriterTest, IncreaseOffset) {
95 : static const uint32_t kFirstOffset = 121;
96 : static const uint32_t kSecondOffset = 16;
97 :
98 1 : EhFrameWriter writer(zone());
99 1 : writer.Initialize();
100 1 : writer.SetBaseAddressOffset(kFirstOffset);
101 : writer.IncreaseBaseAddressOffset(kSecondOffset);
102 1 : writer.Finish(100);
103 :
104 : EhFrameIterator iterator = MakeIterator(&writer);
105 : iterator.SkipToFdeDirectives();
106 :
107 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kDefCfaOffset,
108 0 : iterator.GetNextOpcode());
109 2 : EXPECT_EQ(kFirstOffset, iterator.GetNextULeb128());
110 :
111 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kDefCfaOffset,
112 0 : iterator.GetNextOpcode());
113 2 : EXPECT_EQ(kFirstOffset + kSecondOffset, iterator.GetNextULeb128());
114 1 : }
115 :
116 15444 : TEST_F(EhFrameWriterTest, SetRegister) {
117 1 : Register test_register = Register::from_code(kTestRegisterCode);
118 :
119 1 : EhFrameWriter writer(zone());
120 1 : writer.Initialize();
121 1 : writer.SetBaseAddressRegister(test_register);
122 1 : writer.Finish(100);
123 :
124 : EhFrameIterator iterator = MakeIterator(&writer);
125 : iterator.SkipToFdeDirectives();
126 :
127 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kDefCfaRegister,
128 0 : iterator.GetNextOpcode());
129 2 : EXPECT_EQ(static_cast<uint32_t>(kTestRegisterCode),
130 0 : iterator.GetNextULeb128());
131 1 : }
132 :
133 15444 : TEST_F(EhFrameWriterTest, SetRegisterAndOffset) {
134 1 : Register test_register = Register::from_code(kTestRegisterCode);
135 : static const uint32_t kOffset = 0x0BADC0DE;
136 :
137 1 : EhFrameWriter writer(zone());
138 1 : writer.Initialize();
139 1 : writer.SetBaseAddressRegisterAndOffset(test_register, kOffset);
140 1 : writer.Finish(100);
141 :
142 : EhFrameIterator iterator = MakeIterator(&writer);
143 : iterator.SkipToFdeDirectives();
144 :
145 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kDefCfa, iterator.GetNextOpcode());
146 2 : EXPECT_EQ(static_cast<uint32_t>(kTestRegisterCode),
147 0 : iterator.GetNextULeb128());
148 2 : EXPECT_EQ(kOffset, iterator.GetNextULeb128());
149 1 : }
150 :
151 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding6bit) {
152 : static const int kOffset = 42;
153 :
154 1 : EhFrameWriter writer(zone());
155 1 : writer.Initialize();
156 1 : writer.AdvanceLocation(kOffset * EhFrameConstants::kCodeAlignmentFactor);
157 1 : writer.Finish(100);
158 :
159 : EhFrameIterator iterator = MakeIterator(&writer);
160 : iterator.SkipToFdeDirectives();
161 :
162 2 : EXPECT_EQ((1 << 6) | kOffset, iterator.GetNextByte());
163 1 : }
164 :
165 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding6bitDelta) {
166 : static const int kFirstOffset = 42;
167 : static const int kSecondOffset = 62;
168 :
169 1 : EhFrameWriter writer(zone());
170 1 : writer.Initialize();
171 1 : writer.AdvanceLocation(kFirstOffset * EhFrameConstants::kCodeAlignmentFactor);
172 1 : writer.AdvanceLocation(kSecondOffset *
173 1 : EhFrameConstants::kCodeAlignmentFactor);
174 1 : writer.Finish(100);
175 :
176 : EhFrameIterator iterator = MakeIterator(&writer);
177 : iterator.SkipToFdeDirectives();
178 :
179 2 : EXPECT_EQ((1 << 6) | kFirstOffset, iterator.GetNextByte());
180 2 : EXPECT_EQ((1 << 6) | (kSecondOffset - kFirstOffset), iterator.GetNextByte());
181 1 : }
182 :
183 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding8bit) {
184 : static const int kOffset = 0x42;
185 :
186 1 : EhFrameWriter writer(zone());
187 1 : writer.Initialize();
188 1 : writer.AdvanceLocation(kOffset * EhFrameConstants::kCodeAlignmentFactor);
189 1 : writer.Finish(100);
190 :
191 : EhFrameIterator iterator = MakeIterator(&writer);
192 : iterator.SkipToFdeDirectives();
193 :
194 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc1,
195 0 : iterator.GetNextOpcode());
196 2 : EXPECT_EQ(kOffset, iterator.GetNextByte());
197 1 : }
198 :
199 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding8bitDelta) {
200 : static const int kFirstOffset = 0x10;
201 : static const int kSecondOffset = 0x70;
202 : static const int kThirdOffset = 0xB5;
203 :
204 1 : EhFrameWriter writer(zone());
205 1 : writer.Initialize();
206 1 : writer.AdvanceLocation(kFirstOffset * EhFrameConstants::kCodeAlignmentFactor);
207 1 : writer.AdvanceLocation(kSecondOffset *
208 1 : EhFrameConstants::kCodeAlignmentFactor);
209 1 : writer.AdvanceLocation(kThirdOffset * EhFrameConstants::kCodeAlignmentFactor);
210 1 : writer.Finish(100);
211 :
212 : EhFrameIterator iterator = MakeIterator(&writer);
213 : iterator.SkipToFdeDirectives();
214 :
215 2 : EXPECT_EQ((1 << 6) | kFirstOffset, iterator.GetNextByte());
216 :
217 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc1,
218 0 : iterator.GetNextOpcode());
219 2 : EXPECT_EQ(kSecondOffset - kFirstOffset, iterator.GetNextByte());
220 :
221 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc1,
222 0 : iterator.GetNextOpcode());
223 2 : EXPECT_EQ(kThirdOffset - kSecondOffset, iterator.GetNextByte());
224 1 : }
225 :
226 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding16bit) {
227 : static const int kOffset = kMaxUInt8 + 42;
228 1 : ASSERT_LT(kOffset, kMaxUInt16);
229 :
230 1 : EhFrameWriter writer(zone());
231 1 : writer.Initialize();
232 1 : writer.AdvanceLocation(kOffset * EhFrameConstants::kCodeAlignmentFactor);
233 1 : writer.Finish(100);
234 :
235 : EhFrameIterator iterator = MakeIterator(&writer);
236 : iterator.SkipToFdeDirectives();
237 :
238 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc2,
239 0 : iterator.GetNextOpcode());
240 2 : EXPECT_EQ(kOffset, iterator.GetNextUInt16());
241 : }
242 :
243 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding16bitDelta) {
244 : static const int kFirstOffset = 0x41;
245 : static const int kSecondOffset = kMaxUInt8 + 0x42;
246 :
247 1 : EhFrameWriter writer(zone());
248 1 : writer.Initialize();
249 1 : writer.AdvanceLocation(kFirstOffset * EhFrameConstants::kCodeAlignmentFactor);
250 1 : writer.AdvanceLocation(kSecondOffset *
251 1 : EhFrameConstants::kCodeAlignmentFactor);
252 1 : writer.Finish(100);
253 :
254 : EhFrameIterator iterator = MakeIterator(&writer);
255 : iterator.SkipToFdeDirectives();
256 :
257 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc1,
258 0 : iterator.GetNextOpcode());
259 2 : EXPECT_EQ(kFirstOffset, iterator.GetNextByte());
260 :
261 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc2,
262 0 : iterator.GetNextOpcode());
263 2 : EXPECT_EQ(kSecondOffset - kFirstOffset, iterator.GetNextUInt16());
264 1 : }
265 :
266 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding32bit) {
267 : static const uint32_t kOffset = kMaxUInt16 + 42;
268 :
269 1 : EhFrameWriter writer(zone());
270 1 : writer.Initialize();
271 1 : writer.AdvanceLocation(kOffset * EhFrameConstants::kCodeAlignmentFactor);
272 1 : writer.Finish(100);
273 :
274 : EhFrameIterator iterator = MakeIterator(&writer);
275 : iterator.SkipToFdeDirectives();
276 :
277 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc4,
278 0 : iterator.GetNextOpcode());
279 2 : EXPECT_EQ(kOffset, iterator.GetNextUInt32());
280 1 : }
281 :
282 15444 : TEST_F(EhFrameWriterTest, PcOffsetEncoding32bitDelta) {
283 : static const uint32_t kFirstOffset = kMaxUInt16 + 0x42;
284 : static const uint32_t kSecondOffset = kMaxUInt16 + 0x67;
285 :
286 1 : EhFrameWriter writer(zone());
287 1 : writer.Initialize();
288 1 : writer.AdvanceLocation(kFirstOffset * EhFrameConstants::kCodeAlignmentFactor);
289 1 : writer.AdvanceLocation(kSecondOffset *
290 1 : EhFrameConstants::kCodeAlignmentFactor);
291 1 : writer.Finish(100);
292 :
293 : EhFrameIterator iterator = MakeIterator(&writer);
294 : iterator.SkipToFdeDirectives();
295 :
296 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kAdvanceLoc4,
297 0 : iterator.GetNextOpcode());
298 2 : EXPECT_EQ(kFirstOffset, iterator.GetNextUInt32());
299 :
300 2 : EXPECT_EQ((1 << 6) | (kSecondOffset - kFirstOffset), iterator.GetNextByte());
301 1 : }
302 :
303 15444 : TEST_F(EhFrameWriterTest, SaveRegisterUnsignedOffset) {
304 : Register test_register = Register::from_code(kTestRegisterCode);
305 : static const int kOffset =
306 1 : EhFrameConstants::kDataAlignmentFactor > 0 ? 12344 : -12344;
307 :
308 1 : EhFrameWriter writer(zone());
309 1 : writer.Initialize();
310 1 : writer.RecordRegisterSavedToStack(test_register, kOffset);
311 1 : writer.Finish(100);
312 :
313 : EhFrameIterator iterator = MakeIterator(&writer);
314 : iterator.SkipToFdeDirectives();
315 :
316 2 : EXPECT_EQ((2 << 6) | kTestRegisterCode, iterator.GetNextByte());
317 2 : EXPECT_EQ(
318 : static_cast<uint32_t>(kOffset / EhFrameConstants::kDataAlignmentFactor),
319 0 : iterator.GetNextULeb128());
320 1 : }
321 :
322 15444 : TEST_F(EhFrameWriterTest, SaveRegisterSignedOffset) {
323 : Register test_register = Register::from_code(kTestRegisterCode);
324 : static const int kOffset =
325 1 : EhFrameConstants::kDataAlignmentFactor < 0 ? 12344 : -12344;
326 :
327 2 : ASSERT_EQ(kOffset % EhFrameConstants::kDataAlignmentFactor, 0);
328 :
329 1 : EhFrameWriter writer(zone());
330 1 : writer.Initialize();
331 1 : writer.RecordRegisterSavedToStack(test_register, kOffset);
332 1 : writer.Finish(100);
333 :
334 : EhFrameIterator iterator = MakeIterator(&writer);
335 : iterator.SkipToFdeDirectives();
336 :
337 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kOffsetExtendedSf,
338 0 : iterator.GetNextOpcode());
339 2 : EXPECT_EQ(static_cast<uint32_t>(kTestRegisterCode),
340 0 : iterator.GetNextULeb128());
341 2 : EXPECT_EQ(kOffset / EhFrameConstants::kDataAlignmentFactor,
342 0 : iterator.GetNextSLeb128());
343 : }
344 :
345 15444 : TEST_F(EhFrameWriterTest, RegisterNotModified) {
346 1 : Register test_register = Register::from_code(kTestRegisterCode);
347 :
348 1 : EhFrameWriter writer(zone());
349 1 : writer.Initialize();
350 1 : writer.RecordRegisterNotModified(test_register);
351 1 : writer.Finish(100);
352 :
353 : EhFrameIterator iterator = MakeIterator(&writer);
354 : iterator.SkipToFdeDirectives();
355 :
356 2 : EXPECT_EQ(EhFrameConstants::DwarfOpcodes::kSameValue,
357 0 : iterator.GetNextOpcode());
358 2 : EXPECT_EQ(static_cast<uint32_t>(kTestRegisterCode),
359 0 : iterator.GetNextULeb128());
360 1 : }
361 :
362 15444 : TEST_F(EhFrameWriterTest, RegisterFollowsInitialRule) {
363 1 : Register test_register = Register::from_code(kTestRegisterCode);
364 :
365 1 : EhFrameWriter writer(zone());
366 1 : writer.Initialize();
367 1 : writer.RecordRegisterFollowsInitialRule(test_register);
368 1 : writer.Finish(100);
369 :
370 : EhFrameIterator iterator = MakeIterator(&writer);
371 : iterator.SkipToFdeDirectives();
372 :
373 2 : EXPECT_EQ((3 << 6) | kTestRegisterCode, iterator.GetNextByte());
374 1 : }
375 :
376 15444 : TEST_F(EhFrameWriterTest, EhFrameHdrLayout) {
377 : static const int kCodeSize = 10;
378 : static const int kPaddingSize = 6;
379 :
380 1 : EhFrameWriter writer(zone());
381 1 : writer.Initialize();
382 1 : writer.Finish(kCodeSize);
383 :
384 : EhFrameIterator iterator = MakeIterator(&writer);
385 :
386 : // Skip the .eh_frame.
387 :
388 1 : int encoded_cie_size = iterator.GetNextUInt32();
389 : iterator.Skip(encoded_cie_size);
390 1 : int cie_size = encoded_cie_size + kInt32Size;
391 :
392 1 : int encoded_fde_size = iterator.GetNextUInt32();
393 : iterator.Skip(encoded_fde_size);
394 1 : int fde_size = encoded_fde_size + kInt32Size;
395 :
396 : iterator.Skip(EhFrameConstants::kEhFrameTerminatorSize);
397 :
398 : int eh_frame_size =
399 1 : cie_size + fde_size + EhFrameConstants::kEhFrameTerminatorSize;
400 :
401 : //
402 : // Plugging some numbers in the DSO layout shown in eh-frame.cc:
403 : //
404 : // | ... |
405 : // +---------------+ <-- (E) ---------
406 : // | | ^
407 : // | Instructions | 10 bytes | .text
408 : // | | v
409 : // +---------------+ <----------------
410 : // |///////////////|
411 : // |////Padding////| 6 bytes
412 : // |///////////////|
413 : // +---------------+ <---(D)----------
414 : // | | ^
415 : // | CIE | cie_size bytes* |
416 : // | | |
417 : // +---------------+ <-- (C) |
418 : // | | | .eh_frame
419 : // | FDE | fde_size bytes |
420 : // | | |
421 : // +---------------+ |
422 : // | terminator | 4 bytes v
423 : // +---------------+ <-- (B) ---------
424 : // | version | ^
425 : // +---------------+ 4 bytes |
426 : // | encoding | |
427 : // | specifiers | |
428 : // +---------------+ <---(A) | .eh_frame_hdr
429 : // | offset to | |
430 : // | .eh_frame | |
431 : // +---------------+ |
432 : // | ... | ...
433 : //
434 : // (*) the size of the CIE is platform dependent.
435 : //
436 :
437 1 : int eh_frame_hdr_version = iterator.GetNextByte();
438 1 : EXPECT_EQ(EhFrameConstants::kEhFrameHdrVersion, eh_frame_hdr_version);
439 :
440 : // .eh_frame pointer encoding specifier.
441 2 : EXPECT_EQ(EhFrameConstants::kSData4 | EhFrameConstants::kPcRel,
442 0 : iterator.GetNextByte());
443 :
444 : // Lookup table size encoding specifier.
445 2 : EXPECT_EQ(EhFrameConstants::kUData4, iterator.GetNextByte());
446 :
447 : // Lookup table pointers encoding specifier.
448 2 : EXPECT_EQ(EhFrameConstants::kSData4 | EhFrameConstants::kDataRel,
449 0 : iterator.GetNextByte());
450 :
451 : // A -> D
452 1 : int offset_to_eh_frame = iterator.GetNextUInt32();
453 2 : EXPECT_EQ(-(EhFrameConstants::kFdeVersionSize +
454 : EhFrameConstants::kFdeEncodingSpecifiersSize + eh_frame_size),
455 0 : offset_to_eh_frame);
456 :
457 1 : int lut_entries = iterator.GetNextUInt32();
458 2 : EXPECT_EQ(1, lut_entries);
459 :
460 : // B -> E
461 1 : int offset_to_procedure = iterator.GetNextUInt32();
462 2 : EXPECT_EQ(-(eh_frame_size + kPaddingSize + kCodeSize), offset_to_procedure);
463 :
464 : // B -> C
465 1 : int offset_to_fde = iterator.GetNextUInt32();
466 2 : EXPECT_EQ(-(fde_size + EhFrameConstants::kEhFrameTerminatorSize),
467 0 : offset_to_fde);
468 1 : }
469 :
470 : #endif
471 :
472 : } // namespace internal
473 9264 : } // namespace v8
|