xref: /aosp_15_r20/system/unwinding/libunwindstack/utils/PidUtils.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker  *
4*eb293b8fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker  *
8*eb293b8fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker  *
10*eb293b8fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker  * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker  */
16*eb293b8fSAndroid Build Coastguard Worker 
17*eb293b8fSAndroid Build Coastguard Worker #include <errno.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <stdio.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <sys/ptrace.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <sys/types.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <sys/wait.h>
23*eb293b8fSAndroid Build Coastguard Worker #include <time.h>
24*eb293b8fSAndroid Build Coastguard Worker #include <unistd.h>
25*eb293b8fSAndroid Build Coastguard Worker 
26*eb293b8fSAndroid Build Coastguard Worker #include "PidUtils.h"
27*eb293b8fSAndroid Build Coastguard Worker 
28*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
29*eb293b8fSAndroid Build Coastguard Worker 
Exited(pid_t pid)30*eb293b8fSAndroid Build Coastguard Worker static bool Exited(pid_t pid) {
31*eb293b8fSAndroid Build Coastguard Worker   int status;
32*eb293b8fSAndroid Build Coastguard Worker   pid_t wait_pid = waitpid(pid, &status, WNOHANG);
33*eb293b8fSAndroid Build Coastguard Worker   if (wait_pid != pid) {
34*eb293b8fSAndroid Build Coastguard Worker     return false;
35*eb293b8fSAndroid Build Coastguard Worker   }
36*eb293b8fSAndroid Build Coastguard Worker 
37*eb293b8fSAndroid Build Coastguard Worker   if (WIFEXITED(status)) {
38*eb293b8fSAndroid Build Coastguard Worker     fprintf(stderr, "%d died: Process exited with code %d\n", pid, WEXITSTATUS(status));
39*eb293b8fSAndroid Build Coastguard Worker   } else if (WIFSIGNALED(status)) {
40*eb293b8fSAndroid Build Coastguard Worker     fprintf(stderr, "%d died: Process exited due to signal %d\n", pid, WTERMSIG(status));
41*eb293b8fSAndroid Build Coastguard Worker   } else {
42*eb293b8fSAndroid Build Coastguard Worker     fprintf(stderr, "%d died: Process finished for unknown reason\n", pid);
43*eb293b8fSAndroid Build Coastguard Worker   }
44*eb293b8fSAndroid Build Coastguard Worker   return true;
45*eb293b8fSAndroid Build Coastguard Worker }
46*eb293b8fSAndroid Build Coastguard Worker 
Quiesce(pid_t pid)47*eb293b8fSAndroid Build Coastguard Worker bool Quiesce(pid_t pid) {
48*eb293b8fSAndroid Build Coastguard Worker   siginfo_t si;
49*eb293b8fSAndroid Build Coastguard Worker   // Wait for up to 10 seconds.
50*eb293b8fSAndroid Build Coastguard Worker   for (time_t start_time = time(nullptr); time(nullptr) - start_time < 10;) {
51*eb293b8fSAndroid Build Coastguard Worker     if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
52*eb293b8fSAndroid Build Coastguard Worker       return true;
53*eb293b8fSAndroid Build Coastguard Worker     }
54*eb293b8fSAndroid Build Coastguard Worker     if (errno != ESRCH) {
55*eb293b8fSAndroid Build Coastguard Worker       if (errno == EINVAL) {
56*eb293b8fSAndroid Build Coastguard Worker         // The process is in group-stop state, so try and kick the
57*eb293b8fSAndroid Build Coastguard Worker         // process out of that state.
58*eb293b8fSAndroid Build Coastguard Worker         if (ptrace(PTRACE_LISTEN, pid, 0, 0) == -1) {
59*eb293b8fSAndroid Build Coastguard Worker           // Cannot recover from this, so just pretend it worked and see
60*eb293b8fSAndroid Build Coastguard Worker           // if we can unwind.
61*eb293b8fSAndroid Build Coastguard Worker           return true;
62*eb293b8fSAndroid Build Coastguard Worker         }
63*eb293b8fSAndroid Build Coastguard Worker       } else {
64*eb293b8fSAndroid Build Coastguard Worker         perror("ptrace getsiginfo failed");
65*eb293b8fSAndroid Build Coastguard Worker         return false;
66*eb293b8fSAndroid Build Coastguard Worker       }
67*eb293b8fSAndroid Build Coastguard Worker     }
68*eb293b8fSAndroid Build Coastguard Worker     usleep(5000);
69*eb293b8fSAndroid Build Coastguard Worker   }
70*eb293b8fSAndroid Build Coastguard Worker   fprintf(stderr, "%d: Did not quiesce in 10 seconds\n", pid);
71*eb293b8fSAndroid Build Coastguard Worker   return false;
72*eb293b8fSAndroid Build Coastguard Worker }
73*eb293b8fSAndroid Build Coastguard Worker 
Attach(pid_t pid)74*eb293b8fSAndroid Build Coastguard Worker bool Attach(pid_t pid) {
75*eb293b8fSAndroid Build Coastguard Worker   // Wait up to 45 seconds to attach.
76*eb293b8fSAndroid Build Coastguard Worker   for (time_t start_time = time(nullptr); time(nullptr) - start_time < 45;) {
77*eb293b8fSAndroid Build Coastguard Worker     if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
78*eb293b8fSAndroid Build Coastguard Worker       break;
79*eb293b8fSAndroid Build Coastguard Worker     }
80*eb293b8fSAndroid Build Coastguard Worker     if (errno != ESRCH) {
81*eb293b8fSAndroid Build Coastguard Worker       perror("Failed to attach");
82*eb293b8fSAndroid Build Coastguard Worker       return false;
83*eb293b8fSAndroid Build Coastguard Worker     }
84*eb293b8fSAndroid Build Coastguard Worker     usleep(5000);
85*eb293b8fSAndroid Build Coastguard Worker   }
86*eb293b8fSAndroid Build Coastguard Worker 
87*eb293b8fSAndroid Build Coastguard Worker   if (Quiesce(pid)) {
88*eb293b8fSAndroid Build Coastguard Worker     return true;
89*eb293b8fSAndroid Build Coastguard Worker   }
90*eb293b8fSAndroid Build Coastguard Worker 
91*eb293b8fSAndroid Build Coastguard Worker   if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
92*eb293b8fSAndroid Build Coastguard Worker     perror("Failed to detach");
93*eb293b8fSAndroid Build Coastguard Worker   }
94*eb293b8fSAndroid Build Coastguard Worker   return false;
95*eb293b8fSAndroid Build Coastguard Worker }
96*eb293b8fSAndroid Build Coastguard Worker 
Detach(pid_t pid)97*eb293b8fSAndroid Build Coastguard Worker bool Detach(pid_t pid) {
98*eb293b8fSAndroid Build Coastguard Worker   if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
99*eb293b8fSAndroid Build Coastguard Worker     perror("ptrace detach failed");
100*eb293b8fSAndroid Build Coastguard Worker     return false;
101*eb293b8fSAndroid Build Coastguard Worker   }
102*eb293b8fSAndroid Build Coastguard Worker   return true;
103*eb293b8fSAndroid Build Coastguard Worker }
104*eb293b8fSAndroid Build Coastguard Worker 
105*eb293b8fSAndroid Build Coastguard Worker static constexpr time_t kMaxWaitTimeSeconds = 30;
106*eb293b8fSAndroid Build Coastguard Worker 
WaitForPidState(pid_t pid,const std::function<PidRunEnum ()> & state_check_func)107*eb293b8fSAndroid Build Coastguard Worker bool WaitForPidState(pid_t pid, const std::function<PidRunEnum()>& state_check_func) {
108*eb293b8fSAndroid Build Coastguard Worker   PidRunEnum status = PID_RUN_KEEP_GOING;
109*eb293b8fSAndroid Build Coastguard Worker   for (time_t start_time = time(nullptr);
110*eb293b8fSAndroid Build Coastguard Worker        time(nullptr) - start_time < kMaxWaitTimeSeconds && status == PID_RUN_KEEP_GOING;) {
111*eb293b8fSAndroid Build Coastguard Worker     if (Attach(pid)) {
112*eb293b8fSAndroid Build Coastguard Worker       status = state_check_func();
113*eb293b8fSAndroid Build Coastguard Worker       if (status == PID_RUN_PASS) {
114*eb293b8fSAndroid Build Coastguard Worker         return true;
115*eb293b8fSAndroid Build Coastguard Worker       }
116*eb293b8fSAndroid Build Coastguard Worker 
117*eb293b8fSAndroid Build Coastguard Worker       if (!Detach(pid)) {
118*eb293b8fSAndroid Build Coastguard Worker         return false;
119*eb293b8fSAndroid Build Coastguard Worker       }
120*eb293b8fSAndroid Build Coastguard Worker     } else if (Exited(pid)) {
121*eb293b8fSAndroid Build Coastguard Worker       return false;
122*eb293b8fSAndroid Build Coastguard Worker     }
123*eb293b8fSAndroid Build Coastguard Worker     usleep(5000);
124*eb293b8fSAndroid Build Coastguard Worker   }
125*eb293b8fSAndroid Build Coastguard Worker   if (status == PID_RUN_KEEP_GOING) {
126*eb293b8fSAndroid Build Coastguard Worker     fprintf(stderr, "Timed out waiting for pid %d to be ready\n", pid);
127*eb293b8fSAndroid Build Coastguard Worker   }
128*eb293b8fSAndroid Build Coastguard Worker   return status == PID_RUN_PASS;
129*eb293b8fSAndroid Build Coastguard Worker }
130*eb293b8fSAndroid Build Coastguard Worker 
WaitForPidStateAfterAttach(pid_t pid,const std::function<PidRunEnum ()> & state_check_func)131*eb293b8fSAndroid Build Coastguard Worker bool WaitForPidStateAfterAttach(pid_t pid, const std::function<PidRunEnum()>& state_check_func) {
132*eb293b8fSAndroid Build Coastguard Worker   PidRunEnum status;
133*eb293b8fSAndroid Build Coastguard Worker   time_t start_time = time(nullptr);
134*eb293b8fSAndroid Build Coastguard Worker   do {
135*eb293b8fSAndroid Build Coastguard Worker     status = state_check_func();
136*eb293b8fSAndroid Build Coastguard Worker     if (status == PID_RUN_PASS) {
137*eb293b8fSAndroid Build Coastguard Worker       return true;
138*eb293b8fSAndroid Build Coastguard Worker     }
139*eb293b8fSAndroid Build Coastguard Worker     if (!Detach(pid)) {
140*eb293b8fSAndroid Build Coastguard Worker       return false;
141*eb293b8fSAndroid Build Coastguard Worker     }
142*eb293b8fSAndroid Build Coastguard Worker     usleep(5000);
143*eb293b8fSAndroid Build Coastguard Worker   } while (time(nullptr) - start_time < kMaxWaitTimeSeconds && status == PID_RUN_KEEP_GOING &&
144*eb293b8fSAndroid Build Coastguard Worker            Attach(pid));
145*eb293b8fSAndroid Build Coastguard Worker   if (status == PID_RUN_KEEP_GOING) {
146*eb293b8fSAndroid Build Coastguard Worker     fprintf(stderr, "Timed out waiting for pid %d to be ready\n", pid);
147*eb293b8fSAndroid Build Coastguard Worker   }
148*eb293b8fSAndroid Build Coastguard Worker   return status == PID_RUN_PASS;
149*eb293b8fSAndroid Build Coastguard Worker }
150*eb293b8fSAndroid Build Coastguard Worker 
151*eb293b8fSAndroid Build Coastguard Worker }  // namespace unwindstack
152