/*
 * File msc.c - read VC++ debug information from COFF and eventually
 * from PDB files.
 *
 * Copyright (C) 1996, Eric Youngdale.
 *
 * Note - this handles reading debug information for 32 bit applications
 * that run under Windows-NT for example.  I doubt that this would work well
 * for 16 bit applications, but I don't think it really matters since the
 * file format is different, and we should never get in here in such cases.
 *
 * TODO:
 *	Get 16 bit CV stuff working.
 *	Add symbol size to internal symbol table.
 */

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#endif
#include "win.h"
#include "pe_image.h"
#include "peexe.h"
#include "debugger.h"
#include "peexe.h"
#include "xmalloc.h"


/*
 * This is an index we use to keep track of the debug information
 * when we have multiple sources.  We use the same database to also
 * allow us to do an 'info shared' type of deal, and we use the index
 * to eliminate duplicates.
 */
static int DEBUG_next_index = 0;

union any_size
{
  char		 * c;
  short		 * s;
  int		 * i;
  unsigned int   * ui;
};

/*
 * This is a convenience structure used to map portions of the
 * line number table.
 */
struct startend
{
  unsigned int	  start;
  unsigned int	  end;
};

/*
 * This is how we reference the various record types.
 */
union codeview_symbol
{
  struct
  {
    short int	len;
    short int	id;
  } generic;

  struct
  {
	short int	len;
	short int	id;
	unsigned int	offset;
	unsigned short	seg;
	unsigned short	symtype;
	unsigned char	namelen;
	unsigned char	name[1];
  } data;

  struct
  {
	short int	len;
	short int	id;
	unsigned int	pparent;
	unsigned int	pend;
	unsigned int	next;
	unsigned int	offset;
	unsigned short	segment;
	unsigned short	thunk_len;
	unsigned char	thtype;
	unsigned char	namelen;
	unsigned char	name[1];
  } thunk;
  struct
  {
	short int	len;
	short int	id;
	unsigned int	pparent;
	unsigned int	pend;
	unsigned int	next;
	unsigned int	proc_len;
	unsigned int	debug_start;
	unsigned int	debug_end;
	unsigned int	offset;
	unsigned short	segment;
	unsigned short	proctype;
	unsigned char	flags;
	unsigned char	namelen;
	unsigned char	name[1];
  } proc;
  struct
  {
	short int	len;	/* Total length of this entry */
	short int	id;		/* Always S_BPREL32 */
	unsigned int	offset;	/* Stack offset relative to BP */
	unsigned short	symtype;
	unsigned char	namelen;
	unsigned char	name[1];
  } stack;
};

union codeview_type
{
  struct
  {
    short int	len;
    short int	id;
  } generic;

  struct
  {
    short int		len;
    short int		id;
    short int		attribute;
    short int		datatype;
    unsigned char	variant[1];
  } pointer;

  struct
  {
    short int		len;
    short int		id;
    unsigned char	nbits;
    unsigned char	bitoff;
    unsigned short	type;
  } bitfield;

  struct
  {
    short int		len;
    short int		id;
    short int		elemtype;
    short int		idxtype;
    unsigned char	arrlen;
    unsigned char	namelen;
    unsigned char	name[1];
  } array;

  struct
  {
    short int		len;
    short int		id;
    short int		n_element;
    short int		fieldlist;
    short int		property;
    short int		derived;
    short int		vshape;
    unsigned short	structlen;
    unsigned char	namelen;
    unsigned char	name[1];
  } structure;

  struct
  {
    short int		len;
    short int		id;
    short int		count;
    short int		field;
    short int		property;
    unsigned short	un_len;
    unsigned char	namelen;
    unsigned char	name[1];
  } t_union;

  struct
  {
    short int		len;
    short int		id;
    short int		count;
    short int		type;
    short int		field;
    short int		property;
    unsigned char	namelen;
    unsigned char	name[1];
  } enumeration;

  struct
  {
    short int		id;
    short int		attribute;
    unsigned short int	value;
    unsigned char	namelen;
    unsigned char	name[1];
  } enumerate;

  struct
  {
    short int		id;
    short int		type;
    short int		attribute;
    unsigned short int	offset;
    unsigned char	namelen;
    unsigned char	name[1];
  } member;

  struct
  {
    short int		len;
    short int		id;
    short int		count;
    short int		type;
    short int		field;
    short int		property;
    unsigned char	namelen;
    unsigned char	name[1];
  } fieldlist;

};

#define S_BPREL32	0x200
#define S_LDATA32	0x201
#define S_GDATA32	0x202
#define S_PUB32		0x203
#define S_LPROC32	0x204
#define S_GPROC32	0x205
#define S_THUNK32	0x206
#define S_BLOCK32	0x207
#define S_WITH32	0x208
#define S_LABEL32	0x209

#define S_PROCREF	0x400
#define S_DATAREF	0x401
#define S_ALIGN		0x402
#define S_UNKNOWN	0x403

/*
 * This covers the basic datatypes that VC++ seems to be using these days.
 * 32 bit mode only.  There are additional numbers for the pointers in 16
 * bit mode.  There are many other types listed in the documents, but these
 * are apparently not used by the compiler, or represent pointer types
 * that are not used.
 */
#define T_NOTYPE	0x0000	/* Notype */
#define T_ABS		0x0001	/* Abs */
#define T_VOID		0x0003	/* Void */
#define T_CHAR		0x0010	/* signed char */
#define T_SHORT		0x0011	/* short */
#define T_LONG		0x0012	/* long */
#define T_QUAD		0x0013	/* long long */
#define T_UCHAR		0x0020	/* unsigned  char */
#define T_USHORT	0x0021	/* unsigned short */
#define T_ULONG		0x0022	/* unsigned long */
#define T_UQUAD		0x0023	/* unsigned long long */
#define T_REAL32	0x0040	/* float */
#define T_REAL64	0x0041	/* double */
#define T_RCHAR		0x0070	/* real char */
#define T_WCHAR		0x0071	/* wide char */
#define T_INT4		0x0074	/* int */
#define T_UINT4		0x0075	/* unsigned int */

#define T_32PVOID	0x0403	/* 32 bit near pointer to void */
#define T_32PCHAR	0x0410  /* 16:32 near pointer to signed char */
#define T_32PSHORT	0x0411  /* 16:32 near pointer to short */
#define T_32PLONG	0x0412  /* 16:32 near pointer to int */
#define T_32PQUAD	0x0413  /* 16:32 near pointer to long long */
#define T_32PUCHAR	0x0420  /* 16:32 near pointer to unsigned char */
#define T_32PUSHORT	0x0421  /* 16:32 near pointer to unsigned short */
#define T_32PULONG	0x0422	/* 16:32 near pointer to unsigned int */
#define T_32PUQUAD	0x0423  /* 16:32 near pointer to long long */
#define T_32PREAL32	0x0440	/* 16:32 near pointer to float */
#define T_32PREAL64	0x0441	/* 16:32 near pointer to float */
#define T_32PRCHAR	0x0470	/* 16:32 near pointer to real char */
#define T_32PWCHAR	0x0471	/* 16:32 near pointer to real char */
#define T_32PINT4	0x0474	/* 16:32 near pointer to int */
#define T_32PUINT4	0x0475  /* 16:32 near pointer to unsigned int */

#define LF_MODIFIER	0x1
#define LF_POINTER	0x2
#define LF_ARRAY	0x3
#define LF_CLASS	0x4
#define LF_STRUCTURE	0x5
#define LF_UNION	0x6
#define LF_ENUMERATION	0x7
#define LF_PROCEDURE	0x8
#define LF_MFUNCTION	0x9
#define LF_VTSHAPE	0xa
#define LF_BARRAY	0xd
#define LF_DIMARRAY	0x11
#define LF_VFTPATH	0x12

#define LF_SKIP		0x200
#define LF_ARGLIST	0x201
#define LF_FIELDLIST	0x204
#define LF_DERIVED	0x205
#define LF_BITFIELD	0x206

#define LF_BCLASS	0x400
#define LF_VBCLASS	0x401
#define LF_IVBCLASS	0x402
#define LF_ENUMERATE	0x403
#define LF_FRIENDFCN	0x404
#define LF_INDEX	0x405
#define LF_MEMBER	0x406
#define LF_STMEMBER	0x407
#define LF_METHOD	0x408
#define LF_NESTEDTYPE	0x409
#define LF_VFUNCTAB	0x40a
#define LF_FRIENDCLS	0x40b
#define LF_ONEMETHOD	0x40c
#define LF_FUNCOFF	0x40d

#define MAX_BUILTIN_TYPES	0x480
static struct datatype * cv_basic_types[MAX_BUILTIN_TYPES];
static int num_cv_defined_types = 0;
static struct datatype **cv_defined_types = NULL;

/*
 * For the type CODEVIEW debug directory entries, the debug directory
 * points to a structure like this.  The cv_name field is the name
 * of an external .PDB file.
 */
struct CodeViewDebug
{
	char		    cv_nbtype[8];
	unsigned int	    cv_timestamp;
	char		    cv_unknown[4];
	char		    cv_name[1];
};

