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/vector.h"
13 : #include "src/version.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 :
19 : const char* const Log::kLogToTemporaryFile = "&";
20 : const char* const Log::kLogToConsole = "-";
21 :
22 : // static
23 61534 : FILE* Log::CreateOutputHandle(const char* file_name) {
24 : // If we're logging anything, we need to open the log file.
25 61534 : if (!Log::InitLogAtStart()) {
26 : return nullptr;
27 59 : } else if (strcmp(file_name, kLogToConsole) == 0) {
28 0 : return stdout;
29 59 : } else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
30 59 : return base::OS::OpenTemporaryFile();
31 : } else {
32 0 : return base::OS::FOpen(file_name, base::OS::LogFileOpenMode);
33 : }
34 : }
35 :
36 61534 : Log::Log(Logger* logger, const char* file_name)
37 : : is_stopped_(false),
38 61534 : output_handle_(Log::CreateOutputHandle(file_name)),
39 : os_(output_handle_ == nullptr ? stdout : output_handle_),
40 61533 : format_buffer_(NewArray<char>(kMessageBufferSize)),
41 184601 : logger_(logger) {
42 : // --log-all enables all the log flags.
43 61534 : if (FLAG_log_all) {
44 5 : FLAG_log_api = true;
45 5 : FLAG_log_code = true;
46 5 : FLAG_log_suspect = true;
47 5 : FLAG_log_handles = true;
48 5 : FLAG_log_internal_timer_events = true;
49 5 : FLAG_log_function_events = true;
50 : }
51 :
52 : // --prof implies --log-code.
53 61534 : if (FLAG_prof) FLAG_log_code = true;
54 :
55 123009 : if (output_handle_ == nullptr) return;
56 : Log::MessageBuilder msg(this);
57 : LogSeparator kNext = LogSeparator::kSeparator;
58 : msg << "v8-version" << kNext << Version::GetMajor() << kNext
59 : << Version::GetMinor() << kNext << Version::GetBuild() << kNext
60 : << Version::GetPatch();
61 59 : if (strlen(Version::GetEmbedder()) != 0) {
62 : msg << kNext << Version::GetEmbedder();
63 : }
64 : msg << kNext << Version::IsCandidate();
65 : msg.WriteToLogFile();
66 : }
67 :
68 61517 : FILE* Log::Close() {
69 : FILE* result = nullptr;
70 61517 : if (output_handle_ != nullptr) {
71 59 : if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
72 0 : fclose(output_handle_);
73 : } else {
74 : result = output_handle_;
75 : }
76 : }
77 61517 : output_handle_ = nullptr;
78 :
79 61517 : DeleteArray(format_buffer_);
80 61519 : format_buffer_ = nullptr;
81 :
82 61519 : is_stopped_ = false;
83 61519 : return result;
84 : }
85 :
86 45990 : Log::MessageBuilder::MessageBuilder(Log* log)
87 46049 : : log_(log), lock_guard_(&log_->mutex_) {
88 : DCHECK_NOT_NULL(log_->format_buffer_);
89 45990 : }
90 :
91 5562 : void Log::MessageBuilder::AppendString(String str,
92 : base::Optional<int> length_limit) {
93 5562 : if (str.is_null()) return;
94 :
95 : DisallowHeapAllocation no_gc; // Ensure string stays valid.
96 5562 : int length = str->length();
97 5786 : if (length_limit) length = std::min(length, *length_limit);
98 150284 : for (int i = 0; i < length; i++) {
99 : uint16_t c = str->Get(i);
100 72361 : if (c <= 0xFF) {
101 72361 : AppendCharacter(static_cast<char>(c));
102 : } else {
103 : // Escape non-ascii characters.
104 0 : AppendRawFormatString("\\u%04x", c & 0xFFFF);
105 : }
106 : }
107 : }
108 :
109 0 : void Log::MessageBuilder::AppendString(Vector<const char> str) {
110 0 : for (auto i = str.begin(); i < str.end(); i++) AppendCharacter(*i);
111 0 : }
112 :
113 89404 : void Log::MessageBuilder::AppendString(const char* str) {
114 89404 : if (str == nullptr) return;
115 89356 : AppendString(str, strlen(str));
116 : }
117 :
118 72 : void Log::MessageBuilder::AppendString(const char* str, size_t length) {
119 89428 : if (str == nullptr) return;
120 :
121 30007486 : for (size_t i = 0; i < length; i++) {
122 : DCHECK_NE(str[i], '\0');
123 14959029 : AppendCharacter(str[i]);
124 : }
125 : }
126 :
127 144 : void Log::MessageBuilder::AppendFormatString(const char* format, ...) {
128 : va_list args;
129 144 : va_start(args, format);
130 : const int length = FormatStringIntoBuffer(format, args);
131 144 : va_end(args);
132 2826 : for (int i = 0; i < length; i++) {
133 : DCHECK_NE(log_->format_buffer_[i], '\0');
134 1341 : AppendCharacter(log_->format_buffer_[i]);
135 : }
136 144 : }
137 :
138 15032731 : void Log::MessageBuilder::AppendCharacter(char c) {
139 15032731 : if (c >= 32 && c <= 126) {
140 14725114 : if (c == ',') {
141 : // Escape commas to avoid adding column separators.
142 89723 : AppendRawFormatString("\\x2C");
143 14635391 : } else if (c == '\\') {
144 0 : AppendRawFormatString("\\\\");
145 : } else {
146 : // Safe, printable ascii character.
147 : AppendRawCharacter(c);
148 : }
149 307617 : } else if (c == '\n') {
150 : // Escape newlines to avoid adding row separators.
151 307617 : AppendRawFormatString("\\n");
152 : } else {
153 : // Escape non-printable characters.
154 0 : AppendRawFormatString("\\x%02x", c & 0xFF);
155 : }
156 15032731 : }
157 :
158 253 : void Log::MessageBuilder::AppendSymbolName(Symbol symbol) {
159 : DCHECK(!symbol.is_null());
160 253 : OFStream& os = log_->os_;
161 253 : os << "symbol(";
162 253 : if (!symbol->name()->IsUndefined()) {
163 224 : os << "\"";
164 224 : AppendSymbolNameDetails(String::cast(symbol->name()), false);
165 224 : os << "\" ";
166 : }
167 506 : os << "hash " << std::hex << symbol->Hash() << std::dec << ")";
168 253 : }
169 :
170 224 : void Log::MessageBuilder::AppendSymbolNameDetails(String str,
171 : bool show_impl_info) {
172 224 : if (str.is_null()) return;
173 :
174 : DisallowHeapAllocation no_gc; // Ensure string stays valid.
175 224 : OFStream& os = log_->os_;
176 : int limit = str->length();
177 224 : if (limit > 0x1000) limit = 0x1000;
178 224 : if (show_impl_info) {
179 0 : os << (str->IsOneByteRepresentation() ? 'a' : '2');
180 0 : if (StringShape(str).IsExternal()) os << 'e';
181 0 : if (StringShape(str).IsInternalized()) os << '#';
182 0 : os << ':' << str->length() << ':';
183 : }
184 224 : AppendString(str, limit);
185 : }
186 :
187 0 : int Log::MessageBuilder::FormatStringIntoBuffer(const char* format,
188 : va_list args) {
189 397484 : Vector<char> buf(log_->format_buffer_, Log::kMessageBufferSize);
190 397484 : int length = v8::internal::VSNPrintF(buf, format, args);
191 : // |length| is -1 if output was truncated.
192 397484 : if (length == -1) length = Log::kMessageBufferSize;
193 : DCHECK_LE(length, Log::kMessageBufferSize);
194 : DCHECK_GE(length, 0);
195 0 : return length;
196 : }
197 :
198 397340 : void Log::MessageBuilder::AppendRawFormatString(const char* format, ...) {
199 : va_list args;
200 397340 : va_start(args, format);
201 : const int length = FormatStringIntoBuffer(format, args);
202 397340 : va_end(args);
203 2345592 : for (int i = 0; i < length; i++) {
204 : DCHECK_NE(log_->format_buffer_[i], '\0');
205 974126 : AppendRawCharacter(log_->format_buffer_[i]);
206 : }
207 397340 : }
208 :
209 15791452 : void Log::MessageBuilder::AppendRawCharacter(char c) { log_->os_ << c; }
210 :
211 92039 : void Log::MessageBuilder::WriteToLogFile() { log_->os_ << std::endl; }
212 :
213 : template <>
214 89345 : Log::MessageBuilder& Log::MessageBuilder::operator<<<const char*>(
215 : const char* string) {
216 89404 : this->AppendString(string);
217 89345 : return *this;
218 : }
219 :
220 : template <>
221 6734 : Log::MessageBuilder& Log::MessageBuilder::operator<<<void*>(void* pointer) {
222 6734 : OFStream& os = log_->os_;
223 : // Manually format the pointer since on Windows we do not consistently
224 : // get a "0x" prefix.
225 6734 : os << "0x" << std::hex << reinterpret_cast<intptr_t>(pointer) << std::dec;
226 6734 : return *this;
227 : }
228 :
229 : template <>
230 0 : Log::MessageBuilder& Log::MessageBuilder::operator<<<char>(char c) {
231 0 : this->AppendCharacter(c);
232 0 : return *this;
233 : }
234 :
235 : template <>
236 330 : Log::MessageBuilder& Log::MessageBuilder::operator<<<String>(String string) {
237 330 : this->AppendString(string);
238 330 : return *this;
239 : }
240 :
241 : template <>
242 0 : Log::MessageBuilder& Log::MessageBuilder::operator<<<Symbol>(Symbol symbol) {
243 0 : this->AppendSymbolName(symbol);
244 0 : return *this;
245 : }
246 :
247 : template <>
248 5261 : Log::MessageBuilder& Log::MessageBuilder::operator<<<Name>(Name name) {
249 5261 : if (name->IsString()) {
250 5008 : this->AppendString(String::cast(name));
251 : } else {
252 253 : this->AppendSymbolName(Symbol::cast(name));
253 : }
254 5261 : return *this;
255 : }
256 :
257 : template <>
258 181640 : Log::MessageBuilder& Log::MessageBuilder::operator<<<LogSeparator>(
259 : LogSeparator separator) {
260 : // Skip escaping to create a new column.
261 : this->AppendRawCharacter(',');
262 181640 : return *this;
263 : }
264 :
265 : } // namespace internal
266 120216 : } // namespace v8
|