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
Log(Logger * logger)22 Log::Log(Logger* logger)
23 : is_stopped_(false),
24 output_handle_(NULL),
25 message_buffer_(NULL),
26 logger_(logger) {
27 }
28
29
Initialize(const char * log_file_name)30 void Log::Initialize(const char* log_file_name) {
31 message_buffer_ = NewArray<char>(kMessageBufferSize);
32
33 // --log-all enables all the log flags.
34 if (FLAG_log_all) {
35 FLAG_log_api = true;
36 FLAG_log_code = true;
37 FLAG_log_gc = true;
38 FLAG_log_suspect = true;
39 FLAG_log_handles = true;
40 FLAG_log_regexp = true;
41 FLAG_log_internal_timer_events = true;
42 }
43
44 // --prof implies --log-code.
45 if (FLAG_prof) FLAG_log_code = true;
46
47 // If we're logging anything, we need to open the log file.
48 if (Log::InitLogAtStart()) {
49 if (strcmp(log_file_name, kLogToConsole) == 0) {
50 OpenStdout();
51 } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) {
52 OpenTemporaryFile();
53 } else {
54 OpenFile(log_file_name);
55 }
56
57 if (output_handle_ != nullptr) {
58 Log::MessageBuilder msg(this);
59 msg.Append("v8-version,%d,%d,%d,%d,%d", Version::GetMajor(),
60 Version::GetMinor(), Version::GetBuild(), Version::GetPatch(),
61 Version::IsCandidate());
62 msg.WriteToLogFile();
63 }
64 }
65 }
66
67
OpenStdout()68 void Log::OpenStdout() {
69 DCHECK(!IsEnabled());
70 output_handle_ = stdout;
71 }
72
73
OpenTemporaryFile()74 void Log::OpenTemporaryFile() {
75 DCHECK(!IsEnabled());
76 output_handle_ = base::OS::OpenTemporaryFile();
77 }
78
79
OpenFile(const char * name)80 void Log::OpenFile(const char* name) {
81 DCHECK(!IsEnabled());
82 output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode);
83 }
84
85
Close()86 FILE* Log::Close() {
87 FILE* result = NULL;
88 if (output_handle_ != NULL) {
89 if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
90 fclose(output_handle_);
91 } else {
92 result = output_handle_;
93 }
94 }
95 output_handle_ = NULL;
96
97 DeleteArray(message_buffer_);
98 message_buffer_ = NULL;
99
100 is_stopped_ = false;
101 return result;
102 }
103
104
MessageBuilder(Log * log)105 Log::MessageBuilder::MessageBuilder(Log* log)
106 : log_(log),
107 lock_guard_(&log_->mutex_),
108 pos_(0) {
109 DCHECK(log_->message_buffer_ != NULL);
110 }
111
112
Append(const char * format,...)113 void Log::MessageBuilder::Append(const char* format, ...) {
114 Vector<char> buf(log_->message_buffer_ + pos_,
115 Log::kMessageBufferSize - pos_);
116 va_list args;
117 va_start(args, format);
118 AppendVA(format, args);
119 va_end(args);
120 DCHECK(pos_ <= Log::kMessageBufferSize);
121 }
122
123
AppendVA(const char * format,va_list args)124 void Log::MessageBuilder::AppendVA(const char* format, va_list args) {
125 Vector<char> buf(log_->message_buffer_ + pos_,
126 Log::kMessageBufferSize - pos_);
127 int result = v8::internal::VSNPrintF(buf, format, args);
128
129 // Result is -1 if output was truncated.
130 if (result >= 0) {
131 pos_ += result;
132 } else {
133 pos_ = Log::kMessageBufferSize;
134 }
135 DCHECK(pos_ <= Log::kMessageBufferSize);
136 }
137
138
Append(const char c)139 void Log::MessageBuilder::Append(const char c) {
140 if (pos_ < Log::kMessageBufferSize) {
141 log_->message_buffer_[pos_++] = c;
142 }
143 DCHECK(pos_ <= Log::kMessageBufferSize);
144 }
145
146
AppendDoubleQuotedString(const char * string)147 void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) {
148 Append('"');
149 for (const char* p = string; *p != '\0'; p++) {
150 if (*p == '"') {
151 Append('\\');
152 }
153 Append(*p);
154 }
155 Append('"');
156 }
157
158
Append(String * str)159 void Log::MessageBuilder::Append(String* str) {
160 DisallowHeapAllocation no_gc; // Ensure string stay valid.
161 int length = str->length();
162 for (int i = 0; i < length; i++) {
163 Append(static_cast<char>(str->Get(i)));
164 }
165 }
166
167
AppendAddress(Address addr)168 void Log::MessageBuilder::AppendAddress(Address addr) {
169 Append("0x%" V8PRIxPTR, addr);
170 }
171
172
AppendSymbolName(Symbol * symbol)173 void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) {
174 DCHECK(symbol);
175 Append("symbol(");
176 if (!symbol->name()->IsUndefined()) {
177 Append("\"");
178 AppendDetailed(String::cast(symbol->name()), false);
179 Append("\" ");
180 }
181 Append("hash %x)", symbol->Hash());
182 }
183
184
AppendDetailed(String * str,bool show_impl_info)185 void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
186 if (str == NULL) return;
187 DisallowHeapAllocation no_gc; // Ensure string stay valid.
188 int len = str->length();
189 if (len > 0x1000)
190 len = 0x1000;
191 if (show_impl_info) {
192 Append(str->IsOneByteRepresentation() ? 'a' : '2');
193 if (StringShape(str).IsExternal())
194 Append('e');
195 if (StringShape(str).IsInternalized())
196 Append('#');
197 Append(":%i:", str->length());
198 }
199 for (int i = 0; i < len; i++) {
200 uc32 c = str->Get(i);
201 if (c > 0xff) {
202 Append("\\u%04x", c);
203 } else if (c < 32 || c > 126) {
204 Append("\\x%02x", c);
205 } else if (c == ',') {
206 Append("\\,");
207 } else if (c == '\\') {
208 Append("\\\\");
209 } else if (c == '\"') {
210 Append("\"\"");
211 } else {
212 Append("%lc", c);
213 }
214 }
215 }
216
217
AppendStringPart(const char * str,int len)218 void Log::MessageBuilder::AppendStringPart(const char* str, int len) {
219 if (pos_ + len > Log::kMessageBufferSize) {
220 len = Log::kMessageBufferSize - pos_;
221 DCHECK(len >= 0);
222 if (len == 0) return;
223 }
224 Vector<char> buf(log_->message_buffer_ + pos_,
225 Log::kMessageBufferSize - pos_);
226 StrNCpy(buf, str, len);
227 pos_ += len;
228 DCHECK(pos_ <= Log::kMessageBufferSize);
229 }
230
231
WriteToLogFile()232 void Log::MessageBuilder::WriteToLogFile() {
233 DCHECK(pos_ <= Log::kMessageBufferSize);
234 // Assert that we do not already have a new line at the end.
235 DCHECK(pos_ == 0 || log_->message_buffer_[pos_ - 1] != '\n');
236 if (pos_ == Log::kMessageBufferSize) pos_--;
237 log_->message_buffer_[pos_++] = '\n';
238 const int written = log_->WriteToFile(log_->message_buffer_, pos_);
239 if (written != pos_) {
240 log_->stop();
241 log_->logger_->LogFailure();
242 }
243 }
244
245
246 } // namespace internal
247 } // namespace v8
248