blob: 8c5b3869324d76cd8688637e97720d28a8ce4794 [file] [log] [blame]
Andreas Gampe5dd44d02016-08-02 17:20:03 -07001/*
2 * Copyright (C) 2016 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 "native_stack_dump.h"
18
19#include <ostream>
20
21#include <stdio.h>
22
23#include "art_method.h"
24
25// For DumpNativeStack.
26#include <backtrace/Backtrace.h>
27#include <backtrace/BacktraceMap.h>
28
29#if defined(__linux__)
30
31#include <memory>
32#include <vector>
33
34#include <linux/unistd.h>
35#include <signal.h>
36#include <stdlib.h>
37#include <sys/time.h>
38#include <sys/types.h>
39
40#include "arch/instruction_set.h"
41#include "base/memory_tool.h"
42#include "base/mutex.h"
43#include "base/stringprintf.h"
44#include "oat_quick_method_header.h"
45#include "thread-inl.h"
46#include "utils.h"
47
48#endif
49
50namespace art {
51
52#if defined(__linux__)
53
54static constexpr bool kUseAddr2line = !kIsTargetBuild;
55
56ALWAYS_INLINE
57static inline void WritePrefix(std::ostream* os, const char* prefix, bool odd) {
58 if (prefix != nullptr) {
59 *os << prefix;
60 }
61 *os << " ";
62 if (!odd) {
63 *os << " ";
64 }
65}
66
67static bool RunCommand(std::string cmd, std::ostream* os, const char* prefix) {
68 FILE* stream = popen(cmd.c_str(), "r");
69 if (stream) {
70 if (os != nullptr) {
71 bool odd_line = true; // We indent them differently.
72 bool wrote_prefix = false; // Have we already written a prefix?
73 constexpr size_t kMaxBuffer = 128; // Relatively small buffer. Should be OK as we're on an
74 // alt stack, but just to be sure...
75 char buffer[kMaxBuffer];
76 while (!feof(stream)) {
77 if (fgets(buffer, kMaxBuffer, stream) != nullptr) {
78 // Split on newlines.
79 char* tmp = buffer;
80 for (;;) {
81 char* new_line = strchr(tmp, '\n');
82 if (new_line == nullptr) {
83 // Print the rest.
84 if (*tmp != 0) {
85 if (!wrote_prefix) {
86 WritePrefix(os, prefix, odd_line);
87 }
88 wrote_prefix = true;
89 *os << tmp;
90 }
91 break;
92 }
93 if (!wrote_prefix) {
94 WritePrefix(os, prefix, odd_line);
95 }
96 char saved = *(new_line + 1);
97 *(new_line + 1) = 0;
98 *os << tmp;
99 *(new_line + 1) = saved;
100 tmp = new_line + 1;
101 odd_line = !odd_line;
102 wrote_prefix = false;
103 }
104 }
105 }
106 }
107 pclose(stream);
108 return true;
109 } else {
110 return false;
111 }
112}
113
114static void Addr2line(const std::string& map_src, uintptr_t offset, std::ostream& os,
115 const char* prefix) {
116 std::string cmdline(StringPrintf("addr2line --functions --inlines --demangle -e %s %zx",
117 map_src.c_str(), offset));
118 RunCommand(cmdline.c_str(), &os, prefix);
119}
120
121static bool PcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) NO_THREAD_SAFETY_ANALYSIS {
122 uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer(
123 method->GetEntryPointFromQuickCompiledCode()));
124 if (code == 0) {
125 return pc == 0;
126 }
127 uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
128 return code <= pc && pc <= (code + code_size);
129}
130
131void DumpNativeStack(std::ostream& os, pid_t tid, BacktraceMap* existing_map, const char* prefix,
132 ArtMethod* current_method, void* ucontext_ptr) {
133 // b/18119146
134 if (RUNNING_ON_MEMORY_TOOL != 0) {
135 return;
136 }
137
138 BacktraceMap* map = existing_map;
139 std::unique_ptr<BacktraceMap> tmp_map;
140 if (map == nullptr) {
141 tmp_map.reset(BacktraceMap::Create(getpid()));
142 map = tmp_map.get();
143 }
144 std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid, map));
145 if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) {
146 os << prefix << "(backtrace::Unwind failed for thread " << tid
147 << ": " << backtrace->GetErrorString(backtrace->GetError()) << ")\n";
148 return;
149 } else if (backtrace->NumFrames() == 0) {
150 os << prefix << "(no native stack frames for thread " << tid << ")\n";
151 return;
152 }
153
154 // Check whether we have and should use addr2line.
155 bool use_addr2line;
156 if (kUseAddr2line) {
157 // Try to run it to see whether we have it. Push an argument so that it doesn't assume a.out
158 // and print to stderr.
159 use_addr2line = (gAborting > 0) && RunCommand("addr2line -h", nullptr, nullptr);
160 } else {
161 use_addr2line = false;
162 }
163
164 for (Backtrace::const_iterator it = backtrace->begin();
165 it != backtrace->end(); ++it) {
166 // We produce output like this:
167 // ] #00 pc 000075bb8 /system/lib/libc.so (unwind_backtrace_thread+536)
168 // In order for parsing tools to continue to function, the stack dump
169 // format must at least adhere to this format:
170 // #XX pc <RELATIVE_ADDR> <FULL_PATH_TO_SHARED_LIBRARY> ...
171 // The parsers require a single space before and after pc, and two spaces
172 // after the <RELATIVE_ADDR>. There can be any prefix data before the
173 // #XX. <RELATIVE_ADDR> has to be a hex number but with no 0x prefix.
174 os << prefix << StringPrintf("#%02zu pc ", it->num);
175 bool try_addr2line = false;
176 if (!BacktraceMap::IsValid(it->map)) {
177 os << StringPrintf(Is64BitInstructionSet(kRuntimeISA) ? "%016" PRIxPTR " ???"
178 : "%08" PRIxPTR " ???",
179 it->pc);
180 } else {
181 os << StringPrintf(Is64BitInstructionSet(kRuntimeISA) ? "%016" PRIxPTR " "
182 : "%08" PRIxPTR " ",
183 BacktraceMap::GetRelativePc(it->map, it->pc));
184 os << it->map.name;
185 os << " (";
186 if (!it->func_name.empty()) {
187 os << it->func_name;
188 if (it->func_offset != 0) {
189 os << "+" << it->func_offset;
190 }
191 try_addr2line = true;
192 } else if (current_method != nullptr &&
193 Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
194 PcIsWithinQuickCode(current_method, it->pc)) {
195 const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
196 os << JniLongName(current_method) << "+"
197 << (it->pc - reinterpret_cast<uintptr_t>(start_of_code));
198 } else {
199 os << "???";
200 }
201 os << ")";
202 }
203 os << "\n";
204 if (try_addr2line && use_addr2line) {
205 Addr2line(it->map.name, it->pc - it->map.start, os, prefix);
206 }
207 }
208}
209
210void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count) {
211 if (tid == GetTid()) {
212 // There's no point showing that we're reading our stack out of /proc!
213 return;
214 }
215
216 std::string kernel_stack_filename(StringPrintf("/proc/self/task/%d/stack", tid));
217 std::string kernel_stack;
218 if (!ReadFileToString(kernel_stack_filename, &kernel_stack)) {
219 os << prefix << "(couldn't read " << kernel_stack_filename << ")\n";
220 return;
221 }
222
223 std::vector<std::string> kernel_stack_frames;
224 Split(kernel_stack, '\n', &kernel_stack_frames);
225 // We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff",
226 // which looking at the source appears to be the kernel's way of saying "that's all, folks!".
227 kernel_stack_frames.pop_back();
228 for (size_t i = 0; i < kernel_stack_frames.size(); ++i) {
229 // Turn "[<ffffffff8109156d>] futex_wait_queue_me+0xcd/0x110"
230 // into "futex_wait_queue_me+0xcd/0x110".
231 const char* text = kernel_stack_frames[i].c_str();
232 const char* close_bracket = strchr(text, ']');
233 if (close_bracket != nullptr) {
234 text = close_bracket + 2;
235 }
236 os << prefix;
237 if (include_count) {
238 os << StringPrintf("#%02zd ", i);
239 }
240 os << text << "\n";
241 }
242}
243
244#elif defined(__APPLE__)
245
246void DumpNativeStack(std::ostream& os ATTRIBUTE_UNUSED,
247 pid_t tid ATTRIBUTE_UNUSED,
248 BacktraceMap* existing_map ATTRIBUTE_UNUSED,
249 const char* prefix ATTRIBUTE_UNUSED,
250 ArtMethod* current_method ATTRIBUTE_UNUSED,
251 void* ucontext_ptr ATTRIBUTE_UNUSED) {
252}
253
254void DumpKernelStack(std::ostream& os ATTRIBUTE_UNUSED,
255 pid_t tid ATTRIBUTE_UNUSED,
256 const char* prefix ATTRIBUTE_UNUSED,
257 bool include_count ATTRIBUTE_UNUSED) {
258}
259
260#else
261#error "Unsupported architecture for native stack dumps."
262#endif
263
264} // namespace art