From 6256a0ea8fdd051e0f76ac422c353e4ac2b05d35 Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Fri, 31 Oct 2014 02:34:28 +0000 Subject: [PATCH] First cut of PowerPC(64) support in LLDB. Summary: This adds preliminary support for PowerPC/PowerPC64, for FreeBSD. There are some issues still: * Breakpoints don't work well on powerpc64. * Shared libraries don't yet get loaded for a 32-bit process on powerpc64 host. * Backtraces don't work. This is due to PowerPC ABI using a backchain pointer in memory, instead of a dedicated frame pointer register for the backchain. * Breakpoints on functions without debug info may not work correctly for 32-bit powerpc. Reviewers: emaste, tfiala, jingham, clayborg Reviewed By: clayborg Subscribers: emaste, lldb-commits Differential Revision: http://reviews.llvm.org/D5988 llvm-svn: 220944 --- lldb/lib/Makefile | 1 + lldb/source/CMakeLists.txt | 2 + lldb/source/Core/ArchSpec.cpp | 5 +- lldb/source/Host/freebsd/Host.cpp | 47 + lldb/source/Plugins/ABI/CMakeLists.txt | 2 + .../Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp | 1097 ++++++++++++++++ .../source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h | 143 +++ .../Plugins/ABI/SysV-ppc/CMakeLists.txt | 5 + lldb/source/Plugins/ABI/SysV-ppc/Makefile | 14 + .../Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp | 1101 +++++++++++++++++ .../Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h | 143 +++ .../Plugins/ABI/SysV-ppc64/CMakeLists.txt | 5 + lldb/source/Plugins/ABI/SysV-ppc64/Makefile | 14 + .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp | 7 + lldb/source/Plugins/Makefile | 2 +- .../Plugins/ObjectFile/ELF/ELFHeader.cpp | 6 + .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 1 + .../Platform/FreeBSD/PlatformFreeBSD.cpp | 7 + .../Process/FreeBSD/ProcessMonitor.cpp | 2 + .../Plugins/Process/POSIX/CMakeLists.txt | 1 + .../Plugins/Process/POSIX/POSIXThread.cpp | 22 + ...sterContextPOSIXProcessMonitor_powerpc.cpp | 316 +++++ ...gisterContextPOSIXProcessMonitor_powerpc.h | 95 ++ .../Plugins/Process/Utility/CMakeLists.txt | 2 + .../RegisterContextFreeBSD_powerpc.cpp | 227 ++++ .../Utility/RegisterContextFreeBSD_powerpc.h | 66 + .../RegisterContextMacOSXFrameBackchain.cpp | 3 +- .../Utility/RegisterContextPOSIX_powerpc.cpp | 273 ++++ .../Utility/RegisterContextPOSIX_powerpc.h | 173 +++ .../Process/Utility/RegisterContext_powerpc.h | 163 +++ .../Process/Utility/RegisterInfos_powerpc.h | 127 ++ .../Plugins/Process/elf-core/CMakeLists.txt | 1 + .../Process/elf-core/ProcessElfCore.cpp | 1 + .../RegisterContextPOSIXCore_powerpc.cpp | 109 ++ .../RegisterContextPOSIXCore_powerpc.h | 62 + .../Process/elf-core/ThreadElfCore.cpp | 12 + lldb/source/Target/Thread.cpp | 2 + lldb/source/lldb.cpp | 5 + 38 files changed, 4260 insertions(+), 4 deletions(-) create mode 100644 lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp create mode 100644 lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h create mode 100644 lldb/source/Plugins/ABI/SysV-ppc/CMakeLists.txt create mode 100644 lldb/source/Plugins/ABI/SysV-ppc/Makefile create mode 100644 lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp create mode 100644 lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h create mode 100644 lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt create mode 100644 lldb/source/Plugins/ABI/SysV-ppc64/Makefile create mode 100644 lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp create mode 100644 lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h create mode 100644 lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h create mode 100644 lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h create mode 100644 lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp create mode 100644 lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile index 3bd9c222df53..97c82641e0ab 100644 --- a/lldb/lib/Makefile +++ b/lldb/lib/Makefile @@ -34,6 +34,7 @@ USEDLIBS = lldbAPI.a \ lldbPluginABIMacOSX_arm.a \ lldbPluginABIMacOSX_arm64.a \ lldbPluginABIMacOSX_i386.a \ + lldbPluginABISysV_ppc64.a \ lldbPluginABISysV_x86_64.a \ lldbPluginABISysV_hexagon.a \ lldbPluginDisassemblerLLVM.a \ diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt index cede1e7db5ba..999625784a27 100644 --- a/lldb/source/CMakeLists.txt +++ b/lldb/source/CMakeLists.txt @@ -80,6 +80,8 @@ set( LLDB_USED_LIBS lldbPluginABIMacOSX_i386 lldbPluginABISysV_x86_64 lldbPluginABISysV_hexagon + lldbPluginABISysV_ppc + lldbPluginABISysV_ppc64 lldbPluginInstructionARM lldbPluginInstructionARM64 lldbPluginObjectFilePECOFF diff --git a/lldb/source/Core/ArchSpec.cpp b/lldb/source/Core/ArchSpec.cpp index 7750fc546e94..2562e98d74c6 100644 --- a/lldb/source/Core/ArchSpec.cpp +++ b/lldb/source/Core/ArchSpec.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/ELF.h" #include "llvm/Support/Host.h" #include "lldb/Utility/SafeMachO.h" +#include "lldb/Core/Log.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StringList.h" #include "lldb/Host/Endian.h" @@ -84,7 +85,7 @@ static const CoreDefinition g_core_definitions[] = { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, - { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "ppc" }, + { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc602 , "ppc602" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603 , "ppc603" }, @@ -98,7 +99,7 @@ static const CoreDefinition g_core_definitions[] = { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7450 , "ppc7450" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc970 , "ppc970" }, - { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "ppc64" }, + { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "powerpc64" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" }, { eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" }, diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp index 5f065e2810fe..fcf074bafa95 100644 --- a/lldb/source/Host/freebsd/Host.cpp +++ b/lldb/source/Host/freebsd/Host.cpp @@ -286,6 +286,49 @@ Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) return false; } +static lldb::DataBufferSP +GetAuxvData32(lldb_private::Process *process) +{ + struct { + uint32_t ps_argvstr; + int ps_nargvstr; + uint32_t ps_envstr; + int ps_nenvstr; + } ps_strings; + void *ps_strings_addr, *auxv_addr; + struct privElf32_Auxinfo { int a_type; unsigned int a_val; } aux_info32[AT_COUNT]; + struct ptrace_io_desc pid; + DataBufferSP buf_sp; + std::unique_ptr buf_ap(new DataBufferHeap(1024, 0)); + + ps_strings_addr = (void *)0xffffdff0; + pid.piod_op = PIOD_READ_D; + pid.piod_addr = &ps_strings; + pid.piod_offs = ps_strings_addr; + pid.piod_len = sizeof(ps_strings); + if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { + perror("failed to fetch ps_strings"); + buf_ap.release(); + goto done; + } + + auxv_addr = (void *)(ps_strings.ps_envstr + sizeof(uint32_t) * (ps_strings.ps_nenvstr + 1)); + + pid.piod_addr = aux_info32; + pid.piod_offs = auxv_addr; + pid.piod_len = sizeof(aux_info32); + if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) { + perror("failed to fetch aux_info"); + buf_ap.release(); + goto done; + } + memcpy(buf_ap->GetBytes(), aux_info32, pid.piod_len); + buf_sp.reset(buf_ap.release()); + + done: + return buf_sp; +} + lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) { @@ -296,6 +339,10 @@ Host::GetAuxvData(lldb_private::Process *process) struct ps_strings ps_strings; struct ptrace_io_desc pid; DataBufferSP buf_sp; + + if (process->GetAddressByteSize() < HostInfo::GetArchitecture().GetAddressByteSize()) + return GetAuxvData32(process); + std::unique_ptr buf_ap(new DataBufferHeap(1024, 0)); if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) { diff --git a/lldb/source/Plugins/ABI/CMakeLists.txt b/lldb/source/Plugins/ABI/CMakeLists.txt index 74f164c31306..6a487c9123f4 100644 --- a/lldb/source/Plugins/ABI/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/CMakeLists.txt @@ -1,4 +1,6 @@ add_subdirectory(SysV-hexagon) +add_subdirectory(SysV-ppc64) +add_subdirectory(SysV-ppc) add_subdirectory(SysV-x86_64) add_subdirectory(MacOSX-i386) add_subdirectory(MacOSX-arm) diff --git a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp new file mode 100644 index 000000000000..378e47b360c2 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp @@ -0,0 +1,1097 @@ +//===-- ABISysV_ppc.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_ppc.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +using namespace lldb; +using namespace lldb_private; + +enum gcc_dwarf_regnums +{ + gcc_dwarf_r0 = 0, + gcc_dwarf_r1, + gcc_dwarf_r2, + gcc_dwarf_r3, + gcc_dwarf_r4, + gcc_dwarf_r5, + gcc_dwarf_r6, + gcc_dwarf_r7, + gcc_dwarf_r8, + gcc_dwarf_r9, + gcc_dwarf_r10, + gcc_dwarf_r11, + gcc_dwarf_r12, + gcc_dwarf_r13, + gcc_dwarf_r14, + gcc_dwarf_r15, + gcc_dwarf_r16, + gcc_dwarf_r17, + gcc_dwarf_r18, + gcc_dwarf_r19, + gcc_dwarf_r20, + gcc_dwarf_r21, + gcc_dwarf_r22, + gcc_dwarf_r23, + gcc_dwarf_r24, + gcc_dwarf_r25, + gcc_dwarf_r26, + gcc_dwarf_r27, + gcc_dwarf_r28, + gcc_dwarf_r29, + gcc_dwarf_r30, + gcc_dwarf_r31, + gcc_dwarf_f0, + gcc_dwarf_f1, + gcc_dwarf_f2, + gcc_dwarf_f3, + gcc_dwarf_f4, + gcc_dwarf_f5, + gcc_dwarf_f6, + gcc_dwarf_f7, + gcc_dwarf_f8, + gcc_dwarf_f9, + gcc_dwarf_f10, + gcc_dwarf_f11, + gcc_dwarf_f12, + gcc_dwarf_f13, + gcc_dwarf_f14, + gcc_dwarf_f15, + gcc_dwarf_f16, + gcc_dwarf_f17, + gcc_dwarf_f18, + gcc_dwarf_f19, + gcc_dwarf_f20, + gcc_dwarf_f21, + gcc_dwarf_f22, + gcc_dwarf_f23, + gcc_dwarf_f24, + gcc_dwarf_f25, + gcc_dwarf_f26, + gcc_dwarf_f27, + gcc_dwarf_f28, + gcc_dwarf_f29, + gcc_dwarf_f30, + gcc_dwarf_f31, + gcc_dwarf_cr, + gcc_dwarf_fpscr, + gcc_dwarf_xer = 101, + gcc_dwarf_lr = 108, + gcc_dwarf_ctr, + gcc_dwarf_pc, + gcc_dwarf_cfa, +}; + +enum gdb_regnums +{ + gdb_r0 = 0, + gdb_r1, + gdb_r2, + gdb_r3, + gdb_r4, + gdb_r5, + gdb_r6, + gdb_r7, + gdb_r8, + gdb_r9, + gdb_r10, + gdb_r11, + gdb_r12, + gdb_r13, + gdb_r14, + gdb_r15, + gdb_r16, + gdb_r17, + gdb_r18, + gdb_r19, + gdb_r20, + gdb_r21, + gdb_r22, + gdb_r23, + gdb_r24, + gdb_r25, + gdb_r26, + gdb_r27, + gdb_r28, + gdb_r29, + gdb_r30, + gdb_r31, + gdb_lr, + gdb_cr, + gdb_xer, + gdb_ctr, + gdb_pc, +}; + + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, 8, 0, eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL } +static const RegisterInfo +g_register_infos[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0), + DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1), + DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2), + DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3), + DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4), + DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5), + DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6), + DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7), + DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8), + DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9), + DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15), + DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16), + DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17), + DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18), + DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19), + DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20), + DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21), + DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22), + DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23), + DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24), + DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25), + DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26), + DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27), + DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28), + DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30), + DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31), + DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr), + DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), + DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL}, +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); + +const lldb_private::RegisterInfo * +ABISysV_ppc::GetRegisterInfoArray (uint32_t &count) +{ + count = k_num_register_infos; + return g_register_infos; +} + + +size_t +ABISysV_ppc::GetRedZoneSize () const +{ + return 224; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABISysV_ppc::CreateInstance (const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::ppc) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABISysV_ppc); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_ppc::PrepareTrivialCall (Thread &thread, + addr_t sp, + addr_t func_addr, + addr_t return_addr, + llvm::ArrayRef 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%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; + + 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%zd (0x%" PRIx64 ") into %s", 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; +} + +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; + Error 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 +ABISysV_ppc::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? + ClangASTType clang_type = value->GetClangType(); + if (!clang_type) + return false; + bool is_signed; + + if (clang_type.IsIntegerType (is_signed)) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + is_signed, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + else if (clang_type.IsPointerType ()) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + false, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + } + + return true; +} + +Error +ABISysV_ppc::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; + } + + ClangASTType clang_type = new_value_sp->GetClangType(); + 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()) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + 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) + { + 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 (clang_type.IsFloatingPointType (count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + { + size_t bit_width = clang_type.GetBitSize(); + if (bit_width <= 64) + { + 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; + } + + 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 +ABISysV_ppc::GetReturnValueObjectSimple (Thread &thread, + ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_clang_type) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_value_type); + value.SetClangType (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 (); + 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_clang_type.GetByteSize(); + 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 + { + } + } + + 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_clang_type.GetByteSize(); + if (byte_size > 0) + { + + const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0); + if (altivec_reg == NULL) + altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); + if (altivec_reg) + { + if (byte_size <= altivec_reg->byte_size) + { + ProcessSP process_sp (thread.GetProcess()); + if (process_sp) + { + std::unique_ptr 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)) + { + Error 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_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + } + + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_ppc::GetReturnValueObjectImpl (Thread &thread, ClangASTType &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; + + const size_t bit_width = return_clang_type.GetBitSize(); + if (return_clang_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_clang_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; + + ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL); + const size_t field_bit_width = field_clang_type.GetBitSize(); + + // 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 = NULL; + uint32_t copy_from_offset = 0; + + if (field_clang_type.IsIntegerType (is_signed) || field_clang_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 NULL return value object. + return return_valobj_sp; + } + } + else if (field_clang_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; + ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1, + name, + &next_field_bit_offset, + NULL, + NULL); + if (next_field_clang_type.IsIntegerType (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; + ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1, + name, + &prev_field_bit_offset, + NULL, + NULL); + if (prev_field_clang_type.IsIntegerType (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_clang_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, NULL), + return_clang_type); + } + } + + return return_valobj_sp; +} + +bool +ABISysV_ppc::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = gcc_dwarf_lr; + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->SetCFARegister (sp_reg_num); + + // The previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("ppc at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABISysV_ppc::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_lr; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + const int32_t ptr_size = 8; + row->SetCFARegister (LLDB_REGNUM_GENERIC_SP); + row->SetCFAOffset (8); + row->SetOffset (0); + + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); + row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * -2, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("ppc default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr); + return true; +} + +bool +ABISysV_ppc::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + return !RegisterIsCalleeSaved (reg_info); +} + + + +// See "Register Usage" in the +// "System V Application Binary Interface" +// "64-bit PowerPC ELF Application Binary Interface Supplement" +// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc/PPC-elf64abi-1.9.pdf + +bool +ABISysV_ppc::RegisterIsCalleeSaved (const RegisterInfo *reg_info) +{ + if (reg_info) + { + // Preserved registers are : + // r1,r2,r13-r31 + // f14-f31 (not yet) + // v20-v31 (not yet) + // vrsave (not yet) + + const char *name = reg_info->name; + if (name[0] == 'r') + { + if ((name[1] == '1' || name[1] == '2') && name[2] == '\0') + return true; + if (name[1] == '1' && name[2] > '2') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 'f' && name[1] >= '0' && name[1] <= '9') + { + if (name[3] == '1' && name[4] >= '4') + return true; + if ((name[3] == '2' || name[3] == '3') && name[4] != '\0') + return true; + } + + 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 +ABISysV_ppc::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "System V ABI for ppc targets", + CreateInstance); +} + +void +ABISysV_ppc::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +ABISysV_ppc::GetPluginNameStatic() +{ + static ConstString g_name("sysv-ppc"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ABISysV_ppc::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_ppc::GetPluginVersion() +{ + return 1; +} + diff --git a/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h new file mode 100644 index 000000000000..a7aad300e297 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h @@ -0,0 +1,143 @@ +//===-- ABISysV_ppc.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_ppc_h_ +#define liblldb_ABISysV_ppc_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_ppc : + public lldb_private::ABI +{ +public: + + ~ABISysV_ppc() + { + } + + virtual size_t + GetRedZoneSize () const; + + virtual bool + PrepareTrivialCall (lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + + virtual bool + GetArgumentValues (lldb_private::Thread &thread, + lldb_private::ValueList &values) const; + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + lldb::ValueObjectSP + GetReturnValueObjectSimple (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +public: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &type) const; + + virtual bool + CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); + + virtual bool + StackUsesFrames () + { + return true; + } + + // The SysV ppc ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + virtual bool + CallFrameAddressIsValid (lldb::addr_t cfa) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid (lldb::addr_t pc) + { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray (uint32_t &count); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance (const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString + GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + void + CreateRegisterMapIfNeeded (); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_ppc() : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABI_h_ diff --git a/lldb/source/Plugins/ABI/SysV-ppc/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-ppc/CMakeLists.txt new file mode 100644 index 000000000000..55b730253550 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginABISysV_ppc + ABISysV_ppc.cpp + ) diff --git a/lldb/source/Plugins/ABI/SysV-ppc/Makefile b/lldb/source/Plugins/ABI/SysV-ppc/Makefile new file mode 100644 index 000000000000..7a6d38d68337 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginABISysV_ppc +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp new file mode 100644 index 000000000000..e2d7c02ad6e0 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -0,0 +1,1101 @@ +//===-- ABISysV_ppc64.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_ppc64.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +using namespace lldb; +using namespace lldb_private; + +enum gcc_dwarf_regnums +{ + gcc_dwarf_r0 = 0, + gcc_dwarf_r1, + gcc_dwarf_r2, + gcc_dwarf_r3, + gcc_dwarf_r4, + gcc_dwarf_r5, + gcc_dwarf_r6, + gcc_dwarf_r7, + gcc_dwarf_r8, + gcc_dwarf_r9, + gcc_dwarf_r10, + gcc_dwarf_r11, + gcc_dwarf_r12, + gcc_dwarf_r13, + gcc_dwarf_r14, + gcc_dwarf_r15, + gcc_dwarf_r16, + gcc_dwarf_r17, + gcc_dwarf_r18, + gcc_dwarf_r19, + gcc_dwarf_r20, + gcc_dwarf_r21, + gcc_dwarf_r22, + gcc_dwarf_r23, + gcc_dwarf_r24, + gcc_dwarf_r25, + gcc_dwarf_r26, + gcc_dwarf_r27, + gcc_dwarf_r28, + gcc_dwarf_r29, + gcc_dwarf_r30, + gcc_dwarf_r31, + gcc_dwarf_f0, + gcc_dwarf_f1, + gcc_dwarf_f2, + gcc_dwarf_f3, + gcc_dwarf_f4, + gcc_dwarf_f5, + gcc_dwarf_f6, + gcc_dwarf_f7, + gcc_dwarf_f8, + gcc_dwarf_f9, + gcc_dwarf_f10, + gcc_dwarf_f11, + gcc_dwarf_f12, + gcc_dwarf_f13, + gcc_dwarf_f14, + gcc_dwarf_f15, + gcc_dwarf_f16, + gcc_dwarf_f17, + gcc_dwarf_f18, + gcc_dwarf_f19, + gcc_dwarf_f20, + gcc_dwarf_f21, + gcc_dwarf_f22, + gcc_dwarf_f23, + gcc_dwarf_f24, + gcc_dwarf_f25, + gcc_dwarf_f26, + gcc_dwarf_f27, + gcc_dwarf_f28, + gcc_dwarf_f29, + gcc_dwarf_f30, + gcc_dwarf_f31, + gcc_dwarf_cr, + gcc_dwarf_fpscr, + gcc_dwarf_xer = 101, + gcc_dwarf_lr = 108, + gcc_dwarf_ctr, + gcc_dwarf_pc, + gcc_dwarf_cfa, +}; + +enum gdb_regnums +{ + gdb_r0 = 0, + gdb_r1, + gdb_r2, + gdb_r3, + gdb_r4, + gdb_r5, + gdb_r6, + gdb_r7, + gdb_r8, + gdb_r9, + gdb_r10, + gdb_r11, + gdb_r12, + gdb_r13, + gdb_r14, + gdb_r15, + gdb_r16, + gdb_r17, + gdb_r18, + gdb_r19, + gdb_r20, + gdb_r21, + gdb_r22, + gdb_r23, + gdb_r24, + gdb_r25, + gdb_r26, + gdb_r27, + gdb_r28, + gdb_r29, + gdb_r30, + gdb_r31, + gdb_lr, + gdb_cr, + gdb_xer, + gdb_ctr, + gdb_pc, +}; + + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, 8, 0, eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4}, NULL, NULL } +static const RegisterInfo +g_register_infos[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(r0, NULL, gcc_dwarf_r0, gcc_dwarf_r0, LLDB_INVALID_REGNUM, gdb_r0), + DEFINE_GPR(r1, "sp", gcc_dwarf_r1, gcc_dwarf_r1, LLDB_REGNUM_GENERIC_SP, gdb_r1), + DEFINE_GPR(r2, NULL, gcc_dwarf_r2, gcc_dwarf_r2, LLDB_INVALID_REGNUM, gdb_r2), + DEFINE_GPR(r3, "arg1",gcc_dwarf_r3, gcc_dwarf_r3, LLDB_REGNUM_GENERIC_ARG1, gdb_r3), + DEFINE_GPR(r4, "arg2",gcc_dwarf_r4, gcc_dwarf_r4, LLDB_REGNUM_GENERIC_ARG2 ,gdb_r4), + DEFINE_GPR(r5, "arg3",gcc_dwarf_r5, gcc_dwarf_r5, LLDB_REGNUM_GENERIC_ARG3, gdb_r5), + DEFINE_GPR(r6, "arg4",gcc_dwarf_r6, gcc_dwarf_r6, LLDB_REGNUM_GENERIC_ARG4, gdb_r6), + DEFINE_GPR(r7, "arg5",gcc_dwarf_r7, gcc_dwarf_r7, LLDB_REGNUM_GENERIC_ARG5, gdb_r7), + DEFINE_GPR(r8, "arg6",gcc_dwarf_r8, gcc_dwarf_r8, LLDB_REGNUM_GENERIC_ARG6, gdb_r8), + DEFINE_GPR(r9, "arg7",gcc_dwarf_r9, gcc_dwarf_r9, LLDB_REGNUM_GENERIC_ARG7, gdb_r9), + DEFINE_GPR(r10, "arg8",gcc_dwarf_r10, gcc_dwarf_r10, LLDB_REGNUM_GENERIC_ARG8, gdb_r10), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11, gcc_dwarf_r11, LLDB_INVALID_REGNUM, gdb_r11), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12, gcc_dwarf_r12, LLDB_INVALID_REGNUM, gdb_r12), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13, gcc_dwarf_r13, LLDB_INVALID_REGNUM, gdb_r13), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14, gcc_dwarf_r14, LLDB_INVALID_REGNUM, gdb_r14), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15, gcc_dwarf_r15, LLDB_INVALID_REGNUM, gdb_r15), + DEFINE_GPR(r16, NULL, gcc_dwarf_r16, gcc_dwarf_r16, LLDB_INVALID_REGNUM, gdb_r16), + DEFINE_GPR(r17, NULL, gcc_dwarf_r17, gcc_dwarf_r17, LLDB_INVALID_REGNUM, gdb_r17), + DEFINE_GPR(r18, NULL, gcc_dwarf_r18, gcc_dwarf_r18, LLDB_INVALID_REGNUM, gdb_r18), + DEFINE_GPR(r19, NULL, gcc_dwarf_r19, gcc_dwarf_r19, LLDB_INVALID_REGNUM, gdb_r19), + DEFINE_GPR(r20, NULL, gcc_dwarf_r20, gcc_dwarf_r20, LLDB_INVALID_REGNUM, gdb_r20), + DEFINE_GPR(r21, NULL, gcc_dwarf_r21, gcc_dwarf_r21, LLDB_INVALID_REGNUM, gdb_r21), + DEFINE_GPR(r22, NULL, gcc_dwarf_r22, gcc_dwarf_r22, LLDB_INVALID_REGNUM, gdb_r22), + DEFINE_GPR(r23, NULL, gcc_dwarf_r23, gcc_dwarf_r23, LLDB_INVALID_REGNUM, gdb_r23), + DEFINE_GPR(r24, NULL, gcc_dwarf_r24, gcc_dwarf_r24, LLDB_INVALID_REGNUM, gdb_r24), + DEFINE_GPR(r25, NULL, gcc_dwarf_r25, gcc_dwarf_r25, LLDB_INVALID_REGNUM, gdb_r25), + DEFINE_GPR(r26, NULL, gcc_dwarf_r26, gcc_dwarf_r26, LLDB_INVALID_REGNUM, gdb_r26), + DEFINE_GPR(r27, NULL, gcc_dwarf_r27, gcc_dwarf_r27, LLDB_INVALID_REGNUM, gdb_r27), + DEFINE_GPR(r28, NULL, gcc_dwarf_r28, gcc_dwarf_r28, LLDB_INVALID_REGNUM, gdb_r28), + DEFINE_GPR(r29, NULL, gcc_dwarf_r29, gcc_dwarf_r29, LLDB_INVALID_REGNUM, gdb_r29), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30, gcc_dwarf_r30, LLDB_INVALID_REGNUM, gdb_r30), + DEFINE_GPR(r31, NULL, gcc_dwarf_r31, gcc_dwarf_r31, LLDB_INVALID_REGNUM, gdb_r31), + DEFINE_GPR(lr, "lr", gcc_dwarf_lr, gcc_dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_lr), + DEFINE_GPR(cr, "cr", gcc_dwarf_cr, gcc_dwarf_cr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), + DEFINE_GPR(xer, "xer", gcc_dwarf_xer, gcc_dwarf_xer, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(ctr, "ctr", gcc_dwarf_ctr, gcc_dwarf_ctr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc, gcc_dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + { NULL, NULL, 8, 0, eEncodingUint, eFormatHex, { gcc_dwarf_cfa, gcc_dwarf_cfa, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM}, NULL, NULL}, +}; + +static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); + +const lldb_private::RegisterInfo * +ABISysV_ppc64::GetRegisterInfoArray (uint32_t &count) +{ + count = k_num_register_infos; + return g_register_infos; +} + + +size_t +ABISysV_ppc64::GetRedZoneSize () const +{ + return 224; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +ABISP +ABISysV_ppc64::CreateInstance (const ArchSpec &arch) +{ + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::ppc64) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABISysV_ppc64); + return g_abi_sp; + } + return ABISP(); +} + +bool +ABISysV_ppc64::PrepareTrivialCall (Thread &thread, + addr_t sp, + addr_t func_addr, + addr_t return_addr, + llvm::ArrayRef 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%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; + + 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%zd (0x%" PRIx64 ") into %s", 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; +} + +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; + Error 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 +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? + ClangASTType clang_type = value->GetClangType(); + if (!clang_type) + return false; + bool is_signed; + + if (clang_type.IsIntegerType (is_signed)) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + is_signed, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + else if (clang_type.IsPointerType ()) + { + ReadIntegerArgument(value->GetScalar(), + clang_type.GetBitSize(), + false, + thread, + argument_register_ids, + current_argument_register, + current_stack_argument); + } + } + + return true; +} + +Error +ABISysV_ppc64::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; + } + + ClangASTType clang_type = new_value_sp->GetClangType(); + 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()) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + 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) + { + 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 (clang_type.IsFloatingPointType (count, is_complex)) + { + if (is_complex) + error.SetErrorString ("We don't support returning complex values at present"); + else + { + size_t bit_width = clang_type.GetBitSize(); + if (bit_width <= 64) + { + 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; + } + + 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 +ABISysV_ppc64::GetReturnValueObjectSimple (Thread &thread, + ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_clang_type) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_value_type); + value.SetClangType (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 (); + 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_clang_type.GetByteSize(); + 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 + { + } + } + + 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_clang_type.GetByteSize(); + if (byte_size > 0) + { + + const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v0", 0); + if (altivec_reg == NULL) + altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0); + if (altivec_reg) + { + if (byte_size <= altivec_reg->byte_size) + { + ProcessSP process_sp (thread.GetProcess()); + if (process_sp) + { + std::unique_ptr 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)) + { + Error 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_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + } + + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_ppc64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &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; + + const size_t bit_width = return_clang_type.GetBitSize(); + if (return_clang_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_clang_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; + + ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL); + const size_t field_bit_width = field_clang_type.GetBitSize(); + + // 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 = NULL; + uint32_t copy_from_offset = 0; + + if (field_clang_type.IsIntegerType (is_signed) || field_clang_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 NULL return value object. + return return_valobj_sp; + } + } + else if (field_clang_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; + ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1, + name, + &next_field_bit_offset, + NULL, + NULL); + if (next_field_clang_type.IsIntegerType (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; + ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1, + name, + &prev_field_bit_offset, + NULL, + NULL); + if (prev_field_clang_type.IsIntegerType (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_clang_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, NULL), + return_clang_type); + } + } + + return return_valobj_sp; +} + +bool +ABISysV_ppc64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = gcc_dwarf_lr; + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value + row->SetCFARegister (sp_reg_num); + + // The previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("ppc64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABISysV_ppc64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t sp_reg_num = gcc_dwarf_r1; + uint32_t pc_reg_num = gcc_dwarf_lr; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + const int32_t ptr_size = 8; + row->SetCFARegister (LLDB_REGNUM_GENERIC_SP); + row->SetCFAOffset (48); + row->SetOffset (0); + + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -4, true); + row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * -6, true); + row->SetRegisterLocationToAtCFAPlusOffset(gcc_dwarf_cr, ptr_size * -5, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("ppc64 default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(gcc_dwarf_lr); + return true; +} + +bool +ABISysV_ppc64::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + return !RegisterIsCalleeSaved (reg_info); +} + + + +// See "Register Usage" in the +// "System V Application Binary Interface" +// "64-bit PowerPC ELF Application Binary Interface Supplement" +// current version is 1.9 released 2004 at http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf + +bool +ABISysV_ppc64::RegisterIsCalleeSaved (const RegisterInfo *reg_info) +{ + if (reg_info) + { + // Preserved registers are : + // r1,r2,r13-r31 + // cr2-cr4 (partially preserved) + // f14-f31 (not yet) + // v20-v31 (not yet) + // vrsave (not yet) + + const char *name = reg_info->name; + if (name[0] == 'r') + { + if ((name[1] == '1' || name[1] == '2') && name[2] == '\0') + return true; + if (name[1] == '1' && name[2] > '2') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') + { + if (name[2] == '\0') + return false; + if (name[1] == '1' && name[2] >= '4') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + 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 +ABISysV_ppc64::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "System V ABI for ppc64 targets", + CreateInstance); +} + +void +ABISysV_ppc64::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +ABISysV_ppc64::GetPluginNameStatic() +{ + static ConstString g_name("sysv-ppc64"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +ABISysV_ppc64::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_ppc64::GetPluginVersion() +{ + return 1; +} + diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h new file mode 100644 index 000000000000..d77cb9f1efe3 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h @@ -0,0 +1,143 @@ +//===-- ABISysV_ppc64.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_ppc64_h_ +#define liblldb_ABISysV_ppc64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_ppc64 : + public lldb_private::ABI +{ +public: + + ~ABISysV_ppc64() + { + } + + virtual size_t + GetRedZoneSize () const; + + virtual bool + PrepareTrivialCall (lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + + virtual bool + GetArgumentValues (lldb_private::Thread &thread, + lldb_private::ValueList &values) const; + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + lldb::ValueObjectSP + GetReturnValueObjectSimple (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +public: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &type) const; + + virtual bool + CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); + + virtual bool + StackUsesFrames () + { + return true; + } + + // The SysV ppc64 ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + virtual bool + CallFrameAddressIsValid (lldb::addr_t cfa) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid (lldb::addr_t pc) + { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray (uint32_t &count); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance (const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString + GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + void + CreateRegisterMapIfNeeded (); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_ppc64() : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABI_h_ diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt new file mode 100644 index 000000000000..b82da70c89c9 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginABISysV_ppc64 + ABISysV_ppc64.cpp + ) diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/Makefile b/lldb/source/Plugins/ABI/SysV-ppc64/Makefile new file mode 100644 index 000000000000..43fc41d42713 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-ppc64/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginABISysV_ppc64 +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index a7a2d3f76a07..632c01ae773a 100644 --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -558,6 +558,13 @@ DynamicLoaderPOSIXDYLD::GetEntryPoint() return LLDB_INVALID_ADDRESS; m_entry_point = static_cast(I->value); + + const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); + + // On ppc64, the entry point is actually a descriptor. Dereference it. + if (arch.GetMachine() == llvm::Triple::ppc64) + m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8); + return m_entry_point; } diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile index 31964ee48c3c..dce782e5ce8e 100644 --- a/lldb/source/Plugins/Makefile +++ b/lldb/source/Plugins/Makefile @@ -13,7 +13,7 @@ include $(LLDB_LEVEL)/../../Makefile.config PARALLEL_DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-x86_64 \ - ABI/SysV-hexagon \ + ABI/SysV-hexagon ABI/SysV-ppc64 \ Disassembler/llvm \ ObjectContainer/BSD-Archive ObjectFile/ELF ObjectFile/PECOFF \ ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \ diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index f027294b7c57..cfb24f88087b 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -173,6 +173,12 @@ ELFHeader::GetRelocationJumpSlotType() const default: assert(false && "architecture not supported"); break; + case EM_PPC: + slot = R_PPC_JMP_SLOT; + break; + case EM_PPC64: + slot = R_PPC64_JMP_SLOT; + break; case EM_386: case EM_486: slot = R_386_JUMP_SLOT; diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index ea64ff24c00c..e7bf20e18008 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1724,6 +1724,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, static ConstString rodata1_section_name(".rodata1"); static ConstString data2_section_name(".data1"); static ConstString bss_section_name(".bss"); + static ConstString opd_section_name(".opd"); // For ppc64 //StreamFile strm(stdout, false); unsigned i; diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index cc086e3b1206..ae2358ceaa72 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -326,6 +326,13 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite trap_opcode_size = sizeof(g_i386_opcode); } break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + { + static const uint8_t g_ppc_opcode[] = { 0x7f, 0xe0, 0x00, 0x08 }; + trap_opcode = g_ppc_opcode; + trap_opcode_size = sizeof(g_ppc_opcode); + } } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index cb30a159fa12..bd96b6bfa457 100644 --- a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -113,6 +113,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax); } #endif +#ifndef __powerpc__ if (req == PT_GETDBREGS || req == PT_SETDBREGS) { struct dbreg *r = (struct dbreg *) addr; char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; @@ -120,6 +121,7 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, for (int i = 0; i <= 7; i++) log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); } +#endif } return result; diff --git a/lldb/source/Plugins/Process/POSIX/CMakeLists.txt b/lldb/source/Plugins/Process/POSIX/CMakeLists.txt index ad1295298283..8fd7bd1fc8ae 100644 --- a/lldb/source/Plugins/Process/POSIX/CMakeLists.txt +++ b/lldb/source/Plugins/Process/POSIX/CMakeLists.txt @@ -12,5 +12,6 @@ add_lldb_library(lldbPluginProcessPOSIX ProcessPOSIXLog.cpp RegisterContextPOSIXProcessMonitor_arm64.cpp RegisterContextPOSIXProcessMonitor_mips64.cpp + RegisterContextPOSIXProcessMonitor_powerpc.cpp RegisterContextPOSIXProcessMonitor_x86.cpp ) diff --git a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp index 64c9de90800e..1057585e1b2a 100644 --- a/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -34,12 +34,14 @@ #include "Plugins/Process/Linux/ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "Plugins/Process/Utility/UnwindLLDB.h" @@ -167,6 +169,14 @@ POSIXThread::GetRegisterContext() case llvm::Triple::FreeBSD: switch (target_arch.GetMachine()) { + case llvm::Triple::ppc: +#ifndef __powerpc64__ + reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); + break; +#endif + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); + break; case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(target_arch); break; @@ -229,6 +239,14 @@ POSIXThread::GetRegisterContext() m_reg_context_sp.reset(reg_ctx); break; } + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + { + RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } case llvm::Triple::x86: case llvm::Triple::x86_64: { @@ -624,6 +642,8 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset) case llvm::Triple::aarch64: case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: case llvm::Triple::x86: case llvm::Triple::x86_64: { @@ -655,6 +675,8 @@ POSIXThread::GetRegisterName(unsigned reg) case llvm::Triple::aarch64: case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: case llvm::Triple::x86: case llvm::Triple::x86_64: name = GetRegisterContext()->GetRegisterName(reg); diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp new file mode 100644 index 000000000000..0dfb91d5e4eb --- /dev/null +++ b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -0,0 +1,316 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "RegisterContextPOSIX_powerpc.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_powerpc, GetGPRSize()); + dst += GetGPRSize(); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_powerpc, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_powerpc; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() +{ + return 0; +} + diff --git a/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h new file mode 100644 index 000000000000..92a331285515 --- /dev/null +++ b/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +class RegisterContextPOSIXProcessMonitor_powerpc: + public RegisterContextPOSIX_powerpc, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index b9f6c7e7e334..addfa41b0eb9 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -16,6 +16,7 @@ add_lldb_library(lldbPluginProcessUtility RegisterContextDummy.cpp RegisterContextFreeBSD_i386.cpp RegisterContextFreeBSD_mips64.cpp + RegisterContextFreeBSD_powerpc.cpp RegisterContextFreeBSD_x86_64.cpp RegisterContextHistory.cpp RegisterContextLinux_arm64.cpp @@ -29,6 +30,7 @@ add_lldb_library(lldbPluginProcessUtility RegisterContextMemory.cpp RegisterContextPOSIX_arm64.cpp RegisterContextPOSIX_mips64.cpp + RegisterContextPOSIX_powerpc.cpp RegisterContextPOSIX_x86.cpp RegisterContextThreadMemory.cpp StopInfoMachException.cpp diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp new file mode 100644 index 000000000000..375f9b8f65ce --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp @@ -0,0 +1,227 @@ +//===-- RegisterContextFreeBSD_powerpc.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include +#include "RegisterContextPOSIX_powerpc.h" +#include "RegisterContextFreeBSD_powerpc.h" + +using namespace lldb_private; +using namespace lldb; + +// http://svnweb.freebsd.org/base/head/sys/powerpc/include/reg.h +typedef struct _GPR64 +{ + uint64_t r0; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t r26; + uint64_t r27; + uint64_t r28; + uint64_t r29; + uint64_t r30; + uint64_t r31; + uint64_t lr; + uint64_t cr; + uint64_t xer; + uint64_t ctr; + uint64_t pc; +} GPR64; + +typedef struct _GPR32 +{ + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t r13; + uint32_t r14; + uint32_t r15; + uint32_t r16; + uint32_t r17; + uint32_t r18; + uint32_t r19; + uint32_t r20; + uint32_t r21; + uint32_t r22; + uint32_t r23; + uint32_t r24; + uint32_t r25; + uint32_t r26; + uint32_t r27; + uint32_t r28; + uint32_t r29; + uint32_t r30; + uint32_t r31; + uint32_t lr; + uint32_t cr; + uint32_t xer; + uint32_t ctr; + uint32_t pc; +} GPR32; + +typedef struct _FPR +{ + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint64_t f4; + uint64_t f5; + uint64_t f6; + uint64_t f7; + uint64_t f8; + uint64_t f9; + uint64_t f10; + uint64_t f11; + uint64_t f12; + uint64_t f13; + uint64_t f14; + uint64_t f15; + uint64_t f16; + uint64_t f17; + uint64_t f18; + uint64_t f19; + uint64_t f20; + uint64_t f21; + uint64_t f22; + uint64_t f23; + uint64_t f24; + uint64_t f25; + uint64_t f26; + uint64_t f27; + uint64_t f28; + uint64_t f29; + uint64_t f30; + uint64_t f31; + uint64_t fpscr; +} FPR; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_powerpc to declare our g_register_infos_powerpc structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_POWERPC_STRUCT +#include "RegisterInfos_powerpc.h" +#undef DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc() +{ +} + +size_t +RegisterContextFreeBSD_powerpc::GetGPRSize() const +{ + return sizeof(GPR64); +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + llvm_unreachable("Abstract class!"); + return NULL; +} + +uint32_t +RegisterContextFreeBSD_powerpc::GetRegisterCount () const +{ + return 0; +} + +RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32(const ArchSpec &target_arch) : + RegisterContextFreeBSD_powerpc(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32() +{ +} + +size_t +RegisterContextFreeBSD_powerpc32::GetGPRSize() const +{ + return sizeof(GPR32); +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc32::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + return g_register_infos_powerpc32; +} + +uint32_t +RegisterContextFreeBSD_powerpc32::GetRegisterCount () const +{ + return static_cast (sizeof (g_register_infos_powerpc32) / sizeof (g_register_infos_powerpc32 [0])); +} + +RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64(const ArchSpec &target_arch) : + RegisterContextFreeBSD_powerpc(target_arch) +{ +} + +RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64() +{ +} + +size_t +RegisterContextFreeBSD_powerpc64::GetGPRSize() const +{ + return sizeof(GPR64); +} + +const RegisterInfo * +RegisterContextFreeBSD_powerpc64::GetRegisterInfo() const +{ + //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc); + return g_register_infos_powerpc64; +} + +uint32_t +RegisterContextFreeBSD_powerpc64::GetRegisterCount () const +{ + return static_cast (sizeof (g_register_infos_powerpc64) / sizeof (g_register_infos_powerpc64 [0])); +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h new file mode 100644 index 000000000000..b907fe99b5e0 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h @@ -0,0 +1,66 @@ +//===-- RegisterContextFreeBSD_powerpc.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextFreeBSD_powerpc_H_ +#define liblldb_RegisterContextFreeBSD_powerpc_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextFreeBSD_powerpc: + public lldb_private::RegisterInfoInterface +{ +public: + RegisterContextFreeBSD_powerpc(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +class RegisterContextFreeBSD_powerpc32: + public RegisterContextFreeBSD_powerpc +{ +public: + RegisterContextFreeBSD_powerpc32(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc32(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +class RegisterContextFreeBSD_powerpc64: + public RegisterContextFreeBSD_powerpc +{ +public: + RegisterContextFreeBSD_powerpc64(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_powerpc64(); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount() const override; +}; + +#endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index e246e715de86..5579b0b64fc9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,8 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && \ + !defined(__mips__) && !defined(__powerpc__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp new file mode 100644 index 000000000000..a9477d583517 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -0,0 +1,273 @@ +//===-- RegisterContextPOSIX_powerpc.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb_private; +using namespace lldb; + +static const +uint32_t g_gpr_regnums[] = +{ + gpr_r0_powerpc, + gpr_r1_powerpc, + gpr_r2_powerpc, + gpr_r3_powerpc, + gpr_r4_powerpc, + gpr_r5_powerpc, + gpr_r6_powerpc, + gpr_r7_powerpc, + gpr_r8_powerpc, + gpr_r9_powerpc, + gpr_r10_powerpc, + gpr_r11_powerpc, + gpr_r12_powerpc, + gpr_r13_powerpc, + gpr_r14_powerpc, + gpr_r15_powerpc, + gpr_r16_powerpc, + gpr_r17_powerpc, + gpr_r18_powerpc, + gpr_r19_powerpc, + gpr_r20_powerpc, + gpr_r21_powerpc, + gpr_r22_powerpc, + gpr_r23_powerpc, + gpr_r24_powerpc, + gpr_r25_powerpc, + gpr_r26_powerpc, + gpr_r27_powerpc, + gpr_r28_powerpc, + gpr_r29_powerpc, + gpr_r30_powerpc, + gpr_r31_powerpc, + gpr_lr_powerpc, + gpr_cr_powerpc, + gpr_xer_powerpc, + gpr_ctr_powerpc, + gpr_pc_powerpc, +}; + +static const +uint32_t g_fpr_regnums[] = +{ + fpr_f0_powerpc, + fpr_f1_powerpc, + fpr_f2_powerpc, + fpr_f3_powerpc, + fpr_f4_powerpc, + fpr_f5_powerpc, + fpr_f6_powerpc, + fpr_f7_powerpc, + fpr_f8_powerpc, + fpr_f9_powerpc, + fpr_f10_powerpc, + fpr_f11_powerpc, + fpr_f12_powerpc, + fpr_f13_powerpc, + fpr_f14_powerpc, + fpr_f15_powerpc, + fpr_f16_powerpc, + fpr_f17_powerpc, + fpr_f18_powerpc, + fpr_f19_powerpc, + fpr_f20_powerpc, + fpr_f21_powerpc, + fpr_f22_powerpc, + fpr_f23_powerpc, + fpr_f24_powerpc, + fpr_f25_powerpc, + fpr_f26_powerpc, + fpr_f27_powerpc, + fpr_f28_powerpc, + fpr_f29_powerpc, + fpr_f30_powerpc, + fpr_f31_powerpc, + fpr_fpscr_powerpc, +}; + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +static const RegisterSet +g_reg_sets_powerpc[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, g_gpr_regnums }, + { "Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, g_fpr_regnums }, +}; + +bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg) +{ + return reg <= k_num_gpr_registers_powerpc; // GPR's come first. +} + +bool +RegisterContextPOSIX_powerpc::IsFPR(unsigned reg) +{ + // XXX + return (reg >= k_first_fpr) && (reg <= k_last_fpr); +} + +RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + // elf-core yet to support ReadFPR() + ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() +{ +} + +void +RegisterContextPOSIX_powerpc::Invalidate() +{ +} + +void +RegisterContextPOSIX_powerpc::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_powerpc::GetRegisterOffset(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_powerpc::GetRegisterSize(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_powerpc::GetRegisterCount() +{ + size_t num_registers = k_num_registers_powerpc; + return num_registers; +} + +size_t +RegisterContextPOSIX_powerpc::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize(); +} + +const RegisterInfo * +RegisterContextPOSIX_powerpc::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const RegisterInfo * +RegisterContextPOSIX_powerpc::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < k_num_registers_powerpc) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_powerpc::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const RegisterSet * +RegisterContextPOSIX_powerpc::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + return &g_reg_sets_powerpc[set]; + else + return NULL; +} + +const char * +RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg) +{ + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_powerpc::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index) +{ + size_t num_sets = k_num_register_sets; + + return (set_index < num_sets); +} + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + assert (kind < kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + + if (reg_info->kinds[kind] == num) + return reg_idx; + } + + return LLDB_INVALID_REGNUM; +} + diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h new file mode 100644 index 000000000000..3194c3968c98 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -0,0 +1,173 @@ +//===-- RegisterContextPOSIX_powerpc.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_powerpc_H_ +#define liblldb_RegisterContextPOSIX_powerpc_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContext_powerpc.h" + +class ProcessMonitor; + +// --------------------------------------------------------------------------- +// Internal codes for all powerpc registers. +// --------------------------------------------------------------------------- +enum +{ + k_first_gpr_powerpc, + gpr_r0_powerpc = k_first_gpr_powerpc, + gpr_r1_powerpc, + gpr_r2_powerpc, + gpr_r3_powerpc, + gpr_r4_powerpc, + gpr_r5_powerpc, + gpr_r6_powerpc, + gpr_r7_powerpc, + gpr_r8_powerpc, + gpr_r9_powerpc, + gpr_r10_powerpc, + gpr_r11_powerpc, + gpr_r12_powerpc, + gpr_r13_powerpc, + gpr_r14_powerpc, + gpr_r15_powerpc, + gpr_r16_powerpc, + gpr_r17_powerpc, + gpr_r18_powerpc, + gpr_r19_powerpc, + gpr_r20_powerpc, + gpr_r21_powerpc, + gpr_r22_powerpc, + gpr_r23_powerpc, + gpr_r24_powerpc, + gpr_r25_powerpc, + gpr_r26_powerpc, + gpr_r27_powerpc, + gpr_r28_powerpc, + gpr_r29_powerpc, + gpr_r30_powerpc, + gpr_r31_powerpc, + gpr_lr_powerpc, + gpr_cr_powerpc, + gpr_xer_powerpc, + gpr_ctr_powerpc, + gpr_pc_powerpc, + k_last_gpr_powerpc = gpr_pc_powerpc, + + k_first_fpr, + fpr_f0_powerpc = k_first_fpr, + fpr_f1_powerpc, + fpr_f2_powerpc, + fpr_f3_powerpc, + fpr_f4_powerpc, + fpr_f5_powerpc, + fpr_f6_powerpc, + fpr_f7_powerpc, + fpr_f8_powerpc, + fpr_f9_powerpc, + fpr_f10_powerpc, + fpr_f11_powerpc, + fpr_f12_powerpc, + fpr_f13_powerpc, + fpr_f14_powerpc, + fpr_f15_powerpc, + fpr_f16_powerpc, + fpr_f17_powerpc, + fpr_f18_powerpc, + fpr_f19_powerpc, + fpr_f20_powerpc, + fpr_f21_powerpc, + fpr_f22_powerpc, + fpr_f23_powerpc, + fpr_f24_powerpc, + fpr_f25_powerpc, + fpr_f26_powerpc, + fpr_f27_powerpc, + fpr_f28_powerpc, + fpr_f29_powerpc, + fpr_f30_powerpc, + fpr_f31_powerpc, + fpr_fpscr_powerpc, + k_last_fpr = fpr_fpscr_powerpc, + + k_num_registers_powerpc, + k_num_gpr_registers_powerpc = k_last_gpr_powerpc - k_first_gpr_powerpc + 1, + k_num_fpr_registers_powerpc = k_last_fpr - k_first_fpr + 1, +}; + +class RegisterContextPOSIX_powerpc + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_powerpc (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_powerpc(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); + +protected: + uint64_t m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers. + std::unique_ptr m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_powerpc_H_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h new file mode 100644 index 000000000000..cf54cc0c2145 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h @@ -0,0 +1,163 @@ +//===-- RegisterContext_powerpc.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContext_powerpc_H_ +#define liblldb_RegisterContext_powerpc_H_ + +// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF) +enum +{ + gcc_dwarf_r0_powerpc = 0, + gcc_dwarf_r1_powerpc, + gcc_dwarf_r2_powerpc, + gcc_dwarf_r3_powerpc, + gcc_dwarf_r4_powerpc, + gcc_dwarf_r5_powerpc, + gcc_dwarf_r6_powerpc, + gcc_dwarf_r7_powerpc, + gcc_dwarf_r8_powerpc, + gcc_dwarf_r9_powerpc, + gcc_dwarf_r10_powerpc, + gcc_dwarf_r11_powerpc, + gcc_dwarf_r12_powerpc, + gcc_dwarf_r13_powerpc, + gcc_dwarf_r14_powerpc, + gcc_dwarf_r15_powerpc, + gcc_dwarf_r16_powerpc, + gcc_dwarf_r17_powerpc, + gcc_dwarf_r18_powerpc, + gcc_dwarf_r19_powerpc, + gcc_dwarf_r20_powerpc, + gcc_dwarf_r21_powerpc, + gcc_dwarf_r22_powerpc, + gcc_dwarf_r23_powerpc, + gcc_dwarf_r24_powerpc, + gcc_dwarf_r25_powerpc, + gcc_dwarf_r26_powerpc, + gcc_dwarf_r27_powerpc, + gcc_dwarf_r28_powerpc, + gcc_dwarf_r29_powerpc, + gcc_dwarf_r30_powerpc, + gcc_dwarf_r31_powerpc, + gcc_dwarf_f0_powerpc, + gcc_dwarf_f1_powerpc, + gcc_dwarf_f2_powerpc, + gcc_dwarf_f3_powerpc, + gcc_dwarf_f4_powerpc, + gcc_dwarf_f5_powerpc, + gcc_dwarf_f6_powerpc, + gcc_dwarf_f7_powerpc, + gcc_dwarf_f8_powerpc, + gcc_dwarf_f9_powerpc, + gcc_dwarf_f10_powerpc, + gcc_dwarf_f11_powerpc, + gcc_dwarf_f12_powerpc, + gcc_dwarf_f13_powerpc, + gcc_dwarf_f14_powerpc, + gcc_dwarf_f15_powerpc, + gcc_dwarf_f16_powerpc, + gcc_dwarf_f17_powerpc, + gcc_dwarf_f18_powerpc, + gcc_dwarf_f19_powerpc, + gcc_dwarf_f20_powerpc, + gcc_dwarf_f21_powerpc, + gcc_dwarf_f22_powerpc, + gcc_dwarf_f23_powerpc, + gcc_dwarf_f24_powerpc, + gcc_dwarf_f25_powerpc, + gcc_dwarf_f26_powerpc, + gcc_dwarf_f27_powerpc, + gcc_dwarf_f28_powerpc, + gcc_dwarf_f29_powerpc, + gcc_dwarf_f30_powerpc, + gcc_dwarf_f31_powerpc, + gcc_dwarf_cr_powerpc, + gcc_dwarf_fpscr_powerpc, + gcc_dwarf_xer_powerpc = 101, + gcc_dwarf_lr_powerpc = 108, + gcc_dwarf_ctr_powerpc, + gcc_dwarf_pc_powerpc, +}; + +// GDB Register numbers (eRegisterKindGDB) +enum +{ + gdb_r0_powerpc = 0, + gdb_r1_powerpc, + gdb_r2_powerpc, + gdb_r3_powerpc, + gdb_r4_powerpc, + gdb_r5_powerpc, + gdb_r6_powerpc, + gdb_r7_powerpc, + gdb_r8_powerpc, + gdb_r9_powerpc, + gdb_r10_powerpc, + gdb_r11_powerpc, + gdb_r12_powerpc, + gdb_r13_powerpc, + gdb_r14_powerpc, + gdb_r15_powerpc, + gdb_r16_powerpc, + gdb_r17_powerpc, + gdb_r18_powerpc, + gdb_r19_powerpc, + gdb_r20_powerpc, + gdb_r21_powerpc, + gdb_r22_powerpc, + gdb_r23_powerpc, + gdb_r24_powerpc, + gdb_r25_powerpc, + gdb_r26_powerpc, + gdb_r27_powerpc, + gdb_r28_powerpc, + gdb_r29_powerpc, + gdb_r30_powerpc, + gdb_r31_powerpc, + gdb_f0_powerpc, + gdb_f1_powerpc, + gdb_f2_powerpc, + gdb_f3_powerpc, + gdb_f4_powerpc, + gdb_f5_powerpc, + gdb_f6_powerpc, + gdb_f7_powerpc, + gdb_f8_powerpc, + gdb_f9_powerpc, + gdb_f10_powerpc, + gdb_f11_powerpc, + gdb_f12_powerpc, + gdb_f13_powerpc, + gdb_f14_powerpc, + gdb_f15_powerpc, + gdb_f16_powerpc, + gdb_f17_powerpc, + gdb_f18_powerpc, + gdb_f19_powerpc, + gdb_f20_powerpc, + gdb_f21_powerpc, + gdb_f22_powerpc, + gdb_f23_powerpc, + gdb_f24_powerpc, + gdb_f25_powerpc, + gdb_f26_powerpc, + gdb_f27_powerpc, + gdb_f28_powerpc, + gdb_f29_powerpc, + gdb_f30_powerpc, + gdb_f31_powerpc, + gdb_cr_powerpc, + gdb_fpscr_powerpc, + gdb_xer_powerpc = 101, + gdb_lr_powerpc = 108, + gdb_ctr_powerpc, + gdb_pc_powerpc, +}; + +#endif // liblldb_RegisterContext_powerpc_H_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h new file mode 100644 index 000000000000..67dd48705391 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h @@ -0,0 +1,127 @@ +//===-- RegisterInfos_powerpc.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (offsetof(GPR, regname)) +#define FPR_OFFSET(regname) \ + (offsetof(FPR, regname)) + +#ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, lldb_kind) \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, gpr_##reg##_powerpc }, NULL, NULL } +#define DEFINE_FPR(reg, lldb_kind) \ + { #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, \ + eFormatFloat, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, fpr_##reg##_powerpc }, NULL, NULL } + + // General purpose registers. GCC, DWARF, Generic, GDB +#define POWERPC_REGS \ + DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r1, "sp", LLDB_REGNUM_GENERIC_SP), \ + DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r3, "arg1",LLDB_REGNUM_GENERIC_ARG1), \ + DEFINE_GPR(r4, "arg2",LLDB_REGNUM_GENERIC_ARG2), \ + DEFINE_GPR(r5, "arg3",LLDB_REGNUM_GENERIC_ARG3), \ + DEFINE_GPR(r6, "arg4",LLDB_REGNUM_GENERIC_ARG4), \ + DEFINE_GPR(r7, "arg5",LLDB_REGNUM_GENERIC_ARG5), \ + DEFINE_GPR(r8, "arg6",LLDB_REGNUM_GENERIC_ARG6), \ + DEFINE_GPR(r9, "arg7",LLDB_REGNUM_GENERIC_ARG7), \ + DEFINE_GPR(r10, "arg8",LLDB_REGNUM_GENERIC_ARG8), \ + DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \ + DEFINE_GPR(lr, "lr", LLDB_REGNUM_GENERIC_RA), \ + DEFINE_GPR(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \ + DEFINE_GPR(xer, "xer", LLDB_INVALID_REGNUM), \ + DEFINE_GPR(ctr, "ctr", LLDB_INVALID_REGNUM), \ + DEFINE_GPR(pc, "pc", LLDB_REGNUM_GENERIC_PC), \ + DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \ + DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \ + { "fpscr", NULL, 8, FPR_OFFSET(fpscr), eEncodingUint, eFormatHex, { gcc_dwarf_fpscr_powerpc, gcc_dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, gdb_fpscr_powerpc, fpr_fpscr_powerpc }, NULL, NULL }, + //{ NULL, NULL, sizeof(((GPR*)NULL)->r0), 0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_cfa_powerpc}, NULL, NULL} +static RegisterInfo +g_register_infos_powerpc64[] = +{ +#define GPR GPR64 + POWERPC_REGS +#undef GPR +}; + +static RegisterInfo +g_register_infos_powerpc32[] = +{ +#define GPR GPR32 + POWERPC_REGS +#undef GPR +}; +static_assert((sizeof(g_register_infos_powerpc32) / sizeof(g_register_infos_powerpc32[0])) == k_num_registers_powerpc, + "g_register_infos_powerpc32 has wrong number of register infos"); +static_assert((sizeof(g_register_infos_powerpc64) / sizeof(g_register_infos_powerpc64[0])) == k_num_registers_powerpc, + "g_register_infos_powerpc64 has wrong number of register infos"); + +#undef DEFINE_FPR +#undef DEFINE_GPR + +#endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT + +#undef GPR_OFFSET + diff --git a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt index 29c301863476..2f5de56ac1c9 100644 --- a/lldb/source/Plugins/Process/elf-core/CMakeLists.txt +++ b/lldb/source/Plugins/Process/elf-core/CMakeLists.txt @@ -6,5 +6,6 @@ add_lldb_library(lldbPluginProcessElfCore ProcessElfCore.cpp ThreadElfCore.cpp RegisterContextPOSIXCore_mips64.cpp + RegisterContextPOSIXCore_powerpc.cpp RegisterContextPOSIXCore_x86_64.cpp ) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 566816783c7e..38e092f5d32a 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -420,6 +420,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, { lldb::offset_t offset = 0; bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::ppc64 || arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp new file mode 100644 index 000000000000..15b1b44182d7 --- /dev/null +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp @@ -0,0 +1,109 @@ +//===-- RegisterContextCorePOSIX_powerpc.cpp ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_powerpc.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_powerpc(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + m_fpr_buffer.reset(new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize())); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc() +{ +} + +bool +RegisterContextCorePOSIX_powerpc::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadFPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + lldb::offset_t offset = reg_info->byte_offset; + if (reg_info->name[0] == 'f') { + uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + } else { + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + if (reg_info->byte_size < sizeof(v)) + value = (uint32_t)v; + else + value = v; + return true; + } + } + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_powerpc::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h new file mode 100644 index 000000000000..e6575581b360 --- /dev/null +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h @@ -0,0 +1,62 @@ +//===-- RegisterContextCorePOSIX_powerpc.h ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_ +#define liblldb_RegisterContextCorePOSIX_powerpc_H_ + +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +class RegisterContextCorePOSIX_powerpc : + public RegisterContextPOSIX_powerpc +{ +public: + RegisterContextCorePOSIX_powerpc (lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_powerpc(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_ diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 4b611bf45a9f..d62bcfcff600 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -19,8 +19,10 @@ #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "RegisterContextPOSIXCore_mips64.h" +#include "RegisterContextPOSIXCore_powerpc.h" #include "RegisterContextPOSIXCore_x86_64.h" using namespace lldb; @@ -94,6 +96,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { switch (arch.GetMachine()) { + case llvm::Triple::ppc: + reg_interface = new RegisterContextFreeBSD_powerpc32(arch); + break; + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(arch); + break; case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(arch); break; @@ -138,6 +146,10 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) case llvm::Triple::mips64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_powerpc (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 50e6f669cedb..f1beac69a8e6 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -2281,6 +2281,8 @@ Thread::GetUnwinder () case llvm::Triple::aarch64: case llvm::Triple::thumb: case llvm::Triple::mips64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc: case llvm::Triple::hexagon: m_unwinder_ap.reset (new UnwindLLDB (*this)); break; diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index 99a54b2a4e6e..e1de7291f2b6 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -31,6 +31,8 @@ #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" #include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h" #include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" +#include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h" +#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h" #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" #include "Plugins/Instruction/ARM/EmulateInstructionARM.h" @@ -132,6 +134,8 @@ lldb_private::Initialize () ABIMacOSX_arm::Initialize(); ABIMacOSX_arm64::Initialize(); ABISysV_x86_64::Initialize(); + ABISysV_ppc::Initialize(); + ABISysV_ppc64::Initialize(); DisassemblerLLVMC::Initialize(); ObjectContainerBSDArchive::Initialize(); ObjectFileELF::Initialize(); @@ -225,6 +229,7 @@ lldb_private::Terminate () ABIMacOSX_arm::Terminate(); ABIMacOSX_arm64::Terminate(); ABISysV_x86_64::Terminate(); + ABISysV_ppc64::Terminate(); DisassemblerLLVMC::Terminate(); ObjectContainerBSDArchive::Terminate(); ObjectFileELF::Terminate();