• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <string.h>
19 
20 #include <signal.h>
21 #include <stdint.h>
22 #include <sys/ptrace.h>
23 #include <sys/syscall.h>
24 #include <unistd.h>
25 
26 #include <gtest/gtest.h>
27 
28 #include <atomic>
29 #include <memory>
30 #include <sstream>
31 #include <string>
32 #include <thread>
33 #include <vector>
34 
35 #include <unwindstack/Elf.h>
36 #include <unwindstack/MapInfo.h>
37 #include <unwindstack/Maps.h>
38 #include <unwindstack/Memory.h>
39 #include <unwindstack/Regs.h>
40 #include <unwindstack/RegsGetLocal.h>
41 
42 namespace unwindstack {
43 
44 static std::atomic_bool g_ready(false);
45 static volatile bool g_ready_for_remote = false;
46 static volatile bool g_signal_ready_for_remote = false;
47 static std::atomic_bool g_finish(false);
48 static std::atomic_uintptr_t g_ucontext;
49 
50 static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
51 
52 static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
53                                                      "SignalOuterFunction", "InnerFunction",
54                                                      "MiddleFunction",      "OuterFunction"};
55 
SignalHandler(int,siginfo_t *,void * sigcontext)56 static void SignalHandler(int, siginfo_t*, void* sigcontext) {
57   g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
58   while (!g_finish.load()) {
59   }
60 }
61 
SignalInnerFunction()62 extern "C" void SignalInnerFunction() {
63   g_signal_ready_for_remote = true;
64   while (!g_finish.load()) {
65   }
66 }
67 
SignalMiddleFunction()68 extern "C" void SignalMiddleFunction() {
69   SignalInnerFunction();
70 }
71 
SignalOuterFunction()72 extern "C" void SignalOuterFunction() {
73   SignalMiddleFunction();
74 }
75 
SignalCallerHandler(int,siginfo_t *,void *)76 static void SignalCallerHandler(int, siginfo_t*, void*) {
77   SignalOuterFunction();
78 }
79 
ErrorMsg(const std::vector<const char * > & function_names,size_t index,std::stringstream & unwind_stream)80 static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index,
81                             std::stringstream& unwind_stream) {
82   return std::string(
83              "Unwind completed without finding all frames\n"
84              "  Looking for function: ") +
85          function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
86 }
87 
VerifyUnwind(pid_t pid,Memory * memory,Maps * maps,Regs * regs,std::vector<const char * > & function_names)88 static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
89                          std::vector<const char*>& function_names) {
90   size_t function_name_index = 0;
91 
92   std::stringstream unwind_stream;
93   unwind_stream << std::hex;
94   for (size_t frame_num = 0; frame_num < 64; frame_num++) {
95     ASSERT_NE(0U, regs->pc()) << ErrorMsg(function_names, function_name_index, unwind_stream);
96     MapInfo* map_info = maps->Find(regs->pc());
97     ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
98 
99     Elf* elf = map_info->GetElf(pid, true);
100     uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
101     uint64_t adjusted_rel_pc = rel_pc;
102     if (frame_num != 0) {
103       adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
104     }
105     unwind_stream << "  PC: 0x" << regs->pc() << " Rel: 0x" << adjusted_rel_pc;
106     unwind_stream << " Map: ";
107     if (!map_info->name.empty()) {
108       unwind_stream << map_info->name;
109     } else {
110       unwind_stream << " anonymous";
111     }
112     unwind_stream << "<" << map_info->start << "-" << map_info->end << ">";
113 
114     std::string name;
115     uint64_t func_offset;
116     if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
117       if (name == function_names[function_name_index]) {
118         if (++function_name_index == function_names.size()) {
119           return;
120         }
121       }
122       unwind_stream << " " << name;
123     }
124     unwind_stream << "\n";
125     ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory))
126         << ErrorMsg(function_names, function_name_index, unwind_stream);
127   }
128   ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream);
129 }
130 
131 // This test assumes that this code is compiled with optimizations turned
132 // off. If this doesn't happen, then all of the calls will be optimized
133 // away.
InnerFunction(bool local)134 extern "C" void InnerFunction(bool local) {
135   if (local) {
136     LocalMaps maps;
137     ASSERT_TRUE(maps.Parse());
138     std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
139     RegsGetLocal(regs.get());
140     MemoryLocal memory;
141 
142     VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
143   } else {
144     g_ready_for_remote = true;
145     g_ready = true;
146     while (!g_finish.load()) {
147     }
148   }
149 }
150 
MiddleFunction(bool local)151 extern "C" void MiddleFunction(bool local) {
152   InnerFunction(local);
153 }
154 
OuterFunction(bool local)155 extern "C" void OuterFunction(bool local) {
156   MiddleFunction(local);
157 }
158 
TEST(UnwindTest,local)159 TEST(UnwindTest, local) {
160   OuterFunction(true);
161 }
162 
WaitForRemote(pid_t pid,uint64_t addr,bool leave_attached,bool * completed)163 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
164   *completed = false;
165   // Need to sleep before attempting first ptrace. Without this, on the
166   // host it becomes impossible to attach and ptrace set errno to EPERM.
167   usleep(1000);
168   for (size_t i = 0; i < 100; i++) {
169     ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
170     for (size_t j = 0; j < 100; j++) {
171       siginfo_t si;
172       if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
173         MemoryRemote memory(pid);
174         // Read the remote value to see if we are ready.
175         bool value;
176         if (memory.Read(addr, &value, sizeof(value)) && value) {
177           *completed = true;
178           break;
179         }
180       }
181       usleep(1000);
182     }
183     if (leave_attached && *completed) {
184       break;
185     }
186     ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
187     if (*completed) {
188       break;
189     }
190     usleep(1000);
191   }
192 }
193 
TEST(UnwindTest,remote)194 TEST(UnwindTest, remote) {
195   pid_t pid;
196   if ((pid = fork()) == 0) {
197     OuterFunction(false);
198     exit(0);
199   }
200   ASSERT_NE(-1, pid);
201 
202   bool completed;
203   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
204   ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
205 
206   RemoteMaps maps(pid);
207   ASSERT_TRUE(maps.Parse());
208   MemoryRemote memory(pid);
209   uint32_t machine_type;
210   std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
211   ASSERT_TRUE(regs.get() != nullptr);
212 
213   VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
214 
215   ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
216 
217   kill(pid, SIGKILL);
218   ASSERT_EQ(pid, wait(nullptr));
219 }
220 
TEST(UnwindTest,from_context)221 TEST(UnwindTest, from_context) {
222   std::atomic_int tid(0);
223   std::thread thread([&]() {
224     tid = syscall(__NR_gettid);
225     OuterFunction(false);
226   });
227 
228   struct sigaction act, oldact;
229   memset(&act, 0, sizeof(act));
230   act.sa_sigaction = SignalHandler;
231   act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
232   ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
233   // Wait for the tid to get set.
234   for (size_t i = 0; i < 100; i++) {
235     if (tid.load() != 0) {
236       break;
237     }
238     usleep(1000);
239   }
240   ASSERT_NE(0, tid.load());
241   // Portable tgkill method.
242   ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
243 
244   // Wait for context data.
245   void* ucontext;
246   for (size_t i = 0; i < 2000; i++) {
247     ucontext = reinterpret_cast<void*>(g_ucontext.load());
248     if (ucontext != nullptr) {
249       break;
250     }
251     usleep(1000);
252   }
253   ASSERT_TRUE(ucontext != nullptr) << "Timed out waiting for thread to respond to signal.";
254 
255   LocalMaps maps;
256   ASSERT_TRUE(maps.Parse());
257   std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::GetMachineType(), ucontext));
258   MemoryLocal memory;
259 
260   VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
261 
262   ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
263 
264   g_finish = true;
265   thread.join();
266 }
267 
RemoteThroughSignal(unsigned int sa_flags)268 static void RemoteThroughSignal(unsigned int sa_flags) {
269   g_ready = false;
270   g_signal_ready_for_remote = false;
271   g_finish = false;
272 
273   pid_t pid;
274   if ((pid = fork()) == 0) {
275     struct sigaction act, oldact;
276     memset(&act, 0, sizeof(act));
277     act.sa_sigaction = SignalCallerHandler;
278     act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
279     ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
280 
281     OuterFunction(false);
282     exit(0);
283   }
284   ASSERT_NE(-1, pid);
285 
286   bool completed;
287   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
288   ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
289   ASSERT_EQ(0, kill(pid, SIGUSR1));
290   WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
291   ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
292 
293   RemoteMaps maps(pid);
294   ASSERT_TRUE(maps.Parse());
295   MemoryRemote memory(pid);
296   uint32_t machine_type;
297   std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
298   ASSERT_TRUE(regs.get() != nullptr);
299 
300   VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
301 
302   ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
303 
304   kill(pid, SIGKILL);
305   ASSERT_EQ(pid, wait(nullptr));
306 }
307 
TEST(UnwindTest,remote_through_signal)308 TEST(UnwindTest, remote_through_signal) {
309   RemoteThroughSignal(0);
310 }
311 
TEST(UnwindTest,remote_through_signal_sa_siginfo)312 TEST(UnwindTest, remote_through_signal_sa_siginfo) {
313   RemoteThroughSignal(SA_SIGINFO);
314 }
315 
316 }  // namespace unwindstack
317