-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathInAppDebugger.cpp
133 lines (118 loc) · 4.05 KB
/
InAppDebugger.cpp
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
#include "InAppDebugger.h"
#include "Thread.h"
#include "Process.h"
#include <sstream>
#include <stdarg.h>
#include <memory>
#include <assert.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <vector>
#include <errno.h>
using namespace std;
void InAppDebugger::enablePtraceForThisProcess() {
prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0, 0);
}
InAppDebugger::InAppDebugger(InAppDebuggerCallbacks *callbackInterface)
:callbackInterface(callbackInterface) {
callbackInterface->logMessage("In-app debugger initialized");
}
shared_ptr<Process> InAppDebugger::attachToProcess(pid_t targetPid) {
log("Attaching to process %d", targetPid);
shared_ptr<Process> process = Process::Create(this, targetPid);
int x = ptrace(PTRACE_ATTACH, targetPid);
if (x != 0) {
log("Failed to ptrace(PTRACE_ATTACH, %d), errno=%d", targetPid, errno);
return process;
}
int status;
int pid = waitpid(targetPid, &status, 0);
if (pid != targetPid) {
log("Failed to stop %d, errno=%d", targetPid, errno);
return process;
}
x = ptrace(PTRACE_SETOPTIONS, targetPid, nullptr,
PTRACE_O_TRACECLONE|
PTRACE_O_TRACEFORK|
PTRACE_O_TRACESYSGOOD);
if (x != 0) {
log("Failed to ptrace(PTRACE_SETOPTIONS, %d), errno=%d", targetPid, errno);
return process;
}
log("Successfully attached to process %d", targetPid);
processes[targetPid] = process;
threads[targetPid] = process->getMainThread();
processing_queue.push({process->getMainThread(), status});
return process;
}
void InAppDebugger::log(const char *format, ...) {
char buffer[1024];
va_list args;
va_start (args, format);
vsnprintf (buffer,sizeof(buffer),format, args);
va_end (args);
callbackInterface->logMessage(buffer);
}
void InAppDebugger::run() {
log("Entering debugger run loop");
while (threads.size() > 0) {
processEvents();
int status = 0;
pid_t tid = wait4(-1, &status, __WALL, NULL);
auto it = threads.find(tid);
if (it == threads.end()) {
log("Received event 0x%04x from unknown (yet?) thread or process: %d, continuing it", status, tid);
ptrace(PTRACE_SYSCALL,tid,0,0);
continue;
} else {
log("Received event 0x%04x for %d", status, tid);
}
processing_queue.push({it->second, status});
}
log("No more processes/threads under debugging, exiting debugger run loop");
}
void InAppDebugger::processEvents() {
while (!processing_queue.empty()) {
queue<pair<shared_ptr<Thread>, int>> queue;
queue.swap(processing_queue);
while (!queue.empty()) {
queue.front().first->processEvent(queue.front().second);
queue.pop();
}
}
}
void InAppDebugger::removeThread(const pid_t tid) {
threads.erase(tid);
processes.erase(tid);
}
bool InAppDebugger::needLogSyscall(int syscallNo) {
syscallNo = ((unsigned int)syscallNo) & 0xFFFF;
return doLogAllSyscalls || syscallsToLog.find(syscallNo) != syscallsToLog.end();
}
void InAppDebugger::logAllSyscalls() {
doLogAllSyscalls = true;
}
void InAppDebugger::logSyscall(int syscallNo) {
syscallsToLog.insert(syscallNo);
}
void InAppDebugger::onNewThread(shared_ptr<Process> owningProcess, pid_t tid, int status) {
shared_ptr<Thread> thread = make_shared<Thread>(this, tid, owningProcess);
thread->state = Thread::State::WAITING_SYSCALL_LEAVE;
threads[tid] = thread;
//processing_queue.push({thread, status});
}
void InAppDebugger::onNewProcess(shared_ptr<Process> parentProcess, unsigned long pid, int status) {
shared_ptr<Process> process = Process::Create(this, pid);
threads[pid] = process->mainThread;
process->mainThread->state = Thread::State::WAITING_SYSCALL_LEAVE;
//processing_queue.push({process->mainThread, status});
}