1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
base / allocator / partition_allocator / src / partition_alloc / partition_alloc_base / logging.h [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_LOGGING_H_
#define PARTITION_ALLOC_PARTITION_ALLOC_BASE_LOGGING_H_
#include <cassert>
#include <cstddef>
#include <cstdint>
#include "partition_alloc/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_base/component_export.h"
#include "partition_alloc/partition_alloc_base/log_message.h"
// TODO(crbug.com/40158212): Need to update the description, because logging for
// PA standalone library was minimized.
//
// Optional message capabilities
// -----------------------------
// Assertion failed messages and fatal errors are displayed in a dialog box
// before the application exits. However, running this UI creates a message
// loop, which causes application messages to be processed and potentially
// dispatched to existing application windows. Since the application is in a
// bad state when this assertion dialog is displayed, these messages may not
// get processed and hang the dialog, or the application might go crazy.
//
// Therefore, it can be beneficial to display the error dialog in a separate
// process from the main application. When the logging system needs to display
// a fatal error dialog box, it will look for a program called
// "DebugMessage.exe" in the same directory as the application executable. It
// will run this application with the message as the command line, and will
// not include the name of the application as is traditional for easier
// parsing.
//
// The code for DebugMessage.exe is only one line. In WinMain, do:
// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
//
// If DebugMessage.exe is not found, the logging code will use a normal
// MessageBox, potentially causing the problems discussed above.
// Instructions
// ------------
//
// Make a bunch of macros for logging. The way to log things is to stream
// things to PA_LOG(<a particular severity level>). E.g.,
//
// PA_LOG(INFO) << "Found " << num_cookies << " cookies";
//
// You can also do conditional logging:
//
// PA_LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
// The CHECK(condition) macro is active in both debug and release builds and
// effectively performs a PA_LOG(FATAL) which terminates the process and
// generates a crashdump unless a debugger is attached.
//
// There are also "debug mode" logging macros like the ones above:
//
// PA_DLOG(INFO) << "Found cookies";
//
// PA_DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
// All "debug mode" logging is compiled away to nothing for non-debug mode
// compiles. PA_LOG_IF and development flags also work well together
// because the code can be compiled away sometimes.
//
// We also have
//
// PA_LOG_ASSERT(assertion);
// PA_DLOG_ASSERT(assertion);
//
// which is syntactic sugar for PA_{,D}LOG_IF(FATAL, assert fails) << assertion;
//
// There are "verbose level" logging macros. They look like
//
// PA_VLOG(1) << "I'm printed when you run the program with --v=1 or more";
// PA_VLOG(2) << "I'm printed when you run the program with --v=2 or more";
//
// These always log at the INFO log level (when they log at all).
//
// There's also PA_VLOG_IS_ON(n) "verbose level" condition macro. To be used as
//
// if (PA_VLOG_IS_ON(2)) {
// // do some logging preparation and logging
// // that can't be accomplished with just PA_VLOG(2) << ...;
// }
//
// There is also a PA_VLOG_IF "verbose level" condition macro for sample
// cases, when some extra computation and preparation for logs is not
// needed.
//
// PA_VLOG_IF(1, (size > 1024))
// << "I'm printed when size is more than 1024 and when you run the "
// "program with --v=1 or more";
//
// We also override the standard 'assert' to use 'PA_DLOG_ASSERT'.
//
// Lastly, there is:
//
// PA_PLOG(ERROR) << "Couldn't do foo";
// PA_DPLOG(ERROR) << "Couldn't do foo";
// PA_PLOG_IF(ERROR, cond) << "Couldn't do foo";
// PA_DPLOG_IF(ERROR, cond) << "Couldn't do foo";
// PA_PCHECK(condition) << "Couldn't do foo";
// PA_DPCHECK(condition) << "Couldn't do foo";
//
// which append the last system error to the message in string form (taken from
// GetLastError() on Windows and errno on POSIX).
//
// The supported severity levels for macros that allow you to specify one
// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
//
// Very important: logging a message at the FATAL severity level causes
// the program to terminate (after the message is logged).
//
// There is the special severity of DFATAL, which logs FATAL in DCHECK-enabled
// builds, ERROR in normal mode.
//
// Output is formatted as per the following example:
// [VERBOSE1:drm_device_handle.cc(90)] Succeeded
// authenticating /dev/dri/card0 in 0 ms with 1 attempt(s)
//
// The colon separated fields inside the brackets are as follows:
// 1. The log level
// 2. The filename and line number where the log was instantiated
//
// Additional logging-related information can be found here:
// https://chromium.googlesource.com/chromium/src/+/main/docs/linux/debugging.md#Logging
namespace partition_alloc::internal::logging {
// Sets the log level. Anything at or above this level will be written to the
// log file/displayed to the user (if applicable). Anything below this level
// will be silently ignored. The log level defaults to 0 (everything is logged
// up to level INFO) if this function is not called.
// Note that log messages for VLOG(x) are logged at level -x, so setting
// the min log level to negative values enables verbose logging.
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) void SetMinLogLevel(int level);
// Gets the current log level.
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) int GetMinLogLevel();
// Used by PA_LOG_IS_ON to lazy-evaluate stream arguments.
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE)
bool ShouldCreateLogMessage(int severity);
// Gets the PA_VLOG default verbosity level.
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) int GetVlogVerbosity();
// A few definitions of macros that don't generate much code. These are used
// by PA_LOG() and LOG_IF, etc. Since these are used all over our code, it's
// better to have compact code for these operations.
#define PA_COMPACT_GOOGLE_LOG_EX_INFO(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_INFO)
#define PA_COMPACT_GOOGLE_PLOG_EX_INFO(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_INFO, \
error_code)
#define PA_COMPACT_GOOGLE_LOG_EX_WARNING(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_WARNING)
#define PA_COMPACT_GOOGLE_PLOG_EX_WARNING(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_WARNING)
#define PA_COMPACT_GOOGLE_LOG_EX_ERROR(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_ERROR)
#define PA_COMPACT_GOOGLE_PLOG_EX_ERROR(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_ERROR, \
error_code)
#define PA_COMPACT_GOOGLE_LOG_EX_FATAL(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_FATAL)
#define PA_COMPACT_GOOGLE_PLOG_EX_FATAL(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, ::partition_alloc::internal::logging::LOGGING_FATAL, \
error_code)
#define PA_COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_DFATAL)
#define PA_COMPACT_GOOGLE_PLOG_EX_DFATAL(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_DFATAL, error_code)
#define PA_COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_DCHECK)
#define PA_COMPACT_GOOGLE_PLOG_EX_DCHECK(ClassName, error_code) \
::partition_alloc::internal::logging::ClassName( \
__FILE__, __LINE__, \
::partition_alloc::internal::logging::LOGGING_DCHECK, error_code)
#define PA_COMPACT_GOOGLE_LOG_INFO PA_COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
#define PA_COMPACT_GOOGLE_LOG_WARNING \
PA_COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
#define PA_COMPACT_GOOGLE_LOG_ERROR PA_COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
#define PA_COMPACT_GOOGLE_LOG_FATAL PA_COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
#define PA_COMPACT_GOOGLE_LOG_DFATAL PA_COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
#define PA_COMPACT_GOOGLE_LOG_DCHECK PA_COMPACT_GOOGLE_LOG_EX_DCHECK(LogMessage)
#if PA_BUILDFLAG(IS_WIN)
// wingdi.h defines ERROR to be 0. When we call PA_LOG(ERROR), it gets
// substituted with 0, and it expands to PA_COMPACT_GOOGLE_LOG_0. To allow us
// to keep using this syntax, we define this macro to do the same thing
// as PA_COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
// the Windows SDK does for consistency.
#define PA_ERROR 0
#define PA_COMPACT_GOOGLE_LOG_EX_0(ClassName) \
PA_COMPACT_GOOGLE_LOG_EX_ERROR(ClassName)
#define PA_COMPACT_GOOGLE_LOG_0 PA_COMPACT_GOOGLE_LOG_ERROR
// Needed for LOG_IS_ON(ERROR).
constexpr LogSeverity LOGGING_0 = LOGGING_ERROR;
#endif
// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
// always fire if they fail.
#define PA_LOG_IS_ON(severity) \
(::partition_alloc::internal::logging::ShouldCreateLogMessage( \
::partition_alloc::internal::logging::LOGGING_##severity))
// We don't do any caching tricks with VLOG_IS_ON() like the
// google-glog version since it increases binary size. This means
// that using the v-logging functions in conjunction with --vmodule
// may be slow.
#define PA_VLOG_IS_ON(verboselevel) \
((verboselevel) <= ::partition_alloc::internal::logging::GetVlogVerbosity())
// Helper macro which avoids evaluating the arguments to a stream if
// the condition doesn't hold. Condition is evaluated once and only once.
#define PA_LAZY_STREAM(stream, condition) \
!(condition) \
? (void)0 \
: ::partition_alloc::internal::logging::LogMessageVoidify() & (stream)
// We use the preprocessor's merging operator, "##", so that, e.g.,
// PA_LOG(INFO) becomes the token PA_COMPACT_GOOGLE_LOG_INFO. There's some
// funny subtle difference between ostream member streaming functions (e.g.,
// ostream::operator<<(int) and ostream non-member streaming functions
// (e.g., ::operator<<(ostream&, string&): it turns out that it's
// impossible to stream something like a string directly to an unnamed
// ostream. We employ a neat hack by calling the stream() member
// function of LogMessage which seems to avoid the problem.
#define PA_LOG_STREAM(severity) PA_COMPACT_GOOGLE_LOG_##severity.stream()
#define PA_LOG(severity) \
PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_LOG_IS_ON(severity))
#define PA_LOG_IF(severity, condition) \
PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_LOG_IS_ON(severity) && (condition))
// The VLOG macros log with negative verbosities.
#define PA_VLOG_STREAM(verbose_level) \
::partition_alloc::internal::logging::LogMessage(__FILE__, __LINE__, \
-(verbose_level)) \
.stream()
#define PA_VLOG(verbose_level) \
PA_LAZY_STREAM(PA_VLOG_STREAM(verbose_level), PA_VLOG_IS_ON(verbose_level))
#define PA_VLOG_IF(verbose_level, condition) \
PA_LAZY_STREAM(PA_VLOG_STREAM(verbose_level), \
PA_VLOG_IS_ON(verbose_level) && (condition))
#if PA_BUILDFLAG(IS_WIN)
#define PA_VPLOG_STREAM(verbose_level) \
::partition_alloc::internal::logging::Win32ErrorLogMessage( \
__FILE__, __LINE__, -(verbose_level), \
::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
.stream()
#elif PA_BUILDFLAG(IS_POSIX) || PA_BUILDFLAG(IS_FUCHSIA)
#define PA_VPLOG_STREAM(verbose_level) \
::partition_alloc::internal::logging::ErrnoLogMessage( \
__FILE__, __LINE__, -(verbose_level), \
::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
.stream()
#endif
#define PA_VPLOG(verbose_level) \
PA_LAZY_STREAM(PA_VPLOG_STREAM(verbose_level), PA_VLOG_IS_ON(verbose_level))
#define PA_VPLOG_IF(verbose_level, condition) \
PA_LAZY_STREAM(PA_VPLOG_STREAM(verbose_level), \
PA_VLOG_IS_ON(verbose_level) && (condition))
// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
#define PA_LOG_ASSERT(condition) \
PA_LOG_IF(FATAL, !(PA_ANALYZER_ASSUME_TRUE(condition))) \
<< "Assert failed: " #condition ". "
#if PA_BUILDFLAG(IS_WIN)
#define PA_PLOG_STREAM(severity) \
PA_COMPACT_GOOGLE_PLOG_EX_##severity( \
Win32ErrorLogMessage, \
::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
.stream()
#elif PA_BUILDFLAG(IS_POSIX) || PA_BUILDFLAG(IS_FUCHSIA)
#define PA_PLOG_STREAM(severity) \
PA_COMPACT_GOOGLE_PLOG_EX_##severity( \
ErrnoLogMessage, \
::partition_alloc::internal::logging::GetLastSystemErrorCode()) \
.stream()
#endif
#define PA_PLOG(severity) \
PA_LAZY_STREAM(PA_PLOG_STREAM(severity), PA_LOG_IS_ON(severity))
#define PA_PLOG_IF(severity, condition) \
PA_LAZY_STREAM(PA_PLOG_STREAM(severity), \
PA_LOG_IS_ON(severity) && (condition))
// Note that g_swallow_stream is used instead of an arbitrary PA_LOG() stream to
// avoid the creation of an object with a non-trivial destructor (LogMessage).
// On MSVC x86 (checked on 2015 Update 3), this causes a few additional
// pointless instructions to be emitted even at full optimization level, even
// though the : arm of the ternary operator is clearly never executed. Using a
// simpler object to be &'d with Voidify() avoids these extra instructions.
// Using a simpler POD object with a templated operator<< also works to avoid
// these instructions. However, this causes warnings on statically defined
// implementations of operator<<(std::ostream, ...) in some .cc files, because
// they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an
// ostream* also is not suitable, because some compilers warn of undefined
// behavior.
#define PA_EAT_STREAM_PARAMETERS \
true ? (void)0 \
: ::partition_alloc::internal::logging::LogMessageVoidify() & \
(*::partition_alloc::internal::logging::g_swallow_stream)
// Definitions for DLOG et al.
#if PA_BUILDFLAG(DCHECKS_ARE_ON)
#define PA_DLOG_IS_ON(severity) PA_LOG_IS_ON(severity)
#define PA_DLOG_IF(severity, condition) PA_LOG_IF(severity, condition)
#define PA_DLOG_ASSERT(condition) PA_LOG_ASSERT(condition)
#define PA_DPLOG_IF(severity, condition) PA_PLOG_IF(severity, condition)
#define PA_DVLOG_IF(verboselevel, condition) PA_VLOG_IF(verboselevel, condition)
#define PA_DVPLOG_IF(verboselevel, condition) \
PA_VPLOG_IF(verboselevel, condition)
#else // PA_BUILDFLAG(DCHECKS_ARE_ON)
// If !PA_BUILDFLAG(DCHECKS_ARE_ON), we want to avoid emitting any references
// to |condition| (which may reference a variable defined only if
// PA_BUILDFLAG(DCHECKS_ARE_ON)). Contrast this with DCHECK et al., which has
// different behavior.
#define PA_DLOG_IS_ON(severity) false
#define PA_DLOG_IF(severity, condition) PA_EAT_STREAM_PARAMETERS
#define PA_DLOG_ASSERT(condition) PA_EAT_STREAM_PARAMETERS
#define PA_DPLOG_IF(severity, condition) PA_EAT_STREAM_PARAMETERS
#define PA_DVLOG_IF(verboselevel, condition) PA_EAT_STREAM_PARAMETERS
#define PA_DVPLOG_IF(verboselevel, condition) PA_EAT_STREAM_PARAMETERS
#endif // PA_BUILDFLAG(DCHECKS_ARE_ON)
#define PA_DLOG(severity) \
PA_LAZY_STREAM(PA_LOG_STREAM(severity), PA_DLOG_IS_ON(severity))
#define PA_DPLOG(severity) \
PA_LAZY_STREAM(PA_PLOG_STREAM(severity), PA_DLOG_IS_ON(severity))
#define PA_DVLOG(verboselevel) PA_DVLOG_IF(verboselevel, true)
#define PA_DVPLOG(verboselevel) PA_DVPLOG_IF(verboselevel, true)
// Definitions for DCHECK et al.
#if PA_BUILDFLAG(DCHECK_IS_CONFIGURABLE)
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) extern LogSeverity LOGGING_DCHECK;
#else
constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL;
#endif // PA_BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// Redefine the standard assert to use our nice log files
#undef assert
#define assert(x) PA_DLOG_ASSERT(x)
// Async signal safe logging mechanism.
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE)
void RawLog(int level, const char* message);
#define PA_RAW_LOG(level, message) \
::partition_alloc::internal::logging::RawLog( \
::partition_alloc::internal::logging::LOGGING_##level, message)
} // namespace partition_alloc::internal::logging
#endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_LOGGING_H_