xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/dwarf2/index-cache.c (revision 4439cfd0acf9c7dc90625e5cd83b2317a9ab8967)
1 /* Caching of GDB/DWARF index files.
2 
3    Copyright (C) 1994-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "dwarf2/index-cache.h"
22 
23 #include "build-id.h"
24 #include "cli/cli-cmds.h"
25 #include "cli/cli-decode.h"
26 #include "command.h"
27 #include "gdbsupport/scoped_mmap.h"
28 #include "gdbsupport/pathstuff.h"
29 #include "dwarf2/index-write.h"
30 #include "dwarf2/read.h"
31 #include "dwarf2/dwz.h"
32 #include "objfiles.h"
33 #include "gdbsupport/selftest.h"
34 #include <string>
35 #include <stdlib.h>
36 
37 /* When set to true, show debug messages about the index cache.  */
38 static bool debug_index_cache = false;
39 
40 #define index_cache_debug(FMT, ...)					       \
41   debug_prefixed_printf_cond_nofunc (debug_index_cache, "index-cache", \
42 				     FMT, ## __VA_ARGS__)
43 
44 /* The index cache directory, used for "set/show index-cache directory".  */
45 static std::string index_cache_directory;
46 
47 /* See dwarf-index.cache.h.  */
48 index_cache global_index_cache;
49 
50 /* set/show index-cache commands.  */
51 static cmd_list_element *set_index_cache_prefix_list;
52 static cmd_list_element *show_index_cache_prefix_list;
53 
54 /* Default destructor of index_cache_resource.  */
55 index_cache_resource::~index_cache_resource () = default;
56 
57 /* See dwarf-index-cache.h.  */
58 
59 void
60 index_cache::set_directory (std::string dir)
61 {
62   gdb_assert (!dir.empty ());
63 
64   m_dir = std::move (dir);
65 
66   index_cache_debug ("now using directory %s", m_dir.c_str ());
67 }
68 
69 /* See dwarf-index-cache.h.  */
70 
71 void
72 index_cache::enable ()
73 {
74   index_cache_debug ("enabling (%s)", m_dir.c_str ());
75 
76   m_enabled = true;
77 }
78 
79 /* See dwarf-index-cache.h.  */
80 
81 void
82 index_cache::disable ()
83 {
84   index_cache_debug ("disabling");
85 
86   m_enabled = false;
87 }
88 
89 /* See dwarf-index-cache.h.  */
90 
91 void
92 index_cache::store (dwarf2_per_objfile *per_objfile)
93 {
94   objfile *obj = per_objfile->objfile;
95 
96   if (!enabled ())
97     return;
98 
99   /* If the objfile does not correspond to an actual file, skip it.  */
100   if ((obj->flags & OBJF_NOT_FILENAME) != 0)
101     return;
102 
103   /* Get build id of objfile.  */
104   const bfd_build_id *build_id = build_id_bfd_get (obj->obfd.get ());
105   if (build_id == nullptr)
106     {
107       index_cache_debug ("objfile %s has no build id",
108 			 objfile_name (obj));
109       return;
110     }
111 
112   std::string build_id_str = build_id_to_string (build_id);
113 
114   /* Get build id of dwz file, if present.  */
115   gdb::optional<std::string> dwz_build_id_str;
116   const dwz_file *dwz = dwarf2_get_dwz_file (per_objfile->per_bfd);
117   const char *dwz_build_id_ptr = NULL;
118 
119   if (dwz != nullptr)
120     {
121       const bfd_build_id *dwz_build_id = build_id_bfd_get (dwz->dwz_bfd.get ());
122 
123       if (dwz_build_id == nullptr)
124 	{
125 	  index_cache_debug ("dwz objfile %s has no build id",
126 			     dwz->filename ());
127 	  return;
128 	}
129 
130       dwz_build_id_str = build_id_to_string (dwz_build_id);
131       dwz_build_id_ptr = dwz_build_id_str->c_str ();
132     }
133 
134   if (m_dir.empty ())
135     {
136       warning (_("The index cache directory name is empty, skipping store."));
137       return;
138     }
139 
140   try
141     {
142       /* Try to create the containing directory.  */
143       if (!mkdir_recursive (m_dir.c_str ()))
144 	{
145 	  warning (_("index cache: could not make cache directory: %s"),
146 		   safe_strerror (errno));
147 	  return;
148 	}
149 
150       index_cache_debug ("writing index cache for objfile %s",
151 			 objfile_name (obj));
152 
153       /* Write the index itself to the directory, using the build id as the
154 	 filename.  */
155       write_dwarf_index (per_objfile, m_dir.c_str (),
156 			 build_id_str.c_str (), dwz_build_id_ptr,
157 			 dw_index_kind::GDB_INDEX);
158     }
159   catch (const gdb_exception_error &except)
160     {
161       index_cache_debug ("couldn't store index cache for objfile %s: %s",
162 			 objfile_name (obj), except.what ());
163     }
164 }
165 
166 #if HAVE_SYS_MMAN_H
167 
168 /* Hold the resources for an mmapped index file.  */
169 
170 struct index_cache_resource_mmap final : public index_cache_resource
171 {
172   /* Try to mmap FILENAME.  Throw an exception on failure, including if the
173      file doesn't exist. */
174   index_cache_resource_mmap (const char *filename)
175     : mapping (mmap_file (filename))
176   {}
177 
178   scoped_mmap mapping;
179 };
180 
181 /* See dwarf-index-cache.h.  */
182 
183 gdb::array_view<const gdb_byte>
184 index_cache::lookup_gdb_index (const bfd_build_id *build_id,
185 			       std::unique_ptr<index_cache_resource> *resource)
186 {
187   if (!enabled ())
188     return {};
189 
190   if (m_dir.empty ())
191     {
192       warning (_("The index cache directory name is empty, skipping cache "
193 		 "lookup."));
194       return {};
195     }
196 
197   /* Compute where we would expect a gdb index file for this build id to be.  */
198   std::string filename = make_index_filename (build_id, INDEX4_SUFFIX);
199 
200   try
201     {
202       index_cache_debug ("trying to read %s",
203 			 filename.c_str ());
204 
205       /* Try to map that file.  */
206       index_cache_resource_mmap *mmap_resource
207 	= new index_cache_resource_mmap (filename.c_str ());
208 
209       /* Yay, it worked!  Hand the resource to the caller.  */
210       resource->reset (mmap_resource);
211 
212       return gdb::array_view<const gdb_byte>
213 	  ((const gdb_byte *) mmap_resource->mapping.get (),
214 	   mmap_resource->mapping.size ());
215     }
216   catch (const gdb_exception_error &except)
217     {
218       index_cache_debug ("couldn't read %s: %s",
219 			 filename.c_str (), except.what ());
220     }
221 
222   return {};
223 }
224 
225 #else /* !HAVE_SYS_MMAN_H */
226 
227 /* See dwarf-index-cache.h.  This is a no-op on unsupported systems.  */
228 
229 gdb::array_view<const gdb_byte>
230 index_cache::lookup_gdb_index (const bfd_build_id *build_id,
231 			       std::unique_ptr<index_cache_resource> *resource)
232 {
233   return {};
234 }
235 
236 #endif
237 
238 /* See dwarf-index-cache.h.  */
239 
240 std::string
241 index_cache::make_index_filename (const bfd_build_id *build_id,
242 				  const char *suffix) const
243 {
244   std::string build_id_str = build_id_to_string (build_id);
245 
246   return m_dir + SLASH_STRING + build_id_str + suffix;
247 }
248 
249 /* True when we are executing "show index-cache".  This is used to improve the
250    printout a little bit.  */
251 static bool in_show_index_cache_command = false;
252 
253 /* "show index-cache" handler.  */
254 
255 static void
256 show_index_cache_command (const char *arg, int from_tty)
257 {
258   /* Note that we are executing "show index-cache".  */
259   auto restore_flag = make_scoped_restore (&in_show_index_cache_command, true);
260 
261   /* Call all "show index-cache" subcommands.  */
262   cmd_show_list (show_index_cache_prefix_list, from_tty);
263 
264   gdb_printf ("\n");
265   gdb_printf
266     (_("The index cache is currently %s.\n"),
267      global_index_cache.enabled () ? _("enabled") : _("disabled"));
268 }
269 
270 /* "set/show index-cache enabled" set callback.  */
271 
272 static void
273 set_index_cache_enabled_command (bool value)
274 {
275   if (value)
276     global_index_cache.enable ();
277   else
278     global_index_cache.disable ();
279 }
280 
281 /* "set/show index-cache enabled" get callback.  */
282 
283 static bool
284 get_index_cache_enabled_command ()
285 {
286   return global_index_cache.enabled ();
287 }
288 
289 /* "set/show index-cache enabled" show callback.  */
290 
291 static void
292 show_index_cache_enabled_command (ui_file *stream, int from_tty,
293 				  cmd_list_element *cmd, const char *value)
294 {
295   gdb_printf (stream, _("The index cache is %s.\n"), value);
296 }
297 
298 /* "set index-cache directory" handler.  */
299 
300 static void
301 set_index_cache_directory_command (const char *arg, int from_tty,
302 				   cmd_list_element *element)
303 {
304   /* Make sure the index cache directory is absolute and tilde-expanded.  */
305   index_cache_directory = gdb_abspath (index_cache_directory.c_str ());
306   global_index_cache.set_directory (index_cache_directory);
307 }
308 
309 /* "show index-cache stats" handler.  */
310 
311 static void
312 show_index_cache_stats_command (const char *arg, int from_tty)
313 {
314   const char *indent = "";
315 
316   /* If this command is invoked through "show index-cache", make the display a
317      bit nicer.  */
318   if (in_show_index_cache_command)
319     {
320       indent = "  ";
321       gdb_printf ("\n");
322     }
323 
324   gdb_printf (_("%s  Cache hits (this session): %u\n"),
325 	      indent, global_index_cache.n_hits ());
326   gdb_printf (_("%sCache misses (this session): %u\n"),
327 	      indent, global_index_cache.n_misses ());
328 }
329 
330 void _initialize_index_cache ();
331 void
332 _initialize_index_cache ()
333 {
334   /* Set the default index cache directory.  */
335   std::string cache_dir = get_standard_cache_dir ();
336   if (!cache_dir.empty ())
337     {
338       index_cache_directory = cache_dir;
339       global_index_cache.set_directory (std::move (cache_dir));
340     }
341   else
342     warning (_("Couldn't determine a path for the index cache directory."));
343 
344   /* set index-cache */
345   add_basic_prefix_cmd ("index-cache", class_files,
346 			_("Set index-cache options."),
347 			&set_index_cache_prefix_list,
348 			false, &setlist);
349 
350   /* show index-cache */
351   add_prefix_cmd ("index-cache", class_files, show_index_cache_command,
352 		  _("Show index-cache options."), &show_index_cache_prefix_list,
353 		  false, &showlist);
354 
355   /* set/show index-cache enabled */
356   set_show_commands setshow_index_cache_enabled_cmds
357     = add_setshow_boolean_cmd ("enabled", class_files,
358 			       _("Enable the index cache."),
359 			       _("Show whether the index cache is enabled."),
360 			       _("When on, enable the use of the index cache."),
361 			       set_index_cache_enabled_command,
362 			       get_index_cache_enabled_command,
363 			       show_index_cache_enabled_command,
364 			       &set_index_cache_prefix_list,
365 			       &show_index_cache_prefix_list);
366 
367   /* set index-cache on */
368   cmd_list_element *set_index_cache_on_cmd
369     = add_alias_cmd ("on", setshow_index_cache_enabled_cmds.set, class_files,
370 		     false, &set_index_cache_prefix_list);
371   deprecate_cmd (set_index_cache_on_cmd, "set index-cache enabled on");
372   set_index_cache_on_cmd->default_args = "on";
373 
374   /* set index-cache off */
375   cmd_list_element *set_index_cache_off_cmd
376     = add_alias_cmd ("off", setshow_index_cache_enabled_cmds.set, class_files,
377 		     false, &set_index_cache_prefix_list);
378   deprecate_cmd (set_index_cache_off_cmd, "set index-cache enabled off");
379   set_index_cache_off_cmd->default_args = "off";
380 
381   /* set index-cache directory */
382   add_setshow_filename_cmd ("directory", class_files, &index_cache_directory,
383 			    _("Set the directory of the index cache."),
384 			    _("Show the directory of the index cache."),
385 			    NULL,
386 			    set_index_cache_directory_command, NULL,
387 			    &set_index_cache_prefix_list,
388 			    &show_index_cache_prefix_list);
389 
390   /* show index-cache stats */
391   add_cmd ("stats", class_files, show_index_cache_stats_command,
392 	   _("Show some stats about the index cache."),
393 	   &show_index_cache_prefix_list);
394 
395   /* set debug index-cache */
396   add_setshow_boolean_cmd ("index-cache", class_maintenance,
397 			   &debug_index_cache,
398 			   _("Set display of index-cache debug messages."),
399 			   _("Show display of index-cache debug messages."),
400 			   _("\
401 When non-zero, debugging output for the index cache is displayed."),
402 			    NULL, NULL,
403 			    &setdebuglist, &showdebuglist);
404 }
405