/* Copyright (C) 2021 Free Software Foundation, Inc.
   Contributed by Oracle.

   This file is part of GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   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.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#ifndef _HISTABLE_H
#define _HISTABLE_H

//
// The Histable class hierarchy is used to build up a representation of
// the codeobjects (functions, modules, loadObjects, etc.) that make up the
// text address space of a program.  The hierarchy is as follows:
//
//	Histable (public)
//		LoadObject (public)
//		Module (public)
//		Function (public)
//
// Dataobjects are objects from the data address space of a program.
// The reason for calling the base class "Histable" is because these
// objects are all valid objects for computing histograms on.

// A Histable object represents an object in the program text or data.

#include "dbe_structs.h"
#include "Emsg.h"
#include "Expression.h"

class DataObject;
class Function;
class SourceFile;
class DbeFile;
class DbeLine;
template <class ITEM> class Vector;

class Histable
{
  friend class Hist_data;
public:

  enum Type
  {
    INSTR, LINE, FUNCTION, MODULE, LOADOBJECT,
    EADDR, MEMOBJ, INDEXOBJ, PAGE, DOBJECT,
    SOURCEFILE, IOACTFILE, IOACTVFD, IOCALLSTACK,
    HEAPCALLSTACK, EXPERIMENT, OTHER
  };

  // NameFormat for functions and function based objects

  enum NameFormat
  {
    NA, LONG, SHORT, MANGLED, SONAME = 0x10
  };

  static NameFormat
  make_fmt (int fnfmt, bool sofmt = false)
  {
    return (NameFormat) (sofmt ? fnfmt | SONAME : fnfmt);
  }

  static int
  fname_fmt (NameFormat fmt)
  {
    return (fmt & ~SONAME);
  }

  static bool
  soname_fmt (NameFormat fmt)
  {
    return (fmt & SONAME);
  }

  Histable ();
  char *dump ();

  virtual ~Histable ();

  virtual char *
  get_name (NameFormat = NA)
  {
    return name;    // Return the name of the object
  }

  virtual void
  set_name (char * _name)
  {
    name = _name;
  }

  virtual void set_name_from_context (Expression::Context *) { }
  virtual Type get_type () = 0;

  virtual int64_t
  get_size ()
  {
    return 0;
  }

  virtual uint64_t
  get_addr ()
  {
    return 0ULL;
  }

  virtual Vector<Histable*> *get_comparable_objs ();
  Histable *get_compare_obj ();

  virtual Histable *
  convertto (Type, Histable* = NULL)
  {
    return this;
  }

  Vector<Histable*> *comparable_objs;
  int64_t id;       // A unique id of this object, within its specific Type

protected:
  char *name;       // Object name
  int phaseCompareIdx;
  void update_comparable_objs ();
  void dump_comparable_objs ();
  char *type_to_string ();
  void delete_comparable_objs ();
};

typedef Histable::Type Histable_type;

// An Other object represents some random histable object
class Other : public Histable
{
public:

  virtual Type
  get_type ()
  {
    return OTHER;
  }

  uint64_t value64;
  uint32_t tag;
};

// DbeInstr represents an instruction.
//
//   Used by Analyzer for: Disassembly, PCs, Timeline, and Event tabs.
//
class DbeInstr : public Histable
{
public:
  DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr);

  virtual Type
  get_type ()
  {
    return INSTR;
  }

  virtual char *get_name (NameFormat = NA);
  virtual int64_t get_size ();
  virtual uint64_t get_addr ();
  virtual Histable *convertto (Type type, Histable *obj = NULL);
  DbeLine *mapPCtoLine (SourceFile *sf);
  void add_inlined_info (StringBuilder *sb);
  char *get_descriptor ();
  int pc_cmp (DbeInstr *instr2);

  uint64_t addr;
  uint64_t img_offset;      // file offset of the image
  int flags;
  Function *func;
  int lineno;
  int inlinedInd;
  int64_t size;
  bool isUsed;

private:
  NameFormat current_name_format;
};

class DbeEA : public Histable
{
public:

  DbeEA (DataObject *_dobj, Vaddr _eaddr)
  {
    dobj = _dobj;
    eaddr = _eaddr;
  };

  virtual Type
  get_type ()
  {
    return EADDR;
  };

  virtual int64_t
  get_size ()
  {
    return 1;
  };

  virtual uint64_t
  get_addr ()
  {
    return eaddr;
  };

  virtual char *get_name (NameFormat = NA);
  virtual Histable *convertto (Type type, Histable *obj = NULL);

  DataObject *dobj;
  Vaddr eaddr;
};

// DbeLine represents a line in a source file.
//
//   For each top-level DbeLine instance, there are three DbeLine subtypes:
//
//   A The top-level DbeLine is associated with a sourceFile & lineno, but
//     not any particular function.  This form of DbeLine is used
//     to represent Analyzer Source tab lines.
//
//   B Function-specific lines, those associated with a function in addition
//     to the the sourceFile & lineno, are stored in a linked list.
//     (see "dbeline_func_next").
//     This subtype is used to differentiate a line found in #included source
//     that is referenced by multiple functions.
//     It is used in the Analyzer Lines tab.
//
//   C Function-specific "lines" that don't have line number info are referenced
//     from each linked-list element's "dbeline_func_pseudo" field.
//     This subtype is needed when a binary doesn't identify line numbers.
//     It is used in the Analyzer Lines tab.
//
//   When the user switches views between tabs, a selected object in the old
//   tab must be translated to an approprate object in the new tab.
//   When switching to the Source Tab, the top-level DbeLine (dbeline_base)
//     should be used.
//   When switching to the Lines Tab, a function-specific dbeline_func_*
//     should be used.
//

class DbeLine : public Histable
{
public:

  enum Flag
  {
    OMPPRAGMA = 1
  };

  DbeLine (Function *_func, SourceFile *sf, int _lineno);
  virtual ~DbeLine ();
  virtual char *get_name (NameFormat = NA);
  virtual int64_t get_size ();
  virtual uint64_t get_addr ();
  virtual Histable *convertto (Type type, Histable *obj = NULL);

  void init_Offset (uint64_t p_offset);
  int line_cmp (DbeLine *dbl);

  virtual Type
  get_type ()
  {
    return LINE;
  }

  void
  set_flag (Flag flag)
  {
    flags |= flag;
  }

  bool
  is_set (Flag flag)
  {
    return (flags & flag) != 0;
  }

  Function *func;           // note: will be NULL in the base (head) dbeline
  int lineno;
  int64_t size;
  SourceFile *sourceFile;   // Default source file
  SourceFile *include;      // included source file or NULL

  DbeLine *dbeline_base;
  // Head of list, a dbeline associated with sourceFile & lineno, but not func:
  //   dbeline_base->lineno:                 non-zero
  //   dbeline_base->sourceFile:             non-null
  //   dbeline_base->func:                   NULL
  //   dbeline_base->dbeline_base:           this
  //   dbeline_base->dbeline_func_next:      first func-specific dbeline

  DbeLine *dbeline_func_next;
  // If non-null, pointer to a function-specific dbeline where:
  //   dbeline_func_next->lineno:            same as dbeline_base->lineno
  //   dbeline_func_next->sourceFile:        same as dbeline_base->sourceFile
  //   dbeline_func_next->func:              pointer to unique function
  //   dbeline_func_next->dbeline_base:      head of the linked list.
  //   dbeline_func_next->dbeline_func_next: next function-specific dbeline.

private:
  int current_name_format;
  int64_t offset;
  int flags;
};

class HistableFile : public Histable, public DbeMessages
{
public:
  HistableFile ();

  bool isUsed;
  DbeFile *dbeFile;
};

#endif /* _HISTABLE_H */
