Skip to content

Commit e2c99a9

Browse files
Capture build-id in module load events on Linux (#116865)
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.
1 parent a0397e7 commit e2c99a9

File tree

6 files changed

+199
-10
lines changed

6 files changed

+199
-10
lines changed

src/coreclr/nativeaot/Runtime/Pal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ bool PalInit();
161161
// Given the OS handle of a loaded module, compute the upper and lower virtual address bounds (inclusive).
162162
void PalGetModuleBounds(HANDLE hOsHandle, _Out_ uint8_t ** ppLowerBound, _Out_ uint8_t ** ppUpperBound);
163163

164-
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath);
164+
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath, _Out_ uint32_t * pcbBuildId, _Out_ void ** ppBuildId);
165165

166166
struct NATIVE_CONTEXT;
167167

src/coreclr/nativeaot/Runtime/eventpipe/gen-eventing-event-inc.lst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ GenAwareBegin
8383
GenAwareEnd
8484
IncreaseMemoryPressure
8585
LockCreated
86-
ModuleDCEnd_V2
87-
ModuleLoad_V2
86+
ModuleDCEnd_V3
87+
ModuleLoad_V3
8888
PinObjectAtGCTime
8989
PinPlugAtGCTime
9090
PrvDestroyGCHandle

src/coreclr/nativeaot/Runtime/eventtrace.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,32 @@ void ETW::LoaderLog::SendModuleEvent(HANDLE pModule, uint32_t dwEventOptions)
379379
GUID nativeGuid;
380380
uint32_t dwAge;
381381
WCHAR wszPath[1024];
382-
PalGetPDBInfo(pModule, &nativeGuid, &dwAge, wszPath, ARRAY_SIZE(wszPath));
382+
uint32_t cbBuildId;
383+
void* pBuildId;
384+
PalGetPDBInfo(pModule, &nativeGuid, &dwAge, wszPath, ARRAY_SIZE(wszPath), &cbBuildId, &pBuildId);
385+
386+
WCHAR wszBuildId[65];
387+
size_t written = 0;
388+
for (size_t i = 0; i < cbBuildId; i++)
389+
{
390+
if (written + 3 <= ARRAY_SIZE(wszBuildId)) { // 2 hex digits + 1 null terminator
391+
const WCHAR* hexDigits = W("0123456789ABCDEF");
392+
// Convert each byte to hex and append to the output string
393+
uint8_t c = ((uint8_t*)pBuildId)[i];
394+
wszBuildId[written++] = hexDigits[c >> 4];
395+
wszBuildId[written++] = hexDigits[c & 0xF];
396+
} else {
397+
// If buffer not enough to fit, truncate
398+
break;
399+
}
400+
}
401+
wszBuildId[written] = 0;
383402

384403
GUID zeroGuid = { 0 };
385404