struct MiscDebug {
    unsigned int       DataType;
    unsigned int       Length;
    char	       Unicode;
    char	       Reserved[3];
    char	       Data[1];
};

/*
 * This is the header that the COFF variety of debug header points to.
 */
struct CoffDebug {
    unsigned int   N_Sym;
    unsigned int   SymbolOffset;
    unsigned int   N_Linenum;
    unsigned int   LinenumberOffset;
    unsigned int   Unused[4];
};

struct CoffLinenum {
	unsigned int		VirtualAddr;
	unsigned short int	Linenum;
};

struct CoffFiles {
	unsigned int	startaddr;
	unsigned int	endaddr;
	char	      * filename;
	int		linetab_offset;
	int		linecnt;
	struct name_hash **entries;
	int		       neps;
	int		 neps_alloc;
};


struct CoffSymbol {
    union {
        char    ShortName[8];
        struct {
            unsigned int   NotLong;
            unsigned int   StrTaboff;
        } Name;
    } N;
    unsigned int   Value;
    short	   SectionNumber;
    short	   Type;
    char	   StorageClass;
    unsigned char  NumberOfAuxSymbols;
};

struct CoffAuxSection{
  unsigned int   Length;
  unsigned short NumberOfRelocations;
  unsigned short NumberOfLinenumbers;
  unsigned int   CheckSum;
  short          Number;
  char           Selection;
} Section;

/*
 * These two structures are used in the directory within a .DBG file
 * to locate the individual important bits that we might want to see.
 */
struct CV4_DirHead {
  short unsigned int	   dhsize;
  short unsigned int	   desize;
  unsigned int		   ndir;
  unsigned int		   next_offset;
  unsigned int		   flags;
};

struct CV4_DirEnt {
  short unsigned int	   subsect_number;
  short unsigned int	   module_number;
  unsigned int		   offset;
  unsigned int		   size;
};

/*
 * These are the values of interest that the subsect_number field takes.
 */
#define	sstAlignSym		0x125
#define	sstSrcModule		0x127

struct codeview_linetab_hdr
{
  unsigned int		   nline;
  unsigned int		   segno;
  unsigned int		   start;
  unsigned int		   end;
  char			 * sourcefile;
  unsigned short	 * linetab;
  unsigned int		 * offtab;
};

struct codeview_pdb_hdr
{
  char		ident[44];
  unsigned int	blocksize;	   /* Extent size */
  unsigned short loc_freelist;   /* freelist. */
  unsigned short alloc_filesize; /* # extents allocated. */
  unsigned int	toc_len;
  unsigned int	unknown;
  unsigned short toc_ext[1];	   /* array of extent #'s for toc. */
};

/*
 * This is our own structure that we use to keep track of the contents
 * of a PDB file.
 */
struct file_list
{
	int		record_len;
	int		nextents;
	short int     * extent_list;
	unsigned int	linetab_offset;
	unsigned int	linetab_len;
};

/*
 * These are the structures that represent how the file table is set up
 * within the PDB file.
 */
struct filetab_hdr
{
  unsigned short	tab1_file;
  unsigned short	tab2_file;
  unsigned short	gsym_file;
  unsigned short	padding;
  unsigned int		ftab_len;
  unsigned int		fofftab_len;
  unsigned int		hash_len;
  unsigned int		strtab_len;
};

struct file_ent
{
  unsigned int		reserved1;
  unsigned short	datasect_segment;
  unsigned short	reserved2;
  unsigned int		datasect_offset;
  unsigned int		datasect_size;
  unsigned int		datasect_flags;
  unsigned short	reserved3;
  unsigned short	index;
  unsigned short	num6a;
  unsigned short	file_number;
  unsigned int		linetab_offset;
  unsigned int		linetab_len;
  unsigned int		num9;
  unsigned int		num10;
  unsigned int		num11;
  unsigned char		filename[1];
};

/*
 ********************************************************************
 */
struct deferred_debug_info
{
	struct deferred_debug_info	* next;
	char				* load_addr;
	char				* module_name;
	char				* dbg_info;
	int				  dbg_size;
        HMODULE32                         module;
	LPIMAGE_DEBUG_DIRECTORY           dbgdir;
        LPIMAGE_SECTION_HEADER	          sectp;
	int				  nsect;
	short int			  dbg_index;			
	char				  loaded;
};

struct deferred_debug_info * dbglist = NULL;

/*
 * A simple macro that tells us whether a given COFF symbol is a
 * function or not.
 */
#define N_TMASK                             0x0030
#define IMAGE_SYM_DTYPE_FUNCTION            2
#define N_BTSHFT                            4
#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT))


/*
 * This is what we are looking for in the COFF symbols.
 */
#define IMAGE_SYM_CLASS_EXTERNAL            0x2
#define IMAGE_SYM_CLASS_STATIC              0x3
#define IMAGE_SYM_CLASS_FILE                0x67

static 
struct datatype * DEBUG_GetCVType(int typeno)
{
  struct datatype * dt = NULL;

  /*
   * Convert Codeview type numbers into something we can grok internally.
   * Numbers < 0x1000 are all fixed builtin types.  Numbers from 0x1000 and
   * up are all user defined (structs, etc).
   */
  if( typeno < 0x1000 )
    {
      if( typeno < MAX_BUILTIN_TYPES )
	{
	  dt = cv_basic_types[typeno];
	}
    }
  else
    {
      if( typeno - 0x1000 < num_cv_defined_types )
	{
	  dt = cv_defined_types[typeno - 0x1000];
	} 
    }

  return dt;
}

