bool
mem_load(const std::string& image, char
*
*
argv, char
*
*
envp){
/
/
创建内存文件,设置这个参数会在
exec
后自动关闭这个文件
int
fd
=
memfd_create(
"/jit-cache"
, MFD_CLOEXEC);
ftruncate(fd, (
long
)image.size());
/
/
设置文件长度
void
*
mem
=
mmap(nullptr, image.size(), PROT_WRITE, MAP_SHARED, fd,
0
);
memcpy(mem, image.data(), image.size());
munmap(mem, image.size());
/
/
此时已经将ELF内容写入到内存文件里面
int
pid
=
fork();
if
(pid <
0
) {
printf(
"mem_load failed\n"
);
/
/
fork 失败
return
false;
}
else
if
(pid
=
=
0
) {
/
/
这里是子进程,使用 PTRACE_TRACEME 主动建立连接
ptrace(PTRACE_TRACEME);
fexecve(fd, argv, envp);
}
/
/
这里是父进程
int
status;
struct user_regs_struct regs{};
struct iovec iov{};
iov.iov_base
=
®s;
iov.iov_len
=
sizeof(user_regs_struct);
while
(true){
wait(&status);
/
/
等待子进程暂停
if
(WIFEXITED(status)){
break
;
/
/
子进程退出
}
/
/
读取通用寄存器,系统调用号
ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
if
(regs.regs[
8
]
=
=
__NR_faccessat){
/
/
access函数使用的系统调用号
char path[]
=
"/memfd:"
;
long
word;
/
/
注意,PTRACE_PEEKDATA 固定一次读取 sizeof(
long
) 字节长度的内容
word
=
ptrace(PTRACE_PEEKDATA, pid, regs.regs[
1
], NULL);
if
(strcmp(path, (char
*
)&word)
=
=
0
){
/
/
判断是否是我们添加的目录
ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL);
/
/
单步执行,让系统调用执行完
wait(nullptr);
/
/
等待系统调用执行完
ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
/
/
读取寄存器
regs.regs[
0
]
=
0
;
/
/
修改返回值为寄存器
ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
/
/
修改寄存器
ptrace(PTRACE_DETACH, pid, NULL, NULL);
/
/
detach 进程
return
true;
}
}
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
/
/
执行到下一个系统调用时暂停
}
return
false;
}