• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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