1/* DIE indexing
2
3   Copyright (C) 2024 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#ifndef GDB_DWARF2_PARENT_MAP_H
21#define GDB_DWARF2_PARENT_MAP_H
22
23#include <algorithm>
24
25class cooked_index_entry;
26
27/* A class that handles mapping from a DIE range to a parent
28   entry.
29
30   The generated DWARF can sometimes have the declaration for a method
31   in a class (or perhaps namespace) scope, with the definition
32   appearing outside this scope... just one of the many bad things
33   about DWARF.  In order to handle this situation, we defer certain
34   entries until the end of scanning, at which point we'll know the
35   containing context of all the DIEs that we might have scanned.  */
36class parent_map
37{
38public:
39
40  parent_map () = default;
41  ~parent_map () = default;
42
43  /* Move only.  */
44  DISABLE_COPY_AND_ASSIGN (parent_map);
45  parent_map (parent_map &&) = default;
46  parent_map &operator= (parent_map &&) = default;
47
48  /* A reasonably opaque type that is used here to combine a section
49     offset and the 'dwz' flag into a single value.  */
50  enum addr_type : CORE_ADDR { };
51
52  /* Turn a section offset into a value that can be used in a parent
53     map.  */
54  static addr_type form_addr (sect_offset offset, bool is_dwz)
55  {
56    CORE_ADDR value = to_underlying (offset);
57    if (is_dwz)
58      value |= ((CORE_ADDR) 1) << (8 * sizeof (CORE_ADDR) - 1);
59    return addr_type (value);
60  }
61
62  /* Add a new entry to this map.  DIEs from START to END, inclusive,
63     are mapped to PARENT.  */
64  void add_entry (addr_type start, addr_type end,
65		  const cooked_index_entry *parent)
66  {
67    gdb_assert (parent != nullptr);
68    m_map.set_empty (start, end, (void *) parent);
69  }
70
71  /* Look up an entry in this map.  */
72  const cooked_index_entry *find (addr_type search) const
73  {
74    return static_cast<const cooked_index_entry *> (m_map.find (search));
75  }
76
77  /* Return a fixed addrmap that is equivalent to this map.  */
78  addrmap_fixed *to_fixed (struct obstack *obstack) const
79  {
80    return new (obstack) addrmap_fixed (obstack, &m_map);
81  }
82
83private:
84
85  /* An addrmap that maps from section offsets to cooked_index_entry *.  */
86  addrmap_mutable m_map;
87};
88
89/* Keep a collection of parent_map objects, and allow for lookups
90   across all of them.  */
91class parent_map_map
92{
93public:
94
95  parent_map_map () = default;
96  ~parent_map_map () = default;
97
98  DISABLE_COPY_AND_ASSIGN (parent_map_map);
99
100  /* Add a parent_map to this map.  */
101  void add_map (const parent_map &map)
102  {
103    m_maps.push_back (map.to_fixed (&m_storage));
104  }
105
106  /* Look up an entry in this map.  */
107  const cooked_index_entry *find (parent_map::addr_type search) const
108  {
109    for (const auto &iter : m_maps)
110      {
111	const cooked_index_entry *result
112	  = static_cast<const cooked_index_entry *> (iter->find (search));
113	if (result != nullptr)
114	  return result;
115      }
116    return nullptr;
117  }
118
119private:
120
121  /* Storage for the convert maps.  */
122  auto_obstack m_storage;
123
124  /* While conceptually this class is a combination of parent_maps, in
125     practice it is just a number of fixed maps.  This is important
126     because we want to allow concurrent lookups, but a mutable
127     addrmap is based on a splay-tree, which is not thread-safe, even
128     for nominally read-only lookups.  */
129  std::vector<addrmap_fixed *> m_maps;
130};
131
132#endif /* GDB_DWARF2_PARENT_MAP_H */
133