1 //===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 11 // C Includes 12 // C++ Includes 13 #include <algorithm> 14 15 #include "lldb/Core/ArchSpec.h" 16 #include "lldb/Core/DataBufferHeap.h" 17 #include "lldb/Core/Log.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/Section.h" 20 #include "lldb/Core/Section.h" 21 #include "lldb/Core/StreamString.h" 22 #include "lldb/Symbol/CompactUnwindInfo.h" 23 #include "lldb/Symbol/ObjectFile.h" 24 #include "lldb/Symbol/UnwindPlan.h" 25 #include "lldb/Target/Process.h" 26 #include "lldb/Target/Target.h" 27 28 #include "llvm/Support/MathExtras.h" 29 30 using namespace lldb; 31 using namespace lldb_private; 32 33 34 namespace lldb_private { 35 36 // Constants from <mach-o/compact_unwind_encoding.h> 37 38 FLAGS_ANONYMOUS_ENUM() 39 { 40 UNWIND_IS_NOT_FUNCTION_START = 0x80000000, 41 UNWIND_HAS_LSDA = 0x40000000, 42 UNWIND_PERSONALITY_MASK = 0x30000000, 43 }; 44 45 FLAGS_ANONYMOUS_ENUM() 46 { 47 UNWIND_X86_MODE_MASK = 0x0F000000, 48 UNWIND_X86_MODE_EBP_FRAME = 0x01000000, 49 UNWIND_X86_MODE_STACK_IMMD = 0x02000000, 50 UNWIND_X86_MODE_STACK_IND = 0x03000000, 51 UNWIND_X86_MODE_DWARF = 0x04000000, 52 53 UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, 54 UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, 55 56 UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, 57 UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, 58 UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 59 UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 60 61 UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, 62 }; 63 64 enum 65 { 66 UNWIND_X86_REG_NONE = 0, 67 UNWIND_X86_REG_EBX = 1, 68 UNWIND_X86_REG_ECX = 2, 69 UNWIND_X86_REG_EDX = 3, 70 UNWIND_X86_REG_EDI = 4, 71 UNWIND_X86_REG_ESI = 5, 72 UNWIND_X86_REG_EBP = 6, 73 }; 74 75 FLAGS_ANONYMOUS_ENUM() 76 { 77 UNWIND_X86_64_MODE_MASK = 0x0F000000, 78 UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, 79 UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, 80 UNWIND_X86_64_MODE_STACK_IND = 0x03000000, 81 UNWIND_X86_64_MODE_DWARF = 0x04000000, 82 83 UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, 84 UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, 85 86 UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, 87 UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, 88 UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 89 UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 90 91 UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 92 }; 93 94 enum 95 { 96 UNWIND_X86_64_REG_NONE = 0, 97 UNWIND_X86_64_REG_RBX = 1, 98 UNWIND_X86_64_REG_R12 = 2, 99 UNWIND_X86_64_REG_R13 = 3, 100 UNWIND_X86_64_REG_R14 = 4, 101 UNWIND_X86_64_REG_R15 = 5, 102 UNWIND_X86_64_REG_RBP = 6, 103 }; 104 } 105 106 107 #ifndef UNWIND_SECOND_LEVEL_REGULAR 108 #define UNWIND_SECOND_LEVEL_REGULAR 2 109 #endif 110 111 #ifndef UNWIND_SECOND_LEVEL_COMPRESSED 112 #define UNWIND_SECOND_LEVEL_COMPRESSED 3 113 #endif 114 115 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET 116 #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) 117 #endif 118 119 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX 120 #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF) 121 #endif 122 123 #define EXTRACT_BITS(value, mask) \ 124 ( (value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \ 125 (((1 << llvm::countPopulation(static_cast<uint32_t>(mask))))-1) ) 126 127 128 129 //---------------------- 130 // constructor 131 //---------------------- 132 133 134 CompactUnwindInfo::CompactUnwindInfo(ObjectFile& objfile, SectionSP& section_sp) : 135 m_objfile (objfile), 136 m_section_sp (section_sp), 137 m_section_contents_if_encrypted (), 138 m_mutex (), 139 m_indexes (), 140 m_indexes_computed (eLazyBoolCalculate), 141 m_unwindinfo_data (), 142 m_unwindinfo_data_computed (false), 143 m_unwind_header () 144 { 145 146 } 147 148 //---------------------- 149 // destructor 150 //---------------------- 151 152 CompactUnwindInfo::~CompactUnwindInfo() 153 { 154 } 155 156 bool 157 CompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwind_plan) 158 { 159 if (!IsValid (target.GetProcessSP())) 160 { 161 return false; 162 } 163 FunctionInfo function_info; 164 if (GetCompactUnwindInfoForFunction (target, addr, function_info)) 165 { 166 // shortcut return for functions that have no compact unwind 167 if (function_info.encoding == 0) 168 return false; 169 170 ArchSpec arch; 171 if (m_objfile.GetArchitecture (arch)) 172 { 173 174 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 175 if (log && log->GetVerbose()) 176 { 177 StreamString strm; 178 addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize()); 179 log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData()); 180 } 181 182 if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0) 183 { 184 SectionList *sl = m_objfile.GetSectionList (); 185 if (sl) 186 { 187 addr_t func_range_start_file_addr = 188 function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress(); 189 AddressRange func_range (func_range_start_file_addr, 190 function_info.valid_range_offset_end - function_info.valid_range_offset_start, 191 sl); 192 unwind_plan.SetPlanValidAddressRange (func_range); 193 } 194 } 195 196 if (arch.GetTriple().getArch() == llvm::Triple::x86_64) 197 { 198 return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr); 199 } 200 if (arch.GetTriple().getArch() == llvm::Triple::x86) 201 { 202 return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr); 203 } 204 } 205 } 206 return false; 207 } 208 209 bool 210 CompactUnwindInfo::IsValid (const ProcessSP &process_sp) 211 { 212 if (m_section_sp.get() == nullptr) 213 return false; 214 215 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 216 return true; 217 218 ScanIndex (process_sp); 219 220 return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed; 221 } 222 223 void 224 CompactUnwindInfo::ScanIndex (const ProcessSP &process_sp) 225 { 226 Mutex::Locker locker(m_mutex); 227 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 228 return; 229 230 // We can't read the index for some reason. 231 if (m_indexes_computed == eLazyBoolNo) 232 { 233 return; 234 } 235 236 Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 237 if (log) 238 m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes"); 239 240 if (m_unwindinfo_data_computed == false) 241 { 242 if (m_section_sp->IsEncrypted()) 243 { 244 // Can't get section contents of a protected/encrypted section until we have a live 245 // process and can read them out of memory. 246 if (process_sp.get() == nullptr) 247 return; 248 m_section_contents_if_encrypted.reset (new DataBufferHeap (m_section_sp->GetByteSize(), 0)); 249 Error error; 250 if (process_sp->ReadMemory ( 251 m_section_sp->GetLoadBaseAddress (&process_sp->GetTarget()), 252 m_section_contents_if_encrypted->GetBytes(), 253 m_section_sp->GetByteSize(), error) == m_section_sp->GetByteSize() && error.Success()) 254 { 255 m_unwindinfo_data.SetAddressByteSize (process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); 256 m_unwindinfo_data.SetByteOrder (process_sp->GetTarget().GetArchitecture().GetByteOrder()); 257 m_unwindinfo_data.SetData (m_section_contents_if_encrypted, 0); 258 } 259 } 260 else 261 { 262 m_objfile.ReadSectionData (m_section_sp.get(), m_unwindinfo_data); 263 } 264 if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize()) 265 return; 266 m_unwindinfo_data_computed = true; 267 } 268 269 if (m_unwindinfo_data.GetByteSize() > 0) 270 { 271 offset_t offset = 0; 272 273 // struct unwind_info_section_header 274 // { 275 // uint32_t version; // UNWIND_SECTION_VERSION 276 // uint32_t commonEncodingsArraySectionOffset; 277 // uint32_t commonEncodingsArrayCount; 278 // uint32_t personalityArraySectionOffset; 279 // uint32_t personalityArrayCount; 280 // uint32_t indexSectionOffset; 281 // uint32_t indexCount; 282 283 m_unwind_header.version = m_unwindinfo_data.GetU32(&offset); 284 m_unwind_header.common_encodings_array_offset = m_unwindinfo_data.GetU32(&offset); 285 m_unwind_header.common_encodings_array_count = m_unwindinfo_data.GetU32(&offset); 286 m_unwind_header.personality_array_offset = m_unwindinfo_data.GetU32(&offset); 287 m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset); 288 uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset); 289 290 uint32_t indexCount = m_unwindinfo_data.GetU32(&offset); 291 292 if (m_unwind_header.common_encodings_array_offset > m_unwindinfo_data.GetByteSize() 293 || m_unwind_header.personality_array_offset > m_unwindinfo_data.GetByteSize() 294 || indexSectionOffset > m_unwindinfo_data.GetByteSize() 295 || offset > m_unwindinfo_data.GetByteSize()) 296 { 297 Host::SystemLog (Host::eSystemLogError, 298 "error: Invalid offset encountered in compact unwind info, skipping\n"); 299 // don't trust anything from this compact_unwind section if it looks 300 // blatantly invalid data in the header. 301 m_indexes_computed = eLazyBoolNo; 302 return; 303 } 304 305 // Parse the basic information from the indexes 306 // We wait to scan the second level page info until it's needed 307 308 // struct unwind_info_section_header_index_entry 309 // { 310 // uint32_t functionOffset; 311 // uint32_t secondLevelPagesSectionOffset; 312 // uint32_t lsdaIndexArraySectionOffset; 313 // }; 314 315 offset = indexSectionOffset; 316 for (uint32_t idx = 0; idx < indexCount; idx++) 317 { 318 uint32_t function_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 319 uint32_t second_level_offset = m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset 320 uint32_t lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset 321 322 if (second_level_offset > m_section_sp->GetByteSize() || lsda_offset > m_section_sp->GetByteSize()) 323 { 324 m_indexes_computed = eLazyBoolNo; 325 } 326 327 UnwindIndex this_index; 328 this_index.function_offset = function_offset; // 329 this_index.second_level = second_level_offset; 330 this_index.lsda_array_start = lsda_offset; 331 332 if (m_indexes.size() > 0) 333 { 334 m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset; 335 } 336 337 if (second_level_offset == 0) 338 { 339 this_index.sentinal_entry = true; 340 } 341 342 m_indexes.push_back (this_index); 343 } 344 m_indexes_computed = eLazyBoolYes; 345 } 346 else 347 { 348 m_indexes_computed = eLazyBoolNo; 349 } 350 } 351 352 uint32_t 353 CompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset) 354 { 355 // struct unwind_info_section_header_lsda_index_entry 356 // { 357 // uint32_t functionOffset; 358 // uint32_t lsdaOffset; 359 // }; 360 361 offset_t first_entry = lsda_offset; 362 uint32_t low = 0; 363 uint32_t high = lsda_count; 364 while (low < high) 365 { 366 uint32_t mid = (low + high) / 2; 367 offset_t offset = first_entry + (mid * 8); 368 uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 369 uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset 370 if (mid_func_offset == function_offset) 371 { 372 return mid_lsda_offset; 373 } 374 if (mid_func_offset < function_offset) 375 { 376 low = mid + 1; 377 } 378 else 379 { 380 high = mid; 381 } 382 } 383 return 0; 384 } 385 386 lldb::offset_t 387 CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) 388 { 389 // typedef uint32_t compact_unwind_encoding_t; 390 // struct unwind_info_regular_second_level_entry 391 // { 392 // uint32_t functionOffset; 393 // compact_unwind_encoding_t encoding; 394 395 offset_t first_entry = entry_page_offset; 396 397 uint32_t low = 0; 398 uint32_t high = entry_count; 399 uint32_t last = high - 1; 400 while (low < high) 401 { 402 uint32_t mid = (low + high) / 2; 403 offset_t offset = first_entry + (mid * 8); 404 uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 405 uint32_t next_func_offset = 0; 406 if (mid < last) 407 { 408 offset = first_entry + ((mid + 1) * 8); 409 next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 410 } 411 if (mid_func_offset <= function_offset) 412 { 413 if (mid == last || (next_func_offset > function_offset)) 414 { 415 if (entry_func_start_offset) 416 *entry_func_start_offset = mid_func_offset; 417 if (mid != last && entry_func_end_offset) 418 *entry_func_end_offset = next_func_offset; 419 return first_entry + (mid * 8); 420 } 421 else 422 { 423 low = mid + 1; 424 } 425 } 426 else 427 { 428 high = mid; 429 } 430 } 431 return LLDB_INVALID_OFFSET; 432 } 433 434 uint32_t 435 CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) 436 { 437 offset_t first_entry = entry_page_offset; 438 439 uint32_t low = 0; 440 uint32_t high = entry_count; 441 uint32_t last = high - 1; 442 while (low < high) 443 { 444 uint32_t mid = (low + high) / 2; 445 offset_t offset = first_entry + (mid * 4); 446 uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry 447 uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry); 448 mid_func_offset += function_offset_base; 449 uint32_t next_func_offset = 0; 450 if (mid < last) 451 { 452 offset = first_entry + ((mid + 1) * 4); 453 uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry 454 next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (next_entry); 455 next_func_offset += function_offset_base; 456 } 457 if (mid_func_offset <= function_offset_to_find) 458 { 459 if (mid == last || (next_func_offset > function_offset_to_find)) 460 { 461 if (entry_func_start_offset) 462 *entry_func_start_offset = mid_func_offset; 463 if (mid != last && entry_func_end_offset) 464 *entry_func_end_offset = next_func_offset; 465 return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry); 466 } 467 else 468 { 469 low = mid + 1; 470 } 471 } 472 else 473 { 474 high = mid; 475 } 476 } 477 478 return UINT32_MAX; 479 } 480 481 bool 482 CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info) 483 { 484 unwind_info.encoding = 0; 485 unwind_info.lsda_address.Clear(); 486 unwind_info.personality_ptr_address.Clear(); 487 488 if (!IsValid (target.GetProcessSP())) 489 return false; 490 491 addr_t text_section_file_address = LLDB_INVALID_ADDRESS; 492 SectionList *sl = m_objfile.GetSectionList (); 493 if (sl) 494 { 495 SectionSP text_sect = sl->FindSectionByType (eSectionTypeCode, true); 496 if (text_sect.get()) 497 { 498 text_section_file_address = text_sect->GetFileAddress(); 499 } 500 } 501 if (text_section_file_address == LLDB_INVALID_ADDRESS) 502 return false; 503 504 addr_t function_offset = address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress(); 505 506 UnwindIndex key; 507 key.function_offset = function_offset; 508 509 std::vector<UnwindIndex>::const_iterator it; 510 it = std::lower_bound (m_indexes.begin(), m_indexes.end(), key); 511 if (it == m_indexes.end()) 512 { 513 return false; 514 } 515 516 if (it->function_offset != key.function_offset) 517 { 518 if (it != m_indexes.begin()) 519 --it; 520 } 521 522 if (it->sentinal_entry == true) 523 { 524 return false; 525 } 526 527 auto next_it = it + 1; 528 if (next_it != m_indexes.end()) 529 { 530 // initialize the function offset end range to be the start of the 531 // next index offset. If we find an entry which is at the end of 532 // the index table, this will establish the range end. 533 unwind_info.valid_range_offset_end = next_it->function_offset; 534 } 535 536 offset_t second_page_offset = it->second_level; 537 offset_t lsda_array_start = it->lsda_array_start; 538 offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8; 539 540 offset_t offset = second_page_offset; 541 uint32_t kind = m_unwindinfo_data.GetU32(&offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED 542 543 if (kind == UNWIND_SECOND_LEVEL_REGULAR) 544 { 545 // struct unwind_info_regular_second_level_page_header 546 // { 547 // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR 548 // uint16_t entryPageOffset; 549 // uint16_t entryCount; 550 551 // typedef uint32_t compact_unwind_encoding_t; 552 // struct unwind_info_regular_second_level_entry 553 // { 554 // uint32_t functionOffset; 555 // compact_unwind_encoding_t encoding; 556 557 uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset 558 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 559 560 offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end); 561 if (entry_offset == LLDB_INVALID_OFFSET) 562 { 563 return false; 564 } 565 entry_offset += 4; // skip over functionOffset 566 unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding 567 if (unwind_info.encoding & UNWIND_HAS_LSDA) 568 { 569 SectionList *sl = m_objfile.GetSectionList (); 570 if (sl) 571 { 572 uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset); 573 addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 574 unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl); 575 } 576 } 577 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) 578 { 579 uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK); 580 581 if (personality_index > 0) 582 { 583 personality_index--; 584 if (personality_index < m_unwind_header.personality_array_count) 585 { 586 offset_t offset = m_unwind_header.personality_array_offset; 587 offset += 4 * personality_index; 588 SectionList *sl = m_objfile.GetSectionList (); 589 if (sl) 590 { 591 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 592 addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 593 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl); 594 } 595 } 596 } 597 } 598 return true; 599 } 600 else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) 601 { 602 // struct unwind_info_compressed_second_level_page_header 603 // { 604 // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED 605 // uint16_t entryPageOffset; // offset from this 2nd lvl page idx to array of entries 606 // // (an entry has a function offset and index into the encodings) 607 // // NB function offset from the entry in the compressed page 608 // // must be added to the index's functionOffset value. 609 // uint16_t entryCount; 610 // uint16_t encodingsPageOffset; // offset from this 2nd lvl page idx to array of encodings 611 // uint16_t encodingsCount; 612 613 uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset 614 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 615 uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset 616 uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset); // encodingsCount 617 618 uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end); 619 if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count) 620 { 621 return false; 622 } 623 uint32_t encoding = 0; 624 if (encoding_index < m_unwind_header.common_encodings_array_count) 625 { 626 offset = m_unwind_header.common_encodings_array_offset + (encoding_index * sizeof (uint32_t)); 627 encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the commonEncodingsArray 628 } 629 else 630 { 631 uint32_t page_specific_entry_index = encoding_index - m_unwind_header.common_encodings_array_count; 632 offset = second_page_offset + encodings_page_offset + (page_specific_entry_index * sizeof (uint32_t)); 633 encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the page-specific encoding array 634 } 635 if (encoding == 0) 636 return false; 637 638 unwind_info.encoding = encoding; 639 if (unwind_info.encoding & UNWIND_HAS_LSDA) 640 { 641 SectionList *sl = m_objfile.GetSectionList (); 642 if (sl) 643 { 644 uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset); 645 addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 646 unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl); 647 } 648 } 649 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) 650 { 651 uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK); 652 653 if (personality_index > 0) 654 { 655 personality_index--; 656 if (personality_index < m_unwind_header.personality_array_count) 657 { 658 offset_t offset = m_unwind_header.personality_array_offset; 659 offset += 4 * personality_index; 660 SectionList *sl = m_objfile.GetSectionList (); 661 if (sl) 662 { 663 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 664 addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 665 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl); 666 } 667 } 668 } 669 } 670 return true; 671 } 672 return false; 673 } 674 675 enum x86_64_eh_regnum { 676 rax = 0, 677 rdx = 1, 678 rcx = 2, 679 rbx = 3, 680 rsi = 4, 681 rdi = 5, 682 rbp = 6, 683 rsp = 7, 684 r8 = 8, 685 r9 = 9, 686 r10 = 10, 687 r11 = 11, 688 r12 = 12, 689 r13 = 13, 690 r14 = 14, 691 r15 = 15, 692 rip = 16 // this is officially the Return Address register number, but close enough 693 }; 694 695 // Convert the compact_unwind_info.h register numbering scheme 696 // to eRegisterKindEHFrame (eh_frame) register numbering scheme. 697 uint32_t 698 translate_to_eh_frame_regnum_x86_64 (uint32_t unwind_regno) 699 { 700 switch (unwind_regno) 701 { 702 case UNWIND_X86_64_REG_RBX: 703 return x86_64_eh_regnum::rbx; 704 case UNWIND_X86_64_REG_R12: 705 return x86_64_eh_regnum::r12; 706 case UNWIND_X86_64_REG_R13: 707 return x86_64_eh_regnum::r13; 708 case UNWIND_X86_64_REG_R14: 709 return x86_64_eh_regnum::r14; 710 case UNWIND_X86_64_REG_R15: 711 return x86_64_eh_regnum::r15; 712 case UNWIND_X86_64_REG_RBP: 713 return x86_64_eh_regnum::rbp; 714 default: 715 return LLDB_INVALID_REGNUM; 716 } 717 } 718 719 bool 720 CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 721 { 722 unwind_plan.SetSourceName ("compact unwind info"); 723 unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 724 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 725 unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 726 727 unwind_plan.SetLSDAAddress (function_info.lsda_address); 728 unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 729 730 UnwindPlan::RowSP row (new UnwindPlan::Row); 731 732 const int wordsize = 8; 733 int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; 734 switch (mode) 735 { 736 case UNWIND_X86_64_MODE_RBP_FRAME: 737 { 738 row->GetCFAValue().SetIsRegisterPlusOffset ( 739 translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP), 740 2 * wordsize); 741 row->SetOffset (0); 742 row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true); 743 row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); 744 row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); 745 746 uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 747 748 uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 749 750 saved_registers_offset += 2; 751 752 for (int i = 0; i < 5; i++) 753 { 754 uint32_t regnum = saved_registers_locations & 0x7; 755 switch (regnum) 756 { 757 case UNWIND_X86_64_REG_NONE: 758 break; 759 case UNWIND_X86_64_REG_RBX: 760 case UNWIND_X86_64_REG_R12: 761 case UNWIND_X86_64_REG_R13: 762 case UNWIND_X86_64_REG_R14: 763 case UNWIND_X86_64_REG_R15: 764 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true); 765 break; 766 } 767 saved_registers_offset--; 768 saved_registers_locations >>= 3; 769 } 770 unwind_plan.AppendRow (row); 771 return true; 772 } 773 break; 774 775 case UNWIND_X86_64_MODE_STACK_IND: 776 { 777 // The clang in Xcode 6 is emitting incorrect compact unwind encodings for this 778 // style of unwind. It was fixed in llvm r217020. 779 // The clang in Xcode 7 has this fixed. 780 return false; 781 } 782 break; 783 784 case UNWIND_X86_64_MODE_STACK_IMMD: 785 { 786 uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 787 uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 788 uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 789 790 if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 791 { 792 uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 793 794 // offset into the function instructions; 0 == beginning of first instruction 795 uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 796 797 SectionList *sl = m_objfile.GetSectionList (); 798 if (sl) 799 { 800 ProcessSP process_sp = target.GetProcessSP(); 801 if (process_sp) 802 { 803 Address subl_payload_addr (function_info.valid_range_offset_start, sl); 804 subl_payload_addr.Slide (offset_to_subl_insn); 805 Error error; 806 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 807 4, 0, error); 808 if (large_stack_size != 0 && error.Success ()) 809 { 810 // Got the large stack frame size correctly - use it 811 stack_size = large_stack_size + (stack_adjust * wordsize); 812 } 813 else 814 { 815 return false; 816 } 817 } 818 else 819 { 820 return false; 821 } 822 } 823 else 824 { 825 return false; 826 } 827 } 828 829 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize; 830 row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset); 831 832 row->SetOffset (0); 833 row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); 834 row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); 835 836 if (register_count > 0) 837 { 838 839 // We need to include (up to) 6 registers in 10 bits. 840 // That would be 18 bits if we just used 3 bits per reg to indicate 841 // the order they're saved on the stack. 842 // 843 // This is done with Lehmer code permutation, e.g. see 844 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 845 int permunreg[6] = {0, 0, 0, 0, 0, 0}; 846 847 // This decodes the variable-base number in the 10 bits 848 // and gives us the Lehmer code sequence which can then 849 // be decoded. 850 851 switch (register_count) 852 { 853 case 6: 854 permunreg[0] = permutation/120; // 120 == 5! 855 permutation -= (permunreg[0]*120); 856 permunreg[1] = permutation/24; // 24 == 4! 857 permutation -= (permunreg[1]*24); 858 permunreg[2] = permutation/6; // 6 == 3! 859 permutation -= (permunreg[2]*6); 860 permunreg[3] = permutation/2; // 2 == 2! 861 permutation -= (permunreg[3]*2); 862 permunreg[4] = permutation; // 1 == 1! 863 permunreg[5] = 0; 864 break; 865 case 5: 866 permunreg[0] = permutation/120; 867 permutation -= (permunreg[0]*120); 868 permunreg[1] = permutation/24; 869 permutation -= (permunreg[1]*24); 870 permunreg[2] = permutation/6; 871 permutation -= (permunreg[2]*6); 872 permunreg[3] = permutation/2; 873 permutation -= (permunreg[3]*2); 874 permunreg[4] = permutation; 875 break; 876 case 4: 877 permunreg[0] = permutation/60; 878 permutation -= (permunreg[0]*60); 879 permunreg[1] = permutation/12; 880 permutation -= (permunreg[1]*12); 881 permunreg[2] = permutation/3; 882 permutation -= (permunreg[2]*3); 883 permunreg[3] = permutation; 884 break; 885 case 3: 886 permunreg[0] = permutation/20; 887 permutation -= (permunreg[0]*20); 888 permunreg[1] = permutation/4; 889 permutation -= (permunreg[1]*4); 890 permunreg[2] = permutation; 891 break; 892 case 2: 893 permunreg[0] = permutation/5; 894 permutation -= (permunreg[0]*5); 895 permunreg[1] = permutation; 896 break; 897 case 1: 898 permunreg[0] = permutation; 899 break; 900 } 901 902 // Decode the Lehmer code for this permutation of 903 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 904 905 int registers[6] = { UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE }; 906 bool used[7] = { false, false, false, false, false, false, false }; 907 for (uint32_t i = 0; i < register_count; i++) 908 { 909 int renum = 0; 910 for (int j = 1; j < 7; j++) 911 { 912 if (used[j] == false) 913 { 914 if (renum == permunreg[i]) 915 { 916 registers[i] = j; 917 used[j] = true; 918 break; 919 } 920 renum++; 921 } 922 } 923 } 924 925 uint32_t saved_registers_offset = 1; 926 saved_registers_offset++; 927 928 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 929 { 930 switch (registers[i]) 931 { 932 case UNWIND_X86_64_REG_NONE: 933 break; 934 case UNWIND_X86_64_REG_RBX: 935 case UNWIND_X86_64_REG_R12: 936 case UNWIND_X86_64_REG_R13: 937 case UNWIND_X86_64_REG_R14: 938 case UNWIND_X86_64_REG_R15: 939 case UNWIND_X86_64_REG_RBP: 940 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true); 941 saved_registers_offset++; 942 break; 943 } 944 } 945 } 946 unwind_plan.AppendRow (row); 947 return true; 948 } 949 break; 950 951 case UNWIND_X86_64_MODE_DWARF: 952 { 953 return false; 954 } 955 break; 956 957 case 0: 958 { 959 return false; 960 } 961 break; 962 } 963 return false; 964 } 965 966 enum i386_eh_regnum { 967 eax = 0, 968 ecx = 1, 969 edx = 2, 970 ebx = 3, 971 ebp = 4, 972 esp = 5, 973 esi = 6, 974 edi = 7, 975 eip = 8 // this is officially the Return Address register number, but close enough 976 }; 977 978 // Convert the compact_unwind_info.h register numbering scheme 979 // to eRegisterKindEHFrame (eh_frame) register numbering scheme. 980 uint32_t 981 translate_to_eh_frame_regnum_i386 (uint32_t unwind_regno) 982 { 983 switch (unwind_regno) 984 { 985 case UNWIND_X86_REG_EBX: 986 return i386_eh_regnum::ebx; 987 case UNWIND_X86_REG_ECX: 988 return i386_eh_regnum::ecx; 989 case UNWIND_X86_REG_EDX: 990 return i386_eh_regnum::edx; 991 case UNWIND_X86_REG_EDI: 992 return i386_eh_regnum::edi; 993 case UNWIND_X86_REG_ESI: 994 return i386_eh_regnum::esi; 995 case UNWIND_X86_REG_EBP: 996 return i386_eh_regnum::ebp; 997 default: 998 return LLDB_INVALID_REGNUM; 999 } 1000 } 1001 1002 1003 bool 1004 CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 1005 { 1006 unwind_plan.SetSourceName ("compact unwind info"); 1007 unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 1008 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 1009 unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 1010 1011 unwind_plan.SetLSDAAddress (function_info.lsda_address); 1012 unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 1013 1014 UnwindPlan::RowSP row (new UnwindPlan::Row); 1015 1016 const int wordsize = 4; 1017 int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1018 switch (mode) 1019 { 1020 case UNWIND_X86_MODE_EBP_FRAME: 1021 { 1022 row->GetCFAValue().SetIsRegisterPlusOffset ( 1023 translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize); 1024 row->SetOffset (0); 1025 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true); 1026 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1027 row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1028 1029 uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1030 1031 uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1032 1033 saved_registers_offset += 2; 1034 1035 for (int i = 0; i < 5; i++) 1036 { 1037 uint32_t regnum = saved_registers_locations & 0x7; 1038 switch (regnum) 1039 { 1040 case UNWIND_X86_REG_NONE: 1041 break; 1042 case UNWIND_X86_REG_EBX: 1043 case UNWIND_X86_REG_ECX: 1044 case UNWIND_X86_REG_EDX: 1045 case UNWIND_X86_REG_EDI: 1046 case UNWIND_X86_REG_ESI: 1047 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true); 1048 break; 1049 } 1050 saved_registers_offset--; 1051 saved_registers_locations >>= 3; 1052 } 1053 unwind_plan.AppendRow (row); 1054 return true; 1055 } 1056 break; 1057 1058 case UNWIND_X86_MODE_STACK_IND: 1059 case UNWIND_X86_MODE_STACK_IMMD: 1060 { 1061 uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1062 uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1063 uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1064 1065 if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 1066 { 1067 uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); 1068 1069 // offset into the function instructions; 0 == beginning of first instruction 1070 uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1071 1072 SectionList *sl = m_objfile.GetSectionList (); 1073 if (sl) 1074 { 1075 ProcessSP process_sp = target.GetProcessSP(); 1076 if (process_sp) 1077 { 1078 Address subl_payload_addr (function_info.valid_range_offset_start, sl); 1079 subl_payload_addr.Slide (offset_to_subl_insn); 1080 Error error; 1081 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 1082 4, 0, error); 1083 if (large_stack_size != 0 && error.Success ()) 1084 { 1085 // Got the large stack frame size correctly - use it 1086 stack_size = large_stack_size + (stack_adjust * wordsize); 1087 } 1088 else 1089 { 1090 return false; 1091 } 1092 } 1093 else 1094 { 1095 return false; 1096 } 1097 } 1098 else 1099 { 1100 return false; 1101 } 1102 } 1103 1104 int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1105 row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset); 1106 row->SetOffset (0); 1107 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1108 row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1109 1110 if (register_count > 0) 1111 { 1112 1113 // We need to include (up to) 6 registers in 10 bits. 1114 // That would be 18 bits if we just used 3 bits per reg to indicate 1115 // the order they're saved on the stack. 1116 // 1117 // This is done with Lehmer code permutation, e.g. see 1118 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 1119 int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1120 1121 // This decodes the variable-base number in the 10 bits 1122 // and gives us the Lehmer code sequence which can then 1123 // be decoded. 1124 1125 switch (register_count) 1126 { 1127 case 6: 1128 permunreg[0] = permutation/120; // 120 == 5! 1129 permutation -= (permunreg[0]*120); 1130 permunreg[1] = permutation/24; // 24 == 4! 1131 permutation -= (permunreg[1]*24); 1132 permunreg[2] = permutation/6; // 6 == 3! 1133 permutation -= (permunreg[2]*6); 1134 permunreg[3] = permutation/2; // 2 == 2! 1135 permutation -= (permunreg[3]*2); 1136 permunreg[4] = permutation; // 1 == 1! 1137 permunreg[5] = 0; 1138 break; 1139 case 5: 1140 permunreg[0] = permutation/120; 1141 permutation -= (permunreg[0]*120); 1142 permunreg[1] = permutation/24; 1143 permutation -= (permunreg[1]*24); 1144 permunreg[2] = permutation/6; 1145 permutation -= (permunreg[2]*6); 1146 permunreg[3] = permutation/2; 1147 permutation -= (permunreg[3]*2); 1148 permunreg[4] = permutation; 1149 break; 1150 case 4: 1151 permunreg[0] = permutation/60; 1152 permutation -= (permunreg[0]*60); 1153 permunreg[1] = permutation/12; 1154 permutation -= (permunreg[1]*12); 1155 permunreg[2] = permutation/3; 1156 permutation -= (permunreg[2]*3); 1157 permunreg[3] = permutation; 1158 break; 1159 case 3: 1160 permunreg[0] = permutation/20; 1161 permutation -= (permunreg[0]*20); 1162 permunreg[1] = permutation/4; 1163 permutation -= (permunreg[1]*4); 1164 permunreg[2] = permutation; 1165 break; 1166 case 2: 1167 permunreg[0] = permutation/5; 1168 permutation -= (permunreg[0]*5); 1169 permunreg[1] = permutation; 1170 break; 1171 case 1: 1172 permunreg[0] = permutation; 1173 break; 1174 } 1175 1176 // Decode the Lehmer code for this permutation of 1177 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 1178 1179 int registers[6] = { UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE }; 1180 bool used[7] = { false, false, false, false, false, false, false }; 1181 for (uint32_t i = 0; i < register_count; i++) 1182 { 1183 int renum = 0; 1184 for (int j = 1; j < 7; j++) 1185 { 1186 if (used[j] == false) 1187 { 1188 if (renum == permunreg[i]) 1189 { 1190 registers[i] = j; 1191 used[j] = true; 1192 break; 1193 } 1194 renum++; 1195 } 1196 } 1197 } 1198 1199 uint32_t saved_registers_offset = 1; 1200 saved_registers_offset++; 1201 1202 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 1203 { 1204 switch (registers[i]) 1205 { 1206 case UNWIND_X86_REG_NONE: 1207 break; 1208 case UNWIND_X86_REG_EBX: 1209 case UNWIND_X86_REG_ECX: 1210 case UNWIND_X86_REG_EDX: 1211 case UNWIND_X86_REG_EDI: 1212 case UNWIND_X86_REG_ESI: 1213 case UNWIND_X86_REG_EBP: 1214 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true); 1215 saved_registers_offset++; 1216 break; 1217 } 1218 } 1219 } 1220 1221 unwind_plan.AppendRow (row); 1222 return true; 1223 } 1224 break; 1225 1226 case UNWIND_X86_MODE_DWARF: 1227 { 1228 return false; 1229 } 1230 break; 1231 } 1232 return false; 1233 } 1234