1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-10 01:50:53 +09:00

Createdump fixes and cleanup. (dotnet/coreclr#11368)

Fixed "with heap" option to actually include all the heaps. The way /proc/$pid/maps
was parsed missed most of the RW data/heap regions.

Added -u/--full full core dump options.

Removed the useless m_memStatus variable in enummem.cpp.

Commit migrated from 3fb9d8d2fe
This commit is contained in:
Mike McLaughlin 2017-05-03 17:17:22 -07:00 committed by GitHub
parent 7c62357297
commit 6b4e56b652
12 changed files with 175 additions and 126 deletions

View file

@ -62,6 +62,7 @@ Environment variables supported:
-n, --normal - create minidump (default).
-h, --withheap - create minidump with heap.
-t, --triage - create triage minidump.
-u, --full - create full core dump.
-d, --diag - enable diagnostic messages.
# Testing #
@ -73,7 +74,6 @@ The test plan is to modify the SOS tests in the (still) private debuggertests re
- Do we need a full memory dump option? It would not use the _DAC_ to get the memory regions but all the readable memory from the shared module list. Do we include the shared modules' code?
- May need more than just the pid for decorating dump names for docker containers because I think the _pid_ is always 1.
- Do we need all the memory mappings from `/proc/$pid/maps` in the PT\_LOAD sections even though the memory is not actually in the dump? They have a file offset/size of 0. Full dumps generated by the system or _gdb_ do have these un-backed regions.
- Don't know how to get the proper size/range of the non-main thread stacks. Currently uses 4 pages around the stack pointer. The main thread has a memory region in `/proc/$pid/maps`.
- There is no way to get the signal number, etc. that causes the abort from the _createdump_ utility using _ptrace_ or a /proc file. It would have to be passed from CoreCLR on the command line.
- Do we need the "dynamic" sections of each shared module in the core dump? It is part of the "link_map" entry enumerated when gathering the _DSO_ information.
- There may be more versioning and/or build id information needed to be added to the dump.

View file

@ -623,6 +623,7 @@ createdump [options] [dumpFileName]
-n - create minidump.
-h - create minidump with heap (default).
-t - create triage minidump.
-f - create full core dump (everything).
-d - enable diagnostic messages.
Creates a platform (ELF core on Linux, etc.) minidump. The pid can be placed in the dump

View file

@ -14385,6 +14385,7 @@ DECLARE_API(CreateDump)
BOOL normal = FALSE;
BOOL withHeap = FALSE;
BOOL triage = FALSE;
BOOL full = FALSE;
BOOL diag = FALSE;
size_t nArg = 0;
@ -14393,6 +14394,7 @@ DECLARE_API(CreateDump)
{"-n", &normal, COBOOL, FALSE},
{"-h", &withHeap, COBOOL, FALSE},
{"-t", &triage, COBOOL, FALSE},
{"-f", &full, COBOOL, FALSE},
{"-d", &diag, COBOOL, FALSE},
};
CMDValue arg[] =
@ -14407,7 +14409,11 @@ DECLARE_API(CreateDump)
ULONG pid = 0;
g_ExtSystem->GetCurrentProcessId(&pid);
if (withHeap)
if (full)
{
minidumpType = MiniDumpWithFullMemory;
}
else if (withHeap)
{
minidumpType = MiniDumpWithPrivateReadWriteMemory;
}

View file

