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