Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

info: expose more prog jited info #1598

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions btf/ext_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@ func loadExtInfos(r io.ReaderAt, bo binary.ByteOrder, spec *Spec) (*ExtInfos, er
return &ExtInfos{funcInfos, lineInfos, coreRelos}, nil
}

type funcInfoMeta struct{}
type coreRelocationMeta struct{}
type (
funcInfoMeta struct{}
coreRelocationMeta struct{}
)

// Assign per-section metadata from BTF to a section's instructions.
func (ei *ExtInfos) Assign(insns asm.Instructions, section string) {
Expand All @@ -128,8 +130,8 @@ func AssignMetadataToInstructions(
funcInfos = funcInfos[1:]
}

if len(lineInfos.infos) > 0 && lineInfos.infos[0].offset == iter.Offset {
*iter.Ins = iter.Ins.WithSource(lineInfos.infos[0].line)
if len(lineInfos.infos) > 0 && lineInfos.infos[0].Offset == iter.Offset {
*iter.Ins = iter.Ins.WithSource(lineInfos.infos[0].Line)
lineInfos.infos = lineInfos.infos[1:]
}

Expand Down Expand Up @@ -178,9 +180,9 @@ marshal:
}
}

li := &lineInfo{
line: line,
offset: iter.Offset,
li := &LineInfo{
Line: line,
Offset: iter.Offset,
}
if err := li.marshal(&liBuf, b); err != nil {
return nil, nil, fmt.Errorf("write line info: %w", err)
Expand Down Expand Up @@ -518,12 +520,18 @@ func (li *Line) String() string {

// LineInfos contains a sorted list of line infos.
type LineInfos struct {
infos []lineInfo
infos []LineInfo
}

type lineInfo struct {
line *Line
offset asm.RawInstructionOffset
// Lines returns the sorted list of line infos.
func (li *LineInfos) Lines() []LineInfo {
return li.infos
}

// LineInfo represents a line info and its raw instruction offset.
type LineInfo struct {
Line *Line
Offset asm.RawInstructionOffset
}

// Constants for the format of bpfLineInfo.LineCol.
Expand Down Expand Up @@ -557,21 +565,21 @@ func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec
return newLineInfos(lis, spec.strings)
}

func newLineInfo(li bpfLineInfo, strings *stringTable) (lineInfo, error) {
func newLineInfo(li bpfLineInfo, strings *stringTable) (LineInfo, error) {
line, err := strings.Lookup(li.LineOff)
if err != nil {
return lineInfo{}, fmt.Errorf("lookup of line: %w", err)
return LineInfo{}, fmt.Errorf("lookup of line: %w", err)
}

fileName, err := strings.Lookup(li.FileNameOff)
if err != nil {
return lineInfo{}, fmt.Errorf("lookup of filename: %w", err)
return LineInfo{}, fmt.Errorf("lookup of filename: %w", err)
}

lineNumber := li.LineCol >> bpfLineShift
lineColumn := li.LineCol & bpfColumnMax

return lineInfo{
return LineInfo{
&Line{
fileName,
line,
Expand All @@ -584,7 +592,7 @@ func newLineInfo(li bpfLineInfo, strings *stringTable) (lineInfo, error) {

func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineInfos, error) {
lis := LineInfos{
infos: make([]lineInfo, 0, len(blis)),
infos: make([]LineInfo, 0, len(blis)),
}
for _, bli := range blis {
li, err := newLineInfo(bli, strings)
Expand All @@ -594,14 +602,14 @@ func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineInfos, error) {
lis.infos = append(lis.infos, li)
}
sort.Slice(lis.infos, func(i, j int) bool {
return lis.infos[i].offset <= lis.infos[j].offset
return lis.infos[i].Offset <= lis.infos[j].Offset
})
return lis, nil
}

// marshal writes the binary representation of the LineInfo to w.
func (li *lineInfo) marshal(w *bytes.Buffer, b *Builder) error {
line := li.line
func (li *LineInfo) marshal(w *bytes.Buffer, b *Builder) error {
line := li.Line
if line.lineNumber > bpfLineMax {
return fmt.Errorf("line %d exceeds %d", line.lineNumber, bpfLineMax)
}
Expand All @@ -621,7 +629,7 @@ func (li *lineInfo) marshal(w *bytes.Buffer, b *Builder) error {
}

bli := bpfLineInfo{
uint32(li.offset),
uint32(li.Offset),
fileNameOff,
lineOff,
(line.lineNumber << bpfLineShift) | line.lineColumn,
Expand Down
184 changes: 156 additions & 28 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,40 @@ type programStats struct {
recursionMisses uint64
}

// programJitedInfo holds information about JITed info of a program.
type programJitedInfo struct {
// ksyms holds the ksym addresses of the BPF program, including those of its
// subprograms.
//
// Available from 4.18.
ksyms []uintptr
numKsyms uint32

// insns holds the JITed machine native instructions of the program,
// including those of its subprograms.
//
// Available from 4.13.
insns []byte
numInsns uint32

// lineInfos holds the JITed line infos, which are kernel addresses.
//
// Available from 5.0.
lineInfos []uint64
numLineInfos uint32

// lineInfoRecSize is the size of a single line info record.
//
// Available from 5.0.
lineInfoRecSize uint32

// funcLens holds the insns length of each function.
//
// Available from 4.18.
funcLens []uint32
numFuncLens uint32
}

// ProgramInfo describes a program.
type ProgramInfo struct {
Type ProgramType
Expand All @@ -199,12 +233,12 @@ type ProgramInfo struct {
jitedSize uint32
verifiedInstructions uint32

jitedInfo programJitedInfo

lineInfos []byte
numLineInfos uint32
funcInfos []byte
numFuncInfos uint32
ksymInfos []uint64
numKsymInfos uint32
}

func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
Expand Down Expand Up @@ -282,11 +316,37 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
makeSecondCall = true
}

pi.jitedInfo.lineInfoRecSize = info.JitedLineInfoRecSize
if info.JitedProgLen > 0 {
pi.jitedInfo.numInsns = info.JitedProgLen
pi.jitedInfo.insns = make([]byte, info.JitedProgLen)
info2.JitedProgLen = info.JitedProgLen
info2.JitedProgInsns = sys.NewSlicePointer(pi.jitedInfo.insns)
makeSecondCall = true
}

if info.NrJitedFuncLens > 0 {
pi.jitedInfo.numFuncLens = info.NrJitedFuncLens
pi.jitedInfo.funcLens = make([]uint32, info.NrJitedFuncLens)
info2.NrJitedFuncLens = info.NrJitedFuncLens
info2.JitedFuncLens = sys.NewSlicePointer(pi.jitedInfo.funcLens)
makeSecondCall = true
}

if info.NrJitedLineInfo > 0 {
pi.jitedInfo.numLineInfos = info.NrJitedLineInfo
pi.jitedInfo.lineInfos = make([]uint64, info.NrJitedLineInfo)
info2.NrJitedLineInfo = info.NrJitedLineInfo
info2.JitedLineInfo = sys.NewSlicePointer(pi.jitedInfo.lineInfos)
info2.JitedLineInfoRecSize = info.JitedLineInfoRecSize
makeSecondCall = true
}

if info.NrJitedKsyms > 0 {
pi.ksymInfos = make([]uint64, info.NrJitedKsyms)
info2.JitedKsyms = sys.NewSlicePointer(pi.ksymInfos)
pi.jitedInfo.numKsyms = info.NrJitedKsyms
pi.jitedInfo.ksyms = make([]uintptr, info.NrJitedKsyms)
info2.JitedKsyms = sys.NewSlicePointer(pi.jitedInfo.ksyms)
info2.NrJitedKsyms = info.NrJitedKsyms
pi.numKsymInfos = info.NrJitedKsyms
makeSecondCall = true
}

Expand Down Expand Up @@ -380,6 +440,55 @@ func (pi *ProgramInfo) RecursionMisses() (uint64, bool) {
return 0, false
}

// withBTFSpec calls the provided callback with the BTF spec of the program.
//
// The base argument is used to resolve type IDs in the prog's BTF spec.
func (pi *ProgramInfo) withBTFSpec(base *btf.Spec, cb func(*btf.Spec) error) error {
id, ok := pi.BTFID()
if !ok {
return fmt.Errorf("program created without BTF or unsupported kernel: %w", ErrNotSupported)
}

h, err := btf.NewHandleFromID(id)
if err != nil {
return fmt.Errorf("get BTF handle: %w", err)
}
defer h.Close()

spec, err := h.Spec(base)
if err != nil {
return fmt.Errorf("get BTF spec: %w", err)
}

return cb(spec)
}

// LineInfos returns the BTF line information of the program.
//
// Requires CAP_SYS_ADMIN or equivalent for reading BTF information. Returns
// ErrNotSupported if the program was created without BTF or if the kernel
// doesn't support the field.
func (pi *ProgramInfo) LineInfos() (btf.LineInfos, error) {
var li btf.LineInfos
var err error

if len(pi.lineInfos) == 0 {
return li, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
}

err = pi.withBTFSpec(nil, func(spec *btf.Spec) error {
li, err = btf.LoadLineInfos(
bytes.NewReader(pi.lineInfos),
internal.NativeEndian,
pi.numLineInfos,
spec,
)
return err
})

return li, err
}

// Instructions returns the 'xlated' instruction stream of the program
// after it has been verified and rewritten by the kernel. These instructions
// cannot be loaded back into the kernel as-is, this is mainly used for
Expand Down Expand Up @@ -524,11 +633,34 @@ func (pi *ProgramInfo) VerifiedInstructions() (uint32, bool) {
//
// The bool return value indicates whether this optional field is available.
func (pi *ProgramInfo) KsymAddrs() ([]uintptr, bool) {
addrs := make([]uintptr, 0, len(pi.ksymInfos))
for _, addr := range pi.ksymInfos {
addrs = append(addrs, uintptr(addr))
}
return addrs, pi.numKsymInfos > 0
return pi.jitedInfo.ksyms, len(pi.jitedInfo.ksyms) > 0
}

// JitedInsns returns the JITed machine native instructions of the program.
//
// Available from 4.13.
//
// The bool return value indicates whether this optional field is available.
func (pi *ProgramInfo) JitedInsns() ([]byte, bool) {
return pi.jitedInfo.insns, len(pi.jitedInfo.insns) > 0
}

// JitedLineInfos returns the JITed line infos of the program.
//
// Available from 5.0.
//
// The bool return value indicates whether this optional field is available.
func (pi *ProgramInfo) JitedLineInfos() ([]uint64, bool) {
return pi.jitedInfo.lineInfos, len(pi.jitedInfo.lineInfos) > 0
}

// JitedFuncLens returns the insns length of each function in the JITed program.
//
// Available from 4.18.
//
// The bool return value indicates whether this optional field is available.
func (pi *ProgramInfo) JitedFuncLens() ([]uint32, bool) {
return pi.jitedInfo.funcLens, len(pi.jitedInfo.funcLens) > 0
}

// FuncInfos returns the offset and function information of all (sub)programs in
Expand All @@ -540,28 +672,24 @@ func (pi *ProgramInfo) KsymAddrs() ([]uintptr, bool) {
// ErrNotSupported if the program was created without BTF or if the kernel
// doesn't support the field.
func (pi *ProgramInfo) FuncInfos() (btf.FuncOffsets, error) {
id, ok := pi.BTFID()
if pi.numFuncInfos == 0 || !ok {
return nil, fmt.Errorf("program created without BTF or unsupported kernel: %w", ErrNotSupported)
}
var funcs btf.FuncOffsets
var err error

h, err := btf.NewHandleFromID(id)
if err != nil {
return nil, fmt.Errorf("get BTF handle: %w", err)
if len(pi.funcInfos) == 0 {
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
}
defer h.Close()

spec, err := h.Spec(nil)
if err != nil {
return nil, fmt.Errorf("get BTF spec: %w", err)
}
err = pi.withBTFSpec(nil, func(spec *btf.Spec) error {
funcs, err = btf.LoadFuncInfos(
bytes.NewReader(pi.funcInfos),
internal.NativeEndian,
pi.numFuncInfos,
spec,
)
return err
})

return btf.LoadFuncInfos(
bytes.NewReader(pi.funcInfos),
internal.NativeEndian,
pi.numFuncInfos,
spec,
)
return funcs, err
}

func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
Expand Down
3 changes: 3 additions & 0 deletions internal/cmd/gentypes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,13 @@ import (
"ProgInfo", "bpf_prog_info",
[]patch{
replace(objName, "name"),
replace(pointer, "jited_prog_insns"),
replace(pointer, "xlated_prog_insns"),
replace(pointer, "map_ids"),
replace(pointer, "line_info"),
replace(pointer, "jited_line_info"),
replace(pointer, "jited_ksyms"),
replace(pointer, "jited_func_lens"),
replace(pointer, "func_info"),
replace(btfID, "btf_id", "attach_btf_obj_id"),
replace(typeID, "attach_btf_id"),
Expand Down
6 changes: 3 additions & 3 deletions internal/sys/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ type ProgInfo struct {
Tag [8]uint8
JitedProgLen uint32
XlatedProgLen uint32
JitedProgInsns uint64
JitedProgInsns Pointer
XlatedProgInsns Pointer
LoadTime uint64
CreatedByUid uint32
Expand All @@ -734,14 +734,14 @@ type ProgInfo struct {
NrJitedKsyms uint32
NrJitedFuncLens uint32
JitedKsyms Pointer
JitedFuncLens uint64
JitedFuncLens Pointer
BtfId BTFID
FuncInfoRecSize uint32
FuncInfo Pointer
NrFuncInfo uint32
NrLineInfo uint32
LineInfo Pointer
JitedLineInfo uint64
JitedLineInfo Pointer
NrJitedLineInfo uint32
LineInfoRecSize uint32
JitedLineInfoRecSize uint32
Expand Down
Loading