static int
DEBUG_ParseTypeTable(char * table, int len)
{
  int				  arr_max;
  int				  curr_type;
  enum debug_type		  fieldtype;
  int				  elem_size;
  union any_size		  ptr;
  union any_size		  ptr2;
  struct datatype		* subtype;
  char				  symname[256];
  union codeview_type		* type;
  union codeview_type		* type2;
  struct datatype		* typeptr;

  curr_type = 0x1000;

  ptr = (union any_size) (table + 16);
  while( ptr.c - table < len )
    {
      type = (union codeview_type *) ptr.c;

      if( curr_type - 0x1000 >= num_cv_defined_types )
	{
	  num_cv_defined_types += 0x100;
	  cv_defined_types = (struct datatype **) realloc(cv_defined_types,
		  num_cv_defined_types * sizeof(struct datatype *));
	  memset(cv_defined_types + num_cv_defined_types - 0x100,
		 0,
		 0x100 * sizeof(struct datatype *));
	  if( cv_defined_types == NULL )
	    {
	      return FALSE;
	    }
	}

      switch(type->generic.id)
	{
	case LF_POINTER:
	  cv_defined_types[curr_type - 0x1000] = 
	    DEBUG_FindOrMakePointerType(DEBUG_GetCVType(type->pointer.datatype));
	  break;
	case LF_ARRAY:
	  if( type->array.arrlen >= 0x8000 )
	    {
	      /*
	       * This is a numeric leaf, I am too lazy to handle this right
	       * now.
	       */
	      fprintf(stderr, "Ignoring large numberic leaf.\n");
	      break;
	    }
	  if( type->array.namelen != 0 )
	    {
	      memset(symname, 0, sizeof(symname));
	      memcpy(symname, type->array.name, type->array.namelen);
	      typeptr = DEBUG_NewDataType(ARRAY, symname);
	    }
	  else
	    {
	      typeptr = DEBUG_NewDataType(ARRAY, NULL);
	    }
	  cv_defined_types[curr_type - 0x1000] = typeptr;

	  subtype = DEBUG_GetCVType(type->array.elemtype);
	  if(    (subtype == NULL)
	      || (elem_size = DEBUG_GetObjectSize(subtype)) == 0 )
	    {
	      arr_max = 0;
	    }
	  else
	    {
	      arr_max = type->array.arrlen / DEBUG_GetObjectSize(subtype);
	    }

	  DEBUG_SetArrayParams(typeptr, 0, arr_max, subtype);
	  break;
	case LF_FIELDLIST:
	  /*
	   * This is where the basic list of fields is defined for
	   * structures and classes.
	   *
	   * First, we need to look ahead and see whether we are building
	   * a fieldlist for an enum or a struct.
	   */
	  ptr2.i = ptr.i + 1;
	  type2 = (union codeview_type *) ptr2.c;
	  if( type2->member.id == LF_MEMBER )
	    {
	      typeptr = DEBUG_NewDataType(STRUCT, NULL);
	      fieldtype = STRUCT;
	    }
	  else if( type2->member.id == LF_ENUMERATE )
	    {
	      typeptr = DEBUG_NewDataType(ENUM, NULL);
	      fieldtype = ENUM;
	    }
	  else
	    {
	      break;
	    }

	  cv_defined_types[curr_type - 0x1000] = typeptr;
	  while( ptr2.c < (ptr.c + ((type->generic.len + 3) & ~3)) )
	    {
	      type2 = (union codeview_type *) ptr2.c;
	      if( type2->member.id == LF_MEMBER && fieldtype == STRUCT )
		{
		  memset(symname, 0, sizeof(symname));
		  memcpy(symname, type2->member.name, type2->member.namelen);
		  
		  subtype = DEBUG_GetCVType(type2->member.type);
		  elem_size = 0;
		  if( subtype != NULL )
		    {
		      elem_size = DEBUG_GetObjectSize(subtype);
		    }
		  
		  if( type2->member.offset >= 0x8000 )
		    {
		      /*
		       * This is a numeric leaf, I am too lazy to handle this right
		       * now.
		       */
		      fprintf(stderr, "Ignoring large numberic leaf.\n");
		    }
		  else
		    {
		      DEBUG_AddStructElement(typeptr, symname, subtype, 
					     type2->member.offset << 3,
					     elem_size << 3);
		    }
		}
	      else if( type2->member.id == LF_ENUMERATE && fieldtype == ENUM )
		{
		  memset(symname, 0, sizeof(symname));
		  memcpy(symname, type2->enumerate.name, type2->enumerate.namelen);
		  
		  if( type2->enumerate.value >= 0x8000 )
		    {
		      /*
		       * This is a numeric leaf, I am too lazy to handle this right
		       * now.
		       */
		      fprintf(stderr, "Ignoring large numberic leaf.\n");
		    }
		  else
		    {
		      DEBUG_AddStructElement(typeptr, symname, NULL, 
					     type2->enumerate.value, 0);
		    }
		}
	      else
		{
		  /*
		   * Something else I have never seen before.  Either wrong type of
		   * object in the fieldlist, or some other problem which I wouldn't
		   * really know how to handle until it came up.
		   */
		  fprintf(stderr, "Unexpected entry in fieldlist\n");
		  break;
		}


	      ptr2.c += ((type2->member.namelen + 9 + 3) & ~3);
	    }
	  break;
	case LF_STRUCTURE:
	case LF_CLASS:
	  if( type->structure.structlen >= 0x8000 )
	    {
	      /*
	       * This is a numeric leaf, I am too lazy to handle this right
	       * now.
	       */
	      fprintf(stderr, "Ignoring large numberic leaf.\n");
	      break;
	    }
	  memset(symname, 0, sizeof(symname));
	  memcpy(symname, type->structure.name, type->structure.namelen);
	  if( strcmp(symname, "__unnamed") == 0 )
	    {
	      typeptr = DEBUG_NewDataType(STRUCT, NULL);
	    }
	  else
	    {
	      typeptr = DEBUG_NewDataType(STRUCT, symname);
	    }
	  cv_defined_types[curr_type - 0x1000] = typeptr;

	  /*
	   * Now copy the relevant bits from the fieldlist that we specified.
	   */
	  subtype = DEBUG_GetCVType(type->structure.fieldlist);

	  if( subtype != NULL )
	    {
	      DEBUG_SetStructSize(typeptr, type->structure.structlen);
	      DEBUG_CopyFieldlist(typeptr, subtype);
	    }
	  break;
	case LF_UNION:
	  if( type->t_union.un_len >= 0x8000 )
	    {
	      /*
	       * This is a numeric leaf, I am too lazy to handle this right
	       * now.
	       */
	      fprintf(stderr, "Ignoring large numberic leaf.\n");
	      break;
	    }
	  memset(symname, 0, sizeof(symname));
	  memcpy(symname, type->t_union.name, type->t_union.namelen);

	  if( strcmp(symname, "__unnamed") == 0 )
	    {
	      typeptr = DEBUG_NewDataType(STRUCT, NULL);
	    }
	  else
	    {
	      typeptr = DEBUG_NewDataType(STRUCT, symname);
	    }

	  cv_defined_types[curr_type - 0x1000] = typeptr;

	  /*
	   * Now copy the relevant bits from the fieldlist that we specified.
	   */
	  subtype = DEBUG_GetCVType(type->t_union.field);

	  if( subtype != NULL )
	    {
	      DEBUG_SetStructSize(typeptr, type->t_union.un_len);
	      DEBUG_CopyFieldlist(typeptr, subtype);
	    }
	  break;
	case LF_BITFIELD:
	  typeptr = DEBUG_NewDataType(BITFIELD, NULL);
	  cv_defined_types[curr_type - 0x1000] = typeptr;
	  DEBUG_SetBitfieldParams(typeptr, type->bitfield.bitoff,
				  type->bitfield.nbits, 
				  DEBUG_GetCVType(type->bitfield.type));
	  break;
	case LF_ENUMERATION:
	  memset(symname, 0, sizeof(symname));
	  memcpy(symname, type->enumeration.name, type->enumeration.namelen);
	  typeptr = DEBUG_NewDataType(ENUM, symname);
	  cv_defined_types[curr_type - 0x1000] = typeptr;

	  /*
	   * Now copy the relevant bits from the fieldlist that we specified.
	   */
	  subtype = DEBUG_GetCVType(type->enumeration.field);

	  if( subtype != NULL )
	    {
	      DEBUG_CopyFieldlist(typeptr, subtype);
	    }
	  break;
	case LF_DIMARRAY:
	default:
	  break;
	}
      curr_type++;
      ptr.c += (type->generic.len + 3) & ~3;
    }

  return TRUE;
}

void
DEBUG_InitCVDataTypes()
{
  /*
   * These are the common builtin types that are used by VC++.
   */
  cv_basic_types[T_NOTYPE] = NULL;
  cv_basic_types[T_ABS] = NULL;
  cv_basic_types[T_VOID] = DEBUG_NewDataType(BASIC, "void");
  cv_basic_types[T_CHAR] = DEBUG_NewDataType(BASIC, "char");
  cv_basic_types[T_SHORT] = DEBUG_NewDataType(BASIC, "short int");
  cv_basic_types[T_LONG] = DEBUG_NewDataType(BASIC, "long int");
  cv_basic_types[T_QUAD] = DEBUG_NewDataType(BASIC, "long long int");
  cv_basic_types[T_UCHAR] = DEBUG_NewDataType(BASIC, "unsigned char");
  cv_basic_types[T_USHORT] = DEBUG_NewDataType(BASIC, "short unsigned int");
  cv_basic_types[T_ULONG] = DEBUG_NewDataType(BASIC, "long unsigned int");
  cv_basic_types[T_UQUAD] = DEBUG_NewDataType(BASIC, "long long unsigned int");
  cv_basic_types[T_REAL32] = DEBUG_NewDataType(BASIC, "float");
  cv_basic_types[T_REAL64] = DEBUG_NewDataType(BASIC, "double");
  cv_basic_types[T_RCHAR] = DEBUG_NewDataType(BASIC, "char");
  cv_basic_types[T_WCHAR] = DEBUG_NewDataType(BASIC, "short");
  cv_basic_types[T_INT4] = DEBUG_NewDataType(BASIC, "int");
  cv_basic_types[T_UINT4] = DEBUG_NewDataType(BASIC, "unsigned int");

  cv_basic_types[T_32PVOID] = DEBUG_FindOrMakePointerType(cv_basic_types[T_VOID]);
  cv_basic_types[T_32PCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_CHAR]);
  cv_basic_types[T_32PSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_SHORT]);
  cv_basic_types[T_32PLONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_LONG]);
  cv_basic_types[T_32PQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_QUAD]);
  cv_basic_types[T_32PUCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UCHAR]);
  cv_basic_types[T_32PUSHORT] = DEBUG_FindOrMakePointerType(cv_basic_types[T_USHORT]);
  cv_basic_types[T_32PULONG] = DEBUG_FindOrMakePointerType(cv_basic_types[T_ULONG]);
  cv_basic_types[T_32PUQUAD] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UQUAD]);
  cv_basic_types[T_32PREAL32] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL32]);
  cv_basic_types[T_32PREAL64] = DEBUG_FindOrMakePointerType(cv_basic_types[T_REAL64]);
  cv_basic_types[T_32PRCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_RCHAR]);
  cv_basic_types[T_32PWCHAR] = DEBUG_FindOrMakePointerType(cv_basic_types[T_WCHAR]);
  cv_basic_types[T_32PINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_INT4]);
  cv_basic_types[T_32PUINT4] = DEBUG_FindOrMakePointerType(cv_basic_types[T_UINT4]);
}

/*
 * In this function, we keep track of deferred debugging information
 * that we may need later if we were to need to use the internal debugger.
 * We don't fully process it here for performance reasons.
 */
