1 /* debuginfod utilities for GDB.
2 Copyright (C) 2020-2022 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"
24 #include "gdbsupport/gdb_optional.h"
25 #include "cli/cli-cmds.h"
26 #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 static const char debuginfod_on
[] = "on";
34 static const char debuginfod_off
[] = "off";
35 static const char debuginfod_ask
[] = "ask";
37 static const char *debuginfod_enabled_enum
[] =
45 static const char *debuginfod_enabled
=
46 #if defined(HAVE_LIBDEBUGINFOD)
52 static unsigned int debuginfod_verbose
= 1;
54 #ifndef HAVE_LIBDEBUGINFOD
56 debuginfod_source_query (const unsigned char *build_id
,
59 gdb::unique_xmalloc_ptr
<char> *destname
)
61 return scoped_fd (-ENOSYS
);
65 debuginfod_debuginfo_query (const unsigned char *build_id
,
68 gdb::unique_xmalloc_ptr
<char> *destname
)
70 return scoped_fd (-ENOSYS
);
74 debuginfod_exec_query (const unsigned char *build_id
,
77 gdb::unique_xmalloc_ptr
<char> *destname
)
79 return scoped_fd (-ENOSYS
);
82 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
85 #include <elfutils/debuginfod.h>
89 user_data (const char *desc
, const char *fname
)
90 : desc (desc
), fname (fname
), has_printed (false)
93 const char * const desc
;
94 const char * const fname
;
98 /* Deleter for a debuginfod_client. */
100 struct debuginfod_client_deleter
102 void operator() (debuginfod_client
*c
)
108 using debuginfod_client_up
109 = std::unique_ptr
<debuginfod_client
, debuginfod_client_deleter
>;
112 progressfn (debuginfod_client
*c
, long cur
, long total
)
114 user_data
*data
= static_cast<user_data
*> (debuginfod_get_user_data (c
));
115 gdb_assert (data
!= nullptr);
117 if (check_quit_flag ())
119 gdb_printf ("Cancelling download of %s %ps...\n",
121 styled_string (file_name_style
.style (), data
->fname
));
125 if (!data
->has_printed
)
127 /* Include the transfer size, if available. */
130 float size
= 1.0f
* total
/ 1024;
131 const char *unit
= "KB";
133 /* If size is greater than 0.01 MB, set unit to MB. */
140 gdb_printf ("Downloading %.2f %s %s %ps...\n",
141 size
, unit
, data
->desc
,
142 styled_string (file_name_style
.style (),
146 gdb_printf ("Downloading %s %ps...\n", data
->desc
,
147 styled_string (file_name_style
.style (), data
->fname
));
149 data
->has_printed
= true;
155 static debuginfod_client
*
156 get_debuginfod_client ()
158 static debuginfod_client_up global_client
;
160 if (global_client
== nullptr)
162 global_client
.reset (debuginfod_begin ());
164 if (global_client
!= nullptr)
165 debuginfod_set_progressfn (global_client
.get (), progressfn
);
168 return global_client
.get ();
171 /* Check if debuginfod is enabled. If configured to do so, ask the user
172 whether to enable debuginfod. */
175 debuginfod_is_enabled ()
177 const char *urls
= skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR
));
179 if (debuginfod_enabled
== debuginfod_off
184 if (debuginfod_enabled
== debuginfod_ask
)
186 gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
187 "from the following URLs:\n"));
189 gdb::string_view
url_view (urls
);
192 size_t off
= url_view
.find_first_not_of (' ');
193 if (off
== gdb::string_view::npos
)
195 url_view
= url_view
.substr (off
);
196 /* g++ 11.2.1 on s390x, g++ 11.3.1 on ppc64le and g++ 11 on
197 hppa seem convinced url_view might be of SIZE_MAX length.
198 And so complains because the length of an array can only
201 DIAGNOSTIC_IGNORE_STRINGOP_OVERREAD
202 off
= url_view
.find_first_of (' ');
206 styled_string (file_name_style
.style (),
207 gdb::to_string (url_view
.substr (0,
209 if (off
== gdb::string_view::npos
)
211 url_view
= url_view
.substr (off
);
214 int resp
= nquery (_("Enable debuginfod for this session? "));
217 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
218 "setting permanent, add \'set debuginfod " \
219 "enabled off\' to .gdbinit.\n"));
220 debuginfod_enabled
= debuginfod_off
;
224 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
225 "setting permanent, add \'set debuginfod enabled " \
226 "on\' to .gdbinit.\n"));
227 debuginfod_enabled
= debuginfod_on
;
233 /* See debuginfod-support.h */
236 debuginfod_source_query (const unsigned char *build_id
,
239 gdb::unique_xmalloc_ptr
<char> *destname
)
241 if (!debuginfod_is_enabled ())
242 return scoped_fd (-ENOSYS
);
244 debuginfod_client
*c
= get_debuginfod_client ();
247 return scoped_fd (-ENOMEM
);
249 char *dname
= nullptr;
250 user_data
data ("source file", srcpath
);
252 debuginfod_set_user_data (c
, &data
);
253 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
254 if (target_supports_terminal_ours ())
256 term_state
.emplace ();
257 target_terminal::ours ();
260 scoped_fd
fd (debuginfod_find_source (c
,
265 debuginfod_set_user_data (c
, nullptr);
267 if (fd
.get () < 0 && fd
.get () != -ENOENT
)
268 gdb_printf (_("Download failed: %s. Continuing without source file %ps.\n"),
269 safe_strerror (-fd
.get ()),
270 styled_string (file_name_style
.style (), srcpath
));
273 destname
->reset (dname
);
278 /* See debuginfod-support.h */
281 debuginfod_debuginfo_query (const unsigned char *build_id
,
283 const char *filename
,
284 gdb::unique_xmalloc_ptr
<char> *destname
)
286 if (!debuginfod_is_enabled ())
287 return scoped_fd (-ENOSYS
);
289 debuginfod_client
*c
= get_debuginfod_client ();
292 return scoped_fd (-ENOMEM
);
294 char *dname
= nullptr;
295 user_data
data ("separate debug info for", filename
);
297 debuginfod_set_user_data (c
, &data
);
298 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
299 if (target_supports_terminal_ours ())
301 term_state
.emplace ();
302 target_terminal::ours ();
305 scoped_fd
fd (debuginfod_find_debuginfo (c
, build_id
, build_id_len
,
307 debuginfod_set_user_data (c
, nullptr);
309 if (fd
.get () < 0 && fd
.get () != -ENOENT
)
310 gdb_printf (_("Download failed: %s. Continuing without debug info for %ps.\n"),
311 safe_strerror (-fd
.get ()),
312 styled_string (file_name_style
.style (), filename
));
315 destname
->reset (dname
);
320 /* See debuginfod-support.h */
323 debuginfod_exec_query (const unsigned char *build_id
,
325 const char *filename
,
326 gdb::unique_xmalloc_ptr
<char> *destname
)
328 if (!debuginfod_is_enabled ())
329 return scoped_fd (-ENOSYS
);
331 debuginfod_client
*c
= get_debuginfod_client ();
334 return scoped_fd (-ENOMEM
);
336 char *dname
= nullptr;
337 user_data
data ("executable for", filename
);
339 debuginfod_set_user_data (c
, &data
);
340 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
341 if (target_supports_terminal_ours ())
343 term_state
.emplace ();
344 target_terminal::ours ();
347 scoped_fd
fd (debuginfod_find_executable (c
, build_id
, build_id_len
, &dname
));
348 debuginfod_set_user_data (c
, nullptr);
350 if (fd
.get () < 0 && fd
.get () != -ENOENT
)
351 gdb_printf (_("Download failed: %s. " \
352 "Continuing without executable for %ps.\n"),
353 safe_strerror (-fd
.get ()),
354 styled_string (file_name_style
.style (), filename
));
357 destname
->reset (dname
);
363 /* Set callback for "set debuginfod enabled". */
366 set_debuginfod_enabled (const char *value
)
368 #if defined(HAVE_LIBDEBUGINFOD)
369 debuginfod_enabled
= value
;
375 /* Get callback for "set debuginfod enabled". */
378 get_debuginfod_enabled ()
380 return debuginfod_enabled
;
383 /* Show callback for "set debuginfod enabled". */
386 show_debuginfod_enabled (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
390 _("Debuginfod functionality is currently set to "
391 "\"%s\".\n"), debuginfod_enabled
);
394 /* Set callback for "set debuginfod urls". */
397 set_debuginfod_urls (const std::string
&urls
)
399 #if defined(HAVE_LIBDEBUGINFOD)
400 if (setenv (DEBUGINFOD_URLS_ENV_VAR
, urls
.c_str (), 1) != 0)
401 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno
));
407 /* Get callback for "set debuginfod urls". */
409 static const std::string
&
410 get_debuginfod_urls ()
412 static std::string urls
;
413 #if defined(HAVE_LIBDEBUGINFOD)
414 const char *envvar
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
416 if (envvar
!= nullptr)
425 /* Show callback for "set debuginfod urls". */
428 show_debuginfod_urls (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
431 if (value
[0] == '\0')
432 gdb_printf (file
, _("Debuginfod URLs have not been set.\n"));
434 gdb_printf (file
, _("Debuginfod URLs are currently set to:\n%s\n"),
438 /* Show callback for "set debuginfod verbose". */
441 show_debuginfod_verbose_command (ui_file
*file
, int from_tty
,
442 cmd_list_element
*cmd
, const char *value
)
444 gdb_printf (file
, _("Debuginfod verbose output is set to %s.\n"),
448 /* Register debuginfod commands. */
450 void _initialize_debuginfod ();
452 _initialize_debuginfod ()
454 /* set/show debuginfod */
455 add_setshow_prefix_cmd ("debuginfod", class_run
,
456 _("Set debuginfod options."),
457 _("Show debuginfod options."),
458 &set_debuginfod_prefix_list
,
459 &show_debuginfod_prefix_list
,
460 &setlist
, &showlist
);
462 add_setshow_enum_cmd ("enabled", class_run
, debuginfod_enabled_enum
,
463 _("Set whether to use debuginfod."),
464 _("Show whether to use debuginfod."),
466 When on, enable the use of debuginfod to download missing debug info and\n\
468 set_debuginfod_enabled
,
469 get_debuginfod_enabled
,
470 show_debuginfod_enabled
,
471 &set_debuginfod_prefix_list
,
472 &show_debuginfod_prefix_list
);
474 /* set/show debuginfod urls */
475 add_setshow_string_noescape_cmd ("urls", class_run
, _("\
476 Set the list of debuginfod server URLs."), _("\
477 Show the list of debuginfod server URLs."), _("\
478 Manage the space-separated list of debuginfod server URLs that GDB will query \
479 when missing debuginfo, executables or source files.\nThe default value is \
480 copied from the DEBUGINFOD_URLS environment variable."),
483 show_debuginfod_urls
,
484 &set_debuginfod_prefix_list
,
485 &show_debuginfod_prefix_list
);
487 /* set/show debuginfod verbose */
488 add_setshow_zuinteger_cmd ("verbose", class_support
,
489 &debuginfod_verbose
, _("\
490 Set verbosity of debuginfod output."), _("\
491 Show debuginfod debugging."), _("\
492 When set to a non-zero value, display verbose output for each debuginfod \
493 query.\nTo disable, set to zero. Verbose output is displayed by default."),
495 show_debuginfod_verbose_command
,
496 &set_debuginfod_prefix_list
,
497 &show_debuginfod_prefix_list
);