void UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp) { collection::iterator it = m_row_list.begin(); while (it != m_row_list.end()) { RowSP row = *it; if (row->GetOffset() >= row_sp->GetOffset()) break; it++; } if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset()) m_row_list.insert(it, row_sp); }
void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) { if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset()) m_row_list.push_back(row_sp); else m_row_list.back() = row_sp; }
bool CompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) { unwind_plan.SetSourceName ("compact unwind info"); unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); unwind_plan.SetRegisterKind (eRegisterKindEHFrame); unwind_plan.SetLSDAAddress (function_info.lsda_address); unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); UnwindPlan::RowSP row (new UnwindPlan::Row); const int wordsize = 8; int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; switch (mode) { case UNWIND_X86_64_MODE_RBP_FRAME: { row->GetCFAValue().SetIsRegisterPlusOffset ( translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP), 2 * wordsize); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); saved_registers_offset += 2; for (int i = 0; i < 5; i++) { uint32_t regnum = saved_registers_locations & 0x7; switch (regnum) { case UNWIND_X86_64_REG_NONE: break; case UNWIND_X86_64_REG_RBX: case UNWIND_X86_64_REG_R12: case UNWIND_X86_64_REG_R13: case UNWIND_X86_64_REG_R14: case UNWIND_X86_64_REG_R15: row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true); break; } saved_registers_offset--; saved_registers_locations >>= 3; } unwind_plan.AppendRow (row); return true; } break; case UNWIND_X86_64_MODE_STACK_IND: { // The clang in Xcode 6 is emitting incorrect compact unwind encodings for this // style of unwind. It was fixed in llvm r217020. // The clang in Xcode 7 has this fixed. return false; } break; case UNWIND_X86_64_MODE_STACK_IMMD: { uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0) { uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); // offset into the function instructions; 0 == beginning of first instruction uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); SectionList *sl = m_objfile.GetSectionList (); if (sl) { ProcessSP process_sp = target.GetProcessSP(); if (process_sp) { Address subl_payload_addr (function_info.valid_range_offset_start, sl); subl_payload_addr.Slide (offset_to_subl_insn); Error error; uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 4, 0, error); if (large_stack_size != 0 && error.Success ()) { // Got the large stack frame size correctly - use it stack_size = large_stack_size + (stack_adjust * wordsize); } else { return false; } } else { return false; } } else { return false; } } int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize; row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset); row->SetOffset (0); row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); if (register_count > 0) { // We need to include (up to) 6 registers in 10 bits. // That would be 18 bits if we just used 3 bits per reg to indicate // the order they're saved on the stack. // // This is done with Lehmer code permutation, e.g. see // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms int permunreg[6] = {0, 0, 0, 0, 0, 0}; // This decodes the variable-base number in the 10 bits // and gives us the Lehmer code sequence which can then // be decoded. switch (register_count) { case 6: permunreg[0] = permutation/120; // 120 == 5! permutation -= (permunreg[0]*120); permunreg[1] = permutation/24; // 24 == 4! permutation -= (permunreg[1]*24); permunreg[2] = permutation/6; // 6 == 3! permutation -= (permunreg[2]*6); permunreg[3] = permutation/2; // 2 == 2! permutation -= (permunreg[3]*2); permunreg[4] = permutation; // 1 == 1! permunreg[5] = 0; break; case 5: permunreg[0] = permutation/120; permutation -= (permunreg[0]*120); permunreg[1] = permutation/24; permutation -= (permunreg[1]*24); permunreg[2] = permutation/6; permutation -= (permunreg[2]*6); permunreg[3] = permutation/2; permutation -= (permunreg[3]*2); permunreg[4] = permutation; break; case 4: permunreg[0] = permutation/60; permutation -= (permunreg[0]*60); permunreg[1] = permutation/12; permutation -= (permunreg[1]*12); permunreg[2] = permutation/3; permutation -= (permunreg[2]*3); permunreg[3] = permutation; break; case 3: permunreg[0] = permutation/20; permutation -= (permunreg[0]*20); permunreg[1] = permutation/4; permutation -= (permunreg[1]*4); permunreg[2] = permutation; break; case 2: permunreg[0] = permutation/5; permutation -= (permunreg[0]*5); permunreg[1] = permutation; break; case 1: permunreg[0] = permutation; break; } // Decode the Lehmer code for this permutation of // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 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 }; bool used[7] = { false, false, false, false, false, false, false }; for (uint32_t i = 0; i < register_count; i++) { int renum = 0; for (int j = 1; j < 7; j++) { if (used[j] == false) { if (renum == permunreg[i]) { registers[i] = j; used[j] = true; break; } renum++; } } } uint32_t saved_registers_offset = 1; saved_registers_offset++; for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) { switch (registers[i]) { case UNWIND_X86_64_REG_NONE: break; case UNWIND_X86_64_REG_RBX: case UNWIND_X86_64_REG_R12: case UNWIND_X86_64_REG_R13: case UNWIND_X86_64_REG_R14: case UNWIND_X86_64_REG_R15: case UNWIND_X86_64_REG_RBP: row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true); saved_registers_offset++; break; } } } unwind_plan.AppendRow (row); return true; } break; case UNWIND_X86_64_MODE_DWARF: { return false; } break; case 0: { return false; } break; } return false; }