int
DEBUG_RegisterDebugInfo( HMODULE32 hModule, const char *module_name,
                         u_long v_addr, u_long size)
{
  int			  has_codeview = FALSE;
  int			  rtn = FALSE;
  int			  orig_size;
  LPIMAGE_DEBUG_DIRECTORY dbgptr;
  struct deferred_debug_info * deefer;

  orig_size = size;
  dbgptr = (LPIMAGE_DEBUG_DIRECTORY) (hModule + v_addr);
  for(; size >= sizeof(*dbgptr); size -= sizeof(*dbgptr), dbgptr++ )
    {
      switch(dbgptr->Type)
	{
	case IMAGE_DEBUG_TYPE_CODEVIEW:
	case IMAGE_DEBUG_TYPE_MISC:
	  has_codeview = TRUE;
	  break;
	}
    }

  size = orig_size;
  dbgptr = (LPIMAGE_DEBUG_DIRECTORY) (hModule + v_addr);
  for(; size >= sizeof(*dbgptr); size -= sizeof(*dbgptr), dbgptr++ )
    {
      switch(dbgptr->Type)
	{
	case IMAGE_DEBUG_TYPE_COFF:
	  /*
	   * If we have both codeview and COFF debug info, ignore the
	   * coff debug info as  it would just confuse us, and it is 
	   * less complete.
	   *
	   * FIXME - this is broken - if we cannot find the PDB file, then
	   * we end up with no debugging info at all.  In this case, we
	   * should use the COFF info as a backup.
	   */
	  if( has_codeview )
	    {
	      break;
	    }
	case IMAGE_DEBUG_TYPE_CODEVIEW:
	case IMAGE_DEBUG_TYPE_MISC:
	  /*
	   * This is usually an indirection to a .DBG file.
	   * This is similar to (but a slightly older format) from the
	   * PDB file.
	   *
	   * First check to see if the image was 'stripped'.  If so, it
	   * means that this entry points to a .DBG file.  Otherwise,
	   * it just points to itself, and we can ignore this.
	   */
	  if(    (dbgptr->Type == IMAGE_DEBUG_TYPE_MISC)
	      && (PE_HEADER(hModule)->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) == 0 )
	    {
	      break;
	    }

	  deefer = (struct deferred_debug_info *) xmalloc(sizeof(*deefer));
	  deefer->module    = hModule;
	  deefer->load_addr = (char *)hModule;
	  deefer->dbg_info  = NULL;
	  deefer->dbg_size  = 0;

	  /*
	   * Read the important bits.  What we do after this depends
	   * upon the type, but this is always enough so we are able
	   * to proceed if we know what we need to do next.
	   */
	  deefer->dbg_size = dbgptr->SizeOfData;
	  deefer->dbg_info = (char *)(hModule + dbgptr->PointerToRawData);
	  deefer->dbgdir = dbgptr;
	  deefer->next = dbglist;
	  deefer->loaded = FALSE;
	  deefer->dbg_index = DEBUG_next_index;
	  deefer->module_name = xstrdup(module_name);

	  deefer->sectp = PE_SECTIONS(hModule);
	  deefer->nsect = PE_HEADER(hModule)->FileHeader.NumberOfSections;

	  dbglist = deefer;
	  break;
	default:
	}
    }

  DEBUG_next_index++;

  return (rtn);

}

/*
 * ELF modules are also entered into the list - this is so that we
 * can make 'info shared' types of displays possible.
 */
int
DEBUG_RegisterELFDebugInfo(int load_addr, u_long size, char * name)
{
  struct deferred_debug_info * deefer;

  deefer = (struct deferred_debug_info *) xmalloc(sizeof(*deefer));
  deefer->module = 0;
  
  /*
   * Read the important bits.  What we do after this depends
   * upon the type, but this is always enough so we are able
   * to proceed if we know what we need to do next.
   */
  deefer->dbg_size = size;
  deefer->dbg_info = (char *) NULL;
  
  deefer->load_addr = (char *) load_addr;
  deefer->dbgdir = NULL;
  deefer->next = dbglist;
  deefer->loaded = TRUE;
  deefer->dbg_index = DEBUG_next_index;
  deefer->module_name = xstrdup(name);
  dbglist = deefer;

  DEBUG_next_index++;

  return (TRUE);
}



/*
 * Process COFF debugging information embedded in a Win32 application.
 *
 */
static
int
DEBUG_ProcessCoff(struct deferred_debug_info * deefer)
{
  struct CoffAuxSection * aux;
  struct CoffDebug   * coff;
  struct CoffFiles   * coff_files = NULL;
  struct CoffLinenum * coff_linetab;
  char		     * coff_strtab;
  struct CoffSymbol  * coff_sym;
  struct CoffSymbol  * coff_symbol;
  struct CoffFiles   * curr_file = NULL;
  int		       i;
  int		       j;
  int		       k;
  struct CoffLinenum * linepnt;
  int		       linetab_indx;
  char		       namebuff[9];
  char		     * nampnt;
  int		       naux;
  DBG_ADDR	       new_addr;
  int		       nfiles = 0;
  int		       nfiles_alloc = 0;
  struct CoffFiles     orig_file;
  int		       rtn = FALSE;
  char		     * this_file = NULL;

  coff = (struct CoffDebug *) deefer->dbg_info;

  coff_symbol = (struct CoffSymbol *) ((unsigned int) coff + coff->SymbolOffset);
  coff_linetab = (struct CoffLinenum *) ((unsigned int) coff + coff->LinenumberOffset);
  coff_strtab = (char *) ((unsigned int) coff_symbol + 18*coff->N_Sym);

  linetab_indx = 0;

  for(i=0; i < coff->N_Sym; i++ )
    {
      /*
       * We do this because some compilers (i.e. gcc) incorrectly
       * pad the structure up to a 4 byte boundary.  The structure
       * is really only 18 bytes long, so we have to manually make sure
       * we get it right.
       *
       * FIXME - there must be a way to have autoconf figure out the
       * correct compiler option for this.  If it is always gcc, that
       * makes life simpler, but I don't want to force this.
       */
      coff_sym = (struct CoffSymbol *) ((unsigned int) coff_symbol + 18*i);
      naux = coff_sym->NumberOfAuxSymbols;

      if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE )
	{
	  if( nfiles + 1 >= nfiles_alloc )
	    {
	      nfiles_alloc += 10;
	      coff_files = (struct CoffFiles *) realloc( coff_files,
			nfiles_alloc * sizeof(struct CoffFiles));
	    }
	  curr_file = coff_files + nfiles;
	  nfiles++;
	  curr_file->startaddr = 0xffffffff;
	  curr_file->endaddr   = 0;
	  curr_file->filename =  ((char *) coff_sym) + 18;
	  curr_file->linetab_offset = -1;
	  curr_file->linecnt = 0;
	  curr_file->entries = NULL;
	  curr_file->neps = curr_file->neps_alloc = 0;
#if 0
	  fprintf(stderr,"New file %s\n", curr_file->filename);
#endif
	  i += naux;
	  continue;
	}

      /*
       * This guy marks the size and location of the text section
       * for the current file.  We need to keep track of this so
       * we can figure out what file the different global functions
       * go with.
       */
      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
	  && (naux != 0)
	  && (coff_sym->Type == 0)
	  && (coff_sym->SectionNumber == 1) )
	{
	  aux = (struct CoffAuxSection *) ((unsigned int) coff_sym + 18);

	  if( curr_file->linetab_offset != -1 )
	    {
#if 0
	      fprintf(stderr, "Duplicating sect from %s: %x %x %x %d %d\n",
		      curr_file->filename,
		      aux->Length,
		      aux->NumberOfRelocations,
		      aux->NumberOfLinenumbers,
		      aux->Number,
		      aux->Selection);
	      fprintf(stderr, "More sect %d %x %d %d %d\n", 
		      coff_sym->SectionNumber,
		      coff_sym->Value,
		      coff_sym->Type,
		      coff_sym->StorageClass,
		      coff_sym->NumberOfAuxSymbols);
#endif

	      /*
	       * Save this so we can copy bits from it.
	       */
	      orig_file = *curr_file;

	      /*
	       * Duplicate the file entry.  We have no way to describe
	       * multiple text sections in our current way of handling things.
	       */
	      if( nfiles + 1 >= nfiles_alloc )
		{
		  nfiles_alloc += 10;
		  coff_files = (struct CoffFiles *) realloc( coff_files,
							     nfiles_alloc * sizeof(struct CoffFiles));
		}
	      curr_file = coff_files + nfiles;
	      nfiles++;
	      curr_file->startaddr = 0xffffffff;
	      curr_file->endaddr   = 0;
	      curr_file->filename = orig_file.filename;
	      curr_file->linetab_offset = -1;
	      curr_file->linecnt = 0;
	      curr_file->entries = NULL;
	      curr_file->neps = curr_file->neps_alloc = 0;
	    }
#if 0
	  else
	    {
	      fprintf(stderr, "New text sect from %s: %x %x %x %d %d\n",
		      curr_file->filename,
		      aux->Length,
		      aux->NumberOfRelocations,
		      aux->NumberOfLinenumbers,
		      aux->Number,
		      aux->Selection);
	    }
#endif

	  if( curr_file->startaddr > coff_sym->Value )
	    {
	      curr_file->startaddr = coff_sym->Value;
	    }
	  
	  if( curr_file->startaddr > coff_sym->Value )
	    {
	      curr_file->startaddr = coff_sym->Value;
	    }
	  
	  if( curr_file->endaddr < coff_sym->Value + aux->Length )
	    {
	      curr_file->endaddr = coff_sym->Value + aux->Length;
	    }
	  
	  curr_file->linetab_offset = linetab_indx;
	  curr_file->linecnt = aux->NumberOfLinenumbers;
	  linetab_indx += aux->NumberOfLinenumbers;
	  i += naux;
	  continue;
	}

      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
	  && (naux == 0)
	  && (coff_sym->SectionNumber == 1) )
	{
	  /*
	   * This is a normal static function when naux == 0.
	   * Just register it.  The current file is the correct
	   * one in this instance.
	   */
	  if( coff_sym->N.Name.NotLong )
	    {
	      memcpy(namebuff, coff_sym->N.ShortName, 8);
	      namebuff[8] = '\0';
	      nampnt = &namebuff[0];
	    }
	  else
	    {
	      nampnt = coff_strtab + coff_sym->N.Name.StrTaboff;
	    }

	  if( nampnt[0] == '_' )
	    {
	      nampnt++;
	    }

	  new_addr.seg = 0;
	  new_addr.off = (int) (deefer->load_addr + coff_sym->Value);

	  if( curr_file->neps + 1 >= curr_file->neps_alloc )
	    {
	      curr_file->neps_alloc += 10;
	      curr_file->entries = (struct name_hash **) 
		realloc( curr_file->entries, 
			 curr_file->neps_alloc * sizeof(struct name_hash *));
	    }
#if 0
	  fprintf(stderr,"\tAdding static symbol %s\n", nampnt);
#endif
	  curr_file->entries[curr_file->neps++] =
	    DEBUG_AddSymbol( nampnt, &new_addr, this_file, SYM_WIN32 );
	  i += naux;
	  continue;
	}

      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
	  && ISFCN(coff_sym->Type)
          && (coff_sym->SectionNumber > 0) )
	{
	  if( coff_sym->N.Name.NotLong )
	    {
	      memcpy(namebuff, coff_sym->N.ShortName, 8);
	      namebuff[8] = '\0';
	      nampnt = &namebuff[0];
	    }
	  else
	    {
	      nampnt = coff_strtab + coff_sym->N.Name.StrTaboff;
	    }


	  if( nampnt[0] == '_' )
	    {
	      nampnt++;
	    }

	  new_addr.seg = 0;
	  new_addr.off = (int) (deefer->load_addr + coff_sym->Value);

#if 0
	  fprintf(stderr, "%d: %x %s\n", i, new_addr.off, nampnt);

	  fprintf(stderr,"\tAdding global symbol %s\n", nampnt);
#endif

	  /*
	   * Now we need to figure out which file this guy belongs to.
	   */
	  this_file = NULL;
	  for(j=0; j < nfiles; j++)
	    {
	      if( coff_files[j].startaddr <= coff_sym->Value
		  && coff_files[j].endaddr > coff_sym->Value )
		{
		  this_file = coff_files[j].filename;
		  break;
		}
	    }
	  if( coff_files[j].neps + 1 >= coff_files[j].neps_alloc )
	    {
	      coff_files[j].neps_alloc += 10;
	      coff_files[j].entries = (struct name_hash **) 
		realloc( coff_files[j].entries, 
			 coff_files[j].neps_alloc * sizeof(struct name_hash *));
	    }
	  coff_files[j].entries[coff_files[j].neps++] =
	    DEBUG_AddSymbol( nampnt, &new_addr, this_file, SYM_WIN32 );
	  i += naux;
	  continue;
	}

      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
          && (coff_sym->SectionNumber > 0) )
	{
	  /*
	   * Similar to above, but for the case of data symbols.
	   * These aren't treated as entrypoints.
	   */
	  if( coff_sym->N.Name.NotLong )
	    {
	      memcpy(namebuff, coff_sym->N.ShortName, 8);
	      namebuff[8] = '\0';
	      nampnt = &namebuff[0];
	    }
	  else
	    {
	      nampnt = coff_strtab + coff_sym->N.Name.StrTaboff;
	    }


	  if( nampnt[0] == '_' )
	    {
	      nampnt++;
	    }

	  new_addr.seg = 0;
	  new_addr.off = (int) (deefer->load_addr + coff_sym->Value);

#if 0
	  fprintf(stderr, "%d: %x %s\n", i, new_addr.off, nampnt);

	  fprintf(stderr,"\tAdding global data symbol %s\n", nampnt);
#endif

	  /*
	   * Now we need to figure out which file this guy belongs to.
	   */
	  DEBUG_AddSymbol( nampnt, &new_addr, NULL, SYM_WIN32 );
	  i += naux;
	  continue;
	}
	  
      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
	  && (naux == 0) )
	{
	  /*
	   * Ignore these.  They don't have anything to do with
	   * reality.
	   */
	  i += naux;
	  continue;
	}

