#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <ctype.h>

#include "header.h"
#include "cvinfo.h"
#include "cvexefmt.h"

extern PROCESS DebugProcess ;
extern CONTEXT StoppedRegs ;


int DeclType(char *typetab, VARINFO *v,int expand) ;

static int comparefiletime(char *name,char *name1)
{
   int rv ;
   BY_HANDLE_FILE_INFORMATION info,info1 ;

   HANDLE handle = CreateFile(name,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

   if (handle == INVALID_HANDLE_VALUE)
      return 1 ;

   if (!GetFileInformationByHandle((HANDLE)handle,&info)) {
      CloseHandle(handle) ;
      return 1 ;
   }
	
   CloseHandle(handle) ;
   handle = CreateFile(name1,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

   if (handle == INVALID_HANDLE_VALUE)
      return 1 ;

   if (!GetFileInformationByHandle((HANDLE)handle,&info1)) {
      CloseHandle(handle) ;
      return 1 ;
   }
	
   CloseHandle(handle) ;

   if (info1.ftLastWriteTime.dwHighDateTime > info.ftLastWriteTime.dwHighDateTime)
      return 0 ;
   if (info1.ftLastWriteTime.dwHighDateTime < info.ftLastWriteTime.dwHighDateTime)
      return 1 ;
   if (info1.ftLastWriteTime.dwLowDateTime >= info.ftLastWriteTime.dwLowDateTime)
      return 0 ;

   return 1 ;
}
DEBUG_INFO *GetDebugInfo(LPVOID imageBase, char *name, int primary)
{
   char buf[256],*p = buf,*q = name ;
   DEBUG_INFO *rv ;
   unsigned char *info ;
   FILE *fil ;
   int len ;

   while (*q && !isspace(*q))
      *p++ = *q++ ;
   *p = 0 ;

   p = strrchr(buf,'.') ;
   if (p)
      strcpy(p,".lss") ;
   else
      strcat(buf,".lss") ;

   if (comparefiletime(name,buf))
      return 0 ;
      
   fil = fopen(buf,"rb") ;
   if (!fil)
      return 0 ;

   fseek(fil,0L,SEEK_END) ;
   len = ftell(fil) ;
   fseek(fil,0L,SEEK_SET) ;

   info = malloc(len) ;
   if (info == 0) {
      fclose(fil) ;
      return 0 ;
   }
   fread(info,len,1,fil) ;
   fclose(fil) ;

   if (memcmp(info,"LS11",4)) {
      free(info) ;
      return 0 ;
   }          
                   
   rv = (DEBUG_INFO *)malloc(sizeof(DEBUG_INFO)) ;                             
   if (!rv) {
      free(info) ;
      return 0;
   }
   rv->size = len ;
   rv->info = info ;
   rv->base = imageBase ;
   return rv ;
   /* if we get here everything is kosher and it loaded ok. */ 
}
void FreeDebugInfo(DEBUG_INFO *dbg)
{
   if (dbg) {
      free( dbg->info) ;
      free(dbg) ;
   }
}
static void getname(char *buf, char *cname)
{
   memcpy(buf,cname+1,cname[0]) ;
   buf[cname[0]] = 0 ;
}
DWORD GetMainAddress(DEBUG_INFO *dbg)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i ;

   if (!dbg)
      return 0;

   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;
   e = (unsigned char *)dh + dh->cbDirHeader ;

   for (i= 0 ; i < dh->cDir; i++) {
      if (e->SubSection == sstGlobalSym) {
         int base = e->lfo + sizeof(OMFSymHash) ;
         int count = e->cb  - sizeof(OMFSymHash);
         if (*((short *)(dbg->info + base + 2)) == S_SSEARCH) {
            SEARCHSYM *s = base + dbg->info ;
            if (s->startsym) {               int pos = base + s->startsym ;
               PROCSYM32 *p = dbg->info + pos ;
               char namebuf[256] ;
               while (p->rectyp == S_GPROC32) {
                  getname(namebuf,p->name) ;
                  if (!strcmp(namebuf,"main"))
                     return p->off + dbg->base ;
                  if (!strcmp(namebuf,"WinMain"))
                     return p->off + dbg->base ;
                  if (!strcmp(namebuf,"DllEntryPoint"))
                     return p->off + dbg->base ;
                  pos = base + p->pNext ;
                  p = dbg->info + pos ;
               }
            }
         }
         return 0 ;
      }

      e++ ;
   }
   return 0 ;
}
int GetBreakpointLine(int Address, char *module , int *linenum)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i,j ;
   DEBUG_INFO *dbg = DebugProcess.dbg_info ;
   DLL_INFO *dll = DebugProcess.dll_info ;

   while (dll && (unsigned)dll->base <= (unsigned)Address) {
      dbg = dll->dbg_info ;
      dll = dll->next ;
   }

   if (!dbg)
      return 0 ;

   Address -= dbg->base ;
   *linenum = 0 ;
   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;
   e = (unsigned char *)dh + dh->cbDirHeader ;

   for (i= 0 ; i < dh->cDir; i++) {
      if (e->SubSection == sstModule) {
         OMFModule *m ;
         OMFSegDesc *s ;
         m = dbg->info + e->lfo ;
         s = &m->SegInfo ;
         for (j=0; j < m->cSeg; j++) {
            if (s->Seg == 1) { /* code seg */
               if (Address >= s->Off && Address < s->Off + s->cbSeg) {
                  char *str = (char *)m->SegInfo + sizeof(OMFSegDesc) * m->cSeg  ;
                  OMFDirEntry *e1 ;
                  memcpy(module,str+1,str[0]) ;
                  module[str[0]] = 0 ;
                  e1 = (unsigned char *)dh + dh->cbDirHeader ;
                  for (i= 0 ; i < dh->cDir; i++) {
                     if (e1->SubSection == sstSrcModule && e->iMod == e1->iMod) {
                        OMFSourceLine *sl = dbg->info + e1->lfo ;
                        short *lines = (char *)&sl->offset + 4 * sl->cLnOff ;
                        *linenum = lines[0] ;
                        for (i = 1; i < sl->cLnOff; i++) {
                           if (Address < sl->offset[i])
                              break ;
                           *linenum = lines[i] ;
                        }
                        if (i > 0) {
                           return sl->offset[i-1] + dbg->base ;
                        }
                        return 1 ;
                     }
                     e1++ ;
                  }
                  return 0 ;
               }
            }
            s++ ;
         }

      }
      e++ ;
   }
   return 0 ;
}
static int MatchedModule(char *module, char *dbgname)
{
   char buf[256],*p ;
   memcpy(buf,dbgname+1,dbgname[0]) ;
   buf[dbgname[0]] = 0 ;
   if (!xstricmpz(module,buf))
      return TRUE ;
   p = strrchr(module,'\\') ;
   if (p)
      return !xstricmpz(buf,p+1) ;

   return FALSE ;
}
int GetBreakpointAddressByProgram(char *module, int *linenum, DEBUG_INFO *dbg, int inmodule)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i,j ;

   if (!dbg)
      return 0 ;
   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;
   e = (unsigned char *)dh + dh->cbDirHeader ;
   for (i= 0 ; i < dh->cDir; i++) {
      if (e->SubSection == sstModule) {
         OMFModule *m = dbg->info + e->lfo ;
         char *str = (char *)m->SegInfo + sizeof(OMFSegDesc) * m->cSeg  ;
         if (MatchedModule(module,str)) {
            OMFDirEntry *e1 = (unsigned char *)dh + dh->cbDirHeader ;
            for (i= 0 ; i < dh->cDir; i++) {
               if (e1->SubSection == sstSrcModule && e->iMod == e1->iMod) {
                  OMFSourceLine *sl = dbg->info + e1->lfo ;
                  short *lines = (char *)&sl->offset + 4 * sl->cLnOff ;
                  for (i = 0; i < sl->cLnOff; i++) {
                     if (*linenum == lines[i]) {
                        return sl->offset[i] + dbg->base ;
                     }
                  }
                  if (inmodule && sl->cLnOff)
                     return sl->offset[0] + dbg->base ;
                  return 0;
               }
               e1++ ;
            }
            return 0 ;
         }

      }
      e++ ;
   }
   return 0 ;
}

