* debugger/mcs51/break.c, debugger/mcs51/cmd.c,
[fw/sdcc] / debugger / mcs51 / break.c
index 93a00909b4c03395f6cd5a460415d5435bab34b6..0637661932aaf1ad4edf63fe4384114dfa1cd90a 100644 (file)
 #include "sdcdb.h"
 #include "symtab.h"
 #include "break.h"
+#include "cmd.h"
 #include "newalloc.h"
 
-static hTab *bptable = NULL;
+hTab *bptable = NULL;
+char doingSteps    = 0;
 char userBpPresent = 0;
+
 /* call stack can be 1024 deep */
 STACK_DCL(callStack,function *,1024);
 
@@ -41,25 +44,42 @@ char *debug_bp_type_strings[] =
     "STEP"    ,
     "NEXT"    ,
     "FENTRY"  ,
-    "FEXIT", "", ""};
+    "FEXIT", "TMPUSER", ""};
 #endif
 
+static long bpnum = 0;
+
+long getLastBreakptNumber()
+{
+    return bpnum;
+}
+
+void resetHitCount()
+{
+    int k;
+    breakp *bp;
+    for ( bp = hTabFirstItem(bptable,&k); bp ;
+          bp = hTabNextItem(bptable,&k))
+    {
+        bp->hitCnt    = 0;
+        bp->ignoreCnt = 0;
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* setBreakPoint - creates an entry in the break point table       */
 /*-----------------------------------------------------------------*/
 int setBreakPoint (unsigned addr, char addrType, char bpType,
-        int (*callBack)(unsigned,char,char,int,context *) ,
+        int (*callBack)(unsigned,breakp *,context *) ,
         char *fileName, int lineno)
 {
     breakp *bp, *bpl;
-    static long bpnum = 0;
-    char simbuf[50];
 
     Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
         addr,
         debug_bp_type_strings[addrType],
         debug_bp_type_strings[bpType],
-        fileName, lineno));
+        fileName, lineno+1));
 
     /* allocate & init a new bp */
     bp = Safe_calloc(1,sizeof(breakp));
