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