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
);
72 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
75 #include <elfutils/debuginfod.h>
79 user_data (const char *desc
, const char *fname
)
80 : desc (desc
), fname (fname
)
83 const char * const desc
;
84 const char * const fname
;
85 gdb::optional
<ui_out::progress_meter
> meter
;
88 /* Deleter for a debuginfod_client. */
90 struct debuginfod_client_deleter
92 void operator() (debuginfod_client
*c
)
98 using debuginfod_client_up
99 = std::unique_ptr
<debuginfod_client
, debuginfod_client_deleter
>;
102 progressfn (debuginfod_client
*c
, long cur
, long total
)
104 user_data
*data
= static_cast<user_data
*> (debuginfod_get_user_data (c
));
105 gdb_assert (data
!= nullptr);
107 if (check_quit_flag ())
109 printf_filtered ("Cancelling download of %s %ps...\n",
111 styled_string (file_name_style
.style (), data
->fname
));
118 if (!data
->meter
.has_value ())
120 float size_in_mb
= 1.0f
* total
/ (1024 * 1024);
121 string_file
styled_filename (current_uiout
->can_emit_style_escape ());
122 fprintf_styled (&styled_filename
,
123 file_name_style
.style (),
127 = string_printf ("Downloading %.2f MB %s %s", size_in_mb
, data
->desc
,
128 styled_filename
.c_str());
129 data
->meter
.emplace (current_uiout
, message
, 1);
132 current_uiout
->progress ((double)cur
/ (double)total
);
137 static debuginfod_client
*
138 get_debuginfod_client ()
140 static debuginfod_client_up global_client
;
142 if (global_client
== nullptr)
144 global_client
.reset (debuginfod_begin ());
146 if (global_client
!= nullptr)
147 debuginfod_set_progressfn (global_client
.get (), progressfn
);
150 return global_client
.get ();
153 /* Check if debuginfod is enabled. If configured to do so, ask the user
154 whether to enable debuginfod. */
157 debuginfod_is_enabled ()
159 const char *urls
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
161 if (urls
== nullptr || urls
[0] == '\0'
162 || debuginfod_enabled
== debuginfod_off
)
165 if (debuginfod_enabled
== debuginfod_ask
)
167 int resp
= nquery (_("\nThis GDB supports auto-downloading debuginfo " \
168 "from the following URLs:\n%s\nEnable debuginfod " \
169 "for this session? "),
173 printf_filtered (_("Debuginfod has been disabled.\nTo make this " \
174 "setting permanent, add \'set debuginfod " \
175 "enabled off\' to .gdbinit.\n"));
176 debuginfod_enabled
= debuginfod_off
;
180 printf_filtered (_("Debuginfod has been enabled.\nTo make this " \
181 "setting permanent, add \'set debuginfod enabled " \
182 "on\' to .gdbinit.\n"));
183 debuginfod_enabled
= debuginfod_on
;
189 /* See debuginfod-support.h */
192 debuginfod_source_query (const unsigned char *build_id
,
195 gdb::unique_xmalloc_ptr
<char> *destname
)
197 if (!debuginfod_is_enabled ())
198 return scoped_fd (-ENOSYS
);
200 debuginfod_client
*c
= get_debuginfod_client ();
203 return scoped_fd (-ENOMEM
);
205 user_data
data ("source file", srcpath
);
207 debuginfod_set_user_data (c
, &data
);
208 gdb::optional
<target_terminal::scoped_restore_terminal_state
> term_state
;
209 if (target_supports_terminal_ours ())
211 term_state
.emplace ();
212 target_terminal::ours ();
215 scoped_fd
fd (debuginfod_find_source (c
,
220 debuginfod_set_user_data (c
, nullptr);
222 if (debuginfod_verbose
> 0 && fd
.get () < 0 && fd
.get () != -ENOENT
)
223 printf_filtered (_("Download failed: %s. Continuing without source file %ps.\n"),
224 safe_strerror (-fd
.get ()),
225 styled_string (file_name_style
.style (), srcpath
));
228 *destname
= make_unique_xstrdup (srcpath
);
233 /* See debuginfod-support.h */
236 debuginfod_debuginfo_query (const unsigned char *build_id
,
238 const char *filename
,
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 ("separate debug info for", filename
);
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_debuginfo (c
, build_id
, build_id_len
,
262 debuginfod_set_user_data (c
, nullptr);
264 if (debuginfod_verbose
> 0 && fd
.get () < 0 && fd
.get () != -ENOENT
)
265 printf_filtered (_("Download failed: %s. Continuing without debug info for %ps.\n"),
266 safe_strerror (-fd
.get ()),
267 styled_string (file_name_style
.style (), filename
));
270 destname
->reset (dname
);
276 /* Set callback for "set debuginfod enabled". */
279 set_debuginfod_enabled (const char *value
)
281 #if defined(HAVE_LIBDEBUGINFOD)
282 debuginfod_enabled
= value
;
288 /* Get callback for "set debuginfod enabled". */
291 get_debuginfod_enabled ()
293 return debuginfod_enabled
;
296 /* Show callback for "set debuginfod enabled". */
299 show_debuginfod_enabled (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
302 fprintf_filtered (file
,
303 _("Debuginfod functionality is currently set to "
304 "\"%s\".\n"), debuginfod_enabled
);
307 /* Set callback for "set debuginfod urls". */
310 set_debuginfod_urls (const std::string
&urls
)
312 #if defined(HAVE_LIBDEBUGINFOD)
313 if (setenv (DEBUGINFOD_URLS_ENV_VAR
, urls
.c_str (), 1) != 0)
314 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno
));
320 /* Get callback for "set debuginfod urls". */
322 static const std::string
&
323 get_debuginfod_urls ()
325 static std::string urls
;
326 #if defined(HAVE_LIBDEBUGINFOD)
327 const char *envvar
= getenv (DEBUGINFOD_URLS_ENV_VAR
);
329 if (envvar
!= nullptr)
338 /* Show callback for "set debuginfod urls". */
341 show_debuginfod_urls (ui_file
*file
, int from_tty
, cmd_list_element
*cmd
,
344 if (value
[0] == '\0')
345 fprintf_filtered (file
, _("Debuginfod URLs have not been set.\n"));
347 fprintf_filtered (file
, _("Debuginfod URLs are currently set to:\n%s\n"),
351 /* Show callback for "set debuginfod verbose". */
354 show_debuginfod_verbose_command (ui_file
*file
, int from_tty
,
355 cmd_list_element
*cmd
, const char *value
)
357 fprintf_filtered (file
, _("Debuginfod verbose output is set to %s.\n"),
361 /* Register debuginfod commands. */
363 void _initialize_debuginfod ();
365 _initialize_debuginfod ()
367 /* set/show debuginfod */
368 add_setshow_prefix_cmd ("debuginfod", class_run
,
369 _("Set debuginfod options."),
370 _("Show debuginfod options."),
371 &set_debuginfod_prefix_list
,
372 &show_debuginfod_prefix_list
,
373 &setlist
, &showlist
);
375 add_setshow_enum_cmd ("enabled", class_run
, debuginfod_enabled_enum
,
376 _("Set whether to use debuginfod."),
377 _("Show whether to use debuginfod."),
379 When on, enable the use of debuginfod to download missing debug info and\n\
381 set_debuginfod_enabled
,
382 get_debuginfod_enabled
,
383 show_debuginfod_enabled
,
384 &set_debuginfod_prefix_list
,
385 &show_debuginfod_prefix_list
);
387 /* set/show debuginfod urls */
388 add_setshow_string_noescape_cmd ("urls", class_run
, _("\
389 Set the list of debuginfod server URLs."), _("\
390 Show the list of debuginfod server URLs."), _("\
391 Manage the space-separated list of debuginfod server URLs that GDB will query \
392 when missing debuginfo, executables or source files.\nThe default value is \
393 copied from the DEBUGINFOD_URLS environment variable."),
396 show_debuginfod_urls
,
397 &set_debuginfod_prefix_list
,
398 &show_debuginfod_prefix_list
);
400 /* set/show debuginfod verbose */
401 add_setshow_zuinteger_cmd ("verbose", class_support
,
402 &debuginfod_verbose
, _("\
403 Set verbosity of debuginfod output."), _("\
404 Show debuginfod debugging."), _("\
405 When set to a non-zero value, display verbose output for each debuginfod \
406 query.\nTo disable, set to zero. Verbose output is displayed by default."),
408 show_debuginfod_verbose_command
,
409 &set_debuginfod_prefix_list
,
410 &show_debuginfod_prefix_list
);