blob: 712c02bcd7e291d583989975b7f4fd0b7f63ee86 [file] [log] [blame]
Elliott Hughes13f5a582011-09-06 13:39:14 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "logging.h"
18
19#include "runtime.h"
Elliott Hughes5fe594f2011-09-08 12:33:17 -070020#include "thread.h"
Elliott Hughes13f5a582011-09-06 13:39:14 -070021#include "utils.h"
22
Elliott Hughesf5a7a472011-10-07 14:31:02 -070023namespace art {
Elliott Hughes5fe594f2011-09-08 12:33:17 -070024
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -080025LogVerbosity gLogVerbosity;
26
Elliott Hughes72395bf2012-04-24 13:45:26 -070027static LogSeverity gMinimumLogSeverity = INFO;
Elliott Hughes0d39c122012-06-06 16:41:17 -070028static std::string* gCmdLine;
29static std::string* gProgramInvocationName;
30static std::string* gProgramInvocationShortName;
Elliott Hughes72395bf2012-04-24 13:45:26 -070031
Elliott Hughes0d39c122012-06-06 16:41:17 -070032const char* GetCmdLine() {
33 return (gCmdLine != NULL) ? gCmdLine->c_str() : NULL;
34}
35
36const char* ProgramInvocationName() {
37 return (gProgramInvocationName != NULL) ? gProgramInvocationName->c_str() : "art";
38}
39
40const char* ProgramInvocationShortName() {
41 return (gProgramInvocationShortName != NULL) ? gProgramInvocationShortName->c_str() : "art";
42}
43
Elliott Hughes72395bf2012-04-24 13:45:26 -070044// Configure logging based on ANDROID_LOG_TAGS environment variable.
45// We need to parse a string that looks like
46//
47// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
48//
49// The tag (or '*' for the global level) comes first, followed by a colon
50// and a letter indicating the minimum priority level we're expected to log.
51// This can be used to reveal or conceal logs with specific tags.
Elliott Hughes0d39c122012-06-06 16:41:17 -070052void InitLogging(char* argv[]) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070053 // TODO: Move this to a more obvious InitART...
54 GlobalSynchronization::Init();
55
Elliott Hughes0d39c122012-06-06 16:41:17 -070056 // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
57 // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
58 // commonly used.
59 gCmdLine = new std::string(argv[0]);
60 for (size_t i = 1; argv[i] != NULL; ++i) {
61 gCmdLine->append(" ");
62 gCmdLine->append(argv[i]);
63 }
64 gProgramInvocationName = new std::string(argv[0]);
65 const char* last_slash = strrchr(argv[0], '/');
66 gProgramInvocationShortName = new std::string((last_slash != NULL) ? last_slash + 1 : argv[0]);
67
Elliott Hughes72395bf2012-04-24 13:45:26 -070068 const char* tags = getenv("ANDROID_LOG_TAGS");
69 if (tags == NULL) {
70 return;
71 }
72
73 std::vector<std::string> specs;
74 Split(tags, ' ', specs);
75 for (size_t i = 0; i < specs.size(); ++i) {
76 // "tag-pattern:[vdiwefs]"
77 std::string spec(specs[i]);
78 if (spec.size() == 3 && StartsWith(spec, "*:")) {
79 switch (spec[2]) {
80 case 'v': gMinimumLogSeverity = VERBOSE; continue;
81 case 'd': gMinimumLogSeverity = DEBUG; continue;
82 case 'i': gMinimumLogSeverity = INFO; continue;
83 case 'w': gMinimumLogSeverity = WARNING; continue;
84 case 'e': gMinimumLogSeverity = ERROR; continue;
85 case 'f': gMinimumLogSeverity = FATAL; continue;
86 // liblog will even suppress FATAL if you say 's' for silent, but that's crazy!
87 case 's': gMinimumLogSeverity = FATAL; continue;
88 }
89 }
90 LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags << ")";
91 }
92}
93
Elliott Hughes13f5a582011-09-06 13:39:14 -070094LogMessage::~LogMessage() {
Elliott Hughes72395bf2012-04-24 13:45:26 -070095 if (data_->severity < gMinimumLogSeverity) {
96 return; // No need to format something we're not going to output.
97 }
98
Elliott Hughes5fe594f2011-09-08 12:33:17 -070099 // Finish constructing the message.
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700100 if (data_->error != -1) {
101 data_->buffer << ": " << strerror(data_->error);
Elliott Hughes13f5a582011-09-06 13:39:14 -0700102 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700103 std::string msg(data_->buffer.str());
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700104
105 // Do the actual logging with the lock held.
106 {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700107 MutexLock mu(*GlobalSynchronization::logging_lock_);
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700108 if (msg.find('\n') == std::string::npos) {
109 LogLine(msg.c_str());
110 } else {
111 msg += '\n';
112 size_t i = 0;
113 while (i < msg.size()) {
114 size_t nl = msg.find('\n', i);
115 msg[nl] = '\0';
116 LogLine(&msg[i]);
117 i = nl + 1;
118 }
Elliott Hughes13f5a582011-09-06 13:39:14 -0700119 }
120 }
121
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700122 // Abort if necessary.
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700123 if (data_->severity == FATAL) {
Elliott Hughes8593fdb2012-04-21 20:53:44 -0700124 Runtime::Abort();
Elliott Hughes13f5a582011-09-06 13:39:14 -0700125 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700126
127 delete data_;
Elliott Hughes13f5a582011-09-06 13:39:14 -0700128}
129
130std::ostream& LogMessage::stream() {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700131 return data_->buffer;
Elliott Hughes13f5a582011-09-06 13:39:14 -0700132}
Elliott Hughesf5a7a472011-10-07 14:31:02 -0700133
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700134HexDump::HexDump(const void* address, size_t byte_count, bool show_actual_addresses)
135 : address_(address), byte_count_(byte_count), show_actual_addresses_(show_actual_addresses) {
136}
137
138void HexDump::Dump(std::ostream& os) const {
139 if (byte_count_ == 0) {
140 return;
141 }
142
Brian Carlstrom93235f72012-03-29 22:48:15 -0700143 if (address_ == NULL) {
144 os << "00000000:";
145 return;
146 }
147
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700148 static const char gHexDigit[] = "0123456789abcdef";
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700149 const unsigned char* addr = reinterpret_cast<const unsigned char*>(address_);
Elliott Hughes21f32d72011-11-09 17:44:13 -0800150 char out[76]; /* exact fit */
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700151 unsigned int offset; /* offset to show while printing */
152
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700153 if (show_actual_addresses_) {
Elliott Hughes398f64b2012-03-26 18:05:48 -0700154 offset = reinterpret_cast<int>(addr);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700155 } else {
156 offset = 0;
157 }
158 memset(out, ' ', sizeof(out)-1);
159 out[8] = ':';
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700160 out[sizeof(out)-1] = '\0';
161
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700162 size_t byte_count = byte_count_;
Elliott Hughes398f64b2012-03-26 18:05:48 -0700163 int gap = static_cast<int>(offset & 0x0f);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700164 while (byte_count) {
Elliott Hughes24edeb52012-06-18 15:29:46 -0700165 unsigned int line_offset = offset & ~0x0f;
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700166
167 char* hex = out;
168 char* asc = out + 59;
169
Elliott Hughes398f64b2012-03-26 18:05:48 -0700170 for (int i = 0; i < 8; i++) {
Elliott Hughes24edeb52012-06-18 15:29:46 -0700171 *hex++ = gHexDigit[line_offset >> 28];
172 line_offset <<= 4;
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700173 }
174 hex++;
175 hex++;
176
Elliott Hughes398f64b2012-03-26 18:05:48 -0700177 int count = std::min(static_cast<int>(byte_count), 16 - gap);
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700178 CHECK_NE(count, 0);
179 CHECK_LE(count + gap, 16);
180
181 if (gap) {
182 /* only on first line */
183 hex += gap * 3;
184 asc += gap;
185 }
186
Elliott Hughes398f64b2012-03-26 18:05:48 -0700187 int i;
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700188 for (i = gap ; i < count+gap; i++) {
189 *hex++ = gHexDigit[*addr >> 4];
190 *hex++ = gHexDigit[*addr & 0x0f];
191 hex++;
Elliott Hughes398f64b2012-03-26 18:05:48 -0700192 if (*addr >= 0x20 && *addr < 0x7f /*isprint(*addr)*/) {
193 *asc++ = *addr;
194 } else {
195 *asc++ = '.';
196 }
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700197 addr++;
198 }
Elliott Hughes398f64b2012-03-26 18:05:48 -0700199 for (; i < 16; i++) {
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700200 /* erase extra stuff; only happens on last line */
201 *hex++ = ' ';
202 *hex++ = ' ';
203 hex++;
204 *asc++ = ' ';
205 }
206
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700207 os << out;
Elliott Hughes872d4ec2011-10-21 17:07:15 -0700208
209 gap = 0;
210 byte_count -= count;
211 offset += count;
212 }
213}
214
Elliott Hughesbfbf0e22012-03-29 18:09:19 -0700215std::ostream& operator<<(std::ostream& os, const HexDump& rhs) {
216 rhs.Dump(os);
217 return os;
218}
219
Elliott Hughesf5a7a472011-10-07 14:31:02 -0700220} // namespace art