check now pop stack result
[fw/sdcc] / debugger / mcs51 / break.c
1 /*-------------------------------------------------------------------------
2   break.c - Source file for break point management
3         Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
4
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by the
7    Free Software Foundation; either version 2, or (at your option) any
8    later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19    In other words, you are welcome to use, share and improve this program.
20    You are forbidden to forbid anyone else to use, share and improve
21    what you give them.   Help stamp out software-hoarding!
22 -------------------------------------------------------------------------*/
23
24 #include "sdcdb.h"
25 #include "symtab.h"
26 #include "break.h"
27 #include "cmd.h"
28 #include "newalloc.h"
29
30 static hTab *bptable = NULL;
31 char doingSteps    = 0;
32 char userBpPresent = 0;
33                                 
34 /* call stack can be 1024 deep */
35 STACK_DCL(callStack,function *,1024);
36
37 #ifdef SDCDB_DEBUG
38 char *debug_bp_type_strings[] =
39     {"ERR-0",
40      "DATA",
41     "CODE"    ,
42     "A_CODE"  ,
43     "USER"    ,
44     "STEP"    ,
45     "NEXT"    ,
46     "FENTRY"  ,
47     "FEXIT", "TMPUSER", ""};
48 #endif
49
50 static long bpnum = 0;
51
52 long getLastBreakptNumber()
53 {
54     return bpnum;
55 }
56
57 void resetHitCount()
58 {
59     int k;
60     breakp *bp;
61     for ( bp = hTabFirstItem(bptable,&k); bp ;
62           bp = hTabNextItem(bptable,&k)) 
63     {
64         bp->hitCnt    = 0;
65         bp->ignoreCnt = 0;
66     }
67 }
68
69 /*-----------------------------------------------------------------*/
70 /* setBreakPoint - creates an entry in the break point table       */
71 /*-----------------------------------------------------------------*/
72 int setBreakPoint (unsigned addr, char addrType, char bpType,
73         int (*callBack)(unsigned,breakp *,context *) ,
74         char *fileName, int lineno)
75 {
76     breakp *bp, *bpl;
77     char simbuf[50];
78
79     Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
80         addr,
81         debug_bp_type_strings[addrType],
82         debug_bp_type_strings[bpType],
83         fileName, lineno+1));
84
85     /* allocate & init a new bp */
86     bp = Safe_calloc(1,sizeof(breakp));
87     bp->addr = addr;
88     bp->addrType = addrType;
89     bp->bpType = bpType;
90     bp->callBack = callBack;
91     bp->bpnum = ((bpType == USER || bpType == TMPUSER)? ++bpnum : 0);
92     bp->filename = fileName;
93     bp->lineno = lineno;
94
95     /* if this is an user break point then
96        check if there already exists one for this address */
97     if (bpType == USER || bpType == TMPUSER)
98     {
99         for ( bpl = hTabFirstItemWK(bptable,addr) ; bpl;
100               bpl = hTabNextItemWK(bptable)) 
101         {
102
103             /* if also a user break point then issue Note : */
104             if (bpl->bpType == USER || bpType == TMPUSER)
105                 fprintf(stderr,"Note: breakpoint %d also set at pc 0x%x\n",
106                         bpl->bpnum,bpl->addr);
107         }
108
109         fprintf(stderr,"Breakpoint %d at 0x%x: file %s, line %d.\n",
110                 bp->bpnum, addr, fileName, lineno+1);
111
112         userBpPresent++;
113     }
114
115     if (bpType != STEP && bpType != NEXT)
116     {
117         /* if a break point does not already exist then
118            send command to simulator to add one */
119         if (!hTabSearch(bptable,addr))
120             /* send the break command to the simulator */
121             simSetBP (addr);
122     }
123
124     /* now add the break point to list */
125     hTabAddItem(&bptable,addr,bp);
126
127     return bp->bpnum ;
128 }
129
130 /*-----------------------------------------------------------------*/
131 /* deleteSTEPbp - deletes all step break points                    */
132 /*-----------------------------------------------------------------*/
133 void deleteSTEPbp ()
134 {
135     breakp *bp;
136     int k;
137
138     Dprintf(D_break, ("break: Deleting all STEP BPs\n"));
139     /* for break points delete if they are STEP */
140     for ( bp = hTabFirstItem(bptable,&k); bp ;
141           bp = hTabNextItem(bptable,&k)) 
142     {
143
144         /* if this is a step then delete */
145         if (bp->bpType == STEP) 
146         {
147             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
148             Safe_free(bp);
149         }
150     }
151
152 }
153
154 /*-----------------------------------------------------------------*/
155 /* deleteNEXTbp - deletes all step break points                    */
156 /*-----------------------------------------------------------------*/
157 void deleteNEXTbp ()
158 {
159     breakp *bp;
160     int k;
161     char simcmd[50];
162
163     Dprintf(D_break, ("break: Deleting all NEXT BPs\n"));
164
165     /* for break points delete if they are NEXT */
166     for ( bp = hTabFirstItem(bptable,&k); bp ;
167           bp = hTabNextItem(bptable,&k)) 
168     {
169
170         /* if this is a step then delete */
171         if (bp->bpType == NEXT) 
172         {
173             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
174             Safe_free(bp);
175         }
176     }
177
178 }
179
180 static void freeUSERbp(breakp *bp)
181 {
182     if ( bp->commands )
183         Safe_free(bp->commands);
184     if ( bp->condition )
185         Safe_free(bp->condition);
186     Safe_free(bp);
187 }
188
189 /*-----------------------------------------------------------------*/
190 /* deleteUSERbp - deletes USER break point with number             */
191 /*-----------------------------------------------------------------*/
192 void deleteUSERbp (int bpnum)
193 {
194     breakp *bp;
195     int k;
196     char simcmd[50];
197
198     Dprintf(D_break, ("break: deleteUSERbp %d\n", bpnum));
199
200     /* for break points delete if they are STEP */
201     for ( bp = hTabFirstItem(bptable,&k); bp ;
202           bp = hTabNextItem(bptable,&k)) {
203
204         /* if this is a user then delete if break
205            point matches or bpnumber == -1 (meaning delete
206            all user break points */
207         if ((bp->bpType == USER || bp->bpType == TMPUSER )
208             && ( bp->bpnum == bpnum || bpnum == -1)) 
209         {
210             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
211
212             /* if this leaves no other break points then
213                send command to simulator to delete bp from this addr */
214             if (hTabSearch(bptable,bp->addr) == NULL) {
215                 simClearBP (bp->addr);
216                 Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
217
218             }
219             fprintf(stdout,"Deleted breakpoint %d\n",bp->bpnum);
220             userBpPresent-- ;
221             freeUSERbp(bp);
222             if (bpnum == -1)
223                 continue ;
224             else
225                 break;
226         }
227     }
228
229     if (!bp && bpnum != -1)
230         fprintf(stderr,"No breakpoint number %d.\n",bpnum);
231 }
232
233 /*-----------------------------------------------------------------*/
234 /* setUserbpCommand - set commandstring for breakpoint             */
235 /*-----------------------------------------------------------------*/
236 void setUserbpCommand (int bpnum, char *cmds)
237 {
238     breakp *bp;
239     int k;
240     Dprintf(D_break, ("break: setUserbpCommand %d: commands:\n%send\n",
241                       bpnum, cmds));
242
243     for ( bp = hTabFirstItem(bptable,&k); bp ;
244           bp = hTabNextItem(bptable,&k)) 
245     {
246         if ((bp->bpType == USER || bp->bpType == TMPUSER )
247             && ( bp->bpnum == bpnum )) 
248         {
249             if ( bp->commands )
250                 Safe_free(bp->commands);
251             bp->commands = cmds;
252             return;
253         }
254     }
255     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
256 }
257
258 /*-----------------------------------------------------------------*/
259 /* setUserbpCondition - set condition string for breakpoint        */
260 /*-----------------------------------------------------------------*/
261 void setUserbpCondition (int bpnum, char *cond)
262 {
263     breakp *bp;
264     int k;
265     Dprintf(D_break, ("break: setUserbpCondition %d: condition:'%s'\n",
266                       bpnum, cond?cond:""));
267
268     for ( bp = hTabFirstItem(bptable,&k); bp ;
269           bp = hTabNextItem(bptable,&k)) 
270     {
271         if ((bp->bpType == USER || bp->bpType == TMPUSER )
272             && ( bp->bpnum == bpnum )) 
273         {
274             if ( bp->condition )
275                 Safe_free(bp->condition);
276             bp->condition = cond;
277             return;
278         }
279     }
280     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
281 }
282
283 /*-----------------------------------------------------------------*/
284 /* setUserbpIgnCount - set ignorecount for breakpoint              */
285 /*-----------------------------------------------------------------*/
286 void setUserbpIgnCount (int bpnum, int ignorecnt )
287 {
288     breakp *bp;
289     int k;
290     Dprintf(D_break, ("break: setUserbpIgnCount %d: ignorecnt=%d\n",
291                       bpnum, ignorecnt));
292
293     for ( bp = hTabFirstItem(bptable,&k); bp ;
294           bp = hTabNextItem(bptable,&k)) 
295     {
296         if ((bp->bpType == USER || bp->bpType == TMPUSER )
297             && ( bp->bpnum == bpnum )) 
298         {
299             bp->ignoreCnt = bp->hitCnt + ignorecnt;
300             return;
301         }
302     }
303     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
304 }
305
306 /*-----------------------------------------------------------------*/
307 /* listUSERbp - list all user break points                         */
308 /*-----------------------------------------------------------------*/
309 void listUSERbp ()
310 {
311     breakp *bp;
312     int k, isuser;
313
314     /* if there are none then say so & return */
315     if (!userBpPresent) {
316         fprintf(stdout,"No breakpoints.\n");
317         return ;
318     }
319     fprintf(stdout,"Num Type           Disp Enb Address    What\n");
320     for ( bp = hTabFirstItem(bptable,&k) ; bp ;
321           bp = hTabNextItem(bptable,&k)) {
322
323         isuser = 0;
324         if (bp->bpType == USER ) {
325             fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
326                     bp->bpnum,bp->addr,
327                     bp->filename,bp->lineno+1);
328             isuser = 1;
329         }
330         else if (bp->bpType == TMPUSER ) {
331             fprintf(stdout,"%-3d breakpoint      del y   0x%08x at %s:%d\n",
332                     bp->bpnum,bp->addr,
333                     bp->filename,bp->lineno+1);
334             isuser = 1;
335         }
336         if ( ! isuser )
337             continue;
338         if ( bp->ignoreCnt > bp->hitCnt )
339             fprintf(stdout,"\tignore next %d hits\n",
340                     bp->ignoreCnt - bp->hitCnt );
341         if ( bp->condition )
342             fprintf(stdout,"\tstop only if %s\n",bp->condition );
343         if ( bp->hitCnt > 0 )
344             fprintf(stdout,"\tbreakpoint already hit %d time%s\n",
345                     bp->hitCnt,bp->hitCnt>1?"s":"" );
346         
347
348     }
349 }
350
351 /*-----------------------------------------------------------------*/
352 /* simStopBPCB - simulator stopped break point                     */
353 /*-----------------------------------------------------------------*/
354 static int simStopBPCB( unsigned int addr)
355 {
356   fprintf(stdout,"Simulator stopped at Address 0x%04x\n",addr);
357   fprintf(stdout,"%s",simResponse());
358   return 1;
359 }
360
361 /*-----------------------------------------------------------------*/
362 /* clearUSERbp - deletes USER break point at address               */
363 /*-----------------------------------------------------------------*/
364 void clearUSERbp ( unsigned int addr )
365 {
366     breakp *bp;
367     char simcmd[50];
368
369     /* for break points delete if they are STEP */
370     for ( bp = hTabFirstItemWK(bptable,addr); bp ;
371           bp = hTabNextItemWK(bptable)) {
372
373         /* if this is a step then delete */
374         if (bp->bpType == USER || bp->bpType == TMPUSER) 
375         {
376             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
377
378             /* if this leaves no other break points then
379                send command to simulator to delete bp from this addr */
380             if (hTabSearch(bptable,bp->addr) == NULL) 
381             {
382                 simClearBP(bp->addr);
383             }
384             fprintf(stdout,"Deleted breakpoint %d\n",
385                     bp->bpnum);
386             userBpPresent-- ;
387             freeUSERbp(bp);
388             break;
389         }
390     }
391
392     if (!bp)
393         fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
394 }
395
396 /*-----------------------------------------------------------------*/
397 /* dispatchCB - will lookup the bp table and dispatch the cb funcs */
398 /*-----------------------------------------------------------------*/
399 int dispatchCB (unsigned addr, context *ctxt)
400 {
401     breakp *bp;
402     int rv =0;
403
404     Dprintf(D_break, ("break: dispatchCB: addr:0x%x \n", addr));
405
406     /* if no break points set for this address
407        then use a simulator stop break point */
408     if ((bp = hTabFirstItemWK(bptable,addr)) == NULL) {
409       if ( doingSteps == 2 ) return 1;
410       if ( doingSteps ) return 0;
411       if ( contsim    ) return 0;
412       return simStopBPCB(addr);
413     }
414
415     /* dispatch the call back functions */
416     for (; bp; bp = hTabNextItemWK(bptable)) 
417     {
418         rv += (*bp->callBack)(addr,bp,ctxt);
419     }
420
421     if (rv == 0) {
422       Dprintf(D_break, ("break: dispatchCB: WARNING rv==0\n", rv));
423     }
424
425     return rv;
426 }
427
428 /*-----------------------------------------------------------------*/
429 /* fentryCB - callback function for function entry                 */
430 /*-----------------------------------------------------------------*/
431 BP_CALLBACK(fentryCB)
432 {
433     function *func;
434
435     /* we save the value of SP
436        which will be used to display the value of local variables
437        and parameters on the stack */
438     ctxt->func->stkaddr = simGetValue (0x81,'I',1);
439
440     Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry %s sp=0x%02x %p\n",
441                       ctxt->func->sym->name, 
442                       ctxt->func->stkaddr, p_callStack));
443
444     /* and set laddr of calling function to return addr from stack */
445     if ((func = STACK_PEEK(callStack)))
446     { 
447         /* extern stack ?? 'A' */
448         func->laddr = simGetValue (ctxt->func->stkaddr-1,'B',2);
449     }
450     /* add the current function into the call stack */
451     STACK_PUSH(callStack,ctxt->func);
452
453     return 0;
454 }
455
456 /*-----------------------------------------------------------------*/
457 /* fexitCB - call back for function exit                           */
458 /*-----------------------------------------------------------------*/
459 BP_CALLBACK(fexitCB)
460 {
461     function *func;
462     /* pop the top most from the call stack */
463     func = STACK_POP(callStack);
464
465     if (!func)
466     {
467         fprintf(stdout,"Stack underflow\n");
468         return 1;
469     }
470
471     Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry %s %p\n",func->sym->name, p_callStack));
472
473     /* check main function */
474     if ( STACK_EMPTY(callStack) && !strcmp(func->sym->name,"main"))
475     {
476         fprintf(stdout,"Program exited with code %d.\n",simGetValue (0x82,'I',2));
477         return 1;
478     }
479     return 0;
480 }
481 /*-----------------------------------------------------------------*/
482 /* userBpCB - call back function for user break points             */
483 /*-----------------------------------------------------------------*/
484 BP_CALLBACK(userBpCB)
485 {
486     bp->hitCnt++ ;
487     Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry hit=%d ignor=%d\n",
488                       bp->hitCnt, bp->ignoreCnt));
489
490     if ( bp->ignoreCnt > bp->hitCnt )
491         return 0;
492
493     if ( bp->condition )
494     {
495         if (! conditionIsTrue( bp->condition, ctxt ))
496             return 0;
497     }
498
499     if ( bp->commands )
500     {
501         Dprintf(D_break, ("break: userBpCB: commands:%d\n", bp->commands));
502         setCmdLine(bp->commands);
503     }
504     
505     if (srcMode == SRC_CMODE) {
506         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
507                 bp->bpnum,
508                 ctxt->func->sym->name,
509                 ctxt->func->mod->c_name,
510                 ctxt->cline+1);
511         if (ctxt->func->mod && ctxt->cline > 0)
512             fprintf(stdout,"%d\t%s",ctxt->cline+1,
513                     ctxt->func->mod->cLines[ctxt->cline]->src);
514     } else {
515         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
516                 bp->bpnum,
517                 ctxt->func->sym->name,
518                 ctxt->func->mod->asm_name,
519                 ctxt->asmline+1);
520         if (ctxt->func->mod && ctxt->asmline > 0)
521             fprintf(stdout,"%d\t%s",ctxt->asmline+1,
522                     ctxt->func->mod->asmLines[ctxt->asmline]->src);
523     }
524
525     if ( bp->bpType == TMPUSER && bp->bpnum > 0 )
526     {
527         hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
528
529         /* if this leaves no other break points then
530            send command to simulator to delete bp from this addr */
531         if (hTabSearch(bptable,bp->addr) == NULL) 
532         {
533             simClearBP (bp->addr);
534             Dprintf(D_break, ("break: simClearBP 0x%x\n", bp->addr));
535
536         }
537         userBpPresent-- ;
538         freeUSERbp(bp);
539     }
540     return 1;
541 }
542
543 /*-----------------------------------------------------------------*/
544 /* stepBpCB - call back function for step break points             */
545 /*-----------------------------------------------------------------*/
546 BP_CALLBACK(stepBpCB)
547 {
548     static function *lfunc = NULL;
549
550     Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
551
552     if (srcMode == SRC_CMODE) {
553   if ((lfunc && lfunc != ctxt->func) || !lfunc)
554       fprintf(stdout,"%s () at %s:%d\n",
555         ctxt->func->sym->name,
556         ctxt->func->mod->c_name,
557         ctxt->cline+1);
558
559   if (ctxt->func->mod && ctxt->cline > 0) {
560       fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
561         ctxt->func->mod->cLines[ctxt->cline]->src);
562   }
563     } else {
564   if ((lfunc && lfunc != ctxt->func) || !lfunc)
565       fprintf(stdout,"%s () at %s:%d\n",
566         ctxt->func->sym->name,
567         ctxt->func->mod->asm_name,
568         ctxt->asmline);
569
570   if (ctxt->func->mod && ctxt->cline > 0) {
571       fprintf(stdout,"%d\t%s",ctxt->asmline ,
572         ctxt->func->mod->asmLines[ctxt->asmline]->src);
573   }
574     }
575     lfunc = ctxt->func;
576
577     deleteSTEPbp();
578     return 1;
579 }
580
581 /*-----------------------------------------------------------------*/
582 /* nextBpCB - call back function for next break points             */
583 /*-----------------------------------------------------------------*/
584 BP_CALLBACK(nextBpCB)
585 {
586     static function *lfunc = NULL;
587
588     Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
589
590     if (srcMode == SRC_CMODE) {
591   if ((lfunc && lfunc != ctxt->func) || !lfunc)
592       fprintf(stdout,"%s () at %s:%d\n",
593         ctxt->func->sym->name,
594         ctxt->func->mod->c_name,
595         ctxt->cline+1);
596
597   if (ctxt->func->mod && ctxt->cline > 0)
598       fprintf(stdout,"%d\t%s",ctxt->cline+1,
599         ctxt->func->mod->cLines[ctxt->cline]->src);
600     } else {
601   if ((lfunc && lfunc != ctxt->func) || !lfunc)
602       fprintf(stdout,"%s () at %s:%d\n",
603         ctxt->func->sym->name,
604         ctxt->func->mod->asm_name,
605         ctxt->asmline);
606
607   if (ctxt->func->mod && ctxt->asmline > 0)
608       fprintf(stdout,"%d\t%s",ctxt->asmline,
609         ctxt->func->mod->asmLines[ctxt->asmline]->src);
610
611     }
612     lfunc = ctxt->func;
613
614     deleteNEXTbp();
615     return 1;
616 }