@@ -67,34 +87,38 @@ int setBreakPoint (unsigned addr, char addrType, char bpType,
     bp->addrType = addrType;
     bp->bpType = bpType;
     bp->callBack = callBack;
-    bp->bpnum = (bpType == USER ? ++bpnum : 0);
+    bp->bpnum = ((bpType == USER || bpType == TMPUSER)? ++bpnum : 0);
     bp->filename = fileName;
     bp->lineno = lineno;
 
     /* if this is an user break point then
        check if there already exists one for this address */
-    if (bpType == USER) {
-  for ( bpl = hTabFirstItemWK(bptable,addr) ; bpl;
-        bpl = hTabNextItemWK(bptable)) {
-
-      /* if also a user break point then issue Note : */
-      if (bpl->bpType == USER)
-    fprintf(stderr,"Note: breakpoint %d also set at pc 0x%x\n",
-      bpl->bpnum,bpl->addr);
-  }
-
-  fprintf(stderr,"Breakpoint %d at 0x%x: file %s, line %d.\n",
-    bp->bpnum, addr, fileName, lineno);
-
-  userBpPresent++;
+    if (bpType == USER || bpType == TMPUSER)
+    {
+        for ( bpl = hTabFirstItemWK(bptable,addr) ; bpl;
+              bpl = hTabNextItemWK(bptable))
+        {
+
+            /* if also a user break point then issue Note : */
+            if (bpl->bpType == USER || bpType == TMPUSER)
+                fprintf(stderr,"Note: breakpoint %d also set at pc 0x%x\n",
+                        bpl->bpnum,bpl->addr);
+        }
+
+        fprintf(stderr,"Breakpoint %d at 0x%x: file %s, line %d.\n",
+                bp->bpnum, addr, fileName, lineno+1);
+
+        userBpPresent++;
     }
 
-    /* if a break point does not already exist then
-       send command to simulator to add one */
-    if (!hTabSearch(bptable,addr))
-  /* send the break command to the simulator */
-  simSetBP (addr);
-
+    if (bpType != STEP && bpType != NEXT)
+    {
+        /* if a break point does not already exist then
+           send command to simulator to add one */
+        if (!hTabSearch(bptable,addr))
+            /* send the break command to the simulator */
+            simSetBP (addr);
+    }
 
     /* now add the break point to list */
     hTabAddItem(&bptable,addr,bp);
@@ -113,19 +137,15 @@ void deleteSTEPbp ()
     Dprintf(D_break, ("break: Deleting all STEP BPs\n"));
     /* for break points delete if they are STEP */
     for ( bp = hTabFirstItem(bptable,&k); bp ;
-    bp = hTabNextItem(bptable,&k)) {
-
-  /* if this is a step then delete */
-  if (bp->bpType == STEP) {
-      hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
-
-      /* if this leaves no other break points then
-         send command to simulator to delete bp from this addr */
-      if (hTabSearch(bptable,bp->addr) == NULL)
-    simClearBP (bp->addr);
-
-      free(bp);
-  }
+          bp = hTabNextItem(bptable,&k))
+    {
+
+        /* if this is a step then delete */
+        if (bp->bpType == STEP)
+        {
+            hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
+            Safe_free(bp);
+        }
     }
 
 }
@@ -137,31 +157,33 @@ void deleteNEXTbp ()
 {
     breakp *bp;
     int k;
-    char simcmd[50];
 
     Dprintf(D_break, ("break: Deleting all NEXT BPs\n"));
 
     /* for break points delete if they are NEXT */
     for ( bp = hTabFirstItem(bptable,&k); bp ;
-    bp = hTabNextItem(bptable,&k)) {
-
-  /* if this is a step then delete */
-  if (bp->bpType == NEXT) {
-      hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
-
-      /* if this leaves no other break points then
-         send command to simulator to delete bp from this addr */
-      if (hTabSearch(bptable,bp->addr) == NULL) {
-    simClearBP(bp->addr);
-
-      }
-
-      free(bp);
-  }
+          bp = hTabNextItem(bptable,&k))
+    {
+
+        /* if this is a step then delete */
+        if (bp->bpType == NEXT)
+        {
+            hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
+            Safe_free(bp);
+        }
     }
 
 }
 
+static void freeUSERbp(breakp *bp)
+{
+    if ( bp->commands )
+        Safe_free(bp->commands);
+    if ( bp->condition )
+        Safe_free(bp->condition);
+    Safe_free(bp);
+}
+
 /*-----------------------------------------------------------------*/
 /* deleteUSERbp - deletes USER break point with number             */
 /*-----------------------------------------------------------------*/
@@ -169,39 +191,113 @@ void deleteUSERbp (int bpnum)
 {
     breakp *bp;
     int k;
-    char simcmd[50];
 
     Dprintf(D_break, ("break: deleteUSERbp %d\n", bpnum));
 
     /* for break points delete if they are STEP */
     for ( bp = hTabFirstItem(bptable,&k); bp ;
-    bp = hTabNextItem(bptable,&k)) {
-
-  /* if this is a user then delete if break
-     point matches or bpnumber == -1 (meaning delete
-     all user break points */
-  if (bp->bpType == USER && ( bp->bpnum == bpnum || bpnum == -1)) {
-      hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
-
-      /* if this leaves no other break points then
-         send command to simulator to delete bp from this addr */
-      if (hTabSearch(bptable,bp->addr) == NULL) {
-    simClearBP (bp->addr);
-    Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
-
-      }
-      fprintf(stdout,"Deleted breakpoint %d\n",
-        bp->bpnum);
-      userBpPresent --;
-      if (bpnum == -1)
-    continue ;
-      else
-    break;
-  }
+          bp = hTabNextItem(bptable,&k)) {
+
+        /* if this is a user then delete if break
+           point matches or bpnumber == -1 (meaning delete
+           all user break points */
+        if ((bp->bpType == USER || bp->bpType == TMPUSER )
+            && ( bp->bpnum == bpnum || bpnum == -1))
+        {
+            hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
+
+            /* if this leaves no other break points then
+               send command to simulator to delete bp from this addr */
+            if (hTabSearch(bptable,bp->addr) == NULL) {
+                simClearBP (bp->addr);
+                Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
+
+            }
+            fprintf(stdout,"Deleted breakpoint %d\n",bp->bpnum);
+            userBpPresent-- ;
+            freeUSERbp(bp);
+            if (bpnum == -1)
+                continue ;
+            else
+                break;
+        }
     }
 
     if (!bp && bpnum != -1)
-  fprintf(stderr,"No breakpoint number %d.\n",bpnum);
+        fprintf(stderr,"No breakpoint number %d.\n",bpnum);
+}
+
+/*-----------------------------------------------------------------*/
+/* setUserbpCommand - set commandstring for breakpoint             */
+/*-----------------------------------------------------------------*/
+void setUserbpCommand (int bpnum, char *cmds)
+{
+    breakp *bp;
+    int k;
+    Dprintf(D_break, ("break: setUserbpCommand %d: commands:\n%send\n",
+                      bpnum, cmds));
+
+    for ( bp = hTabFirstItem(bptable,&k); bp ;
+          bp = hTabNextItem(bptable,&k))
+    {
+        if ((bp->bpType == USER || bp->bpType == TMPUSER )
+            && ( bp->bpnum == bpnum ))
+        {
+            if ( bp->commands )
+                Safe_free(bp->commands);
+            bp->commands = cmds;
+            return;
+        }
+    }
+    fprintf(stderr,"No breakpoint number %d.\n",bpnum);
+}
+
+/*-----------------------------------------------------------------*/
+/* setUserbpCondition - set condition string for breakpoint        */
+/*-----------------------------------------------------------------*/
+void setUserbpCondition (int bpnum, char *cond)
+{
+    breakp *bp;
+    int k;
+    Dprintf(D_break, ("break: setUserbpCondition %d: condition:'%s'\n",
+                      bpnum, cond?cond:""));
+
+    for ( bp = hTabFirstItem(bptable,&k); bp ;
+          bp = hTabNextItem(bptable,&k))
+    {
+        if ((bp->bpType == USER || bp->bpType == TMPUSER )
+            && ( bp->bpnum == bpnum ))
+        {
+            if ( bp->condition )
+                Safe_free(bp->condition);
+            bp->condition = cond;
+            return;
+        }
+    }
+    fprintf(stderr,"No breakpoint number %d.\n",bpnum);
+}
+
+/*-----------------------------------------------------------------*/
+/* setUserbpIgnCount - set ignorecount for breakpoint              */
+/*-----------------------------------------------------------------*/
+void setUserbpIgnCount (int bpnum, int ignorecnt )
+{
+    breakp *bp;
+    int k;
+    Dprintf(D_break, ("break: setUserbpIgnCount %d: ignorecnt=%d\n",
+                      bpnum, ignorecnt));
+
+    for ( bp = hTabFirstItem(bptable,&k); bp ;
+          bp = hTabNextItem(bptable,&k))
+    {
+        if ((bp->bpType == USER || bp->bpType == TMPUSER )
+            && ( bp->bpnum == bpnum ))
+        {
+            bp->ignoreCnt = bp->hitCnt + ignorecnt;
+            return;
+        }
+    }
+    fprintf(stderr,"No breakpoint number %d.\n",bpnum);
 }
 
 /*-----------------------------------------------------------------*/
@@ -210,23 +306,42 @@ void deleteUSERbp (int bpnum)
 void listUSERbp ()
 {
     breakp *bp;
-    int k;
+    int k, isuser;
 
     /* if there are none then say so & return */
     if (!userBpPresent) {
-  fprintf(stdout,"No breakpoints.\n");
-  return ;
+        fprintf(stdout,"No breakpoints.\n");
+        return ;
     }
     fprintf(stdout,"Num Type           Disp Enb Address    What\n");
     for ( bp = hTabFirstItem(bptable,&k) ; bp ;
-    bp = hTabNextItem(bptable,&k)) {
+          bp = hTabNextItem(bptable,&k)) {
+
+        isuser = 0;
+        if (bp->bpType == USER ) {
+            fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
+                    bp->bpnum,bp->addr,
+                    bp->filename,bp->lineno+1);
+            isuser = 1;
+        }
+        else if (bp->bpType == TMPUSER ) {
+            fprintf(stdout,"%-3d breakpoint      del y   0x%08x at %s:%d\n",
+                    bp->bpnum,bp->addr,
+                    bp->filename,bp->lineno+1);
+            isuser = 1;
+        }
+        if ( ! isuser )
+            continue;
+        if ( bp->ignoreCnt > bp->hitCnt )
+            fprintf(stdout,"\tignore next %d hits\n",
+                    bp->ignoreCnt - bp->hitCnt );
+        if ( bp->condition )
+            fprintf(stdout,"\tstop only if %s\n",bp->condition );
+        if ( bp->hitCnt > 0 )
+            fprintf(stdout,"\tbreakpoint already hit %d time%s\n",
+                    bp->hitCnt,bp->hitCnt>1?"s":"" );
 
-  if (bp->bpType == USER ) {
-      fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
-        bp->bpnum,bp->addr,
-        bp->filename,bp->lineno);
 
-  }
     }
 }
 
