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/>. */
21 #include "gdbsupport/scoped_fd.h"
22 #include "debuginfod-support.h"
23 #include "gdbsupport/gdb_optional.h"
24 #include "cli/cli-cmds.h"
25 #include "cli/cli-style.h"
28 /* Set/show debuginfod commands. */
29 static cmd_list_element
*set_debuginfod_prefix_list
;
30 static cmd_list_element
*show_debuginfod_prefix_list
;
32 static const char debuginfod_on
[] = "on";
33 static const char debuginfod_off
[] = "off";
34 static const char debuginfod_ask
[] = "ask";
36 static const char *debuginfod_enabled_enum
[] =
44 static const char *debuginfod_enabled
=
45 #if defined(HAVE_LIBDEBUGINFOD)
51 static unsigned int debuginfod_verbose
= 1;
53 #ifndef HAVE_LIBDEBUGINFOD
55 debuginfod_source_query (const unsigned char *build_id
,
58 gdb::unique_xmalloc_ptr
<char> *destname
)
60 return scoped_fd (-ENOSYS
);
64 debuginfod_debuginfo_query (const unsigned char *build_id
,
67 gdb::unique_xmalloc_ptr
<char> *destname
)
69 return scoped_fd (-ENOSYS
);
73 debuginfod_exec_query (const unsigned char *build_id
,
76 gdb::unique_xmalloc_ptr
<char> *destname
)
78 return scoped_fd (-ENOSYS
);
81 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
84 #include <elfutils/debuginfod.h>
88 user_data (const char *desc
, const char *fname
)
89 : desc (desc
), fname (fname
)
92 const char * const desc
;
93 const char * const fname
;
94 gdb::optional
<ui_out::progress_meter
> meter
;
97 /* Deleter for a debuginfod_client. */
99 struct debuginfod_client_deleter
101 void operator() (debuginfod_client
*c
)
107 using debuginfod_client_up
108 = std::unique_ptr
<debuginfod_client
, debuginfod_client_deleter
>;
111 progressfn (debuginfod_client
*c
, long cur
, long total
)
113 user_data
*data
= static_cast<user_data
*> (debuginfod_get_user_data (c
));
114 gdb_assert (data
!= nullptr);
116 if (check_quit_flag ())
118 printf_filtered ("Cancelling download of %s %ps...\n",
120 styled_string (file_name_style
.style (), data
->fname
));
127 if (!data
->meter
.has_value ())
129 float size_in_mb
= 1.0f
* total
/ (1024 * 1024);
130 string_file
styled_filename (current_uiout
->can_emit_style_escape ());
131 fprintf_styled (&styled_filename
,
132 file_name_style
.style (),
136 = string_printf ("Downloading %.2f MB %s %s", size_in_mb
, data
->desc
,
137 styled_filename
.c_str());
138 data
->meter
.emplace (current_uiout
, message
, 1);
141 data
->meter
->progress ((double)cur
/ (double)total
);
146 static debuginfod_client
*
147 get_debuginfod_client ()
149 static debuginfod_client_up global_client
;
151 if (global_client
== nullptr)
153 global_client
.reset (debuginfod_begin ());
155 if (global_client
!= nullptr)
156 debuginfod_set_progressfn (global_client
.get (), progressfn
);
159 return global_client
.get ();
162 /* Check if debuginfod is enabled. If configured to do so, ask the user
163 whether to enable debuginfod. */
166 debuginfod_is_enabled ()
168 const char *urls
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
170 if (urls
== nullptr || urls
[0] == '\0'
171 || debuginfod_enabled
== debuginfod_off
)
174 if (debuginfod_enabled
== debuginfod_ask
)
176 int resp
= nquery (_("\nThis GDB supports auto-downloading debuginfo " \
177 "from the following URLs:\n%s\nEnable debuginfod " \
178 "for this session? "),
182 printf_filtered (_("Debuginfod has been disabled.\nTo make this " \
183 "setting permanent, add \'set debuginfod " \
184 "enabled off\' to .gdbinit.\n"));
185 debuginfod_enabled
= debuginfod_off
;
189 printf_filtered (_("Debuginfod has been enabled.\nTo make this " \
190 "setting permanent, add \'set debuginfod enabled " \
191 "on\' to .gdbinit.\n"));
192 debuginfod_enabled
= debuginfod_on
;
198 /* See debuginfod-support.h */
201 debuginfod_source_query (const unsigned char *build_id
,
204 gdb::unique_xmalloc_ptr
<char> *destname
)
206 if (!debuginfod_is_enabled ())
207 return scoped_fd (-ENOSYS
);
209 debuginfod_client
*c
= get_debuginfod_client ();
212 return scoped_fd (-ENOMEM
);
214 char *dname
= nullptr;
215 user_data
data ("source file", srcpath
);
217 debuginfod_set_user_data (c
, &data
);
218 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
219 if (target_supports_terminal_ours ())
221 term_state
.emplace ();
222 target_terminal::ours ();
225 scoped_fd
fd (debuginfod_find_source (c
,
230 debuginfod_set_user_data (c
, nullptr);
232 if (debuginfod_verbose
> 0 && fd
.get () < 0 && fd
.get () != -ENOENT
)
233 printf_filtered (_("Download failed: %s. Continuing without source file %ps.\n"),
234 safe_strerror (-fd
.get ()),
235 styled_string (file_name_style
.style (), srcpath
));
238 destname
->reset (dname
);
243 /* See debuginfod-support.h */
246 debuginfod_debuginfo_query (const unsigned char *build_id
,
248 const char *filename
,
249 gdb::unique_xmalloc_ptr
<char> *destname
)
251 if (!debuginfod_is_enabled ())
252 return scoped_fd (-ENOSYS
);
254 debuginfod_client
*c
= get_debuginfod_client ();
257 return scoped_fd (-ENOMEM
);
259 char *dname
= nullptr;
260 user_data
data ("separate debug info for", filename
);
262 debuginfod_set_user_data (c
, &data
);
263 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
264 if (target_supports_terminal_ours ())
266 term_state
.emplace ();
267 target_terminal::ours ();
270 scoped_fd
fd (debuginfod_find_debuginfo (c
, build_id
, build_id_len
,
272 debuginfod_set_user_data (c
, nullptr);
274 if (debuginfod_verbose
> 0 && fd
.get () < 0 && fd
.get () != -ENOENT
)
275 printf_filtered (_("Download failed: %s. Continuing without debug info for %ps.\n"),
276 safe_strerror (-fd
.get ()),
277 styled_string (file_name_style
.style (), filename
));
280 destname
->reset (dname
);
285 /* See debuginfod-support.h */
288 debuginfod_exec_query (const unsigned char *build_id
,
290 const char *filename
,
291 gdb::unique_xmalloc_ptr
<char> *destname
)
293 if (!debuginfod_is_enabled ())
294 return scoped_fd (-ENOSYS
);
296 debuginfod_client
*c
= get_debuginfod_client ();
299 return scoped_fd (-ENOMEM
);
301 char *dname
= nullptr;
302 user_data
data ("executable for", filename
);
304 debuginfod_set_user_data (c
, &data
);
305 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
306 if (target_supports_terminal_ours ())
308 term_state
.emplace ();
309 target_terminal::ours ();
312 scoped_fd
fd (debuginfod_find_executable (c
, build_id
, build_id_len
, &dname
));
313 debuginfod_set_user_data (c
, nullptr);
315 if (debuginfod_verbose
> 0 && fd
.get () < 0 && fd
.get () != -ENOENT
)
316 printf_filtered (_("Download failed: %s. " \
317 "Continuing without executable for %ps.\n"),
318 safe_strerror (-fd
.get ()),
319 styled_string (file_name_style
.style (), filename
));
322 destname
->reset (dname
);
328 /* Set callback for "set debuginfod enabled". */
331 set_debuginfod_enabled (const char *value
)
333 #if defined(HAVE_LIBDEBUGINFOD)
334 debuginfod_enabled
= value
;
340 /* Get callback for "set debuginfod enabled". */
343 get_debuginfod_enabled ()
345 return debuginfod_enabled
;
348 /* Show callback for "set debuginfod enabled". */
351 show_debuginfod_enabled (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
354 fprintf_filtered (file
,
355 _("Debuginfod functionality is currently set to "
356 "\"%s\".\n"), debuginfod_enabled
);
359 /* Set callback for "set debuginfod urls". */
362 set_debuginfod_urls (const std::string
&urls
)
364 #if defined(HAVE_LIBDEBUGINFOD)
365 if (setenv (DEBUGINFOD_URLS_ENV_VAR
, urls
.c_str (), 1) != 0)
366 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno
));
372 /* Get callback for "set debuginfod urls". */
374 static const std::string
&
375 get_debuginfod_urls ()
377 static std::string urls
;
378 #if defined(HAVE_LIBDEBUGINFOD)
379 const char *envvar
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
381 if (envvar
!= nullptr)
390 /* Show callback for "set debuginfod urls". */
393 show_debuginfod_urls (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
396 if (value
[0] == '\0')
397 fprintf_filtered (file
, _("Debuginfod URLs have not been set.\n"));
399 fprintf_filtered (file
, _("Debuginfod URLs are currently set to:\n%s\n"),
403 /* Show callback for "set debuginfod verbose". */
406 show_debuginfod_verbose_command (ui_file
*file
, int from_tty
,
407 cmd_list_element
*cmd
, const char *value
)
409 fprintf_filtered (file
, _("Debuginfod verbose output is set to %s.\n"),
413 /* Register debuginfod commands. */
415 void _initialize_debuginfod ();
417 _initialize_debuginfod ()
419 /* set/show debuginfod */
420 add_setshow_prefix_cmd ("debuginfod", class_run
,
421 _("Set debuginfod options."),
422 _("Show debuginfod options."),
423 &set_debuginfod_prefix_list
,
424 &show_debuginfod_prefix_list
,
425 &setlist
, &showlist
);
427 add_setshow_enum_cmd ("enabled", class_run
, debuginfod_enabled_enum
,
428 _("Set whether to use debuginfod."),
429 _("Show whether to use debuginfod."),
431 When on, enable the use of debuginfod to download missing debug info and\n\
433 set_debuginfod_enabled
,
434 get_debuginfod_enabled
,
435 show_debuginfod_enabled
,
436 &set_debuginfod_prefix_list
,
437 &show_debuginfod_prefix_list
);
439 /* set/show debuginfod urls */
440 add_setshow_string_noescape_cmd ("urls", class_run
, _("\
441 Set the list of debuginfod server URLs."), _("\
442 Show the list of debuginfod server URLs."), _("\
443 Manage the space-separated list of debuginfod server URLs that GDB will query \
444 when missing debuginfo, executables or source files.\nThe default value is \
445 copied from the DEBUGINFOD_URLS environment variable."),
448 show_debuginfod_urls
,
449 &set_debuginfod_prefix_list
,
450 &show_debuginfod_prefix_list
);
452 /* set/show debuginfod verbose */
453 add_setshow_zuinteger_cmd ("verbose", class_support
,
454 &debuginfod_verbose
, _("\
455 Set verbosity of debuginfod output."), _("\
456 Show debuginfod debugging."), _("\
457 When set to a non-zero value, display verbose output for each debuginfod \
458 query.\nTo disable, set to zero. Verbose output is displayed by default."),
460 show_debuginfod_verbose_command
,
461 &set_debuginfod_prefix_list
,
462 &show_debuginfod_prefix_list
);