1 /* debuginfod utilities for GDB.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "diagnostics.h"
22 #include "gdbsupport/scoped_fd.h"
23 #include "debuginfod-support.h"
25 #include "cli/cli-cmds.h"
26 #include "cli/cli-style.h"
30 /* Set/show debuginfod commands. */
31 static cmd_list_element
*set_debuginfod_prefix_list
;
32 static cmd_list_element
*show_debuginfod_prefix_list
;
34 /* maint set/show debuginfod commands. */
35 static cmd_list_element
*maint_set_debuginfod_cmdlist
;
36 static cmd_list_element
*maint_show_debuginfod_cmdlist
;
38 static const char debuginfod_on
[] = "on";
39 static const char debuginfod_off
[] = "off";
40 static const char debuginfod_ask
[] = "ask";
42 static const char *debuginfod_enabled_enum
[] =
50 static const char *debuginfod_enabled
=
51 #if defined(HAVE_LIBDEBUGINFOD)
57 /* Controls whether ELF/DWARF section downloading is enabled. */
58 static bool debuginfod_download_sections
=
59 #if defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
65 static unsigned int debuginfod_verbose
= 1;
67 #ifndef HAVE_LIBDEBUGINFOD
69 debuginfod_source_query (const unsigned char *build_id
,
72 gdb::unique_xmalloc_ptr
<char> *destname
)
74 return scoped_fd (-ENOSYS
);
78 debuginfod_debuginfo_query (const unsigned char *build_id
,
81 gdb::unique_xmalloc_ptr
<char> *destname
)
83 return scoped_fd (-ENOSYS
);
87 debuginfod_exec_query (const unsigned char *build_id
,
90 gdb::unique_xmalloc_ptr
<char> *destname
)
92 return scoped_fd (-ENOSYS
);
96 debuginfod_section_query (const unsigned char *build_id
,
99 const char *section_name
,
100 gdb::unique_xmalloc_ptr
<char> *destname
)
102 return scoped_fd (-ENOSYS
);
104 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
107 #include <elfutils/debuginfod.h>
111 user_data (const char *desc
, const char *fname
)
112 : desc (desc
), fname (fname
)
115 const char * const desc
;
116 const char * const fname
;
117 ui_out::progress_update progress
;
120 /* Convert SIZE into a unit suitable for use with progress updates.
121 SIZE should in given in bytes and will be converted into KB, MB, GB
122 or remain unchanged. UNIT will be set to "B", "KB", "MB" or "GB"
126 get_size_and_unit (double &size
)
129 /* If size is less than 1 KB then set unit to B. */
134 /* If size is less than 1 MB then set unit to KB. */
139 /* If size is less than 1 GB then set unit to MB. */
147 progressfn (debuginfod_client
*c
, long cur
, long total
)
149 user_data
*data
= static_cast<user_data
*> (debuginfod_get_user_data (c
));
150 gdb_assert (data
!= nullptr);
152 string_file
styled_fname (current_uiout
->can_emit_style_escape ());
153 fprintf_styled (&styled_fname
, file_name_style
.style (), "%s",
156 if (check_quit_flag ())
158 ui_file
*outstream
= get_unbuffered (gdb_stdout
);
159 gdb_printf (outstream
, _("Cancelling download of %s %s...\n"),
160 data
->desc
, styled_fname
.c_str ());
164 if (debuginfod_verbose
== 0)
167 /* Print progress update. Include the transfer size if available. */
170 /* Transfer size is known. */
171 double howmuch
= (double) cur
/ (double) total
;
173 if (howmuch
>= 0.0 && howmuch
<= 1.0)
175 double d_total
= (double) total
;
176 const char *unit
= get_size_and_unit (d_total
);
177 std::string msg
= string_printf ("Downloading %0.2f %s %s %s",
178 d_total
, unit
, data
->desc
,
179 styled_fname
.c_str ());
180 data
->progress
.update_progress (msg
, unit
, howmuch
, d_total
);
185 std::string msg
= string_printf ("Downloading %s %s",
186 data
->desc
, styled_fname
.c_str ());
187 data
->progress
.update_progress (msg
);
191 /* Cleanup ARG, which is a debuginfod_client pointer. */
194 cleanup_debuginfod_client (void *arg
)
196 debuginfod_client
*client
= static_cast<debuginfod_client
*> (arg
);
197 debuginfod_end (client
);
200 /* Return a pointer to the single global debuginfod_client, initialising it
203 static debuginfod_client
*
204 get_debuginfod_client ()
206 static debuginfod_client
*global_client
= nullptr;
208 if (global_client
== nullptr)
210 global_client
= debuginfod_begin ();
212 if (global_client
!= nullptr)
214 /* It is important that we cleanup the debuginfod_client object
215 before calling exit. Some of the libraries used by debuginfod
216 make use of at_exit handlers to perform cleanup.
218 If we wrapped the debuginfod_client in a unique_ptr and relied
219 on its destructor to cleanup then this would be run as part of
220 the global C++ object destructors, which is after the at_exit
221 handlers, which is too late.
223 So instead, we make use of GDB's final cleanup mechanism. */
224 make_final_cleanup (cleanup_debuginfod_client
, global_client
);
225 debuginfod_set_progressfn (global_client
, progressfn
);
229 return global_client
;
232 /* Check if debuginfod is enabled. If configured to do so, ask the user
233 whether to enable debuginfod. */
236 debuginfod_is_enabled ()
238 const char *urls
= skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR
));
240 if (debuginfod_enabled
== debuginfod_off
245 if (debuginfod_enabled
== debuginfod_ask
)
247 gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
248 "from the following URLs:\n"));
250 std::string_view
url_view (urls
);
253 size_t off
= url_view
.find_first_not_of (' ');
254 if (off
== std::string_view::npos
)
256 url_view
= url_view
.substr (off
);
257 /* g++ 11.2.1 on s390x, g++ 11.3.1 on ppc64le and g++ 11 on
258 hppa seem convinced url_view might be of SIZE_MAX length.
259 And so complains because the length of an array can only
262 DIAGNOSTIC_IGNORE_STRINGOP_OVERREAD
263 off
= url_view
.find_first_of (' ');
267 styled_string (file_name_style
.style (),
268 std::string (url_view
.substr (0, off
)).c_str ()));
269 if (off
== std::string_view::npos
)
271 url_view
= url_view
.substr (off
);
274 int resp
= nquery (_("Enable debuginfod for this session? "));
277 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
278 "setting permanent, add \'set debuginfod " \
279 "enabled off\' to .gdbinit.\n"));
280 debuginfod_enabled
= debuginfod_off
;
284 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
285 "setting permanent, add \'set debuginfod enabled " \
286 "on\' to .gdbinit.\n"));
287 debuginfod_enabled
= debuginfod_on
;
293 /* Print the result of the most recent attempted download. */
296 print_outcome (int fd
, const char *desc
, const char *fname
)
298 if (fd
< 0 && fd
!= -ENOENT
)
300 ui_file
*outstream
= get_unbuffered (gdb_stdout
);
301 gdb_printf (outstream
,
302 _("Download failed: %s. Continuing without %s %ps.\n"),
305 styled_string (file_name_style
.style (), fname
));
309 /* See debuginfod-support.h */
312 debuginfod_source_query (const unsigned char *build_id
,
315 gdb::unique_xmalloc_ptr
<char> *destname
)
317 if (!debuginfod_is_enabled ())
318 return scoped_fd (-ENOSYS
);
320 debuginfod_client
*c
= get_debuginfod_client ();
323 return scoped_fd (-ENOMEM
);
325 char *dname
= nullptr;
327 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
330 user_data
data ("source file", srcpath
);
332 debuginfod_set_user_data (c
, &data
);
333 if (target_supports_terminal_ours ())
335 term_state
.emplace ();
336 target_terminal::ours ();
339 fd
= scoped_fd (debuginfod_find_source (c
,
344 debuginfod_set_user_data (c
, nullptr);
347 print_outcome (fd
.get (), "source file", srcpath
);
350 destname
->reset (dname
);
355 /* See debuginfod-support.h */
358 debuginfod_debuginfo_query (const unsigned char *build_id
,
360 const char *filename
,
361 gdb::unique_xmalloc_ptr
<char> *destname
)
363 if (!debuginfod_is_enabled ())
364 return scoped_fd (-ENOSYS
);
366 debuginfod_client
*c
= get_debuginfod_client ();
369 return scoped_fd (-ENOMEM
);
371 char *dname
= nullptr;
373 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
376 user_data
data ("separate debug info for", filename
);
378 debuginfod_set_user_data (c
, &data
);
379 if (target_supports_terminal_ours ())
381 term_state
.emplace ();
382 target_terminal::ours ();
385 fd
= scoped_fd (debuginfod_find_debuginfo (c
, build_id
, build_id_len
,
387 debuginfod_set_user_data (c
, nullptr);
390 print_outcome (fd
.get (), "separate debug info for", filename
);
393 destname
->reset (dname
);
398 /* See debuginfod-support.h */
401 debuginfod_exec_query (const unsigned char *build_id
,
403 const char *filename
,
404 gdb::unique_xmalloc_ptr
<char> *destname
)
406 if (!debuginfod_is_enabled ())
407 return scoped_fd (-ENOSYS
);
409 debuginfod_client
*c
= get_debuginfod_client ();
412 return scoped_fd (-ENOMEM
);
414 char *dname
= nullptr;
416 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
419 user_data
data ("executable for", filename
);
421 debuginfod_set_user_data (c
, &data
);
422 if (target_supports_terminal_ours ())
424 term_state
.emplace ();
425 target_terminal::ours ();
428 fd
= scoped_fd (debuginfod_find_executable (c
, build_id
, build_id_len
,
430 debuginfod_set_user_data (c
, nullptr);
433 print_outcome (fd
.get (), "executable for", filename
);
436 destname
->reset (dname
);
441 /* See debuginfod-support.h */
444 debuginfod_section_query (const unsigned char *build_id
,
446 const char *filename
,
447 const char *section_name
,
448 gdb::unique_xmalloc_ptr
<char> *destname
)
450 #if !defined (HAVE_LIBDEBUGINFOD_FIND_SECTION)
451 return scoped_fd (-ENOSYS
);
454 if (!debuginfod_download_sections
|| !debuginfod_is_enabled ())
455 return scoped_fd (-ENOSYS
);
457 debuginfod_client
*c
= get_debuginfod_client ();
460 return scoped_fd (-ENOMEM
);
462 char *dname
= nullptr;
463 std::string desc
= std::string ("section ") + section_name
+ " for";
465 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
468 user_data
data (desc
.c_str (), filename
);
469 debuginfod_set_user_data (c
, &data
);
470 if (target_supports_terminal_ours ())
472 term_state
.emplace ();
473 target_terminal::ours ();
476 fd
= scoped_fd (debuginfod_find_section (c
, build_id
, build_id_len
,
477 section_name
, &dname
));
478 debuginfod_set_user_data (c
, nullptr);
481 print_outcome (fd
.get (), desc
.c_str (), filename
);
482 gdb_assert (destname
!= nullptr);
485 destname
->reset (dname
);
488 #endif /* HAVE_LIBDEBUGINFOD_FIND_SECTION */
493 /* Set callback for "set debuginfod enabled". */
496 set_debuginfod_enabled (const char *value
)
498 #if defined(HAVE_LIBDEBUGINFOD)
499 debuginfod_enabled
= value
;
501 /* Disabling debuginfod when gdb is not built with it is a no-op. */
502 if (value
!= debuginfod_off
)
507 /* Get callback for "set debuginfod enabled". */
510 get_debuginfod_enabled ()
512 return debuginfod_enabled
;
515 /* Show callback for "set debuginfod enabled". */
518 show_debuginfod_enabled (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
522 _("Debuginfod functionality is currently set to "
523 "\"%s\".\n"), debuginfod_enabled
);
526 /* Set callback for "set debuginfod urls". */
529 set_debuginfod_urls (const std::string
&urls
)
531 #if defined(HAVE_LIBDEBUGINFOD)
532 if (setenv (DEBUGINFOD_URLS_ENV_VAR
, urls
.c_str (), 1) != 0)
533 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno
));
539 /* Get callback for "set debuginfod urls". */
541 static const std::string
&
542 get_debuginfod_urls ()
544 static std::string urls
;
545 #if defined(HAVE_LIBDEBUGINFOD)
546 const char *envvar
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
548 if (envvar
!= nullptr)
557 /* Show callback for "set debuginfod urls". */
560 show_debuginfod_urls (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
563 if (value
[0] == '\0')
564 gdb_printf (file
, _("Debuginfod URLs have not been set.\n"));
566 gdb_printf (file
, _("Debuginfod URLs are currently set to:\n%s\n"),
570 /* Show callback for "set debuginfod verbose". */
573 show_debuginfod_verbose_command (ui_file
*file
, int from_tty
,
574 cmd_list_element
*cmd
, const char *value
)
576 gdb_printf (file
, _("Debuginfod verbose output is set to %s.\n"),
580 /* Set callback for "maint set debuginfod download-sections". */
583 maint_set_debuginfod_download_sections (bool value
)
585 #if !defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
587 error (_("Support for section downloading is not compiled into GDB. " \
588 "Defaulting to \"off\"."));
591 debuginfod_download_sections
= value
;
594 /* Get callback for "maint set debuginfod download-sections". */
597 maint_get_debuginfod_download_sections ()
599 return debuginfod_download_sections
;
602 /* Register debuginfod commands. */
604 void _initialize_debuginfod ();
606 _initialize_debuginfod ()
608 /* set/show debuginfod */
609 add_setshow_prefix_cmd ("debuginfod", class_run
,
610 _("Set debuginfod options."),
611 _("Show debuginfod options."),
612 &set_debuginfod_prefix_list
,
613 &show_debuginfod_prefix_list
,
614 &setlist
, &showlist
);
616 add_setshow_enum_cmd ("enabled", class_run
, debuginfod_enabled_enum
,
617 _("Set whether to use debuginfod."),
618 _("Show whether to use debuginfod."),
620 When set to \"on\", enable the use of debuginfod to download missing\n\
621 debug info and source files. GDB may also download components of debug\n\
622 info instead of entire files. \"off\" disables the use of debuginfod.\n\
623 When set to \"ask\", prompt whether to enable or disable debuginfod." ),
624 set_debuginfod_enabled
,
625 get_debuginfod_enabled
,
626 show_debuginfod_enabled
,
627 &set_debuginfod_prefix_list
,
628 &show_debuginfod_prefix_list
);
630 /* set/show debuginfod urls */
631 add_setshow_string_noescape_cmd ("urls", class_run
, _("\
632 Set the list of debuginfod server URLs."), _("\
633 Show the list of debuginfod server URLs."), _("\
634 Manage the space-separated list of debuginfod server URLs that GDB will query \
635 when missing debuginfo, executables or source files.\nThe default value is \
636 copied from the DEBUGINFOD_URLS environment variable."),
639 show_debuginfod_urls
,
640 &set_debuginfod_prefix_list
,
641 &show_debuginfod_prefix_list
);
643 /* set/show debuginfod verbose */
644 add_setshow_zuinteger_cmd ("verbose", class_support
,
645 &debuginfod_verbose
, _("\
646 Set verbosity of debuginfod output."), _("\
647 Show debuginfod debugging."), _("\
648 When set to a non-zero value, display verbose output for each debuginfod \
649 query.\nTo disable, set to zero. Verbose output is displayed by default."),
651 show_debuginfod_verbose_command
,
652 &set_debuginfod_prefix_list
,
653 &show_debuginfod_prefix_list
);
655 /* maint set/show debuginfod. */
656 add_setshow_prefix_cmd ("debuginfod", class_maintenance
,
657 _("Set debuginfod specific variables."),
658 _("Show debuginfod specific variables."),
659 &maint_set_debuginfod_cmdlist
,
660 &maint_show_debuginfod_cmdlist
,
661 &maintenance_set_cmdlist
, &maintenance_show_cmdlist
);
663 /* maint set/show debuginfod download-sections. */
664 add_setshow_boolean_cmd ("download-sections", class_maintenance
, _("\
665 Set whether debuginfod may download individual ELF/DWARF sections."), _("\
666 Show whether debuginfod may download individual ELF/DWARF sections."), _("\
667 When enabled, debuginfod may attempt to download individual ELF/DWARF \
668 sections from debug info files.\nIf disabled, only whole debug info files \
669 may be downloaded."),
670 maint_set_debuginfod_download_sections
,
671 maint_get_debuginfod_download_sections
,
673 &maint_set_debuginfod_cmdlist
,
674 &maint_show_debuginfod_cmdlist
);