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 // blatently 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.begin()) 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 eRegisterKindGCC (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 (eRegisterKindGCC); 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 return false; 780 } 781 break; 782 783 case UNWIND_X86_64_MODE_STACK_IMMD: 784 { 785 uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 786 uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 787 uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 788 789 if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 790 { 791 uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 792 793 // offset into the function instructions; 0 == beginning of first instruction 794 uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 795 796 SectionList *sl = m_objfile.GetSectionList (); 797 if (sl) 798 { 799 ProcessSP process_sp = target.GetProcessSP(); 800 if (process_sp) 801 { 802 Address subl_payload_addr (function_info.valid_range_offset_start, sl); 803 subl_payload_addr.Slide (offset_to_subl_insn); 804 Error error; 805 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 806 4, 0, error); 807 if (large_stack_size != 0 && error.Success ()) 808 { 809 // Got the large stack frame size correctly - use it 810 stack_size = large_stack_size + (stack_adjust * wordsize); 811 } 812 else 813 { 814 return false; 815 } 816 } 817 else 818 { 819 return false; 820 } 821 } 822 else 823 { 824 return false; 825 } 826 } 827 828 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize; 829 row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset); 830 831 row->SetOffset (0); 832 row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); 833 row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); 834 835 if (register_count > 0) 836 { 837 838 // We need to include (up to) 6 registers in 10 bits. 839 // That would be 18 bits if we just used 3 bits per reg to indicate 840 // the order they're saved on the stack. 841 // 842 // This is done with Lehmer code permutation, e.g. see 843 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 844 int permunreg[6] = {0, 0, 0, 0, 0, 0}; 845 846 // This decodes the variable-base number in the 10 bits 847 // and gives us the Lehmer code sequence which can then 848 // be decoded. 849 850 switch (register_count) 851 { 852 case 6: 853 permunreg[0] = permutation/120; // 120 == 5! 854 permutation -= (permunreg[0]*120); 855 permunreg[1] = permutation/24; // 24 == 4! 856 permutation -= (permunreg[1]*24); 857 permunreg[2] = permutation/6; // 6 == 3! 858 permutation -= (permunreg[2]*6); 859 permunreg[3] = permutation/2; // 2 == 2! 860 permutation -= (permunreg[3]*2); 861 permunreg[4] = permutation; // 1 == 1! 862 permunreg[5] = 0; 863 break; 864 case 5: 865 permunreg[0] = permutation/120; 866 permutation -= (permunreg[0]*120); 867 permunreg[1] = permutation/24; 868 permutation -= (permunreg[1]*24); 869 permunreg[2] = permutation/6; 870 permutation -= (permunreg[2]*6); 871 permunreg[3] = permutation/2; 872 permutation -= (permunreg[3]*2); 873 permunreg[4] = permutation; 874 break; 875 case 4: 876 permunreg[0] = permutation/60; 877 permutation -= (permunreg[0]*60); 878 permunreg[1] = permutation/12; 879 permutation -= (permunreg[1]*12); 880 permunreg[2] = permutation/3; 881 permutation -= (permunreg[2]*3); 882 permunreg[3] = permutation; 883 break; 884 case 3: 885 permunreg[0] = permutation/20; 886 permutation -= (permunreg[0]*20); 887 permunreg[1] = permutation/4; 888 permutation -= (permunreg[1]*4); 889 permunreg[2] = permutation; 890 break; 891 case 2: 892 permunreg[0] = permutation/5; 893 permutation -= (permunreg[0]*5); 894 permunreg[1] = permutation; 895 break; 896 case 1: 897 permunreg[0] = permutation; 898 break; 899 } 900 901 // Decode the Lehmer code for this permutation of 902 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 903 904 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 }; 905 bool used[7] = { false, false, false, false, false, false, false }; 906 for (uint32_t i = 0; i < register_count; i++) 907 { 908 int renum = 0; 909 for (int j = 1; j < 7; j++) 910 { 911 if (used[j] == false) 912 { 913 if (renum == permunreg[i]) 914 { 915 registers[i] = j; 916 used[j] = true; 917 break; 918 } 919 renum++; 920 } 921 } 922 } 923 924 uint32_t saved_registers_offset = 1; 925 saved_registers_offset++; 926 927 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 928 { 929 switch (registers[i]) 930 { 931 case UNWIND_X86_64_REG_NONE: 932 break; 933 case UNWIND_X86_64_REG_RBX: 934 case UNWIND_X86_64_REG_R12: 935 case UNWIND_X86_64_REG_R13: 936 case UNWIND_X86_64_REG_R14: 937 case UNWIND_X86_64_REG_R15: 938 case UNWIND_X86_64_REG_RBP: 939 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true); 940 saved_registers_offset++; 941 break; 942 } 943 } 944 } 945 unwind_plan.AppendRow (row); 946 return true; 947 } 948 break; 949 950 case UNWIND_X86_64_MODE_DWARF: 951 { 952 return false; 953 } 954 break; 955 956 case 0: 957 { 958 return false; 959 } 960 break; 961 } 962 return false; 963 } 964 965 enum i386_eh_regnum { 966 eax = 0, 967 ecx = 1, 968 edx = 2, 969 ebx = 3, 970 ebp = 4, 971 esp = 5, 972 esi = 6, 973 edi = 7, 974 eip = 8 // this is officially the Return Address register number, but close enough 975 }; 976 977 // Convert the compact_unwind_info.h register numbering scheme 978 // to eRegisterKindGCC (eh_frame) register numbering scheme. 979 uint32_t 980 translate_to_eh_frame_regnum_i386 (uint32_t unwind_regno) 981 { 982 switch (unwind_regno) 983 { 984 case UNWIND_X86_REG_EBX: 985 return i386_eh_regnum::ebx; 986 case UNWIND_X86_REG_ECX: 987 return i386_eh_regnum::ecx; 988 case UNWIND_X86_REG_EDX: 989 return i386_eh_regnum::edx; 990 case UNWIND_X86_REG_EDI: 991 return i386_eh_regnum::edi; 992 case UNWIND_X86_REG_ESI: 993 return i386_eh_regnum::esi; 994 case UNWIND_X86_REG_EBP: 995 return i386_eh_regnum::ebp; 996 default: 997 return LLDB_INVALID_REGNUM; 998 } 999 } 1000 1001 1002 bool 1003 CompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 1004 { 1005 unwind_plan.SetSourceName ("compact unwind info"); 1006 unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 1007 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 1008 unwind_plan.SetRegisterKind (eRegisterKindGCC); 1009 1010 unwind_plan.SetLSDAAddress (function_info.lsda_address); 1011 unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 1012 1013 UnwindPlan::RowSP row (new UnwindPlan::Row); 1014 1015 const int wordsize = 4; 1016 int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1017 switch (mode) 1018 { 1019 case UNWIND_X86_MODE_EBP_FRAME: 1020 { 1021 row->GetCFAValue().SetIsRegisterPlusOffset ( 1022 translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize); 1023 row->SetOffset (0); 1024 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true); 1025 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1026 row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1027 1028 uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1029 1030 uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1031 1032 saved_registers_offset += 2; 1033 1034 for (int i = 0; i < 5; i++) 1035 { 1036 uint32_t regnum = saved_registers_locations & 0x7; 1037 switch (regnum) 1038 { 1039 case UNWIND_X86_REG_NONE: 1040 break; 1041 case UNWIND_X86_REG_EBX: 1042 case UNWIND_X86_REG_ECX: 1043 case UNWIND_X86_REG_EDX: 1044 case UNWIND_X86_REG_EDI: 1045 case UNWIND_X86_REG_ESI: 1046 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true); 1047 break; 1048 } 1049 saved_registers_offset--; 1050 saved_registers_locations >>= 3; 1051 } 1052 unwind_plan.AppendRow (row); 1053 return true; 1054 } 1055 break; 1056 1057 case UNWIND_X86_MODE_STACK_IND: 1058 case UNWIND_X86_MODE_STACK_IMMD: 1059 { 1060 uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1061 uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1062 uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1063 1064 if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 1065 { 1066 uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); 1067 1068 // offset into the function instructions; 0 == beginning of first instruction 1069 uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1070 1071 SectionList *sl = m_objfile.GetSectionList (); 1072 if (sl) 1073 { 1074 ProcessSP process_sp = target.GetProcessSP(); 1075 if (process_sp) 1076 { 1077 Address subl_payload_addr (function_info.valid_range_offset_start, sl); 1078 subl_payload_addr.Slide (offset_to_subl_insn); 1079 Error error; 1080 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 1081 4, 0, error); 1082 if (large_stack_size != 0 && error.Success ()) 1083 { 1084 // Got the large stack frame size correctly - use it 1085 stack_size = large_stack_size + (stack_adjust * wordsize); 1086 } 1087 else 1088 { 1089 return false; 1090 } 1091 } 1092 else 1093 { 1094 return false; 1095 } 1096 } 1097 else 1098 { 1099 return false; 1100 } 1101 } 1102 1103 int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1104 row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset); 1105 row->SetOffset (0); 1106 row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1107 row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1108 1109 if (register_count > 0) 1110 { 1111 1112 // We need to include (up to) 6 registers in 10 bits. 1113 // That would be 18 bits if we just used 3 bits per reg to indicate 1114 // the order they're saved on the stack. 1115 // 1116 // This is done with Lehmer code permutation, e.g. see 1117 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 1118 int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1119 1120 // This decodes the variable-base number in the 10 bits 1121 // and gives us the Lehmer code sequence which can then 1122 // be decoded. 1123 1124 switch (register_count) 1125 { 1126 case 6: 1127 permunreg[0] = permutation/120; // 120 == 5! 1128 permutation -= (permunreg[0]*120); 1129 permunreg[1] = permutation/24; // 24 == 4! 1130 permutation -= (permunreg[1]*24); 1131 permunreg[2] = permutation/6; // 6 == 3! 1132 permutation -= (permunreg[2]*6); 1133 permunreg[3] = permutation/2; // 2 == 2! 1134 permutation -= (permunreg[3]*2); 1135 permunreg[4] = permutation; // 1 == 1! 1136 permunreg[5] = 0; 1137 break; 1138 case 5: 1139 permunreg[0] = permutation/120; 1140 permutation -= (permunreg[0]*120); 1141 permunreg[1] = permutation/24; 1142 permutation -= (permunreg[1]*24); 1143 permunreg[2] = permutation/6; 1144 permutation -= (permunreg[2]*6); 1145 permunreg[3] = permutation/2; 1146 permutation -= (permunreg[3]*2); 1147 permunreg[4] = permutation; 1148 break; 1149 case 4: 1150 permunreg[0] = permutation/60; 1151 permutation -= (permunreg[0]*60); 1152 permunreg[1] = permutation/12; 1153 permutation -= (permunreg[1]*12); 1154 permunreg[2] = permutation/3; 1155 permutation -= (permunreg[2]*3); 1156 permunreg[3] = permutation; 1157 break; 1158 case 3: 1159 permunreg[0] = permutation/20; 1160 permutation -= (permunreg[0]*20); 1161 permunreg[1] = permutation/4; 1162 permutation -= (permunreg[1]*4); 1163 permunreg[2] = permutation; 1164 break; 1165 case 2: 1166 permunreg[0] = permutation/5; 1167 permutation -= (permunreg[0]*5); 1168 permunreg[1] = permutation; 1169 break; 1170 case 1: 1171 permunreg[0] = permutation; 1172 break; 1173 } 1174 1175 // Decode the Lehmer code for this permutation of 1176 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 1177 1178 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 }; 1179 bool used[7] = { false, false, false, false, false, false, false }; 1180 for (uint32_t i = 0; i < register_count; i++) 1181 { 1182 int renum = 0; 1183 for (int j = 1; j < 7; j++) 1184 { 1185 if (used[j] == false) 1186 { 1187 if (renum == permunreg[i]) 1188 { 1189 registers[i] = j; 1190 used[j] = true; 1191 break; 1192 } 1193 renum++; 1194 } 1195 } 1196 } 1197 1198 uint32_t saved_registers_offset = 1; 1199 saved_registers_offset++; 1200 1201 for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 1202 { 1203 switch (registers[i]) 1204 { 1205 case UNWIND_X86_REG_NONE: 1206 break; 1207 case UNWIND_X86_REG_EBX: 1208 case UNWIND_X86_REG_ECX: 1209 case UNWIND_X86_REG_EDX: 1210 case UNWIND_X86_REG_EDI: 1211 case UNWIND_X86_REG_ESI: 1212 case UNWIND_X86_REG_EBP: 1213 row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true); 1214 saved_registers_offset++; 1215 break; 1216 } 1217 } 1218 } 1219 1220 unwind_plan.AppendRow (row); 1221 return true; 1222 } 1223 break; 1224 1225 case UNWIND_X86_MODE_DWARF: 1226 { 1227 return false; 1228 } 1229 break; 1230 } 1231 return false; 1232 } 1233