1 // Setup routines for creating fully populated DWFLs. Used in pass 2 and 3.
2 // Copyright (C) 2009 Red Hat, Inc.
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
10 #include "setupdwfl.h"
12 #include "dwarf_wrappers.h"
24 static const char *debuginfo_path_arr
= "+:.debug:/usr/lib/debug:build";
25 static const char *debuginfo_env_arr
= getenv("SYSTEMTAP_DEBUGINFO_PATH");
26 static const char *debuginfo_path
= (debuginfo_env_arr
?: debuginfo_path_arr
);
28 // NB: kernel_build_tree doesn't enter into this, as it's for
29 // kernel-side modules only.
30 static const char *debuginfo_usr_path_arr
= "+:.debug:/usr/lib/debug";
31 static const char *debuginfo_usr_path
= (debuginfo_env_arr
32 ?: debuginfo_usr_path_arr
);
34 static const Dwfl_Callbacks kernel_callbacks
=
36 dwfl_linux_kernel_find_elf
,
37 dwfl_standard_find_debuginfo
,
38 dwfl_offline_section_address
,
39 (char **) & debuginfo_path
42 static const Dwfl_Callbacks user_callbacks
=
45 dwfl_standard_find_debuginfo
,
46 NULL
, /* ET_REL not supported for user space, only ET_EXEC and ET_DYN.
47 dwfl_offline_section_address, */
48 (char **) & debuginfo_usr_path
53 // Store last kernel and user Dwfl for reuse since they are often
54 // re-requested (in phase 2 and then in phase 3).
55 static DwflPtr kernel_dwfl
;
56 static DwflPtr user_dwfl
;
58 // Setup in setup_dwfl_kernel(), for use in setup_dwfl_report_kernel_p().
59 // Either offline_search_modname or offline_search_names is
60 // used. When offline_search_modname is not NULL then
61 // offline_search_names is ignored.
62 static const char *offline_search_modname
;
63 static set
<string
> offline_search_names
;
64 static unsigned offline_modules_found
;
66 // Whether or not we are done reporting kernel modules in
67 // set_dwfl_report_kernel_p().
68 static bool setup_dwfl_done
;
70 // Kept for user_dwfl cache, user modules don't allow wildcards, so
71 // just keep the set of module strings.
72 static set
<string
> user_modset
;
74 // Determines whether or not we will make setup_dwfl_report_kernel_p
75 // report true for all module dependencies. This is necessary for
76 // correctly resolving some dwarf constructs that relocate against
77 // symbols in vmlinux and/or other modules they depend on. See PR10678.
78 static const bool setup_all_deps
= true;
80 // Set up our offline search for kernel modules. We don't want the
81 // offline search iteration to do a complete search of the kernel
82 // build tree, since that's wasteful, so create a predicate that
83 // filters and stops reporting as soon as we got everything.
85 setup_dwfl_report_kernel_p(const char* modname
, const char* filename
)
87 if (pending_interrupts
|| setup_dwfl_done
)
90 // elfutils sends us NULL filenames sometimes if it can't find dwarf
94 // Check kernel first since it is often the only thing needed,
95 // then we never have to parse and setup the module deps map.
96 // It will be reported as the very first thing.
97 if (setup_all_deps
&& ! strcmp (modname
, "kernel"))
99 if ((offline_search_modname
!= NULL
100 && ! strcmp (offline_search_modname
, "kernel"))
101 || (offline_search_names
.size() == 1
102 && *offline_search_names
.begin() == "kernel"))
103 setup_dwfl_done
= true;
105 offline_modules_found
++;
109 // If offline_search_modname is setup use it (either as regexp or
110 // explicit module/kernel name) and ignore offline_search_names.
111 // Otherwise use offline_search_names exclusively.
112 if (offline_search_modname
!= NULL
)
114 if (dwflpp::name_has_wildcard (offline_search_modname
))
116 int match_p
= !fnmatch(offline_search_modname
, modname
, 0);
117 // In the wildcard case, we don't short-circuit (return -1)
118 // analogously to dwflpp::module_name_final_match().
120 offline_modules_found
++;
124 { /* non-wildcard mode, reject mismatching module names */
125 if (strcmp(modname
, offline_search_modname
))
129 // Done, only one name needed and found it.
130 offline_modules_found
++;
131 setup_dwfl_done
= true;
137 { /* find all in set mode, reject mismatching module names */
138 if (offline_search_names
.find(modname
) == offline_search_names
.end())
142 offline_modules_found
++;
143 if (offline_search_names
.size() == offline_modules_found
)
144 setup_dwfl_done
= true;
151 setup_dwfl_kernel (unsigned *modules_found
, systemtap_session
&s
)
153 Dwfl
*dwfl
= dwfl_begin (&kernel_callbacks
);
154 dwfl_assert ("dwfl_begin", dwfl
);
155 dwfl_report_begin (dwfl
);
157 // We have a problem with -r REVISION vs -r BUILDDIR here. If
158 // we're running against a fedora/rhel style kernel-debuginfo
159 // tree, s.kernel_build_tree is not the place where the unstripped
160 // vmlinux will be installed. Rather, it's over yonder at
161 // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is
162 // no way to set the dwfl_callback.debuginfo_path and always
163 // passs the plain kernel_release here. So instead we have to
164 // hard-code this magic here.
165 string elfutils_kernel_path
;
166 if (s
.kernel_build_tree
== string("/lib/modules/"
169 elfutils_kernel_path
= s
.kernel_release
;
171 elfutils_kernel_path
= s
.kernel_build_tree
;
173 offline_modules_found
= 0;
175 // First try to report full path modules.
176 set
<string
>::iterator it
= offline_search_names
.begin();
177 while (it
!= offline_search_names
.end())
181 const char *cname
= (*it
).c_str();
182 Dwfl_Module
*mod
= dwfl_report_offline (dwfl
, cname
, cname
, -1);
184 offline_modules_found
++;
189 // We always need this, even when offline_search_modname is NULL
190 // and offline_search_names is empty because we still might want
191 // the kernel vmlinux reported.
192 setup_dwfl_done
= false;
193 int rc
= dwfl_linux_kernel_report_offline (dwfl
,
194 elfutils_kernel_path
.c_str(),
195 &setup_dwfl_report_kernel_p
);
197 (void) rc
; /* Ignore since the predicate probably returned -1 at some point,
198 And libdwfl interprets that as "whole query failed" rather than
199 "found it already, stop looking". */
201 // NB: the result of an _offline call is the assignment of
202 // virtualized addresses to relocatable objects such as
203 // modules. These have to be converted to real addresses at
204 // run time. See the dwarf_derived_probe ctor and its caller.
206 dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl
, NULL
, NULL
));
207 *modules_found
= offline_modules_found
;
209 StapDwfl
*stap_dwfl
= new StapDwfl(dwfl
);
210 kernel_dwfl
= DwflPtr(stap_dwfl
);
216 setup_dwfl_kernel(const std::string
&name
,
218 systemtap_session
&s
)
220 const char *modname
= name
.c_str();
221 set
<string
> names
; // Default to empty
223 /* Support full path kernel modules, these cannot be regular
224 expressions, so just put them in the search set. */
225 if (name
[0] == '/' || ! dwflpp::name_has_wildcard (modname
))
231 if (kernel_dwfl
!= NULL
232 && offline_search_modname
== modname
233 && offline_search_names
== names
)
235 *found
= offline_modules_found
;
239 offline_search_modname
= modname
;
240 offline_search_names
= names
;
242 return setup_dwfl_kernel(found
, s
);
246 setup_dwfl_kernel(const std::set
<std::string
> &names
,
248 systemtap_session
&s
)
250 if (kernel_dwfl
!= NULL
251 && offline_search_modname
== NULL
252 && offline_search_names
== names
)
254 *found
= offline_modules_found
;
258 offline_search_modname
= NULL
;
259 offline_search_names
= names
;
260 return setup_dwfl_kernel(found
, s
);
264 setup_dwfl_user(const std::string
&name
)
266 if (user_dwfl
!= NULL
267 && user_modset
.size() == 1
268 && (*user_modset
.begin()) == name
)
272 user_modset
.insert(name
);
274 Dwfl
*dwfl
= dwfl_begin (&user_callbacks
);
275 dwfl_assert("dwfl_begin", dwfl
);
276 dwfl_report_begin (dwfl
);
278 // XXX: should support buildid-based naming
279 const char *cname
= name
.c_str();
280 Dwfl_Module
*mod
= dwfl_report_offline (dwfl
, cname
, cname
, -1);
281 dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl
, NULL
, NULL
));
288 StapDwfl
*stap_dwfl
= new StapDwfl(dwfl
);
289 user_dwfl
= DwflPtr(stap_dwfl
);
295 setup_dwfl_user(std::vector
<std::string
>::const_iterator
&begin
,
296 const std::vector
<std::string
>::const_iterator
&end
,
299 // See if we have this dwfl already cached
300 set
<string
> modset(begin
, end
);
301 if (user_dwfl
!= NULL
&& modset
== user_modset
)
304 user_modset
= modset
;
306 Dwfl
*dwfl
= dwfl_begin (&user_callbacks
);
307 dwfl_assert("dwfl_begin", dwfl
);
308 dwfl_report_begin (dwfl
);
310 // XXX: should support buildid-based naming
311 while (begin
!= end
&& dwfl
!= NULL
)
313 const char *cname
= (*begin
).c_str();
314 Dwfl_Module
*mod
= dwfl_report_offline (dwfl
, cname
, cname
, -1);
315 if (! mod
&& all_needed
)
323 dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl
, NULL
, NULL
));
325 StapDwfl
*stap_dwfl
= new StapDwfl(dwfl
);
326 user_dwfl
= DwflPtr(stap_dwfl
);
332 is_user_module(const std::string
&m
)
334 return m
[0] == '/' && m
.rfind(".ko", m
.length() - 1) != m
.length() - 3;