bool EmulateInstructionARM64::EvaluateInstruction(uint32_t evaluate_options) { const uint32_t opcode = m_opcode.GetOpcode32(); Opcode *opcode_data = GetOpcodeForInstruction(opcode); if (opcode_data == NULL) return false; // printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name); const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; bool success = false; // if (m_opcode_cpsr == 0 || m_ignore_conditions == false) // { // m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindLLDB, // gpr_cpsr_arm64, // 0, // &success); // } // Only return false if we are unable to read the CPSR if we care about // conditions if (!success && !m_ignore_conditions) return false; uint32_t orig_pc_value = 0; if (auto_advance_pc) { orig_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success); if (!success) return false; } // Call the Emulate... function. success = (this->*opcode_data->callback)(opcode); if (!success) return false; if (auto_advance_pc) { uint32_t new_pc_value = ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_arm64, 0, &success); if (!success) return false; if (auto_advance_pc && (new_pc_value == orig_pc_value)) { EmulateInstruction::Context context; context.type = eContextAdvancePC; context.SetNoArgs(); if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_arm64, orig_pc_value + 4)) return false; } } return true; }
size_t UnwindAssemblyInstEmulation::ReadMemory( EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t dst_len) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); if (log && log->GetVerbose()) { StreamString strm; strm.Printf( "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64 ", dst = %p, dst_len = %" PRIu64 ", context = ", addr, dst, (uint64_t)dst_len); context.Dump(strm, instruction); log->PutString(strm.GetString()); } memset(dst, 0, dst_len); return dst_len; }
size_t UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t dst_len) { LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); if (log && log->GetVerbose ()) { StreamString strm; strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16llx, dst = %p, dst_len = %zu, context = ", addr, dst, dst_len); context.Dump(strm, instruction); log->PutCString (strm.GetData ()); } return dst_len; }
bool UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, const EmulateInstruction::Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); if (log && log->GetVerbose ()) { StreamString strm; strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name); reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); strm.PutCString (", context = "); context.Dump(strm, instruction); log->PutCString(strm.GetData()); } if (!instruction->IsInstructionConditional()) SetRegisterValue (*reg_info, reg_value); switch (context.type) { case EmulateInstruction::eContextInvalid: case EmulateInstruction::eContextReadOpcode: case EmulateInstruction::eContextImmediate: case EmulateInstruction::eContextAdjustBaseRegister: case EmulateInstruction::eContextRegisterPlusOffset: case EmulateInstruction::eContextAdjustPC: case EmulateInstruction::eContextRegisterStore: case EmulateInstruction::eContextSupervisorCall: case EmulateInstruction::eContextTableBranchReadMemory: case EmulateInstruction::eContextWriteRegisterRandomBits: case EmulateInstruction::eContextWriteMemoryRandomBits: case EmulateInstruction::eContextArithmetic: case EmulateInstruction::eContextAdvancePC: case EmulateInstruction::eContextReturnFromException: case EmulateInstruction::eContextPushRegisterOnStack: case EmulateInstruction::eContextRegisterLoad: // { // const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; // if (reg_num != LLDB_INVALID_REGNUM) // { // const bool can_replace_only_if_unspecified = true; // // m_curr_row.SetRegisterLocationToUndefined (reg_num, // can_replace_only_if_unspecified, // can_replace_only_if_unspecified); // m_curr_row_modified = true; // } // } break; case EmulateInstruction::eContextAbsoluteBranchRegister: case EmulateInstruction::eContextRelativeBranchImmediate: { if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate && context.info.ISAAndImmediate.unsigned_data32 > 0) { m_forward_branch_offset = context.info.ISAAndImmediateSigned.signed_data32; } else if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediateSigned && context.info.ISAAndImmediateSigned.signed_data32 > 0) { m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32; } else if (context.info_type == EmulateInstruction::eInfoTypeImmediate && context.info.unsigned_immediate > 0) { m_forward_branch_offset = context.info.unsigned_immediate; } else if (context.info_type == EmulateInstruction::eInfoTypeImmediateSigned && context.info.signed_immediate > 0) { m_forward_branch_offset = context.info.signed_immediate; } } break; case EmulateInstruction::eContextPopRegisterOffStack: { if (!instruction->IsInstructionConditional()) { const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric]; if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP) { switch (context.info_type) { case EmulateInstruction::eInfoTypeAddress: if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() && context.info.address == m_pushed_regs[reg_num]) { m_curr_row->SetRegisterLocationToSame(reg_num, false /*must_replace*/); m_curr_row_modified = true; } break; case EmulateInstruction::eInfoTypeISA: assert((generic_regnum == LLDB_REGNUM_GENERIC_PC || generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && "eInfoTypeISA used for poping a register other the the PC/FLAGS"); if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) { m_curr_row->SetRegisterLocationToSame(reg_num, false /*must_replace*/); m_curr_row_modified = true; } break; default: assert(false && "unhandled case, add code to handle this!"); break; } } } } break; case EmulateInstruction::eContextSetFramePointer: if (!m_fp_is_cfa && !instruction->IsInstructionConditional()) { m_fp_is_cfa = true; m_cfa_reg_info = *reg_info; const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; assert (cfa_reg_num != LLDB_INVALID_REGNUM); m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); m_curr_row_modified = true; } break; case EmulateInstruction::eContextAdjustStackPointer: // If we have created a frame using the frame pointer, don't follow // subsequent adjustments to the stack pointer. if (!m_fp_is_cfa && !instruction->IsInstructionConditional()) { m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( m_curr_row->GetCFAValue().GetRegisterNumber(), m_initial_sp - reg_value.GetAsUInt64()); m_curr_row_modified = true; } break; } return true; }
size_t UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction, const EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t dst_len) { DataExtractor data (dst, dst_len, instruction->GetArchitecture ().GetByteOrder(), instruction->GetArchitecture ().GetAddressByteSize()); Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); if (log && log->GetVerbose ()) { StreamString strm; strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory ("); data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0); strm.PutCString (", context = "); context.Dump(strm, instruction); log->PutCString (strm.GetData()); } const bool cant_replace = false; switch (context.type) { default: case EmulateInstruction::eContextInvalid: case EmulateInstruction::eContextReadOpcode: case EmulateInstruction::eContextImmediate: case EmulateInstruction::eContextAdjustBaseRegister: case EmulateInstruction::eContextRegisterPlusOffset: case EmulateInstruction::eContextAdjustPC: case EmulateInstruction::eContextRegisterStore: case EmulateInstruction::eContextRegisterLoad: case EmulateInstruction::eContextRelativeBranchImmediate: case EmulateInstruction::eContextAbsoluteBranchRegister: case EmulateInstruction::eContextSupervisorCall: case EmulateInstruction::eContextTableBranchReadMemory: case EmulateInstruction::eContextWriteRegisterRandomBits: case EmulateInstruction::eContextWriteMemoryRandomBits: case EmulateInstruction::eContextArithmetic: case EmulateInstruction::eContextAdvancePC: case EmulateInstruction::eContextReturnFromException: case EmulateInstruction::eContextPopRegisterOffStack: case EmulateInstruction::eContextAdjustStackPointer: break; case EmulateInstruction::eContextPushRegisterOnStack: { uint32_t reg_num = LLDB_INVALID_REGNUM; uint32_t generic_regnum = LLDB_INVALID_REGNUM; if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset) { const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind(); reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind]; generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric]; } else assert (!"unhandled case, add code to handle this!"); if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP) { if (m_pushed_regs.find (reg_num) == m_pushed_regs.end()) { m_pushed_regs[reg_num] = addr; const int32_t offset = addr - m_initial_sp; m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace); m_curr_row_modified = true; } } } break; } return dst_len; }
bool UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction, const EmulateInstruction::Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); if (log && log->GetVerbose ()) { StreamString strm; strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name); reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); strm.PutCString (", context = "); context.Dump(strm, instruction); log->PutCString(strm.GetData()); } const bool must_replace = true; SetRegisterValue (*reg_info, reg_value); switch (context.type) { default: case EmulateInstruction::eContextInvalid: case EmulateInstruction::eContextReadOpcode: case EmulateInstruction::eContextImmediate: case EmulateInstruction::eContextAdjustBaseRegister: case EmulateInstruction::eContextRegisterPlusOffset: case EmulateInstruction::eContextAdjustPC: case EmulateInstruction::eContextRegisterStore: case EmulateInstruction::eContextRegisterLoad: case EmulateInstruction::eContextRelativeBranchImmediate: case EmulateInstruction::eContextAbsoluteBranchRegister: case EmulateInstruction::eContextSupervisorCall: case EmulateInstruction::eContextTableBranchReadMemory: case EmulateInstruction::eContextWriteRegisterRandomBits: case EmulateInstruction::eContextWriteMemoryRandomBits: case EmulateInstruction::eContextArithmetic: case EmulateInstruction::eContextAdvancePC: case EmulateInstruction::eContextReturnFromException: case EmulateInstruction::eContextPushRegisterOnStack: // { // const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; // if (reg_num != LLDB_INVALID_REGNUM) // { // const bool can_replace_only_if_unspecified = true; // // m_curr_row.SetRegisterLocationToUndefined (reg_num, // can_replace_only_if_unspecified, // can_replace_only_if_unspecified); // } // } break; case EmulateInstruction::eContextPopRegisterOffStack: { const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; if (reg_num != LLDB_INVALID_REGNUM) { m_curr_row.SetRegisterLocationToSame (reg_num, must_replace); } } break; case EmulateInstruction::eContextSetFramePointer: if (!m_fp_is_cfa) { m_fp_is_cfa = true; m_cfa_reg_info = *reg_info; const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; assert (cfa_reg_num != LLDB_INVALID_REGNUM); m_curr_row.SetCFARegister(cfa_reg_num); m_curr_row.SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64()); } break; case EmulateInstruction::eContextAdjustStackPointer: // If we have created a frame using the frame pointer, don't follow // subsequent adjustments to the stack pointer. if (!m_fp_is_cfa) { m_curr_row.SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64()); } break; } return true; }