Commit | Line | Data |
---|---|---|
b13d93c2 | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
b13d93c2 | 3 | * |
c0c0989a MJ |
4 | * Copyright (C) 2013 Paul Woegerer <paul.woegerer@mentor.com> |
5 | * Copyright (C) 2015 Antoine Busque <abusque@efficios.com> | |
6 | * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
b13d93c2 PW |
7 | */ |
8 | ||
1ddceb36 | 9 | #define _LGPL_SOURCE |
9d315d6d MJ |
10 | |
11 | /* Has to be included first to override dlfcn.h */ | |
12 | #include <common/compat/dlfcn.h> | |
13 | ||
13436238 | 14 | #include <limits.h> |
8e2aed3f | 15 | #include <stdio.h> |
fb31eb73 | 16 | #include <stdint.h> |
13436238 | 17 | #include <sys/types.h> |
8e2aed3f AB |
18 | #include <unistd.h> |
19 | ||
9d315d6d | 20 | #include "common/elf.h" |
97c7c238 | 21 | #include <lttng/ust-events.h> |
9d315d6d MJ |
22 | #include "common/macros.h" |
23 | #include "common/logging.h" | |
36c52fff | 24 | #include "common/events.h" |
cbba5e04 | 25 | |
8e2aed3f AB |
26 | /* Include link.h last else it conflicts with ust-dlfcn. */ |
27 | #include <link.h> | |
b13d93c2 | 28 | |
13436238 | 29 | #define TRACEPOINT_DEFINE |
6d4658aa | 30 | #include "ust_dl.h" |
13436238 | 31 | |
7b0fdd83 | 32 | static void *(*__lttng_ust_plibc_dlopen)(const char *filename, int flags); |
42330adc | 33 | #ifdef HAVE_DLMOPEN |
7b0fdd83 MD |
34 | static void *(*__lttng_ust_plibc_dlmopen)(Lmid_t nsid, const char *filename, |
35 | int flags); | |
42330adc | 36 | #endif |
b13d93c2 | 37 | static int (*__lttng_ust_plibc_dlclose)(void *handle); |
b13d93c2 PW |
38 | |
39 | static | |
7b0fdd83 | 40 | void *_lttng_ust_dl_libc_dlopen(const char *filename, int flags) |
b13d93c2 PW |
41 | { |
42 | if (!__lttng_ust_plibc_dlopen) { | |
43 | __lttng_ust_plibc_dlopen = dlsym(RTLD_NEXT, "dlopen"); | |
8e2aed3f | 44 | if (!__lttng_ust_plibc_dlopen) { |
b13d93c2 PW |
45 | fprintf(stderr, "%s\n", dlerror()); |
46 | return NULL; | |
47 | } | |
48 | } | |
7b0fdd83 MD |
49 | return __lttng_ust_plibc_dlopen(filename, flags); |
50 | } | |
51 | ||
42330adc | 52 | #ifdef HAVE_DLMOPEN |
7b0fdd83 MD |
53 | static |
54 | void *_lttng_ust_dl_libc_dlmopen(Lmid_t nsid, const char *filename, | |
55 | int flags) | |
56 | { | |
57 | if (!__lttng_ust_plibc_dlmopen) { | |
58 | __lttng_ust_plibc_dlmopen = dlsym(RTLD_NEXT, "dlmopen"); | |
59 | if (!__lttng_ust_plibc_dlmopen) { | |
60 | fprintf(stderr, "%s\n", dlerror()); | |
61 | return NULL; | |
62 | } | |
63 | } | |
64 | return __lttng_ust_plibc_dlmopen(nsid, filename, flags); | |
b13d93c2 | 65 | } |
42330adc | 66 | #endif |
b13d93c2 PW |
67 | |
68 | static | |
69 | int _lttng_ust_dl_libc_dlclose(void *handle) | |
70 | { | |
71 | if (!__lttng_ust_plibc_dlclose) { | |
72 | __lttng_ust_plibc_dlclose = dlsym(RTLD_NEXT, "dlclose"); | |
8e2aed3f | 73 | if (!__lttng_ust_plibc_dlclose) { |
b13d93c2 PW |
74 | fprintf(stderr, "%s\n", dlerror()); |
75 | return -1; | |
76 | } | |
77 | } | |
78 | return __lttng_ust_plibc_dlclose(handle); | |
79 | } | |
80 | ||
81 | static | |
7b0fdd83 MD |
82 | void lttng_ust_dl_dlopen(void *so_base, const char *so_name, |
83 | int flags, void *ip) | |
b13d93c2 | 84 | { |
13436238 | 85 | char resolved_path[PATH_MAX]; |
8e2aed3f AB |
86 | struct lttng_ust_elf *elf; |
87 | uint64_t memsz; | |
83215d66 | 88 | uint8_t *build_id = NULL; |
8e2aed3f | 89 | size_t build_id_len; |
83215d66 | 90 | char *dbg_file = NULL; |
8e2aed3f AB |
91 | uint32_t crc; |
92 | int has_build_id = 0, has_debug_link = 0; | |
93 | int ret; | |
b13d93c2 | 94 | |
13436238 PW |
95 | if (!realpath(so_name, resolved_path)) { |
96 | ERR("could not resolve path '%s'", so_name); | |
97 | return; | |
b13d93c2 | 98 | } |
b13d93c2 | 99 | |
8e2aed3f AB |
100 | elf = lttng_ust_elf_create(resolved_path); |
101 | if (!elf) { | |
09026ccf | 102 | ERR("could not access file %s", resolved_path); |
13436238 | 103 | return; |
b13d93c2 | 104 | } |
13436238 | 105 | |
8e2aed3f AB |
106 | ret = lttng_ust_elf_get_memsz(elf, &memsz); |
107 | if (ret) { | |
108 | goto end; | |
109 | } | |
110 | ret = lttng_ust_elf_get_build_id( | |
111 | elf, &build_id, &build_id_len, &has_build_id); | |
112 | if (ret) { | |
113 | goto end; | |
114 | } | |
115 | ret = lttng_ust_elf_get_debug_link( | |
116 | elf, &dbg_file, &crc, &has_debug_link); | |
117 | if (ret) { | |
118 | goto end; | |
119 | } | |
120 | ||
cbc06a3b | 121 | lttng_ust_tracepoint(lttng_ust_dl, dlopen, |
7b0fdd83 | 122 | ip, so_base, resolved_path, flags, memsz, |
c5c4fd82 | 123 | has_build_id, has_debug_link); |
8e2aed3f AB |
124 | |
125 | if (has_build_id) { | |
cbc06a3b | 126 | lttng_ust_tracepoint(lttng_ust_dl, build_id, |
8e2aed3f | 127 | ip, so_base, build_id, build_id_len); |
8e2aed3f AB |
128 | } |
129 | ||
130 | if (has_debug_link) { | |
cbc06a3b | 131 | lttng_ust_tracepoint(lttng_ust_dl, debug_link, |
8e2aed3f | 132 | ip, so_base, dbg_file, crc); |
8e2aed3f AB |
133 | } |
134 | ||
135 | end: | |
83215d66 MD |
136 | free(dbg_file); |
137 | free(build_id); | |
8e2aed3f | 138 | lttng_ust_elf_destroy(elf); |
13436238 | 139 | return; |
b13d93c2 PW |
140 | } |
141 | ||
42330adc | 142 | #ifdef HAVE_DLMOPEN |
7b0fdd83 MD |
143 | static |
144 | void lttng_ust_dl_dlmopen(void *so_base, Lmid_t nsid, const char *so_name, | |
145 | int flags, void *ip) | |
146 | { | |
147 | char resolved_path[PATH_MAX]; | |
148 | struct lttng_ust_elf *elf; | |
149 | uint64_t memsz; | |
150 | uint8_t *build_id = NULL; | |
151 | size_t build_id_len; | |
152 | char *dbg_file = NULL; | |
153 | uint32_t crc; | |
154 | int has_build_id = 0, has_debug_link = 0; | |
155 | int ret; | |
156 | ||
157 | if (!realpath(so_name, resolved_path)) { | |
158 | ERR("could not resolve path '%s'", so_name); | |
159 | return; | |
160 | } | |
161 | ||
162 | elf = lttng_ust_elf_create(resolved_path); | |
163 | if (!elf) { | |
09026ccf | 164 | ERR("could not access file %s", resolved_path); |
7b0fdd83 MD |
165 | return; |
166 | } | |
167 | ||
168 | ret = lttng_ust_elf_get_memsz(elf, &memsz); | |
169 | if (ret) { | |
170 | goto end; | |
171 | } | |
172 | ret = lttng_ust_elf_get_build_id( | |
173 | elf, &build_id, &build_id_len, &has_build_id); | |
174 | if (ret) { | |
175 | goto end; | |
176 | } | |
177 | ret = lttng_ust_elf_get_debug_link( | |
178 | elf, &dbg_file, &crc, &has_debug_link); | |
179 | if (ret) { | |
180 | goto end; | |
181 | } | |
182 | ||
cbc06a3b | 183 | lttng_ust_tracepoint(lttng_ust_dl, dlmopen, |
7b0fdd83 MD |
184 | ip, so_base, nsid, resolved_path, flags, memsz, |
185 | has_build_id, has_debug_link); | |
186 | ||
187 | if (has_build_id) { | |
cbc06a3b | 188 | lttng_ust_tracepoint(lttng_ust_dl, build_id, |
7b0fdd83 MD |
189 | ip, so_base, build_id, build_id_len); |
190 | } | |
191 | ||
192 | if (has_debug_link) { | |
cbc06a3b | 193 | lttng_ust_tracepoint(lttng_ust_dl, debug_link, |
7b0fdd83 MD |
194 | ip, so_base, dbg_file, crc); |
195 | } | |
196 | ||
197 | end: | |
198 | free(dbg_file); | |
199 | free(build_id); | |
200 | lttng_ust_elf_destroy(elf); | |
201 | return; | |
202 | } | |
42330adc | 203 | #endif |
7b0fdd83 MD |
204 | |
205 | void *dlopen(const char *filename, int flags) | |
b13d93c2 | 206 | { |
8e2aed3f AB |
207 | void *handle; |
208 | ||
7b0fdd83 | 209 | handle = _lttng_ust_dl_libc_dlopen(filename, flags); |
bd703713 | 210 | if (__tracepoint_ptrs_registered && handle) { |
b13d93c2 | 211 | struct link_map *p = NULL; |
8e2aed3f AB |
212 | int ret; |
213 | ||
214 | ret = dlinfo(handle, RTLD_DI_LINKMAP, &p); | |
215 | if (ret != -1 && p != NULL && p->l_addr != 0) { | |
97c7c238 | 216 | lttng_ust_dl_dlopen((void *) p->l_addr, |
7b0fdd83 MD |
217 | p->l_name, flags, LTTNG_UST_CALLER_IP()); |
218 | } | |
219 | } | |
220 | lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); | |
221 | return handle; | |
222 | } | |
223 | ||
42330adc | 224 | #ifdef HAVE_DLMOPEN |
7b0fdd83 MD |
225 | void *dlmopen(Lmid_t nsid, const char *filename, int flags) |
226 | { | |
227 | void *handle; | |
228 | ||
229 | handle = _lttng_ust_dl_libc_dlmopen(nsid, filename, flags); | |
230 | if (__tracepoint_ptrs_registered && handle) { | |
231 | struct link_map *p = NULL; | |
232 | int ret; | |
233 | ||
234 | ret = dlinfo(handle, RTLD_DI_LINKMAP, &p); | |
235 | if (ret != -1 && p != NULL && p->l_addr != 0) { | |
236 | lttng_ust_dl_dlmopen((void *) p->l_addr, | |
237 | nsid, p->l_name, flags, | |
171fcc6f | 238 | LTTNG_UST_CALLER_IP()); |
8e2aed3f | 239 | } |
b13d93c2 | 240 | } |
97c7c238 | 241 | lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); |
b13d93c2 | 242 | return handle; |
7b0fdd83 | 243 | |
b13d93c2 | 244 | } |
42330adc | 245 | #endif |
b13d93c2 PW |
246 | |
247 | int dlclose(void *handle) | |
248 | { | |
97c7c238 MD |
249 | int ret; |
250 | ||
e7953e6e | 251 | if (__tracepoint_ptrs_registered) { |
b13d93c2 | 252 | struct link_map *p = NULL; |
8e2aed3f AB |
253 | |
254 | ret = dlinfo(handle, RTLD_DI_LINKMAP, &p); | |
255 | if (ret != -1 && p != NULL && p->l_addr != 0) { | |
cbc06a3b | 256 | lttng_ust_tracepoint(lttng_ust_dl, dlclose, |
171fcc6f | 257 | LTTNG_UST_CALLER_IP(), |
8e2aed3f AB |
258 | (void *) p->l_addr); |
259 | } | |
b13d93c2 | 260 | } |
97c7c238 MD |
261 | ret = _lttng_ust_dl_libc_dlclose(handle); |
262 | lttng_ust_dl_update(LTTNG_UST_CALLER_IP()); | |
263 | return ret; | |
b13d93c2 | 264 | } |