]> git.zerfleddert.de Git - proxmark3-svn/blob - client/whereami.c
added testing timeout 40 sec to avoid hang VM
[proxmark3-svn] / client / whereami.c
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
10 extern "C" {
11 #endif
12
13 #if defined(__linux__)
14 // make realpath() available:
15 #define _DEFAULT_SOURCE
16 #endif
17
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>
59 //#include <intrin.h> // not required and doesn't exist in old mingw environments
60 #if defined(_MSC_VER)
61 #pragma warning(pop)
62 #endif
63
64 static 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
137 WAI_NOINLINE
138 WAI_FUNCSPEC
139 int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
140 {
141 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
142 }
143
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
147 WAI_FUNCSPEC
148 int 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 }
167 */
168
169 #elif defined(__linux__)
170
171 #include <stdio.h>
172 #include <stdlib.h>
173 #include <string.h>
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>
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
185 WAI_FUNCSPEC
186 int 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
237 WAI_NOINLINE
238 WAI_FUNCSPEC
239 int 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
264 if (sscanf(buffer, "%" SCNx64 "-%" SCNx64 " %s %" SCNx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
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
355 WAI_FUNCSPEC
356 int 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
407 WAI_NOINLINE
408 WAI_FUNCSPEC
409 int 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
464 WAI_FUNCSPEC
465 int 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
514 WAI_FUNCSPEC
515 int 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
568 WAI_FUNCSPEC
569 int 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
618 WAI_NOINLINE
619 WAI_FUNCSPEC
620 int 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