Home | History | Annotate | Line # | Download | only in xray
      1  1.1  kamil //===-- xray_utils.cc -------------------------------------------*- C++ -*-===//
      2  1.1  kamil //
      3  1.1  kamil //                     The LLVM Compiler Infrastructure
      4  1.1  kamil //
      5  1.1  kamil // This file is distributed under the University of Illinois Open Source
      6  1.1  kamil // License. See LICENSE.TXT for details.
      7  1.1  kamil //
      8  1.1  kamil //===----------------------------------------------------------------------===//
      9  1.1  kamil //
     10  1.1  kamil // This file is a part of XRay, a dynamic runtime instrumentation system.
     11  1.1  kamil //
     12  1.1  kamil //===----------------------------------------------------------------------===//
     13  1.1  kamil #include "xray_utils.h"
     14  1.1  kamil 
     15  1.1  kamil #include "sanitizer_common/sanitizer_allocator_internal.h"
     16  1.1  kamil #include "sanitizer_common/sanitizer_common.h"
     17  1.1  kamil #include "xray_allocator.h"
     18  1.1  kamil #include "xray_defs.h"
     19  1.1  kamil #include "xray_flags.h"
     20  1.1  kamil #include <cstdio>
     21  1.1  kamil #include <errno.h>
     22  1.1  kamil #include <fcntl.h>
     23  1.1  kamil #include <iterator>
     24  1.1  kamil #include <stdlib.h>
     25  1.1  kamil #include <sys/types.h>
     26  1.1  kamil #include <tuple>
     27  1.1  kamil #include <unistd.h>
     28  1.1  kamil #include <utility>
     29  1.1  kamil 
     30  1.1  kamil #if SANITIZER_FUCHSIA
     31  1.1  kamil #include "sanitizer_common/sanitizer_symbolizer_fuchsia.h"
     32  1.1  kamil 
     33  1.1  kamil #include <inttypes.h>
     34  1.1  kamil #include <zircon/process.h>
     35  1.1  kamil #include <zircon/sanitizer.h>
     36  1.1  kamil #include <zircon/status.h>
     37  1.1  kamil #include <zircon/syscalls.h>
     38  1.1  kamil #endif
     39  1.1  kamil 
     40  1.1  kamil namespace __xray {
     41  1.1  kamil 
     42  1.1  kamil #if SANITIZER_FUCHSIA
     43  1.1  kamil constexpr const char* ProfileSinkName = "llvm-xray";
     44  1.1  kamil 
     45  1.1  kamil LogWriter::~LogWriter() {
     46  1.1  kamil   _zx_handle_close(Vmo);
     47  1.1  kamil }
     48  1.1  kamil 
     49  1.1  kamil void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {
     50  1.1  kamil   if (Begin == End)
     51  1.1  kamil     return;
     52  1.1  kamil   auto TotalBytes = std::distance(Begin, End);
     53  1.1  kamil 
     54  1.1  kamil   const size_t PageSize = flags()->xray_page_size_override > 0
     55  1.1  kamil                               ? flags()->xray_page_size_override
     56  1.1  kamil                               : GetPageSizeCached();
     57  1.1  kamil   if (RoundUpTo(Offset, PageSize) != RoundUpTo(Offset + TotalBytes, PageSize)) {
     58  1.1  kamil     // Resize the VMO to ensure there's sufficient space for the data.
     59  1.1  kamil     zx_status_t Status = _zx_vmo_set_size(Vmo, Offset + TotalBytes);
     60  1.1  kamil     if (Status != ZX_OK) {
     61  1.1  kamil       Report("Failed to resize VMO: %s\n", _zx_status_get_string(Status));
     62  1.1  kamil       return;
     63  1.1  kamil     }
     64  1.1  kamil   }
     65  1.1  kamil 
     66  1.1  kamil   // Write the data into VMO.
     67  1.1  kamil   zx_status_t Status = _zx_vmo_write(Vmo, Begin, Offset, TotalBytes);
     68  1.1  kamil   if (Status != ZX_OK) {
     69  1.1  kamil     Report("Failed to write: %s\n", _zx_status_get_string(Status));
     70  1.1  kamil     return;
     71  1.1  kamil   }
     72  1.1  kamil   Offset += TotalBytes;
     73  1.1  kamil }
     74  1.1  kamil 
     75  1.1  kamil void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {
     76  1.1  kamil   // Nothing to do here since WriteAll writes directly into the VMO.
     77  1.1  kamil }
     78  1.1  kamil 
     79  1.1  kamil LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {
     80  1.1  kamil   // Create VMO to hold the profile data.
     81  1.1  kamil   zx_handle_t Vmo;
     82  1.1  kamil   zx_status_t Status = _zx_vmo_create(0, 0, &Vmo);
     83  1.1  kamil   if (Status != ZX_OK) {
     84  1.1  kamil     Report("XRay: cannot create VMO: %s\n", _zx_status_get_string(Status));
     85  1.1  kamil     return nullptr;
     86  1.1  kamil   }
     87  1.1  kamil 
     88  1.1  kamil   // Get the KOID of the current process to use in the VMO name.
     89  1.1  kamil   zx_info_handle_basic_t Info;
     90  1.1  kamil   Status = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
     91  1.1  kamil                                sizeof(Info), NULL, NULL);
     92  1.1  kamil   if (Status != ZX_OK) {
     93  1.1  kamil     Report("XRay: cannot get basic info about current process handle: %s\n",
     94  1.1  kamil            _zx_status_get_string(Status));
     95  1.1  kamil     return nullptr;
     96  1.1  kamil   }
     97  1.1  kamil 
     98  1.1  kamil   // Give the VMO a name including our process KOID so it's easy to spot.
     99  1.1  kamil   char VmoName[ZX_MAX_NAME_LEN];
    100  1.1  kamil   internal_snprintf(VmoName, sizeof(VmoName), "%s.%zu", ProfileSinkName,
    101  1.1  kamil                     Info.koid);
    102  1.1  kamil   _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));
    103  1.1  kamil 
    104  1.1  kamil   // Duplicate the handle since __sanitizer_publish_data consumes it and
    105  1.1  kamil   // LogWriter needs to hold onto it.
    106  1.1  kamil   zx_handle_t Handle;
    107  1.1  kamil   Status =_zx_handle_duplicate(Vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);
    108  1.1  kamil   if (Status != ZX_OK) {
    109  1.1  kamil     Report("XRay: cannot duplicate VMO handle: %s\n",
    110  1.1  kamil            _zx_status_get_string(Status));
    111  1.1  kamil     return nullptr;
    112  1.1  kamil   }
    113  1.1  kamil 
    114  1.1  kamil   // Publish the VMO that receives the logging. Note the VMO's contents can
    115  1.1  kamil   // grow and change after publication. The contents won't be read out until
    116  1.1  kamil   // after the process exits.
    117  1.1  kamil   __sanitizer_publish_data(ProfileSinkName, Handle);
    118  1.1  kamil 
    119  1.1  kamil   // Use the dumpfile symbolizer markup element to write the name of the VMO.
    120  1.1  kamil   Report("XRay: " FORMAT_DUMPFILE "\n", ProfileSinkName, VmoName);
    121  1.1  kamil 
    122  1.1  kamil   LogWriter *LW = reinterpret_cast<LogWriter *>(InternalAlloc(sizeof(LogWriter)));
    123  1.1  kamil   new (LW) LogWriter(Vmo);
    124  1.1  kamil   return LW;
    125  1.1  kamil }
    126  1.1  kamil 
    127  1.1  kamil void LogWriter::Close(LogWriter *LW) {
    128  1.1  kamil   LW->~LogWriter();
    129  1.1  kamil   InternalFree(LW);
    130  1.1  kamil }
    131  1.1  kamil #else // SANITIZER_FUCHSIA
    132  1.1  kamil LogWriter::~LogWriter() {
    133  1.1  kamil   internal_close(Fd);
    134  1.1  kamil }
    135  1.1  kamil 
    136  1.1  kamil void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {
    137  1.1  kamil   if (Begin == End)
    138  1.1  kamil     return;
    139  1.1  kamil   auto TotalBytes = std::distance(Begin, End);
    140  1.1  kamil   while (auto Written = write(Fd, Begin, TotalBytes)) {
    141  1.1  kamil     if (Written < 0) {
    142  1.1  kamil       if (errno == EINTR)
    143  1.1  kamil         continue; // Try again.
    144  1.1  kamil       Report("Failed to write; errno = %d\n", errno);
    145  1.1  kamil       return;
    146  1.1  kamil     }
    147  1.1  kamil     TotalBytes -= Written;
    148  1.1  kamil     if (TotalBytes == 0)
    149  1.1  kamil       break;
    150  1.1  kamil     Begin += Written;
    151  1.1  kamil   }
    152  1.1  kamil }
    153  1.1  kamil 
    154  1.1  kamil void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {
    155  1.1  kamil   fsync(Fd);
    156  1.1  kamil }
    157  1.1  kamil 
    158  1.1  kamil LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {
    159  1.1  kamil   // Open a temporary file once for the log.
    160  1.1  kamil   char TmpFilename[256] = {};
    161  1.1  kamil   char TmpWildcardPattern[] = "XXXXXX";
    162  1.1  kamil   auto **Argv = GetArgv();
    163  1.1  kamil   const char *Progname = !Argv ? "(unknown)" : Argv[0];
    164  1.1  kamil   const char *LastSlash = internal_strrchr(Progname, '/');
    165  1.1  kamil 
    166  1.1  kamil   if (LastSlash != nullptr)
    167  1.1  kamil     Progname = LastSlash + 1;
    168  1.1  kamil 
    169  1.1  kamil   int NeededLength = internal_snprintf(
    170  1.1  kamil       TmpFilename, sizeof(TmpFilename), "%s%s.%s",
    171  1.1  kamil       flags()->xray_logfile_base, Progname, TmpWildcardPattern);
    172  1.1  kamil   if (NeededLength > int(sizeof(TmpFilename))) {
    173  1.1  kamil     Report("XRay log file name too long (%d): %s\n", NeededLength, TmpFilename);
    174  1.1  kamil     return nullptr;
    175  1.1  kamil   }
    176  1.1  kamil   int Fd = mkstemp(TmpFilename);
    177  1.1  kamil   if (Fd == -1) {
    178  1.1  kamil     Report("XRay: Failed opening temporary file '%s'; not logging events.\n",
    179  1.1  kamil            TmpFilename);
    180  1.1  kamil     return nullptr;
    181  1.1  kamil   }
    182  1.1  kamil   if (Verbosity())
    183  1.1  kamil     Report("XRay: Log file in '%s'\n", TmpFilename);
    184  1.1  kamil 
    185  1.1  kamil   LogWriter *LW = allocate<LogWriter>();
    186  1.1  kamil   new (LW) LogWriter(Fd);
    187  1.1  kamil   return LW;
    188  1.1  kamil }
    189  1.1  kamil 
    190  1.1  kamil void LogWriter::Close(LogWriter *LW) {
    191  1.1  kamil   LW->~LogWriter();
    192  1.1  kamil   deallocate(LW);
    193  1.1  kamil }
    194  1.1  kamil #endif // SANITIZER_FUCHSIA
    195  1.1  kamil 
    196  1.1  kamil } // namespace __xray
    197