diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h --- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -32,6 +32,15 @@ class MemoryRegionInfo; class ResumeActionList; +struct SharedLibraryInfo { + std::string name; + lldb::addr_t link_map; + lldb::addr_t base_addr; + lldb::addr_t ld_addr; + bool main; + lldb::addr_t next; +}; + // NativeProcessProtocol class NativeProcessProtocol { public: @@ -86,6 +95,11 @@ virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0; + virtual Status + GetLoadedSharedLibraries(std::vector &library_list) { + return Status("Not implemented"); + } + virtual bool IsAlive() const; virtual size_t UpdateThreads() = 0; diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -79,6 +79,9 @@ lldb::addr_t GetSharedLibraryInfoAddress() override; + Status GetLoadedSharedLibraries( + std::vector &library_list) override; + size_t UpdateThreads() override; const ArchSpec &GetArchitecture() const override { return m_arch; } @@ -133,6 +136,17 @@ template lldb::addr_t GetELFImageInfoAddress(); + template struct ELFLinkMap { + T l_addr; + T l_name; + T l_ld; + T l_next; + T l_prev; + }; + template + Status ReadSharedLibraryInfo(lldb::addr_t link_map_addr, + SharedLibraryInfo &info); + private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -2169,3 +2169,76 @@ return LLDB_INVALID_ADDRESS; } + +template +Status NativeProcessLinux::ReadSharedLibraryInfo(lldb::addr_t link_map_addr, + SharedLibraryInfo &info) { + ELFLinkMap link_map; + size_t bytes_read; + auto error = + ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read); + if (!error.Success()) + return error; + + char name_buffer[PATH_MAX]; + error = ReadMemory(link_map.l_name, &name_buffer, sizeof(name_buffer), + bytes_read); + if (!error.Success()) + return error; + + info.name = std::string(name_buffer); + info.link_map = link_map_addr; + info.base_addr = link_map.l_addr; + info.ld_addr = link_map.l_ld; + info.next = link_map.l_next; +#if defined(__linux__) && !defined(__ANDROID__) + // On non-android linux systems, main executable has an empty path. + info.main = info.main.empty(); +#elif defined(__linux__) && defined(__ANDROID__) + // On android, the main executable has a load address of 0. + info.main = info.ld_addr == 0; +#else + info.main = false; +#endif + + return Status(); +} + +Status NativeProcessLinux::GetLoadedSharedLibraries( + std::vector &library_list) { + // Address of DT_DEBUG.d_ptr which points to r_debug + lldb::addr_t info_address = GetSharedLibraryInfoAddress(); + if (info_address == LLDB_INVALID_ADDRESS) + return Status("Invalid shared library info address"); + // Address of r_debug + lldb::addr_t address = 0; + size_t bytes_read; + auto error = + ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read); + if (!error.Success()) + return error; + if (address == 0) + return Status("Invalid r_debug address"); + // Read r_debug.r_map + lldb::addr_t link_map = 0; + error = ReadMemory(address + GetAddressByteSize(), &link_map, + GetAddressByteSize(), bytes_read); + if (!error.Success()) + return error; + if (address == 0) + return Status("Invalid link_map address"); + + while (link_map) { + SharedLibraryInfo info; + if (GetAddressByteSize() == 8) + error = ReadSharedLibraryInfo(link_map, info); + else + error = ReadSharedLibraryInfo(link_map, info); + if (!error.Success()) + return error; + library_list.push_back(info); + link_map = info.next; + } + + return Status(); +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -826,6 +826,9 @@ response.PutCString(";QPassSignals+"); response.PutCString(";qXfer:auxv:read+"); #endif +#if defined(__linux__) + response.PutCString(";qXfer:libraries-svr4:read+"); +#endif return SendPacketNoLock(response.GetString()); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -2772,6 +2772,28 @@ return std::move(*buffer_or_error); } +#if defined(__linux__) + if (object == "libraries-svr4") { + std::vector library_list; + auto status = + m_debugged_process_up->GetLoadedSharedLibraries(library_list); + if (!status.Success()) + return status.ToError(); + + StreamString response; + response.Printf(""); + for (auto const &library : library_list) { + response.Printf("", library.ld_addr); + } + response.Printf(""); + std::unique_ptr memory_buffer_up = std::move( + MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__)); + } +#endif + return llvm::make_error( "Xfer object not supported"); }