summaryrefslogtreecommitdiff
path: root/src/debug/createdump/crashinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/createdump/crashinfo.cpp')
-rw-r--r--src/debug/createdump/crashinfo.cpp522
1 files changed, 429 insertions, 93 deletions
diff --git a/src/debug/createdump/crashinfo.cpp b/src/debug/createdump/crashinfo.cpp
index b825f4d301..edc31616de 100644
--- a/src/debug/createdump/crashinfo.cpp
+++ b/src/debug/createdump/crashinfo.cpp
@@ -89,6 +89,10 @@ CrashInfo::EnumMemoryRegion(
return S_OK;
}
+//
+// Suspends all the threads and creating a list of them. Should be the first before
+// gather any info about the process.
+//
bool
CrashInfo::EnumerateAndSuspendThreads()
{
@@ -134,6 +138,9 @@ CrashInfo::EnumerateAndSuspendThreads()
return true;
}
+//
+// Gather all the necessary crash dump info.
+//
bool
CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
{
@@ -168,42 +175,33 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
// If full memory dump, include everything regardless of permissions
if (minidumpType & MiniDumpWithFullMemory)
{
- for (const MemoryRegion& region : m_moduleMappings)
- {
- if (ValidRegion(region))
- {
- InsertMemoryRegion(region);
- }
+ for (const MemoryRegion& region : m_moduleMappings)
+ {
+ InsertMemoryBackedRegion(region);
}
for (const MemoryRegion& region : m_otherMappings)
{
- if (ValidRegion(region))
- {
- InsertMemoryRegion(region);
- }
+ InsertMemoryBackedRegion(region);
}
}
- else
+ // Add all the heap (read/write) memory regions (m_otherMappings contains the heaps)
+ else if (minidumpType & MiniDumpWithPrivateReadWriteMemory)
{
- // Add all the heap (read/write) memory regions but not the modules' r/w data segments
- if (minidumpType & MiniDumpWithPrivateReadWriteMemory)
+ for (const MemoryRegion& region : m_otherMappings)
{
- for (const MemoryRegion& region : m_otherMappings)
+ if (region.Permissions() == (PF_R | PF_W))
{
- if (region.Permissions() == (PF_R | PF_W))
- {
- if (ValidRegion(region))
- {
- InsertMemoryRegion(region);
- }
- }
+ InsertMemoryBackedRegion(region);
}
}
- // Gather all the useful memory regions from the DAC
- if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
- {
- return false;
- }
+ }
+ // Gather all the useful memory regions from the DAC
+ if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
+ {
+ return false;
+ }
+ if ((minidumpType & MiniDumpWithFullMemory) == 0)
+ {
// Add the thread's stack and some code memory to core
for (ThreadInfo* thread : m_threads)
{
@@ -217,6 +215,19 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
thread->GetThreadCode(&start, &size);
InsertMemoryRegion(start, size);
}
+ // All the regions added so far has been backed by memory. Now add the rest of
+ // mappings so the debuggers like lldb see that an address is code (PF_X) even
+ // if it isn't actually in the core dump.
+ for (const MemoryRegion& region : m_moduleMappings)
+ {
+ assert(!region.IsBackedByMemory());
+ InsertMemoryRegion(region);
+ }
+ for (const MemoryRegion& region : m_otherMappings)
+ {
+ assert(!region.IsBackedByMemory());
+ InsertMemoryRegion(region);
+ }
}
// Join all adjacent memory regions
CombineMemoryRegions();
@@ -235,6 +246,9 @@ CrashInfo::ResumeThreads()
}
}
+//
+// Get the auxv entries to use and add to the core dump
+//
bool
CrashInfo::GetAuxvEntries()
{
@@ -269,6 +283,9 @@ CrashInfo::GetAuxvEntries()
return result;
}
+//
+// Get the module mappings for the core dump NT_FILE notes
+//
bool
CrashInfo::EnumerateModuleMappings()
{
@@ -320,30 +337,38 @@ CrashInfo::EnumerateModuleMappings()
int c = sscanf(line, "%lx-%lx %m[-rwxsp] %lx %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName);
if (c == 4 || c == 5)
{
- if (linuxGateAddress != nullptr && reinterpret_cast<void*>(start) == linuxGateAddress)
- {
- InsertMemoryRegion(start, end - start);
- free(moduleName);
+ // r = read
+ // w = write
+ // x = execute
+ // s = shared
+ // p = private (copy on write)
+ uint32_t regionFlags = 0;
+ if (strchr(permissions, 'r')) {
+ regionFlags |= PF_R;
}
- else {
- uint32_t permissionFlags = 0;
- if (strchr(permissions, 'r')) {
- permissionFlags |= PF_R;
- }
- if (strchr(permissions, 'w')) {
- permissionFlags |= PF_W;
- }
- if (strchr(permissions, 'x')) {
- permissionFlags |= PF_X;
- }
- MemoryRegion memoryRegion(permissionFlags, start, end, offset, moduleName);
+ if (strchr(permissions, 'w')) {
+ regionFlags |= PF_W;
+ }
+ if (strchr(permissions, 'x')) {
+ regionFlags |= PF_X;
+ }
+ if (strchr(permissions, 's')) {
+ regionFlags |= MEMORY_REGION_FLAG_SHARED;
+ }
+ if (strchr(permissions, 'p')) {
+ regionFlags |= MEMORY_REGION_FLAG_PRIVATE;
+ }
+ MemoryRegion memoryRegion(regionFlags, start, end, offset, moduleName);
- if (moduleName != nullptr && *moduleName == '/') {
- m_moduleMappings.insert(memoryRegion);
- }
- else {
- m_otherMappings.insert(memoryRegion);
- }
+ if (moduleName != nullptr && *moduleName == '/') {
+ m_moduleMappings.insert(memoryRegion);
+ }
+ else {
+ m_otherMappings.insert(memoryRegion);
+ }
+ if (linuxGateAddress != nullptr && reinterpret_cast<void*>(start) == linuxGateAddress)
+ {
+ InsertMemoryBackedRegion(memoryRegion);
}
free(permissions);
}
@@ -354,12 +379,12 @@ CrashInfo::EnumerateModuleMappings()
TRACE("Module mappings:\n");
for (const MemoryRegion& region : m_moduleMappings)
{
- region.Print();
+ region.Trace();
}
TRACE("Other mappings:\n");
for (const MemoryRegion& region : m_otherMappings)
{
- region.Print();
+ region.Trace();
}
}
@@ -369,12 +394,16 @@ CrashInfo::EnumerateModuleMappings()
return true;
}
+//
+// All the shared (native) module info to the core dump
+//
bool
CrashInfo::GetDSOInfo()
{
Phdr* phdrAddr = reinterpret_cast<Phdr*>(m_auxvValues[AT_PHDR]);
int phnum = m_auxvValues[AT_PHNUM];
assert(m_auxvValues[AT_PHENT] == sizeof(Phdr));
+ assert(phnum != PN_XNUM);
if (phnum <= 0 || phdrAddr == nullptr) {
return false;
@@ -387,6 +416,7 @@ CrashInfo::GetDSOInfo()
{
Phdr ph;
if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) phdr FAILED\n", phdrAddr, sizeof(ph));
return false;
}
TRACE("DSO: phdr %p type %d (%x) vaddr %016lx memsz %016lx offset %016lx\n",
@@ -396,7 +426,7 @@ CrashInfo::GetDSOInfo()
{
dynamicAddr = reinterpret_cast<ElfW(Dyn)*>(ph.p_vaddr);
}
- else if (ph.p_type == PT_GNU_EH_FRAME)
+ else if (ph.p_type == PT_NOTE || ph.p_type == PT_GNU_EH_FRAME)
{
if (ph.p_vaddr != 0 && ph.p_memsz != 0)
{
@@ -414,6 +444,7 @@ CrashInfo::GetDSOInfo()
for (;;) {
ElfW(Dyn) dyn;
if (!ReadMemory(dynamicAddr, &dyn, sizeof(dyn))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) dyn FAILED\n", dynamicAddr, sizeof(dyn));
return false;
}
TRACE("DSO: dyn %p tag %ld (%lx) d_ptr %016lx\n", dynamicAddr, dyn.d_tag, dyn.d_tag, dyn.d_un.d_ptr);
@@ -430,6 +461,7 @@ CrashInfo::GetDSOInfo()
TRACE("DSO: rdebugAddr %p\n", rdebugAddr);
struct r_debug debugEntry;
if (!ReadMemory(rdebugAddr, &debugEntry, sizeof(debugEntry))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) r_debug FAILED\n", rdebugAddr, sizeof(debugEntry));
return false;
}
@@ -438,8 +470,10 @@ CrashInfo::GetDSOInfo()
for (struct link_map* linkMapAddr = debugEntry.r_map; linkMapAddr != nullptr;) {
struct link_map map;
if (!ReadMemory(linkMapAddr, &map, sizeof(map))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) link_map FAILED\n", linkMapAddr, sizeof(map));
return false;
}
+ // Read the module's name and make sure the memory is added to the core dump
int i = 0;
if (map.l_name != nullptr) {
for (; i < PATH_MAX; i++)
@@ -454,18 +488,134 @@ CrashInfo::GetDSOInfo()
}
}
moduleName[i] = '\0';
- TRACE("DSO: link_map entry %p l_ld %p l_addr %lx %s\n", linkMapAddr, map.l_ld, map.l_addr, (char*)moduleName);
+ TRACE("\nDSO: link_map entry %p l_ld %p l_addr (Ehdr) %lx %s\n", linkMapAddr, map.l_ld, map.l_addr, (char*)moduleName);
+
+ // Read the ELF header and info adding it to the core dump
+ if (!GetELFInfo(map.l_addr)) {
+ return false;
+ }
linkMapAddr = map.l_next;
}
return true;
}
+inline bool
+NameCompare(const char* name, const char* sectionName)
+{
+ return strncmp(name, sectionName, strlen(sectionName) + 1) == 0;
+}
+
+//
+// Add all the necessary ELF headers to the core dump
+//
+bool
+CrashInfo::GetELFInfo(uint64_t baseAddress)
+{
+ if (baseAddress == 0) {
+ return true;
+ }
+ Ehdr ehdr;
+ if (!ReadMemory((void*)baseAddress, &ehdr, sizeof(ehdr))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) ehdr FAILED\n", (void*)baseAddress, sizeof(ehdr));
+ return false;
+ }
+ int phnum = ehdr.e_phnum;
+ int shnum = ehdr.e_shnum;
+ assert(phnum != PN_XNUM);
+ assert(shnum != SHN_XINDEX);
+ assert(ehdr.e_shstrndx != SHN_XINDEX);
+ assert(ehdr.e_phentsize == sizeof(Phdr));
+ assert(ehdr.e_shentsize == sizeof(Shdr));
+ assert(ehdr.e_ident[EI_CLASS] == ELFCLASS64);
+ assert(ehdr.e_ident[EI_DATA] == ELFDATA2LSB);
+
+ TRACE("ELF: type %d mach 0x%x ver %d flags 0x%x phnum %d phoff %016lx phentsize 0x%02x shnum %d shoff %016lx 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, shnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shstrndx);
+
+ if (ehdr.e_phoff != 0 && phnum > 0)
+ {
+ Phdr* phdrAddr = reinterpret_cast<Phdr*>(baseAddress + ehdr.e_phoff);
+
+ // Add the program headers and search for the module's note and unwind info segments
+ for (int i = 0; i < phnum; i++, phdrAddr++)
+ {
+ Phdr ph;
+ if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) {
+ fprintf(stderr, "ReadMemory(%p, %lx) phdr FAILED\n", phdrAddr, sizeof(ph));
+ return false;
+ }
+ TRACE("ELF: phdr %p type %d (%x) vaddr %016lx memsz %016lx paddr %016lx filesz %016lx offset %016lx align %016lx\n",
+ phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_paddr, ph.p_filesz, ph.p_offset, ph.p_align);
+
+ if (ph.p_type == PT_DYNAMIC || ph.p_type == PT_NOTE || ph.p_type == PT_GNU_EH_FRAME)
+ {
+ if (ph.p_vaddr != 0 && ph.p_memsz != 0)
+ {
+ InsertMemoryRegion(baseAddress + ph.p_vaddr, ph.p_memsz);
+ }
+ }
+ }
+ }
+
+ // Skip the "interpreter" module i.e. /lib64/ld-linux-x86-64.so.2 or ld-2.19.so. The in-memory section headers are
+ // not valid. Ignore all failures too because on debug builds of coreclr, the section headers are not in valid memory.
+ if (baseAddress != m_auxvValues[AT_BASE] && ehdr.e_shoff != 0 && shnum > 0 && ehdr.e_shstrndx != SHN_UNDEF)
+ {
+ Shdr* shdrAddr = reinterpret_cast<Shdr*>(baseAddress + ehdr.e_shoff);
+
+ // Get the string table section header
+ Shdr stringTableSectionHeader;
+ if (!ReadMemory(shdrAddr + ehdr.e_shstrndx, &stringTableSectionHeader, sizeof(stringTableSectionHeader))) {
+ TRACE("ELF: %2d shdr %p ReadMemory string table section header FAILED\n", ehdr.e_shstrndx, shdrAddr + ehdr.e_shstrndx);
+ return true;
+ }
+ // Get the string table
+ ArrayHolder<char> stringTable = new char[stringTableSectionHeader.sh_size];
+ if (!ReadMemory((void*)(baseAddress + stringTableSectionHeader.sh_offset), stringTable.GetPtr(), stringTableSectionHeader.sh_size)) {
+ TRACE("ELF: %2d shdr %p ReadMemory string table FAILED\n", ehdr.e_shstrndx, (void*)(baseAddress + stringTableSectionHeader.sh_offset));
+ return true;
+ }
+ // Add the section headers to the core dump
+ for (int sectionIndex = 0; sectionIndex < shnum; sectionIndex++, shdrAddr++)
+ {
+ Shdr sh;
+ if (!ReadMemory(shdrAddr, &sh, sizeof(sh))) {
+ TRACE("ELF: %2d shdr %p ReadMemory FAILED\n", sectionIndex, shdrAddr);
+ return true;
+ }
+ TRACE("ELF: %2d shdr %p type %2d (%x) addr %016lx offset %016lx size %016lx link %08x info %08x name %4d %s\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, &stringTable[sh.sh_name]);
+
+ if (sh.sh_name != SHN_UNDEF && sh.sh_offset > 0 && sh.sh_size > 0) {
+ char* name = &stringTable[sh.sh_name];
+
+ // Add the .eh_frame/.eh_frame_hdr unwind info to the core dump
+ if (NameCompare(name, ".eh_frame") ||
+ NameCompare(name, ".eh_frame_hdr") ||
+ NameCompare(name, ".note.gnu.build-id") ||
+ NameCompare(name, ".note.gnu.ABI-tag") ||
+ NameCompare(name, ".gnu_debuglink"))
+ {
+ TRACE("ELF: %s %p size %016lx\n", name, (void*)(baseAddress + sh.sh_offset), sh.sh_size);
+ InsertMemoryRegion(baseAddress + sh.sh_offset, sh.sh_size);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// Enumerate all the memory regions using the DAC memory region support given a minidump type
+//
bool
CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
{
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
- ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
+ ICLRDataEnumMemoryRegions* clrDataEnumRegions = nullptr;
+ IXCLRDataProcess* clrDataProcess = nullptr;
HMODULE hdac = nullptr;
HRESULT hr = S_OK;
bool result = false;
@@ -475,7 +625,7 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE
dacPath.append(programPath);
dacPath.append("/");
dacPath.append(MAKEDLLNAME_A("mscordaccore"));
-
+
// Load and initialize the DAC
hdac = LoadLibraryA(dacPath.c_str());
if (hdac == nullptr)
@@ -489,17 +639,30 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE
fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
goto exit;
}
- hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&clrDataEnumRegions);
+ if ((minidumpType & MiniDumpWithFullMemory) == 0)
+ {
+ hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&clrDataEnumRegions);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
+ goto exit;
+ }
+ // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
+ hr = clrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
+ goto exit;
+ }
+ }
+ hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), m_dataTarget, (void**)&clrDataProcess);
if (FAILED(hr))
{
- fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
+ fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr);
goto exit;
}
- // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
- hr = clrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
- if (FAILED(hr))
+ if (!EnumerateManagedModules(clrDataProcess))
{
- fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
goto exit;
}
result = true;
@@ -508,6 +671,10 @@ exit:
{
clrDataEnumRegions->Release();
}
+ if (clrDataProcess != nullptr)
+ {
+ clrDataProcess->Release();
+ }
if (hdac != nullptr)
{
FreeLibrary(hdac);
@@ -516,6 +683,104 @@ exit:
}
//
+// Enumerate all the managed modules and replace the module
+// mapping with the module name found.
+//
+bool
+CrashInfo::EnumerateManagedModules(IXCLRDataProcess* clrDataProcess)
+{
+ IXCLRDataModule* clrDataModule = nullptr;
+ CLRDATA_ENUM enumModules = 0;
+ HRESULT hr = S_OK;
+
+ if (FAILED(hr = clrDataProcess->StartEnumModules(&enumModules))) {
+ fprintf(stderr, "StartEnumModules FAILED %08x\n", hr);
+ return false;
+ }
+ while ((hr = clrDataProcess->EnumModule(&enumModules, &clrDataModule)) == S_OK)
+ {
+ DacpGetModuleData moduleData;
+ if (SUCCEEDED(hr = moduleData.Request(clrDataModule)))
+ {
+ TRACE("MODULE: %016lx dyn %d inmem %d file %d pe %016lx pdb %016lx", moduleData.LoadedPEAddress, moduleData.IsDynamic,
+ moduleData.IsInMemory, moduleData.IsFileLayout, moduleData.PEFile, moduleData.InMemoryPdbAddress);
+
+ if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0)
+ {
+ ArrayHolder<WCHAR> wszUnicodeName = new WCHAR[MAX_LONGPATH + 1];
+ if (SUCCEEDED(hr = clrDataModule->GetFileName(MAX_LONGPATH, NULL, wszUnicodeName)))
+ {
+ char* pszName = (char*)malloc(MAX_LONGPATH + 1);
+ if (pszName == nullptr) {
+ fprintf(stderr, "Allocating module name FAILED\n");
+ return false;
+ }
+ sprintf_s(pszName, MAX_LONGPATH, "%S", (WCHAR*)wszUnicodeName);
+ TRACE(" %s\n", pszName);
+
+ // Change the module mapping name
+ ReplaceModuleMapping(moduleData.LoadedPEAddress, pszName);
+ }
+ else {
+ TRACE("\nModule.GetFileName FAILED %08x\n", hr);
+ }
+ }
+ else {
+ TRACE("\n");
+ }
+ }
+ else {
+ TRACE("moduleData.Request FAILED %08x\n", hr);
+ }
+ if (clrDataModule != nullptr) {
+ clrDataModule->Release();
+ }
+ }
+ if (enumModules != 0) {
+ clrDataProcess->EndEnumModules(enumModules);
+ }
+ return true;
+}
+
+//
+// Replace an existing module mapping with one with a different name.
+//
+void
+CrashInfo::ReplaceModuleMapping(CLRDATA_ADDRESS baseAddress, const char* pszName)
+{
+ // Add or change the module mapping for this PE image. The managed assembly images are
+ // already in the module mappings list but in .NET 2.0 they have the name "/dev/zero".
+ MemoryRegion region(PF_R | PF_W | PF_X, baseAddress, baseAddress + PAGE_SIZE, 0, pszName);
+ const auto& found = m_moduleMappings.find(region);
+ if (found == m_moduleMappings.end())
+ {
+ m_moduleMappings.insert(region);
+
+ if (g_diagnostics) {
+ TRACE("MODULE: ADD ");
+ region.Trace();
+ }
+ }
+ else
+ {
+ // Create the new memory region with the managed assembly name.
+ MemoryRegion newRegion(*found, pszName);
+
+ // Remove and cleanup the old one
+ m_moduleMappings.erase(found);
+ const_cast<MemoryRegion&>(*found).Cleanup();
+
+ // Add the new memory region
+ m_moduleMappings.insert(newRegion);
+
+ if (g_diagnostics) {
+ TRACE("MODULE: REPLACE ");
+ newRegion.Trace();
+ }
+ }
+}
+
+//
// ReadMemory from target and add to memory regions list
//
bool
@@ -524,7 +789,6 @@ CrashInfo::ReadMemory(void* address, void* buffer, size_t size)
uint32_t read = 0;
if (FAILED(m_dataTarget->ReadVirtual(reinterpret_cast<CLRDATA_ADDRESS>(address), reinterpret_cast<PBYTE>(buffer), size, &read)))
{
- fprintf(stderr, "ReadMemory(%p, %lx) FAILED\n", address, size);
return false;
}
InsertMemoryRegion(reinterpret_cast<uint64_t>(address), size);
@@ -538,6 +802,8 @@ CrashInfo::ReadMemory(void* address, void* buffer, size_t size)
void
CrashInfo::InsertMemoryRegion(uint64_t address, size_t size)
{
+ assert(size < UINT_MAX);
+
// Round to page boundary
uint64_t start = address & PAGE_MASK;
assert(start > 0);
@@ -546,8 +812,16 @@ CrashInfo::InsertMemoryRegion(uint64_t address, size_t size)
uint64_t end = ((address + size) + (PAGE_SIZE - 1)) & PAGE_MASK;
assert(end > 0);
- MemoryRegion region(start, end);
- InsertMemoryRegion(region);
+ InsertMemoryRegion(MemoryRegion(GetMemoryRegionFlags(start) | MEMORY_REGION_FLAG_MEMORY_BACKED, start, end));
+}
+
+//
+// Adds a memory backed flagged copy of the memory region. The file name is not preserved.
+//
+void
+CrashInfo::InsertMemoryBackedRegion(const MemoryRegion& region)
+{
+ InsertMemoryRegion(MemoryRegion(region, region.Flags() | MEMORY_REGION_FLAG_MEMORY_BACKED));
}
//
@@ -556,52 +830,88 @@ CrashInfo::InsertMemoryRegion(uint64_t address, size_t size)
void
CrashInfo::InsertMemoryRegion(const MemoryRegion& region)
{
- // First check if the full memory region can be added without conflicts
+ // First check if the full memory region can be added without conflicts and is fully valid.
const auto& found = m_memoryRegions.find(region);
if (found == m_memoryRegions.end())
{
- // Add full memory region
- m_memoryRegions.insert(region);
+ // If the region is valid, add the full memory region
+ if (ValidRegion(region)) {
+ m_memoryRegions.insert(region);
+ return;
+ }
}
else
{
- // The memory region is not wholely contained in region found
- if (!found->Contains(region))
- {
- uint64_t start = region.StartAddress();
+ // If the memory region is wholly contained in region found and both have the
+ // same backed by memory state, we're done.
+ if (found->Contains(region) && (found->IsBackedByMemory() == region.IsBackedByMemory())) {
+ return;
+ }
+ }
+ // Either part of the region was invalid, part of it hasn't been added or the backed
+ // by memory state is different.
+ uint64_t start = region.StartAddress();
- // The region overlaps/conflicts with one already in the set so
- // add one page at a time to avoid the overlapping pages.
- uint64_t numberPages = region.Size() >> PAGE_SHIFT;
+ // The region overlaps/conflicts with one already in the set so add one page at a
+ // time to avoid the overlapping pages.
+ uint64_t numberPages = region.Size() >> PAGE_SHIFT;
- for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
- {
- MemoryRegion memoryRegionPage(start, start + PAGE_SIZE);
+ for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
+ {
+ MemoryRegion memoryRegionPage(region.Flags(), start, start + PAGE_SIZE);
- const auto& found = m_memoryRegions.find(memoryRegionPage);
- if (found == m_memoryRegions.end())
- {
- m_memoryRegions.insert(memoryRegionPage);
- }
+ const auto& found = m_memoryRegions.find(memoryRegionPage);
+ if (found == m_memoryRegions.end())
+ {
+ // All the single pages added here will be combined in CombineMemoryRegions()
+ if (ValidRegion(memoryRegionPage)) {
+ m_memoryRegions.insert(memoryRegionPage);
}
}
+ else {
+ assert(found->IsBackedByMemory() || !region.IsBackedByMemory());
+ }
}
}
+//
+// Get the memory region flags for a start address
+//
+uint32_t
+CrashInfo::GetMemoryRegionFlags(uint64_t start)
+{
+ const MemoryRegion* region = SearchMemoryRegions(m_moduleMappings, start);
+ if (region != nullptr) {
+ return region->Flags();
+ }
+ region = SearchMemoryRegions(m_otherMappings, start);
+ if (region != nullptr) {
+ return region->Flags();
+ }
+ TRACE("GetMemoryRegionFlags: FAILED\n");
+ return PF_R | PF_W | PF_X;
+}
+
+//
+// Validates a memory region
+//
bool
CrashInfo::ValidRegion(const MemoryRegion& region)
{
- uint64_t start = region.StartAddress();
- uint64_t numberPages = region.Size() >> PAGE_SHIFT;
-
- for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
+ if (region.IsBackedByMemory())
{
- BYTE buffer[1];
- uint32_t read;
+ uint64_t start = region.StartAddress();
+ uint64_t numberPages = region.Size() >> PAGE_SHIFT;
- if (FAILED(m_dataTarget->ReadVirtual(start, buffer, 1, &read)))
+ for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
{
- return false;
+ BYTE buffer[1];
+ uint32_t read;
+
+ if (FAILED(m_dataTarget->ReadVirtual(start, buffer, 1, &read)))
+ {
+ return false;
+ }
}
}
return true;
@@ -617,28 +927,34 @@ CrashInfo::CombineMemoryRegions()
std::set<MemoryRegion> memoryRegionsNew;
+ // MEMORY_REGION_FLAG_SHARED and MEMORY_REGION_FLAG_PRIVATE are internal flags that
+ // don't affect the core dump so ignore them when comparing the flags.
+ uint32_t flags = m_memoryRegions.begin()->Flags() & (MEMORY_REGION_FLAG_MEMORY_BACKED | MEMORY_REGION_FLAG_PERMISSIONS_MASK);
uint64_t start = m_memoryRegions.begin()->StartAddress();
uint64_t end = start;
for (const MemoryRegion& region : m_memoryRegions)
{
- if (end == region.StartAddress())
+ // To combine a region it needs to be contiguous, same permissions and memory backed flag.
+ if ((end == region.StartAddress()) &&
+ (flags == (region.Flags() & (MEMORY_REGION_FLAG_MEMORY_BACKED | MEMORY_REGION_FLAG_PERMISSIONS_MASK))))
{
end = region.EndAddress();
}
else
{
- MemoryRegion memoryRegion(start, end);
+ MemoryRegion memoryRegion(flags, start, end);
assert(memoryRegionsNew.find(memoryRegion) == memoryRegionsNew.end());
memoryRegionsNew.insert(memoryRegion);
+ flags = region.Flags() & (MEMORY_REGION_FLAG_MEMORY_BACKED | MEMORY_REGION_FLAG_PERMISSIONS_MASK);
start = region.StartAddress();
end = region.EndAddress();
}
}
assert(start != end);
- MemoryRegion memoryRegion(start, end);
+ MemoryRegion memoryRegion(flags, start, end);
assert(memoryRegionsNew.find(memoryRegion) == memoryRegionsNew.end());
memoryRegionsNew.insert(memoryRegion);
@@ -649,11 +965,31 @@ CrashInfo::CombineMemoryRegions()
TRACE("Memory Regions:\n");
for (const MemoryRegion& region : m_memoryRegions)
{
- region.Print();
+ region.Trace();
+ }
+ }
+}
+
+//
+// Searches for a memory region given an address.
+//
+const MemoryRegion*
+CrashInfo::SearchMemoryRegions(const std::set<MemoryRegion>& regions, uint64_t start)
+{
+ std::set<MemoryRegion>::iterator found = regions.find(MemoryRegion(0, start, start + PAGE_SIZE));
+ for (; found != regions.end(); found++)
+ {
+ if (start >= found->StartAddress() && start < found->EndAddress())
+ {
+ return &*found;
}
}
+ return nullptr;
}
+//
+// Get the process or thread status
+//
bool
CrashInfo::GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, char** name)
{