bool CrashInfo::GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType) { // Get the process info if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name)) { return false; } // Get the info about the threads (registers, etc.) for (ThreadInfo* thread : m_threads) { if (!thread->Initialize()) { return false; } } // Get the auxv data if (!GetAuxvEntries()) { 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(pszExePath, 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); thread->GetThreadCode(&start, &size); InsertMemoryRegion(start, size); } // Join all adjacent memory regions CombineMemoryRegions(); return true; }
HRESULT STDMETHODCALLTYPE CrashInfo::EnumMemoryRegion( /* [in] */ CLRDATA_ADDRESS address, /* [in] */ ULONG32 size) { InsertMemoryRegion(address, size); return S_OK; }
bool 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 // // 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 // 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so // 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 [heap] // 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so char* line = NULL; size_t lineLen = 0; int count = 0; ssize_t read; // Making something like: /proc/123/maps char mapPath[128]; int chars = snprintf(mapPath, sizeof(mapPath), "/proc/%d/maps", m_pid); assert(chars > 0 && chars <= sizeof(mapPath)); FILE* mapsFile = fopen(mapPath, "r"); if (mapsFile == NULL) { fprintf(stderr, "fopen(%s) FAILED %s\n", mapPath, strerror(errno)); return false; } // linuxGateAddress is the beginning of the kernel's mapping of // linux-gate.so in the process. It doesn't actually show up in the // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR // aux vector entry, which gives the information necessary to special // case its entry when creating the list of mappings. // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more // information. const void* linuxGateAddress = (const void*)m_auxvValues[AT_SYSINFO_EHDR]; // Reading maps file line by line while ((read = getline(&line, &lineLen, mapsFile)) != -1) { uint64_t start, end, offset; char* permissions = nullptr; char* moduleName = nullptr; 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); } 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 (moduleName != nullptr && *moduleName == '/') { m_moduleMappings.insert(memoryRegion); } else { m_otherMappings.insert(memoryRegion); } } free(permissions); } } if (g_diagnostics) { TRACE("Module mappings:\n"); for (const MemoryRegion& region : m_moduleMappings) { region.Print(); } TRACE("Other mappings:\n"); for (const MemoryRegion& region : m_otherMappings) { region.Print(); } } free(line); // We didn't allocate line, but as per contract of getline we should free it fclose(mapsFile); return true; }
bool CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType) { // Get the process info if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name)) { return false; } // Get the info about the threads (registers, etc.) for (ThreadInfo* thread : m_threads) { if (!thread->Initialize(m_sos ? m_dataTarget : nullptr)) { return false; } } // Get the auxv data if (!GetAuxvEntries()) { return false; } // Gather all the module memory mappings (from /dev/$pid/maps) if (!EnumerateModuleMappings()) { return false; } // Get shared module debug info if (!GetDSOInfo()) { return false; } // 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_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); thread->GetThreadCode(&start, &size); InsertMemoryRegion(start, size); } } // Join all adjacent memory regions CombineMemoryRegions(); return true; }