/* 
   Copyright 2001-2003 Free Software Foundation, Inc.

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

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222

**********************************************************************

SYMTAB.C holds the routines for dealing with the debug info symbol
file.  It also holds the basic routines for formatting the hint data
for the edit window, and basic routines for finding and loading
debug data for the watch window
**********************************************************************

*/
#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 ;

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,

   } ;

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

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,realname[256],*r=realname ;
   DEBUG_INFO *rv ;
   unsigned char *info ;
   FILE *fil ;
   int len ;

   if (name[0] == '"')  {
      q++ ;
      while (*q && *q != '"')
         *p++ = *r++ = *q++ ;
      *p = *r = 0 ;
   }else {
      strcpy(buf,name) ;
      strcpy(realname,name) ;
   }

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

   if (comparefiletime(realname,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 ;
      case S_UDT:
         funcname = ((UDTSYM *)s)->name ;
         break ;
      case S_LABEL32:
         funcname = ((LABELSYM32 *)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 ;
         if (namematch(s,name))
            return offset ;
         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 FindAddressInSymtab(DEBUG_INFO *dbg, char *symtab, int len, int address, char *buf)
{
   int offset = 0 ;

   while (offset < len) {
      struct SYMTYPE *s = symtab + offset ;
      switch (s->rectyp) {
         case S_LDATA32:
         case S_GDATA32:
            if (address == ((DATASYM32 *)s)->off  + dbg->base) {
               memcpy(buf,((DATASYM32 *)s)->name+1,((DATASYM32 *)s)->name[0]) ;
               buf[((DATASYM32 *)s)->name[0]] = 0 ;
               return offset ;
            }
            offset = offset + s->reclen + 2 ;
            break ;
         case S_LPROC32:
         case S_GPROC32:
            if (address == ((PROCSYM32 *)s)->off  + dbg->base) {
               memcpy(buf,((PROCSYM32 *)s)->name+1,((PROCSYM32 *)s)->name[0]) ;
               buf[((PROCSYM32 *)s)->name[0]] = 0 ;
               return offset ;
            }
            offset = ((PROCSYM32 *)s)-> pEnd ;
            break ;
         case S_LABEL32:
            if (address == ((LABELSYM32 *)s)->off  + dbg->base) {
               memcpy(buf,((LABELSYM32 *)s)->name+1,((LABELSYM32 *)s)->name[0]) ;
               buf[((LABELSYM32 *)s)->name[0]] = 0 ;
               return offset ;
            }
            // fallthrough
         default:
            offset = offset + s->reclen + 2 ;
            break ;

      }
   }
   return 0 ;
}
int FindSymbolByAddress(DEBUG_INFO **dbg_info , char **typetab, char **symtab, 
            int *offset, int Address, char *buf)
{
   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 ;

   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 (Address-dbg->base >= s->Off && Address-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 = FindAddressInSymtab(dbg, dbg->info + e1->lfo, e1->cb, Address, buf) ;
                           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 = FindAddressInSymtab(dbg, dbg->info + e->lfo + sizeof(OMFSymHash), 
                  e->cb - sizeof(OMFSymHash), Address, buf) ;
            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) ;
}
int GetNumericLeafSize(short *ptr)
{
   int val = *(ptr) ;
   if (val < LF_NUMERIC)
      return 2 ;
   // LF_LONG is the only thing we are supporting
   return 5 ;
}
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,0) ;
               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) ;
               vx->membername[*nmptr] = 0 ;
               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 += var->itemsize = DeclType(typetab,vx,TRUE,0) ;
      *nextptr = vx ;
      nextptr = &vx->link ;
   }
}
void GetPointerInfo(char *typetab, VARINFO *v)
{
   VARINFO *vx = calloc(sizeof(VARINFO),1) ;
   int ph ;
   v->subtype = vx ;
   vx->type = v->type ;
   sprintf(vx->membername,"*%s",v->membername) ;
   DeclType(typetab,vx,FALSE,&ph) ;
   vx->placeholder = ph ;
}
int DeclType(char *typetab, VARINFO *v, int expand, int *ph)
{
   short * typeptr ;
   char *p ;
   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 ;

   if (ph)
      *ph = FALSE ;
   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 ) ;
         if (ph)
            *ph = !expand ;
         return v->arraysize ;
      case LF_UNION:
         v->unionx = TRUE ;
         if (expand)
            GetStructInfo(typetab,typeptr,v) ;
         v->arraysize = GetNumericLeaf(((lfUnion*)(typeptr+1))->data) ;
         p = (char *)(((lfUnion*)(typeptr+1))->data) + GetNumericLeafSize(((lfUnion*)(typeptr+1))->data) ;
         memcpy(v->structtag,p+1,*p) ;
         if (ph)
            *ph = !expand ;
         return GetNumericLeaf(((lfUnion *)(typeptr + 1))->data) ;
      case LF_STRUCTURE:
      case LF_CLASS:
         v->structure = TRUE ;
         if (expand)
            GetStructInfo(typetab,typeptr,v) ;
         v->arraysize = GetNumericLeaf(((lfClass*)(typeptr+1))->data) ;
         p = (char *)(((lfClass*)(typeptr+1))->data) + GetNumericLeafSize(((lfClass*)(typeptr+1))->data) ;
         memcpy(v->structtag,p+1,*p) ;
         if (ph)
            *ph = !expand ;
         return GetNumericLeaf(((lfClass *)(typeptr + 1))->data) ;
      case LF_ENUM:
         v->enumx = TRUE ;
         v->type = ((lfEnum *)(typeptr+1))->utype ;
         v->typetab = LookupType(typetab, ((lfEnum *)(typeptr+1))->field) ;
         p = (char *)(((lfEnum*)(typeptr+1))->Name) ;
         memcpy(v->structtag,p+1,*p) ;
         return basictypesize(v->type) ;
      case LF_BITFIELD:     // Should only appear in structures
         v->bitfield = TRUE ; 
         v->bitstart = ((lfBitfield *)(typeptr +1))->position ;
         v->bitlength = ((lfBitfield *)(typeptr+1))->length ;
         v->type = ((lfBitfield *)(typeptr+1))->type ;
         return 0 ;
   }
   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 ;
      case S_UDT:
         v->udt = TRUE ;
         v->type = ((UDTSYM *)s)->typind ;
         v->address = 0 ;
         break ;
      case S_LABEL32:
         v->constant = TRUE ;
         v->type = T_PVOID ;
         v->ival = ((LABELSYM32 *)s)->off  + dbg->base ;
         break ;
      default:
         free(v) ;
         return 0 ;
   }
   DeclType(typetab,v,TRUE,0) ;
   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 ;
   }
   return 0 ;
}
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 ;
      }
      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:
