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 -------------------------------------------------------------------------*/
30 #if defined HAVE_LIBREADLINE && HAVE_LIBREADLINE != -1
31 #define HAVE_READLINE_COMPLETITION 1
33 #ifdef HAVE_LIBREADLINE
34 #include <readline/readline.h>
35 #include <readline/history.h>
36 #endif /* HAVE_LIBREADLINE */
42 char *currModName = NULL;
43 cdbrecs *recsRoot = NULL ;
44 set *modules = NULL; /* set of all modules */
45 set *functions = NULL ; /* set of functions */
46 set *symbols = NULL ; /* set of symbols */
47 set *sfrsymbols= NULL ; /* set of symbols of sfr or sbit */
49 structdef **structs = NULL ; /* all structures */
51 linkrec **linkrecs = NULL; /* all linkage editor records */
52 context *currCtxt = NULL;
55 char userinterrupt = 0;
58 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX DIR_SEPARATOR_STRING "small" ;
62 /* fake filename & lineno to make linker */
67 static void commandLoop(FILE *cmdfile);
68 #ifdef HAVE_READLINE_COMPLETITION
69 char *completionCmdSource(const char *text, int state);
70 char *completionCmdFile(const char *text, int state);
71 char *completionCmdInfo(const char *text, int state);
72 char *completionCmdShow(const char *text, int state);
73 char *completionCmdListSymbols(const char *text, int state);
74 char *completionCmdPrintType(const char *text, int state);
75 char *completionCmdPrint(const char *text, int state);
76 char *completionCmdDelUserBp(const char *text, int state);
77 char *completionCmdUnDisplay(const char *text, int state);
78 char *completionCmdSetUserBp(const char *text, int state);
79 char *completionCmdSetOption(const char *text, int state);
81 #define completionCmdSource NULL
82 #define completionCmdFile NULL
83 #define completionCmdInfo NULL
84 #define completionCmdShow NULL
85 #define completionCmdListSymbols NULL
86 #define completionCmdPrintType NULL
87 #define completionCmdPrint NULL
88 #define completionCmdDelUserBp NULL
89 #define completionCmdUnDisplay NULL
90 #define completionCmdSetUserBp NULL
91 #define completionCmdSetOption NULL
92 #endif /* HAVE_READLINE_COMPLETITION */
97 char *cmd ; /* command the user will enter */
98 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
99 #ifdef HAVE_READLINE_COMPLETITION
100 rl_compentry_func_t *completion_func;
103 #endif /* HAVE_READLINE_COMPLETITION */
104 char *htxt ; /* short help text */
107 /* NOTE:- the search is done from the top, so "break" should
108 precede the synonym "b" */
110 { "break" , cmdSetUserBp , completionCmdSetUserBp,
111 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
113 { "tbreak" , cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/,
114 "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
116 { "b" , cmdSetUserBp , completionCmdSetUserBp , NULL,},
118 { "jump" , cmdJump , NULL,
119 "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *<address>]\n",
121 { "clear" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/,
122 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
124 { "cl" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/ , NULL,},
126 { "continue" , cmdContinue , NULL,
127 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
129 { "condition" , cmdCondition , completionCmdDelUserBp/*same as "delete"*/,
130 "condition brkpoint_number expr\t\tSet condition for breakpoint.\n"
132 { "ignore" , cmdIgnore , completionCmdDelUserBp/*same as "delete"*/,
133 "ignore brkpoint_number count\t\tSet ignore count for breakpoint.\n"
135 { "commands" , cmdCommands , completionCmdDelUserBp/*same as "delete"*/,
136 "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n"
138 { "c" , cmdContinue , NULL , NULL,},
140 { "disassemble",cmdDisasmF , NULL, "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" },
141 { "delete" , cmdDelUserBp , completionCmdDelUserBp,
142 "{d}elete n\t\t clears break point number n\n"
144 { "display" , cmdDisplay , completionCmdPrint/*same as "print"*/,
145 "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
147 { "undisplay" , cmdUnDisplay , completionCmdUnDisplay,
148 "undisplay [<variable>]\t dont display this variable or all\n"
150 { "down" , cmdDown , NULL,
151 "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n"
153 { "up" , cmdUp , NULL,
154 "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n"
156 { "d" , cmdDelUserBp , completionCmdDelUserBp, NULL },
158 { "info" , cmdInfo , completionCmdInfo,
159 "info <break stack frame registers all-registers line source functions symbols variables>\n"
160 "\t list all break points, call-stack, frame or register information\n"
163 { "listasm" , cmdListAsm , NULL,
164 "listasm {la}\t\t list assembler code for the current C line\n"
166 { "la" , cmdListAsm , NULL, NULL },
167 { "ls" , cmdListSymbols , completionCmdListSymbols, "ls,lf,lm\t\t list symbols,functions,modules\n" },
168 { "lf" , cmdListFunctions, completionCmdListSymbols, NULL },
169 { "lm" , cmdListModules , completionCmdListSymbols, NULL },
170 { "list" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/,
171 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
173 { "l" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/, NULL },
174 { "show" , cmdShow , completionCmdShow,
176 " <copying warranty>\t copying & distribution terms, warranty\n"
178 { "set" , cmdSetOption , completionCmdSetOption, "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
179 { "stepi" , cmdStepi , NULL,
180 "stepi\t\t\tStep one instruction exactly.\n"
182 { "step" , cmdStep , NULL,
183 "{s}tep\t\t\tStep program until it reaches a different source line.\n"
185 { "source" , cmdSource , completionCmdSource,
186 "source <FILE>\t\t\tRead commands from a file named FILE.\n"
188 { "s" , cmdStep , NULL, NULL },
189 { "nexti" , cmdNexti , NULL,
190 "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
192 { "next" , cmdNext , NULL,
193 "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
195 { "n" , cmdNext , NULL, NULL },
196 { "run" , cmdRun , NULL,
197 "{r}un\t\t\tStart debugged program. \n"
199 { "r" , cmdRun , NULL, NULL },
200 { "ptype" , cmdPrintType , completionCmdPrintType,
201 "{pt}ype <variable>\tprint type information of a variable\n"
203 { "pt" , cmdPrintType , NULL, NULL },
204 { "print" , cmdPrint , completionCmdPrintType,
205 "{p}rint <variable>\t print value of given variable\n"
207 { "output" , cmdOutput , completionCmdPrint/*same as "print"*/,
208 "output <variable>\t print value of given variable without $ and newline \n"
210 { "p" , cmdPrint , completionCmdPrintType, NULL },
211 { "file" , cmdFile , completionCmdFile,
212 "file <filename>\t\t load symbolic information from <filename>\n"
214 { "frame" , cmdFrame , NULL,
215 "{fr}ame\t\t print information about the current Stack\n"
217 { "finish" , cmdFinish , NULL,
218 "{fi}nish\t\t execute till return of current function\n"
220 { "fi" , cmdFinish , NULL, NULL },
221 { "where" , cmdWhere , NULL, "where\t\t print stack\n" },
222 { "fr" , cmdFrame , NULL, NULL },
223 { "f" , cmdFrame , NULL, NULL },
224 { "x /i" , cmdDisasm1 , NULL, "x\t\t disassemble one asm command\n" },
225 { "!" , cmdSimulator , NULL,
226 "!<simulator command>\t send a command directly to the simulator\n"
228 { "." , cmdSimulator , NULL,
229 ".{cmd}\t switch from simulator or debugger command mode\n"
231 { "help" , cmdHelp , NULL,
232 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
234 { "?" , cmdHelp , NULL, NULL },
235 { "h" , cmdHelp , NULL, NULL },
237 { "quit" , cmdQuit , NULL,
238 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
240 { "q" , cmdQuit , NULL, NULL }
243 /*-----------------------------------------------------------------*/
244 /* trimming functions */
245 /*-----------------------------------------------------------------*/
246 char *trim_left(char *s)
254 char *trim_right(char *s)
256 char *p = &s[strlen(s) - 1];
258 while (p >= s && isspace(*p))
267 return trim_right(trim_left(s));
270 /*-----------------------------------------------------------------*/
271 /* gc_strdup - make a string duplicate garbage collector aware */
272 /*-----------------------------------------------------------------*/
273 char *gc_strdup(const char *s)
276 ret = Safe_malloc(strlen(s)+1);
281 /*-----------------------------------------------------------------*/
282 /* alloccpy - allocate copy and return a new string */
283 /*-----------------------------------------------------------------*/
284 char *alloccpy ( char *s, int size)
291 d = Safe_malloc(size+1);
298 /*-----------------------------------------------------------------*/
299 /* resize - resizes array of type with new size */
300 /*-----------------------------------------------------------------*/
301 void **resize (void **array, int newSize)
306 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
308 vptr = calloc(1, sizeof(void **));
311 fprintf(stderr,"sdcdb: out of memory \n");
319 /*-----------------------------------------------------------------*/
320 /* readCdb - reads the cdb files & puts the records into cdbLine */
322 /*-----------------------------------------------------------------*/
323 static int readCdb (FILE *file)
329 if (!(bp = fgets(buffer,sizeof(buffer),file)))
332 currl = Safe_calloc(1,sizeof(cdbrecs));
337 /* make sure this is a cdb record */
338 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
339 /* depending on the record type */
344 currl->type = SYM_REC;
347 currl->type = STRUCT_REC;
350 currl->type = LNK_REC;
353 currl->type = FUNC_REC;
356 currl->type = MOD_REC ;
360 currl->line = Safe_malloc(strlen(bp));
361 strncpy(currl->line,bp,strlen(bp)-1);
362 currl->line[strlen(bp)-1] = '\0';
365 if (!(bp = fgets(buffer,sizeof(buffer),file)))
371 currl->next = Safe_calloc(1,sizeof(cdbrecs));
375 return (recsRoot->line ? 1 : 0);
378 /*-----------------------------------------------------------------*/
379 /* searchDirsFname - search directory list & return the filename */
380 /*-----------------------------------------------------------------*/
381 char *searchDirsFname (char *fname)
387 /* first try the current directory */
388 if ((rfile = fopen(fname,"r"))) {
390 return strdup(fname) ;
394 return strdup(fname);
396 /* make a copy of the source directories */
397 dirs = sdirs = strdup(ssdirl);
399 /* assume that the separator is ':'
400 and try for each directory in the search list */
401 dirs = strtok(dirs,":");
403 if (dirs[strlen(dirs)] == '/')
404 sprintf(buffer,"%s%s",dirs,fname);
406 sprintf(buffer,"%s/%s",dirs,fname);
407 if ((rfile = fopen(buffer,"r")))
409 dirs = strtok(NULL,":");
415 return strdup(buffer);
417 return strdup(fname);
420 /*-----------------------------------------------------------------*/
421 /* searchDirsFopen - go thru list of directories for filename given*/
422 /*-----------------------------------------------------------------*/
423 FILE *searchDirsFopen(char *fname)
429 /* first try the current directory */
430 if ((rfile = fopen(fname,"r")))
435 /* make a copy of the source directories */
436 dirs = sdirs = strdup(ssdirl);
438 /* assume that the separator is ':'
439 and try for each directory in the search list */
440 dirs = strtok(dirs,":");
442 sprintf(buffer,"%s/%s",dirs,fname);
443 if ((rfile = fopen(buffer,"r")))
445 dirs = strtok(NULL,":");
453 /*-----------------------------------------------------------------*/
454 /* loadFile - loads a file into module buffer */
455 /*-----------------------------------------------------------------*/
456 srcLine **loadFile (char *name, int *nlines)
461 srcLine **slines = NULL;
464 if (!(mfile = searchDirsFopen(name))) {
465 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
469 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
472 slines = (srcLine **)resize((void **)slines,*nlines);
474 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
475 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
476 slines[(*nlines)-1]->addr= INT_MAX;
484 /*-----------------------------------------------------------------*/
485 /* loadModules - reads the source files into module structure */
486 /*-----------------------------------------------------------------*/
487 static void loadModules (void)
493 /* go thru the records & find out the module
494 records & load the modules specified */
495 for ( loop = recsRoot ; loop ; loop = loop->next ) {
497 switch (loop->type) {
498 /* for module records do */
500 currMod = parseModule(loop->line, TRUE);
501 currModName = currMod->name ;
503 currMod->cfullname = searchDirsFname(currMod->c_name);
505 /* load it into buffer */
506 currMod->cLines = loadFile (currMod->c_name,
509 /* do the same for the assembler file */
510 currMod->afullname = searchDirsFname(currMod->asm_name);
511 currMod->asmLines=loadFile (currMod->asm_name,
512 &currMod->nasmLines);
515 /* if this is a function record */
517 parseFunc(loop->line);
520 /* if this is a structure record */
522 parseStruct(loop->line);
525 /* if symbol then parse the symbol */
527 parseSymbol(loop->line,&rs,2);
531 parseLnkRec(loop->line);
537 /*-----------------------------------------------------------------*/
538 /* generate extra sets of sfr and sbit symbols */
539 /*-----------------------------------------------------------------*/
540 static void specialFunctionRegs (void)
543 for (sym = setFirstItem(symbols);
545 sym = setNextItem(symbols))
547 if ( sym->addrspace == 'I' ||
548 sym->addrspace == 'J')
550 addSet(&sfrsymbols,sym);
554 /*-----------------------------------------------------------------*/
555 /* functionPoints - determine the execution points within a func */
556 /*-----------------------------------------------------------------*/
557 static void functionPoints (void)
563 // add _main dummy for runtime env
564 if ((func = needExtraMainFunction()))
568 /* alloc new _main function */
569 func1 = Safe_calloc(1,sizeof(function));
571 func1->sym = Safe_calloc(1,sizeof(symbol));
572 *func1->sym = *func->sym;
573 func1->sym->name = alloccpy("_main",5);
574 func1->sym->rname = alloccpy("G$_main$0$",10);
575 /* TODO must be set by symbol information */
576 func1->sym->addr = 0;
577 func1->sym->eaddr = 0x2f;
578 addSet(&functions,func1);
581 /* for all functions do */
582 for ( func = setFirstItem(functions); func;
583 func = setNextItem(functions)) {
589 Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
594 if (!func->sym->addr && !func->sym->eaddr)
597 /* for all source lines in the module find
598 the ones with address >= start and <= end
599 and put them in the point */
601 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
604 func->entryline= INT_MAX-2;
606 func->aentryline = INT_MAX-2 ;
609 /* do it for the C Lines first */
610 for ( j = 0 ; j < mod->ncLines ; j++ ) {
611 if (mod->cLines[j]->addr < INT_MAX &&
612 mod->cLines[j]->addr >= sym->addr &&
613 mod->cLines[j]->addr <= sym->eaddr ) {
616 /* add it to the execution point */
617 if (func->entryline > j)
620 if (func->exitline < j)
623 ep = Safe_calloc(1,sizeof(exePoint));
624 ep->addr = mod->cLines[j]->addr ;
626 ep->block= mod->cLines[j]->block;
627 ep->level= mod->cLines[j]->level;
628 addSet(&func->cfpoints,ep);
631 /* check double line execution points of module */
632 for (ep = setFirstItem(mod->cfpoints); ep;
633 ep = setNextItem(mod->cfpoints))
635 if (ep->addr >= sym->addr &&
636 ep->addr <= sym->eaddr )
638 addSet(&func->cfpoints,ep);
641 /* do the same for asm execution points */
642 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
643 if (mod->asmLines[j]->addr < INT_MAX &&
644 mod->asmLines[j]->addr >= sym->addr &&
645 mod->asmLines[j]->addr <= sym->eaddr ) {
648 /* add it to the execution point */
649 if (func->aentryline > j)
650 func->aentryline = j;
652 if (func->aexitline < j)
655 /* add it to the execution point */
656 ep = Safe_calloc(1,sizeof(exePoint));
657 ep->addr = mod->asmLines[j]->addr ;
659 addSet(&func->afpoints,ep);
662 if ( func->entryline == INT_MAX-2 )
664 if ( func->aentryline == INT_MAX-2 )
665 func->aentryline = 0;
668 if (!( D_sdcdb & sdcdbDebug))
671 Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
676 for (ep = setFirstItem(func->cfpoints); ep;
677 ep = setNextItem(func->cfpoints))
678 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
679 ep->addr,ep->line+1,mod->cLines[ep->line]->src));
681 Dprintf(D_sdcdb, ("sdcdb: and the following ASM exePoints\n"));
682 for (ep = setFirstItem(func->afpoints); ep;
683 ep = setNextItem(func->afpoints))
684 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
685 ep->addr,ep->line+1,mod->asmLines[ep->line]->src));
692 /*-----------------------------------------------------------------*/
693 /* setEntryExitBP - set the entry & exit Break Points for functions*/
694 /*-----------------------------------------------------------------*/
695 DEFSETFUNC(setEntryExitBP)
697 function *func = item;
699 if (func->sym && func->sym->addr && func->sym->eaddr) {
701 /* set the entry break point */
702 setBreakPoint (func->sym->addr , CODE , FENTRY ,
703 fentryCB ,func->mod->c_name , func->entryline);
705 /* set the exit break point */
706 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
707 fexitCB ,func->mod->c_name , func->exitline );
713 /*-----------------------------------------------------------------*/
714 /* cmdFile - load file into the debugger */
715 /*-----------------------------------------------------------------*/
716 int cmdFile (char *s,context *cctxt)
725 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
729 sprintf(buffer,"%s.cdb",s);
730 /* try creating the cdbfile */
731 if (!(cdbFile = searchDirsFopen(buffer))) {
732 fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
736 /* allocate for context */
737 currCtxt = Safe_calloc(1,sizeof(context));
740 /* readin the debug information */
741 if (!readCdb (cdbFile)) {
742 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
747 /* parse and load the modules required */
750 /* determine the execution points for this
754 /* extract known special function registers */
755 specialFunctionRegs();
757 /* start the simulator & setup connection to it */
759 if (INVALID_SOCKET == sock)
763 openSimulator((char **)simArgs,nsimArgs);
764 fprintf(stdout,"%s",simResponse());
765 /* now send the filename to be loaded to the simulator */
766 sprintf(buffer,"%s.ihx",s);
767 bp=searchDirsFname(buffer);
771 /*set the break points
772 required by the debugger . i.e. the function entry
773 and function exit break points */
774 applyToSet(functions,setEntryExitBP);
780 /*-----------------------------------------------------------------*/
781 /* cmdSource - read commands from file */
782 /*-----------------------------------------------------------------*/
783 int cmdSource (char *s, context *cctxt)
789 if (!( cmdfile = searchDirsFopen(s)))
791 fprintf(stderr,"commandfile '%s' not found\n",s);
794 commandLoop( cmdfile );
799 /*-----------------------------------------------------------------*/
800 /* cmdHelp - help command */
801 /*-----------------------------------------------------------------*/
802 int cmdHelp (char *s, context *cctxt)
811 endline = ((*s - '0') * 20) + 20;
813 startline = endline - 20;
817 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
819 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
821 s = strrchr(cmdTab[i].htxt,'\t');
826 fprintf(stdout,"%s",s);
833 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
835 /* command string matches */
837 if ((cmdTab[i].htxt) && (i >= startline))
838 fprintf(stdout,"%s",cmdTab[i].htxt);
846 #define MAX_CMD_LEN 512
847 static char cmdbuff[MAX_CMD_LEN];
848 static int sim_cmd_mode = 0;
850 /*-----------------------------------------------------------------
851 interpretCmd - interpret and do the command. Return 0 to continue,
852 return 1 to exit program.
853 |-----------------------------------------------------------------*/
854 int interpretCmd (char *s)
856 static char *pcmd = NULL;
860 /* if nothing & previous command exists then
861 execute the previous command again */
862 if (*s == '\n' && pcmd)
865 /* if previous command exists & is different
866 from the current command then copy it */
868 if (strcmp(pcmd,s)) {
875 /* trim trailing blanks */
879 if (strcmp(s,".") == 0) {
883 else if (s[0] == '.') {
884 /* kill the preceeding '.' and pass on as SDCDB command */
891 cmdSimulator (s, currCtxt);
895 if (strcmp(s,".") ==0) {
901 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
903 /* command string matches */
904 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
905 if (!cmdTab[i].cmdfunc)
908 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
910 /* if full name then give the file name & position */
911 if (fullname && showfull && currCtxt && currCtxt->func) {
913 if (srcMode == SRC_CMODE)
914 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
915 currCtxt->func->mod->cfullname,
916 currCtxt->cline+1,currCtxt->addr);
918 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
919 currCtxt->func->mod->afullname,
920 currCtxt->asmline,currCtxt->addr);
921 displayAll(currCtxt);
927 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
932 static FILE *actualcmdfile=NULL ;
933 static char *actualcmds=NULL;
934 static int stopcmdlist;
935 /*-----------------------------------------------------------------*/
936 /* getNextCmdLine get additional lines used by special commands */
937 /*-----------------------------------------------------------------*/
938 char *getNextCmdLine(void)
940 //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
945 if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
947 // fprintf(stderr,"getNextCmdLine() returns null\n");
950 //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
954 void setCmdLine( char *cmds )
959 void stopCommandList()
964 #ifdef HAVE_READLINE_COMPLETITION
965 // helper function for doing readline completion.
966 // input: toknum=index of token to find (0=first token)
967 // output: *start=first character index of the token,
968 // or the index of '\0'
969 // *end=first blank character right after the token,
970 // or the index of '\0'
971 // return value: 0=token not found, 1=token found
972 int completionHelper_GetTokenNumber(int toknum, int *start, int *end)
975 const char *p = rl_line_buffer;
981 // start = skip blanks from end
983 while (p[*start] && isspace( p[*start] ))
986 // end = skip non-blanks from start
988 while (p[*end] && !isspace( p[*end] ))
991 if (tok_index == toknum)
997 return 0; // not found
1000 // helper function for doing readline completion.
1001 // returns the token number that we were asked to complete.
1002 // 0=first token (command name), 1=second token...
1003 int completionHelper_GetCurrTokenNumber()
1005 int toknum, start, end;
1007 toknum = start = end = 0;
1010 if (!completionHelper_GetTokenNumber(toknum, &start, &end))
1013 if (rl_point <= end)
1020 // exapmle for vallist on entry:
1021 // "copying\0warranty\0";
1022 char *completionCompleteFromStrList(const char *text, int state, char *vallist)
1030 ptr += strlen(ptr)+1;
1035 if ( (len < strlen(ptr)) &&
1036 !strncmp(text, ptr, len) )
1039 ptr += strlen(ptr)+1;
1045 // readline library completion function.
1046 // completes from the list of all sdcdb command.
1047 char *completionCommandsList(const char *text, int state)
1051 if (state == 0) // new completion?
1052 { // yes, only complete if this is the first token on the line.
1053 int ok = 0; // try to complete this request?
1054 char *p = rl_line_buffer;
1057 while (p && isspace(*p))
1059 if (p-rl_line_buffer == rl_point)
1064 while (p && !isspace(*p))
1066 if (p-rl_line_buffer == rl_point)
1071 if (p-rl_line_buffer == rl_point)
1075 return NULL; // no more completions
1077 i = 0; // ok, gonna complete. initialize static variable.
1081 for (; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1083 int len = strlen(text);
1084 if (len <= strlen(cmdTab[i].cmd))
1086 if (strncmp(text,cmdTab[i].cmd,len) == 0)
1087 return strdup(cmdTab[i].cmd);
1091 return NULL; // no more completions
1094 // readline library completion function.
1095 // completes from the list of symbols.
1096 char *completionSymbolName(const char *text, int state)
1100 if (state == 0) // new completion?
1101 sy = setFirstItem(symbols); // yes
1103 sy = setNextItem(symbols);
1105 for (; sy != NULL; )
1107 int len = strlen(text);
1108 if (len <= strlen(sy->name))
1110 if (strncmp(text,sy->name,len) == 0)
1111 return strdup(sy->name);
1114 sy = setNextItem(symbols);
1119 // readline library completion function.
1120 // completes from the list known functions.
1121 // module_flag - if false, ignore function module name
1122 // if true, compare against module_name:fnction_name
1123 char *completionFunctionName(const char *text, int state, int module_flag)
1127 if (state == 0) // new completion?
1128 f = setFirstItem(functions); // yes
1130 f = setNextItem(functions);
1134 int text_len = strlen(text);
1138 if (text_len <= strlen(f->sym->name) &&
1139 !strncmp(text,f->sym->name,text_len))
1140 return strdup(f->sym->name);
1144 int modname_len = strlen(f->mod->c_name);
1145 int funcname_len = strlen(f->sym->name);
1146 char *functext = malloc(modname_len+funcname_len+2);
1148 strcpy(functext,f->mod->c_name);
1149 strcat(functext,":");
1150 strcat(functext,f->sym->name);
1151 if (text_len <= strlen(functext) &&
1152 !strncmp(text,functext,text_len))
1157 f = setNextItem(functions);
1162 // readline library completion function.
1163 // completes from the list known modules.
1164 char *completionModuleName(const char *text, int state)
1168 if (state == 0) // new completion?
1169 m = setFirstItem(modules); // yes
1171 m = setNextItem(modules);
1175 int len = strlen(text);
1176 if ( (len <= strlen(m->c_name)) &&
1177 !strncmp(text,m->c_name,len) )
1178 return strdup(m->c_name);
1180 if ( (len <= strlen(m->asm_name)) &&
1181 (strncmp(text,m->asm_name,len) == 0) )
1182 return strdup(m->asm_name);
1184 m = setNextItem(modules);
1189 // readline completion function for "file" command
1190 char *completionCmdFile(const char *text, int state)
1194 if (completionHelper_GetCurrTokenNumber() != 1)
1198 // we use filename_completion_function() from the readline library.
1199 return rl_filename_completion_function(text, state);
1202 // readline completion function for "source" command
1203 char *completionCmdSource(const char *text, int state)
1205 return completionCmdFile(text, state);
1208 // readline completion function for "info" command
1209 char *completionCmdInfo(const char *text, int state)
1215 if (completionHelper_GetCurrTokenNumber() != 1)
1219 return completionCompleteFromStrList(text, state,
1220 "break\0stack\0frame\0registers\0all-registers\0"
1221 "line\0source\0functions\0symbols\0variables\0");
1224 // readline completion function for "show" command
1225 char *completionCmdShow(const char *text, int state)
1231 if (completionHelper_GetCurrTokenNumber() != 1)
1234 return completionCompleteFromStrList(text, state, "copying\0warranty\0");
1237 // readline completion function for "la" command
1238 char *completionCmdListSymbols(const char *text, int state)
1244 if (completionHelper_GetCurrTokenNumber() != 1)
1247 return completionCompleteFromStrList(text, state, "v1\0v2\0");
1250 char *completionCmdPrintType(const char *text, int state)
1254 if (completionHelper_GetCurrTokenNumber() != 1)
1257 return completionSymbolName(text, state);
1260 char *completionCmdPrint(const char *text, int state)
1264 int i = completionHelper_GetCurrTokenNumber();
1265 if (i != 1 && i != 2)
1268 return completionSymbolName(text, state);
1271 char *completionCmdDelUserBp(const char *text, int state)
1278 if (completionHelper_GetCurrTokenNumber() != 1)
1284 bp = hTabFirstItem(bptable,&k);
1287 bp = hTabNextItem(bptable,&k);
1289 for ( ; bp ; bp = hTabNextItem(bptable,&k))
1291 if (bp->bpType == USER || bp->bpType == TMPUSER)
1294 sprintf(buff, "%d", bp->bpnum);
1295 return strdup(buff);
1302 // readline completion function for "undisplay" command
1303 char *completionCmdUnDisplay(const char *text, int state)
1305 static dsymbol *dsym;
1309 if (completionHelper_GetCurrTokenNumber() != 1)
1311 dsym = setFirstItem(dispsymbols);
1317 sprintf(buff, "%d", dsym->dnum);
1318 dsym = setNextItem(dispsymbols);
1319 return strdup(buff);
1324 char *completionCmdSetUserBp(const char *text, int state)
1326 static int internal_state; // 0=calling completionFunctionName(text, state, 0)
1327 // 1=calling completionFunctionName(text, 1, 1)
1330 if (completionHelper_GetCurrTokenNumber() != 1)
1335 if (internal_state == 0)
1337 char *p = completionFunctionName(text, state, 0);
1341 return completionFunctionName(text, 0, 1);
1345 return completionFunctionName(text, 1, 1);
1349 char *completionCmdSetOption(const char *text, int state)
1358 currtok = completionHelper_GetCurrTokenNumber();
1360 if (currtok == 2 || currtok == 3)
1362 // make sure token 1 == "variable"
1363 completionHelper_GetTokenNumber(1, &start, &end);
1364 if (end - start != 8 ||
1365 strncmp(rl_line_buffer+start,"variable",8))
1368 else if (currtok != 1)
1377 return completionCompleteFromStrList(text, state,
1381 "srcmode\0listsize\0variable\0");
1383 return completionSymbolName(text, state);
1386 return completionCompleteFromStrList(text, state, "=\0");
1390 // our main readline completion function
1391 // calls the other completion functions as needed.
1392 char *completionMain(const char *text, int state)
1394 static rl_compentry_func_t *compl_func;
1395 int i, start, end, len;
1397 if (state == 0) // new completion?
1401 if (completionHelper_GetCurrTokenNumber() == 0)
1402 compl_func = &completionCommandsList;
1404 { // not completing first token, find the right completion
1405 // function according to the first token the user typed.
1406 completionHelper_GetTokenNumber(0, &start, &end);
1409 for (i=0; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1411 if (!strncmp(rl_line_buffer+start,cmdTab[i].cmd,len) &&
1412 cmdTab[i].cmd[len] == '\0')
1414 compl_func = cmdTab[i].completion_func;
1423 return (*compl_func)(text,state);
1425 #endif /* HAVE_READLINE_COMPLETITION */
1427 /*-----------------------------------------------------------------*/
1428 /* commandLoop - the main command loop or loop over command file */
1429 /*-----------------------------------------------------------------*/
1430 static void commandLoop(FILE *cmdfile)
1432 char *line, save_ch, *s;
1435 #ifdef HAVE_LIBREADLINE
1436 FILE *old_rl_instream, *old_rl_outstream;
1437 actualcmdfile = cmdfile;
1439 #ifdef HAVE_READLINE_COMPLETITION
1440 rl_completion_entry_function = completionMain;
1441 #endif /* HAVE_READLINE_COMPLETITION */
1442 rl_readline_name = "sdcdb"; // Allow conditional parsing of the ~/.inputrc file.
1444 // save readline's input/output streams
1445 // this is done to support nested calls to commandLoop()
1446 // i wonder if it works...
1447 old_rl_instream = rl_instream;
1448 old_rl_outstream = rl_outstream;
1450 // set new streams for readline
1451 if ( cmdfile == stdin )
1452 rl_instream = rl_outstream = NULL; // use stdin/stdout pair
1454 rl_instream = rl_outstream = cmdfile;
1458 if ( cmdfile == stdin )
1461 line_read = (char*)readline ("(sim) ");
1463 line_read = (char*)readline ("(sdcdb) ");
1466 line_read = (char*)readline ("");
1470 /* If the line has any text in it,
1471 save it on the history. */
1472 if (line_read && *line_read)
1473 add_history (line_read);
1475 // FIX: readline returns malloced string.
1476 // should check the source to verify it can be used
1477 // directly. for now - just copy it to cmdbuff.
1478 strcpy(cmdbuff,line_read);
1479 #if defined(_WIN32) || defined(HAVE_RL_FREE)
1489 actualcmdfile = cmdfile;
1493 if ( cmdfile == stdin )
1498 fprintf(stdout,"(sdcdb) ");
1501 //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
1502 // actualcmdfile,cmdfile);
1503 if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
1505 #endif /* HAVE_LIBREADLINE */
1507 if (interpretCmd(cmdbuff))
1510 while ( actualcmds )
1512 strcpy(cmdbuff,actualcmds);
1515 for ( line = cmdbuff; *line ; line = s )
1517 if ( (s=strchr(line ,'\n')))
1524 s += strlen( line );
1527 if (interpretCmd( line ))
1538 #ifdef HAVE_LIBREADLINE
1539 // restore readline's input/output streams
1540 rl_instream = old_rl_instream;
1541 rl_outstream = old_rl_outstream;
1542 #endif /* HAVE_LIBREADLINE */
1545 /*-----------------------------------------------------------------*/
1546 /* printVersionInfo - print the version information */
1547 /*-----------------------------------------------------------------*/
1548 static void printVersionInfo()
1551 "SDCDB is free software and you are welcome to distribute copies of it\n"
1552 "under certain conditions; type \"show copying\" to see the conditions.\n"
1553 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
1554 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
1555 "Type ? for help\n");
1559 /*-----------------------------------------------------------------*/
1560 /* parseCmdLine - parse the commandline arguments */
1561 /*-----------------------------------------------------------------*/
1562 static void parseCmdLine (int argc, char **argv)
1565 char *filename = NULL;
1566 int passon_args_flag = 0; /* if true, pass on args to simulator */
1568 Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
1571 for ( i = 1; i < argc ; i++) {
1572 //fprintf(stdout,"%s\n",argv[i]);
1574 if (passon_args_flag) { /* if true, pass on args to simulator */
1575 simArgs[nsimArgs++] = strdup(argv[i]);
1579 /* if this is an option */
1580 if (argv[i][0] == '-') {
1582 /* if directory then mark directory */
1583 if (strncmp(argv[i],"--directory=",12) == 0) {
1585 ssdirl = &argv[i][12];
1587 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
1588 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1594 if (strncmp(argv[i],"-fullname",9) == 0) {
1599 if (strcmp(argv[i],"-cd") == 0) {
1605 if (strncmp(argv[i],"-cd=",4) == 0) {
1611 if (strncmp(argv[i],"-d=",3) == 0) {
1612 sdcdbDebug = strtol(&argv[i][3],0,0);
1616 if (strncmp(argv[i],"-contsim",8) == 0) {
1620 if (strncmp(argv[i],"-q",2) == 0) {
1625 if (strncmp(argv[i],"-m",2) == 0) {
1626 strncpy(model_str, &argv[i][2], 15);
1627 if (strcmp(model_str,"avr") == 0)
1628 simArgs[0] = "savr";
1629 else if (strcmp(model_str,"xa") == 0)
1631 else if (strcmp(model_str,"z80") == 0)
1632 simArgs[0] = "sz80";
1636 /* -z all remaining options are for simulator */
1637 if (strcmp(argv[i],"-z") == 0) {
1638 passon_args_flag = 1;
1642 /* the simulator arguments */
1645 if (strcmp(argv[i],"-t") == 0 ||
1646 strcmp(argv[i],"-cpu") == 0) {
1648 simArgs[nsimArgs++] = "-t";
1649 simArgs[nsimArgs++] = strdup(argv[++i]);
1653 /* XTAL Frequency */
1654 if (strcmp(argv[i],"-X") == 0 ||
1655 strcmp(argv[i],"-frequency") == 0) {
1656 simArgs[nsimArgs++] = "-X";
1657 simArgs[nsimArgs++] = strdup(argv[++i]);
1662 if ( (strcmp(argv[i],"-S") == 0) ||
1663 (strcmp(argv[i],"-s") == 0)) {
1664 simArgs[nsimArgs++] = strdup(argv[i]);
1665 simArgs[nsimArgs++] = strdup(argv[++i]);
1669 /* network serial port */
1670 if ( (strcmp(argv[i],"-k") == 0)) {
1671 simArgs[nsimArgs++] = strdup(argv[i]);
1672 simArgs[nsimArgs++] = strdup(argv[++i]);
1676 fprintf(stderr,"unknown option %s --- ignored\n",
1680 /* must be file name */
1682 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1687 if (-1 != access(argv[i], 0)) {
1688 /* file exists: strip the cdb or ihx externsion */
1689 char *p = strrchr(argv[i], '.');
1692 (0 == strcmp(p, ".cdb") || 0 == strcmp(p, ".ihx")))
1701 cmdFile(filename,NULL);
1704 /*-----------------------------------------------------------------*/
1705 /* setsignals - catch some signals */
1706 /*-----------------------------------------------------------------*/
1719 /* may be interrupt from user: stop debugger and also simulator */
1726 /* the only child can be the simulator */
1727 static void sigchld(int sig)
1729 /* the only child can be the simulator */
1731 retpid = wait ( &status );
1732 /* if ( retpid == simPid ) */
1740 signal(SIGINT , sigintr );
1741 signal(SIGABRT, bad_signal);
1742 signal(SIGTERM, bad_signal);
1745 signal(SIGHUP , SIG_IGN);
1746 signal(SIGCONT, SIG_IGN);
1747 signal(SIGCHLD, sigchld );
1749 signal(SIGALRM, bad_signal);
1750 //signal(SIGFPE, bad_signal);
1751 //signal(SIGILL, bad_signal);
1752 signal(SIGPIPE, bad_signal);
1753 signal(SIGQUIT, bad_signal);
1754 //signal(SIGSEGV, bad_signal);
1758 /*-----------------------------------------------------------------*/
1760 /*-----------------------------------------------------------------*/
1762 int main ( int argc, char **argv)
1765 printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1767 simArgs[nsimArgs++] = "s51";
1768 simArgs[nsimArgs++] = "-P";
1769 simArgs[nsimArgs++] = "-r 9756";
1770 /* parse command line */
1773 parseCmdLine(argc,argv);