Skip to content

Commit 86e252c

Browse files
[XRay] Add DSO support for XRay instrumentation on X86_64
1 parent 970e2c1 commit 86e252c

22 files changed

+1189
-138
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ CODEGENOPT(XRayIgnoreLoops , 1, 0)
133133
///< Emit the XRay function index section.
134134
CODEGENOPT(XRayFunctionIndex , 1, 1)
135135

136+
///< Set when -fxray-enable-shared is enabled
137+
CODEGENOPT(XRayEnableShared , 1, 0)
136138

137139
///< Set the minimum number of instructions in a function to determine selective
138140
///< XRay instrumentation.

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,11 @@ def fxray_selected_function_group :
29222922
HelpText<"When using -fxray-function-groups, select which group of functions to instrument. Valid range is 0 to fxray-function-groups - 1">,
29232923
MarshallingInfoInt<CodeGenOpts<"XRaySelectedFunctionGroup">, "0">;
29242924

2925+
defm xray_enable_shared : BoolFOption<"xray-enable-shared",
2926+
CodeGenOpts<"XRayEnableShared">, DefaultFalse,
2927+
PosFlag<SetTrue, [], [ClangOption, CC1Option],
2928+
"Enable shared library instrumentation with XRay">,
2929+
NegFlag<SetFalse>>;
29252930

29262931
defm fine_grained_bitfield_accesses : BoolOption<"f", "fine-grained-bitfield-accesses",
29272932
CodeGenOpts<"FineGrainedBitfieldAccesses">, DefaultFalse,

clang/include/clang/Driver/XRayArgs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class XRayArgs {
2727
XRayInstrSet InstrumentationBundle;
2828
llvm::opt::Arg *XRayInstrument = nullptr;
2929
bool XRayRT = true;
30+
bool XRayEnableShared = false;
3031

3132
public:
3233
/// Parses the XRay arguments from an argument list.
@@ -35,6 +36,9 @@ class XRayArgs {
3536
llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const;
3637

3738
bool needsXRayRt() const { return XRayInstrument && XRayRT; }
39+
bool needsXRayDSORt() const {
40+
return XRayInstrument && XRayRT && XRayEnableShared;
41+
}
3842
llvm::ArrayRef<std::string> modeList() const { return Modes; }
3943
XRayInstrSet instrumentationBundle() const { return InstrumentationBundle; }
4044
};

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,10 +1629,14 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
16291629
}
16301630

16311631
bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringList &CmdArgs) {
1632-
if (Args.hasArg(options::OPT_shared))
1633-
return false;
1634-
1635-
if (TC.getXRayArgs().needsXRayRt()) {
1632+
if (Args.hasArg(options::OPT_shared)) {
1633+
if (TC.getXRayArgs().needsXRayDSORt()) {
1634+
CmdArgs.push_back("--whole-archive");
1635+
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray-dso"));
1636+
CmdArgs.push_back("--no-whole-archive");
1637+
return true;
1638+
}
1639+
} else if (TC.getXRayArgs().needsXRayRt()) {
16361640
CmdArgs.push_back("--whole-archive");
16371641
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray"));
16381642
for (const auto &Mode : TC.getXRayArgs().modeList())

clang/lib/Driver/XRayArgs.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
6363
<< XRayInstrument->getSpelling() << Triple.str();
6464
}
6565

66+
if (Args.hasFlag(options::OPT_fxray_enable_shared,
67+
options::OPT_fno_xray_enable_shared, false)) {
68+
XRayEnableShared = true;
69+
70+
// DSO instrumentation is currently limited to x86_64
71+
if (Triple.getArch() != llvm::Triple::x86_64) {
72+
D.Diag(diag::err_drv_unsupported_opt_for_target)
73+
<< "-fxray-enable-shared" << Triple.str();
74+
}
75+
76+
unsigned PICLvl = std::get<1>(tools::ParsePICArgs(TC, Args));
77+
if (!PICLvl) {
78+
D.Diag(diag::err_opt_not_valid_without_opt)
79+
<< "-fxray-enable-shared" << "-fPIC";
80+
}
81+
}
82+
6683
// Both XRay and -fpatchable-function-entry use
6784
// TargetOpcode::PATCHABLE_FUNCTION_ENTER.
6885
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ))
@@ -177,6 +194,10 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
177194
Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index,
178195
options::OPT_fno_xray_function_index);
179196

