Skip to content

Commit cbdcb79

Browse files
authored
add support for init namespace to pid and tid (bpftrace#4254)
* docs: update descriptions about PID namespaces The manual didn't reflect the changes in bpftrace#3428. Signed-off-by: Junxuan Liao <[email protected]> * add support for init namespace to `pid` and `tid` Introduce two function variants of the built-ins. fixes bpftrace#4253. Signed-off-by: Junxuan Liao <[email protected]> --------- Signed-off-by: Junxuan Liao <[email protected]>
1 parent a333ff4 commit cbdcb79

16 files changed

+855
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ and this project adheres to
5555
- [#4126](https://github.com/bpftrace/bpftrace/pull/4126)
5656
- For loops now support `break` and `continue`
5757
- [#4250](https://github.com/bpftrace/bpftrace/pull/4250)
58+
- Add `pid` and `tid` functions for choosing between the initial or the current namespace
59+
- [#4254](https://github.com/bpftrace/bpftrace/pull/4254)
5860
#### Changed
5961
- `-p` CLI flag now applies to all probes (except BEGIN/END)
6062
- [#3800](https://github.com/bpftrace/bpftrace/pull/3800)

docs/migration_guide.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ config = {
2424
}
2525
```
2626

27+
## Versions 0.22.x (or earlier) to 0.24.x (or later)
28+
After https://github.com/bpftrace/bpftrace/pull/3428 `pid` and `tid` are no
29+
longer from the initial namespace.
30+
31+
https://github.com/bpftrace/bpftrace/pull/3428 introduced `pid(init)` and
32+
`tid(init)` which have the old behavior.
33+
Unfortunately, there are no equivalent workarounds in 0.23.x.
34+
2735
## Versions 0.21.x (or earlier) to 0.22.x (or later)
2836

2937
### Added block scoping for scratch variables

man/adoc/bpftrace.adoc

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,8 +1988,8 @@ For string arguments in an action block use the `str()` call to retrieve the val
19881988
| `pid`
19891989
| uint32
19901990
| 4.2
1991-
| get_current_pid_tgid
1992-
| Process ID of the current thread (aka thread group ID), as seen from the init namespace
1991+
| get_current_pid_tgid / get_ns_current_pid_tgid
1992+
| Process ID of the current thread (aka thread group ID), as seen from the PID namespace of bpftrace
19931993

19941994
| `probe`
19951995
| string
@@ -2018,8 +2018,8 @@ For string arguments in an action block use the `str()` call to retrieve the val
20182018
| `tid`
20192019
| uint32
20202020
| 4.2
2021-
| get_current_pid_tgid
2022-
| Thread ID of the current thread, as seen from the init namespace
2021+
| get_current_pid_tgid / get_ns_current_pid_tgid
2022+
| Thread ID of the current thread, as seen from the PID namespace of bpftrace
20232023

20242024
| `uid`
20252025
| uint64
@@ -2141,6 +2141,14 @@ Tracing block I/O sizes > 0 bytes
21412141
| Print file content
21422142
| Async
21432143

2144+
| <<functions-pid, `pid`>>
2145+
| Process ID of the current thread
2146+
| Sync
2147+
2148+
| <<functions-tid, `tid`>>
2149+
| Thread ID of the current thread
2150+
| Sync
2151+
21442152
| <<functions-cgroupid, `cgroupid`>>
21452153
| Resolve cgroup ID
21462154
| Compile Time
@@ -2350,6 +2358,28 @@ tracepoint:syscalls:sys_enter_execve {
23502358
55f683ee2000-55f683ee3000 rw-p 00000000 00:00 0
23512359
----
23522360

2361+
[#functions-pid]
2362+
=== pid
2363+
.variants
2364+
* `uint32 pid([curr_ns|init])`
2365+
2366+
Returns the process ID of the current thread.
2367+
Defaults to `curr_ns`.
2368+
2369+
- `pid(curr_ns)` - The process ID as seen from the PID namespace of bpftrace.
2370+
- `pid(init)` - The process ID as seen from the initial PID namespace.
2371+
2372+
[#functions-tid]
2373+
=== pid
2374+
.variants
2375+
* `uint32 tid([curr_ns|init])`
2376+
2377+
Returns the thread ID of the current thread.
2378+
Defaults to `curr_ns`.
2379+
2380+
- `tid(curr_ns)` - The thread ID as seen from the PID namespace of bpftrace.
2381+
- `tid(init)` - The thread ID as seen from the initial PID namespace.
2382+
23532383
[#functions-cgroupid]
23542384
=== cgroupid
23552385

src/ast/irbuilderbpf.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "bpftrace.h"
99
#include "globalvars.h"
1010
#include "log.h"
11+
#include "types.h"
1112
#include "util/exceptions.h"
1213
#include <filesystem>
1314
#include <llvm/IR/DataLayout.h>
@@ -74,10 +75,10 @@ libbpf::bpf_func_id IRBuilderBPF::selectProbeReadHelper(AddrSpace as, bool str)
7475
// It represents the inode of the initial (global) PID namespace
7576
constexpr uint32_t PROC_PID_INIT_INO = 0xeffffffc;
7677

77-
Value *IRBuilderBPF::CreateGetPid(const Location &loc)
78+
Value *IRBuilderBPF::CreateGetPid(const Location &loc, bool force_init)
7879
{
7980
const auto &pidns = bpftrace_.get_pidns_self_stat();
80-
if (pidns && pidns->st_ino != PROC_PID_INIT_INO) {
81+
if (!force_init && pidns && pidns->st_ino != PROC_PID_INIT_INO) {
8182
// Get namespaced target PID when we're running in a namespace
8283
AllocaInst *res = CreateAllocaBPF(BpfPidnsInfoType(), "bpf_pidns_info");
8384
CreateGetNsPidTgid(
@@ -89,16 +90,16 @@ Value *IRBuilderBPF::CreateGetPid(const Location &loc)
8990
return pid;
9091
}
9192

92-
// Get global target PID when we're in the initial namespace
93+
// Get global target PID otherwise
9394
Value *pidtgid = CreateGetPidTgid(loc);
9495
Value *pid = CreateTrunc(CreateLShr(pidtgid, 32), getInt32Ty(), "pid");
9596
return pid;
9697
}
9798

98-
Value *IRBuilderBPF::CreateGetTid(const Location &loc)
99+
Value *IRBuilderBPF::CreateGetTid(const Location &loc, bool force_init)
99100
{
100101
const auto &pidns = bpftrace_.get_pidns_self_stat();
101-
if (pidns && pidns->st_ino != PROC_PID_INIT_INO) {
102+
if (!force_init && pidns && pidns->st_ino != PROC_PID_INIT_INO) {
102103
// Get namespaced target TID when we're running in a namespace
103104
AllocaInst *res = CreateAllocaBPF(BpfPidnsInfoType(), "bpf_pidns_info");
104105
CreateGetNsPidTgid(
@@ -110,7 +111,7 @@ Value *IRBuilderBPF::CreateGetTid(const Location &loc)
110111
return tid;
111112
}
112113

113-
// Get global target TID when we're in the initial namespace
114+
// Get global target TID otherwise
114115
Value *pidtgid = CreateGetPidTgid(loc);
115116
Value *tid = CreateTrunc(pidtgid, getInt32Ty(), "tid");
116117
return tid;
@@ -128,7 +129,7 @@ AllocaInst *IRBuilderBPF::CreateUSym(Value *val,
128129
StructType *usym_t = GetStructType("usym_t", elements, false);
129130
AllocaInst *buf = CreateAllocaBPF(usym_t, "usym");
130131

131-
Value *pid = CreateGetPid(loc);
132+
Value *pid = CreateGetPid(loc, false);
132133
Value *probe_id_val = Constant::getIntegerValue(getInt32Ty(),
133134
APInt(32, probe_id));
134135

src/ast/irbuilderbpf.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ class IRBuilderBPF : public IRBuilder<> {
199199
StructType *GetStructType(const std::string &name,
200200
const std::vector<llvm::Type *> &elements,
201201
bool packed = false);
202-
Value *CreateGetPid(const Location &loc);
203-
Value *CreateGetTid(const Location &loc);
202+
Value *CreateGetPid(const Location &loc, bool force_init);
203+
Value *CreateGetTid(const Location &loc, bool force_init);
204204
AllocaInst *CreateUSym(Value *val, int probe_id, const Location &loc);
205205
Value *CreateRegisterRead(Value *ctx, const std::string &builtin);
206206
Value *CreateRegisterRead(Value *ctx, int offset, const std::string &name);

src/ast/passes/codegen_llvm.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ static auto getTargetMachine()
9696
return target;
9797
}
9898

99+
static bool shouldForceInitPidNs(const ExpressionList &args)
100+
{
101+
return args.size() == 1 && args.at(0).as<Identifier>()->ident == "init";
102+
}
103+
99104
using namespace llvm;
100105

101106
namespace {
@@ -622,7 +627,7 @@ ScopedExpr CodegenLLVM::kstack_ustack(const std::string &ident,
622627
// ustack keys are special: see IRBuilderBPF::GetStackStructType()
623628
if (is_ustack) {
624629
// store pid
625-
b_.CreateStore(b_.CreateGetPid(loc),
630+
b_.CreateStore(b_.CreateGetPid(loc, false),
626631
b_.CreateGEP(stack_key_struct,
627632
stack_key,
628633
{ b_.getInt64(0), b_.getInt32(2) }));
@@ -669,9 +674,9 @@ ScopedExpr CodegenLLVM::visit(Builtin &builtin)
669674
builtin.builtin_type.stack_type,
670675
builtin.loc);
671676
} else if (builtin.ident == "pid") {
672-
return ScopedExpr(b_.CreateGetPid(builtin.loc));
677+
return ScopedExpr(b_.CreateGetPid(builtin.loc, false));
673678
} else if (builtin.ident == "tid") {
674-
return ScopedExpr(b_.CreateGetTid(builtin.loc));
679+
return ScopedExpr(b_.CreateGetTid(builtin.loc, false));
675680
} else if (builtin.ident == "cgroup") {
676681
return ScopedExpr(b_.CreateGetCurrentCgroupId(builtin.loc));
677682
} else if (builtin.ident == "uid" || builtin.ident == "gid" ||
@@ -1807,6 +1812,14 @@ ScopedExpr CodegenLLVM::visit(Call &call)
18071812
} else {
18081813
return ScopedExpr(b_.CreateGetNs(call.return_type.ts_mode, call.loc));
18091814
}
1815+
} else if (call.func == "pid") {
1816+
bool force_init = shouldForceInitPidNs(call.vargs);
1817+
1818+
return ScopedExpr(b_.CreateGetPid(call.loc, force_init));
1819+
} else if (call.func == "tid") {
1820+
bool force_init = shouldForceInitPidNs(call.vargs);
1821+
1822+
return ScopedExpr(b_.CreateGetTid(call.loc, force_init));
18101823
} else {
18111824
LOG(BUG) << "missing codegen for function \"" << call.func << "\"";
18121825
__builtin_unreachable();

src/ast/passes/semantic_analyser.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,11 @@ static const std::map<std::string, call_spec> CALL_SPEC = {
590590
.arg_types={
591591
map_type_spec{},
592592
} } },
593+
{ "pid",
594+
{ .min_args=0,
595+
.max_args=1,
596+
.discard_ret_warn = true },
597+
},
593598
};
594599
// clang-format on
595600

@@ -754,6 +759,12 @@ void SemanticAnalyser::visit(Identifier &identifier)
754759
} else {
755760
identifier.addError() << "Invalid timestamp mode: " << identifier.ident;
756761
}
762+
} else if (func_ == "pid" || func_ == "tid") {
763+
if (identifier.ident != "curr_ns" && identifier.ident != "init") {
764+
identifier.addError()
765+
<< "Invalid PID namespace mode: " << identifier.ident
766+
<< " (expects: curr_ns or init)";
767+
}
757768
} else {
758769
// Final attempt: try to parse as a stack mode.
759770
ConfigParser<StackMode> parser;
@@ -1729,6 +1740,16 @@ If you're seeing errors, try clamping the string sizes. For example:
17291740
call.addError() << "Failed to initialize sw_tai in "
17301741
"userspace. This is very unexpected.";
17311742
}
1743+
} else if (call.func == "pid" || call.func == "tid") {
1744+
call.return_type = CreateUInt32();
1745+
if (call.vargs.size() == 1) {
1746+
auto &arg = call.vargs.at(0);
1747+
if (!(arg.as<Identifier>())) {
1748+
call.addError() << call.func
1749+
<< "() only supports curr_ns and init as the argument ("
1750+
<< arg.type().GetTy() << " provided)";
1751+
}
1752+
}
17321753
} else {
17331754
call.addError() << "Unknown function: '" << call.func << "'";
17341755
}

tests/codegen/call_pid_tid.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include "common.h"
2+
3+
namespace bpftrace {
4+
namespace test {
5+
namespace codegen {
6+
7+
TEST(codegen, call_pid_tid)
8+
{
9+
test("kprobe:f { @x = pid(); @y = tid() }", NAME);
10+
}
11+
12+
TEST(codegen, call_pid_tid_in_child_ns)
13+
{
14+
auto bpftrace = get_mock_bpftrace();
15+
bpftrace->mock_in_init_pid_ns = false;
16+
bpftrace->helper_check_level_ = 0;
17+
18+
test(*bpftrace, "kprobe:f { @x = pid(); @y = tid() }", NAME);
19+
}
20+
21+
TEST(codegen, call_pid_tid_curr_ns)
22+
{
23+
test("kprobe:f { @x = pid(curr_ns); @y = tid(curr_ns) }", NAME);
24+
}
25+
26+
TEST(codegen, call_pid_tid_curr_ns_in_child_ns)
27+
{
28+
auto bpftrace = get_mock_bpftrace();
29+
bpftrace->mock_in_init_pid_ns = false;
30+
bpftrace->helper_check_level_ = 0;
31+
32+
test(*bpftrace, "kprobe:f { @x = pid(curr_ns); @y = tid(curr_ns) }", NAME);
33+
}
34+
35+
TEST(codegen, call_pid_tid_init)
36+
{
37+
test("kprobe:f { @x = pid(init); @y = tid(init) }", NAME);
38+
}
39+
40+
TEST(codegen, call_pid_tid_init_ns_in_child_ns)
41+
{
42+
auto bpftrace = get_mock_bpftrace();
43+
bpftrace->mock_in_init_pid_ns = false;
44+
bpftrace->helper_check_level_ = 0;
45+
46+
test(*bpftrace, "kprobe:f { @x = pid(init); @y = tid(init) }", NAME);
47+
}
48+
49+
} // namespace codegen
50+
} // namespace test
51+
} // namespace bpftrace

0 commit comments

Comments
 (0)