#if 0
      fprintf(stderr,"Skipping unknown entry %d %d %d\n", coff_sym->StorageClass, 
	      coff_sym->SectionNumber, naux);
#endif

      /*
       * For now, skip past the aux entries.
       */
      i += naux;
      
    }
    
  /*
   * OK, we now should have a list of files, and we should have a list
   * of entrypoints.  We need to sort the entrypoints so that we are
   * able to tie the line numbers with the given functions within the
   * file.
   */
  if( coff_files != NULL )
    {
      for(j=0; j < nfiles; j++)
	{
	  if( coff_files[j].entries != NULL )
	    {
	      qsort(coff_files[j].entries, coff_files[j].neps,
		    sizeof(struct name_hash *), DEBUG_cmp_sym);
	    }
	}

      /*
       * Now pick apart the line number tables, and attach the entries
       * to the given functions.
       */
      for(j=0; j < nfiles; j++)
	{
	  i = 0;
	  for(k=0; k < coff_files[j].linecnt; k++)
	    {
	      /*
	       * Another monstrosity caused by the fact that we are using
	       * a 6 byte structure, and gcc wants to pad structures to 4 byte
	       * boundaries.  Otherwise we could just index into an array.
	       */
	      linepnt = (struct CoffLinenum *) 
		((unsigned int) coff_linetab + 
		 6*(coff_files[j].linetab_offset + k));
	      /*
	       * If we have spilled onto the next entrypoint, then
	       * bump the counter..
	       */
	      while(TRUE)
		{
		  DEBUG_GetSymbolAddr(coff_files[j].entries[i+1], &new_addr);
		  if(   (i+1 < coff_files[j].neps)
			&& (   ((unsigned int) deefer->load_addr + linepnt->VirtualAddr)
			       >= new_addr.off) )
		    {
		      i++;
		    }
		  else
		    {
		      break;
		    }
		}

	      /*
	       * Add the line number.  This is always relative to the
	       * start of the function, so we need to subtract that offset
	       * first.
	       */
	      DEBUG_GetSymbolAddr(coff_files[j].entries[i], &new_addr);
	      DEBUG_AddLineNumber(coff_files[j].entries[i], 
				  linepnt->Linenum,
				  (unsigned int) deefer->load_addr 
				  + linepnt->VirtualAddr 
				  - new_addr.off);
	    }
	}
    }

  rtn = TRUE;

  if( coff_files != NULL )
    {
      for(j=0; j < nfiles; j++)
	{
	  if( coff_files[j].entries != NULL )
	    {
	      free(coff_files[j].entries);
	    }
	}
      free(coff_files);
    }

  return (rtn);

}

/*
 * Process a codeview line number table.  Digestify the thing so that
 * we can easily reference the thing when we process the rest of
 * the information.
 */
static struct codeview_linetab_hdr *
DEBUG_SnarfLinetab(char			     * linetab,
		   int			       size)
{
  int				  file_segcount;
  char				  filename[PATH_MAX];
  unsigned int			* filetab;
  char				* fn;
  int				  i;
  int				  k;
  struct codeview_linetab_hdr   * lt_hdr;
  unsigned int			* lt_ptr;
  int				  nfile;
  int				  nseg;
  union any_size		  pnt;
  union any_size		  pnt2;
  struct startend		* start;
  int				  this_seg;

  /*
   * Now get the important bits.
   */
  pnt = (union any_size) linetab;
  nfile = *pnt.s++;
  nseg = *pnt.s++;

  filetab = (unsigned int *) pnt.c;

  /*
   * Now count up the number of segments in the file.
   */
  nseg = 0;
  for(i=0; i<nfile; i++)
    {
      pnt2 = (union any_size) (linetab + filetab[i]);
      nseg += *pnt2.s;
    }

  /*
   * Next allocate the header we will be returning.
   * There is one header for each segment, so that we can reach in
   * and pull bits as required.
   */
  lt_hdr = (struct codeview_linetab_hdr *) 
    xmalloc((nseg + 1) * sizeof(*lt_hdr));
  if( lt_hdr == NULL )
    {
      goto leave;
    }

  memset(lt_hdr, 0, sizeof(*lt_hdr) * (nseg+1));

  /*
   * Now fill the header we will be returning, one for each segment.
   * Note that this will basically just contain pointers into the existing
   * line table, and we do not actually copy any additional information
   * or allocate any additional memory.
   */

  this_seg = 0;
  for(i=0; i<nfile; i++)
    {
      /*
       * Get the pointer into the segment information.
       */
      pnt2 = (union any_size) (linetab + filetab[i]);
      file_segcount = *pnt2.s;

      pnt2.ui++;
      lt_ptr = (unsigned int *) pnt2.c;
      start = (struct startend *) (lt_ptr + file_segcount);

      /*
       * Now snarf the filename for all of the segments for this file.
       */
      fn = (unsigned char *) (start + file_segcount);
      memset(filename, 0, sizeof(filename));
      memcpy(filename, fn + 1, *fn);
      fn = strdup(filename);

      for(k = 0; k < file_segcount; k++, this_seg++)
	{
	  pnt2 = (union any_size) (linetab + lt_ptr[k]);
	  lt_hdr[this_seg].start      = start[k].start;
	  lt_hdr[this_seg].end	      = start[k].end;
	  lt_hdr[this_seg].sourcefile = fn;
	  lt_hdr[this_seg].segno      = *pnt2.s++;
	  lt_hdr[this_seg].nline      = *pnt2.s++;
	  lt_hdr[this_seg].offtab     =  pnt2.ui;
	  lt_hdr[this_seg].linetab    = (unsigned short *) 
	    (pnt2.ui + lt_hdr[this_seg].nline);
	}
    }

leave:

  return lt_hdr;

}

static int
DEBUG_SnarfCodeView(      struct deferred_debug_info * deefer,
			  char			     * cv_data,
			  int			       size,
			  struct codeview_linetab_hdr * linetab)
{
  struct name_hash	* curr_func = NULL;
  struct wine_locals	* curr_sym = NULL;
  int			  i;
  int			  j;
  int			  len;
  DBG_ADDR		  new_addr;
  int			  nsect;
  union any_size	  ptr;
  IMAGE_SECTION_HEADER  * sectp;
  union	codeview_symbol	* sym;
  char			  symname[PATH_MAX];
  struct name_hash	* thunk_sym = NULL;

  ptr = (union any_size) cv_data;
  nsect = deefer->nsect;
  sectp = deefer->sectp;

  /*
   * Skip over the first word.  Don't really know what it means, but
   * it is useless.
   */
  ptr.ui++;

  /*
   * Loop over the different types of records and whenever we
   * find something we are interested in, record it and move on.
   */
  while( ptr.c - cv_data < size )
    {
      sym = (union codeview_symbol *) ptr.c;

      if( sym->generic.len - sizeof(int) == (ptr.c - cv_data) )
	{
	  /*
	   * This happens when we have indirect symbols that VC++ 4.2
	   * sometimes uses when there isn't a line number table.
	   * We ignore it - we will process and enter all of the
	   * symbols in the global symbol table anyways, so there
	   * isn't much point in keeping track of all of this crap.
	   */
	  break;
	}

      memset(symname, 0, sizeof(symname));
      switch(sym->generic.id)
	{
	case S_GDATA32:
	case S_LDATA32:
	case S_PUB32:
	  /*
	   * First, a couple of sanity checks.
	   */
	  if( sym->data.namelen == 0 )
	    {
	      break;
	    }

	  if( sym->data.seg == 0 || sym->data.seg > nsect )
	    {
	      break;
	    }

	  /*
	   * Global and local data symbols.  We don't associate these
	   * with any given source file.
	   */

	  memcpy(symname, sym->data.name, sym->data.namelen);
	  new_addr.seg = 0;
	  new_addr.type = DEBUG_GetCVType(sym->data.symtype);
	  new_addr.off = (unsigned int) deefer->load_addr + 
	    sectp[sym->data.seg - 1].VirtualAddress + 
	    sym->data.offset;
	  DEBUG_AddSymbol( symname, &new_addr, NULL, SYM_WIN32 | SYM_DATA );
	  break;
	case S_THUNK32:
	  /*
	   * Sort of like a global function, but it just points
	   * to a thunk, which is a stupid name for what amounts to
	   * a PLT slot in the normal jargon that everyone else uses.
	   */
	  memcpy(symname, sym->thunk.name, sym->thunk.namelen);
	  new_addr.seg = 0;
	  new_addr.type = NULL;
	  new_addr.off = (unsigned int) deefer->load_addr + 
	    sectp[sym->thunk.segment - 1].VirtualAddress + 
	    sym->thunk.offset;
	  thunk_sym = DEBUG_AddSymbol( symname, &new_addr, NULL, 
				       SYM_WIN32 | SYM_FUNC);
	  DEBUG_SetSymbolSize(thunk_sym, sym->thunk.thunk_len);
	  break;
	case S_GPROC32:
	case S_LPROC32:
	  /*
	   * Global and static functions.
	   */
	  memcpy(symname, sym->proc.name, sym->proc.namelen);
	  new_addr.seg = 0;
	  new_addr.type = DEBUG_GetCVType(sym->proc.proctype);
	  new_addr.off = (unsigned int) deefer->load_addr + 
	    sectp[sym->proc.segment - 1].VirtualAddress + 
	    sym->proc.offset;
	  /*
	   * See if we can find a segment that this goes with.  If so,
	   * it means that we also may have line number information
	   * for this function.
	   */
	  for(i=0; linetab[i].linetab != NULL; i++)
	    {
	      if(     ((unsigned int) deefer->load_addr 
		       + sectp[linetab[i].segno - 1].VirtualAddress 
		       + linetab[i].start <= new_addr.off)
		  &&  ((unsigned int) deefer->load_addr 
		       + sectp[linetab[i].segno - 1].VirtualAddress 
		       + linetab[i].end > new_addr.off) )
		{
		  break;
		}
	    }

 	  DEBUG_Normalize(curr_func);
	  if( linetab[i].linetab == NULL )
	    {
	      curr_func = DEBUG_AddSymbol( symname, &new_addr, NULL,
					   SYM_WIN32 | SYM_FUNC);
	    }
	  else
	    {
	      /*
	       * First, create the entry.  Then dig through the linetab
	       * and add whatever line numbers are appropriate for this
	       * function.
	       */
	      curr_func = DEBUG_AddSymbol( symname, &new_addr, 
					   linetab[i].sourcefile,
					   SYM_WIN32 | SYM_FUNC);
	      for(j=0; j < linetab[i].nline; j++)
		{
		  if( linetab[i].offtab[j] >= sym->proc.offset 
		      && linetab[i].offtab[j] < sym->proc.offset 
		      + sym->proc.proc_len )
		    {
		      DEBUG_AddLineNumber(curr_func, linetab[i].linetab[j],
					  linetab[i].offtab[j] - sym->proc.offset);
		    }
		}

	    }

	  /*
	   * Add information about where we should set breakpoints
	   * in this function.
	   */
	  DEBUG_SetSymbolBPOff(curr_func, sym->proc.debug_start);
	  DEBUG_SetSymbolSize(curr_func, sym->proc.proc_len);
	  break;
	case S_BPREL32:
	  /*
	   * Function parameters and stack variables.
	   */
	  memcpy(symname, sym->stack.name, sym->stack.namelen);
	  curr_sym = DEBUG_AddLocal(curr_func, 
			 0, 
			 sym->stack.offset, 
			 0, 
			 0, 
			 symname);
	  DEBUG_SetLocalSymbolType(curr_sym, DEBUG_GetCVType(sym->stack.symtype));
	  
	  break;
	default:
	  break;
	}

      /*
       * Adjust pointer to point to next entry, rounding up to a word
       * boundary.  MS preserving alignment?  Stranger things have
       * happened.
       */
      if( sym->generic.id == S_PROCREF
	  || sym->generic.id == S_DATAREF
	  || sym->generic.id == S_UNKNOWN )
	{
	  len = (sym->generic.len + 3) & ~3;
	  len += ptr.c[16] + 1;
	  ptr.c += (len + 3) & ~3;
	}
      else
	{
	  ptr.c += (sym->generic.len + 3) & ~3;
	}
    }

  if( linetab != NULL )
    {
      free(linetab);
    }

  return TRUE;
}


/*
 * Process PDB file which contains debug information.
 *
 * These are really weird beasts.  They are intended to be incrementally
 * updated by the incremental linker, and this means that you need to 
 * be able to remove and add information.  Thus the PDB file is sort of
 * like a block structured device, with a freelist and lists of extent numbers
 * that are used to get the relevant pieces.  In all cases seen so far, the
 * blocksize is always 0x400 bytes.  The header has a field which apparently
 * holds the blocksize, so if it ever changes we are safe.
 *
 * In general, every time we need to extract something from the pdb file,
 * it is easier to copy it into another buffer so we have the information
 * in one contiguous block rather than attempt to try and keep track of when
 * we need to grab another extent from the pdb file.
 *
 * The thing that is a real pain about some MS stuff is that they choose
 * data structures which are not representable in C.  Thus we have to
 * hack around and diddle pointers.
 */
