Skip to content

Commit

Permalink
Factor out ebpf::parse_tracepoint function
Browse files Browse the repository at this point in the history
And moving it to common.cc in order to be able to make
automated tests for it. Following patches are adding
automated test for this function and it seems too much
to link in all the clang/llvm stuff to the test binary
just for single function test.

Adding ebpf::parse_tracepoint that takes istream of the
tracepoint format data and returns tracepoint struct
as std::string.

No functional change is intended or expected.

Signed-off-by: Jiri Olsa <[email protected]>
  • Loading branch information
olsajiri authored and yonghong-song committed Mar 15, 2020
1 parent cd43be4 commit 7fd2fa6
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 104 deletions.
107 changes: 107 additions & 0 deletions src/cc/common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,111 @@ std::string get_pid_exe(pid_t pid) {
return std::string(exe_path);
}

enum class field_kind_t {
common,
data_loc,
regular,
invalid
};

static inline field_kind_t _get_field_kind(std::string const& line,
std::string& field_type,
std::string& field_name) {
auto field_pos = line.find("field:");
if (field_pos == std::string::npos)
return field_kind_t::invalid;

auto field_semi_pos = line.find(';', field_pos);
if (field_semi_pos == std::string::npos)
return field_kind_t::invalid;

auto offset_pos = line.find("offset:", field_semi_pos);
if (offset_pos == std::string::npos)
return field_kind_t::invalid;

auto semi_pos = line.find(';', offset_pos);
if (semi_pos == std::string::npos)
return field_kind_t::invalid;

auto size_pos = line.find("size:", semi_pos);
if (size_pos == std::string::npos)
return field_kind_t::invalid;

semi_pos = line.find(';', size_pos);
if (semi_pos == std::string::npos)
return field_kind_t::invalid;

auto size_str = line.substr(size_pos + 5,
semi_pos - size_pos - 5);
int size = std::stoi(size_str, nullptr);

auto field = line.substr(field_pos + 6/*"field:"*/,
field_semi_pos - field_pos - 6);
auto pos = field.find_last_of("\t ");
if (pos == std::string::npos)
return field_kind_t::invalid;

field_type = field.substr(0, pos);
field_name = field.substr(pos + 1);
if (field_type.find("__data_loc") != std::string::npos)
return field_kind_t::data_loc;
if (field_name.find("common_") == 0)
return field_kind_t::common;
// do not change type definition for array
if (field_name.find("[") != std::string::npos)
return field_kind_t::regular;

// adjust the field_type based on the size of field
// otherwise, incorrect value may be retrieved for big endian
// and the field may have incorrect structure offset.
if (size == 2) {
if (field_type == "char" || field_type == "int8_t")
field_type = "s16";
if (field_type == "unsigned char" || field_type == "uint8_t")
field_type = "u16";
} else if (size == 4) {
if (field_type == "char" || field_type == "short" ||
field_type == "int8_t" || field_type == "int16_t")
field_type = "s32";
if (field_type == "unsigned char" || field_type == "unsigned short" ||
field_type == "uint8_t" || field_type == "uint16_t")
field_type = "u32";
} else if (size == 8) {
if (field_type == "char" || field_type == "short" || field_type == "int" ||
field_type == "int8_t" || field_type == "int16_t" ||
field_type == "int32_t" || field_type == "pid_t")
field_type = "s64";
if (field_type == "unsigned char" || field_type == "unsigned short" ||
field_type == "unsigned int" || field_type == "uint8_t" ||
field_type == "uint16_t" || field_type == "uint32_t" ||
field_type == "unsigned" || field_type == "u32" ||
field_type == "uid_t" || field_type == "gid_t")
field_type = "u64";
}

return field_kind_t::regular;
}

std::string parse_tracepoint(std::istream &input, std::string const& category,
std::string const& event) {
std::string tp_struct = "struct tracepoint__" + category + "__" + event + " {\n";
tp_struct += "\tu64 __do_not_use__;\n";
for (std::string line; getline(input, line); ) {
std::string field_type, field_name;
switch (_get_field_kind(line, field_type, field_name)) {
case field_kind_t::invalid:
case field_kind_t::common:
continue;
case field_kind_t::data_loc:
tp_struct += "\tint data_loc_" + field_name + ";\n";
break;
case field_kind_t::regular:
tp_struct += "\t" + field_type + " " + field_name + ";\n";
break;
}
}

tp_struct += "};\n";
return tp_struct;
}
} // namespace ebpf
2 changes: 2 additions & 0 deletions src/cc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ std::vector<int> get_possible_cpus();

std::string get_pid_exe(pid_t pid);

std::string parse_tracepoint(std::istream &input, std::string const& category,
std::string const& event);
} // namespace ebpf
107 changes: 3 additions & 104 deletions src/cc/frontends/clang/tp_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "frontend_action_common.h"
#include "tp_frontend_action.h"
#include "common.h"

namespace ebpf {

Expand All @@ -42,98 +43,14 @@ using std::vector;
using std::regex;
using std::smatch;
using std::regex_search;
using std::istream;
using std::ifstream;
using namespace clang;

TracepointTypeVisitor::TracepointTypeVisitor(ASTContext &C, Rewriter &rewriter)
: diag_(C.getDiagnostics()), rewriter_(rewriter), out_(llvm::errs()) {
}

enum class field_kind_t {
common,
data_loc,
regular,
invalid
};

static inline field_kind_t _get_field_kind(string const& line,
string& field_type,
string& field_name) {
auto field_pos = line.find("field:");
if (field_pos == string::npos)
return field_kind_t::invalid;

auto field_semi_pos = line.find(';', field_pos);
if (field_semi_pos == string::npos)
return field_kind_t::invalid;

auto offset_pos = line.find("offset:", field_semi_pos);
if (offset_pos == string::npos)
return field_kind_t::invalid;

auto semi_pos = line.find(';', offset_pos);
if (semi_pos == string::npos)
return field_kind_t::invalid;

auto size_pos = line.find("size:", semi_pos);
if (size_pos == string::npos)
return field_kind_t::invalid;

semi_pos = line.find(';', size_pos);
if (semi_pos == string::npos)
return field_kind_t::invalid;

auto size_str = line.substr(size_pos + 5,
semi_pos - size_pos - 5);
int size = std::stoi(size_str, nullptr);

auto field = line.substr(field_pos + 6/*"field:"*/,
field_semi_pos - field_pos - 6);
auto pos = field.find_last_of("\t ");
if (pos == string::npos)
return field_kind_t::invalid;

field_type = field.substr(0, pos);
field_name = field.substr(pos + 1);
if (field_type.find("__data_loc") != string::npos)
return field_kind_t::data_loc;
if (field_name.find("common_") == 0)
return field_kind_t::common;
// do not change type definition for array
if (field_name.find("[") != string::npos)
return field_kind_t::regular;

// adjust the field_type based on the size of field
// otherwise, incorrect value may be retrieved for big endian
// and the field may have incorrect structure offset.
if (size == 2) {
if (field_type == "char" || field_type == "int8_t")
field_type = "s16";
if (field_type == "unsigned char" || field_type == "uint8_t")
field_type = "u16";
} else if (size == 4) {
if (field_type == "char" || field_type == "short" ||
field_type == "int8_t" || field_type == "int16_t")
field_type = "s32";
if (field_type == "unsigned char" || field_type == "unsigned short" ||
field_type == "uint8_t" || field_type == "uint16_t")
field_type = "u32";
} else if (size == 8) {
if (field_type == "char" || field_type == "short" || field_type == "int" ||
field_type == "int8_t" || field_type == "int16_t" ||
field_type == "int32_t" || field_type == "pid_t")
field_type = "s64";
if (field_type == "unsigned char" || field_type == "unsigned short" ||
field_type == "unsigned int" || field_type == "uint8_t" ||
field_type == "uint16_t" || field_type == "uint32_t" ||
field_type == "unsigned" || field_type == "u32" ||
field_type == "uid_t" || field_type == "gid_t")
field_type = "u64";
}

return field_kind_t::regular;
}

string TracepointTypeVisitor::GenerateTracepointStruct(
SourceLocation loc, string const& category, string const& event) {
string format_file = "/sys/kernel/debug/tracing/events/" +
Expand All @@ -142,25 +59,7 @@ string TracepointTypeVisitor::GenerateTracepointStruct(
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;
switch (_get_field_kind(line, field_type, field_name)) {
case field_kind_t::invalid:
case field_kind_t::common:
continue;
case field_kind_t::data_loc:
tp_struct += "\tint data_loc_" + field_name + ";\n";
break;
case field_kind_t::regular:
tp_struct += "\t" + field_type + " " + field_name + ";\n";
break;
}
}

tp_struct += "};\n";
return tp_struct;
return ebpf::parse_tracepoint(input, category, event);
}

static inline bool _is_tracepoint_struct_type(string const& type_name,
Expand Down

0 comments on commit 7fd2fa6

Please sign in to comment.