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