1 // Copyright 2009 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "log-utils.h" 31 #include "string-stream.h" 32 33 namespace v8 { 34 namespace internal { 35 36 37 const char* const Log::kLogToTemporaryFile = "&"; 38 const char* const Log::kLogToConsole = "-"; 39 40 41 Log::Log(Logger* logger) 42 : is_stopped_(false), 43 output_handle_(NULL), 44 mutex_(NULL), 45 message_buffer_(NULL), 46 logger_(logger) { 47 } 48 49 50 void Log::Initialize(const char* log_file_name) { 51 mutex_ = OS::CreateMutex(); 52 message_buffer_ = NewArray<char>(kMessageBufferSize); 53 54 // --log-all enables all the log flags. 55 if (FLAG_log_all) { 56 FLAG_log_runtime = true; 57 FLAG_log_api = true; 58 FLAG_log_code = true; 59 FLAG_log_gc = true; 60 FLAG_log_suspect = true; 61 FLAG_log_handles = true; 62 FLAG_log_regexp = true; 63 FLAG_log_internal_timer_events = true; 64 } 65 66 // --prof implies --log-code. 67 if (FLAG_prof) FLAG_log_code = true; 68 69 // --prof_lazy controls --log-code. 70 if (FLAG_prof_lazy) { 71 FLAG_log_code = false; 72 } 73 74 // If we're logging anything, we need to open the log file. 75 if (Log::InitLogAtStart()) { 76 if (strcmp(log_file_name, kLogToConsole) == 0) { 77 OpenStdout(); 78 } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) { 79 OpenTemporaryFile(); 80 } else { 81 OpenFile(log_file_name); 82 } 83 } 84 } 85 86 87 void Log::OpenStdout() { 88 ASSERT(!IsEnabled()); 89 output_handle_ = stdout; 90 } 91 92 93 void Log::OpenTemporaryFile() { 94 ASSERT(!IsEnabled()); 95 output_handle_ = i::OS::OpenTemporaryFile(); 96 } 97 98 99 void Log::OpenFile(const char* name) { 100 ASSERT(!IsEnabled()); 101 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); 102 } 103 104 105 FILE* Log::Close() { 106 FILE* result = NULL; 107 if (output_handle_ != NULL) { 108 if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) { 109 fclose(output_handle_); 110 } else { 111 result = output_handle_; 112 } 113 } 114 output_handle_ = NULL; 115 116 DeleteArray(message_buffer_); 117 message_buffer_ = NULL; 118 119 delete mutex_; 120 mutex_ = NULL; 121 122 is_stopped_ = false; 123 return result; 124 } 125 126 127 Log::MessageBuilder::MessageBuilder(Log* log) 128 : log_(log), 129 sl(log_->mutex_), 130 pos_(0) { 131 ASSERT(log_->message_buffer_ != NULL); 132 } 133 134 135 void Log::MessageBuilder::Append(const char* format, ...) { 136 Vector<char> buf(log_->message_buffer_ + pos_, 137 Log::kMessageBufferSize - pos_); 138 va_list args; 139 va_start(args, format); 140 AppendVA(format, args); 141 va_end(args); 142 ASSERT(pos_ <= Log::kMessageBufferSize); 143 } 144 145 146 void Log::MessageBuilder::AppendVA(const char* format, va_list args) { 147 Vector<char> buf(log_->message_buffer_ + pos_, 148 Log::kMessageBufferSize - pos_); 149 int result = v8::internal::OS::VSNPrintF(buf, format, args); 150 151 // Result is -1 if output was truncated. 152 if (result >= 0) { 153 pos_ += result; 154 } else { 155 pos_ = Log::kMessageBufferSize; 156 } 157 ASSERT(pos_ <= Log::kMessageBufferSize); 158 } 159 160 161 void Log::MessageBuilder::Append(const char c) { 162 if (pos_ < Log::kMessageBufferSize) { 163 log_->message_buffer_[pos_++] = c; 164 } 165 ASSERT(pos_ <= Log::kMessageBufferSize); 166 } 167 168 169 void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) { 170 Append('"'); 171 for (const char* p = string; *p != '\0'; p++) { 172 if (*p == '"') { 173 Append('\\'); 174 } 175 Append(*p); 176 } 177 Append('"'); 178 } 179 180 181 void Log::MessageBuilder::Append(String* str) { 182 DisallowHeapAllocation no_gc; // Ensure string stay valid. 183 int length = str->length(); 184 for (int i = 0; i < length; i++) { 185 Append(static_cast<char>(str->Get(i))); 186 } 187 } 188 189 190 void Log::MessageBuilder::AppendAddress(Address addr) { 191 Append("0x%" V8PRIxPTR, addr); 192 } 193 194 195 void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) { 196 ASSERT(symbol); 197 Append("symbol("); 198 if (!symbol->name()->IsUndefined()) { 199 Append("\""); 200 AppendDetailed(String::cast(symbol->name()), false); 201 Append("\" "); 202 } 203 Append("hash %x)", symbol->Hash()); 204 } 205 206 207 void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) { 208 if (str == NULL) return; 209 DisallowHeapAllocation no_gc; // Ensure string stay valid. 210 int len = str->length(); 211 if (len > 0x1000) 212 len = 0x1000; 213 if (show_impl_info) { 214 Append(str->IsOneByteRepresentation() ? 'a' : '2'); 215 if (StringShape(str).IsExternal()) 216 Append('e'); 217 if (StringShape(str).IsInternalized()) 218 Append('#'); 219 Append(":%i:", str->length()); 220 } 221 for (int i = 0; i < len; i++) { 222 uc32 c = str->Get(i); 223 if (c > 0xff) { 224 Append("\\u%04x", c); 225 } else if (c < 32 || c > 126) { 226 Append("\\x%02x", c); 227 } else if (c == ',') { 228 Append("\\,"); 229 } else if (c == '\\') { 230 Append("\\\\"); 231 } else if (c == '\"') { 232 Append("\"\""); 233 } else { 234 Append("%lc", c); 235 } 236 } 237 } 238 239 240 void Log::MessageBuilder::AppendStringPart(const char* str, int len) { 241 if (pos_ + len > Log::kMessageBufferSize) { 242 len = Log::kMessageBufferSize - pos_; 243 ASSERT(len >= 0); 244 if (len == 0) return; 245 } 246 Vector<char> buf(log_->message_buffer_ + pos_, 247 Log::kMessageBufferSize - pos_); 248 OS::StrNCpy(buf, str, len); 249 pos_ += len; 250 ASSERT(pos_ <= Log::kMessageBufferSize); 251 } 252 253 254 void Log::MessageBuilder::WriteToLogFile() { 255 ASSERT(pos_ <= Log::kMessageBufferSize); 256 const int written = log_->WriteToFile(log_->message_buffer_, pos_); 257 if (written != pos_) { 258 log_->stop(); 259 log_->logger_->LogFailure(); 260 } 261 } 262 263 264 } } // namespace v8::internal 265