/src/node/deps/postject/postject-api.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef POSTJECT_API_H_ |
2 | | #define POSTJECT_API_H_ |
3 | | |
4 | | #include <stdbool.h> |
5 | | #include <stddef.h> |
6 | | #include <stdlib.h> |
7 | | #include <string.h> |
8 | | |
9 | | #if defined(__APPLE__) && defined(__MACH__) |
10 | | #include <mach-o/dyld.h> |
11 | | #include <mach-o/getsect.h> |
12 | | #elif defined(__linux__) |
13 | | #include <elf.h> |
14 | | #include <link.h> |
15 | | #include <sys/param.h> |
16 | | #elif defined(_WIN32) |
17 | | #include <windows.h> |
18 | | #endif |
19 | | |
20 | | #ifndef POSTJECT_SENTINEL_FUSE |
21 | | #define POSTJECT_SENTINEL_FUSE \ |
22 | | "POSTJECT_SENTINEL_fce680ab2cc467b6e072b8b5df1996b2" |
23 | | #endif |
24 | | |
25 | | struct postject_options { |
26 | | const char* elf_section_name; |
27 | | const char* macho_framework_name; |
28 | | const char* macho_section_name; |
29 | | const char* macho_segment_name; |
30 | | const char* pe_resource_name; |
31 | | }; |
32 | | |
33 | 0 | inline void postject_options_init(struct postject_options* options) { |
34 | 0 | options->elf_section_name = NULL; |
35 | 0 | options->macho_framework_name = NULL; |
36 | 0 | options->macho_section_name = NULL; |
37 | 0 | options->macho_segment_name = NULL; |
38 | 0 | options->pe_resource_name = NULL; |
39 | 0 | } |
40 | | |
41 | 488k | static inline bool postject_has_resource() { |
42 | 488k | static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0"; |
43 | 488k | return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1'; |
44 | 488k | } |
45 | | |
46 | | #if defined(__linux__) |
47 | | static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, |
48 | | size_t size, |
49 | 0 | void* data) { |
50 | | // Snag the dl_phdr_info struct for the main program, then stop iterating |
51 | 0 | *((struct dl_phdr_info*)data) = *info; |
52 | 0 | return 1; |
53 | 0 | } |
54 | | #endif |
55 | | |
56 | | static const void* postject_find_resource( |
57 | | const char* name, |
58 | | size_t* size, |
59 | 0 | const struct postject_options* options) { |
60 | | // Always zero out the size pointer to start |
61 | 0 | if (size != NULL) { |
62 | 0 | *size = 0; |
63 | 0 | } |
64 | |
|
65 | | #if defined(__APPLE__) && defined(__MACH__) |
66 | | char* section_name = NULL; |
67 | | const char* segment_name = "__POSTJECT"; |
68 | | |
69 | | if (options != NULL && options->macho_segment_name != NULL) { |
70 | | segment_name = options->macho_segment_name; |
71 | | } |
72 | | |
73 | | if (options != NULL && options->macho_section_name != NULL) { |
74 | | name = options->macho_section_name; |
75 | | } else if (strncmp(name, "__", 2) != 0) { |
76 | | // Automatically prepend __ to match naming convention |
77 | | section_name = (char*)malloc(strlen(name) + 3); |
78 | | if (section_name == NULL) { |
79 | | return NULL; |
80 | | } |
81 | | strcpy(section_name, "__"); |
82 | | strcat(section_name, name); |
83 | | } |
84 | | |
85 | | unsigned long section_size; |
86 | | char* ptr = NULL; |
87 | | if (options != NULL && options->macho_framework_name != NULL) { |
88 | | #ifdef __clang__ |
89 | | #pragma clang diagnostic push |
90 | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
91 | | #endif |
92 | | ptr = getsectdatafromFramework(options->macho_framework_name, segment_name, |
93 | | section_name != NULL ? section_name : name, |
94 | | §ion_size); |
95 | | } else { |
96 | | ptr = getsectdata(segment_name, section_name != NULL ? section_name : name, |
97 | | §ion_size); |
98 | | #ifdef __clang__ |
99 | | #pragma clang diagnostic pop |
100 | | #endif |
101 | | |
102 | | if (ptr != NULL) { |
103 | | // Add the "virtual memory address slide" amount to ensure a valid pointer |
104 | | // in cases where the virtual memory address have been adjusted by the OS. |
105 | | // |
106 | | // NOTE - `getsectdataFromFramework` already handles this adjustment for |
107 | | // us, which is why we only do it for `getsectdata`, see: |
108 | | // https://web.archive.org/web/20220613234007/https://opensource.apple.com/source/cctools/cctools-590/libmacho/getsecbyname.c.auto.html |
109 | | ptr += _dyld_get_image_vmaddr_slide(0); |
110 | | } |
111 | | } |
112 | | |
113 | | free(section_name); |
114 | | |
115 | | if (size != NULL) { |
116 | | *size = (size_t)section_size; |
117 | | } |
118 | | |
119 | | return ptr; |
120 | | #elif defined(__linux__) |
121 | |
|
122 | 0 | if (options != NULL && options->elf_section_name != NULL) { |
123 | 0 | name = options->elf_section_name; |
124 | 0 | } |
125 | |
|
126 | 0 | struct dl_phdr_info main_program_info; |
127 | 0 | dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info); |
128 | |
|
129 | 0 | uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr; |
130 | 0 | size_t n = main_program_info.dlpi_phnum; |
131 | 0 | uintptr_t base_addr = main_program_info.dlpi_addr; |
132 | | |
133 | | // iterate program header |
134 | 0 | for (; n > 0; n--, p += sizeof(ElfW(Phdr))) { |
135 | 0 | ElfW(Phdr)* phdr = (ElfW(Phdr)*)p; |
136 | | |
137 | | // skip everything but notes |
138 | 0 | if (phdr->p_type != PT_NOTE) { |
139 | 0 | continue; |
140 | 0 | } |
141 | | |
142 | | // note segment starts at base address + segment virtual address |
143 | 0 | uintptr_t pos = (base_addr + phdr->p_vaddr); |
144 | 0 | uintptr_t end = (pos + phdr->p_memsz); |
145 | | |
146 | | // iterate through segment until we reach the end |
147 | 0 | while (pos < end) { |
148 | 0 | if (pos + sizeof(ElfW(Nhdr)) > end) { |
149 | 0 | break; // invalid |
150 | 0 | } |
151 | | |
152 | 0 | ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos; |
153 | 0 | if (note->n_namesz != 0 && note->n_descsz != 0 && |
154 | 0 | strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name, |
155 | 0 | sizeof(name)) == 0) { |
156 | 0 | *size = note->n_descsz; |
157 | | // advance past note header and aligned name |
158 | | // to get to description data |
159 | 0 | return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) + |
160 | 0 | roundup(note->n_namesz, 4)); |
161 | 0 | } |
162 | | |
163 | 0 | pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) + |
164 | 0 | roundup(note->n_descsz, 4)); |
165 | 0 | } |
166 | 0 | } |
167 | 0 | return NULL; |
168 | |
|
169 | | #elif defined(_WIN32) |
170 | | void* ptr = NULL; |
171 | | char* resource_name = NULL; |
172 | | |
173 | | if (options != NULL && options->pe_resource_name != NULL) { |
174 | | name = options->pe_resource_name; |
175 | | } else { |
176 | | // Automatically uppercase the resource name or it won't be found |
177 | | resource_name = (char*)malloc(strlen(name) + 1); |
178 | | if (resource_name == NULL) { |
179 | | return NULL; |
180 | | } |
181 | | strcpy_s(resource_name, strlen(name) + 1, name); |
182 | | CharUpperA(resource_name); // Uppercases inplace |
183 | | } |
184 | | |
185 | | HRSRC resource_handle = |
186 | | FindResourceA(NULL, resource_name != NULL ? resource_name : name, |
187 | | MAKEINTRESOURCEA(10) /* RT_RCDATA */); |
188 | | |
189 | | if (resource_handle) { |
190 | | HGLOBAL global_resource_handle = LoadResource(NULL, resource_handle); |
191 | | |
192 | | if (global_resource_handle) { |
193 | | if (size != NULL) { |
194 | | *size = SizeofResource(NULL, resource_handle); |
195 | | } |
196 | | |
197 | | ptr = LockResource(global_resource_handle); |
198 | | } |
199 | | } |
200 | | |
201 | | free(resource_name); |
202 | | |
203 | | return ptr; |
204 | | #else |
205 | | return NULL; |
206 | | #endif |
207 | 0 | } |
208 | | |
209 | | #endif // POSTJECT_API_H_ |