@@ -13,6 +13,8 @@ CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t s
1313 m_pid(pid),
1414 m_ppid(-1 ),
1515 m_hdac(nullptr ),
16+ m_pClrDataEnumRegions(nullptr ),
17+ m_pClrDataProcess(nullptr ),
1618 m_gatherFrames(gatherFrames),
1719 m_crashThread(crashThread),
1820 m_signal(signal),
@@ -44,6 +46,15 @@ CrashInfo::~CrashInfo()
4446 }
4547 m_moduleInfos.clear ();
4648
49+ // Clean up DAC interfaces
50+ if (m_pClrDataEnumRegions != nullptr )
51+ {
52+ m_pClrDataEnumRegions->Release ();
53+ }
54+ if (m_pClrDataProcess != nullptr )
55+ {
56+ m_pClrDataProcess->Release ();
57+ }
4758 // Unload DAC module
4859 if (m_hdac != nullptr )
4960 {
@@ -190,8 +201,16 @@ CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
190201 thread->GetThreadStack ();
191202 }
192203 }
193- // Gather all the useful memory regions from the DAC
194- if (!EnumerateMemoryRegionsWithDAC (minidumpType))
204+ // Load and initialize DAC interfaces
205+ if (!InitializeDAC ())
206+ {
207+ return false ;
208+ }
209+ if (!EnumerateManagedModules ())
210+ {
211+ return false ;
212+ }
213+ if (!UnwindAllThreads ())
195214 {
196215 return false ;
197216 }
@@ -204,19 +223,15 @@ CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
204223// Enumerate all the memory regions using the DAC memory region support given a minidump type
205224//
206225bool
207- CrashInfo::EnumerateMemoryRegionsWithDAC (MINIDUMP_TYPE minidumpType )
226+ CrashInfo::InitializeDAC ( )
208227{
209228 ReleaseHolder<DumpDataTarget> dataTarget = new DumpDataTarget (*this );
210229 PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr ;
211- ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr ;
212- IXCLRDataProcess* pClrDataProcess = nullptr ;
213- HRESULT hr = S_OK;
214230 bool result = false ;
231+ HRESULT hr = S_OK;
215232
216233 if (!m_coreclrPath.empty ())
217234 {
218- TRACE (" EnumerateMemoryRegionsWithDAC: Memory enumeration STARTED\n " );
219-
220235 // We assume that the DAC is in the same location as the libcoreclr.so module
221236 std::string dacPath;
222237 dacPath.append (m_coreclrPath);
@@ -235,140 +250,156 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
235250 fprintf (stderr, " GetProcAddress(CLRDataCreateInstance) FAILED %d\n " , GetLastError ());
236251 goto exit;
237252 }
238- if ((minidumpType & MiniDumpWithFullMemory) == 0 )
239- {
240- hr = pfnCLRDataCreateInstance (__uuidof (ICLRDataEnumMemoryRegions), dataTarget, (void **)&pClrDataEnumRegions);
241- if (FAILED (hr))
242- {
243- fprintf (stderr, " CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n " , hr);
244- goto exit;
245- }
246- // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
247- hr = pClrDataEnumRegions->EnumMemoryRegions (this , minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
248- if (FAILED (hr))
249- {
250- fprintf (stderr, " EnumMemoryRegions FAILED %08x\n " , hr);
251- goto exit;
252- }
253- }
254- hr = pfnCLRDataCreateInstance (__uuidof (IXCLRDataProcess), dataTarget, (void **)&pClrDataProcess);
253+ hr = pfnCLRDataCreateInstance (__uuidof (ICLRDataEnumMemoryRegions), dataTarget, (void **)&m_pClrDataEnumRegions);
255254 if (FAILED (hr))
256255 {
257- fprintf (stderr, " CLRDataCreateInstance(IXCLRDataProcess ) FAILED %08x\n " , hr);
256+ fprintf (stderr, " CLRDataCreateInstance(ICLRDataEnumMemoryRegions ) FAILED %08x\n " , hr);
258257 goto exit;
259258 }
260- TRACE ( " EnumerateMemoryRegionsWithDAC: Memory enumeration FINISHED \n " );
261- if (! EnumerateManagedModules (pClrDataProcess ))
259+ hr = pfnCLRDataCreateInstance ( __uuidof (IXCLRDataProcess), dataTarget, ( void **)&m_pClrDataProcess );
260+ if (FAILED (hr ))
262261 {
262+ fprintf (stderr, " CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n " , hr);
263263 goto exit;
264264 }
265265 }
266- else {
267- TRACE (" EnumerateMemoryRegionsWithDAC: coreclr not found; not using DAC\n " );
268- }
269- if (!UnwindAllThreads (pClrDataProcess))
266+ else
270267 {
271- goto exit ;
268+ TRACE ( " InitializeDAC: coreclr not found; not using DAC \n " ) ;
272269 }
273270 result = true ;
274271exit:
275- if (pClrDataEnumRegions != nullptr )
276- {
277- pClrDataEnumRegions->Release ();
278- }
279- if (pClrDataProcess != nullptr )
272+ return result;
273+ }
274+
275+ //
276+ // Enumerate all the memory regions using the DAC memory region support given a minidump type
277+ //
278+ bool
279+ CrashInfo::EnumerateMemoryRegionsWithDAC (MINIDUMP_TYPE minidumpType)
280+ {
281+ if (m_pClrDataEnumRegions != nullptr && (minidumpType & MiniDumpWithFullMemory) == 0 )
280282 {
281- pClrDataProcess->Release ();
283+ TRACE (" EnumerateMemoryRegionsWithDAC: Memory enumeration STARTED\n " );
284+
285+ // Since on both Linux and MacOS all the RW regions will be added for heap
286+ // dumps by createdump, the only thing differentiating a MiniDumpNormal and
287+ // a MiniDumpWithPrivateReadWriteMemory is that the later uses the EnumMemory
288+ // APIs. This is kind of expensive on larger applications (4 minutes, or even
289+ // more), and this should already be in RW pages. Change the dump type to the
290+ // faster normal one. This one already ensures necessary DAC globals, etc.
291+ // without the costly assembly, module, class, type runtime data structures
292+ // enumeration.
293+ if (minidumpType & MiniDumpWithPrivateReadWriteMemory)
294+ {
295+ char * fastHeapDumps = getenv (" COMPlus_DbgEnableFastHeapDumps" );
296+ if (fastHeapDumps != nullptr && strcmp (fastHeapDumps, " 1" ) == 0 )
297+ {
298+ minidumpType = MiniDumpNormal;
299+ }
300+ }
301+ // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
302+ HRESULT hr = m_pClrDataEnumRegions->EnumMemoryRegions (this , minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
303+ if (FAILED (hr))
304+ {
305+ fprintf (stderr, " EnumMemoryRegions FAILED %08x\n " , hr);
306+ return false ;
307+ }
308+ TRACE (" EnumerateMemoryRegionsWithDAC: Memory enumeration FINISHED\n " );
282309 }
283- return result ;
310+ return true ;
284311}
285312
286313//
287314// Enumerate all the managed modules and replace the module mapping with the module name found.
288315//
289316bool
290- CrashInfo::EnumerateManagedModules (IXCLRDataProcess* pClrDataProcess )
317+ CrashInfo::EnumerateManagedModules ()
291318{
292319 CLRDATA_ENUM enumModules = 0 ;
293- bool result = true ;
294320 HRESULT hr = S_OK;
295321
296- if (FAILED (hr = pClrDataProcess->StartEnumModules (&enumModules))) {
297- fprintf (stderr, " StartEnumModules FAILED %08x\n " , hr);
298- return false ;
299- }
300-
301- while (true )
322+ if (m_pClrDataProcess != nullptr )
302323 {
303- ReleaseHolder<IXCLRDataModule> pClrDataModule;
304- if ((hr = pClrDataProcess->EnumModule (&enumModules, &pClrDataModule)) != S_OK) {
305- break ;
306- }
324+ TRACE (" EnumerateManagedModules: Module enumeration STARTED\n " );
307325
308- // Skip any dynamic modules. The Request call below on some DACs crashes on dynamic modules.
309- ULONG32 flags;
310- if ((hr = pClrDataModule->GetFlags (&flags)) != S_OK) {
311- TRACE (" MODULE: GetFlags FAILED %08x\n " , hr);
312- continue ;
313- }
314- if (flags & CLRDATA_MODULE_IS_DYNAMIC) {
315- TRACE (" MODULE: Skipping dynamic module\n " );
316- continue ;
326+ if (FAILED (hr = m_pClrDataProcess->StartEnumModules (&enumModules))) {
327+ fprintf (stderr, " StartEnumModules FAILED %08x\n " , hr);
328+ return false ;
317329 }
318330
319- DacpGetModuleData moduleData;
320- if (SUCCEEDED (hr = moduleData.Request (pClrDataModule.GetPtr ())))
331+ while (true )
321332 {
322- TRACE (" MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, (uint64_t )moduleData.LoadedPEAddress , moduleData.IsDynamic ,
323- moduleData.IsInMemory , moduleData.IsFileLayout , (uint64_t )moduleData.PEAssembly , (uint64_t )moduleData.InMemoryPdbAddress );
333+ ReleaseHolder<IXCLRDataModule> pClrDataModule;
334+ if ((hr = m_pClrDataProcess->EnumModule (&enumModules, &pClrDataModule)) != S_OK) {
335+ break ;
336+ }
324337
325- if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0 )
338+ // Skip any dynamic modules. The Request call below on some DACs crashes on dynamic modules.
339+ ULONG32 flags;
340+ if ((hr = pClrDataModule->GetFlags (&flags)) != S_OK) {
341+ TRACE (" MODULE: GetFlags FAILED %08x\n " , hr);
342+ continue ;
343+ }
344+ if (flags & CLRDATA_MODULE_IS_DYNAMIC) {
345+ TRACE (" MODULE: Skipping dynamic module\n " );
346+ continue ;
347+ }
348+
349+ DacpGetModuleData moduleData;
350+ if (SUCCEEDED (hr = moduleData.Request (pClrDataModule.GetPtr ())))
326351 {
327- ArrayHolder<WCHAR> wszUnicodeName = new WCHAR[MAX_LONGPATH + 1 ];
328- if (SUCCEEDED (hr = pClrDataModule->GetFileName (MAX_LONGPATH, nullptr , wszUnicodeName)))
352+ TRACE (" MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, (uint64_t )moduleData.LoadedPEAddress , moduleData.IsDynamic ,
353+ moduleData.IsInMemory , moduleData.IsFileLayout , (uint64_t )moduleData.PEAssembly , (uint64_t )moduleData.InMemoryPdbAddress );
354+
355+ if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0 )
329356 {
330- std::string moduleName = FormatString (" %S" , wszUnicodeName.GetPtr ());
357+ ArrayHolder<WCHAR> wszUnicodeName = new WCHAR[MAX_LONGPATH + 1 ];
358+ if (SUCCEEDED (hr = pClrDataModule->GetFileName (MAX_LONGPATH, nullptr , wszUnicodeName)))
359+ {
360+ std::string moduleName = FormatString (" %S" , wszUnicodeName.GetPtr ());
331361
332- // Change the module mapping name
333- ReplaceModuleMapping (moduleData.LoadedPEAddress , moduleData.LoadedPESize , moduleName);
362+ // Change the module mapping name
363+ ReplaceModuleMapping (moduleData.LoadedPEAddress , moduleData.LoadedPESize , moduleName);
334364
335- // Add managed module info
336- AddModuleInfo (true , moduleData.LoadedPEAddress , pClrDataModule, moduleName);
365+ // Add managed module info
366+ AddModuleInfo (true , moduleData.LoadedPEAddress , pClrDataModule, moduleName);
367+ }
368+ else {
369+ TRACE (" \n Module.GetFileName FAILED %08x\n " , hr);
370+ }
337371 }
338372 else {
339- TRACE (" \n Module.GetFileName FAILED %08x \n " , hr );
373+ TRACE (" \n " );
340374 }
341375 }
342376 else {
343- TRACE (" \n " );
377+ TRACE (" moduleData.Request FAILED %08x \n " , hr );
344378 }
345379 }
346- else {
347- TRACE (" moduleData.Request FAILED %08x\n " , hr);
348- }
349- }
350380
351- if (enumModules != 0 ) {
352- pClrDataProcess->EndEnumModules (enumModules);
381+ if (enumModules != 0 ) {
382+ m_pClrDataProcess->EndEnumModules (enumModules);
383+ }
384+ TRACE (" EnumerateManagedModules: Module enumeration FINISHED\n " );
353385 }
354-
355- return result;
386+ return true ;
356387}
357388
358389//
359390// Unwind all the native threads to ensure that the dwarf unwind info is added to the core dump.
360391//
361392bool
362- CrashInfo::UnwindAllThreads (IXCLRDataProcess* pClrDataProcess )
393+ CrashInfo::UnwindAllThreads ()
363394{
364395 ReleaseHolder<ISOSDacInterface> pSos = nullptr ;
365- if (pClrDataProcess != nullptr ) {
366- pClrDataProcess ->QueryInterface (__uuidof (ISOSDacInterface), (void **)&pSos);
396+ if (m_pClrDataProcess != nullptr ) {
397+ m_pClrDataProcess ->QueryInterface (__uuidof (ISOSDacInterface), (void **)&pSos);
367398 }
368399 // For each native and managed thread
369400 for (ThreadInfo* thread : m_threads)
370401 {
371- if (!thread->UnwindThread (pClrDataProcess , pSos)) {
402+ if (!thread->UnwindThread (m_pClrDataProcess , pSos)) {
372403 return false ;
373404 }
374405 }
@@ -827,5 +858,5 @@ FormatGuid(const GUID* guid)
827858{
828859 uint8_t * bytes = (uint8_t *)guid;
829860 return FormatString (" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ,
830- bytes[3 ], bytes[2 ], bytes[1 ], bytes[0 ], bytes[5 ], bytes[4 ], bytes[7 ], bytes[6 ], bytes[8 ], bytes[9 ], bytes[10 ], bytes[11 ], bytes[12 ], bytes[13 ], bytes[14 ], bytes[15 ]);
861+ bytes[3 ], bytes[2 ], bytes[1 ], bytes[0 ], bytes[5 ], bytes[4 ], bytes[7 ], bytes[6 ], bytes[8 ], bytes[9 ], bytes[10 ], bytes[11 ], bytes[12 ], bytes[13 ], bytes[14 ], bytes[15 ]);
831862}
0 commit comments