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_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 67 void Log::OpenStdout() { 68 DCHECK(!IsEnabled()); 69 output_handle_ = stdout; 70 } 71 72 73 void Log::OpenTemporaryFile() { 74 DCHECK(!IsEnabled()); 75 output_handle_ = base::OS::OpenTemporaryFile(); 76 } 77 78 79 void Log::OpenFile(const char* name) { 80 DCHECK(!IsEnabled()); 81 output_handle_ = base::OS::FOpen(name, base::OS::LogFileOpenMode); 82 } 83 84 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 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 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 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 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 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 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 166 void Log::MessageBuilder::AppendAddress(Address addr) { 167 Append("%p", static_cast<void*>(addr)); 168 } 169 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 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 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 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