Martin adds condition,ignore cmds
[fw/sdcc] / debugger / mcs51 / sdcdb.c
1 /*-------------------------------------------------------------------------
2   sdcdb.c - main source file for sdcdb debugger
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 "simi.h"
27 #include "break.h"
28 #include "cmd.h"
29 #include "newalloc.h"
30
31 #ifdef SDCDB_DEBUG
32 int   sdcdbDebug = 0;
33 #endif
34
35 char *currModName = NULL;
36 cdbrecs *recsRoot = NULL ;
37 set  *modules = NULL;    /* set of all modules */
38 set  *functions = NULL ; /* set of functions */
39 set  *symbols = NULL   ; /* set of symbols */
40 set  *sfrsymbols= NULL ; /* set of symbols of sfr or sbit */
41 int nStructs = 0 ;
42 structdef **structs = NULL ; /* all structures */
43 int nLinkrecs = 0;
44 linkrec **linkrecs = NULL; /* all linkage editor records */
45 context *currCtxt = NULL;
46 short fullname = 0;
47 short showfull = 0;
48 char userinterrupt = 0;
49 char nointerrupt = 0;
50 char contsim = 0;
51 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ;
52 char *simArgs[40];
53 int nsimArgs = 0;
54 char model_str[20];
55 /* fake filename & lineno to make linker */
56 char *filename=NULL;
57 int lineno = 0;
58 int fatalError = 0;
59
60 static void commandLoop(FILE *cmdfile);
61
62 /* command table */
63 struct cmdtab
64 {
65     char      *cmd ;  /* command the user will enter */
66     int (*cmdfunc)(char *,context *);   /* function to execute when command is entered */
67     char *htxt ;    /* short help text */
68
69 } cmdTab[] = {
70     /* NOTE:- the search is done from the top, so "break" should
71        precede the synonym "b" */
72     /* break point */
73     { "break"    ,  cmdSetUserBp  ,
74       "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
75     },
76     { "tbreak"   ,  cmdSetTmpUserBp ,
77       "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
78     },
79     { "b"        ,  cmdSetUserBp  , NULL },
80
81     { "jump"   ,  cmdJump ,
82       "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *<address>]\n",
83     },
84     { "clear"    ,  cmdClrUserBp  ,
85       "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
86     },
87     { "cl"       ,  cmdClrUserBp  , NULL },
88
89     { "continue" ,  cmdContinue   ,
90       "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
91     },
92     { "condition" ,  cmdCondition   ,
93       "condition brkpoint_number expr\t\tSet condition for breakpoint.\n"
94     },
95     { "ignore" ,  cmdIgnore  ,
96       "brkpoint_number count\t\tSet ignore count for breakpoint.\n"
97     },
98     { "commands" ,  cmdCommands  ,
99       "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n"
100     },
101     { "c"        ,  cmdContinue   , NULL },
102
103     { "disassemble",cmdDisasmF    , "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" },
104     { "delete" ,  cmdDelUserBp  ,
105       "{d}elete n\t\t clears break point number n\n"
106     },
107     { "display"    ,  cmdDisplay     ,
108       "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
109     },
110     { "undisplay"  ,  cmdUnDisplay   ,
111       "undisplay [<variable>]\t dont display this variable or all\n"
112     },
113     { "down"     ,  cmdDown      ,
114       "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n"
115     },
116     { "up"       ,  cmdUp      ,
117       "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n"
118     },
119     { "d"        ,  cmdDelUserBp  , NULL },
120
121     { "info"     ,  cmdInfo       ,
122       "info <break stack frame registers all-registers>\n"
123       "\t list all break points, call-stack, frame or register information\n"
124     },
125
126     { "listasm"  ,  cmdListAsm    ,
127       "listasm {la}\t\t list assembler code for the current C line\n"
128     },
129     { "la"       ,  cmdListAsm    , NULL },
130     { "ls"       ,  cmdListSymbols  , "ls,lf,lm\t\t list symbols,functions,modules\n" },
131     { "lf"       ,  cmdListFunctions, NULL },
132     { "lm"       ,  cmdListModules  , NULL },
133     { "list"     ,  cmdListSrc    ,
134       "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
135     },
136     { "l"        ,  cmdListSrc    , NULL },
137     { "show"     ,  cmdShow       ,
138       "show"
139       " <copying warranty>\t copying & distribution terms, warranty\n"
140     },
141     { "set"      ,  cmdSetOption  , "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
142     { "stepi"    ,  cmdStepi      ,
143       "stepi\t\t\tStep one instruction exactly.\n"
144     },
145     { "step"     ,  cmdStep       ,
146       "{s}tep\t\t\tStep program until it reaches a different source line.\n"
147     },
148     { "source"   ,  cmdSource      ,
149       "source <FILE>\t\t\tRead commands from a file named FILE.\n"
150     },
151     { "s"        ,  cmdStep       , NULL },
152     { "nexti"    ,  cmdNexti      ,
153       "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
154     },
155     { "next"     ,  cmdNext       ,
156       "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
157     },
158     { "n"        ,  cmdNext       , NULL },
159     { "run"      ,  cmdRun        ,
160       "{r}un\t\t\tStart debugged program. \n"
161     },
162     { "r"        ,  cmdRun        , NULL },
163     { "ptype"    ,  cmdPrintType  ,
164       "{pt}ype <variable>\tprint type information of a variable\n"
165     },
166     { "pt"       ,  cmdPrintType  , NULL },
167     { "print"    ,  cmdPrint      ,
168       "{p}rint <variable>\t print value of given variable\n"
169     },
170     { "output"   ,  cmdOutput      ,
171       "output <variable>\t print value of given variable without $ and newline \n"
172     },
173     { "p"        ,  cmdPrint      , NULL },
174     { "file"     ,  cmdFile       ,
175       "file <filename>\t\t load symbolic information from <filename>\n"
176     },
177     { "frame"    ,  cmdFrame      ,
178       "{fr}ame\t\t print information about the current Stack\n"
179     },
180     { "finish"   ,  cmdFinish     ,
181       "{fi}nish\t\t execute till return of current function\n"
182     },
183     { "fi"       ,  cmdFinish     , NULL },
184     { "where"    ,  cmdWhere      , "where\t\t print stack\n" },
185     { "fr"       ,  cmdFrame      , NULL },
186     { "f"        ,  cmdFrame      , NULL },
187     { "x /i"     ,  cmdDisasm1    , "x\t\t disassemble one asm command\n" },
188     { "!"        ,  cmdSimulator  ,
189       "!<simulator command>\t send a command directly to the simulator\n"
190     },
191     { "."        ,  cmdSimulator  ,
192       ".{cmd}\t switch from simulator or debugger command mode\n"
193     },
194     { "help"     ,  cmdHelp       ,
195       "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
196     },
197     { "?"        ,  cmdHelp       , NULL },
198     { "h"        ,  cmdHelp       , NULL },
199
200     { "quit"     ,  cmdQuit       ,
201       "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
202     },
203     { "q"        ,  cmdQuit       , NULL }
204 };
205
206 /*-----------------------------------------------------------------*/
207 /* gc_strdup - make a string duplicate garbage collector aware     */
208 /*-----------------------------------------------------------------*/
209 char *gc_strdup(const char *s)
210 {
211     char *ret;
212     ret = Safe_malloc(strlen(s)+1);
213     strcpy(ret, s);
214     return ret;
215 }
216
217 /*-----------------------------------------------------------------*/
218 /* alloccpy - allocate copy and return a new string                */
219 /*-----------------------------------------------------------------*/
220 char *alloccpy ( char *s, int size)
221 {
222     char *d;
223
224     if (!size)
225   return NULL;
226
227     d = Safe_malloc(size+1);
228     memcpy(d,s,size);
229     d[size] = '\0';
230
231     return d;
232 }
233
234 /*-----------------------------------------------------------------*/
235 /* resize - resizes array of type with new size                    */
236 /*-----------------------------------------------------------------*/
237 void **resize (void **array, int newSize)
238 {
239     void **vptr;
240
241     if (array)
242   vptr = Safe_realloc(array,newSize*(sizeof(void **)));
243     else
244   vptr = calloc(1, sizeof(void **));
245
246     if (!vptr) {
247   fprintf(stderr,"sdcdb: out of memory \n");
248   exit(1);
249     }
250
251     return vptr;
252
253 }
254
255 /*-----------------------------------------------------------------*/
256 /* readCdb - reads the cdb files & puts the records into cdbLine   */
257 /*           linked list                                           */
258 /*-----------------------------------------------------------------*/
259 static int readCdb (FILE *file)
260 {
261     cdbrecs *currl ;
262     char buffer[1024];
263     char *bp ;
264
265     if (!(bp = fgets(buffer,sizeof(buffer),file)))
266       return 0;
267
268     currl = Safe_calloc(1,sizeof(cdbrecs));
269     recsRoot = currl ;
270
271     while (1) {
272
273   /* make sure this is a cdb record */
274   if (strchr("STLFM",*bp) && *(bp+1) == ':') {
275       /* depending on the record type */
276
277       switch (*bp) {
278       case 'S':
279     /* symbol record */
280     currl->type = SYM_REC;
281     break;
282       case 'T':
283     currl->type = STRUCT_REC;
284     break;
285       case 'L':
286     currl->type = LNK_REC;
287     break;
288       case 'F':
289     currl->type = FUNC_REC;
290     break;
291       case 'M':
292     currl->type = MOD_REC ;
293       }
294
295       bp += 2;
296       currl->line = Safe_malloc(strlen(bp));
297       strncpy(currl->line,bp,strlen(bp)-1);
298       currl->line[strlen(bp)-1] = '\0';
299   }
300
301   if (!(bp = fgets(buffer,sizeof(buffer),file)))
302       break;
303
304   if (feof(file))
305       break;
306
307   currl->next = Safe_calloc(1,sizeof(cdbrecs));
308   currl = currl->next;
309     }
310
311     return (recsRoot->line ? 1 : 0);
312 }
313
314 /*-----------------------------------------------------------------*/
315 /* searchDirsFname - search directory list & return the filename   */
316 /*-----------------------------------------------------------------*/
317 char *searchDirsFname (char *fname)
318 {
319     char *dirs , *sdirs;
320     FILE *rfile = NULL;
321     char buffer[128];
322
323     /* first try the current directory */
324     if ((rfile = fopen(fname,"r"))) {
325   fclose(rfile);
326   return strdup(fname) ;
327     }
328
329     if (!ssdirl)
330   return strdup(fname);
331
332     /* make a copy of the source directories */
333     dirs = sdirs = strdup(ssdirl);
334
335     /* assume that the separator is ':'
336        and try for each directory in the search list */
337     dirs = strtok(dirs,":");
338     while (dirs) {
339   if (dirs[strlen(dirs)] == '/')
340       sprintf(buffer,"%s%s",dirs,fname);
341   else
342       sprintf(buffer,"%s/%s",dirs,fname);
343   if ((rfile = fopen(buffer,"r")))
344       break ;
345   dirs = strtok(NULL,":");
346     }
347
348     free(sdirs);
349     if (rfile) {
350   fclose(rfile);
351   return strdup(buffer);
352     } else
353   return strdup(fname);
354 }
355
356 /*-----------------------------------------------------------------*/
357 /* searchDirsFopen - go thru list of directories for filename given*/
358 /*-----------------------------------------------------------------*/
359 FILE *searchDirsFopen(char *fname)
360 {
361     char *dirs , *sdirs;
362     FILE *rfile = NULL;
363     char buffer[128];
364
365     /* first try the current directory */
366     if ((rfile = fopen(fname,"r")))
367   return rfile;
368
369     if (!ssdirl)
370   return NULL;
371     /* make a copy of the source directories */
372     dirs = sdirs = strdup(ssdirl);
373
374     /* assume that the separator is ':'
375        and try for each directory in the search list */
376     dirs = strtok(dirs,":");
377     while (dirs) {
378   sprintf(buffer,"%s/%s",dirs,fname);
379   if ((rfile = fopen(buffer,"r")))
380       break ;
381   dirs = strtok(NULL,":");
382     }
383
384     free(sdirs);
385     return rfile ;
386
387 }
388
389 /*-----------------------------------------------------------------*/
390 /* loadFile - loads a file into module buffer                      */
391 /*-----------------------------------------------------------------*/
392 srcLine **loadFile (char *name, int *nlines)
393 {
394     FILE *mfile ;
395     char buffer[512];
396     char *bp;
397     srcLine **slines = NULL;
398
399
400     if (!(mfile = searchDirsFopen(name))) {
401   fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
402   return NULL;
403     }
404
405     while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
406   (*nlines)++;
407
408   slines = (srcLine **)resize((void **)slines,*nlines);
409
410   slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
411   slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
412     }
413
414     fclose(mfile);
415     return slines;
416 }
417
418
419 /*-----------------------------------------------------------------*/
420 /* loadModules - reads the source files into module structure      */
421 /*-----------------------------------------------------------------*/
422 static void loadModules ()
423 {
424     cdbrecs *loop;
425     module *currMod;
426     char *rs;
427
428     /* go thru the records & find out the module
429        records & load the modules specified */
430     for ( loop = recsRoot ; loop ; loop = loop->next ) {
431
432   switch (loop->type) {
433   /* for module records do */
434   case MOD_REC:
435       currMod = parseModule(loop->line,TRUE);
436       currModName = currMod->name ;
437
438       currMod->cfullname = searchDirsFname(currMod->c_name);
439
440       /* load it into buffer */
441       currMod->cLines = loadFile (currMod->c_name,
442           &currMod->ncLines);
443
444       /* do the same for the assembler file */
445       currMod->afullname = searchDirsFname(currMod->asm_name);
446       currMod->asmLines=loadFile (currMod->asm_name,
447           &currMod->nasmLines);
448       break;
449
450   /* if this is a function record */
451   case FUNC_REC:
452       parseFunc(loop->line);
453       break;
454
455   /* if this is a structure record */
456   case STRUCT_REC:
457       parseStruct(loop->line);
458       break;
459
460   /* if symbol then parse the symbol */
461   case  SYM_REC:
462       parseSymbol(loop->line,&rs,2);
463       break;
464
465   case LNK_REC:
466       parseLnkRec(loop->line);
467       break;
468   }
469     }
470 }
471
472 /*-----------------------------------------------------------------*/
473 /* generate extra sets of sfr and sbit symbols                     */
474 /*-----------------------------------------------------------------*/
475 static void specialFunctionRegs ()
476 {
477     symbol *sym;
478     for (sym = setFirstItem(symbols);
479          sym ;
480          sym = setNextItem(symbols))
481     {
482         if ( sym->addrspace == 'I' ||
483              sym->addrspace == 'J')
484         {
485             addSet(&sfrsymbols,sym);
486         }
487     }
488 }
489 /*-----------------------------------------------------------------*/
490 /* functionPoints - determine the execution points within a func   */
491 /*-----------------------------------------------------------------*/
492 static void functionPoints ()
493 {
494     function *func;
495     symbol *sym;
496     exePoint *ep ;
497
498     /* for all functions do */
499     for ( func = setFirstItem(functions); func;
500     func = setNextItem(functions)) {
501   int j ;
502   module *mod;
503
504   sym = func->sym;
505
506   Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
507          func->sym->name,
508          func->sym->addr,
509          func->sym->eaddr));
510
511   if (!func->sym->addr && !func->sym->eaddr)
512       continue ;
513
514   /* for all source lines in the module find
515      the ones with address >= start and <= end
516      and put them in the point */
517   mod = NULL ;
518   if (! applyToSet(modules,moduleWithName,func->modName,&mod))
519       continue ;
520   func->mod = mod ;
521   func->entryline= INT_MAX;
522   func->exitline =  0;
523   func->aentryline = INT_MAX ;
524   func->aexitline = 0;
525
526   /* do it for the C Lines first */
527   for ( j = 0 ; j < mod->ncLines ; j++ ) {
528       if (mod->cLines[j]->addr >= sym->addr &&
529     mod->cLines[j]->addr <= sym->eaddr ) {
530
531
532     /* add it to the execution point */
533     if (func->entryline > j)
534         func->entryline = j;
535
536     if (func->exitline < j)
537         func->exitline = j;
538
539     ep = Safe_calloc(1,sizeof(exePoint));
540     ep->addr =  mod->cLines[j]->addr ;
541     ep->line = j;
542     ep->block= mod->cLines[j]->block;
543     ep->level= mod->cLines[j]->level;
544     addSet(&func->cfpoints,ep);
545       }
546   }
547   /* check double line execution points of module */
548   for (ep = setFirstItem(mod->cfpoints); ep;
549        ep = setNextItem(mod->cfpoints))
550   {
551       if (ep->addr >= sym->addr &&
552           ep->addr <= sym->eaddr ) 
553       {
554           addSet(&func->cfpoints,ep);
555       }
556   }
557   /* do the same for asm execution points */
558   for ( j = 0 ; j < mod->nasmLines ; j++ ) {
559       if (mod->asmLines[j]->addr >= sym->addr &&
560     mod->asmLines[j]->addr <= sym->eaddr ) {
561
562     exePoint *ep ;
563     /* add it to the execution point */
564     if (func->aentryline > j)
565         func->aentryline = j;
566
567     if (func->aexitline < j)
568         func->aexitline = j;
569
570     /* add it to the execution point */
571     ep = Safe_calloc(1,sizeof(exePoint));
572     ep->addr =  mod->asmLines[j]->addr ;
573     ep->line = j;
574     addSet(&func->afpoints,ep);
575       }
576   }
577
578 #ifdef SDCDB_DEBUG
579   if (!( D_sdcdb & sdcdbDebug))
580       continue;
581
582   Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
583          func->sym->name));
584   {
585       exePoint *ep;
586
587       for (ep = setFirstItem(func->cfpoints); ep;
588      ep = setNextItem(func->cfpoints))
589      Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
590          ep->addr,ep->line+1,mod->cLines[ep->line]->src));
591
592       Dprintf(D_sdcdb, ("sdcdb:  and the following ASM exePoints\n"));
593       for (ep = setFirstItem(func->afpoints); ep;
594            ep = setNextItem(func->afpoints))
595         Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
596             ep->addr,ep->line+1,mod->asmLines[ep->line]->src));
597   }
598 #endif
599     }
600 }
601
602
603 /*-----------------------------------------------------------------*/
604 /* setEntryExitBP - set the entry & exit Break Points for functions*/
605 /*-----------------------------------------------------------------*/
606 DEFSETFUNC(setEntryExitBP)
607 {
608     function *func = item;
609
610     if (func->sym && func->sym->addr && func->sym->eaddr) {
611
612   /* set the entry break point */
613   setBreakPoint (func->sym->addr , CODE , FENTRY ,
614            fentryCB ,func->mod->c_name , func->entryline);
615
616   /* set the exit break point */
617   setBreakPoint (func->sym->eaddr , CODE , FEXIT  ,
618            fexitCB  ,func->mod->c_name , func->exitline );
619     }
620
621     return 0;
622 }
623
624 /*-----------------------------------------------------------------*/
625 /* cmdFile - load file into the debugger                           */
626 /*-----------------------------------------------------------------*/
627 int cmdFile (char *s,context *cctxt)
628 {
629     FILE *cdbFile;
630     char buffer[128];
631     char *bp;
632
633     while (isspace(*s)) s++;
634     if (!*s) {
635   fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
636   return 0;
637     }
638
639     sprintf(buffer,"%s.cdb",s);
640     /* try creating the cdbfile */
641     if (!(cdbFile = searchDirsFopen(buffer))) {
642       fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
643       // return 0;
644     }
645
646     /* allocate for context */
647     currCtxt = Safe_calloc(1,sizeof(context));
648
649     if (cdbFile) {
650       /* readin the debug information */
651       if (!readCdb (cdbFile)) {
652         fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
653         //return 0;
654       }
655     }
656
657     /* parse and load the modules required */
658     loadModules();
659
660     /* determine the execution points for this
661        module */
662     functionPoints();
663
664     /* extract known special function registers */
665     specialFunctionRegs();
666
667     /* start the simulator & setup connection to it */
668     if ( sock == -1 )
669         openSimulator((char **)simArgs,nsimArgs);
670     fprintf(stdout,"%s",simResponse());
671     /* now send the filename to be loaded to the simulator */
672     sprintf(buffer,"%s.ihx",s);
673     bp=searchDirsFname(buffer);
674     simLoadFile(bp);
675     free(bp);
676
677     /*set the break points
678        required by the debugger . i.e. the function entry
679        and function exit break points */
680     applyToSet(functions,setEntryExitBP);
681
682     setMainContext();
683     return 0;
684 }
685
686 /*-----------------------------------------------------------------*/
687 /* cmdSource - read commands from file                             */
688 /*-----------------------------------------------------------------*/
689 int cmdSource (char *s, context *cctxt)
690 {
691     FILE *cmdfile;
692     char *bp = s+strlen(s) -1;
693
694     while (isspace(*s))
695       ++s;
696
697     while (isspace(*bp)) bp--;
698     *++bp = '\0';
699
700     if (!( cmdfile = searchDirsFopen(s)))
701     {
702         fprintf(stderr,"commandfile '%s' not found\n",s);
703         return 0;
704     }
705     commandLoop( cmdfile );
706     fclose( cmdfile );
707     return 0;
708 }
709
710 /*-----------------------------------------------------------------*/
711 /* cmdHelp - help command                                          */
712 /*-----------------------------------------------------------------*/
713 int cmdHelp (char *s, context *cctxt)
714 {
715     int i ;
716     int endline = 999;
717     int startline = 0;
718
719     while (isspace(*s))
720       ++s;
721     if (isdigit(*s)) {
722       endline = ((*s - '0') * 20) + 20;
723       if (endline > 0)
724         startline = endline - 20;
725     }
726     else if (*s)
727     {
728         for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) 
729         {
730             if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
731             {
732                 s = strrchr(cmdTab[i].htxt,'\t');
733                 if ( !s )
734                     s = cmdTab[i].htxt;
735                 else
736                     s++;
737                 fprintf(stdout,"%s",s);
738                 break;
739             }
740         }
741         return 0;
742     }
743
744     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
745
746       /* command string matches */
747       
748       if ((cmdTab[i].htxt) && (i >= startline))
749         fprintf(stdout,"%s",cmdTab[i].htxt);
750       if (i == endline)
751         break;
752     }
753
754     return 0;
755 }
756
757 #define MAX_CMD_LEN 512
758 static char cmdbuff[MAX_CMD_LEN];
759 static int sim_cmd_mode = 0;
760
761 /*-----------------------------------------------------------------
762  interpretCmd - interpret and do the command.  Return 0 to continue,
763    return 1 to exit program.
764 |-----------------------------------------------------------------*/
765 int interpretCmd (char *s)
766 {
767     static char *pcmd = NULL;
768     int i ;
769     int rv = 0 ;
770
771     /* if nothing & previous command exists then
772        execute the previous command again */
773     if (*s == '\n' && pcmd)
774       strcpy(s,pcmd);
775
776     /* if previous command exists & is different
777        from the current command then copy it */
778     if (pcmd) {
779       if (strcmp(pcmd,s)) {
780          free(pcmd);
781          pcmd = strdup(s);
782       }
783     } else
784       pcmd = strdup(s);
785
786     /* lookup the command table and do the task required */
787     strtok(s,"\n");
788
789     if (sim_cmd_mode) {
790       if (strcmp(s,".") == 0) {
791         sim_cmd_mode = 0;
792         return 0;
793       }
794       else if (s[0] == '.') {
795         /* kill the preceeding '.' and pass on as SDCDB command */
796         char *s1 = s+1;
797         char *s2 = s;
798         while (*s1 != 0)
799           *s2++ = *s1++;
800         *s2 = 0;
801       } else {
802         cmdSimulator (s, currCtxt);
803         return 0;
804       }
805     } else {
806       if (strcmp(s,".") ==0) {
807         sim_cmd_mode = 1;
808         return 0;
809       }
810     }
811
812     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
813
814       /* command string matches */
815       if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
816         if (!cmdTab[i].cmdfunc)
817           return 1;
818
819         rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
820
821         /* if full name then give the file name & position */
822         if (fullname && showfull && currCtxt && currCtxt->func) {
823           showfull = 0;
824           if (srcMode == SRC_CMODE)
825             fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
826                     currCtxt->func->mod->cfullname,
827                     currCtxt->cline+1,currCtxt->addr);
828           else
829             fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
830                     currCtxt->func->mod->afullname,
831                     currCtxt->asmline,currCtxt->addr);
832           displayAll(currCtxt);
833         }
834         goto ret;
835       }
836     }
837
838     fprintf(stdout,"Undefined command: \"%s\".  Try \"help\".\n",s);
839  ret:
840     return rv;
841 }
842
843 static FILE *actualcmdfile=NULL ;
844 static char *actualcmds=NULL;
845 static int   stopcmdlist;
846 /*-----------------------------------------------------------------*/
847 /* getNextCmdLine get additional lines used by special commands    */
848 /*-----------------------------------------------------------------*/
849 char *getNextCmdLine()
850 {
851     //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
852     if (!actualcmdfile)
853         return NULL;
854     fprintf(stdout,">");
855     fflush(stdout);
856     if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
857     {
858         // fprintf(stderr,"getNextCmdLine() returns null\n");
859         return NULL;
860     }
861     //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
862     return cmdbuff;
863 }
864
865 void setCmdLine( char *cmds )
866 {
867     actualcmds = cmds;
868 }
869
870 void stopCommandList()
871 {
872     stopcmdlist = 1;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* commandLoop - the main command loop or loop over command file   */
877 /*-----------------------------------------------------------------*/
878 static void commandLoop(FILE *cmdfile)
879 {
880     char *line, save_ch, *s;
881     actualcmdfile = cmdfile;
882     while (1) 
883     {
884         if ( cmdfile == stdin )
885         {
886             if (sim_cmd_mode)
887                 printf("(sim) ");
888             else
889                 fprintf(stdout,"(sdcdb) ");        
890             fflush(stdout);
891         }
892
893         //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
894         //        actualcmdfile,cmdfile);
895         if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
896             break;
897
898         if (interpretCmd(cmdbuff))
899             break;
900
901         while ( actualcmds )
902         {
903             strcpy(cmdbuff,actualcmds);
904             actualcmds = NULL;
905             stopcmdlist= 0;
906             for ( line = cmdbuff; *line ; line = s )
907             {
908                 if ( (s=strchr(line ,'\n')))
909                 {
910                     save_ch = *++s;
911                     *s = '\0';
912                 }
913                 else
914                 {
915                     s += strlen( line );
916                     save_ch = '\0';
917                 }
918                 if (interpretCmd( line ))
919                 {
920                     *s = save_ch;
921                     break;
922                 }
923                 *s = save_ch;
924                 if ( stopcmdlist )
925                     break;
926             }
927         }
928     }
929 }
930
931 /*-----------------------------------------------------------------*/
932 /* printVersionInfo - print the version information                */
933 /*-----------------------------------------------------------------*/
934 static void printVersionInfo()
935 {
936     fprintf(stdout,
937       "SDCDB is free software and you are welcome to distribute copies of it\n"
938       "under certain conditions; type \"show copying\" to see the conditions.\n"
939       "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
940       "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
941       "Type ? for help\n");
942
943 }
944
945 /*-----------------------------------------------------------------*/
946 /* parseCmdLine - parse the commandline arguments                  */
947 /*-----------------------------------------------------------------*/
948 static void parseCmdLine (int argc, char **argv)
949 {
950     int i ;
951     char *filename = NULL;
952     int passon_args_flag = 0;  /* if true, pass on args to simulator */
953
954     Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
955     contsim=0;
956
957     for ( i = 1; i < argc ; i++) {
958   //fprintf(stdout,"%s\n",argv[i]);
959
960   if (passon_args_flag) { /* if true, pass on args to simulator */
961     simArgs[nsimArgs++] = strdup(argv[i]);
962     continue;
963   }
964
965   /* if this is an option */
966   if (argv[i][0] == '-') {
967
968       /* if directory then mark directory */
969       if (strncmp(argv[i],"--directory=",12) == 0) {
970     if (!ssdirl)
971         ssdirl = &argv[i][12];
972     else {
973         char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
974         strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
975         ssdirl = p;
976     }
977     continue;
978       }
979
980       if (strncmp(argv[i],"-fullname",9) == 0) {
981     fullname = TRUE;
982     continue;
983       }
984
985       if (strcmp(argv[i],"-cd") == 0) {
986     i++;
987     chdir(argv[i]);
988     continue;
989       }
990
991       if (strncmp(argv[i],"-cd=",4) == 0) {
992     chdir(argv[i][4]);
993     continue;
994       }
995
996 #ifdef SDCDB_DEBUG
997       if (strncmp(argv[i],"-d=",3) == 0) {
998           sdcdbDebug = strtol(&argv[i][3],0,0);
999           continue;
1000       }
1001 #endif
1002       if (strncmp(argv[i],"-contsim",8) == 0) {
1003           contsim=1;
1004           continue;
1005       }
1006       if (strncmp(argv[i],"-q",2) == 0) {
1007           continue;
1008       }
1009
1010       /* model string */
1011       if (strncmp(argv[i],"-m",2) == 0) {
1012         strncpy(model_str, &argv[i][2], 15);
1013         if (strcmp(model_str,"avr") == 0)
1014           simArgs[0] = "savr";
1015         else if (strcmp(model_str,"xa") == 0)
1016           simArgs[0] = "sxa";
1017         else if (strcmp(model_str,"z80") == 0)
1018           simArgs[0] = "sz80";
1019         continue ;
1020       }
1021
1022       /* -z all remaining options are for simulator */
1023       if (strcmp(argv[i],"-z") == 0) {
1024         passon_args_flag = 1;
1025         continue ;
1026       }
1027
1028       /* the simulator arguments */
1029
1030       /* cpu */
1031       if (strcmp(argv[i],"-t") == 0 ||
1032     strcmp(argv[i],"-cpu") == 0) {
1033
1034         simArgs[nsimArgs++] = "-t";
1035         simArgs[nsimArgs++] = strdup(argv[++i]);
1036         continue ;
1037       }
1038
1039       /* XTAL Frequency */
1040       if (strcmp(argv[i],"-X") == 0 ||
1041           strcmp(argv[i],"-frequency") == 0) {
1042         simArgs[nsimArgs++] = "-X";
1043         simArgs[nsimArgs++] = strdup(argv[++i]);
1044         continue ;
1045       }
1046
1047       /* serial port */
1048       if ( (strcmp(argv[i],"-S") == 0) ||
1049            (strcmp(argv[i],"-s") == 0)) {
1050         simArgs[nsimArgs++] = strdup(argv[i]);
1051         simArgs[nsimArgs++] = strdup(argv[++i]);
1052         continue ;
1053       }
1054
1055       fprintf(stderr,"unknown option %s --- ignored\n",
1056         argv[i]);
1057
1058   } else {
1059       /* must be file name */
1060       if (filename) {
1061     fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1062       argv[i]);
1063     continue ;
1064       }
1065
1066       filename = strtok(argv[i],".");
1067
1068   }
1069     }
1070
1071     if (filename)
1072   cmdFile(filename,NULL);
1073 }
1074
1075 /*-----------------------------------------------------------------*/
1076 /* setsignals -  catch some signals                                */
1077 /*-----------------------------------------------------------------*/
1078 #include <signal.h>
1079 static void
1080 bad_signal(int sig)
1081 {
1082     if ( simactive )
1083         closeSimulator();
1084     exit(1);
1085 }
1086
1087 static void
1088 sigintr(int sig)
1089 {
1090     /* may be interrupt from user: stop debugger and also simulator */
1091     userinterrupt = 1;
1092     if ( !nointerrupt )
1093         sendSim("stop\n");
1094 }
1095
1096 /* the only child can be the simulator */
1097 static void sigchld(int sig)
1098 {
1099     /* the only child can be the simulator */
1100     int status, retpid;
1101     retpid = wait ( &status );
1102     /* if ( retpid == simPid ) */
1103     simactive = 0;
1104 }
1105
1106 static void
1107 setsignals()
1108 {
1109     signal(SIGHUP , SIG_IGN);           
1110     signal(SIGCONT, SIG_IGN);           
1111     signal(SIGINT , sigintr );  
1112     signal(SIGTERM, bad_signal);        
1113     signal(SIGCHLD, sigchld );
1114
1115     signal(SIGABRT, bad_signal);
1116     signal(SIGALRM, bad_signal);
1117     //signal(SIGFPE,  bad_signal);
1118     //signal(SIGILL,  bad_signal);
1119     signal(SIGPIPE, bad_signal);
1120     signal(SIGQUIT, bad_signal);
1121     //signal(SIGSEGV, bad_signal);
1122 }
1123
1124 /*-----------------------------------------------------------------*/
1125 /* main -                                                          */
1126 /*-----------------------------------------------------------------*/
1127
1128 int main ( int argc, char **argv)
1129 {
1130     printVersionInfo();
1131     printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1132
1133     simArgs[nsimArgs++] = "s51";
1134     simArgs[nsimArgs++] = "-P";
1135     simArgs[nsimArgs++] = "-r 9756";
1136     /* parse command line */
1137
1138     setsignals();
1139     parseCmdLine(argc,argv);
1140
1141     commandLoop(stdin);
1142
1143     return 0;
1144 }