Update copyright year range in header of all files managed by GDB
[binutils-gdb.git] / gdb / debuginfod-support.c
blob04d254a16012b602eeb835f57268901019567fb5
1 /* debuginfod utilities for GDB.
2 Copyright (C) 2020-2023 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 "defs.h"
20 #include "diagnostics.h"
21 #include <errno.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"
27 #include "cli-out.h"
28 #include "target.h"
30 /* Set/show debuginfod commands. */
31 static cmd_list_element *set_debuginfod_prefix_list;
32 static cmd_list_element *show_debuginfod_prefix_list;
34 static const char debuginfod_on[] = "on";
35 static const char debuginfod_off[] = "off";
36 static const char debuginfod_ask[] = "ask";
38 static const char *debuginfod_enabled_enum[] =
40 debuginfod_on,
41 debuginfod_off,
42 debuginfod_ask,
43 nullptr
46 static const char *debuginfod_enabled =
47 #if defined(HAVE_LIBDEBUGINFOD)
48 debuginfod_ask;
49 #else
50 debuginfod_off;
51 #endif
53 static unsigned int debuginfod_verbose = 1;
55 #ifndef HAVE_LIBDEBUGINFOD
56 scoped_fd
57 debuginfod_source_query (const unsigned char *build_id,
58 int build_id_len,
59 const char *srcpath,
60 gdb::unique_xmalloc_ptr<char> *destname)
62 return scoped_fd (-ENOSYS);
65 scoped_fd
66 debuginfod_debuginfo_query (const unsigned char *build_id,
67 int build_id_len,
68 const char *filename,
69 gdb::unique_xmalloc_ptr<char> *destname)
71 return scoped_fd (-ENOSYS);
74 scoped_fd
75 debuginfod_exec_query (const unsigned char *build_id,
76 int build_id_len,
77 const char *filename,
78 gdb::unique_xmalloc_ptr<char> *destname)
80 return scoped_fd (-ENOSYS);
83 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
85 #else
86 #include <elfutils/debuginfod.h>
88 struct user_data
90 user_data (const char *desc, const char *fname)
91 : desc (desc), fname (fname)
92 { }
94 const char * const desc;
95 const char * const fname;
96 ui_out::progress_update progress;
99 /* Deleter for a debuginfod_client. */
101 struct debuginfod_client_deleter
103 void operator() (debuginfod_client *c)
105 debuginfod_end (c);
109 using debuginfod_client_up
110 = std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
113 /* Convert SIZE into a unit suitable for use with progress updates.
114 SIZE should in given in bytes and will be converted into KB, MB, GB
115 or remain unchanged. UNIT will be set to "B", "KB", "MB" or "GB"
116 accordingly. */
118 static const char *
119 get_size_and_unit (double &size)
121 if (size < 1024)
122 /* If size is less than 1 KB then set unit to B. */
123 return "B";
125 size /= 1024;
126 if (size < 1024)
127 /* If size is less than 1 MB then set unit to KB. */
128 return "K";
130 size /= 1024;
131 if (size < 1024)
132 /* If size is less than 1 GB then set unit to MB. */
133 return "M";
135 size /= 1024;
136 return "G";
139 static int
140 progressfn (debuginfod_client *c, long cur, long total)
142 user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
143 gdb_assert (data != nullptr);
145 string_file styled_fname (current_uiout->can_emit_style_escape ());
146 fprintf_styled (&styled_fname, file_name_style.style (), "%s",
147 data->fname);
149 if (check_quit_flag ())
151 gdb_printf ("Cancelling download of %s %s...\n",
152 data->desc, styled_fname.c_str ());
153 return 1;
156 if (debuginfod_verbose == 0)
157 return 0;
159 /* Print progress update. Include the transfer size if available. */
160 if (total > 0)
162 /* Transfer size is known. */
163 double howmuch = (double) cur / (double) total;
165 if (howmuch >= 0.0 && howmuch <= 1.0)
167 double d_total = (double) total;
168 const char *unit = get_size_and_unit (d_total);
169 std::string msg = string_printf ("Downloading %0.2f %s %s %s",
170 d_total, unit, data->desc,
171 styled_fname.c_str ());
172 data->progress.update_progress (msg, unit, howmuch, d_total);
173 return 0;
177 std::string msg = string_printf ("Downloading %s %s",
178 data->desc, styled_fname.c_str ());
179 data->progress.update_progress (msg);
180 return 0;
183 static debuginfod_client *
184 get_debuginfod_client ()
186 static debuginfod_client_up global_client;
188 if (global_client == nullptr)
190 global_client.reset (debuginfod_begin ());
192 if (global_client != nullptr)
193 debuginfod_set_progressfn (global_client.get (), progressfn);
196 return global_client.get ();
199 /* Check if debuginfod is enabled. If configured to do so, ask the user
200 whether to enable debuginfod. */
202 static bool
203 debuginfod_is_enabled ()
205 const char *urls = skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR));
207 if (debuginfod_enabled == debuginfod_off
208 || urls == nullptr
209 || *urls == '\0')
210 return false;
212 if (debuginfod_enabled == debuginfod_ask)
214 gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
215 "from the following URLs:\n"));
217 gdb::string_view url_view (urls);
218 while (true)
220 size_t off = url_view.find_first_not_of (' ');
221 if (off == gdb::string_view::npos)
222 break;
223 url_view = url_view.substr (off);
224 /* g++ 11.2.1 on s390x, g++ 11.3.1 on ppc64le and g++ 11 on
225 hppa seem convinced url_view might be of SIZE_MAX length.
226 And so complains because the length of an array can only
227 be PTRDIFF_MAX. */
228 DIAGNOSTIC_PUSH
229 DIAGNOSTIC_IGNORE_STRINGOP_OVERREAD
230 off = url_view.find_first_of (' ');
231 DIAGNOSTIC_POP
232 gdb_printf
233 (_(" <%ps>\n"),
234 styled_string (file_name_style.style (),
235 gdb::to_string (url_view.substr (0,
236 off)).c_str ()));
237 if (off == gdb::string_view::npos)
238 break;
239 url_view = url_view.substr (off);
242 int resp = nquery (_("Enable debuginfod for this session? "));
243 if (!resp)
245 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
246 "setting permanent, add \'set debuginfod " \
247 "enabled off\' to .gdbinit.\n"));
248 debuginfod_enabled = debuginfod_off;
249 return false;
252 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
253 "setting permanent, add \'set debuginfod enabled " \
254 "on\' to .gdbinit.\n"));
255 debuginfod_enabled = debuginfod_on;
258 return true;
261 /* Print the result of the most recent attempted download. */
263 static void
264 print_outcome (user_data &data, int fd)
266 /* Clears the current line of progress output. */
267 current_uiout->do_progress_end ();
269 if (fd < 0 && fd != -ENOENT)
270 gdb_printf (_("Download failed: %s. Continuing without %s %ps.\n"),
271 safe_strerror (-fd),
272 data.desc,
273 styled_string (file_name_style.style (), data.fname));
276 /* See debuginfod-support.h */
278 scoped_fd
279 debuginfod_source_query (const unsigned char *build_id,
280 int build_id_len,
281 const char *srcpath,
282 gdb::unique_xmalloc_ptr<char> *destname)
284 if (!debuginfod_is_enabled ())
285 return scoped_fd (-ENOSYS);
287 debuginfod_client *c = get_debuginfod_client ();
289 if (c == nullptr)
290 return scoped_fd (-ENOMEM);
292 char *dname = nullptr;
293 user_data data ("source file", srcpath);
295 debuginfod_set_user_data (c, &data);
296 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
297 if (target_supports_terminal_ours ())
299 term_state.emplace ();
300 target_terminal::ours ();
303 scoped_fd fd (debuginfod_find_source (c,
304 build_id,
305 build_id_len,
306 srcpath,
307 &dname));
308 debuginfod_set_user_data (c, nullptr);
309 print_outcome (data, fd.get ());
311 if (fd.get () >= 0)
312 destname->reset (dname);
314 return fd;
317 /* See debuginfod-support.h */
319 scoped_fd
320 debuginfod_debuginfo_query (const unsigned char *build_id,
321 int build_id_len,
322 const char *filename,
323 gdb::unique_xmalloc_ptr<char> *destname)
325 if (!debuginfod_is_enabled ())
326 return scoped_fd (-ENOSYS);
328 debuginfod_client *c = get_debuginfod_client ();
330 if (c == nullptr)
331 return scoped_fd (-ENOMEM);
333 char *dname = nullptr;
334 user_data data ("separate debug info for", filename);
336 debuginfod_set_user_data (c, &data);
337 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
338 if (target_supports_terminal_ours ())
340 term_state.emplace ();
341 target_terminal::ours ();
344 scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
345 &dname));
346 debuginfod_set_user_data (c, nullptr);
347 print_outcome (data, fd.get ());
349 if (fd.get () >= 0)
350 destname->reset (dname);
352 return fd;
355 /* See debuginfod-support.h */
357 scoped_fd
358 debuginfod_exec_query (const unsigned char *build_id,
359 int build_id_len,
360 const char *filename,
361 gdb::unique_xmalloc_ptr<char> *destname)
363 if (!debuginfod_is_enabled ())
364 return scoped_fd (-ENOSYS);
366 debuginfod_client *c = get_debuginfod_client ();
368 if (c == nullptr)
369 return scoped_fd (-ENOMEM);
371 char *dname = nullptr;
372 user_data data ("executable for", filename);
374 debuginfod_set_user_data (c, &data);
375 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
376 if (target_supports_terminal_ours ())
378 term_state.emplace ();
379 target_terminal::ours ();
382 scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
383 debuginfod_set_user_data (c, nullptr);
384 print_outcome (data, fd.get ());
386 if (fd.get () >= 0)
387 destname->reset (dname);
389 return fd;
391 #endif
393 /* Set callback for "set debuginfod enabled". */
395 static void
396 set_debuginfod_enabled (const char *value)
398 #if defined(HAVE_LIBDEBUGINFOD)
399 debuginfod_enabled = value;
400 #else
401 /* Disabling debuginfod when gdb is not built with it is a no-op. */
402 if (value != debuginfod_off)
403 error (NO_IMPL);
404 #endif
407 /* Get callback for "set debuginfod enabled". */
409 static const char *
410 get_debuginfod_enabled ()
412 return debuginfod_enabled;
415 /* Show callback for "set debuginfod enabled". */
417 static void
418 show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
419 const char *value)
421 gdb_printf (file,
422 _("Debuginfod functionality is currently set to "
423 "\"%s\".\n"), debuginfod_enabled);
426 /* Set callback for "set debuginfod urls". */
428 static void
429 set_debuginfod_urls (const std::string &urls)
431 #if defined(HAVE_LIBDEBUGINFOD)
432 if (setenv (DEBUGINFOD_URLS_ENV_VAR, urls.c_str (), 1) != 0)
433 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno));
434 #else
435 error (NO_IMPL);
436 #endif
439 /* Get callback for "set debuginfod urls". */
441 static const std::string&
442 get_debuginfod_urls ()
444 static std::string urls;
445 #if defined(HAVE_LIBDEBUGINFOD)
446 const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
448 if (envvar != nullptr)
449 urls = envvar;
450 else
451 urls.clear ();
452 #endif
454 return urls;
457 /* Show callback for "set debuginfod urls". */
459 static void
460 show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
461 const char *value)
463 if (value[0] == '\0')
464 gdb_printf (file, _("Debuginfod URLs have not been set.\n"));
465 else
466 gdb_printf (file, _("Debuginfod URLs are currently set to:\n%s\n"),
467 value);
470 /* Show callback for "set debuginfod verbose". */
472 static void
473 show_debuginfod_verbose_command (ui_file *file, int from_tty,
474 cmd_list_element *cmd, const char *value)
476 gdb_printf (file, _("Debuginfod verbose output is set to %s.\n"),
477 value);
480 /* Register debuginfod commands. */
482 void _initialize_debuginfod ();
483 void
484 _initialize_debuginfod ()
486 /* set/show debuginfod */
487 add_setshow_prefix_cmd ("debuginfod", class_run,
488 _("Set debuginfod options."),
489 _("Show debuginfod options."),
490 &set_debuginfod_prefix_list,
491 &show_debuginfod_prefix_list,
492 &setlist, &showlist);
494 add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
495 _("Set whether to use debuginfod."),
496 _("Show whether to use debuginfod."),
497 _("\
498 When on, enable the use of debuginfod to download missing debug info and\n\
499 source files."),
500 set_debuginfod_enabled,
501 get_debuginfod_enabled,
502 show_debuginfod_enabled,
503 &set_debuginfod_prefix_list,
504 &show_debuginfod_prefix_list);
506 /* set/show debuginfod urls */
507 add_setshow_string_noescape_cmd ("urls", class_run, _("\
508 Set the list of debuginfod server URLs."), _("\
509 Show the list of debuginfod server URLs."), _("\
510 Manage the space-separated list of debuginfod server URLs that GDB will query \
511 when missing debuginfo, executables or source files.\nThe default value is \
512 copied from the DEBUGINFOD_URLS environment variable."),
513 set_debuginfod_urls,
514 get_debuginfod_urls,
515 show_debuginfod_urls,
516 &set_debuginfod_prefix_list,
517 &show_debuginfod_prefix_list);
519 /* set/show debuginfod verbose */
520 add_setshow_zuinteger_cmd ("verbose", class_support,
521 &debuginfod_verbose, _("\
522 Set verbosity of debuginfod output."), _("\
523 Show debuginfod debugging."), _("\
524 When set to a non-zero value, display verbose output for each debuginfod \
525 query.\nTo disable, set to zero. Verbose output is displayed by default."),
526 nullptr,
527 show_debuginfod_verbose_command,
528 &set_debuginfod_prefix_list,
529 &show_debuginfod_prefix_list);