Source file: /~heha/hs/borg.zip/DISASM.CPP

/************************************************************************
*		 disasm.cpp						*
* This is a fairly big class, even having split off the disio class.	*
* The class is the class responsible for maintaining the main		*
* disassembly structures of Borg, and for performing the disassembly	*
* analysis. The class has some very old code in it, and hasn't		*
* undergone much improvement for some time, so parts could do with	*
* rewriting.								*
************************************************************************/

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

#include "disasm.h"
#include "dasm.h"
#include "xref.h"
#include "data.h"
#include "gname.h"
#include "schedule.h"
#include "relocs.h"
#include "debug.h"

#ifdef NEW_DSMITEM
dsmitem::dsmitem() { tptr=NULL; }
dsmitem::~dsmitem() {
 if (type!=dsmcode && type!=dsmnameloc && tptr)
// if (tptr && tptr==data)
   delete tptr;
}
#endif
/************************************************************************
* constructor function							*
* - resets a few class globals						*
************************************************************************/
disasm::disasm() {
 lastdis=NULL;
 itables=0;
 jtables=0;
 irefs=0;
 dirty=false;
}

/************************************************************************
* destructor function is currently null					*
************************************************************************/
disasm::~disasm() { }


/************************************************************************
* initnewdsm								*
* - this is some common code i pulled out and put into a function on	*
*   its own. when a new disassembly item is created it initialises some *
*   of the stucture.							*
************************************************************************/
dsmitem * new_dsm(lptr loc,dsmitemtype typ) {
 dsmitem *newdsm=new dsmitem;
 newdsm->addr=loc;
 newdsm->type=typ;
 newdsm->override=over_null;
 newdsm->modrm=0;
 newdsm->mode32=options.mode32;
 newdsm->flags=0;
 newdsm->displayflags=0;
 return newdsm;
}

/************************************************************************
* dissettable								*
* - this function sets up the processor table. It should be called once *
*   when the processor has been selected and before disassembly begins	*
************************************************************************/
void disasm::dissettable(void)
{ int i=0;
  while((procnames[i].num!=0)&&(procnames[i].num!=options.processor))
    i++;
  itable=procnames[i].tab;
}

/************************************************************************
* nextiter_code								*
* - a basic building block piece of code which skips to the next	*
*   code/data item in the disassembly (identified by having a length),	*
*   or returns null if it gets to the end				*
************************************************************************/
dsmitem *disasm::nextiter_code(dsmitem *tblock)
{ if(tblock!=NULL)
  { while(!tblock->length)
    { tblock=nextiterator();
      if(tblock==NULL)
	break;
    }
  }
  return tblock;
}

/************************************************************************
* dsmitem_contains_loc							*
* - a basic building block piece of code which returns true if the	*
*   dsmitem straddles loc						*
* - added in v2.22							*
************************************************************************/
bool dsmitem_contains_loc(dsmitem *d,lptr loc)
{ if((d->addr<loc)&&(d->addr+d->length>loc))
    return true;
  return false;
}

/************************************************************************
* dsmfindaddrtype							*
* - a basic building block piece of code which returns a dsmitem	*
*   pointer using the list class find to find it by loc and type	*
* - added in v2.22							*
************************************************************************/
dsmitem *disasm::dsmfindaddrtype(lptr loc,dsmitemtype typ)
{ dsmitem fnd;
  fnd.addr=loc;
  fnd.type=typ;
  return find(&fnd);
}

/************************************************************************
* oktoname								*
* - this checks that we arent trying to name a location which is in the *
*   middle of an instruction and returns true if it is ok to assign a	*
*   name here								*
************************************************************************/
bool disasm::oktoname(lptr loc)
{ dsmitem *checker;
  // check table for the given address
  checker=dsmfindaddrtype(loc,dsmcode);
  // NULL returned - must be ok.
  if(checker==NULL)
    return true;
  // check bounds.
  if(dsmitem_contains_loc(checker,loc))
    return false;
  return true;
}

/************************************************************************
* checkvalid								*
* - this is called when adding an instruction disassembly to the list	*
* - it checks that an instruction isnt being added which would overlap	*
*   with instructions already in the database				*
* - it will delete any names and xrefs or comments which get in the way *
************************************************************************/
bool disasm::checkvalid(dsmitem *newdsm)
{ dsmitem *lstdsm,*deldsm;
  lstdsm=dsmfindaddrtype(newdsm->addr,dsmnull);
  if(lstdsm==NULL)
    return true;
  // go through the disassembly items nearby and check for any overlaps.
  do
  { if(lstdsm->length)
    { if(newdsm->addr.between(lstdsm->addr,lstdsm->addr+lstdsm->length-1))
	return false;
      if(lstdsm->addr.between(newdsm->addr,newdsm->addr+newdsm->length-1))
	return false;
    }
    if(lstdsm->addr>=(newdsm->addr+newdsm->length))
      break;
    lstdsm=nextiterator();
  } while(lstdsm!=NULL);
  deldsm=dsmfindaddrtype(newdsm->addr,dsmnull);
  // now go through them again, and this time delete any names/xrefs which get
  // in the way.
  do
  { if((!deldsm->length)&&(deldsm->addr.segm==newdsm->addr.segm))
    { if(dsmitem_contains_loc(newdsm,deldsm->addr))
      { switch(deldsm->type)
	{ case dsmnameloc:
#ifdef DEBUG
	    DebugMessage("Deleting Name : %s",deldsm->tptr);
#endif
	    name->delname(deldsm->addr);
	    break;
	  case dsmxref:
#ifdef DEBUG
	    DebugMessage("Deleting Xref at : %04lx:%04lx",deldsm->addr.segm,deldsm->addr.offs);
#endif
	    break;
	  default:
	    break;
	}
	delfrom(deldsm);
	deldsm=dsmfindaddrtype(newdsm->addr,dsmnull);
	if(deldsm==NULL)
	  return true;
      }
    }
    if(newdsm->addr+newdsm->length<=deldsm->addr)
      break;
    deldsm=nextiterator();
  } while(lstdsm!=NULL);
  return true;
}

/************************************************************************
* setcodeoverride							*
* - sets a particular override for a given location			*
* - this subfunction was created in v211 as it was duplicated code in	*
*   several functions							*
************************************************************************/
void disasm::setcodeoverride(lptr loc,byteoverride typ) {
 dsmitem *findit;
 findit=dsmfindaddrtype(loc,dsmcode);
 if (findit && findit->addr==loc && findit->type==dsmcode) {
  findit->override=typ;
  dirty=true;
  cvd->updatewindowifinrange(loc);
 }
}

/************************************************************************
* disargnegate								*
* - as well as an override I added some displayflags for a disassembly	*
*   item. There is a negation item which allows immediates to be	*
*   negated when displayed, and this function sets or resets the flag	*
************************************************************************/
void disasm::disargnegate(lptr loc) {
 dsmitem *findit;
 findit=dsmfindaddrtype(loc,dsmcode);
 if (findit && findit->addr==loc && findit->type==dsmcode) {
  findit->displayflags^=DISPFLAG_NEGATE;
  dirty=true;
  cvd->updatewindowifinrange(loc);
 }
}

/************************************************************************
* disargoverdec								*
* - sets the decimal override for a disassembly item, given the		*
*   location								*
************************************************************************/
void disasm::disargoverdec(lptr loc) {
 setcodeoverride(loc,over_decimal);
}

/************************************************************************
* disargoversingle							*
* - sets the single (float) override for a disassembly item, given the	*
*   location								*
************************************************************************/
void disasm::disargoversingle(lptr loc) {
 setcodeoverride(loc,over_single);
}

/************************************************************************
* disargoverhex								*
* - sets the hex (null) override for a disassembly item, given the	*
*   location								*
************************************************************************/
void disasm::disargoverhex(lptr loc) {
 setcodeoverride(loc,over_null);
}

/************************************************************************
* disargoverchar							*
* - sets the character override for a disassembly item, given the	*
*   location								*
************************************************************************/
void disasm::disargoverchar(lptr loc) {
 setcodeoverride(loc,over_char);
}

