@@ -41,6 +41,7 @@ type SysConfigVars struct {
4141 vma_vm_flags_offset uint32
4242 task_group_leader_offset uint32
4343 task_start_time_offset uint32
44+ pidNamespaceOffsets map [string ]uint32
4445}
4546
4647var (
@@ -139,8 +140,52 @@ func parseVMAOffsets(spec *btf.Spec, vars *SysConfigVars) {
139140 vars .vma_vm_flags_offset = uint32 (flagsOffset )
140141}
141142
143+ func parsePIDNamespaceOffsets (spec * btf.Spec , vars * SysConfigVars ) error {
144+ fields := []struct {
145+ typeName string
146+ field string
147+ variable string
148+ }{
149+ {typeName : "task_struct" , field : "thread_pid" , variable : "task_thread_pid_offset" },
150+ {typeName : "pid" , field : "level" , variable : "pid_level_offset" },
151+ {typeName : "pid" , field : "numbers" , variable : "pid_numbers_offset" },
152+ {typeName : "upid" , field : "nr" , variable : "upid_nr_offset" },
153+ {typeName : "upid" , field : "ns" , variable : "upid_ns_offset" },
154+ {typeName : "pid_namespace" , field : "ns.inum" , variable : "pid_namespace_inum_offset" },
155+ }
156+
157+ vars .pidNamespaceOffsets = make (map [string ]uint32 , len (fields )+ 1 )
158+ for _ , field := range fields {
159+ typ , err := spec .AnyTypeByName (field .typeName )
160+ if err != nil {
161+ return err
162+ }
163+ offset , err := calculateFieldOffset (typ , field .field )
164+ if err != nil {
165+ return err
166+ }
167+ vars .pidNamespaceOffsets [field .variable ] = uint32 (offset )
168+ }
169+
170+ upid , err := spec .AnyTypeByName ("upid" )
171+ if err != nil {
172+ return err
173+ }
174+ upidSize , err := btf .Sizeof (upid )
175+ if err != nil {
176+ return err
177+ }
178+ if upidSize <= 0 {
179+ return fmt .Errorf ("invalid kernel BTF upid size %d" , upidSize )
180+ }
181+ vars .pidNamespaceOffsets ["upid_size" ] = uint32 (upidSize )
182+ return nil
183+ }
184+
142185// parseBTF resolves the SystemConfig data from kernel BTF
143- func parseBTF (vars * SysConfigVars , needTPBase , needProcessStartTime bool ) error {
186+ func parseBTF (vars * SysConfigVars , needTPBase , needProcessStartTime ,
187+ needPIDNamespaceTranslation bool ,
188+ ) error {
144189 fh , err := os .Open ("/sys/kernel/btf/vmlinux" )
145190 if err != nil {
146191 return err
@@ -171,19 +216,27 @@ func parseBTF(vars *SysConfigVars, needTPBase, needProcessStartTime bool) error
171216 }
172217 }
173218
174- if needProcessStartTime {
219+ if needProcessStartTime || needPIDNamespaceTranslation {
175220 groupLeaderOffset , err := calculateFieldOffset (taskStruct , "group_leader" )
176221 if err != nil {
177222 return err
178223 }
179224 vars .task_group_leader_offset = uint32 (groupLeaderOffset )
225+ }
180226
227+ if needProcessStartTime {
181228 startTimeOffset , err := calculateFieldOffset (taskStruct , "start_time" )
182229 if err != nil {
183230 return err
184231 }
185232 vars .task_start_time_offset = uint32 (startTimeOffset )
186233 }
234+
235+ if needPIDNamespaceTranslation {
236+ if err := parsePIDNamespaceOffsets (spec , vars ); err != nil {
237+ return err
238+ }
239+ }
187240 parseVMAOffsets (spec , vars )
188241
189242 return nil
@@ -380,13 +433,16 @@ func getCurrentNS(filename string) (dev, ino uint64, err error) {
380433
381434func determineSysConfig (coll * cebpf.CollectionSpec , maps map [string ]* cebpf.Map ,
382435 kmod * kallsyms.Module , interpretersConfig interpreterconfig.Config , needProcessStartTime bool ,
383- vars * SysConfigVars ,
436+ pidNamespaceTranslation bool , vars * SysConfigVars ,
384437) error {
385438 needTPBase := ! interpretersConfig .Perl .IsDisabled () ||
386439 ! interpretersConfig .Python .IsDisabled () ||
387440 ! interpretersConfig .Ruby .IsDisabled () ||
388441 ! interpretersConfig .Go .IsLabelsDisabled ()
389- if err := parseBTF (vars , needTPBase , needProcessStartTime ); err != nil {
442+ if err := parseBTF (vars , needTPBase , needProcessStartTime , pidNamespaceTranslation ); err != nil {
443+ if pidNamespaceTranslation {
444+ return fmt .Errorf ("PID namespace translation requires readable kernel BTF with task and PID namespace layout: %w" , err )
445+ }
390446 if needProcessStartTime {
391447 return fmt .Errorf ("process age filter requires kernel BTF to resolve task_struct offsets: %w" , err )
392448 }
@@ -573,6 +629,9 @@ func loadRodataVars(coll *cebpf.CollectionSpec, kmod *kallsyms.Module, cfg *Conf
573629 if err != nil {
574630 return fmt .Errorf ("failed to read PID namespace info: %v" , err )
575631 }
632+ if dev == 0 || ino == 0 {
633+ return fmt .Errorf ("invalid PID namespace identity: device=%d, inode=%d" , dev , ino )
634+ }
576635 if err := coll .Variables ["pid_ns_translation_enabled" ].Set (uint8 (1 )); err != nil {
577636 return fmt .Errorf ("failed to set pid_ns_translation_enabled: %v" , err )
578637 }
@@ -582,7 +641,7 @@ func loadRodataVars(coll *cebpf.CollectionSpec, kmod *kallsyms.Module, cfg *Conf
582641 if err := coll .Variables ["target_pid_ns_inode" ].Set (ino ); err != nil {
583642 return fmt .Errorf ("failed to set target_pid_ns_inode: %v" , err )
584643 }
585- log .Infof ("PID namespace translation enabled (dev=%d, ino=%d), only processes traces within the profiler namespace will be collected" , dev , ino )
644+ log .Infof ("PID namespace translation enabled (dev=%d, ino=%d), only process traces visible in the profiler namespace will be collected" , dev , ino )
586645 }
587646
588647 // The Python/native hybrid unwinder's per program loop count defaults to 10
@@ -644,10 +703,17 @@ func loadRodataVars(coll *cebpf.CollectionSpec, kmod *kallsyms.Module, cfg *Conf
644703
645704 if err := determineSysConfig (
646705 systemAnalysisColl , maps , kmod , cfg .InterpretersConfig , cfg .FilterMinProcessAge > 0 ,
647- & rodataVars ,
706+ cfg . PIDNamespaceTranslation , & rodataVars ,
648707 ); err != nil {
649708 return fmt .Errorf ("failed to determine system configs: %v" , err )
650709 }
710+ if cfg .PIDNamespaceTranslation {
711+ for name , offset := range rodataVars .pidNamespaceOffsets {
712+ if err := coll .Variables [name ].Set (offset ); err != nil {
713+ return fmt .Errorf ("failed to set %s: %v" , name , err )
714+ }
715+ }
716+ }
651717 if err := coll .Variables ["tpbase_offset" ].Set (rodataVars .tpbase_offset ); err != nil {
652718 return fmt .Errorf ("failed to set tpbase_offset: %v" , err )
653719 }
0 commit comments