]> sourceware.org Git - systemtap.git/blob - setupdwfl.cxx
NEWS :: mention BPF tapset functions
[systemtap.git] / setupdwfl.cxx
1 // Setup routines for creating fully populated DWFLs. Used in pass 2 and 3.
2 // Copyright (C) 2009-2018 Red Hat, Inc.
3 //
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
7 // later version.
8
9 #include "config.h"
10 #include "setupdwfl.h"
11
12 #include "dwarf_wrappers.h"
13 #include "dwflpp.h"
14 #include "session.h"
15 #include "util.h"
16
17 #include <algorithm>
18 #include <iostream>
19 #include <fstream>
20 #include <sstream>
21 #include <set>
22 #include <string>
23
24 extern "C" {
25 #include <fnmatch.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <time.h>
29 #include <sys/times.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <fcntl.h>
34 #include <limits.h>
35 #include <sys/utsname.h>
36 #include <unistd.h>
37 }
38
39 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
40 static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build";
41 static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
42 static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr);
43
44 // NB: kernel_build_tree doesn't enter into this, as it's for
45 // kernel-side modules only.
46 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
47 static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug";
48 static char *debuginfo_usr_path = (char *)(debuginfo_env_arr
49 ?: debuginfo_usr_path_arr);
50
51 // A pointer to the current systemtap session for use only by a few
52 // dwfl calls. DO NOT rely on this, as it is cleared after use.
53 // This is a kludge.
54 static systemtap_session* current_session_for_find_debuginfo;
55
56 static const Dwfl_Callbacks kernel_callbacks =
57 {
58 dwfl_linux_kernel_find_elf,
59 internal_find_debuginfo,
60 dwfl_offline_section_address,
61 (char **) & debuginfo_path
62 };
63
64 static const Dwfl_Callbacks user_callbacks =
65 {
66 NULL,
67 internal_find_debuginfo,
68 NULL, /* ET_REL not supported for user space, only ET_EXEC and ET_DYN.
69 dwfl_offline_section_address, */
70 (char **) & debuginfo_usr_path
71 };
72
73 using namespace std;
74
75 // Setup in setup_dwfl_kernel(), for use in setup_dwfl_report_kernel_p().
76 // Either offline_search_modname or offline_search_names is
77 // used. When offline_search_modname is not NULL then
78 // offline_search_names is ignored.
79 static const char *offline_search_modname;
80 static set<string> offline_search_names;
81 static unsigned offline_modules_found;
82
83 // Whether or not we are done reporting kernel modules in
84 // set_dwfl_report_kernel_p().
85 static bool setup_dwfl_done;
86
87 // Determines whether or not we will make setup_dwfl_report_kernel_p
88 // report true for all module dependencies. This is necessary for
89 // correctly resolving some dwarf constructs that relocate against
90 // symbols in vmlinux and/or other modules they depend on. See PR10678.
91 static const bool setup_all_deps = true;
92
93 // Where to find the kernel (and the Modules.dep file). Setup in
94 // setup_dwfl_kernel(), used by dwfl_linux_kernel_report_offline() and
95 // setup_mod_deps().
96 static string elfutils_kernel_path;
97
98 static bool is_comma_dash(const char c) { return (c == ',' || c == '-'); }
99
100 // The path to the abrt-action-install-debuginfo-to-abrt-cache program.
101 static const string abrt_path =
102 (access ("/usr/bin/abrt-action-install-debuginfo-to-abrt-cache", X_OK) == 0
103 ? "/usr/bin/abrt-action-install-debuginfo-to-abrt-cache"
104 : (access ("/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache", X_OK) == 0
105 ? "/usr/libexec/abrt-action-install-debuginfo-to-abrt-cache"
106 : ""));
107
108 // The module name is the basename (without the extension) of the module path,
109 // with ',' and '-' replaced by '_'. This is a (more or less safe) heuristic:
110 // the actual name by which the module is known once inside the kernel is not
111 // derived from the path, but from the .gnu.linkonce.this_module section of the
112 // KO. In practice, modules in /lib/modules/ respect this convention, and we
113 // require it as well for out-of-tree kernel modules.
114 string
115 modname_from_path(const string &path)
116 {
117 size_t slash = path.rfind('/');
118 if (slash == string::npos)
119 return "";
120 string name = path.substr(slash + 1);
121
122 // First look for .ko extension variants like ".ko" or ".ko.xz"
123 // If that fails, look for any ".*" extension at all.
124 size_t extension = name.rfind(".ko");
125 if (extension == string::npos)
126 extension = name.rfind('.');
127 if (extension == string::npos)
128 return "";
129
130 name.erase(extension);
131 replace_if(name.begin(), name.end(), is_comma_dash, '_');
132 return name;
133 }
134
135 static bool offline_search_names_find(const string &modpath) {
136 if (offline_search_names.find(modpath) != offline_search_names.end()) return 1;
137 string modname = modname_from_path (modpath);
138 return offline_search_names.find(modname) != offline_search_names.end();
139 }
140
141 // Try to parse modules.dep file,
142 // Simple format: module path (either full or relative), colon,
143 // (possibly empty) space delimited list of module (path)
144 // dependencies.
145 static void
146 setup_mod_deps()
147 {
148 string modulesdep;
149 string kernel_path;
150 ifstream in;
151 string l;
152
153 if (elfutils_kernel_path[0] == '/')
154 {
155 kernel_path = elfutils_kernel_path;
156 }
157 else
158 {
159 string sysroot = "";
160 if (current_session_for_find_debuginfo)
161 sysroot = current_session_for_find_debuginfo->sysroot;
162 kernel_path = sysroot + "/lib/modules/" + elfutils_kernel_path;
163 }
164 modulesdep = kernel_path + "/modules.dep";
165 in.open(modulesdep.c_str());
166 if (in.fail ())
167 return;
168
169 while (getline (in, l))
170 {
171 size_t off = l.find (':');
172 if (off != string::npos)
173 {
174 string modpath, modname;
175 modpath = l.substr (0, off);
176 modname = modname_from_path (modpath);
177 if (modname == "")
178 continue;
179 if (modpath[0] != '/') modpath = kernel_path + "/" + modpath;
180
181 bool dep_needed = 0;
182 if (offline_search_modname != NULL)
183 {
184 if (dwflpp::name_has_wildcard (offline_search_modname))
185 {
186 dep_needed = !fnmatch (offline_search_modname,
187 modname.c_str (), 0);
188 if (dep_needed)
189 offline_search_names.insert (modpath);
190 }
191 else
192 {
193 dep_needed = ! strcmp(modname.c_str (),
194 offline_search_modname);
195 if (dep_needed)
196 offline_search_names.insert (modpath);
197 }
198 }
199 else if (offline_search_names.find(modpath) != offline_search_names.end())
200 dep_needed = 1;
201 else
202 {
203 set<string>::iterator it = offline_search_names.begin();
204 while (it != offline_search_names.end())
205 {
206 string modname;
207 modname = modname_from_path(modpath);
208 if (*it == modname)
209 {
210 dep_needed = 1;
211 offline_search_names.erase(it);
212 offline_search_names.insert(modpath);
213 break;
214 }
215 it++;
216 }
217 }
218
219 if (! dep_needed)
220 continue;
221
222 string depstring = l.substr (off + 1);
223 if (depstring.size () > 0)
224 {
225 stringstream ss (depstring);
226 string deppath;
227 while (ss >> deppath)
228 offline_search_names.insert (deppath);
229
230 }
231 }
232 }
233
234 // We always want kernel (needed in list so size checks match).
235 // Everything needed now stored in offline_search_names.
236 offline_search_names.insert ("kernel");
237 offline_search_modname = NULL;
238 }
239
240 // Set up our offline search for kernel modules. We don't want the
241 // offline search iteration to do a complete search of the kernel
242 // build tree, since that's wasteful, so create a predicate that
243 // filters and stops reporting as soon as we got everything.
244 static int
245 setup_dwfl_report_kernel_p(const char* modname, const char* filename)
246 {
247 assert_no_interrupts();
248
249 if (setup_dwfl_done)
250 return -1;
251
252 assert (current_session_for_find_debuginfo);
253 if (current_session_for_find_debuginfo->verbose > 4)
254 clog << _F("checking pattern '%s' vs. module '%s' file '%s'\n",
255 offline_search_modname ?: "",
256 modname ?: "",
257 filename ?: "");
258
259 // elfutils sends us NULL filenames sometimes if it can't find dwarf
260 if (filename == NULL)
261 return 0;
262
263 // Check kernel first since it is often the only thing needed,
264 // then we never have to parse and setup the module deps map.
265 // It will be reported as the very first thing.
266 if (setup_all_deps && ! strcmp (modname, "kernel"))
267 {
268 if ((offline_search_modname != NULL
269 && ! strcmp (offline_search_modname, "kernel"))
270 || (offline_search_names.size() == 1
271 && *offline_search_names.begin() == "kernel"))
272 setup_dwfl_done = true;
273 else
274 setup_mod_deps();
275
276 offline_modules_found++;
277 return 1;
278 }
279
280 // If offline_search_modname is setup use it (either as regexp or
281 // explicit module/kernel name) and ignore offline_search_names.
282 // Otherwise use offline_search_names exclusively.
283 if (offline_search_modname != NULL)
284 {
285 if (dwflpp::name_has_wildcard (offline_search_modname))
286 {
287 // XXX: see also dwflpp::module_name_matches()
288 int match_p = !fnmatch(offline_search_modname, modname, 0);
289 // In the wildcard case, we don't short-circuit (return -1)
290 // analogously to dwflpp::module_name_final_match().
291 if (match_p)
292 offline_modules_found++;
293 return match_p;
294 }
295 else
296 { /* non-wildcard mode, reject mismatching module names */
297 if (strcmp(modname, offline_search_modname))
298 return 0;
299 else
300 {
301 // Done, only one name needed and found it.
302 offline_modules_found++;
303 setup_dwfl_done = true;
304 return 1;
305 }
306 }
307 }
308 else
309 { /* find all in set mode, reject mismatching module names */
310 if (!offline_search_names_find(filename))
311 return 0;
312 else
313 {
314 offline_modules_found++;
315 if (offline_search_names.size() == offline_modules_found)
316 setup_dwfl_done = true;
317 return 1;
318 }
319 }
320 }
321
322 static char * path_insert_sysroot(string sysroot, string path)
323 {
324 char * path_new;
325 size_t pos = 1;
326 if (path[0] == '/')
327 path.replace(0, 1, sysroot);
328 while (true) {
329 pos = path.find(":/", pos);
330 if (pos == string::npos)
331 break;
332 path.replace(pos, 2, ":" + sysroot);
333 ++pos;
334 }
335 path_new = new char[path.size()+1];
336 strcpy (path_new, path.c_str());
337 return path_new;
338 }
339
340 void debuginfo_path_insert_sysroot(string sysroot)
341 {
342 // FIXME: This is a short-term fix, until we expect sysroot paths to
343 // always end with a '/' (and never be empty).
344 //
345 // The path_insert_sysroot() function assumes that sysroot has a '/'
346 // on the end. Make sure that is true.
347 if (! sysroot.empty() && *(sysroot.end() - 1) != '/')
348 sysroot.append(1, '/');
349 debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path);
350 debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path);
351 }
352
353 static Dwfl *
354 setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
355 {
356 Dwfl *dwfl = dwfl_begin (&kernel_callbacks);
357 DWFL_ASSERT ("dwfl_begin", dwfl);
358 dwfl_report_begin (dwfl);
359
360 // We have a problem with -r REVISION vs -r BUILDDIR here. If
361 // we're running against a fedora/rhel style kernel-debuginfo
362 // tree, s.kernel_build_tree is not the place where the unstripped
363 // vmlinux will be installed. Rather, it's over yonder at
364 // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is
365 // no way to set the dwfl_callback.debuginfo_path and always
366 // passs the plain kernel_release here. So instead we have to
367 // hard-code this magic here.
368 string lib_path = s.sysroot + "/lib/modules/" + s.kernel_release + "/build";
369 if (s.kernel_build_tree == lib_path)
370 {
371 if (s.sysroot != "")
372 // If we have sysroot set does not make sense to pass
373 // short release to dwfl, it won't take a sysroot into
374 // account. Let's construct full path in such case.
375 elfutils_kernel_path = string(s.sysroot + "/lib/modules/" + s.kernel_release);
376 else
377 elfutils_kernel_path = s.kernel_release;
378 }
379 else
380 elfutils_kernel_path = s.kernel_build_tree;
381 offline_modules_found = 0;
382
383 // First try to report full path modules.
384 set<string>::iterator it = offline_search_names.begin();
385 int kernel = 0;
386 while (it != offline_search_names.end())
387 {
388 if ((*it)[0] == '/')
389 {
390 const char *cname = (*it).c_str();
391 Dwfl_Module *mod = dwfl_report_offline (dwfl, cname, cname, -1);
392 if (mod)
393 offline_modules_found++;
394 }
395 else if ((*it) == "kernel")
396 kernel = 1;
397 it++;
398 }
399
400 // We always need this, even when offline_search_modname is NULL
401 // and offline_search_names is empty because we still might want
402 // the kernel vmlinux reported.
403 setup_dwfl_done = false;
404 int rc = dwfl_linux_kernel_report_offline (dwfl,
405 elfutils_kernel_path.c_str(),
406 &setup_dwfl_report_kernel_p);
407
408 (void) rc; /* Ignore since the predicate probably returned -1 at some point,
409 And libdwfl interprets that as "whole query failed" rather than
410 "found it already, stop looking". */
411
412 // NB: the result of an _offline call is the assignment of
413 // virtualized addresses to relocatable objects such as
414 // modules. These have to be converted to real addresses at
415 // run time. See the dwarf_derived_probe ctor and its caller.
416
417 // If no modules were found, and we are probing the kernel,
418 // attempt to download the kernel debuginfo.
419 if(kernel)
420 {
421 // Get the kernel build ID. We still need to call this even if we
422 // already have the kernel debuginfo installed as it adds the
423 // build ID to the script hash.
424 string hex = get_kernel_build_id(s);
425 if (offline_modules_found == 0 && s.download_dbinfo != 0 && !hex.empty())
426 {
427 rc = download_kernel_debuginfo(s, hex);
428 if(rc >= 0)
429 {
430 dwfl_end (dwfl);
431 return setup_dwfl_kernel (modules_found, s);
432 }
433 }
434 }
435
436 DWFL_ASSERT ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
437 *modules_found = offline_modules_found;
438
439 return dwfl;
440 }
441
442 Dwfl*
443 setup_dwfl_kernel(const std::string &name,
444 unsigned *found,
445 systemtap_session &s)
446 {
447 current_session_for_find_debuginfo = &s;
448 const char *modname = name.c_str();
449 set<string> names; // Default to empty
450
451 /* Support full path kernel modules, these cannot be regular
452 expressions, so just put them in the search set. */
453 if (name[0] == '/' || ! dwflpp::name_has_wildcard (modname))
454 {
455 names.insert(name);
456 modname = NULL;
457 }
458
459 offline_search_modname = modname;
460 offline_search_names = names;
461
462 return setup_dwfl_kernel(found, s);
463 }
464
465 Dwfl*
466 setup_dwfl_kernel(const std::set<std::string> &names,
467 unsigned *found,
468 systemtap_session &s)
469 {
470 current_session_for_find_debuginfo = &s;
471
472 offline_search_modname = NULL;
473 offline_search_names = names;
474 return setup_dwfl_kernel(found, s);
475 }
476
477 Dwfl*
478 setup_dwfl_user(const std::string &name)
479 {
480 Dwfl *dwfl = dwfl_begin (&user_callbacks);
481 DWFL_ASSERT("dwfl_begin", dwfl);
482 dwfl_report_begin (dwfl);
483
484 // XXX: should support buildid-based naming
485 const char *cname = name.c_str();
486 Dwfl_Module *mod = dwfl_report_offline (dwfl, cname, cname, -1);
487 DWFL_ASSERT ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
488 if (! mod)
489 {
490 dwfl_end(dwfl);
491 dwfl = NULL;
492 }
493
494 return dwfl;
495 }
496
497 Dwfl*
498 setup_dwfl_user(std::vector<std::string>::const_iterator &begin,
499 const std::vector<std::string>::const_iterator &end,
500 bool all_needed, systemtap_session &s)
501 {
502 current_session_for_find_debuginfo = &s;
503 // See if we have this dwfl already cached
504 set<string> modset(begin, end);
505
506 Dwfl *dwfl = dwfl_begin (&user_callbacks);
507 DWFL_ASSERT("dwfl_begin", dwfl);
508 dwfl_report_begin (dwfl);
509 Dwfl_Module *mod = NULL;
510 // XXX: should support buildid-based naming
511 while (begin != end && dwfl != NULL)
512 {
513 const char *cname = (*begin).c_str();
514 mod = dwfl_report_offline (dwfl, cname, cname, -1);
515 if (! mod && all_needed)
516 {
517 dwfl_end(dwfl);
518 dwfl = NULL;
519 }
520 begin++;
521 }
522
523 /* Extract the build id and add it to the session variable
524 * so it will be added to the script hash */
525 if (mod)
526 {
527 const unsigned char *bits;
528 GElf_Addr vaddr;
529 if(s.verbose > 2)
530 clog << _("Extracting build ID.") << endl;
531 int bits_length = dwfl_module_build_id(mod, &bits, &vaddr);
532
533 /* Convert the binary bits to a hex string */
534 string hex = hex_dump(bits, bits_length);
535
536 //Store the build ID in the session
537 s.build_ids.push_back(hex);
538 }
539
540 if (dwfl)
541 DWFL_ASSERT ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
542
543 return dwfl;
544 }
545
546 bool
547 is_user_module(const std::string &m)
548 {
549 return m[0] == '/' && m.rfind(".ko", m.length() - 1) != m.length() - 3;
550 }
551
552 int
553 internal_find_debuginfo (Dwfl_Module *mod,
554 void **userdata __attribute__ ((unused)),
555 const char *modname __attribute__ ((unused)),
556 GElf_Addr base __attribute__ ((unused)),
557 const char *file_name,
558 const char *debuglink_file,
559 GElf_Word debuglink_crc,
560 char **debuginfo_file_name)
561 {
562
563 int bits_length;
564 string hex;
565
566 /* To Keep track of whether the abrt successfully installed the debuginfo */
567 static int install_dbinfo_failed = 0;
568
569 /* Make sure the current session variable is not null */
570 if(current_session_for_find_debuginfo == NULL)
571 goto call_dwfl_standard_find_debuginfo;
572
573 /* Check to see if download-debuginfo=0 was set */
574 if(!current_session_for_find_debuginfo->download_dbinfo || abrt_path.empty())
575 goto call_dwfl_standard_find_debuginfo;
576
577 /* Check that we haven't already run this */
578 if (install_dbinfo_failed < 0)
579 {
580 if(current_session_for_find_debuginfo->verbose > 1)
581 current_session_for_find_debuginfo->print_warning(_F("We already tried running '%s'", abrt_path.c_str()));
582 goto call_dwfl_standard_find_debuginfo;
583 }
584
585 /* Extract the build ID */
586 const unsigned char *bits;
587 GElf_Addr vaddr;
588 if(current_session_for_find_debuginfo->verbose > 2)
589 clog << _("Extracting build ID.") << endl;
590 bits_length = dwfl_module_build_id(mod, &bits, &vaddr);
591
592 /* Convert the binary bits to a hex string */
593 hex = hex_dump(bits, bits_length);
594
595 /* Search for the debuginfo with the build ID */
596 if(current_session_for_find_debuginfo->verbose > 2)
597 clog << _F("Searching for debuginfo with build ID: '%s'.", hex.c_str()) << endl;
598 if (bits_length > 0)
599 {
600 int fd = dwfl_build_id_find_debuginfo(mod,
601 NULL, NULL, 0,
602 NULL, NULL, 0,
603 debuginfo_file_name);
604 if (fd >= 0)
605 return fd;
606 }
607
608 /* The above failed, so call abrt-action-install-debuginfo-to-abrt-cache
609 to download and install the debuginfo */
610 if(current_session_for_find_debuginfo->verbose > 1)
611 clog << _F("Downloading and installing debuginfo with build ID: '%s' using %s.",
612 hex.c_str(), abrt_path.c_str()) << endl;
613
614 struct tms tms_before;
615 times (& tms_before);
616 struct timeval tv_before;
617 struct tms tms_after;
618 unsigned _sc_clk_tck;
619 struct timeval tv_after;
620 gettimeofday (&tv_before, NULL);
621
622 if(execute_abrt_action_install_debuginfo_to_abrt_cache (hex) < 0)
623 {
624 install_dbinfo_failed = -1;
625 current_session_for_find_debuginfo->print_warning(_F("%s failed.", abrt_path.c_str()));
626 goto call_dwfl_standard_find_debuginfo;
627 }
628
629 _sc_clk_tck = sysconf (_SC_CLK_TCK);
630 times (& tms_after);
631 gettimeofday (&tv_after, NULL);
632 if(current_session_for_find_debuginfo->verbose > 1)
633 clog << _("Download completed in ")
634 << ((tms_after.tms_cutime + tms_after.tms_utime
635 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck)) << "usr/"
636 << ((tms_after.tms_cstime + tms_after.tms_stime
637 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck)) << "sys/"
638 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 +
639 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms"<< endl;
640
641 call_dwfl_standard_find_debuginfo:
642
643 /* Call the original dwfl_standard_find_debuginfo */
644 return dwfl_standard_find_debuginfo(mod, userdata, modname, base,
645 file_name, debuglink_file,
646 debuglink_crc, debuginfo_file_name);
647
648 }
649
650 int
651 execute_abrt_action_install_debuginfo_to_abrt_cache (string hex)
652 {
653 /* Be sure that abrt exists */
654 if (abrt_path.empty())
655 return -1;
656
657 int timeout = current_session_for_find_debuginfo->download_dbinfo;;
658 vector<string> cmd;
659 cmd.push_back ("/bin/sh");
660 cmd.push_back ("-c");
661
662 /* NOTE: abrt does not currently work with asking for confirmation
663 * in version abrt-2.0.3-1.fc15.x86_64, Bugzilla: BZ726192 */
664 if(current_session_for_find_debuginfo->download_dbinfo == -1)
665 {
666 cmd.push_back ("echo " + hex + " | " + abrt_path + " --ids=-");
667 timeout = INT_MAX;
668 current_session_for_find_debuginfo->print_warning(_("Due to bug in abrt, it may continue downloading anyway without asking for confirmation."));
669 }
670 else
671 cmd.push_back ("echo " + hex + " | " + abrt_path + " -y --ids=-");
672
673 /* NOTE: abrt does not allow canceling the download process at the moment
674 * in version abrt-2.0.3-1.fc15.x86_64, Bugzilla: BZ730107 */
675 if(timeout != INT_MAX)
676 current_session_for_find_debuginfo->print_warning(_("Due to a bug in abrt, it may continue downloading after stopping stap if download times out."));
677
678 int pid;
679 if(current_session_for_find_debuginfo->verbose > 1 || current_session_for_find_debuginfo->download_dbinfo == -1)
680 /* Execute abrt-action-install-debuginfo-to-abrt-cache,
681 * showing output from abrt */
682 pid = stap_spawn(current_session_for_find_debuginfo->verbose, cmd, NULL);
683 else
684 {
685 /* Execute abrt-action-install-debuginfo-to-abrt-cache,
686 * without showing output from abrt */
687 posix_spawn_file_actions_t fa;
688 if (posix_spawn_file_actions_init(&fa) != 0)
689 return -1;
690 if(posix_spawn_file_actions_addopen(&fa, 1, "/dev/null", O_WRONLY, 0) != 0)
691 {
692 posix_spawn_file_actions_destroy(&fa);
693 return -1;
694 }
695 pid = stap_spawn(current_session_for_find_debuginfo->verbose, cmd, &fa);
696 posix_spawn_file_actions_destroy(&fa);
697 }
698
699 /* Check to see if either the program successfully completed, or if it timed out. */
700 int rstatus = 0;
701 int timer = 0;
702 int rc = 0;
703 while(timer < timeout)
704 {
705 sleep(1);
706 rc = waitpid(pid, &rstatus, WNOHANG);
707 if(rc < 0)
708 return -1;
709 if (rc > 0 && WIFEXITED(rstatus))
710 break;
711 assert_no_interrupts();
712 timer++;
713 }
714 if(timer == timeout)
715 {
716 /* Timed out! */
717 kill(-pid, SIGINT);
718 current_session_for_find_debuginfo->print_warning(_("Aborted downloading debuginfo: timed out."));
719 return -1;
720 }
721
722 /* Successfully finished downloading! */
723 #if 0 // Should not print this until BZ733690 is fixed as abrt could fail to download
724 // and it would still print success.
725 if(current_session_for_find_debuginfo->verbose > 1 || current_session_for_find_debuginfo->download_dbinfo == -1)
726 clog << _("Download Completed Successfully!") << endl;
727 #endif
728 if(current_session_for_find_debuginfo->verbose > 1 || current_session_for_find_debuginfo->download_dbinfo == -1)
729 clog << _("ABRT finished attempting to download debuginfo.") << endl;
730
731 return 0;
732 }
733
734 /* Get the kernel build ID */
735 string
736 get_kernel_build_id(systemtap_session &s)
737 {
738 bool found = false;
739 string hex;
740
741 // Try to find BuildID from vmlinux.id
742 string kernel_buildID_path = s.kernel_build_tree + "/vmlinux.id";
743 if(s.verbose > 2)
744 clog << _F("Attempting to extract kernel debuginfo build ID from %s", kernel_buildID_path.c_str()) << endl;
745 ifstream buildIDfile;
746 buildIDfile.open(kernel_buildID_path.c_str());
747 if(buildIDfile.is_open())
748 {
749 getline(buildIDfile, hex);
750 if(buildIDfile.good())
751 {
752 found = true;
753 }
754 buildIDfile.close();
755 }
756
757 // Try to find BuildID from the notes file if the above didn't work and we are
758 // building a native module
759 if(found == false && s.native_build)
760 {
761 if(s.verbose > 1)
762 clog << _("Attempting to extract kernel debuginfo build ID from /sys/kernel/notes") << endl;
763
764 const char *notesfile = "/sys/kernel/notes";
765 int fd = open64 (notesfile, O_RDONLY);
766 if (fd < 0)
767 return "";
768
769 assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
770 assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
771
772 union
773 {
774 GElf_Nhdr nhdr;
775 unsigned char data[8192];
776 } buf;
777
778 ssize_t n = read (fd, buf.data, sizeof buf);
779 close (fd);
780
781 if (n <= 0)
782 return "";
783
784 unsigned char *p = buf.data;
785 while (p < &buf.data[n])
786 {
787 /* No translation required since we are reading the native kernel. */
788 GElf_Nhdr *nhdr = (GElf_Nhdr *) p;
789 p += sizeof *nhdr;
790 unsigned char *name = p;
791 p += (nhdr->n_namesz + 3) & -4U;
792 unsigned char *bits = p;
793 p += (nhdr->n_descsz + 3) & -4U;
794
795 if (p <= &buf.data[n]
796 && nhdr->n_type == NT_GNU_BUILD_ID
797 && nhdr->n_namesz == sizeof "GNU"
798 && !memcmp (name, "GNU", sizeof "GNU"))
799 {
800 // Found it.
801 hex = hex_dump(bits, nhdr->n_descsz);
802 found = true;
803 }
804 }
805 }
806 if(found)
807 {
808 return hex;
809 }
810 else
811 return "";
812 }
813
814 /* Find the kernel build ID and attempt to download the matching debuginfo */
815 int download_kernel_debuginfo (systemtap_session &s, string hex)
816 {
817 // NOTE: At some point we want to base the
818 // already_tried_downloading_kernel_debuginfo flag on the build ID rather
819 // than just the stap process.
820
821 // Don't try this again if we already did.
822 static int already_tried_downloading_kernel_debuginfo = 0;
823 if(already_tried_downloading_kernel_debuginfo)
824 return -1;
825
826 // Attempt to download the debuginfo
827 if(s.verbose > 1)
828 clog << _F("Success! Extracted kernel debuginfo build ID: %s", hex.c_str()) << endl;
829 int rc = execute_abrt_action_install_debuginfo_to_abrt_cache(hex);
830 already_tried_downloading_kernel_debuginfo = 1;
831 if (rc < 0)
832 return -1;
833
834 // Success!
835 return 0;
836 }
This page took 0.074994 seconds and 5 git commands to generate.