5e22f58f33395d02efcb1b9d7e54bf505eb40165
[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 "newalloc.h"
28
29 static hTab *bptable = NULL;
30 char doingSteps    = 0;
31 char userBpPresent = 0;
32 /* call stack can be 1024 deep */
33 STACK_DCL(callStack,function *,1024);
34
35 #ifdef SDCDB_DEBUG
36 char *debug_bp_type_strings[] =
37     {"ERR-0",
38      "DATA",
39     "CODE"    ,
40     "A_CODE"  ,
41     "USER"    ,
42     "STEP"    ,
43     "NEXT"    ,
44     "FENTRY"  ,
45     "FEXIT", "", ""};
46 #endif
47
48 /*-----------------------------------------------------------------*/
49 /* setBreakPoint - creates an entry in the break point table       */
50 /*-----------------------------------------------------------------*/
51 int setBreakPoint (unsigned addr, char addrType, char bpType,
52         int (*callBack)(unsigned,char,char,int,context *) ,
53         char *fileName, int lineno)
54 {
55     breakp *bp, *bpl;
56     static long bpnum = 0;
57     char simbuf[50];
58
59     Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
60         addr,
61         debug_bp_type_strings[addrType],
62         debug_bp_type_strings[bpType],
63         fileName, lineno+1));
64
65     /* allocate & init a new bp */
66     bp = Safe_calloc(1,sizeof(breakp));
67     bp->addr = addr;
68     bp->addrType = addrType;
69     bp->bpType = bpType;
70     bp->callBack = callBack;
71     bp->bpnum = (bpType == USER ? ++bpnum : 0);
72     bp->filename = fileName;
73     bp->lineno = lineno;
74
75     /* if this is an user break point then
76        check if there already exists one for this address */
77     if (bpType == USER)
78     {
79         for ( bpl = hTabFirstItemWK(bptable,addr) ; bpl;
80               bpl = hTabNextItemWK(bptable)) 
81         {
82
83             /* if also a user break point then issue Note : */
84             if (bpl->bpType == USER)
85                 fprintf(stderr,"Note: breakpoint %d also set at pc 0x%x\n",
86                         bpl->bpnum,bpl->addr);
87         }
88
89         fprintf(stderr,"Breakpoint %d at 0x%x: file %s, line %d.\n",
90                 bp->bpnum, addr, fileName, lineno+1);
91
92         userBpPresent++;
93     }
94
95     if (bpType != STEP && bpType != NEXT)
96     {
97     /* if a break point does not already exist then
98        send command to simulator to add one */
99     if (!hTabSearch(bptable,addr))
100         /* send the break command to the simulator */
101         simSetBP (addr);
102     }
103
104     /* now add the break point to list */
105     hTabAddItem(&bptable,addr,bp);
106
107     return bp->bpnum ;
108 }
109
110 /*-----------------------------------------------------------------*/
111 /* deleteSTEPbp - deletes all step break points                    */
112 /*-----------------------------------------------------------------*/
113 void deleteSTEPbp ()
114 {
115     breakp *bp;
116     int k;
117
118     Dprintf(D_break, ("break: Deleting all STEP BPs\n"));
119     /* for break points delete if they are STEP */
120     for ( bp = hTabFirstItem(bptable,&k); bp ;
121     bp = hTabNextItem(bptable,&k)) {
122
123   /* if this is a step then delete */
124   if (bp->bpType == STEP) {
125       hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
126
127 #if 0
128       /* if this leaves no other break points then
129          send command to simulator to delete bp from this addr */
130       if (hTabSearch(bptable,bp->addr) == NULL)
131     simClearBP (bp->addr);
132 #endif
133       free(bp);
134   }
135     }
136
137 }
138
139 /*-----------------------------------------------------------------*/
140 /* deleteNEXTbp - deletes all step break points                    */
141 /*-----------------------------------------------------------------*/
142 void deleteNEXTbp ()
143 {
144     breakp *bp;
145     int k;
146     char simcmd[50];
147
148     Dprintf(D_break, ("break: Deleting all NEXT BPs\n"));
149
150     /* for break points delete if they are NEXT */
151     for ( bp = hTabFirstItem(bptable,&k); bp ;
152     bp = hTabNextItem(bptable,&k)) {
153
154   /* if this is a step then delete */
155   if (bp->bpType == NEXT) {
156       hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
157
158 #if 0
159       /* if this leaves no other break points then
160          send command to simulator to delete bp from this addr */
161       if (hTabSearch(bptable,bp->addr) == NULL) {
162     simClearBP(bp->addr);
163
164       }
165 #endif
166       free(bp);
167   }
168     }
169
170 }
171
172 /*-----------------------------------------------------------------*/
173 /* deleteUSERbp - deletes USER break point with number             */
174 /*-----------------------------------------------------------------*/
175 void deleteUSERbp (int bpnum)
176 {
177     breakp *bp;
178     int k;
179     char simcmd[50];
180
181     Dprintf(D_break, ("break: deleteUSERbp %d\n", bpnum));
182
183     /* for break points delete if they are STEP */
184     for ( bp = hTabFirstItem(bptable,&k); bp ;
185     bp = hTabNextItem(bptable,&k)) {
186
187   /* if this is a user then delete if break
188      point matches or bpnumber == -1 (meaning delete
189      all user break points */
190   if (bp->bpType == USER && ( bp->bpnum == bpnum || bpnum == -1)) {
191       hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
192
193       /* if this leaves no other break points then
194          send command to simulator to delete bp from this addr */
195       if (hTabSearch(bptable,bp->addr) == NULL) {
196     simClearBP (bp->addr);
197     Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
198
199       }
200       fprintf(stdout,"Deleted breakpoint %d\n",
201         bp->bpnum);
202       userBpPresent --;
203       if (bpnum == -1)
204     continue ;
205       else
206     break;
207   }
208     }
209
210     if (!bp && bpnum != -1)
211   fprintf(stderr,"No breakpoint number %d.\n",bpnum);
212 }
213
214 /*-----------------------------------------------------------------*/
215 /* listUSERbp - list all user break points                         */
216 /*-----------------------------------------------------------------*/
217 void listUSERbp ()
218 {
219     breakp *bp;
220     int k;
221
222     /* if there are none then say so & return */
223     if (!userBpPresent) {
224   fprintf(stdout,"No breakpoints.\n");
225   return ;
226     }
227     fprintf(stdout,"Num Type           Disp Enb Address    What\n");
228     for ( bp = hTabFirstItem(bptable,&k) ; bp ;
229     bp = hTabNextItem(bptable,&k)) {
230
231   if (bp->bpType == USER ) {
232       fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
233         bp->bpnum,bp->addr,
234         bp->filename,bp->lineno+1);
235
236   }
237     }
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* simStopBPCB - simulator stopped break point                     */
242 /*-----------------------------------------------------------------*/
243 static int simStopBPCB( unsigned int addr)
244 {
245   fprintf(stdout,"Simulator stopped at Address 0x%04x\n",addr);
246   fprintf(stdout,"%s",simResponse());
247   return 1;
248 }
249
250 /*-----------------------------------------------------------------*/
251 /* clearUSERbp - deletes USER break point at address               */
252 /*-----------------------------------------------------------------*/
253 void clearUSERbp ( unsigned int addr )
254 {
255     breakp *bp;
256     char simcmd[50];
257
258     /* for break points delete if they are STEP */
259     for ( bp = hTabFirstItemWK(bptable,addr); bp ;
260     bp = hTabNextItemWK(bptable)) {
261
262   /* if this is a step then delete */
263   if (bp->bpType == USER) {
264       hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
265
266       /* if this leaves no other break points then
267          send command to simulator to delete bp from this addr */
268       if (hTabSearch(bptable,bp->addr) == NULL) {
269     simClearBP(bp->addr);
270
271       }
272       fprintf(stdout,"Deleted breakpoint %d\n",
273         bp->bpnum);
274       userBpPresent-- ;
275       break;
276   }
277     }
278
279     if (!bp)
280   fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
281 }
282
283 /*-----------------------------------------------------------------*/
284 /* dispatchCB - will lookup the bp table and dispatch the cb funcs */
285 /*-----------------------------------------------------------------*/
286 int dispatchCB (unsigned addr, context *ctxt)
287 {
288     breakp *bp;
289     int rv =0;
290
291     Dprintf(D_break, ("break: dispatchCB: addr:0x%x \n", addr));
292
293     /* if no break points set for this address
294        then use a simulator stop break point */
295     if ((bp = hTabFirstItemWK(bptable,addr)) == NULL) {
296       if ( doingSteps == 2 ) return 1;
297       if ( doingSteps ) return 0;
298       if ( contsim    ) return 0;
299       return simStopBPCB(addr);
300     }
301
302     /* dispatch the call back functions */
303     for (; bp; bp = hTabNextItemWK(bptable)) {
304
305       rv += (*bp->callBack)(addr,bp->addrType,
306           bp->bpType,bp->bpnum,ctxt);
307
308     }
309
310     if (rv == 0) {
311       Dprintf(D_break, ("break: dispatchCB: WARNING rv==0\n", rv));
312     }
313
314     return rv;
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* fentryCB - callback function for function entry                 */
319 /*-----------------------------------------------------------------*/
320 BP_CALLBACK(fentryCB)
321 {
322     Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry\n"));
323
324     /* add the current function into the call stack */
325     STACK_PUSH(callStack,ctxt->func);
326
327     /* will have to add code here to get the value of SP
328        which will be used to display the value of local variables
329        and parameters on the stack */
330
331     return 0;
332 }
333
334 /*-----------------------------------------------------------------*/
335 /* fexitCB - call back for function exit                           */
336 /*-----------------------------------------------------------------*/
337 BP_CALLBACK(fexitCB)
338 {
339     Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry\n"));
340
341     /* pop the top most from the call stack */
342     STACK_POP(callStack);
343     return 0;
344 }
345 /*-----------------------------------------------------------------*/
346 /* userBpCB - call back function for user break points             */
347 /*-----------------------------------------------------------------*/
348 BP_CALLBACK(userBpCB)
349 {
350     Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry\n"));
351
352     if (srcMode == SRC_CMODE) {
353   fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
354     bpnum,
355     ctxt->func->sym->name,
356     ctxt->func->mod->c_name,
357     ctxt->cline+1);
358   if (ctxt->func->mod && ctxt->cline > 0)
359       fprintf(stdout,"%d\t%s",ctxt->cline+1,
360         ctxt->func->mod->cLines[ctxt->cline]->src);
361     } else {
362   fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
363     bpnum,
364     ctxt->func->sym->name,
365     ctxt->func->mod->asm_name,
366     ctxt->asmline+1);
367   if (ctxt->func->mod && ctxt->asmline > 0)
368       fprintf(stdout,"%d\t%s",ctxt->asmline+1,
369         ctxt->func->mod->asmLines[ctxt->asmline]->src);
370     }
371
372     return 1;
373 }
374
375 /*-----------------------------------------------------------------*/
376 /* stepBpCB - call back function for step break points             */
377 /*-----------------------------------------------------------------*/
378 BP_CALLBACK(stepBpCB)
379 {
380     static function *lfunc = NULL;
381
382     Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
383
384     if (srcMode == SRC_CMODE) {
385   if ((lfunc && lfunc != ctxt->func) || !lfunc)
386       fprintf(stdout,"%s () at %s:%d\n",
387         ctxt->func->sym->name,
388         ctxt->func->mod->c_name,
389         ctxt->cline+1);
390
391   if (ctxt->func->mod && ctxt->cline > 0) {
392       fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
393         ctxt->func->mod->cLines[ctxt->cline]->src);
394   }
395     } else {
396   if ((lfunc && lfunc != ctxt->func) || !lfunc)
397       fprintf(stdout,"%s () at %s:%d\n",
398         ctxt->func->sym->name,
399         ctxt->func->mod->asm_name,
400         ctxt->asmline);
401
402   if (ctxt->func->mod && ctxt->cline > 0) {
403       fprintf(stdout,"%d\t%s",ctxt->asmline ,
404         ctxt->func->mod->asmLines[ctxt->asmline]->src);
405   }
406     }
407     lfunc = ctxt->func;
408
409     deleteSTEPbp();
410     return 1;
411 }
412
413 /*-----------------------------------------------------------------*/
414 /* nextBpCB - call back function for next break points             */
415 /*-----------------------------------------------------------------*/
416 BP_CALLBACK(nextBpCB)
417 {
418     static function *lfunc = NULL;
419
420     Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
421
422     if (srcMode == SRC_CMODE) {
423   if ((lfunc && lfunc != ctxt->func) || !lfunc)
424       fprintf(stdout,"%s () at %s:%d\n",
425         ctxt->func->sym->name,
426         ctxt->func->mod->c_name,
427         ctxt->cline+1);
428
429   if (ctxt->func->mod && ctxt->cline > 0)
430       fprintf(stdout,"%d\t%s",ctxt->cline+1,
431         ctxt->func->mod->cLines[ctxt->cline]->src);
432     } else {
433   if ((lfunc && lfunc != ctxt->func) || !lfunc)
434       fprintf(stdout,"%s () at %s:%d\n",
435         ctxt->func->sym->name,
436         ctxt->func->mod->asm_name,
437         ctxt->asmline);
438
439   if (ctxt->func->mod && ctxt->asmline > 0)
440       fprintf(stdout,"%d\t%s",ctxt->asmline,
441         ctxt->func->mod->asmLines[ctxt->asmline]->src);
442
443     }
444     lfunc = ctxt->func;
445
446     deleteNEXTbp();
447     return 1;
448 }