a new function for startup (_main)
[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     Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry %s %p\n",func->sym->name, p_callStack));
466
467     /* check main function */
468     if ( STACK_EMPTY(callStack))
469     {
470         fprintf(stdout,"Program exited with code %d.\n",simGetValue (0x82,'I',2));
471         return 1;
472     }
473     return 0;
474 }
475 /*-----------------------------------------------------------------*/
476 /* userBpCB - call back function for user break points             */
477 /*-----------------------------------------------------------------*/
478 BP_CALLBACK(userBpCB)
479 {
480     bp->hitCnt++ ;
481     Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry hit=%d ignor=%d\n",
482                       bp->hitCnt, bp->ignoreCnt));
483
484     if ( bp->ignoreCnt > bp->hitCnt )
485         return 0;
486
487     if ( bp->condition )
488     {
489         if (! conditionIsTrue( bp->condition, ctxt ))
490             return 0;
491     }
492
493     if ( bp->commands )
494     {
495         Dprintf(D_break, ("break: userBpCB: commands:%d\n", bp->commands));
496         setCmdLine(bp->commands);
497     }
498     
499     if (srcMode == SRC_CMODE) {
500         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
501                 bp->bpnum,
502                 ctxt->func->sym->name,
503                 ctxt->func->mod->c_name,
504                 ctxt->cline+1);
505         if (ctxt->func->mod && ctxt->cline > 0)
506             fprintf(stdout,"%d\t%s",ctxt->cline+1,
507                     ctxt->func->mod->cLines[ctxt->cline]->src);
508     } else {
509         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
510                 bp->bpnum,
511                 ctxt->func->sym->name,
512                 ctxt->func->mod->asm_name,
513                 ctxt->asmline+1);
514         if (ctxt->func->mod && ctxt->asmline > 0)
515             fprintf(stdout,"%d\t%s",ctxt->asmline+1,
516                     ctxt->func->mod->asmLines[ctxt->asmline]->src);
517     }
518
519     if ( bp->bpType == TMPUSER && bp->bpnum > 0 )
520     {
521         hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
522
523         /* if this leaves no other break points then
524            send command to simulator to delete bp from this addr */
525         if (hTabSearch(bptable,bp->addr) == NULL) 
526         {
527             simClearBP (bp->addr);
528             Dprintf(D_break, ("break: simClearBP 0x%x\n", bp->addr));
529
530         }
531         userBpPresent-- ;
532         freeUSERbp(bp);
533     }
534     return 1;
535 }
536
537 /*-----------------------------------------------------------------*/
538 /* stepBpCB - call back function for step break points             */
539 /*-----------------------------------------------------------------*/
540 BP_CALLBACK(stepBpCB)
541 {
542     static function *lfunc = NULL;
543
544     Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
545
546     if (srcMode == SRC_CMODE) {
547   if ((lfunc && lfunc != ctxt->func) || !lfunc)
548       fprintf(stdout,"%s () at %s:%d\n",
549         ctxt->func->sym->name,
550         ctxt->func->mod->c_name,
551         ctxt->cline+1);
552
553   if (ctxt->func->mod && ctxt->cline > 0) {
554       fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
555         ctxt->func->mod->cLines[ctxt->cline]->src);
556   }
557     } else {
558   if ((lfunc && lfunc != ctxt->func) || !lfunc)
559       fprintf(stdout,"%s () at %s:%d\n",
560         ctxt->func->sym->name,
561         ctxt->func->mod->asm_name,
562         ctxt->asmline);
563
564   if (ctxt->func->mod && ctxt->cline > 0) {
565       fprintf(stdout,"%d\t%s",ctxt->asmline ,
566         ctxt->func->mod->asmLines[ctxt->asmline]->src);
567   }
568     }
569     lfunc = ctxt->func;
570
571     deleteSTEPbp();
572     return 1;
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* nextBpCB - call back function for next break points             */
577 /*-----------------------------------------------------------------*/
578 BP_CALLBACK(nextBpCB)
579 {
580     static function *lfunc = NULL;
581
582     Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
583
584     if (srcMode == SRC_CMODE) {
585   if ((lfunc && lfunc != ctxt->func) || !lfunc)
586       fprintf(stdout,"%s () at %s:%d\n",
587         ctxt->func->sym->name,
588         ctxt->func->mod->c_name,
589         ctxt->cline+1);
590
591   if (ctxt->func->mod && ctxt->cline > 0)
592       fprintf(stdout,"%d\t%s",ctxt->cline+1,
593         ctxt->func->mod->cLines[ctxt->cline]->src);
594     } else {
595   if ((lfunc && lfunc != ctxt->func) || !lfunc)
596       fprintf(stdout,"%s () at %s:%d\n",
597         ctxt->func->sym->name,
598         ctxt->func->mod->asm_name,
599         ctxt->asmline);
600
601   if (ctxt->func->mod && ctxt->asmline > 0)
602       fprintf(stdout,"%d\t%s",ctxt->asmline,
603         ctxt->func->mod->asmLines[ctxt->asmline]->src);
604
605     }
606     lfunc = ctxt->func;
607
608     deleteNEXTbp();
609     return 1;
610 }