]> Git Repo - binutils.git/blob - gdb/debuginfod-support.c
gdb: remove SYMBOL_CLASS macro, add getter
[binutils.git] / gdb / debuginfod-support.c
1 /* debuginfod utilities for GDB.
2    Copyright (C) 2020-2022 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 <errno.h>
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"
26 #include "target.h"
27
28 /* Set/show debuginfod commands.  */
29 static cmd_list_element *set_debuginfod_prefix_list;
30 static cmd_list_element *show_debuginfod_prefix_list;
31
32 static const char debuginfod_on[] = "on";
33 static const char debuginfod_off[] = "off";
34 static const char debuginfod_ask[] = "ask";
35
36 static const char *debuginfod_enabled_enum[] =
37 {
38   debuginfod_on,
39   debuginfod_off,
40   debuginfod_ask,
41   nullptr
42 };
43
44 static const char *debuginfod_enabled =
45 #if defined(HAVE_LIBDEBUGINFOD)
46   debuginfod_ask;
47 #else
48   debuginfod_off;
49 #endif
50
51 static unsigned int debuginfod_verbose = 1;
52
53 #ifndef HAVE_LIBDEBUGINFOD
54 scoped_fd
55 debuginfod_source_query (const unsigned char *build_id,
56                          int build_id_len,
57                          const char *srcpath,
58                          gdb::unique_xmalloc_ptr<char> *destname)
59 {
60   return scoped_fd (-ENOSYS);
61 }
62
63 scoped_fd
64 debuginfod_debuginfo_query (const unsigned char *build_id,
65                             int build_id_len,
66                             const char *filename,
67                             gdb::unique_xmalloc_ptr<char> *destname)
68 {
69   return scoped_fd (-ENOSYS);
70 }
71
72 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
73
74 #else
75 #include <elfutils/debuginfod.h>
76
77 struct user_data
78 {
79   user_data (const char *desc, const char *fname)
80     : desc (desc), fname (fname)
81   { }
82
83   const char * const desc;
84   const char * const fname;
85   gdb::optional<ui_out::progress_meter> meter;
86 };
87
88 /* Deleter for a debuginfod_client.  */
89
90 struct debuginfod_client_deleter
91 {
92   void operator() (debuginfod_client *c)
93   {
94     debuginfod_end (c);
95   }
96 };
97
98 using debuginfod_client_up
99   = std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
100
101 static int
102 progressfn (debuginfod_client *c, long cur, long total)
103 {
104   user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
105   gdb_assert (data != nullptr);
106
107   if (check_quit_flag ())
108     {
109       printf_filtered ("Cancelling download of %s %ps...\n",
110                        data->desc,
111                        styled_string (file_name_style.style (), data->fname));
112       return 1;
113     }
114
115   if (total == 0)
116     return 0;
117
118   if (!data->meter.has_value ())
119     {
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 (),
124                       "%s",
125                       data->fname);
126       std::string message
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);
130     }
131
132   current_uiout->progress ((double)cur / (double)total);
133
134   return 0;
135 }
136
137 static debuginfod_client *
138 get_debuginfod_client ()
139 {
140   static debuginfod_client_up global_client;
141
142   if (global_client == nullptr)
143     {
144       global_client.reset (debuginfod_begin ());
145
146       if (global_client != nullptr)
147         debuginfod_set_progressfn (global_client.get (), progressfn);
148     }
149
150   return global_client.get ();
151 }
152
153 /* Check if debuginfod is enabled.  If configured to do so, ask the user
154    whether to enable debuginfod.  */
155
156 static bool
157 debuginfod_is_enabled ()
158 {
159   const char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
160
161   if (urls == nullptr || urls[0] == '\0'
162       || debuginfod_enabled == debuginfod_off)
163     return false;
164
165   if (debuginfod_enabled == debuginfod_ask)
166     {
167       int resp = nquery (_("\nThis GDB supports auto-downloading debuginfo " \
168                            "from the following URLs:\n%s\nEnable debuginfod " \
169                            "for this session? "),
170                          urls);
171       if (!resp)
172         {
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;
177           return false;
178         }
179
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;
184     }
185
186   return true;
187 }
188
189 /* See debuginfod-support.h  */
190
191 scoped_fd
192 debuginfod_source_query (const unsigned char *build_id,
193                          int build_id_len,
194                          const char *srcpath,
195                          gdb::unique_xmalloc_ptr<char> *destname)
196 {
197   if (!debuginfod_is_enabled ())
198     return scoped_fd (-ENOSYS);
199
200   debuginfod_client *c = get_debuginfod_client ();
201
202   if (c == nullptr)
203     return scoped_fd (-ENOMEM);
204
205   user_data data ("source file", srcpath);
206
207   debuginfod_set_user_data (c, &data);
208   gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
209   if (target_supports_terminal_ours ())
210     {
211       term_state.emplace ();
212       target_terminal::ours ();
213     }
214
215   scoped_fd fd (debuginfod_find_source (c,
216                                         build_id,
217                                         build_id_len,
218                                         srcpath,
219                                         nullptr));
220   debuginfod_set_user_data (c, nullptr);
221
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));
226
227   if (fd.get () >= 0)
228     *destname = make_unique_xstrdup (srcpath);
229
230   return fd;
231 }
232
233 /* See debuginfod-support.h  */
234
235 scoped_fd
236 debuginfod_debuginfo_query (const unsigned char *build_id,
237                             int build_id_len,
238                             const char *filename,
239                             gdb::unique_xmalloc_ptr<char> *destname)
240 {
241   if (!debuginfod_is_enabled ())
242     return scoped_fd (-ENOSYS);
243
244   debuginfod_client *c = get_debuginfod_client ();
245
246   if (c == nullptr)
247     return scoped_fd (-ENOMEM);
248
249   char *dname = nullptr;
250   user_data data ("separate debug info for", filename);
251
252   debuginfod_set_user_data (c, &data);
253   gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
254   if (target_supports_terminal_ours ())
255     {
256       term_state.emplace ();
257       target_terminal::ours ();
258     }
259
260   scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
261                                            &dname));
262   debuginfod_set_user_data (c, nullptr);
263
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));
268
269   if (fd.get () >= 0)
270     destname->reset (dname);
271
272   return fd;
273 }
274 #endif
275
276 /* Set callback for "set debuginfod enabled".  */
277
278 static void
279 set_debuginfod_enabled (const char *value)
280 {
281 #if defined(HAVE_LIBDEBUGINFOD)
282   debuginfod_enabled = value;
283 #else
284   error (NO_IMPL);
285 #endif
286 }
287
288 /* Get callback for "set debuginfod enabled".  */
289
290 static const char *
291 get_debuginfod_enabled ()
292 {
293   return debuginfod_enabled;
294 }
295
296 /* Show callback for "set debuginfod enabled".  */
297
298 static void
299 show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
300                          const char *value)
301 {
302   fprintf_filtered (file,
303                     _("Debuginfod functionality is currently set to "
304                       "\"%s\".\n"), debuginfod_enabled);
305 }
306
307 /* Set callback for "set debuginfod urls".  */
308
309 static void
310 set_debuginfod_urls (const std::string &urls)
311 {
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));
315 #else
316   error (NO_IMPL);
317 #endif
318 }
319
320 /* Get callback for "set debuginfod urls".  */
321
322 static const std::string&
323 get_debuginfod_urls ()
324 {
325   static std::string urls;
326 #if defined(HAVE_LIBDEBUGINFOD)
327   const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
328
329   if (envvar != nullptr)
330     urls = envvar;
331   else
332     urls.clear ();
333 #endif
334
335   return urls;
336 }
337
338 /* Show callback for "set debuginfod urls".  */
339
340 static void
341 show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
342                       const char *value)
343 {
344   if (value[0] == '\0')
345     fprintf_filtered (file, _("Debuginfod URLs have not been set.\n"));
346   else
347     fprintf_filtered (file, _("Debuginfod URLs are currently set to:\n%s\n"),
348                       value);
349 }
350
351 /* Show callback for "set debuginfod verbose".  */
352
353 static void
354 show_debuginfod_verbose_command (ui_file *file, int from_tty,
355                                  cmd_list_element *cmd, const char *value)
356 {
357   fprintf_filtered (file, _("Debuginfod verbose output is set to %s.\n"),
358                     value);
359 }
360
361 /* Register debuginfod commands.  */
362
363 void _initialize_debuginfod ();
364 void
365 _initialize_debuginfod ()
366 {
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);
374
375   add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
376                         _("Set whether to use debuginfod."),
377                         _("Show whether to use debuginfod."),
378                         _("\
379 When on, enable the use of debuginfod to download missing debug info and\n\
380 source files."),
381                         set_debuginfod_enabled,
382                         get_debuginfod_enabled,
383                         show_debuginfod_enabled,
384                         &set_debuginfod_prefix_list,
385                         &show_debuginfod_prefix_list);
386
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."),
394                                    set_debuginfod_urls,
395                                    get_debuginfod_urls,
396                                    show_debuginfod_urls,
397                                    &set_debuginfod_prefix_list,
398                                    &show_debuginfod_prefix_list);
399
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."),
407                              nullptr,
408                              show_debuginfod_verbose_command,
409                              &set_debuginfod_prefix_list,
410                              &show_debuginfod_prefix_list);
411 }
This page took 0.049245 seconds and 4 git commands to generate.