1 //===-- NameToDIE.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "DWARFUnit.h"
11 #include "lldb/Core/DataFileCache.h"
12 #include "lldb/Symbol/ObjectFile.h"
13 #include "lldb/Utility/ConstString.h"
14 #include "lldb/Utility/DataEncoder.h"
15 #include "lldb/Utility/DataExtractor.h"
16 #include "lldb/Utility/RegularExpression.h"
17 #include "lldb/Utility/Stream.h"
18 #include "lldb/Utility/StreamString.h"
22 using namespace lldb_private
;
23 using namespace lldb_private::plugin::dwarf
;
25 void NameToDIE::Finalize() {
26 m_map
.Sort(std::less
<DIERef
>());
30 void NameToDIE::Insert(ConstString name
, const DIERef
&die_ref
) {
31 m_map
.Append(name
, die_ref
);
34 bool NameToDIE::Find(ConstString name
,
35 llvm::function_ref
<bool(DIERef ref
)> callback
) const {
36 for (const auto &entry
: m_map
.equal_range(name
))
37 if (!callback(entry
.value
))
42 bool NameToDIE::Find(const RegularExpression
®ex
,
43 llvm::function_ref
<bool(DIERef ref
)> callback
) const {
44 for (const auto &entry
: m_map
)
45 if (regex
.Execute(entry
.cstring
.GetCString())) {
46 if (!callback(entry
.value
))
52 void NameToDIE::FindAllEntriesForUnit(
53 DWARFUnit
&s_unit
, llvm::function_ref
<bool(DIERef ref
)> callback
) const {
54 const DWARFUnit
&ns_unit
= s_unit
.GetNonSkeletonUnit();
55 const uint32_t size
= m_map
.GetSize();
56 for (uint32_t i
= 0; i
< size
; ++i
) {
57 const DIERef
&die_ref
= m_map
.GetValueAtIndexUnchecked(i
);
58 if (ns_unit
.GetSymbolFileDWARF().GetFileIndex() == die_ref
.file_index() &&
59 ns_unit
.GetDebugSection() == die_ref
.section() &&
60 ns_unit
.GetOffset() <= die_ref
.die_offset() &&
61 die_ref
.die_offset() < ns_unit
.GetNextUnitOffset()) {
62 if (!callback(die_ref
))
68 void NameToDIE::Dump(Stream
*s
) {
69 const uint32_t size
= m_map
.GetSize();
70 for (uint32_t i
= 0; i
< size
; ++i
) {
71 s
->Format("{0} \"{1}\"\n", m_map
.GetValueAtIndexUnchecked(i
),
72 m_map
.GetCStringAtIndexUnchecked(i
));
76 void NameToDIE::ForEach(
77 std::function
<bool(ConstString name
, const DIERef
&die_ref
)> const
79 const uint32_t size
= m_map
.GetSize();
80 for (uint32_t i
= 0; i
< size
; ++i
) {
81 if (!callback(m_map
.GetCStringAtIndexUnchecked(i
),
82 m_map
.GetValueAtIndexUnchecked(i
)))
87 void NameToDIE::Append(const NameToDIE
&other
) {
88 const uint32_t size
= other
.m_map
.GetSize();
89 for (uint32_t i
= 0; i
< size
; ++i
) {
90 m_map
.Append(other
.m_map
.GetCStringAtIndexUnchecked(i
),
91 other
.m_map
.GetValueAtIndexUnchecked(i
));
95 constexpr llvm::StringLiteral
kIdentifierNameToDIE("N2DI");
97 bool NameToDIE::Decode(const DataExtractor
&data
, lldb::offset_t
*offset_ptr
,
98 const StringTableReader
&strtab
) {
100 llvm::StringRef
identifier((const char *)data
.GetData(offset_ptr
, 4), 4);
101 if (identifier
!= kIdentifierNameToDIE
)
103 const uint32_t count
= data
.GetU32(offset_ptr
);
104 m_map
.Reserve(count
);
105 for (uint32_t i
= 0; i
< count
; ++i
) {
106 llvm::StringRef
str(strtab
.Get(data
.GetU32(offset_ptr
)));
107 // No empty strings allowed in the name to DIE maps.
110 if (std::optional
<DIERef
> die_ref
= DIERef::Decode(data
, offset_ptr
))
111 m_map
.Append(ConstString(str
), *die_ref
);
115 // We must sort the UniqueCStringMap after decoding it since it is a vector
116 // of UniqueCStringMap::Entry objects which contain a ConstString and type T.
117 // ConstString objects are sorted by "const char *" and then type T and
118 // the "const char *" are point values that will depend on the order in which
119 // ConstString objects are created and in which of the 256 string pools they
120 // are created in. So after we decode all of the entries, we must sort the
121 // name map to ensure name lookups succeed. If we encode and decode within
122 // the same process we wouldn't need to sort, so unit testing didn't catch
123 // this issue when first checked in.
124 m_map
.Sort(std::less
<DIERef
>());
128 void NameToDIE::Encode(DataEncoder
&encoder
, ConstStringTable
&strtab
) const {
129 encoder
.AppendData(kIdentifierNameToDIE
);
130 encoder
.AppendU32(m_map
.GetSize());
131 for (const auto &entry
: m_map
) {
132 // Make sure there are no empty strings.
133 assert((bool)entry
.cstring
);
134 encoder
.AppendU32(strtab
.Add(entry
.cstring
));
135 entry
.value
.Encode(encoder
);
139 bool NameToDIE::operator==(const NameToDIE
&rhs
) const {
140 const size_t size
= m_map
.GetSize();
141 if (size
!= rhs
.m_map
.GetSize())
143 for (size_t i
= 0; i
< size
; ++i
) {
144 if (m_map
.GetCStringAtIndex(i
) != rhs
.m_map
.GetCStringAtIndex(i
))
146 if (m_map
.GetValueRefAtIndexUnchecked(i
) !=
147 rhs
.m_map
.GetValueRefAtIndexUnchecked(i
))