@@ -246,31 +361,32 @@ static int simStopBPCB( unsigned int addr)
 void clearUSERbp ( unsigned int addr )
 {
     breakp *bp;
-    char simcmd[50];
 
     /* for break points delete if they are STEP */
     for ( bp = hTabFirstItemWK(bptable,addr); bp ;
-    bp = hTabNextItemWK(bptable)) {
-
-  /* if this is a step then delete */
-  if (bp->bpType == USER) {
-      hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
-
-      /* if this leaves no other break points then
-         send command to simulator to delete bp from this addr */
-      if (hTabSearch(bptable,bp->addr) == NULL) {
-    simClearBP(bp->addr);
-
-      }
-      fprintf(stdout,"Deleted breakpoint %d\n",
-        bp->bpnum);
-      userBpPresent-- ;
-      break;
-  }
+          bp = hTabNextItemWK(bptable)) {
+
+        /* if this is a step then delete */
+        if (bp->bpType == USER || bp->bpType == TMPUSER)
+        {
+            hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
+
+            /* if this leaves no other break points then
+               send command to simulator to delete bp from this addr */
+            if (hTabSearch(bptable,bp->addr) == NULL)
+            {
+                simClearBP(bp->addr);
+            }
+            fprintf(stdout,"Deleted breakpoint %d\n",
+                    bp->bpnum);
+            userBpPresent-- ;
+            freeUSERbp(bp);
+            break;
+        }
     }
 
     if (!bp)
-  fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
+        fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
 }
 
 /*-----------------------------------------------------------------*/
