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::Dump()
59 //----------------------------------------------------------------------
60 void DWARFAbbreviationDeclarationSet::Dump(Stream *s) const {
61   std::for_each(
62       m_decls.begin(), m_decls.end(),
63       bind2nd(std::mem_fun_ref(&DWARFAbbreviationDeclaration::Dump), s));
64 }
65 
66 //----------------------------------------------------------------------
67 // DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
68 //----------------------------------------------------------------------
69 const DWARFAbbreviationDeclaration *
70 DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(
71     dw_uleb128_t abbrCode) const {
72   if (m_idx_offset == UINT32_MAX) {
73     DWARFAbbreviationDeclarationCollConstIter pos;
74     DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
75     for (pos = m_decls.begin(); pos != end; ++pos) {
76       if (pos->Code() == abbrCode)
77         return &(*pos);
78     }
79   } else {
80     uint32_t idx = abbrCode - m_idx_offset;
81     if (idx < m_decls.size())
82       return &m_decls[idx];
83   }
84   return NULL;
85 }
86 
87 //----------------------------------------------------------------------
88 // DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential()
89 //
90 // Append an abbreviation declaration with a sequential code for O(n) lookups.
91 // Handy when creating an DWARFAbbreviationDeclarationSet.
92 //----------------------------------------------------------------------
93 dw_uleb128_t DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(
94     const DWARFAbbreviationDeclaration &abbrevDecl) {
95   // Get the next abbreviation code based on our current array size
96   dw_uleb128_t code = m_decls.size() + 1;
97 
98   // Push the new declaration on the back
99   m_decls.push_back(abbrevDecl);
100 
101   // Update the code for this new declaration
102   m_decls.back().SetCode(code);
103 
104   return code; // return the new abbreviation code!
105 }
106 
107 //----------------------------------------------------------------------
108 // DWARFAbbreviationDeclarationSet::GetUnsupportedForms()
109 //----------------------------------------------------------------------
110 void DWARFAbbreviationDeclarationSet::GetUnsupportedForms(
111     std::set<dw_form_t> &invalid_forms) const {
112   for (const auto &abbr_decl : m_decls) {
113     const size_t num_attrs = abbr_decl.NumAttributes();
114     for (size_t i=0; i<num_attrs; ++i) {
115       dw_form_t form = abbr_decl.GetFormByIndex(i);
116       if (!DWARFFormValue::FormIsSupported(form))
117         invalid_forms.insert(form);
118     }
119   }
120 }
121 
122 //----------------------------------------------------------------------
123 // Encode
124 //
125 // Encode the abbreviation table onto the end of the buffer provided into a
126 // byte representation as would be found in a ".debug_abbrev" debug information
127 // section.
128 //----------------------------------------------------------------------
129 // void
130 // DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf)
131 // const
132 //{
133 //  DWARFAbbreviationDeclarationCollConstIter pos;
134 //  DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
135 //  for (pos = m_decls.begin(); pos != end; ++pos)
136 //      pos->Append(debug_abbrev_buf);
137 //  debug_abbrev_buf.Append8(0);
138 //}
139 
140 //----------------------------------------------------------------------
141 // DWARFDebugAbbrev constructor
142 //----------------------------------------------------------------------
143 DWARFDebugAbbrev::DWARFDebugAbbrev()
144     : m_abbrevCollMap(), m_prev_abbr_offset_pos(m_abbrevCollMap.end()) {}
145 
146 //----------------------------------------------------------------------
147 // DWARFDebugAbbrev::Parse()
148 //----------------------------------------------------------------------
149 llvm::Error DWARFDebugAbbrev::parse(const DWARFDataExtractor &data) {
150   lldb::offset_t offset = 0;
151 
152   while (data.ValidOffset(offset)) {
153     uint32_t initial_cu_offset = offset;
154     DWARFAbbreviationDeclarationSet abbrevDeclSet;
155 
156     llvm::Error error = abbrevDeclSet.extract(data, &offset);
157     if (error)
158       return error;
159 
160     m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
161   }
162   m_prev_abbr_offset_pos = m_abbrevCollMap.end();
163   return llvm::ErrorSuccess();
164 }
165 
166 //----------------------------------------------------------------------
167 // DWARFDebugAbbrev::Dump()
168 //----------------------------------------------------------------------
169 void DWARFDebugAbbrev::Dump(Stream *s) const {
170   if (m_abbrevCollMap.empty()) {
171     s->PutCString("< EMPTY >\n");
172     return;
173   }
174 
175   DWARFAbbreviationDeclarationCollMapConstIter pos;
176   for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos) {
177     s->Printf("Abbrev table for offset: 0x%8.8x\n", pos->first);
178     pos->second.Dump(s);
179   }
180 }
181 
182 //----------------------------------------------------------------------
183 // DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
184 //----------------------------------------------------------------------
185 const DWARFAbbreviationDeclarationSet *
186 DWARFDebugAbbrev::GetAbbreviationDeclarationSet(
187     dw_offset_t cu_abbr_offset) const {
188   DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
189   DWARFAbbreviationDeclarationCollMapConstIter pos;
190   if (m_prev_abbr_offset_pos != end &&
191       m_prev_abbr_offset_pos->first == cu_abbr_offset)
192     return &(m_prev_abbr_offset_pos->second);
193   else {
194     pos = m_abbrevCollMap.find(cu_abbr_offset);
195     m_prev_abbr_offset_pos = pos;
196   }
197 
198   if (pos != m_abbrevCollMap.end())
199     return &(pos->second);
200   return NULL;
201 }
202 
203 //----------------------------------------------------------------------
204 // DWARFDebugAbbrev::GetUnsupportedForms()
205 //----------------------------------------------------------------------
206 void DWARFDebugAbbrev::GetUnsupportedForms(
207     std::set<dw_form_t> &invalid_forms) const {
208   for (const auto &pair : m_abbrevCollMap)
209     pair.second.GetUnsupportedForms(invalid_forms);
210 }
211