|
13 | 13 | #include<sys/time.h> |
14 | 14 | #include<sys/types.h> |
15 | 15 | #include<sys/ucontext.h> |
| 16 | +#include<sys/user.h> |
16 | 17 |
|
17 | 18 | #include<sys/fcntl.h>// open |
18 | 19 | #include<sys/mman.h>// mmap & munmap |
19 | 20 | #include<sys/stat.h>// open |
| 21 | +#include<sys/sysctl.h> |
20 | 22 | #include<unistd.h>// getpagesize |
21 | 23 | // If you don't have execinfo.h then you need devel/libexecinfo from ports. |
22 | 24 | #include<errno.h> |
@@ -46,41 +48,47 @@ static unsigned StringToLong(char* buffer){ |
46 | 48 |
|
47 | 49 | std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses(){ |
48 | 50 | std::vector<SharedLibraryAddress> result; |
49 | | -staticconstint MAP_LENGTH = 1024; |
50 | | -int fd = open("/proc/self/maps", O_RDONLY); |
51 | | -if (fd < 0) return result; |
52 | | -while (true){ |
53 | | -char addr_buffer[11]; |
54 | | - addr_buffer[0] = '0'; |
55 | | - addr_buffer[1] = 'x'; |
56 | | - addr_buffer[10] = 0; |
57 | | -ssize_t bytes_read = read(fd, addr_buffer + 2, 8); |
58 | | -if (bytes_read < 8) break; |
59 | | -unsigned start = StringToLong(addr_buffer); |
60 | | - bytes_read = read(fd, addr_buffer + 2, 1); |
61 | | -if (bytes_read < 1) break; |
62 | | -if (addr_buffer[2] != '-') break; |
63 | | - bytes_read = read(fd, addr_buffer + 2, 8); |
64 | | -if (bytes_read < 8) break; |
65 | | -unsigned end = StringToLong(addr_buffer); |
66 | | -char buffer[MAP_LENGTH]; |
67 | | - bytes_read = -1; |
68 | | -do{ |
69 | | - bytes_read++; |
70 | | -if (bytes_read >= MAP_LENGTH - 1) break; |
71 | | - bytes_read = read(fd, buffer + bytes_read, 1); |
72 | | -if (bytes_read < 1) break; |
73 | | - } while (buffer[bytes_read] != '\n'); |
74 | | - buffer[bytes_read] = 0; |
75 | | -// Ignore mappings that are not executable. |
76 | | -if (buffer[3] != 'x') continue; |
77 | | -char* start_of_path = index(buffer, '/'); |
78 | | -// There may be no filename in this line. Skip to next. |
79 | | -if (start_of_path == nullptr) continue; |
80 | | - buffer[bytes_read] = 0; |
81 | | - result.push_back(SharedLibraryAddress(start_of_path, start, end)); |
| 51 | +int mib[4] ={CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; |
| 52 | +size_t miblen = sizeof(mib) / sizeof(mib[0]); |
| 53 | +size_t buffer_size; |
| 54 | +if (sysctl(mib, miblen, nullptr, &buffer_size, nullptr, 0) == 0){ |
| 55 | +// Overallocate the buffer by 1/3 to account for concurrent |
| 56 | +// kinfo_vmentry change. 1/3 is an arbitrary constant that |
| 57 | +// works in practice. |
| 58 | + buffer_size = buffer_size * 4 / 3; |
| 59 | + std::vector<char> buffer(buffer_size); |
| 60 | +int ret = sysctl(mib, miblen, buffer.data(), &buffer_size, nullptr, 0); |
| 61 | + |
| 62 | +if (ret == 0 || (ret == -1 && errno == ENOMEM)){ |
| 63 | +char* start = buffer.data(); |
| 64 | +char* end = start + buffer_size; |
| 65 | + |
| 66 | +while (start < end){ |
| 67 | +structkinfo_vmentry* map = |
| 68 | +reinterpret_cast<structkinfo_vmentry*>(start); |
| 69 | +constsize_t ssize = map->kve_structsize; |
| 70 | +char* path = map->kve_path; |
| 71 | + |
| 72 | +CHECK_NE(0, ssize); |
| 73 | + |
| 74 | +if ((map->kve_protection & KVME_PROT_READ) != 0 && |
| 75 | + (map->kve_protection & KVME_PROT_EXEC) != 0 && path[0] != '\0'){ |
| 76 | +char* sep = strrchr(path, '/'); |
| 77 | + std::string lib_name; |
| 78 | +if (sep != nullptr){ |
| 79 | + lib_name = std::string(++sep); |
| 80 | + } else{ |
| 81 | + lib_name = std::string(path); |
| 82 | + } |
| 83 | + result.push_back(SharedLibraryAddress( |
| 84 | + lib_name, reinterpret_cast<uintptr_t>(map->kve_start), |
| 85 | +reinterpret_cast<uintptr_t>(map->kve_end))); |
| 86 | + } |
| 87 | + |
| 88 | + start += ssize; |
| 89 | + } |
| 90 | + } |
82 | 91 | } |
83 | | -close(fd); |
84 | 92 | return result; |
85 | 93 | } |
86 | 94 |
|
|
0 commit comments