Skip to content

Commit 4e35f16

Browse files
fixup! [XRay] Add DSO support for XRay instrumentation on X86_64
1 parent c08432f commit 4e35f16

File tree

9 files changed

+336
-88
lines changed

9 files changed

+336
-88
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,9 +1595,9 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
15951595
bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringList &CmdArgs) {
15961596
if (Args.hasArg(options::OPT_shared)) {
15971597
if (TC.getXRayArgs().needsXRayDSORt()) {
1598-
CmdArgs.push_back("-whole-archive");
1598+
CmdArgs.push_back("--whole-archive");
15991599
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray-dso"));
1600-
CmdArgs.push_back("-no-whole-archive");
1600+
CmdArgs.push_back("--no-whole-archive");
16011601
return true;
16021602
}
16031603
} else if (TC.getXRayArgs().needsXRayRt()) {

clang/lib/Driver/XRayArgs.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,21 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
6464
}
6565

6666
if (Args.hasFlag(options::OPT_fxray_enable_shared,
67-
options::OPT_fno_xray_enable_shared, false))
67+
options::OPT_fno_xray_enable_shared, false)) {
6868
XRayEnableShared = true;
6969

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) << "-fxray-enable-shared" << "-fPIC";
79+
}
80+
}
81+
7082
// Both XRay and -fpatchable-function-entry use
7183
// TargetOpcode::PATCHABLE_FUNCTION_ENTER.
7284
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ))
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/lib/xray/CMakeLists.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -393,14 +393,14 @@ else() # not Apple
393393
PARENT_TARGET xray)
394394
# Profiler Mode runtime
395395
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)
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)
404404

405405
if (${arch} IN_LIST XRAY_DSO_SUPPORTED_ARCH)
406406
# TODO: Only implemented for X86 at the moment

compiler-rt/lib/xray/xray_dso_init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ __attribute__((visibility("hidden")));
2828
extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak))
2929
__attribute__((visibility("hidden")));
3030

31-
#if SANITIZER_MAC
31+
#if SANITIZER_APPLE
3232
// HACK: This is a temporary workaround to make XRay build on
3333
// Darwin, but it will probably not work at runtime.
3434
extern const XRaySledEntry __start_xray_instr_map[] = {};

compiler-rt/lib/xray/xray_init.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,15 @@ using namespace __xray;
4545
// the weak symbols defined above (__start_xray_inst_map and
4646
// __stop_xray_instr_map) to initialise the instrumentation map that XRay uses
4747
// for runtime patching/unpatching of instrumentation points.
48-
//
49-
// FIXME: Support DSO instrumentation maps too. The current solution only works
50-
// for statically linked executables.
5148
atomic_uint8_t XRayInitialized{0};
5249

5350
// This should always be updated before XRayInitialized is updated.
5451
SpinMutex XRayInstrMapMutex;
55-
// XRaySledMap XRayInstrMap;
52+
5653
// Contains maps for the main executable as well as DSOs.
57-
// std::vector<XRaySledMap> XRayInstrMaps;
5854
XRaySledMap *XRayInstrMaps;
55+
56+
// Number of binary objects registered.
5957
atomic_uint32_t XRayNumObjects{0};
6058

6159
// Global flag to determine whether the flags have been initialized.
@@ -64,6 +62,9 @@ atomic_uint8_t XRayFlagsInitialized{0};
6462
// A mutex to allow only one thread to initialize the XRay data structures.
6563
SpinMutex XRayInitMutex;
6664

