Merge "Imported Upstream connman version 1.38" into tizen
[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 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <execinfo.h>
32 #include <dlfcn.h>
33
34 #include "connman.h"
35
36 void print_backtrace(const char* program_path, const char* program_exec,
37                 unsigned int offset)
38 {
39         void *frames[99];
40         size_t n_ptrs;
41         unsigned int i;
42         int outfd[2], infd[2];
43         int pathlen;
44         pid_t pid;
45
46         if (!program_exec)
47                 return;
48
49         pathlen = strlen(program_path);
50
51         n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
52         if (n_ptrs < offset)
53                 return;
54
55         if (pipe(outfd) < 0)
56                 return;
57
58         if (pipe(infd) < 0) {
59                 close(outfd[0]);
60                 close(outfd[1]);
61                 return;
62         }
63
64         pid = fork();
65         if (pid < 0) {
66                 close(outfd[0]);
67                 close(outfd[1]);
68                 close(infd[0]);
69                 close(infd[1]);
70                 return;
71         }
72
73         if (pid == 0) {
74                 close(outfd[1]);
75                 close(infd[0]);
76
77                 dup2(outfd[0], STDIN_FILENO);
78                 dup2(infd[1], STDOUT_FILENO);
79
80                 execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
81
82                 exit(EXIT_FAILURE);
83         }
84
85         close(outfd[0]);
86         close(infd[1]);
87
88         connman_error("++++++++ backtrace ++++++++");
89
90         for (i = offset; i < n_ptrs - 1; i++) {
91                 Dl_info info;
92                 char addr[20], buf[PATH_MAX * 2];
93                 int len, written;
94                 char *ptr, *pos;
95
96                 dladdr(frames[i], &info);
97
98                 len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
99                 if (len < 0)
100                         break;
101
102                 written = write(outfd[1], addr, len);
103                 if (written < 0)
104                         break;
105
106                 len = read(infd[0], buf, sizeof(buf) - 1);
107                 if (len < 0)
108                         break;
109
110                 buf[len] = '\0';
111
112                 pos = strchr(buf, '\n');
113                 if (!pos) {
114                         connman_error("Error in backtrace format");
115                         break;
116                 }
117
118                 *pos++ = '\0';
119
120                 if (strcmp(buf, "??") == 0) {
121                         connman_error("#%-2u %p in %s", i - offset,
122                                                 frames[i], info.dli_fname);
123                         continue;
124                 }
125
126                 ptr = strchr(pos, '\n');
127                 if (!ptr) {
128                         connman_error("Error in backtrace format");
129                         break;
130                 }
131
132                 *ptr++ = '\0';
133
134                 if (strncmp(pos, program_path, pathlen) == 0)
135                         pos += pathlen + 1;
136
137                 connman_error("#%-2u %p in %s() at %s", i - offset,
138                                                 frames[i], buf, pos);
139         }
140
141         connman_error("+++++++++++++++++++++++++++");
142
143         kill(pid, SIGTERM);
144
145         close(outfd[1]);
146         close(infd[0]);
147 }