[XRay] Support for Fuchsia

This extends XRay to support Fuchsia.

Differential Revision: https://reviews.llvm.org/D52162

llvm-svn: 347443
This commit is contained in:
Petr Hosek 2018-11-22 02:00:44 +00:00
parent 56f3bb4b36
commit e7dec7848b
12 changed files with 259 additions and 22 deletions

View File

@ -641,7 +641,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD")
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia")
set(COMPILER_RT_HAS_XRAY TRUE)
else()
set(COMPILER_RT_HAS_XRAY FALSE)

View File

@ -31,6 +31,7 @@
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer_fuchsia.h"
#include <zircon/process.h>
#include <zircon/sanitizer.h>
@ -101,7 +102,7 @@ class TracePcGuardController final {
// uses the `dumpfile` symbolizer markup element to highlight the
// dump. See the explanation for this in:
// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
Printf("SanitizerCoverage: {{{dumpfile:%s:%s}}} with up to %u PCs\n",
Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n",
kSancovSinkName, vmo_name_, next_index_ - 1);
}
}

View File

@ -35,6 +35,9 @@ constexpr const char *kFormatData = "{{{data:%p}}}";
// One frame in a backtrace (printed on a line by itself).
constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
// Dump trigger element.
#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"
} // namespace __sanitizer
#endif // SANITIZER_SYMBOLIZER_FUCHSIA_H

View File

@ -19,7 +19,13 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_mutex.h"
#if SANITIZER_FUCHSIA
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/status.h>
#else
#include "sanitizer_common/sanitizer_posix.h"
#endif
#include "xray_defs.h"
#include "xray_utils.h"
#include <cstddef>
@ -33,6 +39,28 @@ namespace __xray {
// mmap'ed memory to back the allocators.
template <class T> T *allocate() XRAY_NEVER_INSTRUMENT {
uptr RoundedSize = RoundUpTo(sizeof(T), GetPageSizeCached());
#if SANITIZER_FUCHSIA
zx_handle_t Vmo;
zx_status_t Status = _zx_vmo_create(RoundedSize, 0, &Vmo);
if (Status != ZX_OK) {
if (Verbosity())
Report("XRay Profiling: Failed to create VMO of size %zu: %s\n",
sizeof(T), _zx_status_get_string(Status));
return nullptr;
}
uintptr_t B;
Status =
_zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
Vmo, 0, sizeof(T), &B);
_zx_handle_close(Vmo);
if (Status != ZX_OK) {
if (Verbosity())
Report("XRay Profiling: Failed to map VMAR of size %zu: %s\n",
sizeof(T), _zx_status_get_string(Status));
return nullptr;
}
return reinterpret_cast<T *>(B);
#else
uptr B = internal_mmap(NULL, RoundedSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int ErrNo;
@ -43,6 +71,7 @@ template <class T> T *allocate() XRAY_NEVER_INSTRUMENT {
RoundedSize, B);
return nullptr;
}
#endif
return reinterpret_cast<T *>(B);
}
@ -50,12 +79,38 @@ template <class T> void deallocate(T *B) XRAY_NEVER_INSTRUMENT {
if (B == nullptr)
return;
uptr RoundedSize = RoundUpTo(sizeof(T), GetPageSizeCached());
#if SANITIZER_FUCHSIA
_zx_vmar_unmap(_zx_vmar_root_self(),
reinterpret_cast<uintptr_t>(B), RoundedSize);
#else
internal_munmap(B, RoundedSize);
#endif
}
template <class T = unsigned char>
T *allocateBuffer(size_t S) XRAY_NEVER_INSTRUMENT {
uptr RoundedSize = RoundUpTo(S * sizeof(T), GetPageSizeCached());
#if SANITIZER_FUCHSIA
zx_handle_t Vmo;
zx_status_t Status = _zx_vmo_create(RoundedSize, 0, &Vmo);
if (Status != ZX_OK) {
if (Verbosity())
Report("XRay Profiling: Failed to create VMO of size %zu: %s\n",
S, _zx_status_get_string(Status));
return nullptr;
}
uintptr_t B;
Status =
_zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
Vmo, 0, S, &B);
_zx_handle_close(Vmo);
if (Status != ZX_OK) {
if (Verbosity())
Report("XRay Profiling: Failed to map VMAR of size %zu: %s\n",
S, _zx_status_get_string(Status));
return nullptr;
}
#else
uptr B = internal_mmap(NULL, RoundedSize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int ErrNo;
@ -66,6 +121,7 @@ T *allocateBuffer(size_t S) XRAY_NEVER_INSTRUMENT {
RoundedSize, B);
return nullptr;
}
#endif
return reinterpret_cast<T *>(B);
}
@ -73,7 +129,11 @@ template <class T> void deallocateBuffer(T *B, size_t S) XRAY_NEVER_INSTRUMENT {
if (B == nullptr)
return;
uptr RoundedSize = RoundUpTo(S * sizeof(T), GetPageSizeCached());
#if SANITIZER_FUCHSIA
_zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast<uintptr_t>(B), RoundedSize);
#else
internal_munmap(B, RoundedSize);
#endif
}
template <class T, class... U>