@@ -286,15 +402,16 @@ int dispatchCB (unsigned addr, context *ctxt)
     /* if no break points set for this address
        then use a simulator stop break point */
     if ((bp = hTabFirstItemWK(bptable,addr)) == NULL) {
+      if ( doingSteps == 2 ) return 1;
+      if ( doingSteps ) return 0;
+      if ( contsim    ) return 0;
       return simStopBPCB(addr);
     }
 
     /* dispatch the call back functions */
-    for (; bp; bp = hTabNextItemWK(bptable)) {
-
-      rv += (*bp->callBack)(addr,bp->addrType,
-          bp->bpType,bp->bpnum,ctxt);
-
+    for (; bp; bp = hTabNextItemWK(bptable))
+    {
+        rv += (*bp->callBack)(addr,bp,ctxt);
     }
 
     if (rv == 0) {
@@ -309,14 +426,25 @@ int dispatchCB (unsigned addr, context *ctxt)
 /*-----------------------------------------------------------------*/
 BP_CALLBACK(fentryCB)
 {
-    Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry\n"));
+    function *func;
 
-    /* add the current function into the call stack */
-    STACK_PUSH(callStack,ctxt->func);
-
-    /* will have to add code here to get the value of SP
+    /* we save the value of SP
        which will be used to display the value of local variables
        and parameters on the stack */
+    ctxt->func->stkaddr = simGetValue (0x81,'I',1);
+
+    Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry %s sp=0x%02x %p\n",
+                      ctxt->func->sym->name,
+                      ctxt->func->stkaddr, p_callStack));
+
+    /* and set laddr of calling function to return addr from stack */
+    if ((func = STACK_PEEK(callStack)))
+    {
+        /* extern stack ?? 'A' */
+        func->laddr = simGetValue (ctxt->func->stkaddr-1,'B',2);
+    }
+    /* add the current function into the call stack */
+    STACK_PUSH(callStack,ctxt->func);
 
     return 0;
 }
@@ -326,10 +454,24 @@ BP_CALLBACK(fentryCB)
 /*-----------------------------------------------------------------*/
 BP_CALLBACK(fexitCB)
 {
-    Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry\n"));
-
+    function *func;
     /* pop the top most from the call stack */
-    STACK_POP(callStack);
+    func = STACK_POP(callStack);
+
+    if (!func)
+    {
+        fprintf(stdout, "Stack underflow\n");
+        return 1;
+    }
+
+    Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry %s %p\n", func->sym->name, p_callStack));
+
+    /* check main function */
+    if ( !strcmp(func->sym->name, "main"))
+    {
+        fprintf(stdout, "Program exited with code %lu.\n", simGetValue (0x82,'I',2));
+        return 1;
+    }
     return 0;
 }
 /*-----------------------------------------------------------------*/
