Skip to content

Commit 938c503

Browse files
committedJul 21, 2016
[compiler-rt][XRay] re-submitting r276117, with fixes for build breakage due to extraneous and missing dependencies and attempts to build on unsupported OSes
Summary: This is a fixed-up version of D21612, to address failure identified post-commit. Original commit description: This patch implements the initialisation and patching routines for the XRay runtime, along with the necessary trampolines for function entry/exit handling. For now we only define the basic hooks for allowing an implementation to define a handler that gets run on function entry/exit. We expose a minimal API for controlling the behaviour of the runtime (patching, cleanup, and setting the handler to invoke when instrumenting). Fixes include: - Gating XRay build to only Linux x86_64 and with the right dependencies in case it is the only library being built - Including <cstddef> to fix std::size_t issue Reviewers: kcc, rnk, echristo Subscribers: mehdi_amini, llvm-commits Differential Revision: https://reviews.llvm.org/D22611 llvm-svn: 276251
1 parent fe22d59 commit 938c503

13 files changed

+647
-2
lines changed
 

‎compiler-rt/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
3737
mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
3838
option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
3939
mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
40+
option(COMPILER_RT_BUILD_XRAY "Build xray" ON)
41+
mark_as_advanced(COMPILER_RT_BUILD_XRAY)
4042

4143
if (COMPILER_RT_STANDALONE_BUILD)
4244
if (NOT LLVM_CONFIG_PATH)

‎compiler-rt/cmake/config-ix.cmake

+11
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
161161
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
162162
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64})
163163
set(ALL_SCUDO_SUPPORTED_ARCH ${X86_64})
164+
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64})
164165

165166
if(APPLE)
166167
include(CompilerRTDarwinUtils)
@@ -350,6 +351,9 @@ if(APPLE)
350351
list_intersect(SCUDO_SUPPORTED_ARCH
351352
ALL_SCUDO_SUPPORTED_ARCH
352353
SANITIZER_COMMON_SUPPORTED_ARCH)
354+
list_intersect(XRAY_SUPPORTED_ARCH
355+
ALL_XRAY_SUPPORTED_ARCH
356+
SANITIZER_COMMON_SUPPORTED_ARCH)
353357
else()
354358
# Architectures supported by compiler-rt libraries.
355359
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
@@ -373,6 +377,7 @@ else()
373377
filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH})
374378
filter_available_targets(SCUDO_SUPPORTED_ARCH
375379
${ALL_SCUDO_SUPPORTED_ARCH})
380+
filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH})
376381
endif()
377382

378383
if (MSVC)
@@ -493,3 +498,9 @@ else()
493498
set(COMPILER_RT_HAS_SCUDO FALSE)
494499
endif()
495500

501+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
502+
OS_NAME MATCHES "Linux")
503+
set(COMPILER_RT_HAS_XRAY TRUE)
504+
else()
505+
set(COMPILER_RT_HAS_XRAY FALSE)
506+
endif()

‎compiler-rt/include/CMakeLists.txt

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@ set(SANITIZER_HEADERS
1010
sanitizer/msan_interface.h
1111
sanitizer/tsan_interface_atomic.h)
1212

13+
set(XRAY_HEADERS
14+
xray/xray_interface.h)
15+
16+
set(COMPILER_RT_HEADERS
17+
${SANITIZER_HEADERS}
18+
${XRAY_HEADERS})
19+
1320
set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
1421

