Skip to content

Capture build-id in module load events on Linux #116865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 25, 2025

Conversation

MichalStrehovsky
Copy link
Member

@MichalStrehovsky MichalStrehovsky commented Jun 20, 2025

Module load events on Windows carry a GUID of the matching PDB. This is used to verify the PDB that is used to analyze traces matches the one of the program.

On Linux, we don't have PDBs and PDB GUID. Instead, we have build-id. Build-id is a binary blob of an unspecified length that is stored both in .debug files and in the program binary. Typically, it is 20 bytes (SHA-1). Since 20 is more than 16, it unfortunately doesn't fit in the space we have. Emit a new version of the event that can fit it.

Cc @brianrob @noahfalk @dotnet/ilc-contrib

Module load events on Windows carry a GUID of the matching PDB. This is used to verify the PDB that is used to analyze traces matches the one of the program.

On Linux, we don't have PDBs and PDB GUID. Instead, we have build-id. Build-id is a binary blob of an unspecified length that is stored both in .debug files and in the program binary. Typically, it is 20 bytes (SHA-1). Since 20 is more than 16, it unfortunately doesn't fit in the space we have. The event however has two GUIDs. So use the space from the other event to store rest of the bits. Should be futureproof up to SHA-256.
@Copilot Copilot AI review requested due to automatic review settings June 20, 2025 15:38
Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR extends module load tracing on Linux to capture the ELF build-id (up to SHA-256) by repurposing the extra GUID field in module events.

  • Expanded PalGetPDBInfo to accept and zero-initialize a pManagedGuidSignature for overflow build-id bytes.
  • Added a Linux-specific implementation in PalUnix.cpp that iterates program headers to extract the GNU build-id into two GUIDs.
  • Updated eventtrace.cpp to pass the new managed GUID into module load events.

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/coreclr/nativeaot/Runtime/windows/PalCommon.cpp Extended PalGetPDBInfo signature and initialized the new GUID
src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp Implemented ELF build-id extraction via dl_iterate_phdr
src/coreclr/nativeaot/Runtime/eventtrace.cpp Passed the new managed GUID into module load ETW events
src/coreclr/nativeaot/Runtime/Pal.h Updated PalGetPDBInfo declaration to include pManagedGuidSignature
Comments suppressed due to low confidence (2)

src/coreclr/nativeaot/Runtime/eventtrace.cpp:382

  • [nitpick] The variable dwAge is used to store the build-id length on Linux but retains its original name suggesting PDB age. Consider renaming dwAge to buildIdLength or a more descriptive name to reflect its dual purpose.
    uint32_t dwAge;

src/coreclr/nativeaot/Runtime/Pal.h:164

  • The function signature for PalGetPDBInfo has changed to include the pManagedGuidSignature parameter. Please update or add a documentation comment to describe the purpose and behavior of this new parameter.
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath, GUID * pManagedGuidSignature);

@brianrob
Copy link
Member

A general question on this: My understanding (and I could be very wrong on this) is that NativeAOT only emits one merged binary. If that's the case, are you expecting this event to be emitted once for the merged binary? If so, we may not need to do this at all - native profilers will get the build ID on their own through the OS mmap event and I'm not sure that eventpipe will ever need it.

Copy link
Member

@noahfalk noahfalk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be using a new version of the ModuleLoad event rather than repurposing existing fields with different meaning. (that is if we decide ModuleLoad events are needed at all, see Brian's comment)

@MichalStrehovsky
Copy link
Member Author

A general question on this: My understanding (and I could be very wrong on this) is that NativeAOT only emits one merged binary. If that's the case, are you expecting this event to be emitted once for the merged binary? If so, we may not need to do this at all - native profilers will get the build ID on their own through the OS mmap event and I'm not sure that eventpipe will ever need it.

Yep, only one native binary. .NET native had a mode where there could be 3 native binaries.

Assume I have an already running process and execute dotnet-gcdump collect - would there be an event captured with the build-id already in the dump? My assumption was that we'd need to execute a loader rundown and generate ModuleLoad events with the build ID (the build ID being the last necessary thing added in this PR) to get that. We need module name and build-id to be able to match up debug information and get type names later when analyzing the gcdump.

Copy link
Member

@noahfalk noahfalk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MichalStrehovsky
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@MichalStrehovsky
Copy link
Member Author

/ba-g unable to match the failure with #117015 that I just filed for some reason

@MichalStrehovsky MichalStrehovsky merged commit e2c99a9 into dotnet:main Jun 25, 2025
114 of 119 checks passed
@MichalStrehovsky MichalStrehovsky deleted the buildidinevent branch June 25, 2025 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants