1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#ifndef _SESSION_H
6#define _SESSION_H
7
8#include <vector>
9#include <string>
10#include <map>
11#include <memory>
12
13/*third party lib*/
14#include <elf.h>
15#include <link.h>
16#include <sys/auxv.h>
17#include <unistd.h>
18
19#include "config.h"
20#include "trace_writer.h"
21#include "zstd_writer.h"
22#include "WaitStatus.h"
23#include "shared_mem_dump.h"
24#include "md_types.h"
25#include "elf_helper.h"
26
27#define RESERVED_SOCKET_FD (1001)
28
29struct MappingInfo {
30 uintptr_t start_addr;
31 int size;
32 int offset; // offset into the backed file.
33 unsigned char exec:1;
34 char name[NAME_MAX];
35};
36
37typedef std::map<std::string, std::shared_ptr<SymbolFile>> ElfSymbolFiles;
38
39
40const int SYSCALL_ENTER_MASK = 0x80000000;
41const int SYSCALL_NO_MASK = 0x7fffffff;
42typedef struct tagSyscallState{
43 // bit 0~30 is syscall number;
44 // bit 31 is syscall enter flag;
45 int state;
46 // bool interrupted;
47 uintptr_t args[6];
48}SyscallState;
49
50class TraceProcess {
51public:
52 typedef enum tagThreadState{
53 TS_RUNNING = 0,
54 TS_SLEEPING,
55 TS_DISK_SLEEP,
56 TS_STOPPED,
57 TS_TRACING_STOP,
58 TS_ZOMBIE,
59 TS_DEAD,
60 }ThreadState;
61
62 enum ContinueType {
63 DONT_CONTINUE = 0,
64 CONTINUE = PTRACE_CONT,
65 CONTINUE_SYSCALL = PTRACE_SYSCALL,
66 };
67
68 enum SyscallBeforeSeccomp {
69 SYSCALL_BEFORE_SECCOMP = 0,
70 SECCOMP_BEFORE_SYSCALL,
71 SYSCALL_BEFORE_SECCOMP_UNKNOWN,
72 };
73
74 TraceProcess(DumpConfig* config);
75 TraceProcess(TraceProcess* parent);
76 ~TraceProcess(void);
77 void stop_record(void);
78 int setup_socket(int* fd_number);
79 int handle_connect(void);
80 int setup_listener(void);
81
82 bool process_status(int status, pid_t tid);
83 bool start_record(pid_t tid);
84 bool empty(void) {
85 for (auto& i : m_childs) {
86 if (!i.get()->get_threads().empty()) return false;
87 }
88 return m_syscall_state.empty();
89 }
90 DumpConfig* get_config(void) { return m_cfg;}
91 int dump_event(int reason, pid_t tid, void* extra_data, int extra_data_size);
92 int dump_clone(pid_t tid, pid_t newtid); //only used in fast mode
93 int dump_maps(int reason, int map_prot);
94
95 std::map<pid_t, SyscallState>& get_threads(void) { return m_syscall_state; }
96
97 typedef struct tagVariableEx {
98 bool is_loaded;
99 bool is_pointer;
100 bool is_pointer_loaded;
101 int max_size;
102 uintptr_t address;
103 uintptr_t address_ptr; // pointer point to memory
104 string sym_name;
105 }VariableEx;
106
107 TraceProcess* get_process(pid_t tid) {
108 if (m_syscall_state.find(tid) != m_syscall_state.end()) {
109 return this;
110 }
111
112 for (auto& i : m_childs) {
113 std::map<pid_t, SyscallState>& ids = i.get()->get_threads();
114 if (ids.find(tid) != ids.end()) {
115 return i.get();
116 }
117 }
118
119 return nullptr;
120 }
121
122 void add_process(shared_ptr<TraceProcess> child, pid_t tid) {
123 m_childs.push_back(child);
124 child.get()->start_record(tid);
125 }
126
127 bool add_thread(pid_t tid) {
128 char path[256];
129 snprintf(path, sizeof(path), "/proc/%d/task/%d", m_pid, tid);
130 if (access(path, F_OK) == 0) {
131 SyscallState st = {0, false, 0};
132 m_syscall_state.insert(pair<pid_t, SyscallState>(tid, st));
133 return true;
134 }
135
136 // A newborn process found!
137 return false;
138 }
139
140 void remove_thread(pid_t tid) {m_syscall_state.erase(tid);}
141 bool get_sym_address(const char* object_name,
142 const char *name, unsigned long *addr);
143
144private:
145
146 TraceProcess* m_parent;
147 long m_sig;
148 ContinueType m_cont_type;
149 pid_t m_pid;
150 int m_nonce;
151
152 DumpConfig* m_cfg;
153 bool m_can_dump;
154 bool m_exec_stop;
155
156 struct {
157 uintptr_t address;
158 uint32_t value;
159 }m_breakpoint;
160
161 int m_page_size;
162
163 struct {
164 int syscall_enter;
165 int syscall_exit;
166 int syscall_exit_miss;
167 int seccomp_stop;
168 int flush_buffer;
169 int maps_change;
170 int event_dumped;
171 int ptrace_error;
172 long hook_dumped;
173 long total_dumped;
174 }m_counter;
175
176 MemoryDumper* m_syscall_dumper;
177
178 std::map<pid_t, SyscallState> m_syscall_state;
179 std::list<std::shared_ptr<TraceProcess>> m_childs;
180
181 std::vector<elf_aux_val_t> m_auxv;
182 std::vector<VmSegment> m_heaps;
183 std::vector<VmSegment> m_heaps_temp; // use to restore m_heaps
184 std::vector<VmSegment> m_syscall_memblks;
185 std::vector<VariableEx> m_global_vars;
186 std::vector<ThreadContext> m_thread_ctx;
187 std::vector<shared_ptr<MappingInfo> > m_mappings;
188
189 ElfSymbolFiles m_symbols;
190
191 ZstdWriter m_maps_file;
192 TraceStream m_ctx_stream;
193 ZstdWriter m_ctx_file;
194
195 // the file only record clone event in fast mode
196 TraceStream m_ctx_stream2;
197 ZstdWriter m_ctx_file2;
198
199 int m_recv_fd;
200 int m_server_socket;
201 int m_recv_socket;
202 int m_send_socket;
203
204 time_t m_begin_time;
205 time_t m_end_time;
206
207 bool remove_break_function(pid_t tid);
208 void break_at_function(pid_t tid);
209 void dump_debugger_count(void);
210 void reset_debugger_count(void);
211 bool handle_seccomp_event(pid_t tid);
212 void process_magic_syscall(pid_t tid, int no, uintptr_t* args);
213 bool process_syscall_exit(pid_t tid, int no, uintptr_t* args, long result);
214 bool process_syscall_enter(pid_t tid, int no, uintptr_t* args);
215 bool process_signal(pid_t tid);
216 int prepare_clone(pid_t tid, int no, uintptr_t* args);
217 int dump_thread_list(pid_t tid);
218 int dump_thread_status(pid_t tid);
219 int dump_thread_context(ThreadContext* ctx);
220 int dump_thread_stack(ThreadContext* ctx);
221 int dump_proc_file(pid_t m_pid, const char* name);
222 int dump_auxv(pid_t m_pid);
223 void post_exec_syscall(pid_t tid);
224 void init_shared_buffers(int size);
225 void get_share_name(uintptr_t name);
226 int get_shared_buffers(char** buf);
227 int flush_shared_buffers(void);
228 void merge_heap(vector<VmSegment>& rw_segs);
229 void check_global_pointer_var_is_assigned(void);
230
231 std::map<pid_t, SyscallState>::iterator get_thread_state(pid_t tid) {
232 auto it = m_syscall_state.find(tid);
233 if (it != m_syscall_state.end()) {
234 return it;
235 }
236
237 assert(0);
238 return m_syscall_state.end();
239 }
240};
241
242#endif
243
244