View File

@ -19,7 +19,9 @@
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_MAC
#include <sys/syscall.h>
#endif
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

View File

@ -16,7 +16,9 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#if !SANITIZER_FUCHSIA
#include "sanitizer_common/sanitizer_posix.h"
#endif
#include "xray_allocator.h"
#include "xray_defs.h"
#include <memory>

View File

@ -20,7 +20,6 @@
#include <limits>
#include <memory>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

View File

@ -22,6 +22,13 @@
#include <string.h>
#include <sys/mman.h>
#if SANITIZER_FUCHSIA
#include <zircon/process.h>
#include <zircon/sanitizer.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#endif
#include "sanitizer_common/sanitizer_addrhashmap.h"
#include "sanitizer_common/sanitizer_common.h"
@ -92,22 +99,48 @@ class MProtectHelper {
public:
explicit MProtectHelper(void *PageAlignedAddr,
std::size_t MProtectLen) XRAY_NEVER_INSTRUMENT
std::size_t MProtectLen,
std::size_t PageSize) XRAY_NEVER_INSTRUMENT
: PageAlignedAddr(PageAlignedAddr),
MProtectLen(MProtectLen),
MustCleanup(false) {}
MustCleanup(false) {
#if SANITIZER_FUCHSIA
MProtectLen = RoundUpTo(MProtectLen, PageSize);
#endif
}
int MakeWriteable() XRAY_NEVER_INSTRUMENT {
#if SANITIZER_FUCHSIA
auto R = __sanitizer_change_code_protection(
reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, true);
if (R != ZX_OK) {
Report("XRay: cannot change code protection: %s\n",
_zx_status_get_string(R));
return -1;
}
MustCleanup = true;
return 0;
#else
auto R = mprotect(PageAlignedAddr, MProtectLen,
PROT_READ | PROT_WRITE | PROT_EXEC);
if (R != -1)
MustCleanup = true;
return R;
#endif
}
~MProtectHelper() XRAY_NEVER_INSTRUMENT {
if (MustCleanup) {
#if SANITIZER_FUCHSIA
auto R = __sanitizer_change_code_protection(
reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, false);
if (R != ZX_OK) {
Report("XRay: cannot change code protection: %s\n",
_zx_status_get_string(R));
}
#else
mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC);
#endif
}
}
};
@ -254,7 +287,7 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT {
reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1));
size_t MProtectLen =
(MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength;
MProtectHelper Protector(PageAlignedAddr, MProtectLen);
MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);
if (Protector.MakeWriteable() == -1) {
Report("Failed mprotect: %d\n", errno);
return XRayPatchingStatus::FAILED;
@ -319,7 +352,7 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId,
reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1));
size_t MProtectLen =
(MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength;
MProtectHelper Protector(PageAlignedAddr, MProtectLen);
MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);
if (Protector.MakeWriteable() == -1) {
Report("Failed mprotect: %d\n", errno);
return XRayPatchingStatus::FAILED;

View File

@ -13,10 +13,32 @@
#ifndef XRAY_EMULATE_TSC_H
#define XRAY_EMULATE_TSC_H
#include "sanitizer_common/sanitizer_common.h"
namespace __xray {
static constexpr uint64_t NanosecondsPerSecond = 1000ULL * 1000 * 1000;
}
#if SANITIZER_FUCHSIA
#include <zircon/syscalls.h>
namespace __xray {
inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
CPU = 0;
return _zx_ticks_get();
}
inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
return _zx_ticks_per_second();
}
} // namespace __xray
#else // SANITIZER_FUCHSIA
#if defined(__x86_64__)
#include "xray_x86_64.inc"
#elif defined(__powerpc64__)
@ -64,5 +86,6 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
#else
#error Target architecture is not supported.
#endif // CPU architecture
#endif // SANITIZER_FUCHSIA
#endif // XRAY_EMULATE_TSC_H

View File

