blob: a38e2a5b5d34af7794812e4480c7249d34e7f873 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/symbols/dwarf_die_scanner.h"
#include <lib/syslog/cpp/macros.h>
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "src/developer/debug/zxdb/symbols/dwarf_tag.h"
namespace zxdb {
DwarfDieScanner2::DwarfDieScanner2(llvm::DWARFUnit* unit) : unit_(unit) {
die_count_ = unit_->getNumDIEs();
parent_indices_.resize(die_count_);
// We prefer not to reallocate and normally the C++ component depth is < 8.
tree_stack_.reserve(8);
tree_stack_.emplace_back(-1, kNoParent, false);
}
DwarfDieScanner2::~DwarfDieScanner2() = default;
const llvm::DWARFDebugInfoEntry* DwarfDieScanner2::Prepare() {
if (done())
return nullptr;
cur_die_ = unit_->getDIEAtIndex(die_index_).getDebugInfoEntry();
// LLVM can provide the depth in O(1) time but not the parent.
int current_depth = static_cast<int>(cur_die_->getDepth());
if (current_depth == tree_stack_.back().depth) {
// Common case: depth not changing. Just update the topmost item in the stack to point to the
// current node.
tree_stack_.back().index = die_index_;
} else {
// Tree changed. First check for moving up in the tree and pop the stack until we're at the
// parent of the current level (this will do nothing when going deeper in the tree), then add
// the current level.
while (tree_stack_.back().depth >= current_depth)
tree_stack_.pop_back();
tree_stack_.emplace_back(current_depth, die_index_, false);
}
// Fix up the inside function flag.
switch (static_cast<DwarfTag>(cur_die_->getTag())) {
case DwarfTag::kLexicalBlock:
case DwarfTag::kVariable:
// Inherits from previous. For a block and a variable there should always be the parent,
// since at least there's the unit root DIE.
FX_DCHECK(tree_stack_.size() >= 2);
tree_stack_.back().inside_function = tree_stack_[tree_stack_.size() - 2].inside_function;
break;
case DwarfTag::kSubprogram:
case DwarfTag::kInlinedSubroutine:
tree_stack_.back().inside_function = true;
break;
default:
tree_stack_.back().inside_function = false;
break;
}
// Save parent info. The parent of this node is the one right before the
// current one (the last one in the stack).
parent_indices_[die_index_] = (tree_stack_.end() - 2)->index;
return cur_die_;
}
void DwarfDieScanner2::Advance() {
FX_DCHECK(!done());
die_index_++;
}
} // namespace zxdb