Remove path name from test case
[binutils-gdb.git] / gdb / debuginfod-support.c
1 /* debuginfod utilities for GDB.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
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.
10
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.
15
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/>. */
18
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"
29
30 /* Set/show debuginfod commands. */
31 static cmd_list_element *set_debuginfod_prefix_list;
32 static cmd_list_element *show_debuginfod_prefix_list;
33
34 /* maint set/show debuginfod commands. */
35 static cmd_list_element *maint_set_debuginfod_cmdlist;
36 static cmd_list_element *maint_show_debuginfod_cmdlist;
37
38 static const char debuginfod_on[] = "on";
39 static const char debuginfod_off[] = "off";
40 static const char debuginfod_ask[] = "ask";
41
42 static const char *debuginfod_enabled_enum[] =
43 {
44 debuginfod_on,
45 debuginfod_off,
46 debuginfod_ask,
47 nullptr
48 };
49
50 static const char *debuginfod_enabled =
51 #if defined(HAVE_LIBDEBUGINFOD)
52 debuginfod_ask;
53 #else
54 debuginfod_off;
55 #endif
56
57 /* Controls whether ELF/DWARF section downloading is enabled. */
58 static bool debuginfod_download_sections =
59 #if defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
60 true;
61 #else
62 false;
63 #endif
64
65 static unsigned int debuginfod_verbose = 1;
66
67 #ifndef HAVE_LIBDEBUGINFOD
68 scoped_fd
69 debuginfod_source_query (const unsigned char *build_id,
70 int build_id_len,
71 const char *srcpath,
72 gdb::unique_xmalloc_ptr<char> *destname)
73 {
74 return scoped_fd (-ENOSYS);
75 }
76
77 scoped_fd
78 debuginfod_debuginfo_query (const unsigned char *build_id,
79 int build_id_len,
80 const char *filename,
81 gdb::unique_xmalloc_ptr<char> *destname)
82 {
83 return scoped_fd (-ENOSYS);
84 }
85
86 scoped_fd
87 debuginfod_exec_query (const unsigned char *build_id,
88 int build_id_len,
89 const char *filename,
90 gdb::unique_xmalloc_ptr<char> *destname)
91 {
92 return scoped_fd (-ENOSYS);
93 }
94
95 scoped_fd
96 debuginfod_section_query (const unsigned char *build_id,
97 int build_id_len,
98 const char *filename,
99 const char *section_name,
100 gdb::unique_xmalloc_ptr<char> *destname)
101 {
102 return scoped_fd (-ENOSYS);
103 }
104 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
105
106 #else
107 #include <elfutils/debuginfod.h>
108
109 struct user_data
110 {
111 user_data (const char *desc, const char *fname)
112 : desc (desc), fname (fname)
113 { }
114
115 const char * const desc;
116 const char * const fname;
117 ui_out::progress_update progress;
118 };
119
120 /* Convert SIZE into a unit suitable for use with progress updates.
121 SIZE should in given in bytes and will be converted into KB, MB, GB
122 or remain unchanged. UNIT will be set to "B", "KB", "MB" or "GB"
123 accordingly. */
124
125 static const char *
126 get_size_and_unit (double &size)
127 {
128 if (size < 1024)
129 /* If size is less than 1 KB then set unit to B. */
130 return "B";
131
132 size /= 1024;
133 if (size < 1024)
134 /* If size is less than 1 MB then set unit to KB. */
135 return "K";
136
137 size /= 1024;
138 if (size < 1024)
139 /* If size is less than 1 GB then set unit to MB. */
140 return "M";
141
142 size /= 1024;
143 return "G";
144 }
145
146 static int
147 progressfn (debuginfod_client *c, long cur, long total)
148 {
149 user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
150 gdb_assert (data != nullptr);
151
152 string_file styled_fname (current_uiout->can_emit_style_escape ());
153 fprintf_styled (&styled_fname, file_name_style.style (), "%s",
154 data->fname);
155
156 if (check_quit_flag ())
157 {
158 gdb_printf ("Cancelling download of %s %s...\n",
159 data->desc, styled_fname.c_str ());
160 return 1;
161 }
162
163 if (debuginfod_verbose == 0)
164 return 0;
165
166 /* Print progress update. Include the transfer size if available. */
167 if (total > 0)
168 {
169 /* Transfer size is known. */
170 double howmuch = (double) cur / (double) total;
171
172 if (howmuch >= 0.0 && howmuch <= 1.0)
173 {
174 double d_total = (double) total;
175 const char *unit = get_size_and_unit (d_total);
176 std::string msg = string_printf ("Downloading %0.2f %s %s %s",
177 d_total, unit, data->desc,
178 styled_fname.c_str ());
179 data->progress.update_progress (msg, unit, howmuch, d_total);
180 return 0;
181 }
182 }
183
184 std::string msg = string_printf ("Downloading %s %s",
185 data->desc, styled_fname.c_str ());
186 data->progress.update_progress (msg);
187 return 0;
188 }
189
190 /* Cleanup ARG, which is a debuginfod_client pointer. */
191
192 static void
193 cleanup_debuginfod_client (void *arg)
194 {
195 debuginfod_client *client = static_cast<debuginfod_client *> (arg);
196 debuginfod_end (client);
197 }
198
199 /* Return a pointer to the single global debuginfod_client, initialising it
200 first if needed. */
201
202 static debuginfod_client *
203 get_debuginfod_client ()
204 {
205 static debuginfod_client *global_client = nullptr;
206
207 if (global_client == nullptr)
208 {
209 global_client = debuginfod_begin ();
210
211 if (global_client != nullptr)
212 {
213 /* It is important that we cleanup the debuginfod_client object
214 before calling exit. Some of the libraries used by debuginfod
215 make use of at_exit handlers to perform cleanup.
216
217 If we wrapped the debuginfod_client in a unique_ptr and relied
218 on its destructor to cleanup then this would be run as part of
219 the global C++ object destructors, which is after the at_exit
220 handlers, which is too late.
221
222 So instead, we make use of GDB's final cleanup mechanism. */
223 make_final_cleanup (cleanup_debuginfod_client, global_client);
224 debuginfod_set_progressfn (global_client, progressfn);
225 }
226 }
227
228 return global_client;
229 }
230
231 /* Check if debuginfod is enabled. If configured to do so, ask the user
232 whether to enable debuginfod. */
233
234 static bool
235 debuginfod_is_enabled ()
236 {
237 const char *urls = skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR));
238
239 if (debuginfod_enabled == debuginfod_off
240 || urls == nullptr
241 || *urls == '\0')
242 return false;
243
244 if (debuginfod_enabled == debuginfod_ask)
245 {
246 gdb_printf (_("\nThis GDB supports auto-downloading debuginfo " \
247 "from the following URLs:\n"));
248
249 gdb::string_view url_view (urls);
250 while (true)
251 {
252 size_t off = url_view.find_first_not_of (' ');
253 if (off == gdb::string_view::npos)
254 break;
255 url_view = url_view.substr (off);
256 /* g++ 11.2.1 on s390x, g++ 11.3.1 on ppc64le and g++ 11 on
257 hppa seem convinced url_view might be of SIZE_MAX length.
258 And so complains because the length of an array can only
259 be PTRDIFF_MAX. */
260 DIAGNOSTIC_PUSH
261 DIAGNOSTIC_IGNORE_STRINGOP_OVERREAD
262 off = url_view.find_first_of (' ');
263 DIAGNOSTIC_POP
264 gdb_printf
265 (_(" <%ps>\n"),
266 styled_string (file_name_style.style (),
267 gdb::to_string (url_view.substr (0,
268 off)).c_str ()));
269 if (off == gdb::string_view::npos)
270 break;
271 url_view = url_view.substr (off);
272 }
273
274 int resp = nquery (_("Enable debuginfod for this session? "));
275 if (!resp)
276 {
277 gdb_printf (_("Debuginfod has been disabled.\nTo make this " \
278 "setting permanent, add \'set debuginfod " \
279 "enabled off\' to .gdbinit.\n"));
280 debuginfod_enabled = debuginfod_off;
281 return false;
282 }
283
284 gdb_printf (_("Debuginfod has been enabled.\nTo make this " \
285 "setting permanent, add \'set debuginfod enabled " \
286 "on\' to .gdbinit.\n"));
287 debuginfod_enabled = debuginfod_on;
288 }
289
290 return true;
291 }
292
293 /* Print the result of the most recent attempted download. */
294
295 static void
296 print_outcome (int fd, const char *desc, const char *fname)
297 {
298 if (fd < 0 && fd != -ENOENT)
299 gdb_printf (_("Download failed: %s. Continuing without %s %ps.\n"),
300 safe_strerror (-fd),
301 desc,
302 styled_string (file_name_style.style (), fname));
303 }
304
305 /* See debuginfod-support.h */
306
307 scoped_fd
308 debuginfod_source_query (const unsigned char *build_id,
309 int build_id_len,
310 const char *srcpath,
311 gdb::unique_xmalloc_ptr<char> *destname)
312 {
313 if (!debuginfod_is_enabled ())
314 return scoped_fd (-ENOSYS);
315
316 debuginfod_client *c = get_debuginfod_client ();
317
318 if (c == nullptr)
319 return scoped_fd (-ENOMEM);
320
321 char *dname = nullptr;
322 scoped_fd fd;
323 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
324
325 {
326 user_data data ("source file", srcpath);
327
328 debuginfod_set_user_data (c, &data);
329 if (target_supports_terminal_ours ())
330 {
331 term_state.emplace ();
332 target_terminal::ours ();
333 }
334
335 fd = scoped_fd (debuginfod_find_source (c,
336 build_id,
337 build_id_len,
338 srcpath,
339 &dname));
340 debuginfod_set_user_data (c, nullptr);
341 }
342
343 print_outcome (fd.get (), "source file", srcpath);
344
345 if (fd.get () >= 0)
346 destname->reset (dname);
347
348 return fd;
349 }
350
351 /* See debuginfod-support.h */
352
353 scoped_fd
354 debuginfod_debuginfo_query (const unsigned char *build_id,
355 int build_id_len,
356 const char *filename,
357 gdb::unique_xmalloc_ptr<char> *destname)
358 {
359 if (!debuginfod_is_enabled ())
360 return scoped_fd (-ENOSYS);
361
362 debuginfod_client *c = get_debuginfod_client ();
363
364 if (c == nullptr)
365 return scoped_fd (-ENOMEM);
366
367 char *dname = nullptr;
368 scoped_fd fd;
369 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
370
371 {
372 user_data data ("separate debug info for", filename);
373
374 debuginfod_set_user_data (c, &data);
375 if (target_supports_terminal_ours ())
376 {
377 term_state.emplace ();
378 target_terminal::ours ();
379 }
380
381 fd = scoped_fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
382 &dname));
383 debuginfod_set_user_data (c, nullptr);
384 }
385
386 print_outcome (fd.get (), "separate debug info for", filename);
387
388 if (fd.get () >= 0)
389 destname->reset (dname);
390
391 return fd;
392 }
393
394 /* See debuginfod-support.h */
395
396 scoped_fd
397 debuginfod_exec_query (const unsigned char *build_id,
398 int build_id_len,
399 const char *filename,
400 gdb::unique_xmalloc_ptr<char> *destname)
401 {
402 if (!debuginfod_is_enabled ())
403 return scoped_fd (-ENOSYS);
404
405 debuginfod_client *c = get_debuginfod_client ();
406
407 if (c == nullptr)
408 return scoped_fd (-ENOMEM);
409
410 char *dname = nullptr;
411 scoped_fd fd;
412 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
413
414 {
415 user_data data ("executable for", filename);
416
417 debuginfod_set_user_data (c, &data);
418 if (target_supports_terminal_ours ())
419 {
420 term_state.emplace ();
421 target_terminal::ours ();
422 }
423
424 fd = scoped_fd (debuginfod_find_executable (c, build_id, build_id_len,
425 &dname));
426 debuginfod_set_user_data (c, nullptr);
427 }
428
429 print_outcome (fd.get (), "executable for", filename);
430
431 if (fd.get () >= 0)
432 destname->reset (dname);
433
434 return fd;
435 }
436
437 /* See debuginfod-support.h */
438
439 scoped_fd
440 debuginfod_section_query (const unsigned char *build_id,
441 int build_id_len,
442 const char *filename,
443 const char *section_name,
444 gdb::unique_xmalloc_ptr<char> *destname)
445 {
446 #if !defined (HAVE_LIBDEBUGINFOD_FIND_SECTION)
447 return scoped_fd (-ENOSYS);
448 #else
449
450 if (!debuginfod_download_sections || !debuginfod_is_enabled ())
451 return scoped_fd (-ENOSYS);
452
453 debuginfod_client *c = get_debuginfod_client ();
454
455 if (c == nullptr)
456 return scoped_fd (-ENOMEM);
457
458 char *dname = nullptr;
459 std::string desc = std::string ("section ") + section_name + " for";
460 scoped_fd fd;
461 gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
462
463 {
464 user_data data (desc.c_str (), filename);
465 debuginfod_set_user_data (c, &data);
466 if (target_supports_terminal_ours ())
467 {
468 term_state.emplace ();
469 target_terminal::ours ();
470 }
471
472 fd = scoped_fd (debuginfod_find_section (c, build_id, build_id_len,
473 section_name, &dname));
474 debuginfod_set_user_data (c, nullptr);
475 }
476
477 print_outcome (fd.get (), desc.c_str (), filename);
478 gdb_assert (destname != nullptr);
479
480 if (fd.get () >= 0)
481 destname->reset (dname);
482
483 return fd;
484 #endif /* HAVE_LIBDEBUGINFOD_FIND_SECTION */
485 }
486
487 #endif
488
489 /* Set callback for "set debuginfod enabled". */
490
491 static void
492 set_debuginfod_enabled (const char *value)
493 {
494 #if defined(HAVE_LIBDEBUGINFOD)
495 debuginfod_enabled = value;
496 #else
497 /* Disabling debuginfod when gdb is not built with it is a no-op. */
498 if (value != debuginfod_off)
499 error (NO_IMPL);
500 #endif
501 }
502
503 /* Get callback for "set debuginfod enabled". */
504
505 static const char *
506 get_debuginfod_enabled ()
507 {
508 return debuginfod_enabled;
509 }
510
511 /* Show callback for "set debuginfod enabled". */
512
513 static void
514 show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
515 const char *value)
516 {
517 gdb_printf (file,
518 _("Debuginfod functionality is currently set to "
519 "\"%s\".\n"), debuginfod_enabled);
520 }
521
522 /* Set callback for "set debuginfod urls". */
523
524 static void
525 set_debuginfod_urls (const std::string &urls)
526 {
527 #if defined(HAVE_LIBDEBUGINFOD)
528 if (setenv (DEBUGINFOD_URLS_ENV_VAR, urls.c_str (), 1) != 0)
529 warning (_("Unable to set debuginfod URLs: %s"), safe_strerror (errno));
530 #else
531 error (NO_IMPL);
532 #endif
533 }
534
535 /* Get callback for "set debuginfod urls". */
536
537 static const std::string&
538 get_debuginfod_urls ()
539 {
540 static std::string urls;
541 #if defined(HAVE_LIBDEBUGINFOD)
542 const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
543
544 if (envvar != nullptr)
545 urls = envvar;
546 else
547 urls.clear ();
548 #endif
549
550 return urls;
551 }
552
553 /* Show callback for "set debuginfod urls". */
554
555 static void
556 show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
557 const char *value)
558 {
559 if (value[0] == '\0')
560 gdb_printf (file, _("Debuginfod URLs have not been set.\n"));
561 else
562 gdb_printf (file, _("Debuginfod URLs are currently set to:\n%s\n"),
563 value);
564 }
565
566 /* Show callback for "set debuginfod verbose". */
567
568 static void
569 show_debuginfod_verbose_command (ui_file *file, int from_tty,
570 cmd_list_element *cmd, const char *value)
571 {
572 gdb_printf (file, _("Debuginfod verbose output is set to %s.\n"),
573 value);
574 }
575
576 /* Set callback for "maint set debuginfod download-sections". */
577
578 static void
579 maint_set_debuginfod_download_sections (bool value)
580 {
581 #if !defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
582 if (value)
583 error (_("Support for section downloading is not compiled into GDB. " \
584 "Defaulting to \"off\"."));
585 #endif
586
587 debuginfod_download_sections = value;
588 }
589
590 /* Get callback for "maint set debuginfod download-sections". */
591
592 static bool
593 maint_get_debuginfod_download_sections ()
594 {
595 return debuginfod_download_sections;
596 }
597
598 /* Register debuginfod commands. */
599
600 void _initialize_debuginfod ();
601 void
602 _initialize_debuginfod ()
603 {
604 /* set/show debuginfod */
605 add_setshow_prefix_cmd ("debuginfod", class_run,
606 _("Set debuginfod options."),
607 _("Show debuginfod options."),
608 &set_debuginfod_prefix_list,
609 &show_debuginfod_prefix_list,
610 &setlist, &showlist);
611
612 add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
613 _("Set whether to use debuginfod."),
614 _("Show whether to use debuginfod."),
615 _("\
616 When set to \"on\", enable the use of debuginfod to download missing\n\
617 debug info and source files. GDB may also download components of debug\n\
618 info instead of entire files. \"off\" disables the use of debuginfod.\n\
619 When set to \"ask\", prompt whether to enable or disable debuginfod." ),
620 set_debuginfod_enabled,
621 get_debuginfod_enabled,
622 show_debuginfod_enabled,
623 &set_debuginfod_prefix_list,
624 &show_debuginfod_prefix_list);
625
626 /* set/show debuginfod urls */
627 add_setshow_string_noescape_cmd ("urls", class_run, _("\
628 Set the list of debuginfod server URLs."), _("\
629 Show the list of debuginfod server URLs."), _("\
630 Manage the space-separated list of debuginfod server URLs that GDB will query \
631 when missing debuginfo, executables or source files.\nThe default value is \
632 copied from the DEBUGINFOD_URLS environment variable."),
633 set_debuginfod_urls,
634 get_debuginfod_urls,
635 show_debuginfod_urls,
636 &set_debuginfod_prefix_list,
637 &show_debuginfod_prefix_list);
638
639 /* set/show debuginfod verbose */
640 add_setshow_zuinteger_cmd ("verbose", class_support,
641 &debuginfod_verbose, _("\
642 Set verbosity of debuginfod output."), _("\
643 Show debuginfod debugging."), _("\
644 When set to a non-zero value, display verbose output for each debuginfod \
645 query.\nTo disable, set to zero. Verbose output is displayed by default."),
646 nullptr,
647 show_debuginfod_verbose_command,
648 &set_debuginfod_prefix_list,
649 &show_debuginfod_prefix_list);
650
651 /* maint set/show debuginfod. */
652 add_setshow_prefix_cmd ("debuginfod", class_maintenance,
653 _("Set debuginfod specific variables."),
654 _("Show debuginfod specific variables."),
655 &maint_set_debuginfod_cmdlist,
656 &maint_show_debuginfod_cmdlist,
657 &maintenance_set_cmdlist, &maintenance_show_cmdlist);
658
659 /* maint set/show debuginfod download-sections. */
660 add_setshow_boolean_cmd ("download-sections", class_maintenance, _("\
661 Set whether debuginfod may download individual ELF/DWARF sections."), _("\
662 Show whether debuginfod may download individual ELF/DWARF sections."), _("\
663 When enabled, debuginfod may attempt to download individual ELF/DWARF \
664 sections from debug info files.\nIf disabled, only whole debug info files \
665 may be downloaded."),
666 maint_set_debuginfod_download_sections,
667 maint_get_debuginfod_download_sections,
668 nullptr,
669 &maint_set_debuginfod_cmdlist,
670 &maint_show_debuginfod_cmdlist);
671 }