When starting a kernel debug session (PlatformDarwinKernel), scan
authorJason Molenda <jmolenda@apple.com>
Thu, 29 Jan 2015 06:20:05 +0000 (06:20 +0000)
committerJason Molenda <jmolenda@apple.com>
Thu, 29 Jan 2015 06:20:05 +0000 (06:20 +0000)
for executable binaries on the local filesystem so the user doesn't
need to provide the path to the correct binary manually.

Also have lldb search for kexts/the kernel in the current working
directory in addition to all the usual places.

<rdar://problem/18126501>

llvm-svn: 227419

lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h

index 8170275..919c10f 100644 (file)
@@ -250,13 +250,16 @@ PlatformDarwinKernel::DebuggerInitialize (lldb_private::Debugger &debugger)
 PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_session) :
     PlatformDarwin (false),    // This is a remote platform
     m_name_to_kext_path_map(),
-    m_directories_searched(),
+    m_search_directories(),
+    m_kernel_binaries(),
     m_ios_debug_session(is_ios_debug_session)
 
 {
     if (GetGlobalProperties()->GetSearchForKexts())
     {
-        SearchForKexts ();
+        CollectKextAndKernelDirectories ();
+        IndexKextsInDirectories ();
+        IndexKernelsInDirectories ();
     }
 }
 
@@ -282,23 +285,26 @@ PlatformDarwinKernel::GetStatus (Stream &strm)
         strm.Printf ("Mac OS X kernel debugging\n");
     else
             strm.Printf ("unknown kernel debugging\n");
-    const uint32_t num_kext_dirs = m_directories_searched.size();
+    const uint32_t num_kext_dirs = m_search_directories.size();
     for (uint32_t i=0; i<num_kext_dirs; ++i)
     {
-        const FileSpec &kext_dir = m_directories_searched[i];
+        const FileSpec &kext_dir = m_search_directories[i];
         strm.Printf (" Kext directories: [%2u] \"%s\"\n", i, kext_dir.GetPath().c_str());
     }
     strm.Printf (" Total number of kexts indexed: %d\n", (int) m_name_to_kext_path_map.size());
 }
 
+// Populate the m_search_directories vector with directories we should search
+// for kernel & kext binaries.
+
 void
-PlatformDarwinKernel::SearchForKexts ()
+PlatformDarwinKernel::CollectKextAndKernelDirectories ()
 {
     // Differentiate between "ios debug session" and "mac debug session" so we don't index
     // kext bundles that won't be used in this debug session.  If this is an ios kext debug
     // session, looking in /System/Library/Extensions is a waste of stat()s, for example.
 
-    // Build up a list of all SDKs we'll be searching for directories of kexts
+    // Build up a list of all SDKs we'll be searching for directories of kexts/kernels
     // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk
     std::vector<FileSpec> sdk_dirs;
     if (m_ios_debug_session != eLazyBoolNo)
@@ -308,8 +314,14 @@ PlatformDarwinKernel::SearchForKexts ()
 
     GetGenericSDKDirectoriesToSearch (sdk_dirs);
 
-    // Build up a list of directories that hold kext bundles on the system
-    // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/System/Library/Extensions
+    // Build up a list of directories that hold may kext bundles & kernels
+    //
+    // e.g. given /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
+    // find 
+    // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/
+    // and
+    // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/System/Library/Extensions
+
     std::vector<FileSpec> kext_dirs;
     SearchSDKsForKextDirectories (sdk_dirs, kext_dirs);
 
@@ -322,10 +334,12 @@ PlatformDarwinKernel::SearchForKexts ()
 
     GetUserSpecifiedDirectoriesToSearch (kext_dirs);
 
-    // We now have a complete list of directories that we will search for kext bundles
-    m_directories_searched = kext_dirs;
+    GetKernelDirectoriesToSearch (kext_dirs);
 
-    IndexKextsInDirectories (kext_dirs);
+    GetCurrentDirectoryToSearch (kext_dirs);
+
+    // We now have a complete list of directories that we will search for kext bundles
+    m_search_directories = kext_dirs;
 }
 
 void
