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

Conversation

Asphaltt
Copy link
Contributor

@Asphaltt Asphaltt commented Oct 24, 2024

For pwru cilium/pwru#451, I'm going to inspect some inner details of bpf progs with LBR. But it requires the JITed info of bpf prog.

Then, expose more prog jited info:

  1. JITed machine native instructions torvalds/linux@1e2709769086 ("bpf: Add BPF_OBJ_GET_INFO_BY_FD")
  2. JITed line info torvalds/linux@c454a46b5efd ("bpf: Add bpf_line_info support")
  3. JITed image lengths torvalds/linux@815581c11cc2 ("bpf: get JITed image lengths of functions via syscall")

@Asphaltt Asphaltt requested review from dylandreimerink and a team as code owners October 24, 2024 12:20
info.go Outdated
Comment on lines 446 to 491
// 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 pi.numFuncInfos == 0 || !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.
func (pi *ProgramInfo) LineInfos() (btf.LineInfos, error) {
var li btf.LineInfos

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

return li, err
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this can be explained better in the docs, but line info is currently already available via the instruction metadata.

insns, err := pi.Instructions()
if err != nil {
  return err
}

iter := insns.Iterate()
for iter.Next() {
  src := iter.Ins.Source()
  if src == nil {
    continue
   }
   
   if line, ok := src.(*btf.Line); ok {
     // Use *btf.Line
   }
 }

So there should be no need for the line info on its own without the instructions to make sense of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line info is used for jited_line_info.

The jited_line_info is the address of the corresponding jited insn. Then, when decode the jited_prog_insns with jited_ksyms, it is able to get the BTF line info for the decoding insn by jited_ksym + relative pc, which equals to jited_line_info.

As a result, it is able to decode jited insns like bpftool prog dump jited PROG.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Furthermore, with such BTF line info for jited_prog_insns, it is able to reflect a bpf prog address, which is captured by LBR, to line info if the address is a jited_line_info.

info.go Outdated Show resolved Hide resolved
info.go Outdated
Comment on lines 197 to 205
// LineInfos holds the JITed line infos, which are kernel addresses.
//
// Available from 5.0.
LineInfos []uint64

// LineInfoRecSize is the size of a single line info record.
//
// Available from 5.0.
LineInfoRecSize uint32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are already parsing the bytes to uint64, so it doesn't really make sense to also expose LineInfoRecSize. Its 8 or the API is broken, so it seems that should be something internal.

On that note, wouldn't it be better if the LineInfo were a struct or interface which can be expanded if the kernel ever decides to change things up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it doesn't really make sense to also expose LineInfoRecSize.

No problem. Let us hide this info, as it is set as 8 bytes in kernel set_info_rec_size():

info->jited_line_info_rec_size = sizeof(__u64);

wouldn't it be better if the LineInfo were a struct or interface which can be expanded if the kernel ever decides to change things up?

No. jited_line_info is the kernel address for its corresponding jited insn. And it is aligned to uint64 in kernel struct bpf_prog_info:

struct bpf_prog_info {
	__aligned_u64 jited_line_info;
}

And in the foreseeable future, its type won't be changed.

Expose these prog jited info:

1. JITed machine native instructions torvalds/linux@1e2709769086 ("bpf: Add BPF_OBJ_GET_INFO_BY_FD")
2. JITed line info torvalds/linux@c454a46b5efd ("bpf: Add bpf_line_info support")
3. JITed image lengths torvalds/linux@815581c11cc2 ("bpf: get JITed image lengths of functions via syscall")

Signed-off-by: Leon Hwang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants