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