private void LoadFile(string name) { var path = Path.Combine(TestsHelper.GetTestFilesLocation(), name); var text = File.ReadAllText(path); var tree = CSharpSyntaxTree.ParseText(text); _compilation = CSharpCompilation.Create("TestCompilation", new[] { tree }); _sut = new ReferencesWalker(_compilation, new Func <string, bool>[] {}); }
private static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("@ Dump2SQLite - Serialize GCHeap to SQLite DB @"); Console.WriteLine(@"Usage: Dump2SQLite \path\to\filename.dmp"); Console.WriteLine(@"Output: SQLite DB (\path\to\filename.sqlite)"); return; } string dumpLocation = args[0]; Stopwatch watch = new Stopwatch(); watch.Start(); LogInfoWithTimeStamp("Loading Crash Dump from: " + dumpLocation + " ..."); DataTarget target = DataTarget.LoadCrashDump(dumpLocation); ClrInfo version = target.ClrVersions[0]; // TODO: Probably add support for Multiple CLRs or at least warn we're picking the first string dacLocation = version.TryGetDacLocation(); ClrRuntime runtime = target.CreateRuntime(dacLocation); var heap = runtime.GetHeap(); if (!heap.CanWalkHeap) { LogErrorWithTimeStamp("Heap is not walkable. Please collect a new dump."); return; } LogInfoWithTimeStamp("Crash Dump loaded."); var perTypeCounts = new Dictionary<int, int>(100000); var fileName = Path.GetFullPath(args[0]).Replace(Path.GetExtension(args[0]), ".sqlite"); LogInfoWithTimeStamp("Creating SQLite Database filename: " + fileName + " ..."); sqlite3* db; int error; if ((error = NativeMethods.sqlite3_open(fileName, out db)) != 0) { LogErrorWithTimeStamp("sqlite3_open failed with error code: " + error); } LogInfoWithTimeStamp("Successfully created SQLite Database filename: " + fileName); LogInfoWithTimeStamp("Creating SQLite Tables ..."); if (!CreateTables(db)) { return; } LogInfoWithTimeStamp("Successfully created SQLite Tables."); error = NativeMethods.sqlite3_exec(db, "BEGIN TRANSACTION;", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (error != 0) { LogErrorWithTimeStamp("sqlite3_exec -> BEGIN TRANSACTION; failed to execute with SQLite error code: " + error); } sqlite3_stmt* insertObjectsStmt, insertTypesStmt, insertRootsStmt, insertBlockingObjectsStmt, insertExceptionsStmt, insertThreadsStmt; if (!PrepareInsertStatement(db, out insertTypesStmt, @"INSERT INTO Types(TypeIndex, Count, Size, Name) VALUES (@1, @2, @3, @4);")) { return; } if (!PrepareInsertStatement(db, out insertObjectsStmt, @"INSERT INTO Objects(ObjectId, TypeIndex, Size, ObjRefs) VALUES (@1, @2, @3, @4);")) { return; } if (!PrepareInsertStatement(db, out insertRootsStmt, @"INSERT INTO Roots(TypeIndex, ObjectId, Address, AppDomainId, ManagedThreadId, IsInterior, IsPinned, IsPossibleFalsePositive, GCRootKind, Name) VALUES (@1, @2, @3, @4, @5, @6, @7, @8, @9, @10);")) { return; } if (!PrepareInsertStatement(db, out insertBlockingObjectsStmt, @"INSERT INTO BlockingObjects(ObjectId, Taken, RecursionCount, Owner, HasSingleOwner, ThreadOwnerIds, ThreadWaiterIds, BlockingReason) VALUES (@1, @2, @3, @4, @5, @6, @7, @8);")) { return; } /* if (!PrepareInsertStatement(db, out insertExceptionsStmt, @"INSERT INTO Exceptions(ExceptionId, TypeId, Type, Message, Address, InnerExceptionId, HResult, StackId, StackTrace) VALUES (@1, @2, @3, @4, @5, @6, @7, @8, @9);")) { return; }*/ /* if (!PrepareInsertStatement(db, out insertThreadsStmt, @"(GcMode, IsFinalizer, Address, IsAlive, OSThreadId, ManagedThreadId, AppDomain, LockCount, Teb, StackBase, StackLimit, StackId, ExceptionId, IsGC, IsDebuggerHelper, IsThreadpoolTimer, IsThreadpoolCompletionPort, IsThreadpoolWorker, IsThreadpoolWait, IsThreadpoolGate, IsSuspendingEE, IsShutdownHelper, IsAbortRequested, IsAborted, ISGCSuspendPending, IsDebugSuspended, IsBackground, IsUnstarted, IsCoInitialized, IsSTA, IsMTA, BlockingObjects, Roots) VALUES (@1, @2, @3, @4, @5, @6, @7, @8, @9, @10);")) { return; }*/ LogInfoWithTimeStamp("Starting to populate Objects Table ..."); var walker = new ReferencesWalker(); foreach (ulong obj in heap.EnumerateObjects()) { ClrType type = heap.GetObjectType(obj); if (type != null) { type.EnumerateRefsOfObjectCarefully(obj, walker.Walk); var references = walker.ToString(); walker.Clear(); int typeIndex = type.Index; if (perTypeCounts.ContainsKey(typeIndex)) { ++perTypeCounts[typeIndex]; } else { perTypeCounts.Add(typeIndex, 1); } NativeMethods.sqlite3_bind_int64(insertObjectsStmt, 1, (long)obj); NativeMethods.sqlite3_bind_int(insertObjectsStmt, 2, typeIndex); NativeMethods.sqlite3_bind_int(insertObjectsStmt, 3, type.BaseSize); NativeMethods.sqlite3_bind_text(insertObjectsStmt, 4, references, references.Length, NativeMethods.Transient); NativeMethods.sqlite3_step(insertObjectsStmt); NativeMethods.sqlite3_reset(insertObjectsStmt); } } LogInfoWithTimeStamp("Successfully populated Objects Table."); LogInfoWithTimeStamp("Starting to populate Types Table ..."); foreach (var type in heap.EnumerateTypes()) { string typeName = type.Name; int typeIndex = type.Index; int count; if (!perTypeCounts.TryGetValue(typeIndex, out count)) { count = 0; } NativeMethods.sqlite3_bind_int(insertTypesStmt, 1, typeIndex); NativeMethods.sqlite3_bind_int64(insertTypesStmt, 2, count); NativeMethods.sqlite3_bind_int(insertTypesStmt, 3, type.BaseSize); NativeMethods.sqlite3_bind_text(insertTypesStmt, 4, typeName, typeName.Length, NativeMethods.Transient); NativeMethods.sqlite3_step(insertTypesStmt); NativeMethods.sqlite3_reset(insertTypesStmt); } LogInfoWithTimeStamp("Successfully populated Types Table."); LogInfoWithTimeStamp("Starting to populate Roots Table ..."); foreach (var root in heap.EnumerateRoots()) { NativeMethods.sqlite3_bind_int(insertRootsStmt, 1, root.Type?.Index ?? -1); NativeMethods.sqlite3_bind_int64(insertRootsStmt, 2, (long)root.Object); NativeMethods.sqlite3_bind_int64(insertRootsStmt, 3, (long)root.Address); NativeMethods.sqlite3_bind_int(insertRootsStmt, 4, root.AppDomain?.Id ?? -1); NativeMethods.sqlite3_bind_int(insertRootsStmt, 5, root.Thread?.ManagedThreadId ?? -1); NativeMethods.sqlite3_bind_int(insertRootsStmt, 6, root.IsInterior ? 1 : 0); NativeMethods.sqlite3_bind_int(insertRootsStmt, 7, root.IsPinned ? 1 : 0); NativeMethods.sqlite3_bind_int(insertRootsStmt, 8, root.IsPossibleFalsePositive ? 1 : 0); string kindString = root.Kind.KindString(); string rootName = root.Name; NativeMethods.sqlite3_bind_text(insertRootsStmt, 9, kindString, kindString.Length, NativeMethods.Transient); NativeMethods.sqlite3_bind_text(insertRootsStmt, 10, rootName, rootName.Length, NativeMethods.Transient); NativeMethods.sqlite3_step(insertRootsStmt); NativeMethods.sqlite3_reset(insertRootsStmt); } LogInfoWithTimeStamp("Successfully populated Roots Table."); LogInfoWithTimeStamp("Starting to populate Blocking Objects Table ..."); foreach (var blockingObject in heap.EnumerateBlockingObjects()) { NativeMethods.sqlite3_bind_int64(insertBlockingObjectsStmt, 1, (long)blockingObject.Object); NativeMethods.sqlite3_bind_int64(insertBlockingObjectsStmt, 2, blockingObject.Taken ? 1 : 0); NativeMethods.sqlite3_bind_int64(insertBlockingObjectsStmt, 3, blockingObject.RecursionCount); NativeMethods.sqlite3_bind_int64(insertBlockingObjectsStmt, 4, blockingObject.Owner?.ManagedThreadId ?? -1); NativeMethods.sqlite3_bind_int(insertBlockingObjectsStmt, 5, blockingObject.HasSingleOwner ? 1 : 0); var owners = blockingObject.Owners.Expand(); NativeMethods.sqlite3_bind_text(insertBlockingObjectsStmt, 6, owners, owners.Length, NativeMethods.Transient); var waiters = blockingObject.Waiters.Expand(); NativeMethods.sqlite3_bind_text(insertBlockingObjectsStmt, 7, waiters, waiters.Length, NativeMethods.Transient); var blockingReason = blockingObject.Reason.KindString(); NativeMethods.sqlite3_bind_text(insertBlockingObjectsStmt, 8, blockingReason, blockingReason.Length, NativeMethods.Transient); NativeMethods.sqlite3_step(insertBlockingObjectsStmt); NativeMethods.sqlite3_reset(insertBlockingObjectsStmt); } LogInfoWithTimeStamp("Successfully populated Blocking Objects Table."); NativeMethods.sqlite3_finalize(insertTypesStmt); NativeMethods.sqlite3_finalize(insertObjectsStmt); NativeMethods.sqlite3_finalize(insertRootsStmt); NativeMethods.sqlite3_finalize(insertBlockingObjectsStmt); error = NativeMethods.sqlite3_exec(db, "END TRANSACTION;", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); if (error != 0) { LogErrorWithTimeStamp("sqlite3_exec -> END TRANSACTION; failed to execute with SQLite error code: " + error); } NativeMethods.sqlite3_close(db); watch.Stop(); LogInfoWithTimeStamp("Processing time: " + watch.ElapsedMilliseconds + " milliseconds"); }