@@ -379,7 +393,6 @@ PlatformDarwinKernel::GetGenericSDKDirectoriesToSearch (std::vector<lldb_private
     {
         directories.push_back (installed_kdks);
     }
-
 }
 
 void
@@ -427,6 +440,50 @@ PlatformDarwinKernel::GetGenericDirectoriesToSearch (std::vector<lldb_private::F
 }
 
 void
+PlatformDarwinKernel::GetKernelDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+    FileSpec system_library_kernels ("/System/Library/Kernels", true);
+    if (system_library_kernels.Exists() && system_library_kernels.IsDirectory())
+    {
+        directories.push_back (system_library_kernels);
+    }
+    FileSpec slek("/System/Library/Extensions/KDK", true);
+    if (slek.Exists() && slek.IsDirectory())
+    {
+        directories.push_back(slek);
+    }
+}
+
+void
+PlatformDarwinKernel::GetCurrentDirectoryToSearch (std::vector<lldb_private::FileSpec> &directories)
+{
+    directories.push_back (FileSpec (".", true));
+
+    FileSpec sle_directory ("System/Library/Extensions", true);
+    if (sle_directory.Exists() && sle_directory.IsDirectory())
+    {
+        directories.push_back (sle_directory);
+    }
+
+    FileSpec le_directory ("Library/Extensions", true);
+    if (le_directory.Exists() && le_directory.IsDirectory())
+    {
+        directories.push_back (le_directory);
+    }
+
+    FileSpec slk_directory ("System/Library/Kernels", true);
+    if (slk_directory.Exists() && slk_directory.IsDirectory())
+    {
+        directories.push_back (slk_directory);
+    }
+    FileSpec slek("System/Library/Extensions/KDK", true);
+    if (slek.Exists() && slek.IsDirectory())
+    {
+        directories.push_back(slek);
+    }
+}
+
+void
 PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
 {
     FileSpecList user_dirs(GetGlobalProperties()->GetKextDirectories());
@@ -450,6 +507,24 @@ PlatformDarwinKernel::GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_priv
             {
                 directories.push_back (dir_sle);
             }
+
+            // Is there a "System/Library/Kernels" subdir of this directory?
+            std::string dir_slk_path = dir.GetPath();
+            dir_slk_path.append ("/System/Library/Kernels");
+            FileSpec dir_slk(dir_slk_path.c_str(), true);
+            if (dir_slk.Exists() && dir_slk.IsDirectory())
+            {
+                directories.push_back (dir_slk);
+            }
+
+            // Is there a "System/Library/Extensions/KDK" subdir of this directory?
+            std::string dir_slek_path = dir.GetPath();
+            dir_slek_path.append ("/System/Library/Kernels");
+            FileSpec dir_slek(dir_slek_path.c_str(), true);
+            if (dir_slek.Exists() && dir_slek.IsDirectory())
+            {
+                directories.push_back (dir_slek);
+            }
         }
     }
 
@@ -523,19 +598,36 @@ PlatformDarwinKernel::GetKextDirectoriesInSDK (void *baton,
             ((std::vector<lldb_private::FileSpec> *)baton)->push_back(le_kext_directory);
         }
 
+        // Check to see if there is a System/Library/Kernels subdir & add it if it exists
+        std::string slk_kernel_path (kext_directory_path);
+        slk_kernel_path.append ("/System/Library/Kernels");
+        FileSpec slk_kernel_directory (slk_kernel_path.c_str(), true);
+        if (slk_kernel_directory.Exists() && slk_kernel_directory.IsDirectory())
+        {
+            ((std::vector<lldb_private::FileSpec> *)baton)->push_back(slk_kernel_directory);
+        }
+
+        // Check to see if there is a System/Library/Extensions/KDK subdir & add it if it exists
+        std::string slek_kernel_path (kext_directory_path);
+        slek_kernel_path.append ("/System/Library/Extensions/KDK");
+        FileSpec slek_kernel_directory (slek_kernel_path.c_str(), true);
+        if (slek_kernel_directory.Exists() && slek_kernel_directory.IsDirectory())
+        {
+            ((std::vector<lldb_private::FileSpec> *)baton)->push_back(slek_kernel_directory);
+        }
     }
     return FileSpec::eEnumerateDirectoryResultNext;
 }
 
 void
