forked from bloomberg/pystack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess.h
More file actions
186 lines (157 loc) Β· 5.71 KB
/
process.h
File metadata and controls
186 lines (157 loc) Β· 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#pragma once
#include <cstdio>
#include <memory>
#include <optional>
#include <stdexcept>
#include <unistd.h>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "elf_common.h"
#include "mem.h"
#include "native_frame.h"
#include "pycompat.h"
#include "unwinder.h"
#include "version.h"
namespace pystack {
template<typename OffsetsStruct>
class Structure;
struct InvalidRemoteObject : public InvalidCopiedMemory
{
const char* what() const noexcept override
{
return "Object copied from remote process is inconsistent";
}
};
class ProcessTracer
{
public:
// Constructors
ProcessTracer(pid_t pid);
ProcessTracer(const ProcessTracer&) = delete;
ProcessTracer& operator=(const ProcessTracer&) = delete;
// Destructors
~ProcessTracer();
// Methods
std::vector<int> getTids() const;
private:
// Data members
std::unordered_set<int> d_tids;
// Methods
void detachFromProcess();
};
class AbstractProcessManager : public std::enable_shared_from_this<AbstractProcessManager>
{
public:
// Enums
enum InterpreterStatus { RUNNING = 1, FINALIZED = 2, UNKNOWN = -1 };
// Constructor
AbstractProcessManager(
pid_t pid,
std::vector<VirtualMap>&& memory_maps,
MemoryMapInformation&& map_info);
// Getters
pid_t Pid() const;
virtual const std::vector<int>& Tids() const = 0;
remote_addr_t getAddressFromCache(const std::string& symbol) const;
void registerAddressInCache(const std::string& symbol, remote_addr_t address) const;
// Methods
std::vector<NativeFrame> unwindThread(pid_t tid) const;
bool isAddressValid(remote_addr_t addr) const;
remote_addr_t findInterpreterStateFromPointer(remote_addr_t pointer) const;
remote_addr_t findInterpreterStateFromPyRuntime(remote_addr_t runtime_addr) const;
remote_addr_t findInterpreterStateFromSymbols() const;
remote_addr_t findInterpreterStateFromElfData() const;
remote_addr_t findInterpreterStateFromDebugOffsets() const;
remote_addr_t findSymbol(const std::string& symbol) const;
ssize_t copyMemoryFromProcess(remote_addr_t addr, size_t size, void* destination) const;
template<typename T>
ssize_t copyObjectFromProcess(remote_addr_t addr, T* destination) const;
std::string getBytesFromAddress(remote_addr_t addr) const;
std::string getStringFromAddress(remote_addr_t addr) const;
std::string getCStringFromAddress(remote_addr_t addr) const;
remote_addr_t scanAllAnonymousMaps() const;
remote_addr_t scanBSS() const;
remote_addr_t scanHeap() const;
InterpreterStatus isInterpreterActive() const;
std::pair<int, int> findPythonVersion() const;
void setPythonVersionFromDebugOffsets();
void setPythonVersion(const std::pair<int, int>& version);
bool versionIsAtLeast(int required_major, int required_minor) const;
const python_v& offsets() const;
protected:
// Data members
pid_t d_pid;
std::optional<VirtualMap> d_main_map{std::nullopt};
std::optional<VirtualMap> d_bss{std::nullopt};
std::optional<VirtualMap> d_heap{std::nullopt};
std::vector<VirtualMap> d_memory_maps;
std::unique_ptr<AbstractRemoteMemoryManager> d_manager;
std::unique_ptr<AbstractUnwinder> d_unwinder;
mutable std::unordered_map<std::string, remote_addr_t> d_symbol_cache;
std::shared_ptr<Analyzer> d_analyzer;
int d_major{};
int d_minor{};
const python_v* d_py_v{};
remote_addr_t d_debug_offsets_addr{};
std::unique_ptr<python_v> d_debug_offsets{};
mutable std::unordered_map<std::string, remote_addr_t> d_type_cache;
// Methods
bool isValidInterpreterState(remote_addr_t addr) const;
bool isValidDictionaryObject(remote_addr_t addr) const;
private:
void warnIfOffsetsAreMismatched(remote_addr_t addr) const;
remote_addr_t findPyRuntimeFromElfData() const;
remote_addr_t findDebugOffsetsFromMaps() const;
std::unique_ptr<python_v> loadDebugOffsets(Structure<py_runtime_v>& py_runtime) const;
bool copyDebugOffsets(Structure<py_runtime_v>& py_runtime, python_v& debug_offsets) const;
bool validateDebugOffsets(const Structure<py_runtime_v>& py_runtime, python_v& debug_offsets) const;
void clampSizes(python_v& debug_offsets) const;
remote_addr_t scanMemoryAreaForInterpreterState(const VirtualMap& map) const;
remote_addr_t scanMemoryAreaForDebugOffsets(const VirtualMap& map) const;
};
template<typename T>
ssize_t
AbstractProcessManager::copyObjectFromProcess(remote_addr_t addr, T* destination) const
{
return this->copyMemoryFromProcess(addr, sizeof(T), destination);
}
class ProcessManager : public AbstractProcessManager
{
public:
// Constructors
ProcessManager(
pid_t pid,
const std::shared_ptr<ProcessTracer>& tracer,
const std::shared_ptr<ProcessAnalyzer>& analyzer,
std::vector<VirtualMap> memory_maps,
MemoryMapInformation map_info);
// Destructors
virtual ~ProcessManager() = default;
// Getters
const std::vector<int>& Tids() const override;
private:
// Data members
std::shared_ptr<ProcessTracer> tracer;
std::vector<int> d_tids;
};
class CoreFileProcessManager : public AbstractProcessManager
{
public:
// Constructors
CoreFileProcessManager(
pid_t pid,
const std::shared_ptr<CoreFileAnalyzer>& analyzer,
std::vector<VirtualMap> memory_maps,
MemoryMapInformation map_info);
// Destructors
virtual ~CoreFileProcessManager() = default;
// Getters
const std::vector<int>& Tids() const override;
private:
// Data members
std::vector<int> d_tids;
std::optional<std::string> d_executable;
};
} // namespace pystack