/* Copyright (C) 2007-2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
*/

/*
 * Contains declarations of classes defined for a variety of DWARF objects.
 */

#ifndef ELFF_DWARF_DIE_H_
#define ELFF_DWARF_DIE_H_

#include "dwarf_defs.h"
#include "elf_alloc.h"

class ElfFile;
class DwarfCU;

/* Encapsulates an object that wraps up a DIE, cached during
 * ELF file parsing.
 */
class DIEObject : public DwarfAllocBase {
 public:
  /* Constructs DIEObject intance.
   * Param:
   *  die - DIE represented with this instance.
   *  parent_cu - Compilation unit this DIE belongs to.
   *  parent_die - Parent DIE object for this DIE. This parameter can be NULL
   *    only for compilation unit DIEs.
   */
  DIEObject(const Dwarf_DIE* die, DwarfCU* parent_cu, DIEObject* parent_die)
      : die_(die),
        parent_cu_(parent_cu),
        parent_die_(parent_die),
        prev_sibling_(NULL),
        last_child_(NULL) {
  }

  /* Destructs DIEObject intance. */
  ~DIEObject();

  /* Gets ELF file this DIE belongs to. */
  ElfFile* elf_file() const;

  /* Gets DWARF tag (DW_TAG_Xxx) for the DIE represented with this instance. */
  Dwarf_Tag get_tag() const;

  /* Gets the best name for this DIE.
   * Some DIEs (such as inline routine DIEs) may have no DW_AT_name property,
   * but may reference to another DIE that may contain DIE name. This method
   * tries its best to get DIE name by iterating through different methods of
   * naming the DIE.
   * Return:
   *  Name for this DIE, or NULL if it was not possible to find a relevant DIE
   *  with DW_AT_name property.
   */
  const char* get_name() const;

  /* Gets DIE's attribute by its ID.
   * Param:
   *  at_id - ID (DW_AT_Xxx) of the attribute to get.
   *  attr - Upon successful return contains requested attribute information.
   * Return:
   *  true on success, or false if attribute for the given ID doesn't exist
   *  in the DIE's attribute list.
   */
  bool get_attrib(Dwarf_At at, DIEAttrib* attr) const;

  /* Gets the leaf DIE object containing given address.
   * See DwarfCU::get_leaf_die_for_address() for method details.
   * See DIEObject::contains_address() for implementation details.
   */
  DIEObject* get_leaf_for_address(Elf_Xword address);

  /* Finds a DIE object for the given die in the branch starting with
   * this DIE object.
   */
  DIEObject* find_die_object(const Dwarf_DIE* die_to_find);

  /* Dumps this object to stdout.
   * Param:
   *  only_this - If true, only this object will be dumped. If this parameter
   *    is false, all the childs and siblings of this object will be dumped
   *    along with this object.
   */
  void dump(bool only_this) const;

 protected:
  /* Checks if this DIE object containing given address.
   * Template param:
   *  AddrType - Type of compilation unin address (4, or 8 bytes), defined by
   *    address_size field of the CU header. Must be Elf_Xword for 8 bytes
   *    address, or Elf_Word for 4 bytes address.
   * Param:
   *  address - Address ti check.
   * Return:
   *  True, if this DIE address ranges (including low_pc, high_pc attributes)
   *  contain given address, or false otherwise.
   */
  template <typename AddrType>
  bool contains_address(Elf_Xword address);

  /* Advances to the DIE's property list.
   * Param:
   *  at_abbr - Upon successful return contains a pointer to the beginning of
   *    DIE attribute abbreviation list. This parameter can be NULL, if the
   *    caller is not interested in attribute abbreviation list for this DIE.
   *  tag - Upon successful return contains DIE's tag. This parameter can be
   *    NULL, if the caller is not interested in the tag value for this DIE.
   * Return:
   *  Pointer to the beginning of the DIE attribute list in mapped .debug_info
   *  section on success, or NULL on failure.
   */
  const Elf_Byte* advance(const Dwarf_Abbr_AT** at_abbr, Dwarf_Tag* tag) const;

 public:
  /* Gets DIE represented with this instance. */
  const Dwarf_DIE* die() const {
    return die_;
  }

  /* Gets compilation unit this DIE belongs to. */
  DwarfCU* parent_cu() const {
    return parent_cu_;
  }

  /* Gets parent DIE object for this die. */
  DIEObject* parent_die() const {
    return parent_die_;
  }

  /* Gets last child object in the list of this DIE's childs. NOTE: for better
   * performace the list is created in reverse order (relatively to the order,
   * in which children DIEs have been discovered).
   */
  DIEObject* last_child() const {
    return last_child_;
  }

  /* Links next child to the list of this DIE childs. */
  void link_child(DIEObject* child) {
    last_child_ = child;
  }

  /* Gets previous sibling of this DIE in the parent's DIE object list. */
  DIEObject* prev_sibling() const {
    return prev_sibling_;
  }

  /* Links next sibling to the list of this DIE siblings. */
  void link_sibling(DIEObject* sibl) {
    prev_sibling_ = sibl;
  }

  /* Checks if this DIE object represents a CU DIE.
   * We relay here on the fact that only CU DIE objects have no parent
   * DIE objects.
   */
  bool is_cu_die() const {
    return parent_die_ == NULL;
  }

  /* Gets this DIE level in the branch.
   * DIE level defines DIE's distance from the CU DIE in the branch this DIE
   * belongs to. In other words, DIE level defines how many parent DIEs exist
   * between this DIE, and the CU DIE. For instance, the CU DIE has level 0,
   * a subroutine a() in this compilation unit has level 1, a soubroutine b(),
   * that has been inlined into subroutine a() will have level 2, a try/catch
   * block in the inlined subroutine b() will have level 3, and so on.
   */
  Elf_Word get_level() const {
    return parent_die_ != NULL ? parent_die_->get_level() + 1 : 0;
  }

 protected:
  /* DIE that is represented with this instance. */
  const Dwarf_DIE*  die_;

  /* Compilation unit this DIE belongs to. */
  DwarfCU*          parent_cu_;

  /* Parent DIE object for this die. */
  DIEObject*        parent_die_;

  /* Last child object in the list of this DIE's childs. NOTE: for better
   * performace the list is created in reverse order (relatively to the order,
   * in which children DIEs have been discovered).
   */
  DIEObject*        last_child_;

  /* Previous sibling of this DIE in the parent's DIE object list. */
  DIEObject*        prev_sibling_;
};

#endif  // ELFF_DWARF_DIE_H_
