Line data Source code
1 : // Copyright 2009 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/log-utils.h"
6 :
7 : #include "src/assert-scope.h"
8 : #include "src/base/platform/platform.h"
9 : #include "src/objects-inl.h"
10 : #include "src/string-stream.h"
11 : #include "src/utils.h"
12 : #include "src/version.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 :
18 : const char* const Log::kLogToTemporaryFile = "&";
19 : const char* const Log::kLogToConsole = "-";
20 :
21 54999 : Log::Log(Logger* logger)
22 : : is_stopped_(false),
23 : output_handle_(nullptr),
24 : message_buffer_(nullptr),
25 54999 : logger_(logger) {}
26 :
27 54998 : void Log::Initialize(const char* log_file_name) {
28 54998 : message_buffer_ = NewArray<char>(kMessageBufferSize);
29 :
30 : // --log-all enables all the log flags.
31 54999 : if (FLAG_log_all) {
32 0 : FLAG_log_api = true;
33 0 : FLAG_log_code = true;
34 0 : FLAG_log_gc = true;
35 0 : FLAG_log_suspect = true;
36 0 : FLAG_log_handles = true;
37 0 : FLAG_log_internal_timer_events = true;
38 : }
39 :
40 : // --prof implies --log-code.
41 54999 : if (FLAG_prof) FLAG_log_code = true;
42 :
43 : // If we're logging anything, we need to open the log file.
44 54999 : if (Log::InitLogAtStart()) {
45 21 : if (strcmp(log_file_name, kLogToConsole) == 0) {
46 : OpenStdout();
47 21 : } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) {
48 : OpenTemporaryFile();
49 : } else {
50 : OpenFile(log_file_name);
51 : }
52 :
53 21 : if (output_handle_ != nullptr) {
54 : Log::MessageBuilder msg(this);
55 21 : if (strlen(Version::GetEmbedder()) == 0) {
56 : msg.Append("v8-version,%d,%d,%d,%d,%d", Version::GetMajor(),
57 : Version::GetMinor(), Version::GetBuild(),
58 42 : Version::GetPatch(), Version::IsCandidate());
59 : } else {
60 : msg.Append("v8-version,%d,%d,%d,%d,%s,%d", Version::GetMajor(),
61 : Version::GetMinor(), Version::GetBuild(),
62 : Version::GetPatch(), Version::GetEmbedder(),
63 0 : Version::IsCandidate());
64 : }
65 21 : msg.WriteToLogFile();
66 : }
67 : }
68 54998 : }
69 :
70 :
71 0 : void Log::OpenStdout() {
72 : DCHECK(!IsEnabled());
73 0 : output_handle_ = stdout;
74 0 : }
75 :
76 :
77 0 : void Log::OpenTemporaryFile() {
78 : DCHECK(!IsEnabled());
79 21 : output_handle_ = base::OS::OpenTemporaryFile();
80 0 : }
81 :
82 :
83 0 : void Log::OpenFile(const char* name) {
84 : DCHECK(!IsEnabled());
85 0 : output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode);
86 0 : }
87 :
88 53365 : FILE* Log::Close() {
89 : FILE* result = nullptr;
90 53365 : if (output_handle_ != nullptr) {
91 21 : if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
92 0 : fclose(output_handle_);
93 : } else {
94 : result = output_handle_;
95 : }
96 : }
97 53365 : output_handle_ = nullptr;
98 :
99 53365 : DeleteArray(message_buffer_);
100 53365 : message_buffer_ = nullptr;
101 :
102 53365 : is_stopped_ = false;
103 53365 : return result;
104 : }
105 :
106 :
107 37997 : Log::MessageBuilder::MessageBuilder(Log* log)
108 : : log_(log),
109 : lock_guard_(&log_->mutex_),
110 76036 : pos_(0) {
111 : DCHECK_NOT_NULL(log_->message_buffer_);
112 37997 : }
113 :
114 :
115 200852 : void Log::MessageBuilder::Append(const char* format, ...) {
116 : Vector<char> buf(log_->message_buffer_ + pos_,
117 : Log::kMessageBufferSize - pos_);
118 : va_list args;
119 200852 : va_start(args, format);
120 200852 : AppendVA(format, args);
121 200852 : va_end(args);
122 : DCHECK_LE(pos_, Log::kMessageBufferSize);
123 200852 : }
124 :
125 :
126 200852 : void Log::MessageBuilder::AppendVA(const char* format, va_list args) {
127 : Vector<char> buf(log_->message_buffer_ + pos_,
128 200852 : Log::kMessageBufferSize - pos_);
129 200852 : int result = v8::internal::VSNPrintF(buf, format, args);
130 :
131 : // Result is -1 if output was truncated.
132 200852 : if (result >= 0) {
133 200852 : pos_ += result;
134 : } else {
135 0 : pos_ = Log::kMessageBufferSize;
136 : }
137 : DCHECK_LE(pos_, Log::kMessageBufferSize);
138 200852 : }
139 :
140 :
141 16451 : void Log::MessageBuilder::Append(const char c) {
142 461435 : if (pos_ < Log::kMessageBufferSize) {
143 461435 : log_->message_buffer_[pos_++] = c;
144 : }
145 : DCHECK_LE(pos_, Log::kMessageBufferSize);
146 16451 : }
147 :
148 :
149 20247 : void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) {
150 : Append('"');
151 424737 : for (const char* p = string; *p != '\0'; p++) {
152 404490 : if (*p == '"') {
153 : Append('\\');
154 : }
155 404490 : Append(*p);
156 : }
157 : Append('"');
158 20247 : }
159 :
160 :
161 0 : void Log::MessageBuilder::Append(String* str) {
162 : DisallowHeapAllocation no_gc; // Ensure string stay valid.
163 : int length = str->length();
164 0 : for (int i = 0; i < length; i++) {
165 0 : Append(static_cast<char>(str->Get(i)));
166 : }
167 0 : }
168 :
169 54224 : void Log::MessageBuilder::AppendAddress(Address addr) {
170 54224 : Append("0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(addr));
171 54224 : }
172 :
173 0 : void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) {
174 : DCHECK(symbol);
175 0 : Append("symbol(");
176 0 : if (!symbol->name()->IsUndefined(symbol->GetIsolate())) {
177 0 : Append("\"");
178 0 : AppendDetailed(String::cast(symbol->name()), false);
179 0 : Append("\" ");
180 : }
181 0 : Append("hash %x)", symbol->Hash());
182 0 : }
183 :
184 :
185 0 : void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
186 0 : if (str == nullptr) return;
187 : DisallowHeapAllocation no_gc; // Ensure string stay valid.
188 : int len = str->length();
189 0 : if (len > 0x1000)
190 : len = 0x1000;
191 0 : if (show_impl_info) {
192 0 : Append(str->IsOneByteRepresentation() ? 'a' : '2');
193 0 : if (StringShape(str).IsExternal())
194 : Append('e');
195 0 : if (StringShape(str).IsInternalized())
196 : Append('#');
197 0 : Append(":%i:", str->length());
198 : }
199 0 : for (int i = 0; i < len; i++) {
200 0 : uc32 c = str->Get(i);
201 0 : if (c > 0xff) {
202 0 : Append("\\u%04x", c);
203 0 : } else if (c < 32 || c > 126) {
204 0 : Append("\\x%02x", c);
205 0 : } else if (c == ',') {
206 0 : Append("\\,");
207 0 : } else if (c == '\\') {
208 0 : Append("\\\\");
209 0 : } else if (c == '\"') {
210 0 : Append("\"\"");
211 : } else {
212 0 : Append("%lc", c);
213 : }
214 : }
215 : }
216 :
217 0 : void Log::MessageBuilder::AppendUnbufferedHeapString(String* str) {
218 0 : if (str == nullptr) return;
219 : DisallowHeapAllocation no_gc; // Ensure string stay valid.
220 : ScopedVector<char> buffer(16);
221 : int len = str->length();
222 0 : for (int i = 0; i < len; i++) {
223 0 : uc32 c = str->Get(i);
224 0 : if (c >= 32 && c <= 126) {
225 0 : if (c == '\"') {
226 0 : AppendUnbufferedCString("\"\"");
227 0 : } else if (c == '\\') {
228 0 : AppendUnbufferedCString("\\\\");
229 : } else {
230 0 : AppendUnbufferedChar(c);
231 : }
232 0 : } else if (c > 0xff) {
233 0 : int length = v8::internal::SNPrintF(buffer, "\\u%04x", c);
234 : DCHECK_EQ(6, length);
235 0 : log_->WriteToFile(buffer.start(), length);
236 : } else {
237 : DCHECK_LE(c, 0xffff);
238 0 : int length = v8::internal::SNPrintF(buffer, "\\x%02x", c);
239 : DCHECK_EQ(4, length);
240 0 : log_->WriteToFile(buffer.start(), length);
241 : }
242 : }
243 : }
244 :
245 0 : void Log::MessageBuilder::AppendUnbufferedChar(char c) {
246 0 : log_->WriteToFile(&c, 1);
247 0 : }
248 :
249 0 : void Log::MessageBuilder::AppendUnbufferedCString(const char* str) {
250 0 : log_->WriteToFile(str, static_cast<int>(strlen(str)));
251 0 : }
252 :
253 0 : void Log::MessageBuilder::AppendStringPart(const char* str, int len) {
254 0 : if (pos_ + len > Log::kMessageBufferSize) {
255 0 : len = Log::kMessageBufferSize - pos_;
256 : DCHECK_GE(len, 0);
257 0 : if (len == 0) return;
258 : }
259 : Vector<char> buf(log_->message_buffer_ + pos_,
260 0 : Log::kMessageBufferSize - pos_);
261 0 : StrNCpy(buf, str, len);
262 0 : pos_ += len;
263 : DCHECK_LE(pos_, Log::kMessageBufferSize);
264 : }
265 :
266 38018 : void Log::MessageBuilder::WriteToLogFile() {
267 : DCHECK_LE(pos_, Log::kMessageBufferSize);
268 : // Assert that we do not already have a new line at the end.
269 : DCHECK(pos_ == 0 || log_->message_buffer_[pos_ - 1] != '\n');
270 38018 : if (pos_ == Log::kMessageBufferSize) pos_--;
271 76036 : log_->message_buffer_[pos_++] = '\n';
272 38018 : const int written = log_->WriteToFile(log_->message_buffer_, pos_);
273 38018 : if (written != pos_) {
274 0 : log_->stop();
275 0 : log_->logger_->LogFailure();
276 : }
277 38018 : }
278 :
279 : } // namespace internal
280 : } // namespace v8
|