whereami.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. // (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
  2. // in case you want to #include "whereami.c" in a larger compilation unit
  3. #if !defined(WHEREAMI_H)
  4. #include "whereami.h"
  5. #endif
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
  10. #include <stdlib.h>
  11. #endif
  12. #if !defined(WAI_MALLOC)
  13. #define WAI_MALLOC(size) malloc(size)
  14. #endif
  15. #if !defined(WAI_FREE)
  16. #define WAI_FREE(p) free(p)
  17. #endif
  18. #if !defined(WAI_REALLOC)
  19. #define WAI_REALLOC(p, size) realloc(p, size)
  20. #endif
  21. #if defined(_WIN32)
  22. #define WIN32_LEAN_AND_MEAN
  23. #if defined(_MSC_VER)
  24. #pragma warning(push, 3)
  25. #endif
  26. #include <windows.h>
  27. #include <intrin.h>
  28. #if defined(_MSC_VER)
  29. #pragma warning(pop)
  30. #endif
  31. #ifndef WAI_NOINLINE
  32. #ifdef _MSC_VER
  33. #define WAI_NOINLINE __declspec(noinline)
  34. #endif
  35. #endif
  36. static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
  37. {
  38. wchar_t buffer1[MAX_PATH];
  39. wchar_t buffer2[MAX_PATH];
  40. wchar_t* path = NULL;
  41. int length = -1;
  42. for (;;)
  43. {
  44. DWORD size;
  45. int length_;
  46. size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0]));
  47. if (size == 0)
  48. break;
  49. else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0])))
  50. {
  51. DWORD size_ = size;
  52. do
  53. {
  54. size_ *= 2;
  55. path = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_);
  56. size = GetModuleFileNameW(NULL, path, size_);
  57. } while (size == size_);
  58. }
  59. else
  60. path = buffer1;
  61. _wfullpath(buffer2, path, MAX_PATH);
  62. length_ = WideCharToMultiByte(CP_UTF8, 0, buffer2, -1, out, capacity, NULL, NULL);
  63. if (length_ == 0)
  64. length_ = WideCharToMultiByte(CP_UTF8, 0, buffer2, -1, NULL, 0, NULL, NULL);
  65. if (length_ == 0)
  66. break;
  67. if (length_ <= capacity && dirname_length)
  68. {
  69. int i;
  70. for (i = length_ - 1; i >= 0; --i)
  71. {
  72. if (out[i] == '\\')
  73. {
  74. *dirname_length = i;
  75. break;
  76. }
  77. }
  78. }
  79. length = length_;
  80. break;
  81. }
  82. if (path != buffer1)
  83. WAI_FREE(path);
  84. return length;
  85. }
  86. WAI_NOINLINE
  87. WAI_FUNCSPEC
  88. int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
  89. {
  90. return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
  91. }
  92. WAI_NOINLINE
  93. WAI_FUNCSPEC
  94. int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
  95. {
  96. HMODULE module;
  97. int length = -1;
  98. #if defined(_MSC_VER)
  99. #pragma warning(push)
  100. #pragma warning(disable: 4054)
  101. #endif
  102. if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)_ReturnAddress(), &module))
  103. #if defined(_MSC_VER)
  104. #pragma warning(pop)
  105. #endif
  106. {
  107. length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
  108. }
  109. return length;
  110. }
  111. #elif defined(__linux__)
  112. #include <stdio.h>
  113. #include <stdlib.h>
  114. #include <string.h>
  115. #include <limits.h>
  116. #ifndef __STDC_FORMAT_MACROS
  117. #define __STDC_FORMAT_MACROS
  118. #endif
  119. #include <inttypes.h>
  120. char *realpath(const char * pathname, char * resolved_path);
  121. #ifndef PATH_MAX
  122. #define PATH_MAX 4096
  123. #endif
  124. #if !defined(WAI_PROC_SELF_EXE)
  125. #define WAI_PROC_SELF_EXE "/proc/self/exe"
  126. #endif
  127. #ifndef WAI_NOINLINE
  128. #ifdef __GNUC__
  129. #define WAI_NOINLINE __attribute__((noinline))
  130. #endif
  131. #endif
  132. WAI_FUNCSPEC
  133. int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
  134. {
  135. char buffer[PATH_MAX];
  136. char* resolved = NULL;
  137. int length = -1;
  138. for (;;)
  139. {
  140. resolved = realpath(WAI_PROC_SELF_EXE, buffer);
  141. if (!resolved)
  142. break;
  143. length = (int)strlen(resolved);
  144. if (length <= capacity)
  145. {
  146. memcpy(out, resolved, length);
  147. if (dirname_length)
  148. {
  149. int i;
  150. for (i = length - 1; i >= 0; --i)
  151. {
  152. if (out[i] == '/')
  153. {
  154. *dirname_length = i;
  155. break;
  156. }
  157. }
  158. }
  159. }
  160. break;
  161. }
  162. return length;
  163. }
  164. #if !defined(WAI_PROC_SELF_MAPS_RETRY)
  165. #define WAI_PROC_SELF_MAPS_RETRY 5
  166. #endif
  167. #if !defined(WAI_PROC_SELF_MAPS)
  168. #define WAI_PROC_SELF_MAPS "/proc/self/maps"
  169. #endif
  170. WAI_NOINLINE
  171. WAI_FUNCSPEC
  172. int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
  173. {
  174. int length = -1;
  175. FILE* maps = NULL;
  176. int i;
  177. for (i = 0; i < WAI_PROC_SELF_MAPS_RETRY; ++i)
  178. {
  179. maps = fopen(WAI_PROC_SELF_MAPS, "r");
  180. if (!maps)
  181. break;
  182. for (;;)
  183. {
  184. char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
  185. uint64_t low, high;
  186. char perms[5];
  187. uint64_t offset;
  188. uint32_t major, minor;
  189. char path[PATH_MAX];
  190. uint32_t inode;
  191. if (!fgets(buffer, sizeof(buffer), maps))
  192. break;
  193. if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
  194. {
  195. uint64_t addr = (uint64_t)(uintptr_t) __builtin_extract_return_addr(__builtin_return_address(0));
  196. if (low <= addr && addr <= high)
  197. {
  198. char* resolved;
  199. resolved = realpath(path, buffer);
  200. if (!resolved)
  201. break;
  202. length = (int)strlen(resolved);
  203. if (length <= capacity)
  204. {
  205. memcpy(out, resolved, length);
  206. if (dirname_length)
  207. {
  208. int i;
  209. for (i = length - 1; i >= 0; --i)
  210. {
  211. if (out[i] == '/')
  212. {
  213. *dirname_length = i;
  214. break;
  215. }
  216. }
  217. }
  218. }
  219. break;
  220. }
  221. }
  222. }
  223. fclose(maps);
  224. if (length != -1)
  225. break;
  226. }
  227. return length;
  228. }
  229. #elif defined(__APPLE__)
  230. #define _DARWIN_BETTER_REALPATH
  231. #include <mach-o/dyld.h>
  232. #include <limits.h>
  233. #include <stdlib.h>
  234. #include <string.h>
  235. #include <dlfcn.h>
  236. #ifndef WAI_NOINLINE
  237. #ifdef __GNUC__
  238. #define WAI_NOINLINE __attribute__((noinline))
  239. #endif
  240. #endif
  241. WAI_FUNCSPEC
  242. int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
  243. {
  244. char buffer1[PATH_MAX];
  245. char buffer2[PATH_MAX];
  246. char* path = buffer1;
  247. char* resolved = NULL;
  248. int length = -1;
  249. for (;;)
  250. {
  251. uint32_t size = (uint32_t)sizeof(buffer1);
  252. if (_NSGetExecutablePath(path, &size) == -1)
  253. {
  254. path = (char*)WAI_MALLOC(size);
  255. if (!_NSGetExecutablePath(path, &size))
  256. break;
  257. }
  258. resolved = realpath(path, buffer2);
  259. if (!resolved)
  260. break;
  261. length = (int)strlen(resolved);
  262. if (length <= capacity)
  263. {
  264. memcpy(out, resolved, length);
  265. if (dirname_length)
  266. {
  267. int i;
  268. for (i = length - 1; i >= 0; --i)
  269. {
  270. if (out[i] == '/')
  271. {
  272. *dirname_length = i;
  273. break;
  274. }
  275. }
  276. }
  277. }
  278. break;
  279. }
  280. if (path != buffer1)
  281. WAI_FREE(path);
  282. return length;
  283. }
  284. WAI_NOINLINE
  285. WAI_FUNCSPEC
  286. int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
  287. {
  288. char buffer[PATH_MAX];
  289. char* resolved = NULL;
  290. int length = -1;
  291. for(;;)
  292. {
  293. Dl_info info;
  294. if (dladdr(__builtin_extract_return_addr(__builtin_return_address(0)), &info))
  295. {
  296. resolved = realpath(info.dli_fname, buffer);
  297. if (!resolved)
  298. break;
  299. length = (int)strlen(resolved);
  300. if (length <= capacity)
  301. {
  302. memcpy(out, resolved, length);
  303. if (dirname_length)
  304. {
  305. int i;
  306. for (i = length - 1; i >= 0; --i)
  307. {
  308. if (out[i] == '/')
  309. {
  310. *dirname_length = i;
  311. break;
  312. }
  313. }
  314. }
  315. }
  316. }
  317. break;
  318. }
  319. return length;
  320. }
  321. #elif defined(__QNXNTO__)
  322. #include <limits.h>
  323. #include <stdio.h>
  324. #include <stdlib.h>
  325. #include <string.h>
  326. #include <dlfcn.h>
  327. #ifndef WAI_NOINLINE
  328. #ifdef __GNUC__
  329. #define WAI_NOINLINE __attribute__((noinline))
  330. #endif
  331. #endif
  332. #if !defined(WAI_PROC_SELF_EXE)
  333. #define WAI_PROC_SELF_EXE "/proc/self/exefile"
  334. #endif
  335. WAI_FUNCSPEC
  336. int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
  337. {
  338. char buffer1[PATH_MAX];
  339. char buffer2[PATH_MAX];
  340. char* resolved = NULL;
  341. FILE* self_exe = NULL;
  342. int length = -1;
  343. for (;;)
  344. {
  345. self_exe = fopen(WAI_PROC_SELF_EXE, "r");
  346. if (!self_exe)
  347. break;
  348. if (!fgets(buffer1, sizeof(buffer1), self_exe))
  349. break;
  350. resolved = realpath(buffer1, buffer2);
  351. if (!resolved)
  352. break;
  353. length = (int)strlen(resolved);
  354. if (length <= capacity)
  355. {
  356. memcpy(out, resolved, length);
  357. if (dirname_length)
  358. {
  359. int i;
  360. for (i = length - 1; i >= 0; --i)
  361. {
  362. if (out[i] == '/')
  363. {
  364. *dirname_length = i;
  365. break;
  366. }
  367. }
  368. }
  369. }
  370. break;
  371. }
  372. fclose(self_exe);
  373. return length;
  374. }
  375. WAI_FUNCSPEC
  376. int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
  377. {
  378. char buffer[PATH_MAX];
  379. char* resolved = NULL;
  380. int length = -1;
  381. for(;;)
  382. {
  383. Dl_info info;
  384. if (dladdr(__builtin_extract_return_addr(__builtin_return_address(0)), &info))
  385. {
  386. resolved = realpath(info.dli_fname, buffer);
  387. if (!resolved)
  388. break;
  389. length = (int)strlen(resolved);
  390. if (length <= capacity)
  391. {
  392. memcpy(out, resolved, length);
  393. if (dirname_length)
  394. {
  395. int i;
  396. for (i = length - 1; i >= 0; --i)
  397. {
  398. if (out[i] == '/')
  399. {
  400. *dirname_length = i;
  401. break;
  402. }
  403. }
  404. }
  405. }
  406. }
  407. break;
  408. }
  409. return length;
  410. }
  411. #endif
  412. #ifdef __cplusplus
  413. }
  414. #endif