diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-02-01 21:55:30 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-02-02 10:09:44 +0100 |
commit | d4df7bc9b1fbdfb5c98134091a9ff998af60954f (patch) | |
tree | dfd2f5128ccf94b6e86d2475aee23acf53fa868c /mysys/my_addr_resolve.c | |
parent | 80d3eee072025f34984e474ea160651eac9e11e5 (diff) | |
parent | 96cb428b350ba48ee17ad9968d08f5318e48258c (diff) | |
download | mariadb-git-d4df7bc9b1fbdfb5c98134091a9ff998af60954f.tar.gz |
Merge branch 'github/10.0' into 10.1
Diffstat (limited to 'mysys/my_addr_resolve.c')
-rw-r--r-- | mysys/my_addr_resolve.c | 109 |
1 files changed, 65 insertions, 44 deletions
diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index 72b04119855..e9685985660 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -133,16 +133,52 @@ err: #include <m_string.h> #include <ctype.h> -#if defined(HAVE_LINK_H) && defined(HAVE_DLOPEN) -#include <link.h> -static ptrdiff_t offset= 0; -#else -#define offset 0 -#endif +#include <sys/wait.h> static int in[2], out[2]; -static int initialized= 0; +static pid_t pid; +static char addr2line_binary[1024]; static char output[1024]; + +int start_addr2line_fork(const char *binary_path) +{ + + if (pid > 0) + { + /* Don't leak FDs */ + close(in[1]); + close(out[0]); + /* Don't create zombie processes. */ + waitpid(pid, NULL, 0); + } + + if (pipe(in) < 0) + return 1; + if (pipe(out) < 0) + return 1; + + pid = fork(); + if (pid == -1) + return 1; + + if (!pid) /* child */ + { + dup2(in[0], 0); + dup2(out[1], 1); + close(in[0]); + close(in[1]); + close(out[0]); + close(out[1]); + execlp("addr2line", "addr2line", "-C", "-f", "-e", binary_path, NULL); + exit(1); + } + + close(in[0]); + close(out[1]); + + return 0; +} + int my_addr_resolve(void *ptr, my_addr_loc *loc) { char input[32]; @@ -158,13 +194,33 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) int line_number_start = -1; ssize_t i; - FD_ZERO(&set); - FD_SET(out[0], &set); + Dl_info info; + void *offset; + + if (!dladdr(ptr, &info)) + return 1; + if (strcmp(addr2line_binary, info.dli_fname)) + { + /* We use dli_fname in case the path is longer than the length of our static + string. We don't want to allocate anything dynamicaly here as we are in + a "crashed" state. */ + if (start_addr2line_fork(info.dli_fname)) + { + addr2line_binary[0] = '\0'; + return 1; + } + /* Save result for future comparisons. */ + strnmov(addr2line_binary, info.dli_fname, sizeof(addr2line_binary)); + } + offset = info.dli_fbase; len= my_snprintf(input, sizeof(input), "%p\n", ptr - offset); if (write(in[1], input, len) <= 0) return 1; + FD_ZERO(&set); + FD_SET(out[0], &set); + /* 10 ms should be plenty of time for addr2line to issue a response. */ timeout.tv_sec = 0; timeout.tv_usec = 10000; @@ -221,41 +277,6 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) const char *my_addr_resolve_init() { - if (!initialized) - { - pid_t pid; - -#if defined(HAVE_LINK_H) && defined(HAVE_DLOPEN) - struct link_map *lm = (struct link_map*) dlopen(0, RTLD_NOW); - if (lm) - offset= lm->l_addr; -#endif - - if (pipe(in) < 0) - return "pipe(in)"; - if (pipe(out) < 0) - return "pipe(out)"; - - pid = fork(); - if (pid == -1) - return "fork"; - - if (!pid) /* child */ - { - dup2(in[0], 0); - dup2(out[1], 1); - close(in[0]); - close(in[1]); - close(out[0]); - close(out[1]); - execlp("addr2line", "addr2line", "-C", "-f", "-e", my_progname, NULL); - exit(1); - } - - close(in[0]); - close(out[1]); - initialized= 1; - } return 0; } #endif |