// -*- C++ -*-
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
// Copyright (C) 1999-2003 Forgotten
// Copyright (C) 2004 Forgotten and the VBA development team

// 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 2, 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,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#ifndef VBA_ELF_H
#define VBA_ELF_H

enum LocationType {
  LOCATION_register,
  LOCATION_memory,
  LOCATION_value
};

#define DW_ATE_bool8ean       0x02
#define DW_ATE_signed        0x05
#define DW_ATE_unsigned      0x07
#define DW_ATE_unsigned_char 0x08

struct ELFHeader {
  uint32 magic;
  uint8 clazz;
  uint8 data;
  uint8 version;
  uint8 pad[9];
  uint16 e_type;
  uint16 e_machine;
  uint32 e_version;
  uint32 e_entry;
  uint32 e_phoff;
  uint32 e_shoff;
  uint32 e_flags;
  uint16 e_ehsize;
  uint16 e_phentsize;
  uint16 e_phnum;
  uint16 e_shentsize;
  uint16 e_shnum;
  uint16 e_shstrndx;
};

struct ELFProgramHeader {
  uint32 type;
  uint32 offset;
  uint32 vaddr;
  uint32 paddr;
  uint32 filesz;
  uint32 memsz;
  uint32 flags;
  uint32 align;
};

struct ELFSectionHeader {
  uint32 name;
  uint32 type;
  uint32 flags;
  uint32 addr;
  uint32 offset;
  uint32 size;
  uint32 link;
  uint32 info;
  uint32 addralign;
  uint32 entsize;
};

struct ELFSymbol {
  uint32 name;
  uint32 value;
  uint32 size;
  uint8 info;
  uint8 other;
  uint16 shndx;
};

struct ELFBlock {
  int length;
  uint8 *data;
};

struct ELFAttr {
  uint32 name;
  uint32 form;
  union {
    uint32 value;
    char *string;
    uint8 *data;
    bool8 flag;
    ELFBlock *block;
  };
};

struct ELFAbbrev {
  uint32 number;
  uint32 tag;
  bool8 hasChildren;
  int numAttrs;
  ELFAttr *attrs;
  ELFAbbrev *next;
};

enum TypeEnum {
  TYPE_base,
  TYPE_pointer,
  TYPE_function,
  TYPE_void,
  TYPE_array,
  TYPE_struct,
  TYPE_reference,
  TYPE_enum,
  TYPE_union
};

struct Type;
struct Object;

struct FunctionType {
  Type *returnType;
  Object *args;
};

struct Member {
  char *name;
  Type *type;
  int bitSize;
  int bitOffset;
  int byteSize;
  ELFBlock *location;
};

struct Struct {
  int memberCount;
  Member *members;
};

struct Array {
  Type *type;
  int maxBounds;
  int *bounds;
};

struct EnumMember {
  char *name;
  uint32 value;
};

struct Enum {
  int count;
  EnumMember *members;
};

struct Type {
  uint32 offset;
  TypeEnum type;
  char *name;
  int encoding;
  int size;
  int bitSize;
  union {
    Type *pointer;
    FunctionType *function;
    Array *array;
    Struct *structure;
    Enum *enumeration;
  };
  Type *next;
};

struct Object {
  char *name;
  int file;
  int line;
  bool8 external;
  Type *type;
  ELFBlock *location;
  uint32 startScope;
  uint32 endScope;
  Object *next;
};

struct Function {
  char *name;
  uint32 lowPC;
  uint32 highPC;
  int file;
  int line;
  bool8 external;
  Type *returnType;
  Object *parameters;
  Object *variables;
  ELFBlock *frameBase;
  Function *next;
};

struct LineInfoItem {
  uint32 address;
  char *file;  
  int line;
};

struct LineInfo {
  int fileCount;
  char **files;
  int number;
  LineInfoItem *lines;
};

struct ARange {
  uint32 lowPC;
  uint32 highPC;
};

struct ARanges {
  uint32 offset;
  int count;
  ARange *ranges;
};

struct CompileUnit {
  uint32 length;
  uint8 *top;
  uint32 offset;
  ELFAbbrev **abbrevs;
  ARanges *ranges;
  char *name;
  char *compdir;  
  uint32 lowPC;
  uint32 highPC;
  bool8 hasLineInfo;
  uint32 lineInfo;
  LineInfo *lineInfoTable;
  Function *functions;
  Function *lastFunction;
  Object *variables;
  Type *types;
  CompileUnit *next;  
};

struct DebugInfo {
  uint8 *debugfile;
  uint8 *abbrevdata;
  uint8 *debugdata;
  uint8 *infodata;
  int numRanges;
  ARanges *ranges;
};

struct Symbol {
  char *name;
  int type;
  int binding;
  uint32 address;
  uint32 value;
  uint32 size;
};

extern uint32 elfReadLEB128(uint8 *, int *);
extern int32 elfReadSignedLEB128(uint8 *, int *);
extern bool8 elfRead(const char *, int &, FILE *f);
extern bool8 elfGetSymbolAddress(char *,uint32 *, uint32 *, int *);
extern char *elfGetAddressSymbol(uint32);
extern char *elfGetSymbol(int, uint32 *, uint32 *, int *);
extern void elfCleanUp();
extern bool8 elfGetCurrentFunction(uint32, Function **, CompileUnit **c);
extern bool8 elfGetObject(char *, Function *, CompileUnit *, Object **);
extern bool8 elfFindLineInUnit(uint32 *, CompileUnit *, int);
extern bool8 elfFindLineInModule(uint32 *, char *, int);
uint32 elfDecodeLocation(Function *, ELFBlock *, LocationType *);
uint32 elfDecodeLocation(Function *, ELFBlock *, LocationType *, uint32);
int elfFindLine(CompileUnit *unit, Function *func, uint32 addr, char **);
#endif
