Bug Summary

File:src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
Warning:line 280, column 7
Value stored to 'length' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name DWARFUnit.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../include -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/obj -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/include -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/clang/include -I /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/obj/../include/lldb/Plugins -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
1//===-- DWARFUnit.cpp -----------------------------------------------------===//
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 "DWARFUnit.h"
10
11#include "lldb/Core/Module.h"
12#include "lldb/Host/StringConvert.h"
13#include "lldb/Symbol/ObjectFile.h"
14#include "lldb/Utility/LLDBAssert.h"
15#include "lldb/Utility/StreamString.h"
16#include "lldb/Utility/Timer.h"
17#include "llvm/Object/Error.h"
18
19#include "DWARFCompileUnit.h"
20#include "DWARFDebugAranges.h"
21#include "DWARFDebugInfo.h"
22#include "DWARFTypeUnit.h"
23#include "LogChannelDWARF.h"
24#include "SymbolFileDWARFDwo.h"
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace std;
29
30extern int g_verbose;
31
32DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
33 const DWARFUnitHeader &header,
34 const DWARFAbbreviationDeclarationSet &abbrevs,
35 DIERef::Section section, bool is_dwo)
36 : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),
37 m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo),
38 m_dwo_id(header.GetDWOId()) {}
39
40DWARFUnit::~DWARFUnit() = default;
41
42// Parses first DIE of a compile unit.
43void DWARFUnit::ExtractUnitDIEIfNeeded() {
44 {
45 llvm::sys::ScopedReader lock(m_first_die_mutex);
46 if (m_first_die)
47 return; // Already parsed
48 }
49 llvm::sys::ScopedWriter lock(m_first_die_mutex);
50 if (m_first_die)
51 return; // Already parsed
52
53 LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", GetOffset())static ::lldb_private::Timer::Category _cat(__PRETTY_FUNCTION__
); ::lldb_private::Timer _scoped_timer(_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()"
, GetOffset()); do { } while (0); auto _scoped_signpost = llvm
::make_scope_exit([&_scoped_timer]() { ::lldb_private::GetSignposts
().endInterval(&_scoped_timer); })
;
54
55 // Set the offset to that of the first DIE and calculate the start of the
56 // next compilation unit header.
57 lldb::offset_t offset = GetFirstDIEOffset();
58
59 // We are in our compile unit, parse starting at the offset we were told to
60 // parse
61 const DWARFDataExtractor &data = GetData();
62 if (offset < GetNextUnitOffset() &&
63 m_first_die.Extract(data, this, &offset)) {
64 AddUnitDIE(m_first_die);
65 return;
66 }
67}
68
69// Parses a compile unit and indexes its DIEs if it hasn't already been done.
70// It will leave this compile unit extracted forever.
71void DWARFUnit::ExtractDIEsIfNeeded() {
72 m_cancel_scopes = true;
73
74 {
75 llvm::sys::ScopedReader lock(m_die_array_mutex);
76 if (!m_die_array.empty())
77 return; // Already parsed
78 }
79 llvm::sys::ScopedWriter lock(m_die_array_mutex);
80 if (!m_die_array.empty())
81 return; // Already parsed
82
83 ExtractDIEsRWLocked();
84}
85
86// Parses a compile unit and indexes its DIEs if it hasn't already been done.
87// It will clear this compile unit after returned instance gets out of scope,
88// no other ScopedExtractDIEs instance is running for this compile unit
89// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs
90// lifetime.
91DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() {
92 ScopedExtractDIEs scoped(*this);
93
94 {
95 llvm::sys::ScopedReader lock(m_die_array_mutex);
96 if (!m_die_array.empty())
97 return scoped; // Already parsed
98 }
99 llvm::sys::ScopedWriter lock(m_die_array_mutex);
100 if (!m_die_array.empty())
101 return scoped; // Already parsed
102
103 // Otherwise m_die_array would be already populated.
104 lldbassert(!m_cancel_scopes)lldb_private::lldb_assert(static_cast<bool>(!m_cancel_scopes
), "!m_cancel_scopes", __FUNCTION__, "/usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp"
, 104)
;
105
106 ExtractDIEsRWLocked();
107 scoped.m_clear_dies = true;
108 return scoped;
109}
110
111DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) {
112 m_cu->m_die_array_scoped_mutex.lock_shared();
113}
114
115DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() {
116 if (!m_cu)
117 return;
118 m_cu->m_die_array_scoped_mutex.unlock_shared();
119 if (!m_clear_dies || m_cu->m_cancel_scopes)
120 return;
121 // Be sure no other ScopedExtractDIEs is running anymore.
122 llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex);
123 llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex);
124 if (m_cu->m_cancel_scopes)
125 return;
126 m_cu->ClearDIEsRWLocked();
127}
128
129DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs)
130 : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) {
131 rhs.m_cu = nullptr;
132}
133
134DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=(
135 DWARFUnit::ScopedExtractDIEs &&rhs) {
136 m_cu = rhs.m_cu;
137 rhs.m_cu = nullptr;
138 m_clear_dies = rhs.m_clear_dies;
139 return *this;
140}
141
142// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be
143// held R/W and m_die_array must be empty.
144void DWARFUnit::ExtractDIEsRWLocked() {
145 llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);
146
147 LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset())static ::lldb_private::Timer::Category _cat(__PRETTY_FUNCTION__
); ::lldb_private::Timer _scoped_timer(_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()"
, GetOffset()); do { } while (0); auto _scoped_signpost = llvm
::make_scope_exit([&_scoped_timer]() { ::lldb_private::GetSignposts
().endInterval(&_scoped_timer); })
;
148
149 // Set the offset to that of the first DIE and calculate the start of the
150 // next compilation unit header.
151 lldb::offset_t offset = GetFirstDIEOffset();
152 lldb::offset_t next_cu_offset = GetNextUnitOffset();
153
154 DWARFDebugInfoEntry die;
155
156 uint32_t depth = 0;
157 // We are in our compile unit, parse starting at the offset we were told to
158 // parse
159 const DWARFDataExtractor &data = GetData();
160 std::vector<uint32_t> die_index_stack;
161 die_index_stack.reserve(32);
162 die_index_stack.push_back(0);
163 bool prev_die_had_children = false;
164 while (offset < next_cu_offset && die.Extract(data, this, &offset)) {
165 const bool null_die = die.IsNULL();
166 if (depth == 0) {
167 assert(m_die_array.empty() && "Compile unit DIE already added")((void)0);
168
169 // The average bytes per DIE entry has been seen to be around 14-20 so
170 // lets pre-reserve half of that since we are now stripping the NULL
171 // tags.
172
173 // Only reserve the memory if we are adding children of the main
174 // compile unit DIE. The compile unit DIE is always the first entry, so
175 // if our size is 1, then we are adding the first compile unit child
176 // DIE and should reserve the memory.
177 m_die_array.reserve(GetDebugInfoSize() / 24);
178 m_die_array.push_back(die);
179
180 if (!m_first_die)
181 AddUnitDIE(m_die_array.front());
182
183 // With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile
184 // units. We are not able to access these DIE *and* the dwo file
185 // simultaneously. We also don't need to do that as the dwo file will
186 // contain a superset of information. So, we don't even attempt to parse
187 // any remaining DIEs.
188 if (m_dwo) {
189 m_die_array.front().SetHasChildren(false);
190 break;
191 }
192
193 } else {
194 if (null_die) {
195 if (prev_die_had_children) {
196 // This will only happen if a DIE says is has children but all it
197 // contains is a NULL tag. Since we are removing the NULL DIEs from
198 // the list (saves up to 25% in C++ code), we need a way to let the
199 // DIE know that it actually doesn't have children.
200 if (!m_die_array.empty())
201 m_die_array.back().SetHasChildren(false);
202 }
203 } else {
204 die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]);
205
206 if (die_index_stack.back())
207 m_die_array[die_index_stack.back()].SetSiblingIndex(
208 m_die_array.size() - die_index_stack.back());
209
210 // Only push the DIE if it isn't a NULL DIE
211 m_die_array.push_back(die);
212 }
213 }
214
215 if (null_die) {
216 // NULL DIE.
217 if (!die_index_stack.empty())
218 die_index_stack.pop_back();
219
220 if (depth > 0)
221 --depth;
222 prev_die_had_children = false;
223 } else {
224 die_index_stack.back() = m_die_array.size() - 1;
225 // Normal DIE
226 const bool die_has_children = die.HasChildren();
227 if (die_has_children) {
228 die_index_stack.push_back(0);
229 ++depth;
230 }
231 prev_die_had_children = die_has_children;
232 }
233
234 if (depth == 0)
235 break; // We are done with this compile unit!
236 }
237
238 if (!m_die_array.empty()) {
239 // The last die cannot have children (if it did, it wouldn't be the last one).
240 // This only makes a difference for malformed dwarf that does not have a
241 // terminating null die.
242 m_die_array.back().SetHasChildren(false);
243
244 if (m_first_die) {
245 // Only needed for the assertion.
246 m_first_die.SetHasChildren(m_die_array.front().HasChildren());
247 lldbassert(m_first_die == m_die_array.front())lldb_private::lldb_assert(static_cast<bool>(m_first_die
== m_die_array.front()), "m_first_die == m_die_array.front()"
, __FUNCTION__, "/usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp"
, 247)
;
248 }
249 m_first_die = m_die_array.front();
250 }
251
252 m_die_array.shrink_to_fit();
253
254 if (m_dwo)
255 m_dwo->ExtractDIEsIfNeeded();
256}
257
258// This is used when a split dwarf is enabled.
259// A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute
260// that points to the first string offset of the CU contribution to the
261// .debug_str_offsets. At the same time, the corresponding split debug unit also
262// may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and
263// for that case, we should find the offset (skip the section header).
264void DWARFUnit::SetDwoStrOffsetsBase() {
265 lldb::offset_t baseOffset = 0;
266
267 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) {
268 if (const auto *contribution =
269 entry->getContribution(llvm::DW_SECT_STR_OFFSETS))
270 baseOffset = contribution->Offset;
271 else
272 return;
273 }
274
275 if (GetVersion() >= 5) {
276 const DWARFDataExtractor &strOffsets =
277 GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
278 uint64_t length = strOffsets.GetU32(&baseOffset);
279 if (length == 0xffffffff)
280 length = strOffsets.GetU64(&baseOffset);
Value stored to 'length' is never read
281
282 // Check version.
283 if (strOffsets.GetU16(&baseOffset) < 5)
284 return;
285
286 // Skip padding.
287 baseOffset += 2;
288 }
289
290 SetStrOffsetsBase(baseOffset);
291}
292
293uint64_t DWARFUnit::GetDWOId() {
294 ExtractUnitDIEIfNeeded();
295 return m_dwo_id;
296}
297
298// m_die_array_mutex must be already held as read/write.
299void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
300 llvm::Optional<uint64_t> addr_base, gnu_addr_base, gnu_ranges_base;
301
302 DWARFAttributes attributes;
303 size_t num_attributes = cu_die.GetAttributes(this, attributes);
304
305 // Extract DW_AT_addr_base first, as other attributes may need it.
306 for (size_t i = 0; i < num_attributes; ++i) {
307 if (attributes.AttributeAtIndex(i) != DW_AT_addr_base)
308 continue;
309 DWARFFormValue form_value;
310 if (attributes.ExtractFormValueAtIndex(i, form_value)) {
311 addr_base = form_value.Unsigned();
312 SetAddrBase(*addr_base);
313 break;
314 }
315 }
316
317 for (size_t i = 0; i < num_attributes; ++i) {
318 dw_attr_t attr = attributes.AttributeAtIndex(i);
319 DWARFFormValue form_value;
320 if (!attributes.ExtractFormValueAtIndex(i, form_value))
321 continue;
322 switch (attr) {
323 case DW_AT_loclists_base:
324 SetLoclistsBase(form_value.Unsigned());
325 break;
326 case DW_AT_rnglists_base:
327 SetRangesBase(form_value.Unsigned());
328 break;
329 case DW_AT_str_offsets_base:
330 SetStrOffsetsBase(form_value.Unsigned());
331 break;
332 case DW_AT_low_pc:
333 SetBaseAddress(form_value.Address());
334 break;
335 case DW_AT_entry_pc:
336 // If the value was already set by DW_AT_low_pc, don't update it.
337 if (m_base_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL)
338 SetBaseAddress(form_value.Address());
339 break;
340 case DW_AT_stmt_list:
341 m_line_table_offset = form_value.Unsigned();
342 break;
343 case DW_AT_GNU_addr_base:
344 gnu_addr_base = form_value.Unsigned();
345 break;
346 case DW_AT_GNU_ranges_base:
347 gnu_ranges_base = form_value.Unsigned();
348 break;
349 case DW_AT_GNU_dwo_id:
350 m_dwo_id = form_value.Unsigned();
351 break;
352 }
353 }
354
355 if (m_is_dwo) {
356 SetDwoStrOffsetsBase();
357 return;
358 }
359
360 std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file =
361 m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die);
362 if (!dwo_symbol_file)
363 return;
364
365 DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id);
366
367 if (!dwo_cu)
368 return; // Can't fetch the compile unit from the dwo file.
369 dwo_cu->SetUserData(this);
370
371 DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();
372 if (!dwo_cu_die.IsValid())
373 return; // Can't fetch the compile unit DIE from the dwo file.
374
375 // Here for DWO CU we want to use the address base set in the skeleton unit
376 // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base
377 // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_*
378 // attributes which were applicable to the DWO units. The corresponding
379 // DW_AT_* attributes standardized in DWARF v5 are also applicable to the main
380 // unit in contrast.
381 if (addr_base)
382 dwo_cu->SetAddrBase(*addr_base);
383 else if (gnu_addr_base)
384 dwo_cu->SetAddrBase(*gnu_addr_base);
385
386 if (GetVersion() <= 4 && gnu_ranges_base)
387 dwo_cu->SetRangesBase(*gnu_ranges_base);
388 else if (dwo_symbol_file->GetDWARFContext()
389 .getOrLoadRngListsData()
390 .GetByteSize() > 0)
391 dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));
392
393 if (GetVersion() >= 5 &&
394 dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() >
395 0)
396 dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));
397 dwo_cu->SetBaseAddress(GetBaseAddress());
398
399 m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu);
400}
401
402size_t DWARFUnit::GetDebugInfoSize() const {
403 return GetLengthByteSize() + GetLength() - GetHeaderByteSize();
404}
405
406const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const {
407 return m_abbrevs;
408}
409
410dw_offset_t DWARFUnit::GetAbbrevOffset() const {
411 return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET(~(dw_offset_t)0);
412}
413
414dw_offset_t DWARFUnit::GetLineTableOffset() {
415 ExtractUnitDIEIfNeeded();
416 return m_line_table_offset;
417}
418
419void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; }
420
421// Parse the rangelist table header, including the optional array of offsets
422// following it (DWARF v5 and later).
423template <typename ListTableType>
424static llvm::Expected<ListTableType>
425ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset,
426 DwarfFormat format) {
427 // We are expected to be called with Offset 0 or pointing just past the table
428 // header. Correct Offset in the latter case so that it points to the start
429 // of the header.
430 if (offset > 0) {
431 uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format);
432 if (offset < HeaderSize)
433 return llvm::createStringError(errc::invalid_argument,
434 "did not detect a valid"
435 " list table with base = 0x%" PRIx64"llx" "\n",
436 offset);
437 offset -= HeaderSize;
438 }
439 ListTableType Table;
440 if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset))
441 return std::move(E);
442 return Table;
443}
444
445void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) {
446 m_loclists_base = loclists_base;
447
448 uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32);
449 if (loclists_base < header_size)
450 return;
451
452 m_loclist_table_header.emplace(".debug_loclists", "locations");
453 uint64_t offset = loclists_base - header_size;
454 if (llvm::Error E = m_loclist_table_header->extract(
455 m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(),
456 &offset)) {
457 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
458 "Failed to extract location list table at offset 0x%" PRIx64"llx" ": %s",
459 loclists_base, toString(std::move(E)).c_str());
460 }
461}
462
463std::unique_ptr<llvm::DWARFLocationTable>
464DWARFUnit::GetLocationTable(const DataExtractor &data) const {
465 llvm::DWARFDataExtractor llvm_data(
466 data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle,
467 data.GetAddressByteSize());
468
469 if (m_is_dwo || GetVersion() >= 5)
470 return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion());
471 return std::make_unique<llvm::DWARFDebugLoc>(llvm_data);
472}
473
474DWARFDataExtractor DWARFUnit::GetLocationData() const {
475 DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();
476 const DWARFDataExtractor &data =
477 GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData();
478 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) {
479 if (const auto *contribution = entry->getContribution(llvm::DW_SECT_EXT_LOC))
480 return DWARFDataExtractor(data, contribution->Offset,
481 contribution->Length);
482 return DWARFDataExtractor();
483 }
484 return data;
485}
486
487void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {
488 lldbassert(!m_rnglist_table_done)lldb_private::lldb_assert(static_cast<bool>(!m_rnglist_table_done
), "!m_rnglist_table_done", __FUNCTION__, "/usr/src/gnu/usr.bin/clang/liblldbPluginSymbolFile/../../../llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp"
, 488)
;
489
490 m_ranges_base = ranges_base;
491}
492
493const llvm::Optional<llvm::DWARFDebugRnglistTable> &
494DWARFUnit::GetRnglistTable() {
495 if (GetVersion() >= 5 && !m_rnglist_table_done) {
496 m_rnglist_table_done = true;
497 if (auto table_or_error =
498 ParseListTableHeader<llvm::DWARFDebugRnglistTable>(
499 m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(),
500 m_ranges_base, DWARF32))
501 m_rnglist_table = std::move(table_or_error.get());
502 else
503 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
504 "Failed to extract range list table at offset 0x%" PRIx64"llx" ": %s",
505 m_ranges_base, toString(table_or_error.takeError()).c_str());
506 }
507 return m_rnglist_table;
508}
509
510// This function is called only for DW_FORM_rnglistx.
511llvm::Expected<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) {
512 if (!GetRnglistTable())
513 return llvm::createStringError(errc::invalid_argument,
514 "missing or invalid range list table");
515 if (!m_ranges_base)
516 return llvm::createStringError(errc::invalid_argument,
517 "DW_FORM_rnglistx cannot be used without "
518 "DW_AT_rnglists_base for CU at 0x%8.8x",
519 GetOffset());
520 if (llvm::Optional<uint64_t> off = GetRnglistTable()->getOffsetEntry(
521 m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), Index))
522 return *off + m_ranges_base;
523 return llvm::createStringError(
524 errc::invalid_argument,
525 "invalid range list table index %u; OffsetEntryCount is %u, "
526 "DW_AT_rnglists_base is %" PRIu64"llu",
527 Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base);
528}
529
530void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {
531 m_str_offsets_base = str_offsets_base;
532}
533
534// It may be called only with m_die_array_mutex held R/W.
535void DWARFUnit::ClearDIEsRWLocked() {
536 m_die_array.clear();
537 m_die_array.shrink_to_fit();
538
539 if (m_dwo)
540 m_dwo->ClearDIEsRWLocked();
541}
542
543lldb::ByteOrder DWARFUnit::GetByteOrder() const {
544 return m_dwarf.GetObjectFile()->GetByteOrder();
545}
546
547void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; }
548
549// Compare function DWARFDebugAranges::Range structures
550static bool CompareDIEOffset(const DWARFDebugInfoEntry &die,
551 const dw_offset_t die_offset) {
552 return die.GetOffset() < die_offset;
553}
554
555// GetDIE()
556//
557// Get the DIE (Debug Information Entry) with the specified offset by first
558// checking if the DIE is contained within this compile unit and grabbing the
559// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file.
560DWARFDIE
561DWARFUnit::GetDIE(dw_offset_t die_offset) {
562 if (die_offset == DW_INVALID_OFFSET(~(dw_offset_t)0))
563 return DWARFDIE(); // Not found
564
565 if (!ContainsDIEOffset(die_offset)) {
566 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
567 "GetDIE for DIE 0x%" PRIx32"x" " is outside of its CU 0x%" PRIx32"x",
568 die_offset, GetOffset());
569 return DWARFDIE(); // Not found
570 }
571
572 ExtractDIEsIfNeeded();
573 DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();
574 DWARFDebugInfoEntry::const_iterator pos =
575 lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);
576
577 if (pos != end && die_offset == (*pos).GetOffset())
578 return DWARFDIE(this, &(*pos));
579 return DWARFDIE(); // Not found
580}
581
582DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
583 ExtractUnitDIEIfNeeded();
584 if (m_dwo)
585 return *m_dwo;
586 return *this;
587}
588
589uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) {
590 if (cu)
591 return cu->GetAddressByteSize();
592 return DWARFUnit::GetDefaultAddressSize();
593}
594
595uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; }
596
597void *DWARFUnit::GetUserData() const { return m_user_data; }
598
599void DWARFUnit::SetUserData(void *d) { m_user_data = d; }
600
601bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() {
602 return GetProducer() != eProducerLLVMGCC;
603}
604
605bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() {
606 // llvm-gcc makes completely invalid decl file attributes and won't ever be
607 // fixed, so we need to know to ignore these.
608 return GetProducer() == eProducerLLVMGCC;
609}
610
611bool DWARFUnit::Supports_unnamed_objc_bitfields() {
612 if (GetProducer() == eProducerClang) {
613 const uint32_t major_version = GetProducerVersionMajor();
614 return major_version > 425 ||
615 (major_version == 425 && GetProducerVersionUpdate() >= 13);
616 }
617 return true; // Assume all other compilers didn't have incorrect ObjC bitfield
618 // info
619}
620
621void DWARFUnit::ParseProducerInfo() {
622 m_producer_version_major = UINT32_MAX0xffffffffU;
623 m_producer_version_minor = UINT32_MAX0xffffffffU;
624 m_producer_version_update = UINT32_MAX0xffffffffU;
625
626 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
627 if (die) {
628
629 const char *producer_cstr =
630 die->GetAttributeValueAsString(this, DW_AT_producer, nullptr);
631 if (producer_cstr) {
632 RegularExpression llvm_gcc_regex(
633 llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple "
634 "Inc\\. build [0-9]+\\) \\(LLVM build "
635 "[\\.0-9]+\\)$"));
636 if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) {
637 m_producer = eProducerLLVMGCC;
638 } else if (strstr(producer_cstr, "clang")) {
639 static RegularExpression g_clang_version_regex(
640 llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)"));
641 llvm::SmallVector<llvm::StringRef, 4> matches;
642 if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr),
643 &matches)) {
644 m_producer_version_major =
645 StringConvert::ToUInt32(matches[1].str().c_str(), UINT32_MAX0xffffffffU, 10);
646 m_producer_version_minor =
647 StringConvert::ToUInt32(matches[2].str().c_str(), UINT32_MAX0xffffffffU, 10);
648 m_producer_version_update =
649 StringConvert::ToUInt32(matches[3].str().c_str(), UINT32_MAX0xffffffffU, 10);
650 }
651 m_producer = eProducerClang;
652 } else if (strstr(producer_cstr, "GNU"))
653 m_producer = eProducerGCC;
654 }
655 }
656 if (m_producer == eProducerInvalid)
657 m_producer = eProcucerOther;
658}
659
660DWARFProducer DWARFUnit::GetProducer() {
661 if (m_producer == eProducerInvalid)
662 ParseProducerInfo();
663 return m_producer;
664}
665
666uint32_t DWARFUnit::GetProducerVersionMajor() {
667 if (m_producer_version_major == 0)
668 ParseProducerInfo();
669 return m_producer_version_major;
670}
671
672uint32_t DWARFUnit::GetProducerVersionMinor() {
673 if (m_producer_version_minor == 0)
674 ParseProducerInfo();
675 return m_producer_version_minor;
676}
677
678uint32_t DWARFUnit::GetProducerVersionUpdate() {
679 if (m_producer_version_update == 0)
680 ParseProducerInfo();
681 return m_producer_version_update;
682}
683
684uint64_t DWARFUnit::GetDWARFLanguageType() {
685 if (m_language_type)
686 return *m_language_type;
687
688 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
689 if (!die)
690 m_language_type = 0;
691 else
692 m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0);
693 return *m_language_type;
694}
695
696bool DWARFUnit::GetIsOptimized() {
697 if (m_is_optimized == eLazyBoolCalculate) {
698 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
699 if (die) {
700 m_is_optimized = eLazyBoolNo;
701 if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) ==
702 1) {
703 m_is_optimized = eLazyBoolYes;
704 }
705 }
706 }
707 return m_is_optimized == eLazyBoolYes;
708}
709
710FileSpec::Style DWARFUnit::GetPathStyle() {
711 if (!m_comp_dir)
712 ComputeCompDirAndGuessPathStyle();
713 return m_comp_dir->GetPathStyle();
714}
715
716const FileSpec &DWARFUnit::GetCompilationDirectory() {
717 if (!m_comp_dir)
718 ComputeCompDirAndGuessPathStyle();
719 return *m_comp_dir;
720}
721
722const FileSpec &DWARFUnit::GetAbsolutePath() {
723 if (!m_file_spec)
724 ComputeAbsolutePath();
725 return *m_file_spec;
726}
727
728FileSpec DWARFUnit::GetFile(size_t file_idx) {
729 return m_dwarf.GetFile(*this, file_idx);
730}
731
732// DWARF2/3 suggests the form hostname:pathname for compilation directory.
733// Remove the host part if present.
734static llvm::StringRef
735removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {
736 if (!path_from_dwarf.contains(':'))
737 return path_from_dwarf;
738 llvm::StringRef host, path;
739 std::tie(host, path) = path_from_dwarf.split(':');
740
741 if (host.contains('/'))
742 return path_from_dwarf;
743
744 // check whether we have a windows path, and so the first character is a
745 // drive-letter not a hostname.
746 if (host.size() == 1 && llvm::isAlpha(host[0]) && path.startswith("\\"))
747 return path_from_dwarf;
748
749 return path;
750}
751
752void DWARFUnit::ComputeCompDirAndGuessPathStyle() {
753 m_comp_dir = FileSpec();
754 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
755 if (!die)
756 return;
757
758 llvm::StringRef comp_dir = removeHostnameFromPathname(
759 die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr));
760 if (!comp_dir.empty()) {
761 FileSpec::Style comp_dir_style =
762 FileSpec::GuessPathStyle(comp_dir).getValueOr(FileSpec::Style::native);
763 m_comp_dir = FileSpec(comp_dir, comp_dir_style);
764 } else {
765 // Try to detect the style based on the DW_AT_name attribute, but just store
766 // the detected style in the m_comp_dir field.
767 const char *name =
768 die->GetAttributeValueAsString(this, DW_AT_name, nullptr);
769 m_comp_dir = FileSpec(
770 "", FileSpec::GuessPathStyle(name).getValueOr(FileSpec::Style::native));
771 }
772}
773
774void DWARFUnit::ComputeAbsolutePath() {
775 m_file_spec = FileSpec();
776 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
777 if (!die)
778 return;
779
780 m_file_spec =
781 FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr),
782 GetPathStyle());
783
784 if (m_file_spec->IsRelative())
785 m_file_spec->MakeAbsolute(GetCompilationDirectory());
786}
787
788SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() {
789 ExtractUnitDIEIfNeeded();
790 if (m_dwo)
791 return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF());
792 return nullptr;
793}
794
795const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
796 if (m_func_aranges_up == nullptr) {
797 m_func_aranges_up = std::make_unique<DWARFDebugAranges>();
798 const DWARFDebugInfoEntry *die = DIEPtr();
799 if (die)
800 die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get());
801
802 if (m_dwo) {
803 const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr();
804 if (dwo_die)
805 dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(),
806 m_func_aranges_up.get());
807 }
808
809 const bool minimize = false;
810 m_func_aranges_up->Sort(minimize);
811 }
812 return *m_func_aranges_up;
813}
814
815llvm::Expected<DWARFUnitHeader>
816DWARFUnitHeader::extract(const DWARFDataExtractor &data,
817 DIERef::Section section,
818 lldb_private::DWARFContext &context,
819 lldb::offset_t *offset_ptr) {
820 DWARFUnitHeader header;
821 header.m_offset = *offset_ptr;
822 header.m_length = data.GetDWARFInitialLength(offset_ptr);
823 header.m_version = data.GetU16(offset_ptr);
824 if (header.m_version == 5) {
825 header.m_unit_type = data.GetU8(offset_ptr);
826 header.m_addr_size = data.GetU8(offset_ptr);
827 header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
828 if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton ||
829 header.m_unit_type == llvm::dwarf::DW_UT_split_compile)
830 header.m_dwo_id = data.GetU64(offset_ptr);
831 } else {
832 header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
833 header.m_addr_size = data.GetU8(offset_ptr);
834 header.m_unit_type =
835 section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile;
836 }
837
838 if (context.isDwo()) {
839 if (header.IsTypeUnit()) {
840 header.m_index_entry =
841 context.GetAsLLVM().getTUIndex().getFromOffset(header.m_offset);
842 } else {
843 header.m_index_entry =
844 context.GetAsLLVM().getCUIndex().getFromOffset(header.m_offset);
845 }
846 }
847
848 if (header.m_index_entry) {
849 if (header.m_abbr_offset) {
850 return llvm::createStringError(
851 llvm::inconvertibleErrorCode(),
852 "Package unit with a non-zero abbreviation offset");
853 }
854 auto *unit_contrib = header.m_index_entry->getContribution();
855 if (!unit_contrib || unit_contrib->Length != header.m_length + 4) {
856 return llvm::createStringError(llvm::inconvertibleErrorCode(),
857 "Inconsistent DWARF package unit index");
858 }
859 auto *abbr_entry =
860 header.m_index_entry->getContribution(llvm::DW_SECT_ABBREV);
861 if (!abbr_entry) {
862 return llvm::createStringError(
863 llvm::inconvertibleErrorCode(),
864 "DWARF package index missing abbreviation column");
865 }
866 header.m_abbr_offset = abbr_entry->Offset;
867 }
868 if (header.IsTypeUnit()) {
869 header.m_type_hash = data.GetU64(offset_ptr);
870 header.m_type_offset = data.GetDWARFOffset(offset_ptr);
871 }
872
873 bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1);
874 bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version);
875 bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8);
876 bool type_offset_OK =
877 !header.IsTypeUnit() || (header.m_type_offset <= header.GetLength());
878
879 if (!length_OK)
880 return llvm::make_error<llvm::object::GenericBinaryError>(
881 "Invalid unit length");
882 if (!version_OK)
883 return llvm::make_error<llvm::object::GenericBinaryError>(
884 "Unsupported unit version");
885 if (!addr_size_OK)
886 return llvm::make_error<llvm::object::GenericBinaryError>(
887 "Invalid unit address size");
888 if (!type_offset_OK)
889 return llvm::make_error<llvm::object::GenericBinaryError>(
890 "Type offset out of range");
891
892 return header;
893}
894
895llvm::Expected<DWARFUnitSP>
896DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,
897 const DWARFDataExtractor &debug_info,
898 DIERef::Section section, lldb::offset_t *offset_ptr) {
899 assert(debug_info.ValidOffset(*offset_ptr))((void)0);
900
901 auto expected_header = DWARFUnitHeader::extract(
902 debug_info, section, dwarf.GetDWARFContext(), offset_ptr);
903 if (!expected_header)
904 return expected_header.takeError();
905
906 const DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev();
907 if (!abbr)
908 return llvm::make_error<llvm::object::GenericBinaryError>(
909 "No debug_abbrev data");
910
911 bool abbr_offset_OK =
912 dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset(
913 expected_header->GetAbbrOffset());
914 if (!abbr_offset_OK)
915 return llvm::make_error<llvm::object::GenericBinaryError>(
916 "Abbreviation offset for unit is not valid");
917
918 const DWARFAbbreviationDeclarationSet *abbrevs =
919 abbr->GetAbbreviationDeclarationSet(expected_header->GetAbbrOffset());
920 if (!abbrevs)
921 return llvm::make_error<llvm::object::GenericBinaryError>(
922 "No abbrev exists at the specified offset.");
923
924 bool is_dwo = dwarf.GetDWARFContext().isDwo();
925 if (expected_header->IsTypeUnit())
926 return DWARFUnitSP(new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs,
927 section, is_dwo));
928 return DWARFUnitSP(new DWARFCompileUnit(dwarf, uid, *expected_header,
929 *abbrevs, section, is_dwo));
930}
931
932const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
933 return m_section == DIERef::Section::DebugTypes
934 ? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData()
935 : m_dwarf.GetDWARFContext().getOrLoadDebugInfoData();
936}
937
938uint32_t DWARFUnit::GetHeaderByteSize() const {
939 switch (m_header.GetUnitType()) {
940 case llvm::dwarf::DW_UT_compile:
941 case llvm::dwarf::DW_UT_partial:
942 return GetVersion() < 5 ? 11 : 12;
943 case llvm::dwarf::DW_UT_skeleton:
944 case llvm::dwarf::DW_UT_split_compile:
945 return 20;
946 case llvm::dwarf::DW_UT_type:
947 case llvm::dwarf::DW_UT_split_type:
948 return GetVersion() < 5 ? 23 : 24;
949 }
950 llvm_unreachable("invalid UnitType.")__builtin_unreachable();
951}
952
953llvm::Optional<uint64_t>
954DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
955 offset_t offset = GetStrOffsetsBase() + index * 4;
956 return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset);
957}
958
959llvm::Expected<DWARFRangeList>
960DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) {
961 if (GetVersion() <= 4) {
962 const DWARFDebugRanges *debug_ranges = m_dwarf.GetDebugRanges();
963 if (!debug_ranges)
964 return llvm::make_error<llvm::object::GenericBinaryError>(
965 "No debug_ranges section");
966 DWARFRangeList ranges;
967 debug_ranges->FindRanges(this, offset, ranges);
968 return ranges;
969 }
970
971 if (!GetRnglistTable())
972 return llvm::createStringError(errc::invalid_argument,
973 "missing or invalid range list table");
974
975 auto range_list_or_error = GetRnglistTable()->findList(
976 m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), offset);
977 if (!range_list_or_error)
978 return range_list_or_error.takeError();
979
980 llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges =
981 range_list_or_error->getAbsoluteRanges(
982 llvm::object::SectionedAddress{GetBaseAddress()},
983 GetAddressByteSize(), [&](uint32_t index) {
984 uint32_t index_size = GetAddressByteSize();
985 dw_offset_t addr_base = GetAddrBase();
986 lldb::offset_t offset = addr_base + index * index_size;
987 return llvm::object::SectionedAddress{
988 m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64(
989 &offset, index_size)};
990 });
991 if (!llvm_ranges)
992 return llvm_ranges.takeError();
993
994 DWARFRangeList ranges;
995 for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) {
996 ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC,
997 llvm_range.HighPC - llvm_range.LowPC));
998 }
999 return ranges;
1000}
1001
1002llvm::Expected<DWARFRangeList>
1003DWARFUnit::FindRnglistFromIndex(uint32_t index) {
1004 llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index);
1005 if (!maybe_offset)
1006 return maybe_offset.takeError();
1007 return FindRnglistFromOffset(*maybe_offset);
1008}