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