// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- // Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Sanjay Ghemawat #include #include "internal_logging.h" #include // for va_end, va_start #include // for vsnprintf, va_list, etc #include // for abort #include // for strlen, memcpy #ifdef HAVE_UNISTD_H #include // for write() #endif #include #include "base/logging.h" // for perftools_vsnprintf #include "base/spinlock.h" // for SpinLockHolder, SpinLock // Variables for storing crash output. Allocated statically since we // may not be able to heap-allocate while crashing. static SpinLock crash_lock(base::LINKER_INITIALIZED); static bool crashed = false; static const int kStatsBufferSize = 16 << 10; static char stats_buffer[kStatsBufferSize] = { 0 }; namespace tcmalloc { static void WriteMessage(const char* msg, int length) { write(STDERR_FILENO, msg, length); } void (*log_message_writer)(const char* msg, int length) = WriteMessage; class Logger { public: bool Add(const LogItem& item); bool AddStr(const char* str, int n); bool AddNum(uint64_t num, int base); // base must be 10 or 16. static const int kBufSize = 200; char* p_; char* end_; char buf_[kBufSize]; }; void Log(LogMode mode, const char* filename, int line, LogItem a, LogItem b, LogItem c, LogItem d) { Logger state; state.p_ = state.buf_; state.end_ = state.buf_ + sizeof(state.buf_); state.AddStr(filename, strlen(filename)) && state.AddStr(":", 1) && state.AddNum(line, 10) && state.AddStr("]", 1) && state.Add(a) && state.Add(b) && state.Add(c) && state.Add(d); // Teminate with newline if (state.p_ >= state.end_) { state.p_ = state.end_ - 1; } *state.p_ = '\n'; state.p_++; int msglen = state.p_ - state.buf_; if (mode == kLog) { (*log_message_writer)(state.buf_, msglen); return; } bool first_crash = false; { SpinLockHolder l(&crash_lock); if (!crashed) { crashed = true; first_crash = true; } } (*log_message_writer)(state.buf_, msglen); if (first_crash && mode == kCrashWithStats) { MallocExtension::instance()->GetStats(stats_buffer, kStatsBufferSize); (*log_message_writer)(stats_buffer, strlen(stats_buffer)); } abort(); } bool Logger::Add(const LogItem& item) { // Separate items with spaces if (p_ < end_) { *p_ = ' '; p_++; } switch (item.tag_) { case LogItem::kStr: return AddStr(item.u_.str, strlen(item.u_.str)); case LogItem::kUnsigned: return AddNum(item.u_.unum, 10); case LogItem::kSigned: if (item.u_.snum < 0) { // The cast to uint64_t is intentionally before the negation // so that we do not attempt to negate -2^63. return AddStr("-", 1) && AddNum(- static_cast(item.u_.snum), 10); } else { return AddNum(static_cast(item.u_.snum), 10); } case LogItem::kPtr: return AddStr("0x", 2) && AddNum(reinterpret_cast(item.u_.ptr), 16); default: return false; } } bool Logger::AddStr(const char* str, int n) { if (end_ - p_ < n) { return false; } else { memcpy(p_, str, n); p_ += n; return true; } } bool Logger::AddNum(uint64_t num, int base) { static const char kDigits[] = "0123456789abcdef"; char space[22]; // more than enough for 2^64 in smallest supported base (10) char* end = space + sizeof(space); char* pos = end; do { pos--; *pos = kDigits[num % base]; num /= base; } while (num > 0 && pos > space); return AddStr(pos, end - pos); } } // end tcmalloc namespace void TCMalloc_Printer::printf(const char* format, ...) { if (left_ > 0) { va_list ap; va_start(ap, format); const int r = perftools_vsnprintf(buf_, left_, format, ap); va_end(ap); if (r < 0) { // Perhaps an old glibc that returns -1 on truncation? left_ = 0; } else if (r > left_) { // Truncation left_ = 0; } else { left_ -= r; buf_ += r; } } }