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 #ifdef HAVE_LIBREADLINE
31 #include <readline/readline.h>
32 #include <readline/history.h>
33 #endif /* HAVE_LIBREADLINE */
39 char *currModName = NULL;
40 cdbrecs *recsRoot = NULL ;
41 set *modules = NULL; /* set of all modules */
42 set *functions = NULL ; /* set of functions */
43 set *symbols = NULL ; /* set of symbols */
44 set *sfrsymbols= NULL ; /* set of symbols of sfr or sbit */
46 structdef **structs = NULL ; /* all structures */
48 linkrec **linkrecs = NULL; /* all linkage editor records */
49 context *currCtxt = NULL;
52 char userinterrupt = 0;
55 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ;
59 /* fake filename & lineno to make linker */
64 static void commandLoop(FILE *cmdfile);
65 #ifdef HAVE_LIBREADLINE
66 char *completionCmdSource(const char *text, int state);
67 char *completionCmdFile(const char *text, int state);
68 char *completionCmdInfo(const char *text, int state);
69 char *completionCmdShow(const char *text, int state);
70 char *completionCmdListSymbols(const char *text, int state);
71 char *completionCmdPrintType(const char *text, int state);
72 char *completionCmdPrint(const char *text, int state);
73 char *completionCmdDelUserBp(const char *text, int state);
74 char *completionCmdUnDisplay(const char *text, int state);
75 char *completionCmdSetUserBp(const char *text, int state);
76 char *completionCmdSetOption(const char *text, int state);
78 #define completionCmdSource NULL
79 #define completionCmdFile NULL
80 #define completionCmdInfo NULL
81 #define completionCmdShow NULL
82 #define completionCmdListSymbols NULL
83 #define completionCmdPrintType NULL
84 #define completionCmdPrint NULL
85 #define completionCmdDelUserBp NULL
86 #define completionCmdUnDisplay NULL
87 #define completionCmdSetUserBp NULL
88 #define completionCmdSetOption NULL
89 #endif /* HAVE_LIBREADLINE */
94 char *cmd ; /* command the user will enter */
95 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
96 #ifdef HAVE_LIBREADLINE
97 rl_compentry_func_t *completion_func;
100 #endif /* HAVE_LIBREADLINE */
101 char *htxt ; /* short help text */
104 /* NOTE:- the search is done from the top, so "break" should
105 precede the synonym "b" */
107 { "break" , cmdSetUserBp , completionCmdSetUserBp,
108 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
110 { "tbreak" , cmdSetTmpUserBp , completionCmdSetUserBp/*same as "break"*/,
111 "tbreak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
113 { "b" , cmdSetUserBp , completionCmdSetUserBp , NULL,},
115 { "jump" , cmdJump , NULL,
116 "jump\t\t\tContinue program being debugged at specified line or address\n [LINE | FILE:LINE | *<address>]\n",
118 { "clear" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/,
119 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
121 { "cl" , cmdClrUserBp , completionCmdSetUserBp/*same as "break"*/ , NULL,},
123 { "continue" , cmdContinue , NULL,
124 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
126 { "condition" , cmdCondition , completionCmdDelUserBp/*same as "delete"*/,
127 "condition brkpoint_number expr\t\tSet condition for breakpoint.\n"
129 { "ignore" , cmdIgnore , completionCmdDelUserBp/*same as "delete"*/,
130 "ignore brkpoint_number count\t\tSet ignore count for breakpoint.\n"
132 { "commands" , cmdCommands , completionCmdDelUserBp/*same as "delete"*/,
133 "commands [brkpoint_number]\t\tSetting commands for breakpoint.\n"
135 { "c" , cmdContinue , NULL , NULL,},
137 { "disassemble",cmdDisasmF , NULL, "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" },
138 { "delete" , cmdDelUserBp , completionCmdDelUserBp,
139 "{d}elete n\t\t clears break point number n\n"
141 { "display" , cmdDisplay , completionCmdPrint/*same as "print"*/,
142 "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
144 { "undisplay" , cmdUnDisplay , completionCmdUnDisplay,
145 "undisplay [<variable>]\t dont display this variable or all\n"
147 { "down" , cmdDown , NULL,
148 "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n"
150 { "up" , cmdUp , NULL,
151 "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n"
153 { "d" , cmdDelUserBp , completionCmdDelUserBp, NULL },
155 { "info" , cmdInfo , completionCmdInfo,
156 "info <break stack frame registers all-registers line source functions symbols variables>\n"
157 "\t list all break points, call-stack, frame or register information\n"
160 { "listasm" , cmdListAsm , NULL,
161 "listasm {la}\t\t list assembler code for the current C line\n"
163 { "la" , cmdListAsm , NULL, NULL },
164 { "ls" , cmdListSymbols , completionCmdListSymbols, "ls,lf,lm\t\t list symbols,functions,modules\n" },
165 { "lf" , cmdListFunctions, completionCmdListSymbols, NULL },
166 { "lm" , cmdListModules , completionCmdListSymbols, NULL },
167 { "list" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/,
168 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
170 { "l" , cmdListSrc , completionCmdSetUserBp/*same as "break"*/, NULL },
171 { "show" , cmdShow , completionCmdShow,
173 " <copying warranty>\t copying & distribution terms, warranty\n"
175 { "set" , cmdSetOption , completionCmdSetOption, "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
176 { "stepi" , cmdStepi , NULL,
177 "stepi\t\t\tStep one instruction exactly.\n"
179 { "step" , cmdStep , NULL,
180 "{s}tep\t\t\tStep program until it reaches a different source line.\n"
182 { "source" , cmdSource , completionCmdSource,
183 "source <FILE>\t\t\tRead commands from a file named FILE.\n"
185 { "s" , cmdStep , NULL, NULL },
186 { "nexti" , cmdNexti , NULL,
187 "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
189 { "next" , cmdNext , NULL,
190 "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
192 { "n" , cmdNext , NULL, NULL },
193 { "run" , cmdRun , NULL,
194 "{r}un\t\t\tStart debugged program. \n"
196 { "r" , cmdRun , NULL, NULL },
197 { "ptype" , cmdPrintType , completionCmdPrintType,
198 "{pt}ype <variable>\tprint type information of a variable\n"
200 { "pt" , cmdPrintType , NULL, NULL },
201 { "print" , cmdPrint , completionCmdPrintType,
202 "{p}rint <variable>\t print value of given variable\n"
204 { "output" , cmdOutput , completionCmdPrint/*same as "print"*/,
205 "output <variable>\t print value of given variable without $ and newline \n"
207 { "p" , cmdPrint , completionCmdPrintType, NULL },
208 { "file" , cmdFile , completionCmdFile,
209 "file <filename>\t\t load symbolic information from <filename>\n"
211 { "frame" , cmdFrame , NULL,
212 "{fr}ame\t\t print information about the current Stack\n"
214 { "finish" , cmdFinish , NULL,
215 "{fi}nish\t\t execute till return of current function\n"
217 { "fi" , cmdFinish , NULL, NULL },
218 { "where" , cmdWhere , NULL, "where\t\t print stack\n" },
219 { "fr" , cmdFrame , NULL, NULL },
220 { "f" , cmdFrame , NULL, NULL },
221 { "x /i" , cmdDisasm1 , NULL, "x\t\t disassemble one asm command\n" },
222 { "!" , cmdSimulator , NULL,
223 "!<simulator command>\t send a command directly to the simulator\n"
225 { "." , cmdSimulator , NULL,
226 ".{cmd}\t switch from simulator or debugger command mode\n"
228 { "help" , cmdHelp , NULL,
229 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
231 { "?" , cmdHelp , NULL, NULL },
232 { "h" , cmdHelp , NULL, NULL },
234 { "quit" , cmdQuit , NULL,
235 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
237 { "q" , cmdQuit , NULL, NULL }
240 /*-----------------------------------------------------------------*/
241 /* trimming functions */
242 /*-----------------------------------------------------------------*/
243 char *trim_left(char *s)
251 char *trim_right(char *s)
253 char *p = &s[strlen(s) - 1];
255 while (p >= s && isspace(*p))
264 return trim_right(trim_left(s));
267 /*-----------------------------------------------------------------*/
268 /* gc_strdup - make a string duplicate garbage collector aware */
269 /*-----------------------------------------------------------------*/
270 char *gc_strdup(const char *s)
273 ret = Safe_malloc(strlen(s)+1);
278 /*-----------------------------------------------------------------*/
279 /* alloccpy - allocate copy and return a new string */
280 /*-----------------------------------------------------------------*/
281 char *alloccpy ( char *s, int size)
288 d = Safe_malloc(size+1);
295 /*-----------------------------------------------------------------*/
296 /* resize - resizes array of type with new size */
297 /*-----------------------------------------------------------------*/
298 void **resize (void **array, int newSize)
303 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
305 vptr = calloc(1, sizeof(void **));
308 fprintf(stderr,"sdcdb: out of memory \n");
316 /*-----------------------------------------------------------------*/
317 /* readCdb - reads the cdb files & puts the records into cdbLine */
319 /*-----------------------------------------------------------------*/
320 static int readCdb (FILE *file)
326 if (!(bp = fgets(buffer,sizeof(buffer),file)))
329 currl = Safe_calloc(1,sizeof(cdbrecs));
334 /* make sure this is a cdb record */
335 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
336 /* depending on the record type */
341 currl->type = SYM_REC;
344 currl->type = STRUCT_REC;
347 currl->type = LNK_REC;
350 currl->type = FUNC_REC;
353 currl->type = MOD_REC ;
357 currl->line = Safe_malloc(strlen(bp));
358 strncpy(currl->line,bp,strlen(bp)-1);
359 currl->line[strlen(bp)-1] = '\0';
362 if (!(bp = fgets(buffer,sizeof(buffer),file)))
368 currl->next = Safe_calloc(1,sizeof(cdbrecs));
372 return (recsRoot->line ? 1 : 0);
375 /*-----------------------------------------------------------------*/
376 /* searchDirsFname - search directory list & return the filename */
377 /*-----------------------------------------------------------------*/
378 char *searchDirsFname (char *fname)
384 /* first try the current directory */
385 if ((rfile = fopen(fname,"r"))) {
387 return strdup(fname) ;
391 return strdup(fname);
393 /* make a copy of the source directories */
394 dirs = sdirs = strdup(ssdirl);
396 /* assume that the separator is ':'
397 and try for each directory in the search list */
398 dirs = strtok(dirs,":");
400 if (dirs[strlen(dirs)] == '/')
401 sprintf(buffer,"%s%s",dirs,fname);
403 sprintf(buffer,"%s/%s",dirs,fname);
404 if ((rfile = fopen(buffer,"r")))
406 dirs = strtok(NULL,":");
412 return strdup(buffer);
414 return strdup(fname);
417 /*-----------------------------------------------------------------*/
418 /* searchDirsFopen - go thru list of directories for filename given*/
419 /*-----------------------------------------------------------------*/
420 FILE *searchDirsFopen(char *fname)
426 /* first try the current directory */
427 if ((rfile = fopen(fname,"r")))
432 /* make a copy of the source directories */
433 dirs = sdirs = strdup(ssdirl);
435 /* assume that the separator is ':'
436 and try for each directory in the search list */
437 dirs = strtok(dirs,":");
439 sprintf(buffer,"%s/%s",dirs,fname);
440 if ((rfile = fopen(buffer,"r")))
442 dirs = strtok(NULL,":");
450 /*-----------------------------------------------------------------*/
451 /* loadFile - loads a file into module buffer */
452 /*-----------------------------------------------------------------*/
453 srcLine **loadFile (char *name, int *nlines)
458 srcLine **slines = NULL;
461 if (!(mfile = searchDirsFopen(name))) {
462 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
466 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
469 slines = (srcLine **)resize((void **)slines,*nlines);
471 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
472 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
473 slines[(*nlines)-1]->addr= INT_MAX;
481 /*-----------------------------------------------------------------*/
482 /* loadModules - reads the source files into module structure */
483 /*-----------------------------------------------------------------*/
484 static void loadModules (void)
490 /* go thru the records & find out the module
491 records & load the modules specified */
492 for ( loop = recsRoot ; loop ; loop = loop->next ) {
494 switch (loop->type) {
495 /* for module records do */
497 currMod = parseModule(loop->line, TRUE);
498 currModName = currMod->name ;
500 currMod->cfullname = searchDirsFname(currMod->c_name);
502 /* load it into buffer */
503 currMod->cLines = loadFile (currMod->c_name,
506 /* do the same for the assembler file */
507 currMod->afullname = searchDirsFname(currMod->asm_name);
508 currMod->asmLines=loadFile (currMod->asm_name,
509 &currMod->nasmLines);
512 /* if this is a function record */
514 parseFunc(loop->line);
517 /* if this is a structure record */
519 parseStruct(loop->line);
522 /* if symbol then parse the symbol */
524 parseSymbol(loop->line,&rs,2);
528 parseLnkRec(loop->line);
534 /*-----------------------------------------------------------------*/
535 /* generate extra sets of sfr and sbit symbols */
536 /*-----------------------------------------------------------------*/
537 static void specialFunctionRegs (void)
540 for (sym = setFirstItem(symbols);
542 sym = setNextItem(symbols))
544 if ( sym->addrspace == 'I' ||
545 sym->addrspace == 'J')
547 addSet(&sfrsymbols,sym);
551 /*-----------------------------------------------------------------*/
552 /* functionPoints - determine the execution points within a func */
553 /*-----------------------------------------------------------------*/
554 static void functionPoints (void)
560 // add _main dummy for runtime env
561 if ((func = needExtraMainFunction()))
565 /* alloc new _main function */
566 func1 = Safe_calloc(1,sizeof(function));
568 func1->sym = Safe_calloc(1,sizeof(symbol));
569 *func1->sym = *func->sym;
570 func1->sym->name = alloccpy("_main",5);
571 func1->sym->rname = alloccpy("G$_main$0$",10);
572 /* TODO must be set by symbol information */
573 func1->sym->addr = 0;
574 func1->sym->eaddr = 0x2f;
575 addSet(&functions,func1);
578 /* for all functions do */
579 for ( func = setFirstItem(functions); func;
580 func = setNextItem(functions)) {
586 Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
591 if (!func->sym->addr && !func->sym->eaddr)
594 /* for all source lines in the module find
595 the ones with address >= start and <= end
596 and put them in the point */
598 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
601 func->entryline= INT_MAX-2;
603 func->aentryline = INT_MAX-2 ;
606 /* do it for the C Lines first */
607 for ( j = 0 ; j < mod->ncLines ; j++ ) {
608 if (mod->cLines[j]->addr < INT_MAX &&
609 mod->cLines[j]->addr >= sym->addr &&
610 mod->cLines[j]->addr <= sym->eaddr ) {
613 /* add it to the execution point */
614 if (func->entryline > j)
617 if (func->exitline < j)
620 ep = Safe_calloc(1,sizeof(exePoint));
621 ep->addr = mod->cLines[j]->addr ;
623 ep->block= mod->cLines[j]->block;
624 ep->level= mod->cLines[j]->level;
625 addSet(&func->cfpoints,ep);
628 /* check double line execution points of module */
629 for (ep = setFirstItem(mod->cfpoints); ep;
630 ep = setNextItem(mod->cfpoints))
632 if (ep->addr >= sym->addr &&
633 ep->addr <= sym->eaddr )
635 addSet(&func->cfpoints,ep);
638 /* do the same for asm execution points */
639 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
640 if (mod->asmLines[j]->addr < INT_MAX &&
641 mod->asmLines[j]->addr >= sym->addr &&
642 mod->asmLines[j]->addr <= sym->eaddr ) {
645 /* add it to the execution point */
646 if (func->aentryline > j)
647 func->aentryline = j;
649 if (func->aexitline < j)
652 /* add it to the execution point */
653 ep = Safe_calloc(1,sizeof(exePoint));
654 ep->addr = mod->asmLines[j]->addr ;
656 addSet(&func->afpoints,ep);
659 if ( func->entryline == INT_MAX-2 )
661 if ( func->aentryline == INT_MAX-2 )
662 func->aentryline = 0;
665 if (!( D_sdcdb & sdcdbDebug))
668 Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
673 for (ep = setFirstItem(func->cfpoints); ep;
674 ep = setNextItem(func->cfpoints))
675 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
676 ep->addr,ep->line+1,mod->cLines[ep->line]->src));
678 Dprintf(D_sdcdb, ("sdcdb: and the following ASM exePoints\n"));
679 for (ep = setFirstItem(func->afpoints); ep;
680 ep = setNextItem(func->afpoints))
681 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
682 ep->addr,ep->line+1,mod->asmLines[ep->line]->src));
689 /*-----------------------------------------------------------------*/
690 /* setEntryExitBP - set the entry & exit Break Points for functions*/
691 /*-----------------------------------------------------------------*/
692 DEFSETFUNC(setEntryExitBP)
694 function *func = item;
696 if (func->sym && func->sym->addr && func->sym->eaddr) {
698 /* set the entry break point */
699 setBreakPoint (func->sym->addr , CODE , FENTRY ,
700 fentryCB ,func->mod->c_name , func->entryline);
702 /* set the exit break point */
703 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
704 fexitCB ,func->mod->c_name , func->exitline );
710 /*-----------------------------------------------------------------*/
711 /* cmdFile - load file into the debugger */
712 /*-----------------------------------------------------------------*/
713 int cmdFile (char *s,context *cctxt)
722 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
726 sprintf(buffer,"%s.cdb",s);
727 /* try creating the cdbfile */
728 if (!(cdbFile = searchDirsFopen(buffer))) {
729 fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
733 /* allocate for context */
734 currCtxt = Safe_calloc(1,sizeof(context));
737 /* readin the debug information */
738 if (!readCdb (cdbFile)) {
739 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
744 /* parse and load the modules required */
747 /* determine the execution points for this
751 /* extract known special function registers */
752 specialFunctionRegs();
754 /* start the simulator & setup connection to it */
756 if (INVALID_SOCKET == sock)
760 openSimulator((char **)simArgs,nsimArgs);
761 fprintf(stdout,"%s",simResponse());
762 /* now send the filename to be loaded to the simulator */
763 sprintf(buffer,"%s.ihx",s);
764 bp=searchDirsFname(buffer);
768 /*set the break points
769 required by the debugger . i.e. the function entry
770 and function exit break points */
771 applyToSet(functions,setEntryExitBP);
777 /*-----------------------------------------------------------------*/
778 /* cmdSource - read commands from file */
779 /*-----------------------------------------------------------------*/
780 int cmdSource (char *s, context *cctxt)
786 if (!( cmdfile = searchDirsFopen(s)))
788 fprintf(stderr,"commandfile '%s' not found\n",s);
791 commandLoop( cmdfile );
796 /*-----------------------------------------------------------------*/
797 /* cmdHelp - help command */
798 /*-----------------------------------------------------------------*/
799 int cmdHelp (char *s, context *cctxt)
808 endline = ((*s - '0') * 20) + 20;
810 startline = endline - 20;
814 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
816 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
818 s = strrchr(cmdTab[i].htxt,'\t');
823 fprintf(stdout,"%s",s);
830 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
832 /* command string matches */
834 if ((cmdTab[i].htxt) && (i >= startline))
835 fprintf(stdout,"%s",cmdTab[i].htxt);
843 #define MAX_CMD_LEN 512
844 static char cmdbuff[MAX_CMD_LEN];
845 static int sim_cmd_mode = 0;
847 /*-----------------------------------------------------------------
848 interpretCmd - interpret and do the command. Return 0 to continue,
849 return 1 to exit program.
850 |-----------------------------------------------------------------*/
851 int interpretCmd (char *s)
853 static char *pcmd = NULL;
857 /* if nothing & previous command exists then
858 execute the previous command again */
859 if (*s == '\n' && pcmd)
862 /* if previous command exists & is different
863 from the current command then copy it */
865 if (strcmp(pcmd,s)) {
872 /* trim trailing blanks */
876 if (strcmp(s,".") == 0) {
880 else if (s[0] == '.') {
881 /* kill the preceeding '.' and pass on as SDCDB command */
888 cmdSimulator (s, currCtxt);
892 if (strcmp(s,".") ==0) {
898 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
900 /* command string matches */
901 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
902 if (!cmdTab[i].cmdfunc)
905 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
907 /* if full name then give the file name & position */
908 if (fullname && showfull && currCtxt && currCtxt->func) {
910 if (srcMode == SRC_CMODE)
911 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
912 currCtxt->func->mod->cfullname,
913 currCtxt->cline+1,currCtxt->addr);
915 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
916 currCtxt->func->mod->afullname,
917 currCtxt->asmline,currCtxt->addr);
918 displayAll(currCtxt);
924 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
929 static FILE *actualcmdfile=NULL ;
930 static char *actualcmds=NULL;
931 static int stopcmdlist;
932 /*-----------------------------------------------------------------*/
933 /* getNextCmdLine get additional lines used by special commands */
934 /*-----------------------------------------------------------------*/
935 char *getNextCmdLine(void)
937 //fprintf(stderr,"getNextCmdLine() actualcmdfile=%p\n",actualcmdfile);
942 if (fgets(cmdbuff,sizeof(cmdbuff),actualcmdfile) == NULL)
944 // fprintf(stderr,"getNextCmdLine() returns null\n");
947 //fprintf(stderr,"getNextCmdLine() returns: %s",cmdbuff);
951 void setCmdLine( char *cmds )
956 void stopCommandList()
961 #ifdef HAVE_LIBREADLINE
962 // helper function for doing readline completion.
963 // input: toknum=index of token to find (0=first token)
964 // output: *start=first character index of the token,
965 // or the index of '\0'
966 // *end=first blank character right after the token,
967 // or the index of '\0'
968 // return value: 0=token not found, 1=token found
969 int completionHelper_GetTokenNumber(int toknum, int *start, int *end)
972 const char *p = rl_line_buffer;
978 // start = skip blanks from end
980 while (p[*start] && isblank( p[*start] ))
983 // end = skip non-blanks from start
985 while (p[*end] && !isblank( p[*end] ))
988 if (tok_index == toknum)
994 return 0; // not found
997 // helper function for doing readline completion.
998 // returns the token number that we were asked to complete.
999 // 0=first token (command name), 1=second token...
1000 int completionHelper_GetCurrTokenNumber()
1002 int toknum, start, end;
1004 toknum = start = end = 0;
1007 if (!completionHelper_GetTokenNumber(toknum, &start, &end))
1010 if (rl_point <= end)
1017 // exapmle for vallist on entry:
1018 // "copying\0warranty\0";
1019 char *completionCompleteFromStrList(const char *text, int state, char *vallist)
1027 ptr += strlen(ptr)+1;
1032 if ( (len < strlen(ptr)) &&
1033 !strncmp(text, ptr, len) )
1036 ptr += strlen(ptr)+1;
1042 // readline library completion function.
1043 // completes from the list of all sdcdb command.
1044 char *completionCommandsList(const char *text, int state)
1048 if (state == 0) // new completion?
1049 { // yes, only complete if this is the first token on the line.
1050 int ok = 0; // try to complete this request?
1051 char *p = rl_line_buffer;
1054 while (p && isblank(*p))
1056 if (p-rl_line_buffer == rl_point)
1061 while (p && !isblank(*p))
1063 if (p-rl_line_buffer == rl_point)
1068 if (p-rl_line_buffer == rl_point)
1072 return NULL; // no more completions
1074 i = 0; // ok, gonna complete. initialize static variable.
1078 for (; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1080 int len = strlen(text);
1081 if (len <= strlen(cmdTab[i].cmd))
1083 if (strncmp(text,cmdTab[i].cmd,len) == 0)
1084 return strdup(cmdTab[i].cmd);
1088 return NULL; // no more completions
1091 // readline library completion function.
1092 // completes from the list of symbols.
1093 char *completionSymbolName(const char *text, int state)
1097 if (state == 0) // new completion?
1098 sy = setFirstItem(symbols); // yes
1100 sy = setNextItem(symbols);
1102 for (; sy != NULL; )
1104 int len = strlen(text);
1105 if (len <= strlen(sy->name))
1107 if (strncmp(text,sy->name,len) == 0)
1108 return strdup(sy->name);
1111 sy = setNextItem(symbols);
1116 // readline library completion function.
1117 // completes from the list known functions.
1118 // module_flag - if false, ignore function module name
1119 // if true, compare against module_name:fnction_name
1120 char *completionFunctionName(const char *text, int state, int module_flag)
1124 if (state == 0) // new completion?
1125 f = setFirstItem(functions); // yes
1127 f = setNextItem(functions);
1131 int text_len = strlen(text);
1135 if (text_len <= strlen(f->sym->name) &&
1136 !strncmp(text,f->sym->name,text_len))
1137 return strdup(f->sym->name);
1141 int modname_len = strlen(f->mod->c_name);
1142 int funcname_len = strlen(f->sym->name);
1143 char *functext = malloc(modname_len+funcname_len+2);
1145 strcpy(functext,f->mod->c_name);
1146 strcat(functext,":");
1147 strcat(functext,f->sym->name);
1148 if (text_len <= strlen(functext) &&
1149 !strncmp(text,functext,text_len))
1154 f = setNextItem(functions);
1159 // readline library completion function.
1160 // completes from the list known modules.
1161 char *completionModuleName(const char *text, int state)
1165 if (state == 0) // new completion?
1166 m = setFirstItem(modules); // yes
1168 m = setNextItem(modules);
1172 int len = strlen(text);
1173 if ( (len <= strlen(m->c_name)) &&
1174 !strncmp(text,m->c_name,len) )
1175 return strdup(m->c_name);
1177 if ( (len <= strlen(m->asm_name)) &&
1178 (strncmp(text,m->asm_name,len) == 0) )
1179 return strdup(m->asm_name);
1181 m = setNextItem(modules);
1186 // readline completion function for "file" command
1187 char *completionCmdFile(const char *text, int state)
1191 if (completionHelper_GetCurrTokenNumber() != 1)
1195 // we use filename_completion_function() from the readline library.
1196 return rl_filename_completion_function(text, state);
1199 // readline completion function for "source" command
1200 char *completionCmdSource(const char *text, int state)
1202 return completionCmdFile(text, state);
1205 // readline completion function for "info" command
1206 char *completionCmdInfo(const char *text, int state)
1212 if (completionHelper_GetCurrTokenNumber() != 1)
1216 return completionCompleteFromStrList(text, state,
1217 "break\0stack\0frame\0registers\0all-registers\0"
1218 "line\0source\0functions\0symbols\0variables\0");
1221 // readline completion function for "show" command
1222 char *completionCmdShow(const char *text, int state)
1228 if (completionHelper_GetCurrTokenNumber() != 1)
1231 return completionCompleteFromStrList(text, state, "copying\0warranty\0");
1234 // readline completion function for "la" command
1235 char *completionCmdListSymbols(const char *text, int state)
1241 if (completionHelper_GetCurrTokenNumber() != 1)
1244 return completionCompleteFromStrList(text, state, "v1\0v2\0");
1247 char *completionCmdPrintType(const char *text, int state)
1251 if (completionHelper_GetCurrTokenNumber() != 1)
1254 return completionSymbolName(text, state);
1257 char *completionCmdPrint(const char *text, int state)
1261 int i = completionHelper_GetCurrTokenNumber();
1262 if (i != 1 && i != 2)
1265 return completionSymbolName(text, state);
1268 char *completionCmdDelUserBp(const char *text, int state)
1275 if (completionHelper_GetCurrTokenNumber() != 1)
1281 bp = hTabFirstItem(bptable,&k);
1284 bp = hTabNextItem(bptable,&k);
1286 for ( ; bp ; bp = hTabNextItem(bptable,&k))
1288 if (bp->bpType == USER || bp->bpType == TMPUSER)
1291 sprintf(buff, "%d", bp->bpnum);
1292 return strdup(buff);
1299 // readline completion function for "undisplay" command
1300 char *completionCmdUnDisplay(const char *text, int state)
1302 static dsymbol *dsym;
1306 if (completionHelper_GetCurrTokenNumber() != 1)
1308 dsym = setFirstItem(dispsymbols);
1314 sprintf(buff, "%d", dsym->dnum);
1315 dsym = setNextItem(dispsymbols);
1316 return strdup(buff);
1321 char *completionCmdSetUserBp(const char *text, int state)
1323 static int internal_state; // 0=calling completionFunctionName(text, state, 0)
1324 // 1=calling completionFunctionName(text, 1, 1)
1327 if (completionHelper_GetCurrTokenNumber() != 1)
1332 if (internal_state == 0)
1334 char *p = completionFunctionName(text, state, 0);
1338 return completionFunctionName(text, 0, 1);
1342 return completionFunctionName(text, 1, 1);
1346 char *completionCmdSetOption(const char *text, int state)
1355 currtok = completionHelper_GetCurrTokenNumber();
1357 if (currtok == 2 || currtok == 3)
1359 // make sure token 1 == "variable"
1360 completionHelper_GetTokenNumber(1, &start, &end);
1361 if (end - start != 8 ||
1362 strncmp(rl_line_buffer+start,"variable",8))
1365 else if (currtok != 1)
1374 return completionCompleteFromStrList(text, state,
1378 "srcmode\0listsize\0variable\0");
1380 return completionSymbolName(text, state);
1383 return completionCompleteFromStrList(text, state, "=\0");
1387 // our main readline completion function
1388 // calls the other completion functions as needed.
1389 char *completionMain(const char *text, int state)
1391 static rl_compentry_func_t *compl_func;
1392 int i, start, end, len;
1394 if (state == 0) // new completion?
1398 if (completionHelper_GetCurrTokenNumber() == 0)
1399 compl_func = &completionCommandsList;
1401 { // not completing first token, find the right completion
1402 // function according to the first token the user typed.
1403 completionHelper_GetTokenNumber(0, &start, &end);
1406 for (i=0; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
1408 if (!strncmp(rl_line_buffer+start,cmdTab[i].cmd,len) &&
1409 cmdTab[i].cmd[len] == '\0')
1411 compl_func = cmdTab[i].completion_func;
1420 return (*compl_func)(text,state);
1422 #endif /* HAVE_LIBREADLINE */
1424 /*-----------------------------------------------------------------*/
1425 /* commandLoop - the main command loop or loop over command file */
1426 /*-----------------------------------------------------------------*/
1427 static void commandLoop(FILE *cmdfile)
1429 char *line, save_ch, *s;
1432 #ifdef HAVE_LIBREADLINE
1433 FILE *old_rl_instream, *old_rl_outstream;
1434 actualcmdfile = cmdfile;
1436 rl_completion_entry_function = completionMain;
1437 rl_readline_name = "sdcdb"; // Allow conditional parsing of the ~/.inputrc file.
1439 // save readline's input/output streams
1440 // this is done to support nested calls to commandLoop()
1441 // i wonder if it works...
1442 old_rl_instream = rl_instream;
1443 old_rl_outstream = rl_outstream;
1445 // set new streams for readline
1446 if ( cmdfile == stdin )
1447 rl_instream = rl_outstream = NULL; // use stdin/stdout pair
1449 rl_instream = rl_outstream = cmdfile;
1453 if ( cmdfile == stdin )
1456 line_read = (char*)readline ("(sim)");
1458 line_read = (char*)readline ("(sdcdb)");
1461 line_read = (char*)readline ("");
1465 /* If the line has any text in it,
1466 save it on the history. */
1467 if (line_read && *line_read)
1468 add_history (line_read);
1470 // FIX: readline returns malloced string.
1471 // should check the source to verify it can be used
1472 // directly. for now - just copy it to cmdbuff.
1473 strcpy(cmdbuff,line_read);
1474 #if defined(_WIN32) || defined(HAVE_RL_FREE)
1484 actualcmdfile = cmdfile;
1488 if ( cmdfile == stdin )
1493 fprintf(stdout,"(sdcdb) ");
1496 //fprintf(stderr,"commandLoop actualcmdfile=%p cmdfile=%p\n",
1497 // actualcmdfile,cmdfile);
1498 if (fgets(cmdbuff,sizeof(cmdbuff),cmdfile) == NULL)
1500 #endif /* HAVE_LIBREADLINE */
1502 if (interpretCmd(cmdbuff))
1505 while ( actualcmds )
1507 strcpy(cmdbuff,actualcmds);
1510 for ( line = cmdbuff; *line ; line = s )
1512 if ( (s=strchr(line ,'\n')))
1519 s += strlen( line );
1522 if (interpretCmd( line ))
1533 #ifdef HAVE_LIBREADLINE
1534 // restore readline's input/output streams
1535 rl_instream = old_rl_instream;
1536 rl_outstream = old_rl_outstream;
1537 #endif /* HAVE_LIBREADLINE */
1540 /*-----------------------------------------------------------------*/
1541 /* printVersionInfo - print the version information */
1542 /*-----------------------------------------------------------------*/
1543 static void printVersionInfo()
1546 "SDCDB is free software and you are welcome to distribute copies of it\n"
1547 "under certain conditions; type \"show copying\" to see the conditions.\n"
1548 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
1549 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
1550 "Type ? for help\n");
1554 /*-----------------------------------------------------------------*/
1555 /* parseCmdLine - parse the commandline arguments */
1556 /*-----------------------------------------------------------------*/
1557 static void parseCmdLine (int argc, char **argv)
1560 char *filename = NULL;
1561 int passon_args_flag = 0; /* if true, pass on args to simulator */
1563 Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
1566 for ( i = 1; i < argc ; i++) {
1567 //fprintf(stdout,"%s\n",argv[i]);
1569 if (passon_args_flag) { /* if true, pass on args to simulator */
1570 simArgs[nsimArgs++] = strdup(argv[i]);
1574 /* if this is an option */
1575 if (argv[i][0] == '-') {
1577 /* if directory then mark directory */
1578 if (strncmp(argv[i],"--directory=",12) == 0) {
1580 ssdirl = &argv[i][12];
1582 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
1583 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
1589 if (strncmp(argv[i],"-fullname",9) == 0) {
1594 if (strcmp(argv[i],"-cd") == 0) {
1600 if (strncmp(argv[i],"-cd=",4) == 0) {
1606 if (strncmp(argv[i],"-d=",3) == 0) {
1607 sdcdbDebug = strtol(&argv[i][3],0,0);
1611 if (strncmp(argv[i],"-contsim",8) == 0) {
1615 if (strncmp(argv[i],"-q",2) == 0) {
1620 if (strncmp(argv[i],"-m",2) == 0) {
1621 strncpy(model_str, &argv[i][2], 15);
1622 if (strcmp(model_str,"avr") == 0)
1623 simArgs[0] = "savr";
1624 else if (strcmp(model_str,"xa") == 0)
1626 else if (strcmp(model_str,"z80") == 0)
1627 simArgs[0] = "sz80";
1631 /* -z all remaining options are for simulator */
1632 if (strcmp(argv[i],"-z") == 0) {
1633 passon_args_flag = 1;
1637 /* the simulator arguments */
1640 if (strcmp(argv[i],"-t") == 0 ||
1641 strcmp(argv[i],"-cpu") == 0) {
1643 simArgs[nsimArgs++] = "-t";
1644 simArgs[nsimArgs++] = strdup(argv[++i]);
1648 /* XTAL Frequency */
1649 if (strcmp(argv[i],"-X") == 0 ||
1650 strcmp(argv[i],"-frequency") == 0) {
1651 simArgs[nsimArgs++] = "-X";
1652 simArgs[nsimArgs++] = strdup(argv[++i]);
1657 if ( (strcmp(argv[i],"-S") == 0) ||
1658 (strcmp(argv[i],"-s") == 0)) {
1659 simArgs[nsimArgs++] = strdup(argv[i]);
1660 simArgs[nsimArgs++] = strdup(argv[++i]);
1664 /* network serial port */
1665 if ( (strcmp(argv[i],"-k") == 0)) {
1666 simArgs[nsimArgs++] = strdup(argv[i]);
1667 simArgs[nsimArgs++] = strdup(argv[++i]);
1671 fprintf(stderr,"unknown option %s --- ignored\n",
1675 /* must be file name */
1677 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
1682 if (-1 != access(argv[i], 0)) {
1683 /* file exists: strip the cdb or ihx externsion */
1684 char *p = strrchr(argv[i], '.');
1687 (0 == strcmp(p, ".cdb") || 0 == strcmp(p, ".ihx")))
1696 cmdFile(filename,NULL);
1699 /*-----------------------------------------------------------------*/
1700 /* setsignals - catch some signals */
1701 /*-----------------------------------------------------------------*/
1714 /* may be interrupt from user: stop debugger and also simulator */
1721 /* the only child can be the simulator */
1722 static void sigchld(int sig)
1724 /* the only child can be the simulator */
1726 retpid = wait ( &status );
1727 /* if ( retpid == simPid ) */
1735 signal(SIGINT , sigintr );
1736 signal(SIGABRT, bad_signal);
1737 signal(SIGTERM, bad_signal);
1740 signal(SIGHUP , SIG_IGN);
1741 signal(SIGCONT, SIG_IGN);
1742 signal(SIGCHLD, sigchld );
1744 signal(SIGALRM, bad_signal);
1745 //signal(SIGFPE, bad_signal);
1746 //signal(SIGILL, bad_signal);
1747 signal(SIGPIPE, bad_signal);
1748 signal(SIGQUIT, bad_signal);
1749 //signal(SIGSEGV, bad_signal);
1753 /*-----------------------------------------------------------------*/
1755 /*-----------------------------------------------------------------*/
1757 int main ( int argc, char **argv)
1760 printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1762 simArgs[nsimArgs++] = "s51";
1763 simArgs[nsimArgs++] = "-P";
1764 simArgs[nsimArgs++] = "-r 9756";
1765 /* parse command line */
1768 parseCmdLine(argc,argv);