Imported Upstream version 1.35
[platform/upstream/connman.git] / src / backtrace.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2016  Yann E. MORIN <yann.morin.1998@free.fr>. All rights reserved.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #define _GNU_SOURCE
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <execinfo.h>
33 #include <dlfcn.h>
34
35 #include "connman.h"
36
37 void print_backtrace(const char* program_path, const char* program_exec,
38                 unsigned int offset)
39 {
40         void *frames[99];
41         size_t n_ptrs;
42         unsigned int i;
43         int outfd[2], infd[2];
44         int pathlen;
45         pid_t pid;
46
47         if (!program_exec)
48                 return;
49
50         pathlen = strlen(program_path);
51
52         n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
53         if (n_ptrs < offset)
54                 return;
55
56         if (pipe(outfd) < 0)
57                 return;
58
59         if (pipe(infd) < 0) {
60                 close(outfd[0]);
61                 close(outfd[1]);
62                 return;
63         }
64
65         pid = fork();
66         if (pid < 0) {
67                 close(outfd[0]);
68                 close(outfd[1]);
69                 close(infd[0]);
70                 close(infd[1]);
71                 return;
72         }
73
74         if (pid == 0) {
75                 close(outfd[1]);
76                 close(infd[0]);
77
78                 dup2(outfd[0], STDIN_FILENO);
79                 dup2(infd[1], STDOUT_FILENO);
80
81                 execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
82
83                 exit(EXIT_FAILURE);
84         }
85
86         close(outfd[0]);
87         close(infd[1]);
88
89         connman_error("++++++++ backtrace ++++++++");
90
91         for (i = offset; i < n_ptrs - 1; i++) {
92                 Dl_info info;
93                 char addr[20], buf[PATH_MAX * 2];
94                 int len, written;
95                 char *ptr, *pos;
96
97                 dladdr(frames[i], &info);
98
99                 len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
100                 if (len < 0)
101                         break;
102
103                 written = write(outfd[1], addr, len);
104                 if (written < 0)
105                         break;
106
107                 len = read(infd[0], buf, sizeof(buf) - 1);
108                 if (len < 0)
109                         break;
110
111                 buf[len] = '\0';
112
113                 pos = strchr(buf, '\n');
114                 *pos++ = '\0';
115
116                 if (strcmp(buf, "??") == 0) {
117                         connman_error("#%-2u %p in %s", i - offset,
118                                                 frames[i], info.dli_fname);
119                         continue;
120                 }
121
122                 ptr = strchr(pos, '\n');
123                 *ptr++ = '\0';
124
125                 if (strncmp(pos, program_path, pathlen) == 0)
126                         pos += pathlen + 1;
127
128                 connman_error("#%-2u %p in %s() at %s", i - offset,
129                                                 frames[i], buf, pos);
130         }
131
132         connman_error("+++++++++++++++++++++++++++");
133
134         kill(pid, SIGTERM);
135
136         close(outfd[1]);
137         close(infd[0]);
138 }