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 <dlfcn.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <link.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <stdint.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
22*387f9dfdSAndroid Build Coastguard Worker #include <sys/mman.h>
23*387f9dfdSAndroid Build Coastguard Worker #include <sys/mount.h>
24*387f9dfdSAndroid Build Coastguard Worker #include <sys/stat.h>
25*387f9dfdSAndroid Build Coastguard Worker #include <sys/types.h>
26*387f9dfdSAndroid Build Coastguard Worker #include <sys/wait.h>
27*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
28*387f9dfdSAndroid Build Coastguard Worker
29*387f9dfdSAndroid Build Coastguard Worker #include <cstdlib>
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker #include "bcc_elf.h"
32*387f9dfdSAndroid Build Coastguard Worker #include "bcc_perf_map.h"
33*387f9dfdSAndroid Build Coastguard Worker #include "bcc_proc.h"
34*387f9dfdSAndroid Build Coastguard Worker #include "bcc_syms.h"
35*387f9dfdSAndroid Build Coastguard Worker #include "catch.hpp"
36*387f9dfdSAndroid Build Coastguard Worker #include "common.h"
37*387f9dfdSAndroid Build Coastguard Worker #include "vendor/tinyformat.hpp"
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker using namespace std;
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Worker static pid_t spawn_child(void *, bool, bool, int (*)(void *));
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("language detection", "[c_api]") {
44*387f9dfdSAndroid Build Coastguard Worker const char *c = bcc_procutils_language(getpid());
45*387f9dfdSAndroid Build Coastguard Worker REQUIRE(c);
46*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(c).compare("c") == 0);
47*387f9dfdSAndroid Build Coastguard Worker }
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("shared object resolution", "[c_api]") {
50*387f9dfdSAndroid Build Coastguard Worker char *libm = bcc_procutils_which_so("m", 0);
51*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libm);
52*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libm[0] == '/');
53*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(libm).find("libm.so") != string::npos);
54*387f9dfdSAndroid Build Coastguard Worker free(libm);
55*387f9dfdSAndroid Build Coastguard Worker }
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("shared object resolution using loaded libraries", "[c_api]") {
58*387f9dfdSAndroid Build Coastguard Worker char *libelf = bcc_procutils_which_so("elf", getpid());
59*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libelf);
60*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libelf[0] == '/');
61*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(libelf).find("libelf") != string::npos);
62*387f9dfdSAndroid Build Coastguard Worker free(libelf);
63*387f9dfdSAndroid Build Coastguard Worker }
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("binary resolution with `which`", "[c_api]") {
66*387f9dfdSAndroid Build Coastguard Worker char *ld = bcc_procutils_which("ld");
67*387f9dfdSAndroid Build Coastguard Worker REQUIRE(ld);
68*387f9dfdSAndroid Build Coastguard Worker REQUIRE(ld[0] == '/');
69*387f9dfdSAndroid Build Coastguard Worker free(ld);
70*387f9dfdSAndroid Build Coastguard Worker }
71*387f9dfdSAndroid Build Coastguard Worker
_test_ksym(const char * sym,const char * mod,uint64_t addr,void * _)72*387f9dfdSAndroid Build Coastguard Worker static void _test_ksym(const char *sym, const char *mod, uint64_t addr, void *_) {
73*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(sym, "startup_64"))
74*387f9dfdSAndroid Build Coastguard Worker REQUIRE(addr != 0x0ull);
75*387f9dfdSAndroid Build Coastguard Worker }
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("list all kernel symbols", "[c_api]") {
78*387f9dfdSAndroid Build Coastguard Worker if (geteuid() != 0)
79*387f9dfdSAndroid Build Coastguard Worker return;
80*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_each_ksym(_test_ksym, NULL);
81*387f9dfdSAndroid Build Coastguard Worker }
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("file-backed mapping identification") {
84*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("/bin/ls") == 1);
85*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("") == 0);
86*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("//anon") == 0);
87*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("/dev/zero") == 0);
88*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("/anon_hugepage") == 0);
89*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("/anon_hugepage (deleted)") == 0);
90*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("[stack") == 0);
91*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("/SYSV") == 0);
92*387f9dfdSAndroid Build Coastguard Worker CHECK(bcc_mapping_is_file_backed("[heap]") == 0);
93*387f9dfdSAndroid Build Coastguard Worker }
94*387f9dfdSAndroid Build Coastguard Worker
95*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name in external library", "[c_api]") {
96*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_resolve_symname("c", "malloc", 0x0, 0, nullptr, &sym) == 0);
99*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module).find("libc.so") != string::npos);
100*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module[0] == '/');
101*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.offset != 0);
102*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_free(sym.module);
103*387f9dfdSAndroid Build Coastguard Worker }
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name in external library using loaded libraries", "[c_api]") {
106*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_resolve_symname("bcc", "bcc_procutils_which", 0x0, getpid(), nullptr, &sym) == 0);
109*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module).find(LIBBCC_NAME) != string::npos);
110*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module[0] == '/');
111*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.offset != 0);
112*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_free(sym.module);
113*387f9dfdSAndroid Build Coastguard Worker }
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker namespace {
116*387f9dfdSAndroid Build Coastguard Worker
zipped_lib_path()117*387f9dfdSAndroid Build Coastguard Worker static std::string zipped_lib_path() {
118*387f9dfdSAndroid Build Coastguard Worker return CMAKE_CURRENT_BINARY_DIR "/archive.zip!/libdebuginfo_test_lib.so";
119*387f9dfdSAndroid Build Coastguard Worker }
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker } // namespace
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name in external zipped library", "[c_api]") {
124*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
125*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_resolve_symname(zipped_lib_path().c_str(), "symbol", 0x0, 0,
126*387f9dfdSAndroid Build Coastguard Worker nullptr, &sym) == 0);
127*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module == zipped_lib_path());
128*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.offset != 0);
129*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_free(sym.module);
130*387f9dfdSAndroid Build Coastguard Worker }
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker namespace {
133*387f9dfdSAndroid Build Coastguard Worker
system(const std::string & command)134*387f9dfdSAndroid Build Coastguard Worker void system(const std::string &command) {
135*387f9dfdSAndroid Build Coastguard Worker if (::system(command.c_str())) {
136*387f9dfdSAndroid Build Coastguard Worker abort();
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker }
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Worker class TmpDir {
141*387f9dfdSAndroid Build Coastguard Worker public:
TmpDir()142*387f9dfdSAndroid Build Coastguard Worker TmpDir() : path_("/tmp/bcc-test-XXXXXX") {
143*387f9dfdSAndroid Build Coastguard Worker if (::mkdtemp(&path_[0]) == nullptr) {
144*387f9dfdSAndroid Build Coastguard Worker abort();
145*387f9dfdSAndroid Build Coastguard Worker }
146*387f9dfdSAndroid Build Coastguard Worker }
147*387f9dfdSAndroid Build Coastguard Worker
~TmpDir()148*387f9dfdSAndroid Build Coastguard Worker ~TmpDir() { system("rm -rf " + path_); }
149*387f9dfdSAndroid Build Coastguard Worker
path() const150*387f9dfdSAndroid Build Coastguard Worker const std::string &path() const { return path_; }
151*387f9dfdSAndroid Build Coastguard Worker
152*387f9dfdSAndroid Build Coastguard Worker private:
153*387f9dfdSAndroid Build Coastguard Worker std::string path_;
154*387f9dfdSAndroid Build Coastguard Worker };
155*387f9dfdSAndroid Build Coastguard Worker
test_debuginfo_only_symbol(const std::string & lib)156*387f9dfdSAndroid Build Coastguard Worker void test_debuginfo_only_symbol(const std::string &lib) {
157*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
158*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_resolve_symname(lib.c_str(), "debuginfo_only_symbol", 0x0, 0,
159*387f9dfdSAndroid Build Coastguard Worker nullptr, &sym) == 0);
160*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module[0] == '/');
161*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.offset != 0);
162*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_free(sym.module);
163*387f9dfdSAndroid Build Coastguard Worker }
164*387f9dfdSAndroid Build Coastguard Worker
165*387f9dfdSAndroid Build Coastguard Worker } // namespace
166*387f9dfdSAndroid Build Coastguard Worker
167*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name via symfs", "[c_api]") {
168*387f9dfdSAndroid Build Coastguard Worker TmpDir tmpdir;
169*387f9dfdSAndroid Build Coastguard Worker std::string lib_path = tmpdir.path() + "/lib.so";
170*387f9dfdSAndroid Build Coastguard Worker std::string symfs = tmpdir.path() + "/symfs";
171*387f9dfdSAndroid Build Coastguard Worker std::string symfs_lib_dir = symfs + "/" + tmpdir.path();
172*387f9dfdSAndroid Build Coastguard Worker std::string symfs_lib_path = symfs_lib_dir + "/lib.so";
173*387f9dfdSAndroid Build Coastguard Worker
174*387f9dfdSAndroid Build Coastguard Worker system("mkdir -p " + symfs);
175*387f9dfdSAndroid Build Coastguard Worker system("cp " CMAKE_CURRENT_BINARY_DIR "/libdebuginfo_test_lib.so " +
176*387f9dfdSAndroid Build Coastguard Worker lib_path);
177*387f9dfdSAndroid Build Coastguard Worker system("mkdir -p " + symfs_lib_dir);
178*387f9dfdSAndroid Build Coastguard Worker system("cp " CMAKE_CURRENT_BINARY_DIR "/debuginfo.so " + symfs_lib_path);
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker ::setenv("BCC_SYMFS", symfs.c_str(), 1);
181*387f9dfdSAndroid Build Coastguard Worker test_debuginfo_only_symbol(lib_path);
182*387f9dfdSAndroid Build Coastguard Worker ::unsetenv("BCC_SYMFS");
183*387f9dfdSAndroid Build Coastguard Worker }
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name via buildid", "[c_api]") {
186*387f9dfdSAndroid Build Coastguard Worker char build_id[128] = {0};
187*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_elf_get_buildid(CMAKE_CURRENT_BINARY_DIR
188*387f9dfdSAndroid Build Coastguard Worker "/libdebuginfo_test_lib.so",
189*387f9dfdSAndroid Build Coastguard Worker build_id) == 0);
190*387f9dfdSAndroid Build Coastguard Worker
191*387f9dfdSAndroid Build Coastguard Worker TmpDir tmpdir;
192*387f9dfdSAndroid Build Coastguard Worker std::string debugso_dir =
193*387f9dfdSAndroid Build Coastguard Worker tmpdir.path() + "/.build-id/" + build_id[0] + build_id[1];
194*387f9dfdSAndroid Build Coastguard Worker std::string debugso = debugso_dir + "/" + (build_id + 2) + ".debug";
195*387f9dfdSAndroid Build Coastguard Worker system("mkdir -p " + debugso_dir);
196*387f9dfdSAndroid Build Coastguard Worker system("cp " CMAKE_CURRENT_BINARY_DIR "/debuginfo.so " + debugso);
197*387f9dfdSAndroid Build Coastguard Worker
198*387f9dfdSAndroid Build Coastguard Worker ::setenv("BCC_DEBUGINFO_ROOT", tmpdir.path().c_str(), 1);
199*387f9dfdSAndroid Build Coastguard Worker test_debuginfo_only_symbol(CMAKE_CURRENT_BINARY_DIR
200*387f9dfdSAndroid Build Coastguard Worker "/libdebuginfo_test_lib.so");
201*387f9dfdSAndroid Build Coastguard Worker ::unsetenv("BCC_DEBUGINFO_ROOT");
202*387f9dfdSAndroid Build Coastguard Worker }
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name via gnu_debuglink", "[c_api]") {
205*387f9dfdSAndroid Build Coastguard Worker test_debuginfo_only_symbol(CMAKE_CURRENT_BINARY_DIR "/with_gnu_debuglink.so");
206*387f9dfdSAndroid Build Coastguard Worker }
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
209*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol name via mini debug info", "[c_api]") {
210*387f9dfdSAndroid Build Coastguard Worker test_debuginfo_only_symbol(CMAKE_CURRENT_BINARY_DIR "/with_gnu_debugdata.so");
211*387f9dfdSAndroid Build Coastguard Worker }
212*387f9dfdSAndroid Build Coastguard Worker #endif
213*387f9dfdSAndroid Build Coastguard Worker
_a_test_function(const char * a_string)214*387f9dfdSAndroid Build Coastguard Worker extern "C" int _a_test_function(const char *a_string) {
215*387f9dfdSAndroid Build Coastguard Worker int i;
216*387f9dfdSAndroid Build Coastguard Worker for (i = 0; a_string[i]; ++i)
217*387f9dfdSAndroid Build Coastguard Worker ;
218*387f9dfdSAndroid Build Coastguard Worker return i;
219*387f9dfdSAndroid Build Coastguard Worker }
220*387f9dfdSAndroid Build Coastguard Worker
setup_tmp_mnts(void)221*387f9dfdSAndroid Build Coastguard Worker static int setup_tmp_mnts(void) {
222*387f9dfdSAndroid Build Coastguard Worker // Disconnect this mount namespace from its parent
223*387f9dfdSAndroid Build Coastguard Worker if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) {
224*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "unable to mark / PRIVATE: %s\n", strerror(errno));
225*387f9dfdSAndroid Build Coastguard Worker return -1;
226*387f9dfdSAndroid Build Coastguard Worker }
227*387f9dfdSAndroid Build Coastguard Worker // create a new tmpfs mounted on /tmp
228*387f9dfdSAndroid Build Coastguard Worker if (mount("tmpfs", "/tmp", "tmpfs", 0, NULL) < 0) {
229*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "unable to mount /tmp in mntns: %s\n", strerror(errno));
230*387f9dfdSAndroid Build Coastguard Worker return -1;
231*387f9dfdSAndroid Build Coastguard Worker }
232*387f9dfdSAndroid Build Coastguard Worker
233*387f9dfdSAndroid Build Coastguard Worker return 0;
234*387f9dfdSAndroid Build Coastguard Worker }
235*387f9dfdSAndroid Build Coastguard Worker
mntns_func(void * arg)236*387f9dfdSAndroid Build Coastguard Worker static int mntns_func(void *arg) {
237*387f9dfdSAndroid Build Coastguard Worker int in_fd, out_fd;
238*387f9dfdSAndroid Build Coastguard Worker char buf[4096];
239*387f9dfdSAndroid Build Coastguard Worker char libpath[1024];
240*387f9dfdSAndroid Build Coastguard Worker ssize_t rb;
241*387f9dfdSAndroid Build Coastguard Worker void *dlhdl;
242*387f9dfdSAndroid Build Coastguard Worker struct link_map *lm;
243*387f9dfdSAndroid Build Coastguard Worker
244*387f9dfdSAndroid Build Coastguard Worker if (setup_tmp_mnts() < 0) {
245*387f9dfdSAndroid Build Coastguard Worker return -1;
246*387f9dfdSAndroid Build Coastguard Worker }
247*387f9dfdSAndroid Build Coastguard Worker
248*387f9dfdSAndroid Build Coastguard Worker // Find libz.so.1, if it's installed
249*387f9dfdSAndroid Build Coastguard Worker dlhdl = dlopen("libz.so.1", RTLD_LAZY);
250*387f9dfdSAndroid Build Coastguard Worker if (dlhdl == NULL) {
251*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unable to dlopen libz.so.1: %s\n", dlerror());
252*387f9dfdSAndroid Build Coastguard Worker return -1;
253*387f9dfdSAndroid Build Coastguard Worker }
254*387f9dfdSAndroid Build Coastguard Worker
255*387f9dfdSAndroid Build Coastguard Worker if (dlinfo(dlhdl, RTLD_DI_LINKMAP, &lm) < 0) {
256*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unable to find origin of libz.so.1: %s\n", dlerror());
257*387f9dfdSAndroid Build Coastguard Worker return -1;
258*387f9dfdSAndroid Build Coastguard Worker }
259*387f9dfdSAndroid Build Coastguard Worker
260*387f9dfdSAndroid Build Coastguard Worker strncpy(libpath, lm->l_name, sizeof(libpath) - 1);
261*387f9dfdSAndroid Build Coastguard Worker dlclose(dlhdl);
262*387f9dfdSAndroid Build Coastguard Worker dlhdl = NULL;
263*387f9dfdSAndroid Build Coastguard Worker
264*387f9dfdSAndroid Build Coastguard Worker // Copy a shared library from shared mntns to private /tmp
265*387f9dfdSAndroid Build Coastguard Worker snprintf(buf, 4096, "%s", libpath);
266*387f9dfdSAndroid Build Coastguard Worker in_fd = open(buf, O_RDONLY);
267*387f9dfdSAndroid Build Coastguard Worker if (in_fd < 0) {
268*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unable to open %s: %s\n", buf, strerror(errno));
269*387f9dfdSAndroid Build Coastguard Worker return -1;
270*387f9dfdSAndroid Build Coastguard Worker }
271*387f9dfdSAndroid Build Coastguard Worker
272*387f9dfdSAndroid Build Coastguard Worker out_fd = open("/tmp/libz.so.1", O_RDWR|O_CREAT|O_EXCL,
273*387f9dfdSAndroid Build Coastguard Worker S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
274*387f9dfdSAndroid Build Coastguard Worker if (out_fd < 0) {
275*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unable to open /tmp/libz.so.1: %s\n", strerror(errno));
276*387f9dfdSAndroid Build Coastguard Worker return -1;
277*387f9dfdSAndroid Build Coastguard Worker }
278*387f9dfdSAndroid Build Coastguard Worker memset(buf, 0, sizeof (buf));
279*387f9dfdSAndroid Build Coastguard Worker while ((rb = read(in_fd, buf, sizeof (buf))) > 0) {
280*387f9dfdSAndroid Build Coastguard Worker if (write(out_fd, buf, rb) < 0) {
281*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Write error: %s\n", strerror(errno));
282*387f9dfdSAndroid Build Coastguard Worker return -1;
283*387f9dfdSAndroid Build Coastguard Worker }
284*387f9dfdSAndroid Build Coastguard Worker }
285*387f9dfdSAndroid Build Coastguard Worker close(in_fd);
286*387f9dfdSAndroid Build Coastguard Worker close(out_fd);
287*387f9dfdSAndroid Build Coastguard Worker
288*387f9dfdSAndroid Build Coastguard Worker dlhdl = dlopen("/tmp/libz.so.1", RTLD_NOW);
289*387f9dfdSAndroid Build Coastguard Worker if (dlhdl == NULL) {
290*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "dlopen error: %s\n", dlerror());
291*387f9dfdSAndroid Build Coastguard Worker return -1;
292*387f9dfdSAndroid Build Coastguard Worker }
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Worker sleep(5);
295*387f9dfdSAndroid Build Coastguard Worker dlclose(dlhdl);
296*387f9dfdSAndroid Build Coastguard Worker
297*387f9dfdSAndroid Build Coastguard Worker return 0;
298*387f9dfdSAndroid Build Coastguard Worker }
299*387f9dfdSAndroid Build Coastguard Worker
300*387f9dfdSAndroid Build Coastguard Worker extern int cmd_scanf(const char *cmd, const char *fmt, ...);
301*387f9dfdSAndroid Build Coastguard Worker
302*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol addresses for a given PID", "[c_api]") {
303*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
304*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol lazy_sym;
305*387f9dfdSAndroid Build Coastguard Worker static struct bcc_symbol_option lazy_opt{
306*387f9dfdSAndroid Build Coastguard Worker .use_debug_file = 1,
307*387f9dfdSAndroid Build Coastguard Worker .check_debug_file_crc = 1,
308*387f9dfdSAndroid Build Coastguard Worker .lazy_symbolize = 1,
309*387f9dfdSAndroid Build Coastguard Worker #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
310*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = BCC_SYM_ALL_TYPES | (1 << STT_PPC64_ELFV2_SYM_LEP),
311*387f9dfdSAndroid Build Coastguard Worker #else
312*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = BCC_SYM_ALL_TYPES,
313*387f9dfdSAndroid Build Coastguard Worker #endif
314*387f9dfdSAndroid Build Coastguard Worker };
315*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(getpid(), nullptr);
316*387f9dfdSAndroid Build Coastguard Worker void *lazy_resolver = bcc_symcache_new(getpid(), &lazy_opt);
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
319*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_resolver);
320*387f9dfdSAndroid Build Coastguard Worker
321*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in our own binary memory space") {
322*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)&_a_test_function, &sym) ==
323*387f9dfdSAndroid Build Coastguard Worker 0);
324*387f9dfdSAndroid Build Coastguard Worker
325*387f9dfdSAndroid Build Coastguard Worker char *this_exe = realpath("/proc/self/exe", NULL);
326*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(this_exe) == sym.module);
327*387f9dfdSAndroid Build Coastguard Worker free(this_exe);
328*387f9dfdSAndroid Build Coastguard Worker
329*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("_a_test_function") == sym.name);
330*387f9dfdSAndroid Build Coastguard Worker
331*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)&_a_test_function, &lazy_sym) ==
332*387f9dfdSAndroid Build Coastguard Worker 0);
333*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
334*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
335*387f9dfdSAndroid Build Coastguard Worker }
336*387f9dfdSAndroid Build Coastguard Worker
337*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in " LIBBCC_NAME) {
338*387f9dfdSAndroid Build Coastguard Worker void *libbcc = dlopen(LIBBCC_NAME, RTLD_LAZY | RTLD_NOLOAD);
339*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libbcc);
340*387f9dfdSAndroid Build Coastguard Worker
341*387f9dfdSAndroid Build Coastguard Worker void *libbcc_fptr = dlsym(libbcc, "bcc_resolve_symname");
342*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libbcc_fptr);
343*387f9dfdSAndroid Build Coastguard Worker
344*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)libbcc_fptr, &sym) == 0);
345*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module).find(LIBBCC_NAME) != string::npos);
346*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("bcc_resolve_symname") == sym.name);
347*387f9dfdSAndroid Build Coastguard Worker
348*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)libbcc_fptr, &lazy_sym) == 0);
349*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
350*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
351*387f9dfdSAndroid Build Coastguard Worker }
352*387f9dfdSAndroid Build Coastguard Worker
353*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in libc") {
354*387f9dfdSAndroid Build Coastguard Worker void *libc_fptr = dlsym(NULL, "strtok");
355*387f9dfdSAndroid Build Coastguard Worker REQUIRE(libc_fptr);
356*387f9dfdSAndroid Build Coastguard Worker
357*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)libc_fptr, &sym) == 0);
358*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
359*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module[0] == '/');
360*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module).find("libc") != string::npos);
361*387f9dfdSAndroid Build Coastguard Worker
362*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)libc_fptr, &lazy_sym) == 0);
363*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
364*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
365*387f9dfdSAndroid Build Coastguard Worker
366*387f9dfdSAndroid Build Coastguard Worker // In some cases, a symbol may have multiple aliases. Since
367*387f9dfdSAndroid Build Coastguard Worker // bcc_symcache_resolve() returns only the first alias of a
368*387f9dfdSAndroid Build Coastguard Worker // symbol, this may not always be "strtok" even if it points
369*387f9dfdSAndroid Build Coastguard Worker // to the same address.
370*387f9dfdSAndroid Build Coastguard Worker bool sym_match = (string("strtok") == sym.name);
371*387f9dfdSAndroid Build Coastguard Worker if (!sym_match) {
372*387f9dfdSAndroid Build Coastguard Worker uint64_t exp_addr, sym_addr;
373*387f9dfdSAndroid Build Coastguard Worker char cmd[256];
374*387f9dfdSAndroid Build Coastguard Worker const char *cmdfmt = "nm %s | grep \" %s$\" | cut -f 1 -d \" \"";
375*387f9dfdSAndroid Build Coastguard Worker
376*387f9dfdSAndroid Build Coastguard Worker // Find address of symbol by the expected name
377*387f9dfdSAndroid Build Coastguard Worker sprintf(cmd, cmdfmt, sym.module, "strtok");
378*387f9dfdSAndroid Build Coastguard Worker REQUIRE(cmd_scanf(cmd, "%lx", &exp_addr) == 0);
379*387f9dfdSAndroid Build Coastguard Worker
380*387f9dfdSAndroid Build Coastguard Worker // Find address of symbol by the name that was
381*387f9dfdSAndroid Build Coastguard Worker // returned by bcc_symcache_resolve()
382*387f9dfdSAndroid Build Coastguard Worker sprintf(cmd, cmdfmt, sym.module, sym.name);
383*387f9dfdSAndroid Build Coastguard Worker REQUIRE(cmd_scanf(cmd, "%lx", &sym_addr) == 0);
384*387f9dfdSAndroid Build Coastguard Worker
385*387f9dfdSAndroid Build Coastguard Worker // If both addresses match, they are definitely
386*387f9dfdSAndroid Build Coastguard Worker // aliases of the same symbol
387*387f9dfdSAndroid Build Coastguard Worker sym_match = (exp_addr == sym_addr);
388*387f9dfdSAndroid Build Coastguard Worker }
389*387f9dfdSAndroid Build Coastguard Worker
390*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym_match);
391*387f9dfdSAndroid Build Coastguard Worker }
392*387f9dfdSAndroid Build Coastguard Worker
393*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in separate mount namespace") {
394*387f9dfdSAndroid Build Coastguard Worker pid_t child;
395*387f9dfdSAndroid Build Coastguard Worker uint64_t addr = 0;
396*387f9dfdSAndroid Build Coastguard Worker uint64_t lazy_addr = 0;
397*387f9dfdSAndroid Build Coastguard Worker
398*387f9dfdSAndroid Build Coastguard Worker child = spawn_child(0, true, true, mntns_func);
399*387f9dfdSAndroid Build Coastguard Worker REQUIRE(child > 0);
400*387f9dfdSAndroid Build Coastguard Worker
401*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
402*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
403*387f9dfdSAndroid Build Coastguard Worker
404*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve_name(resolver, "/tmp/libz.so.1", "zlibVersion",
405*387f9dfdSAndroid Build Coastguard Worker &addr) == 0);
406*387f9dfdSAndroid Build Coastguard Worker REQUIRE(addr != 0);
407*387f9dfdSAndroid Build Coastguard Worker
408*387f9dfdSAndroid Build Coastguard Worker void *lazy_resolver = bcc_symcache_new(child, &lazy_opt);
409*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_resolver);
410*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve_name(lazy_resolver, "/tmp/libz.so.1", "zlibVersion",
411*387f9dfdSAndroid Build Coastguard Worker &lazy_addr) == 0);
412*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_addr == addr);
413*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, child);
414*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(lazy_resolver, child);
415*387f9dfdSAndroid Build Coastguard Worker }
416*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, getpid());
417*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(lazy_resolver, getpid());
418*387f9dfdSAndroid Build Coastguard Worker }
419*387f9dfdSAndroid Build Coastguard Worker
420*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbol addresses for an exited process", "[c-api]") {
421*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
422*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol lazy_sym;
423*387f9dfdSAndroid Build Coastguard Worker static struct bcc_symbol_option lazy_opt {
424*387f9dfdSAndroid Build Coastguard Worker .use_debug_file = 1, .check_debug_file_crc = 1, .lazy_symbolize = 1,
425*387f9dfdSAndroid Build Coastguard Worker #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
426*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = BCC_SYM_ALL_TYPES | (1 << STT_PPC64_ELFV2_SYM_LEP),
427*387f9dfdSAndroid Build Coastguard Worker #else
428*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = BCC_SYM_ALL_TYPES,
429*387f9dfdSAndroid Build Coastguard Worker #endif
430*387f9dfdSAndroid Build Coastguard Worker };
431*387f9dfdSAndroid Build Coastguard Worker
432*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in current namespace") {
__anon395773040302(void *) 433*387f9dfdSAndroid Build Coastguard Worker pid_t child = spawn_child(nullptr, false, false, [](void *) {
434*387f9dfdSAndroid Build Coastguard Worker sleep(5);
435*387f9dfdSAndroid Build Coastguard Worker return 0;
436*387f9dfdSAndroid Build Coastguard Worker });
437*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
438*387f9dfdSAndroid Build Coastguard Worker void *lazy_resolver = bcc_symcache_new(child, &lazy_opt);
439*387f9dfdSAndroid Build Coastguard Worker
440*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
441*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_resolver);
442*387f9dfdSAndroid Build Coastguard Worker
443*387f9dfdSAndroid Build Coastguard Worker kill(child, SIGTERM);
444*387f9dfdSAndroid Build Coastguard Worker
445*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)&_a_test_function, &sym) ==
446*387f9dfdSAndroid Build Coastguard Worker 0);
447*387f9dfdSAndroid Build Coastguard Worker
448*387f9dfdSAndroid Build Coastguard Worker char *this_exe = realpath("/proc/self/exe", NULL);
449*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(this_exe) == sym.module);
450*387f9dfdSAndroid Build Coastguard Worker free(this_exe);
451*387f9dfdSAndroid Build Coastguard Worker
452*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("_a_test_function") == sym.name);
453*387f9dfdSAndroid Build Coastguard Worker
454*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)&_a_test_function,
455*387f9dfdSAndroid Build Coastguard Worker &lazy_sym) == 0);
456*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
457*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
458*387f9dfdSAndroid Build Coastguard Worker }
459*387f9dfdSAndroid Build Coastguard Worker
460*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in separate pid namespace") {
__anon395773040402(void *) 461*387f9dfdSAndroid Build Coastguard Worker pid_t child = spawn_child(nullptr, true, false, [](void *) {
462*387f9dfdSAndroid Build Coastguard Worker sleep(5);
463*387f9dfdSAndroid Build Coastguard Worker return 0;
464*387f9dfdSAndroid Build Coastguard Worker });
465*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
466*387f9dfdSAndroid Build Coastguard Worker void *lazy_resolver = bcc_symcache_new(child, &lazy_opt);
467*387f9dfdSAndroid Build Coastguard Worker
468*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
469*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_resolver);
470*387f9dfdSAndroid Build Coastguard Worker
471*387f9dfdSAndroid Build Coastguard Worker kill(child, SIGTERM);
472*387f9dfdSAndroid Build Coastguard Worker
473*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)&_a_test_function, &sym) ==
474*387f9dfdSAndroid Build Coastguard Worker 0);
475*387f9dfdSAndroid Build Coastguard Worker
476*387f9dfdSAndroid Build Coastguard Worker char *this_exe = realpath("/proc/self/exe", NULL);
477*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(this_exe) == sym.module);
478*387f9dfdSAndroid Build Coastguard Worker free(this_exe);
479*387f9dfdSAndroid Build Coastguard Worker
480*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("_a_test_function") == sym.name);
481*387f9dfdSAndroid Build Coastguard Worker
482*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)&_a_test_function,
483*387f9dfdSAndroid Build Coastguard Worker &lazy_sym) == 0);
484*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
485*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
486*387f9dfdSAndroid Build Coastguard Worker }
487*387f9dfdSAndroid Build Coastguard Worker
488*387f9dfdSAndroid Build Coastguard Worker SECTION("resolve in separate pid and mount namespace") {
__anon395773040502(void *) 489*387f9dfdSAndroid Build Coastguard Worker pid_t child = spawn_child(nullptr, true, true, [](void *) {
490*387f9dfdSAndroid Build Coastguard Worker sleep(5);
491*387f9dfdSAndroid Build Coastguard Worker return 0;
492*387f9dfdSAndroid Build Coastguard Worker });
493*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
494*387f9dfdSAndroid Build Coastguard Worker void *lazy_resolver = bcc_symcache_new(child, &lazy_opt);
495*387f9dfdSAndroid Build Coastguard Worker
496*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
497*387f9dfdSAndroid Build Coastguard Worker REQUIRE(lazy_resolver);
498*387f9dfdSAndroid Build Coastguard Worker
499*387f9dfdSAndroid Build Coastguard Worker kill(child, SIGTERM);
500*387f9dfdSAndroid Build Coastguard Worker
501*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (uint64_t)&_a_test_function, &sym) ==
502*387f9dfdSAndroid Build Coastguard Worker 0);
503*387f9dfdSAndroid Build Coastguard Worker
504*387f9dfdSAndroid Build Coastguard Worker char *this_exe = realpath("/proc/self/exe", NULL);
505*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(this_exe) == sym.module);
506*387f9dfdSAndroid Build Coastguard Worker free(this_exe);
507*387f9dfdSAndroid Build Coastguard Worker
508*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("_a_test_function") == sym.name);
509*387f9dfdSAndroid Build Coastguard Worker
510*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(lazy_resolver, (uint64_t)&_a_test_function,
511*387f9dfdSAndroid Build Coastguard Worker &lazy_sym) == 0);
512*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.name) == sym.name);
513*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(lazy_sym.module) == sym.module);
514*387f9dfdSAndroid Build Coastguard Worker }
515*387f9dfdSAndroid Build Coastguard Worker }
516*387f9dfdSAndroid Build Coastguard Worker
517*387f9dfdSAndroid Build Coastguard Worker #define STACK_SIZE (1024 * 1024)
518*387f9dfdSAndroid Build Coastguard Worker static char child_stack[STACK_SIZE];
519*387f9dfdSAndroid Build Coastguard Worker
perf_map_path(pid_t pid)520*387f9dfdSAndroid Build Coastguard Worker static string perf_map_path(pid_t pid) {
521*387f9dfdSAndroid Build Coastguard Worker return tfm::format("/tmp/perf-%d.map", pid);
522*387f9dfdSAndroid Build Coastguard Worker }
523*387f9dfdSAndroid Build Coastguard Worker
make_perf_map_file(string & path,unsigned long long map_addr)524*387f9dfdSAndroid Build Coastguard Worker static int make_perf_map_file(string &path, unsigned long long map_addr) {
525*387f9dfdSAndroid Build Coastguard Worker FILE *file = fopen(path.c_str(), "w");
526*387f9dfdSAndroid Build Coastguard Worker if (file == NULL) {
527*387f9dfdSAndroid Build Coastguard Worker return -1;
528*387f9dfdSAndroid Build Coastguard Worker }
529*387f9dfdSAndroid Build Coastguard Worker fprintf(file, "%llx 10 dummy_fn\n", map_addr);
530*387f9dfdSAndroid Build Coastguard Worker fprintf(file, "%llx 10 right_next_door_fn\n", map_addr + 0x10);
531*387f9dfdSAndroid Build Coastguard Worker fclose(file);
532*387f9dfdSAndroid Build Coastguard Worker
533*387f9dfdSAndroid Build Coastguard Worker return 0;
534*387f9dfdSAndroid Build Coastguard Worker }
535*387f9dfdSAndroid Build Coastguard Worker
perf_map_func(void * arg)536*387f9dfdSAndroid Build Coastguard Worker static int perf_map_func(void *arg) {
537*387f9dfdSAndroid Build Coastguard Worker string path = perf_map_path(getpid());
538*387f9dfdSAndroid Build Coastguard Worker if (make_perf_map_file(path, (unsigned long long)arg) < 0)
539*387f9dfdSAndroid Build Coastguard Worker return -1;
540*387f9dfdSAndroid Build Coastguard Worker
541*387f9dfdSAndroid Build Coastguard Worker sleep(5);
542*387f9dfdSAndroid Build Coastguard Worker
543*387f9dfdSAndroid Build Coastguard Worker unlink(path.c_str());
544*387f9dfdSAndroid Build Coastguard Worker return 0;
545*387f9dfdSAndroid Build Coastguard Worker }
546*387f9dfdSAndroid Build Coastguard Worker
perf_map_func_mntns(void * arg)547*387f9dfdSAndroid Build Coastguard Worker static int perf_map_func_mntns(void *arg) {
548*387f9dfdSAndroid Build Coastguard Worker string path = perf_map_path(getpid());
549*387f9dfdSAndroid Build Coastguard Worker
550*387f9dfdSAndroid Build Coastguard Worker if (setup_tmp_mnts() < 0) {
551*387f9dfdSAndroid Build Coastguard Worker return -1;
552*387f9dfdSAndroid Build Coastguard Worker }
553*387f9dfdSAndroid Build Coastguard Worker
554*387f9dfdSAndroid Build Coastguard Worker if (make_perf_map_file(path, (unsigned long long)arg) < 0)
555*387f9dfdSAndroid Build Coastguard Worker return -1;
556*387f9dfdSAndroid Build Coastguard Worker
557*387f9dfdSAndroid Build Coastguard Worker sleep(5);
558*387f9dfdSAndroid Build Coastguard Worker
559*387f9dfdSAndroid Build Coastguard Worker unlink(path.c_str());
560*387f9dfdSAndroid Build Coastguard Worker return 0;
561*387f9dfdSAndroid Build Coastguard Worker }
562*387f9dfdSAndroid Build Coastguard Worker
perf_map_func_noop(void * arg)563*387f9dfdSAndroid Build Coastguard Worker static int perf_map_func_noop(void *arg) {
564*387f9dfdSAndroid Build Coastguard Worker if (setup_tmp_mnts() < 0) {
565*387f9dfdSAndroid Build Coastguard Worker return -1;
566*387f9dfdSAndroid Build Coastguard Worker }
567*387f9dfdSAndroid Build Coastguard Worker
568*387f9dfdSAndroid Build Coastguard Worker sleep(5);
569*387f9dfdSAndroid Build Coastguard Worker
570*387f9dfdSAndroid Build Coastguard Worker return 0;
571*387f9dfdSAndroid Build Coastguard Worker }
572*387f9dfdSAndroid Build Coastguard Worker
spawn_child(void * map_addr,bool own_pidns,bool own_mntns,int (* child_func)(void *))573*387f9dfdSAndroid Build Coastguard Worker static pid_t spawn_child(void *map_addr, bool own_pidns, bool own_mntns,
574*387f9dfdSAndroid Build Coastguard Worker int (*child_func)(void *)) {
575*387f9dfdSAndroid Build Coastguard Worker int flags = SIGCHLD;
576*387f9dfdSAndroid Build Coastguard Worker if (own_pidns)
577*387f9dfdSAndroid Build Coastguard Worker flags |= CLONE_NEWPID;
578*387f9dfdSAndroid Build Coastguard Worker if (own_mntns)
579*387f9dfdSAndroid Build Coastguard Worker flags |= CLONE_NEWNS;
580*387f9dfdSAndroid Build Coastguard Worker
581*387f9dfdSAndroid Build Coastguard Worker pid_t child = clone(child_func,
582*387f9dfdSAndroid Build Coastguard Worker /* stack grows down */ child_stack + STACK_SIZE, flags, (void*)map_addr);
583*387f9dfdSAndroid Build Coastguard Worker if (child < 0)
584*387f9dfdSAndroid Build Coastguard Worker return -1;
585*387f9dfdSAndroid Build Coastguard Worker
586*387f9dfdSAndroid Build Coastguard Worker sleep(1); // let the child get set up
587*387f9dfdSAndroid Build Coastguard Worker return child;
588*387f9dfdSAndroid Build Coastguard Worker }
589*387f9dfdSAndroid Build Coastguard Worker
590*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve symbols using /tmp/perf-pid.map", "[c_api]") {
591*387f9dfdSAndroid Build Coastguard Worker const int map_sz = 4096;
592*387f9dfdSAndroid Build Coastguard Worker void *map_addr = mmap(NULL, map_sz, PROT_READ | PROT_EXEC,
593*387f9dfdSAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
594*387f9dfdSAndroid Build Coastguard Worker REQUIRE(map_addr != MAP_FAILED);
595*387f9dfdSAndroid Build Coastguard Worker
596*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol sym;
597*387f9dfdSAndroid Build Coastguard Worker pid_t child = -1;
598*387f9dfdSAndroid Build Coastguard Worker
599*387f9dfdSAndroid Build Coastguard Worker SECTION("same namespace") {
600*387f9dfdSAndroid Build Coastguard Worker child = spawn_child(map_addr, /* own_pidns */ false, false, perf_map_func);
601*387f9dfdSAndroid Build Coastguard Worker REQUIRE(child > 0);
602*387f9dfdSAndroid Build Coastguard Worker
603*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
604*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
605*387f9dfdSAndroid Build Coastguard Worker
606*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (unsigned long long)map_addr,
607*387f9dfdSAndroid Build Coastguard Worker &sym) == 0);
608*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
609*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module) == perf_map_path(child));
610*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("dummy_fn") == sym.name);
611*387f9dfdSAndroid Build Coastguard Worker
612*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (unsigned long long)map_addr + 0x10,
613*387f9dfdSAndroid Build Coastguard Worker &sym) == 0);
614*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
615*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module) == perf_map_path(child));
616*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("right_next_door_fn") == sym.name);
617*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, child);
618*387f9dfdSAndroid Build Coastguard Worker
619*387f9dfdSAndroid Build Coastguard Worker }
620*387f9dfdSAndroid Build Coastguard Worker
621*387f9dfdSAndroid Build Coastguard Worker SECTION("separate namespace") {
622*387f9dfdSAndroid Build Coastguard Worker child = spawn_child(map_addr, /* own_pidns */ true, false, perf_map_func);
623*387f9dfdSAndroid Build Coastguard Worker REQUIRE(child > 0);
624*387f9dfdSAndroid Build Coastguard Worker
625*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
626*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
627*387f9dfdSAndroid Build Coastguard Worker
628*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (unsigned long long)map_addr,
629*387f9dfdSAndroid Build Coastguard Worker &sym) == 0);
630*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
631*387f9dfdSAndroid Build Coastguard Worker // child is PID 1 in its namespace
632*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module) == perf_map_path(1));
633*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("dummy_fn") == sym.name);
634*387f9dfdSAndroid Build Coastguard Worker unlink("/tmp/perf-1.map");
635*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, child);
636*387f9dfdSAndroid Build Coastguard Worker }
637*387f9dfdSAndroid Build Coastguard Worker
638*387f9dfdSAndroid Build Coastguard Worker SECTION("separate pid and mount namespace") {
639*387f9dfdSAndroid Build Coastguard Worker child = spawn_child(map_addr, /* own_pidns */ true, true,
640*387f9dfdSAndroid Build Coastguard Worker perf_map_func_mntns);
641*387f9dfdSAndroid Build Coastguard Worker REQUIRE(child > 0);
642*387f9dfdSAndroid Build Coastguard Worker
643*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
644*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
645*387f9dfdSAndroid Build Coastguard Worker
646*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (unsigned long long)map_addr,
647*387f9dfdSAndroid Build Coastguard Worker &sym) == 0);
648*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
649*387f9dfdSAndroid Build Coastguard Worker // child is PID 1 in its namespace
650*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module) == perf_map_path(1));
651*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("dummy_fn") == sym.name);
652*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, child);
653*387f9dfdSAndroid Build Coastguard Worker }
654*387f9dfdSAndroid Build Coastguard Worker
655*387f9dfdSAndroid Build Coastguard Worker SECTION("separate pid and mount namespace, perf-map in host") {
656*387f9dfdSAndroid Build Coastguard Worker child = spawn_child(map_addr, /* own_pidns */ true, true,
657*387f9dfdSAndroid Build Coastguard Worker perf_map_func_noop);
658*387f9dfdSAndroid Build Coastguard Worker REQUIRE(child > 0);
659*387f9dfdSAndroid Build Coastguard Worker
660*387f9dfdSAndroid Build Coastguard Worker string path = perf_map_path(child);
661*387f9dfdSAndroid Build Coastguard Worker REQUIRE(make_perf_map_file(path, (unsigned long long)map_addr) == 0);
662*387f9dfdSAndroid Build Coastguard Worker
663*387f9dfdSAndroid Build Coastguard Worker void *resolver = bcc_symcache_new(child, nullptr);
664*387f9dfdSAndroid Build Coastguard Worker REQUIRE(resolver);
665*387f9dfdSAndroid Build Coastguard Worker
666*387f9dfdSAndroid Build Coastguard Worker REQUIRE(bcc_symcache_resolve(resolver, (unsigned long long)map_addr,
667*387f9dfdSAndroid Build Coastguard Worker &sym) == 0);
668*387f9dfdSAndroid Build Coastguard Worker REQUIRE(sym.module);
669*387f9dfdSAndroid Build Coastguard Worker // child is PID 1 in its namespace
670*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string(sym.module) == perf_map_path(child));
671*387f9dfdSAndroid Build Coastguard Worker REQUIRE(string("dummy_fn") == sym.name);
672*387f9dfdSAndroid Build Coastguard Worker
673*387f9dfdSAndroid Build Coastguard Worker unlink(path.c_str());
674*387f9dfdSAndroid Build Coastguard Worker bcc_free_symcache(resolver, child);
675*387f9dfdSAndroid Build Coastguard Worker }
676*387f9dfdSAndroid Build Coastguard Worker
677*387f9dfdSAndroid Build Coastguard Worker
678*387f9dfdSAndroid Build Coastguard Worker
679*387f9dfdSAndroid Build Coastguard Worker munmap(map_addr, map_sz);
680*387f9dfdSAndroid Build Coastguard Worker }
681*387f9dfdSAndroid Build Coastguard Worker
682*387f9dfdSAndroid Build Coastguard Worker // must match exactly the defitinion of mod_search in bcc_syms.cc
683*387f9dfdSAndroid Build Coastguard Worker struct mod_search {
684*387f9dfdSAndroid Build Coastguard Worker const char *name;
685*387f9dfdSAndroid Build Coastguard Worker uint64_t inode;
686*387f9dfdSAndroid Build Coastguard Worker uint64_t dev_major;
687*387f9dfdSAndroid Build Coastguard Worker uint64_t dev_minor;
688*387f9dfdSAndroid Build Coastguard Worker uint64_t addr;
689*387f9dfdSAndroid Build Coastguard Worker uint8_t inode_match_only;
690*387f9dfdSAndroid Build Coastguard Worker
691*387f9dfdSAndroid Build Coastguard Worker uint64_t start;
692*387f9dfdSAndroid Build Coastguard Worker uint64_t file_offset;
693*387f9dfdSAndroid Build Coastguard Worker };
694*387f9dfdSAndroid Build Coastguard Worker
695*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("searching for modules in /proc/[pid]/maps", "[c_api][!mayfail]") {
696*387f9dfdSAndroid Build Coastguard Worker std::string dummy_maps_path = CMAKE_CURRENT_BINARY_DIR + std::string("/dummy_proc_map.txt");
697*387f9dfdSAndroid Build Coastguard Worker FILE *dummy_maps = fopen(dummy_maps_path.c_str(), "r");
698*387f9dfdSAndroid Build Coastguard Worker REQUIRE(dummy_maps != NULL);
699*387f9dfdSAndroid Build Coastguard Worker
700*387f9dfdSAndroid Build Coastguard Worker SECTION("name match") {
701*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
702*387f9dfdSAndroid Build Coastguard Worker
703*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
704*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
705*387f9dfdSAndroid Build Coastguard Worker search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
706*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x1;
707*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
708*387f9dfdSAndroid Build Coastguard Worker &search);
709*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
710*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.start == 0x7f1515bad000);
711*387f9dfdSAndroid Build Coastguard Worker }
712*387f9dfdSAndroid Build Coastguard Worker
713*387f9dfdSAndroid Build Coastguard Worker SECTION("expected failure to match (name only search)") {
714*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
715*387f9dfdSAndroid Build Coastguard Worker
716*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
717*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
718*387f9dfdSAndroid Build Coastguard Worker search.name = "/lib/that/isnt/in/maps/libdoesntexist.so";
719*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x1;
720*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
721*387f9dfdSAndroid Build Coastguard Worker &search);
722*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == -1);
723*387f9dfdSAndroid Build Coastguard Worker }
724*387f9dfdSAndroid Build Coastguard Worker
725*387f9dfdSAndroid Build Coastguard Worker SECTION("inode+dev match, names different") {
726*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
727*387f9dfdSAndroid Build Coastguard Worker
728*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
729*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
730*387f9dfdSAndroid Build Coastguard Worker search.name = "/proc/5/root/some/other/path/tolibs/lib/libz.so.1.2.8";
731*387f9dfdSAndroid Build Coastguard Worker search.inode = 72809538;
732*387f9dfdSAndroid Build Coastguard Worker search.dev_major = 0x00;
733*387f9dfdSAndroid Build Coastguard Worker search.dev_minor = 0x1b;
734*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x2;
735*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
736*387f9dfdSAndroid Build Coastguard Worker &search);
737*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
738*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.start == 0x7f15164b5000);
739*387f9dfdSAndroid Build Coastguard Worker }
740*387f9dfdSAndroid Build Coastguard Worker
741*387f9dfdSAndroid Build Coastguard Worker SECTION("inode+dev don't match, names same") {
742*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
743*387f9dfdSAndroid Build Coastguard Worker
744*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
745*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
746*387f9dfdSAndroid Build Coastguard Worker search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
747*387f9dfdSAndroid Build Coastguard Worker search.inode = 9999999;
748*387f9dfdSAndroid Build Coastguard Worker search.dev_major = 0x42;
749*387f9dfdSAndroid Build Coastguard Worker search.dev_minor = 0x1b;
750*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x2;
751*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
752*387f9dfdSAndroid Build Coastguard Worker &search);
753*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == -1);
754*387f9dfdSAndroid Build Coastguard Worker }
755*387f9dfdSAndroid Build Coastguard Worker
756*387f9dfdSAndroid Build Coastguard Worker SECTION("inodes match, dev_major/minor don't, expected failure") {
757*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
758*387f9dfdSAndroid Build Coastguard Worker
759*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
760*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
761*387f9dfdSAndroid Build Coastguard Worker search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
762*387f9dfdSAndroid Build Coastguard Worker search.inode = 72809526;
763*387f9dfdSAndroid Build Coastguard Worker search.dev_major = 0x11;
764*387f9dfdSAndroid Build Coastguard Worker search.dev_minor = 0x11;
765*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x2;
766*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
767*387f9dfdSAndroid Build Coastguard Worker &search);
768*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == -1);
769*387f9dfdSAndroid Build Coastguard Worker }
770*387f9dfdSAndroid Build Coastguard Worker
771*387f9dfdSAndroid Build Coastguard Worker SECTION("inodes match, dev_major/minor don't, match inode only") {
772*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
773*387f9dfdSAndroid Build Coastguard Worker
774*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
775*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
776*387f9dfdSAndroid Build Coastguard Worker search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
777*387f9dfdSAndroid Build Coastguard Worker search.inode = 72809526;
778*387f9dfdSAndroid Build Coastguard Worker search.dev_major = 0x11;
779*387f9dfdSAndroid Build Coastguard Worker search.dev_minor = 0x11;
780*387f9dfdSAndroid Build Coastguard Worker search.addr = 0x2;
781*387f9dfdSAndroid Build Coastguard Worker search.inode_match_only = 1;
782*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
783*387f9dfdSAndroid Build Coastguard Worker &search);
784*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
785*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.start == 0x7f1515bad000);
786*387f9dfdSAndroid Build Coastguard Worker }
787*387f9dfdSAndroid Build Coastguard Worker
788*387f9dfdSAndroid Build Coastguard Worker fclose(dummy_maps);
789*387f9dfdSAndroid Build Coastguard Worker
790*387f9dfdSAndroid Build Coastguard Worker SECTION("seach for lib in zip") {
791*387f9dfdSAndroid Build Coastguard Worker std::string line =
792*387f9dfdSAndroid Build Coastguard Worker "7f151476e000-7f1514779000 r-xp 00001000 00:1b "
793*387f9dfdSAndroid Build Coastguard Worker "72809479 " CMAKE_CURRENT_BINARY_DIR "/archive.zip\n";
794*387f9dfdSAndroid Build Coastguard Worker dummy_maps = fmemopen(nullptr, line.size(), "w+");
795*387f9dfdSAndroid Build Coastguard Worker REQUIRE(fwrite(line.c_str(), line.size(), 1, dummy_maps) == 1);
796*387f9dfdSAndroid Build Coastguard Worker fseek(dummy_maps, 0, SEEK_SET);
797*387f9dfdSAndroid Build Coastguard Worker
798*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
799*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
800*387f9dfdSAndroid Build Coastguard Worker std::string zip_entry_path = zipped_lib_path();
801*387f9dfdSAndroid Build Coastguard Worker search.name = zip_entry_path.c_str();
802*387f9dfdSAndroid Build Coastguard Worker int res = _procfs_maps_each_module(dummy_maps, getpid(),
803*387f9dfdSAndroid Build Coastguard Worker _bcc_syms_find_module, &search);
804*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
805*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.start == 0x7f151476e000);
806*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.file_offset < 0x1000);
807*387f9dfdSAndroid Build Coastguard Worker
808*387f9dfdSAndroid Build Coastguard Worker fclose(dummy_maps);
809*387f9dfdSAndroid Build Coastguard Worker }
810*387f9dfdSAndroid Build Coastguard Worker }
811*387f9dfdSAndroid Build Coastguard Worker
812*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("resolve global addr in libc in this process", "[c_api][!mayfail]") {
813*387f9dfdSAndroid Build Coastguard Worker int pid = getpid();
814*387f9dfdSAndroid Build Coastguard Worker char *sopath = bcc_procutils_which_so("c", pid);
815*387f9dfdSAndroid Build Coastguard Worker uint64_t local_addr = 0x15;
816*387f9dfdSAndroid Build Coastguard Worker uint64_t global_addr;
817*387f9dfdSAndroid Build Coastguard Worker
818*387f9dfdSAndroid Build Coastguard Worker struct mod_search search;
819*387f9dfdSAndroid Build Coastguard Worker memset(&search, 0, sizeof(struct mod_search));
820*387f9dfdSAndroid Build Coastguard Worker search.name = sopath;
821*387f9dfdSAndroid Build Coastguard Worker
822*387f9dfdSAndroid Build Coastguard Worker int res = bcc_procutils_each_module(pid, _bcc_syms_find_module,
823*387f9dfdSAndroid Build Coastguard Worker &search);
824*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
825*387f9dfdSAndroid Build Coastguard Worker REQUIRE(search.start != 0);
826*387f9dfdSAndroid Build Coastguard Worker
827*387f9dfdSAndroid Build Coastguard Worker res = bcc_resolve_global_addr(pid, sopath, local_addr, 0, &global_addr);
828*387f9dfdSAndroid Build Coastguard Worker REQUIRE(res == 0);
829*387f9dfdSAndroid Build Coastguard Worker REQUIRE(global_addr == (search.start + local_addr - search.file_offset));
830*387f9dfdSAndroid Build Coastguard Worker free(sopath);
831*387f9dfdSAndroid Build Coastguard Worker }
832*387f9dfdSAndroid Build Coastguard Worker
833*387f9dfdSAndroid Build Coastguard Worker /* Consider the following scenario: we have some process that maps in a shared library [1] with a
834*387f9dfdSAndroid Build Coastguard Worker * USDT probe [2]. The shared library's .text section doesn't have matching address and file off
835*387f9dfdSAndroid Build Coastguard Worker * [3]. Since the location address in [2] is an offset relative to the base address of whatever.so
836*387f9dfdSAndroid Build Coastguard Worker * in whatever process is mapping it, we need to convert the location address 0x77b8c to a global
837*387f9dfdSAndroid Build Coastguard Worker * address in the process' address space in order to attach to the USDT.
838*387f9dfdSAndroid Build Coastguard Worker *
839*387f9dfdSAndroid Build Coastguard Worker * The formula for this (__so_calc_global_addr) is
840*387f9dfdSAndroid Build Coastguard Worker * global_addr = offset + (mod_start_addr - mod_file_offset)
841*387f9dfdSAndroid Build Coastguard Worker * - (elf_sec_start_addr - elf_sec_file_offset)
842*387f9dfdSAndroid Build Coastguard Worker *
843*387f9dfdSAndroid Build Coastguard Worker * Which for our concrete example is
844*387f9dfdSAndroid Build Coastguard Worker * global_addr = 0x77b8c + (0x7f6cda31e000 - 0x72000) - (0x73c90 - 0x72c90)
845*387f9dfdSAndroid Build Coastguard Worker * global_addr = 0x7f6cda322b8c
846*387f9dfdSAndroid Build Coastguard Worker *
847*387f9dfdSAndroid Build Coastguard Worker * [1 - output from `cat /proc/PID/maps`]
848*387f9dfdSAndroid Build Coastguard Worker * 7f6cda2ab000-7f6cda31e000 r--p 00000000 00:2d 5370022276 /whatever.so
849*387f9dfdSAndroid Build Coastguard Worker * 7f6cda31e000-7f6cda434000 r-xp 00072000 00:2d 5370022276 /whatever.so
850*387f9dfdSAndroid Build Coastguard Worker * 7f6cda434000-7f6cda43d000 r--p 00187000 00:2d 5370022276 /whatever.so
851*387f9dfdSAndroid Build Coastguard Worker * 7f6cda43d000-7f6cda43f000 rw-p 0018f000 00:2d 5370022276 /whatever.so
852*387f9dfdSAndroid Build Coastguard Worker *
853*387f9dfdSAndroid Build Coastguard Worker * [2 - output from `readelf -n /whatever.so`]
854*387f9dfdSAndroid Build Coastguard Worker * stapsdt 0x00000038 NT_STAPSDT (SystemTap probe descriptors)
855*387f9dfdSAndroid Build Coastguard Worker * Provider: test
856*387f9dfdSAndroid Build Coastguard Worker * Name: test_probe
857*387f9dfdSAndroid Build Coastguard Worker * Location: 0x0000000000077b8c, Base: 0x0000000000000000, Semaphore: 0x0000000000000000
858*387f9dfdSAndroid Build Coastguard Worker * Arguments: -8@$5
859*387f9dfdSAndroid Build Coastguard Worker *
860*387f9dfdSAndroid Build Coastguard Worker * [3 - output from `readelf -W --sections /whatever.so`]
861*387f9dfdSAndroid Build Coastguard Worker * [Nr] Name Type Address Off Size ES Flg Lk Inf Al
862*387f9dfdSAndroid Build Coastguard Worker * [16] .text PROGBITS 0000000000073c90 072c90 1132dc 00 AX 0 0 16
863*387f9dfdSAndroid Build Coastguard Worker */
864*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("conversion of module offset to/from global_addr", "[c_api]") {
865*387f9dfdSAndroid Build Coastguard Worker uint64_t global_addr, offset, calc_offset, mod_start_addr, mod_file_offset;
866*387f9dfdSAndroid Build Coastguard Worker uint64_t elf_sec_start_addr, elf_sec_file_offset;
867*387f9dfdSAndroid Build Coastguard Worker
868*387f9dfdSAndroid Build Coastguard Worker /* Initialize per example in comment above */
869*387f9dfdSAndroid Build Coastguard Worker offset = 0x77b8c;
870*387f9dfdSAndroid Build Coastguard Worker mod_start_addr = 0x7f6cda31e000;
871*387f9dfdSAndroid Build Coastguard Worker mod_file_offset = 0x00072000;
872*387f9dfdSAndroid Build Coastguard Worker elf_sec_start_addr = 0x73c90;
873*387f9dfdSAndroid Build Coastguard Worker elf_sec_file_offset = 0x72c90;
874*387f9dfdSAndroid Build Coastguard Worker global_addr = __so_calc_global_addr(mod_start_addr, mod_file_offset,
875*387f9dfdSAndroid Build Coastguard Worker elf_sec_start_addr, elf_sec_file_offset,
876*387f9dfdSAndroid Build Coastguard Worker offset);
877*387f9dfdSAndroid Build Coastguard Worker REQUIRE(global_addr == 0x7f6cda322b8c);
878*387f9dfdSAndroid Build Coastguard Worker
879*387f9dfdSAndroid Build Coastguard Worker /* Reverse operation (global_addr -> offset) should yield original offset */
880*387f9dfdSAndroid Build Coastguard Worker calc_offset = __so_calc_mod_offset(mod_start_addr, mod_file_offset,
881*387f9dfdSAndroid Build Coastguard Worker elf_sec_start_addr, elf_sec_file_offset,
882*387f9dfdSAndroid Build Coastguard Worker global_addr);
883*387f9dfdSAndroid Build Coastguard Worker REQUIRE(calc_offset == offset);
884*387f9dfdSAndroid Build Coastguard Worker }
885*387f9dfdSAndroid Build Coastguard Worker
886*387f9dfdSAndroid Build Coastguard Worker TEST_CASE("get online CPUs", "[c_api]") {
887*387f9dfdSAndroid Build Coastguard Worker std::vector<int> cpus = ebpf::get_online_cpus();
888*387f9dfdSAndroid Build Coastguard Worker int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
889*387f9dfdSAndroid Build Coastguard Worker REQUIRE(cpus.size() == num_cpus);
890*387f9dfdSAndroid Build Coastguard Worker }
891