Skip to content

Spurious BROKEN frame at top of Linux thread stacks in CPU Stacks viewer #2374

@mdh1418

Description

@mdh1418

When viewing CPU stacks from Linux EventPipe .nettrace traces (e.g., collected by one-collect), every thread stack shows a BROKEN frame between the thread/process root and the actual bottom frame (libc.so.6!__clone3), even though the stack is fully intact:

   ROOT
   + Process32 dotnet (97856)
    + Thread (97868) CPU=2879ms
    |+ BROKEN                          ← spurious
    | + libc.so.6!__clone3
    |  + libc.so.6!start_thread
    |   + libcoreclr.so!CorUnix::CPalThread::ThreadEntry(void*)
    |    ...

Possible root cause:
ReasonableTopFrame() in TraceEventStacks.cs determines whether the deepest frame of a call stack is a valid thread entry point. It only recognizes ntdll.dll (Windows) and ntoskrnl.exe (kernel processes) as valid thread roots. On Linux, thread stacks bottom out in libc.so.6!__clone3 (or __clone, __libc_start_main), which fails this check, so every Linux thread stack is unconditionally routed through the "broken stack" encoding.

Possible fix:
Add libc (matching libc.so.6, libc.so, etc.) as a recognized thread-root module in ReasonableTopFrame(), alongside ntdll.dll.
e.g. in

private bool ReasonableTopFrame(StackSourceCallStackIndex callStackIndex, ThreadIndex threadIndex)

                // On Linux, threads start from libc's clone/clone3 or __libc_start_main.
                string fileName = moduleFile.Name;
                if (string.Compare(fileName, "libc", StringComparison.OrdinalIgnoreCase) == 0 ||
                    fileName.StartsWith("libc.", StringComparison.OrdinalIgnoreCase))
                {
                    m_goodTopModuleIndex = moduleFileIndex;
                    return true;
                }

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions