1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <sys/types.h> 20 21 #include <set> 22 #include <string> 23 #include <unordered_set> 24 25 namespace unwindstack { 26 27 // ProcessTracer objects abstract operations for tracing a process and its threads with ptrace(2). 28 class ProcessTracer final { 29 public: 30 ProcessTracer(pid_t pid, bool is_tracing_threads); 31 32 ~ProcessTracer(); 33 34 // ProcessTracer instances are moveable but not copyable because they manage the 35 // state of a process. 36 ProcessTracer(const ProcessTracer&) = delete; 37 ProcessTracer& operator=(const ProcessTracer&) = delete; 38 ProcessTracer(ProcessTracer&&) = default; 39 ProcessTracer& operator=(ProcessTracer&&) = default; 40 pid()41 pid_t pid() const { return pid_; } 42 tids()43 const std::set<pid_t>& tids() const { return tids_; } 44 IsTracingThreads()45 bool IsTracingThreads() const { return is_tracing_threads_; } 46 47 bool Stop(); 48 49 bool Resume(); 50 51 // Like ptrace, it is required to call ProcessTracer::Detach before calling ProcessTracer::Attach 52 // on a different thread of the same process. 53 bool Detach(pid_t tid); 54 55 bool Attach(pid_t tid); 56 57 // This method for determining whether a thread is currently executing instructions from a 58 // desired ELF is not the most time efficient solution. In the interest of simplicity and 59 // limiting memory usage, the UnwinderFromPid, Regs, and Maps instances constructed for 60 // in each check (loop iteration) are thrown away. 61 // 62 // A SIGINT signal handler is set up to allow the user to gracefully exit with CTRL-C if they 63 // decide that they no longer want to wait for the process to enter the desired ELF. 64 bool StopInDesiredElf(const std::string& elf_name); 65 66 // `desired_elf_name` should match the filename of the path (the component following the final 67 // '/') corresponding to the shared library as indicated in /proc/pid/maps. 68 static bool UsesSharedLibrary(pid_t pid, const std::string& desired_elf_name); 69 70 private: 71 static bool ProcIsInDesiredElf(pid_t tid, const std::string& desired_elf_name); 72 73 // Initialize tids_ such that the main thread is the first element and 74 // the remaining tids are in order from least to greatest. 75 bool InitProcessTids(); 76 77 static constexpr pid_t kNoThreadAttached = -2; 78 static constexpr pid_t kKillFailed = -1; 79 static constexpr pid_t kPtraceFailed = -1; 80 static constexpr pid_t kWaitpidFailed = -1; 81 static inline std::atomic_bool keepWaitingForPcInElf = true; 82 const pid_t pid_; 83 bool is_tracing_threads_ = false; 84 std::set<pid_t> tids_; 85 bool is_running_ = true; 86 pid_t cur_attached_tid_ = kNoThreadAttached; 87 }; 88 } // namespace unwindstack 89