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