Index: include/lldb/Core/Architecture.h =================================================================== --- include/lldb/Core/Architecture.h +++ include/lldb/Core/Architecture.h @@ -33,6 +33,40 @@ //------------------------------------------------------------------ virtual void OverrideStopInfo(Thread &thread) = 0; + //------------------------------------------------------------------ + /// This method is used to get the number of bytes that should be + /// skipped, from function start address, to reach the first + /// instruction after the prologue. If overrode, it must return + /// non-zero only if the current address matches one of the known + /// function entry points. + /// + /// This method is called only if the standard platform-independent + /// code fails to get the number of bytes to skip, giving the plugin + /// a chance to try to find the missing info. + /// + /// This is specifically used for PPC64, where functions may have + /// more than one entry point, global and local, so both should + /// be compared with current address, 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(Symbol &func, const Address &curr_addr) const { + return 0; + } + + //------------------------------------------------------------------ + /// Adjust function breakpoint address, if needed. In some cases, + /// the function start address is not the right place to set the + /// breakpoint, specially in functions with multiple entry points. + /// + /// This is specifically used for PPC64, for functions that have + /// both a global and a local entry point. In this case, the + /// breakpoint is adjusted to the first function address reached + /// by both entry points. + //------------------------------------------------------------------ + virtual void AdjustBreakpointAddress(const Symbol &func, + Address &addr) const {} + private: Architecture(const Architecture &) = delete; void operator=(const Architecture &) = delete; Index: lit/Breakpoint/Inputs/ppc64-localentry.s =================================================================== --- /dev/null +++ lit/Breakpoint/Inputs/ppc64-localentry.s @@ -0,0 +1,70 @@ + .text + .abiversion 2 + .globl lfunc + .p2align 4 + .type lfunc,@function +lfunc: # @lfunc +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry lfunc, .Lfunc_lep0-.Lfunc_gep0 +# BB#0: + mr 4, 3 + addis 3, 2, .LC0@toc@ha + ld 3, .LC0@toc@l(3) + stw 4, -12(1) + lwz 4, 0(3) + lwz 5, -12(1) + mullw 4, 4, 5 + extsw 3, 4 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size lfunc, .Lfunc_end0-.Lfunc_begin0 + + .globl main + .p2align 4 + .type main,@function +main: # @main +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry main, .Lfunc_lep1-.Lfunc_gep1 +# BB#0: + mflr 0 + std 31, -8(1) + std 0, 16(1) + stdu 1, -112(1) + mr 31, 1 + li 3, 3 + li 4, 0 + stw 4, 100(31) + extsw 3, 3 + bl .Lfunc_lep0 + nop + extsw 3, 3 + addi 1, 1, 112 + ld 0, 16(1) + ld 31, -8(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size main, .Lfunc_end1-.Lfunc_begin1 + + .section .toc,"aw",@progbits +.LC0: + .tc g_foo[TC],g_foo + .type g_foo,@object # @g_foo + .data + .globl g_foo + .p2align 2 +g_foo: + .long 2 # 0x2 + .size g_foo, 4 Index: lit/Breakpoint/ppc64-localentry.test =================================================================== --- /dev/null +++ lit/Breakpoint/ppc64-localentry.test @@ -0,0 +1,8 @@ +# REQUIRES: powerpc +# +# RUN: llvm-mc -triple=powerpc64le -filetype=obj %p/Inputs/ppc64-localentry.s -o %t +# RUN: lldb-test breakpoints %t %s | FileCheck %s + +breakpoint set -n lfunc +# CHECK-LABEL: breakpoint set -n lfunc +# CHECK: Where: {{.*}}`lfunc + 8 Index: lit/lit.cfg =================================================================== --- lit/lit.cfg +++ lit/lit.cfg @@ -155,6 +155,8 @@ config.available_features.add('arm') if re.search(r'Mips', llvm_config_output_list[2]): config.available_features.add('mips') +if re.search(r'PowerPC', llvm_config_output_list[2]): + config.available_features.add('powerpc') if re.search(r'X86', llvm_config_output_list[2]): config.available_features.add('x86') llvm_config_cmd.wait() 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/Breakpoint/BreakpointResolverName.cpp =================================================================== --- source/Breakpoint/BreakpointResolverName.cpp +++ source/Breakpoint/BreakpointResolverName.cpp @@ -16,11 +16,13 @@ #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Architecture.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" @@ -365,6 +367,12 @@ sc.symbol->GetPrologueByteSize(); if (prologue_byte_size) break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); + else { + Architecture *arch = + m_breakpoint->GetTarget().GetArchitecturePlugin(); + if (arch) + arch->AdjustBreakpointAddress(*sc.symbol, break_addr); + } } } 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,44 @@ +//===-- 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 {} + + //------------------------------------------------------------------ + /// This method compares current address with current function's + /// local entry point, returning the bytes to skip if they match. + //------------------------------------------------------------------ + size_t GetBytesToSkip(Symbol &func, const Address &curr_addr) const override; + + void AdjustBreakpointAddress(const Symbol &func, + Address &addr) 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,69 @@ +//===-- 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/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.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) || + arch.GetTriple().getObjectFormat() != llvm::Triple::ObjectFormatType::ELF) + return nullptr; + return std::unique_ptr(new ArchitecturePPC64()); +} + +ConstString ArchitecturePPC64::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitecturePPC64::GetPluginVersion() { return 1; } + +static int32_t GetLocalEntryOffset(const Symbol &sym) { + unsigned char other = sym.GetFlags() >> 8 & 0xFF; + return llvm::ELF::decodePPC64LocalEntryOffset(other); +} + +size_t ArchitecturePPC64::GetBytesToSkip(Symbol &func, + const Address &curr_addr) const { + if (curr_addr.GetFileAddress() == + func.GetFileAddress() + GetLocalEntryOffset(func)) + return func.GetPrologueByteSize(); + return 0; +} + +void ArchitecturePPC64::AdjustBreakpointAddress(const Symbol &func, + Address &addr) const { + int32_t loffs = GetLocalEntryOffset(func); + if (!loffs) + return; + + addr.SetOffset(addr.GetOffset() + loffs); +} 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,11 +12,13 @@ // 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" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanStepOut.h" @@ -277,6 +279,17 @@ bytes_to_skip = sc.symbol->GetPrologueByteSize(); } + if (bytes_to_skip == 0 && sc.symbol) { + TargetSP target = m_thread.CalculateTarget(); + Architecture *arch = target->GetArchitecturePlugin(); + if (arch) { + Address curr_sec_addr; + target->GetSectionLoadList().ResolveLoadAddress(curr_addr, + curr_sec_addr); + bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr); + } + } + if (bytes_to_skip != 0) { func_start_address.Slide(bytes_to_skip); log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP); Index: tools/lldb-test/SystemInitializerTest.cpp =================================================================== --- tools/lldb-test/SystemInitializerTest.cpp +++ tools/lldb-test/SystemInitializerTest.cpp @@ -33,6 +33,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" @@ -161,6 +162,7 @@ ABISysV_s390x::Initialize(); ArchitectureArm::Initialize(); + ArchitecturePPC64::Initialize(); DisassemblerLLVMC::Initialize(); Index: tools/lldb-test/lldb-test.cpp =================================================================== --- tools/lldb-test/lldb-test.cpp +++ tools/lldb-test/lldb-test.cpp @@ -101,6 +101,12 @@ P.formatLine("Address: {0}+{1:x}", Loc->GetAddress().GetSection()->GetName(), Loc->GetAddress().GetOffset()); + SymbolContext sc; + Loc->GetAddress().CalculateSymbolContext(&sc); + lldb_private::StreamString S; + sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(), + Loc->GetAddress(), false, true, false, true, true); + P.formatLine("Where: {0}", S.GetString()); } } P.NewLine();