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 -------------------------------------------------------------------------*/
35 char *currModName = NULL;
36 cdbrecs *recsRoot = NULL ;
37 set *modules = NULL; /* set of all modules */
38 set *functions = NULL ; /* set of functions */
39 set *symbols = NULL ; /* set of symbols */
40 set *sfrsymbols= NULL ; /* set of symbols of sfr or sbit */
42 structdef **structs = NULL ; /* all structures */
44 linkrec **linkrecs = NULL; /* all linkage editor records */
45 context *currCtxt = NULL;
48 short userinterrupt = 0;
49 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ;
54 /* fake filename & lineno to make linker */
62 char *cmd ; /* command the user will enter */
63 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
64 char *htxt ; /* short help text */
67 /* NOTE:- the search is done from the top, so "break" should
68 precede the synonym "b" */
70 { "break" , cmdSetUserBp ,
71 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION | *<address>]\n",
73 { "b" , cmdSetUserBp , NULL },
75 { "clear" , cmdClrUserBp ,
76 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
78 { "cl" , cmdClrUserBp , NULL },
80 { "continue" , cmdContinue ,
81 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
83 { "c" , cmdContinue , NULL },
85 { "disassemble",cmdDisasmF , "disassemble [startaddr [endaddress]]\tdisassemble asm commands\n" },
86 { "delete" , cmdDelUserBp ,
87 "{d}elete n\t\t clears break point number n\n"
89 { "display" , cmdDisplay ,
90 "display [/<fmt>] [<variable>]\t print value of given variable each time the program stops\n"
92 { "undisplay" , cmdUnDisplay ,
93 "undisplay [<variable>]\t dont display this variable or all\n"
96 "down\t\tSelect and print stack frame called by this one.\nAn argument says how many frames down to go.\n"
99 "up\t\tSelect and print stack frame that called this one.\nAn argument says how many frames up to go.\n"
101 { "d" , cmdDelUserBp , NULL },
104 "info <break stack frame registers all-registers>\n"
105 "\t list all break points, call-stack, frame or register information\n"
108 { "listasm" , cmdListAsm ,
109 "listasm {la}\t\t list assembler code for the current C line\n"
111 { "la" , cmdListAsm , NULL },
112 { "ls" , cmdListSymbols , "ls,lf,lm\t\t list symbols,functions,modules\n" },
113 { "lf" , cmdListFunctions, NULL },
114 { "lm" , cmdListModules , NULL },
115 { "list" , cmdListSrc ,
116 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
118 { "l" , cmdListSrc , NULL },
121 " <copying warranty>\t copying & distribution terms, warranty\n"
123 { "set" , cmdSetOption , "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
124 { "stepi" , cmdStepi ,
125 "stepi\t\t\tStep one instruction exactly.\n"
128 "{s}tep\t\t\tStep program until it reaches a different source line.\n"
130 { "s" , cmdStep , NULL },
131 { "nexti" , cmdNexti ,
132 "nexti\t\t\tStep one instruction, but proceed through subroutine calls.\n"
135 "{n}ext\t\t\tStep program, proceeding through subroutine calls.\n"
137 { "n" , cmdNext , NULL },
139 "{r}un\t\t\tStart debugged program. \n"
141 { "r" , cmdRun , NULL },
142 { "ptype" , cmdPrintType ,
143 "{pt}ype <variable>\tprint type information of a variable\n"
145 { "pt" , cmdPrintType , NULL },
146 { "print" , cmdPrint ,
147 "{p}rint <variable>\t print value of given variable\n"
149 { "output" , cmdOutput ,
150 "output <variable>\t print value of given variable without $ and newline \n"
152 { "p" , cmdPrint , NULL },
154 "file <filename>\t\t load symbolic information from <filename>\n"
156 { "frame" , cmdFrame ,
157 "{fr}ame\t\t print information about the current Stack\n"
159 { "finish" , cmdFinish ,
160 "{fi}nish\t\t execute till return of current function\n"
162 { "fi" , cmdFinish , NULL },
163 { "where" , cmdWhere , "where\t\t print stack\n" },
164 { "fr" , cmdFrame , NULL },
165 { "f" , cmdFrame , NULL },
166 { "x /i" , cmdDisasm1 , "x\t\t disassemble one asm command\n" },
167 { "!" , cmdSimulator ,
168 "!<simulator command>\t send a command directly to the simulator\n"
170 { "." , cmdSimulator ,
171 ".{cmd}\t switch from simulator or debugger command mode\n"
174 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
176 { "?" , cmdHelp , NULL },
177 { "h" , cmdHelp , NULL },
180 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
182 { "q" , cmdQuit , NULL }
185 /*-----------------------------------------------------------------*/
186 /* gc_strdup - make a string duplicate garbage collector aware */
187 /*-----------------------------------------------------------------*/
188 char *gc_strdup(const char *s)
191 ret = Safe_malloc(strlen(s)+1);
196 /*-----------------------------------------------------------------*/
197 /* alloccpy - allocate copy and return a new string */
198 /*-----------------------------------------------------------------*/
199 char *alloccpy ( char *s, int size)
206 d = Safe_malloc(size+1);
213 /*-----------------------------------------------------------------*/
214 /* resize - resizes array of type with new size */
215 /*-----------------------------------------------------------------*/
216 void **resize (void **array, int newSize)
221 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
223 vptr = calloc(1, sizeof(void **));
226 fprintf(stderr,"sdcdb: out of memory \n");
234 /*-----------------------------------------------------------------*/
235 /* readCdb - reads the cdb files & puts the records into cdbLine */
237 /*-----------------------------------------------------------------*/
238 static int readCdb (FILE *file)
244 if (!(bp = fgets(buffer,sizeof(buffer),file)))
247 currl = Safe_calloc(1,sizeof(cdbrecs));
252 /* make sure this is a cdb record */
253 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
254 /* depending on the record type */
259 currl->type = SYM_REC;
262 currl->type = STRUCT_REC;
265 currl->type = LNK_REC;
268 currl->type = FUNC_REC;
271 currl->type = MOD_REC ;
275 currl->line = Safe_malloc(strlen(bp));
276 strncpy(currl->line,bp,strlen(bp)-1);
277 currl->line[strlen(bp)-1] = '\0';
280 if (!(bp = fgets(buffer,sizeof(buffer),file)))
286 currl->next = Safe_calloc(1,sizeof(cdbrecs));
290 return (recsRoot->line ? 1 : 0);
293 /*-----------------------------------------------------------------*/
294 /* searchDirsFname - search directory list & return the filename */
295 /*-----------------------------------------------------------------*/
296 char *searchDirsFname (char *fname)
302 /* first try the current directory */
303 if ((rfile = fopen(fname,"r"))) {
305 return strdup(fname) ;
309 return strdup(fname);
311 /* make a copy of the source directories */
312 dirs = sdirs = strdup(ssdirl);
314 /* assume that the separator is ':'
315 and try for each directory in the search list */
316 dirs = strtok(dirs,":");
318 if (dirs[strlen(dirs)] == '/')
319 sprintf(buffer,"%s%s",dirs,fname);
321 sprintf(buffer,"%s/%s",dirs,fname);
322 if ((rfile = fopen(buffer,"r")))
324 dirs = strtok(NULL,":");
330 return strdup(buffer);
332 return strdup(fname);
335 /*-----------------------------------------------------------------*/
336 /* searchDirsFopen - go thru list of directories for filename given*/
337 /*-----------------------------------------------------------------*/
338 FILE *searchDirsFopen(char *fname)
344 /* first try the current directory */
345 if ((rfile = fopen(fname,"r")))
350 /* make a copy of the source directories */
351 dirs = sdirs = strdup(ssdirl);
353 /* assume that the separator is ':'
354 and try for each directory in the search list */
355 dirs = strtok(dirs,":");
357 sprintf(buffer,"%s/%s",dirs,fname);
358 if ((rfile = fopen(buffer,"r")))
360 dirs = strtok(NULL,":");
368 /*-----------------------------------------------------------------*/
369 /* loadFile - loads a file into module buffer */
370 /*-----------------------------------------------------------------*/
371 srcLine **loadFile (char *name, int *nlines)
376 srcLine **slines = NULL;
379 if (!(mfile = searchDirsFopen(name))) {
380 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
384 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
387 slines = (srcLine **)resize((void **)slines,*nlines);
389 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
390 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
398 /*-----------------------------------------------------------------*/
399 /* loadModules - reads the source files into module structure */
400 /*-----------------------------------------------------------------*/
401 static void loadModules ()
407 /* go thru the records & find out the module
408 records & load the modules specified */
409 for ( loop = recsRoot ; loop ; loop = loop->next ) {
411 switch (loop->type) {
412 /* for module records do */
414 currMod = parseModule(loop->line,TRUE);
415 currModName = currMod->name ;
417 currMod->cfullname = searchDirsFname(currMod->c_name);
419 /* load it into buffer */
420 currMod->cLines = loadFile (currMod->c_name,
423 /* do the same for the assembler file */
424 currMod->afullname = searchDirsFname(currMod->asm_name);
425 currMod->asmLines=loadFile (currMod->asm_name,
426 &currMod->nasmLines);
429 /* if this is a function record */
431 parseFunc(loop->line);
434 /* if this is a structure record */
436 parseStruct(loop->line);
439 /* if symbol then parse the symbol */
441 parseSymbol(loop->line,&rs);
445 parseLnkRec(loop->line);
451 /*-----------------------------------------------------------------*/
452 /* generate extra sets of sfr and sbit symbols */
453 /*-----------------------------------------------------------------*/
454 static void specialFunctionRegs ()
457 for (sym = setFirstItem(symbols);
459 sym = setNextItem(symbols))
461 if ( sym->addrspace == 'I' ||
462 sym->addrspace == 'J')
464 addSet(&sfrsymbols,sym);
468 /*-----------------------------------------------------------------*/
469 /* functionPoints - determine the execution points within a func */
470 /*-----------------------------------------------------------------*/
471 static void functionPoints ()
476 /* for all functions do */
477 for ( func = setFirstItem(functions); func;
478 func = setNextItem(functions)) {
484 Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
489 if (!func->sym->addr && !func->sym->eaddr)
492 /* for all source lines in the module find
493 the ones with address >= start and <= end
494 and put them in the point */
496 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
499 func->entryline= INT_MAX;
501 func->aentryline = INT_MAX ;
504 /* do it for the C Lines first */
505 for ( j = 0 ; j < mod->ncLines ; j++ ) {
506 if (mod->cLines[j]->addr >= sym->addr &&
507 mod->cLines[j]->addr <= sym->eaddr ) {
511 /* add it to the execution point */
512 if (func->entryline > j)
515 if (func->exitline < j)
518 ep = Safe_calloc(1,sizeof(exePoint));
519 ep->addr = mod->cLines[j]->addr ;
521 ep->block= mod->cLines[j]->block;
522 ep->level= mod->cLines[j]->level;
523 addSet(&func->cfpoints,ep);
527 /* do the same for asm execution points */
528 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
529 if (mod->asmLines[j]->addr >= sym->addr &&
530 mod->asmLines[j]->addr <= sym->eaddr ) {
533 /* add it to the execution point */
534 if (func->aentryline > j)
535 func->aentryline = j;
537 if (func->aexitline < j)
540 /* add it to the execution point */
541 ep = Safe_calloc(1,sizeof(exePoint));
542 ep->addr = mod->asmLines[j]->addr ;
544 addSet(&func->afpoints,ep);
549 if (!( D_sdcdb & sdcdbDebug))
552 Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
557 for (ep = setFirstItem(func->cfpoints); ep;
558 ep = setNextItem(func->cfpoints))
559 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
560 ep->addr,ep->line,mod->cLines[ep->line]->src));
562 Dprintf(D_sdcdb, ("sdcdb: and the following ASM exePoints\n"));
563 for (ep = setFirstItem(func->afpoints); ep;
564 ep = setNextItem(func->afpoints))
565 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
566 ep->addr,ep->line,mod->asmLines[ep->line]->src));
573 /*-----------------------------------------------------------------*/
574 /* setEntryExitBP - set the entry & exit Break Points for functions*/
575 /*-----------------------------------------------------------------*/
576 DEFSETFUNC(setEntryExitBP)
578 function *func = item;
580 if (func->sym && func->sym->addr && func->sym->eaddr) {
582 /* set the entry break point */
583 setBreakPoint (func->sym->addr , CODE , FENTRY ,
584 fentryCB ,func->mod->c_name , func->entryline);
586 /* set the exit break point */
587 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
588 fexitCB ,func->mod->c_name , func->exitline );
594 /*-----------------------------------------------------------------*/
595 /* cmdFile - load file into the debugger */
596 /*-----------------------------------------------------------------*/
597 int cmdFile (char *s,context *cctxt)
603 while (isspace(*s)) s++;
605 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
609 sprintf(buffer,"%s.cdb",s);
610 /* try creating the cdbfile */
611 if (!(cdbFile = searchDirsFopen(buffer))) {
612 fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
616 /* allocate for context */
617 currCtxt = Safe_calloc(1,sizeof(context));
620 /* readin the debug information */
621 if (!readCdb (cdbFile)) {
622 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
627 /* parse and load the modules required */
630 /* determine the execution points for this
634 /* extract known special function registers */
635 specialFunctionRegs();
637 /* start the simulator & setup connection to it */
639 openSimulator((char **)simArgs,nsimArgs);
640 fprintf(stdout,"%s",simResponse());
641 /* now send the filename to be loaded to the simulator */
642 sprintf(buffer,"%s.ihx",s);
643 bp=searchDirsFname(buffer);
647 /*set the break points
648 required by the debugger . i.e. the function entry
649 and function exit break points */
650 applyToSet(functions,setEntryExitBP);
656 /*-----------------------------------------------------------------*/
657 /* cmdHelp - help command */
658 /*-----------------------------------------------------------------*/
659 int cmdHelp (char *s, context *cctxt)
668 endline = ((*s - '0') * 20) + 20;
670 startline = endline - 20;
674 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
676 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
678 s = strrchr(cmdTab[i].htxt,'\t');
683 fprintf(stdout,"%s",s);
690 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
692 /* command string matches */
694 if ((cmdTab[i].htxt) && (i >= startline))
695 fprintf(stdout,"%s",cmdTab[i].htxt);
703 #define MAX_CMD_LEN 512
704 static char cmdbuff[MAX_CMD_LEN];
705 static int sim_cmd_mode = 0;
707 /*-----------------------------------------------------------------
708 interpretCmd - interpret and do the command. Return 0 to continue,
709 return 1 to exit program.
710 |-----------------------------------------------------------------*/
711 int interpretCmd (char *s)
713 static char *pcmd = NULL;
717 /* if nothing & previous command exists then
718 execute the previous command again */
719 if (*s == '\n' && pcmd)
722 /* if previous command exists & is different
723 from the current command then copy it */
725 if (strcmp(pcmd,s)) {
732 /* lookup the command table and do the task required */
736 if (strcmp(s,".") == 0) {
740 else if (s[0] == '.') {
741 /* kill the preceeding '.' and pass on as SDCDB command */
748 cmdSimulator (s, currCtxt);
752 if (strcmp(s,".") ==0) {
758 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
760 /* command string matches */
761 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
762 if (!cmdTab[i].cmdfunc)
765 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
767 /* if full name then give the file name & position */
768 if (fullname && showfull && currCtxt && currCtxt->func) {
770 if (srcMode == SRC_CMODE)
771 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
772 currCtxt->func->mod->cfullname,
773 currCtxt->cline,currCtxt->addr);
775 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
776 currCtxt->func->mod->afullname,
777 currCtxt->asmline,currCtxt->addr);
778 displayAll(currCtxt);
784 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
789 /*-----------------------------------------------------------------*/
790 /* commandLoop - the main command loop */
791 /*-----------------------------------------------------------------*/
794 char *prompt = "(sdcdb) ";
795 char *sim_prompt = "(sim) ";
799 printf("%s",sim_prompt);
801 fprintf(stdout,"%s",prompt);
805 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
809 /* make a way to go into "ucSim" mode */
810 if (cmdbuff[0] == '$') {
811 if (sim_cmd_mode) sim_cmd_mode = 0;
812 else sim_cmd_mode = 1;
817 if (interpretCmd(cmdbuff))
822 /*-----------------------------------------------------------------*/
823 /* printVersionInfo - print the version information */
824 /*-----------------------------------------------------------------*/
825 static void printVersionInfo()
828 "SDCDB is free software and you are welcome to distribute copies of it\n"
829 "under certain conditions; type \"show copying\" to see the conditions.\n"
830 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
831 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
832 "Type ? for help\n");
836 /*-----------------------------------------------------------------*/
837 /* parseCmdLine - parse the commandline arguments */
838 /*-----------------------------------------------------------------*/
839 static void parseCmdLine (int argc, char **argv)
842 char *filename = NULL;
843 int passon_args_flag = 0; /* if true, pass on args to simulator */
845 Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
847 for ( i = 1; i < argc ; i++) {
848 //fprintf(stdout,"%s\n",argv[i]);
850 if (passon_args_flag) { /* if true, pass on args to simulator */
851 simArgs[nsimArgs++] = strdup(argv[i]);
855 /* if this is an option */
856 if (argv[i][0] == '-') {
858 /* if directory then mark directory */
859 if (strncmp(argv[i],"--directory=",12) == 0) {
861 ssdirl = &argv[i][12];
863 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
864 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
870 if (strncmp(argv[i],"-fullname",9) == 0) {
875 if (strcmp(argv[i],"-cd") == 0) {
881 if (strncmp(argv[i],"-cd=",4) == 0) {
887 if (strncmp(argv[i],"-d=",3) == 0) {
888 sdcdbDebug = strtol(&argv[i][3],0,0);
894 if (strncmp(argv[i],"-m",2) == 0) {
895 strncpy(model_str, &argv[i][2], 15);
896 if (strcmp(model_str,"avr") == 0)
898 else if (strcmp(model_str,"xa") == 0)
900 else if (strcmp(model_str,"z80") == 0)
905 /* -z all remaining options are for simulator */
906 if (strcmp(argv[i],"-z") == 0) {
907 passon_args_flag = 1;
911 /* the simulator arguments */
914 if (strcmp(argv[i],"-t") == 0 ||
915 strcmp(argv[i],"-cpu") == 0) {
917 simArgs[nsimArgs++] = "-t";
918 simArgs[nsimArgs++] = strdup(argv[++i]);
923 if (strcmp(argv[i],"-X") == 0 ||
924 strcmp(argv[i],"-frequency") == 0) {
925 simArgs[nsimArgs++] = "-X";
926 simArgs[nsimArgs++] = strdup(argv[++i]);
931 if ( (strcmp(argv[i],"-S") == 0) ||
932 (strcmp(argv[i],"-s") == 0)) {
933 simArgs[nsimArgs++] = "-s";
934 simArgs[nsimArgs++] = strdup(argv[++i]);
938 fprintf(stderr,"unknown option %s --- ignored\n",
942 /* must be file name */
944 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
949 filename = strtok(argv[i],".");
955 cmdFile(filename,NULL);
958 /*-----------------------------------------------------------------*/
959 /* setsignals - catch some signals */
960 /*-----------------------------------------------------------------*/
973 /* may be interrupt from user: stop debugger and also simulator */
978 /* the only child can be the simulator */
979 static void sigchld(int sig)
981 /* the only child can be the simulator */
983 retpid = wait ( &status );
984 /* if ( retpid == simPid ) */
991 signal(SIGHUP , bad_signal);
992 signal(SIGINT , sigintr );
993 signal(SIGTERM, bad_signal);
994 signal(SIGCHLD, sigchld );
996 signal(SIGABRT, bad_signal);
997 signal(SIGALRM, bad_signal);
998 signal(SIGFPE, bad_signal);
999 signal(SIGILL, bad_signal);
1000 signal(SIGPIPE, bad_signal);
1001 signal(SIGQUIT, bad_signal);
1002 signal(SIGSEGV, bad_signal);
1005 /*-----------------------------------------------------------------*/
1007 /*-----------------------------------------------------------------*/
1009 int main ( int argc, char **argv)
1012 printf("WARNING: SDCDB is EXPERIMENTAL.\n");
1014 simArgs[nsimArgs++] = "s51";
1015 simArgs[nsimArgs++] = "-P";
1016 simArgs[nsimArgs++] = "-r 9756";
1017 /* parse command line */
1020 parseCmdLine(argc,argv);