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
|
/* ========================================
Copyright (C) 2025 Amlal El Mahrouss, licensed under the Apache 2.0 license.
======================================== */
#pragma once
#ifdef DK_MACH_DEBUGGER
/// @file POSIXMachContract.h
/// @brief POSIX Mach debugger.
#include <DebuggerKit/DebuggerContract.h>
#include <filesystem>
#include <vector>
#ifdef __APPLE__
CK_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address,
vm_offset_t data, mach_msg_type_number_t dataCnt);
CK_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address,
mach_vm_size_t size, boolean_t set_maximum,
vm_prot_t new_protection);
#endif
#define PTRACE_ATTACH PT_ATTACHEXC
#define PTRACE_DETACH PT_DETACH
#define PTRACE_POKETEXT PT_WRITE_I
#define PTRACE_CONT PT_CONTINUE
#define PTRACE_PEEKTEXT PT_READ_I
namespace DebuggerKit::POSIX {
/// =========================================================== ///
/// \brief POSIXMachContract engine class in C++
/// \author Amlal El Mahrouss
/// =========================================================== ///
class POSIXMachContract final DK_DEBUGGER_CONTRACT {
public:
explicit POSIXMachContract() = default;
~POSIXMachContract() override = default;
public:
POSIXMachContract& operator=(const POSIXMachContract&) = default;
POSIXMachContract(const POSIXMachContract&) = default;
public:
bool Attach(CompilerKit::STLString path, CompilerKit::STLString argv,
ProcessID& pid) noexcept override {
pid = fork();
if (pid == 0) {
if (argv.empty()) {
ptrace(PT_TRACE_ME, 0, nullptr, 0);
kill(getpid(), SIGSTOP);
}
std::vector<char*> argv_arr;
argv_arr.push_back(const_cast<char*>(path.c_str()));
argv_arr.push_back(const_cast<char*>(argv.c_str()));
argv_arr.push_back(nullptr);
execv(path.c_str(), argv_arr.data());
_exit(1);
}
m_path = path;
mPid = pid;
pid = this->mPid;
return true;
}
void SetPath(CompilerKit::STLString path) noexcept {
if (path.empty()) {
return;
}
m_path = path;
}
bool BreakAt(CompilerKit::STLString symbol) noexcept override {
if (!m_path.empty() && std::filesystem::exists(m_path) &&
std::filesystem::is_regular_file(m_path)) {
auto handle = dlopen(m_path.c_str(), RTLD_LAZY);
if (handle == nullptr) {
return false;
}
auto addr = dlsym(handle, symbol.c_str());
if (addr == nullptr) {
return false;
}
#ifdef __APPLE__
task_read_t task;
task_for_pid(mach_task_self(), mPid, &task);
uint32_t brk_inst = 0xD43E0000;
mach_vm_protect(task, (mach_vm_address_t) addr, sizeof(uint32_t), false,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
mach_vm_write(task, (mach_vm_address_t) addr, (vm_offset_t) &brk_inst, sizeof(addr));
#endif
return true;
}
return false;
}
#ifdef __APPLE__
bool Break() noexcept override {
task_read_t task;
task_for_pid(mach_task_self(), mPid, &task);
kern_return_t ret = task_suspend(task);
return ret == KERN_SUCCESS;
}
bool Continue() noexcept override {
task_read_t task;
task_for_pid(mach_task_self(), mPid, &task);
kern_return_t ret = task_resume(task);
return ret == KERN_SUCCESS;
}
bool Detach() noexcept override {
this->Continue();
task_read_t task;
task_for_pid(mach_task_self(), mPid, &task);
kern_return_t kr = mach_port_deallocate(mach_task_self(), task);
return kr = KERN_SUCCESS;
}
#endif
private:
ProcessID mPid{0};
CompilerKit::STLString m_path;
};
} // namespace DebuggerKit::POSIX
#endif
|