Martins changes
[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
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 /*-----------------------------------------------------------------*/
858 /* commandLoop - the main command loop or loop over command file   */
859 /*-----------------------------------------------------------------*/
860 static void commandLoop(FILE *cmdfile)
861 {
862     char *line, save_ch, *s;
863     actualcmdfile = cmdfile;
864     while (1) 
865     {
866         if ( cmdfile == stdin )
867         {
868             if (sim_cmd_mode)
869                 printf("(sim) ");
870             else
871                 fprintf(stdout,"(sdcdb) ");        
872             fflush(stdout);
873         }
874
875         if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
876             break;
877
878         if (interpretCmd(cmdbuff))
879             break;
880
881         while ( actualcmds )
882         {
883             strcpy(cmdbuff,actualcmds);
884             actualcmds = NULL;
885             for ( line = cmdbuff; *line ; line = s )
886             {
887                 if ( (s=strchr(line ,'\n')))
888                 {
889                     save_ch = *++s;
890                     *s = '\0';
891                 }
892                 else
893                 {
894                     s += strlen( line );
895                     save_ch = '\0';
896                 }
897                 if (interpretCmd( line ))
898                 {
899                     *s = save_ch;
900                     break;
901                 }
902                 *s = save_ch;
903             }
904         }
905     }
906 }
907
908 /*-----------------------------------------------------------------*/
909 /* printVersionInfo - print the version information                */
910 /*-----------------------------------------------------------------*/
911 static void printVersionInfo()
912 {
913     fprintf(stdout,
914       "SDCDB is free software and you are welcome to distribute copies of it\n"
915       "under certain conditions; type \"show copying\" to see the conditions.\n"
916       "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
917       "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
918       "Type ? for help\n");
919
920 }
921
922 /*-----------------------------------------------------------------*/
923 /* parseCmdLine - parse the commandline arguments                  */
924 /*-----------------------------------------------------------------*/
925 static void parseCmdLine (int argc, char **argv)
926 {
927     int i ;
928     char *filename = NULL;
929     int passon_args_flag = 0;  /* if true, pass on args to simulator */
930
931     Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
932     contsim=0;
933
934     for ( i = 1; i < argc ; i++) {
935   //fprintf(stdout,"%s\n",argv[i]);
936
937   if (passon_args_flag) { /* if true, pass on args to simulator */
938     simArgs[nsimArgs++] = strdup(argv[i]);
939     continue;
940   }
941
942   /* if this is an option */
943   if (argv[i][0] == '-') {
944
945       /* if directory then mark directory */
946       if (strncmp(argv[i],"--directory=",12) == 0) {
947     if (!ssdirl)
948         ssdirl = &argv[i][12];
949     else {
950         char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
951         strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
952         ssdirl = p;
953     }
954     continue;
955       }
956
957       if (strncmp(argv[i],"-fullname",9) == 0) {
958     fullname = TRUE;
959     continue;
960       }
961
962       if (strcmp(argv[i],"-cd") == 0) {
963     i++;
964     chdir(argv[i]);
965     continue;
966       }
967
968       if (strncmp(argv[i],"-cd=",4) == 0) {
969     chdir(argv[i][4]);
970     continue;
971       }
972
973 #ifdef SDCDB_DEBUG
974       if (strncmp(argv[i],"-d=",3) == 0) {
975           sdcdbDebug = strtol(&argv[i][3],0,0);
976           continue;
977       }
978 #endif
979       if (strncmp(argv[i],"-contsim",8) == 0) {
980           contsim=1;
981           continue;
982       }
983       if (strncmp(argv[i],"-q",2) == 0) {
984           continue;
985       }
986
987       /* model string */
988       if (strncmp(argv[i],"-m",2) == 0) {
989         strncpy(model_str, &argv[i][2], 15);
990         if (strcmp(model_str,"avr") == 0)
991           simArgs[0] = "savr";
992         else if (strcmp(model_str,"xa") == 0)
993           simArgs[0] = "sxa";
994         else if (strcmp(model_str,"z80") == 0)
995           simArgs[0] = "sz80";
996         continue ;
997       }
998
999       /* -z all remaining options are for simulator */
1000       if (strcmp(argv[i],"-z") == 0) {
1001         passon_args_flag = 1;
1002         continue ;
1003       }
1004
1005       /* the simulator arguments */
1006
1007       /* cpu */
1008       if (strcmp(argv[i],"-t") == 0 ||
1009     strcmp(argv[i],"-cpu") == 0) {
1010
1011         simArgs[nsimArgs++] = "-t";
1012         simArgs[nsimArgs++] = strdup(argv[++i]);
1013         continue ;
1014       }
1015
1016       /* XTAL Frequency */
1017       if (strcmp(argv[i],"-X") == 0 ||
1018           strcmp(argv[i],"-frequency") == 0) {
1019         simArgs[nsimArgs++] = "-X";
1020         simArgs[nsimArgs++] = strdup(argv[++i]);
1021         continue ;
1022       }
1023
1024       /* serial port */
1025       if ( (strcmp(argv[i],"-S") == 0) ||
1026            (strcmp(argv[i],"-s") == 0)) {
1027         simArgs[nsimArgs++] = strdup(argv[i]);
1028         simArgs[nsimArgs++] = strdup(argv[++i]);
1029         continue ;
1030       }
1031
1032       fprintf(stderr,"unknown option %s --- ignored\n",
1033         argv[i]);
1034
1035   } else {
1036       /* must be file name */
1037       if (filename) {
1038     fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1039       argv[i]);
1040     continue ;
1041       }
1042
1043       filename = strtok(argv[i],".");
1044
1045   }
1046     }
1047
1048     if (filename)
1049   cmdFile(filename,NULL);
1050 }
1051
1052 /*-----------------------------------------------------------------*/
1053 /* setsignals -  catch some signals                                */
1054 /*-----------------------------------------------------------------*/
1055 #include <signal.h>
1056 static void
1057 bad_signal(int sig)
1058 {
1059     if ( simactive )
1060         closeSimulator();
1061     exit(1);
1062 }
1063
1064 static void
1065 sigintr(int sig)
1066 {
1067     /* may be interrupt from user: stop debugger and also simulator */
1068     userinterrupt = 1;
1069     if ( !nointerrupt )
1070         sendSim("stop\n");
1071 }
1072
1073 /* the only child can be the simulator */
1074 static void sigchld(int sig)
1075 {
1076     /* the only child can be the simulator */
1077     int status, retpid;
1078     retpid = wait ( &status );
1079     /* if ( retpid == simPid ) */
1080     simactive = 0;
1081 }
1082
1083 static void
1084 setsignals()
1085 {
1086     signal(SIGHUP , bad_signal);                
1087     signal(SIGINT , sigintr );  
1088     signal(SIGTERM, bad_signal);        
1089     signal(SIGCHLD, sigchld );
1090
1091     signal(SIGABRT, bad_signal);
1092     signal(SIGALRM, bad_signal);
1093     //signal(SIGFPE,  bad_signal);
1094     //signal(SIGILL,  bad_signal);
1095     signal(SIGPIPE, bad_signal);
1096     signal(SIGQUIT, bad_signal);
1097     //signal(SIGSEGV, bad_signal);
1098 }
1099
1100 /*-----------------------------------------------------------------*/
1101 /* main -                                                          */
1102 /*-----------------------------------------------------------------*/
1103
1104 int main ( int argc, char **argv)
1105 {
1106     printVersionInfo();
1107     printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1108
1109     simArgs[nsimArgs++] = "s51";
1110     simArgs[nsimArgs++] = "-P";
1111     simArgs[nsimArgs++] = "-r 9756";
1112     /* parse command line */
1113
1114     setsignals();
1115     parseCmdLine(argc,argv);
1116
1117     commandLoop(stdin);
1118
1119     return 0;
1120 }