/** * Buildroot wrapper for external toolchains. This simply executes the real * toolchain with a number of arguments (sysroot/arch/..) hardcoded, * to ensure the external toolchain uses the correct configuration. * The hardcoded path arguments are defined relative to the actual location * of the binary. * * (C) 2011 Peter Korsgaard * (C) 2011 Daniel Nyström * (C) 2012 Arnout Vandecappelle (Essensium/Mind) * (C) 2013 Spenser Gilliland * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #define _GNU_SOURCE #include #include #include #include #include #include static char path[PATH_MAX]; static char sysroot[PATH_MAX]; /** * GCC errors out with certain combinations of arguments (examples are * -mfloat-abi={hard|soft} and -m{little|big}-endian), so we have to ensure * that we only pass the predefined one to the real compiler if the inverse * option isn't in the argument list. * This specifies the worst case number of extra arguments we might pass * Currently, we have: * -mfloat-abi= * -march= * -mcpu= */ #define EXCLUSIVE_ARGS 3 static char *predef_args[] = { path, "--sysroot", sysroot, #ifdef BR_ABI "-mabi=" BR_ABI, #endif #ifdef BR_FPU "-mfpu=" BR_FPU, #endif #ifdef BR_SOFTFLOAT "-msoft-float", #endif /* BR_SOFTFLOAT */ #ifdef BR_MODE "-m" BR_MODE, #endif #ifdef BR_64 "-m64", #endif #ifdef BR_BINFMT_FLAT "-Wl,-elf2flt", #endif #ifdef BR_MIPS_TARGET_LITTLE_ENDIAN "-EL", #endif #if defined(BR_MIPS_TARGET_BIG_ENDIAN) || defined(BR_ARC_TARGET_BIG_ENDIAN) "-EB", #endif #ifdef BR_ADDITIONAL_CFLAGS BR_ADDITIONAL_CFLAGS #endif }; static void check_unsafe_path(const char *path, int paranoid) { char **c; static char *unsafe_paths[] = { "/lib", "/usr/include", "/usr/lib", "/usr/local/include", "/usr/local/lib", NULL, }; for (c = unsafe_paths; *c != NULL; c++) { if (!strncmp(path, *c, strlen(*c))) { fprintf(stderr, "%s: %s: unsafe header/library path used in cross-compilation: '%s'\n", program_invocation_short_name, paranoid ? "ERROR" : "WARNING", path); if (paranoid) exit(1); continue; } } } int main(int argc, char **argv) { char **args, **cur; char *relbasedir, *absbasedir; char *progpath = argv[0]; char *basename; char *env_debug; char *paranoid_wrapper; int paranoid; int ret, i, count = 0, debug; /* Calculate the relative paths */ basename = strrchr(progpath, '/'); if (basename) { *basename = '\0'; basename++; relbasedir = malloc(strlen(progpath) + 7); if (relbasedir == NULL) { perror(__FILE__ ": malloc"); return 2; } sprintf(relbasedir, "%s/../..", argv[0]); absbasedir = realpath(relbasedir, NULL); } else { basename = progpath; absbasedir = malloc(PATH_MAX + 1); ret = readlink("/proc/self/exe", absbasedir, PATH_MAX); if (ret < 0) { perror(__FILE__ ": readlink"); return 2; } absbasedir[ret] = '\0'; for (i = ret; i > 0; i--) { if (absbasedir[i] == '/') { absbasedir[i] = '\0'; if (++count == 3) break; } } } if (absbasedir == NULL) { perror(__FILE__ ": realpath"); return 2; } /* Fill in the relative paths */ #ifdef BR_CROSS_PATH_REL ret = snprintf(path, sizeof(path), "%s/" BR_CROSS_PATH_REL "/%s", absbasedir, basename); #else /* BR_CROSS_PATH_ABS */ ret = snprintf(path, sizeof(path), BR_CROSS_PATH_ABS "/%s", basename); #endif if (ret >= sizeof(path)) { perror(__FILE__ ": overflow"); return 3; } ret = snprintf(sysroot, sizeof(sysroot), "%s/" BR_SYSROOT, absbasedir); if (ret >= sizeof(sysroot)) { perror(__FILE__ ": overflow"); return 3; } cur = args = malloc(sizeof(predef_args) + (sizeof(char *) * (argc + EXCLUSIVE_ARGS))); if (args == NULL) { perror(__FILE__ ": malloc"); return 2; } /* start with predefined args */ memcpy(cur, predef_args, sizeof(predef_args)); cur += sizeof(predef_args) / sizeof(predef_args[0]); #ifdef BR_FLOAT_ABI /* add float abi if not overridden in args */ for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "-mfloat-abi=", strlen("-mfloat-abi=")) || !strcmp(argv[i], "-msoft-float") || !strcmp(argv[i], "-mhard-float")) break; } if (i == argc) *cur++ = "-mfloat-abi=" BR_FLOAT_ABI; #endif #if defined(BR_ARCH) || \ defined(BR_CPU) /* Add our -march/cpu/abi flags, but only if none are * already specified on the commandline */ for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "-march=", strlen("-march=")) || !strncmp(argv[i], "-mcpu=", strlen("-mcpu=" ))) break; } if (i == argc) { #ifdef BR_ARCH *cur++ = "-march=" BR_ARCH; #endif #ifdef BR_CPU *cur++ = "-mcpu=" BR_CPU; #endif } #endif /* ARCH || CPU */ paranoid_wrapper = getenv("BR_COMPILER_PARANOID_UNSAFE_PATH"); if (paranoid_wrapper && strlen(paranoid_wrapper) > 0) paranoid = 1; else paranoid = 0; /* Check for unsafe library and header paths */ for (i = 1; i < argc; i++) { /* Skip options that do not start with -I and -L */ if (strncmp(argv[i], "-I", 2) && strncmp(argv[i], "-L", 2)) continue; /* We handle two cases: first the case where -I/-L and * the path are separated by one space and therefore * visible as two separate options, and then the case * where they are stuck together forming one single * option. */ if (argv[i][2] == '\0') { i++; if (i == argc) continue; check_unsafe_path(argv[i], paranoid); } else { check_unsafe_path(argv[i] + 2, paranoid); } } /* append forward args */ memcpy(cur, &argv[1], sizeof(char *) * (argc - 1)); cur += argc - 1; /* finish with NULL termination */ *cur = NULL; /* Debug the wrapper to see actual arguments passed to * the compiler: * unset, empty, or 0: do not trace * set to 1 : trace all arguments on a single line * set to 2 : trace one argument per line */ if ((env_debug = getenv("BR2_DEBUG_WRAPPER"))) { debug = atoi(env_debug); if (debug > 0) { fprintf(stderr, "Toolchain wrapper executing:"); for (i = 0; args[i]; i++) fprintf(stderr, "%s'%s'", (debug == 2) ? "\n " : " ", args[i]); fprintf(stderr, "\n"); } } if (execv(path, args)) perror(path); free(args); return 2; }