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 #undef DATADIR
26 #include "symtab.h"
27 #include "break.h"
28 #include "cmd.h"
29 #include "newalloc.h"
30 
31 hTab *bptable = NULL;
32 char doingSteps    = 0;
33 char userBpPresent = 0;
34 
35 /* call stack can be 1024 deep */
36 STACK_DCL(callStack,function *,1024)
37 
38 #ifdef SDCDB_DEBUG
39 char *debug_bp_type_strings[] =
40     {"ERR-0",
41      "DATA",
42     "CODE"    ,
43     "A_CODE"  ,
44     "USER"    ,
45     "STEP"    ,
46     "NEXT"    ,
47     "FENTRY"  ,
48     "FEXIT", "TMPUSER", ""};
49 #endif
50 
51 static long bpnum = 0;
52 
getLastBreakptNumber()53 long getLastBreakptNumber()
54 {
55     return bpnum;
56 }
57 
resetHitCount()58 void resetHitCount()
59 {
60     int k;
61     breakp *bp;
62     for ( bp = hTabFirstItem(bptable,&k); bp ;
63           bp = hTabNextItem(bptable,&k))
64     {
65         bp->hitCnt    = 0;
66         bp->ignoreCnt = 0;
67     }
68 }
69 
70 /*-----------------------------------------------------------------*/
71 /* setBreakPoint - creates an entry in the break point table       */
72 /*-----------------------------------------------------------------*/
setBreakPoint(unsigned addr,char addrType,char bpType,int (* callBack)(unsigned,breakp *,context *),char * fileName,int lineno)73 int setBreakPoint (unsigned addr, char addrType, char bpType,
74         int (*callBack)(unsigned,breakp *,context *) ,
75         char *fileName, int lineno)
76 {
77     breakp *bp, *bpl;
78 
79     Dprintf(D_break, ("setBreakPoint: addr:%x atype:%s bpType:%s [%s:%d]\n",
80         addr,
81         debug_bp_type_strings[(int)addrType],
82         debug_bp_type_strings[(int)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 /*-----------------------------------------------------------------*/
deleteSTEPbp()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 /*-----------------------------------------------------------------*/
deleteNEXTbp()157 void deleteNEXTbp ()
158 {
159     breakp *bp;
160     int k;
161 
162     Dprintf(D_break, ("break: Deleting all NEXT BPs\n"));
163 
164     /* for break points delete if they are NEXT */
165     for ( bp = hTabFirstItem(bptable,&k); bp ;
166           bp = hTabNextItem(bptable,&k))
167     {
168 
169         /* if this is a step then delete */
170         if (bp->bpType == NEXT)
171         {
172             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
173             Safe_free(bp);
174         }
175     }
176 
177 }
178 
freeUSERbp(breakp * bp)179 static void freeUSERbp(breakp *bp)
180 {
181     if ( bp->commands )
182         Safe_free(bp->commands);
183     if ( bp->condition )
184         Safe_free(bp->condition);
185     Safe_free(bp);
186 }
187 
188 /*-----------------------------------------------------------------*/
189 /* deleteUSERbp - deletes USER break point with number             */
190 /*-----------------------------------------------------------------*/
deleteUSERbp(int bpnum)191 void deleteUSERbp (int bpnum)
192 {
193     breakp *bp;
194     int k;
195 
196     Dprintf(D_break, ("break: deleteUSERbp %d\n", bpnum));
197 
198     /* for break points delete if they are STEP */
199     for ( bp = hTabFirstItem(bptable,&k); bp ;
200           bp = hTabNextItem(bptable,&k)) {
201 
202         /* if this is a user then delete if break
203            point matches or bpnumber == -1 (meaning delete
204            all user break points */
205         if ((bp->bpType == USER || bp->bpType == TMPUSER )
206             && ( bp->bpnum == bpnum || bpnum == -1))
207         {
208             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
209 
210             /* if this leaves no other break points then
211                send command to simulator to delete bp from this addr */
212             if (hTabSearch(bptable,bp->addr) == NULL) {
213                 simClearBP (bp->addr);
214                 Dprintf(D_break, ("break: deleteUSERbp:simClearBP 0x%x\n", bp->addr));
215 
216             }
217             fprintf(stdout,"Deleted breakpoint %d\n",bp->bpnum);
218             userBpPresent-- ;
219             freeUSERbp(bp);
220             if (bpnum == -1)
221                 continue ;
222             else
223                 break;
224         }
225     }
226 
227     if (!bp && bpnum != -1)
228         fprintf(stderr,"No breakpoint number %d.\n",bpnum);
229 }
230 
231 /*-----------------------------------------------------------------*/
232 /* setUserbpCommand - set commandstring for breakpoint             */
233 /*-----------------------------------------------------------------*/
setUserbpCommand(int bpnum,char * cmds)234 void setUserbpCommand (int bpnum, char *cmds)
235 {
236     breakp *bp;
237     int k;
238     Dprintf(D_break, ("break: setUserbpCommand %d: commands:\n%send\n",
239                       bpnum, cmds));
240 
241     for ( bp = hTabFirstItem(bptable,&k); bp ;
242           bp = hTabNextItem(bptable,&k))
243     {
244         if ((bp->bpType == USER || bp->bpType == TMPUSER )
245             && ( bp->bpnum == bpnum ))
246         {
247             if ( bp->commands )
248                 Safe_free(bp->commands);
249             bp->commands = cmds;
250             return;
251         }
252     }
253     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
254 }
255 
256 /*-----------------------------------------------------------------*/
257 /* setUserbpCondition - set condition string for breakpoint        */
258 /*-----------------------------------------------------------------*/
setUserbpCondition(int bpnum,char * cond)259 void setUserbpCondition (int bpnum, char *cond)
260 {
261     breakp *bp;
262     int k;
263     Dprintf(D_break, ("break: setUserbpCondition %d: condition:'%s'\n",
264                       bpnum, cond?cond:""));
265 
266     for ( bp = hTabFirstItem(bptable,&k); bp ;
267           bp = hTabNextItem(bptable,&k))
268     {
269         if ((bp->bpType == USER || bp->bpType == TMPUSER )
270             && ( bp->bpnum == bpnum ))
271         {
272             if ( bp->condition )
273                 Safe_free(bp->condition);
274             bp->condition = cond;
275             return;
276         }
277     }
278     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
279 }
280 
281 /*-----------------------------------------------------------------*/
282 /* setUserbpIgnCount - set ignorecount for breakpoint              */
283 /*-----------------------------------------------------------------*/
setUserbpIgnCount(int bpnum,int ignorecnt)284 void setUserbpIgnCount (int bpnum, int ignorecnt )
285 {
286     breakp *bp;
287     int k;
288     Dprintf(D_break, ("break: setUserbpIgnCount %d: ignorecnt=%d\n",
289                       bpnum, ignorecnt));
290 
291     for ( bp = hTabFirstItem(bptable,&k); bp ;
292           bp = hTabNextItem(bptable,&k))
293     {
294         if ((bp->bpType == USER || bp->bpType == TMPUSER )
295             && ( bp->bpnum == bpnum ))
296         {
297             bp->ignoreCnt = bp->hitCnt + ignorecnt;
298             return;
299         }
300     }
301     fprintf(stderr,"No breakpoint number %d.\n",bpnum);
302 }
303 
304 /*-----------------------------------------------------------------*/
305 /* listUSERbp - list all user break points                         */
306 /*-----------------------------------------------------------------*/
listUSERbp()307 void listUSERbp ()
308 {
309     breakp *bp;
310     int k, isuser;
311 
312     /* if there are none then say so & return */
313     if (!userBpPresent) {
314         fprintf(stdout,"No breakpoints.\n");
315         return ;
316     }
317     fprintf(stdout,"Num Type           Disp Enb Address    What\n");
318     for ( bp = hTabFirstItem(bptable,&k) ; bp ;
319           bp = hTabNextItem(bptable,&k)) {
320 
321         isuser = 0;
322         if (bp->bpType == USER ) {
323             fprintf(stdout,"%-3d breakpoint     keep y   0x%08x at %s:%d\n",
324                     bp->bpnum,bp->addr,
325                     bp->filename,bp->lineno+1);
326             isuser = 1;
327         }
328         else if (bp->bpType == TMPUSER ) {
329             fprintf(stdout,"%-3d breakpoint      del y   0x%08x at %s:%d\n",
330                     bp->bpnum,bp->addr,
331                     bp->filename,bp->lineno+1);
332             isuser = 1;
333         }
334         if ( ! isuser )
335             continue;
336         if ( bp->ignoreCnt > bp->hitCnt )
337             fprintf(stdout,"\tignore next %d hits\n",
338                     bp->ignoreCnt - bp->hitCnt );
339         if ( bp->condition )
340             fprintf(stdout,"\tstop only if %s\n",bp->condition );
341         if ( bp->hitCnt > 0 )
342             fprintf(stdout,"\tbreakpoint already hit %d time%s\n",
343                     bp->hitCnt,bp->hitCnt>1?"s":"" );
344 
345 
346     }
347 }
348 
349 /*-----------------------------------------------------------------*/
350 /* simStopBPCB - simulator stopped break point                     */
351 /*-----------------------------------------------------------------*/
simStopBPCB(unsigned int addr)352 static int simStopBPCB( unsigned int addr)
353 {
354   fprintf(stdout,"Simulator stopped at Address 0x%04x\n",addr);
355   fprintf(stdout,"%s",simResponse());
356   return 1;
357 }
358 
359 /*-----------------------------------------------------------------*/
360 /* clearUSERbp - deletes USER break point at address               */
361 /*-----------------------------------------------------------------*/
clearUSERbp(unsigned int addr)362 void clearUSERbp ( unsigned int addr )
363 {
364     breakp *bp;
365 
366     /* for break points delete if they are STEP */
367     for ( bp = hTabFirstItemWK(bptable,addr); bp ;
368           bp = hTabNextItemWK(bptable)) {
369 
370         /* if this is a step then delete */
371         if (bp->bpType == USER || bp->bpType == TMPUSER)
372         {
373             hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
374 
375             /* if this leaves no other break points then
376                send command to simulator to delete bp from this addr */
377             if (hTabSearch(bptable,bp->addr) == NULL)
378             {
379                 simClearBP(bp->addr);
380             }
381             fprintf(stdout,"Deleted breakpoint %d\n",
382                     bp->bpnum);
383             userBpPresent-- ;
384             freeUSERbp(bp);
385             break;
386         }
387     }
388 
389     if (!bp)
390         fprintf(stderr,"No breakpoint at address 0x%x.\n",addr);
391 }
392 
393 /*-----------------------------------------------------------------*/
394 /* dispatchCB - will lookup the bp table and dispatch the cb funcs */
395 /*-----------------------------------------------------------------*/
dispatchCB(unsigned addr,context * ctxt)396 int dispatchCB (unsigned addr, context *ctxt)
397 {
398     breakp *bp;
399     int rv =0;
400 
401     Dprintf(D_break, ("break: dispatchCB: addr:0x%x \n", addr));
402 
403     /* if no break points set for this address
404        then use a simulator stop break point */
405     if ((bp = hTabFirstItemWK(bptable,addr)) == NULL) {
406       if ( doingSteps == 2 ) return 1;
407       if ( doingSteps ) return 0;
408       if ( contsim    ) return 0;
409       return simStopBPCB(addr);
410     }
411 
412     /* dispatch the call back functions */
413     for (; bp; bp = hTabNextItemWK(bptable))
414     {
415         rv += (*bp->callBack)(addr,bp,ctxt);
416     }
417 
418     if (rv == 0) {
419       Dprintf(D_break, ("break: dispatchCB: WARNING rv==0\n"));
420     }
421 
422     return rv;
423 }
424 
425 /*-----------------------------------------------------------------*/
426 /* fentryCB - callback function for function entry                 */
427 /*-----------------------------------------------------------------*/
BP_CALLBACK(fentryCB)428 BP_CALLBACK(fentryCB)
429 {
430     function *func;
431 
432     /* we save the value of SP
433        which will be used to display the value of local variables
434        and parameters on the stack */
435     ctxt->func->stkaddr = simGetValue (0x81,'I',1);
436 
437     Dprintf(D_break, ("break: fentryCB: BP_CALLBACK entry %s sp=0x%02x %p\n",
438                       ctxt->func->sym->name,
439                       ctxt->func->stkaddr, p_callStack));
440 
441     /* and set laddr of calling function to return addr from stack */
442     if ((func = STACK_PEEK(callStack)))
443     {
444         /* extern stack ?? 'A' */
445         func->laddr = simGetValue (ctxt->func->stkaddr-1,'B',2);
446     }
447     /* add the current function into the call stack */
448     STACK_PUSH(callStack,ctxt->func);
449 
450     return 0;
451 }
452 
453 /*-----------------------------------------------------------------*/
454 /* fexitCB - call back for function exit                           */
455 /*-----------------------------------------------------------------*/
BP_CALLBACK(fexitCB)456 BP_CALLBACK(fexitCB)
457 {
458     function *func;
459     /* pop the top most from the call stack */
460     func = STACK_POP(callStack);
461 
462     if (!func)
463     {
464         fprintf(stdout, "Stack underflow\n");
465         return 1;
466     }
467 
468     Dprintf(D_break, ("break: fexitCB: BP_CALLBACK entry %s %p\n", func->sym->name, p_callStack));
469 
470     /* check main function */
471     if ( !strcmp(func->sym->name, "main"))
472     {
473         fprintf(stdout, "Program exited with code %lu.\n", simGetValue (0x82,'I',2));
474         return 1;
475     }
476     return 0;
477 }
478 /*-----------------------------------------------------------------*/
479 /* userBpCB - call back function for user break points             */
480 /*-----------------------------------------------------------------*/
BP_CALLBACK(userBpCB)481 BP_CALLBACK(userBpCB)
482 {
483     bp->hitCnt++ ;
484     Dprintf(D_break, ("break: userBpCB: BP_CALLBACK entry hit=%d ignor=%d\n",
485                       bp->hitCnt, bp->ignoreCnt));
486 
487     if ( bp->ignoreCnt > bp->hitCnt )
488         return 0;
489 
490     if ( bp->condition )
491     {
492         if (! conditionIsTrue( bp->condition, ctxt ))
493             return 0;
494     }
495 
496     if ( bp->commands )
497     {
498         Dprintf(D_break, ("break: userBpCB: commands:%p\n", bp->commands));
499         setCmdLine(bp->commands);
500     }
501 
502     if (srcMode == SRC_CMODE) {
503         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
504                 bp->bpnum,
505                 ctxt->func->sym->name,
506                 ctxt->func->mod->c_name,
507                 ctxt->cline+1);
508         if (ctxt->func->mod && ctxt->cline > 0)
509             fprintf(stdout,"%d\t%s",ctxt->cline+1,
510                     ctxt->func->mod->cLines[ctxt->cline]->src);
511     } else {
512         fprintf(stdout,"Breakpoint %d, %s() at %s:%d\n",
513                 bp->bpnum,
514                 ctxt->func->sym->name,
515                 ctxt->func->mod->asm_name,
516                 ctxt->asmline+1);
517         if (ctxt->func->mod && ctxt->asmline > 0)
518             fprintf(stdout,"%d\t%s",ctxt->asmline+1,
519                     ctxt->func->mod->asmLines[ctxt->asmline]->src);
520     }
521 
522     if ( bp->bpType == TMPUSER && bp->bpnum > 0 )
523     {
524         hTabDeleteItem(&bptable,bp->addr,bp,DELETE_ITEM,NULL);
525 
526         /* if this leaves no other break points then
527            send command to simulator to delete bp from this addr */
528         if (hTabSearch(bptable,bp->addr) == NULL)
529         {
530             simClearBP (bp->addr);
531             Dprintf(D_break, ("break: simClearBP 0x%x\n", bp->addr));
532 
533         }
534         userBpPresent-- ;
535         freeUSERbp(bp);
536     }
537     return 1;
538 }
539 
540 /*-----------------------------------------------------------------*/
541 /* stepBpCB - call back function for step break points             */
542 /*-----------------------------------------------------------------*/
BP_CALLBACK(stepBpCB)543 BP_CALLBACK(stepBpCB)
544 {
545     static function *lfunc = NULL;
546 
547     Dprintf(D_break, ("break: stepBpCB: BP_CALLBACK entry\n"));
548 
549     if (srcMode == SRC_CMODE) {
550   if ((lfunc && lfunc != ctxt->func) || !lfunc)
551       fprintf(stdout,"%s () at %s:%d\n",
552         ctxt->func->sym->name,
553         ctxt->func->mod->c_name,
554         ctxt->cline+1);
555 
556   if (ctxt->func->mod && ctxt->cline > 0) {
557       fprintf(stdout,"%d\t%s",ctxt->cline+1 ,
558         ctxt->func->mod->cLines[ctxt->cline]->src);
559   }
560     } else {
561   if ((lfunc && lfunc != ctxt->func) || !lfunc)
562       fprintf(stdout,"%s () at %s:%d\n",
563         ctxt->func->sym->name,
564         ctxt->func->mod->asm_name,
565         ctxt->asmline);
566 
567   if (ctxt->func->mod && ctxt->cline > 0) {
568       fprintf(stdout,"%d\t%s",ctxt->asmline ,
569         ctxt->func->mod->asmLines[ctxt->asmline]->src);
570   }
571     }
572     lfunc = ctxt->func;
573 
574     deleteSTEPbp();
575     return 1;
576 }
577 
578 /*-----------------------------------------------------------------*/
579 /* nextBpCB - call back function for next break points             */
580 /*-----------------------------------------------------------------*/
BP_CALLBACK(nextBpCB)581 BP_CALLBACK(nextBpCB)
582 {
583     static function *lfunc = NULL;
584 
585     Dprintf(D_break, ("break: nextBpCB: BP_CALLBACK entry\n"));
586 
587     if (srcMode == SRC_CMODE) {
588   if ((lfunc && lfunc != ctxt->func) || !lfunc)
589       fprintf(stdout,"%s () at %s:%d\n",
590         ctxt->func->sym->name,
591         ctxt->func->mod->c_name,
592         ctxt->cline+1);
593 
594   if (ctxt->func->mod && ctxt->cline > 0)
595       fprintf(stdout,"%d\t%s",ctxt->cline+1,
596         ctxt->func->mod->cLines[ctxt->cline]->src);
597     } else {
598   if ((lfunc && lfunc != ctxt->func) || !lfunc)
599       fprintf(stdout,"%s () at %s:%d\n",
600         ctxt->func->sym->name,
601         ctxt->func->mod->asm_name,
602         ctxt->asmline);
603 
604   if (ctxt->func->mod && ctxt->asmline > 0)
605       fprintf(stdout,"%d\t%s",ctxt->asmline,
606         ctxt->func->mod->asmLines[ctxt->asmline]->src);
607 
608     }
609     lfunc = ctxt->func;
610 
611     deleteNEXTbp();
612     return 1;
613 }
614