dyld-832.7.1.tar.gz
[apple/dyld.git] / dyld3 / Diagnostics.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <iostream>
25
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <uuid/uuid.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <_simple.h>
34 #include <unistd.h>
35 #include <sys/uio.h>
36 #include <sys/param.h>
37 #include <sys/sysctl.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #include <dirent.h>
43 #include <mach/mach.h>
44 #include <mach/machine.h>
45 #include <mach/mach_time.h>
46 #include <mach-o/loader.h>
47 #include <mach-o/nlist.h>
48 #include <mach-o/fat.h>
49 #include <pthread.h>
50 #include <libc_private.h>
51
52 #include "Diagnostics.h"
53
54 #if BUILDING_CACHE_BUILDER
55 #include <dispatch/dispatch.h>
56 dispatch_queue_t sWarningQueue = dispatch_queue_create("com.apple.dyld.cache-builder.warnings", NULL);
57 #endif
58
59 Diagnostics::Diagnostics(bool verbose)
60 #if BUILDING_CACHE_BUILDER
61 : _verbose(verbose)
62 , _prefix("")
63 #endif
64 {
65 }
66
67 #if BUILDING_CACHE_BUILDER
68 Diagnostics::Diagnostics(const std::string& prefix, bool verbose)
69 : _verbose(verbose)
70 , _prefix(prefix)
71 {
72 }
73 #endif
74
75 Diagnostics::~Diagnostics()
76 {
77 clearError();
78 }
79
80 void Diagnostics::error(const char* format, ...)
81 {
82 va_list list;
83 va_start(list, format);
84 error(format, list);
85 va_end(list);
86 }
87
88 void Diagnostics::error(const char* format, va_list list)
89 {
90 //FIXME: this should be assertNoError(), but we currently overwrite some errors
91 //assertNoError();
92 _buffer = _simple_salloc();
93 _simple_vsprintf(_buffer, format, list);
94
95 #if BUILDING_CACHE_BUILDER
96 if ( !_verbose )
97 return;
98
99 if (_prefix.empty()) {
100 fprintf(stderr, "%s\n", _simple_string(_buffer));
101 } else {
102 fprintf(stderr, "[%s] %s\n", _prefix.c_str(), _simple_string(_buffer));
103 }
104 #endif
105 }
106
107 bool Diagnostics::hasError() const
108 {
109 return _buffer != nullptr;
110 }
111
112 bool Diagnostics::noError() const
113 {
114 return _buffer == nullptr;
115 }
116
117 void Diagnostics::clearError()
118 {
119 if ( _buffer )
120 _simple_sfree(_buffer);
121 _buffer = nullptr;
122 }
123
124 void Diagnostics::assertNoError() const
125 {
126 if ( _buffer != nullptr )
127 abort_report_np("%s", _simple_string(_buffer));
128 }
129
130 bool Diagnostics::errorMessageContains(const char* subString) const
131 {
132 if ( _buffer == nullptr )
133 return false;
134 return (strstr(_simple_string(_buffer), subString) != nullptr);
135 }
136
137
138 #if !BUILDING_CACHE_BUILDER
139 const char* Diagnostics::errorMessage() const
140 {
141 return _simple_string(_buffer);
142 }
143
144 #else
145 void Diagnostics::warning(const char* format, ...)
146 {
147 _SIMPLE_STRING tmp = _simple_salloc();
148 va_list list;
149 va_start(list, format);
150 _simple_vsprintf(tmp, format, list);
151 va_end(list);
152 #if BUILDING_CACHE_BUILDER
153 dispatch_sync(sWarningQueue, ^{
154 _warnings.insert(_simple_string(tmp));
155 });
156 #else
157 _warnings.insert(_simple_string(tmp));
158 #endif
159 _simple_sfree(tmp);
160 }
161
162 void Diagnostics::verbose(const char* format, ...)
163 {
164 if ( !_verbose )
165 return;
166
167 char* output_string;
168 va_list list;
169 va_start(list, format);
170 vasprintf(&output_string, format, list);
171 va_end(list);
172
173 if (_prefix.empty()) {
174 fprintf(stderr, "%s", output_string);
175 } else {
176 fprintf(stderr, "[%s] %s", _prefix.c_str(), output_string);
177 }
178 free(output_string);
179 }
180
181 const std::string Diagnostics::prefix() const
182 {
183 return _prefix;
184 }
185
186 void Diagnostics::copy(const Diagnostics& other)
187 {
188 if ( other.hasError() )
189 error("%s", other.errorMessage().c_str());
190 for (const std::string& warn : other.warnings())
191 warning("%s", warn.c_str());
192 }
193
194 std::string Diagnostics::errorMessage() const
195 {
196 if ( _buffer != nullptr )
197 return _simple_string(_buffer);
198 else
199 return "";
200 }
201
202 const std::set<std::string> Diagnostics::warnings() const
203 {
204 #if BUILDING_CACHE_BUILDER
205 __block std::set<std::string> retval;
206 dispatch_sync(sWarningQueue, ^{
207 retval = _warnings;
208 });
209 return retval;
210 #else
211 return _warnings;
212 #endif
213 }
214
215 void Diagnostics::clearWarnings()
216 {
217 #if BUILDING_CACHE_BUILDER
218 dispatch_sync(sWarningQueue, ^{
219 _warnings.clear();
220 });
221 #else
222 _warnings.clear();
223 #endif
224 }
225
226 #if BUILDING_CACHE_BUILDER
227 void TimeRecorder::pushTimedSection() {
228 openTimings.push_back(mach_absolute_time());
229 }
230
231 void TimeRecorder::recordTime(const char* format, ...) {
232 uint64_t t = mach_absolute_time();
233 uint64_t previousTime = openTimings.back();
234 openTimings.pop_back();
235
236 char* output_string = nullptr;
237 va_list list;
238 va_start(list, format);
239 vasprintf(&output_string, format, list);
240 va_end(list);
241
242 if (output_string != nullptr) {
243 timings.push_back(TimingEntry {
244 .time = t - previousTime,
245 .logMessage = std::string(output_string),
246 .depth = (int)openTimings.size()
247 });
248 }
249
250 openTimings.push_back(mach_absolute_time());
251 }
252
253 void TimeRecorder::popTimedSection() {
254 openTimings.pop_back();
255 }
256
257 static inline uint32_t absolutetime_to_milliseconds(uint64_t abstime)
258 {
259 return (uint32_t)(abstime/1000/1000);
260 }
261
262 void TimeRecorder::logTimings() {
263 for (const TimingEntry& entry : timings) {
264 for (int i = 0 ; i < entry.depth ; i++) {
265 std::cerr << " ";
266 }
267 std::cerr << "time to " << entry.logMessage << " " << absolutetime_to_milliseconds(entry.time) << "ms" << std::endl;
268 }
269
270 timings.clear();
271 }
272 #endif
273
274 #endif
275