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