[Lldb-commits] [lldb] r363458 - Implement GetSharedLibraryInfoAddress
Antonio Afonso via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 14 14:15:08 PDT 2019
Author: aadsm
Date: Fri Jun 14 14:15:08 2019
New Revision: 363458
URL: http://llvm.org/viewvc/llvm-project?rev=363458&view=rev
Log:
Implement GetSharedLibraryInfoAddress
Summary:
This is the third patch to improve module loading in a series that started here (where I explain the motivation and solution): D62499
Add functions to read the r_debug location to know where the linked list of loaded libraries are so I can generate the `xfer:libraries-svr4` packet.
I'm also using this function to implement `GetSharedLibraryInfoAddress` that was "not implemented" for linux.
Most of this code was inspired by the current ds2 implementation here: https://github.com/facebook/ds2/blob/master/Sources/Target/POSIX/ELFProcess.cpp.
Reviewers: clayborg, xiaobai, labath
Reviewed By: clayborg, labath
Subscribers: emaste, krytarowski, mgorny, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D62501
Added:
lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.cpp
lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.h
lldb/trunk/unittests/Process/POSIX/
lldb/trunk/unittests/Process/POSIX/CMakeLists.txt
lldb/trunk/unittests/Process/POSIX/NativeProcessELFTest.cpp
lldb/trunk/unittests/TestingSupport/Host/
lldb/trunk/unittests/TestingSupport/Host/NativeProcessTestUtils.h
Modified:
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt
lldb/trunk/unittests/Host/NativeProcessProtocolTest.cpp
lldb/trunk/unittests/Process/CMakeLists.txt
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=363458&r1=363457&r2=363458&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Fri Jun 14 14:15:08 2019
@@ -288,7 +288,7 @@ NativeProcessLinux::NativeProcessLinux(:
NativeDelegate &delegate,
const ArchSpec &arch, MainLoop &mainloop,
llvm::ArrayRef<::pid_t> tids)
- : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) {
+ : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
if (m_terminal_fd != -1) {
Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
assert(status.Success());
@@ -1389,11 +1389,6 @@ Status NativeProcessLinux::DeallocateMem
return Status("not implemented");
}
-lldb::addr_t NativeProcessLinux::GetSharedLibraryInfoAddress() {
- // punt on this for now
- return LLDB_INVALID_ADDRESS;
-}
-
size_t NativeProcessLinux::UpdateThreads() {
// The NativeProcessLinux monitoring threads are always up to date with
// respect to thread state and they keep the thread list populated properly.
@@ -2082,18 +2077,3 @@ Status NativeProcessLinux::StopProcessor
return error;
}
-
-llvm::Optional<uint64_t>
-NativeProcessLinux::GetAuxValue(enum AuxVector::EntryType type) {
- if (m_aux_vector == nullptr) {
- auto buffer_or_error = GetAuxvData();
- if (!buffer_or_error)
- return llvm::None;
- DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
- buffer_or_error.get()->getBufferSize(),
- GetByteOrder(), GetAddressByteSize());
- m_aux_vector = llvm::make_unique<AuxVector>(auxv_data);
- }
-
- return m_aux_vector->GetAuxValue(type);
-}
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=363458&r1=363457&r2=363458&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Fri Jun 14 14:15:08 2019
@@ -12,7 +12,6 @@
#include <csignal>
#include <unordered_set>
-#include "Plugins/Process/Utility/AuxVector.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/linux/Support.h"
@@ -22,8 +21,8 @@
#include "lldb/lldb-types.h"
#include "NativeThreadLinux.h"
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
#include "ProcessorTrace.h"
-#include "lldb/Host/common/NativeProcessProtocol.h"
namespace lldb_private {
class Status;
@@ -37,7 +36,7 @@ namespace process_linux {
/// for debugging.
///
/// Changes in the inferior process state are broadcasted.
-class NativeProcessLinux : public NativeProcessProtocol {
+class NativeProcessLinux : public NativeProcessELF {
public:
class Factory : public NativeProcessProtocol::Factory {
public:
@@ -77,8 +76,6 @@ public:
Status DeallocateMemory(lldb::addr_t addr) override;
- lldb::addr_t GetSharedLibraryInfoAddress() override;
-
size_t UpdateThreads() override;
const ArchSpec &GetArchitecture() const override { return m_arch; }
@@ -103,8 +100,6 @@ public:
return getProcFile(GetID(), "auxv");
}
- llvm::Optional<uint64_t> GetAuxValue(enum AuxVector::EntryType type);
-
lldb::user_id_t StartTrace(const TraceOptions &config,
Status &error) override;
@@ -135,7 +130,6 @@ protected:
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;
- std::unique_ptr<AuxVector> m_aux_vector;
LazyBool m_supports_mem_region = eLazyBoolCalculate;
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
Modified: lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt?rev=363458&r1=363457&r2=363458&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/CMakeLists.txt Fri Jun 14 14:15:08 2019
@@ -1,9 +1,11 @@
add_lldb_library(lldbPluginProcessPOSIX PLUGIN
CrashReason.cpp
+ NativeProcessELF.cpp
ProcessMessage.cpp
ProcessPOSIXLog.cpp
LINK_LIBS
+ lldbPluginProcessUtility
lldbUtility
LINK_COMPONENTS
Support
Added: lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.cpp?rev=363458&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.cpp (added)
+++ lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.cpp Fri Jun 14 14:15:08 2019
@@ -0,0 +1,110 @@
+//===-- NativeProcessELF.cpp ---------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessELF.h"
+
+#include "lldb/Utility/DataExtractor.h"
+
+namespace lldb_private {
+
+llvm::Optional<uint64_t>
+NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
+ if (m_aux_vector == nullptr) {
+ auto buffer_or_error = GetAuxvData();
+ if (!buffer_or_error)
+ return llvm::None;
+ DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
+ buffer_or_error.get()->getBufferSize(),
+ GetByteOrder(), GetAddressByteSize());
+ m_aux_vector = llvm::make_unique<AuxVector>(auxv_data);
+ }
+
+ return m_aux_vector->GetAuxValue(type);
+}
+
+lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
+ if (!m_shared_library_info_addr.hasValue()) {
+ if (GetAddressByteSize() == 8)
+ m_shared_library_info_addr =
+ GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
+ llvm::ELF::Elf64_Dyn>();
+ else
+ m_shared_library_info_addr =
+ GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
+ llvm::ELF::Elf32_Dyn>();
+ }
+
+ return m_shared_library_info_addr.getValue();
+}
+
+template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
+ llvm::Optional<uint64_t> maybe_phdr_addr =
+ GetAuxValue(AuxVector::AUXV_AT_PHDR);
+ llvm::Optional<uint64_t> maybe_phdr_entry_size =
+ GetAuxValue(AuxVector::AUXV_AT_PHENT);
+ llvm::Optional<uint64_t> maybe_phdr_num_entries =
+ GetAuxValue(AuxVector::AUXV_AT_PHNUM);
+ if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
+ return LLDB_INVALID_ADDRESS;
+ lldb::addr_t phdr_addr = *maybe_phdr_addr;
+ size_t phdr_entry_size = *maybe_phdr_entry_size;
+ size_t phdr_num_entries = *maybe_phdr_num_entries;
+
+ // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
+ // what the load bias by calculating the difference of the program header
+ // load address and its virtual address.
+ lldb::offset_t load_bias;
+ bool found_load_bias = false;
+ lldb::addr_t dynamic_section_addr = 0;
+ uint64_t dynamic_section_size = 0;
+ bool found_dynamic_section = false;
+ ELF_PHDR phdr_entry;
+ for (size_t i = 0; i < phdr_num_entries; i++) {
+ size_t bytes_read;
+ auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
+ sizeof(phdr_entry), bytes_read);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
+ load_bias = phdr_addr - phdr_entry.p_vaddr;
+ found_load_bias = true;
+ }
+
+ if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
+ dynamic_section_addr = phdr_entry.p_vaddr;
+ dynamic_section_size = phdr_entry.p_memsz;
+ found_dynamic_section = true;
+ }
+ }
+
+ if (!found_load_bias || !found_dynamic_section)
+ return LLDB_INVALID_ADDRESS;
+
+ // Find the DT_DEBUG entry in the .dynamic section
+ dynamic_section_addr += load_bias;
+ ELF_DYN dynamic_entry;
+ size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
+ for (size_t i = 0; i < dynamic_num_entries; i++) {
+ size_t bytes_read;
+ auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
+ &dynamic_entry, sizeof(dynamic_entry), bytes_read);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
+ // link_map.
+ if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
+ return dynamic_section_addr + i * sizeof(dynamic_entry) +
+ sizeof(dynamic_entry.d_tag);
+ }
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+} // namespace lldb_private
\ No newline at end of file
Added: lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.h?rev=363458&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.h (added)
+++ lldb/trunk/source/Plugins/Process/POSIX/NativeProcessELF.h Fri Jun 14 14:15:08 2019
@@ -0,0 +1,46 @@
+//===-- NativeProcessELF.h ------------------------------------ -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessELF_H_
+#define liblldb_NativeProcessELF_H_
+
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "llvm/BinaryFormat/ELF.h"
+
+namespace lldb_private {
+
+/// \class NativeProcessELF
+/// Abstract class that extends \a NativeProcessProtocol with ELF specific
+/// logic. Meant to be subclassed by ELF based NativeProcess* implementations.
+class NativeProcessELF : public NativeProcessProtocol {
+ using NativeProcessProtocol::NativeProcessProtocol;
+
+protected:
+ template <typename T> struct ELFLinkMap {
+ T l_addr;
+ T l_name;
+ T l_ld;
+ T l_next;
+ T l_prev;
+ };
+
+ llvm::Optional<uint64_t> GetAuxValue(enum AuxVector::EntryType type);
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+ lldb::addr_t GetELFImageInfoAddress();
+
+ std::unique_ptr<AuxVector> m_aux_vector;
+ llvm::Optional<lldb::addr_t> m_shared_library_info_addr;
+};
+
+} // namespace lldb_private
+
+#endif
\ No newline at end of file
Modified: lldb/trunk/unittests/Host/NativeProcessProtocolTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Host/NativeProcessProtocolTest.cpp?rev=363458&r1=363457&r2=363458&view=diff
==============================================================================
--- lldb/trunk/unittests/Host/NativeProcessProtocolTest.cpp (original)
+++ lldb/trunk/unittests/Host/NativeProcessProtocolTest.cpp Fri Jun 14 14:15:08 2019
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include "TestingSupport/Host/NativeProcessTestUtils.h"
+
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
@@ -14,142 +16,10 @@ using namespace lldb_private;
using namespace lldb;
using namespace testing;
-namespace {
-class MockDelegate : public NativeProcessProtocol::NativeDelegate {
-public:
- MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));
- MOCK_METHOD2(ProcessStateChanged,
- void(NativeProcessProtocol *Process, StateType State));
- MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));
-};
-
-// NB: This class doesn't use the override keyword to avoid
-// -Winconsistent-missing-override warnings from the compiler. The
-// inconsistency comes from the overriding definitions in the MOCK_*** macros.
-class MockProcess : public NativeProcessProtocol {
-public:
- MockProcess(NativeDelegate &Delegate, const ArchSpec &Arch,
- lldb::pid_t Pid = 1)
- : NativeProcessProtocol(Pid, -1, Delegate), Arch(Arch) {}
-
- MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));
- MOCK_METHOD0(Halt, Status());
- MOCK_METHOD0(Detach, Status());
- MOCK_METHOD1(Signal, Status(int Signo));
- MOCK_METHOD0(Kill, Status());
- MOCK_METHOD3(AllocateMemory,
- Status(size_t Size, uint32_t Permissions, addr_t &Addr));
- MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr));
- MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
- MOCK_METHOD0(UpdateThreads, size_t());
- MOCK_CONST_METHOD0(GetAuxvData,
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());
- MOCK_METHOD2(GetLoadedModuleFileSpec,
- Status(const char *ModulePath, FileSpec &Spec));
- MOCK_METHOD2(GetFileLoadAddress,
- Status(const llvm::StringRef &FileName, addr_t &Addr));
-
- const ArchSpec &GetArchitecture() const /*override*/ { return Arch; }
- Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,
- bool Hardware) /*override*/ {
- if (Hardware)
- return SetHardwareBreakpoint(Addr, Size);
- else
- return SetSoftwareBreakpoint(Addr, Size);
- }
-
- // Redirect base class Read/Write Memory methods to functions whose signatures
- // are more mock-friendly.
- Status ReadMemory(addr_t Addr, void *Buf, size_t Size,
- size_t &BytesRead) /*override*/;
- Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,
- size_t &BytesWritten) /*override*/;
-
- MOCK_METHOD2(ReadMemory,
- llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));
- MOCK_METHOD2(WriteMemory,
- llvm::Expected<size_t>(addr_t Addr,
- llvm::ArrayRef<uint8_t> Data));
-
- using NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode;
- llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,
- size_t Size);
-
-private:
- ArchSpec Arch;
-};
-
-class FakeMemory {
-public:
- FakeMemory(llvm::ArrayRef<uint8_t> Data) : Data(Data) {}
- llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size);
- llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk);
-
-private:
- std::vector<uint8_t> Data;
-};
-} // namespace
-
-Status MockProcess::ReadMemory(addr_t Addr, void *Buf, size_t Size,
- size_t &BytesRead) {
- auto ExpectedMemory = ReadMemory(Addr, Size);
- if (!ExpectedMemory) {
- BytesRead = 0;
- return Status(ExpectedMemory.takeError());
- }
- BytesRead = ExpectedMemory->size();
- assert(BytesRead <= Size);
- std::memcpy(Buf, ExpectedMemory->data(), BytesRead);
- return Status();
-}
-
-Status MockProcess::WriteMemory(addr_t Addr, const void *Buf, size_t Size,
- size_t &BytesWritten) {
- auto ExpectedBytes = WriteMemory(
- Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size));
- if (!ExpectedBytes) {
- BytesWritten = 0;
- return Status(ExpectedBytes.takeError());
- }
- BytesWritten = *ExpectedBytes;
- return Status();
-}
-
-llvm::Expected<std::vector<uint8_t>>
-MockProcess::ReadMemoryWithoutTrap(addr_t Addr, size_t Size) {
- std::vector<uint8_t> Data(Size, 0);
- size_t BytesRead;
- Status ST = NativeProcessProtocol::ReadMemoryWithoutTrap(
- Addr, Data.data(), Data.size(), BytesRead);
- if (ST.Fail())
- return ST.ToError();
- Data.resize(BytesRead);
- return std::move(Data);
-}
-
-llvm::Expected<std::vector<uint8_t>> FakeMemory::Read(addr_t Addr,
- size_t Size) {
- if (Addr >= Data.size())
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Address out of range.");
- Size = std::min(Size, Data.size() - (size_t)Addr);
- auto Begin = std::next(Data.begin(), Addr);
- return std::vector<uint8_t>(Begin, std::next(Begin, Size));
-}
-
-llvm::Expected<size_t> FakeMemory::Write(addr_t Addr,
- llvm::ArrayRef<uint8_t> Chunk) {
- if (Addr >= Data.size())
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Address out of range.");
- size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);
- std::copy_n(Chunk.begin(), Size, &Data[Addr]);
- return Size;
-}
-
TEST(NativeProcessProtocolTest, SetBreakpoint) {
NiceMock<MockDelegate> DummyDelegate;
- MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("x86_64-pc-linux"));
auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
InSequence S;
EXPECT_CALL(Process, ReadMemory(0x47, 1))
@@ -162,7 +32,8 @@ TEST(NativeProcessProtocolTest, SetBreak
TEST(NativeProcessProtocolTest, SetBreakpointFailRead) {
NiceMock<MockDelegate> DummyDelegate;
- MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("x86_64-pc-linux"));
EXPECT_CALL(Process, ReadMemory(0x47, 1))
.WillOnce(Return(ByMove(
llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
@@ -172,7 +43,8 @@ TEST(NativeProcessProtocolTest, SetBreak
TEST(NativeProcessProtocolTest, SetBreakpointFailWrite) {
NiceMock<MockDelegate> DummyDelegate;
- MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("x86_64-pc-linux"));
auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
InSequence S;
EXPECT_CALL(Process, ReadMemory(0x47, 1))
@@ -186,7 +58,8 @@ TEST(NativeProcessProtocolTest, SetBreak
TEST(NativeProcessProtocolTest, SetBreakpointFailVerify) {
NiceMock<MockDelegate> DummyDelegate;
- MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("x86_64-pc-linux"));
auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
InSequence S;
EXPECT_CALL(Process, ReadMemory(0x47, 1))
@@ -201,7 +74,8 @@ TEST(NativeProcessProtocolTest, SetBreak
TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) {
NiceMock<MockDelegate> DummyDelegate;
- MockProcess Process(DummyDelegate, ArchSpec("aarch64-pc-linux"));
+ MockProcess<NativeProcessProtocol> Process(DummyDelegate,
+ ArchSpec("aarch64-pc-linux"));
FakeMemory M{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
EXPECT_CALL(Process, ReadMemory(_, _))
.WillRepeatedly(Invoke(&M, &FakeMemory::Read));
Modified: lldb/trunk/unittests/Process/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/CMakeLists.txt?rev=363458&r1=363457&r2=363458&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/CMakeLists.txt (original)
+++ lldb/trunk/unittests/Process/CMakeLists.txt Fri Jun 14 14:15:08 2019
@@ -1,5 +1,6 @@
add_subdirectory(gdb-remote)
if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
add_subdirectory(Linux)
+ add_subdirectory(POSIX)
endif()
add_subdirectory(minidump)
Added: lldb/trunk/unittests/Process/POSIX/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/POSIX/CMakeLists.txt?rev=363458&view=auto
==============================================================================
--- lldb/trunk/unittests/Process/POSIX/CMakeLists.txt (added)
+++ lldb/trunk/unittests/Process/POSIX/CMakeLists.txt Fri Jun 14 14:15:08 2019
@@ -0,0 +1,8 @@
+include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/POSIX)
+
+add_lldb_unittest(ProcessPOSIXTest
+ NativeProcessELFTest.cpp
+
+ LINK_LIBS
+ lldbPluginProcessPOSIX
+ )
Added: lldb/trunk/unittests/Process/POSIX/NativeProcessELFTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/POSIX/NativeProcessELFTest.cpp?rev=363458&view=auto
==============================================================================
--- lldb/trunk/unittests/Process/POSIX/NativeProcessELFTest.cpp (added)
+++ lldb/trunk/unittests/Process/POSIX/NativeProcessELFTest.cpp Fri Jun 14 14:15:08 2019
@@ -0,0 +1,155 @@
+//===-- NativeProcessELFTest.cpp --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestingSupport/Host/NativeProcessTestUtils.h"
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "Plugins/Process/Utility/AuxVector.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "gmock/gmock.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace testing;
+
+namespace {
+class MockProcessELF : public MockProcess<NativeProcessELF> {
+public:
+ using MockProcess::MockProcess;
+ using NativeProcessELF::GetAuxValue;
+ using NativeProcessELF::GetELFImageInfoAddress;
+};
+
+std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
+ MockProcessELF &process,
+ llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
+ auto addr_size = process.GetAddressByteSize();
+ DataBufferSP buffer_sp(
+ new DataBufferHeap(auxv_data.size() * addr_size * 2, 0));
+ DataEncoder encoder(buffer_sp, process.GetByteOrder(), addr_size);
+ uint32_t offset = 0;
+ for (auto &pair : auxv_data) {
+ offset = encoder.PutAddress(offset, pair.first);
+ offset = encoder.PutAddress(offset, pair.second);
+ }
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::toStringRef(buffer_sp->GetData()), "");
+}
+
+} // namespace
+
+TEST(NativeProcessELFTest, GetAuxValue) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint64_t phdr_addr = 0x42;
+ auto auxv_buffer = CreateAuxvData(
+ process, {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ ASSERT_EQ(phdr_addr, process.GetAuxValue(AuxVector::AUXV_AT_PHDR));
+}
+
+TEST(NativeProcessELFTest, GetELFImageInfoAddress) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint32_t load_base = 0x1000;
+ uint32_t info_addr = 0x3741;
+ uint32_t phdr_addr = load_base + sizeof(llvm::ELF::Elf32_Ehdr);
+
+ auto auxv_buffer = CreateAuxvData(
+ process,
+ {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
+ std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
+ std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ // We're going to set up a fake memory with 2 program headers and 1 entry in
+ // the dynamic section. For simplicity sake they will be contiguous in memory.
+ struct MemoryContents {
+ llvm::ELF::Elf32_Phdr phdr_load;
+ llvm::ELF::Elf32_Phdr phdr_dynamic;
+ llvm::ELF::Elf32_Dyn dyn_debug;
+ } MC;
+ // Setup the 2 program header entries
+ MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
+ MC.phdr_load.p_vaddr = phdr_addr - load_base;
+
+ MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
+ MC.phdr_dynamic.p_vaddr =
+ (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr)) - load_base;
+ MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
+
+ // Setup the single entry in the .dynamic section
+ MC.dyn_debug.d_tag = llvm::ELF::DT_DEBUG;
+ MC.dyn_debug.d_un.d_ptr = info_addr;
+
+ FakeMemory M(&MC, sizeof(MC), phdr_addr);
+ EXPECT_CALL(process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+
+ // Read the address at the elf_info_addr location to make sure we're reading
+ // the correct one.
+ lldb::offset_t info_addr_offset = elf_info_addr - phdr_addr;
+ DataExtractor mem_extractor(&MC, sizeof(MC), process.GetByteOrder(),
+ process.GetAddressByteSize());
+ ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr);
+}
+
+TEST(NativeProcessELFTest, GetELFImageInfoAddress_NoDebugEntry) {
+ NiceMock<MockDelegate> DummyDelegate;
+ MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
+
+ uint32_t phdr_addr = sizeof(llvm::ELF::Elf32_Ehdr);
+
+ auto auxv_buffer = CreateAuxvData(
+ process,
+ {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
+ std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
+ std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
+ EXPECT_CALL(process, GetAuxvData())
+ .WillOnce(Return(ByMove(std::move(auxv_buffer))));
+
+ // We're going to set up a fake memory with 2 program headers and 1 entry in
+ // the dynamic section. For simplicity sake they will be contiguous in memory.
+ struct MemoryContents {
+ llvm::ELF::Elf32_Phdr phdr_load;
+ llvm::ELF::Elf32_Phdr phdr_dynamic;
+ llvm::ELF::Elf32_Dyn dyn_notdebug;
+ } MC;
+ // Setup the 2 program header entries
+ MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
+ MC.phdr_load.p_vaddr = phdr_addr;
+
+ MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
+ MC.phdr_dynamic.p_vaddr = (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr));
+ MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
+
+ // Setup the single entry in the .dynamic section
+ MC.dyn_notdebug.d_tag = llvm::ELF::DT_NULL;
+
+ FakeMemory M(&MC, sizeof(MC), phdr_addr);
+ EXPECT_CALL(process, ReadMemory(_, _))
+ .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
+
+ lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
+ llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
+
+ ASSERT_EQ(elf_info_addr, LLDB_INVALID_ADDRESS);
+}
Added: lldb/trunk/unittests/TestingSupport/Host/NativeProcessTestUtils.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/TestingSupport/Host/NativeProcessTestUtils.h?rev=363458&view=auto
==============================================================================
--- lldb/trunk/unittests/TestingSupport/Host/NativeProcessTestUtils.h (added)
+++ lldb/trunk/unittests/TestingSupport/Host/NativeProcessTestUtils.h Fri Jun 14 14:15:08 2019
@@ -0,0 +1,150 @@
+//===-- NativeProcessTestUtils.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_unittests_Host_NativeProcessTestUtils_h_
+#define lldb_unittests_Host_NativeProcessTestUtils_h_
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace testing;
+
+namespace lldb_private {
+
+class MockDelegate : public NativeProcessProtocol::NativeDelegate {
+public:
+ MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));
+ MOCK_METHOD2(ProcessStateChanged,
+ void(NativeProcessProtocol *Process, StateType State));
+ MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));
+};
+
+// NB: This class doesn't use the override keyword to avoid
+// -Winconsistent-missing-override warnings from the compiler. The
+// inconsistency comes from the overriding definitions in the MOCK_*** macros.
+template <typename T> class MockProcess : public T {
+public:
+ MockProcess(NativeProcessProtocol::NativeDelegate &Delegate,
+ const ArchSpec &Arch, lldb::pid_t Pid = 1)
+ : T(Pid, -1, Delegate), Arch(Arch) {}
+
+ MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));
+ MOCK_METHOD0(Halt, Status());
+ MOCK_METHOD0(Detach, Status());
+ MOCK_METHOD1(Signal, Status(int Signo));
+ MOCK_METHOD0(Kill, Status());
+ MOCK_METHOD3(AllocateMemory,
+ Status(size_t Size, uint32_t Permissions, addr_t &Addr));
+ MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr));
+ MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
+ MOCK_METHOD0(UpdateThreads, size_t());
+ MOCK_CONST_METHOD0(GetAuxvData,
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());
+ MOCK_METHOD2(GetLoadedModuleFileSpec,
+ Status(const char *ModulePath, FileSpec &Spec));
+ MOCK_METHOD2(GetFileLoadAddress,
+ Status(const llvm::StringRef &FileName, addr_t &Addr));
+
+ const ArchSpec &GetArchitecture() const /*override*/ { return Arch; }
+ Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,
+ bool Hardware) /*override*/ {
+ if (Hardware)
+ return this->SetHardwareBreakpoint(Addr, Size);
+ else
+ return this->SetSoftwareBreakpoint(Addr, Size);
+ }
+
+ // Redirect base class Read/Write Memory methods to functions whose signatures
+ // are more mock-friendly.
+ Status ReadMemory(addr_t Addr, void *Buf, size_t Size,
+ size_t &BytesRead) /*override*/ {
+ auto ExpectedMemory = this->ReadMemory(Addr, Size);
+ if (!ExpectedMemory) {
+ BytesRead = 0;
+ return Status(ExpectedMemory.takeError());
+ }
+ BytesRead = ExpectedMemory->size();
+ assert(BytesRead <= Size);
+ std::memcpy(Buf, ExpectedMemory->data(), BytesRead);
+ return Status();
+ }
+
+ Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,
+ size_t &BytesWritten) /*override*/ {
+ auto ExpectedBytes = this->WriteMemory(
+ Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size));
+ if (!ExpectedBytes) {
+ BytesWritten = 0;
+ return Status(ExpectedBytes.takeError());
+ }
+ BytesWritten = *ExpectedBytes;
+ return Status();
+ }
+
+ MOCK_METHOD2(ReadMemory,
+ llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));
+ MOCK_METHOD2(WriteMemory,
+ llvm::Expected<size_t>(addr_t Addr,
+ llvm::ArrayRef<uint8_t> Data));
+
+ using T::GetSoftwareBreakpointTrapOpcode;
+ llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,
+ size_t Size) {
+ std::vector<uint8_t> Data(Size, 0);
+ size_t BytesRead;
+ Status ST =
+ T::ReadMemoryWithoutTrap(Addr, Data.data(), Data.size(), BytesRead);
+ if (ST.Fail())
+ return ST.ToError();
+ Data.resize(BytesRead);
+ return std::move(Data);
+ }
+
+private:
+ ArchSpec Arch;
+};
+
+class FakeMemory {
+public:
+ FakeMemory(llvm::ArrayRef<uint8_t> Data, addr_t start_addr = 0)
+ : Data(Data), m_start_addr(start_addr) {}
+
+ FakeMemory(const void *Data, size_t data_size, addr_t start_addr = 0)
+ : Data((const uint8_t *)Data, ((const uint8_t *)Data) + data_size),
+ m_start_addr(start_addr) {}
+
+ llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size) {
+ Addr -= m_start_addr;
+ if (Addr >= Data.size())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Address out of range.");
+ Size = std::min(Size, Data.size() - (size_t)Addr);
+ auto Begin = std::next(Data.begin(), Addr);
+ return std::vector<uint8_t>(Begin, std::next(Begin, Size));
+ }
+
+ llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk) {
+ Addr -= m_start_addr;
+ if (Addr >= Data.size())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Address out of range.");
+ size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);
+ std::copy_n(Chunk.begin(), Size, &Data[Addr]);
+ return Size;
+ }
+
+private:
+ std::vector<uint8_t> Data;
+ addr_t m_start_addr;
+};
+} // namespace lldb_private
+
+#endif
\ No newline at end of file
More information about the lldb-commits
mailing list