in src/Microsoft.Diagnostics.Runtime/src/MacOS/MachOCoreDump.cs [39:158]
public MachOCoreDump(Stream stream, bool leaveOpen, string displayName)
{
fixed (MachHeader64* header = &_header)
if (stream.Read(new Span<byte>(header, sizeof(MachHeader64))) != sizeof(MachHeader64))
throw new IOException($"Failed to read header from {displayName}.");
if (_header.Magic != MachHeader64.Magic64)
throw new InvalidDataException($"'{displayName}' does not have a valid Mach-O header.");
_stream = stream;
_leaveOpen = leaveOpen;
Dictionary<ulong, uint> threadIds = new Dictionary<ulong, uint>();
List<thread_state_t> contexts = new List<thread_state_t>();
List<MachOSegment> segments = new List<MachOSegment>((int)_header.NumberCommands);
for (int i = 0; i < _header.NumberCommands; i++)
{
long position = stream.Position;
LoadCommandHeader loadCommand = new LoadCommandHeader();
stream.Read(new Span<byte>(&loadCommand, sizeof(LoadCommandHeader)));
long next = position + loadCommand.Size;
switch (loadCommand.Kind)
{
case LoadCommandType.Segment64:
Segment64LoadCommand seg = default;
stream.Read(new Span<byte>(&seg, sizeof(Segment64LoadCommand)));
if (seg.VMAddr == SpecialThreadInfoHeader.SpecialThreadInfoAddress)
{
stream.Position = (long)seg.FileOffset;
SpecialThreadInfoHeader threadInfo = Read<SpecialThreadInfoHeader>(stream);
if (threadInfo.Signature != SpecialThreadInfoHeader.SpecialThreadInfoSignature)
{
segments.Add(new MachOSegment(seg));
}
else
{
for (int j = 0; j < threadInfo.NumberThreadEntries; j++)
{
SpecialThreadInfoEntry threadEntry = Read<SpecialThreadInfoEntry>(stream);
threadIds[threadEntry.StackPointer] = threadEntry.ThreadId;
}
}
}
else
{
segments.Add(new MachOSegment(seg));
}
break;
case LoadCommandType.Thread:
thread_state_t threadState = default;
uint flavor = Read<uint>(stream);
uint count = Read<uint>(stream);
switch (_header.CpuType)
{
case MachOCpuType.X86_64:
if (flavor == X86_THREAD_STATE64)
{
threadState.x64 = Read<x86_thread_state64_t>(stream);
}
break;
case MachOCpuType.ARM64:
if (flavor == ARM_THREAD_STATE64)
{
threadState.arm = Read<arm_thread_state64_t>(stream);
}
break;
}
contexts.Add(threadState);
break;
}
stream.Seek(next, SeekOrigin.Begin);
}
segments.Sort((x, y) => x.Address.CompareTo(y.Address));
_segments = segments.ToArray();
foreach (MachOSegment seg in _segments)
{
MachHeader64 header = ReadMemory<MachHeader64>(seg.Address);
if (header.Magic == MachHeader64.Magic64 && header.FileType == MachOFileType.Dylinker)
{
_dylinker = new MachOModule(this, seg.Address, "dylinker");
break;
}
}
Dictionary<uint, thread_state_t> threadContexts = new();
for (int i = 0; i < contexts.Count; i++)
{
ulong esp = default;
switch (_header.CpuType)
{
case MachOCpuType.X86_64:
esp = contexts[i].x64.__rsp;
break;
case MachOCpuType.ARM64:
esp = contexts[i].arm.__sp;
break;
}
if (threadIds.TryGetValue(esp, out uint threadId))
{
threadContexts.Add(threadId, contexts[i]);
}
else
{
// Use the index as the thread id if the special thread info memory section doesn't exists
threadContexts.Add((uint)i, contexts[i]);
}
}
Threads = threadContexts.ToImmutableDictionary();
}