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
78bf9fb4
Commit
78bf9fb4
authored
May 09, 2017
by
4ast
Committed by
GitHub
May 09, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1141 from palmtenor/mountns
RFC: Improve mount namespace handling
parents
a09c4913
ef9d4b8d
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
324 additions
and
258 deletions
+324
-258
src/cc/CMakeLists.txt
src/cc/CMakeLists.txt
+2
-2
src/cc/bcc_elf.c
src/cc/bcc_elf.c
+16
-6
src/cc/bcc_elf.h
src/cc/bcc_elf.h
+3
-0
src/cc/bcc_perf_map.c
src/cc/bcc_perf_map.c
+8
-0
src/cc/bcc_perf_map.h
src/cc/bcc_perf_map.h
+2
-0
src/cc/bcc_proc.c
src/cc/bcc_proc.c
+13
-113
src/cc/bcc_proc.h
src/cc/bcc_proc.h
+3
-8
src/cc/bcc_syms.cc
src/cc/bcc_syms.cc
+131
-69
src/cc/bcc_syms.h
src/cc/bcc_syms.h
+4
-0
src/cc/bpf_module.cc
src/cc/bpf_module.cc
+4
-4
src/cc/common.cc
src/cc/common.cc
+34
-0
src/cc/common.h
src/cc/common.h
+23
-0
src/cc/frontends/b/codegen_llvm.cc
src/cc/frontends/b/codegen_llvm.cc
+2
-1
src/cc/libbpf.c
src/cc/libbpf.c
+5
-5
src/cc/syms.h
src/cc/syms.h
+47
-8
src/cc/table_desc.h
src/cc/table_desc.h
+21
-37
src/cc/usdt.cc
src/cc/usdt.cc
+2
-2
src/cc/usdt.h
src/cc/usdt.h
+1
-1
src/cc/usdt_args.cc
src/cc/usdt_args.cc
+1
-1
tests/cc/test_c_api.cc
tests/cc/test_c_api.cc
+2
-1
No files found.
src/cc/CMakeLists.txt
View file @
78bf9fb4
...
...
@@ -39,8 +39,8 @@ add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c
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 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 bpffs_table.cc json_map_decl_visitor.cc table_storage.cc exported_files.cc
bcc_syms.cc
usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc
)
add_library
(
bcc-loader-static STATIC libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c
bcc_syms.cc
)
add_library
(
bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc bpffs_table.cc json_map_decl_visitor.cc table_storage.cc exported_files.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc
)
set_target_properties
(
bcc-static PROPERTIES OUTPUT_NAME bcc
)
set
(
llvm_raw_libs bitwriter bpfcodegen irreader linker
...
...
src/cc/bcc_elf.c
View file @
78bf9fb4
...
...
@@ -483,21 +483,31 @@ int bcc_elf_loadaddr(const char *path, uint64_t *address) {
return
res
;
}
int
bcc_elf_
is_shared_obj
(
const
char
*
path
)
{
int
bcc_elf_
get_type
(
const
char
*
path
)
{
Elf
*
e
;
GElf_Ehdr
hdr
;
int
fd
,
res
=
-
1
;
int
fd
;
void
*
res
=
NULL
;
if
(
openelf
(
path
,
&
e
,
&
fd
)
<
0
)
return
-
1
;
if
(
gelf_getehdr
(
e
,
&
hdr
))
res
=
(
hdr
.
e_type
==
ET_DYN
);
res
=
(
void
*
)
gelf_getehdr
(
e
,
&
hdr
);
elf_end
(
e
);
close
(
fd
);
return
res
;
if
(
!
res
)
return
-
1
;
else
return
hdr
.
e_type
;
}
int
bcc_elf_is_exe
(
const
char
*
path
)
{
return
(
bcc_elf_get_type
(
path
)
!=
-
1
)
&&
(
access
(
path
,
X_OK
)
==
0
);
}
int
bcc_elf_is_shared_obj
(
const
char
*
path
)
{
return
bcc_elf_get_type
(
path
)
==
ET_DYN
;
}
#if 0
...
...
src/cc/bcc_elf.h
View file @
78bf9fb4
...
...
@@ -41,7 +41,10 @@ int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback,
int
bcc_elf_loadaddr
(
const
char
*
path
,
uint64_t
*
address
);
int
bcc_elf_foreach_sym
(
const
char
*
path
,
bcc_elf_symcb
callback
,
void
*
payload
);
int
bcc_elf_get_type
(
const
char
*
path
);
int
bcc_elf_is_shared_obj
(
const
char
*
path
);
int
bcc_elf_is_exe
(
const
char
*
path
);
#ifdef __cplusplus
}
...
...
src/cc/bcc_perf_map.c
View file @
78bf9fb4
...
...
@@ -22,6 +22,14 @@
#include "bcc_perf_map.h"
bool
bcc_is_perf_map
(
const
char
*
path
)
{
char
*
pos
=
strstr
(
path
,
".map"
);
// Path ends with ".map"
if
(
pos
==
NULL
||
*
(
pos
+
4
)
!=
0
)
return
false
;
return
access
(
path
,
R_OK
)
==
0
;
}
int
bcc_perf_map_nstgid
(
int
pid
)
{
char
status_path
[
64
];
FILE
*
status
;
...
...
src/cc/bcc_perf_map.h
View file @
78bf9fb4
...
...
@@ -27,6 +27,8 @@ extern "C" {
typedef
int
(
*
bcc_perf_map_symcb
)(
const
char
*
,
uint64_t
,
uint64_t
,
int
,
void
*
);
bool
bcc_is_perf_map
(
const
char
*
path
);
int
bcc_perf_map_nstgid
(
int
pid
);
bool
bcc_perf_map_path
(
char
*
map_path
,
size_t
map_len
,
int
pid
);
int
bcc_perf_map_foreach_sym
(
const
char
*
path
,
bcc_perf_map_symcb
callback
,
...
...
src/cc/bcc_proc.c
View file @
78bf9fb4
...
...
@@ -13,15 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
...
...
@@ -35,23 +31,12 @@
#include "bcc_proc.h"
#include "bcc_elf.h"
static
bool
is_exe
(
const
char
*
path
)
{
struct
stat
s
;
if
(
access
(
path
,
X_OK
)
<
0
)
return
false
;
if
(
stat
(
path
,
&
s
)
<
0
)
return
false
;
return
S_ISREG
(
s
.
st_mode
);
}
char
*
bcc_procutils_which
(
const
char
*
binpath
)
{
char
buffer
[
4096
];
const
char
*
PATH
;
if
(
strchr
(
binpath
,
'/'
))
return
is_exe
(
binpath
)
?
strdup
(
binpath
)
:
0
;
return
bcc_elf_
is_exe
(
binpath
)
?
strdup
(
binpath
)
:
0
;
if
(
!
(
PATH
=
getenv
(
"PATH"
)))
return
0
;
...
...
@@ -65,7 +50,7 @@ char *bcc_procutils_which(const char *binpath) {
buffer
[
path_len
]
=
'/'
;
strcpy
(
buffer
+
path_len
+
1
,
binpath
);
if
(
is_exe
(
buffer
))
if
(
bcc_elf_
is_exe
(
buffer
))
return
strdup
(
buffer
);
}
...
...
@@ -118,7 +103,7 @@ int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
while
(
isspace
(
mapname
[
0
]))
mapname
++
;
if
(
strchr
(
perm
,
'x'
)
&&
bcc_mapping_is_file_backed
(
mapname
))
{
if
(
callback
(
mapname
,
(
uint64_t
)
begin
,
(
uint64_t
)
end
,
payload
)
<
0
)
if
(
callback
(
mapname
,
(
uint64_t
)
begin
,
(
uint64_t
)
end
,
true
,
payload
)
<
0
)
break
;
}
}
...
...
@@ -126,12 +111,18 @@ int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
fclose
(
procmap
);
// Add
a mapping to /tmp/perf-pid.map for the entire address space. This will
// be used if symbols aren't resolved in an earlier mapping.
// Add
ress mapping for the entire address space maybe in /tmp/perf-<PID>.map
//
This will
be used if symbols aren't resolved in an earlier mapping.
char
map_path
[
4096
];
// Try perf-<PID>.map path with process's mount namespace, chroot and NSPID,
// in case it is generated by the process itself.
if
(
bcc_perf_map_path
(
map_path
,
sizeof
(
map_path
),
pid
))
callback
(
map_path
,
0
,
-
1
,
payload
);
callback
(
map_path
,
0
,
-
1
,
true
,
payload
);
// Try perf-<PID>.map path with global root and PID, in case it is generated
// by other Process. Avoid checking mount namespace for this.
int
res
=
snprintf
(
map_path
,
4096
,
"/tmp/perf-%d.map"
,
pid
);
if
(
res
>
0
&&
res
<
4096
)
callback
(
map_path
,
0
,
-
1
,
false
,
payload
);
return
0
;
}
...
...
@@ -398,97 +389,6 @@ void bcc_procutils_free(const char *ptr) {
free
((
void
*
)
ptr
);
}
bool
bcc_procutils_enter_mountns
(
int
pid
,
struct
ns_cookie
*
nc
)
{
char
curnspath
[
4096
];
char
newnspath
[
4096
];
int
oldns
=
-
1
;
int
newns
=
-
1
;
struct
stat
ons_stat
;
struct
stat
nns_stat
;
if
(
nc
==
NULL
)
return
false
;
nc
->
nsc_oldns
=
-
1
;
nc
->
nsc_newns
=
-
1
;
if
(
snprintf
(
curnspath
,
4096
,
"/proc/self/ns/mnt"
)
==
4096
)
{
return
false
;
}
if
(
snprintf
(
newnspath
,
4096
,
"/proc/%d/ns/mnt"
,
pid
)
==
4096
)
{
return
false
;
}
if
((
oldns
=
open
(
curnspath
,
O_RDONLY
))
<
0
)
{
return
false
;
}
if
((
newns
=
open
(
newnspath
,
O_RDONLY
))
<
0
)
{
goto
errout
;
}
if
(
fstat
(
oldns
,
&
ons_stat
)
<
0
)
{
goto
errout
;
}
if
(
fstat
(
newns
,
&
nns_stat
)
<
0
)
{
goto
errout
;
}
/*
* Only switch to the new namespace if it doesn't match the existing
* namespace. This prevents us from getting an EPERM when trying to enter an
* identical namespace.
*/
if
(
ons_stat
.
st_ino
==
nns_stat
.
st_ino
)
{
goto
errout
;
}
if
(
setns
(
newns
,
CLONE_NEWNS
)
<
0
)
{
goto
errout
;
}
nc
->
nsc_oldns
=
oldns
;
nc
->
nsc_newns
=
newns
;
return
true
;
errout:
if
(
oldns
>
-
1
)
{
(
void
)
close
(
oldns
);
}
if
(
newns
>
-
1
)
{
(
void
)
close
(
newns
);
}
return
false
;
}
bool
bcc_procutils_exit_mountns
(
struct
ns_cookie
*
nc
)
{
bool
rc
=
false
;
if
(
nc
==
NULL
)
return
rc
;
if
(
nc
->
nsc_oldns
==
-
1
||
nc
->
nsc_newns
==
-
1
)
return
rc
;
if
(
setns
(
nc
->
nsc_oldns
,
CLONE_NEWNS
)
==
0
)
{
rc
=
true
;
}
if
(
nc
->
nsc_oldns
>
-
1
)
{
(
void
)
close
(
nc
->
nsc_oldns
);
nc
->
nsc_oldns
=
-
1
;
}
if
(
nc
->
nsc_newns
>
-
1
)
{
(
void
)
close
(
nc
->
nsc_newns
);
nc
->
nsc_newns
=
-
1
;
}
return
rc
;
}
/* Detects the following languages + C. */
const
char
*
languages
[]
=
{
"java"
,
"python"
,
"ruby"
,
"php"
,
"node"
};
const
char
*
language_c
=
"c"
;
...
...
src/cc/bcc_proc.h
View file @
78bf9fb4
...
...
@@ -24,12 +24,9 @@ extern "C" {
#include <stdint.h>
struct
ns_cookie
{
int
nsc_oldns
;
int
nsc_newns
;
};
typedef
int
(
*
bcc_procutils_modulecb
)(
const
char
*
,
uint64_t
,
uint64_t
,
void
*
);
// Module name, start address, end address, whether to check mount namespace, payload
typedef
int
(
*
bcc_procutils_modulecb
)(
const
char
*
,
uint64_t
,
uint64_t
,
bool
,
void
*
);
// Symbol name, address, payload
typedef
void
(
*
bcc_procutils_ksymcb
)(
const
char
*
,
uint64_t
,
void
*
);
char
*
bcc_procutils_which_so
(
const
char
*
libname
,
int
pid
);
...
...
@@ -39,8 +36,6 @@ int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
void
*
payload
);
int
bcc_procutils_each_ksym
(
bcc_procutils_ksymcb
callback
,
void
*
payload
);
void
bcc_procutils_free
(
const
char
*
ptr
);
bool
bcc_procutils_enter_mountns
(
int
pid
,
struct
ns_cookie
*
nc
);
bool
bcc_procutils_exit_mountns
(
struct
ns_cookie
*
nc
);
const
char
*
bcc_procutils_language
(
int
pid
);
#ifdef __cplusplus
...
...
src/cc/bcc_syms.cc
View file @
78bf9fb4
...
...
@@ -15,10 +15,13 @@
*/
#include <cxxabi.h>
#include <fcntl.h>
#include <linux/elf.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include "bcc_elf.h"
#include "bcc_perf_map.h"
...
...
@@ -35,7 +38,7 @@ ino_t ProcStat::getinode_() {
bool
ProcStat
::
is_stale
()
{
ino_t
cur_inode
=
getinode_
();
return
(
cur_inode
>
0
)
&&
(
cur_inode
!=
inode_
);
return
(
cur_inode
>
0
)
&&
(
cur_inode
!=
inode_
);
}
ProcStat
::
ProcStat
(
int
pid
)
...
...
@@ -92,7 +95,70 @@ bool KSyms::resolve_name(const char *_unused, const char *name,
return
true
;
}
ProcSyms
::
ProcSyms
(
int
pid
)
:
pid_
(
pid
),
procstat_
(
pid
)
{
load_modules
();
}
ProcMountNS
::
ProcMountNS
(
int
pid
)
{
if
(
pid
<
0
)
return
;
ebpf
::
FileDesc
self_fd
;
ebpf
::
FileDesc
target_fd
;
char
path
[
256
];
int
res
;
res
=
std
::
snprintf
(
path
,
256
,
"/proc/self/ns/mnt"
);
if
(
res
<=
0
||
res
>=
256
)
return
;
if
((
self_fd
=
open
(
path
,
O_RDONLY
))
<
0
)
return
;
res
=
std
::
snprintf
(
path
,
256
,
"/proc/%d/ns/mnt"
,
pid
);
if
(
res
<=
0
||
res
>=
256
)
return
;
if
((
target_fd
=
open
(
path
,
O_RDONLY
))
<
0
)
return
;
struct
stat
self_stat
,
target_stat
;
if
(
fstat
(
self_fd
,
&
self_stat
)
!=
0
)
return
;
if
(
fstat
(
target_fd
,
&
target_stat
)
!=
0
)
return
;
if
(
self_stat
.
st_ino
==
target_stat
.
st_ino
)
// Both current and target Process are in same mount namespace
return
;
self_fd_
=
std
::
move
(
self_fd
);
target_fd_
=
std
::
move
(
target_fd
);
}
ProcMountNSGuard
::
ProcMountNSGuard
(
ProcMountNS
*
mount_ns
)
:
mount_ns_instance_
(
nullptr
),
mount_ns_
(
mount_ns
),
entered_
(
false
)
{
init
();
}
ProcMountNSGuard
::
ProcMountNSGuard
(
int
pid
)
:
mount_ns_instance_
(
pid
>
0
?
new
ProcMountNS
(
pid
)
:
nullptr
),
mount_ns_
(
mount_ns_instance_
.
get
()),
entered_
(
false
)
{
init
();
}
void
ProcMountNSGuard
::
init
()
{
if
(
!
mount_ns_
||
mount_ns_
->
self_fd_
<
0
||
mount_ns_
->
target_fd_
<
0
)
return
;
if
(
setns
(
mount_ns_
->
target_fd_
,
CLONE_NEWNS
)
==
0
)
entered_
=
true
;
}
ProcMountNSGuard
::~
ProcMountNSGuard
()
{
if
(
mount_ns_
&&
entered_
&&
mount_ns_
->
self_fd_
>=
0
)
setns
(
mount_ns_
->
self_fd_
,
CLONE_NEWNS
);
}
ProcSyms
::
ProcSyms
(
int
pid
)
:
pid_
(
pid
),
procstat_
(
pid
),
mount_ns_instance_
(
new
ProcMountNS
(
pid_
))
{
load_modules
();
}
bool
ProcSyms
::
load_modules
()
{
return
bcc_procutils_each_module
(
pid_
,
_add_module
,
this
)
==
0
;
...
...
@@ -100,43 +166,26 @@ bool ProcSyms::load_modules() {
void
ProcSyms
::
refresh
()
{
modules_
.
clear
();
mount_ns_instance_
.
reset
(
new
ProcMountNS
(
pid_
));
load_modules
();
procstat_
.
reset
();
}
int
ProcSyms
::
_add_module
(
const
char
*
modname
,
uint64_t
start
,
uint64_t
end
,
void
*
payload
)
{
struct
ns_cookie
nsc
=
{
-
1
,
-
1
};
bool
ns_switch
=
false
;
int
arc
;
bool
check_mount_ns
,
void
*
payload
)
{
ProcSyms
*
ps
=
static_cast
<
ProcSyms
*>
(
payload
);
auto
it
=
std
::
find_if
(
ps
->
modules_
.
begin
(),
ps
->
modules_
.
end
(),
[
=
](
const
ProcSyms
::
Module
&
m
)
{
return
m
.
name_
==
modname
;
});
auto
it
=
std
::
find_if
(
ps
->
modules_
.
begin
(),
ps
->
modules_
.
end
(),
[
=
](
const
ProcSyms
::
Module
&
m
)
{
return
m
.
name_
==
modname
;
});
if
(
it
==
ps
->
modules_
.
end
())
{
// If modname references a perf-map, determine if we need to enter a mount
// namespace in order to read symbols from it later.
if
(
strstr
(
modname
,
".map"
)
!=
nullptr
)
{
ns_switch
=
bcc_procutils_enter_mountns
(
ps
->
pid_
,
&
nsc
);
if
(
ns_switch
)
{
char
new_modname
[
4096
];
arc
=
access
(
modname
,
R_OK
);
bcc_procutils_exit_mountns
(
&
nsc
);
if
(
arc
!=
0
)
{
snprintf
(
new_modname
,
sizeof
(
new_modname
),
"/tmp/perf-%d.map"
,
ps
->
pid_
);
it
=
ps
->
modules_
.
insert
(
ps
->
modules_
.
end
(),
Module
(
new_modname
,
ps
->
pid_
,
false
));
it
->
ranges_
.
push_back
(
ProcSyms
::
Module
::
Range
(
start
,
end
));
return
0
;
}
}
}
it
=
ps
->
modules_
.
insert
(
ps
->
modules_
.
end
(),
Module
(
modname
,
ps
->
pid_
,
ns_switch
));
auto
module
=
Module
(
modname
,
check_mount_ns
?
ps
->
mount_ns_instance_
.
get
()
:
nullptr
);
if
(
module
.
init
())
it
=
ps
->
modules_
.
insert
(
ps
->
modules_
.
end
(),
std
::
move
(
module
));
else
return
0
;
}
it
->
ranges_
.
push_back
(
ProcSyms
::
Module
::
Range
(
start
,
end
)
);
it
->
ranges_
.
emplace_back
(
start
,
end
);
return
0
;
}
...
...
@@ -172,7 +221,7 @@ bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym,
if
(
original_module
)
sym
->
module
=
original_module
;
return
res
;
}
else
{
}
else
if
(
mod
.
type_
!=
ModuleType
::
PERF_MAP
)
{
// Record the module to which this symbol belongs, so that even if it's
// later found using a perf map, we still report the right module name.
original_module
=
mod
.
name_
.
c_str
();
...
...
@@ -194,13 +243,33 @@ bool ProcSyms::resolve_name(const char *module, const char *name,
return
false
;
}
ProcSyms
::
Module
::
Module
(
const
char
*
name
,
int
pid
,
bool
in_ns
)
:
name_
(
name
),
pid_
(
pid
),
in_ns_
(
in_ns
),
loaded_
(
false
)
{
struct
ns_cookie
nsc
;
ProcSyms
::
Module
::
Module
(
const
char
*
name
,
ProcMountNS
*
mount_ns
)
:
name_
(
name
),
loaded_
(
false
),
mount_ns_
(
mount_ns
),
type_
(
ModuleType
::
UNKNOWN
)
{}
bool
ProcSyms
::
Module
::
init
()
{
ProcMountNSGuard
g
(
mount_ns_
);
int
elf_type
=
bcc_elf_get_type
(
name_
.
c_str
());
if
(
elf_type
>=
0
)
{
if
(
elf_type
==
ET_EXEC
)
{
type_
=
ModuleType
::
EXEC
;
return
true
;
}
if
(
elf_type
==
ET_DYN
)
{
type_
=
ModuleType
::
SO
;
return
true
;
}
return
false
;
}
if
(
bcc_is_perf_map
(
name_
.
c_str
())
==
1
)
{
type_
=
ModuleType
::
PERF_MAP
;
return
true
;
}
bcc_procutils_enter_mountns
(
pid_
,
&
nsc
);
is_so_
=
bcc_elf_is_shared_obj
(
name
)
==
1
;
bcc_procutils_exit_mountns
(
&
nsc
);
return
false
;
}
int
ProcSyms
::
Module
::
_add_symbol
(
const
char
*
symname
,
uint64_t
start
,
...
...
@@ -211,27 +280,17 @@ int ProcSyms::Module::_add_symbol(const char *symname, uint64_t start,
return
0
;
}
bool
ProcSyms
::
Module
::
is_perf_map
()
const
{
return
strstr
(
name_
.
c_str
(),
".map"
)
!=
nullptr
;
}
void
ProcSyms
::
Module
::
load_sym_table
()
{
struct
ns_cookie
nsc
=
{
-
1
,
-
1
};
if
(
loaded_
)
return
;
loaded_
=
true
;
if
(
is_perf_map
())
{
if
(
in_ns_
)
bcc_procutils_enter_mountns
(
pid_
,
&
nsc
);
ProcMountNSGuard
g
(
mount_ns_
);
if
(
type_
==
ModuleType
::
PERF_MAP
)
bcc_perf_map_foreach_sym
(
name_
.
c_str
(),
_add_symbol
,
this
);
}
else
{
bcc_procutils_enter_mountns
(
pid_
,
&
nsc
);
if
(
type_
==
ModuleType
::
EXEC
||
type_
==
ModuleType
::
SO
)
bcc_elf_foreach_sym
(
name_
.
c_str
(),
_add_symbol
,
this
);
}
bcc_procutils_exit_mountns
(
&
nsc
);
std
::
sort
(
syms_
.
begin
(),
syms_
.
end
());
}
...
...
@@ -249,7 +308,7 @@ bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) {
for
(
Symbol
&
s
:
syms_
)
{
if
(
*
(
s
.
name
)
==
symname
)
{
*
addr
=
is_so
()
?
start
()
+
s
.
start
:
s
.
start
;
*
addr
=
type_
==
ModuleType
::
SO
?
start
()
+
s
.
start
:
s
.
start
;
return
true
;
}
}
...
...
@@ -257,7 +316,7 @@ bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) {
}
bool
ProcSyms
::
Module
::
find_addr
(
uint64_t
addr
,
struct
bcc_symbol
*
sym
)
{
uint64_t
offset
=
is_so
()
?
(
addr
-
start
())
:
addr
;
uint64_t
offset
=
type_
==
ModuleType
::
SO
?
(
addr
-
start
())
:
addr
;
load_sym_table
();
...
...
@@ -354,7 +413,7 @@ struct mod_st {
uint64_t
start
;
};
static
int
_find_module
(
const
char
*
modname
,
uint64_t
start
,
uint64_t
end
,
static
int
_find_module
(
const
char
*
modname
,
uint64_t
start
,
uint64_t
end
,
bool
,
void
*
p
)
{
struct
mod_st
*
mod
=
(
struct
mod_st
*
)
p
;
if
(
!
strcmp
(
modname
,
mod
->
name
))
{
...
...
@@ -405,7 +464,7 @@ static int _list_sym(const char *symname, uint64_t addr, uint64_t end,
if
(
!
ELF_TYPE_IS_FUNCTION
(
flags
)
||
addr
==
0
)
return
0
;
SYM_CB
cb
=
(
SYM_CB
)
payload
;
SYM_CB
cb
=
(
SYM_CB
)
payload
;
return
cb
(
symname
,
addr
);
}
...
...
@@ -419,8 +478,6 @@ int bcc_foreach_symbol(const char *module, SYM_CB cb) {
int
bcc_resolve_symname
(
const
char
*
module
,
const
char
*
symname
,
const
uint64_t
addr
,
int
pid
,
struct
bcc_symbol
*
sym
)
{
uint64_t
load_addr
;
struct
ns_cookie
nsc
=
{
-
1
,
-
1
};
bool
success
=
true
;
sym
->
module
=
NULL
;
sym
->
name
=
NULL
;
...
...
@@ -438,32 +495,37 @@ int bcc_resolve_symname(const char *module, const char *symname,
if
(
sym
->
module
==
NULL
)
return
-
1
;
bcc_procutils_enter_mountns
(
pid
,
&
nsc
);
ProcMountNSGuard
g
(
pid
);
if
(
bcc_elf_loadaddr
(
sym
->
module
,
&
load_addr
)
<
0
)
{
sym
->
module
=
NULL
;
success
=
false
;
goto
exitns
;
return
-
1
;
}
sym
->
name
=
symname
;
sym
->
offset
=
addr
;
if
(
sym
->
name
&&
sym
->
offset
==
0x0
)
{
if
(
sym
->
name
&&
sym
->
offset
==
0x0
)
if
(
bcc_find_symbol_addr
(
sym
)
<
0
)
{
sym
->
module
=
NULL
;
success
=
false
;
goto
exitns
;
return
-
1
;
}
}
exitns:
bcc_procutils_exit_mountns
(
&
nsc
);
if
(
!
success
||
sym
->
offset
==
0x0
)
if
(
sym
->
offset
==
0x0
)
return
-
1
;
sym
->
offset
=
(
sym
->
offset
-
load_addr
);
return
0
;
}
void
*
bcc_enter_mount_ns
(
int
pid
)
{
return
static_cast
<
void
*>
(
new
ProcMountNSGuard
(
pid
));
}
void
bcc_exit_mount_ns
(
void
**
guard
)
{
if
(
guard
&&
*
guard
)
{
delete
static_cast
<
ProcMountNSGuard
*>
(
*
guard
);
*
guard
=
NULL
;
}
}
}
src/cc/bcc_syms.h
View file @
78bf9fb4
...
...
@@ -52,6 +52,10 @@ int bcc_foreach_symbol(const char *module, SYM_CB cb);
int
bcc_find_symbol_addr
(
struct
bcc_symbol
*
sym
);
int
bcc_resolve_symname
(
const
char
*
module
,
const
char
*
symname
,
const
uint64_t
addr
,
int
pid
,
struct
bcc_symbol
*
sym
);
void
*
bcc_enter_mount_ns
(
int
pid
);
void
bcc_exit_mount_ns
(
void
**
guard
);
#ifdef __cplusplus
}
#endif
...
...
src/cc/bpf_module.cc
View file @
78bf9fb4
...
...
@@ -329,7 +329,7 @@ unique_ptr<ExecutionEngine> BPFModule::finalize_rw(unique_ptr<Module> m) {
// load an entire c file as a module
int
BPFModule
::
load_cfile
(
const
string
&
file
,
bool
in_memory
,
const
char
*
cflags
[],
int
ncflags
)
{
clang_loader_
=
make_unique
<
ClangLoader
>
(
&*
ctx_
,
flags_
);
clang_loader_
=
ebpf
::
make_unique
<
ClangLoader
>
(
&*
ctx_
,
flags_
);
if
(
clang_loader_
->
parse
(
&
mod_
,
*
ts_
,
file
,
in_memory
,
cflags
,
ncflags
,
id_
))
return
-
1
;
return
0
;
...
...
@@ -341,7 +341,7 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags
// Load in a pre-built list of functions into the initial Module object, then
// build an ExecutionEngine.
int
BPFModule
::
load_includes
(
const
string
&
text
)
{
clang_loader_
=
make_unique
<
ClangLoader
>
(
&*
ctx_
,
flags_
);
clang_loader_
=
ebpf
::
make_unique
<
ClangLoader
>
(
&*
ctx_
,
flags_
);
if
(
clang_loader_
->
parse
(
&
mod_
,
*
ts_
,
text
,
true
,
nullptr
,
0
,
""
))
return
-
1
;
return
0
;
...
...
@@ -353,7 +353,7 @@ int BPFModule::annotate() {
fn
->
addFnAttr
(
Attribute
::
AlwaysInline
);
// separate module to hold the reader functions
auto
m
=
make_unique
<
Module
>
(
"sscanf"
,
*
ctx_
);
auto
m
=
ebpf
::
make_unique
<
Module
>
(
"sscanf"
,
*
ctx_
);
struct
llvmfnpointers
{
llvm
::
Function
*
key_sscanf
;
...
...
@@ -461,7 +461,7 @@ int BPFModule::finalize() {
string
err
;
EngineBuilder
builder
(
move
(
mod_
));
builder
.
setErrorStr
(
&
err
);
builder
.
setMCJITMemoryManager
(
make_unique
<
MyMemoryManager
>
(
&
sections_
));
builder
.
setMCJITMemoryManager
(
ebpf
::
make_unique
<
MyMemoryManager
>
(
&
sections_
));
builder
.
setMArch
(
"bpf"
);
builder
.
setUseOrcMCJITReplacement
(
true
);
engine_
=
unique_ptr
<
ExecutionEngine
>
(
builder
.
create
());
...
...
src/cc/common.cc
View file @
78bf9fb4
...
...
@@ -15,6 +15,8 @@
*/
#include <fstream>
#include <sstream>
#include <unistd.h>
#include "common.h"
namespace
ebpf
{
...
...
@@ -47,5 +49,37 @@ std::vector<int> get_possible_cpus() {
return
read_cpu_range
(
"/sys/devices/system/cpu/possible"
);
}
FileDesc
::
FileDesc
(
int
fd
)
:
fd_
(
fd
)
{}
FileDesc
::
FileDesc
(
FileDesc
&&
that
)
:
fd_
(
-
1
)
{
*
this
=
std
::
move
(
that
);
}
FileDesc
::~
FileDesc
()
{
if
(
fd_
>=
0
)
::
close
(
fd_
);
}
FileDesc
&
FileDesc
::
operator
=
(
int
fd
)
{
if
(
fd_
>=
0
)
::
close
(
fd_
);
fd_
=
fd
;
return
*
this
;
}
FileDesc
&
FileDesc
::
operator
=
(
FileDesc
&&
that
)
{
if
(
fd_
>=
0
)
::
close
(
fd_
);
fd_
=
that
.
fd_
;
that
.
fd_
=
-
1
;
return
*
this
;
}
FileDesc
FileDesc
::
dup
()
const
{
int
dup_fd
=
::
dup
(
fd_
);
return
FileDesc
(
dup_fd
);
}
FileDesc
::
operator
int
()
{
return
fd_
;
}
FileDesc
::
operator
int
()
const
{
return
fd_
;
}
}
// namespace ebpf
src/cc/common.h
View file @
78bf9fb4
...
...
@@ -33,4 +33,27 @@ std::vector<int> get_online_cpus();
std
::
vector
<
int
>
get_possible_cpus
();
/// FileDesc is a helper class for managing open file descriptors. Copy is
/// disallowed (call dup instead), and cleanup happens automatically.
class
FileDesc
{
public:
explicit
FileDesc
(
int
fd
=
-
1
);
FileDesc
(
FileDesc
&&
that
);
FileDesc
(
const
FileDesc
&
that
)
=
delete
;
~
FileDesc
();
FileDesc
&
operator
=
(
int
fd
);
FileDesc
&
operator
=
(
FileDesc
&&
that
);
FileDesc
&
operator
=
(
const
FileDesc
&
that
)
=
delete
;
operator
int
();
operator
int
()
const
;
FileDesc
dup
()
const
;
private:
int
fd_
;
};
}
// namespace ebpf
src/cc/frontends/b/codegen_llvm.cc
View file @
78bf9fb4
...
...
@@ -33,6 +33,7 @@
#include <llvm/IR/Module.h>
#include "bcc_exception.h"
#include "common.h"
#include "codegen_llvm.h"
#include "lexer.h"
#include "libbpf.h"
...
...
@@ -1244,7 +1245,7 @@ StatusTuple CodegenLLVM::visit(Node *root, TableStorage &ts, const string &id) {
map_type
=
BPF_MAP_TYPE_ARRAY
;
ts
.
Insert
(
Path
({
id
,
table
.
first
->
id_
->
name_
}),
{
table
.
first
->
id_
->
name_
,
table_fds_
[
table
.
first
]
,
map_type
,
table
.
first
->
id_
->
name_
,
FileDesc
(
table_fds_
[
table
.
first
])
,
map_type
,
table
.
first
->
key_type_
->
bit_width_
>>
3
,
table
.
first
->
leaf_type_
->
bit_width_
>>
3
,
table
.
first
->
size_
,
0
,
});
...
...
src/cc/libbpf.c
View file @
78bf9fb4
...
...
@@ -38,7 +38,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "bcc_
proc
.h"
#include "bcc_
syms
.h"
#include "libbpf.h"
#include "perf_reader.h"
...
...
@@ -413,8 +413,8 @@ void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, con
char
new_name
[
128
];
struct
perf_reader
*
reader
=
NULL
;
static
char
*
event_type
=
"uprobe"
;
struct
ns_cookie
nsc
=
{
-
1
,
-
1
};
int
n
;
void
*
mount_ns_guard
=
NULL
;
snprintf
(
new_name
,
sizeof
(
new_name
),
"%s_bcc_%d"
,
ev_name
,
getpid
());
reader
=
perf_reader_new
(
cb
,
NULL
,
NULL
,
cb_cookie
,
probe_perf_reader_page_cnt
);
...
...
@@ -435,15 +435,15 @@ void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, con
goto
error
;
}
bcc_procutils_enter_mountns
(
pid
,
&
nsc
);
mount_ns_guard
=
bcc_enter_mount_ns
(
pid
);
if
(
write
(
kfd
,
buf
,
strlen
(
buf
))
<
0
)
{
if
(
errno
==
EINVAL
)
fprintf
(
stderr
,
"check dmesg output for possible cause
\n
"
);
close
(
kfd
);
goto
error
;
}
bcc_procutils_exit_mountns
(
&
nsc
);
close
(
kfd
);
bcc_exit_mount_ns
(
&
mount_ns_guard
);
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/events/%ss/%s"
,
event_type
,
new_name
);
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
reader
,
pid
,
cpu
,
group_fd
)
<
0
)
...
...
@@ -452,7 +452,7 @@ void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, con
return
reader
;
error:
bcc_
procutils_exit_mountns
(
&
nsc
);
bcc_
exit_mount_ns
(
&
mount_ns_guard
);
perf_reader_free
(
reader
);
return
NULL
;
}
...
...
src/cc/syms.h
View file @
78bf9fb4
...
...
@@ -16,12 +16,14 @@
#pragma once
#include <algorithm>
#include <memory>
#include <string>
#include <sys/types.h>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include
<sys/types.h>
#include
"common.h"
class
ProcStat
{
std
::
string
procfs_
;
...
...
@@ -64,6 +66,35 @@ public:
virtual
void
refresh
();
};
class
ProcMountNSGuard
;
class
ProcSyms
;
class
ProcMountNS
{
private:
explicit
ProcMountNS
(
int
pid
);
ebpf
::
FileDesc
self_fd_
;
ebpf
::
FileDesc
target_fd_
;
friend
class
ProcMountNSGuard
;
friend
class
ProcSyms
;
};
class
ProcMountNSGuard
{
public:
explicit
ProcMountNSGuard
(
ProcMountNS
*
mount_ns
);
explicit
ProcMountNSGuard
(
int
pid
);
~
ProcMountNSGuard
();
private:
void
init
();
std
::
unique_ptr
<
ProcMountNS
>
mount_ns_instance_
;
ProcMountNS
*
mount_ns_
;
bool
entered_
;
};
class
ProcSyms
:
SymbolCache
{
struct
Symbol
{
Symbol
(
const
std
::
string
*
name
,
uint64_t
start
,
uint64_t
size
,
int
flags
=
0
)
...
...
@@ -78,6 +109,13 @@ class ProcSyms : SymbolCache {
}
};
enum
class
ModuleType
{
UNKNOWN
,
EXEC
,
SO
,
PERF_MAP
};
struct
Module
{
struct
Range
{
uint64_t
start
;
...
...
@@ -85,13 +123,15 @@ class ProcSyms : SymbolCache {
Range
(
uint64_t
s
,
uint64_t
e
)
:
start
(
s
),
end
(
e
)
{}
};
Module
(
const
char
*
name
,
int
pid
,
bool
in_ns
);
Module
(
const
char
*
name
,
ProcMountNS
*
mount_ns
);
bool
init
();
std
::
string
name_
;
std
::
vector
<
Range
>
ranges_
;
bool
is_so_
;
int
pid_
;
bool
in_ns_
;
bool
loaded_
;
ProcMountNS
*
mount_ns_
;
ModuleType
type_
;
std
::
unordered_set
<
std
::
string
>
symnames_
;
std
::
vector
<
Symbol
>
syms_
;
...
...
@@ -100,8 +140,6 @@ class ProcSyms : SymbolCache {
uint64_t
start
()
const
{
return
ranges_
.
begin
()
->
start
;
}
bool
find_addr
(
uint64_t
addr
,
struct
bcc_symbol
*
sym
);
bool
find_name
(
const
char
*
symname
,
uint64_t
*
addr
);
bool
is_so
()
const
{
return
is_so_
;
}
bool
is_perf_map
()
const
;
static
int
_add_symbol
(
const
char
*
symname
,
uint64_t
start
,
uint64_t
end
,
int
flags
,
void
*
p
);
...
...
@@ -110,8 +148,9 @@ class ProcSyms : SymbolCache {
int
pid_
;
std
::
vector
<
Module
>
modules_
;
ProcStat
procstat_
;
std
::
unique_ptr
<
ProcMountNS
>
mount_ns_instance_
;
static
int
_add_module
(
const
char
*
,
uint64_t
,
uint64_t
,
void
*
);
static
int
_add_module
(
const
char
*
,
uint64_t
,
uint64_t
,
bool
,
void
*
);
bool
load_modules
();
public:
...
...
src/cc/table_desc.h
View file @
78bf9fb4
...
...
@@ -21,6 +21,8 @@
#include <memory>
#include <string>
#include "common.h"
namespace
llvm
{
class
Function
;
}
...
...
@@ -32,41 +34,6 @@ class QualType;
namespace
ebpf
{
class
TableDesc
;
/// FileDesc is a helper class for managing open file descriptors. Copy is
/// disallowed (call dup instead), and cleanup happens automatically.
class
FileDesc
{
friend
TableDesc
;
private:
FileDesc
&
operator
=
(
const
FileDesc
&
that
)
{
fd
=
::
dup
(
that
.
fd
);
return
*
this
;
}
FileDesc
(
const
FileDesc
&
that
)
{
*
this
=
that
;
}
public:
FileDesc
(
int
fd
=
-
1
)
:
fd
(
fd
)
{}
FileDesc
&
operator
=
(
FileDesc
&&
that
)
{
fd
=
that
.
fd
;
that
.
fd
=
-
1
;
return
*
this
;
}
FileDesc
(
FileDesc
&&
that
)
{
*
this
=
std
::
move
(
that
);
}
~
FileDesc
()
{
if
(
fd
>=
0
)
::
close
(
fd
);
}
FileDesc
dup
()
const
{
return
FileDesc
(
*
this
);
}
operator
int
()
{
return
fd
;
}
operator
int
()
const
{
return
fd
;
}
private:
int
fd
;
};
typedef
int
(
*
sscanf_fn
)(
const
char
*
,
void
*
);
typedef
int
(
*
snprintf_fn
)(
char
*
,
size_t
,
const
void
*
);
...
...
@@ -77,8 +44,22 @@ typedef int (*snprintf_fn)(char *, size_t, const void *);
/// so that objects of this class can reside in stl containers.
class
TableDesc
{
private:
TableDesc
(
const
TableDesc
&
)
=
default
;
TableDesc
&
operator
=
(
const
TableDesc
&
)
=
default
;
TableDesc
(
const
TableDesc
&
that
)
:
name
(
that
.
name
),
fd
(
that
.
fd
.
dup
()),
type
(
that
.
type
),
key_size
(
that
.
key_size
),
leaf_size
(
that
.
leaf_size
),
max_entries
(
that
.
max_entries
),
flags
(
that
.
flags
),
key_desc
(
that
.
key_desc
),
leaf_desc
(
that
.
leaf_desc
),
key_sscanf
(
that
.
key_sscanf
),
leaf_sscanf
(
that
.
leaf_sscanf
),
key_snprintf
(
that
.
key_snprintf
),
leaf_snprintf
(
that
.
leaf_snprintf
),
is_shared
(
that
.
is_shared
),
is_extern
(
that
.
is_extern
)
{}
public:
TableDesc
()
...
...
@@ -109,7 +90,10 @@ class TableDesc {
is_shared
(
false
),
is_extern
(
false
)
{}
TableDesc
(
TableDesc
&&
that
)
=
default
;
TableDesc
&
operator
=
(
TableDesc
&&
that
)
=
default
;
TableDesc
&
operator
=
(
const
TableDesc
&
that
)
=
delete
;
TableDesc
dup
()
const
{
return
TableDesc
(
*
this
);
}
std
::
string
name
;
...
...
src/cc/usdt.cc
View file @
78bf9fb4
...
...
@@ -48,7 +48,7 @@ Probe::Probe(const char *bin_path, const char *provider, const char *name,
bool
Probe
::
in_shared_object
()
{
if
(
!
in_shared_object_
)
in_shared_object_
=
(
bcc_elf_is_shared_obj
(
bin_path_
.
c_str
())
==
1
);
in_shared_object_
=
bcc_elf_is_shared_obj
(
bin_path_
.
c_str
()
);
return
in_shared_object_
.
value
();
}
...
...
@@ -199,7 +199,7 @@ void Context::_each_probe(const char *binpath, const struct bcc_elf_usdt *probe,
ctx
->
add_probe
(
binpath
,
probe
);
}
int
Context
::
_each_module
(
const
char
*
modpath
,
uint64_t
,
uint64_t
,
void
*
p
)
{
int
Context
::
_each_module
(
const
char
*
modpath
,
uint64_t
,
uint64_t
,
bool
,
void
*
p
)
{
Context
*
ctx
=
static_cast
<
Context
*>
(
p
);
// Modules may be reported multiple times if they contain more than one
// executable region. We are going to parse the ELF on disk anyway, so we
...
...
src/cc/usdt.h
View file @
78bf9fb4
...
...
@@ -199,7 +199,7 @@ class Context {
static
void
_each_probe
(
const
char
*
binpath
,
const
struct
bcc_elf_usdt
*
probe
,
void
*
p
);
static
int
_each_module
(
const
char
*
modpath
,
uint64_t
,
uint64_t
,
void
*
p
);
static
int
_each_module
(
const
char
*
modpath
,
uint64_t
,
uint64_t
,
bool
,
void
*
p
);
void
add_probe
(
const
char
*
binpath
,
const
struct
bcc_elf_usdt
*
probe
);
std
::
string
resolve_bin_path
(
const
std
::
string
&
bin_path
);
...
...
src/cc/usdt_args.cc
View file @
78bf9fb4
...
...
@@ -39,7 +39,7 @@ bool Argument::get_global_address(uint64_t *address, const std::string &binpath,
.
resolve_name
(
binpath
.
c_str
(),
deref_ident_
->
c_str
(),
address
);
}
if
(
bcc_elf_is_shared_obj
(
binpath
.
c_str
())
==
0
)
{
if
(
!
bcc_elf_is_shared_obj
(
binpath
.
c_str
())
)
{
struct
bcc_symbol
sym
=
{
deref_ident_
->
c_str
(),
binpath
.
c_str
(),
0x0
};
if
(
!
bcc_find_symbol_addr
(
&
sym
)
&&
sym
.
offset
)
{
*
address
=
sym
.
offset
;
...
...
tests/cc/test_c_api.cc
View file @
78bf9fb4
...
...
@@ -21,6 +21,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "bcc_elf.h"
...
...
@@ -306,7 +307,7 @@ static int perf_map_func_noop(void *arg) {
static
pid_t
spawn_child
(
void
*
map_addr
,
bool
own_pidns
,
bool
own_mntns
,
int
(
*
child_func
)(
void
*
))
{
int
flags
=
0
;
int
flags
=
SIGCHLD
;
if
(
own_pidns
)
flags
|=
CLONE_NEWPID
;
if
(
own_mntns
)
...
...
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