-PlatformDarwinKernel::IndexKextsInDirectories (std::vector<lldb_private::FileSpec> kext_dirs)
+PlatformDarwinKernel::IndexKextsInDirectories ()
 {
     std::vector<FileSpec> kext_bundles;
 
-    const uint32_t num_dirs = kext_dirs.size();
+    const uint32_t num_dirs = m_search_directories.size();
     for (uint32_t i = 0; i < num_dirs; i++)
     {
-        const FileSpec &dir = kext_dirs[i];
+        const FileSpec &dir = m_search_directories[i];
         const bool find_directories = true;
         const bool find_files = false;
         const bool find_other = false;
@@ -612,6 +704,56 @@ PlatformDarwinKernel::GetKextsInDirectory (void *baton,
     return FileSpec::eEnumerateDirectoryResultNext;
 }
 
+void
+PlatformDarwinKernel::IndexKernelsInDirectories ()
+{
+    std::vector<FileSpec> kernels;
+
+
+    const uint32_t num_dirs = m_search_directories.size();
+    for (uint32_t i = 0; i < num_dirs; i++)
+    {
+        const FileSpec &dir = m_search_directories[i];
+        const bool find_directories = false;
+        const bool find_files = true;
+        const bool find_other = true;  // I think eFileTypeSymbolicLink are "other"s.
+        FileSpec::EnumerateDirectory (dir.GetPath().c_str(),
+                                      find_directories,
+                                      find_files,
+                                      find_other,
+                                      GetKernelsInDirectory,
+                                      &m_kernel_binaries);
+    }
+}
+
+// Callback for FileSpec::EnumerateDirectory().
+// Step through the entries in a directory like /System/Library/Kernels/, find kernel binaries,
+// add them to m_kernel_binaries.
+
+// We're only doing a filename match here.  We won't try opening the file to see if it's really
+// a kernel or not until we need to find a kernel of a given UUID.  There's no cheap way to find
+// the UUID of a file (or if it's a Mach-O binary at all) without creating a whole Module for
+// the file and throwing it away if it's not wanted.
+
+FileSpec::EnumerateDirectoryResult
+PlatformDarwinKernel::GetKernelsInDirectory (void *baton,
+                                           FileSpec::FileType file_type,
+                                           const FileSpec &file_spec)
+{
+    if (file_type == FileSpec::eFileTypeRegular || file_type == FileSpec::eFileTypeSymbolicLink)
+    {
+        ConstString filename = file_spec.GetFilename();
+        if (strncmp (filename.GetCString(), "kernel", 6) == 0
+            || strncmp (filename.GetCString(), "mach.", 5) == 0)
+        {
+            // This is m_kernel_binaries but we're in a class method here
+            ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec);
+        }
+    }
+    return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
 Error
 PlatformDarwinKernel::GetSharedModule (const ModuleSpec &module_spec,
                                        ModuleSP &module_sp,
@@ -644,6 +786,28 @@ PlatformDarwinKernel::GetSharedModule (const ModuleSpec &module_spec,
         }
     }
 
+    if (kext_bundle_id.compare("mach_kernel") == 0 && module_spec.GetUUID().IsValid())
+    {
+        for (auto possible_kernel : m_kernel_binaries)
+        {
+            if (possible_kernel.Exists())
+            {
+                ModuleSpec kern_spec (possible_kernel);
+                kern_spec.GetUUID() = module_spec.GetUUID();
+                ModuleSP module_sp (new Module (kern_spec));
+                if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec (kern_spec))
+                {
+                    Error error;
+                    error = ModuleList::GetSharedModule (kern_spec, module_sp, NULL, NULL, NULL);
+                    if (module_sp && module_sp->GetObjectFile())
+                    {
+                        return error;
+                    }
+                }
+            }
+        }
+    }
+
     // Else fall back to treating the file's path as an actual file path - defer to PlatformDarwin's GetSharedModule.
     return PlatformDarwin::GetSharedModule (module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
 }
index 1ba2680..ad0bc62 100644 (file)
@@ -66,7 +66,7 @@ public:
     }
 
     virtual uint32_t