1522
# Copy compiler-rt headers to the build tree.
1623
set(out_files)
17-
foreach( f ${SANITIZER_HEADERS} )
24+
foreach( f ${COMPILER_RT_HEADERS} )
1825
set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} )
1926
set( dst ${output_dir}/${f} )
2027
add_custom_command(OUTPUT ${dst}
@@ -32,3 +39,7 @@ set_target_properties(compiler-rt-headers PROPERTIES FOLDER "Compiler-RT Misc")
3239
install(FILES ${SANITIZER_HEADERS}
3340
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
3441
DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/sanitizer)
42+
# Install xray headers.
43+
install(FILES ${XRAY_HEADERS}
44+
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
45+
DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/xray)
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===-- xray_interface.h ----------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// APIs for controlling XRay functionality explicitly.
13+
//===----------------------------------------------------------------------===//
14+
#ifndef XRAY_XRAY_INTERFACE_H
15+
#define XRAY_XRAY_INTERFACE_H
16+
17+
#include <cstdint>
18+
19+
extern "C" {
20+
21+
enum XRayEntryType { ENTRY = 0, EXIT = 1 };
22+
23+
// Provide a function to invoke for when instrumentation points are hit. This is
24+
// a user-visible control surface that overrides the default implementation. The
25+
// function provided should take the following arguments:
26+
//
27+
// - function id: an identifier that indicates the id of a function; this id
28+
// is generated by xray; the mapping between the function id
29+
// and the actual function pointer is available through
30+
// __xray_table.
31+
// - entry type: identifies what kind of instrumentation point was encountered
32+
// (function entry, function exit, etc.). See the enum
33+
// XRayEntryType for more details.
34+
//
35+
// Returns 1 on success, 0 on error.
36+
extern int __xray_set_handler(void (*entry)(int32_t, XRayEntryType));
37+
38+
// This removes whatever the currently provided handler is. Returns 1 on
39+
// success, 0 on error.
40+
extern int __xray_remove_handler();
41+
42+
enum XRayPatchingStatus {
43+
NOT_INITIALIZED = 0,
44+
NOTIFIED = 1,
45+
ONGOING = 2,
46+
FAILED = 3
47+
};
48+
49+
// This tells XRay to patch the instrumentation points. This is an asynchronous
50+
// process, and returns the following status in specific cases:
51+
//
52+
// - 0 : XRay is not initialized.
53+
// - 1 : We've done the notification.
54+
// - 2 : Patching / un-patching is on-going.
55+
extern XRayPatchingStatus __xray_patch();
56+
57+
// Reverses the effect of __xray_patch(). This is an asynchronous process, and
58+
// returns the following status in specific cases.
59+
//
60+
// - 0 : XRay is not initialized.
61+
// - 1 : We've done the notification.
62+
// - 2 : Patching / un-patching is on-going.
63+
extern int __xray_unpatch();
64+
}
65+
66+
#endif

‎compiler-rt/lib/CMakeLists.txt

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
include(AddCompilerRT)
55
include(SanitizerUtils)
66

7+
# Hoist the building of sanitizer_common on whether we're building either the
8+
# sanitizers or xray (or both).
9+
#
10+
#TODO: Refactor sanitizer_common into smaller pieces (e.g. flag parsing, utils).
11+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND
12+
(COMPILER_RT_BUILD_SANITIZERS OR COMPILER_RT_BUILD_XRAY))
13+
add_subdirectory(sanitizer_common)
14+
endif()
15+
716
if(COMPILER_RT_BUILD_BUILTINS)
817
add_subdirectory(builtins)
918
endif()
@@ -14,7 +23,6 @@ if(COMPILER_RT_BUILD_SANITIZERS)
1423
endif()
1524

1625
if(COMPILER_RT_HAS_SANITIZER_COMMON)
17-
add_subdirectory(sanitizer_common)
1826
add_subdirectory(stats)
1927
add_subdirectory(lsan)
2028
add_subdirectory(ubsan)
@@ -57,3 +65,7 @@ if(COMPILER_RT_BUILD_SANITIZERS)
5765
add_subdirectory(scudo)
5866
endif()
5967
endif()
68+
69+
if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY)
70+
add_subdirectory(xray)
71+
endif()

