Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/eh-frame.h" | 5 #include "src/eh-frame.h" |
| 6 #include "src/objects-inl.h" | 6 |
| 7 #include "src/objects.h" | 7 #include <iomanip> |
| 8 #include <ostream> | |
| 9 | |
| 10 #if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM) && \ | |
| 11 !defined(V8_TARGET_ARCH_ARM64) | |
| 12 | |
| 13 // Placeholders for unsupported architectures. | |
| 8 | 14 |
| 9 namespace v8 { | 15 namespace v8 { |
| 10 namespace internal { | 16 namespace internal { |
| 11 | 17 |
| 12 static const int DW_EH_PE_pcrel = 0x10; | 18 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kDataAlignmentFactor = |
| 13 static const int DW_EH_PE_datarel = 0x30; | 19 1; |
| 14 static const int DW_EH_PE_udata4 = 0x03; | 20 |
| 15 static const int DW_EH_PE_sdata4 = 0x0b; | 21 void EhFrameWriter::WriteReturnAddressRegisterCode() { UNIMPLEMENTED(); } |
| 16 | 22 |
| 17 const int EhFrameHdr::kCIESize = 0; | 23 void EhFrameWriter::WriteInitialState() { UNIMPLEMENTED(); } |
| 18 | 24 |
| 19 static const int kVersionSize = 1; | 25 const char* EhFrameWriter::DwarfRegisterCodeToString(int) { |
| 20 static const int kEncodingSpecifiersSize = 3; | 26 UNIMPLEMENTED(); |
| 27 return nullptr; | |
| 28 } | |
| 29 | |
| 30 int EhFrameWriter::RegisterToDwarfCode(Register) { | |
| 31 UNIMPLEMENTED(); | |
| 32 return -1; | |
| 33 } | |
| 34 | |
| 35 } // namespace internal | |
| 36 } // namespace v8 | |
| 37 | |
| 38 #endif | |
| 39 | |
| 40 namespace v8 { | |
| 41 namespace internal { | |
| 42 | |
| 43 STATIC_CONST_MEMBER_DEFINITION const int EhFrameWriter::kTerminatorSize; | |
| 44 STATIC_CONST_MEMBER_DEFINITION const uint32_t EhFrameWriter::kInt32Placeholder; | |
|
rmcilroy
2016/07/05 10:56:12
I don't think you need these do you?
Stefano Sanfilippo
2016/07/05 16:02:13
Unfortunately I do, otherwise I get a linking erro
| |
| 45 | |
| 46 EhFrameWriter::EhFrameWriter() | |
| 47 : last_pc_offset_(0), | |
| 48 eh_frame_finalised_(false), | |
| 49 base_register_(no_reg), | |
| 50 base_offset_(0) { | |
|
rmcilroy
2016/07/05 10:56:12
Set cie_size_ to zero here, to ensure they are pro
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 51 eh_frame_buffer_.reserve(100); | |
|
rmcilroy
2016/07/05 10:56:12
100 seems slightly random. Why not 128?
Stefano Sanfilippo
2016/07/05 16:02:13
I observed that the eh_frame for our code objects
rmcilroy
2016/07/06 13:59:30
64 in that case seems reasonable in that case (see
Stefano Sanfilippo
2016/07/06 16:54:49
Done, I went with 128 so we are covered in almost
| |
| 52 int cie_start_offset = eh_frame_offset(); | |
| 53 WriteCIE(); | |
| 54 cie_size_ = eh_frame_offset() - cie_start_offset; | |
|
rmcilroy
2016/07/05 10:56:12
Set this in WriteCIE ?
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 55 WriteFDEHeader(); | |
| 56 } | |
| 57 | |
| 58 void EhFrameWriter::WriteCIE() { | |
| 59 static const int kCIEIdentifier = 0; | |
| 60 static const int kCIEVersion = 3; | |
| 61 static const int kCodeAlignmentFactor = 1; | |
| 62 static const int kAugmentationDataSize = 2; | |
| 63 static const byte kAugmentationString[] = {'z', 'L', 'R', 0}; | |
| 64 | |
| 65 int cie_size_offset = eh_frame_offset(); | |
| 66 WriteInt32(kInt32Placeholder); | |
| 67 int cie_start_offset = eh_frame_offset(); | |
| 68 WriteInt32(kCIEIdentifier); | |
| 69 WriteByte(kCIEVersion); | |
| 70 WriteBytes(&kAugmentationString[0], sizeof(kAugmentationString)); | |
| 71 WriteSLEB128(kCodeAlignmentFactor); | |
| 72 WriteSLEB128(kDataAlignmentFactor); | |
| 73 WriteReturnAddressRegisterCode(); | |
| 74 WriteByte(kAugmentationDataSize); | |
| 75 WriteByte(kOmit); | |
| 76 WriteByte(kSData4 | kPcRel); | |
| 77 DCHECK_EQ(eh_frame_offset() - cie_size_offset, kInitialStateOffsetInCIE); | |
| 78 WriteInitialState(); | |
| 79 Align(); | |
| 80 int cie_end_offset = eh_frame_offset(); | |
| 81 int encoded_cie_size = cie_end_offset - cie_start_offset; | |
| 82 PatchInt32(cie_size_offset, encoded_cie_size); | |
|
rmcilroy
2016/07/05 10:56:12
Some whitespace would be good to break up this cod
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 83 } | |
| 84 | |
| 85 void EhFrameWriter::WriteFDEHeader() { | |
| 86 DCHECK_EQ(eh_frame_offset(), fde_offset()); | |
|
rmcilroy
2016/07/05 10:56:12
DCHECK_NE(cie_size_, 0)
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 87 WriteInt32(kInt32Placeholder); // Placeholder for size of the FDE | |
| 88 WriteInt32(cie_size_ + kInt32Size); // Backwards offset to the CIE | |
| 89 DCHECK_EQ(eh_frame_offset(), procedure_address_offset()); | |
| 90 WriteInt32(kInt32Placeholder); // Placeholder for pointer to procedure | |
| 91 DCHECK_EQ(eh_frame_offset(), procedure_size_offset()); | |
| 92 WriteInt32(kInt32Placeholder); // Placeholder for size of the procedure | |
| 93 WriteByte(0); // No augmentation data | |
|
rmcilroy
2016/07/05 10:56:12
Newlines between each of these fields, with commen
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 94 } | |
| 95 | |
| 96 void EhFrameWriter::Align() { | |
| 97 DCHECK(!eh_frame_finalised_); | |
| 98 | |
| 99 int unpadded_size = eh_frame_offset(); | |
| 100 int padded_size = RoundUp(unpadded_size, 8); | |
| 101 int padding_size = padded_size - unpadded_size; | |
| 102 | |
| 103 static const byte kPadding[] = {kNop, kNop, kNop, kNop, | |
| 104 kNop, kNop, kNop, kNop}; | |
| 105 DCHECK_LE(padding_size, static_cast<int>(sizeof(kPadding))); | |
| 106 WriteBytes(&kPadding[0], padding_size); | |
| 107 } | |
| 108 | |
| 109 void EhFrameWriter::AdvanceLocation(int pc_offset) { | |
| 110 DCHECK(!eh_frame_finalised_); | |
| 111 DCHECK_GE(pc_offset, last_pc_offset_); | |
| 112 uint32_t delta = pc_offset - last_pc_offset_; | |
| 113 | |
| 114 if (delta <= kLocationMask) { | |
| 115 WriteByte((kLocationTag << kLocationMaskSize) | (delta & kLocationMask)); | |
| 116 } else if (delta <= kMaxUInt8) { | |
| 117 WriteByte(kAdvanceLoc1); | |
| 118 WriteByte(delta); | |
| 119 } else if (delta <= kMaxUInt16) { | |
| 120 WriteByte(kAdvanceLoc2); | |
| 121 WriteInt16(delta); | |
| 122 } else { | |
| 123 WriteByte(kAdvanceLoc4); | |
| 124 WriteInt32(delta); | |
| 125 } | |
| 126 | |
| 127 last_pc_offset_ = pc_offset; | |
| 128 } | |
| 129 | |
| 130 void EhFrameWriter::SetBaseAddressOffset(int base_offset) { | |
| 131 DCHECK(!eh_frame_finalised_); | |
| 132 DCHECK_GE(base_offset, 0); | |
| 133 WriteByte(kDefCfaOffset); | |
| 134 WriteULEB128(base_offset); | |
| 135 base_offset_ = base_offset; | |
| 136 } | |
| 137 | |
| 138 void EhFrameWriter::SetBaseAddressRegister(Register base_register) { | |
| 139 DCHECK(!eh_frame_finalised_); | |
| 140 int code = RegisterToDwarfCode(base_register); | |
| 141 WriteByte(kDefCfaRegister); | |
| 142 WriteULEB128(code); | |
| 143 base_register_ = base_register; | |
| 144 } | |
| 145 | |
| 146 void EhFrameWriter::SetBaseAddressRegisterAndOffset(Register base_register, | |
| 147 int base_offset) { | |
| 148 DCHECK(!eh_frame_finalised_); | |
| 149 int code = RegisterToDwarfCode(base_register); | |
| 150 WriteByte(kDefCfa); | |
| 151 WriteULEB128(code); | |
| 152 WriteULEB128(base_offset); | |
| 153 base_offset_ = base_offset; | |
| 154 base_register_ = base_register; | |
| 155 } | |
| 156 | |
| 157 void EhFrameWriter::RegisterSavedToStack(int register_code, int offset) { | |
|
rmcilroy
2016/07/05 10:56:12
RecordRegisterSavedToStack
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 158 DCHECK(!eh_frame_finalised_); | |
| 159 DCHECK_EQ(offset % kDataAlignmentFactor, 0); | |
| 160 int factored_offset = offset / std::abs(kDataAlignmentFactor); | |
| 161 if (factored_offset >= 0) { | |
| 162 DCHECK_LE(register_code, kSavedRegisterMask); | |
| 163 WriteByte((kSavedRegisterTag << kSavedRegisterMaskSize) | | |
| 164 (register_code & kSavedRegisterMask)); | |
| 165 WriteULEB128(factored_offset); | |
| 166 } else { | |
| 167 WriteByte(kOffsetExtendedSf); | |
| 168 WriteULEB128(register_code); | |
| 169 WriteSLEB128(factored_offset); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 void EhFrameWriter::RegisterIsValid(Register name) { | |
|
rmcilroy
2016/07/05 10:56:12
RecordRegisterIsValid
Stefano Sanfilippo
2016/07/05 16:02:13
Done.
| |
| 174 int code = RegisterToDwarfCode(name); | |
| 175 DCHECK(!eh_frame_finalised_); | |
| 176 DCHECK_GE(code, 0); | |
| 177 WriteByte(kSameValue); | |
| 178 WriteULEB128(code); | |
| 179 } | |
| 180 | |
| 181 void EhFrameWriter::Finish(int code_size) { | |
| 182 DCHECK(!eh_frame_finalised_); | |
| 183 DCHECK_GE(eh_frame_offset(), cie_size_); | |
| 184 | |
| 185 Align(); | |
| 186 | |
| 187 // Write the size of the FDE now that we know it. | |
| 188 int fde_size = eh_frame_offset() - fde_offset(); | |
| 189 PatchInt32(fde_offset(), fde_size); | |
| 190 | |
| 191 // Write the size and offset to procedure. | |
| 192 PatchInt32(procedure_address_offset(), | |
| 193 -(RoundUp(code_size, 8) + procedure_address_offset())); | |
| 194 PatchInt32(procedure_size_offset(), code_size); | |
| 195 | |
| 196 // Terminate the .eh_frame. | |
| 197 static const byte kTerminator[kTerminatorSize] = {0}; | |
| 198 WriteBytes(&kTerminator[0], kTerminatorSize); | |
| 199 | |
| 200 // Write .eh_frame_hdr | |
| 201 EhFrameHdr eh_frame_hdr(code_size, eh_frame_offset(), cie_size_); | |
| 202 WriteBytes(reinterpret_cast<const byte*>(&eh_frame_hdr), | |
| 203 EhFrameHdr::kRecordSize); | |
| 204 | |
| 205 eh_frame_finalised_ = true; | |
| 206 } | |
| 207 | |
| 208 void EhFrameWriter::GetEhFrame(CodeDesc* desc) { | |
| 209 DCHECK(eh_frame_finalised_); | |
| 210 desc->unwinding_info_size = static_cast<int>(eh_frame_buffer_.size()); | |
| 211 desc->unwinding_info = eh_frame_buffer_.data(); | |
| 212 } | |
| 213 | |
| 214 void EhFrameWriter::WriteULEB128(uint32_t value) { | |
| 215 do { | |
| 216 byte chunk = value & 0x7f; | |
| 217 value >>= 7; | |
| 218 if (value != 0) chunk |= 0x80; | |
| 219 eh_frame_buffer_.push_back(chunk); | |
| 220 } while (value != 0); | |
| 221 } | |
| 222 | |
| 223 void EhFrameWriter::WriteSLEB128(int32_t value) { | |
| 224 static const int kSignBitMask = 0x40; | |
| 225 bool done; | |
| 226 do { | |
| 227 byte chunk = value & 0x7f; | |
| 228 value >>= 7; | |
| 229 done = ((value == 0) && ((chunk & kSignBitMask) == 0)) || | |
| 230 ((value == -1) && ((chunk & kSignBitMask) != 0)); | |
| 231 if (!done) chunk |= 0x80; | |
| 232 eh_frame_buffer_.push_back(chunk); | |
| 233 } while (!done); | |
| 234 } | |
| 235 | |
| 236 // static | |
| 237 uint32_t EhFrameWriter::DecodeULEB128(const byte* encoded, int* encoded_size) { | |
| 238 const byte* current = encoded; | |
| 239 uint32_t result = 0; | |
| 240 int shift = 0; | |
| 241 | |
| 242 do { | |
| 243 DCHECK_LT(shift, 8 * static_cast<int>(sizeof(result))); | |
| 244 result |= (*current & 0x7f) << shift; | |
| 245 shift += 7; | |
| 246 } while (*current++ >= 128); | |
| 247 | |
| 248 DCHECK_NOT_NULL(encoded_size); | |
| 249 *encoded_size = static_cast<int>(current - encoded); | |
| 250 | |
| 251 return result; | |
| 252 } | |
| 253 | |
| 254 // static | |
| 255 int32_t EhFrameWriter::DecodeSLEB128(const byte* encoded, int* encoded_size) { | |
| 256 static const byte kSignBitMask = 0x40; | |
| 257 | |
| 258 const byte* current = encoded; | |
| 259 int32_t result = 0; | |
| 260 int shift = 0; | |
| 261 byte chunk; | |
| 262 | |
| 263 do { | |
| 264 chunk = *current++; | |
| 265 DCHECK_LT(shift, 8 * static_cast<int>(sizeof(result))); | |
| 266 result |= (chunk & 0x7f) << shift; | |
| 267 shift += 7; | |
| 268 } while (chunk >= 128); | |
| 269 | |
| 270 // Sign extend the result if the last chunk has the sign bit set. | |
| 271 if (chunk & kSignBitMask) result |= (~0ull) << shift; | |
| 272 | |
| 273 DCHECK_NOT_NULL(encoded_size); | |
| 274 *encoded_size = static_cast<int>(current - encoded); | |
| 275 | |
| 276 return result; | |
| 277 } | |
| 278 | |
| 279 #ifdef ENABLE_DISASSEMBLER | |
| 280 | |
| 281 namespace { | |
| 282 | |
| 283 class StreamModifiersScope final { | |
| 284 public: | |
| 285 explicit StreamModifiersScope(std::ostream* stream) | |
| 286 : stream_(stream), flags_(stream->flags()) {} | |
| 287 ~StreamModifiersScope() { stream_->flags(flags_); } | |
| 288 | |
| 289 private: | |
| 290 std::ostream* stream_; | |
| 291 std::ios::fmtflags flags_; | |
| 292 }; | |
| 293 | |
| 294 } // namespace | |
| 295 | |
| 296 // static | |
| 297 void EhFrameWriter::DumpDWARFDirectives(std::ostream& stream, // NOLINT | |
| 298 const byte* begin, const byte* end) { | |
| 299 StreamModifiersScope modifiers_scope(&stream); | |
| 300 | |
| 301 const byte* cur = begin; | |
| 302 uint32_t offset_in_procedure = 0; | |
| 303 | |
| 304 while (cur != end) { | |
| 305 stream << reinterpret_cast<const void*>(cur) << " "; | |
| 306 | |
| 307 if (((*cur >> kLocationMaskSize) & 0xff) == kLocationTag) { | |
| 308 int value = *cur & kLocationMask; | |
| 309 cur += sizeof(byte); | |
| 310 offset_in_procedure += value; | |
| 311 stream << "| pc_offset=" << std::dec << offset_in_procedure | |
| 312 << " (delta=0x" << std::hex << value << ")\n"; | |
| 313 continue; | |
| 314 } | |
| 315 | |
| 316 if (((*cur >> kSavedRegisterMaskSize) & 0xff) == kSavedRegisterTag) { | |
| 317 stream << "| " << DwarfRegisterCodeToString(*cur & kLocationMask); | |
| 318 cur += sizeof(byte); | |
| 319 int decoded_size = 0; | |
| 320 int decoded_offset = static_cast<int>(DecodeULEB128(cur, &decoded_size)); | |
| 321 cur += decoded_size; | |
| 322 stream << " saved at base" << std::showpos << std::dec | |
| 323 << decoded_offset * kDataAlignmentFactor << '\n'; | |
| 324 continue; | |
| 325 } | |
| 326 | |
| 327 uint8_t bytecode = *cur; | |
| 328 cur += sizeof(byte); | |
| 329 | |
| 330 switch (bytecode) { | |
| 331 case kOffsetExtendedSf: { | |
| 332 int decoded_size = 0; | |
| 333 stream << "| " | |
| 334 << DwarfRegisterCodeToString(DecodeULEB128(cur, &decoded_size)); | |
| 335 cur += decoded_size; | |
| 336 int32_t decoded_offset = DecodeSLEB128(cur, &decoded_size); | |
| 337 cur += decoded_size; | |
| 338 stream << " saved at base" << std::showpos << std::dec | |
| 339 << decoded_offset * kDataAlignmentFactor << '\n'; | |
| 340 } | |
| 341 case kAdvanceLoc1: { | |
| 342 unsigned value = *reinterpret_cast<const uint8_t*>(cur); | |
| 343 cur += sizeof(uint8_t); | |
| 344 offset_in_procedure += value; | |
| 345 stream << "| pc_offset=" << std::dec << offset_in_procedure | |
| 346 << " (delta=0x" << std::hex << value << ")\n"; | |
| 347 break; | |
| 348 } | |
| 349 case kAdvanceLoc2: { | |
| 350 uint16_t value = ReadUnalignedUInt16(cur); | |
| 351 cur += sizeof(uint16_t); | |
| 352 offset_in_procedure += value; | |
| 353 stream << "| pc_offset=" << std::dec << offset_in_procedure | |
| 354 << " (delta=0x" << std::hex << value << ")\n"; | |
| 355 break; | |
| 356 } | |
| 357 case kAdvanceLoc4: { | |
| 358 uint32_t value = ReadUnalignedUInt32(cur); | |
| 359 offset_in_procedure += value; | |
| 360 cur += sizeof(uint32_t); | |
| 361 stream << "| pc_offset=" << std::dec << offset_in_procedure | |
| 362 << " (delta=0x" << std::hex << value << ")\n"; | |
| 363 break; | |
| 364 } | |
| 365 case kDefCfa: { | |
| 366 int decoded_size = 0; | |
| 367 int base_register = DecodeULEB128(cur, &decoded_size); | |
| 368 cur += decoded_size; | |
| 369 int base_offset = DecodeULEB128(cur, &decoded_size); | |
| 370 cur += decoded_size; | |
| 371 stream << "| base_register=" << DwarfRegisterCodeToString(base_register) | |
| 372 << ", base_offset=0x" << std::hex << base_offset << '\n'; | |
| 373 break; | |
| 374 } | |
| 375 case kDefCfaOffset: { | |
| 376 int decoded_size = 0; | |
| 377 stream << "| base_offset=0x" << std::hex | |
| 378 << DecodeULEB128(cur, &decoded_size) << '\n'; | |
| 379 cur += decoded_size; | |
| 380 break; | |
| 381 } | |
| 382 case kDefCfaRegister: { | |
| 383 int decoded_size = 0; | |
| 384 stream << "| base_register=" | |
| 385 << DwarfRegisterCodeToString(DecodeULEB128(cur, &decoded_size)) | |
| 386 << '\n'; | |
| 387 cur += decoded_size; | |
| 388 break; | |
| 389 } | |
| 390 case kSameValue: { | |
| 391 int decoded_size = 0; | |
| 392 stream << "| " | |
| 393 << DwarfRegisterCodeToString(DecodeULEB128(cur, &decoded_size)) | |
| 394 << " to initial value\n"; | |
| 395 cur += decoded_size; | |
| 396 break; | |
| 397 } | |
| 398 case kNop: | |
| 399 stream << "| nop\n"; | |
| 400 break; | |
| 401 default: | |
| 402 UNREACHABLE(); | |
| 403 return; | |
| 404 } | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 // static | |
| 409 void EhFrameWriter::DisassembleToStream(std::ostream& stream, // NOLINT | |
| 410 const byte* start, const byte* end) { | |
| 411 // The encoded CIE size does not include the size field itself. | |
| 412 const int cie_size = ReadUnalignedUInt32(start) + kInt32Size; | |
| 413 const int fde_offset = cie_size; | |
| 414 | |
| 415 const byte* cie_directives_start = start + kInitialStateOffsetInCIE; | |
| 416 const byte* cie_directives_end = start + cie_size; | |
| 417 DCHECK_LE(cie_directives_start, cie_directives_end); | |
| 418 | |
| 419 stream << reinterpret_cast<const void*>(start) << " .eh_frame: CIE\n"; | |
| 420 DumpDWARFDirectives(stream, cie_directives_start, cie_directives_end); | |
| 421 | |
| 422 const byte* procedure_offset_address = | |
| 423 start + fde_offset + kProcedureAddressOffsetInFde; | |
| 424 int32_t procedure_offset = | |
| 425 ReadUnalignedValue<int32_t>(procedure_offset_address); | |
| 426 | |
| 427 const byte* procedure_size_address = | |
| 428 start + fde_offset + kProcedureSizeOffsetInFde; | |
| 429 uint32_t procedure_size = ReadUnalignedUInt32(procedure_size_address); | |
| 430 | |
| 431 const byte* fde_start = start + fde_offset; | |
| 432 stream << reinterpret_cast<const void*>(fde_start) << " .eh_frame: FDE\n" | |
| 433 << reinterpret_cast<const void*>(procedure_offset_address) | |
| 434 << " | procedure offset=" << procedure_offset << '\n' | |
| 435 << reinterpret_cast<const void*>(procedure_size_address) | |
| 436 << " | procedure size=" << procedure_size << '\n'; | |
| 437 | |
| 438 const int fde_directives_offset = fde_offset + 4 * kInt32Size + 1; | |
| 439 | |
| 440 const byte* fde_directives_start = start + fde_directives_offset; | |
| 441 const byte* fde_directives_end = | |
| 442 end - EhFrameHdr::kRecordSize - kTerminatorSize; | |
| 443 DCHECK_LE(fde_directives_start, fde_directives_end); | |
| 444 | |
| 445 DumpDWARFDirectives(stream, fde_directives_start, fde_directives_end); | |
| 446 | |
| 447 const byte* fde_terminator_start = fde_directives_end; | |
| 448 stream << reinterpret_cast<const void*>(fde_terminator_start) | |
| 449 << " .eh_frame: terminator\n"; | |
| 450 | |
| 451 const byte* eh_frame_hdr_start = fde_terminator_start + kTerminatorSize; | |
| 452 stream << reinterpret_cast<const void*>(eh_frame_hdr_start) | |
| 453 << " .eh_frame_hdr: placeholder\n"; | |
| 454 } | |
| 455 | |
| 456 #endif | |
| 21 | 457 |
| 22 // | 458 // |
| 23 // In order to calculate offsets in the .eh_frame_hdr, we must know the layout | 459 // In order to calculate offsets in the .eh_frame_hdr, we must know the layout |
| 24 // of the DSO generated by perf inject, which is assumed to be the following: | 460 // of the DSO generated by perf inject, which is assumed to be the following: |
| 25 // | 461 // |
| 26 // | ... | | | 462 // | ... | | |
| 27 // +---------------+ <-- (F) --- | Larger offsets in file | 463 // +---------------+ <-- (F) --- | Larger offsets in file |
| 28 // | | ^ | | 464 // | | ^ | |
| 29 // | Instructions | | .text v | 465 // | Instructions | | .text v |
| 30 // | | v | 466 // | | v |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 44 // | version | ^ | 480 // | version | ^ |
| 45 // +---------------+ | | 481 // +---------------+ | |
| 46 // | encoding | | | 482 // | encoding | | |
| 47 // | specifiers | | | 483 // | specifiers | | |
| 48 // +---------------+ <---(A) | .eh_frame_hdr | 484 // +---------------+ <---(A) | .eh_frame_hdr |
| 49 // | offset to | | | 485 // | offset to | | |
| 50 // | .eh_frame | | | 486 // | .eh_frame | | |
| 51 // +---------------+ | | 487 // +---------------+ | |
| 52 // | ... | ... | 488 // | ... | ... |
| 53 // | 489 // |
| 54 // (F) is aligned at a 16-byte boundary. | 490 // (F) is aligned to a 16-byte boundary. |
| 55 // (D) is aligned at a 8-byte boundary. | 491 // (D) is aligned to a 8-byte boundary. |
| 56 // (B) is aligned at a 4-byte boundary. | 492 // (B) is aligned to a 4-byte boundary. |
| 57 // (E), (C) and (A) have no alignment requirements. | 493 // (C) is aligned to an addressing unit size boundary. |
| 494 // (E) and (A) have no alignment requirements. | |
| 58 // | 495 // |
| 59 // The distance between (A) and (B) is 4 bytes. | 496 // The distance between (A) and (B) is 4 bytes. |
| 60 // | 497 // |
| 61 // The size of the .eh_frame is required to be a multiple of the pointer size, | 498 // The size of the FDE is required to be a multiple of the pointer size, which |
| 62 // which means that (B) will be naturally aligned to a 4-byte boundary on all | 499 // means that (B) will be naturally aligned to a 4-byte boundary on all the |
| 63 // the architectures we support. | 500 // architectures we support. |
| 64 // | 501 // |
| 65 // Because (E) has no alignment requirements, there is padding between (E) and | 502 // Because (E) has no alignment requirements, there is padding between (E) and |
| 66 // (D). (F) is aligned at a 16-byte boundary, thus to a 8-byte one as well. | 503 // (D). (F) is aligned at a 16-byte boundary, thus to a 8-byte one as well. |
| 67 // | 504 // |
| 68 EhFrameHdr::EhFrameHdr(Code* code) { | 505 EhFrameHdr::EhFrameHdr(int code_size, int eh_frame_size, int cie_size) { |
| 69 int code_size = code->is_crankshafted() ? code->safepoint_table_offset() | 506 static const int kFdeVersionSize = 1; |
| 70 : code->instruction_size(); | 507 static const int kFdeEncodingSpecifiersSize = 3; |
| 71 version_ = 1; | |
| 72 eh_frame_ptr_encoding_ = DW_EH_PE_sdata4 | DW_EH_PE_pcrel; | |
| 73 lut_size_encoding_ = DW_EH_PE_udata4; | |
| 74 lut_entries_encoding_ = DW_EH_PE_sdata4 | DW_EH_PE_datarel; | |
| 75 | 508 |
| 76 // .eh_frame pointer and LUT | 509 version_ = kEhFrameHdrVersion; |
| 77 if (code->has_unwinding_info()) { | |
| 78 DCHECK_GE(code->unwinding_info_size(), EhFrameHdr::kRecordSize); | |
| 79 int eh_frame_size = code->unwinding_info_size() - EhFrameHdr::kRecordSize; | |
| 80 | 510 |
| 81 offset_to_eh_frame_ = | 511 eh_frame_ptr_encoding_ = EhFrameWriter::kSData4 | EhFrameWriter::kPcRel; |
| 82 -(eh_frame_size + kVersionSize + kEncodingSpecifiersSize); // A -> D | 512 lut_size_encoding_ = EhFrameWriter::kUData4; |
| 83 lut_entries_number_ = 1; | 513 lut_entries_encoding_ = EhFrameWriter::kSData4 | EhFrameWriter::kDataRel; |
| 84 offset_to_procedure_ = -(RoundUp(code_size, 8) + eh_frame_size); // B -> F | 514 offset_to_eh_frame_ = -(eh_frame_size + kFdeVersionSize + |
| 85 offset_to_fde_ = -(eh_frame_size - kCIESize); // B -> C | 515 kFdeEncodingSpecifiersSize); // A -> D |
| 86 } else { | 516 lut_entries_number_ = 1; |
| 87 // Create a dummy table | 517 offset_to_procedure_ = -(RoundUp(code_size, 8) + eh_frame_size); // B -> F |
| 88 offset_to_eh_frame_ = 0; | 518 offset_to_fde_ = -(eh_frame_size - cie_size); // B -> C |
| 89 lut_entries_number_ = 0; | 519 } |
| 90 offset_to_procedure_ = 0; | 520 |
| 91 offset_to_fde_ = 0; | 521 // static |
| 92 } | 522 EhFrameHdr EhFrameHdr::CreateEmptyHeader() { |
| 523 EhFrameHdr dummy_frame; | |
| 524 dummy_frame.version_ = kEhFrameHdrVersion; | |
| 525 dummy_frame.eh_frame_ptr_encoding_ = | |
| 526 EhFrameWriter::kSData4 | EhFrameWriter::kPcRel; | |
| 527 dummy_frame.lut_size_encoding_ = EhFrameWriter::kUData4; | |
| 528 dummy_frame.lut_entries_encoding_ = | |
| 529 EhFrameWriter::kSData4 | EhFrameWriter::kDataRel; | |
| 530 dummy_frame.offset_to_eh_frame_ = 0; | |
| 531 dummy_frame.lut_entries_number_ = 0; | |
| 532 dummy_frame.offset_to_procedure_ = 0; | |
| 533 dummy_frame.offset_to_fde_ = 0; | |
| 534 return dummy_frame; | |
| 93 } | 535 } |
| 94 | 536 |
| 95 } // namespace internal | 537 } // namespace internal |
| 96 } // namespace v8 | 538 } // namespace v8 |
| OLD | NEW |