1 /* debuginfod utilities for GDB.
2    Copyright (C) 2020 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 "cli/cli-style.h"
22 #include "gdbsupport/scoped_fd.h"
23 #include "debuginfod-support.h"
24 
25 #ifndef HAVE_LIBDEBUGINFOD
26 scoped_fd
debuginfod_source_query(const unsigned char * build_id,int build_id_len,const char * srcpath,gdb::unique_xmalloc_ptr<char> * destname)27 debuginfod_source_query (const unsigned char *build_id,
28 			 int build_id_len,
29 			 const char *srcpath,
30 			 gdb::unique_xmalloc_ptr<char> *destname)
31 {
32   return scoped_fd (-ENOSYS);
33 }
34 
35 scoped_fd
debuginfod_debuginfo_query(const unsigned char * build_id,int build_id_len,const char * filename,gdb::unique_xmalloc_ptr<char> * destname)36 debuginfod_debuginfo_query (const unsigned char *build_id,
37 			    int build_id_len,
38 			    const char *filename,
39 			    gdb::unique_xmalloc_ptr<char> *destname)
40 {
41   return scoped_fd (-ENOSYS);
42 }
43 #else
44 #include <elfutils/debuginfod.h>
45 
46 struct user_data
47 {
user_datauser_data48   user_data (const char *desc, const char *fname)
49     : desc (desc), fname (fname), has_printed (false)
50   { }
51 
52   const char * const desc;
53   const char * const fname;
54   bool has_printed;
55 };
56 
57 static int
progressfn(debuginfod_client * c,long cur,long total)58 progressfn (debuginfod_client *c, long cur, long total)
59 {
60   user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c));
61 
62   if (check_quit_flag ())
63     {
64       printf_filtered ("Cancelling download of %s %ps...\n",
65 		       data->desc,
66 		       styled_string (file_name_style.style (), data->fname));
67       return 1;
68     }
69 
70   if (!data->has_printed && total != 0)
71     {
72       /* Print this message only once.  */
73       data->has_printed = true;
74       printf_filtered ("Downloading %s %ps...\n",
75 		       data->desc,
76 		       styled_string (file_name_style.style (), data->fname));
77     }
78 
79   return 0;
80 }
81 
82 static debuginfod_client *
debuginfod_init()83 debuginfod_init ()
84 {
85   debuginfod_client *c = debuginfod_begin ();
86 
87   if (c != nullptr)
88     debuginfod_set_progressfn (c, progressfn);
89 
90   return c;
91 }
92 
93 /* See debuginfod-support.h  */
94 
95 scoped_fd
debuginfod_source_query(const unsigned char * build_id,int build_id_len,const char * srcpath,gdb::unique_xmalloc_ptr<char> * destname)96 debuginfod_source_query (const unsigned char *build_id,
97 			 int build_id_len,
98 			 const char *srcpath,
99 			 gdb::unique_xmalloc_ptr<char> *destname)
100 {
101   if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
102     return scoped_fd (-ENOSYS);
103 
104   debuginfod_client *c = debuginfod_init ();
105 
106   if (c == nullptr)
107     return scoped_fd (-ENOMEM);
108 
109   user_data data ("source file", srcpath);
110 
111   debuginfod_set_user_data (c, &data);
112   scoped_fd fd (debuginfod_find_source (c,
113 					build_id,
114 					build_id_len,
115 					srcpath,
116 					nullptr));
117 
118   /* TODO: Add 'set debug debuginfod' command to control when error messages are shown.  */
119   if (fd.get () < 0 && fd.get () != -ENOENT)
120     printf_filtered (_("Download failed: %s.  Continuing without source file %ps.\n"),
121 		     safe_strerror (-fd.get ()),
122 		     styled_string (file_name_style.style (),  srcpath));
123   else
124     destname->reset (xstrdup (srcpath));
125 
126   debuginfod_end (c);
127   return fd;
128 }
129 
130 /* See debuginfod-support.h  */
131 
132 scoped_fd
debuginfod_debuginfo_query(const unsigned char * build_id,int build_id_len,const char * filename,gdb::unique_xmalloc_ptr<char> * destname)133 debuginfod_debuginfo_query (const unsigned char *build_id,
134 			    int build_id_len,
135 			    const char *filename,
136 			    gdb::unique_xmalloc_ptr<char> *destname)
137 {
138   if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
139     return scoped_fd (-ENOSYS);
140 
141   debuginfod_client *c = debuginfod_init ();
142 
143   if (c == nullptr)
144     return scoped_fd (-ENOMEM);
145 
146   char *dname = nullptr;
147   user_data data ("separate debug info for", filename);
148 
149   debuginfod_set_user_data (c, &data);
150   scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len, &dname));
151 
152   if (fd.get () < 0 && fd.get () != -ENOENT)
153     printf_filtered (_("Download failed: %s.  Continuing without debug info for %ps.\n"),
154 		     safe_strerror (-fd.get ()),
155 		     styled_string (file_name_style.style (),  filename));
156 
157   destname->reset (dname);
158   debuginfod_end (c);
159   return fd;
160 }
161 #endif
162