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

Allow changing line info data in btf.Line #1413

Closed
MarcusWichelmann opened this issue Apr 2, 2024 · 11 comments · Fixed by #1417
Closed

Allow changing line info data in btf.Line #1413

MarcusWichelmann opened this issue Apr 2, 2024 · 11 comments · Fixed by #1417
Labels
enhancement New feature or request

Comments

@MarcusWichelmann
Copy link
Contributor

MarcusWichelmann commented Apr 2, 2024

Describe the bug

I'd like to change the line field in the btf.Line structure for a single instruction of a program, but cannot find a way to do that.

Background

I'm templating an eBPF program by replacing a placeholder function in its instructions with some custom instructions. Then I use WithMetadata() (see #832) to copy over the metadata of the first placeholder instruction (that has the symbol) to the new one.

This works fine, but I'd like to also change the BTF line info for the first instruction to contain some information about the inserted logic so it can be recognized in an instruction dump / verifier log.

I could use .WithSource(asm.Comment("ABC")) for that, but this causes a missing bpf_line_info for 1 funcs starting from func#1 verifier error, because the line info seems to go missing then.

What I probably need to do is, to retrieve the existing bpf.Line structure using .Source().(*btf.Line) and change its fields, but these are unexported, so there doesn't seem to be a way to do that.

I'd like to discuss what would be the preferred solution here, before I make a pull request.

How to reproduce

Load an eBPF program and call this on the first instruction of a function (the one with the symbol):

insns[i] = insns[i].WithMetadata(insn.Metadata).WithSource(asm.Comment("ABC"))

Then try to load the program and check the verifier error.

Version information

github.com/cilium/ebpf v0.14.0

@MarcusWichelmann MarcusWichelmann added the bug Something isn't working label Apr 2, 2024
@lmb
Copy link
Collaborator

lmb commented Apr 2, 2024

I'm using the same functionality in the library for https://github.com/cilium/ebpf/pull/1402/commits I think we could just export the fields in Line as you suggested. cc @dylandreimerink

@lmb lmb added enhancement New feature or request and removed bug Something isn't working labels Apr 2, 2024
@dylandreimerink
Copy link
Member

dylandreimerink commented Apr 2, 2024

Yes. I think that would be alright. There isn't any guarding of values needed, so just exposing fields should be safe.

Are you thinking of just exposing Line or the rest of the fields as well? (seem odd otherwise)

Edit: We do have some restrictions imposed on us, namely maximums for the line size and column (since column only gets 10 bits when encoded). So we might want to consider using Setter methods instead of exported fields

@MarcusWichelmann
Copy link
Contributor Author

MarcusWichelmann commented Apr 2, 2024

Wow, you're fast.

@dylandreimerink Yeah would probably make sense to export all of them then. Add setters for all of them?

Should I make a PR?

@dylandreimerink
Copy link
Member

Just realized I missed something, see the edited message. We basically have a choice between exporting the fields which might cause marshaling errors when used incorrectly or add some input validation on the btf.Line object.

@MarcusWichelmann
Copy link
Contributor Author

What would be your preferred solution? Are there other ways how invalid values can get into that structure which would make a validation before marshalling necessary instead of just checking in the setters? Or where would you put that validation?

@MarcusWichelmann
Copy link
Contributor Author

MarcusWichelmann commented Apr 2, 2024

Also there seems to be some validation already:

ebpf/btf/ext_info.go

Lines 594 to 600 in a330a78

if line.lineNumber > bpfLineMax {
return fmt.Errorf("line %d exceeds %d", line.lineNumber, bpfLineMax)
}
if line.lineColumn > bpfColumnMax {
return fmt.Errorf("column %d exceeds %d", line.lineColumn, bpfColumnMax)
}

Isn't that sufficient?

@dylandreimerink
Copy link
Member

Isn't that sufficient?

Its a matter of preference and perhaps UX to some extent. The current types for the fields don't indicate there are any limits. So in the case of just exporting, someone may come along, have some code that modifies a field. It would be very possible that this wouldn't blow up until some day the code changes, field becomes to long, and then you get an error at a completely unrelated location (marshaling). That would be a pain in the ass to debug. While, if we have an erroneous setter, which fails on bad input, you place the error message closer to the source of it. At the cost of having validation logic in multiple locations and forcing the user to do additional error checking.

I can argue it both ways, so I will let @lmb get his say in first 😄 .

@lmb
Copy link
Collaborator

lmb commented Apr 2, 2024

Do you care about line, column and file at all? The only thing that the verifier currently renders is the line, all the other bits can stay zero. We could consider just exporting Line.Line. As an alternative, we could turn any Source that is a Stringer into a Line:

if stringer, ok := ins.Source().(fmt.Stringer); ok {
   // synthesise line info with line 0, col 0, etc.
}

P.S. That would imply that Comment are emitted into the verifier log.

@MarcusWichelmann
Copy link
Contributor Author

MarcusWichelmann commented Apr 2, 2024

As an alternative, we could turn any Source that is a Stringer into a Line.

That would also work. All I want is adding a comment string to the line that is also visible in the verifier log / instruction dump. The file/line/column information of the placeholder that was replaced isn't that interesting in my case, anyway, so it could just be zero.

@MarcusWichelmann
Copy link
Contributor Author

@lmb So we'll go that route? I'll submit a PR for that tomorrow.

@lmb
Copy link
Collaborator

lmb commented Apr 3, 2024

@MarcusWichelmann SGTM.

MarcusWichelmann added a commit to MarcusWichelmann/ebpf that referenced this issue Apr 3, 2024
When an asm.Comment is added to an instruction, existing source
information like btf.Line will be replaced. But in some cases,
instructions without line information won't pass the verifier. The
expected behavior would be, that the comment gets synthesized into a
line info where everything but the line string is zero. This commit
implements this.

Fixes cilium#1413

Signed-off-by: Marcus Wichelmann <mail@marcusw.de>
MarcusWichelmann added a commit to MarcusWichelmann/ebpf that referenced this issue Apr 5, 2024
When an asm.Comment is added to an instruction, existing source
information like btf.Line will be replaced. But in some cases,
instructions without line information won't pass the verifier. The
expected behavior would be, that the comment gets synthesized into a
line info where everything but the line string is zero. This commit
implements this.

Fixes cilium#1413

Signed-off-by: Marcus Wichelmann <mail@marcusw.de>
lmb pushed a commit that referenced this issue Apr 8, 2024
When an asm.Comment is added to an instruction, existing source
information like btf.Line will be replaced. But in some cases,
instructions without line information won't pass the verifier. The
expected behavior would be, that the comment gets synthesized into a
line info where everything but the line string is zero. This commit
implements this.

Fixes #1413

Signed-off-by: Marcus Wichelmann <mail@marcusw.de>
@lmb lmb closed this as completed in #1417 Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants