]> git.zerfleddert.de Git - proxmark3-svn/blame - client/whereami.c
Fix issues with commit 4197a3f on some linux distributions and old mingw environments...
[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
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>
5a6a7aff 54//#include <intrin.h> // not required and doesn't exist in old mingw environments
4197a3f6 55#if defined(_MSC_VER)
56#pragma warning(pop)
57#endif
58
59static 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
132WAI_NOINLINE
133WAI_FUNCSPEC
134int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
135{
136 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
137}
138
5a6a7aff 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
4197a3f6 142WAI_FUNCSPEC
143int 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}
5a6a7aff 162 */
4197a3f6 163
164#elif defined(__linux__)
165
166#include <stdio.h>
167#include <stdlib.h>
168#include <string.h>
5a6a7aff 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>
4197a3f6 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
180WAI_FUNCSPEC
181int 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
232WAI_NOINLINE
233WAI_FUNCSPEC
234int 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
350WAI_FUNCSPEC
351int 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
402WAI_NOINLINE
403WAI_FUNCSPEC
404int 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
459WAI_FUNCSPEC
460int 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
509WAI_FUNCSPEC
510int 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
563WAI_FUNCSPEC
564int 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
613WAI_NOINLINE
614WAI_FUNCSPEC
615int 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