diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp | 590 |
1 files changed, 307 insertions, 283 deletions
diff --git a/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp index 78d2623..a5f9017 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -197,7 +197,7 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset) const size_t aug_str_len = strlen(cie_sp->augmentation); // A 'z' may be present as the first character of the string. // If present, the Augmentation Data field shall be present. - // The contents of the Augmentation Data shall be intepreted + // The contents of the Augmentation Data shall be interpreted // according to other characters in the Augmentation String. if (cie_sp->augmentation[0] == 'z') { @@ -276,38 +276,8 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset) uint8_t primary_opcode = inst & 0xC0; uint8_t extended_opcode = inst & 0x3F; - if (extended_opcode == DW_CFA_def_cfa) - { - // Takes two unsigned LEB128 operands representing a register - // number and a (non-factored) offset. The required action - // is to define the current CFA rule to use the provided - // register and offset. - uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); - cie_sp->initial_row.SetCFARegister (reg_num); - cie_sp->initial_row.SetCFAOffset (op_offset); - continue; - } - if (primary_opcode == DW_CFA_offset) - { - // 0x80 - high 2 bits are 0x2, lower 6 bits are register. - // Takes two arguments: an unsigned LEB128 constant representing a - // factored offset and a register number. The required action is to - // change the rule for the register indicated by the register number - // to be an offset(N) rule with a value of - // (N = factored offset * data_align). - uint32_t reg_num = extended_opcode; - int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * cie_sp->data_align; - UnwindPlan::Row::RegisterLocation reg_location; - reg_location.SetAtCFAPlusOffset(op_offset); - cie_sp->initial_row.SetRegisterInfo (reg_num, reg_location); - continue; - } - if (extended_opcode == DW_CFA_nop) - { - continue; - } - break; // Stop if we hit an unrecognized opcode + if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, cie_sp->data_align, offset, cie_sp->initial_row)) + break; // Stop if we hit an unrecognized opcode } } @@ -366,6 +336,31 @@ DWARFCallFrameInfo::GetFDEIndex () cie_offset = current_entry + 4 - cie_id; } + if (next_entry > m_cfi_data.GetByteSize() + 1) + { + Host::SystemLog (Host::eSystemLogError, + "error: Invalid fde/cie next entry offset of 0x%x found in cie/fde at 0x%x\n", + next_entry, + current_entry); + // Don't trust anything in this eh_frame section if we find blatently + // invalid data. + m_fde_index.Clear(); + m_fde_index_initialized = true; + return; + } + if (cie_offset > m_cfi_data.GetByteSize()) + { + Host::SystemLog (Host::eSystemLogError, + "error: Invalid cie offset of 0x%x found in cie/fde at 0x%x\n", + cie_offset, + current_entry); + // Don't trust anything in this eh_frame section if we find blatently + // invalid data. + m_fde_index.Clear(); + m_fde_index_initialized = true; + return; + } + if (cie_id == 0 || cie_id == UINT32_MAX || len == 0) { m_cie_map[current_entry] = ParseCIE (current_entry); @@ -490,8 +485,6 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr unwind_plan.SetPersonalityFunctionPtr (personality_function_ptr); } - uint32_t reg_num = 0; - int32_t op_offset = 0; uint32_t code_align = cie->code_align; int32_t data_align = cie->data_align; @@ -512,11 +505,13 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr uint8_t primary_opcode = inst & 0xC0; uint8_t extended_opcode = inst & 0x3F; - if (primary_opcode) + if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align, offset, *row)) { - switch (primary_opcode) + if (primary_opcode) { - case DW_CFA_advance_loc : // (Row Creation Instruction) + switch (primary_opcode) + { + case DW_CFA_advance_loc : // (Row Creation Instruction) { // 0x40 - high 2 bits are 0x1, lower 6 bits are delta // takes a single argument that represents a constant delta. The // required action is to create a new table row with a location @@ -528,29 +523,15 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr *newrow = *row.get(); row.reset (newrow); row->SlideOffset(extended_opcode * code_align); + break; } - break; - - case DW_CFA_offset : - { // 0x80 - high 2 bits are 0x2, lower 6 bits are register - // takes two arguments: an unsigned LEB128 constant representing a - // factored offset and a register number. The required action is to - // change the rule for the register indicated by the register number - // to be an offset(N) rule with a value of - // (N = factored offset * data_align). - reg_num = extended_opcode; - op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; - reg_location.SetAtCFAPlusOffset(op_offset); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - case DW_CFA_restore : + case DW_CFA_restore : { // 0xC0 - high 2 bits are 0x3, lower 6 bits are register // takes a single argument that represents a register number. The // required action is to change the rule for the indicated register // to the rule assigned it by the initial_instructions in the CIE. - reg_num = extended_opcode; + uint32_t reg_num = extended_opcode; // We only keep enough register locations around to // unwind what is in our thread, and these are organized // by the register index in that state, so we need to convert our @@ -558,18 +539,15 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location)) row->SetRegisterInfo (reg_num, reg_location); + break; } - break; + } } - } - else - { - switch (extended_opcode) + else { - case DW_CFA_nop : // 0x0 - break; - - case DW_CFA_set_loc : // 0x1 (Row Creation Instruction) + switch (extended_opcode) + { + case DW_CFA_set_loc : // 0x1 (Row Creation Instruction) { // DW_CFA_set_loc takes a single argument that represents an address. // The required action is to create a new table row using the @@ -581,10 +559,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr *newrow = *row.get(); row.reset (newrow); row->SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress()); + break; } - break; - case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction) + case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction) { // takes a single uword argument that represents a constant delta. // This instruction is identical to DW_CFA_advance_loc except for the @@ -594,10 +572,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr *newrow = *row.get(); row.reset (newrow); row->SlideOffset (m_cfi_data.GetU8(&offset) * code_align); + break; } - break; - case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction) + case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction) { // takes a single uword argument that represents a constant delta. // This instruction is identical to DW_CFA_advance_loc except for the @@ -607,10 +585,10 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr *newrow = *row.get(); row.reset (newrow); row->SlideOffset (m_cfi_data.GetU16(&offset) * code_align); + break; } - break; - case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction) + case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction) { // takes a single uword argument that represents a constant delta. // This instruction is identical to DW_CFA_advance_loc except for the @@ -620,68 +598,21 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr *newrow = *row.get(); row.reset (newrow); row->SlideOffset (m_cfi_data.GetU32(&offset) * code_align); + break; } - break; - case DW_CFA_offset_extended : // 0x5 - { - // takes two unsigned LEB128 arguments representing a register number - // and a factored offset. This instruction is identical to DW_CFA_offset - // except for the encoding and size of the register argument. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; - reg_location.SetAtCFAPlusOffset(op_offset); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - - case DW_CFA_restore_extended : // 0x6 + case DW_CFA_restore_extended : // 0x6 { // takes a single unsigned LEB128 argument that represents a register // number. This instruction is identical to DW_CFA_restore except for // the encoding and size of the register argument. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location)) row->SetRegisterInfo (reg_num, reg_location); + break; } - break; - case DW_CFA_undefined : // 0x7 - { - // takes a single unsigned LEB128 argument that represents a register - // number. The required action is to set the rule for the specified - // register to undefined. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - reg_location.SetUndefined(); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - - case DW_CFA_same_value : // 0x8 - { - // takes a single unsigned LEB128 argument that represents a register - // number. The required action is to set the rule for the specified - // register to same value. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - reg_location.SetSame(); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - - case DW_CFA_register : // 0x9 - { - // takes two unsigned LEB128 arguments representing register numbers. - // The required action is to set the rule for the first register to be - // the second register. - - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - reg_location.SetInRegister(other_reg_num); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - - case DW_CFA_remember_state : // 0xA + case DW_CFA_remember_state : // 0xA { // These instructions define a stack of information. Encountering the // DW_CFA_remember_state instruction means to save the rules for every @@ -694,184 +625,277 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *row.get(); row.reset (newrow); + break; } - break; - - case DW_CFA_restore_state : // 0xB - // These instructions define a stack of information. Encountering the - // DW_CFA_remember_state instruction means to save the rules for every - // register on the current row on the stack. Encountering the - // DW_CFA_restore_state instruction means to pop the set of rules off - // the stack and place them in the current row. (This operation is - // useful for compilers that move epilogue code into the body of a - // function.) + + case DW_CFA_restore_state : // 0xB { + // These instructions define a stack of information. Encountering the + // DW_CFA_remember_state instruction means to save the rules for every + // register on the current row on the stack. Encountering the + // DW_CFA_restore_state instruction means to pop the set of rules off + // the stack and place them in the current row. (This operation is + // useful for compilers that move epilogue code into the body of a + // function.) + lldb::addr_t offset = row->GetOffset (); row = stack.back (); stack.pop_back (); + row->SetOffset (offset); + break; } - break; - case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction) - { - // Takes two unsigned LEB128 operands representing a register - // number and a (non-factored) offset. The required action - // is to define the current CFA rule to use the provided - // register and offset. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); - row->SetCFARegister (reg_num); - row->SetCFAOffset (op_offset); - } - break; + case DW_CFA_val_offset : // 0x14 + case DW_CFA_val_offset_sf : // 0x15 + default: + break; + } + } + } + } + unwind_plan.AppendRow(row); - case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction) - { - // takes a single unsigned LEB128 argument representing a register - // number. The required action is to define the current CFA rule to - // use the provided register (but to keep the old offset). - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - row->SetCFARegister (reg_num); - } - break; + return true; +} - case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction) - { - // Takes a single unsigned LEB128 operand representing a - // (non-factored) offset. The required action is to define - // the current CFA rule to use the provided offset (but - // to keep the old register). - op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); - row->SetCFAOffset (op_offset); - } - break; +bool +DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode, + uint8_t extended_opcode, + int32_t data_align, + lldb::offset_t& offset, + UnwindPlan::Row& row) +{ + UnwindPlan::Row::RegisterLocation reg_location; - case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction) - { - size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset); - offset += (uint32_t)block_len; - } - break; + if (primary_opcode) + { + switch (primary_opcode) + { + case DW_CFA_offset: + { // 0x80 - high 2 bits are 0x2, lower 6 bits are register + // takes two arguments: an unsigned LEB128 constant representing a + // factored offset and a register number. The required action is to + // change the rule for the register indicated by the register number + // to be an offset(N) rule with a value of + // (N = factored offset * data_align). + uint8_t reg_num = extended_opcode; + int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo(reg_num, reg_location); + return true; + } + } + } + else + { + switch (extended_opcode) + { + case DW_CFA_nop : // 0x0 + return true; - case DW_CFA_expression : // 0x10 - { - // Takes two operands: an unsigned LEB128 value representing - // a register number, and a DW_FORM_block value representing a DWARF - // expression. The required action is to change the rule for the - // register indicated by the register number to be an expression(E) - // rule where E is the DWARF expression. That is, the DWARF - // expression computes the address. The value of the CFA is - // pushed on the DWARF evaluation stack prior to execution of - // the DWARF expression. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); - const uint8_t *block_data = (uint8_t *)m_cfi_data.GetData(&offset, block_len); - - reg_location.SetAtDWARFExpression(block_data, block_len); - row->SetRegisterInfo (reg_num, reg_location); - } - break; + case DW_CFA_offset_extended : // 0x5 + { + // takes two unsigned LEB128 arguments representing a register number + // and a factored offset. This instruction is identical to DW_CFA_offset + // except for the encoding and size of the register argument. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo(reg_num, reg_location); + return true; + } - case DW_CFA_offset_extended_sf : // 0x11 - { - // takes two operands: an unsigned LEB128 value representing a - // register number and a signed LEB128 factored offset. This - // instruction is identical to DW_CFA_offset_extended except - //that the second operand is signed and factored. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; - reg_location.SetAtCFAPlusOffset(op_offset); - row->SetRegisterInfo (reg_num, reg_location); - } - break; + case DW_CFA_undefined : // 0x7 + { + // takes a single unsigned LEB128 argument that represents a register + // number. The required action is to set the rule for the specified + // register to undefined. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetUndefined(); + row.SetRegisterInfo(reg_num, reg_location); + return true; + } - case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction) - { - // Takes two operands: an unsigned LEB128 value representing - // a register number and a signed LEB128 factored offset. - // This instruction is identical to DW_CFA_def_cfa except - // that the second operand is signed and factored. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; - row->SetCFARegister (reg_num); - row->SetCFAOffset (op_offset); - } - break; + case DW_CFA_same_value : // 0x8 + { + // takes a single unsigned LEB128 argument that represents a register + // number. The required action is to set the rule for the specified + // register to same value. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetSame(); + row.SetRegisterInfo (reg_num, reg_location); + return true; + } - case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction) - { - // takes a signed LEB128 operand representing a factored - // offset. This instruction is identical to DW_CFA_def_cfa_offset - // except that the operand is signed and factored. - op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; - row->SetCFAOffset (op_offset); - } - break; + case DW_CFA_register : // 0x9 + { + // takes two unsigned LEB128 arguments representing register numbers. + // The required action is to set the rule for the first register to be + // the second register. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetInRegister(other_reg_num); + row.SetRegisterInfo (reg_num, reg_location); + return true; + } - case DW_CFA_val_expression : // 0x16 - { - // takes two operands: an unsigned LEB128 value representing a register - // number, and a DW_FORM_block value representing a DWARF expression. - // The required action is to change the rule for the register indicated - // by the register number to be a val_expression(E) rule where E is the - // DWARF expression. That is, the DWARF expression computes the value of - // the given register. The value of the CFA is pushed on the DWARF - // evaluation stack prior to execution of the DWARF expression. - reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); - uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); - const uint8_t* block_data = (uint8_t*)m_cfi_data.GetData(&offset, block_len); + case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction) + { + // Takes two unsigned LEB128 operands representing a register + // number and a (non-factored) offset. The required action + // is to define the current CFA rule to use the provided + // register and offset. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); + row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset); + return true; + } + + case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction) + { + // takes a single unsigned LEB128 argument representing a register + // number. The required action is to define the current CFA rule to + // use the provided register (but to keep the old offset). + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, row.GetCFAValue().GetOffset()); + return true; + } + + case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction) + { + // Takes a single unsigned LEB128 operand representing a + // (non-factored) offset. The required action is to define + // the current CFA rule to use the provided offset (but + // to keep the old register). + int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); + row.GetCFAValue().SetIsRegisterPlusOffset(row.GetCFAValue().GetRegisterNumber(), op_offset); + return true; + } + + case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction) + { + size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset); + const uint8_t *block_data = static_cast<const uint8_t*>(m_cfi_data.GetData(&offset, block_len)); + row.GetCFAValue().SetIsDWARFExpression(block_data, block_len); + return true; + } + + case DW_CFA_expression : // 0x10 + { + // Takes two operands: an unsigned LEB128 value representing + // a register number, and a DW_FORM_block value representing a DWARF + // expression. The required action is to change the rule for the + // register indicated by the register number to be an expression(E) + // rule where E is the DWARF expression. That is, the DWARF + // expression computes the address. The value of the CFA is + // pushed on the DWARF evaluation stack prior to execution of + // the DWARF expression. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); + const uint8_t *block_data = static_cast<const uint8_t*>(m_cfi_data.GetData(&offset, block_len)); + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetAtDWARFExpression(block_data, block_len); + row.SetRegisterInfo(reg_num, reg_location); + return true; + } + + case DW_CFA_offset_extended_sf : // 0x11 + { + // takes two operands: an unsigned LEB128 value representing a + // register number and a signed LEB128 factored offset. This + // instruction is identical to DW_CFA_offset_extended except + //that the second operand is signed and factored. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + UnwindPlan::Row::RegisterLocation reg_location; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo(reg_num, reg_location); + return true; + } + + case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction) + { + // Takes two operands: an unsigned LEB128 value representing + // a register number and a signed LEB128 factored offset. + // This instruction is identical to DW_CFA_def_cfa except + // that the second operand is signed and factored. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + row.GetCFAValue().SetIsRegisterPlusOffset (reg_num, op_offset); + return true; + } + + case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction) + { + // takes a signed LEB128 operand representing a factored + // offset. This instruction is identical to DW_CFA_def_cfa_offset + // except that the operand is signed and factored. + int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + uint32_t cfa_regnum = row.GetCFAValue().GetRegisterNumber(); + row.GetCFAValue().SetIsRegisterPlusOffset(cfa_regnum, op_offset); + return true; + } + + case DW_CFA_val_expression : // 0x16 + { + // takes two operands: an unsigned LEB128 value representing a register + // number, and a DW_FORM_block value representing a DWARF expression. + // The required action is to change the rule for the register indicated + // by the register number to be a val_expression(E) rule where E is the + // DWARF expression. That is, the DWARF expression computes the value of + // the given register. The value of the CFA is pushed on the DWARF + // evaluation stack prior to execution of the DWARF expression. + uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); + const uint8_t* block_data = (const uint8_t*)m_cfi_data.GetData(&offset, block_len); //#if defined(__i386__) || defined(__x86_64__) -// // The EH frame info for EIP and RIP contains code that looks for traps to -// // be a specific type and increments the PC. -// // For i386: -// // DW_CFA_val_expression where: -// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34), -// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref, -// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, -// // DW_OP_and, DW_OP_plus -// // This basically does a: -// // eip = ucontenxt.mcontext32->gpr.eip; -// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4) -// // eip++; -// // -// // For x86_64: -// // DW_CFA_val_expression where: -// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref, -// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3, -// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus -// // This basically does a: -// // rip = ucontenxt.mcontext64->gpr.rip; -// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4) -// // rip++; -// // The trap comparisons and increments are not needed as it hoses up the unwound PC which -// // is expected to point at least past the instruction that causes the fault/trap. So we -// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes -// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num) -// { -// if (thread->Is64Bit()) -// { -// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst) -// block_len = 8; -// } -// else -// { -// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst) -// block_len = 7; -// } -// } +// // The EH frame info for EIP and RIP contains code that looks for traps to +// // be a specific type and increments the PC. +// // For i386: +// // DW_CFA_val_expression where: +// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34), +// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref, +// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, +// // DW_OP_and, DW_OP_plus +// // This basically does a: +// // eip = ucontenxt.mcontext32->gpr.eip; +// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4) +// // eip++; +// // +// // For x86_64: +// // DW_CFA_val_expression where: +// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref, +// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3, +// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus +// // This basically does a: +// // rip = ucontenxt.mcontext64->gpr.rip; +// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4) +// // rip++; +// // The trap comparisons and increments are not needed as it hoses up the unwound PC which +// // is expected to point at least past the instruction that causes the fault/trap. So we +// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes +// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num) +// { +// if (thread->Is64Bit()) +// { +// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst) +// block_len = 8; +// } +// else +// { +// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst) +// block_len = 7; +// } +// } //#endif - reg_location.SetIsDWARFExpression(block_data, block_len); - row->SetRegisterInfo (reg_num, reg_location); - } - break; - - case DW_CFA_val_offset : // 0x14 - case DW_CFA_val_offset_sf : // 0x15 - default: - break; + reg_location.SetIsDWARFExpression(block_data, block_len); + row.SetRegisterInfo (reg_num, reg_location); + return true; } } } - unwind_plan.AppendRow(row); - - return true; + return false; } |