1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2016 GitHub, Inc.
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker #include <linux/version.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <sys/types.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <sys/wait.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Worker #include "catch.hpp"
23*387f9dfdSAndroid Build Coastguard Worker #include "usdt.h"
24*387f9dfdSAndroid Build Coastguard Worker #include "api/BPF.h"
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Worker /* required to insert USDT probes on this very executable --
27*387f9dfdSAndroid Build Coastguard Worker * we're gonna be testing them live! */
28*387f9dfdSAndroid Build Coastguard Worker #include "folly/tracing/StaticTracepoint.h"
29*387f9dfdSAndroid Build Coastguard Worker
a_probed_function()30*387f9dfdSAndroid Build Coastguard Worker static int a_probed_function() {
31*387f9dfdSAndroid Build Coastguard Worker int an_int = 23 + getpid();
32*387f9dfdSAndroid Build Coastguard Worker void *a_pointer = malloc(4);
33*387f9dfdSAndroid Build Coastguard Worker FOLLY_SDT(libbcc_test, sample_probe_1, an_int, a_pointer);
34*387f9dfdSAndroid Build Coastguard Worker free(a_pointer);
35*387f9dfdSAndroid Build Coastguard Worker return an_int;
36*387f9dfdSAndroid Build Coastguard Worker }
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
FOLLY_SDT_DEFINE_SEMAPHORE(libbcc_test,sample_probe_2)39*387f9dfdSAndroid Build Coastguard Worker FOLLY_SDT_DEFINE_SEMAPHORE(libbcc_test, sample_probe_2)
40*387f9dfdSAndroid Build Coastguard Worker static int a_probed_function_with_sem() {
41*387f9dfdSAndroid Build Coastguard Worker int an_int = 23 + getpid();
42*387f9dfdSAndroid Build Coastguard Worker void *a_pointer = malloc(4);
43*387f9dfdSAndroid Build Coastguard Worker FOLLY_SDT_WITH_SEMAPHORE(libbcc_test, sample_probe_2, an_int, a_pointer);
44*387f9dfdSAndroid Build Coastguard Worker free(a_pointer);
45*387f9dfdSAndroid Build Coastguard Worker return an_int;
46*387f9dfdSAndroid Build Coastguard Worker }
47*387f9dfdSAndroid Build Coastguard Worker #endif // linux version >= 4.20
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Worker extern "C" int lib_probed_function();
50*387f9dfdSAndroid Build Coastguard Worker
call_shared_lib_func()51*387f9dfdSAndroid Build Coastguard Worker int call_shared_lib_func() {
52*387f9dfdSAndroid Build Coastguard Worker return lib_probed_function();
53*387f9dfdSAndroid Build Coastguard Worker }
54*387f9dfdSAndroid Build Coastguard Worker
55*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test finding a probe in our own process", "[usdt]") {
56*387f9dfdSAndroid Build Coastguard Worker USDT::Context ctx(getpid());
57*387f9dfdSAndroid Build Coastguard Worker REQUIRE(ctx.num_probes() >= 1);
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker SECTION("our test probe") {
60*387f9dfdSAndroid Build Coastguard Worker auto probe = ctx.get("sample_probe_1");
61*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe);
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker if(probe->in_shared_object(probe->bin_path()))
64*387f9dfdSAndroid Build Coastguard Worker return;
65*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->name() == "sample_probe_1");
66*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->provider() == "libbcc_test");
67*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->bin_path().find("/test_libbcc") != std::string::npos);
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_locations() == 1);
70*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_arguments() == 2);
71*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->need_enable() == false);
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker REQUIRE(a_probed_function() != 0);
74*387f9dfdSAndroid Build Coastguard Worker }
75*387f9dfdSAndroid Build Coastguard Worker }
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test probe's attributes with C++ API", "[usdt]") {
78*387f9dfdSAndroid Build Coastguard Worker const ebpf::USDT u("/proc/self/exe", "libbcc_test", "sample_probe_1", "on_event");
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker REQUIRE(u.binary_path() == "/proc/self/exe");
81*387f9dfdSAndroid Build Coastguard Worker REQUIRE(u.pid() == -1);
82*387f9dfdSAndroid Build Coastguard Worker REQUIRE(u.provider() == "libbcc_test");
83*387f9dfdSAndroid Build Coastguard Worker REQUIRE(u.name() == "sample_probe_1");
84*387f9dfdSAndroid Build Coastguard Worker REQUIRE(u.probe_func() == "on_event");
85*387f9dfdSAndroid Build Coastguard Worker }
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test fine a probe in our own binary with C++ API", "[usdt]") {
88*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
89*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u("/proc/self/exe", "libbcc_test", "sample_probe_1", "on_event");
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
92*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt(u);
95*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt(u);
98*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
99*387f9dfdSAndroid Build Coastguard Worker }
100*387f9dfdSAndroid Build Coastguard Worker
101*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test fine probes in our own binary with C++ API", "[usdt]") {
102*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
103*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u("/proc/self/exe", "libbcc_test", "sample_probe_1", "on_event");
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
106*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt_all();
109*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt_all();
112*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
113*387f9dfdSAndroid Build Coastguard Worker }
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test fine a probe in our Process with C++ API", "[usdt]") {
116*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
117*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(::getpid(), "libbcc_test", "sample_probe_1", "on_event");
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
120*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt(u);
123*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
124*387f9dfdSAndroid Build Coastguard Worker
125*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt(u);
126*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
127*387f9dfdSAndroid Build Coastguard Worker }
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test find a probe in our process' shared libs with c++ API", "[usdt]") {
130*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
131*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(::getpid(), "libbcc_test", "sample_lib_probe_1", "on_event");
132*387f9dfdSAndroid Build Coastguard Worker
133*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
134*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() == "");
135*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
136*387f9dfdSAndroid Build Coastguard Worker }
137*387f9dfdSAndroid Build Coastguard Worker
138*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test usdt partial init w/ fail init_usdt", "[usdt]") {
139*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
140*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(::getpid(), "libbcc_test", "sample_lib_probe_nonexistent", "on_event");
141*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT p(::getpid(), "libbcc_test", "sample_lib_probe_1", "on_event");
142*387f9dfdSAndroid Build Coastguard Worker
143*387f9dfdSAndroid Build Coastguard Worker // We should be able to fail initialization and subsequently do bpf.init w/o USDT
144*387f9dfdSAndroid Build Coastguard Worker // successfully
145*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init_usdt(u);
146*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() != "");
147*387f9dfdSAndroid Build Coastguard Worker REQUIRE(!res.ok());
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Worker // Shouldn't be necessary to re-init bpf object either after failure to init w/
150*387f9dfdSAndroid Build Coastguard Worker // bad USDT
151*387f9dfdSAndroid Build Coastguard Worker res = bpf.init("int on_event() { return 0; }", {}, {u});
152*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() != "");
153*387f9dfdSAndroid Build Coastguard Worker REQUIRE(!res.ok());
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker res = bpf.init_usdt(p);
156*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() == "");
157*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker res = bpf.init("int on_event() { return 0; }", {}, {});
160*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() == "");
161*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
162*387f9dfdSAndroid Build Coastguard Worker }
163*387f9dfdSAndroid Build Coastguard Worker
164*387f9dfdSAndroid Build Coastguard Worker class ChildProcess {
165*387f9dfdSAndroid Build Coastguard Worker pid_t pid_;
166*387f9dfdSAndroid Build Coastguard Worker
167*387f9dfdSAndroid Build Coastguard Worker public:
ChildProcess(const char * name,char * const argv[])168*387f9dfdSAndroid Build Coastguard Worker ChildProcess(const char *name, char *const argv[]) {
169*387f9dfdSAndroid Build Coastguard Worker pid_ = fork();
170*387f9dfdSAndroid Build Coastguard Worker if (pid_ == 0) {
171*387f9dfdSAndroid Build Coastguard Worker execvp(name, argv);
172*387f9dfdSAndroid Build Coastguard Worker exit(0);
173*387f9dfdSAndroid Build Coastguard Worker }
174*387f9dfdSAndroid Build Coastguard Worker if (spawned()) {
175*387f9dfdSAndroid Build Coastguard Worker usleep(250000);
176*387f9dfdSAndroid Build Coastguard Worker if (kill(pid_, 0) < 0)
177*387f9dfdSAndroid Build Coastguard Worker pid_ = -1;
178*387f9dfdSAndroid Build Coastguard Worker }
179*387f9dfdSAndroid Build Coastguard Worker }
180*387f9dfdSAndroid Build Coastguard Worker
~ChildProcess()181*387f9dfdSAndroid Build Coastguard Worker ~ChildProcess() {
182*387f9dfdSAndroid Build Coastguard Worker if (spawned()) {
183*387f9dfdSAndroid Build Coastguard Worker int status;
184*387f9dfdSAndroid Build Coastguard Worker kill(pid_, SIGKILL);
185*387f9dfdSAndroid Build Coastguard Worker if (waitpid(pid_, &status, 0) != pid_)
186*387f9dfdSAndroid Build Coastguard Worker abort();
187*387f9dfdSAndroid Build Coastguard Worker }
188*387f9dfdSAndroid Build Coastguard Worker }
189*387f9dfdSAndroid Build Coastguard Worker
spawned() const190*387f9dfdSAndroid Build Coastguard Worker bool spawned() const { return pid_ > 0; }
pid() const191*387f9dfdSAndroid Build Coastguard Worker pid_t pid() const { return pid_; }
192*387f9dfdSAndroid Build Coastguard Worker };
193*387f9dfdSAndroid Build Coastguard Worker
194*387f9dfdSAndroid Build Coastguard Worker extern int cmd_scanf(const char *cmd, const char *fmt, ...);
195*387f9dfdSAndroid Build Coastguard Worker
probe_num_locations(const char * bin_path,const char * func_name)196*387f9dfdSAndroid Build Coastguard Worker static int probe_num_locations(const char *bin_path, const char *func_name) {
197*387f9dfdSAndroid Build Coastguard Worker int num_locations;
198*387f9dfdSAndroid Build Coastguard Worker char cmd[512];
199*387f9dfdSAndroid Build Coastguard Worker const char *cmdfmt = "readelf -n %s | grep -c \"Name: %s$\"";
200*387f9dfdSAndroid Build Coastguard Worker
201*387f9dfdSAndroid Build Coastguard Worker sprintf(cmd, cmdfmt, bin_path, func_name);
202*387f9dfdSAndroid Build Coastguard Worker if (cmd_scanf(cmd, "%d", &num_locations) != 0) {
203*387f9dfdSAndroid Build Coastguard Worker return -1;
204*387f9dfdSAndroid Build Coastguard Worker }
205*387f9dfdSAndroid Build Coastguard Worker
206*387f9dfdSAndroid Build Coastguard Worker return num_locations;
207*387f9dfdSAndroid Build Coastguard Worker }
208*387f9dfdSAndroid Build Coastguard Worker
probe_num_arguments(const char * bin_path,const char * func_name)209*387f9dfdSAndroid Build Coastguard Worker static int probe_num_arguments(const char *bin_path, const char *func_name) {
210*387f9dfdSAndroid Build Coastguard Worker int num_arguments;
211*387f9dfdSAndroid Build Coastguard Worker char cmd[512];
212*387f9dfdSAndroid Build Coastguard Worker const char *cmdfmt = "readelf -n %s | grep -m 1 -A 2 \" %s$\" | " \
213*387f9dfdSAndroid Build Coastguard Worker "tail -1 | cut -d \" \" -f 6- | wc -w";
214*387f9dfdSAndroid Build Coastguard Worker
215*387f9dfdSAndroid Build Coastguard Worker sprintf(cmd, cmdfmt, bin_path, func_name);
216*387f9dfdSAndroid Build Coastguard Worker if (cmd_scanf(cmd, "%d", &num_arguments) != 0) {
217*387f9dfdSAndroid Build Coastguard Worker return -1;
218*387f9dfdSAndroid Build Coastguard Worker }
219*387f9dfdSAndroid Build Coastguard Worker
220*387f9dfdSAndroid Build Coastguard Worker return num_arguments;
221*387f9dfdSAndroid Build Coastguard Worker }
222*387f9dfdSAndroid Build Coastguard Worker
223*387f9dfdSAndroid Build Coastguard Worker // Unsharing pid namespace requires forking
224*387f9dfdSAndroid Build Coastguard Worker // this uses pgrep to find the child process, by searching for a process
225*387f9dfdSAndroid Build Coastguard Worker // that has the unshare as its parent
unshared_child_pid(const int ppid)226*387f9dfdSAndroid Build Coastguard Worker static int unshared_child_pid(const int ppid) {
227*387f9dfdSAndroid Build Coastguard Worker int child_pid;
228*387f9dfdSAndroid Build Coastguard Worker char cmd[512];
229*387f9dfdSAndroid Build Coastguard Worker const char *cmdfmt = "pgrep -P %d";
230*387f9dfdSAndroid Build Coastguard Worker
231*387f9dfdSAndroid Build Coastguard Worker sprintf(cmd, cmdfmt, ppid);
232*387f9dfdSAndroid Build Coastguard Worker if (cmd_scanf(cmd, "%d", &child_pid) != 0) {
233*387f9dfdSAndroid Build Coastguard Worker return -1;
234*387f9dfdSAndroid Build Coastguard Worker }
235*387f9dfdSAndroid Build Coastguard Worker return child_pid;
236*387f9dfdSAndroid Build Coastguard Worker }
237*387f9dfdSAndroid Build Coastguard Worker
238*387f9dfdSAndroid Build Coastguard Worker // FIXME This seems like a legitimate bug with probing ruby where the
239*387f9dfdSAndroid Build Coastguard Worker // ruby symbols are in libruby.so?
240*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt][!mayfail]") {
241*387f9dfdSAndroid Build Coastguard Worker size_t mri_probe_count = 0;
242*387f9dfdSAndroid Build Coastguard Worker
243*387f9dfdSAndroid Build Coastguard Worker SECTION("without a running Ruby process") {
244*387f9dfdSAndroid Build Coastguard Worker USDT::Context ctx("ruby");
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Worker if (!ctx.loaded())
247*387f9dfdSAndroid Build Coastguard Worker return;
248*387f9dfdSAndroid Build Coastguard Worker
249*387f9dfdSAndroid Build Coastguard Worker REQUIRE(ctx.num_probes() > 10);
250*387f9dfdSAndroid Build Coastguard Worker mri_probe_count = ctx.num_probes();
251*387f9dfdSAndroid Build Coastguard Worker
252*387f9dfdSAndroid Build Coastguard Worker SECTION("GC static probe") {
253*387f9dfdSAndroid Build Coastguard Worker auto name = "gc__mark__begin";
254*387f9dfdSAndroid Build Coastguard Worker auto probe = ctx.get(name);
255*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe);
256*387f9dfdSAndroid Build Coastguard Worker
257*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->in_shared_object(probe->bin_path()) == true);
258*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->name() == name);
259*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->provider() == "ruby");
260*387f9dfdSAndroid Build Coastguard Worker
261*387f9dfdSAndroid Build Coastguard Worker auto bin_path = probe->bin_path();
262*387f9dfdSAndroid Build Coastguard Worker bool bin_path_match =
263*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/ruby") != std::string::npos) ||
264*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/libruby") != std::string::npos);
265*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bin_path_match);
266*387f9dfdSAndroid Build Coastguard Worker
267*387f9dfdSAndroid Build Coastguard Worker int exp_locations, exp_arguments;
268*387f9dfdSAndroid Build Coastguard Worker exp_locations = probe_num_locations(bin_path.c_str(), name);
269*387f9dfdSAndroid Build Coastguard Worker exp_arguments = probe_num_arguments(bin_path.c_str(), name);
270*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_locations() == exp_locations);
271*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_arguments() == exp_arguments);
272*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->need_enable() == true);
273*387f9dfdSAndroid Build Coastguard Worker }
274*387f9dfdSAndroid Build Coastguard Worker
275*387f9dfdSAndroid Build Coastguard Worker SECTION("object creation probe") {
276*387f9dfdSAndroid Build Coastguard Worker auto name = "object__create";
277*387f9dfdSAndroid Build Coastguard Worker auto probe = ctx.get(name);
278*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe);
279*387f9dfdSAndroid Build Coastguard Worker
280*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->in_shared_object(probe->bin_path()) == true);
281*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->name() == name);
282*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->provider() == "ruby");
283*387f9dfdSAndroid Build Coastguard Worker
284*387f9dfdSAndroid Build Coastguard Worker auto bin_path = probe->bin_path();
285*387f9dfdSAndroid Build Coastguard Worker bool bin_path_match =
286*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/ruby") != std::string::npos) ||
287*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/libruby") != std::string::npos);
288*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bin_path_match);
289*387f9dfdSAndroid Build Coastguard Worker
290*387f9dfdSAndroid Build Coastguard Worker int exp_locations, exp_arguments;
291*387f9dfdSAndroid Build Coastguard Worker exp_locations = probe_num_locations(bin_path.c_str(), name);
292*387f9dfdSAndroid Build Coastguard Worker exp_arguments = probe_num_arguments(bin_path.c_str(), name);
293*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_locations() == exp_locations);
294*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_arguments() == exp_arguments);
295*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->need_enable() == true);
296*387f9dfdSAndroid Build Coastguard Worker }
297*387f9dfdSAndroid Build Coastguard Worker
298*387f9dfdSAndroid Build Coastguard Worker SECTION("array creation probe") {
299*387f9dfdSAndroid Build Coastguard Worker auto name = "array__create";
300*387f9dfdSAndroid Build Coastguard Worker auto probe = ctx.get(name);
301*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe);
302*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->name() == name);
303*387f9dfdSAndroid Build Coastguard Worker
304*387f9dfdSAndroid Build Coastguard Worker auto bin_path = probe->bin_path().c_str();
305*387f9dfdSAndroid Build Coastguard Worker int exp_locations, exp_arguments;
306*387f9dfdSAndroid Build Coastguard Worker exp_locations = probe_num_locations(bin_path, name);
307*387f9dfdSAndroid Build Coastguard Worker exp_arguments = probe_num_arguments(bin_path, name);
308*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_locations() == exp_locations);
309*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_arguments() == exp_arguments);
310*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->need_enable() == true);
311*387f9dfdSAndroid Build Coastguard Worker }
312*387f9dfdSAndroid Build Coastguard Worker }
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Worker SECTION("with a running Ruby process") {
315*387f9dfdSAndroid Build Coastguard Worker static char _ruby[] = "ruby";
316*387f9dfdSAndroid Build Coastguard Worker char *const argv[2] = {_ruby, NULL};
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Worker ChildProcess ruby(argv[0], argv);
319*387f9dfdSAndroid Build Coastguard Worker if (!ruby.spawned())
320*387f9dfdSAndroid Build Coastguard Worker return;
321*387f9dfdSAndroid Build Coastguard Worker
322*387f9dfdSAndroid Build Coastguard Worker USDT::Context ctx(ruby.pid());
323*387f9dfdSAndroid Build Coastguard Worker REQUIRE(ctx.num_probes() >= mri_probe_count);
324*387f9dfdSAndroid Build Coastguard Worker
325*387f9dfdSAndroid Build Coastguard Worker SECTION("get probe in running process") {
326*387f9dfdSAndroid Build Coastguard Worker auto name = "gc__mark__begin";
327*387f9dfdSAndroid Build Coastguard Worker auto probe = ctx.get(name);
328*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe);
329*387f9dfdSAndroid Build Coastguard Worker
330*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->in_shared_object(probe->bin_path()) == true);
331*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->name() == name);
332*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->provider() == "ruby");
333*387f9dfdSAndroid Build Coastguard Worker
334*387f9dfdSAndroid Build Coastguard Worker auto bin_path = probe->bin_path();
335*387f9dfdSAndroid Build Coastguard Worker bool bin_path_match =
336*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/ruby") != std::string::npos) ||
337*387f9dfdSAndroid Build Coastguard Worker (bin_path.find("/libruby") != std::string::npos);
338*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bin_path_match);
339*387f9dfdSAndroid Build Coastguard Worker
340*387f9dfdSAndroid Build Coastguard Worker int exp_locations, exp_arguments;
341*387f9dfdSAndroid Build Coastguard Worker exp_locations = probe_num_locations(bin_path.c_str(), name);
342*387f9dfdSAndroid Build Coastguard Worker exp_arguments = probe_num_arguments(bin_path.c_str(), name);
343*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_locations() == exp_locations);
344*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->num_arguments() == exp_arguments);
345*387f9dfdSAndroid Build Coastguard Worker REQUIRE(probe->need_enable() == true);
346*387f9dfdSAndroid Build Coastguard Worker }
347*387f9dfdSAndroid Build Coastguard Worker }
348*387f9dfdSAndroid Build Coastguard Worker }
349*387f9dfdSAndroid Build Coastguard Worker
350*387f9dfdSAndroid Build Coastguard Worker // These tests are expected to fail if there is no Ruby with dtrace probes
351*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("test probing running Ruby process in namespaces",
352*387f9dfdSAndroid Build Coastguard Worker "[usdt][!mayfail]") {
353*387f9dfdSAndroid Build Coastguard Worker SECTION("in separate mount namespace") {
354*387f9dfdSAndroid Build Coastguard Worker static char _unshare[] = "unshare";
355*387f9dfdSAndroid Build Coastguard Worker const char *const argv[4] = {_unshare, "--mount", "ruby", NULL};
356*387f9dfdSAndroid Build Coastguard Worker
357*387f9dfdSAndroid Build Coastguard Worker ChildProcess unshare(argv[0], (char **const)argv);
358*387f9dfdSAndroid Build Coastguard Worker if (!unshare.spawned())
359*387f9dfdSAndroid Build Coastguard Worker return;
360*387f9dfdSAndroid Build Coastguard Worker int ruby_pid = unshare.pid();
361*387f9dfdSAndroid Build Coastguard Worker
362*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
363*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(ruby_pid, "ruby", "gc__mark__begin", "on_event");
364*387f9dfdSAndroid Build Coastguard Worker u.set_probe_matching_kludge(1); // Also required for overlayfs...
365*387f9dfdSAndroid Build Coastguard Worker
366*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
367*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() == "");
368*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
369*387f9dfdSAndroid Build Coastguard Worker
370*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt(u, ruby_pid);
371*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
372*387f9dfdSAndroid Build Coastguard Worker
373*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt(u, ruby_pid);
374*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
375*387f9dfdSAndroid Build Coastguard Worker }
376*387f9dfdSAndroid Build Coastguard Worker
377*387f9dfdSAndroid Build Coastguard Worker SECTION("in separate mount namespace and separate PID namespace") {
378*387f9dfdSAndroid Build Coastguard Worker static char _unshare[] = "unshare";
379*387f9dfdSAndroid Build Coastguard Worker const char *const argv[8] = {_unshare, "--fork",
380*387f9dfdSAndroid Build Coastguard Worker "--mount", "--pid", "--mount-proc",
381*387f9dfdSAndroid Build Coastguard Worker "ruby", NULL};
382*387f9dfdSAndroid Build Coastguard Worker
383*387f9dfdSAndroid Build Coastguard Worker ChildProcess unshare(argv[0], (char **const)argv);
384*387f9dfdSAndroid Build Coastguard Worker if (!unshare.spawned())
385*387f9dfdSAndroid Build Coastguard Worker return;
386*387f9dfdSAndroid Build Coastguard Worker int ruby_pid = unshared_child_pid(unshare.pid());
387*387f9dfdSAndroid Build Coastguard Worker
388*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
389*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(ruby_pid, "ruby", "gc__mark__begin", "on_event");
390*387f9dfdSAndroid Build Coastguard Worker u.set_probe_matching_kludge(1); // Also required for overlayfs...
391*387f9dfdSAndroid Build Coastguard Worker
392*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
393*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.msg() == "");
394*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
395*387f9dfdSAndroid Build Coastguard Worker
396*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt(u, ruby_pid);
397*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
398*387f9dfdSAndroid Build Coastguard Worker
399*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt(u, ruby_pid);
400*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
401*387f9dfdSAndroid Build Coastguard Worker
402*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
403*387f9dfdSAndroid Build Coastguard Worker std::string pid_root= "/proc/" + std::to_string(ruby_pid) + "/root/";
404*387f9dfdSAndroid Build Coastguard Worker std::string module = pid_root + "usr/local/bin/ruby";
405*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_resolve_symname(module.c_str(), "rb_gc_mark", 0x0, ruby_pid, nullptr, &sym) == 0);
406*387f9dfdSAndroid Build Coastguard Worker REQUIRE(std::string(sym.module).find(pid_root, 1) == std::string::npos);
407*387f9dfdSAndroid Build Coastguard Worker kill(ruby_pid, SIGKILL);
408*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_free(sym.module);
409*387f9dfdSAndroid Build Coastguard Worker }
410*387f9dfdSAndroid Build Coastguard Worker }
411*387f9dfdSAndroid Build Coastguard Worker
412*387f9dfdSAndroid Build Coastguard Worker #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
413*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("Test uprobe refcnt semaphore activation", "[usdt]") {
414*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF bpf;
415*387f9dfdSAndroid Build Coastguard Worker
416*387f9dfdSAndroid Build Coastguard Worker REQUIRE(!FOLLY_SDT_IS_ENABLED(libbcc_test, sample_probe_2));
417*387f9dfdSAndroid Build Coastguard Worker
418*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u("/proc/self/exe", "libbcc_test", "sample_probe_2", "on_event");
419*387f9dfdSAndroid Build Coastguard Worker
420*387f9dfdSAndroid Build Coastguard Worker auto res = bpf.init("int on_event() { return 0; }", {}, {u});
421*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
422*387f9dfdSAndroid Build Coastguard Worker
423*387f9dfdSAndroid Build Coastguard Worker res = bpf.attach_usdt(u);
424*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
425*387f9dfdSAndroid Build Coastguard Worker
426*387f9dfdSAndroid Build Coastguard Worker REQUIRE(FOLLY_SDT_IS_ENABLED(libbcc_test, sample_probe_2));
427*387f9dfdSAndroid Build Coastguard Worker
428*387f9dfdSAndroid Build Coastguard Worker res = bpf.detach_usdt(u);
429*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res.ok());
430*387f9dfdSAndroid Build Coastguard Worker
431*387f9dfdSAndroid Build Coastguard Worker REQUIRE(a_probed_function_with_sem() != 0);
432*387f9dfdSAndroid Build Coastguard Worker }
433*387f9dfdSAndroid Build Coastguard Worker #endif // linux version >= 4.20
434