Revert "Revert "Implement xfer:libraries-svr4:read packet""

This reverts commit 08c38f77c5fb4d3735ec215032fed8ee6730b3db.

llvm-svn: 366847
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 7637237..b40b701 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -2076,4 +2076,4 @@
   m_processor_trace_monitor.erase(iter);
 
   return error;
-}
+}
\ No newline at end of file
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index e85ca3b..4e7f0a1 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -9,12 +9,12 @@
 #ifndef liblldb_NativeProcessNetBSD_H_
 #define liblldb_NativeProcessNetBSD_H_
 
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/FileSpec.h"
 
 #include "NativeThreadNetBSD.h"
-#include "lldb/Host/common/NativeProcessProtocol.h"
 
 namespace lldb_private {
 namespace process_netbsd {
@@ -25,7 +25,7 @@
 /// for debugging.
 ///
 /// Changes in the inferior process state are broadcasted.
-class NativeProcessNetBSD : public NativeProcessProtocol {
+class NativeProcessNetBSD : public NativeProcessELF {
 public:
   class Factory : public NativeProcessProtocol::Factory {
   public:
diff --git a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
index 559b16c..50b2d05 100644
--- a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
+++ b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp
@@ -107,4 +107,73 @@
   return LLDB_INVALID_ADDRESS;
 }
 
-} // namespace lldb_private
\ No newline at end of file
+template <typename T>
+llvm::Expected<SVR4LibraryInfo>
+NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
+  ELFLinkMap<T> link_map;
+  size_t bytes_read;
+  auto error =
+      ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
+  if (!error.Success())
+    return error.ToError();
+
+  char name_buffer[PATH_MAX];
+  error = ReadMemory(link_map.l_name, &name_buffer, sizeof(name_buffer),
+                     bytes_read);
+  if (bytes_read == 0)
+    return error.ToError();
+  name_buffer[PATH_MAX - 1] = '\0';
+
+  SVR4LibraryInfo info;
+  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;
+
+  return info;
+}
+
+llvm::Expected<std::vector<SVR4LibraryInfo>>
+NativeProcessELF::GetLoadedSVR4Libraries() {
+  // Address of DT_DEBUG.d_ptr which points to r_debug
+  lldb::addr_t info_address = GetSharedLibraryInfoAddress();
+  if (info_address == LLDB_INVALID_ADDRESS)
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Invalid shared library info address");
+  // Address of r_debug
+  lldb::addr_t address = 0;
+  size_t bytes_read;
+  auto status =
+      ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
+  if (!status.Success())
+    return status.ToError();
+  if (address == 0)
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Invalid r_debug address");
+  // Read r_debug.r_map
+  lldb::addr_t link_map = 0;
+  status = ReadMemory(address + GetAddressByteSize(), &link_map,
+                      GetAddressByteSize(), bytes_read);
+  if (!status.Success())
+    return status.ToError();
+  if (address == 0)
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Invalid link_map address");
+
+  std::vector<SVR4LibraryInfo> library_list;
+  while (link_map) {
+    llvm::Expected<SVR4LibraryInfo> info =
+        GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
+                                  : ReadSVR4LibraryInfo<uint32_t>(link_map);
+    if (!info)
+      return info.takeError();
+    if (!info->name.empty() && info->base_addr != 0)
+      library_list.push_back(*info);
+    link_map = info->next;
+  }
+
+  return library_list;
+}
+
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h
index 84dc8d0..4fb513b 100644
--- a/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h
+++ b/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h
@@ -37,6 +37,13 @@
   template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
   lldb::addr_t GetELFImageInfoAddress();
 
+  llvm::Expected<std::vector<SVR4LibraryInfo>>
+  GetLoadedSVR4Libraries() override;
+
+  template <typename T>
+  llvm::Expected<SVR4LibraryInfo>
+  ReadSVR4LibraryInfo(lldb::addr_t link_map_addr);
+
   std::unique_ptr<AuxVector> m_aux_vector;
   llvm::Optional<lldb::addr_t> m_shared_library_info_addr;
 };
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index d095c7a..9767d3e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -825,6 +825,7 @@
 #if defined(__linux__) || defined(__NetBSD__)
   response.PutCString(";QPassSignals+");
   response.PutCString(";qXfer:auxv:read+");
+  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
index 1966076..190db34 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2765,6 +2765,24 @@
     return std::move(*buffer_or_error);
   }
 
+  if (object == "libraries-svr4") {
+    auto library_list = m_debugged_process_up->GetLoadedSVR4Libraries();
+    if (!library_list)
+      return library_list.takeError();
+
+    StreamString response;
+    response.Printf("<library-list-svr4 version=\"1.0\">");
+    for (auto const &library : *library_list) {
+      response.Printf("<library name=\"%s\" ",
+                      XMLEncodeAttributeValue(library.name.c_str()).c_str());
+      response.Printf("lm=\"0x%" PRIx64 "\" ", library.link_map);
+      response.Printf("l_addr=\"0x%" PRIx64 "\" ", library.base_addr);
+      response.Printf("l_ld=\"0x%" PRIx64 "\" />", library.ld_addr);
+    }
+    response.Printf("</library-list-svr4>");
+    return MemoryBuffer::getMemBufferCopy(response.GetString(), __FUNCTION__);
+  }
+
   return llvm::make_error<PacketUnimplementedError>(
       "Xfer object not supported");
 }
@@ -3283,3 +3301,28 @@
 
   return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
 }
+
+std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue(
+    llvm::StringRef value) {
+  std::string result;
+  for (const char &c : value) {
+    switch (c) {
+    case '\'':
+      result += "&apos;";
+      break;
+    case '"':
+      result += "&quot;";
+      break;
+    case '<':
+      result += "&lt;";
+      break;
+    case '>':
+      result += "&gt;";
+      break;
+    default:
+      result += c;
+      break;
+    }
+  }
+  return result;
+}
\ No newline at end of file
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 068ea52..088ba92 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -196,6 +196,8 @@
   llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   ReadXferObject(llvm::StringRef object, llvm::StringRef annex);
 
+  static std::string XMLEncodeAttributeValue(llvm::StringRef value);
+
 private:
   void HandleInferiorState_Exited(NativeProcessProtocol *process);