newProgramInfoFromFd queries program information about the given fd. [sys.ObjInfo] is attempted first, supplementing any missing values with information from /proc/self/fdinfo. Ignores EINVAL from ObjInfo as well as ErrNotSupported from reading fdinfo (indicating the file exists, but no fields of i
(fd *sys.FD)
| 351 | // ErrNotSupported from reading fdinfo (indicating the file exists, but no |
| 352 | // fields of interest were found). If both fail, an error is always returned. |
| 353 | func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) { |
| 354 | var info sys.ProgInfo |
| 355 | err1 := sys.ObjInfo(fd, &info) |
| 356 | // EINVAL means the kernel doesn't support BPF_OBJ_GET_INFO_BY_FD. Continue |
| 357 | // with fdinfo if that's the case. |
| 358 | if err1 != nil && !errors.Is(err1, unix.EINVAL) { |
| 359 | return nil, fmt.Errorf("getting object info: %w", err1) |
| 360 | } |
| 361 | |
| 362 | typ, err := ProgramTypeForPlatform(platform.Native, info.Type) |
| 363 | if err != nil { |
| 364 | return nil, fmt.Errorf("program type: %w", err) |
| 365 | } |
| 366 | |
| 367 | pi := ProgramInfo{ |
| 368 | Type: typ, |
| 369 | id: ProgramID(info.Id), |
| 370 | Tag: hex.EncodeToString(info.Tag[:]), |
| 371 | Name: unix.ByteSliceToString(info.Name[:]), |
| 372 | btf: btf.ID(info.BtfId), |
| 373 | jitedSize: info.JitedProgLen, |
| 374 | loadTime: time.Duration(info.LoadTime), |
| 375 | verifiedInstructions: info.VerifiedInsns, |
| 376 | numInsns: info.XlatedProgLen, |
| 377 | } |
| 378 | |
| 379 | // Supplement OBJ_INFO with data from /proc/self/fdinfo. It contains fields |
| 380 | // like memlock that is not present in OBJ_INFO. |
| 381 | err2 := readProgramInfoFromProc(fd, &pi) |
| 382 | if err2 != nil && !errors.Is(err2, ErrNotSupported) { |
| 383 | return nil, fmt.Errorf("getting map info from fdinfo: %w", err2) |
| 384 | } |
| 385 | |
| 386 | if err1 != nil && err2 != nil { |
| 387 | return nil, fmt.Errorf("ObjInfo and fdinfo both failed: objinfo: %w, fdinfo: %w", err1, err2) |
| 388 | } |
| 389 | |
| 390 | if platform.IsWindows && info.Tag == [8]uint8{} { |
| 391 | // Windows doesn't support the tag field, clear it for now. |
| 392 | pi.Tag = "" |
| 393 | } |
| 394 | |
| 395 | // Start with a clean struct for the second call, otherwise we may get EFAULT. |
| 396 | var info2 sys.ProgInfo |
| 397 | |
| 398 | makeSecondCall := false |
| 399 | |
| 400 | if info.NrMapIds > 0 { |
| 401 | pi.maps = make([]MapID, info.NrMapIds) |
| 402 | info2.NrMapIds = info.NrMapIds |
| 403 | info2.MapIds = sys.SlicePointer(pi.maps) |
| 404 | makeSecondCall = true |
| 405 | } else if haveProgramInfoMapIDs() == nil { |
| 406 | // This program really has no associated maps. |
| 407 | pi.maps = make([]MapID, 0) |
| 408 | } else { |
| 409 | // The kernel doesn't report associated maps. |
| 410 | pi.maps = nil |
searching dependent graphs…