• 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_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 
AppendAddress(Address addr)167 void Log::MessageBuilder::AppendAddress(Address addr) {
168   Append("%p", static_cast<void*>(addr));
169 }
170 
AppendSymbolName(Symbol * symbol)171 void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) {
172   DCHECK(symbol);
173   Append("symbol(");
174   if (!symbol->name()->IsUndefined(symbol->GetIsolate())) {
175     Append("\"");
176     AppendDetailed(String::cast(symbol->name()), false);
177     Append("\" ");
178   }
179   Append("hash %x)", symbol->Hash());
180 }
181 
182 
AppendDetailed(String * str,bool show_impl_info)183 void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
184   if (str == NULL) return;
185   DisallowHeapAllocation no_gc;  // Ensure string stay valid.
186   int len = str->length();
187   if (len > 0x1000)
188     len = 0x1000;
189   if (show_impl_info) {
190     Append(str->IsOneByteRepresentation() ? 'a' : '2');
191     if (StringShape(str).IsExternal())
192       Append('e');
193     if (StringShape(str).IsInternalized())
194       Append('#');
195     Append(":%i:", str->length());
196   }
197   for (int i = 0; i < len; i++) {
198     uc32 c = str->Get(i);
199     if (c > 0xff) {
200       Append("\\u%04x", c);
201     } else if (c < 32 || c > 126) {
202       Append("\\x%02x", c);
203     } else if (c == ',') {
204       Append("\\,");
205     } else if (c == '\\') {
206       Append("\\\\");
207     } else if (c == '\"') {
208       Append("\"\"");
209     } else {
210       Append("%lc", c);
211     }
212   }
213 }
214 
215 
AppendStringPart(const char * str,int len)216 void Log::MessageBuilder::AppendStringPart(const char* str, int len) {
217   if (pos_ + len > Log::kMessageBufferSize) {
218     len = Log::kMessageBufferSize - pos_;
219     DCHECK(len >= 0);
220     if (len == 0) return;
221   }
222   Vector<char> buf(log_->message_buffer_ + pos_,
223                    Log::kMessageBufferSize - pos_);
224   StrNCpy(buf, str, len);
225   pos_ += len;
226   DCHECK(pos_ <= Log::kMessageBufferSize);
227 }
228 
229 
WriteToLogFile()230 void Log::MessageBuilder::WriteToLogFile() {
231   DCHECK(pos_ <= Log::kMessageBufferSize);
232   // Assert that we do not already have a new line at the end.
233   DCHECK(pos_ == 0 || log_->message_buffer_[pos_ - 1] != '\n');
234   if (pos_ == Log::kMessageBufferSize) pos_--;
235   log_->message_buffer_[pos_++] = '\n';
236   const int written = log_->WriteToFile(log_->message_buffer_, pos_);
237   if (written != pos_) {
238     log_->stop();
239     log_->logger_->LogFailure();
240   }
241 }
242 
243 
244 }  // namespace internal
245 }  // namespace v8
246