* debugger/mcs51/sdcdb.c, debugger/mcs51/simi.c:
[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         slines[(*nlines)-1]->addr= INT_MAX;
413     }
414
415     fclose(mfile);
416     return slines;
417 }
418
419
420 /*-----------------------------------------------------------------*/
421 /* loadModules - reads the source files into module structure      */
422 /*-----------------------------------------------------------------*/
423 static void loadModules (void)
424 {
425     cdbrecs *loop;
426     module *currMod;
427     char *rs;
428
429     /* go thru the records & find out the module
430        records & load the modules specified */
431     for ( loop = recsRoot ; loop ; loop = loop->next ) {
432
433         switch (loop->type) {
434         /* for module records do */
435         case MOD_REC:
436             currMod = parseModule(loop->line,TRUE);
437             currModName = currMod->name ;
438
439             currMod->cfullname = searchDirsFname(currMod->c_name);
440
441             /* load it into buffer */
442             currMod->cLines = loadFile (currMod->c_name,
443             &currMod->ncLines);
444
445             /* do the same for the assembler file */
446             currMod->afullname = searchDirsFname(currMod->asm_name);
447             currMod->asmLines=loadFile (currMod->asm_name,
448                 &currMod->nasmLines);
449             break;
450
451         /* if this is a function record */
452         case FUNC_REC:
453             parseFunc(loop->line);
454             break;
455
456         /* if this is a structure record */
457         case STRUCT_REC:
458             parseStruct(loop->line);
459             break;
460
461         /* if symbol then parse the symbol */
462         case  SYM_REC:
463             parseSymbol(loop->line,&rs,2);
464             break;
465
466         case LNK_REC:
467             parseLnkRec(loop->line);
468             break;
469         }
470     }
471 }
472
473 /*-----------------------------------------------------------------*/
474 /* generate extra sets of sfr and sbit symbols                     */
475 /*-----------------------------------------------------------------*/
476 static void specialFunctionRegs (void)
477 {
478     symbol *sym;
479     for (sym = setFirstItem(symbols);
480          sym ;
481          sym = setNextItem(symbols))
482     {
483         if ( sym->addrspace == 'I' ||
484              sym->addrspace == 'J')
485         {
486             addSet(&sfrsymbols,sym);
487         }
488     }
489 }
490 /*-----------------------------------------------------------------*/
491 /* functionPoints - determine the execution points within a func   */
492 /*-----------------------------------------------------------------*/
493 static void functionPoints (void)
494 {
495     function *func;
496     symbol *sym;
497     exePoint *ep ;
498
499     // add _main dummy for runtime env
500     if ((func = needExtraMainFunction()))
501     {
502         function *func1;
503
504         /* alloc new _main function */
505         func1 = Safe_calloc(1,sizeof(function));
506         *func1 = *func;
507         func1->sym = Safe_calloc(1,sizeof(symbol));
508         *func1->sym =  *func->sym;
509         func1->sym->name  = alloccpy("_main",5);
510         func1->sym->rname = alloccpy("G$_main$0$",10);
511         /* TODO must be set by symbol information */
512         func1->sym->addr  = 0;
513         func1->sym->eaddr = 0x2f;
514         addSet(&functions,func1);
515     }
516
517     /* for all functions do */
518     for ( func = setFirstItem(functions); func;
519           func = setNextItem(functions)) {
520         int j ;
521         module *mod;
522
523         sym = func->sym;
524
525         Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
526                           func->sym->name,
527                           func->sym->addr,
528                           func->sym->eaddr));
529
530         if (!func->sym->addr && !func->sym->eaddr)
531             continue ;
532
533         /* for all source lines in the module find
534            the ones with address >= start and <= end
535            and put them in the point */
536         mod = NULL ;
537         if (! applyToSet(modules,moduleWithName,func->modName,&mod))
538             continue ;
539         func->mod = mod ;
540         func->entryline= INT_MAX-2;
541         func->exitline =  0;
542         func->aentryline = INT_MAX-2 ;
543         func->aexitline = 0;
544
545         /* do it for the C Lines first */
546         for ( j = 0 ; j < mod->ncLines ; j++ ) {
547             if (mod->cLines[j]->addr < INT_MAX &&
548                 mod->cLines[j]->addr >= sym->addr &&
549                 mod->cLines[j]->addr <= sym->eaddr ) {
550
551
552                 /* add it to the execution point */
553                 if (func->entryline > j)
554                     func->entryline = j;
555
556                 if (func->exitline < j)
557                     func->exitline = j;
558
559                 ep = Safe_calloc(1,sizeof(exePoint));
560                 ep->addr =  mod->cLines[j]->addr ;
561                 ep->line = j;
562                 ep->block= mod->cLines[j]->block;
563                 ep->level= mod->cLines[j]->level;
564                 addSet(&func->cfpoints,ep);
565             }
566         }
567         /* check double line execution points of module */
568         for (ep = setFirstItem(mod->cfpoints); ep;
569              ep = setNextItem(mod->cfpoints))
570         {
571             if (ep->addr >= sym->addr &&
572                 ep->addr <= sym->eaddr )
573             {
574                 addSet(&func->cfpoints,ep);
575             }
576         }
577         /* do the same for asm execution points */
578         for ( j = 0 ; j < mod->nasmLines ; j++ ) {
579             if (mod->asmLines[j]->addr < INT_MAX &&
580                 mod->asmLines[j]->addr >= sym->addr &&
581                 mod->asmLines[j]->addr <= sym->eaddr ) {
582
583                 exePoint *ep ;
584                 /* add it to the execution point */
585                 if (func->aentryline > j)
586                     func->aentryline = j;
587
588                 if (func->aexitline < j)
589                     func->aexitline = j;
590
591                 /* add it to the execution point */
592                 ep = Safe_calloc(1,sizeof(exePoint));
593                 ep->addr =  mod->asmLines[j]->addr ;
594                 ep->line = j;
595                 addSet(&func->afpoints,ep);
596             }
597         }
598         if ( func->entryline == INT_MAX-2 )
599             func->entryline = 0;
600         if ( func->aentryline == INT_MAX-2 )
601             func->aentryline = 0;
602
603 #ifdef SDCDB_DEBUG
604         if (!( D_sdcdb & sdcdbDebug))
605             continue;
606
607         Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
608                           func->sym->name));
609         {
610             exePoint *ep;
611
612             for (ep = setFirstItem(func->cfpoints); ep;
613                  ep = setNextItem(func->cfpoints))
614                 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
615                                   ep->addr,ep->line+1,mod->cLines[ep->line]->src));
616
617             Dprintf(D_sdcdb, ("sdcdb:  and the following ASM exePoints\n"));
618             for (ep = setFirstItem(func->afpoints); ep;
619                  ep = setNextItem(func->afpoints))
620                 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
621                                    ep->addr,ep->line+1,mod->asmLines[ep->line]->src));
622         }
623 #endif
624     }
625 }
626
627
628 /*-----------------------------------------------------------------*/
629 /* setEntryExitBP - set the entry & exit Break Points for functions*/
630 /*-----------------------------------------------------------------*/
631 DEFSETFUNC(setEntryExitBP)
632 {
633     function *func = item;
634
635     if (func->sym && func->sym->addr && func->sym->eaddr) {
636
637         /* set the entry break point */
638         setBreakPoint (func->sym->addr , CODE , FENTRY ,
639             fentryCB ,func->mod->c_name , func->entryline);
640
641         /* set the exit break point */
642         setBreakPoint (func->sym->eaddr , CODE , FEXIT  ,
643             fexitCB  ,func->mod->c_name , func->exitline );
644     }
645
646     return 0;
647 }
648
649 /*-----------------------------------------------------------------*/
650 /* cmdFile - load file into the debugger                           */
651 /*-----------------------------------------------------------------*/
652 int cmdFile (char *s,context *cctxt)
653 {
654     FILE *cdbFile;
655     char buffer[128];
656     char *bp;
657
658     while (isspace(*s)) s++;
659     if (!*s) {
660         fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
661         return 0;
662     }
663
664     sprintf(buffer,"%s.cdb",s);
665     /* try creating the cdbfile */
666     if (!(cdbFile = searchDirsFopen(buffer))) {
667         fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
668         // return 0;
669     }
670
671     /* allocate for context */
672     currCtxt = Safe_calloc(1,sizeof(context));
673
674     if (cdbFile) {
675         /* readin the debug information */
676         if (!readCdb (cdbFile)) {
677             fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
678           //return 0;
679         }
680     }
681
682     /* parse and load the modules required */
683     loadModules();
684
685     /* determine the execution points for this
686        module */
687     functionPoints();
688
689     /* extract known special function registers */
690     specialFunctionRegs();
691
692     /* start the simulator & setup connection to it */
693     if ( sock == -1 )
694         openSimulator((char **)simArgs,nsimArgs);
695     fprintf(stdout,"%s",simResponse());
696     /* now send the filename to be loaded to the simulator */
697     sprintf(buffer,"%s.ihx",s);
698     bp=searchDirsFname(buffer);
699     simLoadFile(bp);
700     free(bp);
701
702     /*set the break points
703        required by the debugger . i.e. the function entry
704        and function exit break points */
705     applyToSet(functions,setEntryExitBP);
706
707     setMainContext();
708     return 0;
709 }
710
711 /*-----------------------------------------------------------------*/
712 /* cmdSource - read commands from file                             */
713 /*-----------------------------------------------------------------*/
714 int cmdSource (char *s, context *cctxt)
715 {
716     FILE *cmdfile;
717     char *bp = s+strlen(s) -1;
718
719     while (isspace(*s))
720       ++s;
721
722     while (isspace(*bp)) bp--;
723     *++bp = '\0';
724
725     if (!( cmdfile = searchDirsFopen(s)))
726     {
727         fprintf(stderr,"commandfile '%s' not found\n",s);
728         return 0;
729     }
730     commandLoop( cmdfile );
731     fclose( cmdfile );
732     return 0;
733 }
734
735 /*-----------------------------------------------------------------*/
736 /* cmdHelp - help command                                          */
737 /*-----------------------------------------------------------------*/
738 int cmdHelp (char *s, context *cctxt)
739 {
740     int i ;
741     int endline = 999;
742     int startline = 0;
743
744     while (isspace(*s))
745         ++s;
746     if (isdigit(*s)) {
747         endline = ((*s - '0') * 20) + 20;
748         if (endline > 0)
749             startline = endline - 20;
750     }
751     else if (*s)
752     {
753         for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
754         {
755             if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
756             {
757                 s = strrchr(cmdTab[i].htxt,'\t');
758                 if ( !s )
759                     s = cmdTab[i].htxt;
760                 else
761                     s++;
762                 fprintf(stdout,"%s",s);
763                 break;
764             }
765         }
766         return 0;
767     }
768
769     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
770
771         /* command string matches */
772
773         if ((cmdTab[i].htxt) && (i >= startline))
774             fprintf(stdout,"%s",cmdTab[i].htxt);
775         if (i == endline)
776             break;
777     }
778
779     return 0;
780 }
781
782 #define MAX_CMD_LEN 512
783 static char cmdbuff[MAX_CMD_LEN];
784 static int sim_cmd_mode = 0;
785
786 /*-----------------------------------------------------------------
787  interpretCmd - interpret and do the command.  Return 0 to continue,
788    return 1 to exit program.
789 |-----------------------------------------------------------------*/
790 int interpretCmd (char *s)
791 {
792     static char *pcmd = NULL;
793     int i ;
794     int rv = 0 ;
795
796     /* if nothing & previous command exists then
797        execute the previous command again */
798     if (*s == '\n' && pcmd)
799         strcpy(s,pcmd);
800
801     /* if previous command exists & is different
802        from the current command then copy it */
803     if (pcmd) {
804         if (strcmp(pcmd,s)) {
805            free(pcmd);
806            pcmd = strdup(s);
807         }
808     } else
809         pcmd = strdup(s);
810
811     /* lookup the command table and do the task required */
812     strtok(s,"\n");
813
814     if (sim_cmd_mode) {
815         if (strcmp(s,".") == 0) {
816           sim_cmd_mode = 0;
817           return 0;
818         }
819         else if (s[0] == '.') {
820             /* kill the preceeding '.' and pass on as SDCDB command */
821             char *s1 = s+1;
822             char *s2 = s;
823             while (*s1 != 0)
824                 *s2++ = *s1++;
825             *s2 = 0;
826         } else {
827             cmdSimulator (s, currCtxt);
828             return 0;
829         }
830     } else {
831         if (strcmp(s,".") ==0) {
832             sim_cmd_mode = 1;
833             return 0;
834         }
835     }
836
837     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
838
839         /* command string matches */
840         if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
841             if (!cmdTab[i].cmdfunc)
842                 return 1;
843
844             rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
845
846             /* if full name then give the file name & position */
847             if (fullname && showfull && currCtxt && currCtxt->func) {
848                 showfull = 0;
849                 if (srcMode == SRC_CMODE)
850                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
851                         currCtxt->func->mod->cfullname,
852                         currCtxt->cline+1,currCtxt->addr);
853                 else
854                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
855                         currCtxt->func->mod->afullname,
856                         currCtxt->asmline,currCtxt->addr);
857                 displayAll(currCtxt);
858             }
859             goto ret;
860         }
861     }
862
863     fprintf(stdout,"Undefined command: \"%s\".  Try \"help\".\n",s);
864  ret:
865     return rv;
866 }
867
868 static FILE *actualcmdfile=NULL ;
869 static char *actualcmds=NULL;
870 static int   stopcmdlist;
871 /*-----------------------------------------------------------------*/
872 /* getNextCmdLine get additional lines used by special commands    */
873 /*-----------------------------------------------------------------*/
874 char *getNextCmdLine(void)
875 {
876     //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
877     if (!actualcmdfile)
878         return NULL;
879     fprintf(stdout,">");
880     fflush(stdout);
881     if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
882     {
883         // fprintf(stderr,"getNextCmdLine() returns null\n");
884         return NULL;
885     }
886     //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
887     return cmdbuff;
888 }
889
890 void setCmdLine( char *cmds )
891 {
892     actualcmds = cmds;
893 }
894
895 void stopCommandList()
896 {
897     stopcmdlist = 1;
898 }
899
900 /*-----------------------------------------------------------------*/
901 /* commandLoop - the main command loop or loop over command file   */
902 /*-----------------------------------------------------------------*/
903 static void commandLoop(FILE *cmdfile)
904 {
905     char *line, save_ch, *s;
906     actualcmdfile = cmdfile;
907     while (1)
908     {
909         if ( cmdfile == stdin )
910         {
911             if (sim_cmd_mode)
912                 printf("(sim) ");
913             else
914                 fprintf(stdout,"(sdcdb) ");
915             fflush(stdout);
916         }
917
918         //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
919         //        actualcmdfile,cmdfile);
920         if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
921             break;
922
923         if (interpretCmd(cmdbuff))
924             break;
925
926         while ( actualcmds )
927         {
928             strcpy(cmdbuff,actualcmds);
929             actualcmds = NULL;
930             stopcmdlist= 0;
931             for ( line = cmdbuff; *line ; line = s )
932             {
933                 if ( (s=strchr(line ,'\n')))
934                 {
935                     save_ch = *++s;
936                     *s = '\0';
937                 }
938                 else
939                 {
940                     s += strlen( line );
941                     save_ch = '\0';
942                 }
943                 if (interpretCmd( line ))
944                 {
945                     *s = save_ch;
946                     break;
947                 }
948                 *s = save_ch;
949                 if ( stopcmdlist )
950                     break;
951             }
952         }
953     }
954 }
955
956 /*-----------------------------------------------------------------*/
957 /* printVersionInfo - print the version information                */
958 /*-----------------------------------------------------------------*/
959 static void printVersionInfo()
960 {
961     fprintf(stdout,
962         "SDCDB is free software and you are welcome to distribute copies of it\n"
963         "under certain conditions; type \"show copying\" to see the conditions.\n"
964         "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
965         "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
966         "Type ? for help\n");
967
968 }
969
970 /*-----------------------------------------------------------------*/
971 /* parseCmdLine - parse the commandline arguments                  */
972 /*-----------------------------------------------------------------*/
973 static void parseCmdLine (int argc, char **argv)
974 {
975     int i ;
976     char *filename = NULL;
977     int passon_args_flag = 0;  /* if true, pass on args to simulator */
978
979     Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
980     contsim=0;
981
982     for ( i = 1; i < argc ; i++) {
983         //fprintf(stdout,"%s\n",argv[i]);
984
985         if (passon_args_flag) { /* if true, pass on args to simulator */
986             simArgs[nsimArgs++] = strdup(argv[i]);
987             continue;
988         }
989
990         /* if this is an option */
991         if (argv[i][0] == '-') {
992
993             /* if directory then mark directory */
994             if (strncmp(argv[i],"--directory=",12) == 0) {
995                 if (!ssdirl)
996                     ssdirl = &argv[i][12];
997                 else {
998                     char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
999                     strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1000                     ssdirl = p;
1001                 }
1002                 continue;
1003             }
1004
1005             if (strncmp(argv[i],"-fullname",9) == 0) {
1006                 fullname = TRUE;
1007                 continue;
1008             }
1009
1010             if (strcmp(argv[i],"-cd") == 0) {
1011                 i++;
1012                 chdir(argv[i]);
1013                  continue;
1014             }
1015
1016             if (strncmp(argv[i],"-cd=",4) == 0) {
1017                 chdir(argv[i][4]);
1018                 continue;
1019             }
1020
1021 #ifdef SDCDB_DEBUG
1022             if (strncmp(argv[i],"-d=",3) == 0) {
1023                 sdcdbDebug = strtol(&argv[i][3],0,0);
1024                 continue;
1025             }
1026 #endif
1027             if (strncmp(argv[i],"-contsim",8) == 0) {
1028                 contsim=1;
1029                 continue;
1030             }
1031             if (strncmp(argv[i],"-q",2) == 0) {
1032                 continue;
1033             }
1034
1035             /* model string */
1036             if (strncmp(argv[i],"-m",2) == 0) {
1037                 strncpy(model_str, &argv[i][2], 15);
1038                 if (strcmp(model_str,"avr") == 0)
1039                     simArgs[0] = "savr";
1040                 else if (strcmp(model_str,"xa") == 0)
1041                     simArgs[0] = "sxa";
1042                 else if (strcmp(model_str,"z80") == 0)
1043                     simArgs[0] = "sz80";
1044                 continue ;
1045             }
1046
1047             /* -z all remaining options are for simulator */
1048             if (strcmp(argv[i],"-z") == 0) {
1049                 passon_args_flag = 1;
1050                 continue ;
1051             }
1052
1053             /* the simulator arguments */
1054
1055             /* cpu */
1056             if (strcmp(argv[i],"-t") == 0 ||
1057                 strcmp(argv[i],"-cpu") == 0) {
1058
1059                 simArgs[nsimArgs++] = "-t";
1060                 simArgs[nsimArgs++] = strdup(argv[++i]);
1061                 continue ;
1062             }
1063
1064             /* XTAL Frequency */
1065             if (strcmp(argv[i],"-X") == 0 ||
1066                 strcmp(argv[i],"-frequency") == 0) {
1067                 simArgs[nsimArgs++] = "-X";
1068                 simArgs[nsimArgs++] = strdup(argv[++i]);
1069                 continue ;
1070             }
1071
1072             /* serial port */
1073             if ( (strcmp(argv[i],"-S") == 0) ||
1074                 (strcmp(argv[i],"-s") == 0)) {
1075                 simArgs[nsimArgs++] = strdup(argv[i]);
1076                 simArgs[nsimArgs++] = strdup(argv[++i]);
1077                 continue ;
1078             }
1079
1080             /* network serial port */
1081             if ( (strcmp(argv[i],"-k") == 0)) {
1082                 simArgs[nsimArgs++] = strdup(argv[i]);
1083                 simArgs[nsimArgs++] = strdup(argv[++i]);
1084                 continue ;
1085             }
1086
1087             fprintf(stderr,"unknown option %s --- ignored\n",
1088                 argv[i]);
1089
1090         } else {
1091             /* must be file name */
1092             if (filename) {
1093                 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1094                     argv[i]);
1095                 continue ;
1096             }
1097
1098             filename = strtok(argv[i],".");
1099
1100         }
1101     }
1102
1103     if (filename)
1104         cmdFile(filename,NULL);
1105 }
1106
1107 /*-----------------------------------------------------------------*/
1108 /* setsignals -  catch some signals                                */
1109 /*-----------------------------------------------------------------*/
1110 #include <signal.h>
1111 static void
1112 bad_signal(int sig)
1113 {
1114     if ( simactive )
1115         closeSimulator();
1116     exit(1);
1117 }
1118
1119 static void
1120 sigintr(int sig)
1121 {
1122     /* may be interrupt from user: stop debugger and also simulator */
1123     userinterrupt = 1;
1124     if ( !nointerrupt )
1125         sendSim("stop\n");
1126 }
1127
1128 #ifndef _WIN32
1129 /* the only child can be the simulator */
1130 static void sigchld(int sig)
1131 {
1132     /* the only child can be the simulator */
1133     int status, retpid;
1134     retpid = wait ( &status );
1135     /* if ( retpid == simPid ) */
1136     simactive = 0;
1137 }
1138 #endif
1139
1140 static void
1141 setsignals()
1142 {
1143     signal(SIGINT , sigintr );
1144     signal(SIGABRT, bad_signal);
1145     signal(SIGTERM, bad_signal);
1146
1147 #ifndef _WIN32
1148     signal(SIGHUP , SIG_IGN);
1149     signal(SIGCONT, SIG_IGN);
1150     signal(SIGCHLD, sigchld );
1151
1152     signal(SIGALRM, bad_signal);
1153     //signal(SIGFPE,  bad_signal);
1154     //signal(SIGILL,  bad_signal);
1155     signal(SIGPIPE, bad_signal);
1156     signal(SIGQUIT, bad_signal);
1157     //signal(SIGSEGV, bad_signal);
1158 #endif
1159 }
1160
1161 /*-----------------------------------------------------------------*/
1162 /* main -                                                          */
1163 /*-----------------------------------------------------------------*/
1164
1165 int main ( int argc, char **argv)
1166 {
1167     printVersionInfo();
1168     printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1169
1170     simArgs[nsimArgs++] = "s51";
1171     simArgs[nsimArgs++] = "-P";
1172     simArgs[nsimArgs++] = "-r 9756";
1173     /* parse command line */
1174
1175     setsignals();
1176     parseCmdLine(argc,argv);
1177
1178     commandLoop(stdin);
1179
1180     return 0;
1181 }