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