]> git.zerfleddert.de Git - proxmark3-svn/blame - client/whereami.c
adjust hardnested compiler fix to accurate version
[proxmark3-svn] / client / whereami.c
CommitLineData
4197a3f6 1// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
2// https://github.com/gpakosz/whereami
3
4// in case you want to #include "whereami.c" in a larger compilation unit
5#if !defined(WHEREAMI_H)
6#include <whereami.h>
7#endif
8
9#ifdef __cplusplus
10extern "C" {
11#endif
12
a9d08ed0 13#if defined(__linux__)
14// make realpath() available:
15#define _DEFAULT_SOURCE
16#endif
17
4197a3f6 18#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
19#include <stdlib.h>
20#endif
21
22#if !defined(WAI_MALLOC)
23#define WAI_MALLOC(size) malloc(size)
24#endif
25
26#if !defined(WAI_FREE)
27#define WAI_FREE(p) free(p)
28#endif
29
30#if !defined(WAI_REALLOC)
31#define WAI_REALLOC(p, size) realloc(p, size)
32#endif
33
34#ifndef WAI_NOINLINE
35#if defined(_MSC_VER)
36#define WAI_NOINLINE __declspec(noinline)
37#elif defined(__GNUC__)
38#define WAI_NOINLINE __attribute__((noinline))
39#else
40#error unsupported compiler
41#endif
42#endif
43
44#if defined(_MSC_VER)
45#define WAI_RETURN_ADDRESS() _ReturnAddress()
46#elif defined(__GNUC__)
47#define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
48#else
49#error unsupported compiler
50#endif
51
52#if defined(_WIN32)
53
54#define WIN32_LEAN_AND_MEAN
55#if defined(_MSC_VER)
56#pragma warning(push, 3)
57#endif
58#include <windows.h>
5a6a7aff 59//#include <intrin.h> // not required and doesn't exist in old mingw environments
4197a3f6 60#if defined(_MSC_VER)
61#pragma warning(pop)
62#endif
63
64static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
65{
66 wchar_t buffer1[MAX_PATH];
67 wchar_t buffer2[MAX_PATH];
68 wchar_t* path = NULL;
69 int length = -1;
70
71 for (;;)
72 {
73 DWORD size;
74 int length_, length__;
75
76 size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0]));
77
78 if (size == 0)
79 break;
80 else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0])))
81 {
82 DWORD size_ = size;
83 do
84 {
85 wchar_t* path_;
86
87 path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2);
88 if (!path_)
89 break;
90 size_ *= 2;
91 path = path_;
92 size = GetModuleFileNameW(module, path, size_);
93 }
94 while (size == size_);
95
96 if (size == size_)
97 break;
98 }
99 else
100 path = buffer1;
101
102 if (!_wfullpath(buffer2, path, MAX_PATH))
103 break;
104 length_ = (int)wcslen(buffer2);
105 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_ , out, capacity, NULL, NULL);
106
107 if (length__ == 0)
108 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL);
109 if (length__ == 0)
110 break;
111
112 if (length__ <= capacity && dirname_length)
113 {
114 int i;
115
116 for (i = length__ - 1; i >= 0; --i)
117 {
118 if (out[i] == '\\')
119 {
120 *dirname_length = i;
121 break;
122 }
123 }
124 }
125
126 length = length__;
127
128 break;
129 }
130
131 if (path != buffer1)
132 WAI_FREE(path);
133
134 return length;
135}
136
137WAI_NOINLINE
138WAI_FUNCSPEC
139int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
140{
141 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
142}
143
5a6a7aff 144// GetModuleHandleEx() is not available on old mingw environments. We don't need getModulePath() yet.
145// Sacrifice it for the time being to improve backwards compatibility
146/* WAI_NOINLINE
4197a3f6 147WAI_FUNCSPEC
148int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
149{
150 HMODULE module;
151 int length = -1;
152
153#if defined(_MSC_VER)
154#pragma warning(push)
155#pragma warning(disable: 4054)
156#endif
157 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
158#if defined(_MSC_VER)
159#pragma warning(pop)
160#endif
161 {
162 length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
163 }
164
165 return length;
166}
5a6a7aff 167 */
4197a3f6 168
169#elif defined(__linux__)
170
171#include <stdio.h>
172#include <stdlib.h>
173#include <string.h>
5a6a7aff 174// #include <limits.h> // not all linux distributions define PATH_MAX in limits.h because it depends on the filesystem. Therefore use...
175#include <linux/limits.h>
4197a3f6 176#ifndef __STDC_FORMAT_MACROS
177#define __STDC_FORMAT_MACROS
178#endif
179#include <inttypes.h>
180
181#if !defined(WAI_PROC_SELF_EXE)
182#define WAI_PROC_SELF_EXE "/proc/self/exe"
183#endif
184
185WAI_FUNCSPEC
186int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
187{
188 char buffer[PATH_MAX];
189 char* resolved = NULL;
190 int length = -1;
191
192 for (;;)
193 {
194 resolved = realpath(WAI_PROC_SELF_EXE, buffer);
195 if (!resolved)
196 break;
197
198 length = (int)strlen(resolved);
199 if (length <= capacity)
200 {
201 memcpy(out, resolved, length);
202
203 if (dirname_length)
204 {
205 int i;
206
207 for (i = length - 1; i >= 0; --i)
208 {
209 if (out[i] == '/')
210 {
211 *dirname_length = i;
212 break;
213 }
214 }
215 }
216 }
217
218 break;
219 }
220
221 return length;
222}
223
224#if !defined(WAI_PROC_SELF_MAPS_RETRY)
225#define WAI_PROC_SELF_MAPS_RETRY 5
226#endif
227
228#if !defined(WAI_PROC_SELF_MAPS)
229#define WAI_PROC_SELF_MAPS "/proc/self/maps"
230#endif
231
232#if defined(__ANDROID__) || defined(ANDROID)
233#include <fcntl.h>
234#include <sys/mman.h>
235#endif
236
237WAI_NOINLINE
238WAI_FUNCSPEC
239int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
240{
241 int length = -1;
242 FILE* maps = NULL;
243 int i;
244
245 for (i = 0; i < WAI_PROC_SELF_MAPS_RETRY; ++i)
246 {
247 maps = fopen(WAI_PROC_SELF_MAPS, "r");
248 if (!maps)
249 break;
250
251 for (;;)
252 {
253 char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
254 uint64_t low, high;
255 char perms[5];
256 uint64_t offset;
257 uint32_t major, minor;
258 char path[PATH_MAX];
259 uint32_t inode;
260
261 if (!fgets(buffer, sizeof(buffer), maps))
262 break;
263
7cb8516c 264 if (sscanf(buffer, "%" SCNx64 "-%" SCNx64 " %s %" SCNx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
4197a3f6 265 {
266 uint64_t addr = (uint64_t)(uintptr_t)WAI_RETURN_ADDRESS();
267 if (low <= addr && addr <= high)
268 {
269 char* resolved;
270
271 resolved = realpath(path, buffer);
272 if (!resolved)
273 break;
274
275 length = (int)strlen(resolved);
276#if defined(__ANDROID__) || defined(ANDROID)
277 if (length > 4
278 &&buffer[length - 1] == 'k'
279 &&buffer[length - 2] == 'p'
280 &&buffer[length - 3] == 'a'
281 &&buffer[length - 4] == '.')
282 {
283 int fd = open(path, O_RDONLY);
284 char* begin;
285 char* p;
286
287 begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
288 p = begin + offset;
289
290 while (p >= begin) // scan backwards
291 {
292 if (*((uint32_t*)p) == 0x04034b50UL) // local file header found
293 {
294 uint16_t length_ = *((uint16_t*)(p + 26));
295
296 if (length + 2 + length_ < (int)sizeof(buffer))
297 {
298 memcpy(&buffer[length], "!/", 2);
299 memcpy(&buffer[length + 2], p + 30, length_);
300 length += 2 + length_;
301 }
302
303 break;
304 }
305
306 p -= 4;
307 }
308
309 munmap(begin, offset);
310 close(fd);
311 }
312#endif
313 if (length <= capacity)
314 {
315 memcpy(out, resolved, length);
316
317 if (dirname_length)
318 {
319 int i;
320
321 for (i = length - 1; i >= 0; --i)
322 {
323 if (out[i] == '/')
324 {
325 *dirname_length = i;
326 break;
327 }
328 }
329 }
330 }
331
332 break;
333 }
334 }
335 }
336
337 fclose(maps);
338
339 if (length != -1)
340 break;
341 }
342
343 return length;
344}
345
346#elif defined(__APPLE__)
347
348#define _DARWIN_BETTER_REALPATH
349#include <mach-o/dyld.h>
350#include <limits.h>
351#include <stdlib.h>
352#include <string.h>
353#include <dlfcn.h>
354
355WAI_FUNCSPEC
356int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
357{
358 char buffer1[PATH_MAX];
359 char buffer2[PATH_MAX];
360 char* path = buffer1;
361 char* resolved = NULL;
362 int length = -1;
363
364 for (;;)
365 {
366 uint32_t size = (uint32_t)sizeof(buffer1);
367 if (_NSGetExecutablePath(path, &size) == -1)
368 {
369 path = (char*)WAI_MALLOC(size);
370 if (!_NSGetExecutablePath(path, &size))
371 break;
372 }
373
374 resolved = realpath(path, buffer2);
375 if (!resolved)
376 break;
377
378 length = (int)strlen(resolved);
379 if (length <= capacity)
380 {
381 memcpy(out, resolved, length);
382
383 if (dirname_length)
384 {
385 int i;
386
387 for (i = length - 1; i >= 0; --i)
388 {
389 if (out[i] == '/')
390 {
391 *dirname_length = i;
392 break;
393 }
394 }
395 }
396 }
397
398 break;
399 }
400
401 if (path != buffer1)
402 WAI_FREE(path);
403
404 return length;
405}
406
407WAI_NOINLINE
408WAI_FUNCSPEC
409int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
410{
411 char buffer[PATH_MAX];
412 char* resolved = NULL;
413 int length = -1;
414
415 for(;;)
416 {
417 Dl_info info;
418
419 if (dladdr(WAI_RETURN_ADDRESS(), &info))
420 {
421 resolved = realpath(info.dli_fname, buffer);
422 if (!resolved)
423 break;
424
425 length = (int)strlen(resolved);
426 if (length <= capacity)
427 {
428 memcpy(out, resolved, length);
429
430 if (dirname_length)
431 {
432 int i;
433
434 for (i = length - 1; i >= 0; --i)
435 {
436 if (out[i] == '/')
437 {
438 *dirname_length = i;
439 break;
440 }
441 }
442 }
443 }
444 }
445
446 break;
447 }
448
449 return length;
450}
451
452#elif defined(__QNXNTO__)
453
454#include <limits.h>
455#include <stdio.h>
456#include <stdlib.h>
457#include <string.h>
458#include <dlfcn.h>
459
460#if !defined(WAI_PROC_SELF_EXE)
461#define WAI_PROC_SELF_EXE "/proc/self/exefile"
462#endif
463
464WAI_FUNCSPEC
465int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
466{
467 char buffer1[PATH_MAX];
468 char buffer2[PATH_MAX];
469 char* resolved = NULL;
470 FILE* self_exe = NULL;
471 int length = -1;
472
473 for (;;)
474 {
475 self_exe = fopen(WAI_PROC_SELF_EXE, "r");
476 if (!self_exe)
477 break;
478
479 if (!fgets(buffer1, sizeof(buffer1), self_exe))
480 break;
481
482 resolved = realpath(buffer1, buffer2);
483 if (!resolved)
484 break;
485
486 length = (int)strlen(resolved);
487 if (length <= capacity)
488 {
489 memcpy(out, resolved, length);
490
491 if (dirname_length)
492 {
493 int i;
494
495 for (i = length - 1; i >= 0; --i)
496 {
497 if (out[i] == '/')
498 {
499 *dirname_length = i;
500 break;
501 }
502 }
503 }
504 }
505
506 break;
507 }
508
509 fclose(self_exe);
510
511 return length;
512}
513
514WAI_FUNCSPEC
515int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
516{
517 char buffer[PATH_MAX];
518 char* resolved = NULL;
519 int length = -1;
520
521 for(;;)
522 {
523 Dl_info info;
524
525 if (dladdr(WAI_RETURN_ADDRESS(), &info))
526 {
527 resolved = realpath(info.dli_fname, buffer);
528 if (!resolved)
529 break;
530
531 length = (int)strlen(resolved);
532 if (length <= capacity)
533 {
534 memcpy(out, resolved, length);
535
536 if (dirname_length)
537 {
538 int i;
539
540 for (i = length - 1; i >= 0; --i)
541 {
542 if (out[i] == '/')
543 {
544 *dirname_length = i;
545 break;
546 }
547 }
548 }
549 }
550 }
551
552 break;
553 }
554
555 return length;
556}
557
558#elif defined(__DragonFly__) || defined(__FreeBSD__) || \
559 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
560
561#include <limits.h>
562#include <stdlib.h>
563#include <string.h>
564#include <sys/types.h>
565#include <sys/sysctl.h>
566#include <dlfcn.h>
567
568WAI_FUNCSPEC
569int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
570{
571 char buffer1[PATH_MAX];
572 char buffer2[PATH_MAX];
573 char* path = buffer1;
574 char* resolved = NULL;
575 int length = -1;
576
577 for (;;)
578 {
579 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
580 size_t size = sizeof(buffer1);
581
582 if (sysctl(mib, (u_int)(sizeof(mib) / sizeof(mib[0])), path, &size, NULL, 0) != 0)
583 break;
584
585 resolved = realpath(path, buffer2);
586 if (!resolved)
587 break;
588
589 length = (int)strlen(resolved);
590 if (length <= capacity)
591 {
592 memcpy(out, resolved, length);
593
594 if (dirname_length)
595 {
596 int i;
597
598 for (i = length - 1; i >= 0; --i)
599 {
600 if (out[i] == '/')
601 {
602 *dirname_length = i;
603 break;
604 }
605 }
606 }
607 }
608
609 break;
610 }
611
612 if (path != buffer1)
613 WAI_FREE(path);
614
615 return length;
616}
617
618WAI_NOINLINE
619WAI_FUNCSPEC
620int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
621{
622 char buffer[PATH_MAX];
623 char* resolved = NULL;
624 int length = -1;
625
626 for(;;)
627 {
628 Dl_info info;
629
630 if (dladdr(WAI_RETURN_ADDRESS(), &info))
631 {
632 resolved = realpath(info.dli_fname, buffer);
633 if (!resolved)
634 break;
635
636 length = (int)strlen(resolved);
637 if (length <= capacity)
638 {
639 memcpy(out, resolved, length);
640
641 if (dirname_length)
642 {
643 int i;
644
645 for (i = length - 1; i >= 0; --i)
646 {
647 if (out[i] == '/')
648 {
649 *dirname_length = i;
650 break;
651 }
652 }
653 }
654 }
655 }
656
657 break;
658 }
659
660 return length;
661}
662
663#else
664
665#error unsupported platform
666
667#endif
668
669#ifdef __cplusplus
670}
671#endif
Impressum, Datenschutz