in src/Microsoft.Diagnostics.Runtime/src/Windows/Minidump.cs [180:286]
private async Task<ThreadReadResult> ReadThreadData(Stream stream)
{
Dictionary<uint, (uint Rva, uint Size, ulong Teb)> threadContextLocations = new Dictionary<uint, (uint Rva, uint Size, ulong Teb)>();
// This will select ThreadListStread, ThreadExListStream, and ThreadInfoListStream in that order.
// We prefer to pull contexts from the *ListStreams but if those don't exist or are missing threads
// we still want threadIDs which don't have context records for IDataReader.EnumerateThreads.
var directories = from d in _directories
where d.StreamType == MinidumpStreamType.ThreadListStream ||
d.StreamType == MinidumpStreamType.ThreadExListStream ||
d.StreamType == MinidumpStreamType.ThreadInfoListStream
orderby d.StreamType ascending
select d;
var threadBuilder = ImmutableArray.CreateBuilder<uint>();
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
try
{
foreach (MinidumpDirectory directory in _directories.Where(d => d.StreamType == MinidumpStreamType.ThreadListStream || d.StreamType == MinidumpStreamType.ThreadExListStream))
{
if (directory.StreamType == MinidumpStreamType.ThreadListStream)
{
uint numThreads = await ReadAsync<uint>(stream, buffer, directory.Rva).ConfigureAwait(false);
if (numThreads == 0)
continue;
int count = ResizeBytesForArray<MinidumpThread>(numThreads, ref buffer);
int read = await ReadAsync(stream, buffer, count).ConfigureAwait(false);
for (int i = 0; i < read; i += SizeOf<MinidumpThread>())
{
MinidumpThread thread = Unsafe.As<byte, MinidumpThread>(ref buffer[i]);
if (!threadContextLocations.ContainsKey(thread.ThreadId))
threadBuilder.Add(thread.ThreadId);
threadContextLocations[thread.ThreadId] = (thread.ThreadContext.Rva, thread.ThreadContext.DataSize, thread.Teb);
}
}
else if (directory.StreamType == MinidumpStreamType.ThreadExListStream)
{
uint numThreads = await ReadAsync<uint>(stream, buffer, directory.Rva).ConfigureAwait(false);
if (numThreads == 0)
continue;
int count = ResizeBytesForArray<MinidumpThreadEx>(numThreads, ref buffer);
int read = await ReadAsync(stream, buffer, count).ConfigureAwait(false);
for (int i = 0; i < read; i += SizeOf<MinidumpThreadEx>())
{
MinidumpThreadEx thread = Unsafe.As<byte, MinidumpThreadEx>(ref buffer[i]);
if (!threadContextLocations.ContainsKey(thread.ThreadId))
threadBuilder.Add(thread.ThreadId);
threadContextLocations[thread.ThreadId] = (thread.ThreadContext.Rva, thread.ThreadContext.DataSize, thread.Teb);
}
}
else if (directory.StreamType == MinidumpStreamType.ThreadInfoListStream)
{
MinidumpThreadInfoList threadInfoList = await ReadAsync<MinidumpThreadInfoList>(stream, buffer, directory.Rva).ConfigureAwait(false);
if (threadInfoList.NumberOfEntries <= 0)
continue;
if (threadInfoList.SizeOfEntry != SizeOf<MinidumpThreadInfo>())
throw new InvalidDataException($"ThreadInfoList.SizeOfEntry=0x{threadInfoList.SizeOfEntry:x}, but sizeof(MinidumpThreadInfo)=0x{SizeOf<MinidumpThreadInfo>()}");
stream.Position = directory.Rva + threadInfoList.SizeOfHeader;
int count = ResizeBytesForArray<MinidumpThreadInfo>((ulong)threadInfoList.NumberOfEntries, ref buffer);
int read = await ReadAsync(stream, buffer, count).ConfigureAwait(false);
for (int i = 0; i < read; i += threadInfoList.SizeOfEntry)
{
MinidumpThreadInfo thread = Unsafe.As<byte, MinidumpThreadInfo>(ref buffer[i]);
if (!threadContextLocations.ContainsKey(thread.ThreadId))
{
threadContextLocations[thread.ThreadId] = (0, 0, 0);
threadBuilder.Add(thread.ThreadId);
}
}
}
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
var contextBuilder = ImmutableArray.CreateBuilder<MinidumpContextData>(threadContextLocations.Count);
var tebBuilder = ImmutableDictionary.CreateBuilder<uint, ulong>();
foreach (KeyValuePair<uint, (uint Rva, uint Size, ulong Teb)> item in threadContextLocations.OrderBy(k => k.Key))
{
uint threadId = item.Key;
contextBuilder.Add(new MinidumpContextData(threadId, item.Value.Rva, item.Value.Size));
tebBuilder.Add(threadId, item.Value.Teb);
}
return new ThreadReadResult()
{
ContextData = contextBuilder.MoveToImmutable(),
Tebs = tebBuilder.ToImmutable(),
Threads = threadBuilder.ToImmutable()
};
}