1
+ /*
2
+ Copyright © 2024, Kitsunebi Games EMV
3
+ Distributed under the Boost Software License, Version 1.0,
4
+ see LICENSE file.
5
+
6
+ Authors: Luna Nielsen
7
+ */
8
+
9
+ /**
10
+ Extensions to dyld API.
11
+ */
12
+ module os.mach.dyld ;
13
+ import dyld = core.sys.darwin.mach.dyld ;
14
+ import core.sys.darwin.dlfcn ;
15
+ import core.sys.darwin.mach.loader ;
16
+ import core.sys.darwin.mach.dyld :
17
+ _dyld_get_image_header,
18
+ _dyld_get_image_name,
19
+ _dyld_image_count;
20
+
21
+ version (OSX )
22
+ version = Darwin;
23
+ else version (iOS)
24
+ version = Darwin;
25
+ else version (TVOS)
26
+ version = Darwin;
27
+ else version (WatchOS)
28
+ version = Darwin;
29
+
30
+ version (Darwin):
31
+ extern (C ) nothrow @nogc :
32
+
33
+ /**
34
+ 32-bit mach header.
35
+ */
36
+ alias mach_header_32 = dyld.mach_header;
37
+
38
+ /**
39
+ 64-bit mach header.
40
+ */
41
+ alias mach_header_64 = dyld.mach_header_64;
42
+
43
+ /**
44
+ 32-bit mach section.
45
+ */
46
+ alias mach_section_32 = dyld.section;
47
+
48
+ /**
49
+ 64-bit mach section.
50
+ */
51
+ alias mach_section_64 = dyld.section_64;
52
+
53
+ /**
54
+ 32-bit mach section.
55
+ */
56
+ alias mach_segment_32 = dyld.segment_command;
57
+
58
+ /**
59
+ 64-bit mach section.
60
+ */
61
+ alias mach_segment_64 = dyld.segment_command_64;
62
+
63
+ /**
64
+ A mach header which matches the current device's architecture.
65
+ */
66
+ version (D_LP64 ) alias mach_header = mach_header_64;
67
+ else alias mach_header = mach_header_32;
68
+
69
+ /**
70
+ A mach section which matches the current device's architecture.
71
+ */
72
+ version (D_LP64 ) alias mach_section = mach_section_64;
73
+ else alias mach_section = mach_section_32;
74
+
75
+ /**
76
+ A mach segment which matches the current device's architecture.
77
+ */
78
+ version (D_LP64 ) alias mach_segment = mach_segment_64;
79
+ else alias mach_segment = mach_segment_32;
80
+
81
+ // Mask value for the mode value added to a dlopen handle.
82
+ enum size_t RTLD_MODEMASK = cast (size_t )- 4 ;
83
+
84
+ /**
85
+ Attempt to find a mach_header from its dlopen handle.
86
+
87
+ Returns: mach_header address or `null` on failure.
88
+ */
89
+ const (mach_header)* dyld_get_dlopen_image_header (void * handle) {
90
+ auto idx = dylib_get_dlopen_image_index(handle);
91
+ if (idx >= 0 ) {
92
+ return cast (const (mach_header)* )_dyld_get_image_header(cast (uint )idx);
93
+ }
94
+ return null ;
95
+ }
96
+
97
+ /**
98
+ Attempts to get the image path of a dlopen handle.
99
+
100
+ Returns: Image path on success, `null` on failure.
101
+ */
102
+ const (char )* dylib_get_dlopen_image_path (void * handle) {
103
+ auto idx = dylib_get_dlopen_image_index(handle);
104
+ if (idx >= 0 ) {
105
+ return _dyld_get_image_name (cast (uint )idx);
106
+ }
107
+ return null ;
108
+ }
109
+
110
+ /**
111
+ Attempts to get the image index of a dlopen handle.
112
+
113
+ Returns: Image index on success, `-1` on failure.
114
+ */
115
+ ptrdiff_t dylib_get_dlopen_image_index (void * handle) {
116
+ foreach (i; 0 .. _dyld_image_count()) {
117
+
118
+ // By passing RTLD_NOLOAD we won't be attempting to
119
+ // load an unloaded library.
120
+ // This prevents oopsies where you're trying to get the index
121
+ // of an image that is somehow not loaded (name mismatch??)
122
+ const (char )* name = _dyld_get_image_name(i);
123
+ if (void * probeHandle = dlopen(name, RTLD_NOLOAD | RTLD_LAZY )) {
124
+ dlclose(probeHandle);
125
+
126
+ // We strip the mode bits off the handle.
127
+ // So that we can match handles despite which RTLD parameters were passed.
128
+ if ((cast (size_t )handle & RTLD_MODEMASK ) ==
129
+ (cast (size_t )probeHandle & RTLD_MODEMASK ))
130
+ return i;
131
+ }
132
+ }
133
+ return - 1 ;
134
+ }
135
+
136
+ /**
137
+ Finds dlopen handle associated with the given mach_header.
138
+
139
+ Returns: Handle on success, `-1` on failure.
140
+ */
141
+ void * dylib_get_handle_for_header (const (mach_header)* header) {
142
+ Dl_info info;
143
+ if (dladdr(header, &info)) {
144
+
145
+ // Lookup the handle by getting the dli_fname from the header.
146
+ // since the header is located *within* the address space of
147
+ // the dylib.
148
+ void * handle = dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_LAZY );
149
+ dlclose(handle);
150
+ return handle;
151
+ }
152
+
153
+ // Not found.
154
+ return null ;
155
+ }
0 commit comments