386405
if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleLoad)
387406
{
388-
FireEtwModuleLoad_V2(
407+
FireEtwModuleLoad_V3(
389408
ULONGLONG(pModule),
390409
0, // AssemblyID
391410
ETW::LoaderLog::LoaderStructs::NativeModule, // Module Flags
@@ -398,12 +417,13 @@ void ETW::LoaderLog::SendModuleEvent(HANDLE pModule, uint32_t dwEventOptions)
398417
NULL, // ManagedPdbBuildPath,
399418
&nativeGuid, // NativePdbSignature,
400419
dwAge, // NativePdbAge,
401-
wszPath // NativePdbBuildPath,
420+
wszPath, // NativePdbBuildPath,
421+
wszBuildId // NativeBuildId,
402422
);
403423
}
404424
else if (dwEventOptions & ETW::EnumerationLog::EnumerationStructs::DomainAssemblyModuleDCEnd)
405425
{
406-
FireEtwModuleDCEnd_V2(
426+
FireEtwModuleDCEnd_V3(
407427
ULONGLONG(pModule),
408428
0, // AssemblyID
409429
ETW::LoaderLog::LoaderStructs::NativeModule, // Module Flags
@@ -416,7 +436,8 @@ void ETW::LoaderLog::SendModuleEvent(HANDLE pModule, uint32_t dwEventOptions)
416436
NULL, // ManagedPdbBuildPath,
417437
&nativeGuid, // NativePdbSignature,
418438
dwAge, // NativePdbAge,
419-
wszPath // NativePdbBuildPath,
439+
wszPath, // NativePdbBuildPath,
440+
wszBuildId // NativeBuildId,
420441
);
421442
}
422443
else

src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444

4545
#ifdef TARGET_LINUX
4646
#include <sys/syscall.h>
47+
#include <link.h>
48+
#include <elf.h>
4749
#endif
4850

4951
#if HAVE_PTHREAD_GETTHREADID_NP
@@ -95,13 +97,96 @@ void RhFailFast()
9597
abort();
9698
}
9799

98-
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath)
100+
#if TARGET_LINUX
101+
102+
struct PalGetPDBInfoPhdrCallbackData
103+
{
104+
void* Base;
105+
void* BuildID;
106+
uint32_t BuildIDLength;
107+
};
108+
109+
static int PalGetPDBInfoPhdrCallback(struct dl_phdr_info *info, size_t size, void* pData)
110+
{
111+
struct PalGetPDBInfoPhdrCallbackData* pCallbackData = (struct PalGetPDBInfoPhdrCallbackData*)pData;
112+
113+
// Find the module of interest
114+
void* loadAddress = NULL;
115+
for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++)
116+
{
117+
if (info->dlpi_phdr[i].p_type == PT_LOAD)
118+
{
119+
loadAddress = (void*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
120+
if (loadAddress == pCallbackData->Base)
121+
break;
122+
}
123+
}
124+
125+
if (loadAddress != pCallbackData->Base)
126+
{
127+
return 0;
128+
}
129+
130+
// Got the module of interest. Now iterate program headers and try to find the GNU build ID note
131+
for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++)
132+
{
133+
// Must be a note section. We don't check the name because while there's a convention for the name,
134+
// the convention is not mandatory.
135+
if (info->dlpi_phdr[i].p_type != PT_NOTE)
136+
continue;
137+
138+
// Got a note section, iterate over the contents and find the GNU build id one
139+
ElfW(Nhdr) *note = (ElfW(Nhdr)*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
140+
ElfW(Addr) align = info->dlpi_phdr[i].p_align;
141+
ElfW(Addr) size = info->dlpi_phdr[i].p_memsz;
142+
ElfW(Addr) start = (ElfW(Addr))note;
143+
144+
while ((ElfW(Addr)) (note + 1) - start < size)
145+
{
146+
if (note->n_namesz == 4
147+
&& note->n_type == NT_GNU_BUILD_ID
148+
&& memcmp(note + 1, "GNU", 4) == 0)
149+
{
150+
// Got the note, fill out the callback data and return.
151+
pCallbackData->BuildID = (uint8_t*)note + sizeof(ElfW(Nhdr)) + ALIGN_UP(note->n_namesz, align);
152+
pCallbackData->BuildIDLength = note->n_descsz;
153+
return 1;
154+
}
155+
156+
// Skip over the note. Size of the note is determined by the header and payload (aligned)
157+
size_t offset = sizeof(ElfW(Nhdr))
158+
+ ALIGN_UP(note->n_namesz, align)
159+
+ ALIGN_UP(note->n_descsz, align);
160+
note = (ElfW(Nhdr)*)((uint8_t*)note + offset);
161+
}
162+
}
163+
164+
return 0;
165+
}
166+
#endif
167+
168+
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath, _Out_ uint32_t * pcbBuildId, _Out_ void ** ppBuildId)
99169
{
100170
memset(pGuidSignature, 0, sizeof(*pGuidSignature));
101171
*pdwAge = 0;
172+
*ppBuildId = NULL;
173+
*pcbBuildId = 0;
102174
if (cchPath <= 0)
103175
return;
104176
wszPath[0] = L'\0';
177+
178+
#if TARGET_LINUX
179+
struct PalGetPDBInfoPhdrCallbackData data;
180+
data.Base = hOsHandle;
181+
182+
if (!dl_iterate_phdr(&PalGetPDBInfoPhdrCallback, &data))
183+
{
184+
return;
185+
}
186+
187+
*pcbBuildId = data.BuildIDLength;
188+
*ppBuildId = data.BuildID;
189+
#endif
105190
}
106191

