]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/dwarf2/cooked-index.c
gdb: provide const-correct versions of addrmap::find and addrmap::foreach
[thirdparty/binutils-gdb.git] / gdb / dwarf2 / cooked-index.c
CommitLineData
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"
23#include "cp-support.h"
55fc1623 24#include "c-lang.h"
51f5a4b8
TT
25#include "ada-lang.h"
26#include "split-name.h"
27#include <algorithm>
ac37b79c
TT
28#include "safe-ctype.h"
29#include "gdbsupport/selftest.h"
30
31/* See cooked-index.h. */
32
33bool
34cooked_index_entry::compare (const char *stra, const char *strb,
35 bool completing)
36{
37 /* If we've ever matched "<" in both strings, then we disable the
38 special template parameter handling. */
39 bool seen_lt = false;
40
41 while (*stra != '\0'
42 && *strb != '\0'
43 && (TOLOWER ((unsigned char) *stra)
44 == TOLOWER ((unsigned char ) *strb)))
45 {
46 if (*stra == '<')
47 seen_lt = true;
48 ++stra;
49 ++strb;
50 }
51
52 unsigned c1 = TOLOWER ((unsigned char) *stra);
53 unsigned c2 = TOLOWER ((unsigned char) *strb);
54
55 if (completing)
56 {
57 /* When completing, if one string ends earlier than the other,
58 consider them as equal. Also, completion mode ignores the
59 special '<' handling. */
60 if (c1 == '\0' || c2 == '\0')
61 return false;
62 /* Fall through to the generic case. */
63 }
64 else if (seen_lt)
65 {
66 /* Fall through to the generic case. */
67 }
68 else if (c1 == '\0' || c1 == '<')
69 {
70 /* Maybe they both end at the same spot. */
71 if (c2 == '\0' || c2 == '<')
72 return false;
73 /* First string ended earlier. */
74 return true;
75 }
76 else if (c2 == '\0' || c2 == '<')
77 {
78 /* Second string ended earlier. */
79 return false;
80 }
81
82 return c1 < c2;
83}
84
85#if GDB_SELF_TEST
86
87namespace {
88
89void
90test_compare ()
91{
92 SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", false));
93 SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", false));
94 SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", true));
95 SELF_CHECK (!cooked_index_entry::compare ("abcd", "abcd", true));
96
97 SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE", false));
98 SELF_CHECK (!cooked_index_entry::compare ("ABCDE", "abcd", false));
99 SELF_CHECK (!cooked_index_entry::compare ("abcd", "ABCDE", true));
100 SELF_CHECK (!cooked_index_entry::compare ("ABCDE", "abcd", true));
101
102 SELF_CHECK (!cooked_index_entry::compare ("name", "name<>", false));
103 SELF_CHECK (!cooked_index_entry::compare ("name<>", "name", false));
104 SELF_CHECK (!cooked_index_entry::compare ("name", "name<>", true));
105 SELF_CHECK (!cooked_index_entry::compare ("name<>", "name", true));
106
107 SELF_CHECK (!cooked_index_entry::compare ("name<arg>", "name<arg>", false));
108 SELF_CHECK (!cooked_index_entry::compare ("name<arg>", "name<arg>", false));
109 SELF_CHECK (!cooked_index_entry::compare ("name<arg>", "name<arg>", true));
110 SELF_CHECK (!cooked_index_entry::compare ("name<arg>", "name<ag>", true));
111
112 SELF_CHECK (!cooked_index_entry::compare ("name<arg<more>>",
113 "name<arg<more>>", false));
114
115 SELF_CHECK (!cooked_index_entry::compare ("name", "name<arg<more>>", false));
116 SELF_CHECK (!cooked_index_entry::compare ("name<arg<more>>", "name", false));
117 SELF_CHECK (cooked_index_entry::compare ("name<arg<", "name<arg<more>>",
118 false));
119 SELF_CHECK (!cooked_index_entry::compare ("name<arg<",
120 "name<arg<more>>",
121 true));
122 SELF_CHECK (!cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
123 false));
124 SELF_CHECK (!cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
125 true));
126
127 SELF_CHECK (cooked_index_entry::compare ("", "abcd", false));
128 SELF_CHECK (!cooked_index_entry::compare ("", "abcd", true));
129 SELF_CHECK (!cooked_index_entry::compare ("abcd", "", false));
130 SELF_CHECK (!cooked_index_entry::compare ("abcd", "", true));
131}
132
133} /* anonymous namespace */
134
135#endif /* GDB_SELF_TEST */
51f5a4b8 136
51f5a4b8
TT
137/* See cooked-index.h. */
138
139const char *
140cooked_index_entry::full_name (struct obstack *storage) const
141{
72b580b8 142 if ((flags & IS_LINKAGE) != 0 || parent_entry == nullptr)
51f5a4b8
TT
143 return canonical;
144
145 const char *sep = nullptr;
2c474c46 146 switch (per_cu->lang ())
51f5a4b8
TT
147 {
148 case language_cplus:
149 case language_rust:
150 sep = "::";
151 break;
152
153 case language_go:
154 case language_d:
155 case language_ada:
156 sep = ".";
157 break;
51f5a4b8 158
72b580b8
TT
159 default:
160 return canonical;
161 }
51f5a4b8 162
72b580b8 163 parent_entry->write_scope (storage, sep);
51f5a4b8
TT
164 obstack_grow0 (storage, canonical, strlen (canonical));
165 return (const char *) obstack_finish (storage);
166}
167
168/* See cooked-index.h. */
169
170void
171cooked_index_entry::write_scope (struct obstack *storage,
172 const char *sep) const
173{
174 if (parent_entry != nullptr)
175 parent_entry->write_scope (storage, sep);
176 obstack_grow (storage, canonical, strlen (canonical));
177 obstack_grow (storage, sep, strlen (sep));
178}
179
180/* See cooked-index.h. */
181
182const cooked_index_entry *
183cooked_index::add (sect_offset die_offset, enum dwarf_tag tag,
184 cooked_index_flag flags, const char *name,
185 const cooked_index_entry *parent_entry,
186 dwarf2_per_cu_data *per_cu)
187{
188 cooked_index_entry *result = create (die_offset, tag, flags, name,
189 parent_entry, per_cu);
190 m_entries.push_back (result);
191
192 /* An explicitly-tagged main program should always override the
193 implicit "main" discovery. */
194 if ((flags & IS_MAIN) != 0)
195 m_main = result;
2c474c46 196 else if (per_cu->lang () != language_ada
51f5a4b8
TT
197 && m_main == nullptr
198 && strcmp (name, "main") == 0)
199 m_main = result;
200
201 return result;
202}
203
46114cb7
TT
204/* See cooked-index.h. */
205
20a26f4e
TT
206void
207cooked_index::finalize ()
46114cb7 208{
20a26f4e 209 m_future = gdb::thread_pool::g_thread_pool->post_task ([this] ()
46114cb7 210 {
20a26f4e
TT
211 do_finalize ();
212 });
51f5a4b8
TT
213}
214
215/* See cooked-index.h. */
216
217gdb::unique_xmalloc_ptr<char>
20a26f4e
TT
218cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
219 htab_t gnat_entries)
51f5a4b8
TT
220{
221 std::string canonical = ada_decode (entry->name, false, false);
222 if (canonical.empty ())
223 return {};
224 std::vector<gdb::string_view> names = split_name (canonical.c_str (),
225 split_style::DOT);
226 gdb::string_view tail = names.back ();
227 names.pop_back ();
228
229 const cooked_index_entry *parent = nullptr;
230 for (const auto &name : names)
231 {
232 uint32_t hashval = dwarf5_djb_hash (name);
233 void **slot = htab_find_slot_with_hash (gnat_entries, &name,
234 hashval, INSERT);
235 /* CUs are processed in order, so we only need to check the most
236 recent entry. */
237 cooked_index_entry *last = (cooked_index_entry *) *slot;
238 if (last == nullptr || last->per_cu != entry->per_cu)
239 {
240 gdb::unique_xmalloc_ptr<char> new_name
241 = make_unique_xstrndup (name.data (), name.length ());
20a26f4e
TT
242 last = create (entry->die_offset, DW_TAG_namespace,
243 0, new_name.get (), parent,
244 entry->per_cu);
51f5a4b8
TT
245 last->canonical = last->name;
246 m_names.push_back (std::move (new_name));
247 *slot = last;
248 }
249
250 parent = last;
251 }
252
253 entry->parent_entry = parent;
254 return make_unique_xstrndup (tail.data (), tail.length ());
255}
256
257/* See cooked-index.h. */
258
259void
20a26f4e 260cooked_index::do_finalize ()
51f5a4b8
TT
261{
262 auto hash_name_ptr = [] (const void *p)
263 {
264 const cooked_index_entry *entry = (const cooked_index_entry *) p;
265 return htab_hash_pointer (entry->name);
266 };
267
268 auto eq_name_ptr = [] (const void *a, const void *b) -> int
269 {
270 const cooked_index_entry *ea = (const cooked_index_entry *) a;
271 const cooked_index_entry *eb = (const cooked_index_entry *) b;
272 return ea->name == eb->name;
273 };
274
275 /* We can use pointer equality here because names come from
276 .debug_str, which will normally be unique-ified by the linker.
277 Also, duplicates are relatively harmless -- they just mean a bit
278 of extra memory is used. */
279 htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr,
280 nullptr, xcalloc, xfree));
281
5a89072f
TT
282 auto hash_entry = [] (const void *e)
283 {
284 const cooked_index_entry *entry = (const cooked_index_entry *) e;
285 return dwarf5_djb_hash (entry->canonical);
286 };
287
288 auto eq_entry = [] (const void *a, const void *b) -> int
289 {
290 const cooked_index_entry *ae = (const cooked_index_entry *) a;
291 const gdb::string_view *sv = (const gdb::string_view *) b;
292 return (strlen (ae->canonical) == sv->length ()
293 && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
294 };
295
20a26f4e
TT
296 htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
297 nullptr, xcalloc, xfree));
46114cb7 298
20a26f4e
TT
299 for (cooked_index_entry *entry : m_entries)
300 {
301 gdb_assert (entry->canonical == nullptr);
bed34ce7 302 if ((entry->flags & IS_LINKAGE) != 0)
20a26f4e 303 entry->canonical = entry->name;
bed34ce7 304 else if (entry->per_cu->lang () == language_ada)
51f5a4b8 305 {
bed34ce7
TT
306 gdb::unique_xmalloc_ptr<char> canon_name
307 = handle_gnat_encoded_entry (entry, gnat_entries.get ());
308 if (canon_name == nullptr)
309 entry->canonical = entry->name;
310 else
311 {
312 entry->canonical = canon_name.get ();
313 m_names.push_back (std::move (canon_name));
314 }
315 }
55fc1623
TT
316 else if (entry->per_cu->lang () == language_cplus
317 || entry->per_cu->lang () == language_c)
bed34ce7
TT
318 {
319 void **slot = htab_find_slot (seen_names.get (), entry,
320 INSERT);
321 if (*slot == nullptr)
20a26f4e
TT
322 {
323 gdb::unique_xmalloc_ptr<char> canon_name
55fc1623
TT
324 = (entry->per_cu->lang () == language_cplus
325 ? cp_canonicalize_string (entry->name)
326 : c_canonicalize_name (entry->name));
20a26f4e
TT
327 if (canon_name == nullptr)
328 entry->canonical = entry->name;
329 else
330 {
331 entry->canonical = canon_name.get ();
332 m_names.push_back (std::move (canon_name));
333 }
334 }
51f5a4b8
TT
335 else
336 {
bed34ce7
TT
337 const cooked_index_entry *other
338 = (const cooked_index_entry *) *slot;
339 entry->canonical = other->canonical;
51f5a4b8
TT
340 }
341 }
bed34ce7
TT
342 else
343 entry->canonical = entry->name;
51f5a4b8
TT
344 }
345
346 m_names.shrink_to_fit ();
347 m_entries.shrink_to_fit ();
348 std::sort (m_entries.begin (), m_entries.end (),
349 [] (const cooked_index_entry *a, const cooked_index_entry *b)
350 {
351 return *a < *b;
352 });
353}
20a26f4e
TT
354
355/* See cooked-index.h. */
356
357cooked_index::range
35e17631 358cooked_index::find (const std::string &name, bool completing) const
20a26f4e
TT
359{
360 wait ();
361
35e17631 362 auto lower = std::lower_bound (m_entries.cbegin (), m_entries.cend (), name,
20a26f4e 363 [=] (const cooked_index_entry *entry,
ac37b79c 364 const std::string &n)
20a26f4e 365 {
ac37b79c
TT
366 return cooked_index_entry::compare (entry->canonical, n.c_str (),
367 completing);
20a26f4e
TT
368 });
369
35e17631 370 auto upper = std::upper_bound (m_entries.cbegin (), m_entries.cend (), name,
ac37b79c 371 [=] (const std::string &n,
20a26f4e
TT
372 const cooked_index_entry *entry)
373 {
ac37b79c
TT
374 return cooked_index_entry::compare (n.c_str (), entry->canonical,
375 completing);
20a26f4e
TT
376 });
377
378 return range (lower, upper);
379}
380
381cooked_index_vector::cooked_index_vector (vec_type &&vec)
382 : m_vector (std::move (vec))
383{
384 for (auto &idx : m_vector)
385 idx->finalize ();
386}
387
388/* See cooked-index.h. */
389
390dwarf2_per_cu_data *
391cooked_index_vector::lookup (CORE_ADDR addr)
392{
393 for (const auto &index : m_vector)
394 {
395 dwarf2_per_cu_data *result = index->lookup (addr);
396 if (result != nullptr)
397 return result;
398 }
399 return nullptr;
400}
401
402/* See cooked-index.h. */
403
404std::vector<addrmap *>
405cooked_index_vector::get_addrmaps ()
406{
407 std::vector<addrmap *> result;
408 for (const auto &index : m_vector)
409 result.push_back (index->m_addrmap);
410 return result;
411}
412
413/* See cooked-index.h. */
414
415cooked_index_vector::range
35e17631 416cooked_index_vector::find (const std::string &name, bool completing) const
20a26f4e
TT
417{
418 std::vector<cooked_index::range> result_range;
419 result_range.reserve (m_vector.size ());
420 for (auto &entry : m_vector)
421 result_range.push_back (entry->find (name, completing));
422 return range (std::move (result_range));
423}
424
425/* See cooked-index.h. */
426
427const cooked_index_entry *
428cooked_index_vector::get_main () const
429{
430 const cooked_index_entry *result = nullptr;
431
432 for (const auto &index : m_vector)
433 {
434 const cooked_index_entry *entry = index->get_main ();
435 if (result == nullptr
436 || ((result->flags & IS_MAIN) == 0
437 && entry != nullptr
438 && (entry->flags & IS_MAIN) != 0))
439 result = entry;
440 }
441
442 return result;
443}
ac37b79c
TT
444
445void _initialize_cooked_index ();
446void
447_initialize_cooked_index ()
448{
449#if GDB_SELF_TEST
450 selftests::register_test ("cooked_index_entry::compare", test_compare);
451#endif
452}