Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dbgshim fails to decode libcoreclr.so headers from Snap install #3530

Merged
merged 1 commit into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/dbgshim/dbgshim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ class RuntimeStartupHelper
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;
}

Expand Down Expand Up @@ -407,7 +408,7 @@ class RuntimeStartupHelper
// Invoke the callback on error
m_callback(NULL, m_parameter, hr);
}

// Runtime module found (return true)
return true;
}

Expand Down Expand Up @@ -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
{
Expand Down
73 changes: 61 additions & 12 deletions src/shared/dbgutil/elfreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))) {
mikem8361 marked this conversation as resolved.
Show resolved Hide resolved
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.
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand All @@ -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) {
Expand All @@ -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);
}

//
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions src/shared/dbgutil/elfreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ class ElfReader
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);
Expand All @@ -63,10 +64,11 @@ class ElfReader
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@
<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>
Expand Down Expand Up @@ -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>
Expand Down