blob: 0e67dfc444af68aaa46caac10bf83d311a5a6e2f [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_INDEX_NODE_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INDEX_NODE_H_
#include <iosfwd>
#include <map>
#include <string>
#include <vector>
namespace zxdb {
class DwarfSymbolFactory;
// An in-progress replacement for IndexNode. Not ready to use yet.
class IndexNode {
public:
using Map = std::map<std::string, IndexNode>;
// The type of an index node. There are several "physical" kinds which are associated with
// children of each node. These physical ones count up from 0 so one can iterate over them
// from to up until < kEndPhysical to iterate the child categories.
enum class Kind : int {
kNamespace = 0,
kType,
kFunction,
kVar,
kEndPhysical, // Marker for the end of the kinds that have children for every node.
kNone = kEndPhysical,
kRoot, // Root index node (meaning nothing semantically).
};
// A reference to a DIE that doesn't need the unit or the underlying llvm::DwarfDebugInfoEntry to
// be kept. This allows the discarding of the full parsed DIE structures after indexing. It can be
// converted back to a DIE, which will cause the DWARFUnit to be re-parsed.
//
// The offset stored in this structure is the offset from the beginning of the .debug_info
// section, which is the same as the offset stored in the llvm::DWARFDebugInfoEntry.
//
// Random code reading the index can convert a SymbolRef to a Symbol object using
// ModuleSymbols::IndexSymbolRefToSymbol().
//
// TODO(bug 53091) in the future we may want to add ELF symbol support to this class.
class SymbolRef {
public:
enum Kind {
kNull, // Empty.
kDwarf, // Normal DWARF symbol.
kDwarfDeclaration, // A DWARF declaration.
};
SymbolRef() = default;
SymbolRef(Kind kind, uint64_t offset) : kind_(kind), offset_(offset) {}
Kind kind() const { return kind_; }
bool is_declaration() const { return kind_ == kDwarfDeclaration; }
uint64_t offset() const { return offset_; }
private:
Kind kind_ = kNull;
uint64_t offset_ = 0;
};
explicit IndexNode(Kind kind) : kind_(kind) {}
~IndexNode() = default;
Kind kind() const { return kind_; }
// The SymbolRef can be omitted when indexing namespaces as the DIEs are not stored for that case.
IndexNode* AddChild(Kind kind, const char* name);
IndexNode* AddChild(Kind kind, const char* name, const SymbolRef& ref);
void AddDie(const SymbolRef& ref);
const Map& namespaces() const { return children_[static_cast<int>(Kind::kNamespace)]; }
Map& namespaces() { return children_[static_cast<int>(Kind::kNamespace)]; }
const Map& types() const { return children_[static_cast<int>(Kind::kType)]; }
Map& types() { return children_[static_cast<int>(Kind::kType)]; }
const Map& functions() const { return children_[static_cast<int>(Kind::kFunction)]; }
Map& functions() { return children_[static_cast<int>(Kind::kFunction)]; }
const Map& vars() const { return children_[static_cast<int>(Kind::kVar)]; }
Map& vars() { return children_[static_cast<int>(Kind::kVar)]; }
// Returns the map for the given child kind. This will assert for >= kEndPhysical ("kNone" and
// "kRoot") which aren't child kinds.
const Map& MapForKind(Kind kind) const;
Map& MapForKind(Kind kind);
// AsString is useful only in small unit tests since even a small module can have many megabytes
// of dump.
std::string AsString(int indent_level = 0) const;
// Dump DIEs for debugging. A node does not contain its own name (this is stored in the parent's
// map). If printing some node other than the root, specify the name.
//
// If non-null, |factory_for_loc| will be used to add extra location information to certain types
// of entries. Currently this prints out the relative code ranges for functions, and the DIE
// offset of the indexed item for everything else.
void Dump(std::ostream& out, DwarfSymbolFactory* factory_for_loc = nullptr,
int indent_level = 0) const;
void Dump(const std::string& name, std::ostream& out,
DwarfSymbolFactory* factory_for_loc = nullptr, int indent_level = 0) const;
const std::vector<SymbolRef>& dies() const { return dies_; }
private:
Kind kind_;
// TODO(brettw) evaluate whether we can save a lot of memory using optionally-null unique_ptrs
// here since in most cases all but one of these maps will be empty.
Map children_[static_cast<int>(Kind::kEndPhysical)];
// Contains the references to the definitions (if possible) or the declarations (if not) of the
// type, function, or variable. This will not have any entries for namespaces.
//
// TODO(brettw) consider an optimization because in most cases there will be exactly one DIE.
std::vector<SymbolRef> dies_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INDEX_NODE_H_