forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request iovisor#602 from goldshtn/auto-tp
Full tracepoint support in Clang front-end
- Loading branch information
Showing
8 changed files
with
335 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* Copyright (c) 2016 Sasha Goldshtein | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
#include <linux/bpf.h> | ||
#include <linux/version.h> | ||
#include <sys/utsname.h> | ||
#include <unistd.h> | ||
|
||
#include <fstream> | ||
#include <regex> | ||
|
||
#include <clang/AST/ASTConsumer.h> | ||
#include <clang/AST/ASTContext.h> | ||
#include <clang/AST/RecordLayout.h> | ||
#include <clang/Frontend/CompilerInstance.h> | ||
#include <clang/Frontend/MultiplexConsumer.h> | ||
#include <clang/Rewrite/Core/Rewriter.h> | ||
|
||
#include "tp_frontend_action.h" | ||
|
||
namespace ebpf { | ||
|
||
using std::map; | ||
using std::set; | ||
using std::string; | ||
using std::to_string; | ||
using std::unique_ptr; | ||
using std::vector; | ||
using std::regex; | ||
using std::smatch; | ||
using std::regex_search; | ||
using std::ifstream; | ||
using namespace clang; | ||
|
||
TracepointTypeVisitor::TracepointTypeVisitor(ASTContext &C, Rewriter &rewriter) | ||
: C(C), diag_(C.getDiagnostics()), rewriter_(rewriter), out_(llvm::errs()) { | ||
} | ||
|
||
static inline bool _is_valid_field(string const& line, | ||
string& field_type, | ||
string& field_name) { | ||
auto field_pos = line.find("field:"); | ||
if (field_pos == string::npos) | ||
return false; | ||
|
||
auto semi_pos = line.find(';', field_pos); | ||
if (semi_pos == string::npos) | ||
return false; | ||
|
||
auto size_pos = line.find("size:", semi_pos); | ||
if (size_pos == string::npos) | ||
return false; | ||
|
||
auto field = line.substr(field_pos + 6/*"field:"*/, | ||
semi_pos - field_pos - 6); | ||
auto pos = field.find_last_of("\t "); | ||
if (pos == string::npos) | ||
return false; | ||
|
||
field_type = field.substr(0, pos); | ||
field_name = field.substr(pos + 1); | ||
if (field_type.find("__data_loc") != string::npos) | ||
return false; | ||
if (field_name.find("common_") == 0) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
string TracepointTypeVisitor::GenerateTracepointStruct( | ||
SourceLocation loc, string const& category, string const& event) { | ||
string format_file = "/sys/kernel/debug/tracing/events/" + | ||
category + "/" + event + "/format"; | ||
ifstream input(format_file.c_str()); | ||
if (!input) | ||
return ""; | ||
|
||
string tp_struct = "struct tracepoint__" + category + "__" + event + " {\n"; | ||
tp_struct += "\tu64 __do_not_use__;\n"; | ||
for (string line; getline(input, line); ) { | ||
string field_type, field_name; | ||
if (!_is_valid_field(line, field_type, field_name)) | ||
continue; | ||
tp_struct += "\t" + field_type + " " + field_name + ";\n"; | ||
} | ||
|
||
tp_struct += "};\n"; | ||
return tp_struct; | ||
} | ||
|
||
static inline bool _is_tracepoint_struct_type(string const& type_name, | ||
string& tp_category, | ||
string& tp_event) { | ||
// We are looking to roughly match the regex: | ||
// (?:struct|class)\s+tracepoint__(\S+)__(\S+) | ||
// Not using std::regex because older versions of GCC don't support it yet. | ||
// E.g., the libstdc++ that ships with Ubuntu 14.04. | ||
|
||
auto first_space_pos = type_name.find_first_of("\t "); | ||
if (first_space_pos == string::npos) | ||
return false; | ||
auto first_tok = type_name.substr(0, first_space_pos); | ||
if (first_tok != "struct" && first_tok != "class") | ||
return false; | ||
|
||
auto non_space_pos = type_name.find_first_not_of("\t ", first_space_pos); | ||
auto second_space_pos = type_name.find_first_of("\t ", non_space_pos); | ||
auto second_tok = type_name.substr(non_space_pos, | ||
second_space_pos - non_space_pos); | ||
if (second_tok.find("tracepoint__") != 0) | ||
return false; | ||
|
||
auto tp_event_pos = second_tok.rfind("__"); | ||
if (tp_event_pos == string::npos) | ||
return false; | ||
tp_event = second_tok.substr(tp_event_pos + 2); | ||
|
||
auto tp_category_pos = second_tok.find("__"); | ||
if (tp_category_pos == tp_event_pos) | ||
return false; | ||
tp_category = second_tok.substr(tp_category_pos + 2, | ||
tp_event_pos - tp_category_pos - 2); | ||
return true; | ||
} | ||
|
||
|
||
bool TracepointTypeVisitor::VisitFunctionDecl(FunctionDecl *D) { | ||
if (D->isExternallyVisible() && D->hasBody()) { | ||
// If this function has a tracepoint structure as an argument, | ||
// add that structure declaration based on the structure name. | ||
for (auto it = D->param_begin(); it != D->param_end(); ++it) { | ||
auto arg = *it; | ||
auto type = arg->getType(); | ||
if (type->isPointerType() && | ||
type->getPointeeType()->isStructureOrClassType()) { | ||
auto type_name = QualType::getAsString(type.split()); | ||
string tp_cat, tp_evt; | ||
if (_is_tracepoint_struct_type(type_name, tp_cat, tp_evt)) { | ||
string tp_struct = GenerateTracepointStruct( | ||
D->getLocStart(), tp_cat, tp_evt); | ||
// Get the actual function declaration point (the macro instantiation | ||
// point if using the TRACEPOINT_PROBE macro instead of the macro | ||
// declaration point in bpf_helpers.h). | ||
auto insert_loc = D->getLocStart(); | ||
insert_loc = rewriter_.getSourceMgr().getFileLoc(insert_loc); | ||
rewriter_.InsertText(insert_loc, tp_struct); | ||
} | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
TracepointTypeConsumer::TracepointTypeConsumer(ASTContext &C, Rewriter &rewriter) | ||
: visitor_(C, rewriter) { | ||
} | ||
|
||
bool TracepointTypeConsumer::HandleTopLevelDecl(DeclGroupRef Group) { | ||
for (auto D : Group) | ||
visitor_.TraverseDecl(D); | ||
return true; | ||
} | ||
|
||
TracepointFrontendAction::TracepointFrontendAction(llvm::raw_ostream &os) | ||
: os_(os), rewriter_(new Rewriter) { | ||
} | ||
|
||
void TracepointFrontendAction::EndSourceFileAction() { | ||
rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_); | ||
os_.flush(); | ||
} | ||
|
||
unique_ptr<ASTConsumer> TracepointFrontendAction::CreateASTConsumer( | ||
CompilerInstance &Compiler, llvm::StringRef InFile) { | ||
rewriter_->setSourceMgr(Compiler.getSourceManager(), Compiler.getLangOpts()); | ||
return unique_ptr<ASTConsumer>(new TracepointTypeConsumer( | ||
Compiler.getASTContext(), *rewriter_)); | ||
} | ||
|
||
} |
Oops, something went wrong.