Fix dump creation on MacOS Ventura (#79356)
authorMike McLaughlin <mikem@microsoft.com>
Wed, 7 Dec 2022 23:17:41 +0000 (15:17 -0800)
committerGitHub <noreply@github.com>
Wed, 7 Dec 2022 23:17:41 +0000 (15:17 -0800)
Use the task_info(TASK_DYLD_INFO) API to get the dylinker info instead of
enumerating all the memory regions. This works on Ventura and simplifies
the module enumeration quite a bit.

src/coreclr/debug/createdump/crashinfo.h
src/coreclr/debug/createdump/crashinfomac.cpp
src/coreclr/debug/dbgutil/machoreader.cpp
src/coreclr/debug/dbgutil/machoreader.h

index 50c0cca..7e46c65 100644 (file)
@@ -142,7 +142,6 @@ private:
 #ifdef __APPLE__
     bool EnumerateMemoryRegions();
     void InitializeOtherMappings();
-    bool TryFindDyLinker(mach_vm_address_t address, mach_vm_size_t size, bool* found);
     void VisitModule(MachOModule& module);
     void VisitSegment(MachOModule& module, const segment_command_64& segment);
     void VisitSection(MachOModule& module, const section_64& section);
index f1f91ff..21ec72f 100644 (file)
@@ -148,18 +148,23 @@ CrashInfo::EnumerateMemoryRegions()
         }
     }
 
-    // Now find all the modules and add them to the module list
-    for (const MemoryRegion& region : m_allMemoryRegions)
+    // Get the dylinker info and enumerate all the modules
+    struct task_dyld_info dyld_info;
+    mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    kern_return_t result = ::task_info(Task(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
+    if (result != KERN_SUCCESS)
     {
-        bool found;
-        if (!TryFindDyLinker(region.StartAddress(), region.Size(), &found)) {
-            return false;
-        }
-        if (found) {
-            break;
-        }
+        TRACE("EnumerateMemoryRegions: task_info(TASK_DYLD_INFO) FAILED %x %s\n", result, mach_error_string(result));
+        return false;
+    }
+
+    // Enumerate all the modules in dyld's image cache. VisitModule is called for every module found.
+    if (!EnumerateModules(dyld_info.all_image_info_addr))
+    {
+        return false;
     }
-    TRACE("AllMemoryRegions %06llx native ModuleMappings %06llx\n", cbAllMemoryRegions / PAGE_SIZE, m_cbModuleMappings / PAGE_SIZE);
+
+    TRACE("EnumerateMemoryRegions: cbAllMemoryRegions %06llx native cbModuleMappings %06llx\n", cbAllMemoryRegions / PAGE_SIZE, m_cbModuleMappings / PAGE_SIZE);
     return true;
 }
 
@@ -216,46 +221,6 @@ CrashInfo::InitializeOtherMappings()
     TRACE("OtherMappings: %06llx\n", cbOtherMappings / PAGE_SIZE);
 }
 