‎compiler-rt/lib/xray/CMakeLists.txt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Build for the XRay runtime support library.
2+
3+
set(XRAY_SOURCES
4+
xray_init.cc
5+
xray_interface.cc
6+
xray_flags.cc
7+
)
8+
9+
set(x86_64_SOURCES
10+
xray_trampoline_x86.S
11+
${XRAY_SOURCES})
12+
13+
include_directories(..)
14+
include_directories(../../include)
15+
16+
set(XRAY_CFLAGS ${SANITIZER_COMMON_CFLAGS})
17+
18+
set(XRAY_COMMON_DEFINITIONS XRAY_HAS_EXCEPTIONS=1)
19+
20+
add_compiler_rt_object_libraries(RTXray
21+
ARCHS ${XRAY_SUPPORTED_ARCH}
22+
SOURCES ${XRAY_SOURCES} CFLAGS ${XRAY_CFLAGS}
23+
DEFS ${XRAY_COMMON_DEFINITIONS})
24+
25+
add_custom_target(xray)
26+
set(XRAY_COMMON_RUNTIME_OBJECT_LIBS
27+
RTSanitizerCommon
28+
RTSanitizerCommonLibc)
29+
30+
foreach (arch ${XRAY_SUPPORTED_ARCH})
31+
if (CAN_TARGET_${arch})
32+
add_compiler_rt_runtime(clang_rt.xray
33+
STATIC
34+
ARCHS ${arch}
35+
SOURCES ${${arch}_SOURCES}
36+
CFLAGS ${XRAY_CFLAGS}
37+
DEFS ${XRAY_COMMON_DEFINITIONS}
38+
OBJECT_LIBS ${XRAY_COMMON_RUNTIME_OBJECT_LIBS}
39+
PARENT_TARGET xray)
40+
endif ()
41+
endforeach()
42+
43+
add_dependencies(compiler-rt xray)
44+
45+
# if(COMPILER_RT_INCLUDE_TESTS)
46+
# add_subdirectory(tests)
47+
# endif()