197+
if (XRayEnableShared)
198+
Args.addOptInFlag(CmdArgs, options::OPT_fxray_enable_shared,
199+
options::OPT_fno_xray_enable_shared);
200+
180201
if (const Arg *A =
181202
Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) {
182203
int Value;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fPIC -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s
2+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fpic -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s
3+
// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s
4+
// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fno-PIC -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-PIC
5+
// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fno-pic -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-PIC
6+
7+
// On 64 bit darwin, PIC is always enabled
8+
// RUN: %clang -### --target=x86_64-apple-darwin -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s
9+
10+
// Check unsupported targets
11+
// RUN: not %clang -### --target=aarch64-pc-freebsd -fPIC -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TARGET
12+
// RUN: not %clang -### --target=arm64-apple-macos -fPIC -fxray-instrument -fxray-enable-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TARGET
13+
14+
// CHECK: "-cc1" {{.*}}"-fxray-instrument" {{.*}}"-fxray-enable-shared"
15+
// ERR-TARGET: error: unsupported option '-fxray-enable-shared' for target
16+
// ERR-PIC: error: option '-fxray-enable-shared' cannot be specified without '-fPIC'
17+

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ else()
104104
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}
105105
powerpc64le ${HEXAGON} ${LOONGARCH64})
106106
endif()
107+
set(ALL_XRAY_DSO_SUPPORTED_ARCH ${X86_64})
107108
set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64})
108109

109110
if (UNIX)

compiler-rt/cmake/config-ix.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,9 @@ if(APPLE)
668668
list_intersect(XRAY_SUPPORTED_ARCH
669669
ALL_XRAY_SUPPORTED_ARCH
670670
SANITIZER_COMMON_SUPPORTED_ARCH)
671+
list_intersect(XRAY_DSO_SUPPORTED_ARCH
672+
ALL_XRAY_DSO_SUPPORTED_ARCH
673+
SANITIZER_COMMON_SUPPORTED_ARCH)
671674
list_intersect(SHADOWCALLSTACK_SUPPORTED_ARCH
672675
ALL_SHADOWCALLSTACK_SUPPORTED_ARCH
673676
SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -702,6 +705,7 @@ else()
702705
filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH})
703706
filter_available_targets(SCUDO_STANDALONE_SUPPORTED_ARCH ${ALL_SCUDO_STANDALONE_SUPPORTED_ARCH})
704707
filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH})
708+
filter_available_targets(XRAY_DSO_SUPPORTED_ARCH ${ALL_XRAY_DSO_SUPPORTED_ARCH})
705709
filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH
706710
${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH})
707711
filter_available_targets(GWP_ASAN_SUPPORTED_ARCH ${ALL_GWP_ASAN_SUPPORTED_ARCH})

compiler-rt/include/xray/xray_interface.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,50 @@ enum XRayPatchingStatus {
9797
/// for possible result values.
9898
extern XRayPatchingStatus __xray_patch();
9999

100+
extern XRayPatchingStatus __xray_patch_object(int32_t ObjId);
101+
100102
/// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible
101103
/// result values.
102104
extern XRayPatchingStatus __xray_unpatch();
103105

106+
extern XRayPatchingStatus __xray_unpatch_object(int32_t ObjId);
107+
104108
/// This patches a specific function id. See XRayPatchingStatus for possible
105109
/// result values.
106110
extern XRayPatchingStatus __xray_patch_function(int32_t FuncId);
107111

112+
extern XRayPatchingStatus __xray_patch_function_in_object(int32_t FuncId,
113+
int32_t ObjId);
114+
108115
/// This unpatches a specific function id. See XRayPatchingStatus for possible
109116
/// result values.
110117
extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId);
111118

