1 // (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
2 // https://github.com/gpakosz/whereami
4 // in case you want to #include "whereami.c" in a larger compilation unit
5 #if !defined(WHEREAMI_H)
13 #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
17 #if !defined(WAI_MALLOC)
18 #define WAI_MALLOC(size) malloc(size)
21 #if !defined(WAI_FREE)
22 #define WAI_FREE(p) free(p)
25 #if !defined(WAI_REALLOC)
26 #define WAI_REALLOC(p, size) realloc(p, size)
31 #define WAI_NOINLINE __declspec(noinline)
32 #elif defined(__GNUC__)
33 #define WAI_NOINLINE __attribute__((noinline))
35 #error unsupported compiler
40 #define WAI_RETURN_ADDRESS() _ReturnAddress()
41 #elif defined(__GNUC__)
42 #define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
44 #error unsupported compiler
49 #define WIN32_LEAN_AND_MEAN
51 #pragma warning(push, 3)
59 static int WAI_PREFIX(getModulePath_
)(HMODULE module
, char* out
, int capacity
, int* dirname_length
)
61 wchar_t buffer1
[MAX_PATH
];
62 wchar_t buffer2
[MAX_PATH
];
69 int length_
, length__
;
71 size
= GetModuleFileNameW(module
, buffer1
, sizeof(buffer1
) / sizeof(buffer1
[0]));
75 else if (size
== (DWORD
)(sizeof(buffer1
) / sizeof(buffer1
[0])))
82 path_
= (wchar_t*)WAI_REALLOC(path
, sizeof(wchar_t) * size_
* 2);
87 size
= GetModuleFileNameW(module
, path
, size_
);
89 while (size
== size_
);
97 if (!_wfullpath(buffer2
, path
, MAX_PATH
))
99 length_
= (int)wcslen(buffer2
);
100 length__
= WideCharToMultiByte(CP_UTF8
, 0, buffer2
, length_
, out
, capacity
, NULL
, NULL
);
103 length__
= WideCharToMultiByte(CP_UTF8
, 0, buffer2
, length_
, NULL
, 0, NULL
, NULL
);
107 if (length__
<= capacity
&& dirname_length
)
111 for (i
= length__
- 1; i
>= 0; --i
)
134 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
136 return WAI_PREFIX(getModulePath_
)(NULL
, out
, capacity
, dirname_length
);
141 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
146 #if defined(_MSC_VER)
147 #pragma warning(push)
148 #pragma warning(disable: 4054)
150 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
, (LPCTSTR
)WAI_RETURN_ADDRESS(), &module
))
151 #if defined(_MSC_VER)
155 length
= WAI_PREFIX(getModulePath_
)(module
, out
, capacity
, dirname_length
);
161 #elif defined(__linux__)
167 #ifndef __STDC_FORMAT_MACROS
168 #define __STDC_FORMAT_MACROS
170 #include <inttypes.h>
172 #if !defined(WAI_PROC_SELF_EXE)
173 #define WAI_PROC_SELF_EXE "/proc/self/exe"
177 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
179 char buffer
[PATH_MAX
];
180 char* resolved
= NULL
;
185 resolved
= realpath(WAI_PROC_SELF_EXE
, buffer
);
189 length
= (int)strlen(resolved
);
190 if (length
<= capacity
)
192 memcpy(out
, resolved
, length
);
198 for (i
= length
- 1; i
>= 0; --i
)
215 #if !defined(WAI_PROC_SELF_MAPS_RETRY)
216 #define WAI_PROC_SELF_MAPS_RETRY 5
219 #if !defined(WAI_PROC_SELF_MAPS)
220 #define WAI_PROC_SELF_MAPS "/proc/self/maps"
223 #if defined(__ANDROID__) || defined(ANDROID)
225 #include <sys/mman.h>
230 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
236 for (i
= 0; i
< WAI_PROC_SELF_MAPS_RETRY
; ++i
)
238 maps
= fopen(WAI_PROC_SELF_MAPS
, "r");
244 char buffer
[PATH_MAX
< 1024 ? 1024 : PATH_MAX
];
248 uint32_t major
, minor
;
252 if (!fgets(buffer
, sizeof(buffer
), maps
))
255 if (sscanf(buffer
, "%" PRIx64
"-%" PRIx64
" %s %" PRIx64
" %x:%x %u %s\n", &low
, &high
, perms
, &offset
, &major
, &minor
, &inode
, path
) == 8)
257 uint64_t addr
= (uint64_t)(uintptr_t)WAI_RETURN_ADDRESS();
258 if (low
<= addr
&& addr
<= high
)
262 resolved
= realpath(path
, buffer
);
266 length
= (int)strlen(resolved
);
267 #if defined(__ANDROID__) || defined(ANDROID)
269 &&buffer
[length
- 1] == 'k'
270 &&buffer
[length
- 2] == 'p'
271 &&buffer
[length
- 3] == 'a'
272 &&buffer
[length
- 4] == '.')
274 int fd
= open(path
, O_RDONLY
);
278 begin
= (char*)mmap(0, offset
, PROT_READ
, MAP_SHARED
, fd
, 0);
281 while (p
>= begin
) // scan backwards
283 if (*((uint32_t*)p
) == 0x04034b50UL
) // local file header found
285 uint16_t length_
= *((uint16_t*)(p
+ 26));
287 if (length
+ 2 + length_
< (int)sizeof(buffer
))
289 memcpy(&buffer
[length
], "!/", 2);
290 memcpy(&buffer
[length
+ 2], p
+ 30, length_
);
291 length
+= 2 + length_
;
300 munmap(begin
, offset
);
304 if (length
<= capacity
)
306 memcpy(out
, resolved
, length
);
312 for (i
= length
- 1; i
>= 0; --i
)
337 #elif defined(__APPLE__)
339 #define _DARWIN_BETTER_REALPATH
340 #include <mach-o/dyld.h>
347 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
349 char buffer1
[PATH_MAX
];
350 char buffer2
[PATH_MAX
];
351 char* path
= buffer1
;
352 char* resolved
= NULL
;
357 uint32_t size
= (uint32_t)sizeof(buffer1
);
358 if (_NSGetExecutablePath(path
, &size
) == -1)
360 path
= (char*)WAI_MALLOC(size
);
361 if (!_NSGetExecutablePath(path
, &size
))
365 resolved
= realpath(path
, buffer2
);
369 length
= (int)strlen(resolved
);
370 if (length
<= capacity
)
372 memcpy(out
, resolved
, length
);
378 for (i
= length
- 1; i
>= 0; --i
)
400 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
402 char buffer
[PATH_MAX
];
403 char* resolved
= NULL
;
410 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
412 resolved
= realpath(info
.dli_fname
, buffer
);
416 length
= (int)strlen(resolved
);
417 if (length
<= capacity
)
419 memcpy(out
, resolved
, length
);
425 for (i
= length
- 1; i
>= 0; --i
)
443 #elif defined(__QNXNTO__)
451 #if !defined(WAI_PROC_SELF_EXE)
452 #define WAI_PROC_SELF_EXE "/proc/self/exefile"
456 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
458 char buffer1
[PATH_MAX
];
459 char buffer2
[PATH_MAX
];
460 char* resolved
= NULL
;
461 FILE* self_exe
= NULL
;
466 self_exe
= fopen(WAI_PROC_SELF_EXE
, "r");
470 if (!fgets(buffer1
, sizeof(buffer1
), self_exe
))
473 resolved
= realpath(buffer1
, buffer2
);
477 length
= (int)strlen(resolved
);
478 if (length
<= capacity
)
480 memcpy(out
, resolved
, length
);
486 for (i
= length
- 1; i
>= 0; --i
)
506 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
508 char buffer
[PATH_MAX
];
509 char* resolved
= NULL
;
516 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
518 resolved
= realpath(info
.dli_fname
, buffer
);
522 length
= (int)strlen(resolved
);
523 if (length
<= capacity
)
525 memcpy(out
, resolved
, length
);
531 for (i
= length
- 1; i
>= 0; --i
)
549 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
550 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
555 #include <sys/types.h>
556 #include <sys/sysctl.h>
560 int WAI_PREFIX(getExecutablePath
)(char* out
, int capacity
, int* dirname_length
)
562 char buffer1
[PATH_MAX
];
563 char buffer2
[PATH_MAX
];
564 char* path
= buffer1
;
565 char* resolved
= NULL
;
570 int mib
[4] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
571 size_t size
= sizeof(buffer1
);
573 if (sysctl(mib
, (u_int
)(sizeof(mib
) / sizeof(mib
[0])), path
, &size
, NULL
, 0) != 0)
576 resolved
= realpath(path
, buffer2
);
580 length
= (int)strlen(resolved
);
581 if (length
<= capacity
)
583 memcpy(out
, resolved
, length
);
589 for (i
= length
- 1; i
>= 0; --i
)
611 int WAI_PREFIX(getModulePath
)(char* out
, int capacity
, int* dirname_length
)
613 char buffer
[PATH_MAX
];
614 char* resolved
= NULL
;
621 if (dladdr(WAI_RETURN_ADDRESS(), &info
))
623 resolved
= realpath(info
.dli_fname
, buffer
);
627 length
= (int)strlen(resolved
);
628 if (length
<= capacity
)
630 memcpy(out
, resolved
, length
);
636 for (i
= length
- 1; i
>= 0; --i
)
656 #error unsupported platform