]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/dwarf2/cooked-index.c
6209590febb784d7761f157c45ebeb2ec911c47f
[thirdparty/binutils-gdb.git] / gdb / dwarf2 / cooked-index.c
1 /* DIE indexing
2
3 Copyright (C) 2022-2025 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 "dwarf2/cooked-index.h"
21 #include "dwarf2/read.h"
22 #include "dwarf2/stringify.h"
23 #include "event-top.h"
24 #include "maint.h"
25 #include "observable.h"
26 #include "run-on-main-thread.h"
27 #include "gdbsupport/task-group.h"
28 #include "cli/cli-cmds.h"
29
30 /* We don't want gdb to exit while it is in the process of writing to
31 the index cache. So, all live cooked index vectors are stored
32 here, and then these are all waited for before exit proceeds. */
33 static gdb::unordered_set<cooked_index *> active_vectors;
34
35 /* Return true if LANG requires canonicalization. This is used
36 primarily to work around an issue computing the name of "main".
37 This function must be kept in sync with
38 cooked_index_shard::finalize. */
39
40 static bool
41 language_requires_canonicalization (enum language lang)
42 {
43 return (lang == language_ada
44 || lang == language_c
45 || lang == language_cplus);
46 }
47
48 cooked_index::cooked_index (cooked_index_worker_up &&worker)
49 : m_state (std::move (worker))
50 {
51 /* ACTIVE_VECTORS is not locked, and this assert ensures that this
52 will be caught if ever moved to the background. */
53 gdb_assert (is_main_thread ());
54 active_vectors.insert (this);
55 }
56
57 void
58 cooked_index::start_reading ()
59 {
60 m_state->start ();
61 }
62
63 void
64 cooked_index::wait (cooked_state desired_state, bool allow_quit)
65 {
66 gdb_assert (desired_state != cooked_state::INITIAL);
67
68 /* If the state object has been deleted, then that means waiting is
69 completely done. */
70 if (m_state == nullptr)
71 return;
72
73 if (m_state->wait (desired_state, allow_quit))
74 {
75 /* Only the main thread can modify this. */
76 gdb_assert (is_main_thread ());
77 m_state.reset (nullptr);
78 }
79 }
80
81 void
82 cooked_index::set_contents ()
83 {
84 gdb_assert (m_shards.empty ());
85 m_shards = m_state->release_shards ();
86
87 m_state->set (cooked_state::MAIN_AVAILABLE);
88
89 /* This is run after finalization is done -- but not before. If
90 this task were submitted earlier, it would have to wait for
91 finalization. However, that would take a slot in the global
92 thread pool, and if enough such tasks were submitted at once, it
93 would cause a livelock. */
94 gdb::task_group finalizers ([this] ()
95 {
96 m_state->set (cooked_state::FINALIZED);
97 m_state->write_to_cache (index_for_writing ());
98 m_state->set (cooked_state::CACHE_DONE);
99 });
100
101 for (auto &shard : m_shards)
102 {
103 auto this_shard = shard.get ();
104 const parent_map_map *parent_maps = m_state->get_parent_map_map ();
105 finalizers.add_task ([=] ()
106 {
107 scoped_time_it time_it ("DWARF finalize worker",
108 m_state->m_per_command_time);
109 this_shard->finalize (parent_maps);
110 });
111 }
112
113 finalizers.start ();
114 }
115
116 cooked_index::~cooked_index ()
117 {
118 /* Wait for index-creation to be done, though this one must also
119 waited for by the per-BFD object to ensure the required data
120 remains live. */
121 wait (cooked_state::CACHE_DONE);
122
123 /* Remove our entry from the global list. See the assert in the
124 constructor to understand this. */
125 gdb_assert (is_main_thread ());
126 active_vectors.erase (this);
127 }
128
129 /* See cooked-index.h. */
130
131 dwarf2_per_cu *
132 cooked_index::lookup (unrelocated_addr addr)
133 {
134 /* Ensure that the address maps are ready. */
135 wait (cooked_state::MAIN_AVAILABLE, true);
136 for (const auto &shard : m_shards)
137 {
138 dwarf2_per_cu *result = shard->lookup (addr);
139 if (result != nullptr)
140 return result;
141 }
142 return nullptr;
143 }
144
145 /* See cooked-index.h. */
146
147 std::vector<const addrmap *>
148 cooked_index::get_addrmaps ()
149 {
150 /* Ensure that the address maps are ready. */
151 wait (cooked_state::MAIN_AVAILABLE, true);
152 std::vector<const addrmap *> result;
153 for (const auto &shard : m_shards)
154 result.push_back (shard->m_addrmap);
155 return result;
156 }
157
158 /* See cooked-index.h. */
159
160 cooked_index::range
161 cooked_index::find (const std::string &name, bool completing)
162 {
163 wait (cooked_state::FINALIZED, true);
164 std::vector<cooked_index_shard::range> result_range;
165 result_range.reserve (m_shards.size ());
166 for (auto &shard : m_shards)
167 result_range.push_back (shard->find (name, completing));
168 return range (std::move (result_range));
169 }
170
171 /* See cooked-index.h. */
172
173 const char *
174 cooked_index::get_main_name (struct obstack *obstack, enum language *lang)
175 const
176 {
177 const cooked_index_entry *entry = get_main ();
178 if (entry == nullptr)
179 return nullptr;
180
181 *lang = entry->lang;
182 return entry->full_name (obstack, FOR_MAIN);
183 }
184
185 /* See cooked_index.h. */
186
187 const cooked_index_entry *
188 cooked_index::get_main () const
189 {
190 const cooked_index_entry *best_entry = nullptr;
191 for (const auto &shard : m_shards)
192 {
193 const cooked_index_entry *entry = shard->get_main ();
194 /* Choose the first "main" we see. We only do this for names
195 not requiring canonicalization. At this point in the process
196 names might not have been canonicalized. However, currently,
197 languages that require this step also do not use
198 DW_AT_main_subprogram. An assert is appropriate here because
199 this filtering is done in get_main. */
200 if (entry != nullptr)
201 {
202 if ((entry->flags & IS_MAIN) != 0)
203 {
204 if (!language_requires_canonicalization (entry->lang))
205 {
206 /* There won't be one better than this. */
207 return entry;
208 }
209 }
210 else
211 {
212 /* This is one that is named "main". Here we don't care
213 if the language requires canonicalization, due to how
214 the entry is detected. Entries like this have worse
215 priority than IS_MAIN entries. */
216 if (best_entry == nullptr)
217 best_entry = entry;
218 }
219 }
220 }
221
222 return best_entry;
223 }
224
225 quick_symbol_functions_up
226 cooked_index::make_quick_functions () const
227 {
228 return quick_symbol_functions_up (new cooked_index_functions);
229 }
230
231 /* See cooked-index.h. */
232
233 void
234 cooked_index::dump (gdbarch *arch)
235 {
236 auto_obstack temp_storage;
237
238 gdb_printf (" entries:\n");
239 gdb_printf ("\n");
240
241 size_t i = 0;
242 for (const cooked_index_entry *entry : this->all_entries ())
243 {
244 QUIT;
245
246 gdb_printf (" [%zu] ((cooked_index_entry *) %p)\n", i++, entry);
247 gdb_printf (" name: %s\n", entry->name);
248 gdb_printf (" canonical: %s\n", entry->canonical);
249 gdb_printf (" qualified: %s\n",
250 entry->full_name (&temp_storage, 0, "::"));
251 gdb_printf (" DWARF tag: %s\n", dwarf_tag_name (entry->tag));
252 gdb_printf (" flags: %s\n", to_string (entry->flags).c_str ());
253 gdb_printf (" DIE offset: %s\n", sect_offset_str (entry->die_offset));
254
255 if ((entry->flags & IS_PARENT_DEFERRED) != 0)
256 gdb_printf (" parent: deferred (%" PRIx64 ")\n",
257 entry->get_deferred_parent ());
258 else if (entry->get_parent () != nullptr)
259 gdb_printf (" parent: ((cooked_index_entry *) %p) [%s]\n",
260 entry->get_parent (), entry->get_parent ()->name);
261 else
262 gdb_printf (" parent: ((cooked_index_entry *) 0)\n");
263
264 gdb_printf ("\n");
265 }
266
267 const cooked_index_entry *main_entry = this->get_main ();
268 if (main_entry != nullptr)
269 gdb_printf (" main: ((cooked_index_entry *) %p) [%s]\n", main_entry,
270 main_entry->name);
271 else
272 gdb_printf (" main: ((cooked_index_entry *) 0)\n");
273
274 gdb_printf ("\n");
275 gdb_printf (" address maps:\n");
276 gdb_printf ("\n");
277
278 std::vector<const addrmap *> addrmaps = this->get_addrmaps ();
279 for (i = 0; i < addrmaps.size (); ++i)
280 {
281 const addrmap *addrmap = addrmaps[i];
282
283 gdb_printf (" [%zu] ((addrmap *) %p)\n", i, addrmap);
284 gdb_printf ("\n");
285
286 if (addrmap == nullptr)
287 continue;
288
289 addrmap->foreach ([arch] (CORE_ADDR start_addr, const void *obj)
290 {
291 QUIT;
292
293 const char *start_addr_str = paddress (arch, start_addr);
294
295 if (obj != nullptr)
296 {
297 const dwarf2_per_cu *per_cu
298 = static_cast<const dwarf2_per_cu *> (obj);
299 gdb_printf (" [%s] ((dwarf2_per_cu *) %p)\n",
300 start_addr_str, per_cu);
301 }
302 else
303 gdb_printf (" [%s] ((dwarf2_per_cu *) 0)\n", start_addr_str);
304
305 return 0;
306 });
307
308 gdb_printf ("\n");
309 }
310 }
311
312 /* Wait for all the index cache entries to be written before gdb
313 exits. */
314 static void
315 wait_for_index_cache (int)
316 {
317 gdb_assert (is_main_thread ());
318 for (cooked_index *item : active_vectors)
319 item->wait_completely ();
320 }
321
322 /* A maint command to wait for the cache. */
323
324 static void
325 maintenance_wait_for_index_cache (const char *args, int from_tty)
326 {
327 wait_for_index_cache (0);
328 }
329
330 INIT_GDB_FILE (cooked_index)
331 {
332 add_cmd ("wait-for-index-cache", class_maintenance,
333 maintenance_wait_for_index_cache, _("\
334 Wait until all pending writes to the index cache have completed.\n\
335 Usage: maintenance wait-for-index-cache"),
336 &maintenancelist);
337
338 gdb::observers::gdb_exiting.attach (wait_for_index_cache, "cooked-index");
339 }