119+
extern XRayPatchingStatus __xray_unpatch_function_in_object(int32_t FuncId,
120+
int32_t ObjId);
121+
112122
/// This function returns the address of the function provided a valid function
113123
/// id. We return 0 if we encounter any error, even if 0 may be a valid function
114124
/// address.
115125
extern uintptr_t __xray_function_address(int32_t FuncId);
116126

127+
extern uintptr_t __xray_function_address_in_object(int32_t FuncId,
128+
int32_t ObjId);
129+
117130
/// This function returns the maximum valid function id. Returns 0 if we
118131
/// encounter errors (when there are no instrumented functions, etc.).
119132
extern size_t __xray_max_function_id();
120133

134+
extern size_t __xray_max_function_id_in_object(int32_t ObjId);
135+
136+
extern size_t __xray_num_objects();
137+
138+
extern int32_t __xray_unpack_function_id(int32_t PackedId);
139+
140+
extern int32_t __xray_unpack_object_id(int32_t PackedId);
141+
142+
extern int32_t __xray_pack_id(int32_t FuncId, int32_t ObjId);
143+
121144
/// Initialize the required XRay data structures. This is useful in cases where
122145
/// users want to control precisely when the XRay instrumentation data
123146
/// structures are initialized, for example when the XRay library is built with

compiler-rt/lib/xray/CMakeLists.txt

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ set(XRAY_SOURCES
1010
xray_utils.cpp
1111
)
1212

