@@ -9,16 +9,20 @@ import (
9
9
"context"
10
10
"errors"
11
11
"fmt"
12
+ "io"
12
13
"log/slog"
13
14
"sync"
14
15
16
+ "github.com/cilium/ebpf"
15
17
"github.com/cilium/ebpf/link"
16
18
"github.com/cilium/ebpf/rlimit"
17
19
18
20
"go.opentelemetry.io/otel/trace"
19
21
22
+ "go.opentelemetry.io/auto/internal/pkg/inject"
20
23
"go.opentelemetry.io/auto/internal/pkg/instrumentation/bpffs"
21
24
"go.opentelemetry.io/auto/internal/pkg/instrumentation/probe"
25
+ "go.opentelemetry.io/auto/internal/pkg/instrumentation/utils"
22
26
"go.opentelemetry.io/auto/internal/pkg/opentelemetry"
23
27
"go.opentelemetry.io/auto/internal/pkg/process"
24
28
)
@@ -54,6 +58,7 @@ type Manager struct {
54
58
probeMu sync.Mutex
55
59
state managerState
56
60
stateMu sync.RWMutex
61
+ collectionOpts * ebpf.CollectionOptions
57
62
}
58
63
59
64
// NewManager returns a new [Manager].
@@ -88,6 +93,18 @@ func NewManager(
88
93
return nil , err
89
94
}
90
95
96
+ m .collectionOpts = & ebpf.CollectionOptions {
97
+ Maps : ebpf.MapOptions {
98
+ PinPath : bpffs .PathForTargetApplication (m .proc ),
99
+ },
100
+ }
101
+
102
+ alloc , err := process .Allocate (logger , pid )
103
+ if err != nil {
104
+ return nil , err
105
+ }
106
+ m .proc .Allocation = alloc
107
+
91
108
m .logger .Info ("loaded process info" , "process" , m .proc )
92
109
93
110
m .filterUnusedProbes ()
@@ -215,7 +232,7 @@ func (m *Manager) applyConfig(c Config) error {
215
232
216
233
if ! currentlyEnabled && newEnabled {
217
234
m .logger .Info ("Enabling probe" , "id" , id )
218
- err = errors .Join (err , p . Load ( m . exe , m . proc , c . SamplingConfig ))
235
+ err = errors .Join (err , m . LoadProbe ( p , id , c ))
219
236
if err == nil {
220
237
m .runProbe (p )
221
238
}
@@ -379,8 +396,7 @@ func (m *Manager) loadProbes() error {
379
396
// Load probes
380
397
for name , i := range m .probes {
381
398
if isProbeEnabled (name , m .currentConfig ) {
382
- m .logger .Info ("loading probe" , "name" , name )
383
- err := i .Load (exe , m .proc , m .currentConfig .SamplingConfig )
399
+ err := m .LoadProbe (i , name , m .currentConfig )
384
400
if err != nil {
385
401
m .logger .Error (
386
402
"error while loading probes, cleaning up" ,
@@ -398,6 +414,175 @@ func (m *Manager) loadProbes() error {
398
414
return nil
399
415
}
400
416
417
+ func (m * Manager ) LoadProbe (i probe.Probe , name probe.ID , cfg Config ) error {
418
+ m .logger .Info ("loading probe" , "name" , name )
419
+
420
+ err := i .Init (cfg .SamplingConfig )
421
+ if err != nil {
422
+ return errors .Join (err , m .cleanup ())
423
+ }
424
+
425
+ spec , err := i .Spec ()
426
+ if err != nil {
427
+ return errors .Join (err , m .cleanup ())
428
+ }
429
+
430
+ err = m .InjectProbeConsts (i , spec )
431
+ if err != nil {
432
+ return err
433
+ }
434
+
435
+ c , err := utils .InitializeEBPFCollection (spec , m .collectionOpts )
436
+ if err != nil {
437
+ return err
438
+ }
439
+ i .SetCollection (c )
440
+ return nil
441
+ }
442
+
443
+ func (m * Manager ) InjectProbeConsts (i probe.Probe , spec * ebpf.CollectionSpec ) error {
444
+ var err error
445
+ var opts []inject.Option
446
+ for _ , cnst := range i .GetConsts () {
447
+ if l , ok := cnst .(probe.SetLogger ); ok {
448
+ cnst = l .SetLogger (i .GetLogger ())
449
+ }
450
+
451
+ o , e := cnst .InjectOption (m .proc )
452
+ err = errors .Join (err , e )
453
+ if e == nil && o != nil {
454
+ opts = append (opts , o )
455
+ }
456
+ }
457
+ if err != nil {
458
+ return err
459
+ }
460
+
461
+ return inject .Constants (spec , opts ... )
462
+ }
463
+
464
+ func (m * Manager ) loadUprobesFromProbe (i probe.Probe ) error {
465
+ for _ , up := range i .GetUprobes () {
466
+ var skip bool
467
+ for _ , pc := range up .PackageConstraints {
468
+ if pc .Constraints .Check (m .proc .Modules [pc .Package ]) {
469
+ continue
470
+ }
471
+
472
+ var logFn func (string , ... any )
473
+ switch pc .FailureMode {
474
+ case probe .FailureModeIgnore :
475
+ logFn = i .GetLogger ().Debug
476
+ case probe .FailureModeWarn :
477
+ logFn = i .GetLogger ().Warn
478
+ default :
479
+ // Unknown and FailureModeError.
480
+ return fmt .Errorf (
481
+ "uprobe %s package constraint (%s) not met, version %v" ,
482
+ up .Sym ,
483
+ pc .Constraints .String (),
484
+ m .proc .Modules [pc .Package ])
485
+ }
486
+
487
+ logFn (
488
+ "package constraint not meet, skipping uprobe" ,
489
+ "probe" , i .Manifest ().ID ,
490
+ "symbol" , up .Sym ,
491
+ "package" , pc .Package ,
492
+ "constraint" , pc .Constraints .String (),
493
+ "version" , m .proc .Modules [pc .Package ],
494
+ )
495
+
496
+ skip = true
497
+ break
498
+ }
499
+ if skip {
500
+ continue
501
+ }
502
+
503
+ err := m .loadUprobe (up , i .GetCollection ())
504
+ if err != nil {
505
+ var logFn func (string , ... any )
506
+ switch up .FailureMode {
507
+ case probe .FailureModeIgnore :
508
+ logFn = i .GetLogger ().Debug
509
+ case probe .FailureModeWarn :
510
+ logFn = i .GetLogger ().Warn
511
+ default :
512
+ // Unknown and FailureModeError.
513
+ return err
514
+ }
515
+ logFn ("failed to load uprobe" , "probe" , i .Manifest ().ID , "symbol" , up .Sym , "error" , err )
516
+ continue
517
+ }
518
+ _ = i .UpdateClosers (up )
519
+ }
520
+ return nil
521
+ }
522
+
523
+ func (m * Manager ) loadUprobe (u * probe.Uprobe , c * ebpf.Collection ) error {
524
+ offset , err := m .proc .GetFunctionOffset (u .Sym )
525
+ if err != nil {
526
+ return err
527
+ }
528
+
529
+ var closers []io.Closer
530
+
531
+ if u .EntryProbe != "" {
532
+ entryProg , ok := c .Programs [u .EntryProbe ]
533
+ if ! ok {
534
+ return fmt .Errorf ("entry probe %s not found" , u .EntryProbe )
535
+ }
536
+ opts := & link.UprobeOptions {Address : offset , PID : int (m .proc .ID )}
537
+ l , err := m .exe .Uprobe ("" , entryProg , opts )
538
+ if err != nil {
539
+ return err
540
+ }
541
+ closers = append (closers , l )
542
+ }
543
+
544
+ if u .ReturnProbe != "" {
545
+ retProg , ok := c .Programs [u .ReturnProbe ]
546
+ if ! ok {
547
+ return fmt .Errorf ("return probe %s not found" , u .ReturnProbe )
548
+ }
549
+ retOffsets , err := m .proc .GetFunctionReturns (u .Sym )
550
+ if err != nil {
551
+ return err
552
+ }
553
+
554
+ for _ , ret := range retOffsets {
555
+ opts := & link.UprobeOptions {Address : ret , PID : int (m .proc .ID )}
556
+ l , err := m .exe .Uprobe ("" , retProg , opts )
557
+ if err != nil {
558
+ return err
559
+ }
560
+ closers = append (closers , l )
561
+ }
562
+ }
563
+
564
+ old := u .Closers .Swap (& closers )
565
+ if old != nil {
566
+ // load called twice without calling Close. Try and handle gracefully.
567
+ var err error
568
+ for _ , closer := range * old {
569
+ err = errors .Join (err , closer .Close ())
570
+ }
571
+ return err
572
+ }
573
+
574
+ return nil
575
+ }
576
+
577
+ func (m * Manager ) mount () error {
578
+ if m .proc .Allocation != nil {
579
+ m .logger .Debug ("Mounting bpffs" , "allocation" , m .proc .Allocation )
580
+ } else {
581
+ m .logger .Debug ("Mounting bpffs" )
582
+ }
583
+ return bpffsMount (m .proc )
584
+ }
585
+
401
586
func (m * Manager ) cleanup () error {
402
587
ctx := context .Background ()
403
588
err := m .cp .Shutdown (context .Background ())
0 commit comments