65+
// Registers XRay sleds and trampolines coming from the main executable or one
66+
// of the linked DSOs.
67+
// Returns the object ID if registration is successful, -1 otherwise.
6768
int32_t
6869
__xray_register_sleds(const XRaySledEntry *SledsBegin,
6970
const XRaySledEntry *SledsEnd,
@@ -145,8 +146,9 @@ void __xray_init() XRAY_NEVER_INSTRUMENT {
145146
// Pre-allocation takes up approx. 5kB for XRayMaxObjects=64.
146147
XRayInstrMaps = allocateBuffer<XRaySledMap>(XRayMaxObjects);
147148

148-
int MainBinaryId = __xray_register_sleds(__start_xray_instr_map, __stop_xray_instr_map,
149-
__start_xray_fn_idx, __stop_xray_fn_idx, false, {});
149+
int MainBinaryId =
150+
__xray_register_sleds(__start_xray_instr_map, __stop_xray_instr_map,
151+
__start_xray_fn_idx, __stop_xray_fn_idx, false, {});
150152

151153
// The executable should always get ID 0.
152154
if (MainBinaryId != 0) {
@@ -162,6 +164,9 @@ void __xray_init() XRAY_NEVER_INSTRUMENT {
162164
#endif
163165
}
164166

167+
// Registers XRay sleds and trampolines of an instrumented DSO.
168+
// Returns the object ID if registration is successful, -1 otherwise.
169+
//
165170
// Default visibility is hidden, so we have to explicitly make it visible to
166171
// DSO.
167172
SANITIZER_INTERFACE_ATTRIBUTE int32_t __xray_register_dso(
@@ -191,6 +196,11 @@ SANITIZER_INTERFACE_ATTRIBUTE int32_t __xray_register_dso(
191196
return ObjId;
192197
}
193198

199+
// Deregisters a DSO from the main XRay runtime.
200+
// Called from the DSO-local runtime when the library is unloaded (e.g. if
201+
// dlclose is called).
202+
// Returns true if the object ID is valid and the DSO was successfully
203+
// deregistered.
194204
SANITIZER_INTERFACE_ATTRIBUTE bool
195205
__xray_deregister_dso(int32_t ObjId) XRAY_NEVER_INSTRUMENT {
196206

@@ -220,7 +230,7 @@ __xray_deregister_dso(int32_t ObjId) XRAY_NEVER_INSTRUMENT {
220230
if (Verbosity())
221231
Report("Can't deregister object with ID %d: object is not loaded.\n",
222232
ObjId);
223-
return false;
233+
return true;
224234
}
225235
// Mark DSO as unloaded. No need to unpatch.
226236
Entry.Loaded = false;

compiler-rt/lib/xray/xray_interface.cpp

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
#include "xray_interface_internal.h"
16+
#include "llvm/Support/ErrorHandling.h"
1617

1718
#include <cinttypes>
1819
#include <cstdio>
@@ -289,24 +290,9 @@ XRayPatchingStatus patchFunction(int32_t FuncId, int32_t ObjId,
289290
// controlPatching implements the common internals of the patching/unpatching
290291
// implementation. |Enable| defines whether we're enabling or disabling the
291292
// runtime XRay instrumentation.
292-
XRayPatchingStatus controlPatching(bool Enable,
293-
int32_t ObjId) XRAY_NEVER_INSTRUMENT {
294-
295-
if (!atomic_load(&XRayInitialized, memory_order_acquire))
296-
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
297-
298-
uint8_t NotPatching = false;
299-
if (!atomic_compare_exchange_strong(
300-
&XRayPatching, &NotPatching, true, memory_order_acq_rel))
301-
return XRayPatchingStatus::ONGOING; // Already patching.
302-
303-
uint8_t PatchingSuccess = false;
304-
auto XRayPatchingStatusResetter =
305-
at_scope_exit([&PatchingSuccess] {
306-
if (!PatchingSuccess)
307-
atomic_store(&XRayPatching, false, memory_order_release);
308-
});
309-
293+
// This function should only be called after ensuring that XRay is initialized
294+
// and no other thread is currently patching.
295+
XRayPatchingStatus controlPatchingObjectUnchecked(bool Enable, int32_t ObjId) {
310296
XRaySledMap InstrMap;
311297
{
312298
SpinMutexLock Guard(&XRayInstrMapMutex);
@@ -382,10 +368,80 @@ XRayPatchingStatus controlPatching(bool Enable,
382368
patchSled(Sled, Enable, PackedId, InstrMap.Trampolines);
383369
}
384370
atomic_store(&XRayPatching, false, memory_order_release);
385-
PatchingSuccess = true;
386371
return XRayPatchingStatus::SUCCESS;
387372
}
388373

374+
375+
// Controls patching for all registered objects.
376+
// Returns: SUCCESS, if patching succeeds for all objects.
377+
// NOT_INITIALIZED, if one or more objects returned NOT_INITIALIZED
378+
// but none failed.
379+
// FAILED, if patching of one or more objects failed.
380+
XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT {
381+
if (!atomic_load(&XRayInitialized, memory_order_acquire))
382+
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
383+
384+
uint8_t NotPatching = false;
385+
if (!atomic_compare_exchange_strong(
386+
&XRayPatching, &NotPatching, true, memory_order_acq_rel))
387+
return XRayPatchingStatus::ONGOING; // Already patching.
388+
389+
auto XRayPatchingStatusResetter =
390+
at_scope_exit([] {
391+
atomic_store(&XRayPatching, false, memory_order_release);
392+
});
393+
394+
unsigned NumObjects = __xray_num_objects();
395+
396+
XRayPatchingStatus CombinedStatus{NOT_INITIALIZED};
397+
for (unsigned I = 0; I < NumObjects; ++I) {
398+
if (!isObjectLoaded(I))
399+
continue;
400+
auto LastStatus = controlPatchingObjectUnchecked(Enable, I);
401+
switch (LastStatus) {
402+
case SUCCESS:
403+
if (CombinedStatus == NOT_INITIALIZED)
404+
CombinedStatus = SUCCESS;
405+
break;
406+
case FAILED:
407+
// Report failure, but try to patch the remaining objects
408+
CombinedStatus = FAILED;
409+
break;
410+
case NOT_INITIALIZED:
411+
// XRay has been initialized but there are no sleds available for this
412+
// object. Try to patch remaining objects.
413+
if (CombinedStatus != FAILED)
414+
CombinedStatus = NOT_INITIALIZED;
415+
break;
416+
case ONGOING:
417+
llvm_unreachable("Status ONGOING should not appear at this point");
418+
default:
419+
llvm_unreachable("Unhandled patching status");
420+
}
421+
}
422+
return CombinedStatus;
423+
}
424+
425+
// Controls patching for one object.
426+
XRayPatchingStatus controlPatching(bool Enable,
427+
int32_t ObjId) XRAY_NEVER_INSTRUMENT {
428+
429+
if (!atomic_load(&XRayInitialized, memory_order_acquire))
430+
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
431+
432+
uint8_t NotPatching = false;
433+
if (!atomic_compare_exchange_strong(
434+
&XRayPatching, &NotPatching, true, memory_order_acq_rel))
435+
return XRayPatchingStatus::ONGOING; // Already patching.
436+
437+
auto XRayPatchingStatusResetter =
438+
at_scope_exit([] {
439+
atomic_store(&XRayPatching, false, memory_order_release);
440+
});
441+
442+
return controlPatchingObjectUnchecked(Enable, ObjId);
443+
}
444+
389445
XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId,
390446
bool Enable) XRAY_NEVER_INSTRUMENT {
391447
XRaySledMap InstrMap;
@@ -420,7 +476,7 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId,
420476
return XRayPatchingStatus::FAILED;
421477
}
422478

423-
// Here we compute the minumum sled and maximum sled associated with a
479+
// Here we compute the minimum sled and maximum sled associated with a
424480
// particular function ID.
425481
XRayFunctionSledIndex SledRange;
426482
if (InstrMap.SledsIndex) {
@@ -518,57 +574,15 @@ uint16_t __xray_register_event_type(
518574
}
519575

520576
XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT {
521-
XRayPatchingStatus CombinedStatus{SUCCESS};
522-
for (size_t I = 0; I < __xray_num_objects(); ++I) {
523-
if (!isObjectLoaded(I))
524-
continue;
525-
auto LastStatus = controlPatching(true, I);
526-
switch (LastStatus) {
527-
case FAILED:
528-
CombinedStatus = FAILED;
529-
break;
530-
case NOT_INITIALIZED:
531-
if (CombinedStatus != FAILED)
532-
CombinedStatus = NOT_INITIALIZED;
533-
break;
534-
case ONGOING:
535-
if (CombinedStatus != FAILED && CombinedStatus != NOT_INITIALIZED)
536-
CombinedStatus = ONGOING;
537-
break;
538-
default:
539-
break;
540-
}
541-
}
542-
return CombinedStatus;
577+
return controlPatching(true);
543578
}
544579

545580
XRayPatchingStatus __xray_patch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT {
546581
return controlPatching(true, ObjId);
547582
}
548583

549584
XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT {
550-
XRayPatchingStatus CombinedStatus{SUCCESS};
551-
for (size_t I = 0; I < __xray_num_objects(); ++I) {
552-
if (!isObjectLoaded(I))
553-
continue;
554-
auto LastStatus = controlPatching(false, I);
555-
switch (LastStatus) {
556-
case FAILED:
557-
CombinedStatus = FAILED;
558-
break;
559-
case NOT_INITIALIZED:
560-
if (CombinedStatus != FAILED)
561-
CombinedStatus = NOT_INITIALIZED;
562-
break;
563-
case ONGOING:
564-
if (CombinedStatus != FAILED && CombinedStatus != NOT_INITIALIZED)
565-
CombinedStatus = ONGOING;
566-
break;
567-
default:
568-
break;
569-
}
570-
}
571-
return CombinedStatus;
585+
return controlPatching(false);
572586
}
573587

574588
XRayPatchingStatus __xray_unpatch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT {

compiler-rt/test/xray/TestCases/Posix/dlopen.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: split-file %s %t
55
// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-enable-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so
66
// RUN: %clangxx_xray -g -fPIC -rdynamic -fxray-instrument -fxray-enable-shared -std=c++11 %t/main.cpp -o %t/main.o
7-
7+
//
88
// RUN: XRAY_OPTIONS="patch_premain=true" %run %t/main.o %t/testlib.so 2>&1 | FileCheck %s
99

1010
// REQUIRES: target=x86_64{{.*}}
@@ -16,11 +16,8 @@
1616
#include <cstdio>
1717
#include <dlfcn.h>
1818

19-
bool called = false;
20-
2119
void test_handler(int32_t fid, XRayEntryType type) {
2220
printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type));
23-
called = true;
2421
}
2522

2623
[[clang::xray_always_instrument]] void instrumented_in_executable() {

0 commit comments

Comments
 (0)