107192
static void UnmaskActivationSignal()

src/coreclr/nativeaot/Runtime/windows/PalCommon.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ void PalGetModuleBounds(HANDLE hOsHandle, _Out_ uint8_t ** ppLowerBound, _Out_ u
5050
//
5151
// This is a simplification of similar code in CLR's GetCodeViewInfo
5252
// in eventtrace.cpp.
53-
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath)
53+
void PalGetPDBInfo(HANDLE hOsHandle, GUID * pGuidSignature, _Out_ uint32_t * pdwAge, _Out_writes_z_(cchPath) WCHAR * wszPath, int32_t cchPath, _Out_ uint32_t * pcbBuildId, _Out_ void ** ppBuildId)
5454
{
5555
// Zero-init [out]-params
5656
ZeroMemory(pGuidSignature, sizeof(*pGuidSignature));
57+
*ppBuildId = NULL;
58+
*pcbBuildId = 0;
5759
*pdwAge = 0;
5860
if (cchPath <= 0)
5961
return;

src/coreclr/vm/ClrEtwAll.man

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,40 @@
19321932
</UserData>
19331933
</template>
19341934

1935+
<template tid="ModuleLoadUnload_V3">
1936+
<data name="ModuleID" inType="win:UInt64" outType="win:HexInt64" />
1937+
<data name="AssemblyID" inType="win:UInt64" outType="win:HexInt64" />
1938+
<data name="ModuleFlags" inType="win:UInt32" map="ModuleFlagsMap" />
1939+
<data name="Reserved1" inType="win:UInt32" />
1940+
<data name="ModuleILPath" inType="win:UnicodeString" />
1941+
<data name="ModuleNativePath" inType="win:UnicodeString" />
1942+
<data name="ClrInstanceID" inType="win:UInt16" />
1943+
<data name="ManagedPdbSignature" inType="win:GUID" />
1944+
<data name="ManagedPdbAge" inType="win:UInt32" />
1945+
<data name="ManagedPdbBuildPath" inType="win:UnicodeString" />
1946+
<data name="NativePdbSignature" inType="win:GUID" />
1947+
<data name="NativePdbAge" inType="win:UInt32" />
1948+
<data name="NativePdbBuildPath" inType="win:UnicodeString" />
1949+
<data name="NativeBuildID" inType="win:UnicodeString" />
1950+
<UserData>
1951+
<ModuleLoadUnload_V3 xmlns="myNs">
1952+
<ModuleID> %1 </ModuleID>
1953+
<AssemblyID> %2 </AssemblyID>
1954+
<ModuleFlags> %3 </ModuleFlags>
1955+
<ModuleILPath> %4 </ModuleILPath>
1956+
<ModuleNativePath> %5 </ModuleNativePath>
1957+
<ClrInstanceID> %6 </ClrInstanceID>
1958+
<ManagedPdbSignature> %7 </ManagedPdbSignature>
1959+
<ManagedPdbAge> %8 </ManagedPdbAge>
1960+
<ManagedPdbBuildPath> %9 </ManagedPdbBuildPath>
1961+
<NativePdbSignature> %10 </NativePdbSignature>
1962+
<NativePdbAge> %11 </NativePdbAge>
1963+
<NativePdbBuildPath> %12 </NativePdbBuildPath>
1964+
<NativeBuildID> %13 </NativeBuildID>
1965+
</ModuleLoadUnload_V3>
1966+
</UserData>
1967+
</template>
1968+
19351969
<template tid="AssemblyLoadUnload">
19361970
<data name="AssemblyID" inType="win:UInt64" outType="win:HexInt64" />
19371971
<data name="AppDomainID" inType="win:UInt64" outType="win:HexInt64" />
@@ -4008,6 +4042,11 @@
40084042
task="CLRLoader"
40094043
symbol="ModuleLoad_V2" message="$(string.RuntimePublisher.ModuleLoad_V2EventMessage)"/>
40104044

4045+
<event value="152" version="3" level="win:Informational" template="ModuleLoadUnload_V3"
4046+
keywords ="LoaderKeyword PerfTrackKeyword" opcode="ModuleLoad"
4047+
task="CLRLoader"
4048+
symbol="ModuleLoad_V3" message="$(string.RuntimePublisher.ModuleLoad_V3EventMessage)"/>
4049+
40114050
<event value="153" version="0" level="win:Informational" template="ModuleLoadUnload"
40124051
keywords ="LoaderKeyword" opcode="ModuleUnload"
40134052
task="CLRLoader"
@@ -4676,6 +4715,41 @@
46764715
</UserData>
46774716
</template>
46784717

4718+
<template tid="ModuleLoadUnloadRundown_V3">
4719+
<data name="ModuleID" inType="win:UInt64" outType="win:HexInt64" />
4720+
<data name="AssemblyID" inType="win:UInt64" outType="win:HexInt64" />
4721+
<data name="ModuleFlags" inType="win:UInt32" map="ModuleFlagsMap" />
4722+
<data name="Reserved1" inType="win:UInt32" />
4723+
<data name="ModuleILPath" inType="win:UnicodeString" />
4724+
<data name="ModuleNativePath" inType="win:UnicodeString" />
4725+
<data name="ClrInstanceID" inType="win:UInt16" />
4726+
<data name="ManagedPdbSignature" inType="win:GUID" />
4727+
<data name="ManagedPdbAge" inType="win:UInt32" />
4728+
<data name="ManagedPdbBuildPath" inType="win:UnicodeString" />
4729+
<data name="NativePdbSignature" inType="win:GUID" />
4730+
<data name="NativePdbAge" inType="win:UInt32" />
4731+
<data name="NativePdbBuildPath" inType="win:UnicodeString" />
4732+
<data name="NativeBuildID" inType="win:UnicodeString" />
4733+
4734+
<UserData>
4735+
<ModuleLoadUnloadRundown_V3 xmlns="myNs">
4736+
<ModuleID> %1 </ModuleID>
4737+
<AssemblyID> %2 </AssemblyID>
4738+
<ModuleFlags> %3 </ModuleFlags>
4739+
<ModuleILPath> %4 </ModuleILPath>
4740+
<ModuleNativePath> %5 </ModuleNativePath>
4741+
<ClrInstanceID> %6 </ClrInstanceID>
4742+
<ManagedPdbSignature> %7 </ManagedPdbSignature>
4743+
<ManagedPdbAge> %8 </ManagedPdbAge>
4744+
<ManagedPdbBuildPath> %9 </ManagedPdbBuildPath>
4745+
<NativePdbSignature> %10 </NativePdbSignature>
4746+
<NativePdbAge> %11 </NativePdbAge>
4747+
<NativePdbBuildPath> %12 </NativePdbBuildPath>
4748+
<NativeBuildID> %13 </NativeBuildID>
4749+
</ModuleLoadUnloadRundown_V3>
4750+
</UserData>
4751+
</template>
4752+
46794753
<template tid="AssemblyLoadUnloadRundown">
46804754
<data name="AssemblyID" inType="win:UInt64" outType="win:HexInt64" />
46814755
<data name="AppDomainID" inType="win:UInt64" outType="win:HexInt64" />
@@ -5200,6 +5274,11 @@
52005274
task="CLRLoaderRundown"
52015275
symbol="ModuleDCEnd_V2" message="$(string.RundownPublisher.ModuleDCEnd_V2EventMessage)"/>
52025276

5277+
<event value="154" version="3" level="win:Informational" template="ModuleLoadUnloadRundown_V3"
5278+
keywords ="LoaderRundownKeyword PerfTrackRundownKeyword" opcode="ModuleDCEnd"
5279+
task="CLRLoaderRundown"
5280+
symbol="ModuleDCEnd_V3" message="$(string.RundownPublisher.ModuleDCEnd_V3EventMessage)"/>
5281+
52035282
<event value="155" version="0" level="win:Informational" template="AssemblyLoadUnloadRundown"
52045283
keywords ="LoaderRundownKeyword" opcode="AssemblyDCStart"
52055284
task="CLRLoaderRundown"
@@ -8597,6 +8676,7 @@
85978676
<string id="RuntimePublisher.ModuleLoadEventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;ModuleILPath=%4;%nModuleNativePath=%5" />
85988677
<string id="RuntimePublisher.ModuleLoad_V1EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6" />
85998678
<string id="RuntimePublisher.ModuleLoad_V2EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6;%nManagedPdbSignature=%7;%nManagedPdbAge=%8;%nManagedPdbBuildPath=%9;%nNativePdbSignature=%10;%nNativePdbAge=%11;%nNativePdbBuildPath=%12" />
8679+
<string id="RuntimePublisher.ModuleLoad_V3EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6;%nManagedPdbSignature=%7;%nManagedPdbAge=%8;%nManagedPdbBuildPath=%9;%nNativePdbSignature=%10;%nNativePdbAge=%11;%nNativePdbBuildPath=%12;%nNativeBuildID=%13" />
86008680
<string id="RuntimePublisher.ModuleUnloadEventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;ModuleILPath=%4;%nModuleNativePath=%5" />
86018681
<string id="RuntimePublisher.ModuleUnload_V1EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6" />
86028682
<string id="RuntimePublisher.ModuleUnload_V2EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6;%nManagedPdbSignature=%7;%nManagedPdbAge=%8;%nManagedPdbBuildPath=%9;%nNativePdbSignature=%10;%nNativePdbAge=%11;%nNativePdbBuildPath=%12" />
@@ -8680,6 +8760,7 @@
86808760
<string id="RundownPublisher.ModuleDCEndEventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;ModuleILPath=%4;ModuleNativePath=%5" />
86818761
<string id="RundownPublisher.ModuleDCEnd_V1EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;ModuleILPath=%4;ModuleNativePath=%5;%nClrInstanceID=%6" />
86828762
<string id="RundownPublisher.ModuleDCEnd_V2EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6;%nManagedPdbSignature=%7;%nManagedPdbAge=%8;%nManagedPdbBuildPath=%9;%nNativePdbSignature=%10;%nNativePdbAge=%11;%nNativePdbBuildPath=%12" />
8763+
<string id="RundownPublisher.ModuleDCEnd_V3EventMessage" value="ModuleID=%1;%nAssemblyID=%2;%nModuleFlags=%3;%nModuleILPath=%4;%nModuleNativePath=%5;%nClrInstanceID=%6;%nManagedPdbSignature=%7;%nManagedPdbAge=%8;%nManagedPdbBuildPath=%9;%nNativePdbSignature=%10;%nNativePdbAge=%11;%nNativePdbBuildPath=%12;%nNativeBuildID=%13" />
86838764
<string id="RundownPublisher.AssemblyDCStartEventMessage" value="AssemblyID=%1;%nAppDomainID=%2;%nAssemblyFlags=%3;FullyQualifiedAssemblyName=%4" />
86848765
<string id="RundownPublisher.AssemblyDCStart_V1EventMessage" value="AssemblyID=%1;%nAppDomainID=%2;%nAssemblyFlags=%3;FullyQualifiedAssemblyName=%4;%nClrInstanceID=%5" />
86858766
<string id="RundownPublisher.AssemblyDCEndEventMessage" value="AssemblyID=%1;%nAppDomainID=%2;%nAssemblyFlags=%3;FullyQualifiedAssemblyName=%4" />

0 commit comments

Comments
 (0)