Some NFC changes to how we scan of kexts & kernels in memory in the
DynamicLoaderDarwinKernel plugin.  Created a new function ReadMachHeader
and instead of reading through the target cached memory reader,
start by reading only a mach header sized chunk of memory, then
check it for a valid mach-o magic # and use the size of the load
commands to pre-fetch the entire load commands of the kext which
is the only thing we're going to read, instead of letting the generic
mach-o parser read it in 512 byte chunks.

Functionally this is doing exactly the same thing as before, but by
cutting down on the # of packets going back and forth, even on a 
local connection it's close to a quarter faster than it was before.

<rdar://problem/38570146> 



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@334995 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index fbf255a..6d114d9 100644
--- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -8,8 +8,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "lldb/Utility/SafeMachO.h"
-
 #include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Core/Debugger.h"
@@ -368,9 +366,50 @@
 }
 
 //----------------------------------------------------------------------
+// Read the mach_header struct out of memory and return it.
+// Returns true if the mach_header was successfully read,
+// Returns false if there was a problem reading the header, or it was not
+// a Mach-O header.
+//----------------------------------------------------------------------
+
+bool
+DynamicLoaderDarwinKernel::ReadMachHeader(addr_t addr, Process *process, llvm::MachO::mach_header &header) {
+  Status read_error;
+
+  // Read the mach header and see whether it looks like a kernel
+  if (process->DoReadMemory (addr, &header, sizeof(header), read_error) !=
+      sizeof(header))
+    return false;
+
+  const uint32_t magicks[] = { llvm::MachO::MH_MAGIC_64, llvm::MachO::MH_MAGIC, llvm::MachO::MH_CIGAM, llvm::MachO::MH_CIGAM_64};
+
+  bool found_matching_pattern = false;
+  for (size_t i = 0; i < llvm::array_lengthof (magicks); i++)
+    if (::memcmp (&header.magic, &magicks[i], sizeof (uint32_t)) == 0)
+        found_matching_pattern = true;
+
+  if (found_matching_pattern == false)
+      return false;
+
+  if (header.magic == llvm::MachO::MH_CIGAM ||
+      header.magic == llvm::MachO::MH_CIGAM_64) {
+    header.magic = llvm::ByteSwap_32(header.magic);
+    header.cputype = llvm::ByteSwap_32(header.cputype);
+    header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype);
+    header.filetype = llvm::ByteSwap_32(header.filetype);
+    header.ncmds = llvm::ByteSwap_32(header.ncmds);
+    header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds);
+    header.flags = llvm::ByteSwap_32(header.flags);
+  }
+
+  return true;
+}
+
+//----------------------------------------------------------------------
 // Given an address in memory, look to see if there is a kernel image at that
-// address. Returns a UUID; if a kernel was not found at that address,
-// UUID.IsValid() will be false.
+// address.
+// Returns a UUID; if a kernel was not found at that address, UUID.IsValid()
+// will be false.
 //----------------------------------------------------------------------
 lldb_private::UUID
 DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr,
@@ -384,42 +423,14 @@
                 "looking for kernel binary at 0x%" PRIx64,
                 addr);
 
-  // First try a quick test -- read the first 4 bytes and see if there is a
-  // valid Mach-O magic field there (the first field of the
-  // mach_header/mach_header_64 struct).
-
-  Status read_error;
-  uint8_t magicbuf[4];
-  if (process->ReadMemoryFromInferior (addr, magicbuf, sizeof (magicbuf), read_error) != sizeof (magicbuf))
-      return UUID();
-
-  const uint32_t magicks[] = { llvm::MachO::MH_MAGIC_64, llvm::MachO::MH_MAGIC, llvm::MachO::MH_CIGAM, llvm::MachO::MH_CIGAM_64};
-
-  bool found_matching_pattern = false;
-  for (size_t i = 0; i < llvm::array_lengthof (magicks); i++)
-    if (::memcmp (magicbuf, &magicks[i], sizeof (magicbuf)) == 0)
-        found_matching_pattern = true;
-
-  if (found_matching_pattern == false)
-      return UUID();
-
-  // Read the mach header and see whether it looks like a kernel
   llvm::MachO::mach_header header;
-  if (process->DoReadMemory(addr, &header, sizeof(header), read_error) !=
-      sizeof(header))
+
+  if (ReadMachHeader (addr, process, header) == false)
     return UUID();
 
-  if (header.magic == llvm::MachO::MH_CIGAM ||
-      header.magic == llvm::MachO::MH_CIGAM_64) {
-    header.magic = llvm::ByteSwap_32(header.magic);
-    header.cputype = llvm::ByteSwap_32(header.cputype);
-    header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype);
-    header.filetype = llvm::ByteSwap_32(header.filetype);
-    header.ncmds = llvm::ByteSwap_32(header.ncmds);
-    header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds);
-    header.flags = llvm::ByteSwap_32(header.flags);
-  }
-
+  // First try a quick test -- read the first 4 bytes and see if there is a
+  // valid Mach-O magic field there
+  // (the first field of the mach_header/mach_header_64 struct).
   // A kernel is an executable which does not have the dynamic link object flag
   // set.
   if (header.filetype == llvm::MachO::MH_EXECUTE &&
@@ -639,8 +650,17 @@
   FileSpec file_spec;
   file_spec.SetFile(m_name.c_str(), false, FileSpec::Style::native);
 
+  llvm::MachO::mach_header mh;
+  size_t size_to_read = 512;
+  if (ReadMachHeader (m_load_address, process, mh)) {
+    if (mh.magic == llvm::MachO::MH_CIGAM || llvm::MachO::MH_MAGIC)
+      size_to_read = sizeof (llvm::MachO::mach_header) + mh.sizeofcmds;
+    if (mh.magic == llvm::MachO::MH_CIGAM_64 || llvm::MachO::MH_MAGIC_64)
+      size_to_read = sizeof (llvm::MachO::mach_header_64) + mh.sizeofcmds;
+  }
+
   ModuleSP memory_module_sp =
-      process->ReadModuleFromMemory(file_spec, m_load_address);
+      process->ReadModuleFromMemory(file_spec, m_load_address, size_to_read);
 
   if (memory_module_sp.get() == NULL)
     return false;
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
index ad4f7c6..75998f1 100644
--- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
+++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
@@ -17,6 +17,9 @@
 #include <vector>
 
 // Other libraries and framework includes
+
+#include "lldb/Utility/SafeMachO.h"
+
 // Project includes
 #include "lldb/Target/DynamicLoader.h"
 #include "lldb/Target/Process.h"
@@ -284,6 +287,9 @@
   static lldb::addr_t
   SearchForKernelViaExhaustiveSearch(lldb_private::Process *process);
 
+  static bool
+  ReadMachHeader(lldb::addr_t addr, lldb_private::Process *process, llvm::MachO::mach_header &mh);
+
   static lldb_private::UUID
   CheckForKernelImageAtAddress(lldb::addr_t addr,
                                lldb_private::Process *process);