]>
Commit | Line | Data |
---|---|---|
51f5a4b8 TT |
1 | /* DIE indexing |
2 | ||
213516ef | 3 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
51f5a4b8 TT |
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/cooked-index.h" | |
22 | #include "dwarf2/read.h" | |
7d82b08e | 23 | #include "dwarf2/stringify.h" |
52e5e48e | 24 | #include "dwarf2/index-cache.h" |
51f5a4b8 | 25 | #include "cp-support.h" |
55fc1623 | 26 | #include "c-lang.h" |
51f5a4b8 TT |
27 | #include "ada-lang.h" |
28 | #include "split-name.h" | |
52e5e48e TT |
29 | #include "observable.h" |
30 | #include "run-on-main-thread.h" | |
51f5a4b8 | 31 | #include <algorithm> |
e0f4b3ec | 32 | #include "gdbsupport/gdb-safe-ctype.h" |
ac37b79c | 33 | #include "gdbsupport/selftest.h" |
307733cc | 34 | #include <chrono> |
52e5e48e | 35 | #include <unordered_set> |
f0c3dcc1 | 36 | #include "cli/cli-cmds.h" |
52e5e48e TT |
37 | |
38 | /* We don't want gdb to exit while it is in the process of writing to | |
39 | the index cache. So, all live cooked index vectors are stored | |
40 | here, and then these are all waited for before exit proceeds. */ | |
41 | static std::unordered_set<cooked_index *> active_vectors; | |
ac37b79c TT |
42 | |
43 | /* See cooked-index.h. */ | |
44 | ||
7d82b08e SM |
45 | std::string |
46 | to_string (cooked_index_flag flags) | |
47 | { | |
48 | static constexpr cooked_index_flag::string_mapping mapping[] = { | |
49 | MAP_ENUM_FLAG (IS_MAIN), | |
50 | MAP_ENUM_FLAG (IS_STATIC), | |
51 | MAP_ENUM_FLAG (IS_ENUM_CLASS), | |
52 | MAP_ENUM_FLAG (IS_LINKAGE), | |
53 | MAP_ENUM_FLAG (IS_TYPE_DECLARATION), | |
54 | }; | |
55 | ||
56 | return flags.to_string (mapping); | |
57 | } | |
58 | ||
59 | /* See cooked-index.h. */ | |
60 | ||
47fe57c9 TT |
61 | bool |
62 | language_requires_canonicalization (enum language lang) | |
63 | { | |
64 | return (lang == language_ada | |
65 | || lang == language_c | |
66 | || lang == language_cplus); | |
67 | } | |
68 | ||
69 | /* See cooked-index.h. */ | |
70 | ||
c121e82c | 71 | int |
ac37b79c | 72 | cooked_index_entry::compare (const char *stra, const char *strb, |
c121e82c | 73 | comparison_mode mode) |
ac37b79c | 74 | { |
c121e82c TT |
75 | auto munge = [] (char c) -> unsigned char |
76 | { | |
77 | /* We want to sort '<' before any other printable character. | |
78 | So, rewrite '<' to something just before ' '. */ | |
79 | if (c == '<') | |
80 | return '\x1f'; | |
81 | return TOLOWER ((unsigned char) c); | |
82 | }; | |
ac37b79c TT |
83 | |
84 | while (*stra != '\0' | |
85 | && *strb != '\0' | |
c121e82c | 86 | && (munge (*stra) == munge (*strb))) |
ac37b79c | 87 | { |
ac37b79c TT |
88 | ++stra; |
89 | ++strb; | |
90 | } | |
91 | ||
c121e82c TT |
92 | unsigned char c1 = munge (*stra); |
93 | unsigned char c2 = munge (*strb); | |
ac37b79c | 94 | |
c121e82c TT |
95 | if (c1 == c2) |
96 | return 0; | |
97 | ||
98 | /* When completing, if STRB ends earlier than STRA, consider them as | |
99 | equal. When comparing, if STRB ends earlier and STRA ends with | |
100 | '<', consider them as equal. */ | |
101 | if (mode == COMPLETE || (mode == MATCH && c1 == munge ('<'))) | |
ac37b79c | 102 | { |
c121e82c TT |
103 | if (c2 == '\0') |
104 | return 0; | |
ac37b79c TT |
105 | } |
106 | ||
c121e82c | 107 | return c1 < c2 ? -1 : 1; |
ac37b79c TT |
108 | } |
109 | ||
110 | #if GDB_SELF_TEST | |
111 | ||
112 | namespace { | |
113 | ||
114 | void | |
115 | test_compare () | |
116 | { | |
c121e82c TT |
117 | /* Convenience aliases. */ |
118 | const auto mode_compare = cooked_index_entry::MATCH; | |
119 | const auto mode_sort = cooked_index_entry::SORT; | |
120 | const auto mode_complete = cooked_index_entry::COMPLETE; | |
121 | ||
122 | SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", | |
123 | mode_compare) == 0); | |
124 | SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", | |
125 | mode_complete) == 0); | |
126 | ||
127 | SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", | |
128 | mode_compare) < 0); | |
129 | SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", | |
130 | mode_compare) > 0); | |
131 | SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", | |
132 | mode_complete) < 0); | |
133 | SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", | |
134 | mode_complete) == 0); | |
135 | ||
136 | SELF_CHECK (cooked_index_entry::compare ("name", "name<>", | |
137 | mode_compare) < 0); | |
138 | SELF_CHECK (cooked_index_entry::compare ("name<>", "name", | |
139 | mode_compare) == 0); | |
140 | SELF_CHECK (cooked_index_entry::compare ("name", "name<>", | |
141 | mode_complete) < 0); | |
142 | SELF_CHECK (cooked_index_entry::compare ("name<>", "name", | |
143 | mode_complete) == 0); | |
144 | ||
145 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", | |
146 | mode_compare) == 0); | |
147 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", | |
148 | mode_compare) > 0); | |
149 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", | |
150 | mode_complete) == 0); | |
151 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", | |
152 | mode_complete) > 0); | |
153 | ||
154 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", | |
155 | "name<arg<more>>", | |
156 | mode_compare) == 0); | |
157 | ||
158 | SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>", | |
159 | mode_compare) < 0); | |
160 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name", | |
161 | mode_compare) == 0); | |
162 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", | |
163 | mode_compare) > 0); | |
164 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", | |
165 | mode_complete) == 0); | |
166 | ||
167 | SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0); | |
168 | SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0); | |
169 | SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0); | |
170 | SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0); | |
171 | ||
172 | SELF_CHECK (cooked_index_entry::compare ("func", "func<type>", | |
173 | mode_sort) < 0); | |
174 | SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1", | |
175 | mode_sort) < 0); | |
ac37b79c TT |
176 | } |
177 | ||
178 | } /* anonymous namespace */ | |
179 | ||
180 | #endif /* GDB_SELF_TEST */ | |
51f5a4b8 | 181 | |
51f5a4b8 TT |
182 | /* See cooked-index.h. */ |
183 | ||
184 | const char * | |
47fe57c9 | 185 | cooked_index_entry::full_name (struct obstack *storage, bool for_main) const |
51f5a4b8 | 186 | { |
47fe57c9 TT |
187 | const char *local_name = for_main ? name : canonical; |
188 | ||
72b580b8 | 189 | if ((flags & IS_LINKAGE) != 0 || parent_entry == nullptr) |
47fe57c9 | 190 | return local_name; |
51f5a4b8 TT |
191 | |
192 | const char *sep = nullptr; | |
2c474c46 | 193 | switch (per_cu->lang ()) |
51f5a4b8 TT |
194 | { |
195 | case language_cplus: | |
196 | case language_rust: | |
197 | sep = "::"; | |
198 | break; | |
199 | ||
200 | case language_go: | |
201 | case language_d: | |
202 | case language_ada: | |
203 | sep = "."; | |
204 | break; | |
51f5a4b8 | 205 | |
72b580b8 | 206 | default: |
47fe57c9 | 207 | return local_name; |
72b580b8 | 208 | } |
51f5a4b8 | 209 | |
47fe57c9 TT |
210 | parent_entry->write_scope (storage, sep, for_main); |
211 | obstack_grow0 (storage, local_name, strlen (local_name)); | |
51f5a4b8 TT |
212 | return (const char *) obstack_finish (storage); |
213 | } | |
214 | ||
215 | /* See cooked-index.h. */ | |
216 | ||
217 | void | |
218 | cooked_index_entry::write_scope (struct obstack *storage, | |
47fe57c9 TT |
219 | const char *sep, |
220 | bool for_main) const | |
51f5a4b8 TT |
221 | { |
222 | if (parent_entry != nullptr) | |
47fe57c9 TT |
223 | parent_entry->write_scope (storage, sep, for_main); |
224 | const char *local_name = for_main ? name : canonical; | |
225 | obstack_grow (storage, local_name, strlen (local_name)); | |
51f5a4b8 TT |
226 | obstack_grow (storage, sep, strlen (sep)); |
227 | } | |
228 | ||
229 | /* See cooked-index.h. */ | |
230 | ||
231 | const cooked_index_entry * | |
a8dc6718 SM |
232 | cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag, |
233 | cooked_index_flag flags, const char *name, | |
234 | const cooked_index_entry *parent_entry, | |
235 | dwarf2_per_cu_data *per_cu) | |
51f5a4b8 TT |
236 | { |
237 | cooked_index_entry *result = create (die_offset, tag, flags, name, | |
238 | parent_entry, per_cu); | |
239 | m_entries.push_back (result); | |
240 | ||
241 | /* An explicitly-tagged main program should always override the | |
242 | implicit "main" discovery. */ | |
243 | if ((flags & IS_MAIN) != 0) | |
244 | m_main = result; | |
51f5a4b8 TT |
245 | |
246 | return result; | |
247 | } | |
248 | ||
46114cb7 TT |
249 | /* See cooked-index.h. */ |
250 | ||
20a26f4e | 251 | void |
a8dc6718 | 252 | cooked_index_shard::finalize () |
46114cb7 | 253 | { |
20a26f4e | 254 | m_future = gdb::thread_pool::g_thread_pool->post_task ([this] () |
46114cb7 | 255 | { |
20a26f4e TT |
256 | do_finalize (); |
257 | }); | |
51f5a4b8 TT |
258 | } |
259 | ||
260 | /* See cooked-index.h. */ | |
261 | ||
262 | gdb::unique_xmalloc_ptr<char> | |
a8dc6718 SM |
263 | cooked_index_shard::handle_gnat_encoded_entry (cooked_index_entry *entry, |
264 | htab_t gnat_entries) | |
51f5a4b8 TT |
265 | { |
266 | std::string canonical = ada_decode (entry->name, false, false); | |
267 | if (canonical.empty ()) | |
268 | return {}; | |
269 | std::vector<gdb::string_view> names = split_name (canonical.c_str (), | |
270 | split_style::DOT); | |
271 | gdb::string_view tail = names.back (); | |
272 | names.pop_back (); | |
273 | ||
274 | const cooked_index_entry *parent = nullptr; | |
275 | for (const auto &name : names) | |
276 | { | |
277 | uint32_t hashval = dwarf5_djb_hash (name); | |
278 | void **slot = htab_find_slot_with_hash (gnat_entries, &name, | |
279 | hashval, INSERT); | |
280 | /* CUs are processed in order, so we only need to check the most | |
281 | recent entry. */ | |
282 | cooked_index_entry *last = (cooked_index_entry *) *slot; | |
283 | if (last == nullptr || last->per_cu != entry->per_cu) | |
284 | { | |
285 | gdb::unique_xmalloc_ptr<char> new_name | |
286 | = make_unique_xstrndup (name.data (), name.length ()); | |
20a26f4e TT |
287 | last = create (entry->die_offset, DW_TAG_namespace, |
288 | 0, new_name.get (), parent, | |
289 | entry->per_cu); | |
51f5a4b8 TT |
290 | last->canonical = last->name; |
291 | m_names.push_back (std::move (new_name)); | |
292 | *slot = last; | |
293 | } | |
294 | ||
295 | parent = last; | |
296 | } | |
297 | ||
298 | entry->parent_entry = parent; | |
299 | return make_unique_xstrndup (tail.data (), tail.length ()); | |
300 | } | |
301 | ||
302 | /* See cooked-index.h. */ | |
303 | ||
304 | void | |
a8dc6718 | 305 | cooked_index_shard::do_finalize () |
51f5a4b8 TT |
306 | { |
307 | auto hash_name_ptr = [] (const void *p) | |
308 | { | |
309 | const cooked_index_entry *entry = (const cooked_index_entry *) p; | |
310 | return htab_hash_pointer (entry->name); | |
311 | }; | |
312 | ||
313 | auto eq_name_ptr = [] (const void *a, const void *b) -> int | |
314 | { | |
315 | const cooked_index_entry *ea = (const cooked_index_entry *) a; | |
316 | const cooked_index_entry *eb = (const cooked_index_entry *) b; | |
317 | return ea->name == eb->name; | |
318 | }; | |
319 | ||
320 | /* We can use pointer equality here because names come from | |
321 | .debug_str, which will normally be unique-ified by the linker. | |
322 | Also, duplicates are relatively harmless -- they just mean a bit | |
323 | of extra memory is used. */ | |
324 | htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr, | |
325 | nullptr, xcalloc, xfree)); | |
326 | ||
5a89072f TT |
327 | auto hash_entry = [] (const void *e) |
328 | { | |
329 | const cooked_index_entry *entry = (const cooked_index_entry *) e; | |
330 | return dwarf5_djb_hash (entry->canonical); | |
331 | }; | |
332 | ||
333 | auto eq_entry = [] (const void *a, const void *b) -> int | |
334 | { | |
335 | const cooked_index_entry *ae = (const cooked_index_entry *) a; | |
336 | const gdb::string_view *sv = (const gdb::string_view *) b; | |
337 | return (strlen (ae->canonical) == sv->length () | |
338 | && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0); | |
339 | }; | |
340 | ||
20a26f4e TT |
341 | htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry, |
342 | nullptr, xcalloc, xfree)); | |
46114cb7 | 343 | |
20a26f4e TT |
344 | for (cooked_index_entry *entry : m_entries) |
345 | { | |
47fe57c9 TT |
346 | /* Note that this code must be kept in sync with |
347 | language_requires_canonicalization. */ | |
20a26f4e | 348 | gdb_assert (entry->canonical == nullptr); |
bed34ce7 | 349 | if ((entry->flags & IS_LINKAGE) != 0) |
20a26f4e | 350 | entry->canonical = entry->name; |
bed34ce7 | 351 | else if (entry->per_cu->lang () == language_ada) |
51f5a4b8 | 352 | { |
bed34ce7 TT |
353 | gdb::unique_xmalloc_ptr<char> canon_name |
354 | = handle_gnat_encoded_entry (entry, gnat_entries.get ()); | |
355 | if (canon_name == nullptr) | |
356 | entry->canonical = entry->name; | |
357 | else | |
358 | { | |
359 | entry->canonical = canon_name.get (); | |
360 | m_names.push_back (std::move (canon_name)); | |
361 | } | |
362 | } | |
55fc1623 TT |
363 | else if (entry->per_cu->lang () == language_cplus |
364 | || entry->per_cu->lang () == language_c) | |
bed34ce7 TT |
365 | { |
366 | void **slot = htab_find_slot (seen_names.get (), entry, | |
367 | INSERT); | |
368 | if (*slot == nullptr) | |
20a26f4e TT |
369 | { |
370 | gdb::unique_xmalloc_ptr<char> canon_name | |
55fc1623 TT |
371 | = (entry->per_cu->lang () == language_cplus |
372 | ? cp_canonicalize_string (entry->name) | |
373 | : c_canonicalize_name (entry->name)); | |
20a26f4e TT |
374 | if (canon_name == nullptr) |
375 | entry->canonical = entry->name; | |
376 | else | |
377 | { | |
378 | entry->canonical = canon_name.get (); | |
379 | m_names.push_back (std::move (canon_name)); | |
380 | } | |
b6c55de7 | 381 | *slot = entry; |
20a26f4e | 382 | } |
51f5a4b8 TT |
383 | else |
384 | { | |
bed34ce7 TT |
385 | const cooked_index_entry *other |
386 | = (const cooked_index_entry *) *slot; | |
387 | entry->canonical = other->canonical; | |
51f5a4b8 TT |
388 | } |
389 | } | |
bed34ce7 TT |
390 | else |
391 | entry->canonical = entry->name; | |
51f5a4b8 TT |
392 | } |
393 | ||
394 | m_names.shrink_to_fit (); | |
395 | m_entries.shrink_to_fit (); | |
396 | std::sort (m_entries.begin (), m_entries.end (), | |
397 | [] (const cooked_index_entry *a, const cooked_index_entry *b) | |
398 | { | |
399 | return *a < *b; | |
400 | }); | |
401 | } | |
20a26f4e TT |
402 | |
403 | /* See cooked-index.h. */ | |
404 | ||
a8dc6718 SM |
405 | cooked_index_shard::range |
406 | cooked_index_shard::find (const std::string &name, bool completing) const | |
20a26f4e TT |
407 | { |
408 | wait (); | |
409 | ||
c121e82c TT |
410 | cooked_index_entry::comparison_mode mode = (completing |
411 | ? cooked_index_entry::COMPLETE | |
412 | : cooked_index_entry::MATCH); | |
413 | ||
35e17631 | 414 | auto lower = std::lower_bound (m_entries.cbegin (), m_entries.cend (), name, |
20a26f4e | 415 | [=] (const cooked_index_entry *entry, |
ac37b79c | 416 | const std::string &n) |
20a26f4e | 417 | { |
c121e82c | 418 | return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) < 0; |
20a26f4e TT |
419 | }); |
420 | ||
35e17631 | 421 | auto upper = std::upper_bound (m_entries.cbegin (), m_entries.cend (), name, |
ac37b79c | 422 | [=] (const std::string &n, |
20a26f4e TT |
423 | const cooked_index_entry *entry) |
424 | { | |
c121e82c | 425 | return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) > 0; |
20a26f4e TT |
426 | }); |
427 | ||
428 | return range (lower, upper); | |
429 | } | |
430 | ||
307733cc TT |
431 | /* See cooked-index.h. */ |
432 | ||
433 | void | |
434 | cooked_index_shard::wait (bool allow_quit) const | |
435 | { | |
436 | if (allow_quit) | |
437 | { | |
438 | std::chrono::milliseconds duration { 15 }; | |
439 | while (m_future.wait_for (duration) == gdb::future_status::timeout) | |
440 | QUIT; | |
441 | } | |
442 | else | |
443 | m_future.wait (); | |
444 | } | |
445 | ||
6f214d0f | 446 | cooked_index::cooked_index (vec_type &&vec) |
20a26f4e TT |
447 | : m_vector (std::move (vec)) |
448 | { | |
449 | for (auto &idx : m_vector) | |
450 | idx->finalize (); | |
52e5e48e | 451 | |
52e5e48e TT |
452 | /* ACTIVE_VECTORS is not locked, and this assert ensures that this |
453 | will be caught if ever moved to the background. */ | |
454 | gdb_assert (is_main_thread ()); | |
455 | active_vectors.insert (this); | |
456 | } | |
457 | ||
6f214d0f TT |
458 | /* See cooked-index.h. */ |
459 | ||
460 | void | |
461 | cooked_index::start_writing_index (dwarf2_per_bfd *per_bfd) | |
462 | { | |
463 | /* This must be set after all the finalization tasks have been | |
464 | started, because it may call 'wait'. */ | |
465 | m_write_future | |
466 | = gdb::thread_pool::g_thread_pool->post_task ([this, per_bfd] () | |
467 | { | |
468 | maybe_write_index (per_bfd); | |
469 | }); | |
470 | } | |
471 | ||
52e5e48e TT |
472 | cooked_index::~cooked_index () |
473 | { | |
474 | /* The 'finalize' method may be run in a different thread. If | |
475 | this object is destroyed before this completes, then the method | |
476 | will end up writing to freed memory. Waiting for this to | |
477 | complete avoids this problem; and the cost seems ignorable | |
478 | because creating and immediately destroying the debug info is a | |
479 | relatively rare thing to do. */ | |
480 | for (auto &item : m_vector) | |
481 | item->wait (false); | |
482 | ||
483 | /* Likewise for the index-creating future, though this one must also | |
484 | waited for by the per-BFD object to ensure the required data | |
485 | remains live. */ | |
486 | wait_completely (); | |
487 | ||
488 | /* Remove our entry from the global list. See the assert in the | |
489 | constructor to understand this. */ | |
490 | gdb_assert (is_main_thread ()); | |
491 | active_vectors.erase (this); | |
20a26f4e TT |
492 | } |
493 | ||
494 | /* See cooked-index.h. */ | |
495 | ||
496 | dwarf2_per_cu_data * | |
19455ee1 | 497 | cooked_index::lookup (CORE_ADDR addr) |
20a26f4e TT |
498 | { |
499 | for (const auto &index : m_vector) | |
500 | { | |
501 | dwarf2_per_cu_data *result = index->lookup (addr); | |
502 | if (result != nullptr) | |
503 | return result; | |
504 | } | |
505 | return nullptr; | |
506 | } | |
507 | ||
508 | /* See cooked-index.h. */ | |
509 | ||
70ca3a6b | 510 | std::vector<const addrmap *> |
19455ee1 | 511 | cooked_index::get_addrmaps () const |
20a26f4e | 512 | { |
70ca3a6b | 513 | std::vector<const addrmap *> result; |
20a26f4e TT |
514 | for (const auto &index : m_vector) |
515 | result.push_back (index->m_addrmap); | |
516 | return result; | |
517 | } | |
518 | ||
519 | /* See cooked-index.h. */ | |
520 | ||
19455ee1 SM |
521 | cooked_index::range |
522 | cooked_index::find (const std::string &name, bool completing) const | |
20a26f4e | 523 | { |
a8dc6718 | 524 | std::vector<cooked_index_shard::range> result_range; |
20a26f4e TT |
525 | result_range.reserve (m_vector.size ()); |
526 | for (auto &entry : m_vector) | |
527 | result_range.push_back (entry->find (name, completing)); | |
528 | return range (std::move (result_range)); | |
529 | } | |
530 | ||
531 | /* See cooked-index.h. */ | |
532 | ||
533 | const cooked_index_entry * | |
19455ee1 | 534 | cooked_index::get_main () const |
20a26f4e TT |
535 | { |
536 | const cooked_index_entry *result = nullptr; | |
537 | ||
538 | for (const auto &index : m_vector) | |
539 | { | |
540 | const cooked_index_entry *entry = index->get_main (); | |
47fe57c9 TT |
541 | /* Choose the first "main" we see. The choice among several is |
542 | arbitrary. See the comment by the sole caller to understand | |
543 | the rationale for filtering by language. */ | |
544 | if (entry != nullptr | |
545 | && !language_requires_canonicalization (entry->per_cu->lang ())) | |
546 | { | |
547 | result = entry; | |
548 | break; | |
549 | } | |
20a26f4e TT |
550 | } |
551 | ||
552 | return result; | |
553 | } | |
ac37b79c | 554 | |
7d82b08e SM |
555 | /* See cooked-index.h. */ |
556 | ||
557 | void | |
19455ee1 | 558 | cooked_index::dump (gdbarch *arch) const |
7d82b08e SM |
559 | { |
560 | /* Ensure the index is done building. */ | |
561 | this->wait (); | |
562 | ||
563 | gdb_printf (" entries:\n"); | |
564 | gdb_printf ("\n"); | |
565 | ||
566 | size_t i = 0; | |
567 | for (const cooked_index_entry *entry : this->all_entries ()) | |
568 | { | |
569 | QUIT; | |
570 | ||
571 | gdb_printf (" [%zu] ((cooked_index_entry *) %p)\n", i++, entry); | |
572 | gdb_printf (" name: %s\n", entry->name); | |
573 | gdb_printf (" canonical: %s\n", entry->canonical); | |
574 | gdb_printf (" DWARF tag: %s\n", dwarf_tag_name (entry->tag)); | |
575 | gdb_printf (" flags: %s\n", to_string (entry->flags).c_str ()); | |
902d61e3 | 576 | gdb_printf (" DIE offset: 0x%" PRIx64 "\n", |
7d82b08e SM |
577 | to_underlying (entry->die_offset)); |
578 | ||
579 | if (entry->parent_entry != nullptr) | |
580 | gdb_printf (" parent: ((cooked_index_entry *) %p) [%s]\n", | |
581 | entry->parent_entry, entry->parent_entry->name); | |
582 | else | |
583 | gdb_printf (" parent: ((cooked_index_entry *) 0)\n"); | |
584 | ||
585 | gdb_printf ("\n"); | |
586 | } | |
587 | ||
588 | const cooked_index_entry *main_entry = this->get_main (); | |
589 | if (main_entry != nullptr) | |
590 | gdb_printf (" main: ((cooked_index_entry *) %p) [%s]\n", main_entry, | |
591 | main_entry->name); | |
592 | else | |
593 | gdb_printf (" main: ((cooked_index_entry *) 0)\n"); | |
594 | ||
595 | gdb_printf ("\n"); | |
596 | gdb_printf (" address maps:\n"); | |
597 | gdb_printf ("\n"); | |
598 | ||
599 | std::vector<const addrmap *> addrmaps = this->get_addrmaps (); | |
600 | for (i = 0; i < addrmaps.size (); ++i) | |
601 | { | |
602 | const addrmap &addrmap = *addrmaps[i]; | |
603 | ||
604 | gdb_printf (" [%zu] ((addrmap *) %p)\n", i, &addrmap); | |
605 | gdb_printf ("\n"); | |
606 | ||
607 | addrmap.foreach ([arch] (CORE_ADDR start_addr, const void *obj) | |
608 | { | |
609 | QUIT; | |
610 | ||
611 | const char *start_addr_str = paddress (arch, start_addr); | |
612 | ||
613 | if (obj != nullptr) | |
614 | { | |
615 | const dwarf2_per_cu_data *per_cu | |
616 | = static_cast<const dwarf2_per_cu_data *> (obj); | |
617 | gdb_printf (" [%s] ((dwarf2_per_cu_data *) %p)\n", | |
618 | start_addr_str, per_cu); | |
619 | } | |
620 | else | |
621 | gdb_printf (" [%s] ((dwarf2_per_cu_data *) 0)\n", | |
622 | start_addr_str); | |
623 | ||
624 | return 0; | |
625 | }); | |
626 | ||
627 | gdb_printf ("\n"); | |
628 | } | |
629 | } | |
630 | ||
52e5e48e TT |
631 | void |
632 | cooked_index::maybe_write_index (dwarf2_per_bfd *per_bfd) | |
633 | { | |
634 | /* Wait for finalization. */ | |
635 | wait (); | |
636 | ||
637 | /* (maybe) store an index in the cache. */ | |
638 | global_index_cache.store (per_bfd); | |
639 | } | |
640 | ||
641 | /* Wait for all the index cache entries to be written before gdb | |
642 | exits. */ | |
643 | static void | |
644 | wait_for_index_cache (int) | |
645 | { | |
646 | gdb_assert (is_main_thread ()); | |
647 | for (cooked_index *item : active_vectors) | |
648 | item->wait_completely (); | |
649 | } | |
650 | ||
f0c3dcc1 TT |
651 | /* A maint command to wait for the cache. */ |
652 | ||
653 | static void | |
654 | maintenance_wait_for_index_cache (const char *args, int from_tty) | |
655 | { | |
656 | wait_for_index_cache (0); | |
657 | } | |
658 | ||
ac37b79c TT |
659 | void _initialize_cooked_index (); |
660 | void | |
661 | _initialize_cooked_index () | |
662 | { | |
663 | #if GDB_SELF_TEST | |
664 | selftests::register_test ("cooked_index_entry::compare", test_compare); | |
665 | #endif | |
52e5e48e | 666 | |
f0c3dcc1 TT |
667 | add_cmd ("wait-for-index-cache", class_maintenance, |
668 | maintenance_wait_for_index_cache, _("\ | |
4779ed97 TT |
669 | Wait until all pending writes to the index cache have completed.\n\ |
670 | Usage: maintenance wait-for-index-cache"), | |
f0c3dcc1 TT |
671 | &maintenancelist); |
672 | ||
52e5e48e | 673 | gdb::observers::gdb_exiting.attach (wait_for_index_cache, "cooked-index"); |
ac37b79c | 674 | } |