Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}