1+ #include <stdlib.h>
2+ #include <stdio.h>
3+ #include <string.h>
4+ #include <ctype.h>
5+ #include <errno.h>
6+
7+ #include <unistd.h>
8+ #include <sys/wait.h>
9+
10+ #include "fs/getexec.h"
11+ #include "fs/parentpath.h"
12+ #include "fs/sep.h"
13+ #include "fstream.h"
14+ #include "errors.h"
15+ #include "obggcc.h"
16+ #include "query.h"
17+
18+ static const char HYPHEN [] = "-" ;
19+ static const char BINUTILS_STRIP [] = "strip" ;
20+
21+ #define BINFMT_X86_64 (0x01)
22+ #define BINFMT_i386 (0x02)
23+ #define BINFMT_MIPS64EL (0x03)
24+ #define BINFMT_MIPSEL (0x04)
25+ #define BINFMT_RISCV64 (0x05)
26+ #define BINFMT_AARCH64 (0x06)
27+ #define BINFMT_ARM (0x07)
28+
29+ #define BINFMT_SIZE (40)
30+
31+ struct binfmt {
32+ int type ;
33+ const char * name ;
34+ unsigned char magic [BINFMT_SIZE ];
35+ unsigned char mask [BINFMT_SIZE ];
36+ };
37+
38+ static const struct binfmt binfmts [] = {
39+ {
40+ .type = BINFMT_X86_64 ,
41+ .name = "x86_64" ,
42+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x2 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0x3e , 0x0 },
43+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xfe , 0xfc , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff }
44+ },
45+ {
46+ .type = BINFMT_i386 ,
47+ .name = "i386" ,
48+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x1 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0x3 , 0x0 },
49+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xfe , 0xfc , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff }
50+ },
51+ {
52+ .type = BINFMT_MIPS64EL ,
53+ .name = "mips64el" ,
54+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x2 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0x8 , 0x0 },
55+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x0 , 0xfe , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff }
56+ },
57+ {
58+ .type = BINFMT_MIPSEL ,
59+ .name = "mipsel" ,
60+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x1 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0x8 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 },
61+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x0 , 0xfe , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x20 }
62+ },
63+ {
64+ .type = BINFMT_RISCV64 ,
65+ .name = "riscv64" ,
66+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x2 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0xf3 , 0x0 },
67+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x0 , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff }
68+ },
69+ {
70+ .type = BINFMT_AARCH64 ,
71+ .name = "aarch64" ,
72+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x2 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0xb7 },
73+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x0 , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff }
74+ },
75+ {
76+ .type = BINFMT_ARM ,
77+ .name = "arm" ,
78+ .magic = {0x7f , 0x45 , 0x4c , 0x46 , 0x1 , 0x1 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x0 , 0x28 , 0x0 },
79+ .mask = {0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x0 , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe , 0xff , 0xff , 0xff }
80+ }
81+ };
82+
83+ static const struct binfmt * binfmt_guess (const char * const filename ) {
84+
85+ unsigned char chunk [BINFMT_SIZE ];
86+
87+ unsigned char a [BINFMT_SIZE ];
88+ unsigned char b [BINFMT_SIZE ];
89+
90+ const struct binfmt * fmt = NULL ;
91+
92+ size_t index = 0 ;
93+ size_t offset = 0 ;
94+
95+ fstream_t * stream = NULL ;
96+
97+ int status = 0 ;
98+
99+ memset (chunk , '\0' , sizeof (chunk ));
100+ memset (a , '\0' , sizeof (a ));
101+ memset (b , '\0' , sizeof (b ));
102+
103+ stream = fstream_open (filename , FSTREAM_READ );
104+
105+ if (stream == NULL ) {
106+ goto end ;
107+ }
108+
109+ if (fstream_read (stream , chunk , sizeof (chunk )) == FSTREAM_ERROR ) {
110+ goto end ;
111+ }
112+
113+ for (index = 0 ; index < sizeof (binfmts ) / sizeof (* binfmts ); index ++ ) {
114+ fmt = & binfmts [index ];
115+
116+ for (offset = 0 ; offset < BINFMT_SIZE ; offset ++ ) {
117+ a [offset ] = (fmt -> magic [offset ] & fmt -> mask [offset ]);
118+ }
119+
120+ for (offset = 0 ; offset < BINFMT_SIZE ; offset ++ ) {
121+ b [offset ] = (chunk [offset ] & fmt -> mask [offset ]);
122+ }
123+
124+ if (memcmp (a , b , BINFMT_SIZE ) == 0 ) {
125+ goto end ;
126+ }
127+ }
128+
129+ fmt = NULL ;
130+
131+ end :;
132+
133+ fstream_close (stream );
134+
135+ return fmt ;
136+
137+ }
138+
139+ static const char * binfmt_get_triplet (const struct binfmt * const fmt ) {
140+
141+ switch (fmt -> type ) {
142+ case BINFMT_X86_64 :
143+ #if defined(OBGGCC )
144+ return "x86_64-unknown-linux-gnu" ;
145+ #elif defined(PINO )
146+ return "x86_64-unknown-linux-android" ;
147+ #endif
148+ case BINFMT_i386 :
149+ #if defined(OBGGCC )
150+ return "i386-unknown-linux-gnu" ;
151+ #elif defined(PINO )
152+ return "i686-unknown-linux-android" ;
153+ #endif
154+ case BINFMT_MIPS64EL :
155+ #if defined(OBGGCC )
156+ return "mips64el-unknown-linux-gnuabi64" ;
157+ #elif defined(PINO )
158+ return "mips64el-unknown-linux-android" ;
159+ #endif
160+ case BINFMT_MIPSEL :
161+ #if defined(OBGGCC )
162+ return "mipsel-unknown-linux-gnu" ;
163+ #elif defined(PINO )
164+ return "mipsel-unknown-linux-android" ;
165+ #endif
166+ case BINFMT_RISCV64 :
167+ #if defined(PINO )
168+ return "riscv64-unknown-linux-android" ;
169+ #endif
170+ case BINFMT_AARCH64 :
171+ #if defined(OBGGCC )
172+ return "aarch64-unknown-linux-gnu" ;
173+ #elif defined(PINO )
174+ return "aarch64-unknown-linux-android" ;
175+ #endif
176+ case BINFMT_ARM :
177+ #if defined(OBGGCC )
178+ return "arm-unknown-linux-gnueabihf" ;
179+ #elif defined(PINO )
180+ return "armv7-unknown-linux-androideabi" ;
181+ #endif
182+ }
183+
184+ return NULL ;
185+
186+ }
187+
188+ int main (int argc , char * argv [], char * envp []) {
189+
190+ hquery_t query = {0 };
191+
192+ pid_t pid = 0 ;
193+ int wstatus = 0 ;
194+
195+ int verbose = 0 ;
196+
197+ int err = ERR_SUCCESS ;
198+
199+ const struct binfmt * fmt = NULL ;
200+
201+ const char * triplet = NULL ;
202+
203+ char * parent_directory = NULL ;
204+ char * app_filename = NULL ;
205+
206+ char * cur = NULL ;
207+ char * executable = NULL ;
208+
209+ size_t index = 0 ;
210+
211+ char * * args = NULL ;
212+
213+ size_t kargc = 0 ;
214+ char * * kargv = NULL ;
215+
216+ size_t inputsc = 0 ;
217+ char * * inputs = NULL ;
218+
219+ kargv = malloc (
220+ sizeof (* argv ) * (
221+ argc +
222+ 1 /* NULL */
223+ )
224+ );
225+
226+ if (kargv == NULL ) {
227+ err = ERR_MEM_ALLOC_FAILURE ;
228+ goto end ;
229+ }
230+
231+ inputs = malloc (sizeof (* argv ) * (argc + 1 ));
232+
233+ if (inputs == NULL ) {
234+ err = ERR_MEM_ALLOC_FAILURE ;
235+ goto end ;
236+ }
237+
238+ query_load_environ (& query );
239+
240+ verbose = query_get_bool (& query , ENV_VERBOSE ) == 1 ;
241+
242+ for (index = 1 ; index < (size_t ) argc ; index ++ ) {
243+ cur = argv [index ];
244+
245+ if (cur [0 ] == '-' ) {
246+ kargv [kargc ++ ] = cur ;
247+ } else {
248+ inputs [inputsc ++ ] = cur ;
249+ }
250+ }
251+
252+ if (inputsc == 0 ) {
253+ fprintf (stderr , "nothing here but crickets\n" );
254+ goto end ;
255+ }
256+
257+ kargv [kargc ++ ] = NULL ;
258+
259+ app_filename = get_app_filename ();
260+
261+ if (app_filename == NULL ) {
262+ err = ERR_GET_APP_FILENAME_FAILURE ;
263+ goto end ;
264+ }
265+
266+ parent_directory = malloc (strlen (app_filename ) + 1 );
267+
268+ if (parent_directory == NULL ) {
269+ err = ERR_MEM_ALLOC_FAILURE ;
270+ goto end ;
271+ }
272+
273+ /* Get the directory where our executable is (i.e., <prefix>/bin) */
274+ get_parent_path (app_filename , parent_directory , 1 );
275+
276+ args = malloc (
277+ sizeof (* kargv ) * (
278+ kargc +
279+ 1 + /* <triplet>-<strip> */
280+ 1 + /* <input> */
281+ 1 /* NULL */
282+ )
283+ );
284+
285+ if (args == NULL ) {
286+ err = ERR_MEM_ALLOC_FAILURE ;
287+ goto end ;
288+ }
289+
290+ memcpy (& args [1 ], kargv , kargc * sizeof (* kargv ));
291+
292+ for (index = 0 ; index < inputsc ; index ++ ) {
293+ cur = inputs [index ];
294+
295+ fmt = binfmt_guess (cur );
296+
297+ if (fmt == NULL ) {
298+ err = ERR_BINFMT_GUESS_FAILURE ;
299+ goto end ;
300+ }
301+
302+ triplet = binfmt_get_triplet (fmt );
303+
304+ if (triplet == NULL ) {
305+ err = ERR_BINFMT_GUESS_FAILURE ;
306+ goto end ;
307+ }
308+
309+ free (executable );
310+
311+ executable = malloc (strlen (parent_directory ) + strlen (PATHSEP_S ) + strlen (triplet ) + strlen (HYPHEN ) + strlen (BINUTILS_STRIP ) + 1 );
312+
313+ if (executable == NULL ) {
314+ err = ERR_MEM_ALLOC_FAILURE ;
315+ goto end ;
316+ }
317+
318+ strcpy (executable , parent_directory );
319+ strcat (executable , PATHSEP_S );
320+ strcat (executable , triplet );
321+ strcat (executable , HYPHEN );
322+ strcat (executable , BINUTILS_STRIP );
323+
324+ args [0 ] = executable ;
325+ args [kargc ] = cur ;
326+ args [kargc + 1 ] = NULL ;
327+ puts (cur );
328+ if (verbose ) {
329+ obggcc_print_args (args );
330+ }
331+
332+ pid = fork ();
333+
334+ if (pid == 0 ) {
335+ if (execve (executable , args , environ ) == -1 ) {
336+ fprintf (stderr , "fatal error: %s: %s\n" , obggcc_strerror (ERR_EXECVE_FAILURE ), strerror (errno ));
337+ _exit (EXIT_FAILURE );
338+ }
339+ } else if (pid > 0 ) {
340+ wait (& wstatus );
341+ wstatus = WIFSIGNALED (wstatus ) ? 128 + WTERMSIG (wstatus ) : WEXITSTATUS (wstatus );
342+
343+ if (wstatus != EXIT_SUCCESS ) {
344+ err = ERR_EXECVE_SUBPROCESS_FAILURE ;
345+ goto end ;
346+ }
347+ } else {
348+ err = ERR_FORK_FAILURE ;
349+ goto end ;
350+ }
351+ }
352+
353+ end :;
354+
355+ free (executable );
356+ free (kargv );
357+ free (args );
358+ free (parent_directory );
359+ free (app_filename );
360+
361+ query_free (& query );
362+
363+ if (err != ERR_SUCCESS ) {
364+ cur = strerror (errno );
365+
366+ fprintf (stderr , "fatal error: %s" , obggcc_strerror (err ));
367+
368+ switch (err ) {
369+ case ERR_EXECVE_FAILURE :
370+ case ERR_COPY_FILE_FAILURE :
371+ case ERR_GET_APP_FILENAME_FAILURE :
372+ case ERR_MEM_ALLOC_FAILURE :
373+ fprintf (stderr , ": %s" , cur );
374+ break ;
375+ }
376+
377+ fprintf (stderr , "\n" );
378+
379+ return EXIT_FAILURE ;
380+ }
381+
382+ return EXIT_SUCCESS ;
383+
384+ }
0 commit comments