Fix dbgshim fails to decode libcoreclr.so headers from Snap install (#3530)
authorMike McLaughlin <mikem@microsoft.com>
Thu, 1 Dec 2022 22:07:24 +0000 (14:07 -0800)
committerGitHub <noreply@github.com>
Thu, 1 Dec 2022 22:07:24 +0000 (14:07 -0800)
Issue: https://github.com/dotnet/diagnostics/issues/3510

Add GetBuildIdFromSectionHeader that used when getting the build id note
from the program headers failures.

src/dbgshim/dbgshim.cpp
src/shared/dbgutil/elfreader.cpp
src/shared/dbgutil/elfreader.h
src/tests/DbgShim.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt

index ef8623dbc5736f8a344b5801bad1ce92b47ce616..2a2c572d02daf1676da6ddd320e36ca967e383ac 100644 (file)
@@ -354,6 +354,7 @@ public:
             hr = GetTargetCLRMetrics(clrInfo.RuntimeModulePath, NULL, &clrInfo, NULL);
             if (FAILED(hr))
             { 
+                // Runtime module not found (return false). This isn't an error that needs to be reported via the callback.
                 return false;
             }
 
@@ -407,7 +408,7 @@ public:
             // Invoke the callback on error
             m_callback(NULL, m_parameter, hr);
         }
-
+        // Runtime module found (return true)
         return true;
     }
 
