Skip to content

Commit 34d952d

Browse files
Add dyld helpers
1 parent e330a66 commit 34d952d

File tree

2 files changed

+170
-3
lines changed

2 files changed

+170
-3
lines changed

source/os/mach/dyld.d

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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+
}

source/mach/ports.d source/os/mach/ports.d

+15-3
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,29 @@
99
/**
1010
Mach Ports bindings
1111
*/
12-
module mach.ports;
12+
module os.mach.ports;
1313
import objc.os;
1414

15-
extern(C) nothrow @nogc:
15+
version (OSX)
16+
version = Darwin;
17+
else version (iOS)
18+
version = Darwin;
19+
else version (TVOS)
20+
version = Darwin;
21+
else version (WatchOS)
22+
version = Darwin;
1623

24+
version (Darwin):
25+
extern (C) nothrow @nogc:
26+
27+
// Contains definitions for mach_port_t and natural_t.
1728
public import core.sys.darwin.mach.port;
29+
1830
public import core.sys.darwin.mach.kern_return;
1931
public import core.sys.darwin.mach.semaphore;
2032

2133
/// IPC Space
22-
struct ipc_space;
34+
struct ipc_space; // @suppress(dscanner.style.phobos_naming_convention)
2335
alias ipc_space_t = ipc_space*;
2436

2537
/**

0 commit comments

Comments
 (0)