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

Trace external pointers through maps #1285

Merged
merged 2 commits into from
Oct 27, 2017

Conversation

pchaigno
Copy link
Contributor

@pchaigno pchaigno commented Aug 6, 2017

The bcc rewriter currently traces external pointers using
ProbeVisitor in order to replace dereferences with calls to
bpf_probe_read. It is, however, unable to trace them through maps.

This pull request fixes this for simple (yet common) cases. Through a
first traversal of the Clang AST, MapVisitor looks for calls to
update (and insert) to find maps with an external pointer as value.
When ProbeVisitor runs, in a second time, it looks for calls to
lookup (and lookup_or_init). If the map was registered as having an
external pointer as value, the l-value of the lookup assignment is
marked as being an external pointer.

Two traversals of the Clang AST are needed because the update of a
map may happen after the lookup in the AST. Therefore, the first
traversal makes sure we inspect all updates before acting on lookups.
To implement this two-stage traversal without parsing the AST twice,
ProbeConsumer and BTypeConsumer now implement
HandleTranslationUnit, which is called after a whole translation
unit has been parsed.

This change should probably be considered a breaking API change. In
bcc, it breaks a few tools that were relying on the rewriter not
being able to replace dereferences. For instance, the
bpf_probe_read(&saddr, sizeof(saddr), &skp->__sk_common.skc_rcv_saddr)
expression in examples/tracing/tcpv4connect.py now returns an error.

Fixes #253.

/cc @drzaeus77

@pchaigno pchaigno force-pushed the track-external-pointers-maps branch 4 times, most recently from 294a0e9 to 91ccf40 Compare August 6, 2017 14:11
@drzaeus77 drzaeus77 self-requested a review August 11, 2017 16:15
@brendangregg
Copy link
Member

Looks like a good improvement.

Copy link
Collaborator

@yonghong-song yonghong-song left a comment

Choose a reason for hiding this comment

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

Thanks for fixing this. Definitely positive for user programs. A few comments are inlined with the codes.

}
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not fully understand why we need to track map.update or map.insert here?
It is totally possible that map.update and map.insert not in the same compilation unit, e.g., populated by user space or shared with another bpf program. Then we will not able to trace map value pointers below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Where would you track map.update and map.insert if not here?

Yes, if the updates/inserts are not in the same compilation unit, we can't trace map value pointers. I don't think there's much we can do in that case, at least without hints from developers.

return true;

if (memb_name == "lookup" || memb_name == "lookup_or_init") {
if (m_.find(Ref->getDecl()) != m_.end()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again not sure whether we need this m_ check or not. What if we do not check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The m_ check makes sure the map has an external pointer as value. AFAIK, the only way to know that is to track them from the function arguments (what's already implemented) to the map.inserts/updates, remember that, and use it when we meet the map.lookups (what this pull request implements).

@@ -773,7 +852,8 @@ void BFrontendAction::EndSourceFileAction() {
unique_ptr<ASTConsumer> BFrontendAction::CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile) {
rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts());
vector<unique_ptr<ASTConsumer>> consumers;
consumers.push_back(unique_ptr<ASTConsumer>(new ProbeConsumer(Compiler.getASTContext(), *rewriter_)));
consumers.push_back(unique_ptr<ASTConsumer>(new MapConsumer(m_)));
consumers.push_back(unique_ptr<ASTConsumer>(new ProbeConsumer(Compiler.getASTContext(), *rewriter_, m_)));
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we use handleTranslationUnit to post process ProbeConsumer and BTypeConsumer, I am wondering whether we need ProbeConsumer and BTypeConsumer registered as the BFrontendAction consumer. We can do post process at MapConsumer handleTranslationUnit?

Note that this implementation changes how each construct is processed by ProbeConsumer and BTypeConsumer. The old implementation will call the processing function for each consumer for each construct at a time before moving to the next construct. The new implementation will process all constructs for one consumer before moving to the next consumer.

Look at the ProbeConsumer and BTypeConsumer code, they are largely independent so it should be okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we use handleTranslationUnit to post process ProbeConsumer and BTypeConsumer, I am wondering whether we need ProbeConsumer and BTypeConsumer registered as the BFrontendAction consumer. We can do post process at MapConsumer handleTranslationUnit?

So we'd have a single Consumer for all visitors? Sure 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in the last commit.

@pchaigno
Copy link
Contributor Author

@yonghong-song Thanks for the review and sorry for the delay to answer.

@pchaigno pchaigno force-pushed the track-external-pointers-maps branch from 91ccf40 to 114a5ee Compare September 16, 2017 18:15
@pchaigno pchaigno force-pushed the track-external-pointers-maps branch from 114a5ee to 3c75763 Compare October 14, 2017 12:20
@4ast
Copy link
Member

4ast commented Oct 26, 2017

Looks great. Probably needs rebase before merge?

The bcc rewriter currently traces external pointers using
ProbeVisitor in order to replace dereferences with calls to
bpf_probe_read. It is, however, unable to trace them through maps.

This commit remedy this for simple (yet common) cases. Through a
first traversal of the Clang AST, MapVisitor looks for calls to
update (and insert) to find maps with an external pointer as value.
When ProbeVisitor runs, in a second time, it looks for calls to
lookup (and lookup_or_init). If the map was registered as having an
external pointer as value, the l-value of the lookup assignment is
marked as being an external pointer.

Two traversals of the Clang AST are needed because the update of a
map may happen after the lookup in the AST. Therefore, the first
traversal makes sure we inspect all updates before acting on lookups.
To implement this two-stage traversal without parsing the AST twice,
ProbeConsumer and BTypeConsumer now implement HandleTranslationUnit,
which is called after a whole translation unit has been parsed.
@pchaigno pchaigno force-pushed the track-external-pointers-maps branch from 3c75763 to 55cf837 Compare October 26, 2017 06:49
@pchaigno
Copy link
Contributor Author

pchaigno commented Oct 26, 2017

Probably needs rebase before merge?

@4ast Done (with a new commit to address @yonghong-song's comment above).

@pchaigno pchaigno force-pushed the track-external-pointers-maps branch from 55cf837 to e67cb56 Compare October 26, 2017 09:47
Copy link
Collaborator

@yonghong-song yonghong-song left a comment

Choose a reason for hiding this comment

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

LGTM

@yonghong-song yonghong-song merged commit 6e45749 into iovisor:master Oct 27, 2017
@pchaigno pchaigno deleted the track-external-pointers-maps branch October 27, 2017 16:35
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.

invalid mem access when navigating struct sock
4 participants