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 Log::Log(Logger* logger) 23 : is_stopped_(false), 24 output_handle_(NULL), 25 message_buffer_(NULL), 26 logger_(logger) { 27 } 28 29 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 68 void Log::OpenStdout() { 69 DCHECK(!IsEnabled()); 70 output_handle_ = stdout; 71 } 72 73 74 void Log::OpenTemporaryFile() { 75 DCHECK(!IsEnabled()); 76 output_handle_ = base::OS::OpenTemporaryFile(); 77 } 78 79 80 void Log::OpenFile(const char* name) { 81 DCHECK(!IsEnabled()); 82 output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode); 83 } 84 85 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 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 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 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 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 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 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 168 void Log::MessageBuilder::AppendAddress(Address addr) { 169 Append("0x%" V8PRIxPTR, addr); 170 } 171 172 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 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 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 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