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/>. */
19 #include "diagnostics.h"
21 #include "gdbsupport/scoped_fd.h"
22 #include "debuginfod-support.h"
24 #include "cli/cli-cmds.h"
25 #include "cli/cli-style.h"
29 /* Set/show debuginfod commands. */
30 static cmd_list_element
*set_debuginfod_prefix_list
;
31 static cmd_list_element
*show_debuginfod_prefix_list
;
33 /* maint set/show debuginfod commands. */
34 static cmd_list_element
*maint_set_debuginfod_cmdlist
;
35 static cmd_list_element
*maint_show_debuginfod_cmdlist
;
37 static const char debuginfod_on
[] = "on";
38 static const char debuginfod_off
[] = "off";
39 static const char debuginfod_ask
[] = "ask";
41 static const char *debuginfod_enabled_enum
[] =
49 static const char *debuginfod_enabled
=
50 #if defined(HAVE_LIBDEBUGINFOD)
56 /* Controls whether ELF/DWARF section downloading is enabled. */
57 static bool debuginfod_download_sections
=
58 #if defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
64 static unsigned int debuginfod_verbose
= 1;
66 #ifndef HAVE_LIBDEBUGINFOD
68 debuginfod_source_query (const unsigned char *build_id
,
71 gdb::unique_xmalloc_ptr
<char> *destname
)
73 return scoped_fd (-ENOSYS
);
77 debuginfod_debuginfo_query (const unsigned char *build_id
,
80 gdb::unique_xmalloc_ptr
<char> *destname
)
82 return scoped_fd (-ENOSYS
);
86 debuginfod_exec_query (const unsigned char *build_id
,
89 gdb::unique_xmalloc_ptr
<char> *destname
)
91 return scoped_fd (-ENOSYS
);
95 debuginfod_section_query (const unsigned char *build_id
,
98 const char *section_name
,
99 gdb::unique_xmalloc_ptr
<char> *destname
)
101 return scoped_fd (-ENOSYS
);
103 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
106 #include <elfutils/debuginfod.h>
110 user_data (const char *desc
, const char *fname
)
111 : desc (desc
), fname (fname
)
114 const char * const desc
;
115 const char * const fname
;
116 ui_out::progress_update progress
;
119 /* Convert SIZE into a unit suitable for use with progress updates.
120 SIZE should in given in bytes and will be converted into KB, MB, GB
121 or remain unchanged. UNIT will be set to "B", "KB", "MB" or "GB"
125 get_size_and_unit (double &size
)
128 /* If size is less than 1 KB then set unit to B. */
133 /* If size is less than 1 MB then set unit to KB. */
138 /* If size is less than 1 GB then set unit to MB. */
146 progressfn (debuginfod_client
*c
, long cur
, long total
)
148 user_data
*data
= static_cast<user_data
*> (debuginfod_get_user_data (c
));
149 gdb_assert (data
!= nullptr);
151 string_file
styled_fname (current_uiout
->can_emit_style_escape ());
152 fprintf_styled (&styled_fname
, file_name_style
.style (), "%s",
155 if (check_quit_flag ())
157 ui_file
*outstream
= get_unbuffered (gdb_stdout
);
158 gdb_printf (outstream
, _("Cancelling download of %s %s...\n"),
159 data
->desc
, styled_fname
.c_str ());
163 if (debuginfod_verbose
== 0)
166 /* Print progress update. Include the transfer size if available. */
169 /* Transfer size is known. */
170 double howmuch
= (double) cur
/ (double) total
;
172 if (howmuch
>= 0.0 && howmuch
<= 1.0)
174 double d_total
= (double) total
;
175 const char *unit
= get_size_and_unit (d_total
);
176 std::string msg
= string_printf ("Downloading %0.2f %s %s %s",
177 d_total
, unit
, data
->desc
,
178 styled_fname
.c_str ());
179 data
->progress
.update_progress (msg
, unit
, howmuch
, d_total
);
184 std::string msg
= string_printf ("Downloading %s %s",
185 data
->desc
, styled_fname
.c_str ());
186 data
->progress
.update_progress (msg
);
190 /* Return a pointer to the single global debuginfod_client, initialising it
193 static debuginfod_client
*
194 get_debuginfod_client ()
196 static debuginfod_client
*global_client
= nullptr;
198 if (global_client
== nullptr)
200 global_client
= debuginfod_begin ();
202 if (global_client
!= nullptr)
204 /* It is important that we cleanup the debuginfod_client object
205 before calling exit. Some of the libraries used by debuginfod
206 make use of at_exit handlers to perform cleanup.
208 If we wrapped the debuginfod_client in a unique_ptr and relied
209 on its destructor to cleanup then this would be run as part of
210 the global C++ object destructors, which is after the at_exit
211 handlers, which is too late.
213 So instead, we make use of GDB's final cleanup mechanism. */
214 add_final_cleanup ([] ()
216 debuginfod_end (global_client
);
218 debuginfod_set_progressfn (global_client
, progressfn
);
222 return global_client
;
225 /* Check if debuginfod is enabled. If configured to do so, ask the user
226 whether to enable debuginfod. */
229 debuginfod_is_enabled ()
231 const char *urls
= skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR
));
233 if (debuginfod_enabled
== debuginfod_off
238 if (debuginfod_enabled
== debuginfod_ask
)
240 gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
241 "from the following URLs:\n"));
243 std::string_view
url_view (urls
);
246 size_t off
= url_view
.find_first_not_of (' ');
247 if (off
== std::string_view::npos
)
249 url_view
= url_view
.substr (off
);
250 /* g++ 11.2.1 on s390x, g++ 11.3.1 on ppc64le and g++ 11 on
251 hppa seem convinced url_view might be of SIZE_MAX length.
252 And so complains because the length of an array can only
255 DIAGNOSTIC_IGNORE_STRINGOP_OVERREAD
256 off
= url_view
.find_first_of (' ');
260 styled_string (file_name_style
.style (),
261 std::string (url_view
.substr (0, off
)).c_str ()));
262 if (off
== std::string_view::npos
)
264 url_view
= url_view
.substr (off
);
267 int resp
= nquery (_("Enable debuginfod for this session? "));
270 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
271 "setting permanent, add \'set debuginfod " \
272 "enabled off\' to .gdbinit.\n"));
273 debuginfod_enabled
= debuginfod_off
;
277 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
278 "setting permanent, add \'set debuginfod enabled " \
279 "on\' to .gdbinit.\n"));
280 debuginfod_enabled
= debuginfod_on
;
286 /* Print the result of the most recent attempted download. */
289 print_outcome (int fd
, const char *desc
, const char *fname
)
291 if (fd
< 0 && fd
!= -ENOENT
)
293 ui_file
*outstream
= get_unbuffered (gdb_stdout
);
294 gdb_printf (outstream
,
295 _("Download failed: %s. Continuing without %s %ps.\n"),
298 styled_string (file_name_style
.style (), fname
));
302 /* See debuginfod-support.h */
305 debuginfod_source_query (const unsigned char *build_id
,
308 gdb::unique_xmalloc_ptr
<char> *destname
)
310 if (!debuginfod_is_enabled ())
311 return scoped_fd (-ENOSYS
);
313 debuginfod_client
*c
= get_debuginfod_client ();
316 return scoped_fd (-ENOMEM
);
318 char *dname
= nullptr;
320 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
323 user_data
data ("source file", srcpath
);
325 debuginfod_set_user_data (c
, &data
);
326 if (target_supports_terminal_ours ())
328 term_state
.emplace ();
329 target_terminal::ours ();
332 fd
= scoped_fd (debuginfod_find_source (c
,
337 debuginfod_set_user_data (c
, nullptr);
340 print_outcome (fd
.get (), "source file", srcpath
);
343 destname
->reset (dname
);
348 /* See debuginfod-support.h */
351 debuginfod_debuginfo_query (const unsigned char *build_id
,
353 const char *filename
,
354 gdb::unique_xmalloc_ptr
<char> *destname
)
356 if (!debuginfod_is_enabled ())
357 return scoped_fd (-ENOSYS
);
359 debuginfod_client
*c
= get_debuginfod_client ();
362 return scoped_fd (-ENOMEM
);
364 char *dname
= nullptr;
366 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
369 user_data
data ("separate debug info for", filename
);
371 debuginfod_set_user_data (c
, &data
);
372 if (target_supports_terminal_ours ())
374 term_state
.emplace ();
375 target_terminal::ours ();
378 fd
= scoped_fd (debuginfod_find_debuginfo (c
, build_id
, build_id_len
,
380 debuginfod_set_user_data (c
, nullptr);
383 print_outcome (fd
.get (), "separate debug info for", filename
);
386 destname
->reset (dname
);
391 /* See debuginfod-support.h */
394 debuginfod_exec_query (const unsigned char *build_id
,
396 const char *filename
,
397 gdb::unique_xmalloc_ptr
<char> *destname
)
399 if (!debuginfod_is_enabled ())
400 return scoped_fd (-ENOSYS
);
402 debuginfod_client
*c
= get_debuginfod_client ();
405 return scoped_fd (-ENOMEM
);
407 char *dname
= nullptr;
409 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
412 user_data
data ("file", filename
);
414 debuginfod_set_user_data (c
, &data
);
415 if (target_supports_terminal_ours ())
417 term_state
.emplace ();
418 target_terminal::ours ();
421 fd
= scoped_fd (debuginfod_find_executable (c
, build_id
, build_id_len
,
423 debuginfod_set_user_data (c
, nullptr);
426 print_outcome (fd
.get (), "file", filename
);
429 destname
->reset (dname
);
434 /* See debuginfod-support.h */
437 debuginfod_section_query (const unsigned char *build_id
,
439 const char *filename
,
440 const char *section_name
,
441 gdb::unique_xmalloc_ptr
<char> *destname
)
443 #if !defined (HAVE_LIBDEBUGINFOD_FIND_SECTION)
444 return scoped_fd (-ENOSYS
);
447 if (!debuginfod_download_sections
|| !debuginfod_is_enabled ())
448 return scoped_fd (-ENOSYS
);
450 debuginfod_client
*c
= get_debuginfod_client ();
453 return scoped_fd (-ENOMEM
);
455 char *dname
= nullptr;
456 std::string desc
= std::string ("section ") + section_name
+ " for";
458 std::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
461 user_data
data (desc
.c_str (), filename
);
462 debuginfod_set_user_data (c
, &data
);
463 if (target_supports_terminal_ours ())
465 term_state
.emplace ();
466 target_terminal::ours ();
469 fd
= scoped_fd (debuginfod_find_section (c
, build_id
, build_id_len
,
470 section_name
, &dname
));
471 debuginfod_set_user_data (c
, nullptr);
474 print_outcome (fd
.get (), desc
.c_str (), filename
);
475 gdb_assert (destname
!= nullptr);
478 destname
->reset (dname
);
481 #endif /* HAVE_LIBDEBUGINFOD_FIND_SECTION */
486 /* Set callback for "set debuginfod enabled". */
489 set_debuginfod_enabled (const char *value
)
491 #if defined(HAVE_LIBDEBUGINFOD)
492 debuginfod_enabled
= value
;
494 /* Disabling debuginfod when gdb is not built with it is a no-op. */
495 if (value
!= debuginfod_off
)
500 /* Get callback for "set debuginfod enabled". */
503 get_debuginfod_enabled ()
505 return debuginfod_enabled
;
508 /* Show callback for "set debuginfod enabled". */
511 show_debuginfod_enabled (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
515 _("Debuginfod functionality is currently set to "
516 "\"%s\".\n"), debuginfod_enabled
);
519 /* Set callback for "set debuginfod urls". */
522 set_debuginfod_urls (const std::string
&urls
)
524 #if defined(HAVE_LIBDEBUGINFOD)
525 if (setenv (DEBUGINFOD_URLS_ENV_VAR
, urls
.c_str (), 1) != 0)
526 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno
));
532 /* Get callback for "set debuginfod urls". */
534 static const std::string
&
535 get_debuginfod_urls ()
537 static std::string urls
;
538 #if defined(HAVE_LIBDEBUGINFOD)
539 const char *envvar
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
541 if (envvar
!= nullptr)
550 /* Show callback for "set debuginfod urls". */
553 show_debuginfod_urls (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
556 if (value
[0] == '\0')
557 gdb_printf (file
, _("Debuginfod URLs have not been set.\n"));
559 gdb_printf (file
, _("Debuginfod URLs are currently set to:\n%s\n"),
563 /* Show callback for "set debuginfod verbose". */
566 show_debuginfod_verbose_command (ui_file
*file
, int from_tty
,
567 cmd_list_element
*cmd
, const char *value
)
569 gdb_printf (file
, _("Debuginfod verbose output is set to %s.\n"),
573 /* Set callback for "maint set debuginfod download-sections". */
576 maint_set_debuginfod_download_sections (bool value
)
578 #if !defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
580 error (_("Support for section downloading is not compiled into GDB. " \
581 "Defaulting to \"off\"."));
584 debuginfod_download_sections
= value
;
587 /* Get callback for "maint set debuginfod download-sections". */
590 maint_get_debuginfod_download_sections ()
592 return debuginfod_download_sections
;
595 /* Register debuginfod commands. */
597 void _initialize_debuginfod ();
599 _initialize_debuginfod ()
601 /* set/show debuginfod */
602 add_setshow_prefix_cmd ("debuginfod", class_run
,
603 _("Set debuginfod options."),
604 _("Show debuginfod options."),
605 &set_debuginfod_prefix_list
,
606 &show_debuginfod_prefix_list
,
607 &setlist
, &showlist
);
609 add_setshow_enum_cmd ("enabled", class_run
, debuginfod_enabled_enum
,
610 _("Set whether to use debuginfod."),
611 _("Show whether to use debuginfod."),
613 When set to \"on\", enable the use of debuginfod to download missing\n\
614 debug info and source files. GDB may also download components of debug\n\
615 info instead of entire files. \"off\" disables the use of debuginfod.\n\
616 When set to \"ask\", prompt whether to enable or disable debuginfod." ),
617 set_debuginfod_enabled
,
618 get_debuginfod_enabled
,
619 show_debuginfod_enabled
,
620 &set_debuginfod_prefix_list
,
621 &show_debuginfod_prefix_list
);
623 /* set/show debuginfod urls */
624 add_setshow_string_noescape_cmd ("urls", class_run
, _("\
625 Set the list of debuginfod server URLs."), _("\
626 Show the list of debuginfod server URLs."), _("\
627 Manage the space-separated list of debuginfod server URLs that GDB will\n\
628 query when missing debuginfo, executables or source files.\n\
629 The default value is copied from the DEBUGINFOD_URLS environment variable."),
632 show_debuginfod_urls
,
633 &set_debuginfod_prefix_list
,
634 &show_debuginfod_prefix_list
);
636 /* set/show debuginfod verbose */
637 add_setshow_zuinteger_cmd ("verbose", class_support
,
638 &debuginfod_verbose
, _("\
639 Set verbosity of debuginfod output."), _("\
640 Show debuginfod debugging."), _("\
641 When set to a non-zero value, display verbose output for each debuginfod \
642 query.\nTo disable, set to zero. Verbose output is displayed by default."),
644 show_debuginfod_verbose_command
,
645 &set_debuginfod_prefix_list
,
646 &show_debuginfod_prefix_list
);
648 /* maint set/show debuginfod. */
649 add_setshow_prefix_cmd ("debuginfod", class_maintenance
,
650 _("Set debuginfod specific variables."),
651 _("Show debuginfod specific variables."),
652 &maint_set_debuginfod_cmdlist
,
653 &maint_show_debuginfod_cmdlist
,
654 &maintenance_set_cmdlist
, &maintenance_show_cmdlist
);
656 /* maint set/show debuginfod download-sections. */
657 add_setshow_boolean_cmd ("download-sections", class_maintenance
, _("\
658 Set whether debuginfod may download individual ELF/DWARF sections."), _("\
659 Show whether debuginfod may download individual ELF/DWARF sections."), _("\
660 When enabled, debuginfod may attempt to download individual ELF/DWARF\n\
661 sections from debug info files.\n\
662 If disabled, only whole debug info files may be downloaded."),
663 maint_set_debuginfod_download_sections
,
664 maint_get_debuginfod_download_sections
,
666 &maint_set_debuginfod_cmdlist
,
667 &maint_show_debuginfod_cmdlist
);