GDB (xrefs)
Loading...
Searching...
No Matches
debuginfod-support.c
Go to the documentation of this file.
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. */
33
34/* maint set/show debuginfod commands. */
37
38static const char debuginfod_on[] = "on";
39static const char debuginfod_off[] = "off";
40static const char debuginfod_ask[] = "ask";
41
42static const char *debuginfod_enabled_enum[] =
43{
47 nullptr
48};
49
50static const char *debuginfod_enabled =
51#if defined(HAVE_LIBDEBUGINFOD)
53#else
55#endif
56
57/* Controls whether ELF/DWARF section downloading is enabled. */
59#if defined(HAVE_LIBDEBUGINFOD_FIND_SECTION)
60 true;
61#else
62 false;
63#endif
64
65static unsigned int debuginfod_verbose = 1;
66
67#ifndef HAVE_LIBDEBUGINFOD
68scoped_fd
69debuginfod_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
77scoped_fd
78debuginfod_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
86scoped_fd
87debuginfod_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
95scoped_fd
96debuginfod_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
109struct 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;
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
125static const char *
126get_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
146static int
147progressfn (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
192static void
193cleanup_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
202static debuginfod_client *
203get_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
234static bool
235debuginfod_is_enabled ()
236{
237 const char *urls = skip_spaces (getenv (DEBUGINFOD_URLS_ENV_VAR));
238
240 || urls == nullptr
241 || *urls == '\0')
242 return false;
243
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
265 (_(" <%ps>\n"),
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"));
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"));
288 }
289
290 return true;
291}
292
293/* Print the result of the most recent attempted download. */
294
295static void
296print_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,
303}
304
305/* See debuginfod-support.h */
306
307scoped_fd
308debuginfod_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);
330 {
331 term_state.emplace ();
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
353scoped_fd
354debuginfod_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);
376 {
377 term_state.emplace ();
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
396scoped_fd
397debuginfod_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);
419 {
420 term_state.emplace ();
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
439scoped_fd
440debuginfod_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);
467 {
468 term_state.emplace ();
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
491static void
493{
494#if defined(HAVE_LIBDEBUGINFOD)
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
505static const char *
510
511/* Show callback for "set debuginfod enabled". */
512
513static void
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
524static void
525set_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
537static const std::string&
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
555static void
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
568static void
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
578static void
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
588}
589
590/* Get callback for "maint set debuginfod download-sections". */
591
592static bool
597
598/* Register debuginfod commands. */
599
601void
603{
604 /* set/show debuginfod */
605 add_setshow_prefix_cmd ("debuginfod", class_run,
606 _("Set debuginfod options."),
607 _("Show debuginfod options."),
610 &setlist, &showlist);
611
613 _("Set whether to use debuginfod."),
614 _("Show whether to use debuginfod."),
615 _("\
616When set to \"on\", enable the use of debuginfod to download missing\n\
617debug info and source files. GDB may also download components of debug\n\
618info instead of entire files. \"off\" disables the use of debuginfod.\n\
619When set to \"ask\", prompt whether to enable or disable debuginfod." ),
625
626 /* set/show debuginfod urls */
628Set the list of debuginfod server URLs."), _("\
629Show the list of debuginfod server URLs."), _("\
630Manage the space-separated list of debuginfod server URLs that GDB will query \
631when missing debuginfo, executables or source files.\nThe default value is \
632copied from the DEBUGINFOD_URLS environment variable."),
638
639 /* set/show debuginfod verbose */
641 &debuginfod_verbose, _("\
642Set verbosity of debuginfod output."), _("\
643Show debuginfod debugging."), _("\
644When set to a non-zero value, display verbose output for each debuginfod \
645query.\nTo disable, set to zero. Verbose output is displayed by default."),
646 nullptr,
650
651 /* maint set/show debuginfod. */
653 _("Set debuginfod specific variables."),
654 _("Show debuginfod specific variables."),
658
659 /* maint set/show debuginfod download-sections. */
660 add_setshow_boolean_cmd ("download-sections", class_maintenance, _("\
661Set whether debuginfod may download individual ELF/DWARF sections."), _("\
662Show whether debuginfod may download individual ELF/DWARF sections."), _("\
663When enabled, debuginfod may attempt to download individual ELF/DWARF \
664sections from debug info files.\nIf disabled, only whole debug info files \
665may be downloaded."),
668 nullptr,
671}
ui_file_style style() const
Definition cli-style.c:169
static void ours()
Definition target.c:1070
struct cmd_list_element * showlist
Definition cli-cmds.c:127
struct cmd_list_element * setlist
Definition cli-cmds.c:119
struct cmd_list_element * maintenance_show_cmdlist
Definition maint.c:752
struct cmd_list_element * maintenance_set_cmdlist
Definition maint.c:751
set_show_commands add_setshow_enum_cmd(const char *name, enum command_class theclass, const char *const *enumlist, const char **var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
Definition cli-decode.c:688
set_show_commands add_setshow_prefix_cmd(const char *name, command_class theclass, const char *set_doc, const char *show_doc, cmd_list_element **set_subcommands_list, cmd_list_element **show_subcommands_list, cmd_list_element **set_list, cmd_list_element **show_list)
Definition cli-decode.c:428
set_show_commands add_setshow_boolean_cmd(const char *name, enum command_class theclass, bool *var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
Definition cli-decode.c:809
set_show_commands add_setshow_string_noescape_cmd(const char *name, enum command_class theclass, std::string *var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
Definition cli-decode.c:953
set_show_commands add_setshow_zuinteger_cmd(const char *name, enum command_class theclass, unsigned int *var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
cli_style_option file_name_style
@ class_maintenance
Definition command.h:65
@ class_support
Definition command.h:58
@ class_run
Definition command.h:54
static const char debuginfod_on[]
static cmd_list_element * set_debuginfod_prefix_list
static void show_debuginfod_urls(ui_file *file, int from_tty, cmd_list_element *cmd, const char *value)
static void set_debuginfod_enabled(const char *value)
static unsigned int debuginfod_verbose
static const char * debuginfod_enabled
scoped_fd debuginfod_debuginfo_query(const unsigned char *build_id, int build_id_len, const char *filename, gdb::unique_xmalloc_ptr< char > *destname)
#define NO_IMPL
void _initialize_debuginfod()
static bool maint_get_debuginfod_download_sections()
scoped_fd debuginfod_exec_query(const unsigned char *build_id, int build_id_len, const char *filename, gdb::unique_xmalloc_ptr< char > *destname)
scoped_fd debuginfod_section_query(const unsigned char *build_id, int build_id_len, const char *filename, const char *section_name, gdb::unique_xmalloc_ptr< char > *destname)
static const char debuginfod_ask[]
scoped_fd debuginfod_source_query(const unsigned char *build_id, int build_id_len, const char *srcpath, gdb::unique_xmalloc_ptr< char > *destname)
static void show_debuginfod_verbose_command(ui_file *file, int from_tty, cmd_list_element *cmd, const char *value)
static const char * get_debuginfod_enabled()
static void set_debuginfod_urls(const std::string &urls)
static const char debuginfod_off[]
static bool debuginfod_download_sections
static cmd_list_element * show_debuginfod_prefix_list
static void maint_set_debuginfod_download_sections(bool value)
static cmd_list_element * maint_show_debuginfod_cmdlist
static void show_debuginfod_enabled(ui_file *file, int from_tty, cmd_list_element *cmd, const char *value)
static const char * debuginfod_enabled_enum[]
static const std::string & get_debuginfod_urls()
static cmd_list_element * maint_set_debuginfod_cmdlist
int check_quit_flag(void)
Definition extension.c:857
size_t size
Definition go32-nat.c:239
int value
Definition py-param.c:79
Definition value.h:130
bool target_supports_terminal_ours(void)
Definition target.c:1114
static styled_string_s * styled_string(const ui_file_style &style, const char *str, styled_string_s &&tmp={})
Definition ui-out.h:151
#define current_uiout
Definition ui-out.h:40
int nquery(const char *ctlstr,...)
Definition utils.c:908
void fprintf_styled(struct ui_file *stream, const ui_file_style &style, const char *format,...)
Definition utils.c:1898
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1886