blob: 4b9b8d116f8b05c8972fe0dc142f09cd11778289 [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.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DWARF_DIE_SCANNER_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DWARF_DIE_SCANNER_H_
#include <lib/syslog/cpp/macros.h>
#include <stdint.h>
#include <utility>
#include <vector>
namespace llvm {
class DWARFDebugInfoEntry;
class DWARFUnit;
} // namespace llvm
namespace zxdb {
// This is a helper class for generating a zxdb::Index.
//
// It works in two phases. In the first, it linearly iterates through the DIEs of a unit. The
// calling code does:
//
// while (!scanner.done()) {
// current_die = scanner.Prepare();
// ... work on current_die ...
// scanner.Advance();
// }
//
// In the second phase, the scanner can provide extra information for a DIE in the unit in constant
// time.
//
// This class exists because in LLVM, getting the parent of a DIE used to require an inefficient
// linear search. Since LLVM provides a direct way to get parent index, the necessity of this class
// is largely elimiated.
class DwarfDieScanner2 {
public:
static constexpr uint32_t kNoParent = static_cast<uint32_t>(-1);
// The unit pointer must outlive this class.
explicit DwarfDieScanner2(llvm::DWARFUnit* unit);
~DwarfDieScanner2();
// Call at the beginning of each iteration (when !done()) to get the current DIE. This is required
// to be called before Advance() as it sets some internal state.
const llvm::DWARFDebugInfoEntry* Prepare();
// Advances to the next DIE.
void Advance();
uint32_t die_index() const { return die_index_; }
uint32_t die_count() const { return die_count_; }
bool done() const { return die_index_ == die_count_; }
// Returns true if the current stack position is considered to be directly inside a function.
// Lexical blocks count as being inside a function, but if a new type is defined inside a function
// the children of that type are no longer considered to be inside a function.
//
// This is used to avoid indexing function-local variables.
bool is_inside_function() const { return tree_stack_.back().inside_function; }
// Return the parent's index of a DIE in constant time. Will return kNoParent for the root.
uint32_t GetParentIndex(uint32_t index) const;
private:
// Stores the list of parent indices according to the current depth in the tree. At any given
// point, the parent index of the current node will be tree_stack.back(). inside_function should
// be set if this node or any parent node is a function.
struct StackEntry {
StackEntry(unsigned i, bool f) : index(i), inside_function(f) {}
unsigned index;
// Tracks whether this node is a child of a function with no intermediate types. This is to
// avoid indexing local variables inside functions or inside blocks inside functions.
bool inside_function;
};
llvm::DWARFUnit* unit_;
uint32_t die_count_ = 0;
uint32_t die_index_ = 0;
const llvm::DWARFDebugInfoEntry* cur_die_ = nullptr;
std::vector<StackEntry> tree_stack_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DWARF_DIE_SCANNER_H_