/* static */
int
DEBUG_ProcessPDBFile(struct deferred_debug_info * deefer, char * full_filename)
{
  char			      * addr = (char *) 0xffffffff;
  unsigned int			blocksize;
  unsigned int			bufflen = 0;
  char			      * buffer = NULL;
  unsigned short	      * extent_table;
  int				fd = -1;
  struct file_ent	      * fent;
  char			      * filename;
  struct file_list	      * filelist = NULL;
  unsigned int			gsym_record = 0;
  char			      * gsymtab = NULL;
  struct filetab_hdr	      * hd;
  int				i;
  int				j;
  unsigned int			last_extent;
  struct codeview_linetab_hdr * linetab;
  unsigned int			nblocks;
  unsigned int			npair;
  unsigned int			offset;
  struct codeview_pdb_hdr     * pdbhdr;
  unsigned int		      * pnt;
  struct stat			statbuf;
  int				status;
  unsigned short	      * table;
  char			      * toc;
  unsigned int			toc_blocks;
  
  /*
   * FIXME - we should use some kind of search path mechanism to locate
   * PDB files.  Right now we just look in the current working directory,
   * which works much of the time, I guess.  Ideally we should be able to
   * map the filename back using the settings in wine.ini and perhaps
   * we could find it there.  This bit of coding is left as an exercise
   * for the reader. :-).
   */
  filename = strrchr(full_filename, '\\');
  if( filename == NULL )
    {
      filename = full_filename;
    }
  else
    {
      filename++;
    }

  status = stat(filename, &statbuf);
  if( status == -1 )
    {
      fprintf(stderr, "Unable to open .PDB file %s\n", filename);
      goto leave;
    }

  /*
   * Now open the file, so that we can mmap() it.
   */
  fd = open(filename, O_RDONLY);
  if( fd == -1 )
    {
      fprintf(stderr, "Unable to open .DBG file %s\n", filename);
      goto leave;
    }


  /*
   * Now mmap() the file.
   */
  addr = mmap(0, statbuf.st_size, PROT_READ, 
	      MAP_PRIVATE, fd, 0);
  if( addr == (char *) 0xffffffff )
    {
      fprintf(stderr, "Unable to mmap .DBG file %s\n", filename);
      goto leave;
    }

  /*
   * Now that we have the formalities over and done with, we need
   * to find the table of contents for the PDB file.
   */
  pdbhdr = (struct codeview_pdb_hdr *) addr;
  blocksize = pdbhdr->blocksize;
  last_extent = (statbuf.st_size + blocksize - 1) / blocksize;

  /*
   * The TOC itself isn't always contiguous, so we need to extract a few
   * extents from the file to form the TOC.
   */
  toc_blocks = (pdbhdr->toc_len + blocksize - 1) / blocksize;
  toc = (char *) xmalloc(toc_blocks * blocksize);
  table = pdbhdr->toc_ext;
  for(i=0; i < toc_blocks; i++)
    {
      memcpy(toc + blocksize*i, addr + table[i]*blocksize, blocksize);
    }

  /*
   * Next build our own table which will have the size and extent block
   * list for each record in the PDB file.
   *
   * The TOC starts out with the number of files.  Then it is followed by
   * (npair * 2*sizeof(int)) bytes of information, which are pairs of ints.
   * The first one is the size of the record (in bytes), and the second one
   * is something else which I haven't figured out yet.
   */
  pnt = (unsigned int *) toc;
  npair = *pnt++;
  extent_table = (unsigned short *) ((unsigned int) toc +
				     npair * 2 * sizeof(int) + sizeof(int));

  /*
   * Sanity check.
   */
  if( sizeof(int) + 2*sizeof(int)*npair > pdbhdr->toc_len )
    {
      goto leave;
    }
  
  filelist = (struct file_list *) xmalloc(npair * sizeof(*filelist));
  if( filelist == NULL )
    {
      goto leave;
    }
  memset(filelist, 0, npair * sizeof(*filelist));

  nblocks = 0;
  for(i=0; i < npair; i++)
    {
      filelist[i].record_len = pnt[i*2];
      filelist[i].nextents   = (filelist[i].record_len + blocksize - 1) 
	/ blocksize;
      filelist[i].extent_list = extent_table + nblocks;
      nblocks += filelist[i].nextents;

      /*
       * These get filled in later when we parse one of the records.
       */
      filelist[i].linetab_offset = 0;
      filelist[i].linetab_len = 0;
    }

  /*
   * OK, now walk through the various records and pick out the bits we
   * really want to see.  Some of the records are extra special, and
   * we need to handle these a little bit differently.
   */
  for(i=0; i < npair; i++)
    {
      if( filelist[i].record_len == 0xffffffff )
	{
	  continue;
	}

      /*
       * Make sure our buffer is large enough to hold the record.
       */
      if( bufflen < filelist[i].nextents * blocksize )
	{
	  bufflen = filelist[i].nextents * blocksize;
	  buffer = (char *) realloc(buffer, bufflen);
	}

      /*
       * Do this just for completeness.  It makes debugging easier
       * if we have a clean indication of where the record ends.
       */
      memset(buffer, 0, filelist[i].nextents * blocksize);

      /*
       * Next, build the record using the extent list.
       */
      for(j=0; j < filelist[i].nextents; j++)
	{
	  memcpy(buffer + j * blocksize,
		 addr + filelist[i].extent_list[j] * blocksize,
		 blocksize);
	}

      pnt = (unsigned int *) buffer;

      /*
       * OK, now figure out what to do with it.
       */

      /*
       * Always ignore the first entry.  It seems to contain a backup copy
       * of the TOC (the last time the file was modified??)
       */
      if( i == 0 )
	{
	  continue;
	}

      /* 
       * The second entry as a id block.  It contains a magic number
       * to identify the compiler, plus it also contains the timestamp
       * which must match the timestamp in the executable.  
       */
      if( i == 1 )
	{

	  if( ((*pnt != 19950623) && (*pnt != 19950814))
	      || (filelist[i].record_len != 0x24)
	      || (pnt[1] != ((struct CodeViewDebug *)(deefer->dbg_info))->cv_timestamp) )
	    {
	      goto leave;
	    }
	}

      /*
       * The third entry contains pointers to the global symbol table,
       * plus it also contains additional information about each record
       * in the PDB file.
       */
      if( i == 3 )
	{
	  hd = (struct filetab_hdr *) buffer;

	  gsym_record = hd->gsym_file;
	  gsymtab = (char *) xmalloc( filelist[gsym_record].nextents 
				      * blocksize);
	  memset(gsymtab, 0, filelist[gsym_record].nextents * blocksize);
	  
	  for(j=0; j < filelist[gsym_record].nextents; j++)
	    {
	      memcpy(gsymtab + j * blocksize,
		     addr + filelist[gsym_record].extent_list[j] * blocksize,
		     blocksize);
	    }

	  /*
	   * This record also contains information about where in the
	   * remaining records we will be able to find the start of the
	   * line number table.  We could locate that bit using heuristics,
	   * but since we have the info handy, we might as well use it.
	   */
	  offset = sizeof(*hd);
	  while(1==1)
	    {
	      fent = (struct file_ent *) (buffer + offset);
	      if( offset > hd->ftab_len )
		{
		  break;
		}

	      if( fent->file_number == 0 || fent->file_number >= npair )
		{
 		  break;
		}

	      filelist[fent->file_number].linetab_offset = 
		fent->linetab_offset;
	      filelist[fent->file_number].linetab_len = 
		fent->linetab_len;
	      /*
	       * Figure out the offset of the next entry.
	       * There is a fixed part of the record and a variable
	       * length filename which we must also skip past.
	       */
	      offset += ((unsigned int) &fent->filename - (unsigned int) fent)
		+ strlen(fent->filename) + 1;
	      offset += strlen(buffer+offset) + 1;
	      offset = (offset + 3) & ~3;
	    }
	}
      

      /*
       * Two different magic numbers used as dates.
       * These indicate the 'type' table.
       */
      if(       *pnt == 19950410
	     || *pnt == 19951122 )
	{
	  DEBUG_ParseTypeTable(buffer, filelist[i].record_len);
	  continue;
	}

      /*
       * This is something we really want to look at, since it contains
       * real debug info.  Anything that doesn't match this can be
       * ignored for now.
       */
      if( *pnt == 1 )
	{
	  /*
	   * First, snag the line table, if we have one.  This always
	   * occurs at the end of the record, so we take the linetab
	   * offset as the end of the normal part of the record.
	   */
	  linetab = NULL;
	  if( filelist[i].linetab_len != 0 )
	    {
	      linetab = DEBUG_SnarfLinetab(buffer + filelist[i].linetab_offset,
					   filelist[i].linetab_len);
	      DEBUG_SnarfCodeView(deefer, buffer,
				  filelist[i].linetab_offset,
				  linetab);
	    }
	  else
	    {
	      DEBUG_SnarfCodeView(deefer, buffer,
				  filelist[i].record_len,
				  linetab);
	    }
	  continue;
	}
    }

  /*
   * Finally, process the global symbol table itself.  There isn't
   * a line number component to this, so we just toss everything
   * into the mix and it all should work out.
   */
  if( gsym_record != 0 )
    {
      DEBUG_SnarfCodeView(deefer, gsymtab - sizeof(int), 
			  filelist[gsym_record].record_len,
			  NULL);
    }
  
leave:

  if( gsymtab != NULL )
    {
      free(gsymtab);
      gsymtab = NULL;
    }

  if( buffer != NULL )
    {
      free(buffer);
    }

  if( filelist != NULL )
    {
      free(filelist);
    }

  if( addr != (char *) 0xffffffff )
    {
      munmap(addr, statbuf.st_size);
    }

  if( fd != -1 )
    {
      close(fd);
    }

  return TRUE;
}

