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
| #include <stdio.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> /* open */ #include <stdint.h> /* uint64_t */ #include <stdlib.h> /* size_t */ #include <unistd.h> /* pread, sysconf */
typedef struct { uint64_t pfn : 54; unsigned int soft_dirty : 1; unsigned int file_page : 1; unsigned int swapped : 1; unsigned int present : 1; } PagemapEntry;
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) { size_t nread; ssize_t ret; uint64_t data; uintptr_t vpn;
vpn = vaddr / sysconf(_SC_PAGE_SIZE); nread = 0; while (nread < sizeof(data)) { ret = pread(pagemap_fd, &data, sizeof(data) - nread, vpn * sizeof(data) + nread); nread += ret; if (ret <= 0) { return 1; } } entry->pfn = data & (((uint64_t)1 << 54) - 1); entry->soft_dirty = (data >> 54) & 1; entry->file_page = (data >> 61) & 1; entry->swapped = (data >> 62) & 1; entry->present = (data >> 63) & 1; return 0; } int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) { char pagemap_file[BUFSIZ]; int pagemap_fd;
//读取对应进程地址映射 snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid); pagemap_fd = open(pagemap_file, O_RDONLY); if (pagemap_fd < 0) { return 1; } PagemapEntry entry; //条目获取 if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) { return 1; } close(pagemap_fd); *paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE)); return 0; }
int main(void) { setbuf(stdout, 0); int a = 0; pid_t pid = fork(); if (pid == 0) { //子进程 printf("Pid:%d\n",getpid()); printf("child: \n\tvirtual address:\t%llx\n\tphysical address:\t%llx\n", &a, syscall(335, &a)); sleep(2); } else { //父进程 printf("Pid:%d\n",getpid()); printf("parent: \n\tvirtual address:\t%llx\n\tphysical address:\t%llx\n", &a, syscall(335, &a)); uintptr_t aptr = &a; uintptr_t aphy = NULL; //子进程中该变量的物理地址 virt_to_phys_user(&aphy, pid, aptr); printf("child:\n\tpagemap approach:\t%llx\n", aphy); sleep(2); } return 0; }
|