14
14
using Datadog . Trace . Telemetry ;
15
15
using Datadog . Trace . Telemetry . DTOs ;
16
16
using Datadog . Trace . TestHelpers ;
17
+ using Datadog . Trace . Util ;
18
+ using ELFSharp . ELF ;
19
+ using ELFSharp . ELF . Sections ;
17
20
using FluentAssertions ;
18
21
using FluentAssertions . Execution ;
19
22
using Newtonsoft . Json . Linq ;
@@ -549,28 +552,27 @@ void ValidateStacktrace(JToken callstack)
549
552
frame . Should ( ) . NotBeNull ( $ "couldn't find expected frame { expectedFrame } ") ;
550
553
}
551
554
552
- if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
555
+ var validatedModules = new HashSet < string > ( ) ;
556
+
557
+ foreach ( var frame in frames )
553
558
{
554
- var validatedModules = new HashSet < string > ( ) ;
559
+ var moduleName = frame [ "names" ] [ 0 ] [ "name" ] . Value < string > ( ) . Split ( '!' ) . First ( ) ;
555
560
556
- // Validate PDBs
557
- foreach ( var frame in frames )
561
+ if ( moduleName . Length > 0 && ! moduleName . StartsWith ( "<" ) && Path . IsPathRooted ( moduleName ) )
558
562
{
559
- // Open the PE file
560
- var moduleName = frame [ "names" ] [ 0 ] [ "name" ] . Value < string > ( ) . Split ( '!' ) . First ( ) ;
561
-
562
- if ( moduleName . Length > 0 && ! moduleName . StartsWith ( "<" ) && Path . IsPathRooted ( moduleName ) )
563
+ if ( ! validatedModules . Add ( moduleName ) )
563
564
{
564
- if ( ! validatedModules . Add ( moduleName ) )
565
- {
566
- continue ;
567
- }
565
+ continue ;
566
+ }
568
567
568
+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
569
+ {
570
+ // Validate PDBs
569
571
var pdbNode = frame [ "normalized_ip" ] [ "meta" ] [ "Pdb" ] ;
570
-
571
572
var hash = ( ( JArray ) pdbNode [ "guid" ] ) . Select ( g => g . Value < byte > ( ) ) . ToArray ( ) ;
572
573
var age = pdbNode [ "age" ] . Value < uint > ( ) ;
573
574
575
+ // Open the PE file
574
576
using var file = File . OpenRead ( moduleName ) ;
575
577
using var peReader = new PEReader ( file ) ;
576
578
@@ -581,17 +583,38 @@ void ValidateStacktrace(JToken callstack)
581
583
age . Should ( ) . Be ( unchecked ( ( uint ) pdbInfo . Age ) ) ;
582
584
hash . Should ( ) . Equal ( pdbInfo . Guid . ToByteArray ( ) ) ;
583
585
}
586
+ else if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
587
+ {
588
+ // Validate sofile
589
+ if ( frame [ "normalized_ip" ] == null )
590
+ {
591
+ // On linux we can face cases where the build_id is not available:
592
+ // - specifically on alpine, /lib/ld-musl-XX do not have a build_id.
593
+ // - We are looking at a frame for which the library was unloaded /memfd:doublemapper (deleted)
594
+ continue ;
595
+ }
596
+
597
+ var elfNode = frame [ "normalized_ip" ] [ "meta" ] [ "Elf" ] ;
598
+ var buildId = ( ( JArray ) elfNode [ "build_id" ] ) . Select ( g => g . Value < byte > ( ) ) . ToArray ( ) ;
599
+
600
+ using var elf = ELFReader . Load ( moduleName ) ;
601
+ var buildIdNote = elf . GetSection ( ".note.gnu.build-id" ) as INoteSection ;
602
+ buildId . Should ( ) . Equal ( buildIdNote . Description ) ;
603
+ }
584
604
}
605
+ }
585
606
586
- validatedModules . Should ( ) . NotBeEmpty ( ) ;
607
+ validatedModules . Should ( ) . NotBeEmpty ( ) ;
587
608
588
609
#if NETFRAMEWORK
589
- var clrModuleName = "clr.dll" ;
610
+ var clrModuleName = "clr.dll" ;
590
611
#else
591
- var clrModuleName = "coreclr.dll" ;
612
+ var clrModuleName = RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ? "libcoreclr.so" : "coreclr.dll" ;
592
613
#endif
593
614
594
- validatedModules . Should ( ) . ContainMatch ( $@ "*\{ clrModuleName } ") ;
615
+ if ( ! Utils . IsAlpine ( ) )
616
+ {
617
+ validatedModules . Should ( ) . ContainMatch ( $@ "*{ Path . DirectorySeparatorChar } { clrModuleName } ") ;
595
618
}
596
619
}
597
620
}
0 commit comments