private void StepDecoder() { ulong pos = m_ReadPos; ulong maxpos = m_WritePos; if (m_SeenStringRollback > 0) { m_SeenStrings.RemoveRange(m_SeenStrings.Count - m_SeenStringRollback, m_SeenStringRollback); m_SeenStringRollback = 0; } if (m_SeenStackRollback > 0) { m_SeenStacks.RemoveRange(m_SeenStacks.Count - m_SeenStackRollback, m_SeenStackRollback); m_SeenStackRollback = 0; } while (pos < maxpos) { if (!ReadUnsigned(out m_CurrCode, ref pos)) { return; } if (!Enum.IsDefined(typeof(EventCode), (EventCode)m_CurrCode)) { throw new IOException(String.Format("Bad event code {0} at pos {1}\n", m_CurrCode, pos - 1)); } if (!ReadUnsigned(out m_CurrScope, ref pos)) { return; } if (0 != m_CurrScope) { if (!ReadStringIndex(out m_CurrScopeDataIndex, ref pos)) { return; } } else { m_CurrScopeDataIndex = -1; } ulong timestamp; if (!ReadUnsigned(out timestamp, ref pos)) { return; } // Only commit after the whole thing read successfully, as the UI thread could sample the // timestamp at any time to put in a trace marker. m_CurrTimestamp = timestamp; if (!ReadBackTraceIndex(out m_CurrBackTraceIndex, ref pos)) { return; } switch ((EventCode)m_CurrCode) { case EventCode.BeginStream: string pname; ulong ptrsize; ulong magic; ulong timer_freq; ulong well_known_address; if (!ReadUnsigned(out magic, ref pos)) { return; } if (magic != StreamMagic) { throw new IOException(String.Format("Bad stream magic {0:x8}, expected {1:x8}", magic, StreamMagic)); } if (!ReadString(out pname, ref pos)) { return; } if (!ReadUnsigned(out ptrsize, ref pos)) { return; } if (!ReadUnsigned(out timer_freq, ref pos)) { return; } if (!ReadUnsigned(out well_known_address, ref pos)) { return; } MetaData.PlatformName = pname; MetaData.PointerSizeBytes = (int)ptrsize; MetaData.TimerFrequency = timer_freq; MetaData.MemTraceInitCommonAddress = well_known_address; // Nothing written. break; case EventCode.EndStream: // Nothing written. break; case EventCode.ModuleDump: { List <ModuleInfo> tmp = new List <ModuleInfo>(); for (; ;) { ulong ctrl; if (!ReadUnsigned(out ctrl, ref pos)) { return; } if (0 == ctrl) { break; } string modname; ulong modbase; ulong modsize; if (!ReadString(out modname, ref pos)) { return; } if (!ReadUnsigned(out modbase, ref pos)) { return; } if (!ReadUnsigned(out modsize, ref pos)) { return; } if (modname.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) { MetaData.ExecutableName = Path.GetFileNameWithoutExtension(modname); } tmp.Add(new ModuleInfo { BaseAddress = modbase, SizeBytes = modsize, Name = modname }); } // We got all of it. Commit. MetaData.Modules = tmp; } // Nothing written. break; case EventCode.Mark: { string name; if (!ReadString(out name, ref pos)) { return; } MetaData.AddMark(new TraceMark { Name = name, TimeStamp = m_CurrTimestamp }); } // Nothing written. break; case EventCode.AddressAllocate: { ulong addr, size; int name_index; if (!ReadUnsigned(out addr, ref pos)) { return; } if (!ReadUnsigned(out size, ref pos)) { return; } if (!ReadStringIndex(out name_index, ref pos)) { return; } if (!m_AddressCreateEvents.ContainsKey(addr)) { m_AddressCreateEvents[addr] = m_Out.BaseStream.Position; BeginOutEvent(); m_Out.Write(addr); m_Out.Write(size); m_Out.Write(name_index); } else { MetaData.AddWarning("Attempt to allocate already allocated virtual address {0:x16}", addr); } } break; case EventCode.AddressFree: { ulong addr; if (!ReadUnsigned(out addr, ref pos)) { return; } // Handle sloppy runtime code reporting frees multiple times :( if (m_AddressCreateEvents.ContainsKey(addr)) { BeginOutEvent(); m_Out.Write(addr); m_Out.Write(m_AddressCreateEvents[addr]); m_AddressCreateEvents.Remove(addr); } else { MetaData.AddWarning("Attempt to free non-allocated virtual address {0:x16}", addr); } } break; case EventCode.VirtualCommit: case EventCode.VirtualDecommit: { ulong addr, size; if (!ReadUnsigned(out addr, ref pos)) { return; } if (!ReadUnsigned(out size, ref pos)) { return; } BeginOutEvent(); m_Out.Write(addr); m_Out.Write(size); } break; case EventCode.HeapCreate: { ulong id; int str_index; if (!ReadUnsigned(out id, ref pos)) { return; } if (!ReadStringIndex(out str_index, ref pos)) { return; } m_HeapCreateEvents[id] = m_Out.BaseStream.Position; BeginOutEvent(); m_Out.Write(id); m_Out.Write(str_index); } break; case EventCode.HeapDestroy: { ulong id; if (!ReadUnsigned(out id, ref pos)) { return; } if (m_HeapCreateEvents.ContainsKey(id)) { BeginOutEvent(); m_Out.Write(id); m_Out.Write(m_HeapCreateEvents[id]); m_HeapCreateEvents.Remove(id); } else { MetaData.AddWarning("Attempt to destroy non-existing heap id={0:x16}", id); } } break; case EventCode.HeapAddCore: case EventCode.HeapRemoveCore: { ulong id, addr, size; if (!ReadUnsigned(out id, ref pos)) { return; } if (!ReadUnsigned(out addr, ref pos)) { return; } if (!ReadUnsigned(out size, ref pos)) { return; } BeginOutEvent(); m_Out.Write(id); m_Out.Write(addr); m_Out.Write(size); } break; case EventCode.HeapAllocate: { ulong addr, size, heap_id; if (!ReadUnsigned(out heap_id, ref pos)) { return; } if (!ReadUnsigned(out addr, ref pos)) { return; } if (!ReadUnsigned(out size, ref pos)) { return; } var key = new AllocationKey { HeapId = heap_id, Address = addr }; if (!m_AllocCreateEvents.ContainsKey(key)) { m_AllocCreateEvents[key] = m_Out.BaseStream.Position; BeginOutEvent(); m_Out.Write((uint)heap_id); m_Out.Write(addr); m_Out.Write(size); } else { MetaData.AddWarning("Attempt to allocate already-allocated address {0:x16} size {0:x16}", addr, size); } } break; case EventCode.HeapReallocate: { ulong heap_id, old_addr, new_addr, new_size; if (!ReadUnsigned(out heap_id, ref pos)) { return; } if (!ReadUnsigned(out old_addr, ref pos)) { return; } if (!ReadUnsigned(out new_addr, ref pos)) { return; } if (!ReadUnsigned(out new_size, ref pos)) { return; } long npos = m_Out.BaseStream.Position; var key = new AllocationKey { HeapId = heap_id, Address = old_addr }; if (m_AllocCreateEvents.ContainsKey(key)) { BeginOutEvent(); m_Out.Write((uint)heap_id); m_Out.Write(old_addr); m_Out.Write(new_addr); m_Out.Write(new_size); m_Out.Write(m_AllocCreateEvents[key]); m_AllocCreateEvents.Remove(key); var new_key = new AllocationKey { HeapId = heap_id, Address = new_addr }; m_AllocCreateEvents[new_key] = npos; } else { MetaData.AddWarning("Attempt to reallocate non-allocated address {0:x16}", old_addr); } break; } case EventCode.HeapFree: { ulong addr, heap_id; if (!ReadUnsigned(out heap_id, ref pos)) { return; } if (!ReadUnsigned(out addr, ref pos)) { return; } if (addr != 0) { var key = new AllocationKey { HeapId = heap_id, Address = addr }; if (m_AllocCreateEvents.ContainsKey(key)) { BeginOutEvent(); m_Out.Write((uint)heap_id); m_Out.Write(addr); m_Out.Write(m_AllocCreateEvents[key]); m_AllocCreateEvents.Remove(key); } else { MetaData.AddWarning("Attempt to free non-allocated address {0:x16}", addr); } } } break; default: throw new IOException(String.Format("Unexpected event code {0}", m_CurrCode)); } // Commit data decoded so far m_ReadPos = pos; m_SeenStringRollback = 0; m_SeenStackRollback = 0; MetaData.MaxTimeStamp = m_CurrTimestamp; ++MetaData.EventCount; } }