@@ -1293,12 +1294,13 @@ GetTargetCLRMetrics(
     {
         if (IsCoreClr(wszModulePath))
         {
-            // Get the runtime index info (build id) for Linux/MacOS
-            if (!TryGetBuildIdFromFile(wszModulePath, pClrInfoOut->RuntimeBuildId, MAX_BUILDID_SIZE, &pClrInfoOut->RuntimeBuildIdSize)) 
+            // Get the runtime index info (build id) for Linux/MacOS. If getting the build id fails for any reason, return success
+            // but with an invalid ClrInfo (unknown index type, no build id) so ProvideLibraries fails in InvokeStartupCallback and
+            // invokes the callback with an error.
+            if (TryGetBuildIdFromFile(wszModulePath, pClrInfoOut->RuntimeBuildId, MAX_BUILDID_SIZE, &pClrInfoOut->RuntimeBuildIdSize)) 
             {
-                return E_FAIL;
+                pClrInfoOut->IndexType = LIBRARY_PROVIDER_INDEX_TYPE::Runtime;
             }
-            pClrInfoOut->IndexType = LIBRARY_PROVIDER_INDEX_TYPE::Runtime; 
         }
         else
         { 
index f01d8a5611a4dfb68ead31bdfe97a08f3dae3235..3f438caa40897a139ff1adcc2d4f6b992b4f2225 100644 (file)
@@ -148,7 +148,14 @@ TryGetBuildIdFromFile(const WCHAR* modulePath, BYTE* buffer, ULONG bufferSize, P
     {
         if (reader.EnumerateProgramHeaders(0, nullptr, nullptr))
         {
-            return reader.GetBuildId(buffer, bufferSize, pBuildSize);
+            if (reader.GetBuildId(buffer, bufferSize, pBuildSize))
+            {
+                return true;
+            }
+        }
+        if (reader.GetBuildIdFromSectionHeader(0, buffer, bufferSize, pBuildSize))
+        {
+            return true;
         }
     }
     return false;
@@ -543,6 +550,40 @@ ElfReader::GetBuildId(BYTE* buffer, ULONG bufferSize, PULONG pBuildSize)
 
 #ifdef HOST_UNIX
 
+bool
+ElfReader::GetBuildIdFromSectionHeader(uint64_t baseAddress, BYTE* buffer, ULONG bufferSize, PULONG pBuildSize)
+{
+    Elf_Ehdr ehdr;
+    if (!ReadHeader(baseAddress, ehdr)) {
+        return false;
+    }
+    if (ehdr.e_shoff == 0 || ehdr.e_shnum <= 0) {
+        return false;
+    }
+    Elf_Shdr* shdrAddr = reinterpret_cast<Elf_Shdr*>(baseAddress + ehdr.e_shoff);
+    for (int sectionIndex = 0; sectionIndex < ehdr.e_shnum; sectionIndex++, shdrAddr++)
+    {
+        Elf_Shdr sh;
+        if (!ReadMemory(shdrAddr, &sh, sizeof(sh))) {
+            Trace("GetBuildIdFromSectionHeader: %2d shdr %p ReadMemory FAILED\n", sectionIndex, shdrAddr);
+            return false;
+        }
+        Trace("GetBuildIdFromSectionHeader: %2d shdr %p type %2d (%x) addr %016lx offset %016lx size %016lx link %08x info %08x name %4d\n",
+            sectionIndex, shdrAddr, sh.sh_type, sh.sh_type, sh.sh_addr, sh.sh_offset, sh.sh_size, sh.sh_link, sh.sh_info, sh.sh_name);
+
+        if (sh.sh_type == SHT_NOTE)
+        {
+            m_noteStart = baseAddress + sh.sh_offset;
+            m_noteEnd = baseAddress + sh.sh_offset + sh.sh_size;
+            if (GetBuildId(buffer, bufferSize, pBuildSize))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 //
 // Enumerate all the ELF info starting from the root program header. This
 // function doesn't cache any state in the ElfReader class.
@@ -615,14 +656,12 @@ ElfReader::EnumerateLinkMapEntries(Elf_Dyn* dynamicAddr)
         }
         // Read the module's name and make sure the memory is added to the core dump
         std::string moduleName;
-        int i = 0;
-        if (map.l_name != nullptr)
+        if (map.l_name != 0)
         {
-            for (; i < PATH_MAX; i++)
+            for (int i = 0; i < PATH_MAX; i++)
             {
                 char ch;
-                char* l_name = const_cast<char*>(map.l_name);
-                if (!ReadMemory(l_name + i, &ch, sizeof(ch))) {
+                if (!ReadMemory(map.l_name + i, &ch, sizeof(ch))) {
                     Trace("DSO: ReadMemory link_map name %p + %d FAILED\n", map.l_name, i);
                     break;
                 }
@@ -632,7 +671,7 @@ ElfReader::EnumerateLinkMapEntries(Elf_Dyn* dynamicAddr)
                 moduleName.append(1, ch);
             }
         }
-        Trace("\nDSO: link_map entry %p l_ld %p l_addr (Ehdr) %" PRIx " %s\n", linkMapAddr, map.l_ld, map.l_addr, moduleName.c_str());
+        Trace("\nDSO: link_map entry %p l_ld %p l_addr (Ehdr) %p l_name %p %s\n", linkMapAddr, map.l_ld, map.l_addr, map.l_name, moduleName.c_str());
 
         // Call the derived class for each module
         VisitModule(map.l_addr, moduleName);
@@ -646,11 +685,10 @@ ElfReader::EnumerateLinkMapEntries(Elf_Dyn* dynamicAddr)
 #endif // HOST_UNIX
 
 bool
-ElfReader::EnumerateProgramHeaders(uint64_t baseAddress, uint64_t* ploadbias, Elf_Dyn** pdynamicAddr)
+ElfReader::ReadHeader(uint64_t baseAddress, Elf_Ehdr& ehdr)
 {
-    Elf_Ehdr ehdr;
-    if (!ReadMemory((void*)baseAddress, &ehdr, sizeof(ehdr))) {
-        Trace("ERROR: EnumerateProgramHeaders ReadMemory(%p, %" PRIx ") ehdr FAILED\n", (void*)baseAddress, sizeof(ehdr));
+    if (!ReadMemory((void*)baseAddress, &ehdr, sizeof(Elf_Ehdr))) {
+        Trace("ERROR: EnumerateProgramHeaders ReadMemory(%p, %" PRIx ") ehdr FAILED\n", (void*)baseAddress, sizeof(Elf_Ehdr));
         return false;
     }
     if (memcmp(ehdr.e_ident, ElfMagic, strlen(ElfMagic)) != 0) {
@@ -673,9 +711,18 @@ ElfReader::EnumerateProgramHeaders(uint64_t baseAddress, uint64_t* ploadbias, El
     }
     Trace("ELF: type %d mach 0x%x ver %d flags 0x%x phnum %d phoff %" PRIxA " phentsize 0x%02x shnum %d shoff %" PRIxA " shentsize 0x%02x shstrndx %d\n",
         ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_flags, phnum, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_shnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shstrndx);
+    return true;
+}
 
+bool
+ElfReader::EnumerateProgramHeaders(uint64_t baseAddress, uint64_t* ploadbias, Elf_Dyn** pdynamicAddr)
+{
+    Elf_Ehdr ehdr;
+    if (!ReadHeader(baseAddress, ehdr)) {
+        return false;
+    }
     Elf_Phdr* phdrAddr = reinterpret_cast<Elf_Phdr*>(baseAddress + ehdr.e_phoff);
-    return EnumerateProgramHeaders(phdrAddr, phnum, baseAddress, ploadbias, pdynamicAddr);
+    return EnumerateProgramHeaders(phdrAddr, ehdr.e_phnum, baseAddress, ploadbias, pdynamicAddr);
 }
 
 //
@@ -797,6 +844,8 @@ Elf64_Ehdr::Elf64_Ehdr()
     e_machine = EM_X86_64;
 #elif defined(TARGET_ARM64)
     e_machine = EM_AARCH64;
+#elif defined(TARGET_LOONGARCH64)
+    e_machine = EM_LOONGARCH;
 #endif
     e_flags = 0;
     e_version = 1;
index 483fb36ea1fe4f13978f3e9df6df6bf12681b25d..73daa53d052704c199a5caa52f9949751a68c4e8 100644 (file)
@@ -48,13 +48,14 @@ private:
 public:
     ElfReader(bool isFileLayout);
     virtual ~ElfReader();
+    bool PopulateForSymbolLookup(uint64_t baseAddress);
+    bool TryLookupSymbol(std::string symbolName, uint64_t* symbolOffset);
+    bool GetBuildId(BYTE* buffer, ULONG bufferSize, PULONG pBuildSize);
 #ifdef HOST_UNIX
     bool EnumerateElfInfo(ElfW(Phdr)* phdrAddr, int phnum);
+    bool GetBuildIdFromSectionHeader(uint64_t baseAddress, BYTE* buffer, ULONG bufferSize, PULONG pBuildSize);
 #endif
-    bool PopulateForSymbolLookup(uint64_t baseAddress);
-    bool TryLookupSymbol(std::string symbolName, uint64_t* symbolOffset);
     bool EnumerateProgramHeaders(uint64_t baseAddress, uint64_t* ploadbias = nullptr, ElfW(Dyn)** pdynamicAddr = nullptr);
-    bool GetBuildId(BYTE* buffer, ULONG bufferSize, PULONG pBuildSize);
 
 private:
     bool GetSymbol(int32_t index, ElfW(Sym)* symbol);
@@ -63,10 +64,11 @@ private:
     uint32_t Hash(const std::string& symbolName);
     bool GetChain(int index, int32_t* chain);
     bool GetStringAtIndex(int index, std::string& result);
+    bool ReadHeader(uint64_t baseAddress, ElfW(Ehdr)& ehdr);
+    bool EnumerateProgramHeaders(ElfW(Phdr)* phdrAddr, int phnum, uint64_t baseAddress, uint64_t* ploadbias, ElfW(Dyn)** pdynamicAddr);
 #ifdef HOST_UNIX
     bool EnumerateLinkMapEntries(ElfW(Dyn)* dynamicAddr);
 #endif
-    bool EnumerateProgramHeaders(ElfW(Phdr)* phdrAddr, int phnum, uint64_t baseAddress, uint64_t* ploadbias, ElfW(Dyn)** pdynamicAddr);
 #ifdef __FreeBSD__
     virtual void VisitModule(caddr_t baseAddress, std::string& moduleName) { };
 #else
index 31decaa95b0ab1c6c2e5244cc31a8fc5d360421b..0fac8d369804f2f4ded59e78b1b750de6620adaf 100644 (file)
   <BuildProjectFrameworkLatest Condition="StartsWith('$(RuntimeVersionLatest)', '6')">net6.0</BuildProjectFrameworkLatest>
 
   <TestProduct>ProjectK</TestProduct>
-  <DebuggeeSourceRoot>$(RepoRootDir)\src\tests\DbgShim.UnitTests\Debuggees</DebuggeeSourceRoot>
-  <DebuggeeMsbuildAuxRoot>$(RepoRootDir)\eng\AuxMsbuildFiles</DebuggeeMsbuildAuxRoot>
+  <DebuggeeSourceRoot>$(RepoRootDir)/src/tests/DbgShim.UnitTests/Debuggees</DebuggeeSourceRoot>
+  <DebuggeeMsbuildAuxRoot>$(RepoRootDir)/eng/AuxMsbuildFiles</DebuggeeMsbuildAuxRoot>
   <DebuggeeBuildProcess>cli</DebuggeeBuildProcess>
   <DebuggeeName>SimpleDebuggee</DebuggeeName>
 
   !-- Use the global.json SDK to build and the test SDK/runtime to run -->
-  <!--
-  <CliPath>$(RepoRootDir)/.dotnet/dotnet</CliPath>
-  -->
   <CliPath>$(DotNetRoot)/dotnet</CliPath>
 
   <NuGetPackageFeeds>
@@ -83,7 +80,7 @@
           <RuntimeFrameworkVersion>$(RuntimeVersionLatest)</RuntimeFrameworkVersion>
         </Option>
         <Option Condition="'$(RuntimeVersion60)' != ''">
-          <DebuggeeBuildRoot>$(RootBinDir)\Debuggees</DebuggeeBuildRoot>
+          <DebuggeeBuildRoot>$(RootBinDir)/Debuggees</DebuggeeBuildRoot>
           <BuildProjectFramework>net6.0</BuildProjectFramework>
           <RuntimeFrameworkVersion>$(RuntimeVersion60)</RuntimeFrameworkVersion>
         </Option>