From 1e2e336c14e09b90158ebb4d742c15d84a32f7fb Mon Sep 17 00:00:00 2001 From: Paul Floyd Date: Sat, 15 Nov 2025 14:31:36 +0100 Subject: [PATCH] Darwin launcher: executable path changes Fixes memcheck/tests/execve2 Merged from https://github.com/LouisBrunner/valgrind-macos.git --- coregrind/launcher-darwin.c | 56 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/coregrind/launcher-darwin.c b/coregrind/launcher-darwin.c index 933050617..743f7c943 100644 --- a/coregrind/launcher-darwin.c +++ b/coregrind/launcher-darwin.c @@ -64,7 +64,7 @@ static struct { MacOS X, but .. the Apple PPC descriptors refer to the BE variant, since the LE variant is something that appeared long after Apple dropped PPC. */ - { CPU_TYPE_POWERPC, "ppc", "ppc32" }, + { CPU_TYPE_POWERPC, "ppc", "ppc32" }, { CPU_TYPE_POWERPC64, "ppc64", "ppc64be" } }; static int valid_archs_count = sizeof(valid_archs)/sizeof(valid_archs[0]); @@ -156,7 +156,7 @@ static const char *select_arch( if (bytes != sizeof(buf)) { return NULL; } - + // If it's thin, return that arch. { struct mach_header *mh = (struct mach_header *)buf; @@ -182,7 +182,7 @@ static const char *select_arch( if (fat_has_cputype(fh, default_cputype)) { return default_arch; } - + // Scan fat headers for any supported arch. for (i = 0; i < valid_archs_count; i++) { if (fat_has_cputype(fh, valid_archs[i].cputype)) { @@ -191,7 +191,7 @@ static const char *select_arch( } } } - + return NULL; } @@ -210,6 +210,7 @@ int main(int argc, char** argv, char** envp) const char *default_arch; cpu_type_t default_cputype; char *toolfile; + char* executable_path; char launcher_name[PATH_MAX+1]; char* new_line; char* set_cwd; @@ -218,7 +219,7 @@ int main(int argc, char** argv, char** envp) char **new_argv; int new_argc; - /* Start the debugging-log system ASAP. First find out how many + /* Start the debugging-log system ASAP. First find out how many "-d"s were specified. This is a pre-scan of the command line. At the same time, look for the tool name. */ loglevel = 0; @@ -235,9 +236,9 @@ int main(int argc, char** argv, char** envp) } break; } - if (0 == strcmp(argv[i], "-d")) + if (0 == strcmp(argv[i], "-d")) loglevel++; - if (0 == strncmp(argv[i], "--tool=", 7)) + if (0 == strncmp(argv[i], "--tool=", 7)) toolname = argv[i] + 7; if (0 == strncmp(argv[i], "--arch=", 7)) archname = argv[i] + 7; @@ -251,7 +252,7 @@ int main(int argc, char** argv, char** envp) if (toolname) { VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname); } else { - VG_(debugLog)(1, "launcher", + VG_(debugLog)(1, "launcher", "no tool requested, defaulting to 'memcheck'\n"); toolname = "memcheck"; } @@ -296,14 +297,14 @@ int main(int argc, char** argv, char** envp) free(vgpreload_core); } - /* Find the "default" arch (VGCONF_ARCH_PRI from configure). + /* Find the "default" arch (VGCONF_ARCH_PRI from configure). This is the preferred arch from fat files and the fallback. */ default_arch = NULL; default_cputype = 0; for (i = 0; i < valid_archs_count; i++) { if (!valid_archs[i].cputype) continue; - if (0 == strncmp(VG_PLATFORM, valid_archs[i].valgrind_name, - strlen(valid_archs[i].valgrind_name))) + if (0 == strncmp(VG_PLATFORM, valid_archs[i].valgrind_name, + strlen(valid_archs[i].valgrind_name))) { default_arch = valid_archs[i].valgrind_name; default_cputype = valid_archs[i].cputype; @@ -319,7 +320,7 @@ int main(int argc, char** argv, char** envp) // --arch from command line arch = NULL; for (i = 0; i < valid_archs_count; i++) { - if (0 == strcmp(archname, valid_archs[i].apple_name) || + if (0 == strcmp(archname, valid_archs[i].apple_name) || 0 == strcmp(archname, valid_archs[i].valgrind_name)) { arch = valid_archs[i].valgrind_name; @@ -328,28 +329,28 @@ int main(int argc, char** argv, char** envp) } if (i == valid_archs_count) barf("Unknown --arch '%s'", archname); assert(NULL != arch); - VG_(debugLog)(1, "launcher", "using arch '%s' from --arch=%s\n", + VG_(debugLog)(1, "launcher", "using arch '%s' from --arch=%s\n", arch, archname); - } + } else if (clientname == NULL) { // no client executable; use default as fallback - VG_(debugLog)(1, "launcher", + VG_(debugLog)(1, "launcher", "no client specified, defaulting arch to '%s'\n", default_arch); arch = default_arch; - } + } else if ((arch = select_arch(clientname, default_cputype,default_arch))) { // arch from client executable VG_(debugLog)(1, "launcher", "selected arch '%s'\n", arch); - } + } else { // nothing found in client executable; use default as fallback - VG_(debugLog)(1, "launcher", + VG_(debugLog)(1, "launcher", "no arch detected, defaulting arch to '%s'\n", default_arch); arch = default_arch; } - + cwd = getcwd(NULL, 0); if (!cwd) barf("Current directory no longer exists."); @@ -357,28 +358,35 @@ int main(int argc, char** argv, char** envp) we can tell stage2. stage2 will use the name for recursive invocations of valgrind on child processes. */ memset(launcher_name, 0, PATH_MAX+1); - for (i = 0; envp[i]; i++) + for (i = 0; envp[i]; i++) ; /* executable path is after last envp item */ /* envp[i] == NULL ; envp[i+1] == executable_path */ - if (envp[i+1][0] != '/') { + executable_path = envp[i+1]; + /* Since macOS 10.14.6, executable_path is prefixed by "executable_path=", + like an environment list */ + if (strlen(executable_path) > 16 && strncmp(executable_path, "executable_path=", 16) == 0) { + executable_path = &executable_path[16]; + } + if (executable_path[0] != '/') { strcpy(launcher_name, cwd); strcat(launcher_name, "/"); } - if (strlen(launcher_name) + strlen(envp[i+1]) > PATH_MAX) + if (strlen(launcher_name) + strlen(executable_path) > PATH_MAX) barf("launcher path is too long"); - strcat(launcher_name, envp[i+1]); + strcat(launcher_name, executable_path); VG_(debugLog)(1, "launcher", "launcher_name = %s\n", launcher_name); /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */ asprintf(&new_line, VALGRIND_LAUNCHER "=%s", launcher_name); /* tediously augment the env: VALGRIND_STARTUP_PWD_%PID_XYZZY=current_working_dir */ - asprintf(&set_cwd, "VALGRIND_STARTUP_PWD_%u_XYZZY=%s", getppid(), cwd); + asprintf(&set_cwd, "VALGRIND_STARTUP_PWD_%d_XYZZY=%s", getppid(), cwd); // Note that Apple binaries get a secret fourth arg, "char* apple", which // contains the executable path. Don't forget about it. for (j = 0; envp[j]; j++) ; + // 4 includes VALGRIND_LAUNCHER, VALGRIND_STARTUP_PWD, NULL and executable_path new_env = malloc((j+4) * sizeof(char*)); if (new_env == NULL) barf("malloc of new_env failed."); -- 2.47.3