]>
Commit | Line | Data |
---|---|---|
51f5a4b8 TT |
1 | /* DIE indexing |
2 | ||
1d506c26 | 3 | Copyright (C) 2022-2024 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), | |
7d82b08e SM |
51 | MAP_ENUM_FLAG (IS_LINKAGE), |
52 | MAP_ENUM_FLAG (IS_TYPE_DECLARATION), | |
42bd6b5f | 53 | MAP_ENUM_FLAG (IS_PARENT_DEFERRED), |
7d82b08e SM |
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 | ||
33c6eaae TT |
69 | /* Return true if a plain "main" could be the main program for this |
70 | language. Languages that are known to use some other mechanism are | |
71 | excluded here. */ | |
72 | ||
73 | static bool | |
74 | language_may_use_plain_main (enum language lang) | |
75 | { | |
76 | /* No need to handle "unknown" here. */ | |
77 | return (lang == language_c | |
78 | || lang == language_objc | |
79 | || lang == language_cplus | |
80 | || lang == language_m2 | |
81 | || lang == language_asm | |
82 | || lang == language_opencl | |
83 | || lang == language_minimal); | |
84 | } | |
85 | ||
47fe57c9 TT |
86 | /* See cooked-index.h. */ |
87 | ||
c121e82c | 88 | int |
ac37b79c | 89 | cooked_index_entry::compare (const char *stra, const char *strb, |
c121e82c | 90 | comparison_mode mode) |
ac37b79c | 91 | { |
c121e82c TT |
92 | auto munge = [] (char c) -> unsigned char |
93 | { | |
94 | /* We want to sort '<' before any other printable character. | |
95 | So, rewrite '<' to something just before ' '. */ | |
96 | if (c == '<') | |
97 | return '\x1f'; | |
98 | return TOLOWER ((unsigned char) c); | |
99 | }; | |
ac37b79c TT |
100 | |
101 | while (*stra != '\0' | |
102 | && *strb != '\0' | |
c121e82c | 103 | && (munge (*stra) == munge (*strb))) |
ac37b79c | 104 | { |
ac37b79c TT |
105 | ++stra; |
106 | ++strb; | |
107 | } | |
108 | ||
c121e82c TT |
109 | unsigned char c1 = munge (*stra); |
110 | unsigned char c2 = munge (*strb); | |
ac37b79c | 111 | |
c121e82c TT |
112 | if (c1 == c2) |
113 | return 0; | |
114 | ||
115 | /* When completing, if STRB ends earlier than STRA, consider them as | |
116 | equal. When comparing, if STRB ends earlier and STRA ends with | |
117 | '<', consider them as equal. */ | |
118 | if (mode == COMPLETE || (mode == MATCH && c1 == munge ('<'))) | |
ac37b79c | 119 | { |
c121e82c TT |
120 | if (c2 == '\0') |
121 | return 0; | |
ac37b79c TT |
122 | } |
123 | ||
c121e82c | 124 | return c1 < c2 ? -1 : 1; |
ac37b79c TT |
125 | } |
126 | ||
127 | #if GDB_SELF_TEST | |
128 | ||
129 | namespace { | |
130 | ||
131 | void | |
132 | test_compare () | |
133 | { | |
c121e82c TT |
134 | /* Convenience aliases. */ |
135 | const auto mode_compare = cooked_index_entry::MATCH; | |
136 | const auto mode_sort = cooked_index_entry::SORT; | |
137 | const auto mode_complete = cooked_index_entry::COMPLETE; | |
138 | ||
139 | SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", | |
140 | mode_compare) == 0); | |
141 | SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd", | |
142 | mode_complete) == 0); | |
143 | ||
144 | SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", | |
145 | mode_compare) < 0); | |
146 | SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", | |
147 | mode_compare) > 0); | |
148 | SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", | |
149 | mode_complete) < 0); | |
150 | SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd", | |
151 | mode_complete) == 0); | |
152 | ||
153 | SELF_CHECK (cooked_index_entry::compare ("name", "name<>", | |
154 | mode_compare) < 0); | |
155 | SELF_CHECK (cooked_index_entry::compare ("name<>", "name", | |
156 | mode_compare) == 0); | |
157 | SELF_CHECK (cooked_index_entry::compare ("name", "name<>", | |
158 | mode_complete) < 0); | |
159 | SELF_CHECK (cooked_index_entry::compare ("name<>", "name", | |
160 | mode_complete) == 0); | |
161 | ||
162 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", | |
163 | mode_compare) == 0); | |
164 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", | |
165 | mode_compare) > 0); | |
166 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>", | |
167 | mode_complete) == 0); | |
168 | SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>", | |
169 | mode_complete) > 0); | |
170 | ||
171 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", | |
172 | "name<arg<more>>", | |
173 | mode_compare) == 0); | |
174 | ||
175 | SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>", | |
176 | mode_compare) < 0); | |
177 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name", | |
178 | mode_compare) == 0); | |
179 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", | |
180 | mode_compare) > 0); | |
181 | SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<", | |
182 | mode_complete) == 0); | |
183 | ||
184 | SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0); | |
185 | SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0); | |
186 | SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0); | |
187 | SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0); | |
188 | ||
189 | SELF_CHECK (cooked_index_entry::compare ("func", "func<type>", | |
190 | mode_sort) < 0); | |
191 | SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1", | |
192 | mode_sort) < 0); | |
ac37b79c TT |
193 | } |
194 | ||
195 | } /* anonymous namespace */ | |
196 | ||
197 | #endif /* GDB_SELF_TEST */ | |
51f5a4b8 | 198 | |
51f5a4b8 TT |
199 | /* See cooked-index.h. */ |
200 | ||
201 | const char * | |
47fe57c9 | 202 | cooked_index_entry::full_name (struct obstack *storage, bool for_main) const |
51f5a4b8 | 203 | { |
47fe57c9 TT |
204 | const char *local_name = for_main ? name : canonical; |
205 | ||
850fce8b | 206 | if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr) |
47fe57c9 | 207 | return local_name; |
51f5a4b8 TT |
208 | |
209 | const char *sep = nullptr; | |
5902fa8a | 210 | switch (lang) |
51f5a4b8 TT |
211 | { |
212 | case language_cplus: | |
213 | case language_rust: | |
214 | sep = "::"; | |
215 | break; | |
216 | ||
217 | case language_go: | |
218 | case language_d: | |
219 | case language_ada: | |
220 | sep = "."; | |
221 | break; | |
51f5a4b8 | 222 | |
72b580b8 | 223 | default: |
47fe57c9 | 224 | return local_name; |
72b580b8 | 225 | } |
51f5a4b8 | 226 | |
850fce8b | 227 | get_parent ()->write_scope (storage, sep, for_main); |
47fe57c9 | 228 | obstack_grow0 (storage, local_name, strlen (local_name)); |
51f5a4b8 TT |
229 | return (const char *) obstack_finish (storage); |
230 | } | |
231 | ||
232 | /* See cooked-index.h. */ | |
233 | ||
234 | void | |
235 | cooked_index_entry::write_scope (struct obstack *storage, | |
47fe57c9 TT |
236 | const char *sep, |
237 | bool for_main) const | |
51f5a4b8 | 238 | { |
850fce8b TV |
239 | if (get_parent () != nullptr) |
240 | get_parent ()->write_scope (storage, sep, for_main); | |
47fe57c9 TT |
241 | const char *local_name = for_main ? name : canonical; |
242 | obstack_grow (storage, local_name, strlen (local_name)); | |
51f5a4b8 TT |
243 | obstack_grow (storage, sep, strlen (sep)); |
244 | } | |
245 | ||
246 | /* See cooked-index.h. */ | |
247 | ||
920bcec0 | 248 | cooked_index_entry * |
a8dc6718 | 249 | cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag, |
5902fa8a TT |
250 | cooked_index_flag flags, enum language lang, |
251 | const char *name, | |
42bd6b5f | 252 | cooked_index_entry_ref parent_entry, |
a8dc6718 | 253 | dwarf2_per_cu_data *per_cu) |
51f5a4b8 | 254 | { |
5902fa8a | 255 | cooked_index_entry *result = create (die_offset, tag, flags, lang, name, |
51f5a4b8 TT |
256 | parent_entry, per_cu); |
257 | m_entries.push_back (result); | |
258 | ||
259 | /* An explicitly-tagged main program should always override the | |
260 | implicit "main" discovery. */ | |
261 | if ((flags & IS_MAIN) != 0) | |
262 | m_main = result; | |
42bd6b5f TV |
263 | else if ((flags & IS_PARENT_DEFERRED) == 0 |
264 | && parent_entry.resolved == nullptr | |
33c6eaae | 265 | && m_main == nullptr |
5902fa8a | 266 | && language_may_use_plain_main (lang) |
33c6eaae TT |
267 | && strcmp (name, "main") == 0) |
268 | m_main = result; | |
51f5a4b8 TT |
269 | |
270 | return result; | |
271 | } | |
272 | ||
46114cb7 TT |
273 | /* See cooked-index.h. */ |
274 | ||
51f5a4b8 | 275 | gdb::unique_xmalloc_ptr<char> |
a8dc6718 SM |
276 | cooked_index_shard::handle_gnat_encoded_entry (cooked_index_entry *entry, |
277 | htab_t gnat_entries) | |
51f5a4b8 | 278 | { |
957ce537 TT |
279 | /* We decode Ada names in a particular way: operators and wide |
280 | characters are left as-is. This is done to make name matching a | |
281 | bit simpler; and for wide characters, it means the choice of Ada | |
282 | source charset does not affect the indexer directly. */ | |
283 | std::string canonical = ada_decode (entry->name, false, false, false); | |
51f5a4b8 TT |
284 | if (canonical.empty ()) |
285 | return {}; | |
8082468f | 286 | std::vector<std::string_view> names = split_name (canonical.c_str (), |
fe26aa95 | 287 | split_style::DOT_STYLE); |
8082468f | 288 | std::string_view tail = names.back (); |
51f5a4b8 TT |
289 | names.pop_back (); |
290 | ||
291 | const cooked_index_entry *parent = nullptr; | |
292 | for (const auto &name : names) | |
293 | { | |
294 | uint32_t hashval = dwarf5_djb_hash (name); | |
295 | void **slot = htab_find_slot_with_hash (gnat_entries, &name, | |
296 | hashval, INSERT); | |
297 | /* CUs are processed in order, so we only need to check the most | |
298 | recent entry. */ | |
299 | cooked_index_entry *last = (cooked_index_entry *) *slot; | |
300 | if (last == nullptr || last->per_cu != entry->per_cu) | |
301 | { | |
302 | gdb::unique_xmalloc_ptr<char> new_name | |
303 | = make_unique_xstrndup (name.data (), name.length ()); | |
20a26f4e | 304 | last = create (entry->die_offset, DW_TAG_namespace, |
5902fa8a | 305 | 0, language_ada, new_name.get (), parent, |
20a26f4e | 306 | entry->per_cu); |
51f5a4b8 TT |
307 | last->canonical = last->name; |
308 | m_names.push_back (std::move (new_name)); | |
309 | *slot = last; | |
310 | } | |
311 | ||
312 | parent = last; | |
313 | } | |
314 | ||
850fce8b | 315 | entry->set_parent (parent); |
51f5a4b8 TT |
316 | return make_unique_xstrndup (tail.data (), tail.length ()); |
317 | } | |
318 | ||
319 | /* See cooked-index.h. */ | |
320 | ||
321 | void | |
33c6eaae | 322 | cooked_index_shard::finalize () |
51f5a4b8 TT |
323 | { |
324 | auto hash_name_ptr = [] (const void *p) | |
325 | { | |
326 | const cooked_index_entry *entry = (const cooked_index_entry *) p; | |
327 | return htab_hash_pointer (entry->name); | |
328 | }; | |
329 | ||
330 | auto eq_name_ptr = [] (const void *a, const void *b) -> int | |
331 | { | |
332 | const cooked_index_entry *ea = (const cooked_index_entry *) a; | |
333 | const cooked_index_entry *eb = (const cooked_index_entry *) b; | |
334 | return ea->name == eb->name; | |
335 | }; | |
336 | ||
337 | /* We can use pointer equality here because names come from | |
338 | .debug_str, which will normally be unique-ified by the linker. | |
339 | Also, duplicates are relatively harmless -- they just mean a bit | |
340 | of extra memory is used. */ | |
341 | htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr, | |
342 | nullptr, xcalloc, xfree)); | |
343 | ||
5a89072f TT |
344 | auto hash_entry = [] (const void *e) |
345 | { | |
346 | const cooked_index_entry *entry = (const cooked_index_entry *) e; | |
347 | return dwarf5_djb_hash (entry->canonical); | |
348 | }; | |
349 | ||
350 | auto eq_entry = [] (const void *a, const void *b) -> int | |
351 | { | |
352 | const cooked_index_entry *ae = (const cooked_index_entry *) a; | |
8082468f | 353 | const std::string_view *sv = (const std::string_view *) b; |
5a89072f TT |
354 | return (strlen (ae->canonical) == sv->length () |
355 | && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0); | |
356 | }; | |
357 | ||
20a26f4e TT |
358 | htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry, |
359 | nullptr, xcalloc, xfree)); | |
46114cb7 | 360 | |
20a26f4e TT |
361 | for (cooked_index_entry *entry : m_entries) |
362 | { | |
47fe57c9 TT |
363 | /* Note that this code must be kept in sync with |
364 | language_requires_canonicalization. */ | |
20a26f4e | 365 | gdb_assert (entry->canonical == nullptr); |
bed34ce7 | 366 | if ((entry->flags & IS_LINKAGE) != 0) |
20a26f4e | 367 | entry->canonical = entry->name; |
5902fa8a | 368 | else if (entry->lang == language_ada) |
51f5a4b8 | 369 | { |
bed34ce7 TT |
370 | gdb::unique_xmalloc_ptr<char> canon_name |
371 | = handle_gnat_encoded_entry (entry, gnat_entries.get ()); | |
372 | if (canon_name == nullptr) | |
373 | entry->canonical = entry->name; | |
374 | else | |
375 | { | |
376 | entry->canonical = canon_name.get (); | |
377 | m_names.push_back (std::move (canon_name)); | |
378 | } | |
379 | } | |
5902fa8a | 380 | else if (entry->lang == language_cplus || entry->lang == language_c) |
bed34ce7 TT |
381 | { |
382 | void **slot = htab_find_slot (seen_names.get (), entry, | |
383 | INSERT); | |
384 | if (*slot == nullptr) | |
20a26f4e TT |
385 | { |
386 | gdb::unique_xmalloc_ptr<char> canon_name | |
5902fa8a | 387 | = (entry->lang == language_cplus |
55fc1623 TT |
388 | ? cp_canonicalize_string (entry->name) |
389 | : c_canonicalize_name (entry->name)); | |
20a26f4e TT |
390 | if (canon_name == nullptr) |
391 | entry->canonical = entry->name; | |
392 | else | |
393 | { | |
394 | entry->canonical = canon_name.get (); | |
395 | m_names.push_back (std::move (canon_name)); | |
396 | } | |
b6c55de7 | 397 | *slot = entry; |
20a26f4e | 398 | } |
51f5a4b8 TT |
399 | else |
400 | { | |
bed34ce7 TT |
401 | const cooked_index_entry *other |
402 | = (const cooked_index_entry *) *slot; | |
403 | entry->canonical = other->canonical; | |
51f5a4b8 TT |
404 | } |
405 | } | |
bed34ce7 TT |
406 | else |
407 | entry->canonical = entry->name; | |
51f5a4b8 TT |
408 | } |
409 | ||
410 | m_names.shrink_to_fit (); | |
411 | m_entries.shrink_to_fit (); | |
412 | std::sort (m_entries.begin (), m_entries.end (), | |
413 | [] (const cooked_index_entry *a, const cooked_index_entry *b) | |
414 | { | |
415 | return *a < *b; | |
416 | }); | |
417 | } | |
20a26f4e TT |
418 | |
419 | /* See cooked-index.h. */ | |
420 | ||
a8dc6718 SM |
421 | cooked_index_shard::range |
422 | cooked_index_shard::find (const std::string &name, bool completing) const | |
20a26f4e | 423 | { |
c121e82c TT |
424 | cooked_index_entry::comparison_mode mode = (completing |
425 | ? cooked_index_entry::COMPLETE | |
426 | : cooked_index_entry::MATCH); | |
427 | ||
35e17631 | 428 | auto lower = std::lower_bound (m_entries.cbegin (), m_entries.cend (), name, |
20a26f4e | 429 | [=] (const cooked_index_entry *entry, |
ac37b79c | 430 | const std::string &n) |
20a26f4e | 431 | { |
c121e82c | 432 | return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) < 0; |
20a26f4e TT |
433 | }); |
434 | ||
35e17631 | 435 | auto upper = std::upper_bound (m_entries.cbegin (), m_entries.cend (), name, |
ac37b79c | 436 | [=] (const std::string &n, |
20a26f4e TT |
437 | const cooked_index_entry *entry) |
438 | { | |
c121e82c | 439 | return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) > 0; |
20a26f4e TT |
440 | }); |
441 | ||
442 | return range (lower, upper); | |
443 | } | |
444 | ||
307733cc | 445 | |
33c6eaae TT |
446 | cooked_index::cooked_index (dwarf2_per_objfile *per_objfile) |
447 | : m_state (std::make_unique<cooked_index_worker> (per_objfile)), | |
448 | m_per_bfd (per_objfile->per_bfd) | |
20a26f4e | 449 | { |
52e5e48e TT |
450 | /* ACTIVE_VECTORS is not locked, and this assert ensures that this |
451 | will be caught if ever moved to the background. */ | |
452 | gdb_assert (is_main_thread ()); | |
453 | active_vectors.insert (this); | |
454 | } | |
455 | ||
33c6eaae TT |
456 | void |
457 | cooked_index::start_reading () | |
458 | { | |
459 | m_state->start (); | |
460 | } | |
6f214d0f TT |
461 | |
462 | void | |
33c6eaae | 463 | cooked_index::wait (cooked_state desired_state, bool allow_quit) |
6f214d0f | 464 | { |
33c6eaae | 465 | gdb_assert (desired_state != cooked_state::INITIAL); |
8adc5522 | 466 | |
33c6eaae TT |
467 | /* If the state object has been deleted, then that means waiting is |
468 | completely done. */ | |
469 | if (m_state == nullptr) | |
470 | return; | |
471 | ||
472 | if (m_state->wait (desired_state, allow_quit)) | |
473 | { | |
474 | /* Only the main thread can modify this. */ | |
475 | gdb_assert (is_main_thread ()); | |
476 | m_state.reset (nullptr); | |
477 | } | |
478 | } | |
479 | ||
480 | void | |
481 | cooked_index::set_contents (vec_type &&vec) | |
482 | { | |
483 | gdb_assert (m_vector.empty ()); | |
484 | m_vector = std::move (vec); | |
485 | ||
486 | m_state->set (cooked_state::MAIN_AVAILABLE); | |
487 | ||
488 | index_cache_store_context ctx (global_index_cache, m_per_bfd); | |
489 | ||
490 | /* This is run after finalization is done -- but not before. If | |
491 | this task were submitted earlier, it would have to wait for | |
492 | finalization. However, that would take a slot in the global | |
493 | thread pool, and if enough such tasks were submitted at once, it | |
494 | would cause a livelock. */ | |
495 | gdb::task_group finalizers ([this, ctx = std::move (ctx)] () | |
496 | { | |
497 | m_state->set (cooked_state::FINALIZED); | |
498 | maybe_write_index (m_per_bfd, ctx); | |
499 | }); | |
500 | ||
501 | for (auto &idx : m_vector) | |
502 | { | |
503 | auto this_index = idx.get (); | |
504 | finalizers.add_task ([=] () { this_index->finalize (); }); | |
505 | } | |
506 | ||
507 | finalizers.start (); | |
6f214d0f TT |
508 | } |
509 | ||
52e5e48e TT |
510 | cooked_index::~cooked_index () |
511 | { | |
33c6eaae | 512 | /* Wait for index-creation to be done, though this one must also |
52e5e48e TT |
513 | waited for by the per-BFD object to ensure the required data |
514 | remains live. */ | |
33c6eaae | 515 | wait (cooked_state::CACHE_DONE); |
52e5e48e TT |
516 | |
517 | /* Remove our entry from the global list. See the assert in the | |
518 | constructor to understand this. */ | |
519 | gdb_assert (is_main_thread ()); | |
520 | active_vectors.erase (this); | |
20a26f4e TT |
521 | } |
522 | ||
523 | /* See cooked-index.h. */ | |
524 | ||
525 | dwarf2_per_cu_data * | |
bdb4b803 | 526 | cooked_index::lookup (unrelocated_addr addr) |
20a26f4e | 527 | { |
33c6eaae TT |
528 | /* Ensure that the address maps are ready. */ |
529 | wait (cooked_state::MAIN_AVAILABLE, true); | |
20a26f4e TT |
530 | for (const auto &index : m_vector) |
531 | { | |
532 | dwarf2_per_cu_data *result = index->lookup (addr); | |
533 | if (result != nullptr) | |
534 | return result; | |
535 | } | |
536 | return nullptr; | |
537 | } | |
538 | ||
539 | /* See cooked-index.h. */ | |
540 | ||
70ca3a6b | 541 | std::vector<const addrmap *> |
33c6eaae | 542 | cooked_index::get_addrmaps () |
20a26f4e | 543 | { |
33c6eaae TT |
544 | /* Ensure that the address maps are ready. */ |
545 | wait (cooked_state::MAIN_AVAILABLE, true); | |
70ca3a6b | 546 | std::vector<const addrmap *> result; |
20a26f4e TT |
547 | for (const auto &index : m_vector) |
548 | result.push_back (index->m_addrmap); | |
549 | return result; | |
550 | } | |
551 | ||
552 | /* See cooked-index.h. */ | |
553 | ||
19455ee1 | 554 | cooked_index::range |
33c6eaae | 555 | cooked_index::find (const std::string &name, bool completing) |
20a26f4e | 556 | { |
33c6eaae | 557 | wait (cooked_state::FINALIZED, true); |
a8dc6718 | 558 | std::vector<cooked_index_shard::range> result_range; |
20a26f4e TT |
559 | result_range.reserve (m_vector.size ()); |
560 | for (auto &entry : m_vector) | |
561 | result_range.push_back (entry->find (name, completing)); | |
562 | return range (std::move (result_range)); | |
563 | } | |
564 | ||
565 | /* See cooked-index.h. */ | |
566 | ||
33c6eaae TT |
567 | const char * |
568 | cooked_index::get_main_name (struct obstack *obstack, enum language *lang) | |
569 | const | |
570 | { | |
571 | const cooked_index_entry *entry = get_main (); | |
572 | if (entry == nullptr) | |
573 | return nullptr; | |
574 | ||
5902fa8a | 575 | *lang = entry->lang; |
33c6eaae TT |
576 | return entry->full_name (obstack, true); |
577 | } | |
578 | ||
579 | /* See cooked_index.h. */ | |
580 | ||
20a26f4e | 581 | const cooked_index_entry * |
19455ee1 | 582 | cooked_index::get_main () const |
20a26f4e | 583 | { |
33c6eaae | 584 | const cooked_index_entry *best_entry = nullptr; |
20a26f4e TT |
585 | for (const auto &index : m_vector) |
586 | { | |
587 | const cooked_index_entry *entry = index->get_main (); | |
33c6eaae TT |
588 | /* Choose the first "main" we see. We only do this for names |
589 | not requiring canonicalization. At this point in the process | |
590 | names might not have been canonicalized. However, currently, | |
591 | languages that require this step also do not use | |
592 | DW_AT_main_subprogram. An assert is appropriate here because | |
593 | this filtering is done in get_main. */ | |
594 | if (entry != nullptr) | |
47fe57c9 | 595 | { |
33c6eaae TT |
596 | if ((entry->flags & IS_MAIN) != 0) |
597 | { | |
5902fa8a | 598 | if (!language_requires_canonicalization (entry->lang)) |
33c6eaae TT |
599 | { |
600 | /* There won't be one better than this. */ | |
601 | return entry; | |
602 | } | |
603 | } | |
604 | else | |
605 | { | |
606 | /* This is one that is named "main". Here we don't care | |
607 | if the language requires canonicalization, due to how | |
608 | the entry is detected. Entries like this have worse | |
609 | priority than IS_MAIN entries. */ | |
610 | if (best_entry == nullptr) | |
611 | best_entry = entry; | |
612 | } | |
47fe57c9 | 613 | } |
20a26f4e TT |
614 | } |
615 | ||
33c6eaae | 616 | return best_entry; |
20a26f4e | 617 | } |
ac37b79c | 618 | |
7d82b08e SM |
619 | /* See cooked-index.h. */ |
620 | ||
621 | void | |
33c6eaae | 622 | cooked_index::dump (gdbarch *arch) |
7d82b08e | 623 | { |
8f258a6c TV |
624 | auto_obstack temp_storage; |
625 | ||
7d82b08e SM |
626 | gdb_printf (" entries:\n"); |
627 | gdb_printf ("\n"); | |
628 | ||
629 | size_t i = 0; | |
630 | for (const cooked_index_entry *entry : this->all_entries ()) | |
631 | { | |
632 | QUIT; | |
633 | ||
634 | gdb_printf (" [%zu] ((cooked_index_entry *) %p)\n", i++, entry); | |
635 | gdb_printf (" name: %s\n", entry->name); | |
636 | gdb_printf (" canonical: %s\n", entry->canonical); | |
8f258a6c | 637 | gdb_printf (" qualified: %s\n", entry->full_name (&temp_storage, false)); |
7d82b08e SM |
638 | gdb_printf (" DWARF tag: %s\n", dwarf_tag_name (entry->tag)); |
639 | gdb_printf (" flags: %s\n", to_string (entry->flags).c_str ()); | |
b8a175b4 | 640 | gdb_printf (" DIE offset: %s\n", sect_offset_str (entry->die_offset)); |
7d82b08e | 641 | |
42bd6b5f TV |
642 | if ((entry->flags & IS_PARENT_DEFERRED) != 0) |
643 | gdb_printf (" parent: deferred (%" PRIx64 ")\n", | |
644 | entry->get_deferred_parent ()); | |
645 | else if (entry->get_parent () != nullptr) | |
7d82b08e | 646 | gdb_printf (" parent: ((cooked_index_entry *) %p) [%s]\n", |
850fce8b | 647 | entry->get_parent (), entry->get_parent ()->name); |
7d82b08e SM |
648 | else |
649 | gdb_printf (" parent: ((cooked_index_entry *) 0)\n"); | |
650 | ||
651 | gdb_printf ("\n"); | |
652 | } | |
653 | ||
654 | const cooked_index_entry *main_entry = this->get_main (); | |
655 | if (main_entry != nullptr) | |
656 | gdb_printf (" main: ((cooked_index_entry *) %p) [%s]\n", main_entry, | |
657 | main_entry->name); | |
658 | else | |
659 | gdb_printf (" main: ((cooked_index_entry *) 0)\n"); | |
660 | ||
661 | gdb_printf ("\n"); | |
662 | gdb_printf (" address maps:\n"); | |
663 | gdb_printf ("\n"); | |
664 | ||
665 | std::vector<const addrmap *> addrmaps = this->get_addrmaps (); | |
666 | for (i = 0; i < addrmaps.size (); ++i) | |
667 | { | |
668 | const addrmap &addrmap = *addrmaps[i]; | |
669 | ||
670 | gdb_printf (" [%zu] ((addrmap *) %p)\n", i, &addrmap); | |
671 | gdb_printf ("\n"); | |
672 | ||
673 | addrmap.foreach ([arch] (CORE_ADDR start_addr, const void *obj) | |
674 | { | |
675 | QUIT; | |
676 | ||
677 | const char *start_addr_str = paddress (arch, start_addr); | |
678 | ||
679 | if (obj != nullptr) | |
680 | { | |
681 | const dwarf2_per_cu_data *per_cu | |
682 | = static_cast<const dwarf2_per_cu_data *> (obj); | |
683 | gdb_printf (" [%s] ((dwarf2_per_cu_data *) %p)\n", | |
684 | start_addr_str, per_cu); | |
685 | } | |
686 | else | |
687 | gdb_printf (" [%s] ((dwarf2_per_cu_data *) 0)\n", | |
688 | start_addr_str); | |
689 | ||
690 | return 0; | |
691 | }); | |
692 | ||
693 | gdb_printf ("\n"); | |
694 | } | |
695 | } | |
696 | ||
52e5e48e | 697 | void |
8adc5522 TV |
698 | cooked_index::maybe_write_index (dwarf2_per_bfd *per_bfd, |
699 | const index_cache_store_context &ctx) | |
52e5e48e | 700 | { |
52e5e48e | 701 | /* (maybe) store an index in the cache. */ |
33c6eaae TT |
702 | global_index_cache.store (m_per_bfd, ctx); |
703 | m_state->set (cooked_state::CACHE_DONE); | |
52e5e48e TT |
704 | } |
705 | ||
706 | /* Wait for all the index cache entries to be written before gdb | |
707 | exits. */ | |
708 | static void | |
709 | wait_for_index_cache (int) | |
710 | { | |
711 | gdb_assert (is_main_thread ()); | |
712 | for (cooked_index *item : active_vectors) | |
713 | item->wait_completely (); | |
714 | } | |
715 | ||
f0c3dcc1 TT |
716 | /* A maint command to wait for the cache. */ |
717 | ||
718 | static void | |
719 | maintenance_wait_for_index_cache (const char *args, int from_tty) | |
720 | { | |
721 | wait_for_index_cache (0); | |
722 | } | |
723 | ||
ac37b79c TT |
724 | void _initialize_cooked_index (); |
725 | void | |
726 | _initialize_cooked_index () | |
727 | { | |
728 | #if GDB_SELF_TEST | |
729 | selftests::register_test ("cooked_index_entry::compare", test_compare); | |
730 | #endif | |
52e5e48e | 731 | |
f0c3dcc1 TT |
732 | add_cmd ("wait-for-index-cache", class_maintenance, |
733 | maintenance_wait_for_index_cache, _("\ | |
4779ed97 TT |
734 | Wait until all pending writes to the index cache have completed.\n\ |
735 | Usage: maintenance wait-for-index-cache"), | |
f0c3dcc1 TT |
736 | &maintenancelist); |
737 | ||
52e5e48e | 738 | gdb::observers::gdb_exiting.attach (wait_for_index_cache, "cooked-index"); |
ac37b79c | 739 | } |