ValueObjectSP ABISysV_s390x::GetReturnValueObjectImpl( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; if (!return_compiler_type) return return_valobj_sp; ExecutionContext exe_ctx(thread.shared_from_this()); return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); if (return_valobj_sp) return return_valobj_sp; RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); if (!reg_ctx_sp) return return_valobj_sp; if (return_compiler_type.IsAggregateType()) { // FIXME: This is just taking a guess, r2 may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should // check to see if it uses a memory return, and if we are at the first // instruction and if so stash away the return location. Then we would // only return the memory return value if we know it is valid. unsigned r2_id = reg_ctx_sp->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); return_valobj_sp = ValueObjectMemory::Create( &thread, "", Address(storage_addr, nullptr), return_compiler_type); } return return_valobj_sp; }
ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_clang_type) const { ValueObjectSP return_valobj_sp; if (!return_clang_type) return return_valobj_sp; ExecutionContext exe_ctx (thread.shared_from_this()); return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type); if (return_valobj_sp) return return_valobj_sp; RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); if (!reg_ctx_sp) return return_valobj_sp; if (return_clang_type.IsAggregateType()) { unsigned eax_id = reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; lldb::addr_t storage_addr = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff); return_valobj_sp = ValueObjectMemory::Create (&thread, "", Address (storage_addr, nullptr), return_clang_type); } return return_valobj_sp; }
static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, bool is_signed, Thread &thread, uint32_t *argument_register_ids, unsigned int ¤t_argument_register, addr_t ¤t_stack_argument) { if (bit_width > 64) return false; // Scalar can't hold large integer arguments if (current_argument_register < 6) { scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned( argument_register_ids[current_argument_register], 0); current_argument_register++; if (is_signed) scalar.SignExtend(bit_width); } else { uint32_t byte_size = (bit_width + (8 - 1)) / 8; Status error; if (thread.GetProcess()->ReadScalarIntegerFromMemory( current_stack_argument, byte_size, is_signed, scalar, error)) { current_stack_argument += byte_size; return true; } return false; } return true; }
bool ABIMacOSX_i386::GetArgumentValues (Thread &thread, ValueList &values) const { unsigned int num_values = values.GetSize(); unsigned int value_index; // Get the pointer to the first stack argument so we have a place to start // when reading data RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; addr_t sp = reg_ctx->GetSP(0); if (!sp) return false; addr_t current_stack_argument = sp + 4; // jump over return address for (value_index = 0; value_index < num_values; ++value_index) { Value *value = values.GetValueAtIndex(value_index); if (!value) return false; // We currently only support extracting values with Clang QualTypes. // Do we care about others? CompilerType compiler_type (value->GetCompilerType()); if (compiler_type) { bool is_signed; if (compiler_type.IsIntegerType (is_signed)) { ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), is_signed, thread.GetProcess().get(), current_stack_argument); } else if (compiler_type.IsPointerType()) { ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), false, thread.GetProcess().get(), current_stack_argument); } } } return true; }
UnwindLibUnwind::UnwindLibUnwind (Thread &thread, unw_addr_space_t addr_space) : Unwind (thread), m_addr_space (addr_space), m_cursors() { m_pc_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); m_sp_regnum = thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); }
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, Address &function, ValueList &args, bool stop_other_threads, bool discard_on_error) : ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), m_valid (false), m_stop_other_threads (stop_other_threads), m_arg_addr (0), m_args (&args), m_process (thread.GetProcess()), m_thread (thread) { SetOkayToDiscard (discard_on_error); Process& process = thread.GetProcess(); Target& target = process.GetTarget(); const ABI *abi = process.GetABI(); if(!abi) return; lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); SymbolContextList contexts; SymbolContext context; ModuleSP executableModuleSP (target.GetExecutableModule()); if (!executableModuleSP || !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts)) return; contexts.GetContextAtIndex(0, context); m_start_addr = context.symbol->GetValue(); lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&process); if(!thread.SaveFrameZeroState(m_register_backup)) return; m_function_addr = function; lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&process); if (!abi->PrepareNormalCall(thread, spBelowRedZone, FunctionLoadAddr, StartLoadAddr, *m_args)) return; m_valid = true; }
bool ABISysV_i386::GetArgumentValues (Thread &thread, ValueList &values) const { unsigned int num_values = values.GetSize(); unsigned int value_index; RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; // Get pointer to the first stack argument addr_t sp = reg_ctx->GetSP(0); if (!sp) return false; addr_t current_stack_argument = sp + 4; // jump over return address for (value_index = 0; value_index < num_values; ++value_index) { Value *value = values.GetValueAtIndex(value_index); if (!value) return false; // Currently: Support for extracting values with Clang QualTypes only. CompilerType clang_type (value->GetCompilerType()); if (clang_type) { bool is_signed; if (clang_type.IsIntegerType (is_signed)) { ReadIntegerArgument(value->GetScalar(), clang_type.GetBitSize(&thread), is_signed, thread.GetProcess().get(), current_stack_argument); } else if (clang_type.IsPointerType()) { ReadIntegerArgument(value->GetScalar(), clang_type.GetBitSize(&thread), false, thread.GetProcess().get(), current_stack_argument); } } } return true; }
bool UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly( AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0) return false; if (m_assembly_inspection_engine == nullptr) return false; ProcessSP process_sp(thread.GetProcess()); if (process_sp.get() == nullptr) return false; const bool prefer_file_cache = true; std::vector<uint8_t> function_text(func.GetByteSize()); Status error; if (process_sp->GetTarget().ReadMemory( func.GetBaseAddress(), prefer_file_cache, function_text.data(), func.GetByteSize(), error) == func.GetByteSize()) { RegisterContextSP reg_ctx(thread.GetRegisterContext()); m_assembly_inspection_engine->Initialize(reg_ctx); return m_assembly_inspection_engine->GetNonCallSiteUnwindPlanFromAssembly( function_text.data(), func.GetByteSize(), func, unwind_plan); } return false; }
bool ABISysV_i386::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef<addr_t> args) const { RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); // While using register info to write a register value to memory, the register info // just needs to have the correct size of a 32 bit register, the actual register it // pertains to is not important, just the size needs to be correct. // "eax" is used here for this purpose. const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax"); if (!reg_info_32) return false; // TODO this should actually never happen Error error; RegisterValue reg_value; // Make room for the argument(s) on the stack sp -= 4 * args.size(); // SP Alignment sp &= ~(16ull-1ull); // 16-byte alignment // Write arguments onto the stack addr_t arg_pos = sp; for (addr_t arg : args) { reg_value.SetUInt32(arg); error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, arg_pos, reg_info_32->byte_size, reg_value); if (error.Fail()) return false; arg_pos += 4; } // The return address is pushed onto the stack sp -= 4; reg_value.SetUInt32(return_addr); error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, sp, reg_info_32->byte_size, reg_value); if (error.Fail()) return false; // Setting %esp to the actual stack value. if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp)) return false; // Setting %eip to the address of the called function. if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, func_addr)) return false; return true; }
//---------------------------------------------------------------------- // ThreadPlanCallFunction: Plan to call a single function //---------------------------------------------------------------------- bool ThreadPlanCallFunction::ConstructorSetup (Thread &thread, ABI *& abi, lldb::addr_t &start_load_addr, lldb::addr_t &function_load_addr) { SetIsMasterPlan (true); SetOkayToDiscard (false); SetPrivate (true); ProcessSP process_sp (thread.GetProcess()); if (!process_sp) return false; abi = process_sp->GetABI().get(); if (!abi) return false; Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); SetBreakpoints(); m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); // If we can't read memory at the point of the process where we are planning to put our function, we're // not going to get any further... Error error; process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error); if (!error.Success()) { m_constructor_errors.Printf ("Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", m_function_sp); if (log) log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } Module *exe_module = GetTarget().GetExecutableModulePointer(); if (exe_module == NULL) { m_constructor_errors.Printf ("Can't execute code without an executable module."); if (log) log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } else { ObjectFile *objectFile = exe_module->GetObjectFile(); if (!objectFile) { m_constructor_errors.Printf ("Could not find object file for module \"%s\".", exe_module->GetFileSpec().GetFilename().AsCString()); if (log) log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } m_start_addr = objectFile->GetEntryPointAddress(); if (!m_start_addr.IsValid()) { m_constructor_errors.Printf ("Could not find entry point address for executable module \"%s\".", exe_module->GetFileSpec().GetFilename().AsCString()); if (log) log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } } start_load_addr = m_start_addr.GetLoadAddress (&GetTarget()); // Checkpoint the thread state so we can restore it later. if (log && log->GetVerbose()) ReportRegisterState ("About to checkpoint thread before function call. Original register state was:"); if (!thread.CheckpointThreadState (m_stored_thread_state)) { m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state."); if (log) log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } function_load_addr = m_function_addr.GetLoadAddress (&GetTarget()); return true; }
ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; if (!return_compiler_type) return return_valobj_sp; ExecutionContext exe_ctx(thread.shared_from_this()); return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); if (return_valobj_sp) return return_valobj_sp; RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); if (!reg_ctx_sp) return return_valobj_sp; const size_t bit_width = return_compiler_type.GetBitSize(&thread); if (return_compiler_type.IsAggregateType()) { Target *target = exe_ctx.GetTargetPtr(); bool is_memory = true; if (bit_width <= 128) { ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); DataBufferSP data_sp(new DataBufferHeap(16, 0)); DataExtractor return_ext(data_sp, target_byte_order, target->GetArchitecture().GetAddressByteSize()); const RegisterInfo *r3_info = reg_ctx_sp->GetRegisterInfoByName("r3", 0); const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0); RegisterValue r3_value, rdx_value; reg_ctx_sp->ReadRegister(r3_info, r3_value); reg_ctx_sp->ReadRegister(rdx_info, rdx_value); DataExtractor r3_data, rdx_data; r3_value.GetData(r3_data); rdx_value.GetData(rdx_data); uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far const uint32_t num_children = return_compiler_type.GetNumFields(); // Since we are in the small struct regime, assume we are not in memory. is_memory = false; for (uint32_t idx = 0; idx < num_children; idx++) { std::string name; uint64_t field_bit_offset = 0; bool is_signed; bool is_complex; uint32_t count; CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); const size_t field_bit_width = field_compiler_type.GetBitSize(&thread); // If there are any unaligned fields, this is stored in memory. if (field_bit_offset % field_bit_width != 0) { is_memory = true; break; } uint32_t field_byte_width = field_bit_width / 8; uint32_t field_byte_offset = field_bit_offset / 8; DataExtractor *copy_from_extractor = nullptr; uint32_t copy_from_offset = 0; if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || field_compiler_type.IsPointerType()) { if (integer_bytes < 8) { if (integer_bytes + field_byte_width <= 8) { // This is in RAX, copy from register to our result structure: copy_from_extractor = &r3_data; copy_from_offset = integer_bytes; integer_bytes += field_byte_width; } else { // The next field wouldn't fit in the remaining space, so we // pushed it to rdx. copy_from_extractor = &rdx_data; copy_from_offset = 0; integer_bytes = 8 + field_byte_width; } } else if (integer_bytes + field_byte_width <= 16) { copy_from_extractor = &rdx_data; copy_from_offset = integer_bytes - 8; integer_bytes += field_byte_width; } else { // The last field didn't fit. I can't see how that would happen w/o // the overall size being // greater than 16 bytes. For now, return a nullptr return value // object. return return_valobj_sp; } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { // Structs with long doubles are always passed in memory. if (field_bit_width == 128) { is_memory = true; break; } else if (field_bit_width == 64) { copy_from_offset = 0; fp_bytes += field_byte_width; } else if (field_bit_width == 32) { // This one is kind of complicated. If we are in an "eightbyte" // with another float, we'll // be stuffed into an xmm register with it. If we are in an // "eightbyte" with one or more ints, // then we will be stuffed into the appropriate GPR with them. bool in_gpr; if (field_byte_offset % 8 == 0) { // We are at the beginning of one of the eightbytes, so check the // next element (if any) if (idx == num_children - 1) in_gpr = false; else { uint64_t next_field_bit_offset = 0; CompilerType next_field_compiler_type = return_compiler_type.GetFieldAtIndex(idx + 1, name, &next_field_bit_offset, nullptr, nullptr); if (next_field_compiler_type.IsIntegerOrEnumerationType( is_signed)) in_gpr = true; else { copy_from_offset = 0; in_gpr = false; } } } else if (field_byte_offset % 4 == 0) { // We are inside of an eightbyte, so see if the field before us is // floating point: // This could happen if somebody put padding in the structure. if (idx == 0) in_gpr = false; else { uint64_t prev_field_bit_offset = 0; CompilerType prev_field_compiler_type = return_compiler_type.GetFieldAtIndex(idx - 1, name, &prev_field_bit_offset, nullptr, nullptr); if (prev_field_compiler_type.IsIntegerOrEnumerationType( is_signed)) in_gpr = true; else { copy_from_offset = 4; in_gpr = false; } } } else { is_memory = true; continue; } // Okay, we've figured out whether we are in GPR or XMM, now figure // out which one. if (in_gpr) { if (integer_bytes < 8) { // This is in RAX, copy from register to our result structure: copy_from_extractor = &r3_data; copy_from_offset = integer_bytes; integer_bytes += field_byte_width; } else { copy_from_extractor = &rdx_data; copy_from_offset = integer_bytes - 8; integer_bytes += field_byte_width; } } else { fp_bytes += field_byte_width; } } } // These two tests are just sanity checks. If I somehow get the // type calculation wrong above it is better to just return nothing // than to assert or crash. if (!copy_from_extractor) return return_valobj_sp; if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize()) return return_valobj_sp; copy_from_extractor->CopyByteOrderedData( copy_from_offset, field_byte_width, data_sp->GetBytes() + field_byte_offset, field_byte_width, target_byte_order); } if (!is_memory) { // The result is in our data buffer. Let's make a variable object out // of it: return_valobj_sp = ValueObjectConstResult::Create( &thread, return_compiler_type, ConstString(""), return_ext); } } // FIXME: This is just taking a guess, r3 may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should // check to see if it uses a memory // return, and if we are at the first instruction and if so stash away the // return location. Then we would // only return the memory return value if we know it is valid. if (is_memory) { unsigned r3_id = reg_ctx_sp->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); return_valobj_sp = ValueObjectMemory::Create( &thread, "", Address(storage_addr, nullptr), return_compiler_type); } } return return_valobj_sp; }
ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; Value value; if (!return_compiler_type) return return_valobj_sp; // value.SetContext (Value::eContextTypeClangType, return_value_type); value.SetCompilerType(return_compiler_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { value.SetValueType(Value::eValueTypeScalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers. llvm::Optional<uint64_t> byte_size = return_compiler_type.GetByteSize(nullptr); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r2", 0), 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; switch (*byte_size) { default: break; case sizeof(uint64_t): if (is_signed) value.GetScalar() = (int64_t)(raw_value); else value.GetScalar() = (uint64_t)(raw_value); success = true; break; case sizeof(uint32_t): if (is_signed) value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); else value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); success = true; break; case sizeof(uint16_t): if (is_signed) value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); else value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); success = true; break; case sizeof(uint8_t): if (is_signed) value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); else value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); success = true; break; } } else if (type_flags & eTypeIsFloat) { if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { llvm::Optional<uint64_t> byte_size = return_compiler_type.GetByteSize(nullptr); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; if (reg_ctx->ReadRegister(f0_info, f0_value)) { DataExtractor data; if (f0_value.GetData(data)) { lldb::offset_t offset = 0; if (*byte_size == sizeof(float)) { value.GetScalar() = (float)data.GetFloat(&offset); success = true; } else if (*byte_size == sizeof(double)) { value.GetScalar() = (double)data.GetDouble(&offset); success = true; } else if (*byte_size == sizeof(long double)) { // Don't handle long double yet. } } } } } } if (success) return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsPointer) { unsigned r2_id = reg_ctx->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); value.SetValueType(Value::eValueTypeScalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } return return_valobj_sp; }
bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { bool do_augment_unwindplan = true; UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset(0); UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset(-1); int wordsize = 8; ProcessSP process_sp(thread.GetProcess()); if (process_sp.get() == nullptr) return false; wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize(); RegisterNumber sp_regnum(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); RegisterNumber pc_regnum(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); // Does this UnwindPlan describe the prologue? I want to see that the CFA is // set in terms of the stack pointer plus an offset, and I want to see that // rip is retrieved at the CFA-wordsize. If there is no description of the // prologue, don't try to augment this eh_frame unwinder code, fall back to // assembly parsing instead. if (first_row->GetCFAValue().GetValueType() != UnwindPlan::Row::FAValue::isRegisterPlusOffset || RegisterNumber(thread, unwind_plan.GetRegisterKind(), first_row->GetCFAValue().GetRegisterNumber()) != sp_regnum || first_row->GetCFAValue().GetOffset() != wordsize) { return false; } UnwindPlan::Row::RegisterLocation first_row_pc_loc; if (!first_row->GetRegisterInfo( pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), first_row_pc_loc) || !first_row_pc_loc.IsAtCFAPlusOffset() || first_row_pc_loc.GetOffset() != -wordsize) { return false; } // It looks like the prologue is described. Is the epilogue described? If it // is, no need to do any augmentation. if (first_row != last_row && first_row->GetOffset() != last_row->GetOffset()) { // The first & last row have the same CFA register and the same CFA offset // value and the CFA register is esp/rsp (the stack pointer). // We're checking that both of them have an unwind rule like "CFA=esp+4" or // CFA+rsp+8". if (first_row->GetCFAValue().GetValueType() == last_row->GetCFAValue().GetValueType() && first_row->GetCFAValue().GetRegisterNumber() == last_row->GetCFAValue().GetRegisterNumber() && first_row->GetCFAValue().GetOffset() == last_row->GetCFAValue().GetOffset()) { // Get the register locations for eip/rip from the first & last rows. Are // they both CFA plus an offset? Is it the same offset? UnwindPlan::Row::RegisterLocation last_row_pc_loc; if (last_row->GetRegisterInfo( pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()), last_row_pc_loc)) { if (last_row_pc_loc.IsAtCFAPlusOffset() && first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) { // One last sanity check: Is the unwind rule for getting the caller // pc value "deref the CFA-4" or "deref the CFA-8"? // If so, we have an UnwindPlan that already describes the epilogue // and we don't need to modify it at all. if (first_row_pc_loc.GetOffset() == -wordsize) { do_augment_unwindplan = false; } } } } } if (do_augment_unwindplan) { if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0) return false; if (m_assembly_inspection_engine == nullptr) return false; const bool prefer_file_cache = true; std::vector<uint8_t> function_text(func.GetByteSize()); Status error; if (process_sp->GetTarget().ReadMemory( func.GetBaseAddress(), prefer_file_cache, function_text.data(), func.GetByteSize(), error) == func.GetByteSize()) { RegisterContextSP reg_ctx(thread.GetRegisterContext()); m_assembly_inspection_engine->Initialize(reg_ctx); return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite( function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx); } } return false; }
ThreadPlanSP ObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool stop_others) { ThreadPlanSP ret_plan_sp; lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); MsgsendMap::iterator pos; pos = m_msgSend_map.find (curr_pc); if (pos != m_msgSend_map.end()) { Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); const DispatchFunction *this_dispatch = &g_dispatch_functions[(*pos).second]; lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); Process *process = thread.CalculateProcess(); const ABI *abi = process->GetABI(); if (abi == NULL) return ret_plan_sp; Target *target = thread.CalculateTarget(); // FIXME: Since neither the value nor the Clang QualType know their ASTContext, // we have to make sure the type we put in our value list comes from the same ASTContext // the ABI will use to get the argument values. THis is the bottom-most frame's module. ClangASTContext *clang_ast_context = target->GetScratchClangASTContext(); ValueList argument_values; Value input_value; void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false); input_value.SetValueType (Value::eValueTypeScalar); input_value.SetContext (Value::eContextTypeOpaqueClangQualType, clang_void_ptr_type); int obj_index; int sel_index; // If this is a struct return dispatch, then the first argument is the // return struct pointer, and the object is the second, and the selector is the third. // Otherwise the object is the first and the selector the second. if (this_dispatch->stret_return) { obj_index = 1; sel_index = 2; argument_values.PushValue(input_value); argument_values.PushValue(input_value); argument_values.PushValue(input_value); } else { obj_index = 0; sel_index = 1; argument_values.PushValue(input_value); argument_values.PushValue(input_value); } bool success = abi->GetArgumentValues (thread, argument_values); if (!success) return ret_plan_sp; // Okay, the first value here is the object, we actually want the class of that object. // For now we're just going with the ISA. // FIXME: This should really be the return value of [object class] to properly handle KVO interposition. Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); // This is a little cheesy, but since object->isa is the first field, // making the object value a load address value and resolving it will get // the pointer sized data pointed to by that value... ExecutionContext exec_ctx; thread.Calculate (exec_ctx); isa_value.SetValueType(Value::eValueTypeLoadAddress); isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext()); if (this_dispatch->fixedup == DispatchFunction::eFixUpFixed) { // For the FixedUp method the Selector is actually a pointer to a // structure, the second field of which is the selector number. Value *sel_value = argument_values.GetValueAtIndex(sel_index); sel_value->GetScalar() += process->GetAddressByteSize(); sel_value->SetValueType(Value::eValueTypeLoadAddress); sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext()); } else if (this_dispatch->fixedup == DispatchFunction::eFixUpToFix) { // FIXME: If the method dispatch is not "fixed up" then the selector is actually a // pointer to the string name of the selector. We need to look that up... // For now I'm going to punt on that and just return no plan. if (log) log->Printf ("Punting on stepping into un-fixed-up method dispatch."); return ret_plan_sp; } // FIXME: If this is a dispatch to the super-class, we need to get the super-class from // the class, and disaptch to that instead. // But for now I just punt and return no plan. if (this_dispatch->is_super) { if (log) log->Printf ("Punting on stepping into super method dispatch."); return ret_plan_sp; } ValueList dispatch_values; dispatch_values.PushValue (isa_value); dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index))); if (log) { log->Printf("Resolving method call for class - 0x%llx and selector - 0x%llx", dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong()); } lldb::addr_t impl_addr = LookupInCache (dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong()); if (impl_addr == LLDB_INVALID_ADDRESS) { Address resolve_address(NULL, this_dispatch->stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr); StreamString errors; { // Scope for mutex locker: Mutex::Locker locker(m_impl_function_mutex); if (!m_impl_function.get()) { m_impl_function.reset(new ClangFunction(process->GetTargetTriple().GetCString(), clang_ast_context, clang_void_ptr_type, resolve_address, dispatch_values)); unsigned num_errors = m_impl_function->CompileFunction(errors); if (num_errors) { if (log) log->Printf ("Error compiling function: \"%s\".", errors.GetData()); return ret_plan_sp; } errors.Clear(); if (!m_impl_function->WriteFunctionWrapper(exec_ctx, errors)) { if (log) log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); return ret_plan_sp; } } } errors.Clear(); // Now write down the argument values for this call. lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; if (!m_impl_function->WriteFunctionArguments (exec_ctx, args_addr, resolve_address, dispatch_values, errors)) return ret_plan_sp; ret_plan_sp.reset (new ThreadPlanStepThroughObjCTrampoline (thread, this, args_addr, argument_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(), dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(), stop_others)); } else { if (log) log->Printf ("Found implementation address in cache: 0x%llx", impl_addr); ret_plan_sp.reset (new ThreadPlanRunToAddress (thread, impl_addr, stop_others)); } } return ret_plan_sp; }
bool ABISysV_mips::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef<addr_t> args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); if (log) { StreamString s; s.Printf("ABISysV_mips::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, (uint64_t)return_addr); for (size_t i = 0; i < args.size(); ++i) s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]); s.PutCString (")"); log->PutCString(s.GetString().c_str()); } RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const RegisterInfo *reg_info = NULL; RegisterValue reg_value; // Argument registers const char *reg_names[] = { "r4", "r5", "r6", "r7" }; llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end(); // Write arguments to registers for (size_t i = 0; i < llvm::array_lengthof(reg_names); ++i) { if (ai == ae) break; reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; ++ai; } // If we have more than 4 arguments --Spill onto the stack if (ai != ae) { // No of arguments to go on stack size_t num_stack_regs = args.size(); // Allocate needed space for args on the stack sp -= (num_stack_regs * 4); // Keep the stack 8 byte aligned sp &= ~(8ull-1ull); // just using arg1 to get the right size const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); addr_t arg_pos = sp+16; size_t i = 4; for (; ai != ae; ++ai) { reg_value.SetUInt32(*ai); if (log) log->Printf("About to write arg%zd (0x%" PRIx64 ") at 0x%" PRIx64 "", i+1, args[i], arg_pos); if (reg_ctx->WriteRegisterValueToMemory(reg_info, arg_pos, reg_info->byte_size, reg_value).Fail()) return false; arg_pos += reg_info->byte_size; i++; } } Error error; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); // Set "sp" to the requested value if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp)) return false; if (log) log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr); // Set "ra" to the return address if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_info, return_addr)) return false; if (log) log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr); // Set pc to the address of the called function. if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) return false; return true; }
bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef<addr_t> args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) { StreamString s; s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, (uint64_t)return_addr); for (size_t i = 0; i < args.size(); ++i) s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]); s.PutCString(")"); log->PutString(s.GetString()); } RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const RegisterInfo *reg_info = nullptr; if (args.size() > 8) // TODO handle more than 8 arguments return false; for (size_t i = 0; i < args.size(); ++i) { reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name); if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; } // First, align the SP if (log) log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull)); sp &= ~(0xfull); // 16-byte alignment sp -= 8; Status error; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); ProcessSP process_sp(thread.GetProcess()); RegisterValue reg_value; if (log) log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); // Save return address onto the stack if (!process_sp->WritePointerToMemory(sp, return_addr, error)) return false; // %r1 is set to the actual stack value. if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) return false; // %pc is set to the address of the called function. if (log) log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr); if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) return false; return true; }
void ArchitectureArm::OverrideStopInfo(Thread &thread) { // We need to check if we are stopped in Thumb mode in a IT instruction // and detect if the condition doesn't pass. If this is the case it means // we won't actually execute this instruction. If this happens we need to // clear the stop reason to no thread plans think we are stopped for a // reason and the plans should keep going. // // We do this because when single stepping many ARM processes, debuggers // often use the BVR/BCR registers that says "stop when the PC is not // equal to its current value". This method of stepping means we can end // up stopping on instructions inside an if/then block that wouldn't get // executed. By fixing this we can stop the debugger from seeming like // you stepped through both the "if" _and_ the "else" clause when source // level stepping because the debugger stops regardless due to the BVR/BCR // triggering a stop. // // It also means we can set breakpoints on instructions inside an an // if/then block and correctly skip them if we use the BKPT instruction. // The ARM and Thumb BKPT instructions are unconditional even when executed // in a Thumb IT block. // // If your debugger inserts software traps in ARM/Thumb code, it will // need to use 16 and 32 bit instruction for 16 and 32 bit thumb // instructions respectively. If your debugger inserts a 16 bit thumb // trap on top of a 32 bit thumb instruction for an opcode that is inside // an if/then, it will change the it/then to conditionally execute your // 16 bit trap and then cause your program to crash if it executes the // trailing 16 bits (the second half of the 32 bit thumb instruction you // partially overwrote). RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); if (!reg_ctx_sp) return; const uint32_t cpsr = reg_ctx_sp->GetFlags(0); if (cpsr == 0) return; // Read the J and T bits to get the ISETSTATE const uint32_t J = Bit32(cpsr, 24); const uint32_t T = Bit32(cpsr, 5); const uint32_t ISETSTATE = J << 1 | T; if (ISETSTATE == 0) { // NOTE: I am pretty sure we want to enable the code below // that detects when we stop on an instruction in ARM mode // that is conditional and the condition doesn't pass. This // can happen if you set a breakpoint on an instruction that // is conditional. We currently will _always_ stop on the // instruction which is bad. You can also run into this while // single stepping and you could appear to run code in the "if" // and in the "else" clause because it would stop at all of the // conditional instructions in both. // In such cases, we really don't want to stop at this location. // I will check with the lldb-dev list first before I enable this. #if 0 // ARM mode: check for condition on intsruction const addr_t pc = reg_ctx_sp->GetPC(); Status error; // If we fail to read the opcode we will get UINT64_MAX as the // result in "opcode" which we can use to detect if we read a // valid opcode. const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error); if (opcode <= UINT32_MAX) { const uint32_t condition = Bits32((uint32_t)opcode, 31, 28); if (!ARMConditionPassed(condition, cpsr)) { // We ARE stopped on an ARM instruction whose condition doesn't // pass so this instruction won't get executed. // Regardless of why it stopped, we need to clear the stop info thread.SetStopInfo (StopInfoSP()); } } #endif } else if (ISETSTATE == 1) { // Thumb mode const uint32_t ITSTATE = Bits32(cpsr, 15, 10) << 2 | Bits32(cpsr, 26, 25); if (ITSTATE != 0) { const uint32_t condition = Bits32(ITSTATE, 7, 4); if (!ARMConditionPassed(condition, cpsr)) { // We ARE stopped in a Thumb IT instruction on an instruction whose // condition doesn't pass so this instruction won't get executed. // Regardless of why it stopped, we need to clear the stop info thread.SetStopInfo(StopInfoSP()); } } } }
bool ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, lldb::addr_t sp , lldb::addr_t pc , lldb::addr_t ra , llvm::Type &prototype, llvm::ArrayRef<ABI::CallArgument> args) const { // default number of register passed arguments for varg functions const int nVArgRegParams = 1; Error error; // grab the process so we have access to the memory for spilling lldb::ProcessSP proc = thread.GetProcess( ); // push host data onto target for ( size_t i = 0; i < args.size( ); i++ ) { const ABI::CallArgument &arg = args[i]; // skip over target values if ( arg.type == ABI::CallArgument::TargetValue ) continue; // round up to 8 byte multiple size_t argSize = ( arg.size | 0x7 ) + 1; // create space on the stack for this data sp -= argSize; // write this argument onto the stack of the host process proc.get( )->WriteMemory( sp, arg.data, arg.size, error ); if ( error.Fail( ) ) return false; // update the argument with the target pointer //XXX: This is a gross hack for getting around the const *((size_t*)(&arg.value)) = sp; } #if HEX_ABI_DEBUG // print the original stack pointer printf( "sp : %04lx \n", sp ); #endif // make sure number of parameters matches prototype assert( prototype.getFunctionNumParams( ) == args.size( ) ); // check if this is a variable argument function bool isVArg = prototype.isFunctionVarArg(); // get the register context for modifying all of the registers RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; // number of arguments passed by register int nRegArgs = nVArgRegParams; if (! isVArg ) { // number of arguments is limited by [R0 : R5] space nRegArgs = args.size( ); if ( nRegArgs > 6 ) nRegArgs = 6; } // pass arguments that are passed via registers for ( int i = 0; i < nRegArgs; i++ ) { // get the parameter as a u32 uint32_t param = (uint32_t)args[i].value; // write argument into register if (!reg_ctx->WriteRegisterFromUnsigned( i, param )) return false; } // number of arguments to spill onto stack int nSpillArgs = args.size( ) - nRegArgs; // make space on the stack for arguments sp -= 4 * nSpillArgs; // align stack on an 8 byte boundary if ( sp & 7 ) sp -= 4; // arguments that are passed on the stack for ( size_t i = nRegArgs, offs=0; i < args.size( ); i++ ) { // get the parameter as a u32 uint32_t param = (uint32_t)args[i].value; // write argument to stack proc->WriteMemory( sp + offs, (void*)¶m, sizeof( param ), error ); if ( !error.Success( ) ) return false; // offs += 4; } // update registers with current function call state reg_ctx->WriteRegisterFromUnsigned ( 41, pc ); reg_ctx->WriteRegisterFromUnsigned ( 31, ra ); reg_ctx->WriteRegisterFromUnsigned ( 29, sp ); // reg_ctx->WriteRegisterFromUnsigned ( FP ??? ); #if HEX_ABI_DEBUG // quick and dirty stack dumper for debugging for ( int i = -8; i < 8; i++ ) { uint32_t data = 0; lldb::addr_t addr = sp + i * 4; proc->ReadMemory( addr, (void*)&data, sizeof( data ), error ); printf( "\n0x%04lx 0x%08x ", addr, data ); if ( i == 0 ) printf( "<<-- sp" ); } printf( "\n" ); #endif return true; }
bool ABISysV_ppc::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef<addr_t> args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); if (log) { StreamString s; s.Printf("ABISysV_ppc::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, (uint64_t)return_addr); for (size_t i = 0; i < args.size(); ++i) s.Printf (", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]); s.PutCString (")"); log->PutCString(s.GetString().c_str()); } RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const RegisterInfo *reg_info = NULL; if (args.size() > 8) // TODO handle more than 8 arguments return false; for (size_t i = 0; i < args.size(); ++i) { reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name); if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; } // First, align the SP if (log) log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull)); sp &= ~(0xfull); // 16-byte alignment sp -= 8; Error error; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); ProcessSP process_sp (thread.GetProcess()); RegisterValue reg_value; #if 0 // This code adds an extra frame so that we don't lose the function that we came from // by pushing the PC and the FP and then writing the current FP to point to the FP value // we just pushed. It is disabled for now until the stack backtracing code can be debugged. // Save current PC const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); if (reg_ctx->ReadRegister(pc_reg_info, reg_value)) { if (log) log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) return false; sp -= 8; // Save current FP if (reg_ctx->ReadRegister(fp_reg_info, reg_value)) { if (log) log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64()); if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error)) return false; } // Setup FP backchain reg_value.SetUInt64 (sp); if (log) log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64()); if (!reg_ctx->WriteRegister(fp_reg_info, reg_value)) { return false; } sp -= 8; } #endif if (log) log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); // Save return address onto the stack if (!process_sp->WritePointerToMemory(sp, return_addr, error)) return false; // %r1 is set to the actual stack value. if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp)) return false; // %pc is set to the address of the called function. if (log) log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr); if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) return false; return true; }
ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple (Thread &thread, CompilerType &return_clang_type) const { ValueObjectSP return_valobj_sp; Value value; if (!return_clang_type) return return_valobj_sp; value.SetCompilerType (return_clang_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; const uint32_t type_flags = return_clang_type.GetTypeInfo (); unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB]; // Following "IF ELSE" block categorizes various 'Fundamental Data Types'. // The terminology 'Fundamental Data Types' used here is adopted from // Table 2.1 of the reference document (specified on top of this file) if (type_flags & eTypeIsPointer) // 'Pointer' { uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ; value.SetValueType(Value::eValueTypeScalar); value.GetScalar() = ptr; return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if ((type_flags & eTypeIsScalar) || (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' { value.SetValueType(Value::eValueTypeScalar); const size_t byte_size = return_clang_type.GetByteSize(nullptr); bool success = false; if (type_flags & eTypeIsInteger) // 'Integral' except enum { const bool is_signed = ((type_flags & eTypeIsSigned) != 0); uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ; raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32; switch (byte_size) { default: break; case 16: // For clang::BuiltinType::UInt128 & Int128 // ToDo: Need to decide how to handle it break ; case 8: if (is_signed) value.GetScalar() = (int64_t)(raw_value); else value.GetScalar() = (uint64_t)(raw_value); success = true; break; case 4: if (is_signed) value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); else value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); success = true; break; case 2: if (is_signed) value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); else value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); success = true; break; case 1: if (is_signed) value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); else value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); success = true; break; } if (success) return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsEnumeration) // handles enum { uint32_t enm = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff ; value.SetValueType(Value::eValueTypeScalar); value.GetScalar() = enm; return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsFloat) // 'Floating Point' { if (byte_size <= 12) // handles float, double, long double, __float80 { const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0); RegisterValue st0_value; if (reg_ctx->ReadRegister (st0_info, st0_value)) { DataExtractor data; if (st0_value.GetData(data)) { lldb::offset_t offset = 0; long double value_long_double = data.GetLongDouble(&offset); if (byte_size == 4) // float is 4 bytes { float value_float = (float)value_long_double; value.GetScalar() = value_float; success = true; } else if (byte_size == 8) // double is 8 bytes { // On Android Platform: long double is also 8 bytes // It will be handled here only. double value_double = (double)value_long_double; value.GetScalar() = value_double; success = true; } else if (byte_size == 12) // long double and __float80 are 12 bytes on i386 { value.GetScalar() = value_long_double; success = true; } } } if (success) return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if(byte_size == 16) // handles __float128 { lldb::addr_t storage_addr = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff); return_valobj_sp = ValueObjectMemory::Create (&thread, "", Address (storage_addr, nullptr), return_clang_type); } } else // Neither 'Integral' nor 'Floating Point' { // If flow reaches here then check type_flags // This type_flags is unhandled } } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point' { // ToDo: Yet to be implemented } else if (type_flags & eTypeIsVector) // 'Packed' { const size_t byte_size = return_clang_type.GetByteSize(nullptr); if (byte_size > 0) { const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); if (vec_reg == nullptr) vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); if (vec_reg) { if (byte_size <= vec_reg->byte_size) { ProcessSP process_sp (thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(vec_reg, reg_value)) { Error error; if (reg_value.GetAsMemoryData (vec_reg, heap_data_ap->GetBytes(), heap_data_ap->GetByteSize(), byte_order, error)) { DataExtractor data (DataBufferSP (heap_data_ap.release()), byte_order, process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); return_valobj_sp = ValueObjectConstResult::Create (&thread, return_clang_type, ConstString(""), data); } } } } else if (byte_size <= vec_reg->byte_size*2) { const RegisterInfo *vec_reg2 = reg_ctx->GetRegisterInfoByName("xmm1", 0); if (vec_reg2) { ProcessSP process_sp (thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; RegisterValue reg_value2; if (reg_ctx->ReadRegister(vec_reg, reg_value) && reg_ctx->ReadRegister(vec_reg2, reg_value2)) { Error error; if (reg_value.GetAsMemoryData (vec_reg, heap_data_ap->GetBytes(), vec_reg->byte_size, byte_order, error) && reg_value2.GetAsMemoryData (vec_reg2, heap_data_ap->GetBytes() + vec_reg->byte_size, heap_data_ap->GetByteSize() - vec_reg->byte_size, byte_order, error)) { DataExtractor data (DataBufferSP (heap_data_ap.release()), byte_order, process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); return_valobj_sp = ValueObjectConstResult::Create (&thread, return_clang_type, ConstString(""), data); } } } } } } } } else // 'Decimal Floating Point' { //ToDo: Yet to be implemented } return return_valobj_sp; }
bool ABISysV_s390x::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef<addr_t> args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) { StreamString s; s.Printf("ABISysV_s390x::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, (uint64_t)return_addr); for (size_t i = 0; i < args.size(); ++i) s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]); s.PutCString(")"); log->PutString(s.GetString()); } RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfoByName("r14", 0); ProcessSP process_sp(thread.GetProcess()); // Allocate a new stack frame and space for stack arguments if necessary addr_t arg_pos = 0; if (args.size() > 5) { sp -= 8 * (args.size() - 5); arg_pos = sp; } sp -= 160; // Process arguments for (size_t i = 0; i < args.size(); ++i) { if (i < 5) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name); if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; } else { Status error; if (log) log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") onto stack", static_cast<uint64_t>(i + 1), args[i]); if (!process_sp->WritePointerToMemory(arg_pos, args[i], error)) return false; arg_pos += 8; } } // %r14 is set to the return address if (log) log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr); if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr)) return false; // %r15 is set to the actual stack value. if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) return false; // %pc is set to the address of the called function. if (log) log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr); if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) return false; return true; }
ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_clang_type) const { ValueObjectSP return_valobj_sp; Value value; if (!return_clang_type) return return_valobj_sp; ExecutionContext exe_ctx (thread.shared_from_this()); if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL) return return_valobj_sp; value.SetCompilerType(return_clang_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; bool is_signed = false; bool is_complex = false; uint32_t count = 0; // In MIPS register "r2" (v0) holds the integer function return values const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0); size_t bit_width = return_clang_type.GetBitSize(&thread); if (return_clang_type.IsIntegerType (is_signed)) { switch (bit_width) { default: return return_valobj_sp; case 64: { const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); uint64_t raw_value; raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX; raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0) & UINT32_MAX)) << 32; if (is_signed) value.GetScalar() = (int64_t)raw_value; else value.GetScalar() = (uint64_t)raw_value; } break; case 32: if (is_signed) value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX); else value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX); break; case 16: if (is_signed) value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX); else value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX); break; case 8: if (is_signed) value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX); else value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX); break; } } else if (return_clang_type.IsPointerType ()) { uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX; value.GetScalar() = ptr; } else if (return_clang_type.IsAggregateType ()) { // Structure/Vector is always passed in memory and pointer to that memory is passed in r2. uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 0); // We have got the address. Create a memory object out of it return_valobj_sp = ValueObjectMemory::Create (&thread, "", Address (mem_address, NULL), return_clang_type); return return_valobj_sp; } else if (return_clang_type.IsFloatingPointType (count, is_complex)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); if (count == 1 && !is_complex) { switch (bit_width) { default: return return_valobj_sp; case 64: { static_assert(sizeof(double) == sizeof(uint64_t), ""); uint64_t raw_value; raw_value = reg_ctx->ReadRegisterAsUnsigned(f0_info, 0) & UINT32_MAX; raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(f1_info, 0) & UINT32_MAX)) << 32; value.GetScalar() = *reinterpret_cast<double*>(&raw_value); break; } case 32: { static_assert(sizeof(float) == sizeof(uint32_t), ""); uint32_t raw_value = reg_ctx->ReadRegisterAsUnsigned(f0_info, 0) & UINT32_MAX; value.GetScalar() = *reinterpret_cast<float*>(&raw_value); break; } } } else { // not handled yet return return_valobj_sp; } } else { // not handled yet return return_valobj_sp; } // If we get here, we have a valid Value, so make our ValueObject out of it: return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); return return_valobj_sp; }
StopInfoSP StopInfoMachException::CreateStopReasonWithMachException ( Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, bool pc_already_adjusted, bool adjust_pc_if_needed ) { if (exc_type != 0) { uint32_t pc_decrement = 0; ExecutionContext exe_ctx (thread.shared_from_this()); Target *target = exe_ctx.GetTargetPtr(); const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch; switch (exc_type) { case 1: // EXC_BAD_ACCESS break; case 2: // EXC_BAD_INSTRUCTION switch (cpu) { case llvm::Triple::ppc: case llvm::Triple::ppc64: switch (exc_code) { case 1: // EXC_PPC_INVALID_SYSCALL case 2: // EXC_PPC_UNIPL_INST case 3: // EXC_PPC_PRIVINST case 4: // EXC_PPC_PRIVREG break; case 5: // EXC_PPC_TRACE return StopInfo::CreateStopReasonToTrace (thread); case 6: // EXC_PPC_PERFMON break; } break; default: break; } break; case 3: // EXC_ARITHMETIC case 4: // EXC_EMULATION break; case 5: // EXC_SOFTWARE if (exc_code == 0x10003) // EXC_SOFT_SIGNAL return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code); break; case 6: // EXC_BREAKPOINT { bool is_software_breakpoint = false; bool is_trace_if_software_breakpoint_missing = false; switch (cpu) { case llvm::Triple::x86: case llvm::Triple::x86_64: if (exc_code == 1) // EXC_I386_SGL { if (!exc_sub_code) return StopInfo::CreateStopReasonToTrace(thread); // It's a watchpoint, then. // The exc_sub_code indicates the data break address. lldb::WatchpointSP wp_sp; if (target) wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. // Set the hardware index if that's the case. if (exc_data_count >=3) wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } } else if (exc_code == 2 || // EXC_I386_BPT exc_code == 3) // EXC_I386_BPTFLT { // KDP returns EXC_I386_BPTFLT for trace breakpoints if (exc_code == 3) is_trace_if_software_breakpoint_missing = true; is_software_breakpoint = true; if (!pc_already_adjusted) pc_decrement = 1; } break; case llvm::Triple::ppc: case llvm::Triple::ppc64: is_software_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT break; case llvm::Triple::arm: if (exc_code == 0x102) { // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled // data break address from our watchpoint list. lldb::WatchpointSP wp_sp; if (target) wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); if (wp_sp && wp_sp->IsEnabled()) { // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. // Set the hardware index if that's the case. if (exc_data_count >=3) wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS if (thread.GetTemporaryResumeState() == eStateStepping) return StopInfo::CreateStopReasonToTrace(thread); } else if (exc_code == 1) { is_software_breakpoint = true; is_trace_if_software_breakpoint_missing = true; } break; default: break; } if (is_software_breakpoint) { RegisterContextSP reg_ctx_sp (thread.GetRegisterContext()); addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; ProcessSP process_sp (thread.CalculateProcess()); lldb::BreakpointSiteSP bp_site_sp; if (process_sp) bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp && bp_site_sp->IsEnabled()) { // Update the PC if we were asked to do so, but only do // so if we find a breakpoint that we know about cause // this could be a trap instruction in the code if (pc_decrement > 0 && adjust_pc_if_needed) reg_ctx_sp->SetPC (pc); // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. if (bp_site_sp->ValidForThisThread (&thread)) return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID()); else return StopInfoSP(); } // Don't call this a trace if we weren't single stepping this thread. if (is_trace_if_software_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping) { return StopInfo::CreateStopReasonToTrace (thread); } } } break; case 7: // EXC_SYSCALL case 8: // EXC_MACH_SYSCALL case 9: // EXC_RPC_ALERT case 10: // EXC_CRASH break; } return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code)); } return StopInfoSP(); }
bool ABIMacOSX_arm::GetArgumentValues (Thread &thread, ValueList &values) const { uint32_t num_values = values.GetSize(); ExecutionContext exe_ctx (thread.shared_from_this()); // For now, assume that the types in the AST values come from the Target's // scratch AST. clang::ASTContext *ast_context = exe_ctx.GetTargetRef().GetScratchClangASTContext()->getASTContext(); // Extract the register context so we can read arguments from registers RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; addr_t sp = reg_ctx->GetSP(0); if (!sp) return false; for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) { // We currently only support extracting values with Clang QualTypes. // Do we care about others? Value *value = values.GetValueAtIndex(value_idx); if (!value) return false; void *value_type = value->GetClangType(); if (value_type) { bool is_signed = false; size_t bit_width = 0; if (ClangASTContext::IsIntegerType (value_type, is_signed)) { bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type); } else if (ClangASTContext::IsPointerOrReferenceType (value_type)) { bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type); } else { // We only handle integer, pointer and reference types currently... return false; } if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) { if (value_idx < 4) { // Arguments 1-4 are in r0-r3... const RegisterInfo *arg_reg_info = NULL; // Search by generic ID first, then fall back to by name uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); if (arg_reg_num != LLDB_INVALID_REGNUM) { arg_reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num); } else { switch (value_idx) { case 0: arg_reg_info = reg_ctx->GetRegisterInfoByName("r0"); break; case 1: arg_reg_info = reg_ctx->GetRegisterInfoByName("r1"); break; case 2: arg_reg_info = reg_ctx->GetRegisterInfoByName("r2"); break; case 3: arg_reg_info = reg_ctx->GetRegisterInfoByName("r3"); break; } } if (arg_reg_info) { RegisterValue reg_value; if (reg_ctx->ReadRegister(arg_reg_info, reg_value)) { if (is_signed) reg_value.SignExtend(bit_width); if (!reg_value.GetScalarValue(value->GetScalar())) return false; continue; } } return false; } else { // Arguments 5 on up are on the stack const uint32_t arg_byte_size = (bit_width + (8-1)) / 8; Error error; if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error)) return false; sp += arg_byte_size; } } } } return true; }
Error ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) { Error error; if (!new_value_sp) { error.SetErrorString("Empty value object for return value."); return error; } CompilerType clang_type = new_value_sp->GetCompilerType(); if (!clang_type) { error.SetErrorString ("Null clang type for return value."); return error; } Thread *thread = frame_sp->GetThread().get(); bool is_signed; uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); bool set_it_simple = false; if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType()) { DataExtractor data; Error data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); if (data_error.Fail()) { error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); return error; } lldb::offset_t offset = 0; if (num_bytes <= 8) { const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0); if (num_bytes <= 4) { uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value)) set_it_simple = true; } else { uint32_t raw_value = data.GetMaxU32(&offset, 4); if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value)) { const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0); uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset); if (reg_ctx->WriteRegisterFromUnsigned (r3_info, raw_value)) set_it_simple = true; } } } else { error.SetErrorString("We don't support returning longer than 64 bit integer values at present."); } } else if (clang_type.IsFloatingPointType (count, is_complex)) { if (is_complex) error.SetErrorString ("We don't support returning complex values at present"); else error.SetErrorString ("We don't support returning float values at present"); } if (!set_it_simple) error.SetErrorString ("We only support setting simple integer return types at present."); return error; }
bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const { unsigned int num_values = values.GetSize(); unsigned int value_index; // Extract the register context so we can read arguments from registers RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; // Get the pointer to the first stack argument so we have a place to start // when reading data addr_t sp = reg_ctx->GetSP(0); if (!sp) return false; addr_t current_stack_argument = sp + 48; // jump over return address uint32_t argument_register_ids[8]; argument_register_ids[0] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1) ->kinds[eRegisterKindLLDB]; argument_register_ids[1] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2) ->kinds[eRegisterKindLLDB]; argument_register_ids[2] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3) ->kinds[eRegisterKindLLDB]; argument_register_ids[3] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4) ->kinds[eRegisterKindLLDB]; argument_register_ids[4] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5) ->kinds[eRegisterKindLLDB]; argument_register_ids[5] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6) ->kinds[eRegisterKindLLDB]; argument_register_ids[6] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG7) ->kinds[eRegisterKindLLDB]; argument_register_ids[7] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG8) ->kinds[eRegisterKindLLDB]; unsigned int current_argument_register = 0; for (value_index = 0; value_index < num_values; ++value_index) { Value *value = values.GetValueAtIndex(value_index); if (!value) return false; // We currently only support extracting values with Clang QualTypes. // Do we care about others? CompilerType compiler_type = value->GetCompilerType(); if (!compiler_type) return false; bool is_signed; if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), is_signed, thread, argument_register_ids, current_argument_register, current_stack_argument); } else if (compiler_type.IsPointerType()) { ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), false, thread, argument_register_ids, current_argument_register, current_stack_argument); } } return true; }
bool ABIMacOSX_arm::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t function_addr, addr_t return_addr, addr_t *arg1_ptr, addr_t *arg2_ptr, addr_t *arg3_ptr, addr_t *arg4_ptr, addr_t *arg5_ptr, addr_t *arg6_ptr) const { RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); RegisterValue reg_value; if (arg1_ptr) { reg_value.SetUInt32(*arg1_ptr); if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r0"), reg_value)) return false; if (arg2_ptr) { reg_value.SetUInt32(*arg2_ptr); if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r1"), reg_value)) return false; if (arg3_ptr) { reg_value.SetUInt32(*arg3_ptr); if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r2"), reg_value)) return false; if (arg4_ptr) { reg_value.SetUInt32(*arg4_ptr); const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3"); if (!reg_ctx->WriteRegister (reg_info, reg_value)) return false; if (arg5_ptr) { // Keep the stack 8 byte aligned, not that we need to sp -= 8; sp &= ~(8ull-1ull); reg_value.SetUInt32(*arg5_ptr); if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp, reg_info->byte_size, reg_value).Fail()) return false; if (arg6_ptr) { reg_value.SetUInt32(*arg6_ptr); if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp + 4, reg_info->byte_size, reg_value).Fail()) return false; } } } } } } TargetSP target_sp (thread.CalculateTarget()); Address so_addr; // Figure out if our return address is ARM or Thumb by using the // Address::GetCallableLoadAddress(Target*) which will figure out the ARM // thumb-ness and set the correct address bits for us. so_addr.SetLoadAddress (return_addr, target_sp.get()); return_addr = so_addr.GetCallableLoadAddress (target_sp.get()); // Set "lr" to the return address if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_num, return_addr)) return false; // Set "sp" to the requested value if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp)) return false; // If bit zero or 1 is set, this must be a thumb function, no need to figure // this out from the symbols. so_addr.SetLoadAddress (function_addr, target_sp.get()); function_addr = so_addr.GetCallableLoadAddress (target_sp.get()); const RegisterInfo *cpsr_reg_info = reg_ctx->GetRegisterInfoByName("cpsr"); const uint32_t curr_cpsr = reg_ctx->ReadRegisterAsUnsigned(cpsr_reg_info, 0); // Make a new CPSR and mask out any Thumb IT (if/then) bits uint32_t new_cpsr = curr_cpsr & ~MASK_CPSR_IT_MASK; // If bit zero or 1 is set, this must be thumb... if (function_addr & 1ull) new_cpsr |= MASK_CPSR_T; // Set T bit in CPSR else new_cpsr &= ~MASK_CPSR_T; // Clear T bit in CPSR if (new_cpsr != curr_cpsr) { if (!reg_ctx->WriteRegisterFromUnsigned (cpsr_reg_info, new_cpsr)) return false; } function_addr &= ~1ull; // clear bit zero since the CPSR will take care of the mode for us // Set "pc" to the address requested if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, function_addr)) return false; return true; }
Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) { Status error; if (!new_value_sp) { error.SetErrorString("Empty value object for return value."); return error; } CompilerType compiler_type = new_value_sp->GetCompilerType(); if (!compiler_type) { error.SetErrorString("Null clang type for return value."); return error; } Thread *thread = frame_sp->GetThread().get(); bool is_signed; uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); bool set_it_simple = false; if (compiler_type.IsIntegerOrEnumerationType(is_signed) || compiler_type.IsPointerType()) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); DataExtractor data; Status data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); if (data_error.Fail()) { error.SetErrorStringWithFormat( "Couldn't convert return value to raw data: %s", data_error.AsCString()); return error; } lldb::offset_t offset = 0; if (num_bytes <= 8) { uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value)) set_it_simple = true; } else { error.SetErrorString("We don't support returning longer than 64 bit " "integer values at present."); } } else if (compiler_type.IsFloatingPointType(count, is_complex)) { if (is_complex) error.SetErrorString( "We don't support returning complex values at present"); else { size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); if (bit_width <= 64) { DataExtractor data; Status data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); if (data_error.Fail()) { error.SetErrorStringWithFormat( "Couldn't convert return value to raw data: %s", data_error.AsCString()); return error; } unsigned char buffer[16]; ByteOrder byte_order = data.GetByteOrder(); data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order); set_it_simple = true; } else { // FIXME - don't know how to do 80 bit long doubles yet. error.SetErrorString( "We don't support returning float values > 64 bits at present"); } } } if (!set_it_simple) { // Okay we've got a structure or something that doesn't fit in a simple // register. // We should figure out where it really goes, but we don't support this yet. error.SetErrorString("We only support setting simple integer and float " "return types at present."); } return error; }
ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread, lldb_private::ClangASTType &ast_type) const { Value value; ValueObjectSP return_valobj_sp; void *value_type = ast_type.GetOpaqueQualType(); if (!value_type) return return_valobj_sp; clang::ASTContext *ast_context = ast_type.GetASTContext(); if (!ast_context) return return_valobj_sp; value.SetContext (Value::eContextTypeClangType, value_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; bool is_signed; // Get the pointer to the first stack argument so we have a place to start // when reading data const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0); if (ClangASTContext::IsIntegerType (value_type, is_signed)) { size_t bit_width = ClangASTType::GetClangTypeBitWidth(ast_context, value_type); switch (bit_width) { default: return return_valobj_sp; case 64: { const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0); uint64_t raw_value; raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX; raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32; if (is_signed) value.GetScalar() = (int64_t)raw_value; else value.GetScalar() = (uint64_t)raw_value; } break; case 32: if (is_signed) value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX); else value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX); break; case 16: if (is_signed) value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX); else value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX); break; case 8: if (is_signed) value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX); else value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX); break; } } else if (ClangASTContext::IsPointerType (value_type)) { uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX; value.GetScalar() = ptr; } else { // not handled yet return return_valobj_sp; } // If we get here, we have a valid Value, so make our ValueObject out of it: return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), ast_type.GetASTContext(), value, ConstString("")); return return_valobj_sp; }
ValueObjectSP ABISysV_ppc64::GetReturnValueObjectSimple( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; Value value; if (!return_compiler_type) return return_valobj_sp; // value.SetContext (Value::eContextTypeClangType, return_value_type); value.SetCompilerType(return_compiler_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { value.SetValueType(Value::eValueTypeScalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers const size_t byte_size = return_compiler_type.GetByteSize(nullptr); uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( reg_ctx->GetRegisterInfoByName("r3", 0), 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; switch (byte_size) { default: break; case sizeof(uint64_t): if (is_signed) value.GetScalar() = (int64_t)(raw_value); else value.GetScalar() = (uint64_t)(raw_value); success = true; break; case sizeof(uint32_t): if (is_signed) value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); else value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); success = true; break; case sizeof(uint16_t): if (is_signed) value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); else value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); success = true; break; case sizeof(uint8_t): if (is_signed) value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); else value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); success = true; break; } } else if (type_flags & eTypeIsFloat) { if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else { const size_t byte_size = return_compiler_type.GetByteSize(nullptr); if (byte_size <= sizeof(long double)) { const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); RegisterValue f1_value; if (reg_ctx->ReadRegister(f1_info, f1_value)) { DataExtractor data; if (f1_value.GetData(data)) { lldb::offset_t offset = 0; if (byte_size == sizeof(float)) { value.GetScalar() = (float)data.GetFloat(&offset); success = true; } else if (byte_size == sizeof(double)) { value.GetScalar() = (double)data.GetDouble(&offset); success = true; } } } } } } if (success) return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsPointer) { unsigned r3_id = reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); value.SetValueType(Value::eValueTypeScalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { const size_t byte_size = return_compiler_type.GetByteSize(nullptr); if (byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", 0); if (altivec_reg) { if (byte_size <= altivec_reg->byte_size) { ProcessSP process_sp(thread.GetProcess()); if (process_sp) { std::unique_ptr<DataBufferHeap> heap_data_ap( new DataBufferHeap(byte_size, 0)); const ByteOrder byte_order = process_sp->GetByteOrder(); RegisterValue reg_value; if (reg_ctx->ReadRegister(altivec_reg, reg_value)) { Status error; if (reg_value.GetAsMemoryData( altivec_reg, heap_data_ap->GetBytes(), heap_data_ap->GetByteSize(), byte_order, error)) { DataExtractor data(DataBufferSP(heap_data_ap.release()), byte_order, process_sp->GetTarget() .GetArchitecture() .GetAddressByteSize()); return_valobj_sp = ValueObjectConstResult::Create( &thread, return_compiler_type, ConstString(""), data); } } } } } } } return return_valobj_sp; }