diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-04-24 12:27:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-04-24 12:27:52 -0400 |
commit | 1f947b4786c310c13147400d737cd48bd2f05da4 (patch) | |
tree | 2dce8f3fc852fa325fbbc59ee54113f5e89da2ea /lib/shlib.c | |
parent | a9f644c24f0b2cccf5b38872a50812efb2dd1e79 (diff) | |
download | spmc-1f947b4786c310c13147400d737cd48bd2f05da4.tar.gz |
Add macos specific code
Diffstat (limited to 'lib/shlib.c')
-rw-r--r-- | lib/shlib.c | 84 |
1 files changed, 73 insertions, 11 deletions
diff --git a/lib/shlib.c b/lib/shlib.c index a8222af..04dbb49 100644 --- a/lib/shlib.c +++ b/lib/shlib.c @@ -9,13 +9,19 @@ char *shlib_deps_objdump(const char *_filename) { char cmd[PATH_MAX]; memset(cmd, '\0', sizeof(cmd)); + if (_filename == NULL) { + spmerrno = EINVAL; + spmerrno_cause("_filename was NULL"); + return NULL; + } + if ((filename = strdup(_filename)) == NULL) { fprintf(SYSERROR); return NULL; } strchrdel(filename, SHELL_INVALID); - snprintf(cmd, sizeof(cmd), "%s %s '%s'", SPM_SHLIB_EXEC, "-p", filename); + snprintf(cmd, sizeof(cmd), "%s %s '%s'", SPM_SHLIB_EXEC, SPM_SHLIB_EXEC_ARGS, filename); shell(&proc, SHELL_OUTPUT, cmd); if (proc->returncode != 0) { @@ -32,41 +38,97 @@ char *shlib_deps_objdump(const char *_filename) { StrList *shlib_deps(const char *filename) { char **data = NULL; - char *output = NULL; + char *raw_data = NULL; StrList *result = NULL; + if (filename == NULL) { + spmerrno = EINVAL; + spmerrno_cause("filename was NULL"); + return NULL; + } + // Get output from objdump // TODO: use preprocessor or another function to select the correct shlib_deps_*() in the future - if ((output = shlib_deps_objdump(filename)) == NULL) { + if ((raw_data = shlib_deps_objdump(filename)) == NULL) { return NULL; } // Initialize list array if ((result = strlist_init()) == NULL) { - free(output); + free(raw_data); return NULL; } // Split output into individual lines - if ((data = split(output, "\n")) == NULL) { - free(output); + if ((data = split(raw_data, "\n")) == NULL) { + free(raw_data); strlist_free(result); return NULL; } - // Parse output: - // Collapse whitespace and extract the NEEDED libraries (second field) - // AFAIK when "NEEDED" is present, a string containing the library name is guaranteed to be there + // Collapse all whitespace in each line + // i.e. " stuff things" -> "stuff things" for (size_t i = 0; data[i] != NULL; i++) { data[i] = normalize_space(data[i]); + } + + for (size_t i = 0; data[i] != NULL; i++) { + char **field = NULL; + char reason[255] = {0,}; + +#if OS_LINUX + // Extract the NEEDED libraries (second field) + // AFAIK when "NEEDED" is present, a string containing the library name is guaranteed to be there if (startswith(data[i], "NEEDED")) { - char **field = split(data[i], " "); + if ((field = split(data[i], " ")) == NULL) { + strlist_free(result); + result = NULL; + break; + } + + // record library path + strlist_append(result, field[1]); + split_free(field); + } +#elif OS_DARWIN + size_t offset_name = i + 2; // how many lines to look ahead after reaching LC_LOAD_DYLIB + size_t numLines; + for (numLines = 0; data[numLines] != NULL; numLines++); // get line count + + // Find APPLE's equivalent to NEEDED on Linux + if (startswith(data[i], "cmd LC_LOAD_DYLIB")) { + // Don't overrun the data buffer + if (offset_name > numLines || data[offset_name] == NULL) { + break; + } + + // split on: "name /library/path" + if ((field = split(data[offset_name], " ")) == NULL) { + sprintf(reason, "'%s' produced unreadable output", SPM_SHLIB_EXEC, i, offset_name); + spmerrno = SPM_ERR_PARSE; + spmerrno_cause(reason); + + strlist_free(result); + result = NULL; + break; + } + + // verify it was actually "name ..." + if (strcmp(field[0], "name") != 0) { + sprintf(reason, "'%s' produced unexpected LC_LOAD_DYLIB format between lines %zu:%zu", SPM_SHLIB_EXEC, i, offset_name); + spmerrno = SPM_ERR_PARSE; + spmerrno_cause(reason); + break; + } + + // record library path strlist_append(result, field[1]); split_free(field); } +#endif } - free(output); + free(raw_data); split_free(data); return result; } |