Use 'ao-dbg' instead of 's51' to communicate with TeleMetrum
[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 #define link unix_link
25 #define _GNU_SOURCE
26 #include <unistd.h>
27 #undef link
28 #include "sdcdb.h"
29 #include "symtab.h"
30 #include "simi.h"
31 #include "break.h"
32 #include "cmd.h"
33 #include "newalloc.h"
34 #if defined HAVE_LIBREADLINE && HAVE_LIBREADLINE != -1
35 #define HAVE_READLINE_COMPLETITION  1
36 #endif
37 #ifdef HAVE_LIBREADLINE
38 #include <readline/readline.h>
39 #include <readline/history.h>
40 #endif  /* HAVE_LIBREADLINE */
41
42 #ifdef SDCDB_DEBUG
43 int   sdcdbDebug = 0;
44 #endif
45
46 char *currModName = NULL;
47 cdbrecs *recsRoot = NULL ;
48 set  *modules = NULL;    /* set of all modules */
49 set  *functions = NULL ; /* set of functions */
50 set  *symbols = NULL   ; /* set of symbols */
51 set  *sfrsymbols= NULL ; /* set of symbols of sfr or sbit */
52 int nStructs = 0 ;
53 structdef **structs = NULL ; /* all structures */
54 int nLinkrecs = 0;
55 linkrec **linkrecs = NULL; /* all linkage editor records */
56 context *currCtxt = NULL;
57 short fullname = 0;
58 short showfull = 0;
59 char userinterrupt = 0;
60 char nointerrupt = 0;
61 char contsim = 0;
62 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX DIR_SEPARATOR_STRING "small" ;
63 char *simArgs[40];
64 int nsimArgs = 0;
65 char model_str[20];
66 /* fake filename & lineno to make linker */
67 char *filename=NULL;
68 char *current_directory;
69 int lineno = 0;
70 int fatalError = 0;
71
72 static void commandLoop(FILE *cmdfile);
73 #ifdef HAVE_READLINE_COMPLETITION
74 char *completionCmdSource(const char *text, int state);
75 char *completionCmdFile(const char *text, int state);
76 char *completionCmdInfo(const char *text, int state);
77 char *completionCmdShow(const char *text, int state);
78 char *completionCmdListSymbols(const char *text, int state);
79 char *completionCmdPrintType(const char *text, int state);
80 char *completionCmdPrint(const char *text, int state);
81 char *completionCmdDelUserBp(const char *text, int state);
82 char *completionCmdUnDisplay(const char *text, int state);
83 char *completionCmdSetUserBp(const char *text, int state);
84 char *completionCmdSetOption(const char *text, int state);
85 #else
86 #define completionCmdSource NULL
87 #define completionCmdFile NULL
88 #define completionCmdInfo NULL
89 #define completionCmdShow NULL
90 #define completionCmdListSymbols NULL
91 #define completionCmdPrintType NULL
92 #define completionCmdPrint NULL
93 #define completionCmdDelUserBp NULL
94 #define completionCmdUnDisplay NULL
95 #define completionCmdSetUserBp NULL
96 #define completionCmdSetOption NULL
97 #endif /* HAVE_READLINE_COMPLETITION */
98
99 /* command table */
100 struct cmdtab
101 {
102     char      *cmd ;  /* command the user will enter */
103     int (*cmdfunc)(char *,context *);   /* function to execute when command is entered */
104 #ifdef HAVE_READLINE_COMPLETITION
105     rl_compentry_func_t *completion_func;
106 #else
107     void *dummy;
108 #endif  /* HAVE_READLINE_COMPLETITION */
109     char *htxt ;    /* short help text */
110
111 } cmdTab[] = {
112     /* NOTE:- the search is done from the top, so "break" should
113        precede the synonym "b" */
114     /* break point */
115     { "break"    ,  cmdSetUserBp  , completionCmdSetUserBp,
116       "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
117     },
118     { "tbreak"   ,  cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/,
119       "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
120     },
121     { "b"        ,  cmdSetUserBp  , completionCmdSetUserBp ,  NULL,},
122
123     { "jump"   ,  cmdJump , NULL,
124       "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *<address>]\n",
125     },
126     { "clear"    ,  cmdClrUserBp  , completionCmdSetUserBp/*same as "break"*/,
127       "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
128     },
129     { "cl"       ,  cmdClrUserBp  , completionCmdSetUserBp/*same as "break"*/ , NULL,},
130
131     { "continue" ,  cmdContinue   ,  NULL,
132       "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
133     },
134     { "condition" ,  cmdCondition   ,  completionCmdDelUserBp/*same as "delete"*/,
135       "condition brkpoint_number expr\t\tSet condition for breakpoint.\n"
136     },
137     { "ignore" ,  cmdIgnore  ,  completionCmdDelUserBp/*same as "delete"*/,
138       "ignore brkpoint_number count\t\tSet ignore count for breakpoint.\n"
139     },
140     { "commands" ,  cmdCommands  ,  completionCmdDelUserBp/*same as "delete"*/,
141       "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n"
142     },
143     { "c"        ,  cmdContinue   , NULL ,  NULL,},
144
145     { "disassemble",cmdDisasmF    ,  NULL, "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" },
146     { "delete" ,  cmdDelUserBp  , completionCmdDelUserBp,
147       "{d}elete n\t\t clears break point number n\n"
148     },
149     { "display"    ,  cmdDisplay     , completionCmdPrint/*same as "print"*/,
150       "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
151     },
152     { "undisplay"  ,  cmdUnDisplay   , completionCmdUnDisplay,
153       "undisplay [<variable>]\t dont display this variable or all\n"
154     },
155     { "down"     ,  cmdDown      , NULL,
156       "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n"
157     },
158     { "up"       ,  cmdUp      , NULL,
159       "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n"
160     },
161     { "d"        ,  cmdDelUserBp  , completionCmdDelUserBp, NULL },
162
163     { "info"     ,  cmdInfo       , completionCmdInfo,
164       "info <break stack frame registers all-registers line source functions symbols variables>\n"
165       "\t list all break points, call-stack, frame or register information\n"
166     },
167
168     { "listasm"  ,  cmdListAsm    , NULL,
169       "listasm {la}\t\t list assembler code for the current C line\n"
170     },
171     { "la"       ,  cmdListAsm    , NULL, NULL },
172     { "ls"       ,  cmdListSymbols  , completionCmdListSymbols, "ls,lf,lm\t\t list symbols,functions,modules\n" },
173     { "lf"       ,  cmdListFunctions, completionCmdListSymbols, NULL },
174     { "lm"       ,  cmdListModules  , completionCmdListSymbols, NULL },
175     { "list"     ,  cmdListSrc    , completionCmdSetUserBp/*same as "break"*/,
176       "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
177     },
178     { "l"        ,  cmdListSrc    , completionCmdSetUserBp/*same as "break"*/, NULL },
179     { "show"     ,  cmdShow       , completionCmdShow,
180       "show"
181       " <copying warranty>\t copying & distribution terms, warranty\n"
182     },
183     { "set"      ,  cmdSetOption  , completionCmdSetOption, "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
184     { "stepi"    ,  cmdStepi      , NULL,
185       "stepi\t\t\tStep one instruction exactly.\n"
186     },
187     { "step"     ,  cmdStep       , NULL,
188       "{s}tep\t\t\tStep program until it reaches a different source line.\n"
189     },
190     { "source"   ,  cmdSource      , completionCmdSource,
191       "source <FILE>\t\t\tRead commands from a file named FILE.\n"
192     },
193     { "s"        ,  cmdStep       , NULL, NULL },
194     { "nexti"    ,  cmdNexti      , NULL,
195       "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
196     },
197     { "next"     ,  cmdNext       , NULL,
198       "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
199     },
200     { "n"        ,  cmdNext       , NULL, NULL },
201     { "run"      ,  cmdRun        , NULL,
202       "{r}un\t\t\tStart debugged program. \n"
203     },
204     { "r"        ,  cmdRun        , NULL, NULL },
205     { "ptype"    ,  cmdPrintType  , completionCmdPrintType,
206       "{pt}ype <variable>\tprint type information of a variable\n"
207     },
208     { "pt"       ,  cmdPrintType  , NULL, NULL },
209     { "print"    ,  cmdPrint      , completionCmdPrintType,
210       "{p}rint <variable>\t print value of given variable\n"
211     },
212     { "output"   ,  cmdOutput      , completionCmdPrint/*same as "print"*/,
213       "output <variable>\t print value of given variable without $ and newline \n"
214     },
215     { "p"        ,  cmdPrint      , completionCmdPrintType, NULL },
216     { "file"     ,  cmdFile       , completionCmdFile,
217       "file <filename>\t\t load symbolic information from <filename>\n"
218     },
219     { "frame"    ,  cmdFrame      , NULL,
220       "{fr}ame\t\t print information about the current Stack\n"
221     },
222     { "finish"   ,  cmdFinish     , NULL,
223       "{fi}nish\t\t execute till return of current function\n"
224     },
225     { "fi"       ,  cmdFinish     , NULL, NULL },
226     { "where"    ,  cmdWhere      , NULL, "where\t\t print stack\n" },
227     { "fr"       ,  cmdFrame      , NULL, NULL },
228     { "f"        ,  cmdFrame      , NULL, NULL },
229     { "x /i"     ,  cmdDisasm1    , NULL, "x\t\t disassemble one asm command\n" },
230     { "!"        ,  cmdSimulator  , NULL,
231       "!<simulator command>\t send a command directly to the simulator\n"
232     },
233     { "."        ,  cmdSimulator  , NULL,
234       ".{cmd}\t switch from simulator or debugger command mode\n"
235     },
236     { "help"     ,  cmdHelp       , NULL,
237       "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
238     },
239     { "?"        ,  cmdHelp       , NULL, NULL },
240     { "h"        ,  cmdHelp       , NULL, NULL },
241
242     { "quit"     ,  cmdQuit       , NULL,
243       "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
244     },
245     { "q"        ,  cmdQuit       , NULL, NULL }
246 };
247
248 /*-----------------------------------------------------------------*/
249 /* trimming functions                                              */
250 /*-----------------------------------------------------------------*/
251 char *trim_left(char *s)
252 {
253     while (isspace(*s))
254         ++s;
255
256     return s;
257 }
258
259 char *trim_right(char *s)
260 {
261     char *p = &s[strlen(s) - 1];
262
263     while (p >= s && isspace(*p))
264       --p;
265     *++p = '\0';
266
267     return s;
268 }
269
270 char *trim(char *s)
271 {
272     return trim_right(trim_left(s));
273 }
274
275 /*-----------------------------------------------------------------*/
276 /* gc_strdup - make a string duplicate garbage collector aware     */
277 /*-----------------------------------------------------------------*/
278 char *gc_strdup(const char *s)
279 {
280     char *ret;
281     ret = Safe_malloc(strlen(s)+1);
282     strcpy(ret, s);
283     return ret;
284 }
285
286 /*-----------------------------------------------------------------*/
287 /* alloccpy - allocate copy and return a new string                */
288 /*-----------------------------------------------------------------*/
289 char *alloccpy ( char *s, int size)
290 {
291     char *d;
292
293     if (!size)
294         return NULL;
295
296     d = Safe_malloc(size+1);
297     memcpy(d,s,size);
298     d[size] = '\0';
299
300     return d;
301 }
302
303 /*-----------------------------------------------------------------*/
304 /* resize - resizes array of type with new size                    */
305 /*-----------------------------------------------------------------*/
306 void **resize (void **array, int newSize)
307 {
308     void **vptr;
309
310     if (array)
311         vptr = Safe_realloc(array,newSize*(sizeof(void **)));
312     else
313         vptr = calloc(1, sizeof(void **));
314
315     if (!vptr) {
316         fprintf(stderr,"sdcdb: out of memory \n");
317         exit(1);
318     }
319
320     return vptr;
321
322 }
323
324 /*-----------------------------------------------------------------*/
325 /* readCdb - reads the cdb files & puts the records into cdbLine   */
326 /*           linked list                                           */
327 /*-----------------------------------------------------------------*/
328 static int readCdb (FILE *file)
329 {
330     cdbrecs *currl ;
331     char buffer[1024];
332     char *bp ;
333
334     if (!(bp = fgets(buffer,sizeof(buffer),file)))
335         return 0;
336
337     currl = Safe_calloc(1,sizeof(cdbrecs));
338     recsRoot = currl ;
339
340     while (1) {
341
342         /* make sure this is a cdb record */
343         if (strchr("STLFM",*bp) && *(bp+1) == ':') {
344             /* depending on the record type */
345
346             switch (*bp) {
347             case 'S':
348                 /* symbol record */
349                 currl->type = SYM_REC;
350                 break;
351             case 'T':
352                 currl->type = STRUCT_REC;
353                 break;
354             case 'L':
355                 currl->type = LNK_REC;
356                 break;
357             case 'F':
358                 currl->type = FUNC_REC;
359                 break;
360             case 'M':
361                 currl->type = MOD_REC ;
362             }
363
364             bp += 2;
365             currl->line = Safe_malloc(strlen(bp));
366             strncpy(currl->line,bp,strlen(bp)-1);
367             currl->line[strlen(bp)-1] = '\0';
368         }
369
370         if (!(bp = fgets(buffer,sizeof(buffer),file)))
371             break;
372
373         if (feof(file))
374             break;
375
376         currl->next = Safe_calloc(1,sizeof(cdbrecs));
377         currl = currl->next;
378     }
379
380     return (recsRoot->line ? 1 : 0);
381 }
382
383 /*-----------------------------------------------------------------*/
384 /* searchDirsFname - search directory list & return the filename   */
385 /*-----------------------------------------------------------------*/
386 char *searchDirsFname (char *fname)
387 {
388     char *dirs , *sdirs;
389     FILE *rfile = NULL;
390     char buffer[1024];
391
392     /* first try the current directory */
393     if ((rfile = fopen(fname,"r"))) {
394         fclose(rfile);
395         return strdup(fname) ;
396     }
397
398     if (!ssdirl)
399         return strdup(fname);
400
401     /* make a copy of the source directories */
402     dirs = sdirs = strdup(ssdirl);
403
404     /* assume that the separator is ':'
405        and try for each directory in the search list */
406     dirs = strtok(dirs,":");
407     while (dirs) {
408         if (dirs[strlen(dirs)] == '/')
409             sprintf(buffer,"%s%s",dirs,fname);
410         else
411             sprintf(buffer,"%s/%s",dirs,fname);
412         if ((rfile = fopen(buffer,"r")))
413             break ;
414         dirs = strtok(NULL,":");
415     }
416
417     free(sdirs);
418     if (rfile) {
419         fclose(rfile);
420         return strdup(buffer);
421     } else
422         return strdup(fname);
423 }
424
425 /*-----------------------------------------------------------------*/
426 /* searchDirsFopen - go thru list of directories for filename given*/
427 /*-----------------------------------------------------------------*/
428 FILE *searchDirsFopen(char *fname)
429 {
430     char *dirs , *sdirs;
431     FILE *rfile = NULL;
432     char buffer[1024];
433
434     /* first try the current directory */
435     if ((rfile = fopen(fname,"r")))
436         return rfile;
437
438     if (!ssdirl)
439         return NULL;
440     /* make a copy of the source directories */
441     dirs = sdirs = strdup(ssdirl);
442
443     /* assume that the separator is ':'
444        and try for each directory in the search list */
445     dirs = strtok(dirs,":");
446     while (dirs) {
447         sprintf(buffer,"%s/%s",dirs,fname);
448         if ((rfile = fopen(buffer,"r")))
449             break ;
450         dirs = strtok(NULL,":");
451     }
452
453     free(sdirs);
454     return rfile ;
455
456 }
457
458 /*-----------------------------------------------------------------*/
459 /* loadFile - loads a file into module buffer                      */
460 /*-----------------------------------------------------------------*/
461 srcLine **loadFile (char *name, int *nlines)
462 {
463     FILE *mfile ;
464     char buffer[512];
465     char *bp;
466     srcLine **slines = NULL;
467
468
469     if (!(mfile = searchDirsFopen(name))) {
470         fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
471         return NULL;
472     }
473
474     while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
475         (*nlines)++;
476
477         slines = (srcLine **)resize((void **)slines,*nlines);
478
479         slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
480         slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
481         slines[(*nlines)-1]->addr= INT_MAX;
482     }
483
484     fclose(mfile);
485     return slines;
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* loadModules - reads the source files into module structure      */
491 /*-----------------------------------------------------------------*/
492 static void loadModules (void)
493 {
494     cdbrecs *loop;
495     module *currMod;
496     char *rs;
497
498     /* go thru the records & find out the module
499        records & load the modules specified */
500     for ( loop = recsRoot ; loop ; loop = loop->next ) {
501
502         switch (loop->type) {
503         /* for module records do */
504         case MOD_REC:
505             currMod = parseModule(loop->line, TRUE);
506             currModName = currMod->name ;
507
508             currMod->cfullname = searchDirsFname(currMod->c_name);
509
510             /* load it into buffer */
511             currMod->cLines = loadFile (currMod->c_name,
512             &currMod->ncLines);
513
514             /* do the same for the assembler file */
515             currMod->afullname = searchDirsFname(currMod->asm_name);
516             currMod->asmLines=loadFile (currMod->asm_name,
517                 &currMod->nasmLines);
518             break;
519
520         /* if this is a function record */
521         case FUNC_REC:
522             parseFunc(loop->line);
523             break;
524
525         /* if this is a structure record */
526         case STRUCT_REC:
527             parseStruct(loop->line);
528             break;
529
530         /* if symbol then parse the symbol */
531         case  SYM_REC:
532             parseSymbol(loop->line,&rs,2);
533             break;
534
535         case LNK_REC:
536             parseLnkRec(loop->line);
537             break;
538         }
539     }
540 }
541
542 /*-----------------------------------------------------------------*/
543 /* generate extra sets of sfr and sbit symbols                     */
544 /*-----------------------------------------------------------------*/
545 static void specialFunctionRegs (void)
546 {
547     symbol *sym;
548     for (sym = setFirstItem(symbols);
549          sym ;
550          sym = setNextItem(symbols))
551     {
552         if ( sym->addrspace == 'I' ||
553              sym->addrspace == 'J')
554         {
555             addSet(&sfrsymbols,sym);
556         }
557     }
558 }
559 /*-----------------------------------------------------------------*/
560 /* functionPoints - determine the execution points within a func   */
561 /*-----------------------------------------------------------------*/
562 static void functionPoints (void)
563 {
564     function *func;
565     symbol *sym;
566     exePoint *ep ;
567
568     // add _main dummy for runtime env
569     if ((func = needExtraMainFunction()))
570     {
571         function *func1;
572
573         /* alloc new _main function */
574         func1 = Safe_calloc(1,sizeof(function));
575         *func1 = *func;
576         func1->sym = Safe_calloc(1,sizeof(symbol));
577         *func1->sym =  *func->sym;
578         func1->sym->name  = alloccpy("_main",5);
579         func1->sym->rname = alloccpy("G$_main$0$",10);
580         /* TODO must be set by symbol information */
581         func1->sym->addr  = 0;
582         func1->sym->eaddr = 0x2f;
583         addSet(&functions,func1);
584     }
585
586     /* for all functions do */
587     for ( func = setFirstItem(functions); func;
588           func = setNextItem(functions)) {
589         int j ;
590         module *mod;
591
592         sym = func->sym;
593
594         Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
595                           func->sym->name,
596                           func->sym->addr,
597                           func->sym->eaddr));
598
599         if (!func->sym->addr && !func->sym->eaddr)
600             continue ;
601
602         /* for all source lines in the module find
603            the ones with address >= start and <= end
604            and put them in the point */
605         mod = NULL ;
606         if (! applyToSet(modules,moduleWithName,func->modName,&mod))
607             continue ;
608         func->mod = mod ;
609         func->entryline= INT_MAX-2;
610         func->exitline =  0;
611         func->aentryline = INT_MAX-2 ;
612         func->aexitline = 0;
613
614         /* do it for the C Lines first */
615         for ( j = 0 ; j < mod->ncLines ; j++ ) {
616             if (mod->cLines[j]->addr < INT_MAX &&
617                 mod->cLines[j]->addr >= sym->addr &&
618                 mod->cLines[j]->addr <= sym->eaddr ) {
619
620
621                 /* add it to the execution point */
622                 if (func->entryline > j)
623                     func->entryline = j;
624
625                 if (func->exitline < j)
626                     func->exitline = j;
627
628                 ep = Safe_calloc(1,sizeof(exePoint));
629                 ep->addr =  mod->cLines[j]->addr ;
630                 ep->line = j;
631                 ep->block= mod->cLines[j]->block;
632                 ep->level= mod->cLines[j]->level;
633                 addSet(&func->cfpoints,ep);
634             }
635         }
636         /* check double line execution points of module */
637         for (ep = setFirstItem(mod->cfpoints); ep;
638              ep = setNextItem(mod->cfpoints))
639         {
640             if (ep->addr >= sym->addr &&
641                 ep->addr <= sym->eaddr )
642             {
643                 addSet(&func->cfpoints,ep);
644             }
645         }
646         /* do the same for asm execution points */
647         for ( j = 0 ; j < mod->nasmLines ; j++ ) {
648             if (mod->asmLines[j]->addr < INT_MAX &&
649                 mod->asmLines[j]->addr >= sym->addr &&
650                 mod->asmLines[j]->addr <= sym->eaddr ) {
651
652                 exePoint *ep ;
653                 /* add it to the execution point */
654                 if (func->aentryline > j)
655                     func->aentryline = j;
656
657                 if (func->aexitline < j)
658                     func->aexitline = j;
659
660                 /* add it to the execution point */
661                 ep = Safe_calloc(1,sizeof(exePoint));
662                 ep->addr =  mod->asmLines[j]->addr ;
663                 ep->line = j;
664                 addSet(&func->afpoints,ep);
665             }
666         }
667         if ( func->entryline == INT_MAX-2 )
668             func->entryline = 0;
669         if ( func->aentryline == INT_MAX-2 )
670             func->aentryline = 0;
671
672 #ifdef SDCDB_DEBUG
673         if (!( D_sdcdb & sdcdbDebug))
674             continue;
675
676         Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
677                           func->sym->name));
678         {
679             exePoint *ep;
680
681             for (ep = setFirstItem(func->cfpoints); ep;
682                  ep = setNextItem(func->cfpoints))
683                 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
684                                   ep->addr,ep->line+1,mod->cLines[ep->line]->src));
685
686             Dprintf(D_sdcdb, ("sdcdb:  and the following ASM exePoints\n"));
687             for (ep = setFirstItem(func->afpoints); ep;
688                  ep = setNextItem(func->afpoints))
689                 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
690                                    ep->addr,ep->line+1,mod->asmLines[ep->line]->src));
691         }
692 #endif
693     }
694 }
695
696 /*-----------------------------------------------------------------*/
697 /* cmdFile - load file into the debugger                           */
698 /*-----------------------------------------------------------------*/
699 int cmdFile (char *s,context *cctxt)
700 {
701     FILE *cdbFile;
702     char buffer[1024];
703     char *bp;
704
705     s = trim_left(s);
706
707     if (!*s) {
708         fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
709         return 0;
710     }
711
712     sprintf(buffer,"%s.cdb",s);
713     /* try creating the cdbfile */
714     if (!(cdbFile = searchDirsFopen(buffer))) {
715         fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
716         // return 0;
717     }
718
719     /* allocate for context */
720     currCtxt = Safe_calloc(1,sizeof(context));
721
722     if (cdbFile) {
723         /* readin the debug information */
724         if (!readCdb (cdbFile)) {
725             fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
726           //return 0;
727         }
728     }
729
730     /* parse and load the modules required */
731     loadModules();
732
733     /* determine the execution points for this
734        module */
735     functionPoints();
736
737     /* extract known special function registers */
738     specialFunctionRegs();
739
740     /* start the simulator & setup connection to it */
741 #ifdef _WIN32
742     if (INVALID_SOCKET == sock)
743 #else
744     if ( sock == -1 )
745 #endif
746         openSimulator((char **)simArgs,nsimArgs);
747     fprintf(stdout,"%s",simResponse());
748     /* now send the filename to be loaded to the simulator */
749     sprintf(buffer,"%s.ihx",s);
750     bp=searchDirsFname(buffer);
751     simLoadFile(bp);
752     free(bp);
753
754     /*set the break points
755        required by the debugger . i.e. the function entry
756        and function exit break points */
757 //    applyToSet(functions,setEntryExitBP);
758
759     setMainContext();
760     return 0;
761 }
762
763 /*-----------------------------------------------------------------*/
764 /* cmdSource - read commands from file                             */
765 /*-----------------------------------------------------------------*/
766 int cmdSource (char *s, context *cctxt)
767 {
768     FILE *cmdfile;
769
770     s = trim(s);
771
772     if (!( cmdfile = searchDirsFopen(s)))
773     {
774         fprintf(stderr,"commandfile '%s' not found\n",s);
775         return 0;
776     }
777     commandLoop( cmdfile );
778     fclose( cmdfile );
779     return 0;
780 }
781
782 /*-----------------------------------------------------------------*/
783 /* cmdHelp - help command                                          */
784 /*-----------------------------------------------------------------*/
785 int cmdHelp (char *s, context *cctxt)
786 {
787     int i ;
788     int endline = 999;
789     int startline = 0;
790
791     s = trim_left(s);
792
793     if (isdigit(*s)) {
794         endline = ((*s - '0') * 20) + 20;
795         if (endline > 0)
796             startline = endline - 20;
797     }
798     else if (*s)
799     {
800         for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
801         {
802             if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
803             {
804                 s = strrchr(cmdTab[i].htxt,'\t');
805                 if ( !s )
806                     s = cmdTab[i].htxt;
807                 else
808                     s++;
809                 fprintf(stdout,"%s",s);
810                 break;
811             }
812         }
813         return 0;
814     }
815
816     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
817
818         /* command string matches */
819
820         if ((cmdTab[i].htxt) && (i >= startline))
821             fprintf(stdout,"%s",cmdTab[i].htxt);
822         if (i == endline)
823             break;
824     }
825
826     return 0;
827 }
828
829 #define MAX_CMD_LEN 512
830 static char cmdbuff[MAX_CMD_LEN];
831 static int sim_cmd_mode = 0;
832
833 char *
834 canonname(char *file)
835 {
836     static char buffer[1024];
837     if (*file == '/')
838         return file;
839     sprintf(buffer,"%s/%s", current_directory, file);
840     return buffer;
841 }
842
843 /*-----------------------------------------------------------------
844  interpretCmd - interpret and do the command.  Return 0 to continue,
845    return 1 to exit program.
846 |-----------------------------------------------------------------*/
847 int interpretCmd (char *s)
848 {
849     static char *pcmd = NULL;
850     int i ;
851     int rv = 0 ;
852
853     /* if nothing & previous command exists then
854        execute the previous command again */
855     if ((*s == '\n' || *s == '\0') && pcmd)
856         strcpy(s,pcmd);
857
858     /* if previous command exists & is different
859        from the current command then copy it */
860     if (pcmd) {
861         if (strcmp(pcmd,s)) {
862            free(pcmd);
863            pcmd = strdup(s);
864         }
865     } else
866         pcmd = strdup(s);
867
868     /* trim trailing blanks */
869     s = trim_right(s);
870
871     if (sim_cmd_mode) {
872         if (strcmp(s,".") == 0) {
873           sim_cmd_mode = 0;
874           return 0;
875         }
876         else if (s[0] == '.') {
877             /* kill the preceeding '.' and pass on as SDCDB command */
878             char *s1 = s+1;
879             char *s2 = s;
880             while (*s1 != 0)
881                 *s2++ = *s1++;
882             *s2 = 0;
883         } else {
884             cmdSimulator (s, currCtxt);
885             return 0;
886         }
887     } else {
888         if (strcmp(s,".") ==0) {
889             sim_cmd_mode = 1;
890             return 0;
891         }
892     }
893
894     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
895
896         /* command string matches */
897         if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
898             if (!cmdTab[i].cmdfunc)
899                 return 1;
900
901             rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
902
903             /* if full name then give the file name & position */
904             if (fullname && showfull && currCtxt && currCtxt->func) {
905                 showfull = 0;
906                 if (srcMode == SRC_CMODE)
907                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
908                         canonname(currCtxt->func->mod->cfullname),
909                         currCtxt->cline+1,currCtxt->addr);
910                 else
911                     fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
912                         canonname(currCtxt->func->mod->afullname),
913                         currCtxt->asmline,currCtxt->addr);
914                 displayAll(currCtxt);
915             }
916             goto ret;
917         }
918     }
919
920     fprintf(stdout,"Undefined command: \"%s\".  Try \"help\".\n",s);
921  ret:
922     return rv;
923 }
924
925 static FILE *actualcmdfile=NULL ;
926 static char *actualcmds=NULL;
927 static int   stopcmdlist;
928 /*-----------------------------------------------------------------*/
929 /* getNextCmdLine get additional lines used by special commands    */
930 /*-----------------------------------------------------------------*/
931 char *getNextCmdLine(void)
932 {
933     //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
934     if (!actualcmdfile)
935         return NULL;
936     fprintf(stdout,">");
937     fflush(stdout);
938     if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
939     {
940         // fprintf(stderr,"getNextCmdLine() returns null\n");
941         return NULL;
942     }
943     //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
944     return cmdbuff;
945 }
946
947 void setCmdLine( char *cmds )
948 {
949     actualcmds = cmds;
950 }
951
952 void stopCommandList()
953 {
954     stopcmdlist = 1;
955 }
956
957 #ifdef HAVE_READLINE_COMPLETITION
958 // helper function for doing readline completion.
959 // input: toknum=index of token to find (0=first token)
960 // output: *start=first character index of the token,
961 //                or the index of '\0'
962 //         *end=first blank character right after the token,
963 //                or the index of '\0'
964 // return value: 0=token not found, 1=token found
965 int completionHelper_GetTokenNumber(int toknum, int *start, int *end)
966 {
967     int tok_index;
968     const char *p = rl_line_buffer;
969
970     tok_index = 0;
971     *start = *end = 0;
972     while (p[*end] != 0)
973     {
974         // start = skip blanks from end
975         *start = *end;
976         while (p[*start] && isspace( p[*start] ))
977             (*start)++;
978
979         // end = skip non-blanks from start
980         *end = *start;
981         while (p[*end] && !isspace( p[*end] ))
982             (*end)++;
983
984         if (tok_index == toknum)
985             return 1;   // found
986
987         tok_index++;
988     }
989
990     return 0;   // not found
991 }
992
993 // helper function for doing readline completion.
994 // returns the token number that we were asked to complete.
995 // 0=first token (command name), 1=second token...
996 int completionHelper_GetCurrTokenNumber()
997 {
998     int toknum, start, end;
999
1000     toknum = start = end = 0;
1001     while (1)
1002     {
1003         if (!completionHelper_GetTokenNumber(toknum, &start, &end))
1004             return toknum;
1005
1006         if (rl_point <= end)
1007             return toknum;
1008
1009         toknum++;
1010     }
1011 }
1012
1013 // exapmle for vallist on entry:
1014 //          "copying\0warranty\0";
1015 char *completionCompleteFromStrList(const char *text, int state, char *vallist)
1016 {
1017     static char *ptr;
1018     int len;
1019
1020     if (state == 0)
1021         ptr = vallist;
1022     else
1023         ptr += strlen(ptr)+1;
1024
1025     len = strlen(text);
1026     while (*ptr)
1027     {
1028         if ( (len < strlen(ptr)) &&
1029               !strncmp(text, ptr, len) )
1030             return strdup(ptr);
1031
1032         ptr += strlen(ptr)+1;
1033     }
1034
1035     return NULL;
1036 }
1037
1038 // readline library completion function.
1039 // completes from the list of all sdcdb command.
1040 char *completionCommandsList(const char *text, int state)
1041 {
1042     static int i = 0;
1043
1044     if (state == 0) // new completion?
1045     {   // yes, only complete if this is the first token on the line.
1046         int ok = 0; // try to complete this request?
1047         char *p = rl_line_buffer;
1048
1049         // skip blanks
1050         while (p && isspace(*p))
1051         {
1052             if (p-rl_line_buffer == rl_point)
1053                 ok = 1;
1054             p++;
1055         }
1056
1057         while (p && !isspace(*p))
1058         {
1059             if (p-rl_line_buffer == rl_point)
1060                 ok = 1;
1061             p++;
1062         }
1063
1064         if (p-rl_line_buffer == rl_point)
1065             ok = 1;
1066
1067         if ( !ok )
1068             return NULL; // no more completions
1069
1070         i = 0;  // ok, gonna complete. initialize static variable.
1071     }
1072     else i++;
1073
1074     for (; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1075     {
1076         int len = strlen(text);
1077         if (len <= strlen(cmdTab[i].cmd))
1078         {
1079             if (strncmp(text,cmdTab[i].cmd,len) == 0)
1080                 return strdup(cmdTab[i].cmd);
1081         }
1082     }
1083
1084     return NULL; // no more completions
1085 }
1086
1087 // readline library completion function.
1088 // completes from the list of symbols.
1089 char *completionSymbolName(const char *text, int state)
1090 {
1091     static symbol *sy;
1092
1093     if (state == 0) // new completion?
1094         sy = setFirstItem(symbols); // yes
1095     else
1096       sy = setNextItem(symbols);
1097
1098     for (; sy != NULL; )
1099     {
1100         int len = strlen(text);
1101         if (len <= strlen(sy->name))
1102         {
1103             if (strncmp(text,sy->name,len) == 0)
1104                 return strdup(sy->name);
1105         }
1106
1107         sy = setNextItem(symbols);
1108     }
1109     return NULL;
1110 }
1111
1112 // readline library completion function.
1113 // completes from the list known functions.
1114 // module_flag - if false, ignore function module name
1115 //               if true, compare against module_name:fnction_name
1116 char *completionFunctionName(const char *text, int state, int module_flag)
1117 {
1118     static function *f;
1119
1120     if (state == 0) // new completion?
1121         f = setFirstItem(functions); // yes
1122     else
1123       f = setNextItem(functions);
1124
1125     for (; f != NULL; )
1126     {
1127         int text_len = strlen(text);
1128
1129         if (!module_flag)
1130         {
1131             if (text_len <= strlen(f->sym->name) &&
1132                 !strncmp(text,f->sym->name,text_len))
1133                 return strdup(f->sym->name);
1134         }
1135         else
1136         {
1137             int modname_len = strlen(f->mod->c_name);
1138             int funcname_len = strlen(f->sym->name);
1139             char *functext = malloc(modname_len+funcname_len+2);
1140             //assert(functext);
1141             strcpy(functext,f->mod->c_name);
1142             strcat(functext,":");
1143             strcat(functext,f->sym->name);
1144             if (text_len <= strlen(functext) &&
1145                 !strncmp(text,functext,text_len))
1146                 return functext;
1147             else
1148                 free(functext);
1149         }
1150         f = setNextItem(functions);
1151     }
1152     return NULL;
1153 }
1154
1155 // readline library completion function.
1156 // completes from the list known modules.
1157 char *completionModuleName(const char *text, int state)
1158 {
1159     static module *m;
1160
1161     if (state == 0) // new completion?
1162         m = setFirstItem(modules); // yes
1163     else
1164       m = setNextItem(modules);
1165
1166     for (; m != NULL; )
1167     {
1168         int len = strlen(text);
1169         if ( (len <= strlen(m->c_name)) &&
1170              !strncmp(text,m->c_name,len) )
1171             return strdup(m->c_name);
1172
1173         if ( (len <= strlen(m->asm_name)) &&
1174              (strncmp(text,m->asm_name,len) == 0) )
1175             return strdup(m->asm_name);
1176
1177         m = setNextItem(modules);
1178     }
1179     return NULL;
1180 }
1181
1182 // readline completion function for "file" command
1183 char *completionCmdFile(const char *text, int state)
1184 {
1185     if (state == 0)
1186     {
1187         if (completionHelper_GetCurrTokenNumber() != 1)
1188             return NULL;
1189     }
1190
1191     // we use filename_completion_function() from the readline library.
1192     return rl_filename_completion_function(text, state);
1193 }
1194
1195 // readline completion function for "source" command
1196 char *completionCmdSource(const char *text, int state)
1197 {
1198     return completionCmdFile(text, state);
1199 }
1200
1201 // readline completion function for "info" command
1202 char *completionCmdInfo(const char *text, int state)
1203 {
1204     static char *ptr;
1205
1206     if (state == 0)
1207     {
1208         if (completionHelper_GetCurrTokenNumber() != 1)
1209             return NULL;
1210     }
1211
1212     return completionCompleteFromStrList(text, state,
1213             "break\0stack\0frame\0registers\0all-registers\0"
1214             "line\0source\0functions\0symbols\0variables\0");
1215 }
1216
1217 // readline completion function for "show" command
1218 char *completionCmdShow(const char *text, int state)
1219 {
1220     static char *ptr;
1221
1222     if (state == 0)
1223     {
1224         if (completionHelper_GetCurrTokenNumber() != 1)
1225             return NULL;
1226     }
1227     return completionCompleteFromStrList(text, state, "copying\0warranty\0");
1228 }
1229
1230 // readline completion function for "la" command
1231 char *completionCmdListSymbols(const char *text, int state)
1232 {
1233     static char *ptr;
1234
1235     if (state == 0)
1236     {
1237         if (completionHelper_GetCurrTokenNumber() != 1)
1238             return NULL;
1239     }
1240     return completionCompleteFromStrList(text, state, "v1\0v2\0");
1241 }
1242
1243 char *completionCmdPrintType(const char *text, int state)
1244 {
1245     if (state == 0)
1246     {
1247         if (completionHelper_GetCurrTokenNumber() != 1)
1248             return NULL;
1249     }
1250     return completionSymbolName(text, state);
1251 }
1252
1253 char *completionCmdPrint(const char *text, int state)
1254 {
1255     if (state == 0)
1256     {
1257         int i = completionHelper_GetCurrTokenNumber();
1258         if (i != 1 && i != 2)
1259             return NULL;
1260     }
1261     return completionSymbolName(text, state);
1262 }
1263
1264 char *completionCmdDelUserBp(const char *text, int state)
1265 {
1266     static breakp *bp;
1267     static int k;
1268
1269     if (state == 0)
1270     {
1271         if (completionHelper_GetCurrTokenNumber() != 1)
1272             return NULL;
1273
1274         if (!userBpPresent)
1275             return NULL;
1276
1277         bp = hTabFirstItem(bptable,&k);
1278     }
1279     else
1280         bp = hTabNextItem(bptable,&k);
1281
1282     for ( ; bp ; bp = hTabNextItem(bptable,&k))
1283     {
1284         if (bp->bpType == USER || bp->bpType == TMPUSER)
1285         {
1286             char buff[20];
1287             sprintf(buff, "%d", bp->bpnum);
1288             return strdup(buff);
1289         }
1290     }
1291
1292     return NULL;
1293 }
1294
1295 // readline completion function for "undisplay" command
1296 char *completionCmdUnDisplay(const char *text, int state)
1297 {
1298     static dsymbol *dsym;
1299
1300     if (state == 0)
1301     {
1302         if (completionHelper_GetCurrTokenNumber() != 1)
1303             return NULL;
1304         dsym = setFirstItem(dispsymbols);
1305     }
1306
1307     if (dsym)
1308     {
1309         char buff[30];
1310         sprintf(buff, "%d", dsym->dnum);
1311         dsym = setNextItem(dispsymbols);
1312         return strdup(buff);
1313     }
1314     return NULL;
1315 }
1316
1317 char *completionCmdSetUserBp(const char *text, int state)
1318 {
1319     static int internal_state; // 0=calling completionFunctionName(text, state, 0)
1320                                // 1=calling completionFunctionName(text, 1, 1)
1321     if (state == 0)
1322     {
1323         if (completionHelper_GetCurrTokenNumber() != 1)
1324             return NULL;
1325
1326         internal_state = 0;
1327     }
1328     if (internal_state == 0)
1329     {
1330         char *p = completionFunctionName(text, state, 0);
1331         if (p)
1332             return p;
1333         internal_state = 1;
1334         return completionFunctionName(text, 0, 1);
1335     }
1336     else
1337     {
1338         return completionFunctionName(text, 1, 1);
1339     }
1340 }
1341
1342 char *completionCmdSetOption(const char *text, int state)
1343 {
1344     static char *ptr;
1345     static int currtok;
1346
1347     if (state == 0)
1348     {
1349         int start,end;
1350
1351         currtok = completionHelper_GetCurrTokenNumber();
1352
1353         if (currtok == 2 || currtok == 3)
1354         {
1355             // make sure token 1 == "variable"
1356             completionHelper_GetTokenNumber(1, &start, &end);
1357             if (end - start != 8 ||
1358                 strncmp(rl_line_buffer+start,"variable",8))
1359                 return NULL;
1360         }
1361         else if (currtok != 1)
1362         {
1363             return NULL;
1364         }
1365     }
1366
1367     switch (currtok)
1368     {
1369         case 1:
1370             return completionCompleteFromStrList(text, state,
1371 #ifdef SDCDB_DEBUG
1372                 "debug\0"
1373 #endif
1374                 "srcmode\0listsize\0variable\0");
1375         case 2:
1376             return completionSymbolName(text, state);
1377
1378         case 3:
1379             return completionCompleteFromStrList(text, state, "=\0");
1380     }
1381 }
1382
1383 // our main readline completion function
1384 // calls the other completion functions as needed.
1385 char *completionMain(const char *text, int state)
1386 {
1387     static rl_compentry_func_t *compl_func;
1388     int i, start, end, len;
1389
1390     if (state == 0) // new completion?
1391     {
1392         compl_func = NULL;
1393
1394         if (completionHelper_GetCurrTokenNumber() == 0)
1395             compl_func = &completionCommandsList;
1396         else
1397         {   // not completing first token, find the right completion
1398             // function according to the first token the user typed.
1399             completionHelper_GetTokenNumber(0, &start, &end);
1400             len = end-start;
1401
1402             for (i=0; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1403             {
1404                 if (!strncmp(rl_line_buffer+start,cmdTab[i].cmd,len) &&
1405                     cmdTab[i].cmd[len] == '\0')
1406                 {
1407                     compl_func = cmdTab[i].completion_func;
1408                     break;
1409                 }
1410             }
1411         }
1412         if (!compl_func)
1413             return NULL;
1414     }
1415
1416     return (*compl_func)(text,state);
1417 }
1418 #endif  /* HAVE_READLINE_COMPLETITION */
1419
1420 /*-----------------------------------------------------------------*/
1421 /* commandLoop - the main command loop or loop over command file   */
1422 /*-----------------------------------------------------------------*/
1423 static void commandLoop(FILE *cmdfile)
1424 {
1425     char *line, save_ch, *s;
1426     char *line_read;
1427
1428 #ifdef HAVE_LIBREADLINE
1429     FILE *old_rl_instream, *old_rl_outstream;
1430     actualcmdfile = cmdfile;
1431
1432 #ifdef HAVE_READLINE_COMPLETITION
1433     rl_completion_entry_function = completionMain;
1434 #endif  /* HAVE_READLINE_COMPLETITION */
1435     rl_readline_name = "sdcdb"; // Allow conditional parsing of the ~/.inputrc file.
1436
1437     // save readline's input/output streams
1438     // this is done to support nested calls to commandLoop()
1439     // i wonder if it works...
1440     old_rl_instream = rl_instream;
1441     old_rl_outstream = rl_outstream;
1442
1443     // set new streams for readline
1444     if ( cmdfile == stdin )
1445         rl_instream = rl_outstream = NULL;  // use stdin/stdout pair
1446     else
1447         rl_instream = rl_outstream = cmdfile;
1448
1449       while (1)
1450       {
1451           if ( cmdfile == stdin )
1452           {
1453               if (sim_cmd_mode)
1454                   line_read = (char*)readline ("(sim) ");
1455               else
1456                   line_read = (char*)readline ("(sdcdb) ");
1457           }
1458           else
1459               line_read = (char*)readline ("");
1460
1461         if (line_read)
1462         {
1463             /* If the line has any text in it,
1464                save it on the history. */
1465             if (line_read && *line_read)
1466               add_history (line_read);
1467
1468              // FIX: readline returns malloced string.
1469              //   should check the source to verify it can be used
1470              //    directly. for now - just copy it to cmdbuff.
1471             strcpy(cmdbuff,line_read);
1472 #if defined(_WIN32) || defined(HAVE_RL_FREE)
1473             rl_free(line_read);
1474 #else
1475             free(line_read);
1476 #endif
1477             line_read = NULL;
1478         }
1479         else
1480             break;  // EOF
1481 #else
1482     actualcmdfile = cmdfile;
1483
1484     while (1)
1485     {
1486         if ( cmdfile == stdin )
1487         {
1488             if (sim_cmd_mode)
1489                 printf("(sim) ");
1490             else
1491                 fprintf(stdout,"(sdcdb) ");
1492             fflush(stdout);
1493         }
1494         //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
1495         //        actualcmdfile,cmdfile);
1496         if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
1497             break;
1498 #endif  /* HAVE_LIBREADLINE */
1499
1500           if (interpretCmd(cmdbuff))
1501               break;
1502
1503         while ( actualcmds )
1504         {
1505             strcpy(cmdbuff,actualcmds);
1506             actualcmds = NULL;
1507             stopcmdlist= 0;
1508             for ( line = cmdbuff; *line ; line = s )
1509             {
1510                 if ( (s=strchr(line ,'\n')))
1511                 {
1512                     save_ch = *++s;
1513                     *s = '\0';
1514                 }
1515                 else
1516                 {
1517                     s += strlen( line );
1518                     save_ch = '\0';
1519                 }
1520                 if (interpretCmd( line ))
1521                 {
1522                     *s = save_ch;
1523                     break;
1524                 }
1525                 *s = save_ch;
1526                 if ( stopcmdlist )
1527                     break;
1528             }
1529         }
1530     }
1531 #ifdef HAVE_LIBREADLINE
1532     // restore readline's input/output streams
1533     rl_instream = old_rl_instream;
1534     rl_outstream = old_rl_outstream;
1535 #endif  /* HAVE_LIBREADLINE */
1536 }
1537
1538 /*-----------------------------------------------------------------*/
1539 /* printVersionInfo - print the version information                */
1540 /*-----------------------------------------------------------------*/
1541 static void printVersionInfo()
1542 {
1543     fprintf(stdout,
1544         "SDCDB is free software and you are welcome to distribute copies of it\n"
1545         "under certain conditions; type \"show copying\" to see the conditions.\n"
1546         "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
1547         "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
1548         "Type ? for help\n");
1549
1550 }
1551
1552 /*-----------------------------------------------------------------*/
1553 /* parseCmdLine - parse the commandline arguments                  */
1554 /*-----------------------------------------------------------------*/
1555 static void parseCmdLine (int argc, char **argv)
1556 {
1557     int i ;
1558     char *filename = NULL;
1559     int passon_args_flag = 0;  /* if true, pass on args to simulator */
1560
1561     Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
1562     contsim=0;
1563
1564     for ( i = 1; i < argc ; i++) {
1565         //fprintf(stdout,"%s\n",argv[i]);
1566
1567         if (passon_args_flag) { /* if true, pass on args to simulator */
1568             simArgs[nsimArgs++] = strdup(argv[i]);
1569             continue;
1570         }
1571
1572         /* if this is an option */
1573         if (argv[i][0] == '-') {
1574
1575             /* if directory then mark directory */
1576             if (strncmp(argv[i],"--directory=",12) == 0) {
1577                 if (!ssdirl)
1578                     ssdirl = &argv[i][12];
1579                 else {
1580                     char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
1581                     strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1582                     ssdirl = p;
1583                 }
1584                 continue;
1585             }
1586
1587             if (strncmp(argv[i],"-fullname",9) == 0) {
1588                 fullname = TRUE;
1589                 continue;
1590             }
1591
1592             if (strcmp(argv[i],"-cd") == 0) {
1593                 i++;
1594                 chdir(argv[i]);
1595                  continue;
1596             }
1597
1598             if (strncmp(argv[i],"-cd=",4) == 0) {
1599                 chdir(argv[i]+4);
1600                 continue;
1601             }
1602
1603 #ifdef SDCDB_DEBUG
1604             if (strncmp(argv[i],"-d=",3) == 0) {
1605                 sdcdbDebug = strtol(&argv[i][3],0,0);
1606                 continue;
1607             }
1608 #endif
1609             if (strncmp(argv[i],"-contsim",8) == 0) {
1610                 contsim=1;
1611                 continue;
1612             }
1613             if (strncmp(argv[i],"-q",2) == 0) {
1614                 continue;
1615             }
1616
1617             /* model string */
1618             if (strncmp(argv[i],"-m",2) == 0) {
1619                 strncpy(model_str, &argv[i][2], 15);
1620                 if (strcmp(model_str,"avr") == 0)
1621                     simArgs[0] = "savr";
1622                 else if (strcmp(model_str,"xa") == 0)
1623                     simArgs[0] = "sxa";
1624                 else if (strcmp(model_str,"z80") == 0)
1625                     simArgs[0] = "sz80";
1626                 continue ;
1627             }
1628
1629             /* -z all remaining options are for simulator */
1630             if (strcmp(argv[i],"-z") == 0) {
1631                 passon_args_flag = 1;
1632                 continue ;
1633             }
1634
1635             /* the simulator arguments */
1636
1637             /* cpu */
1638             if (strcmp(argv[i],"-t") == 0 ||
1639                 strcmp(argv[i],"-cpu") == 0) {
1640
1641                 simArgs[nsimArgs++] = "-t";
1642                 simArgs[nsimArgs++] = strdup(argv[++i]);
1643                 continue ;
1644             }
1645
1646             /* XTAL Frequency */
1647             if (strcmp(argv[i],"-X") == 0 ||
1648                 strcmp(argv[i],"-frequency") == 0) {
1649                 simArgs[nsimArgs++] = "-X";
1650                 simArgs[nsimArgs++] = strdup(argv[++i]);
1651                 continue ;
1652             }
1653
1654             /* serial port */
1655             if ( (strcmp(argv[i],"-S") == 0) ||
1656                 (strcmp(argv[i],"-s") == 0) ||
1657                  (strcmp(argv[i],"-T") == 0) ||
1658                  (strcmp(argv[i],"--tty") == 0)) {
1659                 simArgs[nsimArgs++] = "--tty";
1660                 simArgs[nsimArgs++] = strdup(argv[++i]);
1661                 continue ;
1662             }
1663
1664             /* network serial port */
1665             if ( (strcmp(argv[i],"-k") == 0)) {
1666                 simArgs[nsimArgs++] = strdup(argv[i]);
1667                 simArgs[nsimArgs++] = strdup(argv[++i]);
1668                 continue ;
1669             }
1670
1671             fprintf(stderr,"unknown option %s --- ignored\n",
1672                 argv[i]);
1673
1674         } else {
1675             /* must be file name */
1676             if (filename) {
1677                 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1678                     argv[i]);
1679                 continue ;
1680             }
1681
1682             if (-1 != access(argv[i], 0)) {
1683                 /* file exists: strip the cdb or ihx externsion */
1684                 char *p = strrchr(argv[i], '.');
1685
1686                 if (NULL != p &&
1687                     (0 == strcmp(p, ".cdb") || 0 == strcmp(p, ".ihx")))
1688                     *p = '\0';
1689             }
1690             filename = argv[i];
1691
1692         }
1693     }
1694
1695     if (filename)
1696         cmdFile(filename,NULL);
1697 }
1698
1699 /*-----------------------------------------------------------------*/
1700 /* setsignals -  catch some signals                                */
1701 /*-----------------------------------------------------------------*/
1702 #include <signal.h>
1703 static void
1704 bad_signal(int sig)
1705 {
1706     if ( simactive )
1707         closeSimulator();
1708     exit(1);
1709 }
1710
1711 static void
1712 sigintr(int sig)
1713 {
1714     /* may be interrupt from user: stop debugger and also simulator */
1715     userinterrupt = 1;
1716     if ( !nointerrupt )
1717         sendSim("stop\n");
1718 }
1719
1720 #ifndef _WIN32
1721 /* the only child can be the simulator */
1722 static void sigchld(int sig)
1723 {
1724     /* the only child can be the simulator */
1725     int status, retpid;
1726     retpid = wait ( &status );
1727     /* if ( retpid == simPid ) */
1728     simactive = 0;
1729 }
1730 #endif
1731
1732 static void
1733 setsignals()
1734 {
1735     signal(SIGINT , sigintr );
1736     signal(SIGABRT, bad_signal);
1737     signal(SIGTERM, bad_signal);
1738
1739 #ifndef _WIN32
1740     signal(SIGHUP , SIG_IGN);
1741     signal(SIGCONT, SIG_IGN);
1742     signal(SIGCHLD, sigchld );
1743
1744     signal(SIGALRM, bad_signal);
1745     //signal(SIGFPE,  bad_signal);
1746     //signal(SIGILL,  bad_signal);
1747     signal(SIGPIPE, bad_signal);
1748     signal(SIGQUIT, bad_signal);
1749     //signal(SIGSEGV, bad_signal);
1750 #endif
1751 }
1752
1753 /*-----------------------------------------------------------------*/
1754 /* main -                                                          */
1755 /*-----------------------------------------------------------------*/
1756
1757 int main ( int argc, char **argv)
1758 {
1759     printVersionInfo();
1760     printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1761
1762     current_directory = get_current_dir_name();
1763     simArgs[nsimArgs++] = "ao-dbg";
1764     simArgs[nsimArgs++] = "-P";
1765     simArgs[nsimArgs++] = "-r 9756";
1766     /* parse command line */
1767
1768     setsignals();
1769     parseCmdLine(argc,argv);
1770
1771     commandLoop(stdin);
1772
1773     return 0;
1774 }