/************************************************************************
* disargoveroffsetdseg							*
* - sets the dseg override for a disassembly item, given the location	*
* - NB at present it does not affect xrefs, to be done.......		*
************************************************************************/
void disasm::disargoveroffsetdseg(lptr loc) {
 dsmitem *findit;
 lptr j;
 findit=dsmfindaddrtype(loc,dsmcode);
 if (findit && findit->addr==loc && findit->type==dsmcode) {
  findit->override=over_dsoffset;
  dirty=true;
  cvd->updatewindowifinrange(loc);
  if (options.mode32 && findit->length>=4) {
   j.assign(options.dseg,((dword *)(&findit->data[findit->length-4]))[0]);
   xrefs->addxref(j,loc);
  }
 }
}

// Generates a label out of memory string given, len=number of characters
void MakeStrLabel(char *callit, byte *mem, int len, bool unicode) {
 callit[0]='s'; callit[1]='_';
 if (len>GNAME_MAXLEN-2) len=GNAME_MAXLEN-2;
 if (unicode) for (int l=0;l<len;l++) {
  callit[l+2]=(char)((*(WCHAR*)mem)++);
 }else CopyMemory(callit+2,mem,len);
 callit[len+2]='\0';
 cleanstring(callit);
}

/************************************************************************
* disdatastring								*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - C style								*
************************************************************************/
void disasm::disdatastring(lptr loc) {
 dsegitem *dblock;
 dsmitem *newdsm;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 actuallen=0;
 while ((dblock->data+(loc-dblock->addr)+actuallen)[0]) {
  actuallen++;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen++;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=asmstr;
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data,actuallen,false);
//  callit[0]='s';
//  callit[1]='_';
//  if (actuallen>GNAME_MAXLEN-2) {
//   callit[GNAME_MAXLEN]=0;
//   lstrcpyn(callit+2,(char *)newdsm->data,GNAME_MAXLEN-3);
//  }else lstrcpy(callit+2,(char *)newdsm->data);
//  cleanstring(callit);
  addto(newdsm);
  dirty=true;
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdataucstring							*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - unicode C style							*
************************************************************************/
void disasm::disdataucstring(lptr loc) { // unicode c-style string.
 dsegitem *dblock;
 dsmitem *newdsm;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 actuallen=0;
 while((dblock->data+(loc-dblock->addr)+actuallen)[0]) {
  actuallen++;
  maxlen--;
  if (!maxlen) return;
  actuallen++;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen+=2;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=&asmstr[3];
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data,actuallen/2,true);
//  callit[0]='s';
//  callit[1]='_';
//  i=2;
//  while (i<GNAME_MAXLEN-1) {
//   callit[i]=newdsm->data[(i-2)*2];
//   i++;
//   if (i*2>actuallen) break;
//  }
//  callit[i]=0;
//  cleanstring(callit);
  addto(newdsm);
  dirty=true;
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdataupstring							*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - Unicode Pascal style						*
************************************************************************/
void disasm::disdataupstring(lptr loc) { // unicode pascal style string.
 dsegitem *dblock;
 dsmitem *newdsm;
 word tlen;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 maxlen-=1;
 actuallen=0;
 tlen=((word *)(dblock->data+(loc-dblock->addr)))[0];
 while (tlen) {
  actuallen++;
  tlen--;
  maxlen--;
  if (!maxlen) return;
  actuallen++;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen+=2;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=asmstr+4;
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data+2,actuallen/2,true);
//  callit[0]='s';
//  callit[1]='_';
//  i=2;
//  while(i<GNAME_MAXLEN-1) {
//   callit[i]=newdsm->data[(i-1)*2];
//   i++;
//   if (i*2>actuallen) break;
//  }
//  callit[i]=0;
//  cleanstring(callit);
  addto(newdsm);
  dirty=true;
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdatadosstring							*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - DOS style								*
************************************************************************/
void disasm::disdatadosstring(lptr loc) {
 dsegitem *dblock;
 dsmitem *newdsm;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 actuallen=0;
 while ((dblock->data+(loc-dblock->addr)+actuallen)[0]!='$') {
  actuallen++;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen++;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=&asmstr[2];
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data,actuallen,false);
//  callit[0]='s';
//  callit[1]='_';
//  lstrcpyn(callit+2,(char *)newdsm->data,min(GNAME_MAXLEN-2,actuallen));
//  cleanstring(callit);
  addto(newdsm);
  dirty=true;
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdatageneralstring							*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - general string is defined as printable characters			*
************************************************************************/
void disasm::disdatageneralstring(lptr loc) {
 dsegitem *dblock;
 dsmitem *newdsm;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 actuallen=0;
 while (isprint((dblock->data+(loc-dblock->addr)+actuallen)[0])) {
  actuallen++;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen++;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=&asmstr[2];
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data,actuallen,false);
//  callit[0]='s';
//  callit[1]='_';
//  lstrcpyn(callit+2,(char *)newdsm->data,actuallen>GNAME_MAXLEN-2?GNAME_MAXLEN-3:actuallen);
//    cleanstring(callit);
  addto(newdsm);
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdatapstring							*
* - disassembles a string at location loc.				*
* - also names the location using the string.				*
* - Pascal style							*
************************************************************************/
void disasm::disdatapstring(lptr loc) {
 dsegitem *dblock;
 dsmitem *newdsm;
 byte tlen;
 dword maxlen,actuallen;
 char callit[GNAME_MAXLEN+1];
 dblock=dta->findseg(loc);
 if (!dblock) return;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return;
 actuallen=0;
 tlen=(dblock->data+(loc-dblock->addr))[0];
 while (tlen) {
  actuallen++;
  tlen--;
  maxlen--;
  if (!maxlen) return;
 }
 actuallen++;
 if (actuallen>0xffff) return; // tooo big
 newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=&asmstr[1];
 newdsm->length=(word)actuallen;	       // string length
 newdsm->data=dblock->data+(loc-dblock->addr);
 if (checkvalid(newdsm)) {
  MakeStrLabel(callit,newdsm->data+1,actuallen,false);
//  callit[0]='s';
//    callit[1]='_';
//    if(actuallen>GNAME_MAXLEN-2)
//    { callit[GNAME_MAXLEN]=0;
//      lstrcpyn(callit+2,(char *)newdsm->data+1,GNAME_MAXLEN-3);
//    }
//    else
//    { callit[actuallen+2]=0;
//      lstrcpyn(callit+2,(char *)newdsm->data+1,actuallen);
//    }
//    cleanstring(callit);
  addto(newdsm);
  dirty=true;
  name->addname(newdsm->addr,callit);
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdata								*
* - disassembles a dataitem, the common parts of the routines which	*
*   disassemble particular types (words,dwords, etc)			*
************************************************************************/
void disasm::disdata(lptr loc,asminstdata *asmwd,byte len,byteoverride overr) {
 dsegitem *dblock;
 dblock=dta->findseg(loc);
 if (!dblock) return;
 dsmitem *newdsm=new_dsm(loc,dsmcode);
 newdsm->tptr=asmwd;
 newdsm->length=len;
 newdsm->data=dblock->data+(loc-dblock->addr);
 newdsm->override=overr;
 if (checkvalid(newdsm)) {
  addto(newdsm);
  dirty=true;
    //check if need to update window.
  cvd->updatewindowifinrange(loc);
 }else delete newdsm;
}

/************************************************************************
* disdataword								*
* - disassembles a word at location loc.				*
************************************************************************/
void disasm::disdataword(lptr loc) {
 disdata(loc,&asmword[0],2,over_null);
}

/************************************************************************
* disdatadword								*
* - disassembles a dword at location loc.				 *
************************************************************************/
void disasm::disdatadword(lptr loc) {
 disdata(loc,&asmdword[0],4,over_null);
}

/************************************************************************
* disdatasingle								*
* - disassembles a single (float) at location loc.			*
************************************************************************/
void disasm::disdatasingle(lptr loc) {
 disdata(loc,&asm_fp[0],4,over_null);
}

/************************************************************************
* disdatadouble								*
* - disassembles a double (float) at location loc.			*
************************************************************************/
void disasm::disdatadouble(lptr loc) {
 disdata(loc,&asm_fp[1],8,over_null);
}

/************************************************************************
* disdatalongdouble							*
* - disassembles a long double at location loc.				*
************************************************************************/
void disasm::disdatalongdouble(lptr loc) {
 disdata(loc,&asm_fp[2],10,over_null);
}

/************************************************************************
* disdatadsoffword							*
* - disassembles an offset data item stored at a location		*
* - short for disdatadword and changing it to an offset,ie dword offset *
************************************************************************/
void disasm::disdatadsoffword(lptr loc) {
 disdata(loc,&asmdword[0],4,over_dsoffset);
}

/************************************************************************
* addcomment								*
* - called to add an auto comment to the disassembly, where the auto	*
*   comment will be edittable by the user. this is used in resource	*
*   analysis.								*
************************************************************************/
void disasm::addcomment(lptr loc,char *comment) {
 char *nm;
 nm=new char[lstrlen(comment)+1];
 lstrcpy(nm,comment);
 disautocomment(loc,dsmcomment,(unsigned char *)nm);
}

/************************************************************************
* disname_or_ordinal							*
* - part of the resource item analysis, this looks for either an	*
*   ordinal number, or a name, and disassembles the data adding auto	*
*   comments too.							*
************************************************************************/
int disasm::disname_or_ordinal(lptr loc,bool comment_ctrl) {
 dsegitem *dblock;
 dword maxlen,idnum;
 dblock=dta->findseg(loc);
 if (!dblock) return 0;
 maxlen=dblock->size-(loc-dblock->addr);
 if (maxlen<2) return 0;
 idnum=((word *)(dblock->data+(loc-dblock->addr)))[0];
 if (idnum==0xffff) { // ordinal follows
  disdataword(loc);
  idnum=((word *)(dblock->data+(loc-dblock->addr)))[1];
  disdataword(loc+2);
    // ctrl class -> add description for class
  if (comment_ctrl) {
   switch (idnum) {
    case 0x0080:
	  addcomment(loc+2,"[Button]");
	  break;
    case 0x0081:
	  addcomment(loc+2,"[Edit]");
	  break;
    case 0x0082:
	  addcomment(loc+2,"[Static]");
	  break;
    case 0x0083:
	  addcomment(loc+2,"[List Box]");
	  break;
    case 0x0084:
	  addcomment(loc+2,"[Scroll Bar]");
	  break;
    case 0x0085:
	  addcomment(loc+2,"[Combo Box]");
	  break;
   }
  }
  return 4;
 }
 disdataucstring(loc);
 return getlength(loc);
}

/************************************************************************
* disdialog								*
* - disassembles a dialog resource, by which I mean that data items are *
*   disassembled to dwords, strings, etc, and the whole lot is		*
*   commented with what the fields are					*
* - at the moment basename is unused, for future refinement ?		*
************************************************************************/
void disasm::disdialog(lptr loc,char* /*basename*/) {
 lptr cloc;
 int ilen,numctrls;
 dsmitem *findit;
 bool exd;
 dsegitem *dblock;
 dword maxlen,idnum,hdrstyle;
  // ho hum, things are never simple
  // - after adding the dialog format i found that some dialogs were just completely
  // different - the so called dialogex dialogs, and after much hunting around i found
  // some details on microsofts site (wow). so then i hacked the code up to do it....
  // dialog header
  exd=false;
  dblock=dta->findseg(loc);
  if(dblock==NULL)
    return;
  maxlen=dblock->size-(loc-dblock->addr);
  if(maxlen<4)
    return;
  idnum=((dword *)(dblock->data+(loc-dblock->addr)))[0];
  if(idnum==0xffff0001)
    exd=true; // whoah, dialogex found
  /* basic struct is as follows:
  struct dialogboxheader
  { unsigned long style,extendedstyle;
    unsigned short numberofitems;
    unsigned short x,y;
    unsigned short cx,cy;
  };*/
  if(exd)
  { addcomment(loc,"Signature+Version");
    disdatadword(loc);
    addcomment(loc+4,"HelpID");
    disdatadword(loc+4);
    loc=loc+8;
  }
  if(exd)
    addcomment(loc,"Extended Style");
  else
    addcomment(loc,"Style");
  disdatadword(loc);
  if(exd)
    addcomment(loc+4,"Style");
  else
    addcomment(loc+4,"Extended Style");
  disdatadword(loc+4);
  addcomment(loc+8,"Number of Items");
  disdataword(loc+8);
  addcomment(loc+10,"x");
  disdataword(loc+10);
  addcomment(loc+12,"y");
  disdataword(loc+12);
  addcomment(loc+14,"cx");
  disdataword(loc+14);
  addcomment(loc+16,"cy");
  disdataword(loc+16);
  cloc=loc+18;
  addcomment(cloc,"Menu name/ordinal");
  ilen=disname_or_ordinal(cloc,false);
  cloc+=ilen;
  addcomment(cloc,"Class name/ordinal");
  ilen=disname_or_ordinal(cloc,false);
  cloc+=ilen;
  addcomment(cloc,"Caption");
  disdataucstring(cloc);
  cloc+=getlength(cloc);
  findit=dsmfindaddrtype(loc+4*(exd?1:0),dsmcode);
  hdrstyle=0;
  if(findit!=NULL)
  { if((findit->addr==loc+4*(exd?1:0))&&(findit->type==dsmcode))
      hdrstyle=((dword *)findit->data)[0];
  }
  // i noticed a reference to DS_SHELLFONT on msdn, but what is that ????????
  if (hdrstyle&DS_SETFONT)  // if ds_setfont then 2 more items...in theory
  { addcomment(cloc,"font pointsize");
    disdataword(cloc);
    cloc+=2;
    if(exd) // more options with exd
    { addcomment(cloc,"weight");
      disdataword(cloc);
      cloc+=2;
      addcomment(cloc,"italic");
      //disdatabyte(cloc);
      cloc+=1;
      addcomment(cloc,"charset");
      //disdatabyte(cloc);
      cloc+=1;
    }
    addcomment(cloc,"font");
    disdataucstring(cloc);
    cloc+=getlength(cloc);
  }
  // now do controls
  findit=dsmfindaddrtype(loc+8,dsmcode);
  numctrls=0;
  if(findit!=NULL)
  { if((findit->addr==loc+8)&&(findit->type==dsmcode))
      numctrls=((word *)findit->data)[0];
  }
  /*struct ctrlheader
  { unsigned long style,extendedstyle;
    unsigned short x,y;
    unsigned short cx,cy;
    unsigned short wid;
  };*/
  while(numctrls)
  { if(cloc.offs&0x03)
      cloc.offs=(cloc.offs|0x03)+1;
    if(exd)
    { addcomment(cloc,"HelpID");
      disdatadword(cloc);
      cloc+=4;
    }
    if(exd)
      addcomment(cloc,"Extended Style");
    else
      addcomment(cloc,"Style");
    disdatadword(cloc);
    if(exd)
      addcomment(cloc+4,"Style");
    else
      addcomment(cloc+4,"Extended Style");
    disdatadword(cloc+4);
    addcomment(cloc+8,"x");
    disdataword(cloc+8);
    addcomment(cloc+10,"y");
    disdataword(cloc+10);
    addcomment(cloc+12,"cx");
    disdataword(cloc+12);
    addcomment(cloc+14,"cy");
    disdataword(cloc+14);
    addcomment(cloc+16,"wid");
    disdataword(cloc+16);
    cloc+=18;
    if(exd)
      if(cloc.offs&0x03)
	cloc.offs=(cloc.offs|0x03)+1;
    addcomment(cloc,"Class id");
    ilen=disname_or_ordinal(cloc,true);
    cloc+=ilen;
    addcomment(cloc,"Text");
    ilen=disname_or_ordinal(cloc,false);
    cloc+=ilen;
    addcomment(cloc,"Extra Stuff");
    disdataword(cloc);
    findit=dsmfindaddrtype(cloc,dsmcode);
    if(findit!=NULL)
    { if((findit->addr==cloc)&&(findit->type==dsmcode))
	cloc+=((word *)findit->data)[0];
    }
    cloc+=2;
    numctrls--;
  }
}
#ifdef __BORLANDC__
#pragma warn +par
#endif

/************************************************************************
* disstringtable							*
* - disassembles a string table, by which I mean that the strings are	*
*   disassembled into strings and the locations are named according to	*
*   the strings id numbers (I chose this in preference to naming by	*
*   string because they are a resource, and so the locations will not	*
*   be referenced, but if the program wants to use them then it will	*
*   use the id numbers, and make an API call to get hold of them).	*
************************************************************************/
void disasm::disstringtable(lptr loc,char *basename) {
 int i;
 lptr cloc;
 char callit[40];
 dword idnum;
 int ipt;
 dsmitem *lastdsm;
 ipt=0;
 idnum=0;
 if (basename) {
  while ((basename[ipt])&&(basename[ipt]!=':')) ipt++;
  if (basename[ipt]==':') {
   ipt++;
   while (basename[ipt]) {
    if (basename[ipt]>='a') idnum=idnum*16+basename[ipt]-'a'+10;
    else idnum=idnum*16+basename[ipt]-'0';
    ipt++;
    if (basename[ipt]=='h') break;
   }
  }
 }
 cloc=loc;
 for (i=0;i<16;i++) { // 16 strings in a stringtable, of type unicode_pascal.
  disdataupstring(cloc);
  if (idnum) {
   wsprintf(callit,"String_ID_%lx",(idnum-1)*16+i);
   name->addname(cloc,callit);
  }
  lastdsm=dsmfindaddrtype(cloc,dsmcode);
  if (!lastdsm) break;
  if (lastdsm->type!=dsmcode || lastdsm->addr!=cloc) break;
  cloc+=lastdsm->length;
 }
}

/************************************************************************
* codeseek								*
* - this is the aggressive code search if it is chosen as an option. It *
*   has a low priority, and so appears near the end of the queue. It	*
*   hunts for possible code to disassemble in the code segments (added	*
*   as a task during file load for each code segment). When it finds an *
*   undisassembled byte it tries to disassemble from that point, and	*
*   drops into the background again until disassembly has been done	*
* - note that if it doesnt find anything in a short time it exits and	*
*   puts a continuation request in to the scheduler, this ensures that	*
*   userrequests are answered quickly					*
************************************************************************/
void disasm::codeseek(lptr loc) {
 bool doneblock;
 dsegitem *dblock;
 dsmitem *tblock;
 int dcount,ilength;
  // check if already done.
 dblock=dta->findseg(loc);	// find segment item.
 dcount=0;
 if (!dblock) return;
 do{
  doneblock=false;
  ilength=1;
  dsmfindaddrtype(loc,dsmnull);
  tblock=nextiterator();
  tblock=nextiter_code(tblock);
  if (tblock) {
   if((tblock->addr.segm==loc.segm)&&(dsmitem_contains_loc(tblock,loc)))
     doneblock=true;
   while (tblock->addr==loc) {
    if (tblock->length) ilength=tblock->length;
    if (tblock->type!=dsmcomment) {
     doneblock=true;
     break;
    }
    tblock=nextiterator();
    if (!tblock) break;
   }
  }
  if (doneblock) {
   loc+=ilength;
   dcount++;
   if (loc>=(dblock->addr+dblock->size)) return;
   if (dcount>1000) {	 // dont forget the main thread!
    scheduler.addtask(seek_code,priority_continuation,loc,NULL);
    return;
   }
  }
 } while (doneblock);
  // decode it.
 scheduler.addtask(seek_code,priority_aggressivesearch,loc+1,NULL);
 scheduler.addtask(dis_code,priority_possiblecode,loc,NULL);
}

/************************************************************************
* disexportblock							*
* - this disassembles a block of code, from an export address, but only *
*   if the export address is in a code segment				*
************************************************************************/
void disasm::disexportblock(lptr loc) {
 dsegitem *dblock;
 dblock=dta->findseg(loc);
 if (!dblock) return;
 if (dblock->typ==code32) disblock(loc);
}

/************************************************************************
* disblock								*
* - disassembles a block from the starting point loc, calling		*
*   decodeinst for each instruction.					*
* - we dont just keep going in here, but only disassemble a few		*
*   instructions then ask for a continuation and quit back to the	*
*   scheduler for userrequests to be processed. If Borg seems to slow	*
*   on your machine when you scroll around and it is still analysing	*
*   then try dropping the number of instructions to disassemble and	*
*   window updates should occur more often.				*
* - If Borg cannot disassemble for whatever reason, or if a ret or jmp	*
*   type instruction is reached then we finish.				*
************************************************************************/
void disasm::disblock(lptr loc) {
 byte ibuff[20];		      // ibuff is the disassembly buffer - m/c is moved here
				      // for disassembly - no checking of eof is then needed
				      // until after the code is identified.
 dsegitem *dblock;
 int i,disasmcount;
 bool doneblock;
 dsmitem *tblock;
 dword aaddr;
 byte *mcode;
 asminstdata *codefound;

 dblock=dta->findseg(loc);	// find segment item.
 disasmcount=0;
 if (!dblock) return;
 if (dblock->typ==uninitdata) return;
 if (loc>=dblock->addr+dblock->size) return;
 doneblock=false;
 while (!doneblock) { // don't spend too long in here
  disasmcount++;
  if (disasmcount>50) {
   scheduler.addtask(dis_code,priority_continuation,loc,NULL);
   return;
  }
  memset(ibuff,0,20);
    // check if already done.
  dsmfindaddrtype(loc,dsmnull);
  tblock=nextiterator();
  tblock=nextiter_code(tblock);
  if (tblock) {
   if((tblock->addr.segm==loc.segm)&&(dsmitem_contains_loc(tblock,loc)))
	doneblock=true;
   while (tblock->addr==loc) {
    if (tblock->type!=dsmcomment) {
     doneblock=true;
     break;
    }
    tblock=nextiterator();
    if (!tblock) break;
   }
  }
   // decode it.
  if (doneblock) break;
  aaddr=loc-dblock->addr;
  mcode=dblock->data+aaddr;
  i=0;
  while ((i<15)&&(aaddr<dblock->size)) {
   ibuff[i]=mcode[i];
   i++;
   aaddr++;
  }
  tblock=decodeinst(ibuff,mcode,loc,TABLE_MAIN,options.mode32,0);
  if (tblock) {
   if (!checkvalid(tblock)) {
    delete tblock;
    tblock=NULL;
   }
  }
  if (tblock) {
   addto(tblock);
      //check if need to update window.
   cvd->updatewindowifinrange(loc);
   loc.offs+=tblock->length;
   if (loc-dblock->addr>dblock->size) {
    doneblock=true;
    delfrom(tblock);
   }
  }else doneblock=true;
  if (doneblock) break;
    // check if end (jmp,ret,etc)
  codefound=(asminstdata *)tblock->tptr;
  if(codefound->flags&FLAGS_JMP || codefound->flags&FLAGS_RET) doneblock=true;
 }
}

/************************************************************************
* decodeinst								*
* - disassembles one instruction					*
* - in some ways this is the single most important function in Borg. It *
*   disassembles an instruction adding a disassembled item to the	*
*   database. It uses the options we have set, and the processor tables *
*   identified.								*
* - If some kind of call or conditional jump is reached then Borg	*
*   just adds another disassembly task to the scheduler to look at	*
*   later, and then carries on.						*
* - Note that this function is recursive, for handling some complex	*
*   x86 overrides, note that the recursion depth is limited but Borg	*
*   should handle complex prefix byte sequences and 'double sequences'	*
* - The majority of the code here is some of the oldest code in Borg,	*
*   and probably some of the most complex.				*
* - xreffing and windowupdates are performed from here			*
************************************************************************/
dsmitem *disasm::decodeinst(byte *ibuff,byte *mcode,lptr loc,byte tabtype,bool omode32,int depth)
{ int tablenum=0;	      // asmtable table number
  int instnum;		      // instruction num in table
  asminstdata *insttab;
  dsmitem *newdsm;
  dword flgs;		      // inst flags
  argtype a1,a2,a3;	      // inst args
  lptr j;		      // jump/call target
  byte *dta;
  byte length;
  gnameitem *imp;
  char *impname;
  bool righttable;
  byte cbyte,mbyte;
  bool fupbyte;
  cbyte=ibuff[0];
  if(tabtype==TABLE_EXT)
    cbyte=ibuff[1];
  if(tabtype==TABLE_EXT2)
    cbyte=ibuff[2];
  if((tabtype==TABLE_EXT2)&&(options.processor==PROC_Z80))
    cbyte=ibuff[3];
  while(itable[tablenum].table!=NULL)  // search tables
  { righttable=true;
    if((itable[tablenum].type!=tabtype)||(itable[tablenum].minlim>cbyte)||
      (itable[tablenum].maxlim<cbyte)) righttable=false;
    if(((tabtype==TABLE_EXT)||(tabtype==TABLE_EXT2))&&(ibuff[0]!=itable[tablenum].extnum))
      righttable=false;
    if((tabtype==TABLE_EXT2)&&(ibuff[1]!=itable[tablenum].extnum2))
      righttable=false;
    if(righttable)
    { insttab=itable[tablenum].table;	   // need to search this now
      instnum=0;
      mbyte=cbyte;
      fupbyte=false;
      if(itable[tablenum].divisor)
	mbyte=(byte)(mbyte/itable[tablenum].divisor);
      if(itable[tablenum].mask)
	mbyte&=itable[tablenum].mask;
      else	// follow up byte encodings (KNI,AMD3DNOW)
      { fupbyte=true;
	flgs=insttab[instnum].flags;
	a1=insttab[instnum].arg1;
	a2=insttab[instnum].arg2;
	a3=insttab[instnum].arg3;
#ifdef __BORLANDC__
#pragma warn -sig
#endif
	length=(byte)(1+arglength(a1,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,true)
	       +arglength(a2,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,true)
	       +arglength(a3,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,true)
	       +itable[tablenum].modrmpos);
#ifdef __BORLANDC__
#pragma warn +sig
#endif
	// addition for table extensions where inst is part of modrm byte
	if(((tabtype==TABLE_EXT)||(tabtype==TABLE_EXT2))&&(length==1))
	  length++;
	mbyte=ibuff[length];
      }
      while((insttab[instnum].name!=NULL)||(insttab[instnum].instbyte)||(insttab[instnum].processor))
      { if((omode32)&&(insttab[instnum].flags&FLAGS_OMODE16));
	else if((!omode32)&&(insttab[instnum].flags&FLAGS_OMODE32));
	else if((insttab[instnum].instbyte==mbyte)&&(insttab[instnum].processor&options.processor))
	{ // found it
	  if(insttab[instnum].name==NULL)
	  { if(tabtype==TABLE_MAIN)
	      return decodeinst(ibuff,mcode,loc,TABLE_EXT,omode32,5);
	    else
	      return decodeinst(ibuff,mcode,loc,TABLE_EXT2,omode32,5);
	  }
	  else
	  { // interpret flags,etc
	    flgs=insttab[instnum].flags;
	    if((flgs&FLAGS_OPERPREFIX)&&(depth<5))
	    { newdsm=decodeinst(ibuff+1,mcode+1,loc+1,tabtype,!omode32,depth+1);
	      if(newdsm==NULL)
		return NULL;
	      newdsm->addr.offs--;
	      newdsm->length++;
	      newdsm->modrm++;
	      newdsm->data--;
	      return newdsm;
	    }
	    if((flgs&FLAGS_ADDRPREFIX)&&(depth<5))
	    { options.mode32=!options.mode32;
	      options.mode16=!options.mode16;
	      newdsm=decodeinst(ibuff+1,mcode+1,loc+1,tabtype,omode32,depth+1);
	      options.mode32=!options.mode32;
	      options.mode16=!options.mode16;
	      if(newdsm==NULL)
		return NULL;
	      newdsm->addr.offs--;
	      newdsm->length++;
	      newdsm->modrm++;
	      newdsm->data--;
	      newdsm->flags=newdsm->flags|FLAGS_ADDRPREFIX;
	      return newdsm;
	    }
	    if((flgs&FLAGS_SEGPREFIX)&&(depth<5))
	    { newdsm=decodeinst(ibuff+1,mcode+1,loc+1,tabtype,omode32,depth+1);
	      if(newdsm==NULL)
		return NULL;
	      newdsm->addr.offs--;
	      newdsm->length++;
	      newdsm->modrm++;
	      newdsm->data--;
	      newdsm->flags=newdsm->flags|FLAGS_SEGPREFIX;
	      return newdsm;
	    }
	    if((flgs&FLAGS_PREFIX)&&(depth<5))
	    { newdsm=decodeinst(ibuff+1,mcode+1,loc+1,tabtype,omode32,depth+1);
	      if(newdsm==NULL)
		return NULL;
	      newdsm->addr.offs--;
	      newdsm->length++;
	      newdsm->modrm++;
	      newdsm->data--;
	      newdsm->flags=newdsm->flags|FLAGS_PREFIX;
	      return newdsm;
	    }
	    newdsm=new_dsm(loc,dsmcode);
	    newdsm->tptr=(void *)&insttab[instnum];
	    newdsm->modrm=(byte)(1+itable[tablenum].modrmpos);
	    newdsm->data=mcode;
	    newdsm->mode32=omode32;
	    if(flgs&FLAGS_16BIT)
	      newdsm->mode32=false;
	    if(flgs&FLAGS_32BIT)
	      newdsm->mode32=true;
	    newdsm->flags=flgs;
	    a1=insttab[instnum].arg1;
	    a2=insttab[instnum].arg2;
	    a3=insttab[instnum].arg3;
#ifdef __BORLANDC__
#pragma warn -sig
#endif
	    length=(byte)(1+arglength(a1,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,newdsm->mode32)
	       +arglength(a2,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,newdsm->mode32)
	       +arglength(a3,mcode[1+itable[tablenum].modrmpos],mcode[2+itable[tablenum].modrmpos],flgs,newdsm->mode32)
	       +itable[tablenum].modrmpos);
#ifdef __BORLANDC__
#pragma warn +sig
#endif
	    // addition for table extensions where inst is part of modrm byte
	    if(((tabtype==TABLE_EXT)||(tabtype==TABLE_EXT2))&&((length==1)||(options.processor==PROC_Z80)))
	      length++;
	    if(options.processor==PROC_Z80)
	    { if(tabtype==TABLE_EXT2)
		length++;
	      if(flgs&FLAGS_INDEXREG)
		length++;
	    }
	    if(fupbyte)
	      length++;
	    newdsm->length=length;
	    if(!checkvalid(newdsm))
	    { delete newdsm;
	      return NULL;
	    }
	    if(flgs&(FLAGS_JMP|FLAGS_CALL|FLAGS_CJMP))
	    { switch(a1)
	      { case ARG_RELIMM:
		  j=loc;
		  dta=mcode+length;
		  if(options.mode32)
		  { dta-=4;
		    j+=((dword *)dta)[0]+length;
		  }
		  else
		  { dta-=2;
		    j+=(word)(((word *)dta)[0]+length);
		  }
		  scheduler.addtask(dis_code,priority_definitecode,j,NULL);
		  xrefs->addxref(j,newdsm->addr);
		  break;
		case ARG_RELIMM8:
		  j=loc;
		  dta=mcode+length-1;
		  if(options.mode32)
		  { if(dta[0]&0x80)
		      j+=(dword)(dta[0]+0xffffff00+length);
		    else
		      j+=(dword)(dta[0]+length);
		  }
		  else
		  { if(dta[0]&0x80)
		      j+=(word)(dta[0]+0xff00+length);
		    else
		      j+=(word)(dta[0]+length);
		  }
		  scheduler.addtask(dis_code,priority_definitecode,j,NULL);
		  xrefs->addxref(j,newdsm->addr);
		  break;
		case ARG_FADDR:
		  dta=mcode+length;
		  if(options.mode32)
		  { dta-=6;
		    j.assign(((word *)(&dta[4]))[0],((dword *)(&dta[0]))[0]);
		  }
		  else
		  { dta-=4;
		    j.assign(((word *)(&dta[2]))[0],((word *)(&dta[0]))[0]);
		  }
		  scheduler.addtask(dis_code,priority_definitecode,j,NULL);
		  xrefs->addxref(j,newdsm->addr);
		  break;
		case ARG_MODRM:
		case ARG_MODRM_FPTR:
		  if(options.mode32)
		  { if((newdsm->data[0]==0xff)&&(newdsm->data[1]==0x25)&&(tabtype==TABLE_EXT))
		    { j.assign(loc.segm,((dword *)(&newdsm->data[2]))[0]);
		      if(import->isname(j))
		      { imp=import->nextiterator();
			impname=new char[GNAME_MAXLEN+1];
			impname[0]='_';
			impname[GNAME_MAXLEN]=0;
			lstrcpyn(&impname[1],imp->name,GNAME_MAXLEN-2);
			//if(!name->isname(segm,offs))
			scheduler.addtask(namecurloc,priority_nameloc,loc,impname);
		      }
		    }
		  }
		  scheduler.addtask(dis_jumptable,priority_definitecode,loc,NULL);
		  break;
		default:
		  break;
	      }
	    }
	    switch(a1)
	    { case ARG_IMM32:
		if(reloc->isreloc(loc+length-4))
		{ newdsm->override=over_dsoffset;
		  dta=mcode+length-4;
		  j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		  xrefs->addxref(j,newdsm->addr);
		}
		break;
	      case ARG_IMM:
		if(options.mode32)
		{ if(reloc->isreloc(loc+length-4))
		  { newdsm->override=over_dsoffset;
		    dta=mcode+length-4;
		    j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		    xrefs->addxref(j,newdsm->addr);
		  }
		}
		break;
	      case ARG_MEMLOC:
		if(options.mode32)
		{ newdsm->override=over_dsoffset;
		  dta=mcode+length-4;
		  j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		  xrefs->addxref(j,newdsm->addr);
		}
		break;
	      case ARG_MMXMODRM:
	      case ARG_XMMMODRM:
	      case ARG_MODRM_S:
	      case ARG_MODRMM512:
	      case ARG_MODRMQ:
	      case ARG_MODRM_SREAL:
	      case ARG_MODRM_PTR:
	      case ARG_MODRM_WORD:
	      case ARG_MODRM_SINT:
	      case ARG_MODRM_EREAL:
	      case ARG_MODRM_DREAL:
	      case ARG_MODRM_WINT:
	      case ARG_MODRM_LINT:
	      case ARG_MODRM_BCD:
	      case ARG_MODRM_FPTR:
	      case ARG_MODRM:
		if(options.mode32)
		  if((newdsm->data[newdsm->modrm]&0xc7)==5) // straight disp32
		  { dta=mcode+newdsm->modrm+1;
		    j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		    xrefs->addxref(j,newdsm->addr);
		  }
		break;
	      default:
		break;
	    }
	    switch(a2)
	    { case ARG_IMM32:
		if(reloc->isreloc(loc+length-4))
		{ newdsm->override=over_dsoffset;
		  dta=mcode+length-4;
		  j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		  xrefs->addxref(j,newdsm->addr);
		}
		break;
	      case ARG_IMM:
		if(options.mode32)
		{ if(reloc->isreloc(loc+length-4))
		  { newdsm->override=over_dsoffset;
		    dta=mcode+length-4;
		    j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		    xrefs->addxref(j,newdsm->addr);
		  }
		}
		break;
	      case ARG_MEMLOC:
		if(options.mode32)
		{ newdsm->override=over_dsoffset;
		  dta=mcode+length-4;
		  j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		  xrefs->addxref(j,newdsm->addr);
		}
		break;
	      case ARG_MMXMODRM:
	      case ARG_XMMMODRM:
	      case ARG_MODRM_S:
	      case ARG_MODRMM512:
	      case ARG_MODRMQ:
	      case ARG_MODRM_SREAL:
	      case ARG_MODRM_PTR:
	      case ARG_MODRM_WORD:
	      case ARG_MODRM_SINT:
	      case ARG_MODRM_EREAL:
	      case ARG_MODRM_DREAL:
	      case ARG_MODRM_WINT:
	      case ARG_MODRM_LINT:
	      case ARG_MODRM_BCD:
	      case ARG_MODRM_FPTR:
	      case ARG_MODRM:
		if(options.mode32)
		  if((newdsm->data[newdsm->modrm]&0xc7)==5) // straight disp32
		  { dta=mcode+newdsm->modrm+1;
		    j.assign(options.dseg,((dword *)(&dta[0]))[0]);
		    xrefs->addxref(j,newdsm->addr);
		  }
		break;
	      default:
		break;
	    }
	    return newdsm;
	  }
	}
	instnum++;
      }
    }
    tablenum++;
  }
  return NULL;
}

/************************************************************************
* arglength								*
* - a function which returns the increase in length of an instruction	*
*   due to its argtype, used by the decodeinst engine in calculating	*
*   the instruction length						*
************************************************************************/
byte disasm::arglength(argtype a,byte modrmbyte,byte sibbyte,dword flgs,bool omode32)
{ byte rm;
  switch(a)
  { case ARG_IMM:
      if(flgs&FLAGS_8BIT)
	return 1;
      if(!omode32)
	return 2;
      else
	return 4;
    case ARG_NONEBYTE:
      return 1;
    case ARG_RELIMM:
    case ARG_MEMLOC:
      if(options.mode16)
	return 2;
      else
	return 4;
    case ARG_RELIMM8:
    case ARG_SIMM8:
    case ARG_IMM8:
    case ARG_IMM8_IND:
      return 1;
    case ARG_IMM32:
      return 4;
    case ARG_IMM16_A:
    case ARG_IMM16:
    case ARG_MEMLOC16:
      return 2;
    case ARG_FADDR:
      if(options.mode16)
	return 4;
      else
	return 6;
    case ARG_MODREG:
    case ARG_MMXMODRM:
    case ARG_XMMMODRM:
    case ARG_MODRM8:
    case ARG_MODRM16:
    case ARG_MODRM_S:
    case ARG_MODRMM512:
    case ARG_MODRMQ:
    case ARG_MODRM_SREAL:
    case ARG_MODRM_PTR:
    case ARG_MODRM_WORD:
    case ARG_MODRM_SINT:
    case ARG_MODRM_EREAL:
    case ARG_MODRM_DREAL:
    case ARG_MODRM_WINT:
    case ARG_MODRM_LINT:
    case ARG_MODRM_BCD:
    case ARG_MODRM_FPTR:
    case ARG_MODRM:
      rm=(byte)((modrmbyte&0xc0)>>6);
      switch(rm)
      { case 0:
	  if(options.mode32)
	  { if((modrmbyte&0x07)==5)
	      return 5; // disp32
	    if((modrmbyte&0x07)==4)
	    { if((sibbyte&0x07)==5)
		return 6;
	      return 2; //sib byte - need to check if r=5 also.
	    }
	  }
	  else
	    if((modrmbyte&0x07)==6)
	      return 3;
	  break;
	case 1:
	  if(options.mode32)
	  { if((modrmbyte&0x07)==4)
	    { return 3; //sib byte
	    }
	  }
	  return 2; // disp8
	case 2:
	  if(options.mode32)
	  { if((modrmbyte&0x07)==4)
	      return 6; //sib byte
	    return 5; // disp32
	  }
	  else
	    return 3; // disp16
	case 3:
	  return 1;
      }
      return 1;
    default:
      break;
  }
  return 0;
}

/************************************************************************
* compare function							*
* - the compare function for the list of disassembled instructions.	*
* - the disassembled instructions are kept in order using location, and *
*   type where type indicates instruction, comment, segheader line, etc *
*   as these are kept in the database of disassembled instructions. The *
*   window that the user sees into the disassembly is simply a view of	*
*   this database with one line per record.				*
************************************************************************/
int disasm::compare(dsmitem *i,dsmitem *j)
{ if(i->addr==j->addr)
  { if(i->type==j->type)
      return 0;
    else if(i->type>j->type)
      return 1;
    return -1;
  }
  if(i->addr>j->addr)
    return 1;
  return -1;
}

/************************************************************************
* deletion function							*
* - in deleting the database we delete any comments that may be		*
*   attached, overrides the standard list item delete function		*
************************************************************************/
//deletion function for list
#ifndef NEW_DSMITEM
void disasm::delfunc(dsmitem *i) { // bugfix by Mark Ogden - added dsmnameloc
 if (i->type!=dsmcode && i->type!=dsmnameloc && i->tptr)
   delete i->tptr;
 delete i;
}
#endif
/************************************************************************
* undefineline								*
* - this simply deletes any code item in the disassembly database, for	*
*   the users current line in the database/window			*
************************************************************************/
void disasm::undefineline(void) {
 dsmitem *tblock;
 lptr outhere;
 tblock=cvd->findcurrentline();
 if (!tblock) return;
 outhere=tblock->addr;
 tblock=nextiter_code(tblock);
 if (tblock && outhere==tblock->addr) {
  delfrom(tblock);
  dirty=true;
  cvd->updatewindow();
 }
}

/************************************************************************
* undefinelines								*
* - undefines the next 10 lines of code, or until a non-disassembled	*
*   item is found							*
************************************************************************/
void disasm::undefinelines(void) {
 dsmitem *tblock;
 lptr outhere;
 int i;
 tblock=cvd->findcurrentline();
 if (!tblock) return;
 outhere=tblock->addr;
 for (i=0;i<10;i++) {
  tblock=nextiter_code(tblock);
  if (tblock && outhere==tblock->addr) {
   outhere+=tblock->length;
   delfrom(tblock);
   dirty=true;
   tblock=nextiterator();
  }else	break;
 }
 cvd->updatewindow();
}

/************************************************************************
* undefinelines_long							*
* - here we continue undefining any code items in the database from the *
*   users line until we come to a location which is not code, or some	*
*   other kind of item in the database, like a comment, name, or xref	*
************************************************************************/
void disasm::undefinelines_long(void) {
 dsmitem *tblock;
 lptr outhere;
 tblock=cvd->findcurrentline();
 if (!tblock) return;
 outhere=tblock->addr;
 tblock=nextiter_code(tblock);
 while (tblock) {
  if (!tblock->length) break;
  if (outhere==tblock->addr) {
   outhere+=tblock->length;
   delfrom(tblock);
   dirty=true;
   tblock=nextiterator();
  }else break;
 }
 cvd->updatewindow();
}

/************************************************************************
* undefineblock								*
* - a block undefine using a selected block of code, we simply undefine *
*   any code items found between the start and end points of the block	*
************************************************************************/
void disasm::undefineblock(lptr ufrom,lptr uto) {
 dsmitem *tblock;
 lptr outhere;
 tblock=dsmfindaddrtype(ufrom,dsmcode);
 if (!tblock) return;
 outhere=tblock->addr;
 while (tblock) {
  if (tblock->addr>uto) break;
  if (tblock->type==dsmcode && tblock->addr>=ufrom) {
   delfrom(tblock);
   dirty=true;
  }
  tblock=nextiterator();
 }
 cvd->updatewindow();
}

/************************************************************************
* discomment								*
* - this adds a comment to the disassembly database. It is used to add	*
*   different types of comments (like segheaders and user entered	*
*   comments)								*
************************************************************************/
void disasm::discomment(lptr loc,dsmitemtype typ,byte *comment) {
 dsmitem *newdsm=new_dsm(loc,typ);
 newdsm->tptr=(void *)comment;
 newdsm->length=0;
 newdsm->data=comment;
 addto(newdsm);
 dirty=true;
 cvd->updatewindowifinrange(loc);
}

/************************************************************************
* disautocomment							*
* - this is a second function to add a comment to the disassembly	*
*   database, but only if there is no comment already there. This is	*
*   used to add disassembler autocomments. This is currently only used	*
*   in resource disassembly, but could easily be used to add standard	*
*   comments for particular instructions or for API calls, or for DOS	*
*   INTs.								*
************************************************************************/
void disasm::disautocomment(lptr loc,dsmitemtype typ,byte *comment) {
 dsmitem *newdsm,*fdsm;
 fdsm=dsmfindaddrtype(loc,typ);
 if (fdsm && fdsm->addr==loc && fdsm->type==typ) {
  delete comment;
  return;
 }
 newdsm=new_dsm(loc,typ);
 newdsm->tptr=(void *)comment;
 newdsm->length=0;
 newdsm->data=comment;
 addto(newdsm);
 dirty=true;
 cvd->updatewindowifinrange(loc);
}

/************************************************************************
* delcomment								*
* - this is used to delete comments from the database. Typically it is	*
*   called when the user enters a comment for a location. We delete the *
*   old one and then add the new one later.				*
************************************************************************/
void disasm::delcomment(lptr loc,dsmitemtype typ) {
 dsmitem *fdsm;
 fdsm=dsmfindaddrtype(loc,typ);
 if (fdsm && fdsm->addr==loc && fdsm->type==typ) {
  delfrom(fdsm);
  dirty=true;
  cvd->updatewindowifinrange(loc);
 }
}

/************************************************************************
* interpretmod								*
* - this is used by the jumptable detection routines in order to	*
*   examine a modrm/sib encoding for information			*
* - it returns information about offsets and indexes and the registers	*
*   in use, and any multiplier						*
************************************************************************/
bool disasm::interpretmod(byte *data,dword *toffs,byte *indexreg,
  byte *indexreg2,byte *indexamount,int *numjumps) {
 byte rm,modrm,sib;
 rm=(byte)((data[0]&0xc0)>>6);
 modrm=(byte)(data[0]&0x07);
 switch (rm) {
  case 0:
      if(options.mode32)
      { if(modrm==5)   // disp32 only.
	{ *toffs=((dword *)(&data[1]))[0];
	  *numjumps=1;
	}
	else if(modrm==4)	 // case 4=sib
	{ sib=data[1];
	  if((sib&0x07)==5)
	    *toffs=((dword *)(&data[2]))[0];  // disp32
	  else
	    return false; // no disp
	  if(((sib>>3)&0x07)==4)
	    *numjumps=1;  // no scaled index reg
	  else
	  { *indexreg=(byte)((sib>>3)&0x07);
	    switch(sib>>6)
	    { case 0:
		*indexamount=1;
		break;
	      case 1:
		*indexamount=2;
		break;
	      case 2:
		*indexamount=4;
		break;
	      case 3:
		*indexamount=8;
		break;
	    }
	  }
	}
	else
	  return false; // no disp
      }
      else // 16-bit mode
      { if(modrm==6) // disp16 only
	{ *toffs=((word *)(&data[1]))[0];
	  *numjumps=1;
	}
	else
	  return false; // no disp
      }
      break;
  case 1:
      return false; // all disp8 offsets - don't follow
  case 2:
      if(options.mode32)
      { if(modrm==4)	    // case 4=sib
	{ sib=data[1];
	  *toffs=((dword *)(&data[2]))[0];
	  *indexreg2=(byte)(sib&0x07);
	  if(((sib>>3)&0x07)==4); // no scaled index reg
	  else
	  { *indexreg=(byte)((sib>>3)&0x07);
	    switch(sib>>6)
	    { case 0:
		*indexamount=1;
		break;
	      case 1:
		*indexamount=2;
		break;
	      case 2:
		*indexamount=4;
		break;
	      case 3:
		*indexamount=8;
		break;
	    }
	  }
	}
	else
	{ *toffs=((dword *)(&data[1]))[0];
	  *indexreg2=(byte)(data[0]&0x07);
	}
      }
      else // 16bit mode
      { *toffs=((word *)(&data[1]))[0];
	*indexreg=(byte)(data[0]&0x07); // NB double index reg eg bx+si
      }
      break;
  case 3:
      // case 3 - no jump table offset present. indirect jump.
      return false;
 }
 return true;
}

/************************************************************************
* disjumptable								*
* - this was written some ago as a quick hack for decoding jump tables	*
* - it tries to obtain information on the table itself, and looks for	*
*   an indication of the number of items in the table by examining	*
*   prior instructions, although it is quite unintelligent in some	*
*   ways.								*
* - it also looks for indextables which are used in complex jumptables	*
*   to decode an initial case number for the jumptable.			*
* - although good for some compilers the output from some modern	*
*   compilers does not fare well in the analysis.			*
************************************************************************/
void disasm::disjumptable(lptr loc) {
 dsmitem *investigate;
 dsegitem *dblock,*idblock;
 byte *data;
 byte pbyte;	    // prefix byte
 lptr t,it,index,xr;
 int numjumps,inumjumps;
 int i;
 byte indexreg,indexamount,indexreg2;
 byte iindexreg,iindexamount,iindexreg2;
 char *tablename,tablenum[10];
 bool itable;
 pbyte=0;
 numjumps=0;
 indexreg=0;
 indexreg2=0;
 indexamount=0;
 inumjumps=0;
 iindexreg=0;
 iindexreg2=0;
 iindexamount=0;
 investigate=dsmfindaddrtype(loc,dsmcode);
 if (!investigate) return;
  // check that inst is still there/ correct type of jump
  // adjust for any segment overrides added since
  if((loc-investigate->addr)<4)
    loc.offs=investigate->addr.offs;
  if((investigate->addr!=loc)||(investigate->type!=dsmcode))
    return;
  if(DSMITEM_ARG1(investigate)!=ARG_MODRM)
    return;
  if(!(investigate->flags&(FLAGS_JMP|FLAGS_CALL|FLAGS_CJMP)))
    return;
  data=investigate->data+investigate->modrm;
  if(!interpretmod(data,&t.offs,&indexreg,&indexreg2,&indexamount,&numjumps))
    return;
  // find target - jump table, need to use default ds:/ check for cs: override
  if(investigate->flags&FLAGS_SEGPREFIX)
  { pbyte=investigate->data[0];
    if((pbyte==0x66)||(pbyte==0x67))
      pbyte=investigate->data[1];
    if((pbyte==0x66)||(pbyte==0x67))
      pbyte=investigate->data[2];
  }
  t.segm=options.dseg;
  if(pbyte==0x2e)t.segm=loc.segm;
  dblock=dta->findseg(t);      // find segment item.
 if (!dblock) return;
  // look at previous instructions for number of entries
  itable=false;
  if(!numjumps)
  { for(i=0;i<10;i++)
    { investigate=(dsmitem *)lastiterator();
      if(investigate==NULL)
	break;					    // no previous insts
      if((investigate->addr.segm!=loc.segm)||(investigate->addr.offs+50<loc.offs))
	break; // too far back
      if(investigate->type!=dsmcode)
	i--;				   // skip non-code
      else
      if(((!lstrcmp(DSMITEM_NAME(investigate),"mov"))
	||(!lstrcmp(DSMITEM_NAME(investigate),"movzx")))
	&&((DSMITEM_ARG1(investigate)==ARG_MODRM)
	||(DSMITEM_ARG1(investigate)==ARG_MODRM8)))
      { if(!itable)
	  if(interpretmod(investigate->data+investigate->modrm,&it.offs,&iindexreg,&iindexreg2,&iindexamount,&inumjumps))
	  { itable=true;
	    index.offs=investigate->addr.offs;
	  }
      }
      else
      if(((!lstrcmp(DSMITEM_NAME(investigate),"mov"))
	||(!lstrcmp(DSMITEM_NAME(investigate),"movzx")))
	&&((DSMITEM_ARG2(investigate)==ARG_MODRM)
	||(DSMITEM_ARG2(investigate)==ARG_MODRM8)))
      { if(!itable)
	  if(interpretmod(investigate->data+investigate->modrm,&it.offs,&iindexreg,&iindexreg2,&iindexamount,&inumjumps))
	  { itable=true;
	    index.offs=investigate->addr.offs;
	  }
      }
      else
      if(investigate->data[0]==0x3b)	// cmp inst
      { if(options.mode32)
	  numjumps=((dword *)(&investigate->data[1]))[0]+1;
	else
	  numjumps=((word *)(&investigate->data[1]))[0]+1;
	break;
      }
      else
      if(investigate->data[0]==0x3d)	// cmp inst
      { if(options.mode32)
	  numjumps=((dword *)(&investigate->data[1]))[0]+1;
	else
	  numjumps=((word *)(&investigate->data[1]))[0]+1;
	break;
      }
      else
      if((investigate->data[0]==0x83)&&(investigate->data[1]>=0xc0)) // cmp reg,imm8
      { numjumps=investigate->data[2]+1;
	break;
      }
    }
  }
  if(itable)
  { it.segm=t.segm;
    idblock=dta->findseg(it);
    if(idblock==NULL)
      return;
    inumjumps=numjumps;
    if((inumjumps<2)||(inumjumps>0x100))
      return;
    numjumps=0;
    for(i=0;i<inumjumps;i++)
    { if(it+i>dblock->addr+dblock->size)
	return;
      if((dblock->data+(it-dblock->addr)+i)[0]>numjumps)
	numjumps=(dblock->data+(it-dblock->addr)+i)[0];
    }
    numjumps++;
  }
  // add code disassemblies to scheduler
  // name it
  if((!numjumps)||(numjumps>0x100))
    return;
  tablename=new char[20];
  if(numjumps>1)
  { jtables++;
    wsprintf(tablenum,"%d",jtables);
    lstrcpy(tablename,"jumptable_");
  }
  else
  { irefs++;
    wsprintf(tablenum,"%d",irefs);
    lstrcpy(tablename,"indirectref_");
  }
  lstrcat(tablename,tablenum);
  // imports and exports added to this list - build 17
  if (!name->isname(t) && !expt->isname(t) && !import->isname(t))
    scheduler.addtask(namecurloc,priority_nameloc,t,tablename);
  xrefs->addxref(t,loc);
  if(itable)
  { tablename=new char[20];
    itables++;
    wsprintf(tablenum,"%d",itables);
    lstrcpy(tablename,"indextable_");
    lstrcat(tablename,tablenum);
    if(!name->isname(it))
      scheduler.addtask(namecurloc,priority_nameloc,it,tablename);
    index.segm=loc.segm;
    xrefs->addxref(it,index);
  }
  // disassemble data
  // disassemble code
  if(!indexamount)
    if(options.mode32)
      indexamount=4;
    else
      indexamount=2;
  for(i=0;i<numjumps;i++)
  { if(t+i*indexamount>dblock->addr+dblock->size)
      return;
    if(options.mode32)
    { xr.assign(loc.segm,((dword *)(dblock->data+(t-dblock->addr)+i*indexamount))[0]);
      scheduler.addtask(dis_datadsoffword,priority_data,t+i*indexamount,NULL);
      scheduler.addtask(dis_code,priority_definitecode,xr,NULL);
      xrefs->addxref(xr,t+i*indexamount);
    }
    else
    { xr.assign(loc.segm,((word *)(dblock->data+(t-dblock->addr)+i*indexamount))[0]);
      scheduler.addtask(dis_dataword,priority_data,t+i*indexamount,NULL);
      scheduler.addtask(dis_code,priority_definitecode,xr,NULL);
      xrefs->addxref(xr,t+i*indexamount);
    }
  }
}

/************************************************************************
* disxref								*
* - this puts an xref line into the disassembly database for a given	*
*   loc, but only if one is not already present.			*
* - rewritten Borg 2.22 so that new is only called when necessary	*
************************************************************************/
void disasm::disxref(lptr loc)
{ dsmitem *newdsm,*chk;
  char *locname;
  chk=dsmfindaddrtype(loc,dsmxref);
  if(chk!=NULL)
  { if((chk->type==dsmxref)&&(chk->addr==loc))
      return;
    if((chk->length)&&(chk->addr.segm==loc.segm)&&(dsmitem_contains_loc(chk,loc)))
      return;
  }
  newdsm=new_dsm(loc,dsmxref);
  newdsm->tptr=NULL;
  newdsm->length=0;
  newdsm->data=NULL;
  addto(newdsm);
  if (! (expt->isname(loc) || import->isname(loc) || name->isname(loc)))
  { locname=new char[20];
    sprintf(locname,"loc_%08x",loc.offs);
    scheduler.addtask(namecurloc,priority_nameloc,loc,locname);
  }
  cvd->updatewindowifinrange(loc);
}

/************************************************************************
* getlength								*
* - an external interface routine which just returns the given		*
*   locations disassembled code length. It is used by the search engine *
* - default return value of 1 means 'db'				*
************************************************************************/
int disasm::getlength(lptr loc) {
 dsmitem *fnd;
 fnd=dsmfindaddrtype(loc,dsmcode);
 if (!fnd || fnd->addr!=loc || fnd->type!=dsmcode)  return 1;
 return fnd->length;
}


Detected encoding: ASCII (7 bit)2