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 |