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