-bool
-CrashInfo::TryFindDyLinker(mach_vm_address_t address, mach_vm_size_t size, bool* found)
-{
-    bool result = true;
-    *found = false;
-
-    if (size > sizeof(mach_header_64))
-    {
-        mach_header_64 header;
-        size_t read = 0;
-        if (ReadProcessMemory((void*)address, &header, sizeof(mach_header_64), &read))
-        { 
-            if (header.magic == MH_MAGIC_64)
-            {
-                TRACE("TryFindDyLinker: found module header at %016llx %08llx ncmds %d sizeofcmds %08x type %02x\n",
-                    address,
-                    size,
-                    header.ncmds,
-                    header.sizeofcmds,
-                    header.filetype);
-
-                if (header.filetype == MH_DYLINKER)
-                {
-                    TRACE("TryFindDyLinker: found dylinker\n");
-                    *found = true;
-
-                    // Enumerate all the modules in dyld's image cache. VisitModule is called for every module found.
-                    result = EnumerateModules(address, &header);
-                }
-            }
-        }
-        else 
-        {
-            TRACE("TryFindDyLinker: ReadProcessMemory header at %p %d FAILED\n", address, read);
-        }
-    }
-
-    return result;
-}
-
 void CrashInfo::VisitModule(MachOModule& module)
 {
     AddModuleInfo(false, module.BaseAddress(), nullptr, module.Name());
index 7fef34e..399b186 100644 (file)
@@ -75,7 +75,7 @@ TryGetSymbol(ICorDebugDataTarget* dataTarget, uint64_t baseAddress, const char*
 // MachO module 
 //--------------------------------------------------------------------
 
-MachOModule::MachOModule(MachOReader& reader, mach_vm_address_t baseAddress, mach_header_64* header, std::string* name) :
+MachOModule::MachOModule(MachOReader& reader, mach_vm_address_t baseAddress, std::string* name) :
     m_reader(reader),
     m_baseAddress(baseAddress),
     m_loadBias(0),
@@ -84,9 +84,6 @@ MachOModule::MachOModule(MachOReader& reader, mach_vm_address_t baseAddress, mac
     m_nlists(nullptr),
     m_strtabAddress(0)
 {
-    if (header != nullptr) {
-        m_header = *header;
-    }
     if (name != nullptr) {
         m_name = *name;
     }
@@ -363,43 +360,25 @@ MachOReader::MachOReader()
 }
 
 bool
-MachOReader::EnumerateModules(mach_vm_address_t address, mach_header_64* header)
+MachOReader::EnumerateModules(mach_vm_address_t dyldInfoAddress)
 {
-    _ASSERTE(header->magic == MH_MAGIC_64);
-    _ASSERTE(header->filetype == MH_DYLINKER);
-
-    MachOModule dylinker(*this, address, header);
-
-    // Search for symbol for the dyld image info cache
-    uint64_t dyldInfoAddress = 0;
-    if (!dylinker.TryLookupSymbol("dyld_all_image_infos", &dyldInfoAddress))
-    {
-        Trace("ERROR: Can not find the _dyld_all_image_infos symbol\n");
-        return false;
-    }
-
     // Read the all image info from the dylinker image
     dyld_all_image_infos dyldInfo;
-
     if (!ReadMemory((void*)dyldInfoAddress, &dyldInfo, sizeof(dyld_all_image_infos)))
     {
         Trace("ERROR: Failed to read dyld_all_image_infos at %p\n", (void*)dyldInfoAddress);
         return false;
     }
-    std::string dylinkerPath;
-    if (!ReadString(dyldInfo.dyldPath, dylinkerPath))
+    Trace("MOD: infoArray %p infoArrayCount %d\n", dyldInfo.infoArray, dyldInfo.infoArrayCount);
+
+    // Create the dyld module info
+    if (!CreateModule(dyldInfo.dyldImageLoadAddress, dyldInfo.dyldPath))
     {
-        Trace("ERROR: Failed to read name at %p\n", dyldInfo.dyldPath);
+        Trace("ERROR: Failed to read dyld header at %p\n", dyldInfo.dyldImageLoadAddress);
         return false;
     }
-    dylinker.SetName(dylinkerPath);
-    Trace("MOD: %016llx %08x %s\n", dylinker.BaseAddress(), dylinker.Header().flags, dylinker.Name().c_str());
-    VisitModule(dylinker);
-
     void* imageInfosAddress = (void*)dyldInfo.infoArray;
     size_t imageInfosSize = dyldInfo.infoArrayCount * sizeof(dyld_image_info);
-    Trace("MOD: infoArray %p infoArrayCount %d\n", dyldInfo.infoArray, dyldInfo.infoArrayCount);
-
     ArrayHolder<dyld_image_info> imageInfos = new (std::nothrow) dyld_image_info[dyldInfo.infoArrayCount];
     if (imageInfos == nullptr)
     {
@@ -413,23 +392,27 @@ MachOReader::EnumerateModules(mach_vm_address_t address, mach_header_64* header)
     }
     for (int i = 0; i < dyldInfo.infoArrayCount; i++)
     {
-        mach_vm_address_t imageAddress = (mach_vm_address_t)imageInfos[i].imageLoadAddress;
-        const char* imageFilePathAddress = imageInfos[i].imageFilePath;
+        // Ignore any errors and continue to next module
+        CreateModule(imageInfos[i].imageLoadAddress, imageInfos[i].imageFilePath);
+    }
+    return true;
+}
 
-        std::string imagePath;
-        if (!ReadString(imageFilePathAddress, imagePath))
-        {
-            Trace("ERROR: Failed to read image name at %p\n", imageFilePathAddress);
-            continue;
-        }
-        MachOModule module(*this, imageAddress, nullptr, &imagePath);
-        if (!module.ReadHeader())
-        {
-            continue;
-        }
-        Trace("MOD: %016llx %08x %s\n", imageAddress, module.Header().flags, imagePath.c_str());
-        VisitModule(module);
+bool
+MachOReader::CreateModule(const struct mach_header*    imageAddress, const char* imageFilePathAddress)
+{
+    std::string imagePath;
+    if (!ReadString(imageFilePathAddress, imagePath))
+    {
+        return false;
+    }
+    MachOModule module(*this, (mach_vm_address_t)imageAddress, &imagePath);
+    if (!module.ReadHeader())
+    {
+        return false;
     }
+    Trace("MOD: %016llx %08x %s\n", imageAddress, module.Header().flags, imagePath.c_str());
+    VisitModule(module);
     return true;
 }
 
index a5f458b..8650f26 100644 (file)
@@ -27,7 +27,7 @@ private:
     uint64_t m_strtabAddress;
 
 public:
-    MachOModule(MachOReader& reader, mach_vm_address_t baseAddress, mach_header_64* header = nullptr, std::string* name = nullptr);
+    MachOModule(MachOReader& reader, mach_vm_address_t baseAddress, std::string* name = nullptr);
     ~MachOModule();
 
     inline mach_vm_address_t BaseAddress() const { return m_baseAddress; }
@@ -41,8 +41,6 @@ public:
     bool EnumerateSegments();
 
 private:
-    inline void SetName(std::string& name) { m_name = name; }
-
     bool ReadLoadCommands();
     bool ReadSymbolTable();
     uint64_t GetAddressFromFileOffset(uint32_t offset);
@@ -54,9 +52,10 @@ class MachOReader
     friend MachOModule;
 public:
     MachOReader();
-    bool EnumerateModules(mach_vm_address_t address, mach_header_64* header);
+    bool EnumerateModules(mach_vm_address_t dyldInfoAddress);
 
 private:
+    bool CreateModule(const struct mach_header*        imageAddress, const char* imageFilePathAddress);
     bool ReadString(const char* address, std::string& str);
     virtual void VisitModule(MachOModule& module) { };
     virtual void VisitSegment(MachOModule& module, const segment_command_64& segment) { };