@ -155,33 +155,68 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
{
return false;
}
// Get shared module debug info
if (!GetDSOInfo())
{
return false;
}
// Gather all the module memory mappings (from /dev/$pid/maps)
if (!EnumerateModuleMappings())
{
return false;
}
// Gather all the useful memory regions from the DAC
if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
// Get shared module debug info
if (!GetDSOInfo())
{
return false;
}
// Add the thread's stack and some code memory to core
for (ThreadInfo* thread : m_threads)
// If full memory dump, include everything regardless of permissions
if (minidumpType & MiniDumpWithFullMemory)
{
uint64_t start;
size_t size;
for (const MemoryRegion& region : m_moduleMappings)
{
if (ValidRegion(region))
{
InsertMemoryRegion(region);
}
}
for (const MemoryRegion& region : m_otherMappings)
{
if (ValidRegion(region))
{
InsertMemoryRegion(region);
}
}
}
else
{
// 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)
{
if (region.Permissions() == (PF_R | PF_W))
{
if (ValidRegion(region))
{
InsertMemoryRegion(region);
}
}
}
}
// Gather all the useful memory regions from the DAC
if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
{
return false;
}
// Add the thread's stack and some code memory to core
for (ThreadInfo* thread : m_threads)
{
uint64_t start;
size_t size;
// Add the thread's stack and some of the code
thread->GetThreadStack(*this, &start, &size);
InsertMemoryRegion(start, size);
// Add the thread's stack and some of the code
thread->GetThreadStack(*this, &start, &size);
InsertMemoryRegion(start, size);
thread->GetThreadCode(&start, &size);
InsertMemoryRegion(start, size);
thread->GetThreadCode(&start, &size);
InsertMemoryRegion(start, size);
}
}
// Join all adjacent memory regions
CombineMemoryRegions();
@ -240,7 +275,7 @@ CrashInfo::EnumerateModuleMappings()
// Here we read /proc/<pid>/maps file in order to parse it and figure out what it says
// about a library we are looking for. This file looks something like this:
//
// [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file
// [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file
//
// 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so
// 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so
@ -282,8 +317,8 @@ CrashInfo::EnumerateModuleMappings()
char* permissions = nullptr;
char* moduleName = nullptr;
int c = 0;
if ((c = sscanf(line, "%lx-%lx %m[-rwxsp] %lx %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName)) == 5)
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)
{
@ -334,60 +369,6 @@ CrashInfo::EnumerateModuleMappings()
return true;
}
bool
CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
{
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
HMODULE hdac = nullptr;
HRESULT hr = S_OK;
bool result = false;
// We assume that the DAC is in the same location as this createdump exe
std::string dacPath;
dacPath.append(programPath);
dacPath.append("/");
dacPath.append(MAKEDLLNAME_A("mscordaccore"));
// Load and initialize the DAC
hdac = LoadLibraryA(dacPath.c_str());
if (hdac == nullptr)
{
fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
goto exit;
}
pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
if (pfnCLRDataCreateInstance == nullptr)
{
fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
goto exit;
}
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;
}
result = true;
exit:
if (clrDataEnumRegions != nullptr)
{
clrDataEnumRegions->Release();
}
if (hdac != nullptr)
{
FreeLibrary(hdac);
}
return result;
}
bool
CrashInfo::GetDSOInfo()
{
@ -471,6 +452,60 @@ CrashInfo::GetDSOInfo()
return true;
}
bool
CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
{
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
HMODULE hdac = nullptr;
HRESULT hr = S_OK;
bool result = false;
// We assume that the DAC is in the same location as this createdump exe
std::string dacPath;
dacPath.append(programPath);
dacPath.append("/");
dacPath.append(MAKEDLLNAME_A("mscordaccore"));
// Load and initialize the DAC
hdac = LoadLibraryA(dacPath.c_str());
if (hdac == nullptr)
{
fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
goto exit;
}
pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
if (pfnCLRDataCreateInstance == nullptr)
{
fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
goto exit;
}
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;
}
result = true;
exit:
if (clrDataEnumRegions != nullptr)
{
clrDataEnumRegions->Release();
}
if (hdac != nullptr)
{
FreeLibrary(hdac);
}
return result;
}
//
// ReadMemory from target and add to memory regions list
//
@ -501,38 +536,67 @@ CrashInfo::InsertMemoryRegion(uint64_t address, size_t size)
uint64_t end = ((address + size) + (PAGE_SIZE - 1)) & PAGE_MASK;
assert(end > 0);
MemoryRegion memoryRegionFull(start, end);
MemoryRegion region(start, end);
InsertMemoryRegion(region);
}
//
// Add a memory region to the list
//
void
CrashInfo::InsertMemoryRegion(const MemoryRegion& region)
{
// First check if the full memory region can be added without conflicts
const auto& found = m_memoryRegions.find(memoryRegionFull);
const auto& found = m_memoryRegions.find(region);
if (found == m_memoryRegions.end())
{
// Add full memory region
m_memoryRegions.insert(memoryRegionFull);
m_memoryRegions.insert(region);
}
else
{
// The memory region is not wholely contained in region found
if (!found->Contains(memoryRegionFull))
if (!found->Contains(region))
{
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 = (end - start) >> PAGE_SHIFT;
uint64_t numberPages = region.Size() >> PAGE_SHIFT;
for (int p = 0; p < numberPages; p++, start += PAGE_SIZE)
{
MemoryRegion memoryRegion(start, start + PAGE_SIZE);
MemoryRegion memoryRegionPage(start, start + PAGE_SIZE);
const auto& found = m_memoryRegions.find(memoryRegion);
const auto& found = m_memoryRegions.find(memoryRegionPage);
if (found == m_memoryRegions.end())
{
m_memoryRegions.insert(memoryRegion);
m_memoryRegions.insert(memoryRegionPage);
}
}
}
}
}
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)
{
BYTE buffer[1];
uint32_t read;
if (FAILED(m_dataTarget->ReadVirtual(start, buffer, 1, &read)))
{
return false;
}
}
return true;
}
//
// Combine any adjacent memory regions into one
//

View file

@ -65,9 +65,11 @@ public:
private:
bool GetAuxvEntries();
bool EnumerateModuleMappings();
bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType);
bool GetDSOInfo();
bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType);
bool ReadMemory(void* address, void* buffer, size_t size);
void InsertMemoryRegion(uint64_t address, size_t size);
void InsertMemoryRegion(const MemoryRegion& region);
bool ValidRegion(const MemoryRegion& region);
void CombineMemoryRegions();
};

View file

@ -29,6 +29,10 @@ CreateDumpCommon(const char* programPath, const char* dumpPathTemplate, MINIDUMP
dumpType = "triage minidump";
break;
case MiniDumpWithFullMemory:
dumpType = "full dump";
break;
default:
break;
}

