11cb0ef41Sopenharmony_ci// Copyright 2009 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/logging/log-utils.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <atomic> 81cb0ef41Sopenharmony_ci#include <memory> 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h" 111cb0ef41Sopenharmony_ci#include "src/base/platform/platform.h" 121cb0ef41Sopenharmony_ci#include "src/base/strings.h" 131cb0ef41Sopenharmony_ci#include "src/base/vector.h" 141cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h" 151cb0ef41Sopenharmony_ci#include "src/common/globals.h" 161cb0ef41Sopenharmony_ci#include "src/execution/isolate-utils.h" 171cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 181cb0ef41Sopenharmony_ci#include "src/objects/string-inl.h" 191cb0ef41Sopenharmony_ci#include "src/strings/string-stream.h" 201cb0ef41Sopenharmony_ci#include "src/utils/version.h" 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cinamespace v8 { 231cb0ef41Sopenharmony_cinamespace internal { 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciconst char* const Log::kLogToTemporaryFile = "+"; 261cb0ef41Sopenharmony_ciconst char* const Log::kLogToConsole = "-"; 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci// static 291cb0ef41Sopenharmony_ciFILE* Log::CreateOutputHandle(std::string file_name) { 301cb0ef41Sopenharmony_ci // If we're logging anything, we need to open the log file. 311cb0ef41Sopenharmony_ci if (!FLAG_log) { 321cb0ef41Sopenharmony_ci return nullptr; 331cb0ef41Sopenharmony_ci } else if (Log::IsLoggingToConsole(file_name)) { 341cb0ef41Sopenharmony_ci return stdout; 351cb0ef41Sopenharmony_ci } else if (Log::IsLoggingToTemporaryFile(file_name)) { 361cb0ef41Sopenharmony_ci return base::OS::OpenTemporaryFile(); 371cb0ef41Sopenharmony_ci } else { 381cb0ef41Sopenharmony_ci return base::OS::FOpen(file_name.c_str(), base::OS::LogFileOpenMode); 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci// static 431cb0ef41Sopenharmony_cibool Log::IsLoggingToConsole(std::string file_name) { 441cb0ef41Sopenharmony_ci return file_name.compare(Log::kLogToConsole) == 0; 451cb0ef41Sopenharmony_ci} 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// static 481cb0ef41Sopenharmony_cibool Log::IsLoggingToTemporaryFile(std::string file_name) { 491cb0ef41Sopenharmony_ci return file_name.compare(Log::kLogToTemporaryFile) == 0; 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciLog::Log(Logger* logger, std::string file_name) 531cb0ef41Sopenharmony_ci : logger_(logger), 541cb0ef41Sopenharmony_ci file_name_(file_name), 551cb0ef41Sopenharmony_ci output_handle_(Log::CreateOutputHandle(file_name)), 561cb0ef41Sopenharmony_ci os_(output_handle_ == nullptr ? stdout : output_handle_), 571cb0ef41Sopenharmony_ci format_buffer_(NewArray<char>(kMessageBufferSize)) { 581cb0ef41Sopenharmony_ci if (output_handle_) WriteLogHeader(); 591cb0ef41Sopenharmony_ci} 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_civoid Log::WriteLogHeader() { 621cb0ef41Sopenharmony_ci Log::MessageBuilder msg(this); 631cb0ef41Sopenharmony_ci LogSeparator kNext = LogSeparator::kSeparator; 641cb0ef41Sopenharmony_ci msg << "v8-version" << kNext << Version::GetMajor() << kNext 651cb0ef41Sopenharmony_ci << Version::GetMinor() << kNext << Version::GetBuild() << kNext 661cb0ef41Sopenharmony_ci << Version::GetPatch(); 671cb0ef41Sopenharmony_ci if (strlen(Version::GetEmbedder()) != 0) { 681cb0ef41Sopenharmony_ci msg << kNext << Version::GetEmbedder(); 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci msg << kNext << Version::IsCandidate(); 711cb0ef41Sopenharmony_ci msg.WriteToLogFile(); 721cb0ef41Sopenharmony_ci msg << "v8-platform" << kNext << V8_OS_STRING << kNext << V8_TARGET_OS_STRING; 731cb0ef41Sopenharmony_ci msg.WriteToLogFile(); 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_cistd::unique_ptr<Log::MessageBuilder> Log::NewMessageBuilder() { 771cb0ef41Sopenharmony_ci // Fast check of is_logging() without taking the lock. Bail out immediately if 781cb0ef41Sopenharmony_ci // logging isn't enabled. 791cb0ef41Sopenharmony_ci if (!logger_->is_logging()) return {}; 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci std::unique_ptr<Log::MessageBuilder> result(new Log::MessageBuilder(this)); 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci // The first invocation of is_logging() might still read an old value. It is 841cb0ef41Sopenharmony_ci // fine if a background thread starts logging a bit later, but we want to 851cb0ef41Sopenharmony_ci // avoid background threads continue logging after logging was already closed. 861cb0ef41Sopenharmony_ci if (!logger_->is_logging()) return {}; 871cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(format_buffer_.get()); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci return result; 901cb0ef41Sopenharmony_ci} 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ciFILE* Log::Close() { 931cb0ef41Sopenharmony_ci FILE* result = nullptr; 941cb0ef41Sopenharmony_ci if (output_handle_ != nullptr) { 951cb0ef41Sopenharmony_ci fflush(output_handle_); 961cb0ef41Sopenharmony_ci result = output_handle_; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci output_handle_ = nullptr; 991cb0ef41Sopenharmony_ci format_buffer_.reset(); 1001cb0ef41Sopenharmony_ci return result; 1011cb0ef41Sopenharmony_ci} 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_cistd::string Log::file_name() const { return file_name_; } 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciLog::MessageBuilder::MessageBuilder(Log* log) 1061cb0ef41Sopenharmony_ci : log_(log), lock_guard_(&log_->mutex_) { 1071cb0ef41Sopenharmony_ci} 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendString(String str, 1101cb0ef41Sopenharmony_ci base::Optional<int> length_limit) { 1111cb0ef41Sopenharmony_ci if (str.is_null()) return; 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; // Ensure string stays valid. 1141cb0ef41Sopenharmony_ci PtrComprCageBase cage_base = GetPtrComprCageBase(str); 1151cb0ef41Sopenharmony_ci SharedStringAccessGuardIfNeeded access_guard(str); 1161cb0ef41Sopenharmony_ci int length = str.length(); 1171cb0ef41Sopenharmony_ci if (length_limit) length = std::min(length, *length_limit); 1181cb0ef41Sopenharmony_ci for (int i = 0; i < length; i++) { 1191cb0ef41Sopenharmony_ci uint16_t c = str.Get(i, cage_base, access_guard); 1201cb0ef41Sopenharmony_ci if (c <= 0xFF) { 1211cb0ef41Sopenharmony_ci AppendCharacter(static_cast<char>(c)); 1221cb0ef41Sopenharmony_ci } else { 1231cb0ef41Sopenharmony_ci // Escape non-ascii characters. 1241cb0ef41Sopenharmony_ci AppendRawFormatString("\\u%04x", c & 0xFFFF); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci } 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendString(base::Vector<const char> str) { 1301cb0ef41Sopenharmony_ci for (auto i = str.begin(); i < str.end(); i++) AppendCharacter(*i); 1311cb0ef41Sopenharmony_ci} 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendString(const char* str) { 1341cb0ef41Sopenharmony_ci if (str == nullptr) return; 1351cb0ef41Sopenharmony_ci AppendString(str, strlen(str)); 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendString(const char* str, size_t length, 1391cb0ef41Sopenharmony_ci bool is_one_byte) { 1401cb0ef41Sopenharmony_ci if (str == nullptr) return; 1411cb0ef41Sopenharmony_ci if (is_one_byte) { 1421cb0ef41Sopenharmony_ci for (size_t i = 0; i < length; i++) { 1431cb0ef41Sopenharmony_ci DCHECK_IMPLIES(is_one_byte, str[i] != '\0'); 1441cb0ef41Sopenharmony_ci AppendCharacter(str[i]); 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci } else { 1471cb0ef41Sopenharmony_ci DCHECK_EQ(length % 2, 0); 1481cb0ef41Sopenharmony_ci for (size_t i = 0; i + 1 < length; i += 2) { 1491cb0ef41Sopenharmony_ci AppendTwoByteCharacter(str[i], str[i + 1]); 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendFormatString(const char* format, ...) { 1551cb0ef41Sopenharmony_ci va_list args; 1561cb0ef41Sopenharmony_ci va_start(args, format); 1571cb0ef41Sopenharmony_ci const int length = FormatStringIntoBuffer(format, args); 1581cb0ef41Sopenharmony_ci va_end(args); 1591cb0ef41Sopenharmony_ci for (int i = 0; i < length; i++) { 1601cb0ef41Sopenharmony_ci DCHECK_NE(log_->format_buffer_[i], '\0'); 1611cb0ef41Sopenharmony_ci AppendCharacter(log_->format_buffer_[i]); 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendTwoByteCharacter(char c1, char c2) { 1661cb0ef41Sopenharmony_ci if (c2 == 0) { 1671cb0ef41Sopenharmony_ci AppendCharacter(c1); 1681cb0ef41Sopenharmony_ci } else { 1691cb0ef41Sopenharmony_ci // Escape non-printable characters. 1701cb0ef41Sopenharmony_ci AppendRawFormatString("\\u%02x%02x", c1 & 0xFF, c2 & 0xFF); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci} 1731cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendCharacter(char c) { 1741cb0ef41Sopenharmony_ci if (c >= 32 && c <= 126) { 1751cb0ef41Sopenharmony_ci if (c == ',') { 1761cb0ef41Sopenharmony_ci // Escape commas to avoid adding column separators. 1771cb0ef41Sopenharmony_ci AppendRawFormatString("\\x2C"); 1781cb0ef41Sopenharmony_ci } else if (c == '\\') { 1791cb0ef41Sopenharmony_ci AppendRawFormatString("\\\\"); 1801cb0ef41Sopenharmony_ci } else { 1811cb0ef41Sopenharmony_ci // Safe, printable ascii character. 1821cb0ef41Sopenharmony_ci AppendRawCharacter(c); 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci } else if (c == '\n') { 1851cb0ef41Sopenharmony_ci // Escape newlines to avoid adding row separators. 1861cb0ef41Sopenharmony_ci AppendRawFormatString("\\n"); 1871cb0ef41Sopenharmony_ci } else { 1881cb0ef41Sopenharmony_ci // Escape non-printable characters. 1891cb0ef41Sopenharmony_ci AppendRawFormatString("\\x%02x", c & 0xFF); 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci} 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendSymbolName(Symbol symbol) { 1941cb0ef41Sopenharmony_ci DCHECK(!symbol.is_null()); 1951cb0ef41Sopenharmony_ci OFStream& os = log_->os_; 1961cb0ef41Sopenharmony_ci os << "symbol("; 1971cb0ef41Sopenharmony_ci if (!symbol.description().IsUndefined()) { 1981cb0ef41Sopenharmony_ci os << "\""; 1991cb0ef41Sopenharmony_ci AppendSymbolNameDetails(String::cast(symbol.description()), false); 2001cb0ef41Sopenharmony_ci os << "\" "; 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci os << "hash " << std::hex << symbol.hash() << std::dec << ")"; 2031cb0ef41Sopenharmony_ci} 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendSymbolNameDetails(String str, 2061cb0ef41Sopenharmony_ci bool show_impl_info) { 2071cb0ef41Sopenharmony_ci if (str.is_null()) return; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; // Ensure string stays valid. 2101cb0ef41Sopenharmony_ci OFStream& os = log_->os_; 2111cb0ef41Sopenharmony_ci int limit = str.length(); 2121cb0ef41Sopenharmony_ci if (limit > 0x1000) limit = 0x1000; 2131cb0ef41Sopenharmony_ci if (show_impl_info) { 2141cb0ef41Sopenharmony_ci os << (str.IsOneByteRepresentation() ? 'a' : '2'); 2151cb0ef41Sopenharmony_ci if (StringShape(str).IsExternal()) os << 'e'; 2161cb0ef41Sopenharmony_ci if (StringShape(str).IsInternalized()) os << '#'; 2171cb0ef41Sopenharmony_ci os << ':' << str.length() << ':'; 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci AppendString(str, limit); 2201cb0ef41Sopenharmony_ci} 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ciint Log::MessageBuilder::FormatStringIntoBuffer(const char* format, 2231cb0ef41Sopenharmony_ci va_list args) { 2241cb0ef41Sopenharmony_ci base::Vector<char> buf(log_->format_buffer_.get(), Log::kMessageBufferSize); 2251cb0ef41Sopenharmony_ci int length = base::VSNPrintF(buf, format, args); 2261cb0ef41Sopenharmony_ci // |length| is -1 if output was truncated. 2271cb0ef41Sopenharmony_ci if (length == -1) length = Log::kMessageBufferSize; 2281cb0ef41Sopenharmony_ci DCHECK_LE(length, Log::kMessageBufferSize); 2291cb0ef41Sopenharmony_ci DCHECK_GE(length, 0); 2301cb0ef41Sopenharmony_ci return length; 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendRawFormatString(const char* format, ...) { 2341cb0ef41Sopenharmony_ci va_list args; 2351cb0ef41Sopenharmony_ci va_start(args, format); 2361cb0ef41Sopenharmony_ci const int length = FormatStringIntoBuffer(format, args); 2371cb0ef41Sopenharmony_ci va_end(args); 2381cb0ef41Sopenharmony_ci for (int i = 0; i < length; i++) { 2391cb0ef41Sopenharmony_ci DCHECK_NE(log_->format_buffer_[i], '\0'); 2401cb0ef41Sopenharmony_ci AppendRawCharacter(log_->format_buffer_[i]); 2411cb0ef41Sopenharmony_ci } 2421cb0ef41Sopenharmony_ci} 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_civoid Log::MessageBuilder::AppendRawCharacter(char c) { log_->os_ << c; } 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_civoid Log::MessageBuilder::WriteToLogFile() { 2471cb0ef41Sopenharmony_ci log_->os_ << std::endl; 2481cb0ef41Sopenharmony_ci} 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_citemplate <> 2511cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<const char*>( 2521cb0ef41Sopenharmony_ci const char* string) { 2531cb0ef41Sopenharmony_ci this->AppendString(string); 2541cb0ef41Sopenharmony_ci return *this; 2551cb0ef41Sopenharmony_ci} 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_citemplate <> 2581cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<void*>(void* pointer) { 2591cb0ef41Sopenharmony_ci OFStream& os = log_->os_; 2601cb0ef41Sopenharmony_ci // Manually format the pointer since on Windows we do not consistently 2611cb0ef41Sopenharmony_ci // get a "0x" prefix. 2621cb0ef41Sopenharmony_ci os << "0x" << std::hex << reinterpret_cast<intptr_t>(pointer) << std::dec; 2631cb0ef41Sopenharmony_ci return *this; 2641cb0ef41Sopenharmony_ci} 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_citemplate <> 2671cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<char>(char c) { 2681cb0ef41Sopenharmony_ci this->AppendCharacter(c); 2691cb0ef41Sopenharmony_ci return *this; 2701cb0ef41Sopenharmony_ci} 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_citemplate <> 2731cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<String>(String string) { 2741cb0ef41Sopenharmony_ci this->AppendString(string); 2751cb0ef41Sopenharmony_ci return *this; 2761cb0ef41Sopenharmony_ci} 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_citemplate <> 2791cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<Symbol>(Symbol symbol) { 2801cb0ef41Sopenharmony_ci this->AppendSymbolName(symbol); 2811cb0ef41Sopenharmony_ci return *this; 2821cb0ef41Sopenharmony_ci} 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_citemplate <> 2851cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<Name>(Name name) { 2861cb0ef41Sopenharmony_ci if (name.IsString()) { 2871cb0ef41Sopenharmony_ci this->AppendString(String::cast(name)); 2881cb0ef41Sopenharmony_ci } else { 2891cb0ef41Sopenharmony_ci this->AppendSymbolName(Symbol::cast(name)); 2901cb0ef41Sopenharmony_ci } 2911cb0ef41Sopenharmony_ci return *this; 2921cb0ef41Sopenharmony_ci} 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_citemplate <> 2951cb0ef41Sopenharmony_ciLog::MessageBuilder& Log::MessageBuilder::operator<<<LogSeparator>( 2961cb0ef41Sopenharmony_ci LogSeparator separator) { 2971cb0ef41Sopenharmony_ci // Skip escaping to create a new column. 2981cb0ef41Sopenharmony_ci this->AppendRawCharacter(','); 2991cb0ef41Sopenharmony_ci return *this; 3001cb0ef41Sopenharmony_ci} 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci} // namespace internal 3031cb0ef41Sopenharmony_ci} // namespace v8 304