/* CLASS: HLBreakLib
   High Level Breakpoint/Exec Library (BKPTEXEC.DLL)
   Provide high level breakpoints, asm level breakpoints and execution control
   mechanism.

*/!!

inherit(ProvidedLibs, #HLBreakLib, #(asmStepSema  /* go semaphores */
srcStepSema
goIntoSema
goUntilSema
goSema), 2, nil)!!

now(class(HLBreakLib))!!

/* semiPRIVATE -- should only be called via require(HLBreakLib)
   Define entry points and load library.  Define any structs required.
*/
Def provide(self, path)
{
  ^initialise( new(self:ancestor), path )
}
!!

now(HLBreakLib)!!

/* set step mask flag */
Def setStepMask(self, value | stepMaskRef)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXSETSTEPMASK], value);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil;
  endif;
}
!!

/* get step mask flag */
Def getStepMask(self | stepMaskRef)
{ 
  stepMaskRef := new(Struct, 2);
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETSTEPMASK], stepMaskRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil;
  endif;
  ^byteAt(stepMaskRef, 0);
}
!!

/* 12/3/1992 17:06 - PUBLIC
  Return number of breakpoints if there is 1 or more breakpoints set, 
  else nil.
*/
Def anyBkpts?(self | bkptSetRef, numBkpt)
{ 
  bkptSetRef := new(Struct, 4);
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETBKPTCOUNT], bkptSetRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil;
  endif;
  /* Return # of breakpoints */
  numBkpt := wordAt(bkptSetRef, 0);
  if numBkpt > 0 then
    ^numBkpt;
  endif;
  ^nil;  
}
!!

/* 12/3/1992 17:03 - PUBLIC
  Reset the emulator and let it free run.
*/
Def resetAndGo(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall( procs[#BXRESETANDSTARTEMULATION]);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then 
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil 
  endif;
  ^lastError;
}
!!

/* 3/23/1992 13:25 - PUBLIC
  Set an asm level breakpoint.
  Return a breakpoint descriptor or nil.
  Note: addrDesc is created by calling createAddress(AddressLibClass$Inst)
  and the hi-level Breakpoint Server will consume it even if error occurred.
*/
Def prime_setAsmBkpt(self, state, life, addrDesc | descRef )
{ 
  descRef := new(Struct, 4);
  if not(state) cor not(life) cor not(addrDesc) cor not(descRef) then
    ^nil;
  endif;  
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXSETBKPT], asInt(state), asInt(life),
                       asLong(addrDesc), descRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
   ^nil;
  endif;
  ^longAt(descRef, 0);
}
!!

/* PUBLIC - 08/25/92
  Assmbly level step.
*/
Def asmStepType(self, stepType, numSteps)
{
  if pcallLock(self)
  then
    lastError := pcall( procs[#BXASMSTEPINTOOROVER], asLong(numSteps), asInt(stepType) );
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then 
    displayError(ErrorTextLibClass$Inst,lastError,CHECK_MODE);
    ^nil 
  endif;
  ^lastError;
}
!!

/* 3/23/1992 13:35 - PUBLIC
  Get the reason for the last break in emulation.
*/
Def getBkptCause(self | cause)
{ 
  cause := new(Struct, 4);
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETCAUSEOFLASTBREAK], cause);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^wordAt(cause, 0);
}
!!

/* 6/26/1992 13:11 - PUBLIC
  Get the next address range breakpoint. 
  Return a tuple #(loopDesc, bkptDesc) or nil if no more descriptor.
  EX: getAllAddrBkptNext(HLBreakLib, addrRangeDes, loopDesc);
*/
Def getAllAddrBkptNext(self, addrRangeDesc, loopDesc | loopDescRef, bkptDescRef)
{ 
  loopDescRef := new(Struct, 4);
  bkptDescRef := new(Struct, 4);
  /* specified the loopDesc */
  if not(loopDesc) then
     loopDesc := 0; /* NULL to Start */
  endif;     
  putLong(loopDescRef, asLong(loopDesc), 0);
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETBKPTBYADDRESSNEXT], addrRangeDesc, loopDescRef, bkptDescRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    /* Do not display error message if error occured in a predictable situation */
    if (lastError <> ER_BX_NO_BKPT_AVAILABLE) cand 
      (lastError <> ER_BX_LOOP_COMPLETE) then 
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;
    ^nil;
  endif;
  ^tuple(longAt(loopDescRef, 0), longAt(bkptDescRef, 0));    
}