View file

@ -159,7 +159,6 @@ DumpDataTarget::ReadVirtual(
size_t read = pread64(m_fd, buffer, size, (off64_t)address);
if (read == -1)
{
fprintf(stderr, "ReadVirtual FAILED %016lx %08x\n", address, size);
*done = 0;
return E_FAIL;
}

View file

@ -9,6 +9,7 @@ const char* g_help = "createdump [options] pid\n"
"-n, --normal - create minidump.\n"
"-h, --withheap - create minidump with heap (default).\n"
"-t, --triage - create triage minidump.\n"
"-u, --full - create full core dump.\n"
"-d, --diag - enable diagnostic messages.\n";
bool CreateDumpCommon(const char* programPath, const char* dumpPathTemplate, MINIDUMP_TYPE minidumpType, CrashInfo* crashInfo);
@ -60,6 +61,10 @@ int __cdecl main(const int argc, const char* argv[])
{
minidumpType = MiniDumpFilterTriage;
}
else if ((strcmp(*argv, "-u") == 0) || (strcmp(*argv, "--full") == 0))
{
minidumpType = MiniDumpWithFullMemory;
}
else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0))
{
g_diagnostics = true;

View file

@ -36,35 +36,12 @@ public:
assert((end & ~PAGE_MASK) == 0);
}
const uint32_t Permissions() const
{
return m_permissions;
}
const uint64_t StartAddress() const
{
return m_startAddress;
}
const uint64_t EndAddress() const
{
return m_endAddress;
}
const uint64_t Size() const
{
return m_endAddress - m_startAddress;
}
const uint64_t Offset() const
{
return m_offset;
}
const char* FileName() const
{
return m_fileName;
}
const uint32_t Permissions() const { return m_permissions; }
const uint64_t StartAddress() const { return m_startAddress; }
const uint64_t EndAddress() const { return m_endAddress; }
const uint64_t Size() const { return m_endAddress - m_startAddress; }
const uint64_t Offset() const { return m_offset; }
const char* FileName() const { return m_fileName; }
bool operator<(const MemoryRegion& rhs) const
{
@ -88,10 +65,10 @@ public:
void Print() const
{
if (m_fileName != nullptr) {
TRACE("%016lx - %016lx (%04ld) %016lx %x %s\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_offset, m_permissions, m_fileName);
TRACE("%016lx - %016lx (%06ld) %016lx %x %s\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_offset, m_permissions, m_fileName);
}
else {
TRACE("%016lx - %016lx (%04ld) %02x\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_permissions);
TRACE("%016lx - %016lx (%06ld) %x\n", m_startAddress, m_endAddress, (Size() >> PAGE_SHIFT), m_permissions);
}
}
};

View file

@ -6305,8 +6305,6 @@ bool ClrDataAccess::ReportMem(TADDR addr, TSIZE_T size, bool fExpectSuccess /*=
status = m_enumMemCb->EnumMemoryRegion(TO_CDADDR(addr), enumSize);
if (status != S_OK)
{
m_memStatus = status;
// If dump generation was cancelled, allow us to throw upstack so we'll actually quit.
if ((fExpectSuccess) && (status != COR_E_OPERATIONCANCELED))
return false;

View file

@ -1432,7 +1432,6 @@ private:
ICLRMetadataLocator * m_legacyMetaDataLocator;
LONG m_refs;
HRESULT m_memStatus;
MDImportsCache m_mdImports;
ICLRDataEnumMemoryRegionsCallback* m_enumMemCb;
ICLRDataEnumMemoryRegionsCallback2* m_updateMemCb;

View file

@ -374,7 +374,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerHeap(IN CLRDataEnumMemoryFlags fla
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@ -394,7 +393,7 @@ HRESULT ClrDataAccess::DumpManagedObject(CLRDataEnumMemoryFlags flags, OBJECTREF
{
SUPPORTS_DAC;
HRESULT status = S_OK;
HRESULT status = S_OK;
if (objRef == NULL)
{
@ -1616,7 +1615,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerSkinny(IN CLRDataEnumMemoryFlags f
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@ -1667,7 +1665,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerMicroTriage(IN CLRDataEnumMemoryFl
// now dump the memory get dragged in by using DAC API implicitly.
m_dumpStats.m_cbImplicity = m_instances.DumpAllInstances(m_enumMemCb);
status = m_memStatus;
// Do not let any remaining implicitly enumerated memory leak out.
Flush();
@ -1811,8 +1808,6 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerCustom()
status = E_INVALIDARG;
}
status = m_memStatus;
return S_OK;
}
@ -1935,7 +1930,6 @@ ClrDataAccess::EnumMemoryRegions(IN ICLRDataEnumMemoryRegionsCallback* callback,
// We should not be trying to enumerate while we have an enumeration outstanding
_ASSERTE(m_enumMemCb==NULL);
m_memStatus = S_OK;
m_enumMemCb = callback;
// QI for ICLRDataEnumMemoryRegionsCallback2 will succeed only for Win8+.