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

Add Maps to Instruction metadata #567

Merged
merged 1 commit into from
Mar 8, 2022

Conversation

dylandreimerink
Copy link
Member

This PR improves the existing per-instruction metadata, as discussed in #564 and fixes #515.

This PR moves the existing Instruction.Reference and Instruction.Symbol metadata to a separate struct called metadata. asm.Instruction now has a pointer to this metadata struct. The Instruction struct now has exported getters and setters to get and modify this metadata. The design is such that we only assign metadata to instructions if we have to, since most instructions don't have metadata.

Copying instructions will not automatically copy the metadata since Instruction has a pointer to metadata. Therefor the setters will perform a copy-on-write, so upon the first modification of metadata, the instruction will get a new metadata object which is copied from the existing one and then modified.

These setters all have value receivers which return the modified instruction. This choice was made because it makes it easier to use the setters in the DSL, since you can't call functions with pointer receivers on literals. By returning a modified instruction we make method chaining possible, which fits well with the rest of the DSL.

We also added Filename, Line and LineCol to the metadata and getters and setters for them to Instruction. The ELF reader was modified to add looked-up LineInfo from the .BTF.ext section to the program instructions. This allows us to print the original source code info along with the program instructions when formatting asm.Instructions.

By attaching this info the the instruction makes it relocation-proof. In future PRs we might even be able to marshal blobs to be loaded into the kernel so would guarantee correct BTF line info for relocated programs and BTF line info for programs created via the DSL.

Lastly, this PR adds map references to the per-instruction metadata. This allows us to add references to ebpf.Map to the program instructions themselves, specifically during rewriting, which prevents the maps from being garbage collected, thus fixing #515

Copy link
Collaborator

@lmb lmb left a comment

Choose a reason for hiding this comment

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

Hi Dylan,

Thanks for the PR! I started the review yesterday, but only managed to finish it today.

  • Can you explain what the kernel uses the various bits of information for? I know that SetLine ends up in the verifier log, but what about File, Line, Column?
  • How does the library use this information? Seems like we ignore File, Line, Column?
  • Is it possible to only pass e.g. Line, but leave other bits empty?

Regarding the metadata, I'd prefer if the setters modified the instruction instead of making a copy, so pointer receivers. Behind the scenes metadata would still be copied. Intuitively I expect a setter to make changes to the object I'm calling it on. Calling the setters also becomes awkward judging from the changes in the PRs.

I also saw that you merged master into your feature branch, maybe that was an accident? Doing that makes merges much messier, please rebase instead.

@dylandreimerink
Copy link
Member Author

Can you explain what the kernel uses the various bits of information for? I know that SetLine ends up in the verifier log, but what about File, Line, Column?

As far as I know, the kernel doesn't use any of the .BTF.ext data(LineInfos and FuncInfos) itself, as far as I can tell from the initial commit the main goal was to add source code references for in the verifier as well as when reading the xlated and jitted instructions back from the kernel.

How does the library use this information? Seems like we ignore File, Line, Column?

I used the Line to add to Instructions.Format which now has a output similar to bpftool and llvm when outputting instructions with lineinfo.

The Filename and Column information isn't currently used by the library directly. My motivation for adding is was to use them outside of the library in edb where I use the information to display the relevant source file and place the cursor at the correct line within that file.

Is it possible to only pass e.g. Line, but leave other bits empty?

Yea it should be. If we were to create a LineInfo object from the metadata we can leave the LineCol and FileNameOff at 0. Which I believe are valid values, since the line and column can both be zero and a offset of 0 within the strings table will just result in an empty string. I think the most important part is to not have duplicate InsnOff values within the same function, which should not be an issue.

@dylandreimerink
Copy link
Member Author

Got almost everything. The only thing left is to make btf.LineInfo a fmt.Stringer, which we can do as soon as #572 has been merged. I can rebase and update WIP: asm: Replaced seperate getters/setters with Context once that is done.

Copy link
Collaborator

@ti-mo ti-mo left a comment

Choose a reason for hiding this comment

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

Went through it in detail, great work! This has been on our minds for a few months now and will open some exciting new possibilities.

@lmb
Copy link
Collaborator

lmb commented Mar 4, 2022

@dylandreimerink can you add a Fixes #515 to the commit with map metadata?

Copy link
Collaborator

@ti-mo ti-mo left a comment

Choose a reason for hiding this comment

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

Have a few last comments. Looks like the commit title and message of asm,elf_reader: added instruction context is now outdated.

As discussed offline, let's only merge the Map support here, the .BTF.ext unmarshaler needs a few changes since we're processing LineInfos per section again.

@ti-mo ti-mo force-pushed the feature/asm-metadata branch from 9aa26fe to fa83acc Compare March 8, 2022 15:24
This commit adds the ability to add a Map pointer to an Instruction.
The main reason for doing so is to maintain a reference to a Map while it is
being referred to from a ProgramSpec.

Before, loading an ELF referring to a pinned map caused the map to be opened
and its fd to be included in Instructions. If garbage collection ran between
loading the ELF and inserting the program into the kernel, the map's fd may
have been closed before the program can be inserted.

Resolving Maps into FDs and embedding them into an Instruction has been moved
to Instructions.Marshal().

Associating a Map with an Instruction happens with the new `AssociateMap()`,
replacing the now-deprecated `RewriteMapPtr()`.

Fixes cilium#515
@ti-mo ti-mo force-pushed the feature/asm-metadata branch from fa83acc to 9ef93aa Compare March 8, 2022 17:01
@ti-mo
Copy link
Collaborator

ti-mo commented Mar 8, 2022

The LineInfo metadata was split off from this PR as this one already touched several subtle interactions regarding maps between the loader, linker and marshaler. This one is good to go for now.

@ti-mo ti-mo merged commit ee79822 into cilium:master Mar 8, 2022
@ti-mo ti-mo changed the title Add add sparse per-instruction metadata Add Maps to Instruction metadata Mar 8, 2022
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.

Map file descriptor is closed after RewriteMaps
3 participants