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