!!

/* PRIVATE
   Define all entry points for library as prototypes.
*/
Def addImportProcs(self)
{
  add( self, #INITCSERVER,                1, #(0, 0)            );
  add( self, #BXASMSTEP,                  1, #(1)               );
  add( self, #BXASMSTEPINTOOROVER,        1, #(1, 0)            );
  add( self, #BXDISABLEALLBKPTS,          1, nil                );
  add( self, #BXDISABLEBKPT,              1, #(1)               );
  add( self, #BXENABLEALLBKPTS,           1, nil                );
  add( self, #BXENABLEBKPT,               1, #(1)               );
  add( self, #BXGETALLBKPTNEXT,           1, #(1,1)             );
  add( self, #BXGETBKPT,                  1, #(1,1,1,1)         );
  add( self, #BXGETBKPTBYADDRESSNEXT,     1, #(1,1,1)           );
  add( self, #BXGETBKPTCOUNT,             1, #(1)               );
  add( self, #BXGETCAUSEOFLASTBREAK,      1, #(1)               );
  add( self, #BXGETSRCBKPT,               1, #(1,1,1,1,1,1,1)   );
  add( self, #BXGETSRCBKPTNAMES,          1, #(1,1,1,1)         );
  add( self, #BXGETSRCBKPTNEXT,           1, #(1,1,1)           );
  add( self, #BXGOINTOCALLRETURN,         1, #(0, 0)            );
  add( self, #BXGOUNTILCALLRETURN,        1, #(0, 0)            );
  add( self, #BXHALTEMULATION,            1, nil                );
  add( self, #BXREMOVEALLBKPTS,           1, nil                );
  add( self, #BXREMOVEBKPT,               1, #(1)               );
  add( self, #BXRESETANDSTARTEMULATION,   1, nil                );
  add( self, #BXSETBKPT,                  1, #(0,0,1,1)         );
  add( self, #BXSETSRCBKPT,               1, #(0,0,1,0,0,1,1,1) );
  add( self, #BXSRCSTEP,                  1, #(0, 0, 1)         );
  add( self, #BXSTARTEMULATION,           1, nil                );
  add( self, #BXSETSTEPMASK,              1, #(0)               );
  add( self, #BXGETSTEPMASK,              1, #(1)               );

}!!

/* PUBLIC */
Def asmStep(self, numInstructions)
{
  if asmStepSema then ^nil; endif ;
  
  asmStepSema := #true ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#BXASMSTEP], asLong(numInstructions) ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  asmStepSema := nil ;

  if (lastError <> GOOD) then 
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil 
  endif;
  ^lastError;
}
!!

/* 3/23/1992 13:53 - PUBLIC
  Disable all breakpoints.
*/
Def disableAllBkpt(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXDISABLEALLBKPTS]);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;  
}
!!

/* 3/23/1992 13:49 - PUBLIC
  Disable a breakpoint.
*/
Def disableBkpt(self, desc)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXDISABLEBKPT], asLong(desc));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
  endif;
  ^lastError;  
}
!!

/* 3/23/1992 13:53 - PUBLIC
  Enable all breakpoints.
*/
Def enableAllBkpt(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXENABLEALLBKPTS]);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;  
}
!!

/* 3/23/1992 13:49 - PUBLIC
  Enable a breakpoint.
*/
Def enableBkpt(self, desc)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXENABLEBKPT], asLong(desc));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;  
}
!!

/* PUBLIC */
Def free(self)
{
  free( self:ancestor );
}
!!

/* 6/2/1992 16:52 - PUBLIC
  Get the next breakpoint. 
  Return a tuple #(loopDesc, bkptDesc) or nil if no more descriptor.
  EX: getAllBkptNext(HLBreakLib, nil);
*/
Def getAllBkptNext(self, loopDesc | loopDescRef, bkptDescRef)
{ 
  loopDescRef := new(Struct, 4);
  bkptDescRef := new(Struct, 4);
  /* specified the loopDesc */
  if not(loopDesc) then
     loopDesc := 0; /* NULL */
  endif;     
  putLong(loopDescRef, asLong(loopDesc), 0);
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETALLBKPTNEXT], loopDescRef, bkptDescRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    /* Do not display error message if error occured in a predictable situation */
    if (lastError <> ER_BX_NO_BKPT_AVAILABLE) cand 
      (lastError <> ER_BX_LOOP_COMPLETE) then 
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;
    ^nil;
  endif;
  ^tuple(longAt(loopDescRef, 0), longAt(bkptDescRef, 0));    
}


!!

/* 3/23/1992 13:35 - PUBLIC
  Get information about a asm breakpoint.
  return a tuple #(state, life, addrDesc) or nil.
  Note: Caller need to free the addrDesc by calling destroyAddress(AddressLib).
*/
Def getBkpt(self, desc | stateRef, lifeRef, addrRef)
{ 
  stateRef := new(Struct, 2);
  lifeRef := new(Struct, 2);
  addrRef := new(Struct, 4);
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETBKPT], asLong(desc), stateRef, lifeRef, addrRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^tuple(byteAt(stateRef, 0), byteAt(lifeRef, 0), longAt(addrRef, 0));
}
!!

/* 6/15/1992 12:57 - PUBLIC
  Get breakpoint names.
  return nil or tuple #(moduleNameStr, funcNameStr)
*/
Def getBkptNames(self, bkptID | moduleRefName, moduleName, funcName)
{ 
  moduleRefName := new( Struct, 4);
  moduleName := new(Struct, 4);
  funcName := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#BXGETSRCBKPTNAMES], bkptID, moduleRefName, moduleName,
     funcName);
    pcallUNLock(self);
  endif;
  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;         
  ^tuple(getTextFromAddr(self, longAt(moduleName, 0)), 
      getTextFromAddr(self, longAt(funcName, 0)));
}
!!

/* 3/23/1992 13:11 - PUBLIC 
  Get the next source breakpoint.
  return a tuple #(loopDesc, bkptDesc) or nil.
*/
Def getNextSourceBkpt(self, module, loopDesc | loopDescRef, bkptDescRef)
{ 
  loopDescRef := new(Struct, 4);
  bkptDescRef := new(Struct, 4);
  /* specified the loopDesc */
  if not(loopDesc) then
     loopDesc := 0; /* NULL */
  endif;     
  putLong(loopDescRef, asLong(loopDesc), 0);
  
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETSRCBKPTNEXT], asLong(module), loopDescRef,
    bkptDescRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    /* Do not display error message if error occured in a predictable situation */
    if (lastError <> ER_BX_NO_BKPT_AVAILABLE) cand 
      (lastError <> ER_BX_LOOP_COMPLETE) then 
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;
    ^nil;
  endif;
  ^tuple(longAt(loopDescRef, 0), longAt(bkptDescRef, 0));    
}
!!

/* 3/23/1992 12:57 - PUBLIC 
  Get information about the source breakpoint.
  return a tuple of
    #(state, life, module, lineNum, colStart, colEnd) 
    or nil.
*/
Def getSourceBkpt(self, desc | stateRef, lifeRef, moduleRef, lineNumRef,
  colStartRef, colEndRef)
{ 
  stateRef := new(Struct, 2);
  lifeRef := new(Struct, 2);
  moduleRef := new(Struct, 4);
  lineNumRef := new(Struct, 2);
  colStartRef := new(Struct, 2);
  colEndRef := new(Struct, 2);
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGETSRCBKPT], asLong(desc), 
    stateRef, lifeRef, moduleRef,
    lineNumRef, colStartRef, colEndRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^tuple(byteAt(stateRef, 0), byteAt(lifeRef, 0), longAt(moduleRef, 0),
    wordAt(lineNumRef, 0), byteAt(colStartRef, 0), byteAt(colEndRef, 0));  
  
}
!!

/* 6/15/1992 13:16 - PRIVATE 
  Take a "LPSTR" and convert its text into an Actor string object.
  Return nil if failed. 
  */
Def getTextFromAddr(self, longCAddress)
{ 
  /* Check if address is not nil nor NULL */
  if not(longCAddress) cor (longCAddress = 0L) then
    ^nil;
  endif;
  
  /* Create a new Struct and convert the string into it */
  ^removeNulls(physicalString(copyFromLong(new(Struct, 256), longCAddress)));
}
!!

/* PUBLIC */
Def go(self)
{
  if goSema then ^nil; endif ;
  
  goSema := #true;

  if pcallLock(self)
  then
    lastError := pcall( procs[#BXSTARTEMULATION] ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  goSema := nil ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;  
   ^lastError;
}

!!

/* 3/23/1992 14:37 - PUBLIC 
  Do a Go-Into-Return.
*/
Def goIntoCallReturn(self, gran, callRetType)
{ 
  if goIntoSema then ^nil; endif ;
  
  goIntoSema := #true;

  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGOINTOCALLRETURN], asInt(gran), callRetType);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  goIntoSema := nil ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;  
  ^lastError;
}
!!

/* 3/23/1992 14:34 - PUBLIC
  Do a go-until return.
 */
Def goUntilCallReturn(self, gran, callRetType)
{ 
  if goUntilSema then ^nil; endif ;
 
  goUntilSema := #true ;

  if pcallLock(self)
  then
    lastError := pcall(procs[#BXGOUNTILCALLRETURN], asInt(gran), callRetType);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  goUntilSema := nil ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;   
}
!!

/* PUBLIC */
Def halt(self)
{
  if pcallLock(self)
  then
    lastError := pcall( procs[#BXHALTEMULATION]);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if lastError <> GOOD then 
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil 
  endif;
  goUntilSema := goIntoSema  := nil;
  srcStepSema := asmStepSema := goSema := nil;
  ^lastError;
}
!!

/* PRIVATE 
   Open and initialize variable server library & load trigger dll
*/
Def initialise(self, path)
{
   setName( self, path ) ;
   addImportProcs( self ) ;

   load( self ) ;  /* raises alert if fails: alert(System, self, #libLoad) */
}
!!

/* 3/23/1992 13:53 - PUBLIC
  Remove all breakpoints.
*/
Def removeAllBkpt(self)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXREMOVEALLBKPTS]);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD)
  then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;  
}
!!

/* 3/23/1992 13:49 - PUBLIC
  Remove a breakpoint.
*/
Def removeBkpt(self, desc)
{ 
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXREMOVEBKPT], asLong(desc));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
  endif;
  ^lastError;  
}
!!

/* 3/23/1992 13:25 - PUBLIC
  Set an asm level breakpoint. Return a breakpoint descriptor or nil.
*/
Def setAsmBkpt(self, state, life, addrDesc | result)
{ 
  if not(result := prime_setAsmBkpt(self, state, life, addrDesc)) then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil;
  endif;
  ^result;
}
!!

/* 3/23/1992 12:47 - PUBLIC 
  Set a source level breakpoint.
  return a bkpt Desc or nil.
*/
Def setSourceBkpt(self, state, life, moduleDesc, lineNum, col, str, addrDesc 
  | descRef )
{ 
  descRef := new(Struct, 4); 
  if (not(state) cor not(life) cor not(moduleDesc) cor not(lineNum) cor
     not(lineNum) cor not(col) cor not(str) cor not(addrDesc) cor not(descRef)) then
    ^nil;       
  endif;   
  if pcallLock(self)
  then
    lastError := pcall(procs[#BXSETSRCBKPT], 
    asInt(state),            /* enum */
    asInt(life),             /* enum */
    asLong(moduleDesc),      /* U32  */
    lineNum,                 /* U16  */  
    asInt(col),              /* U8   */
    asciiz(str),             /* U32  */   
    addrDesc,                /* ADDR_DESCRIPTOR */ 
    descRef);                /* U32  */
    
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^longAt(descRef, 0);  
}
!!

/* 3/23/1992 14:29 - PUBLIC
  Step by the source line or statement.
 */
Def sourceStep(self, stepType, gran, count)
{ 
  if srcStepSema then ^nil ; endif ;
  
  srcStepSema := #true ;

  if pcallLock(self)
  then
    lastError := pcall(procs[#BXSRCSTEP], asInt(stepType), asInt(gran), asLong(count));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  srcStepSema := nil ;

  if (lastError <> GOOD) then
     displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
     ^nil;
  endif;
  ^lastError;
}
!!
