Fix: work-around glibc lying about dlsym()/dlerror() leafness
[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 <link.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <stdint.h>
30 #include <stddef.h>
31 #include <stdio.h>
32
33 #include <usterr-signal-safe.h>
34 #include "lttng-tracer-core.h"
35 #include "lttng-ust-baddr.h"
36
37 #define TRACEPOINT_DEFINE
38 #define TRACEPOINT_CREATE_PROBES
39 #define TP_SESSION_CHECK
40 #include "ust_baddr_statedump.h"
41
42 struct extract_data {
43 void *owner;
44 void *exec_baddr; /* executable base address */
45 };
46
47 /*
48 * Trace baddr into all sessions for which statedump is pending owned by
49 * the caller thread.
50 */
51 static
52 int trace_baddr(void *base_addr_ptr,
53 const char *resolved_path,
54 int vdso,
55 void *owner)
56 {
57 struct cds_list_head *sessionsp;
58 struct lttng_session *session;
59 struct stat sostat;
60
61 if (vdso || stat(resolved_path, &sostat)) {
62 sostat.st_size = 0;
63 sostat.st_mtime = -1;
64 }
65 /*
66 * UST lock nests within dynamic loader lock.
67 */
68 if (ust_lock()) {
69 /*
70 * Stop iteration on headers if need to exit.
71 */
72 ust_unlock();
73 return 1;
74 }
75
76 sessionsp = _lttng_get_sessions();
77 cds_list_for_each_entry(session, sessionsp, node) {
78 if (session->owner != owner)
79 continue;
80 if (!session->statedump_pending)
81 continue;
82 tracepoint(ust_baddr_statedump, soinfo,
83 session, base_addr_ptr,
84 resolved_path, sostat.st_size,
85 sostat.st_mtime);
86 }
87 ust_unlock();
88 return 0;
89 }
90
91 static
92 int extract_soinfo_events(struct dl_phdr_info *info, size_t size, void *_data)
93 {
94 int j;
95 struct extract_data *data = _data;
96 void *owner = data->owner;
97
98 for (j = 0; j < info->dlpi_phnum; j++) {
99 char resolved_path[PATH_MAX];
100 void *base_addr_ptr;
101 int vdso = 0;
102
103 if (info->dlpi_phdr[j].p_type != PT_LOAD)
104 continue;
105
106 /* Calculate virtual memory address of the loadable segment */
107 base_addr_ptr = (void *) info->dlpi_addr
108 + info->dlpi_phdr[j].p_vaddr;
109
110 if ((info->dlpi_name == NULL || info->dlpi_name[0] == 0)
111 && !data->exec_baddr) {
112 /*
113 * Only the first phdr encountered is considered
114 * as the program executable. The following
115 * could be e.g. vdso. Don't mistakenly dump
116 * them as being the program executable.
117 */
118 data->exec_baddr = base_addr_ptr;
119 /*
120 * Deal with program executable outside of phdr
121 * iteration.
122 */
123 break;
124 }
125 if (info->dlpi_name == NULL || info->dlpi_name[0] == 0) {
126 /* Found vDSO. */
127 snprintf(resolved_path, PATH_MAX - 1, "[vdso]");
128 vdso = 1;
129 } else {
130 /*
131 * For regular dl_phdr_info entries we have to check if
132 * the path to the shared object really exists.
133 */
134 if (!realpath(info->dlpi_name, resolved_path)) {
135 /* Path unknown, put the 'path' into brackets */
136 snprintf(resolved_path, PATH_MAX - 1, "[%s]",
137 info->dlpi_name);
138 vdso = 1;
139 }
140 }
141 if (trace_baddr(base_addr_ptr, resolved_path, vdso, owner)) {
142 return 1;
143 }
144 /*
145 * We are only interested in the base address (lowest virtual
146 * address associated with the memory image), skip the rest
147 */
148 break;
149 }
150 return 0;
151 }
152
153 static
154 void dump_exec_baddr(struct extract_data *data)
155 {
156 void *owner = data->owner;
157 Dl_info dl_info = { 0 };
158 void *base_addr_ptr;
159 char resolved_path[PATH_MAX];
160
161 base_addr_ptr = data->exec_baddr;
162 if (!base_addr_ptr)
163 return;
164 /*
165 * We have to use Dl_info to determine the executable full path.
166 */
167 if (!dladdr(base_addr_ptr, &dl_info))
168 return;
169 if (!realpath(dl_info.dli_fname, resolved_path))
170 return;
171 trace_baddr(base_addr_ptr, resolved_path, 0, owner);
172 }
173
174 int lttng_ust_baddr_statedump(void *owner)
175 {
176 struct extract_data data;
177
178 if (getenv("LTTNG_UST_WITHOUT_BADDR_STATEDUMP"))
179 return 0;
180
181 data.owner = owner;
182 data.exec_baddr = NULL;
183 /*
184 * Iterate through the list of currently loaded shared objects and
185 * generate events for loadable segments using
186 * extract_soinfo_events.
187 */
188 dl_iterate_phdr(extract_soinfo_events, &data);
189 /*
190 * We cannot call dladdr() from within phdr iteration, without
191 * causing constructor vs dynamic loader vs multithread internal
192 * deadlocks, so dump the executable outside of the phdr
193 * iteration.
194 */
195 dump_exec_baddr(&data);
196 return 0;
197 }
198
199 void lttng_ust_baddr_statedump_init(void)
200 {
201 __tracepoints__init();
202 __tracepoints__ptrs_init();
203 __lttng_events_init__ust_baddr_statedump();
204 }
205
206 void lttng_ust_baddr_statedump_destroy(void)
207 {
208 __lttng_events_exit__ust_baddr_statedump();
209 __tracepoints__ptrs_destroy();
210 __tracepoints__destroy();
211 }
This page took 0.033266 seconds and 4 git commands to generate.