int GetBreakpointAddress(char *module, int *linenum, int inmodule)
{
   DLL_INFO *dll = DebugProcess.dll_info ;
   int rv = GetBreakpointAddressByProgram(module, linenum, DebugProcess.dbg_info,inmodule) ;
   if (rv)
      return rv ;

   while (dll) {
      rv = GetBreakpointAddressByProgram(module, linenum, dll->dbg_info,inmodule) ;
      if (rv)
         return rv ;
      dll = dll->next ;
   }
   return 0 ;
}
SHORT * GetLineTableByDBG(char *module, DEBUG_INFO *dbg, int *count)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i,j ;

   if (!dbg)
      return 0 ;
   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;
   e = (unsigned char *)dh + dh->cbDirHeader ;
   for (i= 0 ; i < dh->cDir; i++) {
      if (e->SubSection == sstModule) {
         OMFModule *m = dbg->info + e->lfo ;
         char *str = (char *)m->SegInfo + sizeof(OMFSegDesc) * m->cSeg  ;
         if (MatchedModule(module,str)) {
            OMFDirEntry *e1 = (unsigned char *)dh + dh->cbDirHeader ;
            for (i= 0 ; i < dh->cDir; i++) {
               if (e1->SubSection == sstSrcModule && e->iMod == e1->iMod) {
                  OMFSourceLine *sl = dbg->info + e1->lfo ;
                  *count = sl->cLnOff ;
                  return (char *)&sl->offset + 4 * sl->cLnOff ;
               }
               e1++ ;
            }
            return 0 ;
         }

      }
      e++ ;
   }
   return 0 ;
}
SHORT *GetLineTable(char *module, int *count)
{
   DLL_INFO *dll = DebugProcess.dll_info ;
   short *rv = 0 ;
   *count = 0 ;
   rv = GetLineTableByDBG(module,DebugProcess.dbg_info, count) ;
   if (rv)
      return rv ;

   while (dll) {
      rv = GetLineTableByDBG(module, dll->dbg_info,count) ;
      if (rv)
         return rv ;
      dll = dll->next ;
   }
   return 0 ;
}
static int FindFunctionInSymtab(DEBUG_INFO *dbg, int symtab, int address, int seladdress)
{
   char *symtab_base = dbg->info + symtab + sizeof(OMFSymHash) ;
   int offset = 0 ;

   SEARCHSYM *s = symtab_base ;
   if (s->rectyp == S_SSEARCH) {
      offset = s->startsym ;
      while (offset) {
         PROCSYM32 *p = symtab_base + offset ;
         if (p->rectyp != S_GPROC32 && p->rectyp != S_LPROC32)
            return 0 ;
         if (address >= p->off && address < p->off + p->len && 
               seladdress >= p->off && seladdress < p->off + p->len) {
            return offset ;
         }
         offset = p->pNext ;
      }
   }
   return 0 ;
}
static int FindFunctionByAddress(DEBUG_INFO *dbg ,char **symtab, int *offset, int Address, int SelAddress)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i,j ;

   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;
   e = (unsigned char *)dh + dh->cbDirHeader ;
   for (i= 0 ; i < dh->cDir; i++) {
      if (e->SubSection == sstModule) {
         OMFModule *m ;
         OMFSegDesc *s ;
         m = dbg->info + e->lfo ;
         s = &m->SegInfo ;
         for (j=0; j < m->cSeg; j++) {
            if (s->Seg == 1) { /* code seg */
               if (Address >= s->Off && Address < s->Off + s->cbSeg) {
                  OMFDirEntry *e1 = (unsigned char *)dh + dh->cbDirHeader ;
                  for (i= 0 ; i < dh->cDir; i++) {
                     if (e1->SubSection == sstAlignSym && e->iMod == e1->iMod) {
                        int offs = FindFunctionInSymtab(dbg,e1->lfo,Address,SelAddress) ;
                        if (offs) {
                           *symtab = dbg->info + e1->lfo ;
                           *offset = offs ;
                           return TRUE ;
                        } else {
                           e = (unsigned char *)dh + dh->cbDirHeader ;
                           for (i= 0; i < dh->cDir; i++) {
                              if (e->SubSection == sstGlobalSym) {
                                 offs = FindFunctionInSymtab(dbg, e->lfo, Address, SelAddress) ;
                                 if (offs) {
                                    *symtab = dbg->info + e->lfo + sizeof(OMFSymHash);
                                    *offset = offs ;
                                    return TRUE ;
                                 }
                                 else
                                    return FALSE ;
                              }
                              e++ ;
                           }
                           return 0 ;
                        }
                     }
                     e1++ ;
                  }
               }
               break ;
            }
            s++ ;
         }
      }
      e++ ;
   }
   return 0 ;
}
static int namematch(SYMTYPE *s, char *name)
{
   char *funcname ;
   switch (s->rectyp) {
      case S_BPREL32:
        funcname = ((BPRELSYM32 *)s)->name ; 
        break ;
      case S_REGISTER:
         
         funcname = ((REGSYM *)s)->name ;
         break ;
      case S_LDATA32:
      case S_GDATA32:
         funcname = ((DATASYM32 *)s)->name ;
         break ;
      case S_LPROC32:
      case S_GPROC32:
         funcname = ((PROCSYM32 *)s)->name ;
         break ;
      default:
         return FALSE ;
   }
   if (strlen(name) != funcname[0])
      return 0;
   return !strncmp(funcname+1,name,funcname[0]) ;
}
static int FindSymbolInFunction(char *symtab, int offset, 
         char *name, int Address)
{
   PROCSYM32 *func = symtab + offset  ;
   int endoffs = func->pEnd ;
   int blockoffs = offset ;
   int findoffs = blockoffs ;
   BLOCKSYM32 *blk ;

   // First find the enclosing block
   while (findoffs < endoffs) {
      BLOCKSYM32 *b = symtab + findoffs;
      if (b->rectyp == S_BLOCK32) {
         if (b->off <= Address && Address < b->off +b->len) {
            blockoffs = findoffs ;
            endoffs = b->pEnd ;
            findoffs += b->reclen + 2;
         } else
            findoffs = b->pEnd ;
      } else
         findoffs += b->reclen + 2;
   }
   // now blockoffs has the point to the innermost block
   blk = symtab + blockoffs ;
   while (blk) {
      int end = blk->rectyp == S_BLOCK32 ? blk->pEnd : func->pEnd ;
      findoffs = (unsigned char *)blk - (unsigned char *)symtab + blk->reclen + 2;
      while (findoffs < end) {
         BLOCKSYM32 *p = findoffs + symtab ;
         if (p->rectyp == S_BLOCK32)
            findoffs = p->pEnd ;
         else {
            if (namematch(p, name)) {
               return findoffs ;
            }
            findoffs += p->reclen + 2 ;
         }
      }
      if (blk->rectyp == S_BLOCK32)
         blk = symtab + blk->pParent ;
      else
         blk = 0 ;
   }
   return 0 ;
} 
static int FindSymbolInSymtab( char *symtab, int len, char *name)
{
   int offset = 0 ;

   while (offset < len) {
      struct SYMTYPE *s = symtab + offset ;
      if (s->rectyp == S_LPROC32 || s->rectyp == S_GPROC32) {
         PROCSYM32 *p = s ;
         offset = p-> pEnd ;
      } else {
         if (namematch(s, name)) {
            return offset ;
         }
         offset = offset + s->reclen + 2;
      }
   }
   return 0 ;
}
int FindSymbol(DEBUG_INFO **dbg_info , char **typetab, char **symtab, 
            int *offset, int Address, int SelAddress, char *name)
{
   OMFSignature *sig ;
   OMFDirHeader *dh ;
   OMFDirEntry *e ;
   int i,j ;
   DEBUG_INFO *dbg = DebugProcess.dbg_info ;
   DLL_INFO *dll = DebugProcess.dll_info ;
   int funcoffs ;

   *typetab = 0 ;

   while (dll && (unsigned)dll->base <= (unsigned)Address) {
      dbg = dll->dbg_info ;
      dll = dll->next ;
   }
   if (!dbg)
      return 0 ;

   *dbg_info = dbg ;
   // Find the types table
   sig = dbg->info ;
   dh = dbg->info + sig->filepos ;

   // See if it is a function argument or variable
   funcoffs = FindFunctionByAddress(dbg,symtab,offset,Address-dbg->base,SelAddress-dbg->base) ;
   if (funcoffs) {
      int offs = FindSymbolInFunction(*symtab, *offset, name,Address-dbg->base) ;
      if (offs) {
         e = (unsigned char *)dh + dh->cbDirHeader ;
         for (i= 0 ; i < dh->cDir; i++) {
            if (e->SubSection == sstGlobalTypes) {
               *typetab = dbg->info + e->lfo ;
               break ;
            } 
            e++ ;
         }
         *offset = offs;
         return TRUE ;
      }
   }
   if (dbg) {
      sig = dbg->info ;
      dh = dbg->info + sig->filepos ;
      *dbg_info = dbg ;
      // check the local symbol table
      e = (unsigned char *)dh + dh->cbDirHeader ;
      for (i= 0 ; i < dh->cDir; i++) {
         if (e->SubSection == sstModule) {
            OMFModule *m ;
            OMFSegDesc *s ;
            m = dbg->info + e->lfo ;
            s = &m->SegInfo ;
            for (j=0; j < m->cSeg; j++) {
               if (s->Seg == 1) { /* code seg */
                  if (SelAddress-dbg->base >= s->Off && SelAddress-dbg->base < s->Off + s->cbSeg) {
                     OMFDirEntry *e1 = (unsigned char *)dh + dh->cbDirHeader ;

                     for (i= 0 ; i < dh->cDir; i++) {
                        if (e1->SubSection == sstAlignSym && e->iMod == e1->iMod) {
                           int offs = FindSymbolInSymtab(dbg->info + e1->lfo, e1->cb, name) ;
                           if (offs) {
                              e = (unsigned char *)dh + dh->cbDirHeader ;
                              for (i= 0 ; i < dh->cDir; i++) {
                                 if (e->SubSection == sstGlobalTypes) {
                                    *typetab = dbg->info + e->lfo ;
                                    break ;
                                 } 
                                 e++ ;
                              }
                              *symtab = dbg->info + e1->lfo ;
                              *offset = offs ;
                              return 1 ;
                           }
                        }
                        e1++ ;
                     }
                  }
                  break ;
               }
               s++ ;
            }
         }
         e++ ;
      }
      // And check the global symtab for the program this is a part of
      e = (unsigned char *)dh + dh->cbDirHeader ;
      for (i= 0; i < dh->cDir; i++) {
         if (e->SubSection == sstGlobalSym) {
            int offs = FindSymbolInSymtab(dbg->info + e->lfo + sizeof(OMFSymHash), 
                        e->cb - sizeof(OMFSymHash), name) ;
            if (offs) {
               OMFDirEntry *e1 = (unsigned char *)dh + dh->cbDirHeader ;
               for (i= 0 ; i < dh->cDir; i++) {
                  if (e1->SubSection == sstGlobalTypes) {
                     *typetab = dbg->info + e1->lfo ;
                     break ;
                  } 
                  e1++ ;
               }
               *symtab = dbg->info + e->lfo + sizeof(OMFSymHash) ;
               *offset = offs ;
               return TRUE ;
            }
            else
               return FALSE ;
         }
         e++ ;
      }
   }


   return 0 ;
}
int FindFunctionName(char *buf, int Address)
{
   char *symtab ;
   DEBUG_INFO *dbg = DebugProcess.dbg_info;
   int offset ;
   DLL_INFO *dll ;
   buf[0] = 0 ;

   dll = DebugProcess.dll_info ;

   while (dll && (unsigned)dll->base <= (unsigned)Address) {
      dbg = dll->dbg_info ;
      dll = dll->next ;
   }
   if (dbg && FindFunctionByAddress(dbg ,&symtab, &offset, Address-dbg->base,Address-dbg->base)) {
         PROCSYM32 *p = symtab + offset ;
         getname(buf,p->name) ;
         return 1 ;
   }
   return 0 ;
}
char * LookupType(char *typetab, int typenum)
{
   OMFGlobalTypes *p = typetab ;
   int offset ;
   typenum -= CV_FIRST_NONPRIM ;
   if (typenum < 0 || typenum >=p->cTypes)
      return 0 ;

   offset = p->typeOffset[typenum] + (char *)&p->cTypes - typetab ;

   return offset + typetab;
}

