* debugger/mcs51/sdcdb.c: partially fixed
[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 #ifdef _WIN32
694     if (INVALID_SOCKET == sock)
695 #else
696     if ( sock == -1 )
697 #endif
698         openSimulator((char **)simArgs,nsimArgs);
699     fprintf(stdout,"%s",simResponse());
700     /* now send the filename to be loaded to the simulator */
701     sprintf(buffer,"%s.ihx",s);
702     bp=searchDirsFname(buffer);
703     simLoadFile(bp);
704     free(bp);
705
706     /*set the break points
707        required by the debugger . i.e. the function entry
708        and function exit break points */
709     applyToSet(functions,setEntryExitBP);
710
711     setMainContext();
712     return 0;
713 }
714
715 /*-----------------------------------------------------------------*/
716 /* cmdSource - read commands from file                             */
717 /*-----------------------------------------------------------------*/
718 int cmdSource (char *s, context *cctxt)
719 {
720     FILE *cmdfile;
721     char *bp = s+strlen(s) -1;
722
723     while (isspace(*s))
724       ++s;
725
726     while (isspace(*bp)) bp--;
727     *++bp = '\0';
728
729     if (!( cmdfile = searchDirsFopen(s)))
730     {
731         fprintf(stderr,"commandfile '%s' not found\n",s);
732         return 0;
733     }
734     commandLoop( cmdfile );
735     fclose( cmdfile );
736     return 0;
737 }
738
739 /*-----------------------------------------------------------------*/
740 /* cmdHelp - help command                                          */
741 /*-----------------------------------------------------------------*/
742 int cmdHelp (char *s, context *cctxt)
743 {
744     int i ;
745     int endline = 999;
746     int startline = 0;
747
748     while (isspace(*s))
749         ++s;
750     if (isdigit(*s)) {
751         endline = ((*s - '0') * 20) + 20;
752         if (endline > 0)
753             startline = endline - 20;
754     }
755     else if (*s)
756     {
757         for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
758         {
759             if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
760             {
761                 s = strrchr(cmdTab[i].htxt,'\t');
762                 if ( !s )
763                     s = cmdTab[i].htxt;
764                 else
765                     s++;
766                 fprintf(stdout,"%s",s);
767                 break;
768             }
769         }
770         return 0;
771     }
772
773     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
774
775         /* command string matches */
776
777         if ((cmdTab[i].htxt) && (i >= startline))
778             fprintf(stdout,"%s",cmdTab[i].htxt);
779         if (i == endline)
780             break;
781     }
782
783     return 0;
784 }
785
786 #define MAX_CMD_LEN 512
787 static char cmdbuff[MAX_CMD_LEN];
788 static int sim_cmd_mode = 0;
789
790 /*-----------------------------------------------------------------
791  interpretCmd - interpret and do the command.  Return 0 to continue,
792    return 1 to exit program.
793 |-----------------------------------------------------------------*/
794 int interpretCmd (char *s)
795 {
796     static char *pcmd = NULL;
797     int i ;
798     int rv = 0 ;
799
800     /* if nothing & previous command exists then
801        execute the previous command again */
802     if (*s == '\n' && pcmd)
803         strcpy(s,pcmd);
804
805     /* if previous command exists & is different
806        from the current command then copy it */
807     if (pcmd) {
808         if (strcmp(pcmd,s)) {
809            free(pcmd);
810            pcmd = strdup(s);
811         }
812     } else
813         pcmd = strdup(s);
814
815     /* lookup the command table and do the task required */
816     strtok(s,"\n");
817
818     if (sim_cmd_mode) {
819         if (strcmp(s,".") == 0) {
820           sim_cmd_mode = 0;
821           return 0;
822         }
823         else if (s[0] == '.') {
824             /* kill the preceeding '.' and pass on as SDCDB command */
825             char *s1 = s+1;
826             char *s2 = s;
827             while (*s1 != 0)
828                 *s2++ = *s1++;
829             *s2 = 0;
830         } else {
831             cmdSimulator (s, currCtxt);
832             return 0;
833         }
834     } else {
835         if (strcmp(s,".") ==0) {
836             sim_cmd_mode = 1;
837             return 0;
838         }
839     }
840
841     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
842
843         /* command string matches */
844         if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
845             if (!cmdTab[i].cmdfunc)
846                 return 1;
847
848             rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
849
850             /* if full name then give the file name & position */
851             if (fullname && showfull && currCtxt && currCtxt->func) {
852                 showfull = 0;
853                 if (srcMode == SRC_CMODE)
854                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
855                         currCtxt->func->mod->cfullname,
856                         currCtxt->cline+1,currCtxt->addr);
857                 else
858                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
859                         currCtxt->func->mod->afullname,
860                         currCtxt->asmline,currCtxt->addr);
861                 displayAll(currCtxt);
862             }
863             goto ret;
864         }
865     }
866
867     fprintf(stdout,"Undefined command: \"%s\".  Try \"help\".\n",s);
868  ret:
869     return rv;
870 }
871
872 static FILE *actualcmdfile=NULL ;
873 static char *actualcmds=NULL;
874 static int   stopcmdlist;
875 /*-----------------------------------------------------------------*/
876 /* getNextCmdLine get additional lines used by special commands    */
877 /*-----------------------------------------------------------------*/
878 char *getNextCmdLine(void)
879 {
880     //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
881     if (!actualcmdfile)
882         return NULL;
883     fprintf(stdout,">");
884     fflush(stdout);
885     if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
886     {
887         // fprintf(stderr,"getNextCmdLine() returns null\n");
888         return NULL;
889     }
890     //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
891     return cmdbuff;
892 }
893
894 void setCmdLine( char *cmds )
895 {
896     actualcmds = cmds;
897 }
898
899 void stopCommandList()
900 {
901     stopcmdlist = 1;
902 }
903
904 /*-----------------------------------------------------------------*/
905 /* commandLoop - the main command loop or loop over command file   */
906 /*-----------------------------------------------------------------*/
907 static void commandLoop(FILE *cmdfile)
908 {
909     char *line, save_ch, *s;
910     actualcmdfile = cmdfile;
911     while (1)
912     {
913         if ( cmdfile == stdin )
914         {
915             if (sim_cmd_mode)
916                 printf("(sim) ");
917             else
918                 fprintf(stdout,"(sdcdb) ");
919             fflush(stdout);
920         }
921
922         //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
923         //        actualcmdfile,cmdfile);
924         if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
925             break;
926
927         if (interpretCmd(cmdbuff))
928             break;
929
930         while ( actualcmds )
931         {
932             strcpy(cmdbuff,actualcmds);
933             actualcmds = NULL;
934             stopcmdlist= 0;
935             for ( line = cmdbuff; *line ; line = s )
936             {
937                 if ( (s=strchr(line ,'\n')))
938                 {
939                     save_ch = *++s;
940                     *s = '\0';
941                 }
942                 else
943                 {
944                     s += strlen( line );
945                     save_ch = '\0';
946                 }
947                 if (interpretCmd( line ))
948                 {
949                     *s = save_ch;
950                     break;
951                 }
952                 *s = save_ch;
953                 if ( stopcmdlist )
954                     break;
955             }
956         }
957     }
958 }
959
960 /*-----------------------------------------------------------------*/
961 /* printVersionInfo - print the version information                */
962 /*-----------------------------------------------------------------*/
963 static void printVersionInfo()
964 {
965     fprintf(stdout,
966         "SDCDB is free software and you are welcome to distribute copies of it\n"
967         "under certain conditions; type \"show copying\" to see the conditions.\n"
968         "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
969         "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
970         "Type ? for help\n");
971
972 }
973
974 /*-----------------------------------------------------------------*/
975 /* parseCmdLine - parse the commandline arguments                  */
976 /*-----------------------------------------------------------------*/
977 static void parseCmdLine (int argc, char **argv)
978 {
979     int i ;
980     char *filename = NULL;
981     int passon_args_flag = 0;  /* if true, pass on args to simulator */
982
983     Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
984     contsim=0;
985
986     for ( i = 1; i < argc ; i++) {
987         //fprintf(stdout,"%s\n",argv[i]);
988
989         if (passon_args_flag) { /* if true, pass on args to simulator */
990             simArgs[nsimArgs++] = strdup(argv[i]);
991             continue;
992         }
993
994         /* if this is an option */
995         if (argv[i][0] == '-') {
996
997             /* if directory then mark directory */
998             if (strncmp(argv[i],"--directory=",12) == 0) {
999                 if (!ssdirl)
1000                     ssdirl = &argv[i][12];
1001                 else {
1002                     char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
1003                     strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1004                     ssdirl = p;
1005                 }
1006                 continue;
1007             }
1008
1009             if (strncmp(argv[i],"-fullname",9) == 0) {
1010                 fullname = TRUE;
1011                 continue;
1012             }
1013
1014             if (strcmp(argv[i],"-cd") == 0) {
1015                 i++;
1016                 chdir(argv[i]);
1017                  continue;
1018             }
1019
1020             if (strncmp(argv[i],"-cd=",4) == 0) {
1021                 chdir(argv[i][4]);
1022                 continue;
1023             }
1024
1025 #ifdef SDCDB_DEBUG
1026             if (strncmp(argv[i],"-d=",3) == 0) {
1027                 sdcdbDebug = strtol(&argv[i][3],0,0);
1028                 continue;
1029             }
1030 #endif
1031             if (strncmp(argv[i],"-contsim",8) == 0) {
1032                 contsim=1;
1033                 continue;
1034             }
1035             if (strncmp(argv[i],"-q",2) == 0) {
1036                 continue;
1037             }
1038
1039             /* model string */
1040             if (strncmp(argv[i],"-m",2) == 0) {
1041                 strncpy(model_str, &argv[i][2], 15);
1042                 if (strcmp(model_str,"avr") == 0)
1043                     simArgs[0] = "savr";
1044                 else if (strcmp(model_str,"xa") == 0)
1045                     simArgs[0] = "sxa";
1046                 else if (strcmp(model_str,"z80") == 0)
1047                     simArgs[0] = "sz80";
1048                 continue ;
1049             }
1050
1051             /* -z all remaining options are for simulator */
1052             if (strcmp(argv[i],"-z") == 0) {
1053                 passon_args_flag = 1;
1054                 continue ;
1055             }
1056
1057             /* the simulator arguments */
1058
1059             /* cpu */
1060             if (strcmp(argv[i],"-t") == 0 ||
1061                 strcmp(argv[i],"-cpu") == 0) {
1062
1063                 simArgs[nsimArgs++] = "-t";
1064                 simArgs[nsimArgs++] = strdup(argv[++i]);
1065                 continue ;
1066             }
1067
1068             /* XTAL Frequency */
1069             if (strcmp(argv[i],"-X") == 0 ||
1070                 strcmp(argv[i],"-frequency") == 0) {
1071                 simArgs[nsimArgs++] = "-X";
1072                 simArgs[nsimArgs++] = strdup(argv[++i]);
1073                 continue ;
1074             }
1075
1076             /* serial port */
1077             if ( (strcmp(argv[i],"-S") == 0) ||
1078                 (strcmp(argv[i],"-s") == 0)) {
1079                 simArgs[nsimArgs++] = strdup(argv[i]);
1080                 simArgs[nsimArgs++] = strdup(argv[++i]);
1081                 continue ;
1082             }
1083
1084             /* network serial port */
1085             if ( (strcmp(argv[i],"-k") == 0)) {
1086                 simArgs[nsimArgs++] = strdup(argv[i]);
1087                 simArgs[nsimArgs++] = strdup(argv[++i]);
1088                 continue ;
1089             }
1090
1091             fprintf(stderr,"unknown option %s --- ignored\n",
1092                 argv[i]);
1093
1094         } else {
1095             /* must be file name */
1096             if (filename) {
1097                 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1098                     argv[i]);
1099                 continue ;
1100             }
1101
1102             if (-1 != access(argv[i], 0)) {
1103                 /* file exists: strip the cdb or ihx externsion */
1104                 filename = argv[i];
1105                 char *p = strrchr(argv[i], '.');
1106
1107                 if (NULL != p &&
1108                     (0 == strcmp(p, ".dcb") || 0 == strcmp(p, ".ihx")))
1109                     *p = '\0';
1110             }
1111             filename = argv[i];
1112
1113         }
1114     }
1115
1116     if (filename)
1117         cmdFile(filename,NULL);
1118 }
1119
1120 /*-----------------------------------------------------------------*/
1121 /* setsignals -  catch some signals                                */
1122 /*-----------------------------------------------------------------*/
1123 #include <signal.h>
1124 static void
1125 bad_signal(int sig)
1126 {
1127     if ( simactive )
1128         closeSimulator();
1129     exit(1);
1130 }
1131
1132 static void
1133 sigintr(int sig)
1134 {
1135     /* may be interrupt from user: stop debugger and also simulator */
1136     userinterrupt = 1;
1137     if ( !nointerrupt )
1138         sendSim("stop\n");
1139 }
1140
1141 #ifndef _WIN32
1142 /* the only child can be the simulator */
1143 static void sigchld(int sig)
1144 {
1145     /* the only child can be the simulator */
1146     int status, retpid;
1147     retpid = wait ( &status );
1148     /* if ( retpid == simPid ) */
1149     simactive = 0;
1150 }
1151 #endif
1152
1153 static void
1154 setsignals()
1155 {
1156     signal(SIGINT , sigintr );
1157     signal(SIGABRT, bad_signal);
1158     signal(SIGTERM, bad_signal);
1159
1160 #ifndef _WIN32
1161     signal(SIGHUP , SIG_IGN);
1162     signal(SIGCONT, SIG_IGN);
1163     signal(SIGCHLD, sigchld );
1164
1165     signal(SIGALRM, bad_signal);
1166     //signal(SIGFPE,  bad_signal);
1167     //signal(SIGILL,  bad_signal);
1168     signal(SIGPIPE, bad_signal);
1169     signal(SIGQUIT, bad_signal);
1170     //signal(SIGSEGV, bad_signal);
1171 #endif
1172 }
1173
1174 /*-----------------------------------------------------------------*/
1175 /* main -                                                          */
1176 /*-----------------------------------------------------------------*/
1177
1178 int main ( int argc, char **argv)
1179 {
1180     printVersionInfo();
1181     printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1182
1183     simArgs[nsimArgs++] = "s51";
1184     simArgs[nsimArgs++] = "-P";
1185     simArgs[nsimArgs++] = "-r 9756";
1186     /* parse command line */
1187
1188     setsignals();
1189     parseCmdLine(argc,argv);
1190
1191     commandLoop(stdin);
1192
1193     return 0;
1194 }