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