int GetNumericLeaf(short *ptr)
{
   int val = *(ptr) ;
   if (val < LF_NUMERIC)
      return val ;
   // LF_LONG is the only thing we are supporting
   return *(int *)(ptr + 1) ;
}
void GetStructInfo (char *typetab, short *type, VARINFO *var)
{
   short *typeptr = LookupType(typetab,((lfStructure *)(type +1))->field) ;
   VARINFO **v = &var->subtype ;
   while (*(typeptr +1) == LF_FIELDLIST) {
      int done = FALSE ;
      int len ;
      len = *typeptr - 2;
      typeptr += 2 ;
      while (len && !done ) {
         VARINFO *vx ;
         int xlen ;
         char *nmptr ;
         switch(*typeptr) {
            case LF_MEMBER:
               vx = *v = calloc(sizeof(VARINFO),1) ;
               v = &(*v)->link ;
               vx->offset = GetNumericLeaf(&((lfMember *)typeptr)->offset) ;
               vx->address = var->address + vx->offset ;
               vx->type = ((lfMember *)typeptr)->index ;
               DeclType(typetab,vx,TRUE) ;
               xlen = sizeof(lfMember) - CV_ZEROLEN ;
               if ((*(short *)((char *)typeptr) + xlen) < LF_NUMERIC)
                  xlen += 2 ;
               else
                  xlen += 6 ;
               nmptr = (char *)typeptr + xlen ;
               strncpy(vx->membername,nmptr+1,*nmptr) ;
               xlen += *nmptr+1;
               if ((*(((char *)typeptr) + xlen) & 0xf0) == 0xf0)
                  xlen += *(((char *)typeptr) + xlen) & 15 ;
               (char *)typeptr += xlen ;
               break ;
            case LF_INDEX:
               typeptr = LookupType(typetab,((lfIndex *)typeptr)->index) ;
               done = TRUE ;
               break ;
            default:
               return ;
         }
      }
   }
}
int basictypesize(int type)
{
   if (CV_MODE(type) != CV_TM_DIRECT)
      return 4 ;
    switch (CV_TYPE(type)) {
      case CV_SIGNED:
      case CV_UNSIGNED:
      case CV_BOOLEAN:
         return 1 << CV_SUBT(type) ;
      case CV_REAL:
         switch(CV_SUBT(type)) {
            case CV_RC_REAL32:
               return 4 ;
            case CV_RC_REAL64:
               return 8 ;
            default:
               return 10 ;
         }
         break ;
      case CV_INT:
         return 1<< (CV_SUBT(type)/2) ;
    }
    return 0 ;
}
void GetArrayInfo (char *typetab, short *type, VARINFO *var)
{
   int i = 0,z = 0 ;
   VARINFO **nextptr = &var->subtype ;
   while (i < var->arraysize) {
      VARINFO *vx =calloc(sizeof(VARINFO),1) ;
      if (!vx)
         return ;
      vx->offset = i ;
      vx->address = var->address ;
      vx->type = var->type ;
      sprintf(vx->membername,"%s[%d]",var->membername, z++) ;
      i += DeclType(typetab,vx,TRUE) ;
      *nextptr = vx ;
      nextptr = &vx->link ;
   }
}
void GetPointerInfo(char *typetab, VARINFO *v)
{
   VARINFO *vx = calloc(sizeof(VARINFO),1) ;
   v->subtype = vx ;
   vx->placeholder = TRUE ;
   vx->type = v->type ;
   sprintf(vx->membername,"*%s",v->membername) ;
   if (!(CV_IS_PRIMITIVE(v->type)))
      DeclType(typetab,vx,FALSE) ; // Have to prevent infinite loops
}
int DeclType(char *typetab, VARINFO *v, int expand)
{
   short * typeptr ;
   if (CV_IS_PRIMITIVE(v->type)) {
      if (CV_TYP_IS_PTR(v->type)) {
         v->pointer = TRUE ;
         v->type = CV_NEWMODE(v->type,CV_TM_DIRECT) ;
         GetPointerInfo(typetab, v) ;
         return 4 ;
      } 
      return basictypesize(v->type) ;
   }
   typeptr = LookupType(typetab,v->type) ;
   v->typetab = typeptr ;

   switch(typeptr[1]) {
      case LF_POINTER:
         v->pointer = TRUE ;
         v->type = ((lfPointer *)(typeptr +1 ))->u.utype ;
         v->typetab = LookupType(typetab, v->type) ;
         if (expand)
            GetPointerInfo(typetab, v) ;
         return 4 ;
      case LF_ARRAY:
         v->array = TRUE ;
         v->type = ((lfArray *)(typeptr +1))->elemtype ;
         v->arraysize = GetNumericLeaf(&((lfArray *)(typeptr +1))->data) ;
         if (expand)
            GetArrayInfo(typetab,typeptr,v ) ;
         return v->arraysize ;
      case LF_UNION:
         v->unionx = TRUE ;
         if (expand)
            GetStructInfo(typetab,typeptr,v) ;
         return GetNumericLeaf(((lfClass *)(typeptr + 1))->data) ;
      case LF_STRUCTURE:
      case LF_CLASS:
         v->structure = TRUE ;
         if (expand)
            GetStructInfo(typetab,typeptr,v) ;
         return GetNumericLeaf(((lfUnion *)(typeptr + 1))->data) ;
      case LF_ENUM:
         v->enumx = TRUE ;
         v->type = ((lfEnum *)(typeptr+1))->utype ;
         v->typetab = LookupType(typetab, ((lfEnum *)(typeptr+1))->field) ;
         return basictypesize(v->type) ;
      case LF_BITFIELD:     // Should only appear in structures
         v->bitfield = TRUE ; 
         v->bitstart = ((lfBitfield *)typeptr)->position ;
         v->bitlength = ((lfBitfield *)typeptr)->length ;
         v->type = ((lfBitfield *)typeptr)->type ;
         return 0 ;
   }
}      
VARINFO *GetVarInfo(DEBUG_INFO *dbg, char *typetab, char *symtab, int offset, char *name)
{
   SYMTYPE *s = symtab + offset ;
   VARINFO *v = calloc(sizeof(VARINFO),1) ;
   if (!v)
      return 0 ;
   strcpy(v->membername,name) ;
   switch (s->rectyp) {
      case S_BPREL32:
        v->address = ((BPRELSYM32 *)s)->off  + StoppedRegs.Ebp; 
        v->type = ((BPRELSYM32 *)s)->typind ;
        break ;
      case S_REGISTER:
         v->address = ((REGSYM *)s)->reg ;
         v->type = ((REGSYM *)s)->typind ;
         break ;
      case S_LDATA32:
      case S_GDATA32:
         v->address = ((DATASYM32 *)s)->off  + dbg->base; 
         v->type = ((DATASYM32 *)s)->typind ;
         break ;
      case S_LPROC32:
      case S_GPROC32:
         v->address = ((PROCSYM32 *)s)->off  + dbg->base ;
         v->type = T_PVOID ;
         break ;
      default:
         free(v) ;
         return 0 ;
   }
   DeclType(typetab,v,TRUE) ;
   return v ;

}
void FreeVarInfo(VARINFO *info)
{
   while (info) {
      VARINFO *chain = info->link ;
      FreeVarInfo(info->subtype) ;
      free(info) ;
      info = chain ;
   }
}
int ReadValue(int address, void *val, int size)
{
   int len ;
   if (address < 0x1000) { // register
      switch(address) {
         case CV_REG_AL:
            *(char *)val = StoppedRegs.Eax & 0xff ;
            return 1;
         case CV_REG_CL:
            *(char *)val = StoppedRegs.Ecx & 0xff ;
            return 1;
         case CV_REG_DL:
            *(char *)val = StoppedRegs.Edx & 0xff ;
            return 1;
         case CV_REG_BL:
            *(char *)val = StoppedRegs.Ebx & 0xff ;
            return 1;
         case CV_REG_AH:
            *(char *)val = (StoppedRegs.Eax >> 8)& 0xff ;
            return 1;
         case CV_REG_CH:
            *(char *)val = (StoppedRegs.Ecx >> 8)& 0xff ;
            return 1;
         case CV_REG_DH:
            *(char *)val = (StoppedRegs.Edx >> 8)& 0xff ;
            return 1;
         case CV_REG_BH:
            *(char *)val = (StoppedRegs.Ebx >> 8)& 0xff ;
            return 1;
         case CV_REG_AX:
            *(short *)val = StoppedRegs.Eax & 0xffff ;
            return 2;
         case CV_REG_CX:
            *(short *)val = StoppedRegs.Ecx & 0xffff ;
            return 2;
         case CV_REG_DX:
            *(short *)val = StoppedRegs.Edx & 0xffff ;
            return 2;
         case CV_REG_BX:
            *(short *)val = StoppedRegs.Ebx & 0xffff ;
            return 2;
         case CV_REG_SP:
            *(short *)val = StoppedRegs.Esp & 0xffff ;
            return 2;
         case CV_REG_BP:
            *(short *)val = StoppedRegs.Ebp & 0xffff ;
            return 2;
         case CV_REG_SI:
            *(short *)val = StoppedRegs.Esi & 0xffff ;
            return 2;
         case CV_REG_DI:
            *(short *)val = StoppedRegs.Edi & 0xffff ;
            return 2;
         case CV_REG_EAX:
            *(int *)val = StoppedRegs.Eax ;
            return 4;
         case CV_REG_ECX:
            *(int *)val = StoppedRegs.Ecx ;
            return 4;
         case CV_REG_EDX:
            *(int *)val = StoppedRegs.Edx ;
            return 4;
         case CV_REG_EBX:
            *(int *)val = StoppedRegs.Ebx ;
            return 4;
         case CV_REG_ESP:
            *(int *)val = StoppedRegs.Esp ;
            return 4;
         case CV_REG_EBP:
            *(int *)val = StoppedRegs.Ebp ;
            return 4;
         case CV_REG_ESI:
            *(int *)val = StoppedRegs.Esi ;
            return 4;
         case CV_REG_EDI:
            *(int *)val = StoppedRegs.Edi ;
            return 4;
         case CV_REG_ST0:              // not supported
         case CV_REG_ST1:
         case CV_REG_ST2:
         case CV_REG_ST3:
         case CV_REG_ST4:
         case CV_REG_ST5:
         case CV_REG_ST6:
         case CV_REG_ST7:
            return 0 ;
      }
   } else {
      ReadProcessMemory(DebugProcess.hProcess,(LPVOID)address,(LPVOID) val,size, &len ) ;
      return len ;
   }
}
int HintBasicType(VARINFO *info, int *signedtype, char *data)
{
   if (CV_TYP_IS_REAL(info->type)) {
      switch(info->type) {
         case T_REAL32:
            ReadValue(info->address,data,4) ;
            break ;
         case T_REAL64:
            ReadValue(info->address,data,8) ;
            break ;
         case T_REAL80:
            ReadValue(info->address,data,10) ;
            break ;
         default:
            return 0;
      }
      return info->type ;
   } else {
      int size ;
      *(int *)data = 0 ;
      if (CV_TYP_IS_SIGNED(info->type))
         *signedtype = TRUE ;
      else
         *signedtype = FALSE ;
      switch (CV_TYPE(info->type)) {
         case CV_INT:
            size = 1 << (CV_SUBT(info->type)/2) ;
            break ;
         case CV_SIGNED:
         case CV_UNSIGNED:
            size = 1 << CV_SUBT(info->type) ;
            break ;
         case CV_BOOLEAN:
            ReadValue(info->address,data,1) ;
            return info->type ;
            break ;
      }
      ReadValue(info->address,data,size) ;
      if (*signedtype) {
         switch(size) {
            case 1:
               if (*data & 0x80)
                  *(int *)data |= 0xffffff00 ;
               break ;
            case 2:
               if (*(short *)data & 0x8000)
                  *(int *)data |= 0xffff0000 ;
               break ;
            case 4:
               break ;
            default:
               return 0;
         }
      }
      return T_INT4 ;
   }
}
void HintEnum(char *typetab, VARINFO *info,char *buf, int toenum, int onevalue)
{
   int signedtype ;
   int v ;
   short *typeptr = info->typetab ;
   HintBasicType(info, &signedtype, &v) ;
   while (*(typeptr +1) == LF_FIELDLIST) {
      int done = FALSE ;
      int len = *typeptr - 2;
      typeptr += 2 ;
      while (len > 0 && !done ) {
         int xlen ;
         char *nmptr ;
         switch(*typeptr) {
            case LF_ENUMERATE:
               xlen = sizeof (lfEnumerate) -1;
               if (v < LF_NUMERIC)
                  xlen += 2 ;
               else
                  xlen += 6 ;
               nmptr = ((char *)typeptr) + xlen ;
               if (GetNumericLeaf(&((lfEnumerate *)typeptr)->value) == v) {
                  char buf1[256] ;
                  memset(buf1,0,256) ;   
                  strncpy(buf1,nmptr + 1, *nmptr) ;
                  if (toenum)
                     sprintf(buf,"ENUM: %s(%u)",buf1,v) ; 
                  else if (onevalue)
                     sprintf(buf,"%s",buf1) ; 
                  else
                     sprintf(buf,"%s(%u)",buf1,v) ; 
                  return ;
               }
               xlen += *nmptr + 1;
               if ((*((char *)typeptr+xlen) & 0xf0) == 0xf0)
                  xlen += *((char *)typeptr + xlen) & 15 ;
               (char *)typeptr += xlen ;
               len -= xlen ;
               break ;
            case LF_INDEX:
               typeptr = LookupType(typetab,((lfIndex *)typeptr)->index) ;
               done = TRUE ;
               break ;
            default:
               sprintf(buf,"ENUM: (UNKNOWN)(%u)",v) ;
               return ;
         }
      }
   }
   sprintf(buf,"ENUM: (UNKNOWN)(%u)",v) ;
}
int HintBf(VARINFO *info, int *signedtype)
{
   static unsigned bitmask[] = { 1,3,7,0xf,0x1f,0x3f,0x7f,0xff,
         0x1ff, 0x3ff,0x7ff,0xfff, 0x1fff, 0x3fff,0x7fff,0xffff,
         0x1ffff, 0x3ffff,0x7ffff,0xfffff, 0x1fffff, 0x3fffff,0x7fffff,0xffffff,
         0x1ffffff, 0x3ffffff,0x7ffffff,0xfffffff, 0x1fffffff, 0x3fffffff,0x7fffffff,0xffffffff,

   } ;
   char data[10] ;
   int v ;
   HintBasicType(info, signedtype,&data) ;
   v = *(int *)data ;
   if (*signedtype) {
      v <<= 32 - info->bitstart -info->bitlength;
      v >>= 32 - info->bitlength ;
   } else {
      v >>= info->bitstart ;
      v &= bitmask[info->bitlength] ;
   }
   return v ;
}

