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 62883 : FILE* Log::CreateOutputHandle(const char* file_name) {
24 : // If we're logging anything, we need to open the log file.
25 62883 : if (!Log::InitLogAtStart()) {
26 : return nullptr;
27 61 : } else if (strcmp(file_name, kLogToConsole) == 0) {
28 0 : return stdout;
29 61 : } else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
30 61 : return base::OS::OpenTemporaryFile();
31 : } else {
32 0 : return base::OS::FOpen(file_name, base::OS::LogFileOpenMode);
33 : }
34 : }
35 :
36 62883 : Log::Log(Logger* logger, const char* file_name)
37 : : is_stopped_(false),
38 62883 : output_handle_(Log::CreateOutputHandle(file_name)),
39 : os_(output_handle_ == nullptr ? stdout : output_handle_),
40 62883 : format_buffer_(NewArray<char>(kMessageBufferSize)),
41 188649 : logger_(logger) {
42 : // --log-all enables all the log flags.
43 62883 : 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 62883 : if (FLAG_prof) FLAG_log_code = true;
54 :
55 125705 : 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 61 : if (strlen(Version::GetEmbedder()) != 0) {
62 : msg << kNext << Version::GetEmbedder();
63 : }
64 : msg << kNext << Version::IsCandidate();
65 : msg.WriteToLogFile();
66 : }
67 :
68 62868 : FILE* Log::Close() {
69 : FILE* result = nullptr;
70 62868 : if (output_handle_ != nullptr) {
71 61 : if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
72 0 : fclose(output_handle_);
73 : } else {
74 : result = output_handle_;
75 : }
76 : }
77 62868 : output_handle_ = nullptr;
78 :
79 62868 : DeleteArray(format_buffer_);
80 62868 : format_buffer_ = nullptr;
81 :
82 62868 : is_stopped_ = false;
83 62868 : return result;
84 : }
85 :
86 46604 : Log::MessageBuilder::MessageBuilder(Log* log)
87 46665 : : log_(log), lock_guard_(&log_->mutex_) {
88 : DCHECK_NOT_NULL(log_->format_buffer_);
89 46604 : }
90 :
91 6192 : void Log::MessageBuilder::AppendString(String str,
92 6192 : base::Optional<int> length_limit) {
93 6192 : if (str.is_null()) return;
94 :
95 : DisallowHeapAllocation no_gc; // Ensure string stays valid.
96 6192 : int length = str->length();
97 6477 : if (length_limit) length = std::min(length, *length_limit);
98 83054 : for (int i = 0; i < length; i++) {
99 : uint16_t c = str->Get(i);
100 83054 : if (c <= 0xFF) {
101 83054 : 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 90848 : void Log::MessageBuilder::AppendString(const char* str) {
114 181696 : if (str == nullptr) return;
115 90800 : AppendString(str, strlen(str));
116 : }
117 :
118 90891 : void Log::MessageBuilder::AppendString(const char* str, size_t length) {
119 181782 : if (str == nullptr) return;
120 :
121 16557864 : for (size_t i = 0; i < length; i++) {
122 : DCHECK_NE(str[i], '\0');
123 16557864 : AppendCharacter(str[i]);
124 : }
125 : }
126 :
127 186 : void Log::MessageBuilder::AppendFormatString(const char* format, ...) {
128 : va_list args;
129 186 : va_start(args, format);
130 186 : const int length = FormatStringIntoBuffer(format, args);
131 186 : va_end(args);
132 2055 : for (int i = 0; i < length; i++) {
133 : DCHECK_NE(log_->format_buffer_[i], '\0');
134 1869 : AppendCharacter(log_->format_buffer_[i]);
135 : }
136 186 : }
137 :
138 16642787 : void Log::MessageBuilder::AppendCharacter(char c) {
139 16642787 : if (c >= 32 && c <= 126) {
140 16317435 : if (c == ',') {
141 : // Escape commas to avoid adding column separators.
142 89744 : AppendRawFormatString("\\x2C");
143 16227691 : } else if (c == '\\') {
144 0 : AppendRawFormatString("\\\\");
145 : } else {
146 : // Safe, printable ascii character.
147 : AppendRawCharacter(c);
148 : }
149 325352 : } else if (c == '\n') {
150 : // Escape newlines to avoid adding row separators.
151 325352 : AppendRawFormatString("\\n");
152 : } else {
153 : // Escape non-printable characters.
154 0 : AppendRawFormatString("\\x%02x", c & 0xFF);
155 : }
156 16642787 : }
157 :
158 289 : void Log::MessageBuilder::AppendSymbolName(Symbol symbol) {
159 : DCHECK(!symbol.is_null());
160 289 : OFStream& os = log_->os_;
161 289 : os << "symbol(";
162 578 : if (!symbol->name()->IsUndefined()) {
163 285 : os << "\"";
164 570 : AppendSymbolNameDetails(String::cast(symbol->name()), false);
165 285 : os << "\" ";
166 : }
167 578 : os << "hash " << std::hex << symbol->Hash() << std::dec << ")";
168 289 : }
169 :
170 285 : void Log::MessageBuilder::AppendSymbolNameDetails(String str,
171 : bool show_impl_info) {
172 570 : if (str.is_null()) return;
173 :
174 : DisallowHeapAllocation no_gc; // Ensure string stays valid.
175 285 : OFStream& os = log_->os_;
176 : int limit = str->length();
177 285 : if (limit > 0x1000) limit = 0x1000;
178 285 : 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 285 : AppendString(str, limit);
185 : }
186 :
187 415282 : int Log::MessageBuilder::FormatStringIntoBuffer(const char* format,
188 : va_list args) {
189 415282 : Vector<char> buf(log_->format_buffer_, Log::kMessageBufferSize);
190 415282 : int length = v8::internal::VSNPrintF(buf, format, args);
191 : // |length| is -1 if output was truncated.
192 415282 : if (length == -1) length = Log::kMessageBufferSize;
193 : DCHECK_LE(length, Log::kMessageBufferSize);
194 : DCHECK_GE(length, 0);
195 415282 : return length;
196 : }
197 :
198 415096 : void Log::MessageBuilder::AppendRawFormatString(const char* format, ...) {
199 : va_list args;
200 415096 : va_start(args, format);
201 415096 : const int length = FormatStringIntoBuffer(format, args);
202 415096 : va_end(args);
203 1424776 : for (int i = 0; i < length; i++) {
204 : DCHECK_NE(log_->format_buffer_[i], '\0');
205 1009680 : AppendRawCharacter(log_->format_buffer_[i]);
206 : }
207 415096 : }
208 :
209 17422648 : void Log::MessageBuilder::AppendRawCharacter(char c) { log_->os_ << c; }
210 :
211 93269 : void Log::MessageBuilder::WriteToLogFile() { log_->os_ << std::endl; }
212 :
213 : template <>
214 90787 : Log::MessageBuilder& Log::MessageBuilder::operator<<<const char*>(
215 : const char* string) {
216 90848 : this->AppendString(string);
217 90787 : return *this;
218 : }
219 :
220 : template <>
221 59912 : Log::MessageBuilder& Log::MessageBuilder::operator<<<void*>(void* pointer) {
222 59912 : OFStream& os = log_->os_;
223 : // Manually format the pointer since on Windows we do not consistently
224 : // get a "0x" prefix.
225 59912 : os << "0x" << std::hex << reinterpret_cast<intptr_t>(pointer) << std::dec;
226 59912 : 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 371 : Log::MessageBuilder& Log::MessageBuilder::operator<<<String>(String string) {
237 371 : this->AppendString(string);
238 371 : 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 5825 : Log::MessageBuilder& Log::MessageBuilder::operator<<<Name>(Name name) {
249 5825 : if (name->IsString()) {
250 5536 : this->AppendString(String::cast(name));
251 : } else {
252 289 : this->AppendSymbolName(Symbol::cast(name));
253 : }
254 5825 : return *this;
255 : }
256 :
257 : template <>
258 184972 : Log::MessageBuilder& Log::MessageBuilder::operator<<<LogSeparator>(
259 : LogSeparator separator) {
260 : // Skip escaping to create a new column.
261 : this->AppendRawCharacter(',');
262 184972 : return *this;
263 : }
264 :
265 : } // namespace internal
266 183867 : } // namespace v8
|