12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214 |
- /****************************************************************************
- * dcc project procedure list builder
- * (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
- ****************************************************************************/
- #include <string.h>
- #include <stdlib.h> /* For exit() */
- #include <sstream>
- #include <stdio.h>
- #include <algorithm>
- #include "dcc.h"
- using namespace std;
- static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
- static boolT process_JMP (ICODE * pIcode, STATE * pstate,
- CALL_GRAPH * pcallGraph);
- static boolT process_CALL(ICODE * pIcode, CALL_GRAPH * pcallGraph,
- STATE * pstate);
- static void process_operands(ICODE * pIcode, Function * pProc, STATE * pstate,
- Int ix);
- static void setBits(int16 type, dword start, dword len);
- static SYM * updateGlobSym(dword operand, Int size, word duFlag);
- static void process_MOV(ICODE * pIcode, STATE * pstate);
- static SYM * lookupAddr (LLOperand *pm, STATE * pstate, Int size, word duFlag);
- void interactDis(Function * initProc, Int ic);
- static dword SynthLab;
- /* Parses the program, builds the call graph, and returns the list of
- * procedures found */
- void parse (CALL_GRAPH * *pcallGraph)
- {
- STATE state;
- /* Set initial state */
- memset(&state, 0, sizeof(STATE));
- state.setState(rES, 0); /* PSP segment */
- state.setState(rDS, 0);
- state.setState(rCS, prog.initCS);
- state.setState(rSS, prog.initSS);
- state.setState(rSP, prog.initSP);
- state.IP = ((dword)prog.initCS << 4) + prog.initIP;
- SynthLab = SYNTHESIZED_MIN;
- // default-construct a Function object !
- pProcList.push_back(Function::Create());
- /* Check for special settings of initial state, based on idioms of the
- startup code */
- state.checkStartup();
- Function &start_proc(pProcList.front());
- /* Make a struct for the initial procedure */
- if (prog.offMain != -1)
- {
- /* We know where main() is. Start the flow of control from there */
- start_proc.procEntry = prog.offMain;
- /* In medium and large models, the segment of main may (will?) not be
- the same as the initial CS segment (of the startup code) */
- state.setState(rCS, prog.segMain);
- start_proc.name = "main";
- state.IP = prog.offMain;
- }
- else
- {
- /* Create initial procedure at program start address */
- start_proc.name="start";
- start_proc.procEntry = (dword)state.IP;
- }
- /* The state info is for the first procedure */
- start_proc.state = state;
- /* Set up call graph initial node */
- *pcallGraph = new CALL_GRAPH;
- (*pcallGraph)->proc = pProcList.begin();
- /* This proc needs to be called to set things up for LibCheck(), which
- checks a proc to see if it is a know C (etc) library */
- SetupLibCheck();
- /* Recursively build entire procedure list */
- pProcList.front().FollowCtrl (*pcallGraph, &state);
- /* This proc needs to be called to clean things up from SetupLibCheck() */
- CleanupLibCheck();
- }
- /* Updates the type of the symbol in the symbol table. The size is updated
- * if necessary (0 means no update necessary). */
- static void updateSymType (dword symbol, hlType symType, Int size)
- { Int i;
- for (i = 0; i < symtab.size(); i++)
- if (symtab[i].label == symbol)
- {
- symtab[i].type = symType;
- if (size != 0)
- symtab[i].size = size;
- break;
- }
- }
- /* Returns the size of the string pointed by sym and delimited by delim.
- * Size includes delimiter. */
- Int strSize (byte *sym, char delim)
- {
- Int i;
- for (i = 0; *sym++ != delim; i++)
- ;
- return (i+1);
- }
- Function *fakeproc=Function::Create(0,0,"fake");
- /* FollowCtrl - Given an initial procedure, state information and symbol table
- * builds a list of procedures reachable from the initial procedure
- * using a depth first search. */
- void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
- {
- ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
- ICODE eIcode; /* extra icodes for iDIV, iIDIV, iXCHG */
- SYM * psym;
- dword offset;
- eErrorId err;
- boolT done = FALSE;
- dword lab;
- if (name.find("chkstk") != string::npos)
- {
- // Danger! Dcc will likely fall over in this code.
- // So we act as though we have done with this proc
- // pProc->flg &= ~TERMINATES; // Not sure about this
- done = TRUE;
- // And mark it as a library function, so structure() won't choke on it
- flg |= PROC_ISLIB;
- return;
- }
- if (option.VeryVerbose)
- {
- printf("Parsing proc %s at %lX\n", name.c_str(), pstate->IP);
- }
- while (! done && ! (err = scan(pstate->IP, &_Icode)))
- {
- pstate->IP += (dword)_Icode.ic.ll.numBytes;
- setBits(BM_CODE, _Icode.ic.ll.label, (dword)_Icode.ic.ll.numBytes);
- process_operands(&_Icode,pstate);
- /* Keep track of interesting instruction flags in procedure */
- flg |= (_Icode.ic.ll.flg & (NOT_HLL | FLOAT_OP));
- /* Check if this instruction has already been parsed */
- if (Icode.labelSrch(_Icode.ic.ll.label, lab))
- { /* Synthetic jump */
- _Icode.type = LOW_LEVEL;
- _Icode.ic.ll.opcode = iJMP;
- _Icode.ic.ll.flg = I | SYNTHETIC | NO_OPS;
- _Icode.ic.ll.src.SetImmediateOp(Icode[lab].GetLlLabel());
- _Icode.ic.ll.label = SynthLab++;
- }
- /* Copy Icode to Proc */
- if ((_Icode.ic.ll.opcode == iDIV) || (_Icode.ic.ll.opcode == iIDIV))
- {
- /* MOV rTMP, reg */
- memset (&eIcode, 0, sizeof (ICODE));
- eIcode.type = LOW_LEVEL;
- eIcode.ic.ll.opcode = iMOV;
- eIcode.ic.ll.dst.regi = rTMP;
- if (_Icode.ic.ll.flg & B)
- {
- eIcode.ic.ll.flg |= B;
- eIcode.ic.ll.src.regi = rAX;
- eIcode.setRegDU( rAX, eUSE);
- }
- else /* implicit dx:ax */
- {
- eIcode.ic.ll.flg |= IM_SRC;
- eIcode.setRegDU( rAX, eUSE);
- eIcode.setRegDU( rDX, eUSE);
- }
- eIcode.setRegDU( rTMP, eDEF);
- eIcode.ic.ll.flg |= SYNTHETIC;
- /* eIcode.ic.ll.label = SynthLab++; */
- eIcode.ic.ll.label = _Icode.ic.ll.label;
- Icode.addIcode(&eIcode);
- /* iDIV, iIDIV */
- Icode.addIcode(&_Icode);
- /* iMOD */
- memset (&eIcode, 0, sizeof (ICODE));
- eIcode.type = LOW_LEVEL;
- eIcode.ic.ll.opcode = iMOD;
- eIcode.ic.ll.src = _Icode.ic.ll.src;
- eIcode.du = _Icode.du;
- eIcode.ic.ll.flg = (_Icode.ic.ll.flg | SYNTHETIC);
- eIcode.ic.ll.label = SynthLab++;
- pIcode = Icode.addIcode(&eIcode);
- }
- else if (_Icode.ic.ll.opcode == iXCHG)
- {
- /* MOV rTMP, regDst */
- memset (&eIcode, 0, sizeof (ICODE));
- eIcode.type = LOW_LEVEL;
- eIcode.ic.ll.opcode = iMOV;
- eIcode.ic.ll.dst.regi = rTMP;
- eIcode.ic.ll.src.regi = _Icode.ic.ll.dst.regi;
- eIcode.setRegDU( rTMP, eDEF);
- eIcode.setRegDU( eIcode.ic.ll.src.regi, eUSE);
- eIcode.ic.ll.flg |= SYNTHETIC;
- /* eIcode.ic.ll.label = SynthLab++; */
- eIcode.ic.ll.label = _Icode.ic.ll.label;
- Icode.addIcode(&eIcode);
- /* MOV regDst, regSrc */
- _Icode.ic.ll.opcode = iMOV;
- _Icode.ic.ll.flg |= SYNTHETIC;
- /* Icode.ic.ll.label = SynthLab++; */
- Icode.addIcode(&_Icode);
- _Icode.ic.ll.opcode = iXCHG; /* for next case */
- /* MOV regSrc, rTMP */
- memset (&eIcode, 0, sizeof (ICODE));
- eIcode.type = LOW_LEVEL;
- eIcode.ic.ll.opcode = iMOV;
- eIcode.ic.ll.dst.regi = _Icode.ic.ll.src.regi;
- eIcode.ic.ll.src.regi = rTMP;
- eIcode.setRegDU( eIcode.ic.ll.dst.regi, eDEF);
- eIcode.setRegDU( rTMP, eUSE);
- eIcode.ic.ll.flg |= SYNTHETIC;
- eIcode.ic.ll.label = SynthLab++;
- pIcode = Icode.addIcode(&eIcode);
- }
- else
- pIcode = Icode.addIcode(&_Icode);
- switch (_Icode.ic.ll.opcode) {
- /*** Conditional jumps ***/
- case iLOOP: case iLOOPE: case iLOOPNE:
- case iJB: case iJBE: case iJAE: case iJA:
- case iJL: case iJLE: case iJGE: case iJG:
- case iJE: case iJNE: case iJS: case iJNS:
- case iJO: case iJNO: case iJP: case iJNP:
- case iJCXZ:
- { STATE StCopy;
- int ip = Icode.size()-1; /* Index of this jump */
- ICODE &prev(Icode.back()); /* Previous icode */
- boolT fBranch = FALSE;
- pstate->JCond.regi = 0;
- /* This sets up range check for indexed JMPs hopefully
- * Handles JA/JAE for fall through and JB/JBE on branch
- */
- if (ip > 0 && prev.ic.ll.opcode == iCMP && (prev.ic.ll.flg & I))
- {
- pstate->JCond.immed = (int16)prev.ic.ll.src.op();
- if (_Icode.ic.ll.opcode == iJA || _Icode.ic.ll.opcode == iJBE)
- pstate->JCond.immed++;
- if (_Icode.ic.ll.opcode == iJAE || _Icode.ic.ll.opcode == iJA)
- pstate->JCond.regi = prev.ic.ll.dst.regi;
- fBranch = (boolT)
- (_Icode.ic.ll.opcode == iJB || _Icode.ic.ll.opcode == iJBE);
- }
- StCopy = *pstate;
- //memcpy(&StCopy, pstate, sizeof(STATE));
- /* Straight line code */
- this->FollowCtrl (pcallGraph, &StCopy); // recurrent ?
- if (fBranch) /* Do branching code */
- {
- pstate->JCond.regi = prev.ic.ll.dst.regi;
- }
- /* Next icode. Note: not the same as GetLastIcode() because of the call
- to FollowCtrl() */
- pIcode = Icode.GetIcode(ip);
- } /* Fall through to do the jump path */
- /*** Jumps ***/
- case iJMP:
- case iJMPF: /* Returns TRUE if we've run into a loop */
- done = process_JMP (pIcode, pstate, pcallGraph);
- break;
- /*** Calls ***/
- case iCALL:
- case iCALLF:
- done = process_CALL (pIcode, pcallGraph, pstate);
- break;
- /*** Returns ***/
- case iRET:
- case iRETF:
- this->flg |= (_Icode.ic.ll.opcode == iRET)? PROC_NEAR:PROC_FAR;
- /* Fall through */
- case iIRET:
- this->flg &= ~TERMINATES;
- done = TRUE;
- break;
- case iINT:
- if (_Icode.ic.ll.src.op() == 0x21 && pstate->f[rAH])
- {
- Int funcNum = pstate->r[rAH];
- Int operand;
- Int size;
- /* Save function number */
- Icode.back().ic.ll.dst.off = (int16)funcNum;
- //Icode.GetIcode(Icode.GetNumIcodes() - 1)->
- /* Program termination: int21h, fn 00h, 31h, 4Ch */
- done = (boolT)(funcNum == 0x00 || funcNum == 0x31 ||
- funcNum == 0x4C);
- /* String functions: int21h, fn 09h */
- if (pstate->f[rDX]) /* offset goes into DX */
- if (funcNum == 0x09)
- {
- operand = ((dword)(word)pstate->r[rDS]<<4) +
- (dword)(word)pstate->r[rDX];
- size = prog.fCOM ?
- strSize (&prog.Image[operand], '$') :
- strSize (&prog.Image[operand + 0x100], '$');
- updateSymType (operand, TYPE_STR, size);
- }
- }
- else if ((_Icode.ic.ll.src.op() == 0x2F) && (pstate->f[rAH]))
- {
- Icode.back().ic.ll.dst.off = pstate->r[rAH];
- }
- else /* Program termination: int20h, int27h */
- done = (boolT)(_Icode.ic.ll.src.op() == 0x20 ||
- _Icode.ic.ll.src.op() == 0x27);
- if (done)
- pIcode->ic.ll.flg |= TERMINATES;
- break;
- case iMOV:
- process_MOV(pIcode, pstate);
- break;
- /* case iXCHG:
- process_MOV (pIcode, pstate);
- break; **** HERE ***/
- case iSHL:
- if (pstate->JCond.regi == _Icode.ic.ll.dst.regi)
- if ((_Icode.ic.ll.flg & I) && _Icode.ic.ll.src.op() == 1)
- pstate->JCond.immed *= 2;
- else
- pstate->JCond.regi = 0;
- break;
- case iLEA:
- if (_Icode.ic.ll.src.regi == 0) /* direct mem offset */
- pstate->setState( _Icode.ic.ll.dst.regi, _Icode.ic.ll.src.off);
- break;
- case iLDS: case iLES:
- if ((psym = lookupAddr(&_Icode.ic.ll.src, pstate, 4, eDuVal::USE))
- /* && (Icode.ic.ll.flg & SEG_IMMED) */ ) {
- offset = LH(&prog.Image[psym->label]);
- pstate->setState( (_Icode.ic.ll.opcode == iLDS)? rDS: rES,
- LH(&prog.Image[psym->label + 2]));
- pstate->setState( _Icode.ic.ll.dst.regi, (int16)offset);
- psym->type = TYPE_PTR;
- }
- break;
- }
- }
- if (err) {
- this->flg &= ~TERMINATES;
- if (err == INVALID_386OP || err == INVALID_OPCODE)
- {
- fatalError(err, prog.Image[_Icode.ic.ll.label], _Icode.ic.ll.label);
- this->flg |= PROC_BADINST;
- }
- else if (err == IP_OUT_OF_RANGE)
- fatalError (err, _Icode.ic.ll.label);
- else
- reportError(err, _Icode.ic.ll.label);
- }
- }
- /* process_JMP - Handles JMPs, returns TRUE if we should end recursion */
- boolT Function::process_JMP (ICODE * pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
- {
- static byte i2r[4] = {rSI, rDI, rBP, rBX};
- ICODE _Icode;
- dword cs, offTable, endTable;
- dword i, k, seg, target;
- dword tmp;
- if (pIcode->ic.ll.flg & I)
- {
- if (pIcode->ic.ll.opcode == iJMPF)
- pstate->setState( rCS, LH(prog.Image + pIcode->ic.ll.label + 3));
- i = pstate->IP = pIcode->ic.ll.src.op();
- if ((long)i < 0)
- {
- exit(1);
- }
- /* Return TRUE if jump target is already parsed */
- return Icode.labelSrch(i, tmp);
- }
- /* We've got an indirect JMP - look for switch() stmt. idiom of the form
- * JMP word ptr word_offset[rBX | rSI | rDI] */
- seg = (pIcode->ic.ll.src.seg)? pIcode->ic.ll.src.seg: rDS;
- /* Ensure we have a word offset & valid seg */
- if (pIcode->ic.ll.opcode == iJMP && (pIcode->ic.ll.flg & WORD_OFF) &&
- pstate->f[seg] &&
- (pIcode->ic.ll.src.regi == INDEXBASE + 4 ||
- pIcode->ic.ll.src.regi == INDEXBASE + 5 || /* Idx reg. BX, SI, DI */
- pIcode->ic.ll.src.regi == INDEXBASE + 7))
- {
- offTable = ((dword)(word)pstate->r[seg] << 4) + pIcode->ic.ll.src.off;
- /* Firstly look for a leading range check of the form:-
- * CMP {BX | SI | DI}, immed
- * JA | JAE | JB | JBE
- * This is stored in the current state as if we had just
- * followed a JBE branch (i.e. [reg] lies between 0 - immed).
- */
- if (pstate->JCond.regi == i2r[pIcode->ic.ll.src.regi-(INDEXBASE+4)])
- endTable = offTable + pstate->JCond.immed;
- else
- endTable = (dword)prog.cbImage;
- /* Search for first byte flagged after start of table */
- for (i = offTable; i <= endTable; i++)
- if (BITMAP(i, BM_CODE | BM_DATA))
- break;
- endTable = i & ~1; /* Max. possible table size */
- /* Now do some heuristic pruning. Look for ptrs. into the table
- * and for addresses that don't appear to point to valid code.
- */
- cs = (dword)(word)pstate->r[rCS] << 4;
- for (i = offTable; i < endTable; i += 2)
- {
- target = cs + LH(&prog.Image[i]);
- if (target < endTable && target >= offTable)
- endTable = target;
- else if (target >= (dword)prog.cbImage)
- endTable = i;
- }
- for (i = offTable; i < endTable; i += 2)
- {
- target = cs + LH(&prog.Image[i]);
- /* Be wary of 00 00 as code - it's probably data */
- if (! (prog.Image[target] || prog.Image[target+1]) ||
- scan(target, &_Icode))
- endTable = i;
- }
- /* Now for each entry in the table take a copy of the current
- * state and recursively call FollowCtrl(). */
- if (offTable < endTable)
- {
- STATE StCopy;
- Int ip;
- dword *psw;
- setBits(BM_DATA, offTable, endTable - offTable);
- pIcode->ic.ll.flg |= SWITCH;
- pIcode->ic.ll.caseTbl.numEntries = (endTable - offTable) / 2;
- psw = (dword*)allocMem(pIcode->ic.ll.caseTbl.numEntries*sizeof(dword));
- pIcode->ic.ll.caseTbl.entries = psw;
- for (i = offTable, k = 0; i < endTable; i += 2)
- {
- memcpy(&StCopy, pstate, sizeof(STATE));
- StCopy.IP = cs + LH(&prog.Image[i]);
- ip = Icode.size();
- FollowCtrl (pcallGraph, &StCopy);
- Icode.GetIcode(ip)->ic.ll.caseTbl.numEntries = k++;
- Icode.GetIcode(ip)->ic.ll.flg |= CASE;
- *psw++ = Icode[ip].GetLlLabel();
- }
- return TRUE;
- }
- }
- /* Can't do anything with this jump */
- flg |= PROC_IJMP;
- flg &= ~TERMINATES;
- interactDis(this, this->Icode.size()-1);
- return TRUE;
- }
- /* Process procedure call.
- * Note: We assume that CALL's will return unless there is good evidence to
- * the contrary - thus we return FALSE unless all paths in the called
- * procedure end in DOS exits. This is reasonable since C procedures
- * will always include the epilogue after the call anyway and it's to
- * be assumed that if an assembler program contains a CALL that the
- * programmer expected it to come back - otherwise surely a JMP would
- * have been used. */
- boolT Function::process_CALL (ICODE * pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
- {
- Int ip = Icode.size() - 1;
- STATE localState; /* Local copy of the machine state */
- dword off;
- boolT indirect;
- /* For Indirect Calls, find the function address */
- indirect = FALSE;
- //pIcode->ic.ll.immed.proc.proc=fakeproc;
- if ( not pIcode->isLlFlag(I) )
- {
- /* Not immediate, i.e. indirect call */
- if (pIcode->ic.ll.dst.regi && (!option.Calls))
- {
- /* We have not set the brave option to attempt to follow
- the execution path through register indirect calls.
- So we just exit this function, and ignore the call.
- We probably should not have parsed this deep, anyway.
- */
- return FALSE;
- }
- /* Offset into program image is seg:off of read input */
- /* Note: this assumes that the pointer itself is at
- es:0 where es:0 is the start of the image. This is
- usually wrong! Consider also CALL [BP+0E] in which the
- segment for the pointer is in SS! - Mike */
- off = (dword)(word)pIcode->ic.ll.dst.off +
- ((dword)(word)pIcode->ic.ll.dst.segValue << 4);
- /* Address of function is given by 4 (CALLF) or 2 (CALL) bytes at
- * previous offset into the program image */
- dword tgtAddr=0;
- if (pIcode->ic.ll.opcode == iCALLF)
- tgtAddr= LH(&prog.Image[off]) + (dword)(LH(&prog.Image[off+2])) << 4;
- else
- tgtAddr= LH(&prog.Image[off]) + (dword)(word)state.r[rCS] << 4;
- pIcode->ic.ll.src.SetImmediateOp( tgtAddr );
- pIcode->ic.ll.flg |= I;
- indirect = TRUE;
- }
- /* Process CALL. Function address is located in pIcode->ic.ll.immed.op */
- if (pIcode->ic.ll.flg & I)
- {
- /* Search procedure list for one with appropriate entry point */
- ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
- [pIcode](const Function &f) ->
- bool { return f.procEntry==pIcode->ic.ll.src.op(); });
- /* Create a new procedure node and save copy of the state */
- if (iter==pProcList.end())
- {
- pProcList.push_back(Function::Create());
- Function &x(pProcList.back());
- iter = (++pProcList.rbegin()).base();
- x.procEntry = pIcode->ic.ll.src.op();
- LibCheck(x);
- if (x.flg & PROC_ISLIB)
- {
- /* A library function. No need to do any more to it */
- pcallGraph->insertCallGraph (this, iter);
- iter = (++pProcList.rbegin()).base();
- Icode.GetIcode(ip)->ic.ll.src.proc.proc = &x;
- return false;
- }
- if (indirect)
- x.flg |= PROC_ICALL;
- if (x.name.empty()) /* Don't overwrite existing name */
- {
- ostringstream os;
- os<<"proc_"<< ++prog.cProcs;
- x.name = os.str();
- }
- x.depth = x.depth + 1;
- x.flg |= TERMINATES;
- /* Save machine state in localState, load up IP and CS.*/
- localState = *pstate;
- pstate->IP = pIcode->ic.ll.src.op();
- if (pIcode->ic.ll.opcode == iCALLF)
- pstate->setState( rCS, LH(prog.Image + pIcode->ic.ll.label + 3));
- x.state = *pstate;
- /* Insert new procedure in call graph */
- pcallGraph->insertCallGraph (this, iter);
- /* Process new procedure */
- x.FollowCtrl (pcallGraph, pstate);
- /* Restore segment registers & IP from localState */
- pstate->IP = localState.IP;
- pstate->setState( rCS, localState.r[rCS]);
- pstate->setState( rDS, localState.r[rDS]);
- pstate->setState( rES, localState.r[rES]);
- pstate->setState( rSS, localState.r[rSS]);
- }
- else
- pcallGraph->insertCallGraph (this, iter);
- Icode[ip].ic.ll.src.proc.proc = &(*iter); // ^ target proc
- /* return ((p->flg & TERMINATES) != 0); */
- return FALSE;
- }
- return FALSE; // Cristina, please check!!
- }
- /* process_MOV - Handles state changes due to simple assignments */
- static void process_MOV(ICODE * pIcode, STATE * pstate)
- {
- SYM * psym, *psym2; /* Pointer to symbol in global symbol table */
- byte dstReg = pIcode->ic.ll.dst.regi;
- byte srcReg = pIcode->ic.ll.src.regi;
- if (dstReg > 0 && dstReg < INDEXBASE)
- {
- if (pIcode->ic.ll.flg & I)
- pstate->setState( dstReg, (int16)pIcode->ic.ll.src.op());
- else if (srcReg == 0) /* direct memory offset */
- {
- psym = lookupAddr(&pIcode->ic.ll.src, pstate, 2, eDuVal::USE);
- if (psym && ((psym->flg & SEG_IMMED) || psym->duVal.val))
- pstate->setState( dstReg, LH(&prog.Image[psym->label]));
- }
- else if (srcReg < INDEXBASE && pstate->f[srcReg]) /* reg */
- {
- pstate->setState( dstReg, pstate->r[srcReg]);
- /* Follow moves of the possible index register */
- if (pstate->JCond.regi == srcReg)
- pstate->JCond.regi = dstReg;
- }
- }
- else if (dstReg == 0) { /* direct memory offset */
- psym = lookupAddr (&pIcode->ic.ll.dst, pstate, 2, eDEF);
- if (psym && ! (psym->duVal.val)) /* no initial value yet */
- if (pIcode->ic.ll.flg & I) { /* immediate */
- prog.Image[psym->label] = (byte)pIcode->ic.ll.src.op();
- prog.Image[psym->label+1] = (byte)(pIcode->ic.ll.src.op()>>8);
- psym->duVal.val = 1;
- }
- else if (srcReg == 0) { /* direct mem offset */
- psym2 = lookupAddr (&pIcode->ic.ll.src, pstate, 2, eDuVal::USE);
- if (psym2 && ((psym->flg & SEG_IMMED) || (psym->duVal.val)))
- {
- prog.Image[psym->label] = (byte)prog.Image[psym2->label];
- prog.Image[psym->label+1] =
- (byte)(prog.Image[psym2->label+1] >> 8);
- psym->duVal.val=1;
- }
- }
- else if (srcReg < INDEXBASE && pstate->f[srcReg]) /* reg */
- {
- prog.Image[psym->label] = (byte)pstate->r[srcReg];
- prog.Image[psym->label+1] = (byte)(pstate->r[srcReg] >> 8);
- psym->duVal.val;
- }
- }
- }
- /* Type of the symbol according to the number of bytes it uses */
- static hlType cbType[] = {TYPE_UNKNOWN, TYPE_BYTE_UNSIGN, TYPE_WORD_SIGN,
- TYPE_UNKNOWN, TYPE_LONG_SIGN};
- /* Creates an entry in the global symbol table (symtab) if the variable
- * is not there yet. If it is part of the symtab, the size of the variable
- * is checked and updated if the old size was less than the new size (ie.
- * the maximum size is always saved). */
- static SYM * updateGlobSym (dword operand, Int size, word duFlag)
- {
- Int i;
- /* Check for symbol in symbol table */
- for (i = 0; i < symtab.size(); i++)
- if (symtab[i].label == operand)
- {
- if (symtab[i].size < size)
- symtab[i].size = size;
- break;
- }
- /* New symbol, not in symbol table */
- if (i == symtab.size())
- {
- SYM v;
- sprintf (v.name, "var%05lX", operand);
- v.label = operand;
- v.size = size;
- v.type = cbType[size];
- if (duFlag == eDuVal::USE) /* must already have init value */
- {
- v.duVal.use =1; // USEVAL;
- v.duVal.val =1;
- }
- else
- {
- v.duVal.setFlags(duFlag);
- }
- symtab.push_back(v);
- }
- return (&symtab[i]);
- }
- /* Updates the offset entry to the stack frame table (arguments),
- * and returns a pointer to such entry. */
- static void updateFrameOff (STKFRAME * ps, int16 off, Int size, word duFlag)
- {
- Int i;
- /* Check for symbol in stack frame table */
- for (i = 0; i < ps->sym.size(); i++)
- {
- if (ps->sym[i].off == off)
- {
- if (ps->sym[i].size < size)
- {
- ps->sym[i].size = size;
- }
- break;
- }
- }
- /* New symbol, not in table */
- if (i == ps->sym.size())
- {
- STKSYM new_sym;
- sprintf (new_sym.name, "arg%ld", i);
- new_sym.off = off;
- new_sym.size = size;
- new_sym.type = cbType[size];
- if (duFlag == eDuVal::USE) /* must already have init value */
- {
- new_sym.duVal.use=1;
- //new_sym.duVal.val=1;
- }
- else
- {
- new_sym.duVal.setFlags(duFlag);
- }
- ps->sym.push_back(new_sym);
- ps->numArgs++;
- }
- /* Save maximum argument offset */
- if ((dword)ps->maxOff < (off + (dword)size))
- ps->maxOff = off + (int16)size;
- }
- /* lookupAddr - Looks up a data reference in the symbol table and stores it
- * if necessary.
- * Returns a pointer to the symbol in the
- * symbol table, or Null if it's not a direct memory offset. */
- static SYM * lookupAddr (LLOperand *pm, STATE *pstate, Int size, word duFlag)
- {
- Int i;
- SYM * psym;
- dword operand;
- if (pm->regi == 0) { /* Global var */
- if (pm->segValue) { /* there is a value in the seg field */
- operand = opAdr (pm->segValue, pm->off);
- psym = updateGlobSym (operand, size, duFlag);
- /* Check for out of bounds */
- if (psym->label >= (dword)prog.cbImage)
- return (NULL);
- return (psym);
- }
- else if (pstate->f[pm->seg]) { /* new value */
- pm->segValue = pstate->r[pm->seg];
- operand = opAdr(pm->segValue, pm->off);
- i = symtab.size();
- psym = updateGlobSym (operand, size, duFlag);
- /* Flag new memory locations that are segment values */
- if (symtab.size() > i)
- {
- if (size == 4)
- operand += 2; /* High word */
- for (i = 0; i < prog.cReloc; i++)
- if (prog.relocTable[i] == operand) {
- psym->flg = SEG_IMMED;
- break;
- }
- }
- /* Check for out of bounds */
- if (psym->label >= (dword)prog.cbImage)
- return (NULL);
- return (psym);
- }
- }
- return (NULL);
- }
- /* setState - Assigns a value to a reg. */
- void STATE::setState(word reg, int16 value)
- {
- value &= 0xFFFF;
- r[reg] = value;
- f[reg] = TRUE;
- switch (reg) {
- case rAX: case rCX: case rDX: case rBX:
- r[reg + rAL - rAX] = value & 0xFF;
- f[reg + rAL - rAX] = TRUE;
- r[reg + rAH - rAX] = (value >> 8) & 0xFF;
- f[reg + rAH - rAX] = TRUE;
- break;
- case rAL: case rCL: case rDL: case rBL:
- if (f[reg - rAL + rAH]) {
- r[reg - rAL + rAX] =(r[reg - rAL + rAH] << 8) + (value & 0xFF);
- f[reg - rAL + rAX] = TRUE;
- }
- break;
- case rAH: case rCH: case rDH: case rBH:
- if (f[reg - rAH + rAL])
- {
- r[reg - rAH + rAX] = r[reg - rAH + rAL] + ((value & 0xFF) << 8);
- f[reg - rAH + rAX] = TRUE;
- }
- break;
- }
- }
- /* labelSrchRepl - Searches Icode for instruction with label = target, and
- replaces *pIndex with an icode index */
- bool labelSrch(CIcodeRec &pIcode, Int numIp, dword target, Int *pIndex)
- {
- Int i;
- for (i = 0; i < numIp; i++)
- {
- if (pIcode[i].ic.ll.label == target)
- {
- *pIndex = i;
- return true;
- }
- }
- return false;
- }
- static void setBits(int16 type, dword start, dword len)
- /* setBits - Sets memory bitmap bits for BM_CODE or BM_DATA (additively) */
- {
- dword i;
- if (start < (dword)prog.cbImage)
- {
- if (start + len > (dword)prog.cbImage)
- len = (dword)(prog.cbImage - start);
- for (i = start + len - 1; i >= start; i--)
- {
- prog.map[i >> 2] |= type << ((i & 3) << 1);
- if (i == 0) break; // Fixes inf loop!
- }
- }
- }
- /* DU bit definitions for each reg value - including index registers */
- dword duReg[] = { 0x00,
- 0x11001, 0x22002, 0x44004, 0x88008, /* word regs */
- 0x10, 0x20, 0x40, 0x80,
- 0x100, 0x200, 0x400, 0x800, /* seg regs */
- 0x1000, 0x2000, 0x4000, 0x8000, /* byte regs */
- 0x10000, 0x20000, 0x40000, 0x80000,
- 0x100000, /* tmp reg */
- 0x48, 0x88, 0x60, 0xA0, /* index regs */
- 0x40, 0x80, 0x20, 0x08 };
- /* Checks which registers where used and updates the du.u flag.
- * Places local variables on the local symbol table.
- * Arguments: d : SRC or DST icode operand
- * pIcode: ptr to icode instruction
- * pProc : ptr to current procedure structure
- * pstate: ptr to current procedure state
- * size : size of the operand
- * ix : current index into icode array */
- static void use (opLoc d, ICODE * pIcode, Function * pProc, STATE * pstate, Int size, Int ix)
- {
- LLOperand * pm = (d == SRC)? &pIcode->ic.ll.src: &pIcode->ic.ll.dst;
- SYM * psym;
- if (pm->regi == 0 || pm->regi >= INDEXBASE)
- {
- if (pm->regi == INDEXBASE + 6) /* indexed on bp */
- {
- if (pm->off >= 2)
- updateFrameOff (&pProc->args, pm->off, size, eDuVal::USE);
- else if (pm->off < 0)
- pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
- }
- else if (pm->regi == INDEXBASE + 2 || pm->regi == INDEXBASE + 3)
- pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off,
- (byte)((pm->regi == INDEXBASE + 2) ? rSI : rDI));
- else if ((pm->regi >= INDEXBASE + 4) && (pm->regi <= INDEXBASE + 7))
- {
- if ((pm->seg == rDS) && (pm->regi == INDEXBASE + 7)) /* bx */
- {
- if (pm->off > 0) /* global indexed variable */
- pProc->localId.newIntIdx(pm->segValue, pm->off, rBX,ix, TYPE_WORD_SIGN);
- }
- pIcode->du.use |= duReg[pm->regi];
- }
- else if (psym = lookupAddr(pm, pstate, size, eDuVal::USE))
- {
- setBits (BM_DATA, psym->label, (dword)size);
- pIcode->ic.ll.flg |= SYM_USE;
- pIcode->ic.ll.caseTbl.numEntries = psym - &symtab[0];
- }
- }
- /* Use of register */
- else if ((d == DST) || ((d == SRC) && (pIcode->ic.ll.flg & I) != I))
- pIcode->du.use |= duReg[pm->regi];
- }
- /* Checks which registers were defined (ie. got a new value) and updates the
- * du.d flag.
- * Places local variables in the local symbol table. */
- static void def (opLoc d, ICODE * pIcode, Function * pProc, STATE * pstate, Int size,
- Int ix)
- {
- LLOperand *pm = (d == SRC)? &pIcode->ic.ll.src: &pIcode->ic.ll.dst;
- SYM * psym;
- if (pm->regi == 0 || pm->regi >= INDEXBASE)
- {
- if (pm->regi == INDEXBASE + 6) /* indexed on bp */
- {
- if (pm->off >= 2)
- updateFrameOff (&pProc->args, pm->off, size, eDEF);
- else if (pm->off < 0)
- pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
- }
- else if (pm->regi == INDEXBASE + 2 || pm->regi == INDEXBASE + 3)
- {
- pProc->localId.newByteWordStk(TYPE_WORD_SIGN, pm->off,
- (byte)((pm->regi == INDEXBASE + 2) ? rSI : rDI));
- }
- else if ((pm->regi >= INDEXBASE + 4) && (pm->regi <= INDEXBASE + 7))
- {
- if ((pm->seg == rDS) && (pm->regi == INDEXBASE + 7)) /* bx */
- {
- if (pm->off > 0) /* global var */
- pProc->localId.newIntIdx(pm->segValue, pm->off, rBX,ix, TYPE_WORD_SIGN);
- }
- pIcode->du.use |= duReg[pm->regi];
- }
- else if (psym = lookupAddr(pm, pstate, size, eDEF))
- {
- setBits(BM_DATA, psym->label, (dword)size);
- pIcode->ic.ll.flg |= SYM_DEF;
- pIcode->ic.ll.caseTbl.numEntries = psym - &symtab[0];
- }
- }
- /* Definition of register */
- else if ((d == DST) || ((d == SRC) && (pIcode->ic.ll.flg & I) != I))
- {
- pIcode->du.def |= duReg[pm->regi];
- pIcode->du1.numRegsDef++;
- }
- }
- /* use_def - operand is both use and def'd.
- * Note: the destination will always be a register, stack variable, or global
- * variable. */
- static void use_def(opLoc d, ICODE * pIcode, Function * pProc, STATE * pstate, Int cb,
- Int ix)
- {
- LLOperand * pm = (d == SRC)? &pIcode->ic.ll.src: &pIcode->ic.ll.dst;
- use (d, pIcode, pProc, pstate, cb, ix);
- if (pm->regi < INDEXBASE) /* register */
- {
- pIcode->du.def |= duReg[pm->regi];
- pIcode->du1.numRegsDef++;
- }
- }
- /* Set DU vector, local variables and arguments, and DATA bits in the
- * bitmap */
- void Function::process_operands(ICODE * pIcode, STATE * pstate)
- {
- Int ix=Icode.size();
- Int i;
- Int sseg = (pIcode->ic.ll.src.seg)? pIcode->ic.ll.src.seg: rDS;
- Int cb = (pIcode->ic.ll.flg & B) ? 1: 2;
- flags32 Imm = (pIcode->ic.ll.flg & I);
- switch (pIcode->ic.ll.opcode) {
- case iAND: case iOR: case iXOR:
- case iSAR: case iSHL: case iSHR:
- case iRCL: case iRCR: case iROL: case iROR:
- case iADD: case iADC: case iSUB: case iSBB:
- if (! Imm) {
- use(SRC, pIcode, this, pstate, cb, ix);
- }
- case iINC: case iDEC: case iNEG: case iNOT:
- case iAAA: case iAAD: case iAAM: case iAAS:
- case iDAA: case iDAS:
- use_def(DST, pIcode, this, pstate, cb, ix);
- break;
- case iXCHG:
- /* This instruction is replaced by 3 instructions, only need
- * to define the src operand and use the destination operand
- * in the mean time. */
- use(SRC, pIcode, this, pstate, cb, ix);
- def(DST, pIcode, this, pstate, cb, ix);
- break;
- case iTEST: case iCMP:
- if (! Imm)
- use(SRC, pIcode, this, pstate, cb, ix);
- use(DST, pIcode, this, pstate, cb, ix);
- break;
- case iDIV: case iIDIV:
- use(SRC, pIcode, this, pstate, cb, ix);
- if (cb == 1)
- pIcode->du.use |= duReg[rTMP];
- break;
- case iMUL: case iIMUL:
- use(SRC, pIcode, this, pstate, cb, ix);
- if (! Imm)
- {
- use (DST, pIcode, this, pstate, cb, ix);
- if (cb == 1)
- {
- pIcode->du.def |= duReg[rAX];
- pIcode->du1.numRegsDef++;
- }
- else
- {
- pIcode->du.def |= (duReg[rAX] | duReg[rDX]);
- pIcode->du1.numRegsDef += 2;
- }
- }
- else
- def (DST, pIcode, this, pstate, cb, ix);
- break;
- case iSIGNEX:
- cb = (pIcode->ic.ll.flg & SRC_B) ? 1 : 2;
- if (cb == 1) /* byte */
- {
- pIcode->du.def |= duReg[rAX];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rAL];
- }
- else /* word */
- {
- pIcode->du.def |= (duReg[rDX] | duReg[rAX]);
- pIcode->du1.numRegsDef += 2;
- pIcode->du.use |= duReg[rAX];
- }
- break;
- case iCALLF: /* Ignore def's on CS for now */
- cb = 4;
- case iCALL: case iPUSH: case iPOP:
- if (! Imm) {
- if (pIcode->ic.ll.opcode == iPOP)
- def(DST, pIcode, this, pstate, cb, ix);
- else
- use(DST, pIcode, this, pstate, cb, ix);
- }
- break;
- case iESC: /* operands may be larger */
- use(DST, pIcode, this, pstate, cb, ix);
- break;
- case iLDS: case iLES:
- pIcode->du.def |= duReg[(pIcode->ic.ll.opcode == iLDS) ? rDS : rES];
- pIcode->du1.numRegsDef++;
- cb = 4;
- case iMOV:
- use(SRC, pIcode, this, pstate, cb, ix);
- def(DST, pIcode, this, pstate, cb, ix);
- break;
- case iLEA:
- use(SRC, pIcode, this, pstate, 2, ix);
- def(DST, pIcode, this, pstate, 2, ix);
- break;
- case iBOUND:
- use(SRC, pIcode, this, pstate, 4, ix);
- use(DST, pIcode, this, pstate, cb, ix);
- break;
- case iJMPF:
- cb = 4;
- case iJMP:
- if (! Imm)
- use(SRC, pIcode, this, pstate, cb, ix);
- break;
- case iLOOP: case iLOOPE: case iLOOPNE:
- pIcode->du.def |= duReg[rCX];
- pIcode->du1.numRegsDef++;
- case iJCXZ:
- pIcode->du.use |= duReg[rCX];
- break;
- case iREPNE_CMPS: case iREPE_CMPS: case iREP_MOVS:
- pIcode->du.def |= duReg[rCX];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rCX];
- case iCMPS: case iMOVS:
- pIcode->du.def |= duReg[rSI] | duReg[rDI];
- pIcode->du1.numRegsDef += 2;
- pIcode->du.use |= duReg[rSI] | duReg[rDI] | duReg[rES] | duReg[sseg];
- break;
- case iREPNE_SCAS: case iREPE_SCAS: case iREP_STOS: case iREP_INS:
- pIcode->du.def |= duReg[rCX];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rCX];
- case iSCAS: case iSTOS: case iINS:
- pIcode->du.def |= duReg[rDI];
- pIcode->du1.numRegsDef++;
- if (pIcode->ic.ll.opcode == iREP_INS || pIcode->ic.ll.opcode== iINS)
- {
- pIcode->du.use |= duReg[rDI] | duReg[rES] | duReg[rDX];
- }
- else
- {
- pIcode->du.use |= duReg[rDI] | duReg[rES] | duReg[(cb == 2)? rAX: rAL];
- }
- break;
- case iREP_LODS:
- pIcode->du.def |= duReg[rCX];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rCX];
- case iLODS:
- pIcode->du.def |= duReg[rSI] | duReg[(cb==2)? rAX: rAL];
- pIcode->du1.numRegsDef += 2;
- pIcode->du.use |= duReg[rSI] | duReg[sseg];
- break;
- case iREP_OUTS:
- pIcode->du.def |= duReg[rCX];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rCX];
- case iOUTS:
- pIcode->du.def |= duReg[rSI];
- pIcode->du1.numRegsDef++;
- pIcode->du.use |= duReg[rSI] | duReg[rDX] | duReg[sseg];
- break;
- case iIN: case iOUT:
- def(DST, pIcode, this, pstate, cb, ix);
- if (! Imm)
- {
- pIcode->du.use |= duReg[rDX];
- }
- break;
- }
- for (i = rSP; i <= rBH; i++) /* Kill all defined registers */
- if (pIcode->ic.ll.flagDU.d & (1 << i))
- pstate->f[i] = FALSE;
- }
|