void HintValue(char *typetab, VARINFO *info, char *buf)
{
   int i ;
   if (info->structure) {
      sprintf(buf,"STRUCTURE: %p",info->address) ;
   } else if (info->unionx) {
      sprintf(buf,"UNION: %p",info->address) ;
   } else if (info->pointer) {
      int val ;
      if (ReadValue(info->address,&val,4))
         sprintf(buf,"POINTER: %p", val) ;
      else 
         sprintf(buf,"POINTER: <UNKNOWN>") ;
   } else if (info->enumx)
      HintEnum(typetab,info,buf,TRUE,FALSE) ;
   else if (info->bitfield) {
      int signedtype ;
      int v= HintBf(info,&signedtype) ;
      if (signedtype)
         sprintf(buf,"%d(%x)",v,v) ;
      else
         sprintf(buf,"%u(%x)",v,v) ;
   } else if (info->array) {
      sprintf(buf,"ARRAY: %p",info->address) ;
   } else {
      int signedtype ;
      char buf1[10];
      int v;
      switch(HintBasicType(info,&signedtype,buf1)) {
         case T_INT4:
            v = *(int *)buf1 ;
            if (signedtype)
               sprintf(buf,"%d(%x)",v,v) ;
            else
               sprintf(buf,"%u(%x)",v,v) ;
            break ;
         case T_BOOL08:
            if (buf1[0])
               sprintf(buf,"True") ;
            else
               sprintf(buf,"False") ;
            break ;
         case T_REAL32:
            sprintf(buf,"%f",(double)*(float *)buf1) ;
            break ;
         case T_REAL80:
            asm fld tbyte ptr [buf1] ;
            asm fstp qword ptr [buf1] ; 
         case T_REAL64:
            sprintf(buf,"%f",*(double *)buf1) ;
            break ;
         default:
            sprintf(buf,"unknown type") ;
            break ;
      }
   }
}