@@ -337,28 +479,60 @@ BP_CALLBACK(fexitCB)
 /*-----------------------------------------------------------------*/
 BP_CALLBACK(userBpCB)
 {
-    Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry\n"));
+    bp->hitCnt++ ;
+    Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry hit=%d ignor=%d\n",
+                      bp->hitCnt, bp->ignoreCnt));
+
+    if ( bp->ignoreCnt > bp->hitCnt )
+        return 0;
+
+    if ( bp->condition )
+    {
+        if (! conditionIsTrue( bp->condition, ctxt ))
+            return 0;
+    }
+
+    if ( bp->commands )
+    {
+        Dprintf(D_break, ("break: userBpCB: commands:%p\n", bp->commands));
+        setCmdLine(bp->commands);
+    }
 
     if (srcMode == SRC_CMODE) {
-  fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
-    bpnum,
-    ctxt->func->sym->name,
-    ctxt->func->mod->c_name,
-    ctxt->cline);
-  if (ctxt->func->mod && ctxt->cline > 0)
-      fprintf(stdout,"%d\t%s",ctxt->cline,
-        ctxt->func->mod->cLines[ctxt->cline]->src);
+        fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
+                bp->bpnum,
+                ctxt->func->sym->name,
+                ctxt->func->mod->c_name,
+                ctxt->cline+1);
+        if (ctxt->func->mod && ctxt->cline > 0)
+            fprintf(stdout,"%d\t%s",ctxt->cline+1,
+                    ctxt->func->mod->cLines[ctxt->cline]->src);
     } else {
-  fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
-    bpnum,
-    ctxt->func->sym->name,
-    ctxt->func->mod->asm_name,
-    ctxt->asmline);
-  if (ctxt->func->mod && ctxt->asmline > 0)
-      fprintf(stdout,"%d\t%s",ctxt->asmline,
-        ctxt->func->mod->asmLines[ctxt->asmline]->src);
+        fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
+                bp->bpnum,
+                ctxt->func->sym->name,
+                ctxt->func->mod->asm_name,
+                ctxt->asmline+1);
+        if (ctxt->func->mod && ctxt->asmline > 0)
+            fprintf(stdout,"%d\t%s",ctxt->asmline+1,
+                    ctxt->func->mod->asmLines[ctxt->asmline]->src);
     }
 
+    if ( bp->bpType == TMPUSER && bp->bpnum > 0 )
+    {
+        hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
+
+        /* if this leaves no other break points then
+           send command to simulator to delete bp from this addr */
+        if (hTabSearch(bptable,bp->addr) == NULL)
+        {
+            simClearBP (bp->addr);
+            Dprintf(D_break, ("break: simClearBP 0x%x\n", bp->addr));
+
+        }
+        userBpPresent-- ;
+        freeUSERbp(bp);
+    }
     return 1;
 }
 
@@ -376,10 +550,10 @@ BP_CALLBACK(stepBpCB)
       fprintf(stdout,"%s () at %s:%d\n",
         ctxt->func->sym->name,
         ctxt->func->mod->c_name,
-        ctxt->cline);
+        ctxt->cline+1);
 
   if (ctxt->func->mod && ctxt->cline > 0) {
-      fprintf(stdout,"%d\t%s",ctxt->cline ,
+      fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
         ctxt->func->mod->cLines[ctxt->cline]->src);
   }
     } else {
@@ -414,10 +588,10 @@ BP_CALLBACK(nextBpCB)
       fprintf(stdout,"%s () at %s:%d\n",
         ctxt->func->sym->name,
         ctxt->func->mod->c_name,
-        ctxt->cline);
+        ctxt->cline+1);
 
   if (ctxt->func->mod && ctxt->cline > 0)
-      fprintf(stdout,"%d\t%s",ctxt->cline,
+      fprintf(stdout,"%d\t%s",ctxt->cline+1,
         ctxt->func->mod->cLines[ctxt->cline]->src);
     } else {
   if ((lfunc && lfunc != ctxt->func) || !lfunc)