‎compiler-rt/lib/xray/xray_flags.cc

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===-- xray_flags.cc -------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// XRay flag parsing logic.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "xray_flags.h"
16+
#include "sanitizer_common/sanitizer_common.h"
17+
#include "sanitizer_common/sanitizer_flag_parser.h"
18+
#include "sanitizer_common/sanitizer_libc.h"
19+
20+
using namespace __sanitizer;
21+
22+
namespace __xray {
23+
24+
Flags xray_flags_dont_use_directly; // use via flags().
25+
26+
void Flags::SetDefaults() {
27+
#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
28+
#include "xray_flags.inc"
29+
#undef XRAY_FLAG
30+
}
31+
32+
static void RegisterXRayFlags(FlagParser *P, Flags *F) {
33+
#define XRAY_FLAG(Type, Name, DefaultValue, Description) \
34+
RegisterFlag(P, #Name, Description, &F->Name);
35+
#include "xray_flags.inc"
36+
#undef XRAY_FLAG
37+
}
38+
39+
void InitializeFlags() {
40+
SetCommonFlagsDefaults();
41+
auto *F = flags();
42+
F->SetDefaults();
43+
44+
FlagParser XRayParser;
45+
RegisterXRayFlags(&XRayParser, F);
46+
RegisterCommonFlags(&XRayParser);
47+
48+
// Override from command line.
49+
XRayParser.ParseString(GetEnv("XRAY_OPTIONS"));
50+
51+
InitializeCommonFlags();
52+
53+
if (Verbosity())
54+
ReportUnrecognizedFlags();
55+
56+
if (common_flags()->help) {
57+
XRayParser.PrintFlagDescriptions();
58+
}
59+
}
60+
61+
} // namespace __xray

‎compiler-rt/lib/xray/xray_flags.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===-- xray_flags.h -------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instruementation system.
11+
//
12+
// XRay runtime flags.
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef XRAY_FLAGS_H
16+
#define XRAY_FLAGS_H
17+
18+
#include "sanitizer_common/sanitizer_flag_parser.h"
19+
20+
namespace __xray {
21+
22+
struct Flags {
23+
#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name;
24+
#include "xray_flags.inc"
25+
#undef XRAY_FLAG
26+
27+
void SetDefaults();
28+
};
29+
30+
extern Flags xray_flags_dont_use_directly;
31+
inline Flags *flags() { return &xray_flags_dont_use_directly; }
32+
33+
void InitializeFlags();
34+
35+
} // namespace __xray
36+
37+
#endif // XRAY_FLAGS_H

‎compiler-rt/lib/xray/xray_flags.inc

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- xray_flags.inc ------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// XRay runtime flags.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
#ifndef XRAY_FLAG
14+
#error "Define XRAY_FLAG prior to including this file!"
15+
#endif
16+
17+
XRAY_FLAG(bool, patch_premain, true,
18+
"Whether to patch instrumentation points before main.")

‎compiler-rt/lib/xray/xray_init.cc

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===-- xray_init.cc --------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// XRay initialisation logic.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include <atomic>
16+
#include <fcntl.h>
17+
#include <strings.h>
18+
#include <unistd.h>
19+
20+
#include "sanitizer_common/sanitizer_common.h"
21+
#include "xray_flags.h"
22+
#include "xray_interface_internal.h"
23+
24+
extern "C" {
25+
extern void __xray_init();
26+
extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak));
27+
extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak));
28+
}
29+
30+
using namespace __xray;
31+
32+
// We initialize some global variables that pertain to specific sections of XRay
33+
// data structures in the binary. We do this for the current process using
34+
// /proc/curproc/map and make sure that we're able to get it. We signal failure
35+
// via a global atomic boolean to indicate whether we've initialized properly.
36+
//
37+
std::atomic<bool> XRayInitialized{false};
38+
39+
// This should always be updated before XRayInitialized is updated.
40+
std::atomic<__xray::XRaySledMap> XRayInstrMap{};
41+
42+
// __xray_init() will do the actual loading of the current process' memory map
43+
// and then proceed to look for the .xray_instr_map section/segment.
44+
void __xray_init() {
45+
InitializeFlags();
46+
if (__start_xray_instr_map == nullptr) {
47+
Report("XRay instrumentation map missing. Not initializing XRay.\n");
48+
return;
49+
}
50+
51+
// Now initialize the XRayInstrMap global struct with the address of the
52+
// entries, reinterpreted as an array of XRaySledEntry objects. We use the
53+
// virtual pointer we have from the section to provide us the correct
54+
// information.
55+
__xray::XRaySledMap SledMap{};
56+
SledMap.Sleds = __start_xray_instr_map;
57+
SledMap.Entries = __stop_xray_instr_map - __start_xray_instr_map;
58+
XRayInstrMap.store(SledMap, std::memory_order_release);
59+
XRayInitialized.store(true, std::memory_order_release);
60+
61+
if (flags()->patch_premain)
62+
__xray_patch();
63+
}
64+
65+
__attribute__((section(".preinit_array"),
66+
used)) void (*__local_xray_preinit)(void) = __xray_init;
+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//===-- xray_interface.cpp --------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// Implementation of the API functions.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "xray_interface_internal.h"
17+
#include <atomic>
18+
#include <cstdint>
19+
#include <cstdio>
20+
#include <errno.h>
21+
#include <limits>
22+
#include <sys/mman.h>
23+
24+
namespace __xray {
25+
26+
// This is the function to call when we encounter the entry or exit sleds.
27+
std::atomic<void (*)(int32_t, XRayEntryType)> XRayPatchedFunction{nullptr};
28+
29+
} // namespace __xray
30+
31+
extern "C" {
32+
// The following functions have to be defined in assembler, on a per-platform
33+
// basis. See xray_trampoline_*.s files for implementations.
34+
extern void __xray_FunctionEntry();
35+
extern void __xray_FunctionExit();
36+
}
37+
38+
extern std::atomic<bool> XRayInitialized;
39+
extern std::atomic<__xray::XRaySledMap> XRayInstrMap;
40+
41+
int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) {
42+
if (XRayInitialized.load(std::memory_order_acquire)) {
43+
__xray::XRayPatchedFunction.store(entry, std::memory_order_release);
44+
return 1;
45+
}
46+
return 0;
47+
}
48+
49+
std::atomic<bool> XRayPatching{false};
50+
51+
XRayPatchingStatus __xray_patch() {
52+
// FIXME: Make this happen asynchronously. For now just do this sequentially.
53+
if (!XRayInitialized.load(std::memory_order_acquire))
54+
return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.
55+
56+
static bool NotPatching = false;
57+
if (!XRayPatching.compare_exchange_strong(NotPatching, true,
58+
std::memory_order_acq_rel,
59+
std::memory_order_acquire)) {
60+
return XRayPatchingStatus::ONGOING; // Already patching.
61+
}
62+
63+
// Step 1: Compute the function id, as a unique identifier per function in the
64+
// instrumentation map.
65+
__xray::XRaySledMap InstrMap = XRayInstrMap.load(std::memory_order_acquire);
66+
if (InstrMap.Entries == 0)
67+
return XRayPatchingStatus::NOT_INITIALIZED;
68+
69+
int32_t FuncId = 1;
70+
static constexpr uint8_t CallOpCode = 0xe8;
71+
static constexpr uint16_t MovR10Seq = 0xba41;
72+
static constexpr uint8_t JmpOpCode = 0xe9;
73+
uint64_t CurFun = 0;
74+
for (std::size_t I = 0; I < InstrMap.Entries; I++) {
75+
auto Sled = InstrMap.Sleds[I];
76+
auto F = Sled.Function;
77+
if (CurFun == 0)
78+
CurFun = F;
79+
if (F != CurFun) {
80+
++FuncId;
81+
CurFun = F;
82+
}
83+
84+
// While we're here, we should patch the nop sled. To do that we mprotect
85+
// the page containing the function to be writeable.
86+
void *PageAlignedAddr =
87+
reinterpret_cast<void *>(Sled.Address & ~((2 << 16) - 1));
88+
std::size_t MProtectLen =
89+
(Sled.Address + 12) - reinterpret_cast<uint64_t>(PageAlignedAddr);
90+
if (mprotect(PageAlignedAddr, MProtectLen,
91+
PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
92+
printf("Failed mprotect: %d\n", errno);
93+
return XRayPatchingStatus::FAILED;
94+
}
95+
96+
static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
97+
static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};
98+
if (Sled.Kind == XRayEntryType::ENTRY) {
99+
// Here we do the dance of replacing the following sled:
100+
//
101+
// xray_sled_n:
102+
// jmp +9
103+
// <9 byte nop>
104+
//
105+
// With the following:
106+
//
107+
// mov r10d, <function id>
108+
// call <relative 32bit offset to entry trampoline>
109+
//
110+
// We need to do this in the following order:
111+
//
112+
// 1. Put the function id first, 2 bytes from the start of the sled (just
113+
// after the 2-byte jmp instruction).
114+
// 2. Put the call opcode 6 bytes from the start of the sled.
115+
// 3. Put the relative offset 7 bytes from the start of the sled.
116+
// 4. Do an atomic write over the jmp instruction for the "mov r10d"
117+
// opcode and first operand.
118+
//
119+
// Prerequisite is to compute the relative offset to the
120+
// __xray_FunctionEntry function's address.
121+
int64_t TrampolineOffset =
122+
reinterpret_cast<int64_t>(__xray_FunctionEntry) -
123+
(static_cast<int64_t>(Sled.Address) + 11);
124+
if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
125+
// FIXME: Print out an error here.
126+
continue;
127+
}
128+
*reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
129+
*reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
130+
*reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
131+
std::atomic_store_explicit(
132+
reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
133+
std::memory_order_release);
134+
}
135+
136+
if (Sled.Kind == XRayEntryType::EXIT) {
137+
// Here we do the dance of replacing the following sled:
138+
//
139+
// xray_sled_n:
140+
// ret
141+
// <10 byte nop>
142+
//
143+
// With the following:
144+
//
145+
// mov r10d, <function id>
146+
// jmp <relative 32bit offset to exit trampoline>
147+
//
148+
// 1. Put the function id first, 2 bytes from the start of the sled (just
149+
// after the 1-byte ret instruction).
150+
// 2. Put the jmp opcode 6 bytes from the start of the sled.
151+
// 3. Put the relative offset 7 bytes from the start of the sled.
152+
// 4. Do an atomic write over the jmp instruction for the "mov r10d"
153+
// opcode and first operand.
154+
//
155+
// Prerequisite is to compute the relative offset fo the
156+
// __xray_FunctionExit function's address.
157+
int64_t TrampolineOffset =
158+
reinterpret_cast<int64_t>(__xray_FunctionExit) -
159+
(static_cast<int64_t>(Sled.Address) + 11);
160+
if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
161+
// FIXME: Print out an error here.
162+
continue;
163+
}
164+
*reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
165+
*reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
166+
*reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
167+
std::atomic_store_explicit(
168+
reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
169+
std::memory_order_release);
170+
}
171+
172+
if (mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC) == -1) {
173+
printf("Failed mprotect: %d\n", errno);
174+
return XRayPatchingStatus::FAILED;
175+
}
176+
}
177+
XRayPatching.store(false, std::memory_order_release);
178+
return XRayPatchingStatus::NOTIFIED;
179+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- xray_interface_internal.h -------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// Implementation of the API functions. See also include/xray/xray_interface.h.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
#ifndef XRAY_INTERFACE_INTERNAL_H
16+
#define XRAY_INTERFACE_INTERNAL_H
17+
18+
#include "xray/xray_interface.h"
19+
#include <cstddef>
20+
#include <cstdint>
21+
22+
extern "C" {
23+
24+
struct XRaySledEntry {
25+
uint64_t Address;
26+
uint64_t Function;
27+
unsigned char Kind;
28+
unsigned char AlwaysInstrument;
29+
unsigned char Padding[14]; // Need 32 bytes
30+
};
31+
}
32+
33+
namespace __xray {
34+
35+
struct XRaySledMap {
36+
const XRaySledEntry *Sleds;
37+
size_t Entries;
38+
};
39+
40+
} // namespace __xray
41+
42+
#endif
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===-- xray_trampoline_x86.s -----------------------------------*- ASM -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of XRay, a dynamic runtime instrumentation system.
11+
//
12+
// This implements the X86-specific assembler for the trampolines.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
.text
17+
.file "xray_trampoline_x86.S"
18+
.globl __xray_FunctionEntry
19+
.align 16, 0x90
20+
.type __xray_FunctionEntry,@function
21+
22+
__xray_FunctionEntry:
23+
.cfi_startproc
24+
// Save caller provided registers before doing any actual work.
25+
pushq %rbp
26+
.cfi_def_cfa_offset 16
27+
subq $72, %rsp
28+
movq %rdi, 64(%rsp)
29+
movq %rax, 56(%rsp)
30+
movq %rdx, 48(%rsp)
31+
movq %rsi, 40(%rsp)
32+
movq %rcx, 32(%rsp)
33+
movq %r8, 24(%rsp)
34+
movq %r9, 16(%rsp)
35+
36+
// de-mangled, that's __xray::XRayPatchedFunction, and we're doing an acquire
37+
// load (on x86 is a normal mov instruction).
38+
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
39+
testq %rax, %rax
40+
je .Ltmp0
41+
42+
// assume that %r10d has the function id.
43+
movl %r10d, %edi
44+
xor %esi,%esi
45+
callq *%rax
46+
.Ltmp0:
47+
// restore the registers
48+
movq 64(%rsp), %rdi
49+
movq 56(%rsp), %rax
50+
movq 48(%rsp), %rdx
51+
movq 40(%rsp), %rsi
52+
movq 32(%rsp), %rcx
53+
movq 24(%rsp), %r8
54+
movq 16(%rsp), %r9
55+
addq $72, %rsp
56+
popq %rbp
57+
retq
58+
.Ltmp1:
59+
.size __xray_FunctionEntry, .Ltmp1-__xray_FunctionEntry
60+
.cfi_endproc
61+
62+
.globl __xray_FunctionExit
63+
.align 16, 0x90
64+
.type __xray_FunctionExit,@function
65+
__xray_FunctionExit:
66+
.cfi_startproc
67+
// Save the important registers first. Since we're assuming that this
68+
// function is only jumped into, we only preserve the registers for
69+
// returning.
70+
// FIXME: Figure out whether this is sufficient.
71+
pushq %rbp
72+
.cfi_def_cfa_offset 16
73+
subq $24, %rsp
74+
.cfi_def_cfa_offset 32
75+
movq %rax, 16(%rsp)
76+
movq %rdx, 8(%rsp)
77+
movq _ZN6__xray19XRayPatchedFunctionE(%rip), %rax
78+
testq %rax,%rax
79+
je .Ltmp2
80+
81+
movl %r10d, %edi
82+
movl $1, %esi
83+
callq *%rax
84+
.Ltmp2:
85+
// Restore the important registers.
86+
movq 16(%rsp), %rax
87+
movq 8(%rsp), %rdx
88+
addq $24, %rsp
89+
popq %rbp
90+
retq
91+
.Ltmp3:
92+
.size __xray_FunctionExit, .Ltmp3-__xray_FunctionExit
93+
.cfi_endproc

0 commit comments

Comments
 (0)
Please sign in to comment.