| OLD | NEW |
| 1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 #include <config.h> | 33 #include <config.h> |
| 34 #include "internal_logging.h" | 34 #include "internal_logging.h" |
| 35 #include <stdarg.h> // for va_end, va_start | 35 #include <stdarg.h> // for va_end, va_start |
| 36 #include <stdio.h> // for vsnprintf, va_list, etc | 36 #include <stdio.h> // for vsnprintf, va_list, etc |
| 37 #include <stdlib.h> // for abort | 37 #include <stdlib.h> // for abort |
| 38 #include <string.h> // for strlen, memcpy | 38 #include <string.h> // for strlen, memcpy |
| 39 #ifdef HAVE_UNISTD_H | 39 #ifdef HAVE_UNISTD_H |
| 40 #include <unistd.h> // for write() | 40 #include <unistd.h> // for write() |
| 41 #endif | 41 #endif |
| 42 | 42 |
| 43 #include <gperftools/malloc_extension.h> | 43 #include <google/malloc_extension.h> |
| 44 #include "base/logging.h" // for perftools_vsnprintf | 44 #include "base/logging.h" // for perftools_vsnprintf |
| 45 #include "base/spinlock.h" // for SpinLockHolder, SpinLock | 45 #include "base/spinlock.h" // for SpinLockHolder, SpinLock |
| 46 | 46 |
| 47 static const int kLogBufSize = 800; | 47 static const int kLogBufSize = 800; |
| 48 | 48 |
| 49 // Variables for storing crash output. Allocated statically since we | 49 void TCMalloc_MESSAGE(const char* filename, |
| 50 // may not be able to heap-allocate while crashing. | 50 int line_number, |
| 51 static SpinLock crash_lock(base::LINKER_INITIALIZED); | 51 const char* format, ...) { |
| 52 static bool crashed = false; | 52 char buf[kLogBufSize]; |
| 53 const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number); |
| 54 if (n < kLogBufSize) { |
| 55 va_list ap; |
| 56 va_start(ap, format); |
| 57 perftools_vsnprintf(buf + n, kLogBufSize - n, format, ap); |
| 58 va_end(ap); |
| 59 } |
| 60 write(STDERR_FILENO, buf, strlen(buf)); |
| 61 } |
| 62 |
| 53 static const int kStatsBufferSize = 16 << 10; | 63 static const int kStatsBufferSize = 16 << 10; |
| 54 static char stats_buffer[kStatsBufferSize] = { 0 }; | 64 static char stats_buffer[kStatsBufferSize] = { 0 }; |
| 55 | 65 |
| 56 namespace tcmalloc { | 66 static void TCMalloc_CRASH_internal(bool dump_stats, |
| 57 | 67 const char* filename, |
| 58 static void WriteMessage(const char* msg, int length) { | 68 int line_number, |
| 59 write(STDERR_FILENO, msg, length); | 69 const char* format, va_list ap) { |
| 60 } | 70 char buf[kLogBufSize]; |
| 61 | 71 const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number); |
| 62 void (*log_message_writer)(const char* msg, int length) = WriteMessage; | 72 if (n < kLogBufSize) { |
| 63 | 73 perftools_vsnprintf(buf + n, kLogBufSize - n, format, ap); |
| 64 | |
| 65 class Logger { | |
| 66 public: | |
| 67 bool Add(const LogItem& item); | |
| 68 bool AddStr(const char* str, int n); | |
| 69 bool AddNum(uint64_t num, int base); // base must be 10 or 16. | |
| 70 | |
| 71 static const int kBufSize = 200; | |
| 72 char* p_; | |
| 73 char* end_; | |
| 74 char buf_[kBufSize]; | |
| 75 }; | |
| 76 | |
| 77 void Log(LogMode mode, const char* filename, int line, | |
| 78 LogItem a, LogItem b, LogItem c, LogItem d) { | |
| 79 Logger state; | |
| 80 state.p_ = state.buf_; | |
| 81 state.end_ = state.buf_ + sizeof(state.buf_); | |
| 82 state.AddStr(filename, strlen(filename)) | |
| 83 && state.AddStr(":", 1) | |
| 84 && state.AddNum(line, 10) | |
| 85 && state.AddStr("]", 1) | |
| 86 && state.Add(a) | |
| 87 && state.Add(b) | |
| 88 && state.Add(c) | |
| 89 && state.Add(d); | |
| 90 | |
| 91 // Teminate with newline | |
| 92 if (state.p_ >= state.end_) { | |
| 93 state.p_ = state.end_ - 1; | |
| 94 } | 74 } |
| 95 *state.p_ = '\n'; | 75 write(STDERR_FILENO, buf, strlen(buf)); |
| 96 state.p_++; | 76 if (dump_stats) { |
| 97 | |
| 98 int msglen = state.p_ - state.buf_; | |
| 99 if (mode == kLog) { | |
| 100 (*log_message_writer)(state.buf_, msglen); | |
| 101 return; | |
| 102 } | |
| 103 | |
| 104 bool first_crash = false; | |
| 105 { | |
| 106 SpinLockHolder l(&crash_lock); | |
| 107 if (!crashed) { | |
| 108 crashed = true; | |
| 109 first_crash = true; | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 (*log_message_writer)(state.buf_, msglen); | |
| 114 if (first_crash && mode == kCrashWithStats) { | |
| 115 MallocExtension::instance()->GetStats(stats_buffer, kStatsBufferSize); | 77 MallocExtension::instance()->GetStats(stats_buffer, kStatsBufferSize); |
| 116 (*log_message_writer)(stats_buffer, strlen(stats_buffer)); | 78 write(STDERR_FILENO, stats_buffer, strlen(stats_buffer)); |
| 117 } | 79 } |
| 118 | 80 |
| 119 abort(); | 81 abort(); |
| 120 } | 82 } |
| 121 | 83 |
| 122 bool Logger::Add(const LogItem& item) { | 84 void TCMalloc_CRASH(bool dump_stats, |
| 123 // Separate items with spaces | 85 const char* filename, |
| 124 if (p_ < end_) { | 86 int line_number, |
| 125 *p_ = ' '; | 87 const char* format, ...) { |
| 126 p_++; | 88 va_list ap; |
| 127 } | 89 va_start(ap, format); |
| 128 | 90 TCMalloc_CRASH_internal(dump_stats, filename, line_number, format, ap); |
| 129 switch (item.tag_) { | 91 va_end(ap); |
| 130 case LogItem::kStr: | |
| 131 return AddStr(item.u_.str, strlen(item.u_.str)); | |
| 132 case LogItem::kUnsigned: | |
| 133 return AddNum(item.u_.unum, 10); | |
| 134 case LogItem::kSigned: | |
| 135 if (item.u_.snum < 0) { | |
| 136 // The cast to uint64_t is intentionally before the negation | |
| 137 // so that we do not attempt to negate -2^63. | |
| 138 return AddStr("-", 1) | |
| 139 && AddNum(- static_cast<uint64_t>(item.u_.snum), 10); | |
| 140 } else { | |
| 141 return AddNum(static_cast<uint64_t>(item.u_.snum), 10); | |
| 142 } | |
| 143 case LogItem::kPtr: | |
| 144 return AddStr("0x", 2) | |
| 145 && AddNum(reinterpret_cast<uintptr_t>(item.u_.ptr), 16); | |
| 146 default: | |
| 147 return false; | |
| 148 } | |
| 149 } | 92 } |
| 150 | 93 |
| 151 bool Logger::AddStr(const char* str, int n) { | 94 |
| 152 if (end_ - p_ < n) { | 95 void TCMalloc_CrashReporter::PrintfAndDie(const char* format, ...) { |
| 153 return false; | 96 va_list ap; |
| 154 } else { | 97 va_start(ap, format); |
| 155 memcpy(p_, str, n); | 98 TCMalloc_CRASH_internal(dump_stats_, file_, line_, format, ap); |
| 156 p_ += n; | 99 va_end(ap); |
| 157 return true; | |
| 158 } | |
| 159 } | 100 } |
| 160 | 101 |
| 161 bool Logger::AddNum(uint64_t num, int base) { | |
| 162 static const char kDigits[] = "0123456789abcdef"; | |
| 163 char space[22]; // more than enough for 2^64 in smallest supported base (10) | |
| 164 char* end = space + sizeof(space); | |
| 165 char* pos = end; | |
| 166 do { | |
| 167 pos--; | |
| 168 *pos = kDigits[num % base]; | |
| 169 num /= base; | |
| 170 } while (num > 0 && pos > space); | |
| 171 return AddStr(pos, end - pos); | |
| 172 } | |
| 173 | |
| 174 } // end tcmalloc namespace | |
| 175 | |
| 176 void TCMalloc_Printer::printf(const char* format, ...) { | 102 void TCMalloc_Printer::printf(const char* format, ...) { |
| 177 if (left_ > 0) { | 103 if (left_ > 0) { |
| 178 va_list ap; | 104 va_list ap; |
| 179 va_start(ap, format); | 105 va_start(ap, format); |
| 180 const int r = perftools_vsnprintf(buf_, left_, format, ap); | 106 const int r = perftools_vsnprintf(buf_, left_, format, ap); |
| 181 va_end(ap); | 107 va_end(ap); |
| 182 if (r < 0) { | 108 if (r < 0) { |
| 183 // Perhaps an old glibc that returns -1 on truncation? | 109 // Perhaps an old glibc that returns -1 on truncation? |
| 184 left_ = 0; | 110 left_ = 0; |
| 185 } else if (r > left_) { | 111 } else if (r > left_) { |
| 186 // Truncation | 112 // Truncation |
| 187 left_ = 0; | 113 left_ = 0; |
| 188 } else { | 114 } else { |
| 189 left_ -= r; | 115 left_ -= r; |
| 190 buf_ += r; | 116 buf_ += r; |
| 191 } | 117 } |
| 192 } | 118 } |
| 193 } | 119 } |
| OLD | NEW |