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), has_printed (false)
92 const char * const desc;
93 const char * const fname;
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 gdb_printf ("Cancelling download of %s %ps...\n",
120 styled_string (file_name_style.style (), data->fname));
124 if (!data->has_printed)
126 /* Include the transfer size, if available. */
129 float size = 1.0f * total / 1024;
130 const char *unit = "KB";
132 /* If size is greater than 0.01 MB, set unit to MB. */
139 gdb_printf ("Downloading %.2f %s %s %ps...\n",
140 size, unit, data->desc,
141 styled_string (file_name_style.style (),
145 gdb_printf ("Downloading %s %ps...\n", data->desc,
146 styled_string (file_name_style.style (), data->fname));
148 data->has_printed = true;
154 static debuginfod_client *
155 get_debuginfod_client ()
157 static debuginfod_client_up global_client;
159 if (global_client == nullptr)
161 global_client.reset (debuginfod_begin ());
163 if (global_client != nullptr)
164 debuginfod_set_progressfn (global_client.get (), progressfn);
167 return global_client.get ();
170 /* Check if debuginfod is enabled. If configured to do so, ask the user
171 whether to enable debuginfod. */
174 debuginfod_is_enabled ()
176 const char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
178 if (urls == nullptr || urls[0] == '\0'
179 || debuginfod_enabled == debuginfod_off)
182 if (debuginfod_enabled == debuginfod_ask)
184 int resp = nquery (_("\nThis GDB supports auto-downloading debuginfo " \
185 "from the following URLs:\n%s\nEnable debuginfod " \
186 "for this session? "),
190 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
191 "setting permanent, add \'set debuginfod " \
192 "enabled off\' to .gdbinit.\n"));
193 debuginfod_enabled = debuginfod_off;
197 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
198 "setting permanent, add \'set debuginfod enabled " \
199 "on\' to .gdbinit.\n"));
200 debuginfod_enabled = debuginfod_on;
206 /* See debuginfod-support.h */
209 debuginfod_source_query (const unsigned char *build_id,
212 gdb::unique_xmalloc_ptr<char> *destname)
214 if (!debuginfod_is_enabled ())
215 return scoped_fd (-ENOSYS);
217 debuginfod_client *c = get_debuginfod_client ();
220 return scoped_fd (-ENOMEM);
222 char *dname = nullptr;
223 user_data data ("source file", srcpath);
225 debuginfod_set_user_data (c, &data);
226 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
227 if (target_supports_terminal_ours ())
229 term_state.emplace ();
230 target_terminal::ours ();
233 scoped_fd fd (debuginfod_find_source (c,
238 debuginfod_set_user_data (c, nullptr);
240 if (debuginfod_verbose > 0 && fd.get () < 0 && fd.get () != -ENOENT)
241 gdb_printf (_("Download failed: %s. Continuing without source file %ps.\n"),
242 safe_strerror (-fd.get ()),
243 styled_string (file_name_style.style (), srcpath));
246 destname->reset (dname);
251 /* See debuginfod-support.h */
254 debuginfod_debuginfo_query (const unsigned char *build_id,
256 const char *filename,
257 gdb::unique_xmalloc_ptr<char> *destname)
259 if (!debuginfod_is_enabled ())
260 return scoped_fd (-ENOSYS);
262 debuginfod_client *c = get_debuginfod_client ();
265 return scoped_fd (-ENOMEM);
267 char *dname = nullptr;
268 user_data data ("separate debug info for", filename);
270 debuginfod_set_user_data (c, &data);
271 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
272 if (target_supports_terminal_ours ())
274 term_state.emplace ();
275 target_terminal::ours ();
278 scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
280 debuginfod_set_user_data (c, nullptr);
282 if (debuginfod_verbose > 0 && fd.get () < 0 && fd.get () != -ENOENT)
283 gdb_printf (_("Download failed: %s. Continuing without debug info for %ps.\n"),
284 safe_strerror (-fd.get ()),
285 styled_string (file_name_style.style (), filename));
288 destname->reset (dname);
293 /* See debuginfod-support.h */
296 debuginfod_exec_query (const unsigned char *build_id,
298 const char *filename,
299 gdb::unique_xmalloc_ptr<char> *destname)
301 if (!debuginfod_is_enabled ())
302 return scoped_fd (-ENOSYS);
304 debuginfod_client *c = get_debuginfod_client ();
307 return scoped_fd (-ENOMEM);
309 char *dname = nullptr;
310 user_data data ("executable for", filename);
312 debuginfod_set_user_data (c, &data);
313 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
314 if (target_supports_terminal_ours ())
316 term_state.emplace ();
317 target_terminal::ours ();
320 scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
321 debuginfod_set_user_data (c, nullptr);
323 if (debuginfod_verbose > 0 && fd.get () < 0 && fd.get () != -ENOENT)
324 gdb_printf (_("Download failed: %s. " \
325 "Continuing without executable for %ps.\n"),
326 safe_strerror (-fd.get ()),
327 styled_string (file_name_style.style (), filename));
330 destname->reset (dname);
336 /* Set callback for "set debuginfod enabled". */
339 set_debuginfod_enabled (const char *value)
341 #if defined(HAVE_LIBDEBUGINFOD)
342 debuginfod_enabled = value;
348 /* Get callback for "set debuginfod enabled". */
351 get_debuginfod_enabled ()
353 return debuginfod_enabled;
356 /* Show callback for "set debuginfod enabled". */
359 show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
363 _("Debuginfod functionality is currently set to "
364 "\"%s\".\n"), debuginfod_enabled);
367 /* Set callback for "set debuginfod urls". */
370 set_debuginfod_urls (const std::string &urls)
372 #if defined(HAVE_LIBDEBUGINFOD)
373 if (setenv (DEBUGINFOD_URLS_ENV_VAR, urls.c_str (), 1) != 0)
374 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno));
380 /* Get callback for "set debuginfod urls". */
382 static const std::string&
383 get_debuginfod_urls ()
385 static std::string urls;
386 #if defined(HAVE_LIBDEBUGINFOD)
387 const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
389 if (envvar != nullptr)
398 /* Show callback for "set debuginfod urls". */
401 show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
404 if (value[0] == '\0')
405 gdb_printf (file, _("Debuginfod URLs have not been set.\n"));
407 gdb_printf (file, _("Debuginfod URLs are currently set to:\n%s\n"),
411 /* Show callback for "set debuginfod verbose". */
414 show_debuginfod_verbose_command (ui_file *file, int from_tty,
415 cmd_list_element *cmd, const char *value)
417 gdb_printf (file, _("Debuginfod verbose output is set to %s.\n"),
421 /* Register debuginfod commands. */
423 void _initialize_debuginfod ();
425 _initialize_debuginfod ()
427 /* set/show debuginfod */
428 add_setshow_prefix_cmd ("debuginfod", class_run,
429 _("Set debuginfod options."),
430 _("Show debuginfod options."),
431 &set_debuginfod_prefix_list,
432 &show_debuginfod_prefix_list,
433 &setlist, &showlist);
435 add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
436 _("Set whether to use debuginfod."),
437 _("Show whether to use debuginfod."),
439 When on, enable the use of debuginfod to download missing debug info and\n\
441 set_debuginfod_enabled,
442 get_debuginfod_enabled,
443 show_debuginfod_enabled,
444 &set_debuginfod_prefix_list,
445 &show_debuginfod_prefix_list);
447 /* set/show debuginfod urls */
448 add_setshow_string_noescape_cmd ("urls", class_run, _("\
449 Set the list of debuginfod server URLs."), _("\
450 Show the list of debuginfod server URLs."), _("\
451 Manage the space-separated list of debuginfod server URLs that GDB will query \
452 when missing debuginfo, executables or source files.\nThe default value is \
453 copied from the DEBUGINFOD_URLS environment variable."),
456 show_debuginfod_urls,
457 &set_debuginfod_prefix_list,
458 &show_debuginfod_prefix_list);
460 /* set/show debuginfod verbose */
461 add_setshow_zuinteger_cmd ("verbose", class_support,
462 &debuginfod_verbose, _("\
463 Set verbosity of debuginfod output."), _("\
464 Show debuginfod debugging."), _("\
465 When set to a non-zero value, display verbose output for each debuginfod \
466 query.\nTo disable, set to zero. Verbose output is displayed by default."),
468 show_debuginfod_verbose_command,
469 &set_debuginfod_prefix_list,
470 &show_debuginfod_prefix_list);