1 /*
2 * Copyright (C) 2020 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 <errno.h>
18 #include <signal.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <memory>
24 #include <mutex>
25 #include <string>
26 #include <vector>
27
28 #include <android-base/errno_restorer.h>
29 #include <android-base/threads.h>
30
31 #include <unwindstack/Log.h>
32 #include <unwindstack/Regs.h>
33 #include <unwindstack/Unwinder.h>
34
35 #include "ThreadEntry.h"
36
37 namespace unwindstack {
38
SignalLogOnly(int,siginfo_t *,void *)39 static void SignalLogOnly(int, siginfo_t*, void*) {
40 android::base::ErrnoRestorer restore;
41
42 log_async_safe("pid %d, tid %d: Received a spurious thread signal\n", getpid(),
43 static_cast<int>(android::base::GetThreadId()));
44 }
45
SignalHandler(int,siginfo_t *,void * sigcontext)46 static void SignalHandler(int, siginfo_t*, void* sigcontext) {
47 android::base::ErrnoRestorer restore;
48
49 ThreadEntry* entry = ThreadEntry::Get(android::base::GetThreadId(), false);
50 if (!entry) {
51 return;
52 }
53
54 entry->CopyUcontextFromSigcontext(sigcontext);
55
56 // Indicate the ucontext is now valid.
57 entry->Wake();
58 // Pause the thread until the unwind is complete. This avoids having
59 // the thread run ahead causing problems.
60 // The number indicates that we are waiting for the second Wake() call
61 // overall which is made by the thread requesting an unwind.
62 if (entry->Wait(WAIT_FOR_UNWIND_TO_COMPLETE)) {
63 // Do not remove the entry here because that can result in a deadlock
64 // if the code cannot properly send a signal to the thread under test.
65 entry->Wake();
66 } else {
67 // At this point, it is possible that entry has been freed, so just exit.
68 log_async_safe("Timed out waiting for unwind thread to indicate it completed.");
69 }
70 }
71
ThreadUnwinder(size_t max_frames,Maps * maps)72 ThreadUnwinder::ThreadUnwinder(size_t max_frames, Maps* maps)
73 : UnwinderFromPid(max_frames, getpid(), Regs::CurrentArch(), maps) {}
74
ThreadUnwinder(size_t max_frames,const ThreadUnwinder * unwinder)75 ThreadUnwinder::ThreadUnwinder(size_t max_frames, const ThreadUnwinder* unwinder)
76 : UnwinderFromPid(max_frames, getpid(), Regs::CurrentArch()) {
77 process_memory_ = unwinder->process_memory_;
78 maps_ = unwinder->maps_;
79 jit_debug_ = unwinder->jit_debug_;
80 dex_files_ = unwinder->dex_files_;
81 initted_ = unwinder->initted_;
82 }
83
SendSignalToThread(int signal,pid_t tid)84 ThreadEntry* ThreadUnwinder::SendSignalToThread(int signal, pid_t tid) {
85 static std::mutex action_mutex;
86 std::lock_guard<std::mutex> guard(action_mutex);
87
88 ThreadEntry* entry = ThreadEntry::Get(tid);
89 entry->Lock();
90 struct sigaction new_action = {.sa_sigaction = SignalHandler,
91 .sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK};
92 struct sigaction old_action = {};
93 sigemptyset(&new_action.sa_mask);
94 if (sigaction(signal, &new_action, &old_action) != 0) {
95 log_async_safe("sigaction failed: %s", strerror(errno));
96 ThreadEntry::Remove(entry);
97 last_error_.code = ERROR_SYSTEM_CALL;
98 return nullptr;
99 }
100
101 if (tgkill(getpid(), tid, signal) != 0) {
102 // Do not emit an error message, this might be expected. Set the
103 // error and let the caller decide.
104 if (errno == ESRCH) {
105 last_error_.code = ERROR_THREAD_DOES_NOT_EXIST;
106 } else {
107 last_error_.code = ERROR_SYSTEM_CALL;
108 }
109
110 sigaction(signal, &old_action, nullptr);
111 ThreadEntry::Remove(entry);
112 return nullptr;
113 }
114
115 // Wait for the thread to get the ucontext. The number indicates
116 // that we are waiting for the first Wake() call made by the thread.
117 bool wait_completed = entry->Wait(WAIT_FOR_UCONTEXT);
118 if (wait_completed) {
119 return entry;
120 }
121
122 if (old_action.sa_sigaction == nullptr) {
123 // If the wait failed, it could be that the signal could not be delivered
124 // within the timeout. Add a signal handler that's simply going to log
125 // something so that we don't crash if the signal eventually gets
126 // delivered. Only do this if there isn't already an action set up.
127 struct sigaction log_action = {.sa_sigaction = SignalLogOnly,
128 .sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK};
129 sigemptyset(&log_action.sa_mask);
130 sigaction(signal, &log_action, nullptr);
131 } else {
132 sigaction(signal, &old_action, nullptr);
133 }
134
135 // Check to see if the thread has disappeared.
136 if (tgkill(getpid(), tid, 0) == -1 && errno == ESRCH) {
137 last_error_.code = ERROR_THREAD_DOES_NOT_EXIST;
138 } else {
139 last_error_.code = ERROR_THREAD_TIMEOUT;
140 log_async_safe("Timed out waiting for signal handler to get ucontext data.");
141 }
142
143 ThreadEntry::Remove(entry);
144
145 return nullptr;
146 }
147
UnwindWithSignal(int signal,pid_t tid,const std::vector<std::string> * initial_map_names_to_skip,const std::vector<std::string> * map_suffixes_to_ignore)148 void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid,
149 const std::vector<std::string>* initial_map_names_to_skip,
150 const std::vector<std::string>* map_suffixes_to_ignore) {
151 ClearErrors();
152 if (tid == pid_) {
153 last_error_.code = ERROR_UNSUPPORTED;
154 return;
155 }
156
157 if (!Init()) {
158 return;
159 }
160
161 ThreadEntry* entry = SendSignalToThread(signal, tid);
162 if (entry == nullptr) {
163 return;
164 }
165
166 std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), entry->GetUcontext()));
167 SetRegs(regs.get());
168 UnwinderFromPid::Unwind(initial_map_names_to_skip, map_suffixes_to_ignore);
169
170 // Tell the signal handler to exit and release the entry.
171 entry->Wake();
172
173 // Wait for the thread to indicate it is done with the ThreadEntry.
174 if (!entry->Wait(WAIT_FOR_THREAD_TO_RESTART)) {
175 // Send a warning, but do not mark as a failure to unwind.
176 log_async_safe("Timed out waiting for signal handler to indicate it finished.");
177 }
178
179 ThreadEntry::Remove(entry);
180 }
181
182 } // namespace unwindstack
183