13+
set(XRAY_DSO_SOURCES
14+
xray_dso_init.cpp
15+
)
16+
1317
# Implementation files for all XRay modes.
1418
set(XRAY_FDR_MODE_SOURCES
1519
xray_fdr_flags.cpp
@@ -33,6 +37,11 @@ set(x86_64_SOURCES
3337
xray_trampoline_x86_64.S
3438
)
3539

40+
set(x86_64_DSO_SOURCES
41+
xray_trampoline_x86_64.S
42+
)
43+
44+
3645
set(arm_SOURCES
3746
xray_arm.cpp
3847
xray_trampoline_arm.S
@@ -128,10 +137,12 @@ set(XRAY_IMPL_HEADERS
128137
# consumption by tests.
129138
set(XRAY_ALL_SOURCE_FILES
130139
${XRAY_SOURCES}
140+
${XRAY_DSO_SOURCES}
131141
${XRAY_FDR_MODE_SOURCES}
132142
${XRAY_BASIC_MODE_SOURCES}
133143
${XRAY_PROFILING_MODE_SOURCES}
134144
${x86_64_SOURCES}
145+
${x86_64_DSO_SOURCES}
135146
${arm_SOURCES}
136147
${armhf_SOURCES}
137148
${hexagon_SOURCES}
@@ -162,6 +173,9 @@ set(XRAY_CFLAGS
162173
${COMPILER_RT_CXX_CFLAGS})
163174
set(XRAY_COMMON_DEFINITIONS SANITIZER_COMMON_NO_REDEFINE_BUILTINS XRAY_HAS_EXCEPTIONS=1)
164175

176+
# DSO trampolines need to be compiled with GOT addressing
177+
set(XRAY_COMMON_DEFINITIONS_DSO ${XRAY_COMMON_DEFINITIONS} XRAY_PIC)
178+
165179
# Too many existing bugs, needs cleanup.
166180
append_list_if(COMPILER_RT_HAS_WNO_FORMAT -Wno-format XRAY_CFLAGS)
167181

@@ -201,7 +215,16 @@ if (APPLE)
201215
CFLAGS ${XRAY_CFLAGS}
202216
DEFS ${XRAY_COMMON_DEFINITIONS}
203217
DEPS ${XRAY_DEPS})
218+
add_compiler_rt_object_libraries(RTXrayDSO
219+
OS ${XRAY_SUPPORTED_OS}
220+
ARCHS ${XRAY_DSO_SUPPORTED_ARCH}
221+
SOURCES ${XRAY_DSO_SOURCES}
222+
ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS}
223+
CFLAGS ${XRAY_CFLAGS}
224+
DEFS ${XRAY_COMMON_DEFINITIONS_DSO}
225+
DEPS ${XRAY_DEPS})
204226
set(XRAY_RTXRAY_ARCH_LIBS "")
227+
set(XRAY_DSO_RTXRAY_ARCH_LIBS "")
205228
foreach(arch ${XRAY_SUPPORTED_ARCH})
206229
if(NOT ${arch} IN_LIST XRAY_SOURCE_ARCHS)
207230
continue()
@@ -215,6 +238,17 @@ if (APPLE)
215238
DEFS ${XRAY_COMMON_DEFINITIONS}
216239
DEPS ${XRAY_DEPS})
217240
list(APPEND XRAY_RTXRAY_ARCH_LIBS RTXray_${arch})
241+
if (${arch} IN_LIST XRAY_DSO_SUPPORTED_ARCH)
242+
add_compiler_rt_object_libraries(RTXrayDSO_${arch}
243+
OS ${XRAY_SUPPORTED_OS}
244+
ARCHS ${XRAY_DSO_SUPPORTED_ARCH}
245+
SOURCES ${${arch}_DSO_SOURCES}
246+
ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS}
247+
CFLAGS ${XRAY_CFLAGS}
248+
DEFS ${XRAY_COMMON_DEFINITIONS_DSO}
249+
DEPS ${XRAY_DEPS})
250+
list(APPEND XRAY_DSO_RTXRAY_ARCH_LIBS RTXrayDSO_${arch})
251+
endif()
218252
endforeach()
219253
add_compiler_rt_object_libraries(RTXrayFDR
220254
OS ${XRAY_SUPPORTED_OS}
@@ -252,6 +286,17 @@ if (APPLE)
252286
LINK_FLAGS ${XRAY_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
253287
LINK_LIBS ${XRAY_LINK_LIBS}
254288
PARENT_TARGET xray)
289+
add_compiler_rt_runtime(clang_rt.xray-dso
290+
STATIC
291+
OS ${XRAY_SUPPORTED_OS}
292+
ARCHS ${XRAY_DSO_SUPPORTED_ARCH}
293+
OBJECT_LIBS RTXrayDSO ${XRAY_DSO_RTXRAY_ARCH_LIBS}
294+
CFLAGS ${XRAY_CFLAGS}
295+
DEFS ${XRAY_COMMON_DEFINITIONS}
296+
LINK_FLAGS ${XRAY_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
297+
LINK_LIBS ${XRAY_LINK_LIBS}
298+
PARENT_TARGET xray)
299+
255300
add_compiler_rt_runtime(clang_rt.xray-fdr
256301
STATIC
257302
OS ${XRAY_SUPPORTED_OS}
@@ -346,16 +391,37 @@ else() # not Apple
346391
DEFS ${XRAY_COMMON_DEFINITIONS}
347392
OBJECT_LIBS RTXrayBASIC
348393
PARENT_TARGET xray)
349-
# Profiler Mode runtime
350-
add_compiler_rt_runtime(clang_rt.xray-profiling
351-
STATIC
352-
ARCHS ${arch}
353-
CFLAGS ${XRAY_CFLAGS}
354-
LINK_FLAGS ${XRAY_LINK_FLAGS}
355-
LINK_LIBS ${XRAY_LINK_LIBS}
356-
DEFS ${XRAY_COMMON_DEFINITIONS}
357-
OBJECT_LIBS RTXrayPROFILING
358-
PARENT_TARGET xray)
394+
# Profiler Mode runtime
395+
add_compiler_rt_runtime(clang_rt.xray-profiling
396+
STATIC
397+
ARCHS ${arch}
398+
CFLAGS ${XRAY_CFLAGS}
399+
LINK_FLAGS ${XRAY_LINK_FLAGS}
400+
LINK_LIBS ${XRAY_LINK_LIBS}
401+
DEFS ${XRAY_COMMON_DEFINITIONS}
402+
OBJECT_LIBS RTXrayPROFILING
403+
PARENT_TARGET xray)
404+
405+
if (${arch} IN_LIST XRAY_DSO_SUPPORTED_ARCH)
406+
# TODO: Only implemented for X86 at the moment
407+
add_compiler_rt_object_libraries(RTXrayDSO
408+
ARCHS ${arch}
409+
SOURCES ${XRAY_DSO_SOURCES} ${${arch}_DSO_SOURCES}
410+
ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS}
411+
CFLAGS ${XRAY_CFLAGS}
412+
DEFS ${XRAY_COMMON_DEFINITIONS_DSO}
413+
DEPS ${XRAY_DEPS})
414+
# DSO runtime archive
415+
add_compiler_rt_runtime(clang_rt.xray-dso
416+
STATIC
417+
ARCHS ${arch}
418+
CFLAGS ${XRAY_CFLAGS}
419+
LINK_FLAGS ${XRAY_LINK_FLAGS}
420+
LINK_LIBS ${XRAY_LINK_LIBS}
421+
DEFS ${XRAY_COMMON_DEFINITIONS}
422+
OBJECT_LIBS RTXrayDSO
423+
PARENT_TARGET xray)
424+
endif()
359425
endforeach()
360426
endif() # not Apple
361427

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===-- xray_init.cpp -------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of XRay, a dynamic runtime instrumentation system.
10+
//
11+
// XRay initialisation logic for DSOs.
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "sanitizer_common/sanitizer_atomic.h"
15+
#include "xray_defs.h"
16+
#include "xray_flags.h"
17+
#include "xray_interface_internal.h"
18+
19+
using namespace __sanitizer;
20+
21+
extern "C" {
22+
extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak))
23+
__attribute__((visibility("hidden")));
24+
extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak))
25+
__attribute__((visibility("hidden")));
26+
extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak))
27+
__attribute__((visibility("hidden")));
28+
extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak))
29+
__attribute__((visibility("hidden")));
30+
31+
#if SANITIZER_APPLE
32+
// HACK: This is a temporary workaround to make XRay build on
33+
// Darwin, but it will probably not work at runtime.
34+
extern const XRaySledEntry __start_xray_instr_map[] = {};
35+
extern const XRaySledEntry __stop_xray_instr_map[] = {};
36+
extern const XRayFunctionSledIndex __start_xray_fn_idx[] = {};
37+
extern const XRayFunctionSledIndex __stop_xray_fn_idx[] = {};
38+
#endif
39+
}
40+
41+
// Handler functions to call in the patched entry/exit sled.
42+
extern atomic_uintptr_t XRayPatchedFunction;
43+
extern atomic_uintptr_t XRayArgLogger;
44+
extern atomic_uintptr_t XRayPatchedCustomEvent;
45+
extern atomic_uintptr_t XRayPatchedTypedEvent;
46+
47+
static int __xray_object_id{-1};
48+
49+
// Note: .preinit_array initialization does not work for DSOs
50+
__attribute__((constructor(0))) static void
51+
__xray_init_dso() XRAY_NEVER_INSTRUMENT {
52+
// Register sleds in main XRay runtime.
53+
__xray_object_id =
54+
__xray_register_dso(__start_xray_instr_map, __stop_xray_instr_map,
55+
__start_xray_fn_idx, __stop_xray_fn_idx, {});
56+
}
57+
58+
__attribute__((destructor(0))) static void
59+
__xray_finalize_dso() XRAY_NEVER_INSTRUMENT {
60+
// Inform the main runtime that this DSO is no longer used.
61+
__xray_deregister_dso(__xray_object_id);
62+
}

0 commit comments

Comments
 (0)