summaryrefslogtreecommitdiff
path: root/mysys/my_addr_resolve.c
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-02-06 14:50:50 +0100
committerSergei Golubchik <serg@mariadb.org>2018-02-06 14:50:50 +0100
commit4771ae4b22d2bdef0aafc563570c71d4636a2493 (patch)
treed115bd7c68b1e6feab68ff6fcd547e0c86c79296 /mysys/my_addr_resolve.c
parent60f51af755ea9d07c20a596ba21de184816fa265 (diff)
parent0c25e58db6b045df92c209d396031cac5b528bbf (diff)
downloadmariadb-git-4771ae4b22d2bdef0aafc563570c71d4636a2493.tar.gz
Merge branch 'github/10.1' into 10.2
Diffstat (limited to 'mysys/my_addr_resolve.c')
-rw-r--r--mysys/my_addr_resolve.c165
1 files changed, 92 insertions, 73 deletions
diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c
index 83716bf11e1..10f8552f226 100644
--- a/mysys/my_addr_resolve.c
+++ b/mysys/my_addr_resolve.c
@@ -34,13 +34,6 @@ static const char *strip_path(const char *s)
return prev;
}
-#if defined(HAVE_LINK_H) && defined(HAVE_DLOPEN)
-#include <link.h>
-static ptrdiff_t offset= 0;
-#else
-#define offset 0
-#endif
-
/*
The following is very much single-threaded code and it's only supposed
to be used on shutdown or for a crash report
@@ -145,10 +138,52 @@ err:
#include <m_string.h>
#include <ctype.h>
+#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];
@@ -156,69 +191,88 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc)
ssize_t total_bytes_read = 0;
ssize_t extra_bytes_read = 0;
+ ssize_t parsed = 0;
fd_set set;
struct timeval timeout;
int filename_start = -1;
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 2;
+ }
+ /* 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;
+ return 3;
+
+ FD_ZERO(&set);
+ FD_SET(out[0], &set);
- /* 10 ms should be plenty of time for addr2line to issue a response. */
+ /* 100 ms should be plenty of time for addr2line to issue a response. */
timeout.tv_sec = 0;
- timeout.tv_usec = 10000;
+ timeout.tv_usec = 100000;
/* Read in a loop till all the output from addr2line is complete. */
- while (select(out[0] + 1, &set, NULL, NULL, &timeout) > 0)
+ while (parsed == total_bytes_read &&
+ select(out[0] + 1, &set, NULL, NULL, &timeout) > 0)
{
extra_bytes_read= read(out[0], output + total_bytes_read,
sizeof(output) - total_bytes_read);
if (extra_bytes_read < 0)
- return 2;
+ return 4;
/* Timeout or max bytes read. */
if (extra_bytes_read == 0)
break;
total_bytes_read += extra_bytes_read;
- }
-
- /* Failed starting addr2line. */
- if (total_bytes_read == 0)
- return 3;
- /* Go through the addr2line response and get the required data.
- The response is structured in 2 lines. The first line contains the function
- name, while the second one contains <filename>:<line number> */
- for (i = 0; i < total_bytes_read; i++) {
- if (output[i] == '\n') {
- filename_start = i + 1;
- output[i] = '\0';
- }
- if (filename_start != -1 && output[i] == ':') {
- line_number_start = i + 1;
- output[i] = '\0';
- }
- if (line_number_start != -1) {
- loc->line= atoi(output + line_number_start);
- break;
+ /* Go through the addr2line response and get the required data.
+ The response is structured in 2 lines. The first line contains the function
+ name, while the second one contains <filename>:<line number> */
+ for (; parsed < total_bytes_read; parsed++)
+ {
+ if (output[parsed] == '\n')
+ {
+ filename_start = parsed + 1;
+ output[parsed] = '\0';
+ }
+ if (filename_start != -1 && output[parsed] == ':')
+ {
+ line_number_start = parsed + 1;
+ output[parsed] = '\0';
+ break;
+ }
}
}
+
/* Response is malformed. */
if (filename_start == -1 || line_number_start == -1)
- return 4;
+ return 5;
loc->func= output;
loc->file= output + filename_start;
+ loc->line= atoi(output + line_number_start);
/* Addr2line was unable to extract any meaningful information. */
if (strcmp(loc->file, "??") == 0)
- return 5;
+ return 6;
loc->file= strip_path(loc->file);
@@ -227,41 +281,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