@ -27,12 +27,108 @@
#include <unistd.h>
#include <utility>
#if SANITIZER_FUCHSIA
#include "sanitizer_common/sanitizer_symbolizer_fuchsia.h"
#include <inttypes.h>
#include <zircon/process.h>
#include <zircon/sanitizer.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#endif
namespace __xray {
void printToStdErr(const char *Buffer) XRAY_NEVER_INSTRUMENT {
fprintf(stderr, "%s", Buffer);
#if SANITIZER_FUCHSIA
constexpr const char* ProfileSinkName = "llvm-xray";
LogWriter::~LogWriter() {
_zx_handle_close(Vmo);
}
void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {
if (Begin == End)
return;
auto TotalBytes = std::distance(Begin, End);
const size_t PageSize = flags()->xray_page_size_override > 0
? flags()->xray_page_size_override
: GetPageSizeCached();
if (RoundUpTo(Offset, PageSize) != RoundUpTo(Offset + TotalBytes, PageSize)) {
// Resize the VMO to ensure there's sufficient space for the data.
zx_status_t Status = _zx_vmo_set_size(Vmo, Offset + TotalBytes);
if (Status != ZX_OK) {
Report("Failed to resize VMO: %s\n", _zx_status_get_string(Status));
return;
}
}
// Write the data into VMO.
zx_status_t Status = _zx_vmo_write(Vmo, Begin, Offset, TotalBytes);
if (Status != ZX_OK) {
Report("Failed to write: %s\n", _zx_status_get_string(Status));
return;
}
Offset += TotalBytes;
}
void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {
// Nothing to do here since WriteAll writes directly into the VMO.
}
LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {
// Create VMO to hold the profile data.
zx_handle_t Vmo;
zx_status_t Status = _zx_vmo_create(0, 0, &Vmo);
if (Status != ZX_OK) {
Report("XRay: cannot create VMO: %s\n", _zx_status_get_string(Status));
return nullptr;
}
// Get the KOID of the current process to use in the VMO name.
zx_info_handle_basic_t Info;
Status = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
sizeof(Info), NULL, NULL);
if (Status != ZX_OK) {
Report("XRay: cannot get basic info about current process handle: %s\n",
_zx_status_get_string(Status));
return nullptr;
}
// Give the VMO a name including our process KOID so it's easy to spot.
char VmoName[ZX_MAX_NAME_LEN];
internal_snprintf(VmoName, sizeof(VmoName), "%s.%zu", ProfileSinkName,
Info.koid);
_zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));
// Duplicate the handle since __sanitizer_publish_data consumes it and
// LogWriter needs to hold onto it.
zx_handle_t Handle;
Status =_zx_handle_duplicate(Vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);
if (Status != ZX_OK) {
Report("XRay: cannot duplicate VMO handle: %s\n",
_zx_status_get_string(Status));
return nullptr;
}
// Publish the VMO that receives the logging. Note the VMO's contents can
// grow and change after publication. The contents won't be read out until
// after the process exits.
__sanitizer_publish_data(ProfileSinkName, Handle);
// Use the dumpfile symbolizer markup element to write the name of the VMO.
Report("XRay: " FORMAT_DUMPFILE "\n", ProfileSinkName, VmoName);
LogWriter *LW = reinterpret_cast<LogWriter *>(InternalAlloc(sizeof(LogWriter)));
new (LW) LogWriter(Vmo);
return LW;
}
void LogWriter::Close(LogWriter *LW) {
LW->~LogWriter();
InternalFree(LW);
}
#else // SANITIZER_FUCHSIA
LogWriter::~LogWriter() {
internal_close(Fd);
}
@ -95,5 +191,6 @@ void LogWriter::Close(LogWriter *LW) {
LW->~LogWriter();
deallocate(LW);
}
#endif // SANITIZER_FUCHSIA
} // namespace __xray

View File

@ -20,30 +20,41 @@
#include <sys/types.h>
#include <utility>
#include "sanitizer_common/sanitizer_common.h"
#if SANITIZER_FUCHSIA
#include <zircon/types.h>
#endif
namespace __xray {
class LogWriter {
public:
#if SANITIZER_FUCHSIA
LogWriter(zx_handle_t Vmo) : Vmo(Vmo) {}
#else
explicit LogWriter(int Fd) : Fd(Fd) {}
~LogWriter();
#endif
~LogWriter();
// Write a character range into a log.
void WriteAll(const char *Begin, const char *End);
// Write a character range into a log.
void WriteAll(const char *Begin, const char *End);
void Flush();
void Flush();
// Returns a new log instance initialized using the flag-provided values.
static LogWriter *Open();
// Closes and deallocates the log instance.
static void Close(LogWriter *LogWriter);
// Returns a new log instance initialized using the flag-provided values.
static LogWriter *Open();
// Closes and deallocates the log instance.
static void Close(LogWriter *LogWriter);
private:
int Fd = -1;
#if SANITIZER_FUCHSIA
zx_handle_t Vmo = ZX_HANDLE_INVALID;
uint64_t Offset = 0;
#else
int Fd = -1;
#endif
};
// Default implementation of the reporting interface for sanitizer errors.
void printToStdErr(const char *Buffer);
constexpr size_t gcd(size_t a, size_t b) {
return (b == 0) ? a : gcd(b, a % b);
}

View File

@ -1,6 +1,8 @@
#include "cpuid.h"
#include "sanitizer_common/sanitizer_common.h"
#if !SANITIZER_FUCHSIA
#include "sanitizer_common/sanitizer_posix.h"
#endif
#include "xray_defs.h"
#include "xray_interface_internal.h"
@ -11,6 +13,8 @@
#include <machine/cpu.h>
#endif
#include <sys/sysctl.h>
#elif SANITIZER_FUCHSIA
#include <zircon/syscalls.h>
#endif
#include <atomic>
@ -104,7 +108,7 @@ uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
return 0;
}
#else
#elif !SANITIZER_FUCHSIA
uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
/* Not supported */
return 0;
@ -321,6 +325,7 @@ bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
return false;
}
#if !SANITIZER_FUCHSIA
// We determine whether the CPU we're running on has the correct features we
// need. In x86_64 this will be rdtscp support.
bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
@ -343,5 +348,6 @@ bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
}
return true;
}
#endif
} // namespace __xray