summaryrefslogtreecommitdiff
path: root/debugger/mcs51/break.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /debugger/mcs51/break.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'debugger/mcs51/break.c')
-rw-r--r--debugger/mcs51/break.c613
1 files changed, 613 insertions, 0 deletions
diff --git a/debugger/mcs51/break.c b/debugger/mcs51/break.c
new file mode 100644
index 0000000..efec91e
--- /dev/null
+++ b/debugger/mcs51/break.c
@@ -0,0 +1,613 @@
+/*-------------------------------------------------------------------------
+ break.c - Source file for break point management
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "sdcdb.h"
+#undef DATADIR
+#include "symtab.h"
+#include "break.h"
+#include "cmd.h"
+#include "newalloc.h"
+
+hTab *bptable = NULL;
+char doingSteps = 0;
+char userBpPresent = 0;
+
+/* call stack can be 1024 deep */
+STACK_DCL(callStack,function *,1024)
+
+#ifdef SDCDB_DEBUG
+char *debug_bp_type_strings[] =
+ {"ERR-0",
+ "DATA",
+ "CODE" ,
+ "A_CODE" ,
+ "USER" ,
+ "STEP" ,
+ "NEXT" ,
+ "FENTRY" ,
+ "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,breakp *,context *) ,
+ char *fileName, int lineno)
+{
+ breakp *bp, *bpl;
+
+ Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
+ addr,
+ debug_bp_type_strings[(int)addrType],
+ debug_bp_type_strings[(int)bpType],
+ fileName, lineno+1));
+
+ /* allocate & init a new bp */
+ bp = Safe_calloc(1,sizeof(breakp));
+ bp->addr = addr;
+ bp->addrType = addrType;
+ bp->bpType = bpType;
+ bp->callBack = callBack;
+ 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 || 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 (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);
+
+ return bp->bpnum ;
+}
+
+/*-----------------------------------------------------------------*/
+/* deleteSTEPbp - deletes all step break points */
+/*-----------------------------------------------------------------*/
+void deleteSTEPbp ()
+{
+ breakp *bp;
+ int k;
+
+ 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);
+ Safe_free(bp);
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* deleteNEXTbp - deletes all step break points */
+/*-----------------------------------------------------------------*/
+void deleteNEXTbp ()
+{
+ breakp *bp;
+ int k;
+
+ 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);
+ 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 */
+/*-----------------------------------------------------------------*/
+void deleteUSERbp (int bpnum)
+{
+ breakp *bp;
+ int k;
+
+ 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->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);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* listUSERbp - list all user break points */
+/*-----------------------------------------------------------------*/
+void listUSERbp ()
+{
+ breakp *bp;
+ int k, isuser;
+
+ /* if there are none then say so & return */
+ if (!userBpPresent) {
+ 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)) {
+
+ 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":"" );
+
+
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* simStopBPCB - simulator stopped break point */
+/*-----------------------------------------------------------------*/
+static int simStopBPCB( unsigned int addr)
+{
+ fprintf(stdout,"Simulator stopped at Address 0x%04x\n",addr);
+ fprintf(stdout,"%s",simResponse());
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* clearUSERbp - deletes USER break point at address */
+/*-----------------------------------------------------------------*/
+void clearUSERbp ( unsigned int addr )
+{
+ breakp *bp;
+
+ /* 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 || 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* dispatchCB - will lookup the bp table and dispatch the cb funcs */
+/*-----------------------------------------------------------------*/
+int dispatchCB (unsigned addr, context *ctxt)
+{
+ breakp *bp;
+ int rv =0;
+
+ Dprintf(D_break, ("break: dispatchCB: addr:0x%x \n", addr));
+
+ /* 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,ctxt);
+ }
+
+ if (rv == 0) {
+ Dprintf(D_break, ("break: dispatchCB: WARNING rv==0\n"));
+ }
+
+ return rv;
+}
+
+/*-----------------------------------------------------------------*/
+/* fentryCB - callback function for function entry */
+/*-----------------------------------------------------------------*/
+BP_CALLBACK(fentryCB)
+{
+ function *func;
+
+ /* 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* fexitCB - call back for function exit */
+/*-----------------------------------------------------------------*/
+BP_CALLBACK(fexitCB)
+{
+ function *func;
+ /* pop the top most from the call stack */
+ 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;
+}
+/*-----------------------------------------------------------------*/
+/* userBpCB - call back function for user break points */
+/*-----------------------------------------------------------------*/
+BP_CALLBACK(userBpCB)
+{
+ 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",
+ 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",
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* stepBpCB - call back function for step break points */
+/*-----------------------------------------------------------------*/
+BP_CALLBACK(stepBpCB)
+{
+ static function *lfunc = NULL;
+
+ Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
+
+ if (srcMode == SRC_CMODE) {
+ if ((lfunc && lfunc != ctxt->func) || !lfunc)
+ fprintf(stdout,"%s () at %s:%d\n",
+ 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 {
+ if ((lfunc && lfunc != ctxt->func) || !lfunc)
+ fprintf(stdout,"%s () at %s:%d\n",
+ ctxt->func->sym->name,
+ ctxt->func->mod->asm_name,
+ ctxt->asmline);
+
+ if (ctxt->func->mod && ctxt->cline > 0) {
+ fprintf(stdout,"%d\t%s",ctxt->asmline ,
+ ctxt->func->mod->asmLines[ctxt->asmline]->src);
+ }
+ }
+ lfunc = ctxt->func;
+
+ deleteSTEPbp();
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* nextBpCB - call back function for next break points */
+/*-----------------------------------------------------------------*/
+BP_CALLBACK(nextBpCB)
+{
+ static function *lfunc = NULL;
+
+ Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
+
+ if (srcMode == SRC_CMODE) {
+ if ((lfunc && lfunc != ctxt->func) || !lfunc)
+ fprintf(stdout,"%s () at %s:%d\n",
+ 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 {
+ if ((lfunc && lfunc != ctxt->func) || !lfunc)
+ fprintf(stdout,"%s () at %s:%d\n",
+ 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);
+
+ }
+ lfunc = ctxt->func;
+
+ deleteNEXTbp();
+ return 1;
+}