]> Git Repo - binutils.git/blob - gdb/debuginfod-support.c
Unify gdb printf functions
[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 scoped_fd
73 debuginfod_exec_query (const unsigned char *build_id,
74                        int build_id_len,
75                        const char *filename,
76                        gdb::unique_xmalloc_ptr<char> *destname)
77 {
78   return scoped_fd (-ENOSYS);
79 }
80
81 #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
82
83 #else
84 #include <elfutils/debuginfod.h>
85
86 struct user_data
87 {
88   user_data (const char *desc, const char *fname)
89     : desc (desc), fname (fname), has_printed (false)
90   { }
91
92   const char * const desc;
93   const char * const fname;
94   bool has_printed;
95 };
96
97 /* Deleter for a debuginfod_client.  */
98
99 struct debuginfod_client_deleter
100 {
101   void operator() (debuginfod_client *c)
102   {
103     debuginfod_end (c);
104   }
105 };
106
107 using debuginfod_client_up
108   = std::unique_ptr<debuginfod_client, debuginfod_client_deleter>;
109
110 static int
111 progressfn (debuginfod_client *c, long cur, long total)
112 {
113   user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
114   gdb_assert (data != nullptr);
115
116   if (check_quit_flag ())
117     {
118       gdb_printf ("Cancelling download of %s %ps...\n",
119                   data->desc,
120                   styled_string (file_name_style.style (), data->fname));
121       return 1;
122     }
123
124   if (!data->has_printed)
125     {
126       /* Include the transfer size, if available.  */
127       if (total > 0)
128         {
129           float size = 1.0f * total / 1024;
130           const char *unit = "KB";
131
132           /* If size is greater than 0.01 MB, set unit to MB.  */
133           if (size > 10.24)
134             {
135               size /= 1024;
136               unit = "MB";
137             }
138
139           gdb_printf ("Downloading %.2f %s %s %ps...\n",
140                       size, unit, data->desc,
141                       styled_string (file_name_style.style (),
142                                      data->fname));
143         }
144       else
145         gdb_printf ("Downloading %s %ps...\n", data->desc,
146                     styled_string (file_name_style.style (), data->fname));
147
148       data->has_printed = true;
149     }
150
151   return 0;
152 }
153
154 static debuginfod_client *
155 get_debuginfod_client ()
156 {
157   static debuginfod_client_up global_client;
158
159   if (global_client == nullptr)
160     {
161       global_client.reset (debuginfod_begin ());
162
163       if (global_client != nullptr)
164         debuginfod_set_progressfn (global_client.get (), progressfn);
165     }
166
167   return global_client.get ();
168 }
169
170 /* Check if debuginfod is enabled.  If configured to do so, ask the user
171    whether to enable debuginfod.  */
172
173 static bool
174 debuginfod_is_enabled ()
175 {
176   const char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
177
178   if (urls == nullptr || urls[0] == '\0'
179       || debuginfod_enabled == debuginfod_off)
180     return false;
181
182   if (debuginfod_enabled == debuginfod_ask)
183     {
184       int resp = nquery (_("\nThis GDB supports auto-downloading debuginfo " \
185                            "from the following URLs:\n%s\nEnable debuginfod " \
186                            "for this session? "),
187                          urls);
188       if (!resp)
189         {
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;
194           return false;
195         }
196
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;
201     }
202
203   return true;
204 }
205
206 /* See debuginfod-support.h  */
207
208 scoped_fd
209 debuginfod_source_query (const unsigned char *build_id,
210                          int build_id_len,
211                          const char *srcpath,
212                          gdb::unique_xmalloc_ptr<char> *destname)
213 {
214   if (!debuginfod_is_enabled ())
215     return scoped_fd (-ENOSYS);
216
217   debuginfod_client *c = get_debuginfod_client ();
218
219   if (c == nullptr)
220     return scoped_fd (-ENOMEM);
221
222   char *dname = nullptr;
223   user_data data ("source file", srcpath);
224
225   debuginfod_set_user_data (c, &data);
226   gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
227   if (target_supports_terminal_ours ())
228     {
229       term_state.emplace ();
230       target_terminal::ours ();
231     }
232
233   scoped_fd fd (debuginfod_find_source (c,
234                                         build_id,
235                                         build_id_len,
236                                         srcpath,
237                                         &dname));
238   debuginfod_set_user_data (c, nullptr);
239
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));
244
245   if (fd.get () >= 0)
246     destname->reset (dname);
247
248   return fd;
249 }
250
251 /* See debuginfod-support.h  */
252
253 scoped_fd
254 debuginfod_debuginfo_query (const unsigned char *build_id,
255                             int build_id_len,
256                             const char *filename,
257                             gdb::unique_xmalloc_ptr<char> *destname)
258 {
259   if (!debuginfod_is_enabled ())
260     return scoped_fd (-ENOSYS);
261
262   debuginfod_client *c = get_debuginfod_client ();
263
264   if (c == nullptr)
265     return scoped_fd (-ENOMEM);
266
267   char *dname = nullptr;
268   user_data data ("separate debug info for", filename);
269
270   debuginfod_set_user_data (c, &data);
271   gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
272   if (target_supports_terminal_ours ())
273     {
274       term_state.emplace ();
275       target_terminal::ours ();
276     }
277
278   scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len,
279                                            &dname));
280   debuginfod_set_user_data (c, nullptr);
281
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));
286
287   if (fd.get () >= 0)
288     destname->reset (dname);
289
290   return fd;
291 }
292
293 /* See debuginfod-support.h  */
294
295 scoped_fd
296 debuginfod_exec_query (const unsigned char *build_id,
297                        int build_id_len,
298                        const char *filename,
299                        gdb::unique_xmalloc_ptr<char> *destname)
300 {
301   if (!debuginfod_is_enabled ())
302     return scoped_fd (-ENOSYS);
303
304   debuginfod_client *c = get_debuginfod_client ();
305
306   if (c == nullptr)
307     return scoped_fd (-ENOMEM);
308
309   char *dname = nullptr;
310   user_data data ("executable for", filename);
311
312   debuginfod_set_user_data (c, &data);
313   gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
314   if (target_supports_terminal_ours ())
315     {
316       term_state.emplace ();
317       target_terminal::ours ();
318     }
319
320   scoped_fd fd (debuginfod_find_executable (c, build_id, build_id_len, &dname));
321   debuginfod_set_user_data (c, nullptr);
322
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));
328
329   if (fd.get () >= 0)
330     destname->reset (dname);
331
332   return fd;
333 }
334 #endif
335
336 /* Set callback for "set debuginfod enabled".  */
337
338 static void
339 set_debuginfod_enabled (const char *value)
340 {
341 #if defined(HAVE_LIBDEBUGINFOD)
342   debuginfod_enabled = value;
343 #else
344   error (NO_IMPL);
345 #endif
346 }
347
348 /* Get callback for "set debuginfod enabled".  */
349
350 static const char *
351 get_debuginfod_enabled ()
352 {
353   return debuginfod_enabled;
354 }
355
356 /* Show callback for "set debuginfod enabled".  */
357
358 static void
359 show_debuginfod_enabled (ui_file *file, int from_tty, cmd_list_element *cmd,
360                          const char *value)
361 {
362   gdb_printf (file,
363               _("Debuginfod functionality is currently set to "
364                 "\"%s\".\n"), debuginfod_enabled);
365 }
366
367 /* Set callback for "set debuginfod urls".  */
368
369 static void
370 set_debuginfod_urls (const std::string &urls)
371 {
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));
375 #else
376   error (NO_IMPL);
377 #endif
378 }
379
380 /* Get callback for "set debuginfod urls".  */
381
382 static const std::string&
383 get_debuginfod_urls ()
384 {
385   static std::string urls;
386 #if defined(HAVE_LIBDEBUGINFOD)
387   const char *envvar = getenv (DEBUGINFOD_URLS_ENV_VAR);
388
389   if (envvar != nullptr)
390     urls = envvar;
391   else
392     urls.clear ();
393 #endif
394
395   return urls;
396 }
397
398 /* Show callback for "set debuginfod urls".  */
399
400 static void
401 show_debuginfod_urls (ui_file *file, int from_tty, cmd_list_element *cmd,
402                       const char *value)
403 {
404   if (value[0] == '\0')
405     gdb_printf (file, _("Debuginfod URLs have not been set.\n"));
406   else
407     gdb_printf (file, _("Debuginfod URLs are currently set to:\n%s\n"),
408                 value);
409 }
410
411 /* Show callback for "set debuginfod verbose".  */
412
413 static void
414 show_debuginfod_verbose_command (ui_file *file, int from_tty,
415                                  cmd_list_element *cmd, const char *value)
416 {
417   gdb_printf (file, _("Debuginfod verbose output is set to %s.\n"),
418               value);
419 }
420
421 /* Register debuginfod commands.  */
422
423 void _initialize_debuginfod ();
424 void
425 _initialize_debuginfod ()
426 {
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);
434
435   add_setshow_enum_cmd ("enabled", class_run, debuginfod_enabled_enum,
436                         _("Set whether to use debuginfod."),
437                         _("Show whether to use debuginfod."),
438                         _("\
439 When on, enable the use of debuginfod to download missing debug info and\n\
440 source files."),
441                         set_debuginfod_enabled,
442                         get_debuginfod_enabled,
443                         show_debuginfod_enabled,
444                         &set_debuginfod_prefix_list,
445                         &show_debuginfod_prefix_list);
446
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."),
454                                    set_debuginfod_urls,
455                                    get_debuginfod_urls,
456                                    show_debuginfod_urls,
457                                    &set_debuginfod_prefix_list,
458                                    &show_debuginfod_prefix_list);
459
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."),
467                              nullptr,
468                              show_debuginfod_verbose_command,
469                              &set_debuginfod_prefix_list,
470                              &show_debuginfod_prefix_list);
471 }
This page took 0.053093 seconds and 4 git commands to generate.