blob: cd5fe80184a4607a2d752dbdaeb9e4cfce165300 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H
#define _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H
#include <sys/types.h>
#include <set>
#include <string>
#include <unordered_set>
namespace unwindstack {
// ProcessTracer objects abstract operations for tracing a process and its threads with ptrace(2).
class ProcessTracer final {
public:
ProcessTracer(pid_t pid, bool is_tracing_threads);
~ProcessTracer();
// ProcessTracer instances are moveable but not copyable because they manage the
// state of a process.
ProcessTracer(const ProcessTracer&) = delete;
ProcessTracer& operator=(const ProcessTracer&) = delete;
ProcessTracer(ProcessTracer&&) = default;
ProcessTracer& operator=(ProcessTracer&&) = default;
pid_t pid() const { return pid_; }
const std::set<pid_t>& tids() const { return tids_; }
bool IsTracingThreads() const { return is_tracing_threads_; }
bool Stop();
bool Resume();
// Like ptrace, it is required to call ProcessTracer::Detach before calling ProcessTracer::Attach
// on a different thread of the same process.
bool Detach(pid_t tid);
bool Attach(pid_t tid);
// This method for determining whether a thread is currently executing instructions from a
// desired ELF is not the most time efficient solution. In the interest of simplicity and
// limiting memory usage, the UnwinderFromPid, Regs, and Maps instances constructed for
// in each check (loop iteration) are thrown away.
//
// A SIGINT signal handler is set up to allow the user to gracefully exit with CTRL-C if they
// decide that they no longer want to wait for the process to enter the desired ELF.
bool StopInDesiredElf(const std::string& elf_name);
// `desired_elf_name` should match the filename of the path (the component following the final
// '/') corresponding to the shared library as indicated in /proc/pid/maps.
static bool UsesSharedLibrary(pid_t pid, const std::string& desired_elf_name);
private:
static bool ProcIsInDesiredElf(pid_t tid, const std::string& desired_elf_name);
// Initialize tids_ such that the main thread is the first element and
// the remaining tids are in order from least to greatest.
bool InitProcessTids();
static constexpr pid_t kNoThreadAttached = -2;
static constexpr pid_t kKillFailed = -1;
static constexpr pid_t kPtraceFailed = -1;
static constexpr pid_t kWaitpidFailed = -1;
static inline std::atomic_bool keepWaitingForPcInElf = true;
const pid_t pid_;
bool is_tracing_threads_ = false;
std::set<pid_t> tids_;
bool is_running_ = true;
pid_t cur_attached_tid_ = kNoThreadAttached;
};
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_UTILS_PROCESS_TRACER_H