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 void Log::MessageBuilder::AppendAddress(Address addr) { 168 Append("%p", static_cast<void*>(addr)); 169 } 170 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 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 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 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