Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bcc
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
bcc
Commits
335cbe4f
Commit
335cbe4f
authored
Nov 23, 2016
by
Teng Qin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Basic BCC C++ API
parent
1c89ff5d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
826 additions
and
3 deletions
+826
-3
src/cc/BPF.cc
src/cc/BPF.cc
+397
-0
src/cc/BPF.h
src/cc/BPF.h
+151
-0
src/cc/BPFTable.cc
src/cc/BPFTable.cc
+135
-0
src/cc/BPFTable.h
src/cc/BPFTable.h
+140
-0
src/cc/CMakeLists.txt
src/cc/CMakeLists.txt
+3
-3
No files found.
src/cc/BPF.cc
0 → 100644
View file @
335cbe4f
/*
* Copyright (c) 2016 Facebook, Inc.
*
* 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
*
* http://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 <unistd.h>
#include <cstdio>
#include <exception>
#include <iostream>
#include <memory>
#include <sstream>
#include <vector>
#include "bcc_syms.h"
#include "bpf_module.h"
#include "common.h"
#include "exception.h"
#include "libbpf.h"
#include "perf_reader.h"
#include "BPF.h"
namespace
ebpf
{
std
::
string
uint_to_hex
(
uint64_t
value
)
{
std
::
stringstream
ss
;
ss
<<
std
::
hex
<<
value
;
return
ss
.
str
();
}
std
::
string
sanitize_str
(
std
::
string
str
,
bool
(
*
validator
)(
char
),
char
replacement
=
'_'
)
{
for
(
size_t
i
=
0
;
i
<
str
.
length
();
i
++
)
if
(
!
validator
(
str
[
i
]))
str
[
i
]
=
replacement
;
return
str
;
}
StatusTuple
BPF
::
init
(
const
std
::
string
&
bpf_program
,
std
::
vector
<
std
::
string
>
cflags
)
{
auto
flags_len
=
cflags
.
size
();
const
char
*
flags
[
flags_len
];
for
(
size_t
i
=
0
;
i
<
flags_len
;
i
++
)
flags
[
i
]
=
cflags
[
i
].
c_str
();
if
(
bpf_module_
->
load_string
(
bpf_program
,
flags
,
flags_len
)
!=
0
)
return
mkstatus
(
-
1
,
"Unable to initialize BPF program"
);
return
mkstatus
(
0
);
};
BPF
::~
BPF
()
{
auto
res
=
detach_all
();
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
std
::
cerr
<<
"Failed to detach all probes on destruction: "
<<
std
::
endl
<<
std
::
get
<
1
>
(
res
)
<<
std
::
endl
;
}
StatusTuple
BPF
::
detach_all
()
{
bool
has_error
=
false
;
std
::
string
error_msg
;
for
(
auto
it
:
kprobes_
)
{
auto
res
=
detach_kprobe_event
(
it
.
first
,
it
.
second
);
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
{
error_msg
+=
"Failed to detach kprobe event "
+
it
.
first
+
": "
;
error_msg
+=
std
::
get
<
1
>
(
res
)
+
"
\n
"
;
has_error
=
true
;
}
}
for
(
auto
it
:
uprobes_
)
{
auto
res
=
detach_uprobe_event
(
it
.
first
,
it
.
second
);
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
{
error_msg
+=
"Failed to detach uprobe event "
+
it
.
first
+
": "
;
error_msg
+=
std
::
get
<
1
>
(
res
)
+
"
\n
"
;
has_error
=
true
;
}
}
for
(
auto
it
:
tracepoints_
)
{
auto
res
=
detach_tracepoint_event
(
it
.
first
,
it
.
second
);
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
{
error_msg
+=
"Failed to detach Tracepoint "
+
it
.
first
+
": "
;
error_msg
+=
std
::
get
<
1
>
(
res
)
+
"
\n
"
;
has_error
=
true
;
}
}
for
(
auto
it
:
perf_buffers_
)
{
auto
res
=
it
.
second
->
close
();
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
{
error_msg
+=
"Failed to close perf buffer "
+
it
.
first
+
": "
;
error_msg
+=
std
::
get
<
1
>
(
res
)
+
"
\n
"
;
has_error
=
true
;
}
delete
it
.
second
;
}
if
(
has_error
)
return
mkstatus
(
-
1
,
error_msg
);
else
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
attach_kprobe
(
const
std
::
string
&
kernel_func
,
const
std
::
string
&
probe_func
,
bpf_attach_type
attach_type
,
pid_t
pid
,
int
cpu
,
int
group_fd
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_KPROBE
,
probe_fd
));
std
::
string
probe_event
=
get_kprobe_event
(
kernel_func
,
attach_type
);
if
(
kprobes_
.
find
(
probe_event
)
!=
kprobes_
.
end
())
{
TRY2
(
unload_func
(
probe_func
));
return
mkstatus
(
-
1
,
"kprobe %s already attached"
,
probe_event
.
c_str
());
}
std
::
string
probe_event_desc
=
attach_type_prefix
(
attach_type
);
probe_event_desc
+=
":kprobes/"
+
probe_event
+
" "
+
kernel_func
;
void
*
res
=
bpf_attach_kprobe
(
probe_fd
,
probe_event
.
c_str
(),
probe_event_desc
.
c_str
(),
pid
,
cpu
,
group_fd
,
cb
,
cb_cookie
);
if
(
!
res
)
{
TRY2
(
unload_func
(
probe_func
));
return
mkstatus
(
-
1
,
"Unable to attach %skprobe for %s using %s"
,
attach_type_debug
(
attach_type
).
c_str
(),
kernel_func
.
c_str
(),
probe_func
.
c_str
());
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
func
=
probe_func
;
kprobes_
[
probe_event
]
=
std
::
move
(
p
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
attach_uprobe
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
const
std
::
string
&
probe_func
,
uint64_t
symbol_addr
,
bpf_attach_type
attach_type
,
pid_t
pid
,
int
cpu
,
int
group_fd
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_KPROBE
,
probe_fd
));
bcc_symbol
sym
=
bcc_symbol
();
TRY2
(
check_binary_symbol
(
binary_path
,
symbol
,
symbol_addr
,
&
sym
));
std
::
string
probe_event
=
get_uprobe_event
(
sym
.
module
,
sym
.
offset
,
attach_type
);
if
(
uprobes_
.
find
(
probe_event
)
!=
uprobes_
.
end
())
{
TRY2
(
unload_func
(
probe_func
));
return
mkstatus
(
-
1
,
"uprobe %s already attached"
,
probe_event
.
c_str
());
}
std
::
string
probe_event_desc
=
attach_type_prefix
(
attach_type
);
probe_event_desc
+=
":uprobes/"
+
probe_event
+
" "
;
probe_event_desc
+=
binary_path
+
":0x"
+
uint_to_hex
(
sym
.
offset
);
void
*
res
=
bpf_attach_uprobe
(
probe_fd
,
probe_event
.
c_str
(),
probe_event_desc
.
c_str
(),
pid
,
cpu
,
group_fd
,
cb
,
cb_cookie
);
if
(
!
res
)
{
TRY2
(
unload_func
(
probe_func
));
return
mkstatus
(
-
1
,
"Unable to attach %suprobe for binary %s symbol %s addr %lx using %s
\n
"
,
attach_type_debug
(
attach_type
).
c_str
(),
binary_path
.
c_str
(),
symbol
.
c_str
(),
symbol_addr
,
probe_func
.
c_str
());
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
func
=
probe_func
;
uprobes_
[
probe_event
]
=
std
::
move
(
p
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
attach_tracepoint
(
const
std
::
string
&
tracepoint
,
const
std
::
string
&
probe_func
,
pid_t
pid
,
int
cpu
,
int
group_fd
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_TRACEPOINT
,
probe_fd
));
if
(
tracepoints_
.
find
(
tracepoint
)
!=
tracepoints_
.
end
())
return
mkstatus
(
-
1
,
"Tracepoint %s already attached"
,
tracepoint
.
c_str
());
auto
pos
=
tracepoint
.
find
(
":"
);
if
((
pos
==
std
::
string
::
npos
)
||
(
pos
!=
tracepoint
.
rfind
(
":"
)))
return
mkstatus
(
-
1
,
"Unable to parse Tracepoint %s"
,
tracepoint
.
c_str
());
std
::
string
tp_category
=
tracepoint
.
substr
(
0
,
pos
);
std
::
string
tp_name
=
tracepoint
.
substr
(
pos
+
1
);
void
*
res
=
bpf_attach_tracepoint
(
probe_fd
,
tp_category
.
c_str
(),
tp_name
.
c_str
(),
pid
,
cpu
,
group_fd
,
cb
,
cb_cookie
);
if
(
!
res
)
{
TRY2
(
unload_func
(
probe_func
));
return
mkstatus
(
-
1
,
"Unable to attach Tracepoint %s using %s"
,
tracepoint
.
c_str
(),
probe_func
.
c_str
());
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
func
=
probe_func
;
tracepoints_
[
tracepoint
]
=
std
::
move
(
p
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
detach_kprobe
(
const
std
::
string
&
kernel_func
,
bpf_attach_type
attach_type
)
{
std
::
string
event
=
get_kprobe_event
(
kernel_func
,
attach_type
);
auto
it
=
kprobes_
.
find
(
event
);
if
(
it
==
kprobes_
.
end
())
return
mkstatus
(
-
1
,
"No open %skprobe for %s"
,
attach_type_debug
(
attach_type
).
c_str
(),
kernel_func
.
c_str
());
TRY2
(
detach_kprobe_event
(
it
->
first
,
it
->
second
));
kprobes_
.
erase
(
it
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
detach_uprobe
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
uint64_t
symbol_addr
,
bpf_attach_type
attach_type
)
{
bcc_symbol
sym
=
bcc_symbol
();
TRY2
(
check_binary_symbol
(
binary_path
,
symbol
,
symbol_addr
,
&
sym
));
std
::
string
event
=
get_uprobe_event
(
sym
.
module
,
sym
.
offset
,
attach_type
);
auto
it
=
uprobes_
.
find
(
event
);
if
(
it
==
uprobes_
.
end
())
return
mkstatus
(
-
1
,
"No open %suprobe for binary %s symbol %s addr %lx"
,
attach_type_debug
(
attach_type
).
c_str
(),
binary_path
.
c_str
(),
symbol
.
c_str
(),
symbol_addr
);
TRY2
(
detach_uprobe_event
(
it
->
first
,
it
->
second
));
uprobes_
.
erase
(
it
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
detach_tracepoint
(
const
std
::
string
&
tracepoint
)
{
auto
it
=
tracepoints_
.
find
(
tracepoint
);
if
(
it
==
tracepoints_
.
end
())
return
mkstatus
(
-
1
,
"No open Tracepoint %s"
,
tracepoint
.
c_str
());
TRY2
(
detach_tracepoint_event
(
it
->
first
,
it
->
second
));
tracepoints_
.
erase
(
it
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
open_perf_buffer
(
const
std
::
string
&
name
,
perf_reader_raw_cb
cb
,
void
*
cb_cookie
)
{
if
(
perf_buffers_
.
find
(
name
)
==
perf_buffers_
.
end
())
perf_buffers_
[
name
]
=
new
BPFPerfBuffer
(
bpf_module_
.
get
(),
name
);
auto
table
=
perf_buffers_
[
name
];
TRY2
(
table
->
open
(
cb
,
cb_cookie
));
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
close_perf_buffer
(
const
std
::
string
&
name
)
{
auto
it
=
perf_buffers_
.
find
(
name
);
if
(
it
==
perf_buffers_
.
end
())
return
mkstatus
(
-
1
,
"Perf buffer for %s not open"
,
name
.
c_str
());
TRY2
(
it
->
second
->
close
());
return
mkstatus
(
0
);
}
void
BPF
::
poll_perf_buffer
(
const
std
::
string
&
name
,
int
timeout
)
{
auto
it
=
perf_buffers_
.
find
(
name
);
if
(
it
==
perf_buffers_
.
end
())
return
;
it
->
second
->
poll
(
timeout
);
}
StatusTuple
BPF
::
load_func
(
const
std
::
string
&
func_name
,
enum
bpf_prog_type
type
,
int
&
fd
)
{
if
(
funcs_
.
find
(
func_name
)
!=
funcs_
.
end
())
{
fd
=
funcs_
[
func_name
];
return
mkstatus
(
0
);
}
uint8_t
*
func_start
=
bpf_module_
->
function_start
(
func_name
);
if
(
!
func_start
)
return
mkstatus
(
-
1
,
"Can't find start of function %s"
,
func_name
.
c_str
());
size_t
func_size
=
bpf_module_
->
function_size
(
func_name
);
fd
=
bpf_prog_load
(
type
,
reinterpret_cast
<
struct
bpf_insn
*>
(
func_start
),
func_size
,
bpf_module_
->
license
(),
bpf_module_
->
kern_version
(),
nullptr
,
0
// BPFModule will handle error printing
);
if
(
fd
<
0
)
return
mkstatus
(
-
1
,
"Failed to load %s: %d"
,
func_name
.
c_str
(),
fd
);
funcs_
[
func_name
]
=
fd
;
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
unload_func
(
const
std
::
string
&
func_name
)
{
auto
it
=
funcs_
.
find
(
func_name
);
if
(
it
==
funcs_
.
end
())
return
mkstatus
(
-
1
,
"Probe function %s not loaded"
,
func_name
.
c_str
());
int
res
=
close
(
it
->
second
);
if
(
res
!=
0
)
return
mkstatus
(
-
1
,
"Can't close FD for %s: %d"
,
it
->
first
.
c_str
(),
res
);
funcs_
.
erase
(
it
);
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
check_binary_symbol
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
uint64_t
symbol_addr
,
bcc_symbol
*
output
)
{
int
res
=
bcc_resolve_symname
(
binary_path
.
c_str
(),
symbol
.
c_str
(),
symbol_addr
,
output
);
if
(
res
<
0
)
return
mkstatus
(
-
1
,
"Unable to find offset for binary %s symbol %s address %lx"
,
binary_path
.
c_str
(),
symbol
.
c_str
(),
symbol_addr
);
return
mkstatus
(
0
);
}
std
::
string
BPF
::
get_kprobe_event
(
const
std
::
string
&
kernel_func
,
bpf_attach_type
type
)
{
std
::
string
res
=
attach_type_prefix
(
type
)
+
"_"
;
res
+=
sanitize_str
(
kernel_func
,
&
BPF
::
kprobe_event_validator
);
return
res
;
}
std
::
string
BPF
::
get_uprobe_event
(
const
std
::
string
&
binary_path
,
uint64_t
offset
,
bpf_attach_type
type
)
{
std
::
string
res
=
attach_type_prefix
(
type
)
+
"_"
;
res
+=
sanitize_str
(
binary_path
,
&
BPF
::
uprobe_path_validator
);
res
+=
"_0x"
+
uint_to_hex
(
offset
);
return
res
;
}
StatusTuple
BPF
::
detach_kprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
TRY2
(
unload_func
(
attr
.
func
));
std
::
string
detach_event
=
"-:kprobes/"
+
event
;
if
(
bpf_detach_kprobe
(
detach_event
.
c_str
())
<
0
)
return
mkstatus
(
-
1
,
"Unable to detach kprobe %s"
,
event
.
c_str
());
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
detach_uprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
TRY2
(
unload_func
(
attr
.
func
));
std
::
string
detach_event
=
"-:uprobes/"
+
event
;
if
(
bpf_detach_uprobe
(
detach_event
.
c_str
())
<
0
)
return
mkstatus
(
-
1
,
"Unable to detach uprobe %s"
,
event
.
c_str
());
return
mkstatus
(
0
);
}
StatusTuple
BPF
::
detach_tracepoint_event
(
const
std
::
string
&
tracepoint
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
TRY2
(
unload_func
(
attr
.
func
));
// TODO: bpf_detach_tracepoint currently does nothing.
return
mkstatus
(
0
);
}
}
// namespace ebpf
src/cc/BPF.h
0 → 100644
View file @
335cbe4f
/*
* Copyright (c) 2016 Facebook, Inc.
*
* 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
*
* http://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.
*/
#pragma once
#include <cctype>
#include <memory>
#include <string>
#include "BPFTable.h"
#include "bcc_syms.h"
#include "bpf_module.h"
#include "common.h"
#include "compat/linux/bpf.h"
#include "libbpf.h"
namespace
ebpf
{
enum
class
bpf_attach_type
{
probe_entry
,
probe_return
};
struct
open_probe_t
{
void
*
reader_ptr
;
std
::
string
func
;
};
class
BPF
{
public:
static
const
int
BPF_MAX_STACK_DEPTH
=
127
;
explicit
BPF
(
unsigned
int
flag
=
0
)
:
bpf_module_
(
new
BPFModule
(
flag
))
{}
StatusTuple
init
(
const
std
::
string
&
bpf_program
,
std
::
vector
<
std
::
string
>
cflags
=
{});
~
BPF
();
StatusTuple
detach_all
();
StatusTuple
attach_kprobe
(
const
std
::
string
&
kernel_func
,
const
std
::
string
&
probe_func
,
bpf_attach_type
attach_type
=
bpf_attach_type
::
probe_entry
,
pid_t
pid
=
-
1
,
int
cpu
=
0
,
int
group_fd
=
-
1
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
StatusTuple
detach_kprobe
(
const
std
::
string
&
kernel_func
,
bpf_attach_type
attach_type
=
bpf_attach_type
::
probe_entry
);
StatusTuple
attach_uprobe
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
const
std
::
string
&
probe_func
,
uint64_t
symbol_addr
=
0
,
bpf_attach_type
attach_type
=
bpf_attach_type
::
probe_entry
,
pid_t
pid
=
-
1
,
int
cpu
=
0
,
int
group_fd
=
-
1
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
StatusTuple
detach_uprobe
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
uint64_t
symbol_addr
=
0
,
bpf_attach_type
attach_type
=
bpf_attach_type
::
probe_entry
);
StatusTuple
attach_tracepoint
(
const
std
::
string
&
tracepoint
,
const
std
::
string
&
probe_func
,
pid_t
pid
=
-
1
,
int
cpu
=
0
,
int
group_fd
=
-
1
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
StatusTuple
detach_tracepoint
(
const
std
::
string
&
tracepoint
);
template
<
class
KeyType
,
class
ValueType
>
BPFHashTable
<
KeyType
,
ValueType
>
get_hash_table
(
const
std
::
string
&
name
)
{
return
BPFHashTable
<
KeyType
,
ValueType
>
(
bpf_module_
.
get
(),
name
);
}
BPFStackTable
get_stack_table
(
const
std
::
string
&
name
)
{
return
BPFStackTable
(
bpf_module_
.
get
(),
name
);
}
StatusTuple
open_perf_buffer
(
const
std
::
string
&
name
,
perf_reader_raw_cb
cb
,
void
*
cb_cookie
=
nullptr
);
StatusTuple
close_perf_buffer
(
const
std
::
string
&
name
);
void
poll_perf_buffer
(
const
std
::
string
&
name
,
int
timeout
=
-
1
);
private:
StatusTuple
load_func
(
const
std
::
string
&
func_name
,
enum
bpf_prog_type
type
,
int
&
fd
);
StatusTuple
unload_func
(
const
std
::
string
&
func_name
);
std
::
string
get_kprobe_event
(
const
std
::
string
&
kernel_func
,
bpf_attach_type
type
);
std
::
string
get_uprobe_event
(
const
std
::
string
&
binary_path
,
uint64_t
offset
,
bpf_attach_type
type
);
StatusTuple
detach_kprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
);
StatusTuple
detach_uprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
);
StatusTuple
detach_tracepoint_event
(
const
std
::
string
&
tracepoint
,
open_probe_t
&
attr
);
std
::
string
attach_type_debug
(
bpf_attach_type
type
)
{
switch
(
type
)
{
case
bpf_attach_type
:
:
probe_entry
:
return
""
;
case
bpf_attach_type
:
:
probe_return
:
return
"return "
;
}
return
"ERROR"
;
}
std
::
string
attach_type_prefix
(
bpf_attach_type
type
)
{
switch
(
type
)
{
case
bpf_attach_type
:
:
probe_entry
:
return
"p"
;
case
bpf_attach_type
:
:
probe_return
:
return
"r"
;
}
return
"ERROR"
;
}
static
bool
kprobe_event_validator
(
char
c
)
{
return
(
c
!=
'+'
)
&&
(
c
!=
'.'
);
}
static
bool
uprobe_path_validator
(
char
c
)
{
return
std
::
isalpha
(
c
)
||
std
::
isdigit
(
c
)
||
(
c
==
'_'
);
}
StatusTuple
check_binary_symbol
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
uint64_t
symbol_addr
,
bcc_symbol
*
output
);
std
::
unique_ptr
<
BPFModule
>
bpf_module_
;
std
::
map
<
std
::
string
,
int
>
funcs_
;
std
::
map
<
std
::
string
,
open_probe_t
>
kprobes_
;
std
::
map
<
std
::
string
,
open_probe_t
>
uprobes_
;
std
::
map
<
std
::
string
,
open_probe_t
>
tracepoints_
;
std
::
map
<
std
::
string
,
BPFPerfBuffer
*>
perf_buffers_
;
};
}
// namespace ebpf
src/cc/BPFTable.cc
0 → 100644
View file @
335cbe4f
/*
* Copyright (c) 2016 Facebook, Inc.
*
* 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
*
* http://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 <errno.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include "BPFTable.h"
#include "bcc_syms.h"
#include "common.h"
#include "exception.h"
#include "libbpf.h"
#include "perf_reader.h"
namespace
ebpf
{
BPFStackTable
::~
BPFStackTable
()
{
for
(
auto
it
:
pid_sym_
)
bcc_free_symcache
(
it
.
second
,
it
.
first
);
}
std
::
vector
<
intptr_t
>
BPFStackTable
::
get_stack_addr
(
int
stack_id
)
{
std
::
vector
<
intptr_t
>
res
;
stacktrace_t
stack
;
if
(
!
lookup
(
&
stack_id
,
&
stack
))
return
res
;
for
(
int
i
=
0
;
(
i
<
BPF_MAX_STACK_DEPTH
)
&&
(
stack
.
ip
[
i
]
!=
0
);
i
++
)
res
.
push_back
(
stack
.
ip
[
i
]);
return
res
;
}
std
::
vector
<
std
::
string
>
BPFStackTable
::
get_stack_symbol
(
int
stack_id
,
int
pid
)
{
auto
addresses
=
get_stack_addr
(
stack_id
);
std
::
vector
<
std
::
string
>
res
;
res
.
reserve
(
addresses
.
size
());
if
(
pid
<
0
)
pid
=
-
1
;
if
(
pid_sym_
.
find
(
pid
)
==
pid_sym_
.
end
())
pid_sym_
[
pid
]
=
bcc_symcache_new
(
pid
);
void
*
cache
=
pid_sym_
[
pid
];
bcc_symbol
symbol
;
for
(
auto
addr
:
addresses
)
if
(
bcc_symcache_resolve
(
cache
,
addr
,
&
symbol
)
!=
0
)
res
.
push_back
(
"[UNKNOWN]"
);
else
res
.
push_back
(
symbol
.
demangle_name
);
return
res
;
}
StatusTuple
BPFPerfBuffer
::
open_on_cpu
(
perf_reader_raw_cb
cb
,
int
cpu
,
void
*
cb_cookie
)
{
if
(
cpu_readers_
.
find
(
cpu
)
!=
cpu_readers_
.
end
())
return
mkstatus
(
-
1
,
"Perf buffer already open on CPU %d"
,
cpu
);
auto
reader
=
static_cast
<
perf_reader
*>
(
bpf_open_perf_buffer
(
cb
,
cb_cookie
,
-
1
,
cpu
));
if
(
reader
==
nullptr
)
return
mkstatus
(
-
1
,
"Unable to construct perf reader"
);
int
reader_fd
=
perf_reader_fd
(
reader
);
if
(
!
update
(
&
cpu
,
&
reader_fd
))
{
perf_reader_free
(
static_cast
<
void
*>
(
reader
));
return
mkstatus
(
-
1
,
"Unable to open perf buffer on CPU %d: %s"
,
cpu
,
strerror
(
errno
));
}
cpu_readers_
[
cpu
]
=
static_cast
<
perf_reader
*>
(
reader
);
return
mkstatus
(
0
);
}
StatusTuple
BPFPerfBuffer
::
open
(
perf_reader_raw_cb
cb
,
void
*
cb_cookie
)
{
for
(
int
i
=
0
;
i
<
sysconf
(
_SC_NPROCESSORS_ONLN
);
i
++
)
TRY2
(
open_on_cpu
(
cb
,
i
,
cb_cookie
));
return
mkstatus
(
0
);
}
StatusTuple
BPFPerfBuffer
::
close_on_cpu
(
int
cpu
)
{
auto
it
=
cpu_readers_
.
find
(
cpu
);
if
(
it
==
cpu_readers_
.
end
())
return
mkstatus
(
0
);
perf_reader_free
(
static_cast
<
void
*>
(
it
->
second
));
if
(
!
remove
(
const_cast
<
int
*>
(
&
(
it
->
first
))))
return
mkstatus
(
-
1
,
"Unable to close perf buffer on CPU %d"
,
it
->
first
);
cpu_readers_
.
erase
(
it
);
return
mkstatus
(
0
);
}
StatusTuple
BPFPerfBuffer
::
close
()
{
std
::
string
errors
;
bool
has_error
=
false
;
for
(
int
i
=
0
;
i
<
sysconf
(
_SC_NPROCESSORS_ONLN
);
i
++
)
{
auto
res
=
close_on_cpu
(
i
);
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
{
errors
+=
"Failed to close CPU"
+
std
::
to_string
(
i
)
+
" perf buffer: "
;
errors
+=
std
::
get
<
1
>
(
res
)
+
"
\n
"
;
has_error
=
true
;
}
}
if
(
has_error
)
return
mkstatus
(
-
1
,
errors
);
return
mkstatus
(
0
);
}
void
BPFPerfBuffer
::
poll
(
int
timeout
)
{
perf_reader
*
readers
[
cpu_readers_
.
size
()];
int
i
=
0
;
for
(
auto
it
:
cpu_readers_
)
readers
[
i
++
]
=
it
.
second
;
perf_reader_poll
(
cpu_readers_
.
size
(),
readers
,
timeout
);
}
BPFPerfBuffer
::~
BPFPerfBuffer
()
{
auto
res
=
close
();
if
(
std
::
get
<
0
>
(
res
)
!=
0
)
std
::
cerr
<<
"Failed to close all perf buffer on destruction: "
<<
std
::
get
<
1
>
(
res
)
<<
std
::
endl
;
}
}
// namespace ebpf
src/cc/BPFTable.h
0 → 100644
View file @
335cbe4f
/*
* Copyright (c) 2016 Facebook, Inc.
*
* 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
*
* http://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.
*/
#pragma once
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "bpf_module.h"
#include "common.h"
#include "libbpf.h"
#include "perf_reader.h"
namespace
ebpf
{
template
<
class
KeyType
,
class
ValueType
>
class
BPFTableBase
{
public:
size_t
capacity
()
{
return
capacity_
;
}
protected:
BPFTableBase
(
BPFModule
*
bpf_module
,
const
std
::
string
&
name
)
{
size_t
id_
=
bpf_module
->
table_id
(
name
);
if
(
id_
>=
bpf_module
->
num_tables
())
throw
std
::
invalid_argument
(
"Table "
+
name
+
" does not exist"
);
fd_
=
bpf_module
->
table_fd
(
id_
);
capacity_
=
bpf_module
->
table_max_entries
(
id_
);
};
bool
lookup
(
KeyType
*
key
,
ValueType
*
value
)
{
return
bpf_lookup_elem
(
fd_
,
static_cast
<
void
*>
(
key
),
static_cast
<
void
*>
(
value
))
>=
0
;
}
bool
next
(
KeyType
*
key
,
KeyType
*
next_key
)
{
return
bpf_get_next_key
(
fd_
,
static_cast
<
void
*>
(
key
),
static_cast
<
void
*>
(
next_key
))
>=
0
;
}
bool
update
(
KeyType
*
key
,
ValueType
*
value
)
{
return
bpf_update_elem
(
fd_
,
static_cast
<
void
*>
(
key
),
static_cast
<
void
*>
(
value
),
0
)
>=
0
;
}
bool
remove
(
KeyType
*
key
)
{
return
bpf_delete_elem
(
fd_
,
static_cast
<
void
*>
(
key
))
>=
0
;
}
int
fd_
;
size_t
capacity_
;
};
template
<
class
KeyType
,
class
ValueType
>
class
BPFHashTable
:
protected
BPFTableBase
<
KeyType
,
ValueType
>
{
public:
BPFHashTable
(
BPFModule
*
bpf_module
,
const
std
::
string
&
name
)
:
BPFTableBase
<
KeyType
,
ValueType
>
(
bpf_module
,
name
)
{}
ValueType
get_value
(
const
KeyType
&
key
)
{
ValueType
res
;
if
(
!
this
->
lookup
(
const_cast
<
KeyType
*>
(
&
key
),
&
res
))
throw
std
::
invalid_argument
(
"Key does not exist in the table"
);
return
res
;
}
ValueType
operator
[](
const
KeyType
&
key
)
{
return
get_value
(
key
);
}
std
::
vector
<
std
::
pair
<
KeyType
,
ValueType
>>
get_table_offline
()
{
std
::
vector
<
std
::
pair
<
KeyType
,
ValueType
>>
res
;
KeyType
cur
,
nxt
;
ValueType
value
;
while
(
true
)
{
if
(
!
this
->
next
(
&
cur
,
&
nxt
))
break
;
if
(
!
this
->
lookup
(
&
nxt
,
&
value
))
break
;
res
.
emplace_back
(
nxt
,
value
);
std
::
swap
(
cur
,
nxt
);
}
return
res
;
}
};
// From src/cc/export/helpers.h
static
const
int
BPF_MAX_STACK_DEPTH
=
127
;
struct
stacktrace_t
{
intptr_t
ip
[
BPF_MAX_STACK_DEPTH
];
};
class
BPFStackTable
:
protected
BPFTableBase
<
int
,
stacktrace_t
>
{
public:
BPFStackTable
(
BPFModule
*
bpf_module
,
const
std
::
string
&
name
)
:
BPFTableBase
<
int
,
stacktrace_t
>
(
bpf_module
,
name
)
{}
~
BPFStackTable
();
std
::
vector
<
intptr_t
>
get_stack_addr
(
int
stack_id
);
std
::
vector
<
std
::
string
>
get_stack_symbol
(
int
stack_id
,
int
pid
);
private:
std
::
map
<
int
,
void
*>
pid_sym_
;
};
class
BPFPerfBuffer
:
protected
BPFTableBase
<
int
,
int
>
{
public:
BPFPerfBuffer
(
BPFModule
*
bpf_module
,
const
std
::
string
&
name
)
:
BPFTableBase
<
int
,
int
>
(
bpf_module
,
name
)
{}
~
BPFPerfBuffer
();
StatusTuple
open
(
perf_reader_raw_cb
cb
,
void
*
cb_cookie
);
StatusTuple
close
();
void
poll
(
int
timeout
);
private:
StatusTuple
open_on_cpu
(
perf_reader_raw_cb
cb
,
int
cpu
,
void
*
cb_cookie
);
StatusTuple
close_on_cpu
(
int
cpu
);
std
::
map
<
int
,
perf_reader
*>
cpu_readers_
;
};
}
// namespace ebpf
src/cc/CMakeLists.txt
View file @
335cbe4f
...
...
@@ -35,12 +35,12 @@ if (CMAKE_COMPILER_IS_GNUCC AND LIBCLANG_ISSTATIC)
endif
()
endif
()
add_library
(
bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc
)
add_library
(
bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc
BPF.cc BPFTable.cc
)
set_target_properties
(
bcc-shared PROPERTIES VERSION
${
REVISION_LAST
}
SOVERSION 0
)
set_target_properties
(
bcc-shared PROPERTIES OUTPUT_NAME bcc
)
add_library
(
bcc-loader-static libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c
)
add_library
(
bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc
)
add_library
(
bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc
BPF.cc BPFTable.cc
)
set_target_properties
(
bcc-static PROPERTIES OUTPUT_NAME bcc
)
set
(
llvm_raw_libs bitwriter bpfcodegen irreader linker
...
...
@@ -63,7 +63,7 @@ target_link_libraries(bcc-static b_frontend clang_frontend bcc-loader-static ${c
install
(
TARGETS bcc-shared LIBRARY COMPONENT libbcc
DESTINATION
${
CMAKE_INSTALL_LIBDIR
}
)
install
(
FILES bpf_common.h bpf_module.h bcc_syms.h common.h exception.h libbpf.h perf_reader.h COMPONENT libbcc
install
(
FILES bpf_common.h bpf_module.h bcc_syms.h common.h exception.h libbpf.h perf_reader.h
BPF.h BPFTable.h
COMPONENT libbcc
DESTINATION include/bcc
)
install
(
DIRECTORY compat/linux/ COMPONENT libbcc
DESTINATION include/bcc/compat/linux
...
...
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