1 //===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DWARFDebugAbbrev.h"
10 #include "DWARFDataExtractor.h"
11 #include "lldb/Utility/Stream.h"
12 
13 using namespace lldb;
14 using namespace lldb_private;
15 using namespace std;
16 
17 //----------------------------------------------------------------------
18 // DWARFAbbreviationDeclarationSet::Clear()
19 //----------------------------------------------------------------------
20 void DWARFAbbreviationDeclarationSet::Clear() {
21   m_idx_offset = 0;
22   m_decls.clear();
23 }
24 
25 //----------------------------------------------------------------------
26 // DWARFAbbreviationDeclarationSet::Extract()
27 //----------------------------------------------------------------------
28 llvm::Error
29 DWARFAbbreviationDeclarationSet::extract(const DWARFDataExtractor &data,
30                                          lldb::offset_t *offset_ptr) {
31   const lldb::offset_t begin_offset = *offset_ptr;
32   m_offset = begin_offset;
33   Clear();
34   DWARFAbbreviationDeclaration abbrevDeclaration;
35   dw_uleb128_t prev_abbr_code = 0;
36   DWARFEnumState state = DWARFEnumState::MoreItems;
37   while (state == DWARFEnumState::MoreItems) {
38     llvm::Expected<DWARFEnumState> es =
39         abbrevDeclaration.extract(data, offset_ptr);
40     if (!es)
41       return es.takeError();
42 
43     state = *es;
44     m_decls.push_back(abbrevDeclaration);
45     if (m_idx_offset == 0)
46       m_idx_offset = abbrevDeclaration.Code();
47     else {
48       if (prev_abbr_code + 1 != abbrevDeclaration.Code())
49         m_idx_offset =
50             UINT32_MAX; // Out of order indexes, we can't do O(1) lookups...
51     }
52     prev_abbr_code = abbrevDeclaration.Code();
53   }
54   return llvm::ErrorSuccess();
55 }
56 
57 //----------------------------------------------------------------------
58 // DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
59 //----------------------------------------------------------------------
60 const DWARFAbbreviationDeclaration *
61 DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(
62     dw_uleb128_t abbrCode) const {
63   if (m_idx_offset == UINT32_MAX) {
64     DWARFAbbreviationDeclarationCollConstIter pos;
65     DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
66     for (pos = m_decls.begin(); pos != end; ++pos) {
67       if (pos->Code() == abbrCode)
68         return &(*pos);
69     }
70   } else {
71     uint32_t idx = abbrCode - m_idx_offset;
72     if (idx < m_decls.size())
73       return &m_decls[idx];
74   }
75   return NULL;
76 }
77 
78 //----------------------------------------------------------------------
79 // DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential()
80 //
81 // Append an abbreviation declaration with a sequential code for O(n) lookups.
82 // Handy when creating an DWARFAbbreviationDeclarationSet.
83 //----------------------------------------------------------------------
84 dw_uleb128_t DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(
85     const DWARFAbbreviationDeclaration &abbrevDecl) {
86   // Get the next abbreviation code based on our current array size
87   dw_uleb128_t code = m_decls.size() + 1;
88 
89   // Push the new declaration on the back
90   m_decls.push_back(abbrevDecl);
91 
92   // Update the code for this new declaration
93   m_decls.back().SetCode(code);
94 
95   return code; // return the new abbreviation code!
96 }
97 
98 //----------------------------------------------------------------------
99 // DWARFAbbreviationDeclarationSet::GetUnsupportedForms()
100 //----------------------------------------------------------------------
101 void DWARFAbbreviationDeclarationSet::GetUnsupportedForms(
102     std::set<dw_form_t> &invalid_forms) const {
103   for (const auto &abbr_decl : m_decls) {
104     const size_t num_attrs = abbr_decl.NumAttributes();
105     for (size_t i=0; i<num_attrs; ++i) {
106       dw_form_t form = abbr_decl.GetFormByIndex(i);
107       if (!DWARFFormValue::FormIsSupported(form))
108         invalid_forms.insert(form);
109     }
110   }
111 }
112 
113 //----------------------------------------------------------------------
114 // Encode
115 //
116 // Encode the abbreviation table onto the end of the buffer provided into a
117 // byte representation as would be found in a ".debug_abbrev" debug information
118 // section.
119 //----------------------------------------------------------------------
120 // void
121 // DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf)
122 // const
123 //{
124 //  DWARFAbbreviationDeclarationCollConstIter pos;
125 //  DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
126 //  for (pos = m_decls.begin(); pos != end; ++pos)
127 //      pos->Append(debug_abbrev_buf);
128 //  debug_abbrev_buf.Append8(0);
129 //}
130 
131 //----------------------------------------------------------------------
132 // DWARFDebugAbbrev constructor
133 //----------------------------------------------------------------------
134 DWARFDebugAbbrev::DWARFDebugAbbrev()
135     : m_abbrevCollMap(), m_prev_abbr_offset_pos(m_abbrevCollMap.end()) {}
136 
137 //----------------------------------------------------------------------
138 // DWARFDebugAbbrev::Parse()
139 //----------------------------------------------------------------------
140 llvm::Error DWARFDebugAbbrev::parse(const DWARFDataExtractor &data) {
141   lldb::offset_t offset = 0;
142 
143   while (data.ValidOffset(offset)) {
144     uint32_t initial_cu_offset = offset;
145     DWARFAbbreviationDeclarationSet abbrevDeclSet;
146 
147     llvm::Error error = abbrevDeclSet.extract(data, &offset);
148     if (error)
149       return error;
150 
151     m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
152   }
153   m_prev_abbr_offset_pos = m_abbrevCollMap.end();
154   return llvm::ErrorSuccess();
155 }
156 
157 //----------------------------------------------------------------------
158 // DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
159 //----------------------------------------------------------------------
160 const DWARFAbbreviationDeclarationSet *
161 DWARFDebugAbbrev::GetAbbreviationDeclarationSet(
162     dw_offset_t cu_abbr_offset) const {
163   DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
164   DWARFAbbreviationDeclarationCollMapConstIter pos;
165   if (m_prev_abbr_offset_pos != end &&
166       m_prev_abbr_offset_pos->first == cu_abbr_offset)
167     return &(m_prev_abbr_offset_pos->second);
168   else {
169     pos = m_abbrevCollMap.find(cu_abbr_offset);
170     m_prev_abbr_offset_pos = pos;
171   }
172 
173   if (pos != m_abbrevCollMap.end())
174     return &(pos->second);
175   return NULL;
176 }
177 
178 //----------------------------------------------------------------------
179 // DWARFDebugAbbrev::GetUnsupportedForms()
180 //----------------------------------------------------------------------
181 void DWARFDebugAbbrev::GetUnsupportedForms(
182     std::set<dw_form_t> &invalid_forms) const {
183   for (const auto &pair : m_abbrevCollMap)
184     pair.second.GetUnsupportedForms(invalid_forms);
185 }
186