| /* Maps several pages with or without MAP_NORESEVE. |
| Mappings with MAP_NORESEVE do not show in /proc/self/xmap |
| (only in /proc/self/rmap) until they actually materialize. |
| Very nice from Solaris kernel :-( |
| */ |
| |
| #include <dlfcn.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <wait.h> |
| #include <sys/mman.h> |
| #include <sys/param.h> |
| |
| static void *do_map(int flags) |
| { |
| flags |= MAP_PRIVATE | MAP_ANON; |
| void *addr = mmap(0, PAGESIZE, PROT_READ | PROT_WRITE, flags, -1, 0); |
| if (addr == NULL) { |
| perror("mmap"); |
| exit(1); |
| } else { |
| return addr; |
| } |
| } |
| |
| static void *do_dlopen(const char *pathname) |
| { |
| int mode = RTLD_LAZY | RTLD_LOCAL; |
| void *handle = dlopen(pathname, mode); |
| if (handle == NULL) { |
| fprintf(stderr, "dlopen failed for %s: %s", |
| pathname, dlerror()); |
| exit(1); |
| } else { |
| return handle; |
| } |
| } |
| |
| int main(int argc, const char *argv[]) |
| { |
| do_map(MAP_NORESERVE); |
| do_dlopen("libm.so"); |
| do_map(0); |
| do_map(0); |
| do_map(MAP_NORESERVE); |
| do_dlopen("liby.so"); |
| do_map(MAP_NORESERVE); |
| do_map(0); |
| do_map(0); |
| do_map(MAP_NORESERVE); |
| do_map(MAP_NORESERVE); |
| do_dlopen("libz.so"); |
| do_map(MAP_NORESERVE); |
| do_map(MAP_NORESERVE); |
| do_map(0); |
| |
| pid_t pid = fork(); |
| if (pid == -1) { |
| perror("fork"); |
| exit(1); |
| } |
| |
| if (pid == 0) { |
| do_map(MAP_NORESERVE); |
| do_map(0); |
| do_map(0); |
| do_dlopen("libw.so"); |
| do_map(0); |
| do_map(MAP_NORESERVE); |
| do_map(MAP_NORESERVE); |
| do_map(0); |
| printf("CHILD: PASSED\n"); |
| fflush(stdout); |
| return 0; |
| } |
| |
| int status; |
| if (waitpid(pid, &status, 0) != pid) { |
| perror("waitpid"); |
| } else if ((WIFEXITED(status) != 0) && (WEXITSTATUS(status) == 0)) { |
| printf("PASSED\n"); |
| } else { |
| fprintf(stderr, "FAILED: child exited with unexpected status %s %d\n", |
| WIFEXITED(status) ? "exit" : "signal", |
| WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); |
| } |
| |
| return 0; |
| } |