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

WIP: Add support for attaching uprobes and uretprobes to offsets #1419

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

rafaelroquetto
Copy link
Contributor

@rafaelroquetto rafaelroquetto commented Nov 28, 2024

In its core, this PR adds support for attaching ebf programs to (start and return) offsets, in the same fashion done for "goprobes". The motivation is also the same: uretprobes attachments can be unreliable in contexts where the target process stack changes. In such scenarios, attaching uretprobes may cause the target process to crash.

Under the hood, we scan the target binary for the offsets of the symbols we want to attach to: the start offset, and the offset of every RET instruction present in that function. This approach is not flawless, and will fail if the the function/symbol in question does not posses any RET instruction due to compiler optimisations (see here for an example).

Due to the requirement of handling uprobe offsets, codewise the handling of uprobes and goprobes becomes less distinct. The ultimate goal would be to merge their corresponding code and remove considerable code duplication. A central piece for this is the repurposing of ebpfcommon.FuncPrograms into a more comprehensive data structure that carries the entire context (relevant to our use cases) of ebpf attachments: apart from the start and end programs, it now features the symbol name and the offsets. This also enables us to ditch a few maps that were being used for this purpose, and simplifies the code considerably.

TODO

  • Unit tests for the new uprobe attachment code
  • rename ebpfcommon.FunctionPrograms to a more appropriate term
  • minimise the use of the "probe" jargon everywhere and collapse/delete a few data structures that can be replaced with ebpfcommon.FunctionPrograms
  • merge the attachment parts of GoProbes and UProbes in instrumenter.go

@rafaelroquetto rafaelroquetto added the do-not-merge WIP or something that musn't be merged label Nov 28, 2024
Copy link

codecov bot commented Nov 28, 2024

Codecov Report

Attention: Patch coverage is 76.82119% with 70 lines in your changes missing coverage. Please review.

Project coverage is 80.84%. Comparing base (4174fa5) to head (bf7c80d).

Files with missing lines Patch % Lines
pkg/internal/ebpf/instrumenter.go 70.70% 31 Missing and 15 partials ⚠️
pkg/internal/ebpf/generictracer/generictracer.go 87.64% 7 Missing and 4 partials ⚠️
pkg/internal/goexec/instructions.go 58.33% 3 Missing and 2 partials ⚠️
pkg/internal/ebpf/httptracer/httptracer.go 57.14% 3 Missing ⚠️
pkg/internal/ebpf/tctracer/tctracer.go 57.14% 3 Missing ⚠️
pkg/internal/ebpf/gotracer/gotracer.go 80.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1419      +/-   ##
==========================================
+ Coverage   72.44%   80.84%   +8.39%     
==========================================
  Files         145      146       +1     
  Lines       14916    15045     +129     
==========================================
+ Hits        10806    12163    +1357     
+ Misses       3395     2282    -1113     
+ Partials      715      600     -115     
Flag Coverage Δ
integration-test 59.10% <71.19%> (+0.06%) ⬆️
k8s-integration-test 60.12% <75.82%> (+0.03%) ⬆️
oats-test 34.21% <66.55%> (+0.29%) ⬆️
unittests 51.15% <0.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@grcevski grcevski left a comment

Choose a reason for hiding this comment

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

LGTM! Very cool refactor and so nice to see we use the same mechanism now for Go and non-Go.

return nil
}

func (p *Tracer) UProbes() map[string]map[string]ebpfcommon.FunctionPrograms {
return map[string]map[string]ebpfcommon.FunctionPrograms{
func (p *Tracer) UProbes() map[string]map[string][]*ebpfcommon.ProbeDesc {
Copy link
Contributor

Choose a reason for hiding this comment

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

OK, cool, so this was somewhere I thought we needed to go, having an array of probes on a single function when we need to deal with recompilation. Is this why you allow for this now, or there's another reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually the reason was to normalise the code between GoProbes() and UProbes() - now they both return maps whose values are map[string][]*ebpfcommon.ProbeDesc, which enables the code to handle them to be generic in instrumenter.go (in particular, the instrumentProbes() function).

@@ -357,64 +419,44 @@ func (p *Tracer) SockMsgs() []ebpfcommon.SockMsg { return nil }

func (p *Tracer) SockOps() []ebpfcommon.SockOps { return nil }

func (p *Tracer) RecordInstrumentedLib(id uint64) {
func (p *Tracer) RecordInstrumentedLib(id uint64, closers []io.Closer) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, I really like these splits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do-not-merge WIP or something that musn't be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants