Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bpftrace
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
bpftrace
Commits
6e4ff5a0
Commit
6e4ff5a0
authored
Sep 26, 2018
by
Brendan Gregg
Committed by
GitHub
Sep 26, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #113 from iovisor/tp-format-parser
Tracepoint format parser
parents
8422e64b
a0fab2e1
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
301 additions
and
3 deletions
+301
-3
src/CMakeLists.txt
src/CMakeLists.txt
+1
-0
src/ast/codegen_llvm.cpp
src/ast/codegen_llvm.cpp
+4
-0
src/ast/semantic_analyser.cpp
src/ast/semantic_analyser.cpp
+21
-0
src/clang_parser.cpp
src/clang_parser.cpp
+6
-0
src/clang_parser.h
src/clang_parser.h
+0
-1
src/lexer.l
src/lexer.l
+1
-1
src/main.cpp
src/main.cpp
+4
-1
src/tracepoint_format_parser.cpp
src/tracepoint_format_parser.cpp
+143
-0
src/tracepoint_format_parser.h
src/tracepoint_format_parser.h
+23
-0
tests/CMakeLists.txt
tests/CMakeLists.txt
+2
-0
tests/parser.cpp
tests/parser.cpp
+1
-0
tests/semantic_analyser.cpp
tests/semantic_analyser.cpp
+1
-0
tests/tracepoint_format_parser.cpp
tests/tracepoint_format_parser.cpp
+94
-0
No files found.
src/CMakeLists.txt
View file @
6e4ff5a0
...
...
@@ -8,6 +8,7 @@ add_executable(bpftrace
map.cpp
mapkey.cpp
printf.cpp
tracepoint_format_parser.cpp
types.cpp
list.cpp
)
...
...
src/ast/codegen_llvm.cpp
View file @
6e4ff5a0
...
...
@@ -121,6 +121,10 @@ void CodegenLLVM::visit(Builtin &builtin)
name_id
++
;
expr_
=
b_
.
getInt64
(
builtin
.
name_id
);
}
else
if
(
builtin
.
ident
==
"args"
)
{
expr_
=
ctx_
;
}
else
if
(
builtin
.
ident
==
"ctx"
)
{
// undocumented builtin: for debugging
...
...
src/ast/semantic_analyser.cpp
View file @
6e4ff5a0
...
...
@@ -3,6 +3,7 @@
#include "fake_map.h"
#include "parser.tab.hh"
#include "printf.h"
#include "tracepoint_format_parser.h"
#include "arch/arch.h"
#include <sys/stat.h>
#include <regex>
...
...
@@ -67,6 +68,12 @@ void SemanticAnalyser::visit(Builtin &builtin)
}
else
if
(
!
builtin
.
ident
.
compare
(
0
,
3
,
"arg"
)
&&
builtin
.
ident
.
size
()
==
4
&&
builtin
.
ident
.
at
(
3
)
>=
'0'
&&
builtin
.
ident
.
at
(
3
)
<=
'9'
)
{
for
(
auto
&
attach_point
:
*
probe_
->
attach_points
)
{
ProbeType
type
=
probetype
(
attach_point
->
provider
);
if
(
type
==
ProbeType
::
tracepoint
)
err_
<<
"The "
<<
builtin
.
ident
<<
" builtin can not be used with tracepoint probes"
<<
std
::
endl
;
}
int
arg_num
=
atoi
(
builtin
.
ident
.
substr
(
3
).
c_str
());
if
(
arg_num
>
arch
::
max_arg
())
err_
<<
arch
::
name
()
<<
" doesn't support "
<<
builtin
.
ident
<<
std
::
endl
;
...
...
@@ -79,6 +86,20 @@ void SemanticAnalyser::visit(Builtin &builtin)
else
if
(
builtin
.
ident
==
"username"
)
{
builtin
.
type
=
SizedType
(
Type
::
username
,
8
);
}
else
if
(
builtin
.
ident
==
"args"
)
{
if
(
probe_
->
attach_points
->
size
()
>
1
)
err_
<<
"The args builtin only works for probes with 1 attach point"
<<
std
::
endl
;
auto
&
attach_point
=
probe_
->
attach_points
->
at
(
0
);
ProbeType
type
=
probetype
(
attach_point
->
provider
);
if
(
type
!=
ProbeType
::
tracepoint
)
err_
<<
"The args builtin can only be used with tracepoint probes"
<<
"("
<<
attach_point
->
provider
<<
" used here)"
<<
std
::
endl
;
std
::
string
tracepoint_struct
=
TracepointFormatParser
::
get_struct_name
(
attach_point
->
target
,
attach_point
->
func
);
Struct
&
cstruct
=
bpftrace_
.
structs_
[
tracepoint_struct
];
builtin
.
type
=
SizedType
(
Type
::
cast
,
cstruct
.
size
,
tracepoint_struct
);
builtin
.
type
.
is_pointer
=
true
;
}
else
{
builtin
.
type
=
SizedType
(
Type
::
none
,
0
);
err_
<<
"Unknown builtin variable: '"
<<
builtin
.
ident
<<
"'"
<<
std
::
endl
;
...
...
src/clang_parser.cpp
View file @
6e4ff5a0
#include <clang-c/Index.h>
#include <iostream>
#include <string.h>
#include <sys/utsname.h>
#include "ast.h"
#include "bpftrace.h"
...
...
@@ -142,10 +143,15 @@ void ClangParser::parse(ast::Program *program, StructMap &structs)
},
};
struct
utsname
utsname
;
uname
(
&
utsname
);
std
::
string
kernel_header_include_flag
=
std
::
string
(
"/lib/modules/"
)
+
utsname
.
release
+
"/build/include"
;
CXIndex
index
=
clang_createIndex
(
1
,
1
);
CXTranslationUnit
translation_unit
;
const
char
*
const
args
[]
=
{
"-I"
,
"/bpftrace/include"
,
"-I"
,
kernel_header_include_flag
.
c_str
(),
};
CXErrorCode
error
=
clang_parseTranslationUnit2
(
index
,
...
...
src/clang_parser.h
View file @
6e4ff5a0
...
...
@@ -5,7 +5,6 @@
namespace
bpftrace
{
namespace
ast
{
class
Program
;
}
class
BPFtrace
;
using
StructMap
=
std
::
map
<
std
::
string
,
Struct
>
;
...
...
src/lexer.l
View file @
6e4ff5a0
...
...
@@ -48,7 +48,7 @@ path :(\\.|[_\-\./a-zA-Z0-9])*:
<COMMENT>"*/" BEGIN(INITIAL);
<COMMENT>"EOF" driver.error(loc, std::string("end of file during comment"));
pid|tid|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|name|curtask|rand|ctx|username {
pid|tid|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|name|curtask|rand|ctx|username
|args
{
return Parser::make_BUILTIN(yytext, loc); }
{path} { return Parser::make_PATH(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); }
...
...
src/main.cpp
View file @
6e4ff5a0
...
...
@@ -6,9 +6,10 @@
#include "clang_parser.h"
#include "codegen_llvm.h"
#include "driver.h"
#include "list.h"
#include "printer.h"
#include "semantic_analyser.h"
#include "
list
.h"
#include "
tracepoint_format_parser
.h"
using
namespace
bpftrace
;
...
...
@@ -130,6 +131,8 @@ int main(int argc, char *argv[])
if
(
pid_str
)
bpftrace
.
pid_
=
atoi
(
pid_str
);
TracepointFormatParser
::
parse
(
driver
.
root_
);
if
(
bt_debug
!=
DebugLevel
::
kNone
)
{
ast
::
Printer
p
(
std
::
cout
);
...
...
src/tracepoint_format_parser.cpp
0 → 100644
View file @
6e4ff5a0
#include <fstream>
#include <iostream>
#include <string.h>
#include "ast.h"
#include "struct.h"
#include "tracepoint_format_parser.h"
namespace
bpftrace
{
void
TracepointFormatParser
::
parse
(
ast
::
Program
*
program
)
{
bool
has_tracepoint_probes
=
false
;
for
(
ast
::
Probe
*
probe
:
*
program
->
probes
)
for
(
ast
::
AttachPoint
*
ap
:
*
probe
->
attach_points
)
if
(
ap
->
provider
==
"tracepoint"
)
has_tracepoint_probes
=
true
;
if
(
!
has_tracepoint_probes
)
return
;
program
->
c_definitions
+=
"#include <linux/types.h>
\n
"
;
for
(
ast
::
Probe
*
probe
:
*
program
->
probes
)
{
for
(
ast
::
AttachPoint
*
ap
:
*
probe
->
attach_points
)
{
if
(
ap
->
provider
==
"tracepoint"
)
{
std
::
string
&
category
=
ap
->
target
;
std
::
string
&
event_name
=
ap
->
func
;
std
::
string
format_file_path
=
"/sys/kernel/debug/tracing/events/"
+
category
+
"/"
+
event_name
+
"/format"
;
std
::
ifstream
format_file
(
format_file_path
.
c_str
());
if
(
format_file
.
fail
())
{
std
::
cerr
<<
strerror
(
errno
)
<<
": "
<<
format_file_path
<<
std
::
endl
;
return
;
}
program
->
c_definitions
+=
get_tracepoint_struct
(
format_file
,
category
,
event_name
);
}
}
}
}
std
::
string
TracepointFormatParser
::
get_struct_name
(
const
std
::
string
&
category
,
const
std
::
string
&
event_name
)
{
return
"_tracepoint_"
+
category
+
"_"
+
event_name
;
}
std
::
string
TracepointFormatParser
::
parse_field
(
const
std
::
string
&
line
)
{
auto
field_pos
=
line
.
find
(
"field:"
);
if
(
field_pos
==
std
::
string
::
npos
)
return
""
;
auto
field_semi_pos
=
line
.
find
(
';'
,
field_pos
);
if
(
field_semi_pos
==
std
::
string
::
npos
)
return
""
;
auto
offset_pos
=
line
.
find
(
"offset:"
,
field_semi_pos
);
if
(
offset_pos
==
std
::
string
::
npos
)
return
""
;
auto
offset_semi_pos
=
line
.
find
(
';'
,
offset_pos
);
if
(
offset_semi_pos
==
std
::
string
::
npos
)
return
""
;
auto
size_pos
=
line
.
find
(
"size:"
,
offset_semi_pos
);
if
(
size_pos
==
std
::
string
::
npos
)
return
""
;
auto
size_semi_pos
=
line
.
find
(
';'
,
size_pos
);
if
(
size_semi_pos
==
std
::
string
::
npos
)
return
""
;
int
size
=
std
::
stoi
(
line
.
substr
(
size_pos
+
5
,
size_semi_pos
-
size_pos
-
5
));
std
::
string
field
=
line
.
substr
(
field_pos
+
6
,
field_semi_pos
-
field_pos
-
6
);
auto
field_type_end_pos
=
field
.
find_last_of
(
"
\t
"
);
if
(
field_type_end_pos
==
std
::
string
::
npos
)
return
""
;
std
::
string
field_type
=
field
.
substr
(
0
,
field_type_end_pos
);
std
::
string
field_name
=
field
.
substr
(
field_type_end_pos
+
1
);
if
(
field_type
.
find
(
"__data_loc"
)
!=
std
::
string
::
npos
)
{
field_type
=
"int"
;
field_name
=
"data_loc_"
+
field_name
;
}
// Only adjust field types for non-arrays
if
(
field_name
.
find
(
"["
)
==
std
::
string
::
npos
)
field_type
=
adjust_integer_types
(
field_type
,
size
);
return
" "
+
field_type
+
" "
+
field_name
+
";
\n
"
;
}
std
::
string
TracepointFormatParser
::
adjust_integer_types
(
const
std
::
string
&
field_type
,
int
size
)
{
std
::
string
new_type
=
field_type
;
// Adjust integer fields to correctly sized types
if
(
size
==
2
)
{
if
(
new_type
==
"char"
||
new_type
==
"int8_t"
)
new_type
=
"s16"
;
if
(
new_type
==
"unsigned char"
||
new_type
==
"uint8_t"
)
new_type
=
"u16"
;
}
else
if
(
size
==
4
)
{
if
(
new_type
==
"char"
||
new_type
==
"short"
||
new_type
==
"int8_t"
||
new_type
==
"int16_t"
)
new_type
=
"s32"
;
if
(
new_type
==
"unsigned char"
||
new_type
==
"unsigned short"
||
new_type
==
"uint8_t"
||
new_type
==
"uint16_t"
)
new_type
=
"u32"
;
}
else
if
(
size
==
8
)
{
if
(
new_type
==
"char"
||
new_type
==
"short"
||
new_type
==
"int"
||
new_type
==
"int8_t"
||
new_type
==
"int16_t"
||
new_type
==
"int32_t"
)
new_type
=
"s64"
;
if
(
new_type
==
"unsigned char"
||
new_type
==
"unsigned short"
||
new_type
==
"unsigned int"
||
new_type
==
"uint8_t"
||
new_type
==
"uint16_t"
||
new_type
==
"uint32_t"
)
new_type
=
"u64"
;
}
return
new_type
;
}
std
::
string
TracepointFormatParser
::
get_tracepoint_struct
(
std
::
istream
&
format_file
,
const
std
::
string
&
category
,
const
std
::
string
&
event_name
)
{
std
::
string
format_struct
=
"struct "
+
get_struct_name
(
category
,
event_name
)
+
"
\n
{
\n
"
;
for
(
std
::
string
line
;
getline
(
format_file
,
line
);
)
{
format_struct
+=
parse_field
(
line
);
}
format_struct
+=
"};
\n
"
;
return
format_struct
;
}
}
// namespace bpftrace
src/tracepoint_format_parser.h
0 → 100644
View file @
6e4ff5a0
#pragma once
#include <istream>
namespace
bpftrace
{
namespace
ast
{
class
Program
;
}
class
TracepointFormatParser
{
public:
static
void
parse
(
ast
::
Program
*
program
);
static
std
::
string
get_struct_name
(
const
std
::
string
&
category
,
const
std
::
string
&
event_name
);
private:
static
std
::
string
parse_field
(
const
std
::
string
&
line
);
static
std
::
string
adjust_integer_types
(
const
std
::
string
&
field_type
,
int
size
);
protected:
static
std
::
string
get_tracepoint_struct
(
std
::
istream
&
format_file
,
const
std
::
string
&
category
,
const
std
::
string
&
event_name
);
};
}
// namespace bpftrace
tests/CMakeLists.txt
View file @
6e4ff5a0
...
...
@@ -10,6 +10,7 @@ add_executable(bpftrace_test
main.cpp
parser.cpp
semantic_analyser.cpp
tracepoint_format_parser.cpp
utils.cpp
${
CMAKE_SOURCE_DIR
}
/src/attached_probe.cpp
${
CMAKE_SOURCE_DIR
}
/src/bpftrace.cpp
...
...
@@ -19,6 +20,7 @@ add_executable(bpftrace_test
${
CMAKE_SOURCE_DIR
}
/src/map.cpp
${
CMAKE_SOURCE_DIR
}
/src/mapkey.cpp
${
CMAKE_SOURCE_DIR
}
/src/printf.cpp
${
CMAKE_SOURCE_DIR
}
/src/tracepoint_format_parser.cpp
${
CMAKE_SOURCE_DIR
}
/src/types.cpp
)
...
...
tests/parser.cpp
View file @
6e4ff5a0
...
...
@@ -40,6 +40,7 @@ TEST(Parser, builtin_variables)
test
(
"kprobe:f { retval }"
,
"Program
\n
kprobe:f
\n
builtin: retval
\n
"
);
test
(
"kprobe:f { func }"
,
"Program
\n
kprobe:f
\n
builtin: func
\n
"
);
test
(
"kprobe:f { name }"
,
"Program
\n
kprobe:f
\n
builtin: name
\n
"
);
test
(
"kprobe:f { args }"
,
"Program
\n
kprobe:f
\n
builtin: args
\n
"
);
}
TEST
(
Parser
,
map_assign
)
...
...
tests/semantic_analyser.cpp
View file @
6e4ff5a0
...
...
@@ -63,6 +63,7 @@ TEST(semantic_analyser, builtin_variables)
test
(
"kprobe:f { retval }"
,
0
);
test
(
"kprobe:f { func }"
,
0
);
test
(
"kprobe:f { name }"
,
0
);
test
(
"tracepoint:a:b { args }"
,
0
);
// test("kprobe:f { fake }", 1);
}
...
...
tests/tracepoint_format_parser.cpp
0 → 100644
View file @
6e4ff5a0
#include "gtest/gtest.h"
#include "tracepoint_format_parser.h"
namespace
bpftrace
{
namespace
test
{
namespace
tracepoint_format_parser
{
class
MockTracepointFormatParser
:
public
TracepointFormatParser
{
public:
static
std
::
string
get_tracepoint_struct_public
(
std
::
istream
&
format_file
,
const
std
::
string
&
category
,
const
std
::
string
&
event_name
)
{
return
get_tracepoint_struct
(
format_file
,
category
,
event_name
);
}
};
TEST
(
tracepoint_format_parser
,
tracepoint_struct
)
{
std
::
string
input
=
"name: sys_enter_read
\n
"
"ID: 650
\n
"
"format:
\n
"
" field:unsigned short common_type; offset:0; size:2; signed:0;
\n
"
" field:unsigned char common_flags; offset:2; size:1; signed:0;
\n
"
" field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
\n
"
" field:int common_pid; offset:4; size:4; signed:1;
\n
"
"
\n
"
" field:int __syscall_nr; offset:8; size:4; signed:1;
\n
"
" field:unsigned int fd; offset:16; size:8; signed:0;
\n
"
" field:char * buf; offset:24; size:8; signed:0;
\n
"
" field:size_t count; offset:32; size:8; signed:0;
\n
"
"
\n
"
"print fmt:
\"
fd: 0x%08lx, buf: 0x%08lx, count: 0x%08lx
\"
, ((unsigned long)(REC->fd)), ((unsigned long)(REC->buf)), ((unsigned long)(REC->count))
\n
"
;
std
::
string
expected
=
"struct _tracepoint_syscalls_sys_enter_read
\n
"
"{
\n
"
" unsigned short common_type;
\n
"
" unsigned char common_flags;
\n
"
" unsigned char common_preempt_count;
\n
"
" int common_pid;
\n
"
" int __syscall_nr;
\n
"
" u64 fd;
\n
"
" char * buf;
\n
"
" size_t count;
\n
"
"};
\n
"
;
std
::
istringstream
format_file
(
input
);
std
::
string
result
=
MockTracepointFormatParser
::
get_tracepoint_struct_public
(
format_file
,
"syscalls"
,
"sys_enter_read"
);
EXPECT_EQ
(
expected
,
result
);
}
TEST
(
tracepoint_format_parser
,
array
)
{
std
::
string
input
=
" field:char char_array[8]; offset:0; size:8; signed:1;
\n
"
" field:int int_array[2]; offset:8; size:8; signed:1;
\n
"
;
std
::
string
expected
=
"struct _tracepoint_syscalls_sys_enter_read
\n
"
"{
\n
"
" char char_array[8];
\n
"
" int int_array[2];
\n
"
"};
\n
"
;
std
::
istringstream
format_file
(
input
);
std
::
string
result
=
MockTracepointFormatParser
::
get_tracepoint_struct_public
(
format_file
,
"syscalls"
,
"sys_enter_read"
);
EXPECT_EQ
(
expected
,
result
);
}
TEST
(
tracepoint_format_parser
,
data_loc
)
{
std
::
string
input
=
" field:__data_loc char[] msg; offset:8; size:4; signed:1;"
;
std
::
string
expected
=
"struct _tracepoint_syscalls_sys_enter_read
\n
"
"{
\n
"
" int data_loc_msg;
\n
"
"};
\n
"
;
std
::
istringstream
format_file
(
input
);
std
::
string
result
=
MockTracepointFormatParser
::
get_tracepoint_struct_public
(
format_file
,
"syscalls"
,
"sys_enter_read"
);
EXPECT_EQ
(
expected
,
result
);
}
}
// namespace tracepoint_format_parser
}
// namespace test
}
// namespace bpftrace
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment