| 105 | } |
| 106 | |
| 107 | ModuleLoader::Path ModuleLoader::getModulePath(void* address) |
| 108 | { |
| 109 | if (address == nullptr) |
| 110 | address = reinterpret_cast<void*>(&getModulePath); // any other function in this module would work |
| 111 | |
| 112 | #if defined(_WIN32) |
| 113 | |
| 114 | // Get the handle of the module which contains the address |
| 115 | HMODULE module; |
| 116 | const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | |
| 117 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; |
| 118 | if (!GetModuleHandleExA(flags, reinterpret_cast<LPCSTR>(address), &module)) |
| 119 | throw std::runtime_error("GetModuleHandleExA failed"); |
| 120 | |
| 121 | // Get the path of the module |
| 122 | // Since we don't know the length of the path, we use a buffer of increasing size |
| 123 | DWORD pathSize = MAX_PATH + 1; |
| 124 | for (; ;) |
| 125 | { |
| 126 | std::vector<wchar_t> path(pathSize); |
| 127 | DWORD result = GetModuleFileNameW(module, path.data(), pathSize); |
| 128 | if (result == 0) |
| 129 | throw std::runtime_error("GetModuleFileNameW failed"); |
| 130 | else if (result < pathSize) |
| 131 | return path.data(); |
| 132 | else |
| 133 | pathSize *= 2; |
| 134 | } |
| 135 | |
| 136 | #else |
| 137 | |
| 138 | // dladdr should return an absolute path on Linux except for the main executable |
| 139 | // On macOS it should always return an absolute path |
| 140 | Dl_info info; |
| 141 | if (dladdr(address, &info)) |
| 142 | { |
| 143 | // Check whether the path is absolute |
| 144 | if (info.dli_fname && info.dli_fname[0] == '/') |
| 145 | return info.dli_fname; |
| 146 | } |
| 147 | |
| 148 | #if defined(__APPLE__) |
| 149 | // This shouldn't happen |
| 150 | throw std::runtime_error("failed to get absolute path with dladdr"); |
| 151 | #else |
| 152 | // We failed to get an absolute path, so we try to parse /proc/self/maps |
| 153 | std::ifstream file("/proc/self/maps"); |
| 154 | if (!file) |
| 155 | throw std::runtime_error("could not open /proc/self/maps"); |
| 156 | |
| 157 | // Parse the lines |
| 158 | for (std::string lineStr; std::getline(file, lineStr); ) |
| 159 | { |
| 160 | std::istringstream line(lineStr); |
| 161 | |
| 162 | // Parse the address range |
| 163 | uintptr_t addressBegin, addressEnd; |
| 164 | line >> std::hex; |