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