summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/lib/Makefile3
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp191
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h97
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp315
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h227
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp371
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h165
-rw-r--r--lldb/source/Plugins/DynamicLoader/Linux-DYLD/Makefile14
-rw-r--r--lldb/source/Plugins/Makefile2
-rw-r--r--lldb/source/Plugins/Process/Linux/ProcessLinux.cpp27
-rw-r--r--lldb/source/Plugins/Process/Linux/ProcessLinux.h12
-rw-r--r--lldb/source/lldb.cpp3
12 files changed, 1425 insertions, 2 deletions
diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile
index 881b23c6185..abd9c1d8328 100644
--- a/lldb/lib/Makefile
+++ b/lldb/lib/Makefile
@@ -67,7 +67,8 @@ ifeq ($(HOST_OS),Darwin)
endif
ifeq ($(HOST_OS),Linux)
- USEDLIBS += lldbPluginProcessLinux.a
+ USEDLIBS += lldbPluginProcessLinux.a \
+ lldbPluginDynamicLoaderLinux.a
endif
include $(LEVEL)/Makefile.common
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp
new file mode 100644
index 00000000000..6954e4cac4d
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp
@@ -0,0 +1,191 @@
+//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#include "AuxVector.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+GetMaxU64(DataExtractor &data,
+ uint32_t *offset, uint64_t *value, unsigned int byte_size)
+{
+ uint32_t saved_offset = *offset;
+ *value = data.GetMaxU64(offset, byte_size);
+ return *offset != saved_offset;
+}
+
+static bool
+ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry,
+ uint32_t *offset, unsigned int byte_size)
+{
+ if (!GetMaxU64(data, offset, &entry.type, byte_size))
+ return false;
+
+ if (!GetMaxU64(data, offset, &entry.value, byte_size))
+ return false;
+
+ return true;
+}
+
+DataBufferSP
+AuxVector::GetAuxvData()
+{
+ static const size_t path_size = 128;
+ static char path[path_size];
+ DataBufferSP buf_sp;
+ int fd;
+
+ // Ideally, we would simply create a FileSpec and call ReadFileContents.
+ // However, files in procfs have zero size (since they are, in general,
+ // dynamically generated by the kernel) which is incompatible with the
+ // current ReadFileContents implementation. Therefore we simply stream the
+ // data into a DataBuffer ourselves.
+ if (snprintf(path, path_size, "/proc/%d/auxv", m_process->GetID()) < 0)
+ return buf_sp;
+
+ if ((fd = open(path, O_RDONLY, 0)) < 0)
+ return buf_sp;
+
+ size_t bytes_read = 0;
+ std::auto_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
+ for (;;)
+ {
+ size_t avail = buf_ap->GetByteSize() - bytes_read;
+ ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail);
+
+ if (status < 0)
+ break;
+
+ bytes_read += status;
+
+ if (status == 0)
+ {
+ buf_ap->SetByteSize(bytes_read);
+ buf_sp.reset(buf_ap.release());
+ break;
+ }
+
+ if (avail - status == 0)
+ buf_ap->SetByteSize(2 * buf_ap->GetByteSize());
+ }
+
+ return buf_sp;
+}
+
+void
+AuxVector::ParseAuxv(DataExtractor &data)
+{
+ const unsigned int byte_size = m_process->GetAddressByteSize();
+ uint32_t offset = 0;
+
+ for (;;)
+ {
+ Entry entry;
+
+ if (!ParseAuxvEntry(data, entry, &offset, byte_size))
+ break;
+
+ if (entry.type == AT_NULL)
+ break;
+
+ if (entry.type == AT_IGNORE)
+ continue;
+
+ m_auxv.push_back(entry);
+ }
+}
+
+AuxVector::AuxVector(Process *process)
+ : m_process(process)
+{
+ DataExtractor data;
+ LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ data.SetData(GetAuxvData());
+ data.SetByteOrder(m_process->GetByteOrder());
+ data.SetAddressByteSize(m_process->GetAddressByteSize());
+
+ ParseAuxv(data);
+
+ if (log)
+ DumpToLog(log);
+}
+
+AuxVector::iterator
+AuxVector::FindEntry(EntryType type) const
+{
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ if (I->type == static_cast<uint64_t>(type))
+ return I;
+ }
+
+ return end();
+}
+
+void
+AuxVector::DumpToLog(LogSP log) const
+{
+ if (!log)
+ return;
+
+ log->PutCString("AuxVector: ");
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ log->Printf(" %s [%d]: %lx", GetEntryName(*I), I->type, I->value);
+ }
+}
+
+const char *
+AuxVector::GetEntryName(EntryType type)
+{
+ const char *name;
+
+#define ENTRY_NAME(_type) _type: name = #_type
+ switch (type)
+ {
+ default:
+ name = "unkown";
+ break;
+
+ case ENTRY_NAME(AT_NULL); break;
+ case ENTRY_NAME(AT_IGNORE); break;
+ case ENTRY_NAME(AT_EXECFD); break;
+ case ENTRY_NAME(AT_PHDR); break;
+ case ENTRY_NAME(AT_PHENT); break;
+ case ENTRY_NAME(AT_PHNUM); break;
+ case ENTRY_NAME(AT_PAGESZ); break;
+ case ENTRY_NAME(AT_BASE); break;
+ case ENTRY_NAME(AT_FLAGS); break;
+ case ENTRY_NAME(AT_ENTRY); break;
+ case ENTRY_NAME(AT_NOTELF); break;
+ case ENTRY_NAME(AT_UID); break;
+ case ENTRY_NAME(AT_EUID); break;
+ case ENTRY_NAME(AT_GID); break;
+ case ENTRY_NAME(AT_EGID); break;
+ case ENTRY_NAME(AT_CLKTCK); break;
+ }
+#undef ENTRY_NAME
+
+ return name;
+}
+
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h
new file mode 100644
index 00000000000..7a5b3700fce
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h
@@ -0,0 +1,97 @@
+//===-- AuxVector.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_AuxVector_H_
+#define liblldb_AuxVector_H_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/lldb-forward-rtti.h"
+
+namespace lldb_private {
+class DataExtractor;
+}
+
+/// @class AuxVector
+/// @brief Represents a processes auxiliary vector.
+///
+/// When a process is loaded on Linux a vector of values is placed onto the
+/// stack communicating operating system specific information. On construction
+/// this class locates and parses this information and provides a simple
+/// read-only interface to the entries found.
+class AuxVector {
+
+public:
+ AuxVector(lldb_private::Process *process);
+
+ struct Entry {
+ uint64_t type;
+ uint64_t value;
+
+ Entry() : type(0), value(0) { }
+ };
+
+ /// Constants describing the type of entry.
+ enum EntryType {
+ AT_NULL = 0, ///< End of auxv.
+ AT_IGNORE = 1, ///< Ignore entry.
+ AT_EXECFD = 2, ///< File descriptor of program.
+ AT_PHDR = 3, ///< Program headers.
+ AT_PHENT = 4, ///< Size of program header.
+ AT_PHNUM = 5, ///< Number of program headers.
+ AT_PAGESZ = 6, ///< Page size.
+ AT_BASE = 7, ///< Interpreter base address.
+ AT_FLAGS = 8, ///< Flags.
+ AT_ENTRY = 9, ///< Program entry point.
+ AT_NOTELF = 10, ///< Set if program is not an ELF.
+ AT_UID = 11, ///< UID.
+ AT_EUID = 12, ///< Effective UID.
+ AT_GID = 13, ///< GID.
+ AT_EGID = 14, ///< Effective GID.
+ AT_CLKTCK = 17 ///< Clock frequency (e.g. times(2)).
+ };
+
+private:
+ typedef std::vector<Entry> EntryVector;
+
+public:
+ typedef EntryVector::const_iterator iterator;
+
+ iterator begin() const { return m_auxv.begin(); }
+ iterator end() const { return m_auxv.end(); }
+
+ iterator
+ FindEntry(EntryType type) const;
+
+ static const char *
+ GetEntryName(const Entry &entry) {
+ return GetEntryName(static_cast<EntryType>(entry.type));
+ }
+
+ static const char *
+ GetEntryName(EntryType type);
+
+ void
+ DumpToLog(lldb::LogSP log) const;
+
+private:
+ lldb_private::Process *m_process;
+ EntryVector m_auxv;
+
+ lldb::DataBufferSP
+ GetAuxvData();
+
+ void
+ ParseAuxv(lldb_private::DataExtractor &data);
+};
+
+#endif
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp
new file mode 100644
index 00000000000..8b4795d4c49
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp
@@ -0,0 +1,315 @@
+//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "DYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Locates the address of the rendezvous structure. Returns the address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+static addr_t
+ResolveRendezvousAddress(Process *process)
+{
+ addr_t info_location;
+ addr_t info_addr;
+ Error error;
+ size_t size;
+
+ info_location = process->GetImageInfoAddress();
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ info_addr = 0;
+ size = process->DoReadMemory(info_location, &info_addr,
+ process->GetAddressByteSize(), error);
+ if (size != process->GetAddressByteSize() || error.Fail())
+ return LLDB_INVALID_ADDRESS;
+
+ if (info_addr == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_addr;
+}
+
+DYLDRendezvous::DYLDRendezvous(Process *process)
+ : m_process(process),
+ m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_current(),
+ m_previous(),
+ m_soentries(),
+ m_added_soentries(),
+ m_removed_soentries()
+{
+}
+
+bool
+DYLDRendezvous::Resolve()
+{
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr = ResolveRendezvousAddress(m_process);
+ else
+ cursor = info_addr = m_rendezvous_addr;
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.brk, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ return UpdateSOEntries();
+}
+
+bool
+DYLDRendezvous::IsValid()
+{
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntries()
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ if (m_current.state == eAdd || m_current.state == eDelete)
+ {
+ assert(m_previous.state == eConsistent);
+ m_soentries.clear();
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ }
+
+ // Otherwise check the previous state to determine what to expect and update
+ // accordingly.
+ if (m_previous.state == eAdd)
+ return UpdateSOEntriesForAddition();
+ else if (m_previous.state == eDelete)
+ return UpdateSOEntriesForDeletion();
+
+ return false;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForAddition()
+{
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ if (entry.path.empty())
+ continue;
+
+ pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
+ if (pos == m_soentries.end())
+ {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForDeletion()
+{
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ pos = std::find(entry_list.begin(), entry_list.end(), *I);
+ if (pos == entry_list.end())
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool
+DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ if (entry.path.empty())
+ continue;
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t
+DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size)
+{
+ size_t bytes_read;
+ Error error;
+
+ bytes_read = m_process->DoReadMemory(addr, dst, size, error);
+ if (bytes_read != size || error.Fail())
+ return 0;
+
+ return addr + bytes_read;
+}
+
+std::string
+DYLDRendezvous::ReadStringFromMemory(addr_t addr)
+{
+ std::string str;
+ Error error;
+ size_t size;
+ char c;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ return std::string();
+
+ for (;;) {
+ size = m_process->DoReadMemory(addr, &c, 1, error);
+ if (size != 1 || error.Fail())
+ return std::string();
+ if (c == 0)
+ break;
+ else {
+ str.push_back(c);
+ addr++;
+ }
+ }
+
+ return str;
+}
+
+bool
+DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
+{
+ size_t address_size = m_process->GetAddressByteSize();
+
+ entry.clear();
+
+ if (!(addr = ReadMemory(addr, &entry.base_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.path_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.next, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.prev, address_size)))
+ return false;
+
+ entry.path = ReadStringFromMemory(entry.path_addr);
+
+ return true;
+}
+
+void
+DYLDRendezvous::DumpToLog(LogSP log) const
+{
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("DYLDRendezvous:");
+ log->Printf(" Address: %lx", GetRendezvousAddress());
+ log->Printf(" Version: %d", GetVersion());
+ log->Printf(" Link : %lx", GetLinkMapAddress());
+ log->Printf(" Break : %lx", GetBreakAddress());
+ log->Printf(" LDBase : %lx", GetLDBase());
+ log->Printf(" State : %s",
+ (state == eConsistent) ? "consistent" :
+ (state == eAdd) ? "add" :
+ (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("DYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i)
+ {
+ log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
+ log->Printf(" Base : %lx", I->base_addr);
+ log->Printf(" Path : %lx", I->path_addr);
+ log->Printf(" Dyn : %lx", I->dyn_addr);
+ log->Printf(" Next : %lx", I->next);
+ log->Printf(" Prev : %lx", I->prev);
+ }
+}
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h
new file mode 100644
index 00000000000..e8052ae5b3e
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h
@@ -0,0 +1,227 @@
+//===-- DYLDRendezvous.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_Rendezvous_H_
+#define liblldb_Rendezvous_H_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+class Process;
+}
+
+/// @class DYLDRendezvous
+/// @brief Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// runtime liker each time a module is loaded or unloaded. This class provides
+/// an interface to this structure and maintains a consistent snapshot of the
+/// currently loaded modules.
+class DYLDRendezvous {
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version;
+ lldb::addr_t map_addr;
+ lldb::addr_t brk;
+ uint64_t state;
+ lldb::addr_t ldbase;
+
+ Rendezvous()
+ : version(0), map_addr(0), brk(0), state(0), ldbase(0) { }
+ };
+
+public:
+ DYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// @returns true on success and false on failure.
+ ///
+ /// @see GetBreakAddress().
+ bool
+ Resolve();
+
+ /// @returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool
+ IsValid();
+
+ /// @returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t
+ GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// @returns the version of the rendezvous protocol being used.
+ int
+ GetVersion() const { return m_current.version; }
+
+ /// @returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t
+ GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// @returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// @see Resolve()
+ lldb::addr_t
+ GetBreakAddress() const { return m_current.brk; }
+
+ /// Returns the current state of the rendezvous structure.
+ int
+ GetState() const { return m_current.state; }
+
+ /// @returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t
+ GetLDBase() const { return m_current.ldbase; }
+
+ /// @returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// @returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void
+ DumpToLog(lldb::LogSP log) const;
+
+ /// @brief Constants describing the state of the rendezvous.
+ ///
+ /// @see GetState().
+ enum RendezvousState {
+ eConsistent,
+ eAdd,
+ eDelete
+ };
+
+ /// @brief Structure representing the shared objects currently loaded into
+ /// the inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ std::string path; ///< File name of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator ==(const SOEntry &entry) {
+ return this->path == entry.path;
+ }
+
+ void clear() {
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ path.clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Reads @p size bytes from the inferiors address space starting at @p
+ /// addr.
+ ///
+ /// @returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t
+ ReadMemory(lldb::addr_t addr, void *dst, size_t size);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string
+ ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at @p addr.
+ bool
+ ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool
+ UpdateSOEntries();
+
+ bool
+ UpdateSOEntriesForAddition();
+
+ bool
+ UpdateSOEntriesForDeletion();
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool
+ TakeSnapshot(SOEntryList &entry_list);
+};
+
+#endif
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp
new file mode 100644
index 00000000000..0802ff65575
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp
@@ -0,0 +1,371 @@
+//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+#include <iostream>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "AuxVector.h"
+#include "DynamicLoaderLinuxDYLD.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+DynamicLoaderLinuxDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderLinuxDYLD::Terminate()
+{
+}
+
+const char *
+DynamicLoaderLinuxDYLD::GetPluginName()
+{
+ return "DynamicLoaderLinuxDYLD";
+}
+
+const char *
+DynamicLoaderLinuxDYLD::GetShortPluginName()
+{
+ return "linux-dyld";
+}
+
+const char *
+DynamicLoaderLinuxDYLD::GetPluginNameStatic()
+{
+ return "dynamic-loader.linux-dyld";
+}
+
+const char *
+DynamicLoaderLinuxDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in Linux processes.";
+}
+
+void
+DynamicLoaderLinuxDYLD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+uint32_t
+DynamicLoaderLinuxDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+DynamicLoader *
+DynamicLoaderLinuxDYLD::CreateInstance(Process *process)
+{
+ return new DynamicLoaderLinuxDYLD(process);
+}
+
+DynamicLoaderLinuxDYLD::DynamicLoaderLinuxDYLD(Process *process)
+ : DynamicLoader(process),
+ m_rendezvous(process),
+ m_load_offset(LLDB_INVALID_ADDRESS),
+ m_entry_point(LLDB_INVALID_ADDRESS),
+ m_auxv(NULL)
+{
+}
+
+DynamicLoaderLinuxDYLD::~DynamicLoaderLinuxDYLD()
+{
+}
+
+void
+DynamicLoaderLinuxDYLD::DidAttach()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = m_process->GetTarget().GetExecutableModule();
+ load_offset = ComputeLoadOffset();
+
+ if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+void
+DynamicLoaderLinuxDYLD::DidLaunch()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = m_process->GetTarget().GetExecutableModule();
+ load_offset = ComputeLoadOffset();
+
+ if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ ProbeEntry();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+Error
+DynamicLoaderLinuxDYLD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error();
+}
+
+Log *
+DynamicLoaderLinuxDYLD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+Error
+DynamicLoaderLinuxDYLD::CanLoadImage()
+{
+ return Error();
+}
+
+void
+DynamicLoaderLinuxDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr)
+{
+ ObjectFile *obj_file = module->GetObjectFile();
+ SectionList *sections = obj_file->GetSectionList();
+ SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList();
+ const size_t num_sections = sections->GetSize();
+
+ for (unsigned i = 0; i < num_sections; ++i)
+ {
+ Section *section = sections->GetSectionAtIndex(i).get();
+ lldb::addr_t new_load_addr = section->GetFileAddress() + base_addr;
+ lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section);
+
+ // If the file address of the section is zero then this is not an
+ // allocatable/loadable section (property of ELF sh_addr). Skip it.
+ if (new_load_addr == base_addr)
+ continue;
+
+ if (old_load_addr == LLDB_INVALID_ADDRESS ||
+ old_load_addr != new_load_addr)
+ load_list.SetSectionLoadAddress(section, new_load_addr);
+ }
+}
+
+void
+DynamicLoaderLinuxDYLD::ProbeEntry()
+{
+ Breakpoint *entry_break;
+ addr_t entry;
+
+ if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return;
+
+ entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get();
+ entry_break->SetCallback(EntryBreakpointHit, this, true);
+}
+
+// The runtime linker has run and initialized the rendezvous structure once the
+// process has hit its entry point. When we hit the corresponding breakpoint we
+// interrogate the rendezvous structure to get the load addresses of all
+// dependent modules for the process. Similarly, we can discover the runtime
+// linker function and setup a breakpoint to notify us of any dynamically loaded
+// modules (via dlopen).
+bool
+DynamicLoaderLinuxDYLD::EntryBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderLinuxDYLD* dyld_instance;
+
+ dyld_instance = static_cast<DynamicLoaderLinuxDYLD*>(baton);
+ dyld_instance->LoadAllCurrentModules();
+ dyld_instance->SetRendezvousBreakpoint();
+ return false; // Continue running.
+}
+
+void
+DynamicLoaderLinuxDYLD::SetRendezvousBreakpoint()
+{
+ Breakpoint *dyld_break;
+ addr_t break_addr;
+
+ break_addr = m_rendezvous.GetBreakAddress();
+ dyld_break = m_process->GetTarget().CreateBreakpoint(break_addr, true).get();
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+}
+
+bool
+DynamicLoaderLinuxDYLD::RendezvousBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderLinuxDYLD* dyld_instance;
+
+ dyld_instance = static_cast<DynamicLoaderLinuxDYLD*>(baton);
+ dyld_instance->RefreshModules();
+
+ // Return true to stop the target, false to just let the target run.
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+void
+DynamicLoaderLinuxDYLD::RefreshModules()
+{
+ if (!m_rendezvous.Resolve())
+ return;
+
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad())
+ {
+ ModuleList new_modules;
+
+ E = m_rendezvous.loaded_end();
+ for (I = m_rendezvous.loaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (!module_sp.empty())
+ new_modules.Append(module_sp);
+ }
+ m_process->GetTarget().ModulesDidLoad(new_modules);
+ }
+
+ if (m_rendezvous.ModulesDidUnload())
+ {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSP module_sp = loaded_modules.FindFirstModuleForFileSpec(file);
+ if (!module_sp.empty())
+ old_modules.Append(module_sp);
+ }
+ m_process->GetTarget().ModulesDidUnload(old_modules);
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderLinuxDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop_others)
+{
+ LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ ThreadPlanSP thread_plan_sp;
+
+ if (log)
+ log->PutCString("DynamicLoaderLinuxDYLD: "
+ "GetStepThroughTrampolinePlan not implemented\n");
+
+ return thread_plan_sp;
+}
+
+void
+DynamicLoaderLinuxDYLD::LoadAllCurrentModules()
+{
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+ ModuleList module_list;
+
+ if (!m_rendezvous.Resolve())
+ return;
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), false);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (!module_sp.empty())
+ module_list.Append(module_sp);
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+ModuleSP
+DynamicLoaderLinuxDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ if ((module_sp = modules.FindFirstModuleForFileSpec(file)))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ }
+ else if ((module_sp = target.GetSharedModule(file, target.GetArchitecture())))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ modules.Append(module_sp);
+ }
+
+ return module_sp;
+}
+
+addr_t
+DynamicLoaderLinuxDYLD::ComputeLoadOffset()
+{
+ addr_t virt_entry;
+
+ if (m_load_offset != LLDB_INVALID_ADDRESS)
+ return m_load_offset;
+
+ if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ ModuleSP module = m_process->GetTarget().GetExecutableModule();
+ ObjectFile *exe = module->GetObjectFile();
+ Address file_entry = exe->GetEntryPoint();
+
+ if (!file_entry.IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ m_load_offset = virt_entry - file_entry.GetFileAddress();
+ return m_load_offset;
+}
+
+addr_t
+DynamicLoaderLinuxDYLD::GetEntryPoint()
+{
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+
+ if (m_auxv.get() == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
+
+ if (I == m_auxv->end())
+ return LLDB_INVALID_ADDRESS;
+
+ m_entry_point = static_cast<addr_t>(I->value);
+ return m_entry_point;
+}
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h
new file mode 100644
index 00000000000..bc537ce7746
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h
@@ -0,0 +1,165 @@
+//===-- DynamicLoaderLinux.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_DynamicLoaderLinux_H_
+#define liblldb_DynamicLoaderLinux_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "DYLDRendezvous.h"
+
+class AuxVector;
+
+class DynamicLoaderLinuxDYLD : public lldb_private::DynamicLoader
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process);
+
+ DynamicLoaderLinuxDYLD(lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderLinuxDYLD();
+
+ //------------------------------------------------------------------
+ // DynamicLoader protocol
+ //------------------------------------------------------------------
+
+ virtual void
+ DidAttach();
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ /// Runtime linker rendezvous structure.
+ DYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Auxiliary vector of the inferior process.
+ std::auto_ptr<AuxVector> m_auxv;
+
+ /// Enables a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ void
+ SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool
+ RendezvousBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void
+ RefreshModules();
+
+ /// Updates the load address of every allocatable section in @p module.
+ ///
+ /// @param module The module to traverse.
+ ///
+ /// @param base_addr The virtual base address @p module is loaded at.
+ void
+ UpdateLoadedSections(lldb::ModuleSP module,
+ lldb::addr_t base_addr = 0);
+
+ /// Locates or creates a module given by @p file and updates/loads the
+ /// resulting module at the virtual base address @p base_addr.
+ lldb::ModuleSP
+ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr);
+
+ /// Resolves the entry point for the current inferior process and sets a
+ /// breakpoint at that address.
+ void
+ ProbeEntry();
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ void
+ LoadAllCurrentModules();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ GetEntryPoint();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DynamicLoaderLinuxDYLD);
+};
+
+#endif // liblldb_DynamicLoaderLinuxDYLD_H_
diff --git a/lldb/source/Plugins/DynamicLoader/Linux-DYLD/Makefile b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/Makefile
new file mode 100644
index 00000000000..94025dd3eba
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/Linux-DYLD/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/DynamicLoader/Linux-DYLD/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 := lldbPluginDynamicLoaderLinux
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile
index 14eed8ad8b1..a3d644f78fb 100644
--- a/lldb/source/Plugins/Makefile
+++ b/lldb/source/Plugins/Makefile
@@ -23,7 +23,7 @@ DIRS += DynamicLoader/MacOSX-DYLD ObjectContainer/Universal-Mach-O \
endif
ifeq ($(HOST_OS),Linux)
-DIRS += Process/Linux
+DIRS += Process/Linux DynamicLoader/Linux-DYLD
endif
include $(LLDB_LEVEL)/Makefile
diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp
index 00bdda51036..d7fe1dae0a1 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Target.h"
#include "ProcessLinux.h"
@@ -102,6 +103,19 @@ ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
}
Error
+ProcessLinux::WillLaunch(Module* module)
+{
+ Error error;
+
+ m_dyld_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.linux-dyld"));
+ if (m_dyld_ap.get() == NULL)
+ error.SetErrorString("unable to find the dynamic loader named "
+ "'dynamic-loader.linux-dyld'");
+
+ return error;
+}
+
+Error
ProcessLinux::DoLaunch(Module *module,
char const *argv[],
char const *envp[],
@@ -128,6 +142,13 @@ ProcessLinux::DoLaunch(Module *module,
return error;
}
+void
+ProcessLinux::DidLaunch()
+{
+ if (m_dyld_ap.get() != NULL)
+ m_dyld_ap->DidLaunch();
+}
+
Error
ProcessLinux::DoResume()
{
@@ -371,6 +392,12 @@ ProcessLinux::GetByteOrder() const
return m_byte_order;
}
+DynamicLoader *
+ProcessLinux::GetDynamicLoader()
+{
+ return m_dyld_ap.get();
+}
+
//------------------------------------------------------------------------------
// ProcessInterface protocol.
diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.h b/lldb/source/Plugins/Process/Linux/ProcessLinux.h
index 3e23a7ad37e..fbf14df1988 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.h
@@ -60,6 +60,9 @@ public:
CanDebug(lldb_private::Target &target);
virtual lldb_private::Error
+ WillLaunch(lldb_private::Module *module);
+
+ virtual lldb_private::Error
DoAttachToProcessWithID(lldb::pid_t pid);
virtual lldb_private::Error
@@ -71,6 +74,9 @@ public:
const char *stdout_path,
const char *stderr_path);
+ virtual void
+ DidLaunch();
+
virtual lldb_private::Error
DoResume();
@@ -131,6 +137,9 @@ public:
virtual lldb::addr_t
GetImageInfoAddress();
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader();
+
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
@@ -176,6 +185,9 @@ private:
lldb_private::Mutex m_message_mutex;
std::queue<ProcessMessage> m_message_queue;
+ /// Dynamic loader plugin associated with this process.
+ std::auto_ptr<lldb_private::DynamicLoader> m_dyld_ap;
+
/// Updates the loaded sections provided by the executable.
///
/// FIXME: It would probably be better to delegate this task to the
diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp
index 05c7f4b4517..ac281a269bc 100644
--- a/lldb/source/lldb.cpp
+++ b/lldb/source/lldb.cpp
@@ -44,6 +44,7 @@
#ifdef __linux__
#include "Plugins/Process/Linux/ProcessLinux.h"
+#include "Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h"
#endif
using namespace lldb;
@@ -94,6 +95,7 @@ lldb_private::Initialize ()
#endif
#ifdef __linux__
ProcessLinux::Initialize();
+ DynamicLoaderLinuxDYLD::Initialize();
#endif
}
}
@@ -137,6 +139,7 @@ lldb_private::Terminate ()
#ifdef __linux__
ProcessLinux::Terminate();
+ DynamicLoaderLinuxDYLD::Terminate();
#endif
Log::Terminate();
OpenPOWER on IntegriCloud