-    GetPluginVersion()  override
+    GetPluginVersion() override
     {
         return 1;
     }
@@ -88,7 +88,7 @@ public:
                      lldb::ModuleSP &module_sp,
                      const lldb_private::FileSpecList *module_search_paths_ptr,
                      lldb::ModuleSP *old_module_sp_ptr,
-                     bool *did_create_ptr)  override;
+                     bool *did_create_ptr) override;
 
     bool
     GetSupportedArchitectureAtIndex (uint32_t idx, 
@@ -100,7 +100,6 @@ public:
     void
     CalculateTrapHandlerSymbolNames () override;
 
-
 protected:
 
     // Map from kext bundle ID ("com.apple.filesystems.exfat") to FileSpec for the kext bundle on 
@@ -108,6 +107,7 @@ protected:
     typedef std::multimap<lldb_private::ConstString, lldb_private::FileSpec> BundleIDToKextMap;
     typedef BundleIDToKextMap::iterator BundleIDToKextIterator;
 
+    typedef std::vector<lldb_private::FileSpec> KernelBinaryCollection;
     
     // Array of directories that were searched for kext bundles (used only for reporting to user)
     typedef std::vector<lldb_private::FileSpec> DirectoriesSearchedCollection;
@@ -124,8 +124,9 @@ protected:
                          lldb_private::FileSpec::FileType file_type,
                          const lldb_private::FileSpec &file_spec);
 
+    // Populate m_search_directories vector of directories
     void
-    SearchForKexts();
+    CollectKextAndKernelDirectories ();
 
     // Directories where we may find iOS SDKs with kext bundles in them
     void
@@ -155,6 +156,13 @@ protected:
     void
     GetUserSpecifiedDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
 
+    void
+    GetCurrentDirectoryToSearch (std::vector<lldb_private::FileSpec> &directories);
+
+    // Directories where we may find kernels exclusively
+    void
+    GetKernelDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories);
+
     // Search through a vector of SDK FileSpecs, add any directories that may contain kexts
     // to the vector of kext dir FileSpecs
     void
@@ -163,16 +171,28 @@ protected:
     // Search through all of the directories passed in, find all .kext bundles in those directories,
     // get the CFBundleIDs out of the Info.plists and add the bundle ID and kext path to m_name_to_kext_path_map.
     void
-    IndexKextsInDirectories (std::vector<lldb_private::FileSpec> kext_dirs);
+    IndexKextsInDirectories ();
+
+    // Search through all of the directories passed in, find all kernel binaries in those directories
+    // (look for "kernel*", "mach.*", assume those are kernels.  False positives aren't a huge problem.)
+    void
+    IndexKernelsInDirectories ();
+
+    // Callback which iterates over all the files in a given directory, looking for kernel binaries
+    static lldb_private::FileSpec::EnumerateDirectoryResult 
+    GetKernelsInDirectory (void *baton,
+                         lldb_private::FileSpec::FileType file_type,
+                         const lldb_private::FileSpec &file_spec);
 
     lldb_private::Error
     ExamineKextForMatchingUUID (const lldb_private::FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, const lldb_private::ArchSpec &arch, lldb::ModuleSP &exe_module_sp);
 
 private:
 
-    BundleIDToKextMap m_name_to_kext_path_map; 
-    DirectoriesSearchedCollection m_directories_searched;
-    lldb_private::LazyBool m_ios_debug_session;
+    BundleIDToKextMap             m_name_to_kext_path_map; // multimap of CFBundleID to FileSpec on local filesystem
+    DirectoriesSearchedCollection m_search_directories;    // list of directories we search for kexts/kernels
+    KernelBinaryCollection        m_kernel_binaries;       // list of kernel binaries we found on local filesystem
+    lldb_private::LazyBool        m_ios_debug_session;
 
     DISALLOW_COPY_AND_ASSIGN (PlatformDarwinKernel);