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