1 /*-------------------------------------------------------------------------
2 sdcdb.c - main source file for sdcdb debugger
3 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
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
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.
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.
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 -------------------------------------------------------------------------*/
24 #define link unix_link
34 #if defined HAVE_LIBREADLINE && HAVE_LIBREADLINE != -1
35 #define HAVE_READLINE_COMPLETITION 1
37 #ifdef HAVE_LIBREADLINE
38 #include <readline/readline.h>
39 #include <readline/history.h>
40 #endif /* HAVE_LIBREADLINE */
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 */
53 structdef **structs = NULL ; /* all structures */
55 linkrec **linkrecs = NULL; /* all linkage editor records */
56 context *currCtxt = NULL;
59 char userinterrupt = 0;
62 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX DIR_SEPARATOR_STRING "small" ;
66 /* fake filename & lineno to make linker */
68 char *current_directory;
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);
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 */
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;
108 #endif /* HAVE_READLINE_COMPLETITION */
109 char *htxt ; /* short help text */
112 /* NOTE:- the search is done from the top, so "break" should
113 precede the synonym "b" */
115 { "break" , cmdSetUserBp , completionCmdSetUserBp,
116 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
118 { "tbreak" , cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/,
119 "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
121 { "b" , cmdSetUserBp , completionCmdSetUserBp , NULL,},
123 { "jump" , cmdJump , NULL,
124 "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *<address>]\n",
126 { "clear" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/,
127 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
129 { "cl" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/ , NULL,},
131 { "continue" , cmdContinue , NULL,
132 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
134 { "condition" , cmdCondition , completionCmdDelUserBp/*same as "delete"*/,
135 "condition brkpoint_number expr\t\tSet condition for breakpoint.\n"
137 { "ignore" , cmdIgnore , completionCmdDelUserBp/*same as "delete"*/,
138 "ignore brkpoint_number count\t\tSet ignore count for breakpoint.\n"
140 { "commands" , cmdCommands , completionCmdDelUserBp/*same as "delete"*/,
141 "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n"
143 { "c" , cmdContinue , NULL , NULL,},
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"
149 { "display" , cmdDisplay , completionCmdPrint/*same as "print"*/,
150 "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
152 { "undisplay" , cmdUnDisplay , completionCmdUnDisplay,
153 "undisplay [<variable>]\t dont display this variable or all\n"
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"
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"
161 { "d" , cmdDelUserBp , completionCmdDelUserBp, NULL },
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"
168 { "listasm" , cmdListAsm , NULL,
169 "listasm {la}\t\t list assembler code for the current C line\n"
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"
178 { "l" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/, NULL },
179 { "show" , cmdShow , completionCmdShow,
181 " <copying warranty>\t copying & distribution terms, warranty\n"
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"
187 { "step" , cmdStep , NULL,
188 "{s}tep\t\t\tStep program until it reaches a different source line.\n"
190 { "source" , cmdSource , completionCmdSource,
191 "source <FILE>\t\t\tRead commands from a file named FILE.\n"
193 { "s" , cmdStep , NULL, NULL },
194 { "nexti" , cmdNexti , NULL,
195 "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
197 { "next" , cmdNext , NULL,
198 "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
200 { "n" , cmdNext , NULL, NULL },
201 { "run" , cmdRun , NULL,
202 "{r}un\t\t\tStart debugged program. \n"
204 { "r" , cmdRun , NULL, NULL },
205 { "ptype" , cmdPrintType , completionCmdPrintType,
206 "{pt}ype <variable>\tprint type information of a variable\n"
208 { "pt" , cmdPrintType , NULL, NULL },
209 { "print" , cmdPrint , completionCmdPrintType,
210 "{p}rint <variable>\t print value of given variable\n"
212 { "output" , cmdOutput , completionCmdPrint/*same as "print"*/,
213 "output <variable>\t print value of given variable without $ and newline \n"
215 { "p" , cmdPrint , completionCmdPrintType, NULL },
216 { "file" , cmdFile , completionCmdFile,
217 "file <filename>\t\t load symbolic information from <filename>\n"
219 { "frame" , cmdFrame , NULL,
220 "{fr}ame\t\t print information about the current Stack\n"
222 { "finish" , cmdFinish , NULL,
223 "{fi}nish\t\t execute till return of current function\n"
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"
233 { "." , cmdSimulator , NULL,
234 ".{cmd}\t switch from simulator or debugger command mode\n"
236 { "help" , cmdHelp , NULL,
237 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
239 { "?" , cmdHelp , NULL, NULL },
240 { "h" , cmdHelp , NULL, NULL },
242 { "quit" , cmdQuit , NULL,
243 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
245 { "q" , cmdQuit , NULL, NULL }
248 /*-----------------------------------------------------------------*/
249 /* trimming functions */
250 /*-----------------------------------------------------------------*/
251 char *trim_left(char *s)
259 char *trim_right(char *s)
261 char *p = &s[strlen(s) - 1];
263 while (p >= s && isspace(*p))
272 return trim_right(trim_left(s));
275 /*-----------------------------------------------------------------*/
276 /* gc_strdup - make a string duplicate garbage collector aware */
277 /*-----------------------------------------------------------------*/
278 char *gc_strdup(const char *s)
281 ret = Safe_malloc(strlen(s)+1);
286 /*-----------------------------------------------------------------*/
287 /* alloccpy - allocate copy and return a new string */
288 /*-----------------------------------------------------------------*/
289 char *alloccpy ( char *s, int size)
296 d = Safe_malloc(size+1);
303 /*-----------------------------------------------------------------*/
304 /* resize - resizes array of type with new size */
305 /*-----------------------------------------------------------------*/
306 void **resize (void **array, int newSize)
311 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
313 vptr = calloc(1, sizeof(void **));
316 fprintf(stderr,"sdcdb: out of memory \n");
324 /*-----------------------------------------------------------------*/
325 /* readCdb - reads the cdb files & puts the records into cdbLine */
327 /*-----------------------------------------------------------------*/
328 static int readCdb (FILE *file)
334 if (!(bp = fgets(buffer,sizeof(buffer),file)))
337 currl = Safe_calloc(1,sizeof(cdbrecs));
342 /* make sure this is a cdb record */
343 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
344 /* depending on the record type */
349 currl->type = SYM_REC;
352 currl->type = STRUCT_REC;
355 currl->type = LNK_REC;
358 currl->type = FUNC_REC;
361 currl->type = MOD_REC ;
365 currl->line = Safe_malloc(strlen(bp));
366 strncpy(currl->line,bp,strlen(bp)-1);
367 currl->line[strlen(bp)-1] = '\0';
370 if (!(bp = fgets(buffer,sizeof(buffer),file)))
376 currl->next = Safe_calloc(1,sizeof(cdbrecs));
380 return (recsRoot->line ? 1 : 0);
383 /*-----------------------------------------------------------------*/
384 /* searchDirsFname - search directory list & return the filename */
385 /*-----------------------------------------------------------------*/
386 char *searchDirsFname (char *fname)
392 /* first try the current directory */
393 if ((rfile = fopen(fname,"r"))) {
395 return strdup(fname) ;
399 return strdup(fname);
401 /* make a copy of the source directories */
402 dirs = sdirs = strdup(ssdirl);
404 /* assume that the separator is ':'
405 and try for each directory in the search list */
406 dirs = strtok(dirs,":");
408 if (dirs[strlen(dirs)] == '/')
409 sprintf(buffer,"%s%s",dirs,fname);
411 sprintf(buffer,"%s/%s",dirs,fname);
412 if ((rfile = fopen(buffer,"r")))
414 dirs = strtok(NULL,":");
420 return strdup(buffer);
422 return strdup(fname);
425 /*-----------------------------------------------------------------*/
426 /* searchDirsFopen - go thru list of directories for filename given*/
427 /*-----------------------------------------------------------------*/
428 FILE *searchDirsFopen(char *fname)
434 /* first try the current directory */
435 if ((rfile = fopen(fname,"r")))
440 /* make a copy of the source directories */
441 dirs = sdirs = strdup(ssdirl);
443 /* assume that the separator is ':'
444 and try for each directory in the search list */
445 dirs = strtok(dirs,":");
447 sprintf(buffer,"%s/%s",dirs,fname);
448 if ((rfile = fopen(buffer,"r")))
450 dirs = strtok(NULL,":");
458 /*-----------------------------------------------------------------*/
459 /* loadFile - loads a file into module buffer */
460 /*-----------------------------------------------------------------*/
461 srcLine **loadFile (char *name, int *nlines)
466 srcLine **slines = NULL;
469 if (!(mfile = searchDirsFopen(name))) {
470 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
474 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
477 slines = (srcLine **)resize((void **)slines,*nlines);
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;
489 /*-----------------------------------------------------------------*/
490 /* loadModules - reads the source files into module structure */
491 /*-----------------------------------------------------------------*/
492 static void loadModules (void)
498 /* go thru the records & find out the module
499 records & load the modules specified */
500 for ( loop = recsRoot ; loop ; loop = loop->next ) {
502 switch (loop->type) {
503 /* for module records do */
505 currMod = parseModule(loop->line, TRUE);
506 currModName = currMod->name ;
508 currMod->cfullname = searchDirsFname(currMod->c_name);
510 /* load it into buffer */
511 currMod->cLines = loadFile (currMod->c_name,
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);
520 /* if this is a function record */
522 parseFunc(loop->line);
525 /* if this is a structure record */
527 parseStruct(loop->line);
530 /* if symbol then parse the symbol */
532 parseSymbol(loop->line,&rs,2);
536 parseLnkRec(loop->line);
542 /*-----------------------------------------------------------------*/
543 /* generate extra sets of sfr and sbit symbols */
544 /*-----------------------------------------------------------------*/
545 static void specialFunctionRegs (void)
548 for (sym = setFirstItem(symbols);
550 sym = setNextItem(symbols))
552 if ( sym->addrspace == 'I' ||
553 sym->addrspace == 'J')
555 addSet(&sfrsymbols,sym);
559 /*-----------------------------------------------------------------*/
560 /* functionPoints - determine the execution points within a func */
561 /*-----------------------------------------------------------------*/
562 static void functionPoints (void)
568 // add _main dummy for runtime env
569 if ((func = needExtraMainFunction()))
573 /* alloc new _main function */
574 func1 = Safe_calloc(1,sizeof(function));
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);
586 /* for all functions do */
587 for ( func = setFirstItem(functions); func;
588 func = setNextItem(functions)) {
594 Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
599 if (!func->sym->addr && !func->sym->eaddr)
602 /* for all source lines in the module find
603 the ones with address >= start and <= end
604 and put them in the point */
606 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
609 func->entryline= INT_MAX-2;
611 func->aentryline = INT_MAX-2 ;
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 ) {
621 /* add it to the execution point */
622 if (func->entryline > j)
625 if (func->exitline < j)
628 ep = Safe_calloc(1,sizeof(exePoint));
629 ep->addr = mod->cLines[j]->addr ;
631 ep->block= mod->cLines[j]->block;
632 ep->level= mod->cLines[j]->level;
633 addSet(&func->cfpoints,ep);
636 /* check double line execution points of module */
637 for (ep = setFirstItem(mod->cfpoints); ep;
638 ep = setNextItem(mod->cfpoints))
640 if (ep->addr >= sym->addr &&
641 ep->addr <= sym->eaddr )
643 addSet(&func->cfpoints,ep);
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 ) {
653 /* add it to the execution point */
654 if (func->aentryline > j)
655 func->aentryline = j;
657 if (func->aexitline < j)
660 /* add it to the execution point */
661 ep = Safe_calloc(1,sizeof(exePoint));
662 ep->addr = mod->asmLines[j]->addr ;
664 addSet(&func->afpoints,ep);
667 if ( func->entryline == INT_MAX-2 )
669 if ( func->aentryline == INT_MAX-2 )
670 func->aentryline = 0;
673 if (!( D_sdcdb & sdcdbDebug))
676 Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
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));
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));
696 /*-----------------------------------------------------------------*/
697 /* cmdFile - load file into the debugger */
698 /*-----------------------------------------------------------------*/
699 int cmdFile (char *s,context *cctxt)
708 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
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);
719 /* allocate for context */
720 currCtxt = Safe_calloc(1,sizeof(context));
723 /* readin the debug information */
724 if (!readCdb (cdbFile)) {
725 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
730 /* parse and load the modules required */
733 /* determine the execution points for this
737 /* extract known special function registers */
738 specialFunctionRegs();
740 /* start the simulator & setup connection to it */
742 if (INVALID_SOCKET == sock)
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);
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);
763 /*-----------------------------------------------------------------*/
764 /* cmdSource - read commands from file */
765 /*-----------------------------------------------------------------*/
766 int cmdSource (char *s, context *cctxt)
772 if (!( cmdfile = searchDirsFopen(s)))
774 fprintf(stderr,"commandfile '%s' not found\n",s);
777 commandLoop( cmdfile );
782 /*-----------------------------------------------------------------*/
783 /* cmdHelp - help command */
784 /*-----------------------------------------------------------------*/
785 int cmdHelp (char *s, context *cctxt)
794 endline = ((*s - '0') * 20) + 20;
796 startline = endline - 20;
800 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
802 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
804 s = strrchr(cmdTab[i].htxt,'\t');
809 fprintf(stdout,"%s",s);
816 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
818 /* command string matches */
820 if ((cmdTab[i].htxt) && (i >= startline))
821 fprintf(stdout,"%s",cmdTab[i].htxt);
829 #define MAX_CMD_LEN 512
830 static char cmdbuff[MAX_CMD_LEN];
831 static int sim_cmd_mode = 0;
834 canonname(char *file)
836 static char buffer[1024];
839 sprintf(buffer,"%s/%s", current_directory, file);
843 /*-----------------------------------------------------------------
844 interpretCmd - interpret and do the command. Return 0 to continue,
845 return 1 to exit program.
846 |-----------------------------------------------------------------*/
847 int interpretCmd (char *s)
849 static char *pcmd = NULL;
853 /* if nothing & previous command exists then
854 execute the previous command again */
855 if ((*s == '\n' || *s == '\0') && pcmd)
858 /* if previous command exists & is different
859 from the current command then copy it */
861 if (strcmp(pcmd,s)) {
868 /* trim trailing blanks */
872 if (strcmp(s,".") == 0) {
876 else if (s[0] == '.') {
877 /* kill the preceeding '.' and pass on as SDCDB command */
884 cmdSimulator (s, currCtxt);
888 if (strcmp(s,".") ==0) {
894 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
896 /* command string matches */
897 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
898 if (!cmdTab[i].cmdfunc)
901 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
903 /* if full name then give the file name & position */
904 if (fullname && showfull && currCtxt && currCtxt->func) {
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);
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);
920 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
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)
933 //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
938 if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
940 // fprintf(stderr,"getNextCmdLine() returns null\n");
943 //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
947 void setCmdLine( char *cmds )
952 void stopCommandList()
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)
968 const char *p = rl_line_buffer;
974 // start = skip blanks from end
976 while (p[*start] && isspace( p[*start] ))
979 // end = skip non-blanks from start
981 while (p[*end] && !isspace( p[*end] ))
984 if (tok_index == toknum)
990 return 0; // not found
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()
998 int toknum, start, end;
1000 toknum = start = end = 0;
1003 if (!completionHelper_GetTokenNumber(toknum, &start, &end))
1006 if (rl_point <= end)
1013 // exapmle for vallist on entry:
1014 // "copying\0warranty\0";
1015 char *completionCompleteFromStrList(const char *text, int state, char *vallist)
1023 ptr += strlen(ptr)+1;
1028 if ( (len < strlen(ptr)) &&
1029 !strncmp(text, ptr, len) )
1032 ptr += strlen(ptr)+1;
1038 // readline library completion function.
1039 // completes from the list of all sdcdb command.
1040 char *completionCommandsList(const char *text, int state)
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;
1050 while (p && isspace(*p))
1052 if (p-rl_line_buffer == rl_point)
1057 while (p && !isspace(*p))
1059 if (p-rl_line_buffer == rl_point)
1064 if (p-rl_line_buffer == rl_point)
1068 return NULL; // no more completions
1070 i = 0; // ok, gonna complete. initialize static variable.
1074 for (; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1076 int len = strlen(text);
1077 if (len <= strlen(cmdTab[i].cmd))
1079 if (strncmp(text,cmdTab[i].cmd,len) == 0)
1080 return strdup(cmdTab[i].cmd);
1084 return NULL; // no more completions
1087 // readline library completion function.
1088 // completes from the list of symbols.
1089 char *completionSymbolName(const char *text, int state)
1093 if (state == 0) // new completion?
1094 sy = setFirstItem(symbols); // yes
1096 sy = setNextItem(symbols);
1098 for (; sy != NULL; )
1100 int len = strlen(text);
1101 if (len <= strlen(sy->name))
1103 if (strncmp(text,sy->name,len) == 0)
1104 return strdup(sy->name);
1107 sy = setNextItem(symbols);
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)
1120 if (state == 0) // new completion?
1121 f = setFirstItem(functions); // yes
1123 f = setNextItem(functions);
1127 int text_len = strlen(text);
1131 if (text_len <= strlen(f->sym->name) &&
1132 !strncmp(text,f->sym->name,text_len))
1133 return strdup(f->sym->name);
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);
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))
1150 f = setNextItem(functions);
1155 // readline library completion function.
1156 // completes from the list known modules.
1157 char *completionModuleName(const char *text, int state)
1161 if (state == 0) // new completion?
1162 m = setFirstItem(modules); // yes
1164 m = setNextItem(modules);
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);
1173 if ( (len <= strlen(m->asm_name)) &&
1174 (strncmp(text,m->asm_name,len) == 0) )
1175 return strdup(m->asm_name);
1177 m = setNextItem(modules);
1182 // readline completion function for "file" command
1183 char *completionCmdFile(const char *text, int state)
1187 if (completionHelper_GetCurrTokenNumber() != 1)
1191 // we use filename_completion_function() from the readline library.
1192 return rl_filename_completion_function(text, state);
1195 // readline completion function for "source" command
1196 char *completionCmdSource(const char *text, int state)
1198 return completionCmdFile(text, state);
1201 // readline completion function for "info" command
1202 char *completionCmdInfo(const char *text, int state)
1208 if (completionHelper_GetCurrTokenNumber() != 1)
1212 return completionCompleteFromStrList(text, state,
1213 "break\0stack\0frame\0registers\0all-registers\0"
1214 "line\0source\0functions\0symbols\0variables\0");
1217 // readline completion function for "show" command
1218 char *completionCmdShow(const char *text, int state)
1224 if (completionHelper_GetCurrTokenNumber() != 1)
1227 return completionCompleteFromStrList(text, state, "copying\0warranty\0");
1230 // readline completion function for "la" command
1231 char *completionCmdListSymbols(const char *text, int state)
1237 if (completionHelper_GetCurrTokenNumber() != 1)
1240 return completionCompleteFromStrList(text, state, "v1\0v2\0");
1243 char *completionCmdPrintType(const char *text, int state)
1247 if (completionHelper_GetCurrTokenNumber() != 1)
1250 return completionSymbolName(text, state);
1253 char *completionCmdPrint(const char *text, int state)
1257 int i = completionHelper_GetCurrTokenNumber();
1258 if (i != 1 && i != 2)
1261 return completionSymbolName(text, state);
1264 char *completionCmdDelUserBp(const char *text, int state)
1271 if (completionHelper_GetCurrTokenNumber() != 1)
1277 bp = hTabFirstItem(bptable,&k);
1280 bp = hTabNextItem(bptable,&k);
1282 for ( ; bp ; bp = hTabNextItem(bptable,&k))
1284 if (bp->bpType == USER || bp->bpType == TMPUSER)
1287 sprintf(buff, "%d", bp->bpnum);
1288 return strdup(buff);
1295 // readline completion function for "undisplay" command
1296 char *completionCmdUnDisplay(const char *text, int state)
1298 static dsymbol *dsym;
1302 if (completionHelper_GetCurrTokenNumber() != 1)
1304 dsym = setFirstItem(dispsymbols);
1310 sprintf(buff, "%d", dsym->dnum);
1311 dsym = setNextItem(dispsymbols);
1312 return strdup(buff);
1317 char *completionCmdSetUserBp(const char *text, int state)
1319 static int internal_state; // 0=calling completionFunctionName(text, state, 0)
1320 // 1=calling completionFunctionName(text, 1, 1)
1323 if (completionHelper_GetCurrTokenNumber() != 1)
1328 if (internal_state == 0)
1330 char *p = completionFunctionName(text, state, 0);
1334 return completionFunctionName(text, 0, 1);
1338 return completionFunctionName(text, 1, 1);
1342 char *completionCmdSetOption(const char *text, int state)
1351 currtok = completionHelper_GetCurrTokenNumber();
1353 if (currtok == 2 || currtok == 3)
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))
1361 else if (currtok != 1)
1370 return completionCompleteFromStrList(text, state,
1374 "srcmode\0listsize\0variable\0");
1376 return completionSymbolName(text, state);
1379 return completionCompleteFromStrList(text, state, "=\0");
1383 // our main readline completion function
1384 // calls the other completion functions as needed.
1385 char *completionMain(const char *text, int state)
1387 static rl_compentry_func_t *compl_func;
1388 int i, start, end, len;
1390 if (state == 0) // new completion?
1394 if (completionHelper_GetCurrTokenNumber() == 0)
1395 compl_func = &completionCommandsList;
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);
1402 for (i=0; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1404 if (!strncmp(rl_line_buffer+start,cmdTab[i].cmd,len) &&
1405 cmdTab[i].cmd[len] == '\0')
1407 compl_func = cmdTab[i].completion_func;
1416 return (*compl_func)(text,state);
1418 #endif /* HAVE_READLINE_COMPLETITION */
1420 /*-----------------------------------------------------------------*/
1421 /* commandLoop - the main command loop or loop over command file */
1422 /*-----------------------------------------------------------------*/
1423 static void commandLoop(FILE *cmdfile)
1425 char *line, save_ch, *s;
1428 #ifdef HAVE_LIBREADLINE
1429 FILE *old_rl_instream, *old_rl_outstream;
1430 actualcmdfile = cmdfile;
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.
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;
1443 // set new streams for readline
1444 if ( cmdfile == stdin )
1445 rl_instream = rl_outstream = NULL; // use stdin/stdout pair
1447 rl_instream = rl_outstream = cmdfile;
1451 if ( cmdfile == stdin )
1454 line_read = (char*)readline ("(sim) ");
1456 line_read = (char*)readline ("(sdcdb) ");
1459 line_read = (char*)readline ("");
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);
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)
1482 actualcmdfile = cmdfile;
1486 if ( cmdfile == stdin )
1491 fprintf(stdout,"(sdcdb) ");
1494 //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
1495 // actualcmdfile,cmdfile);
1496 if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
1498 #endif /* HAVE_LIBREADLINE */
1500 if (interpretCmd(cmdbuff))
1503 while ( actualcmds )
1505 strcpy(cmdbuff,actualcmds);
1508 for ( line = cmdbuff; *line ; line = s )
1510 if ( (s=strchr(line ,'\n')))
1517 s += strlen( line );
1520 if (interpretCmd( line ))
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 */
1538 /*-----------------------------------------------------------------*/
1539 /* printVersionInfo - print the version information */
1540 /*-----------------------------------------------------------------*/
1541 static void printVersionInfo()
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");
1552 /*-----------------------------------------------------------------*/
1553 /* parseCmdLine - parse the commandline arguments */
1554 /*-----------------------------------------------------------------*/
1555 static void parseCmdLine (int argc, char **argv)
1558 char *filename = NULL;
1559 int passon_args_flag = 0; /* if true, pass on args to simulator */
1561 Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
1564 for ( i = 1; i < argc ; i++) {
1565 //fprintf(stdout,"%s\n",argv[i]);
1567 if (passon_args_flag) { /* if true, pass on args to simulator */
1568 simArgs[nsimArgs++] = strdup(argv[i]);
1572 /* if this is an option */
1573 if (argv[i][0] == '-') {
1575 /* if directory then mark directory */
1576 if (strncmp(argv[i],"--directory=",12) == 0) {
1578 ssdirl = &argv[i][12];
1580 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
1581 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1587 if (strncmp(argv[i],"-fullname",9) == 0) {
1592 if (strcmp(argv[i],"-cd") == 0) {
1598 if (strncmp(argv[i],"-cd=",4) == 0) {
1604 if (strncmp(argv[i],"-d=",3) == 0) {
1605 sdcdbDebug = strtol(&argv[i][3],0,0);
1609 if (strncmp(argv[i],"-contsim",8) == 0) {
1613 if (strncmp(argv[i],"-q",2) == 0) {
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)
1624 else if (strcmp(model_str,"z80") == 0)
1625 simArgs[0] = "sz80";
1629 /* -z all remaining options are for simulator */
1630 if (strcmp(argv[i],"-z") == 0) {
1631 passon_args_flag = 1;
1635 /* the simulator arguments */
1638 if (strcmp(argv[i],"-t") == 0 ||
1639 strcmp(argv[i],"-cpu") == 0) {
1641 simArgs[nsimArgs++] = "-t";
1642 simArgs[nsimArgs++] = strdup(argv[++i]);
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]);
1655 if ( (strcmp(argv[i],"-S") == 0) ||
1656 (strcmp(argv[i],"-s") == 0)) {
1657 simArgs[nsimArgs++] = strdup(argv[i]);
1658 simArgs[nsimArgs++] = strdup(argv[++i]);
1662 /* network serial port */
1663 if ( (strcmp(argv[i],"-k") == 0)) {
1664 simArgs[nsimArgs++] = strdup(argv[i]);
1665 simArgs[nsimArgs++] = strdup(argv[++i]);
1669 fprintf(stderr,"unknown option %s --- ignored\n",
1673 /* must be file name */
1675 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1680 if (-1 != access(argv[i], 0)) {
1681 /* file exists: strip the cdb or ihx externsion */
1682 char *p = strrchr(argv[i], '.');
1685 (0 == strcmp(p, ".cdb") || 0 == strcmp(p, ".ihx")))
1694 cmdFile(filename,NULL);
1697 /*-----------------------------------------------------------------*/
1698 /* setsignals - catch some signals */
1699 /*-----------------------------------------------------------------*/
1712 /* may be interrupt from user: stop debugger and also simulator */
1719 /* the only child can be the simulator */
1720 static void sigchld(int sig)
1722 /* the only child can be the simulator */
1724 retpid = wait ( &status );
1725 /* if ( retpid == simPid ) */
1733 signal(SIGINT , sigintr );
1734 signal(SIGABRT, bad_signal);
1735 signal(SIGTERM, bad_signal);
1738 signal(SIGHUP , SIG_IGN);
1739 signal(SIGCONT, SIG_IGN);
1740 signal(SIGCHLD, sigchld );
1742 signal(SIGALRM, bad_signal);
1743 //signal(SIGFPE, bad_signal);
1744 //signal(SIGILL, bad_signal);
1745 signal(SIGPIPE, bad_signal);
1746 signal(SIGQUIT, bad_signal);
1747 //signal(SIGSEGV, bad_signal);
1751 /*-----------------------------------------------------------------*/
1753 /*-----------------------------------------------------------------*/
1755 int main ( int argc, char **argv)
1758 printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1760 current_directory = get_current_dir_name();
1761 simArgs[nsimArgs++] = "s51";
1762 simArgs[nsimArgs++] = "-P";
1763 simArgs[nsimArgs++] = "-r 9756";
1764 /* parse command line */
1767 parseCmdLine(argc,argv);