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
13using namespace lldb;
14using namespace lldb_private;
15using namespace std;
16
17// DWARFAbbreviationDeclarationSet::Clear()
18void DWARFAbbreviationDeclarationSet::Clear() {
19  m_idx_offset = 0;
20  m_decls.clear();
21}
22
23// DWARFAbbreviationDeclarationSet::Extract()
24llvm::Error
25DWARFAbbreviationDeclarationSet::extract(const DWARFDataExtractor &data,
26                                         lldb::offset_t *offset_ptr) {
27  const lldb::offset_t begin_offset = *offset_ptr;
28  m_offset = begin_offset;
29  Clear();
30  DWARFAbbreviationDeclaration abbrevDeclaration;
31  dw_uleb128_t prev_abbr_code = 0;
32  while (true) {
33    llvm::Expected<DWARFEnumState> es =
34        abbrevDeclaration.extract(data, offset_ptr);
35    if (!es)
36      return es.takeError();
37    if (*es == DWARFEnumState::Complete)
38      break;
39    m_decls.push_back(abbrevDeclaration);
40    if (m_idx_offset == 0)
41      m_idx_offset = abbrevDeclaration.Code();
42    else if (prev_abbr_code + 1 != abbrevDeclaration.Code()) {
43      // Out of order indexes, we can't do O(1) lookups...
44      m_idx_offset = UINT32_MAX;
45    }
46    prev_abbr_code = abbrevDeclaration.Code();
47  }
48  return llvm::ErrorSuccess();
49}
50
51// DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
52const DWARFAbbreviationDeclaration *
53DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(
54    dw_uleb128_t abbrCode) const {
55  if (m_idx_offset == UINT32_MAX) {
56    DWARFAbbreviationDeclarationCollConstIter pos;
57    DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
58    for (pos = m_decls.begin(); pos != end; ++pos) {
59      if (pos->Code() == abbrCode)
60        return &(*pos);
61    }
62  } else {
63    uint32_t idx = abbrCode - m_idx_offset;
64    if (idx < m_decls.size())
65      return &m_decls[idx];
66  }
67  return nullptr;
68}
69
70
71// DWARFAbbreviationDeclarationSet::GetUnsupportedForms()
72void DWARFAbbreviationDeclarationSet::GetUnsupportedForms(
73    std::set<dw_form_t> &invalid_forms) const {
74  for (const auto &abbr_decl : m_decls) {
75    const size_t num_attrs = abbr_decl.NumAttributes();
76    for (size_t i=0; i<num_attrs; ++i) {
77      dw_form_t form = abbr_decl.GetFormByIndex(i);
78      if (!DWARFFormValue::FormIsSupported(form))
79        invalid_forms.insert(form);
80    }
81  }
82}
83
84// Encode
85//
86// Encode the abbreviation table onto the end of the buffer provided into a
87// byte representation as would be found in a ".debug_abbrev" debug information
88// section.
89// void
90// DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf)
91// const
92//{
93//  DWARFAbbreviationDeclarationCollConstIter pos;
94//  DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
95//  for (pos = m_decls.begin(); pos != end; ++pos)
96//      pos->Append(debug_abbrev_buf);
97//  debug_abbrev_buf.Append8(0);
98//}
99
100// DWARFDebugAbbrev constructor
101DWARFDebugAbbrev::DWARFDebugAbbrev()
102    : m_abbrevCollMap(), m_prev_abbr_offset_pos(m_abbrevCollMap.end()) {}
103
104// DWARFDebugAbbrev::Parse()
105llvm::Error DWARFDebugAbbrev::parse(const DWARFDataExtractor &data) {
106  lldb::offset_t offset = 0;
107
108  while (data.ValidOffset(offset)) {
109    uint32_t initial_cu_offset = offset;
110    DWARFAbbreviationDeclarationSet abbrevDeclSet;
111
112    llvm::Error error = abbrevDeclSet.extract(data, &offset);
113    if (error)
114      return error;
115
116    m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
117  }
118  m_prev_abbr_offset_pos = m_abbrevCollMap.end();
119  return llvm::ErrorSuccess();
120}
121
122// DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
123const DWARFAbbreviationDeclarationSet *
124DWARFDebugAbbrev::GetAbbreviationDeclarationSet(
125    dw_offset_t cu_abbr_offset) const {
126  DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
127  DWARFAbbreviationDeclarationCollMapConstIter pos;
128  if (m_prev_abbr_offset_pos != end &&
129      m_prev_abbr_offset_pos->first == cu_abbr_offset)
130    return &(m_prev_abbr_offset_pos->second);
131  else {
132    pos = m_abbrevCollMap.find(cu_abbr_offset);
133    m_prev_abbr_offset_pos = pos;
134  }
135
136  if (pos != m_abbrevCollMap.end())
137    return &(pos->second);
138  return nullptr;
139}
140
141// DWARFDebugAbbrev::GetUnsupportedForms()
142void DWARFDebugAbbrev::GetUnsupportedForms(
143    std::set<dw_form_t> &invalid_forms) const {
144  for (const auto &pair : m_abbrevCollMap)
145    pair.second.GetUnsupportedForms(invalid_forms);
146}
147