#ifndef BORLANDC
               if (*(int *)data & 0x80000000)
                  *(LLONG_TYPE *)data |= 0xffffffff00000000 ;
#endif
               break ;
            case 8:
               return T_INT8 ;
            default:
               return 0;
         }
      } else if (size == 8)
         return T_INT8 ;
      return T_INT4 ;
   }
}
void HintEnum(char *typetab, VARINFO *info,char *buf, int toenum, int onevalue)
{
   int signedtype ;
   LLONG_TYPE 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)
{
   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-1] ;
   }
   return v ;
}

void HintValue(char *typetab, VARINFO *info, char *buf)
{
   int i ;
   if (info->constant) {
      if (CV_TYP_IS_REAL(info->type))
         sprintf(buf,"%f", (double *)info->fval) ;
      else
         sprintf(buf,"%lld(%llx)", info->ival) ;
   } else 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];
      LLONG_TYPE v;
      switch(HintBasicType(info,&signedtype,buf1)) {
         case T_INT8:
#ifndef BORLANDC
            v = *(LLONG_TYPE *)buf1 ;
            if (signedtype)
               sprintf(buf,"%lld(0x%llx)",v,v) ;
            else
               sprintf(buf,"%llu(0x%llx)",v,v) ;
            break ;
#endif
         default:
            sprintf(buf,"unknown type") ;
            break ;
         case T_INT4:
            v = *(int *)buf1 ;
            if (signedtype)
               sprintf(buf,"%d(0x%x)",(int)v,(int)v) ;
            else
               sprintf(buf,"%u(0x%x)",(int)v,(int)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:
            *(double *)buf1 = *(long double *)buf1 ;
//            asm fld tbyte ptr [buf1] ;
//            asm fstp qword ptr [buf1] ; 
         case T_REAL64:
            sprintf(buf,"%f",*(double *)buf1) ;
            break ;
      }
   }
}
void SimpleTypeName(char *buf, int type)
{
   char *p = buf ;
      if (CV_TYP_IS_REAL(type)) {
         switch(type) {
            case T_REAL32:
               sprintf(buf,"float ") ;
               break ;
            case T_REAL64:
               sprintf(buf,"double ");
               break ;
            case T_REAL80:
               sprintf(buf,"long double ") ;
               break ;
            default:
               sprintf(buf,"unknown") ;
               break ;
         }
      } else {
         int size ;
         if (!CV_TYP_IS_SIGNED(type)) {
            sprintf(p,"unsigned ") ;
            p += strlen(p) ;
         }
         switch (CV_TYPE(type)) {
            case CV_INT:
               size = 1 << (CV_SUBT(type)/2) ;
               break ;
            case CV_SIGNED:
            case CV_UNSIGNED:
               size = 1 << CV_SUBT(type) ;
               break ;
            case CV_BOOLEAN:
               size = -1 ;
               break ;
         }
         switch(size) {
            case -1 :
               sprintf(p,"bool ") ;
               break ;
            case 1:
               sprintf(p,"char ") ;
               break ;
            case 2:
               sprintf(p,"short ") ;
               break ;
            case 4:
               sprintf(p,"int ") ;
               break ;
            case 8:
               sprintf(p,"long long ") ;
               break ;
            default:
               break ;
          }
          p += strlen(p) ;
      }
      
      return buf ;
}
char *SymTypeName(char *buf, char *typetab, VARINFO *v)
{
   short * typeptr ;
   char *p = buf ;
   p[0] = 0 ;
   if (v->constant) {
      strcpy(buf,"constant ") ;
      return buf ;
   } else if (v->pointer) {
         SymTypeName(buf + strlen(buf),typetab,v->subtype) ;
         strcat(buf,"* ") ;
   } else if (CV_IS_PRIMITIVE(v->type)) {
         SimpleTypeName(buf, v->type & ~CV_MMASK) ;
         if (CV_TYP_IS_PTR(v->type))
            strcat(buf,"* ") ;
   } else if (v->unionx) {
         sprintf(buf,"union ") ;
         p = buf + strlen(buf) ;
         sprintf(p,"%s",v->structtag) ; 
   } else if (v->structure) {
         sprintf(buf,"struct ") ;
         p = buf + strlen(buf) ;
         sprintf(p,"%s",v->structtag) ; 
   } else if (v->enumx) {
         sprintf(buf,"enum ") ;
         p = buf + strlen(buf) ;
         sprintf(p,"%s",v->structtag) ; 
   }
   if  (v->array) {
         strcat(buf,"[] ") ;
   }
   if (v->bitfield) {
         p = buf +strlen(buf) ;
         sprintf(p,":%d",v->bitlength) ;
   }
   return buf ;
}      