0637661932aaf1ad4edf63fe4384114dfa1cd90a
[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 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
78     Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
79         addr,
80         debug_bp_type_strings[addrType],
81         debug_bp_type_strings[bpType],
82         fileName, lineno+1));
83
84     /* allocate & init a new bp */
85     bp = Safe_calloc(1,sizeof(breakp));
86     bp->addr = addr;
87     bp->addrType = addrType;
88     bp->bpType = bpType;
89     bp->callBack = callBack;
90     bp->bpnum = ((bpType == USER || bpType == TMPUSER)? ++bpnum : 0);
91     bp->filename = fileName;
92     bp->lineno = lineno;
93
94     /* if this is an user break point then
95        check if there already exists one for this address */
96     if (bpType == USER || bpType == TMPUSER)
97     {
98         for ( bpl = hTabFirstItemWK(bptable,addr) ; bpl;
99               bpl = hTabNextItemWK(bptable))
100         {
101
102             /* if also a user break point then issue Note : */
103             if (bpl->bpType == USER || bpType == TMPUSER)
104                 fprintf(stderr,"Note: breakpoint %d also set at pc 0x%x\n",
105                         bpl->bpnum,bpl->addr);
106         }
107
108         fprintf(stderr,"Breakpoint %d at 0x%x: file %s, line %d.\n",
109                 bp->bpnum, addr, fileName, lineno+1);
110
111         userBpPresent++;
112     }
113
114     if (bpType != STEP && bpType != NEXT)
115     {
116         /* if a break point does not already exist then
117            send command to simulator to add one */
118         if (!hTabSearch(bptable,addr))
119             /* send the break command to the simulator */
120             simSetBP (addr);
121     }
122
123     /* now add the break point to list */
124     hTabAddItem(&bptable,addr,bp);
125
126     return bp->bpnum ;
127 }
128
129 /*-----------------------------------------------------------------*/
130 /* deleteSTEPbp - deletes all step break points                    */
131 /*-----------------------------------------------------------------*/
132 void deleteSTEPbp ()
133 {
134     breakp *bp;
135     int k;
136
137     Dprintf(D_break, ("break: Deleting all STEP BPs\n"));
138     /* for break points delete if they are STEP */
139     for ( bp = hTabFirstItem(bptable,&k); bp ;
140           bp = hTabNextItem(bptable,&k))
141     {
142
143         /* if this is a step then delete */
144         if (bp->bpType == STEP)
145         {
146             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
147             Safe_free(bp);
148         }
149     }
150
151 }
152
153 /*-----------------------------------------------------------------*/
154 /* deleteNEXTbp - deletes all step break points                    */
155 /*-----------------------------------------------------------------*/
156 void deleteNEXTbp ()
157 {
158     breakp *bp;
159     int k;
160
161     Dprintf(D_break, ("break: Deleting all NEXT BPs\n"));
162
163     /* for break points delete if they are NEXT */
164     for ( bp = hTabFirstItem(bptable,&k); bp ;
165           bp = hTabNextItem(bptable,&k))
166     {
167
168         /* if this is a step then delete */
169         if (bp->bpType == NEXT)
170         {
171             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
172             Safe_free(bp);
173         }
174     }
175
176 }
177
178 static void freeUSERbp(breakp *bp)
179 {
180     if ( bp->commands )
181         Safe_free(bp->commands);
182     if ( bp->condition )
183         Safe_free(bp->condition);
184     Safe_free(bp);
185 }
186
187 /*-----------------------------------------------------------------*/
188 /* deleteUSERbp - deletes USER break point with number             */
189 /*-----------------------------------------------------------------*/
190 void deleteUSERbp (int bpnum)
191 {
192     breakp *bp;
193     int k;
194
195     Dprintf(D_break, ("break: deleteUSERbp %d\n", bpnum));
196
197     /* for break points delete if they are STEP */
198     for ( bp = hTabFirstItem(bptable,&k); bp ;
199           bp = hTabNextItem(bptable,&k)) {
200
201         /* if this is a user then delete if break
202            point matches or bpnumber == -1 (meaning delete
203            all user break points */
204         if ((bp->bpType == USER || bp->bpType == TMPUSER )
205             && ( bp->bpnum == bpnum || bpnum == -1))
206         {
207             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
208
209             /* if this leaves no other break points then
210                send command to simulator to delete bp from this addr */
211             if (hTabSearch(bptable,bp->addr) == NULL) {
212                 simClearBP (bp->addr);
213                 Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
214
215             }
216             fprintf(stdout,"Deleted breakpoint %d\n",bp->bpnum);
217             userBpPresent-- ;
218             freeUSERbp(bp);
219             if (bpnum == -1)
220                 continue ;
221             else
222                 break;
223         }
224     }
225
226     if (!bp && bpnum != -1)
227         fprintf(stderr,"No breakpoint number %d.\n",bpnum);
228 }
229
230 /*-----------------------------------------------------------------*/
231 /* setUserbpCommand - set commandstring for breakpoint             */
232 /*-----------------------------------------------------------------*/
233 void setUserbpCommand (int bpnum, char *cmds)
234 {
235     breakp *bp;
236     int k;
237     Dprintf(D_break, ("break: setUserbpCommand %d: commands:\n%send\n",
238                       bpnum, cmds));
239
240     for ( bp = hTabFirstItem(bptable,&k); bp ;
241           bp = hTabNextItem(bptable,&k))
242     {
243         if ((bp->bpType == USER || bp->bpType == TMPUSER )
244             && ( bp->bpnum == bpnum ))
245         {
246             if ( bp->commands )
247                 Safe_free(bp->commands);
248             bp->commands = cmds;
249             return;
250         }
251     }
252     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
253 }
254
255 /*-----------------------------------------------------------------*/
256 /* setUserbpCondition - set condition string for breakpoint        */
257 /*-----------------------------------------------------------------*/
258 void setUserbpCondition (int bpnum, char *cond)
259 {
260     breakp *bp;
261     int k;
262     Dprintf(D_break, ("break: setUserbpCondition %d: condition:'%s'\n",
263                       bpnum, cond?cond:""));
264
265     for ( bp = hTabFirstItem(bptable,&k); bp ;
266           bp = hTabNextItem(bptable,&k))
267     {
268         if ((bp->bpType == USER || bp->bpType == TMPUSER )
269             && ( bp->bpnum == bpnum ))
270         {
271             if ( bp->condition )
272                 Safe_free(bp->condition);
273             bp->condition = cond;
274             return;
275         }
276     }
277     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
278 }
279
280 /*-----------------------------------------------------------------*/
281 /* setUserbpIgnCount - set ignorecount for breakpoint              */
282 /*-----------------------------------------------------------------*/
283 void setUserbpIgnCount (int bpnum, int ignorecnt )
284 {
285     breakp *bp;
286     int k;
287     Dprintf(D_break, ("break: setUserbpIgnCount %d: ignorecnt=%d\n",
288                       bpnum, ignorecnt));
289
290     for ( bp = hTabFirstItem(bptable,&k); bp ;
291           bp = hTabNextItem(bptable,&k))
292     {
293         if ((bp->bpType == USER || bp->bpType == TMPUSER )
294             && ( bp->bpnum == bpnum ))
295         {
296             bp->ignoreCnt = bp->hitCnt + ignorecnt;
297             return;
298         }
299     }
300     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
301 }
302
303 /*-----------------------------------------------------------------*/
304 /* listUSERbp - list all user break points                         */
305 /*-----------------------------------------------------------------*/
306 void listUSERbp ()
307 {
308     breakp *bp;
309     int k, isuser;
310
311     /* if there are none then say so & return */
312     if (!userBpPresent) {
313         fprintf(stdout,"No breakpoints.\n");
314         return ;
315     }
316     fprintf(stdout,"Num Type           Disp Enb Address    What\n");
317     for ( bp = hTabFirstItem(bptable,&k) ; bp ;
318           bp = hTabNextItem(bptable,&k)) {
319
320         isuser = 0;
321         if (bp->bpType == USER ) {
322             fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
323                     bp->bpnum,bp->addr,
324                     bp->filename,bp->lineno+1);
325             isuser = 1;
326         }
327         else if (bp->bpType == TMPUSER ) {
328             fprintf(stdout,"%-3d breakpoint      del y   0x%08x at %s:%d\n",
329                     bp->bpnum,bp->addr,
330                     bp->filename,bp->lineno+1);
331             isuser = 1;
332         }
333         if ( ! isuser )
334             continue;
335         if ( bp->ignoreCnt > bp->hitCnt )
336             fprintf(stdout,"\tignore next %d hits\n",
337                     bp->ignoreCnt - bp->hitCnt );
338         if ( bp->condition )
339             fprintf(stdout,"\tstop only if %s\n",bp->condition );
340         if ( bp->hitCnt > 0 )
341             fprintf(stdout,"\tbreakpoint already hit %d time%s\n",
342                     bp->hitCnt,bp->hitCnt>1?"s":"" );
343
344
345     }
346 }
347
348 /*-----------------------------------------------------------------*/
349 /* simStopBPCB - simulator stopped break point                     */
350 /*-----------------------------------------------------------------*/
351 static int simStopBPCB( unsigned int addr)
352 {
353   fprintf(stdout,"Simulator stopped at Address 0x%04x\n",addr);
354   fprintf(stdout,"%s",simResponse());
355   return 1;
356 }
357
358 /*-----------------------------------------------------------------*/
359 /* clearUSERbp - deletes USER break point at address               */
360 /*-----------------------------------------------------------------*/
361 void clearUSERbp ( unsigned int addr )
362 {
363     breakp *bp;
364
365     /* for break points delete if they are STEP */
366     for ( bp = hTabFirstItemWK(bptable,addr); bp ;
367           bp = hTabNextItemWK(bptable)) {
368
369         /* if this is a step then delete */
370         if (bp->bpType == USER || bp->bpType == TMPUSER)
371         {
372             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
373
374             /* if this leaves no other break points then
375                send command to simulator to delete bp from this addr */
376             if (hTabSearch(bptable,bp->addr) == NULL)
377             {
378                 simClearBP(bp->addr);
379             }
380             fprintf(stdout,"Deleted breakpoint %d\n",
381                     bp->bpnum);
382             userBpPresent-- ;
383             freeUSERbp(bp);
384             break;
385         }
386     }
387
388     if (!bp)
389         fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
390 }
391
392 /*-----------------------------------------------------------------*/
393 /* dispatchCB - will lookup the bp table and dispatch the cb funcs */
394 /*-----------------------------------------------------------------*/
395 int dispatchCB (unsigned addr, context *ctxt)
396 {
397     breakp *bp;
398     int rv =0;
399
400     Dprintf(D_break, ("break: dispatchCB: addr:0x%x \n", addr));
401
402     /* if no break points set for this address
403        then use a simulator stop break point */
404     if ((bp = hTabFirstItemWK(bptable,addr)) == NULL) {
405       if ( doingSteps == 2 ) return 1;
406       if ( doingSteps ) return 0;
407       if ( contsim    ) return 0;
408       return simStopBPCB(addr);
409     }
410
411     /* dispatch the call back functions */
412     for (; bp; bp = hTabNextItemWK(bptable))
413     {
414         rv += (*bp->callBack)(addr,bp,ctxt);
415     }
416
417     if (rv == 0) {
418       Dprintf(D_break, ("break: dispatchCB: WARNING rv==0\n", rv));
419     }
420
421     return rv;
422 }
423
424 /*-----------------------------------------------------------------*/
425 /* fentryCB - callback function for function entry                 */
426 /*-----------------------------------------------------------------*/
427 BP_CALLBACK(fentryCB)
428 {
429     function *func;
430
431     /* we save the value of SP
432        which will be used to display the value of local variables
433        and parameters on the stack */
434     ctxt->func->stkaddr = simGetValue (0x81,'I',1);
435
436     Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry %s sp=0x%02x %p\n",
437                       ctxt->func->sym->name,
438                       ctxt->func->stkaddr, p_callStack));
439
440     /* and set laddr of calling function to return addr from stack */
441     if ((func = STACK_PEEK(callStack)))
442     {
443         /* extern stack ?? 'A' */
444         func->laddr = simGetValue (ctxt->func->stkaddr-1,'B',2);
445     }
446     /* add the current function into the call stack */
447     STACK_PUSH(callStack,ctxt->func);
448
449     return 0;
450 }
451
452 /*-----------------------------------------------------------------*/
453 /* fexitCB - call back for function exit                           */
454 /*-----------------------------------------------------------------*/
455 BP_CALLBACK(fexitCB)
456 {
457     function *func;
458     /* pop the top most from the call stack */
459     func = STACK_POP(callStack);
460
461     if (!func)
462     {
463         fprintf(stdout, "Stack underflow\n");
464         return 1;
465     }
466
467     Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry %s %p\n", func->sym->name, p_callStack));
468
469     /* check main function */
470     if ( !strcmp(func->sym->name, "main"))
471     {
472         fprintf(stdout, "Program exited with code %lu.\n", simGetValue (0x82,'I',2));
473         return 1;
474     }
475     return 0;
476 }
477 /*-----------------------------------------------------------------*/
478 /* userBpCB - call back function for user break points             */
479 /*-----------------------------------------------------------------*/
480 BP_CALLBACK(userBpCB)
481 {
482     bp->hitCnt++ ;
483     Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry hit=%d ignor=%d\n",
484                       bp->hitCnt, bp->ignoreCnt));
485
486     if ( bp->ignoreCnt > bp->hitCnt )
487         return 0;
488
489     if ( bp->condition )
490     {
491         if (! conditionIsTrue( bp->condition, ctxt ))
492             return 0;
493     }
494
495     if ( bp->commands )
496     {
497         Dprintf(D_break, ("break: userBpCB: commands:%p\n", bp->commands));
498         setCmdLine(bp->commands);
499     }
500
501     if (srcMode == SRC_CMODE) {
502         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
503                 bp->bpnum,
504                 ctxt->func->sym->name,
505                 ctxt->func->mod->c_name,
506                 ctxt->cline+1);
507         if (ctxt->func->mod && ctxt->cline > 0)
508             fprintf(stdout,"%d\t%s",ctxt->cline+1,
509                     ctxt->func->mod->cLines[ctxt->cline]->src);
510     } else {
511         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
512                 bp->bpnum,
513                 ctxt->func->sym->name,
514                 ctxt->func->mod->asm_name,
515                 ctxt->asmline+1);
516         if (ctxt->func->mod && ctxt->asmline > 0)
517             fprintf(stdout,"%d\t%s",ctxt->asmline+1,
518                     ctxt->func->mod->asmLines[ctxt->asmline]->src);
519     }
520
521     if ( bp->bpType == TMPUSER && bp->bpnum > 0 )
522     {
523         hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
524
525         /* if this leaves no other break points then
526            send command to simulator to delete bp from this addr */
527         if (hTabSearch(bptable,bp->addr) == NULL)
528         {
529             simClearBP (bp->addr);
530             Dprintf(D_break, ("break: simClearBP 0x%x\n", bp->addr));
531
532         }
533         userBpPresent-- ;
534         freeUSERbp(bp);
535     }
536     return 1;
537 }
538
539 /*-----------------------------------------------------------------*/
540 /* stepBpCB - call back function for step break points             */
541 /*-----------------------------------------------------------------*/
542 BP_CALLBACK(stepBpCB)
543 {
544     static function *lfunc = NULL;
545
546     Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
547
548     if (srcMode == SRC_CMODE) {
549   if ((lfunc && lfunc != ctxt->func) || !lfunc)
550       fprintf(stdout,"%s () at %s:%d\n",
551         ctxt->func->sym->name,
552         ctxt->func->mod->c_name,
553         ctxt->cline+1);
554
555   if (ctxt->func->mod && ctxt->cline > 0) {
556       fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
557         ctxt->func->mod->cLines[ctxt->cline]->src);
558   }
559     } else {
560   if ((lfunc && lfunc != ctxt->func) || !lfunc)
561       fprintf(stdout,"%s () at %s:%d\n",
562         ctxt->func->sym->name,
563         ctxt->func->mod->asm_name,
564         ctxt->asmline);
565
566   if (ctxt->func->mod && ctxt->cline > 0) {
567       fprintf(stdout,"%d\t%s",ctxt->asmline ,
568         ctxt->func->mod->asmLines[ctxt->asmline]->src);
569   }
570     }
571     lfunc = ctxt->func;
572
573     deleteSTEPbp();
574     return 1;
575 }
576
577 /*-----------------------------------------------------------------*/
578 /* nextBpCB - call back function for next break points             */
579 /*-----------------------------------------------------------------*/
580 BP_CALLBACK(nextBpCB)
581 {
582     static function *lfunc = NULL;
583
584     Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
585
586     if (srcMode == SRC_CMODE) {
587   if ((lfunc && lfunc != ctxt->func) || !lfunc)
588       fprintf(stdout,"%s () at %s:%d\n",
589         ctxt->func->sym->name,
590         ctxt->func->mod->c_name,
591         ctxt->cline+1);
592
593   if (ctxt->func->mod && ctxt->cline > 0)
594       fprintf(stdout,"%d\t%s",ctxt->cline+1,
595         ctxt->func->mod->cLines[ctxt->cline]->src);
596     } else {
597   if ((lfunc && lfunc != ctxt->func) || !lfunc)
598       fprintf(stdout,"%s () at %s:%d\n",
599         ctxt->func->sym->name,
600         ctxt->func->mod->asm_name,
601         ctxt->asmline);
602
603   if (ctxt->func->mod && ctxt->asmline > 0)
604       fprintf(stdout,"%d\t%s",ctxt->asmline,
605         ctxt->func->mod->asmLines[ctxt->asmline]->src);
606
607     }
608     lfunc = ctxt->func;
609
610     deleteNEXTbp();
611     return 1;
612 }