/*
 * Process DBG file which contains debug information.
 */
/* static */
int
DEBUG_ProcessDBGFile(struct deferred_debug_info * deefer, char * filename)
{
  char			      * addr = (char *) 0xffffffff;
  char			      * codeview;
  struct CV4_DirHead	      * codeview_dir;
  struct CV4_DirEnt	      * codeview_dent;
  LPIMAGE_DEBUG_DIRECTORY	dbghdr;
  struct deferred_debug_info    deefer2;
  int				fd = -1;
  int				i;
  int				j;
  struct codeview_linetab_hdr * linetab;
  int				nsect;
  LPIMAGE_SEPARATE_DEBUG_HEADER pdbg = NULL;
  IMAGE_SECTION_HEADER        * sectp;
  struct stat			statbuf;
  int				status;
  
  status = stat(filename, &statbuf);
  if( status == -1 )
    {
      fprintf(stderr, "Unable to open .DBG file %s\n", filename);
      goto leave;
    }

  /*
   * Now open the file, so that we can mmap() it.
   */
  fd = open(filename, O_RDONLY);
  if( fd == -1 )
    {
      fprintf(stderr, "Unable to open .DBG file %s\n", filename);
      goto leave;
    }


  /*
   * Now mmap() the file.
   */
  addr = mmap(0, statbuf.st_size, PROT_READ, 
	      MAP_PRIVATE, fd, 0);
  if( addr == (char *) 0xffffffff )
    {
      fprintf(stderr, "Unable to mmap .DBG file %s\n", filename);
      goto leave;
    }

  pdbg = (LPIMAGE_SEPARATE_DEBUG_HEADER) addr;

  if( pdbg->TimeDateStamp != deefer->dbgdir->TimeDateStamp )
    {
      fprintf(stderr, "Warning - %s has incorrect internal timestamp\n",
	      filename);
      goto leave;
   }

  fprintf(stderr, "Processing symbols from %s...\n", filename);

  dbghdr = (LPIMAGE_DEBUG_DIRECTORY) (  addr + sizeof(*pdbg) 
		 + pdbg->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) 
		 + pdbg->ExportedNamesSize);

  sectp = (LPIMAGE_SECTION_HEADER) ((char *) pdbg + sizeof(*pdbg));
  nsect = pdbg->NumberOfSections;

  for( i=0; i < pdbg->DebugDirectorySize / sizeof(*pdbg); i++, dbghdr++ )
    {
      switch(dbghdr->Type)
		{
		case IMAGE_DEBUG_TYPE_COFF:
		  /*
		   * Dummy up a deferred debug header to handle the
		   * COFF stuff embedded within the DBG file.
		   */
		  memset((char *) &deefer2, 0, sizeof(deefer2));
		  deefer2.dbg_info = (addr + dbghdr->PointerToRawData);
		  deefer2.dbg_size = dbghdr->SizeOfData;
		  deefer2.load_addr = deefer->load_addr;

		  DEBUG_ProcessCoff(&deefer2);
		  break;
		case IMAGE_DEBUG_TYPE_CODEVIEW:
		  /*
		   * This is the older format by which codeview stuff is 
		   * stored, known as the 'NB09' format.  Newer executables
		   * and dlls created by VC++ use PDB files instead, which
		   * have lots of internal similarities, but the overall
		   * format and structure is quite different.
		   */
		  codeview = (addr + dbghdr->PointerToRawData);

		  /*
		   * The first thing in the codeview section should be
		   * an 'NB09' identifier.  As a sanity check, make sure
		   * it is there.
		   */
		  if( *((unsigned int*) codeview) != 0x3930424e )
		    {
		      break;
		    }
		  
		  /*
		   * Next we need to find the directory.  This is easy too.
		   */
		  codeview_dir = (struct CV4_DirHead *) 
		    (codeview + ((unsigned int*) codeview)[1]);

		  /*
		   * Some more sanity checks.  Make sure that everything
		   * is as we expect it.
		   */
		  if( codeview_dir->next_offset != 0 
		      || codeview_dir->dhsize != sizeof(*codeview_dir)
		      || codeview_dir->desize != sizeof(*codeview_dent) )
		    {
		      break;
		    }
		  codeview_dent = (struct CV4_DirEnt *) (codeview_dir + 1);

		  for(j=0; j < codeview_dir->ndir; j++, codeview_dent++)
		    {
		      if( codeview_dent->subsect_number == sstAlignSym )
			{
			  /*
			   * Check the previous entry.  If it is a
			   * sstSrcModule, it contains the line number
			   * info for this file.
			   */
			  linetab = NULL;
			  if( codeview_dent[1].module_number == codeview_dent[0].module_number
			      && codeview_dent[1].subsect_number == sstSrcModule )
			    {
			      linetab = DEBUG_SnarfLinetab(
					   codeview + codeview_dent[1].offset,
					   codeview_dent[1].size);
			    }

			  if( codeview_dent[-1].module_number == codeview_dent[0].module_number
			      && codeview_dent[-1].subsect_number == sstSrcModule )
			    {
			      linetab = DEBUG_SnarfLinetab(
					   codeview + codeview_dent[-1].offset,
					   codeview_dent[-1].size);
			    }
			  /*
			   * Now process the CV stuff.
			   */
			  DEBUG_SnarfCodeView(deefer, 
					      codeview + codeview_dent->offset,
					      codeview_dent->size,
					      linetab);
			}
		    }

		  break;
		default:
		  break;
		}
    }
leave:

  if( addr != (char *) 0xffffffff )
    {
      munmap(addr, statbuf.st_size);
    }

  if( fd != -1 )
    {
      close(fd);
    }

  return TRUE;
}

int
DEBUG_ProcessDeferredDebug()
{
  struct deferred_debug_info * deefer;
  struct CodeViewDebug	     * cvd;
  struct MiscDebug	     * misc;
  char			     * filename;
  int			       last_proc = -1;

  DEBUG_InitCVDataTypes();

  for(deefer = dbglist; deefer; deefer = deefer->next)
    {
      if( deefer->loaded )
	{
	  continue;
	}

      if( last_proc != deefer->dbg_index )
	{
	  fprintf(stderr, " %s",deefer->module_name);
	  last_proc = deefer->dbg_index;
	}

      switch(deefer->dbgdir->Type)
	{
	case IMAGE_DEBUG_TYPE_COFF:
	  /*
	   * Standard COFF debug information that VC++ adds when you
	   * use /debugtype:both with the linker.
	   */
#if 0
	  fprintf(stderr, "Processing COFF symbols...\n");
#endif
	  DEBUG_ProcessCoff(deefer);
	  break;
	case IMAGE_DEBUG_TYPE_CODEVIEW:
	  /*
	   * This is a pointer to a PDB file of some sort.
	   */
	  cvd = (struct CodeViewDebug *) deefer->dbg_info;

	  if( strcmp(cvd->cv_nbtype, "NB10") != 0 )
	    {
	      /*
	       * Whatever this is, we don't know how to deal with
	       * it yet.
	       */
	      break;
	    }
	  DEBUG_ProcessPDBFile(deefer, cvd->cv_name);
#if 0
	  fprintf(stderr, "Processing PDB file %s\n", cvd->cv_name);
#endif
	  break;
	case IMAGE_DEBUG_TYPE_MISC:
	  /*
	   * A pointer to a .DBG file of some sort.  These files
	   * can contain either CV4 or COFF information.  Open
	   * the file, and try to do the right thing with it.
	   */
	  misc = (struct MiscDebug *) deefer->dbg_info;

	  filename = strrchr((char *) &misc->Data, '.');

	  /*
	   * Ignore the file if it doesn't have a .DBG extension.
	   */
	  if(    (filename == NULL)
	      || (    (strcmp(filename, ".dbg") != 0)
	           && (strcmp(filename, ".DBG") != 0)) )
	    {
	      break;
	    }

	  filename = (char *) &misc->Data;

	  /*
	   * Do the dirty deed...
	   */
	  DEBUG_ProcessDBGFile(deefer, filename);
      
	  break;
	default:
	  /*
	   * We should never get here...
	   */
	  break;
	}
    }
  return TRUE;

}

/***********************************************************************
 *           DEBUG_InfoShare
 *
 * Display shared libarary information.
 */
void DEBUG_InfoShare(void)
{
  struct deferred_debug_info * deefer;

  fprintf(stderr,"Address\t\tModule\tName\n");

  for(deefer = dbglist; deefer; deefer = deefer->next)
  {
      fprintf(stderr,"0x%8.8x\t(%s)\t%s\n", (unsigned int) deefer->load_addr,
              deefer->module ? "Win32" : "ELF", deefer->module_name);
  }
}

