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 message_buffer_(NULL), 45 logger_(logger) { 46 } 47 48 49 void Log::Initialize(const char* log_file_name) { 50 message_buffer_ = NewArray<char>(kMessageBufferSize); 51 52 // --log-all enables all the log flags. 53 if (FLAG_log_all) { 54 FLAG_log_runtime = true; 55 FLAG_log_api = true; 56 FLAG_log_code = true; 57 FLAG_log_gc = true; 58 FLAG_log_suspect = true; 59 FLAG_log_handles = true; 60 FLAG_log_regexp = true; 61 FLAG_log_internal_timer_events = true; 62 } 63 64 // --prof implies --log-code. 65 if (FLAG_prof) FLAG_log_code = true; 66 67 // If we're logging anything, we need to open the log file. 68 if (Log::InitLogAtStart()) { 69 if (strcmp(log_file_name, kLogToConsole) == 0) { 70 OpenStdout(); 71 } else if (strcmp(log_file_name, kLogToTemporaryFile) == 0) { 72 OpenTemporaryFile(); 73 } else { 74 OpenFile(log_file_name); 75 } 76 } 77 } 78 79 80 void Log::OpenStdout() { 81 ASSERT(!IsEnabled()); 82 output_handle_ = stdout; 83 } 84 85 86 void Log::OpenTemporaryFile() { 87 ASSERT(!IsEnabled()); 88 output_handle_ = i::OS::OpenTemporaryFile(); 89 } 90 91 92 void Log::OpenFile(const char* name) { 93 ASSERT(!IsEnabled()); 94 output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); 95 } 96 97 98 FILE* Log::Close() { 99 FILE* result = NULL; 100 if (output_handle_ != NULL) { 101 if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) { 102 fclose(output_handle_); 103 } else { 104 result = output_handle_; 105 } 106 } 107 output_handle_ = NULL; 108 109 DeleteArray(message_buffer_); 110 message_buffer_ = NULL; 111 112 is_stopped_ = false; 113 return result; 114 } 115 116 117 Log::MessageBuilder::MessageBuilder(Log* log) 118 : log_(log), 119 lock_guard_(&log_->mutex_), 120 pos_(0) { 121 ASSERT(log_->message_buffer_ != NULL); 122 } 123 124 125 void Log::MessageBuilder::Append(const char* format, ...) { 126 Vector<char> buf(log_->message_buffer_ + pos_, 127 Log::kMessageBufferSize - pos_); 128 va_list args; 129 va_start(args, format); 130 AppendVA(format, args); 131 va_end(args); 132 ASSERT(pos_ <= Log::kMessageBufferSize); 133 } 134 135 136 void Log::MessageBuilder::AppendVA(const char* format, va_list args) { 137 Vector<char> buf(log_->message_buffer_ + pos_, 138 Log::kMessageBufferSize - pos_); 139 int result = v8::internal::OS::VSNPrintF(buf, format, args); 140 141 // Result is -1 if output was truncated. 142 if (result >= 0) { 143 pos_ += result; 144 } else { 145 pos_ = Log::kMessageBufferSize; 146 } 147 ASSERT(pos_ <= Log::kMessageBufferSize); 148 } 149 150 151 void Log::MessageBuilder::Append(const char c) { 152 if (pos_ < Log::kMessageBufferSize) { 153 log_->message_buffer_[pos_++] = c; 154 } 155 ASSERT(pos_ <= Log::kMessageBufferSize); 156 } 157 158 159 void Log::MessageBuilder::AppendDoubleQuotedString(const char* string) { 160 Append('"'); 161 for (const char* p = string; *p != '\0'; p++) { 162 if (*p == '"') { 163 Append('\\'); 164 } 165 Append(*p); 166 } 167 Append('"'); 168 } 169 170 171 void Log::MessageBuilder::Append(String* str) { 172 DisallowHeapAllocation no_gc; // Ensure string stay valid. 173 int length = str->length(); 174 for (int i = 0; i < length; i++) { 175 Append(static_cast<char>(str->Get(i))); 176 } 177 } 178 179 180 void Log::MessageBuilder::AppendAddress(Address addr) { 181 Append("0x%" V8PRIxPTR, addr); 182 } 183 184 185 void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) { 186 ASSERT(symbol); 187 Append("symbol("); 188 if (!symbol->name()->IsUndefined()) { 189 Append("\""); 190 AppendDetailed(String::cast(symbol->name()), false); 191 Append("\" "); 192 } 193 Append("hash %x)", symbol->Hash()); 194 } 195 196 197 void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) { 198 if (str == NULL) return; 199 DisallowHeapAllocation no_gc; // Ensure string stay valid. 200 int len = str->length(); 201 if (len > 0x1000) 202 len = 0x1000; 203 if (show_impl_info) { 204 Append(str->IsOneByteRepresentation() ? 'a' : '2'); 205 if (StringShape(str).IsExternal()) 206 Append('e'); 207 if (StringShape(str).IsInternalized()) 208 Append('#'); 209 Append(":%i:", str->length()); 210 } 211 for (int i = 0; i < len; i++) { 212 uc32 c = str->Get(i); 213 if (c > 0xff) { 214 Append("\\u%04x", c); 215 } else if (c < 32 || c > 126) { 216 Append("\\x%02x", c); 217 } else if (c == ',') { 218 Append("\\,"); 219 } else if (c == '\\') { 220 Append("\\\\"); 221 } else if (c == '\"') { 222 Append("\"\""); 223 } else { 224 Append("%lc", c); 225 } 226 } 227 } 228 229 230 void Log::MessageBuilder::AppendStringPart(const char* str, int len) { 231 if (pos_ + len > Log::kMessageBufferSize) { 232 len = Log::kMessageBufferSize - pos_; 233 ASSERT(len >= 0); 234 if (len == 0) return; 235 } 236 Vector<char> buf(log_->message_buffer_ + pos_, 237 Log::kMessageBufferSize - pos_); 238 OS::StrNCpy(buf, str, len); 239 pos_ += len; 240 ASSERT(pos_ <= Log::kMessageBufferSize); 241 } 242 243 244 void Log::MessageBuilder::WriteToLogFile() { 245 ASSERT(pos_ <= Log::kMessageBufferSize); 246 const int written = log_->WriteToFile(log_->message_buffer_, pos_); 247 if (written != pos_) { 248 log_->stop(); 249 log_->logger_->LogFailure(); 250 } 251 } 252 253 254 } } // namespace v8::internal 255