/src/node/deps/postject/postject-api.h
Line  | Count  | Source  | 
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  | 105  | static inline bool postject_has_resource() { | 
42  | 105  |   static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0";  | 
43  | 105  |   return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1';  | 
44  | 105  | }  | 
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_  |