blob: ca1c86ed7f610bf06d5c1449cfb185a535985077 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2005, Google Inc.
3// All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004//
Austin Schuh745610d2015-09-06 18:19:50 -07005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008//
Austin Schuh745610d2015-09-06 18:19:50 -07009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
Brian Silverman20350ac2021-11-17 18:19:55 -080018//
Austin Schuh745610d2015-09-06 18:19:50 -070019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Sanjay Ghemawat <opensource@google.com>
33
34#include <config.h>
35#include "internal_logging.h"
36#include <stdarg.h> // for va_end, va_start
37#include <stdio.h> // for vsnprintf, va_list, etc
38#include <stdlib.h> // for abort
39#include <string.h> // for strlen, memcpy
40#ifdef HAVE_UNISTD_H
41#include <unistd.h> // for write()
42#endif
43
44#include <gperftools/malloc_extension.h>
45#include "base/logging.h" // for perftools_vsnprintf
46#include "base/spinlock.h" // for SpinLockHolder, SpinLock
47
Austin Schuh745610d2015-09-06 18:19:50 -070048// Variables for storing crash output. Allocated statically since we
49// may not be able to heap-allocate while crashing.
50static SpinLock crash_lock(base::LINKER_INITIALIZED);
51static bool crashed = false;
52static const int kStatsBufferSize = 16 << 10;
53static char stats_buffer[kStatsBufferSize] = { 0 };
54
55namespace tcmalloc {
56
57static void WriteMessage(const char* msg, int length) {
58 write(STDERR_FILENO, msg, length);
59}
60
61void (*log_message_writer)(const char* msg, int length) = WriteMessage;
62
63
64class Logger {
65 public:
66 bool Add(const LogItem& item);
67 bool AddStr(const char* str, int n);
68 bool AddNum(uint64_t num, int base); // base must be 10 or 16.
69
70 static const int kBufSize = 200;
71 char* p_;
72 char* end_;
73 char buf_[kBufSize];
74};
75
76void Log(LogMode mode, const char* filename, int line,
77 LogItem a, LogItem b, LogItem c, LogItem d) {
78 Logger state;
79 state.p_ = state.buf_;
80 state.end_ = state.buf_ + sizeof(state.buf_);
81 state.AddStr(filename, strlen(filename))
82 && state.AddStr(":", 1)
83 && state.AddNum(line, 10)
84 && state.AddStr("]", 1)
85 && state.Add(a)
86 && state.Add(b)
87 && state.Add(c)
88 && state.Add(d);
89
90 // Teminate with newline
91 if (state.p_ >= state.end_) {
92 state.p_ = state.end_ - 1;
93 }
94 *state.p_ = '\n';
95 state.p_++;
96
97 int msglen = state.p_ - state.buf_;
98 if (mode == kLog) {
99 (*log_message_writer)(state.buf_, msglen);
100 return;
101 }
102
103 bool first_crash = false;
104 {
105 SpinLockHolder l(&crash_lock);
106 if (!crashed) {
107 crashed = true;
108 first_crash = true;
109 }
110 }
111
112 (*log_message_writer)(state.buf_, msglen);
113 if (first_crash && mode == kCrashWithStats) {
114 MallocExtension::instance()->GetStats(stats_buffer, kStatsBufferSize);
115 (*log_message_writer)(stats_buffer, strlen(stats_buffer));
116 }
117
118 abort();
119}
120
121bool Logger::Add(const LogItem& item) {
122 // Separate items with spaces
123 if (p_ < end_) {
124 *p_ = ' ';
125 p_++;
126 }
127
128 switch (item.tag_) {
129 case LogItem::kStr:
130 return AddStr(item.u_.str, strlen(item.u_.str));
131 case LogItem::kUnsigned:
132 return AddNum(item.u_.unum, 10);
133 case LogItem::kSigned:
134 if (item.u_.snum < 0) {
135 // The cast to uint64_t is intentionally before the negation
136 // so that we do not attempt to negate -2^63.
137 return AddStr("-", 1)
138 && AddNum(- static_cast<uint64_t>(item.u_.snum), 10);
139 } else {
140 return AddNum(static_cast<uint64_t>(item.u_.snum), 10);
141 }
142 case LogItem::kPtr:
143 return AddStr("0x", 2)
144 && AddNum(reinterpret_cast<uintptr_t>(item.u_.ptr), 16);
145 default:
146 return false;
147 }
148}
149
150bool Logger::AddStr(const char* str, int n) {
151 if (end_ - p_ < n) {
152 return false;
153 } else {
154 memcpy(p_, str, n);
155 p_ += n;
156 return true;
157 }
158}
159
160bool Logger::AddNum(uint64_t num, int base) {
161 static const char kDigits[] = "0123456789abcdef";
162 char space[22]; // more than enough for 2^64 in smallest supported base (10)
163 char* end = space + sizeof(space);
164 char* pos = end;
165 do {
166 pos--;
167 *pos = kDigits[num % base];
168 num /= base;
169 } while (num > 0 && pos > space);
170 return AddStr(pos, end - pos);
171}
172
173} // end tcmalloc namespace
174
175void TCMalloc_Printer::printf(const char* format, ...) {
176 if (left_ > 0) {
177 va_list ap;
178 va_start(ap, format);
179 const int r = perftools_vsnprintf(buf_, left_, format, ap);
180 va_end(ap);
181 if (r < 0) {
182 // Perhaps an old glibc that returns -1 on truncation?
183 left_ = 0;
184 } else if (r > left_) {
185 // Truncation
186 left_ = 0;
187 } else {
188 left_ -= r;
189 buf_ += r;
190 }
191 }
192}