Fix: baddr_statedump tracepoint registration
[lttng-ust.git] / liblttng-ust / lttng-ust-baddr.c
1 /*
2 * Copyright (C) 2013 Paul Woegerer <paul_woegerer@mentor.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #define _LGPL_SOURCE
20 #define _GNU_SOURCE
21 #include <dlfcn.h>
22 #include <link.h>
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <stdint.h>
31 #include <stddef.h>
32 #include <stdio.h>
33
34 #include <usterr-signal-safe.h>
35 #include "lttng-tracer-core.h"
36 #include "lttng-ust-baddr.h"
37
38 #define TRACEPOINT_DEFINE
39 #include "ust_baddr_statedump.h"
40
41 struct extract_data {
42 void *owner;
43 void *exec_baddr; /* executable base address */
44 };
45
46 /*
47 * Trace baddr into all sessions for which statedump is pending owned by
48 * the caller thread.
49 */
50 static
51 int trace_baddr(void *base_addr_ptr,
52 const char *resolved_path,
53 int vdso,
54 void *owner)
55 {
56 struct cds_list_head *sessionsp;
57 struct lttng_session *session;
58 struct stat sostat;
59
60 if (vdso || stat(resolved_path, &sostat)) {
61 sostat.st_size = 0;
62 sostat.st_mtime = -1;
63 }
64 /*
65 * UST lock nests within dynamic loader lock.
66 */
67 if (ust_lock()) {
68 /*
69 * Stop iteration on headers if need to exit.
70 */
71 ust_unlock();
72 return 1;
73 }
74
75 sessionsp = _lttng_get_sessions();
76 cds_list_for_each_entry(session, sessionsp, node) {
77 if (session->owner != owner)
78 continue;
79 if (!session->statedump_pending)
80 continue;
81 tracepoint(ust_baddr_statedump, soinfo,
82 session, base_addr_ptr,
83 resolved_path, sostat.st_size,
84 sostat.st_mtime);
85 }
86 ust_unlock();
87 return 0;
88 }
89
90 static
91 int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *_data)
92 {
93 int j;
94 struct extract_data *data = _data;
95 void *owner = data->owner;
96
97 for (j = 0; j < info->dlpi_phnum; j++) {
98 char resolved_path[PATH_MAX];
99 void *base_addr_ptr;
100 int vdso = 0;
101
102 if (info->dlpi_phdr[j].p_type != PT_LOAD)
103 continue;
104
105 /* Calculate virtual memory address of the loadable segment */
106 base_addr_ptr = (void *) info->dlpi_addr
107 + info->dlpi_phdr[j].p_vaddr;
108
109 if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)
110 && !data->exec_baddr) {
111 /*
112 * Only the first phdr encountered is considered
113 * as the program executable. The following
114 * could be e.g. vdso. Don't mistakenly dump
115 * them as being the program executable.
116 */
117 data->exec_baddr = base_addr_ptr;
118 /*
119 * Deal with program executable outside of phdr
120 * iteration.
121 */
122 break;
123 }
124 if (info->dlpi_name == NULL || info->dlpi_name[0] == 0) {
125 /* Found vDSO. */
126 snprintf(resolved_path, PATH_MAX - 1, "[vdso]");
127 vdso = 1;
128 } else {
129 /*
130 * For regular dl_phdr_info entries we have to check if
131 * the path to the shared object really exists.
132 */
133 if (!realpath(info->dlpi_name, resolved_path)) {
134 /* Path unknown, put the 'path' into brackets */
135 snprintf(resolved_path, PATH_MAX - 1, "[%s]",
136 info->dlpi_name);
137 vdso = 1;
138 }
139 }
140 if (trace_baddr(base_addr_ptr, resolved_path, vdso, owner)) {
141 return 1;
142 }
143 /*
144 * We are only interested in the base address (lowest virtual
145 * address associated with the memory image), skip the rest
146 */
147 break;
148 }
149 return 0;
150 }
151
152 static
153 void dump_exec_baddr(struct extract_data *data)
154 {
155 void *owner = data->owner;
156 Dl_info dl_info = { 0 };
157 void *base_addr_ptr;
158 char resolved_path[PATH_MAX];
159
160 base_addr_ptr = data->exec_baddr;
161 if (!base_addr_ptr)
162 return;
163 /*
164 * We have to use Dl_info to determine the executable full path.
165 */
166 if (!dladdr(base_addr_ptr, &dl_info))
167 return;
168 if (!realpath(dl_info.dli_fname, resolved_path))
169 return;
170 trace_baddr(base_addr_ptr, resolved_path, 0, owner);
171 }
172
173 int lttng_ust_baddr_statedump(void *owner)
174 {
175 struct extract_data data;
176
177 if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP"))
178 return 0;
179
180 data.owner = owner;
181 data.exec_baddr = NULL;
182 /*
183 * Iterate through the list of currently loaded shared objects and
184 * generate events for loadable segments using
185 * extract_soinfo_events.
186 */
187 dl_iterate_phdr(extract_soinfo_events, &data);
188 /*
189 * We cannot call dladdr() from within phdr iteration, without
190 * causing constructor vs dynamic loader vs multithread internal
191 * deadlocks, so dump the executable outside of the phdr
192 * iteration.
193 */
194 dump_exec_baddr(&data);
195 return 0;
196 }
197
198 void lttng_ust_baddr_statedump_init(void)
199 {
200 __tracepoints__init();
201 __tracepoints__ptrs_init();
202 }
203
204 void lttng_ust_baddr_statedump_destroy(void)
205 {
206 __tracepoints__ptrs_destroy();
207 __tracepoints__destroy();
208 }
This page took 0.036544 seconds and 4 git commands to generate.