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