blob: 82cc127b521a6fae6b2a2fa07eaa43a47b28e929 [file] [log] [blame]
// Check that loading libraries with different modes (RTLD_LOCAL/RTLD_GLOBAL)
// and dependencies on other DSOs work correctly.
//
// RUN: split-file %s %t
//
// Build shared libs with dependencies b->c and e->f
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testliba.cpp -o %t/testliba.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibc.cpp -o %t/testlibc.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibb.cpp %t/testlibc.so -o %t/testlibb.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibd.cpp -o %t/testlibd.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibf.cpp -o %t/testlibf.so
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibe.cpp %t/testlibf.so -o %t/testlibe.so
//
// Executable links with a and b explicitly and loads d and e at runtime.
// RUN: %clangxx_xray -g -fPIC -rdynamic -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testliba.so %t/testlibb.so -o %t/main.o
//
// RUN: XRAY_OPTIONS="patch_premain=true" %run %t/main.o %t/testlibd.so %t/testlibe.so 2>&1 | FileCheck %s
// REQUIRES: target={{(aarch64|x86_64)-.*}}
//--- main.cpp
#include "xray/xray_interface.h"
#include <cstdio>
#include <dlfcn.h>
[[clang::xray_never_instrument]] void test_handler(int32_t fid,
XRayEntryType type) {
printf("called: %d, object=%d, fn=%d, type=%d\n", fid, (fid >> 24) & 0xFF,
fid & 0x00FFFFFF, static_cast<int32_t>(type));
}
[[clang::xray_always_instrument]] void instrumented_in_executable() {
printf("instrumented_in_executable called\n");
}
typedef void (*dso_func_type)();
[[clang::xray_never_instrument]] void *load_dso(const char *path, int mode) {
void *dso_handle = dlopen(path, mode);
if (!dso_handle) {
printf("failed to load shared library\n");
char *error = dlerror();
if (error) {
fprintf(stderr, "%s\n", error);
}
return nullptr;
}
return dso_handle;
}
[[clang::xray_never_instrument]] void find_and_call(void *dso_handle,
const char *fn) {
dso_func_type dso_fn = (dso_func_type)dlsym(dso_handle, fn);
if (!dso_fn) {
printf("failed to find symbol\n");
char *error = dlerror();
if (error) {
fprintf(stderr, "%s\n", error);
}
return;
}
dso_fn();
}
extern void a();
extern void b();
int main(int argc, char **argv) {
if (argc < 3) {
printf("Shared library arguments missing\n");
// CHECK-NOT: Shared library arguments missing
return 1;
}
const char *dso_path_d = argv[1];
const char *dso_path_e = argv[2];
__xray_set_handler(test_handler);
instrumented_in_executable();
// CHECK: called: {{[0-9]+}}, object=0, fn={{[0-9]+}}, type=0
// CHECK-NEXT: instrumented_in_executable called
// CHECK-NEXT: called: {{[0-9]+}}, object=0, fn={{[0-9]+}}, type=1
a();
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ1:[0-9]+]], fn=1, type=0
// CHECK-NEXT: a called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ1]], fn=1, type=1
// Make sure this object ID does not appear again
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ1]]
b(); // b calls c
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ2:[0-9]+]], fn=1, type=0
// CHECK-NEXT: b called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ3:[0-9]+]], fn=1, type=0
// CHECK-NEXT: c called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ3]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ3]]
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ2]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ2]]
// Now check explicit loading with RTLD_LOCAL
void *dso_handle_d = load_dso(dso_path_d, RTLD_LAZY | RTLD_LOCAL);
void *dso_handle_e = load_dso(dso_path_e, RTLD_LAZY | RTLD_LOCAL);
// CHECK-NOT: failed to load shared library
find_and_call(dso_handle_d, "_Z1dv");
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ4:[0-9]+]], fn=1, type=0
// CHECK-NEXT: d called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ4]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ4]]
find_and_call(dso_handle_e, "_Z1ev");
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ5:[0-9]+]], fn=1, type=0
// CHECK-NEXT: e called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ6:[0-9]+]], fn=1, type=0
// CHECK-NEXT: f called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ6]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ6]]
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ5]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ5]]
// Unload DSOs
dlclose(dso_handle_d);
dlclose(dso_handle_e);
// Repeat test with RTLD_GLOBAL
dso_handle_d = load_dso(dso_path_d, RTLD_LAZY | RTLD_GLOBAL);
dso_handle_e = load_dso(dso_path_e, RTLD_LAZY | RTLD_GLOBAL);
// CHECK-NOT: failed to load shared library
find_and_call(dso_handle_d, "_Z1dv");
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ7:[0-9]+]], fn=1, type=0
// CHECK-NEXT: d called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ7]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ7]]
find_and_call(dso_handle_e, "_Z1ev");
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ8:[0-9]+]], fn=1, type=0
// CHECK-NEXT: e called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ9:[0-9]+]], fn=1, type=0
// CHECK-NEXT: f called
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ9]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ9]]
// CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ8]], fn=1, type=1
// CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ8]]
auto status = __xray_unpatch();
printf("unpatching status: %d\n", static_cast<int32_t>(status));
// CHECK-NEXT: unpatching status: 1
dlclose(dso_handle_d);
dlclose(dso_handle_e);
}
//--- libgenmacro.inc
#include <cstdio>
// Helper macros to quickly generate libraries containing a single function.
#define GENERATE_LIB(NAME) \
[[clang::xray_always_instrument]] void NAME() { printf(#NAME " called\n"); }
#define GENERATE_LIB_WITH_CALL(NAME, FN) \
extern void FN(); \
[[clang::xray_always_instrument]] void NAME() { \
printf(#NAME " called\n"); \
FN(); \
}
//--- testliba.cpp
#include "libgenmacro.inc"
GENERATE_LIB(a)
//--- testlibb.cpp
#include "libgenmacro.inc"
GENERATE_LIB_WITH_CALL(b, c)
//--- testlibc.cpp
#include "libgenmacro.inc"
GENERATE_LIB(c)
//--- testlibd.cpp
#include "libgenmacro.inc"
GENERATE_LIB(d)
//--- testlibe.cpp
#include "libgenmacro.inc"
GENERATE_LIB_WITH_CALL(e, f)
//--- testlibf.cpp
#include "libgenmacro.inc"
GENERATE_LIB(f)