Index: include/lldb/Core/Architecture.h =================================================================== --- include/lldb/Core/Architecture.h +++ include/lldb/Core/Architecture.h @@ -33,6 +33,33 @@ //------------------------------------------------------------------ virtual void OverrideStopInfo(Thread &thread) = 0; + //------------------------------------------------------------------ + /// This method is used to get the number of bytes that should be + /// skipped to reach the first instruction after a function + /// prologue. This number is always relative to first function + /// instruction, which should be set at 'func_start_address', + /// if this method returns any value other than LLDB_INVALID_OFFSET. + /// The first function instruction is defined here as the + /// instruction found at the address of the function symbol and + /// thus is independent of which entry point was used to enter the + /// function. + /// + /// Returning LLDB_INVALID_OFFSET means this method was not able to + /// get the number of bytes to skip, and that the caller should + /// use the standard platform-independent method to get it. + /// + /// This is specifically used for PPC64, where functions may have + /// more than one entry point, global and local, so both should + /// be compared with curr_addr, in order to find out the number of + /// bytes that should be skipped, in case we are stopped at either + /// function entry point. + //------------------------------------------------------------------ + virtual size_t GetBytesToSkip(Target &target, SymbolContext &sc, + lldb::addr_t curr_addr, + Address &func_start_address) const { + return LLDB_INVALID_OFFSET; + } + private: Architecture(const Architecture &) = delete; void operator=(const Architecture &) = delete; Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -43,6 +43,7 @@ #include "Plugins/ABI/SysV-s390x/ABISysV_s390x.h" #include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" #include "Plugins/Architecture/Arm/ArchitectureArm.h" +#include "Plugins/Architecture/PPC64/ArchitecturePPC64.h" #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h" #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" @@ -307,6 +308,7 @@ ABISysV_s390x::Initialize(); ArchitectureArm::Initialize(); + ArchitecturePPC64::Initialize(); DisassemblerLLVMC::Initialize(); Index: source/Host/common/HostInfoBase.cpp =================================================================== --- source/Host/common/HostInfoBase.cpp +++ source/Host/common/HostInfoBase.cpp @@ -373,6 +373,7 @@ case llvm::Triple::aarch64: case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: case llvm::Triple::x86_64: arch_64.SetTriple(triple); arch_32.SetTriple(triple.get32BitArchVariant()); Index: source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp =================================================================== --- source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -70,13 +70,11 @@ //------------------------------------------------------------------ ABISP -ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) { - static ABISP g_abi_sp; +ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp, + const ArchSpec &arch) { if (arch.GetTriple().getArch() == llvm::Triple::ppc64 || arch.GetTriple().getArch() == llvm::Triple::ppc64le) { - if (!g_abi_sp) - g_abi_sp.reset(new ABISysV_ppc64(process_sp)); - return g_abi_sp; + return ABISP(new ABISysV_ppc64(process_sp)); } return ABISP(); } Index: source/Plugins/Architecture/CMakeLists.txt =================================================================== --- source/Plugins/Architecture/CMakeLists.txt +++ source/Plugins/Architecture/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(Arm) +add_subdirectory(PPC64) Index: source/Plugins/Architecture/PPC64/ArchitecturePPC64.h =================================================================== --- /dev/null +++ source/Plugins/Architecture/PPC64/ArchitecturePPC64.h @@ -0,0 +1,51 @@ +//===-- ArchitecturePPC64.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGIN_ARCHITECTURE_PPC64_H +#define LLDB_PLUGIN_ARCHITECTURE_PPC64_H + +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitecturePPC64 : public Architecture { +public: + static ConstString GetPluginNameStatic(); + static void Initialize(); + static void Terminate(); + + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + void OverrideStopInfo(Thread &thread) override {} + + //------------------------------------------------------------------ + /// On PPC64, the global entry point corresponds to first function + /// instruction and the local entry point is always an offset from + /// the global entry point, corresponding to the instructions that + /// should be skipped if the function is being called from a local + /// context. + /// This method compares 'curr_addr' with both global and local + /// function entry points and if either one is equal to 'curr_addr' + /// then 'func_start_address' is set to the global entry point and + /// the prologue size in bytes (relative to the global entry point) + /// is returned. + //------------------------------------------------------------------ + virtual size_t GetBytesToSkip(Target &target, SymbolContext &sc, + lldb::addr_t curr_addr, + Address &func_start_address) const override; + +private: + static std::unique_ptr Create(const ArchSpec &arch); + ArchitecturePPC64() = default; +}; + +} // namespace lldb_private + +#endif // LLDB_PLUGIN_ARCHITECTURE_PPC64_H Index: source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp =================================================================== --- /dev/null +++ source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp @@ -0,0 +1,89 @@ +//===-- ArchitecturePPC64.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/Architecture/PPC64/ArchitecturePPC64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" + +#include "llvm/BinaryFormat/ELF.h" + +using namespace lldb_private; +using namespace lldb; + +ConstString ArchitecturePPC64::GetPluginNameStatic() { + return ConstString("ppc64"); +} + +void ArchitecturePPC64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "PPC64-specific algorithms", + &ArchitecturePPC64::Create); +} + +void ArchitecturePPC64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitecturePPC64::Create); +} + +std::unique_ptr ArchitecturePPC64::Create(const ArchSpec &arch) { + if (arch.GetMachine() != llvm::Triple::ppc64 && + arch.GetMachine() != llvm::Triple::ppc64le) + return nullptr; + return std::unique_ptr(new ArchitecturePPC64()); +} + +ConstString ArchitecturePPC64::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitecturePPC64::GetPluginVersion() { return 1; } + +size_t ArchitecturePPC64::GetBytesToSkip(Target &target, SymbolContext &sc, + lldb::addr_t curr_addr, + Address &func_start_address) const { + // This code handles only ELF files + if (target.GetArchitecture().GetTriple().getObjectFormat() != + llvm::Triple::ObjectFormatType::ELF) { + return LLDB_INVALID_OFFSET; + } + + auto GetLocalEntryOffset = [](Symbol &symbol) { + uint32_t flags = symbol.GetFlags(); + unsigned char other = flags >> 8 & 0xFF; + return llvm::ELF::decodePPC64LocalEntryOffset(other); + }; + + // For either functions or symbols, compare PC with both global and local + // entry points, returning the number of bytes that should be skipped after + // the function global entry point if any address matches. + if (sc.function) { + func_start_address = sc.function->GetAddressRange().GetBaseAddress(); + lldb::addr_t func_abs_start_addr = + func_start_address.GetLoadAddress(&target); + + if (curr_addr == func_abs_start_addr) { + return sc.function->GetPrologueByteSize(); + } else if (sc.symbol) { + if (curr_addr == func_abs_start_addr + GetLocalEntryOffset(*sc.symbol)) + return sc.function->GetPrologueByteSize(); + } + } else if (sc.symbol) { + func_start_address = sc.symbol->GetAddress(); + lldb::addr_t func_abs_start_addr = + func_start_address.GetLoadAddress(&target); + if (curr_addr == func_abs_start_addr || + curr_addr == func_abs_start_addr + GetLocalEntryOffset(*sc.symbol)) + return sc.symbol->GetPrologueByteSize(); + } + + // If we reached this point, then we were not able to match the current + // address with any function entry point. + // As the platform-independent method will certainly be unable to do it too, + // fall back to not skip anything. + return 0; +} Index: source/Plugins/Architecture/PPC64/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Architecture/PPC64/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginArchitecturePPC64 PLUGIN + ArchitecturePPC64.cpp + + LINK_LIBS + lldbPluginProcessUtility + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) Index: source/Target/ThreadPlanStepInRange.cpp =================================================================== --- source/Target/ThreadPlanStepInRange.cpp +++ source/Target/ThreadPlanStepInRange.cpp @@ -12,6 +12,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Core/Architecture.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" @@ -256,25 +257,32 @@ m_step_past_prologue) { lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); if (curr_frame) { - size_t bytes_to_skip = 0; + size_t bytes_to_skip = LLDB_INVALID_OFFSET; lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); + TargetSP target = m_thread.CalculateTarget(); Address func_start_address; SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol); - if (sc.function) { - func_start_address = sc.function->GetAddressRange().GetBaseAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) - bytes_to_skip = sc.function->GetPrologueByteSize(); - } else if (sc.symbol) { - func_start_address = sc.symbol->GetAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) - bytes_to_skip = sc.symbol->GetPrologueByteSize(); + Architecture *architecture = target->GetArchitecturePlugin(); + if (architecture) + bytes_to_skip = architecture->GetBytesToSkip(*target, sc, curr_addr, + func_start_address); + + if (bytes_to_skip == LLDB_INVALID_OFFSET) { + bytes_to_skip = 0; + if (sc.function) { + func_start_address = + sc.function->GetAddressRange().GetBaseAddress(); + if (curr_addr == func_start_address.GetLoadAddress(target.get())) + bytes_to_skip = sc.function->GetPrologueByteSize(); + } else if (sc.symbol) { + func_start_address = sc.symbol->GetAddress(); + if (curr_addr == func_start_address.GetLoadAddress( + m_thread.CalculateTarget().get())) + bytes_to_skip = sc.symbol->GetPrologueByteSize(); + } } if (bytes_to_skip != 0) {