lldb - 如何读取线程内存区域的权限?
lldb - how to read the permissions of a memory region for a thread?
Apple 表示在 ARM64 上 Macs 内存区域可以具有线程的写入或执行权限。有人如何找出 lldb 中线程的内存区域的当前权限?我试过 'memory region ' 但那个 returns rwx.我正在开发一个即时编译器,它将 运行 在我的 M1 Mac 上。为了进行测试,我做了一个即时编译器的小型模拟。
#include <cstdio>
#include <sys/mman.h>
#include <pthread.h>
#include <libkern/OSCacheControl.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
size_t size = 1024 * 1024 * 640;
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT;
int fd = -1;
int offset = 0;
unsigned *addr = 0;
// allocate a mmap'ed region of memory
addr = (unsigned *)mmap(0, size, prot, flags, fd, offset);
if (addr == MAP_FAILED){
printf("failure detected\n");
exit(-1);
}
pthread_jit_write_protect_np(0);
// Write instructions to the memory
addr[0] = 0xd2800005; // mov x5, #0x0
addr[1] = 0x910004a5; // add x5, x5, #0x1
addr[2] = 0x17ffffff; // b <address>
pthread_jit_write_protect_np(1);
sys_icache_invalidate(addr, size);
// Execute the code
int(*f)() = (int (*)()) addr;
(*f)();
return 0;
}
一旦汇编指令开始通过 (*f)() 调用执行,我可以在 Xcode 中暂停执行并键入
memory region {address of instructions}
进入调试器。由于某种原因,它不断返回 'rwx'。我使用的命令是否正确,或者这可能是 lldb 的错误?
当我 运行 你的小程序在 Mac 上我可以四处闲逛时(我在 x86_64 上但没关系,我实际上并不需要运行 说明...)我在 lldb 中看到:
Process 43209 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003f20 protectit`main at protectit.cpp:31
28 addr[2] = 0x17ffffff; // b <address>
29
30 pthread_jit_write_protect_np(1);
-> 31 sys_icache_invalidate(addr, size);
^
32
33 // Execute the code
34 int(*f)() = (int (*)()) addr;
Target 0: (protectit) stopped.
(lldb) memory region addr
[0x0000000101000000-0x0000000129000000) rwx
正如您所报告的那样。然后我用 vmmap 仔细检查:
> vmmap 43209 0x0000000101000000
0x101000000 is in 0x101000000-0x129000000; bytes after start: 0 bytes before end: 671088639
REGION TYPE START - END [ VSIZE RSDNT DIRTY SWAP] PRT/MAX SHRMOD PURGE REGION DETAIL
MALLOC_SMALL 100800000-101000000 [ 8192K 8K 8K 0K] rw-/rwx SM=PRV MallocHelperZone_0x1001c4000
---> VM_ALLOCATE 101000000-129000000 [640.0M 4K 4K 0K] rwx/rwx SM=PRV
GAP OF 0x5ffed7000000 BYTES
MALLOC_NANO 600000000000-600008000000 [128.0M 88K 88K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x1001f1000
所以 vmmap 同意 lldb 的区域是 rwx。
无论 pthread_jit_write_protect_np 在做什么,它似乎都没有改变底层内存区域保护。
我发现我的问题的答案是阅读一个名为 S3_6_c15_c1_5 的未记录的 Apple 寄存器。
此代码从寄存器中读取原始值:
// Returns the S3_6_c15_c1_5 register's value
uint64_t read_S3_6_c15_c1_5_register(void)
{
uint64_t v;
__asm__ __volatile__("isb sy\n"
"mrs %0, S3_6_c15_c1_5\n"
: "=r"(v)::"memory");
return v;
}
此代码告诉您线程的当前模式是什么:
// Returns the mode for a thread.
// Returns "Executable" or "Writable".
// Remember to free() the value returned by this function.
char *get_thread_mode()
{
uint64_t value = read_S3_6_c15_c1_5_register();
char *return_value = (char *) malloc(50);
switch(value)
{
case 0x2010000030300000:
sprintf(return_value, "Writable");
break;
case 0x2010000030100000:
sprintf(return_value, "Executable");
break;
default:
sprintf(return_value, "Unknown state: %llx", value);
}
return return_value;
}
这是一个演示这两个功能的小测试程序:
int main(int argc, char *argv[]) {
pthread_jit_write_protect_np(1);
printf("Thread's mode: %s\n", get_thread_mode());
// The mode is Executable
pthread_jit_write_protect_np(0);
printf("Thread's mode: %s\n", get_thread_mode());
// The mode is Writable
return 0;
}
Apple 表示在 ARM64 上 Macs 内存区域可以具有线程的写入或执行权限。有人如何找出 lldb 中线程的内存区域的当前权限?我试过 'memory region ' 但那个 returns rwx.我正在开发一个即时编译器,它将 运行 在我的 M1 Mac 上。为了进行测试,我做了一个即时编译器的小型模拟。
#include <cstdio>
#include <sys/mman.h>
#include <pthread.h>
#include <libkern/OSCacheControl.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
size_t size = 1024 * 1024 * 640;
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT;
int fd = -1;
int offset = 0;
unsigned *addr = 0;
// allocate a mmap'ed region of memory
addr = (unsigned *)mmap(0, size, prot, flags, fd, offset);
if (addr == MAP_FAILED){
printf("failure detected\n");
exit(-1);
}
pthread_jit_write_protect_np(0);
// Write instructions to the memory
addr[0] = 0xd2800005; // mov x5, #0x0
addr[1] = 0x910004a5; // add x5, x5, #0x1
addr[2] = 0x17ffffff; // b <address>
pthread_jit_write_protect_np(1);
sys_icache_invalidate(addr, size);
// Execute the code
int(*f)() = (int (*)()) addr;
(*f)();
return 0;
}
一旦汇编指令开始通过 (*f)() 调用执行,我可以在 Xcode 中暂停执行并键入
memory region {address of instructions}
进入调试器。由于某种原因,它不断返回 'rwx'。我使用的命令是否正确,或者这可能是 lldb 的错误?
当我 运行 你的小程序在 Mac 上我可以四处闲逛时(我在 x86_64 上但没关系,我实际上并不需要运行 说明...)我在 lldb 中看到:
Process 43209 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003f20 protectit`main at protectit.cpp:31
28 addr[2] = 0x17ffffff; // b <address>
29
30 pthread_jit_write_protect_np(1);
-> 31 sys_icache_invalidate(addr, size);
^
32
33 // Execute the code
34 int(*f)() = (int (*)()) addr;
Target 0: (protectit) stopped.
(lldb) memory region addr
[0x0000000101000000-0x0000000129000000) rwx
正如您所报告的那样。然后我用 vmmap 仔细检查:
> vmmap 43209 0x0000000101000000
0x101000000 is in 0x101000000-0x129000000; bytes after start: 0 bytes before end: 671088639
REGION TYPE START - END [ VSIZE RSDNT DIRTY SWAP] PRT/MAX SHRMOD PURGE REGION DETAIL
MALLOC_SMALL 100800000-101000000 [ 8192K 8K 8K 0K] rw-/rwx SM=PRV MallocHelperZone_0x1001c4000
---> VM_ALLOCATE 101000000-129000000 [640.0M 4K 4K 0K] rwx/rwx SM=PRV
GAP OF 0x5ffed7000000 BYTES
MALLOC_NANO 600000000000-600008000000 [128.0M 88K 88K 0K] rw-/rwx SM=PRV DefaultMallocZone_0x1001f1000
所以 vmmap 同意 lldb 的区域是 rwx。
无论 pthread_jit_write_protect_np 在做什么,它似乎都没有改变底层内存区域保护。
我发现我的问题的答案是阅读一个名为 S3_6_c15_c1_5 的未记录的 Apple 寄存器。
此代码从寄存器中读取原始值:
// Returns the S3_6_c15_c1_5 register's value
uint64_t read_S3_6_c15_c1_5_register(void)
{
uint64_t v;
__asm__ __volatile__("isb sy\n"
"mrs %0, S3_6_c15_c1_5\n"
: "=r"(v)::"memory");
return v;
}
此代码告诉您线程的当前模式是什么:
// Returns the mode for a thread.
// Returns "Executable" or "Writable".
// Remember to free() the value returned by this function.
char *get_thread_mode()
{
uint64_t value = read_S3_6_c15_c1_5_register();
char *return_value = (char *) malloc(50);
switch(value)
{
case 0x2010000030300000:
sprintf(return_value, "Writable");
break;
case 0x2010000030100000:
sprintf(return_value, "Executable");
break;
default:
sprintf(return_value, "Unknown state: %llx", value);
}
return return_value;
}
这是一个演示这两个功能的小测试程序:
int main(int argc, char *argv[]) {
pthread_jit_write_protect_np(1);
printf("Thread's mode: %s\n", get_thread_mode());
// The mode is Executable
pthread_jit_write_protect_np(0);
printf("Thread's mode: %s\n", get_thread_mode());
// The mode is Writable
return 0;
}