| //===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ABIMacOSX_i386.h" |
| |
| // C Includes |
| // C++ Includes |
| #include <vector> |
| |
| // Other libraries and framework includes |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/Triple.h" |
| |
| // Project includes |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/PluginManager.h" |
| #include "lldb/Core/RegisterValue.h" |
| #include "lldb/Core/Scalar.h" |
| #include "lldb/Core/ValueObjectConstResult.h" |
| #include "lldb/Symbol/UnwindPlan.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/RegisterContext.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Utility/ConstString.h" |
| #include "lldb/Utility/Status.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| enum { |
| ehframe_eax = 0, |
| ehframe_ecx, |
| ehframe_edx, |
| ehframe_ebx, |
| ehframe_ebp, // Different from DWARF the regnums - eh_frame esp/ebp had their |
| // regnums switched on i386 darwin |
| ehframe_esp, // Different from DWARF the regnums - eh_frame esp/ebp had their |
| // regnums switched on i386 darwin |
| ehframe_esi, |
| ehframe_edi, |
| ehframe_eip, |
| ehframe_eflags |
| }; |
| |
| enum { |
| dwarf_eax = 0, |
| dwarf_ecx, |
| dwarf_edx, |
| dwarf_ebx, |
| dwarf_esp, |
| dwarf_ebp, |
| dwarf_esi, |
| dwarf_edi, |
| dwarf_eip, |
| dwarf_eflags, |
| dwarf_stmm0 = 11, |
| dwarf_stmm1, |
| dwarf_stmm2, |
| dwarf_stmm3, |
| dwarf_stmm4, |
| dwarf_stmm5, |
| dwarf_stmm6, |
| dwarf_stmm7, |
| dwarf_xmm0 = 21, |
| dwarf_xmm1, |
| dwarf_xmm2, |
| dwarf_xmm3, |
| dwarf_xmm4, |
| dwarf_xmm5, |
| dwarf_xmm6, |
| dwarf_xmm7, |
| dwarf_ymm0 = dwarf_xmm0, |
| dwarf_ymm1 = dwarf_xmm1, |
| dwarf_ymm2 = dwarf_xmm2, |
| dwarf_ymm3 = dwarf_xmm3, |
| dwarf_ymm4 = dwarf_xmm4, |
| dwarf_ymm5 = dwarf_xmm5, |
| dwarf_ymm6 = dwarf_xmm6, |
| dwarf_ymm7 = dwarf_xmm7 |
| }; |
| |
| static RegisterInfo g_register_infos[] = { |
| // NAME ALT SZ OFF ENCODING FORMAT |
| // EH_FRAME DWARF GENERIC |
| // PROCESS PLUGIN LLDB NATIVE |
| // ====== ======= == === ============= ============ |
| // ===================== ===================== ============================ |
| // ==================== ====================== |
| {"eax", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_eax, dwarf_eax, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ebx", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ecx", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_ecx, dwarf_ecx, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"edx", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_edx, dwarf_edx, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"esi", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_esi, dwarf_esi, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"edi", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_edi, dwarf_edi, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ebp", |
| "fp", |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"esp", |
| "sp", |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"eip", |
| "pc", |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {ehframe_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"eflags", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"cs", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ss", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ds", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"es", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fs", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"gs", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm0", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm0, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm1", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm1, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm2", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm2, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm3", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm3, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm4", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm4, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm5", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm5, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm6", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm6, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"stmm7", |
| nullptr, |
| 10, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_stmm7, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fctrl", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fstat", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ftag", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fiseg", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fioff", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"foseg", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fooff", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"fop", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm0", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm1", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm2", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm3", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm4", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm5", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm6", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"xmm7", |
| nullptr, |
| 16, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_xmm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"mxcsr", |
| nullptr, |
| 4, |
| 0, |
| eEncodingUint, |
| eFormatHex, |
| {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm0", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm1", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm2", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm3", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm4", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm5", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm6", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}, |
| {"ymm7", |
| nullptr, |
| 32, |
| 0, |
| eEncodingVector, |
| eFormatVectorOfUInt8, |
| {LLDB_INVALID_REGNUM, dwarf_ymm7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
| LLDB_INVALID_REGNUM}, |
| nullptr, |
| nullptr, |
| nullptr, |
| 0}}; |
| |
| static const uint32_t k_num_register_infos = |
| llvm::array_lengthof(g_register_infos); |
| static bool g_register_info_names_constified = false; |
| |
| const lldb_private::RegisterInfo * |
| ABIMacOSX_i386::GetRegisterInfoArray(uint32_t &count) { |
| // Make the C-string names and alt_names for the register infos into const |
| // C-string values by having the ConstString unique the names in the global |
| // constant C-string pool. |
| if (!g_register_info_names_constified) { |
| g_register_info_names_constified = true; |
| for (uint32_t i = 0; i < k_num_register_infos; ++i) { |
| if (g_register_infos[i].name) |
| g_register_infos[i].name = |
| ConstString(g_register_infos[i].name).GetCString(); |
| if (g_register_infos[i].alt_name) |
| g_register_infos[i].alt_name = |
| ConstString(g_register_infos[i].alt_name).GetCString(); |
| } |
| } |
| count = k_num_register_infos; |
| return g_register_infos; |
| } |
| |
| size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; } |
| |
| //------------------------------------------------------------------ |
| // Static Functions |
| //------------------------------------------------------------------ |
| |
| ABISP |
| ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { |
| static ABISP g_abi_sp; |
| if ((arch.GetTriple().getArch() == llvm::Triple::x86) && |
| (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() || |
| arch.GetTriple().isWatchOS())) { |
| if (!g_abi_sp) |
| g_abi_sp.reset(new ABIMacOSX_i386(process_sp)); |
| return g_abi_sp; |
| } |
| return ABISP(); |
| } |
| |
| bool ABIMacOSX_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); |
| |
| // When writing a register value down to memory, the register info used to |
| // write memory 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. Here we use "eax"... |
| const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax"); |
| if (!reg_info_32) |
| return false; // TODO this should actually never happen |
| |
| // Make room for the argument(s) on the stack |
| |
| Status error; |
| RegisterValue reg_value; |
| |
| // Write any arguments onto the stack |
| sp -= 4 * args.size(); |
| |
| // Align the SP |
| sp &= ~(16ull - 1ull); // 16-byte alignment |
| |
| 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 (yes after we just set the |
| // alignment above!). |
| 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; |
| |
| // %esp is set to the actual stack value. |
| |
| if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp)) |
| return false; |
| |
| // %eip is set to the address of the called function. |
| |
| if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr)) |
| return false; |
| |
| return true; |
| } |
| |
| static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, |
| bool is_signed, Process *process, |
| addr_t ¤t_stack_argument) { |
| |
| uint32_t byte_size = (bit_width + (8 - 1)) / 8; |
| Status error; |
| if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, |
| is_signed, scalar, error)) { |
| current_stack_argument += byte_size; |
| return true; |
| } |
| return false; |
| } |
| |
| 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.IsIntegerOrEnumerationType(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; |
| } |
| |
| Status ABIMacOSX_i386::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()) { |
| 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) { |
| const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0); |
| if (num_bytes <= 4) { |
| uint32_t raw_value = data.GetMaxU32(&offset, num_bytes); |
| |
| if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) |
| set_it_simple = true; |
| } else { |
| uint32_t raw_value = data.GetMaxU32(&offset, 4); |
| |
| if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) { |
| const RegisterInfo *edx_info = |
| reg_ctx->GetRegisterInfoByName("edx", 0); |
| uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset); |
| |
| if (reg_ctx->WriteRegisterFromUnsigned(edx_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 |
| 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; |
| } |
| |
| ValueObjectSP |
| ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread, |
| CompilerType &compiler_type) const { |
| Value value; |
| ValueObjectSP return_valobj_sp; |
| |
| if (!compiler_type) |
| return return_valobj_sp; |
| |
| // value.SetContext (Value::eContextTypeClangType, |
| // compiler_type.GetOpaqueQualType()); |
| value.SetCompilerType(compiler_type); |
| |
| RegisterContext *reg_ctx = thread.GetRegisterContext().get(); |
| if (!reg_ctx) |
| return return_valobj_sp; |
| |
| bool is_signed; |
| |
| if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { |
| size_t bit_width = compiler_type.GetBitSize(&thread); |
| |
| unsigned eax_id = |
| reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; |
| unsigned edx_id = |
| reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB]; |
| |
| switch (bit_width) { |
| default: |
| case 128: |
| // Scalar can't hold 128-bit literals, so we don't handle this |
| return return_valobj_sp; |
| case 64: |
| uint64_t raw_value; |
| raw_value = |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffffffff; |
| raw_value |= |
| (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & |
| 0xffffffff) |
| << 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)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffffffff); |
| else |
| value.GetScalar() = (uint32_t)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffffffff); |
| break; |
| case 16: |
| if (is_signed) |
| value.GetScalar() = (int16_t)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffff); |
| else |
| value.GetScalar() = (uint16_t)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffff); |
| break; |
| case 8: |
| if (is_signed) |
| value.GetScalar() = (int8_t)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xff); |
| else |
| value.GetScalar() = (uint8_t)( |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xff); |
| break; |
| } |
| } else if (compiler_type.IsPointerType()) { |
| unsigned eax_id = |
| reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; |
| uint32_t ptr = |
| thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & |
| 0xffffffff; |
| 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(), value, ConstString("")); |
| return return_valobj_sp; |
| } |
| |
| // This defines the CFA as esp+4 |
| // the saved pc is at CFA-4 (i.e. esp+0) |
| // The saved esp is CFA+0 |
| |
| bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { |
| unwind_plan.Clear(); |
| unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
| |
| uint32_t sp_reg_num = dwarf_esp; |
| uint32_t pc_reg_num = dwarf_eip; |
| |
| UnwindPlan::RowSP row(new UnwindPlan::Row); |
| row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4); |
| row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false); |
| row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); |
| unwind_plan.AppendRow(row); |
| unwind_plan.SetSourceName("i386 at-func-entry default"); |
| unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
| return true; |
| } |
| |
| // This defines the CFA as ebp+8 |
| // The saved pc is at CFA-4 (i.e. ebp+4) |
| // The saved ebp is at CFA-8 (i.e. ebp+0) |
| // The saved esp is CFA+0 |
| |
| bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { |
| unwind_plan.Clear(); |
| unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
| |
| uint32_t fp_reg_num = dwarf_ebp; |
| uint32_t sp_reg_num = dwarf_esp; |
| uint32_t pc_reg_num = dwarf_eip; |
| |
| UnwindPlan::RowSP row(new UnwindPlan::Row); |
| const int32_t ptr_size = 4; |
| |
| row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); |
| row->SetOffset(0); |
| |
| row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); |
| row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); |
| row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); |
| |
| unwind_plan.AppendRow(row); |
| unwind_plan.SetSourceName("i386 default unwind plan"); |
| unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
| unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
| return true; |
| } |
| |
| bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) { |
| return !RegisterIsCalleeSaved(reg_info); |
| } |
| |
| // v. |
| // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130 |
| // -IA- |
| // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4 |
| // |
| // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function |
| // Calling Conventions") says that the following registers on i386 are |
| // preserved aka non-volatile aka callee-saved: |
| // |
| // ebx, ebp, esi, edi, esp |
| |
| bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { |
| if (reg_info) { |
| // Saved registers are ebx, ebp, esi, edi, esp, eip |
| const char *name = reg_info->name; |
| if (name[0] == 'e') { |
| switch (name[1]) { |
| case 'b': |
| if (name[2] == 'x' || name[2] == 'p') |
| return name[3] == '\0'; |
| break; |
| case 'd': |
| if (name[2] == 'i') |
| return name[3] == '\0'; |
| break; |
| case 'i': |
| if (name[2] == 'p') |
| return name[3] == '\0'; |
| break; |
| case 's': |
| if (name[2] == 'i' || name[2] == 'p') |
| return name[3] == '\0'; |
| break; |
| } |
| } |
| if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp |
| return true; |
| if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp |
| return true; |
| if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc |
| return true; |
| } |
| return false; |
| } |
| |
| void ABIMacOSX_i386::Initialize() { |
| PluginManager::RegisterPlugin( |
| GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance); |
| } |
| |
| void ABIMacOSX_i386::Terminate() { |
| PluginManager::UnregisterPlugin(CreateInstance); |
| } |
| |
| lldb_private::ConstString ABIMacOSX_i386::GetPluginNameStatic() { |
| static ConstString g_short_name("abi.macosx-i386"); |
| return g_short_name; |
| } |
| |
| //------------------------------------------------------------------ |
| // PluginInterface protocol |
| //------------------------------------------------------------------ |
| |
| lldb_private::ConstString ABIMacOSX_i386::GetPluginName() { |
| return GetPluginNameStatic(); |
| } |
| |
| uint32_t ABIMacOSX_i386::GetPluginVersion() { return 1; } |