1 //===-- SymbolFileBreakpad.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 "Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h"
10 #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
11 #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Core/Section.h"
15 #include "lldb/Host/FileSystem.h"
16 #include "lldb/Symbol/ObjectFile.h"
17 #include "lldb/Symbol/TypeMap.h"
18 #include "lldb/Utility/Log.h"
19 #include "llvm/ADT/StringExtras.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace lldb_private::breakpad;
24 
25 namespace {
26 class LineIterator {
27 public:
28   // begin iterator for sections of given type
29   LineIterator(ObjectFile &obj, Record::Kind section_type)
30       : m_obj(&obj), m_section_type(toString(section_type)),
31         m_next_section_idx(0) {
32     ++*this;
33   }
34 
35   // end iterator
36   explicit LineIterator(ObjectFile &obj)
37       : m_obj(&obj),
38         m_next_section_idx(m_obj->GetSectionList()->GetNumSections(0)) {}
39 
40   friend bool operator!=(const LineIterator &lhs, const LineIterator &rhs) {
41     assert(lhs.m_obj == rhs.m_obj);
42     if (lhs.m_next_section_idx != rhs.m_next_section_idx)
43       return true;
44     if (lhs.m_next_text.data() != rhs.m_next_text.data())
45       return true;
46     assert(lhs.m_current_text == rhs.m_current_text);
47     assert(rhs.m_next_text == rhs.m_next_text);
48     return false;
49   }
50 
51   const LineIterator &operator++();
52   llvm::StringRef operator*() const { return m_current_text; }
53 
54 private:
55   ObjectFile *m_obj;
56   ConstString m_section_type;
57   uint32_t m_next_section_idx;
58   llvm::StringRef m_current_text;
59   llvm::StringRef m_next_text;
60 };
61 } // namespace
62 
63 const LineIterator &LineIterator::operator++() {
64   const SectionList &list = *m_obj->GetSectionList();
65   size_t num_sections = list.GetNumSections(0);
66   while (m_next_text.empty() && m_next_section_idx < num_sections) {
67     Section &sect = *list.GetSectionAtIndex(m_next_section_idx++);
68     if (sect.GetName() != m_section_type)
69       continue;
70     DataExtractor data;
71     m_obj->ReadSectionData(&sect, data);
72     m_next_text =
73         llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()),
74                         data.GetByteSize());
75   }
76   std::tie(m_current_text, m_next_text) = m_next_text.split('\n');
77   return *this;
78 }
79 
80 static llvm::iterator_range<LineIterator> lines(ObjectFile &obj,
81                                                 Record::Kind section_type) {
82   return llvm::make_range(LineIterator(obj, section_type), LineIterator(obj));
83 }
84 
85 void SymbolFileBreakpad::Initialize() {
86   PluginManager::RegisterPlugin(GetPluginNameStatic(),
87                                 GetPluginDescriptionStatic(), CreateInstance,
88                                 DebuggerInitialize);
89 }
90 
91 void SymbolFileBreakpad::Terminate() {
92   PluginManager::UnregisterPlugin(CreateInstance);
93 }
94 
95 ConstString SymbolFileBreakpad::GetPluginNameStatic() {
96   static ConstString g_name("breakpad");
97   return g_name;
98 }
99 
100 uint32_t SymbolFileBreakpad::CalculateAbilities() {
101   if (!m_obj_file)
102     return 0;
103   if (m_obj_file->GetPluginName() != ObjectFileBreakpad::GetPluginNameStatic())
104     return 0;
105 
106   return CompileUnits | Functions;
107 }
108 
109 uint32_t SymbolFileBreakpad::GetNumCompileUnits() {
110   // TODO
111   return 0;
112 }
113 
114 CompUnitSP SymbolFileBreakpad::ParseCompileUnitAtIndex(uint32_t index) {
115   // TODO
116   return nullptr;
117 }
118 
119 size_t SymbolFileBreakpad::ParseFunctions(CompileUnit &comp_unit) {
120   // TODO
121   return 0;
122 }
123 
124 bool SymbolFileBreakpad::ParseLineTable(CompileUnit &comp_unit) {
125   // TODO
126   return 0;
127 }
128 
129 uint32_t
130 SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr,
131                                          SymbolContextItem resolve_scope,
132                                          SymbolContext &sc) {
133   // TODO
134   return 0;
135 }
136 
137 uint32_t SymbolFileBreakpad::FindFunctions(
138     const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
139     FunctionNameType name_type_mask, bool include_inlines, bool append,
140     SymbolContextList &sc_list) {
141   // TODO
142   if (!append)
143     sc_list.Clear();
144   return sc_list.GetSize();
145 }
146 
147 uint32_t SymbolFileBreakpad::FindFunctions(const RegularExpression &regex,
148                                            bool include_inlines, bool append,
149                                            SymbolContextList &sc_list) {
150   // TODO
151   if (!append)
152     sc_list.Clear();
153   return sc_list.GetSize();
154 }
155 
156 uint32_t SymbolFileBreakpad::FindTypes(
157     const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
158     bool append, uint32_t max_matches,
159     llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {
160   if (!append)
161     types.Clear();
162   return types.GetSize();
163 }
164 
165 size_t
166 SymbolFileBreakpad::FindTypes(const std::vector<CompilerContext> &context,
167                               bool append, TypeMap &types) {
168   if (!append)
169     types.Clear();
170   return types.GetSize();
171 }
172 
173 void SymbolFileBreakpad::AddSymbols(Symtab &symtab) {
174   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
175   Module &module = *m_obj_file->GetModule();
176   addr_t base = module.GetObjectFile()->GetBaseAddress().GetFileAddress();
177   if (base == LLDB_INVALID_ADDRESS) {
178     LLDB_LOG(log, "Unable to fetch the base address of object file. Skipping "
179                   "symtab population.");
180     return;
181   }
182 
183   const SectionList &list = *module.GetSectionList();
184   llvm::DenseMap<addr_t, Symbol> symbols;
185   auto add_symbol = [&](addr_t address, llvm::Optional<addr_t> size,
186                         llvm::StringRef name) {
187     address += base;
188     SectionSP section_sp = list.FindSectionContainingFileAddress(address);
189     if (!section_sp) {
190       LLDB_LOG(log,
191                "Ignoring symbol {0}, whose address ({1}) is outside of the "
192                "object file. Mismatched symbol file?",
193                name, address);
194       return;
195     }
196     symbols.try_emplace(
197         address, /*symID*/ 0, Mangled(name, /*is_mangled*/ false),
198         eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false,
199         /*is_trampoline*/ false, /*is_artificial*/ false,
200         AddressRange(section_sp, address - section_sp->GetFileAddress(),
201                      size.getValueOr(0)),
202         size.hasValue(), /*contains_linker_annotations*/ false, /*flags*/ 0);
203   };
204 
205   for (llvm::StringRef line : lines(*m_obj_file, Record::Func)) {
206     if (auto record = FuncRecord::parse(line))
207       add_symbol(record->getAddress(), record->getSize(), record->getName());
208   }
209 
210   for (llvm::StringRef line : lines(*m_obj_file, Record::Public)) {
211     if (auto record = PublicRecord::parse(line))
212       add_symbol(record->getAddress(), llvm::None, record->getName());
213     else
214       LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line);
215   }
216 
217   for (auto &KV : symbols)
218     symtab.AddSymbol(std::move(KV.second));
219   symtab.CalculateSymbolSizes();
220 }
221