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 */
41 structdef **structs = NULL ; /* all structures */
43 linkrec **linkrecs = NULL; /* all linkage editor records */
44 context *currCtxt = NULL;
47 short userinterrupt = 0;
48 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ;
53 /* fake filename & lineno to make linker */
61 char *cmd ; /* command the user will enter */
62 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
63 char *htxt ; /* short help text */
66 /* NOTE:- the search is done from the top, so "break" should
67 precede the synonym "b" */
69 { "break" , cmdSetUserBp ,
70 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
72 { "b" , cmdSetUserBp , NULL },
74 { "clear" , cmdClrUserBp ,
75 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
77 { "cl" , cmdClrUserBp , NULL },
79 { "continue" , cmdContinue ,
80 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
82 { "c" , cmdContinue , NULL },
84 { "disassemble",cmdDisasmF , "x disassemble asm commands\n" },
85 { "delete" , cmdDelUserBp ,
86 "{d}elete n\t\t clears break point number n\n"
88 { "display" , cmdDisplay ,
89 "display [<variable>]\t print value of given variable each time the program stops\n"
91 { "undisplay" , cmdUnDisplay ,
92 "undisplay [<variable>]\t dont display this variable or all\n"
94 { "d" , cmdDelUserBp , NULL },
97 "info <break stack frame registers all-registers>\n"
98 "\t list all break points, call-stack, frame or register information\n"
101 { "listasm" , cmdListAsm ,
102 "listasm {la}\t\t list assembler code for the current C line\n"
104 { "la" , cmdListAsm , NULL },
105 { "ls" , cmdListSymbols , "ls,lf,lm\t\t list symbols,functions,modules\n" },
106 { "lf" , cmdListFunctions, NULL },
107 { "lm" , cmdListModules , NULL },
108 { "list" , cmdListSrc ,
109 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
111 { "l" , cmdListSrc , NULL },
114 " <copying warranty>\t copying & distribution terms, warranty\n"
116 { "set" , cmdSetOption , "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
118 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
120 { "s" , cmdStep , NULL },
122 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
124 { "n" , cmdNext , NULL },
126 "{r}un\t\t\t Start debugged program. \n"
128 { "r" , cmdRun , NULL },
129 { "ptype" , cmdPrintType ,
130 "{pt}ype <variable>\t print type information of a variable\n"
132 { "pt" , cmdPrintType , NULL },
133 { "print" , cmdPrint ,
134 "{p}rint <variable>\t print value of given variable\n"
136 { "output" , cmdOutput ,
137 "output <variable>\t print value of given variable without $ and newline \n"
139 { "p" , cmdPrint , NULL },
141 "file <filename>\t\t load symbolic information from <filename>\n"
143 { "frame" , cmdFrame ,
144 "{fr}ame\t\t\t print information about the current Stack\n"
146 { "finish" , cmdFinish ,
147 "{fi}nish\t\t execute till return of current function\n"
149 { "fi" , cmdFinish , NULL },
150 { "where" , cmdWhere , "where\t\t\t print stack\n" },
151 { "fr" , cmdFrame , NULL },
152 { "f" , cmdFrame , NULL },
153 { "x /i" , cmdDisasm1 , "x\t\t disassemble one asm command\n" },
154 { "!" , cmdSimulator ,
155 "!<simulator command>\t send a command directly to the simulator\n"
157 { "." , cmdSimulator ,
158 ".{cmd}\t switch from simulator or debugger command mode\n"
161 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
163 { "?" , cmdHelp , NULL },
164 { "h" , cmdHelp , NULL },
167 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
169 { "q" , cmdQuit , NULL }
172 /*-----------------------------------------------------------------*/
173 /* gc_strdup - make a string duplicate garbage collector aware */
174 /*-----------------------------------------------------------------*/
175 char *gc_strdup(const char *s)
178 ret = Safe_malloc(strlen(s)+1);
183 /*-----------------------------------------------------------------*/
184 /* alloccpy - allocate copy and return a new string */
185 /*-----------------------------------------------------------------*/
186 char *alloccpy ( char *s, int size)
193 d = Safe_malloc(size+1);
200 /*-----------------------------------------------------------------*/
201 /* resize - resizes array of type with new size */
202 /*-----------------------------------------------------------------*/
203 void **resize (void **array, int newSize)
208 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
210 vptr = calloc(1, sizeof(void **));
213 fprintf(stderr,"sdcdb: out of memory \n");
221 /*-----------------------------------------------------------------*/
222 /* readCdb - reads the cdb files & puts the records into cdbLine */
224 /*-----------------------------------------------------------------*/
225 static int readCdb (FILE *file)
231 if (!(bp = fgets(buffer,sizeof(buffer),file)))
234 currl = Safe_calloc(1,sizeof(cdbrecs));
239 /* make sure this is a cdb record */
240 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
241 /* depending on the record type */
246 currl->type = SYM_REC;
249 currl->type = STRUCT_REC;
252 currl->type = LNK_REC;
255 currl->type = FUNC_REC;
258 currl->type = MOD_REC ;
262 currl->line = Safe_malloc(strlen(bp));
263 strncpy(currl->line,bp,strlen(bp)-1);
264 currl->line[strlen(bp)-1] = '\0';
267 if (!(bp = fgets(buffer,sizeof(buffer),file)))
273 currl->next = Safe_calloc(1,sizeof(cdbrecs));
277 return (recsRoot->line ? 1 : 0);
280 /*-----------------------------------------------------------------*/
281 /* searchDirsFname - search directory list & return the filename */
282 /*-----------------------------------------------------------------*/
283 char *searchDirsFname (char *fname)
289 /* first try the current directory */
290 if ((rfile = fopen(fname,"r"))) {
292 return strdup(fname) ;
296 return strdup(fname);
298 /* make a copy of the source directories */
299 dirs = sdirs = strdup(ssdirl);
301 /* assume that the separator is ':'
302 and try for each directory in the search list */
303 dirs = strtok(dirs,":");
305 if (dirs[strlen(dirs)] == '/')
306 sprintf(buffer,"%s%s",dirs,fname);
308 sprintf(buffer,"%s/%s",dirs,fname);
309 if ((rfile = fopen(buffer,"r")))
311 dirs = strtok(NULL,":");
317 return strdup(buffer);
319 return strdup(fname);
322 /*-----------------------------------------------------------------*/
323 /* searchDirsFopen - go thru list of directories for filename given*/
324 /*-----------------------------------------------------------------*/
325 FILE *searchDirsFopen(char *fname)
331 /* first try the current directory */
332 if ((rfile = fopen(fname,"r")))
337 /* make a copy of the source directories */
338 dirs = sdirs = strdup(ssdirl);
340 /* assume that the separator is ':'
341 and try for each directory in the search list */
342 dirs = strtok(dirs,":");
344 sprintf(buffer,"%s/%s",dirs,fname);
345 if ((rfile = fopen(buffer,"r")))
347 dirs = strtok(NULL,":");
355 /*-----------------------------------------------------------------*/
356 /* loadFile - loads a file into module buffer */
357 /*-----------------------------------------------------------------*/
358 srcLine **loadFile (char *name, int *nlines)
363 srcLine **slines = NULL;
366 if (!(mfile = searchDirsFopen(name))) {
367 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
371 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
374 slines = (srcLine **)resize((void **)slines,*nlines);
376 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
377 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
385 /*-----------------------------------------------------------------*/
386 /* loadModules - reads the source files into module structure */
387 /*-----------------------------------------------------------------*/
388 static void loadModules ()
394 /* go thru the records & find out the module
395 records & load the modules specified */
396 for ( loop = recsRoot ; loop ; loop = loop->next ) {
398 switch (loop->type) {
399 /* for module records do */
401 currMod = parseModule(loop->line,TRUE);
402 currModName = currMod->name ;
404 currMod->cfullname = searchDirsFname(currMod->c_name);
406 /* load it into buffer */
407 currMod->cLines = loadFile (currMod->c_name,
410 /* do the same for the assembler file */
411 currMod->afullname = searchDirsFname(currMod->asm_name);
412 currMod->asmLines=loadFile (currMod->asm_name,
413 &currMod->nasmLines);
416 /* if this is a function record */
418 parseFunc(loop->line);
421 /* if this is a structure record */
423 parseStruct(loop->line);
426 /* if symbol then parse the symbol */
428 parseSymbol(loop->line,&rs);
432 parseLnkRec(loop->line);
438 /*-----------------------------------------------------------------*/
439 /* functionPoints - determine the execution points within a func */
440 /*-----------------------------------------------------------------*/
441 static void functionPoints ()
446 /* for all functions do */
447 for ( func = setFirstItem(functions); func;
448 func = setNextItem(functions)) {
454 Dprintf(D_sdcdb, ("sdcdb: func '%s' has entry '0x%x' exit '0x%x'\n",
459 if (!func->sym->addr && !func->sym->eaddr)
462 /* for all source lines in the module find
463 the ones with address >= start and <= end
464 and put them in the point */
466 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
469 func->entryline= INT_MAX;
471 func->aentryline = INT_MAX ;
474 /* do it for the C Lines first */
475 for ( j = 0 ; j < mod->ncLines ; j++ ) {
476 if (mod->cLines[j]->addr >= sym->addr &&
477 mod->cLines[j]->addr <= sym->eaddr ) {
481 /* add it to the execution point */
482 if (func->entryline > j)
485 if (func->exitline < j)
488 ep = Safe_calloc(1,sizeof(exePoint));
489 ep->addr = mod->cLines[j]->addr ;
491 ep->block= mod->cLines[j]->block;
492 ep->level= mod->cLines[j]->level;
493 addSet(&func->cfpoints,ep);
497 /* do the same for asm execution points */
498 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
499 if (mod->asmLines[j]->addr >= sym->addr &&
500 mod->asmLines[j]->addr <= sym->eaddr ) {
503 /* add it to the execution point */
504 if (func->aentryline > j)
505 func->aentryline = j;
507 if (func->aexitline < j)
510 /* add it to the execution point */
511 ep = Safe_calloc(1,sizeof(exePoint));
512 ep->addr = mod->asmLines[j]->addr ;
514 addSet(&func->afpoints,ep);
519 if (!( D_sdcdb & sdcdbDebug))
522 Dprintf(D_sdcdb, ("sdcdb: function '%s' has the following C exePoints\n",
527 for (ep = setFirstItem(func->cfpoints); ep;
528 ep = setNextItem(func->cfpoints))
529 Dprintf(D_sdcdb, ("sdcdb: {0x%x,%d} %s",
530 ep->addr,ep->line,mod->cLines[ep->line]->src));
532 Dprintf(D_sdcdb, ("sdcdb: and the following ASM exePoints\n"));
533 for (ep = setFirstItem(func->afpoints); ep;
534 ep = setNextItem(func->afpoints))
535 Dprintf (D_sdcdb, ("sdcdb: {0x%x,%d} %s",
536 ep->addr,ep->line,mod->asmLines[ep->line]->src));
543 /*-----------------------------------------------------------------*/
544 /* setEntryExitBP - set the entry & exit Break Points for functions*/
545 /*-----------------------------------------------------------------*/
546 DEFSETFUNC(setEntryExitBP)
548 function *func = item;
550 if (func->sym && func->sym->addr && func->sym->eaddr) {
552 /* set the entry break point */
553 setBreakPoint (func->sym->addr , CODE , FENTRY ,
554 fentryCB ,func->mod->c_name , func->entryline);
556 /* set the exit break point */
557 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
558 fexitCB ,func->mod->c_name , func->exitline );
564 /*-----------------------------------------------------------------*/
565 /* cmdFile - load file into the debugger */
566 /*-----------------------------------------------------------------*/
567 int cmdFile (char *s,context *cctxt)
573 while (isspace(*s)) s++;
575 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
579 sprintf(buffer,"%s.cdb",s);
580 /* try creating the cdbfile */
581 if (!(cdbFile = searchDirsFopen(buffer))) {
582 fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
586 /* allocate for context */
587 currCtxt = Safe_calloc(1,sizeof(context));
590 /* readin the debug information */
591 if (!readCdb (cdbFile)) {
592 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
597 /* parse and load the modules required */
600 /* determine the execution points for this
604 /* start the simulator & setup connection to it */
606 openSimulator((char **)simArgs,nsimArgs);
607 fprintf(stdout,"%s",simResponse());
608 /* now send the filename to be loaded to the simulator */
609 sprintf(buffer,"%s.ihx",s);
610 bp=searchDirsFname(buffer);
614 /*set the break points
615 required by the debugger . i.e. the function entry
616 and function exit break points */
617 applyToSet(functions,setEntryExitBP);
623 /*-----------------------------------------------------------------*/
624 /* cmdHelp - help command */
625 /*-----------------------------------------------------------------*/
626 int cmdHelp (char *s, context *cctxt)
635 endline = ((*s - '0') * 20) + 20;
637 startline = endline - 20;
641 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
643 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
644 fprintf(stdout,"%s",cmdTab[i].htxt);
649 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
651 /* command string matches */
653 if ((cmdTab[i].htxt) && (i >= startline))
654 fprintf(stdout,"%s",cmdTab[i].htxt);
662 #define MAX_CMD_LEN 512
663 static char cmdbuff[MAX_CMD_LEN];
664 static int sim_cmd_mode = 0;
666 /*-----------------------------------------------------------------
667 interpretCmd - interpret and do the command. Return 0 to continue,
668 return 1 to exit program.
669 |-----------------------------------------------------------------*/
670 int interpretCmd (char *s)
672 static char *pcmd = NULL;
676 /* if nothing & previous command exists then
677 execute the previous command again */
678 if (*s == '\n' && pcmd)
681 /* if previous command exists & is different
682 from the current command then copy it */
684 if (strcmp(pcmd,s)) {
691 /* lookup the command table and do the task required */
695 if (strcmp(s,".") == 0) {
699 else if (s[0] == '.') {
700 /* kill the preceeding '.' and pass on as SDCDB command */
707 cmdSimulator (s, currCtxt);
711 if (strcmp(s,".") ==0) {
717 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
719 /* command string matches */
720 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
721 if (!cmdTab[i].cmdfunc)
724 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
726 /* if full name then give the file name & position */
727 if (fullname && showfull && currCtxt && currCtxt->func) {
729 if (srcMode == SRC_CMODE)
730 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
731 currCtxt->func->mod->cfullname,
732 currCtxt->cline,currCtxt->addr);
734 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
735 currCtxt->func->mod->afullname,
736 currCtxt->asmline,currCtxt->addr);
737 displayAll(currCtxt);
743 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
748 /*-----------------------------------------------------------------*/
749 /* commandLoop - the main command loop */
750 /*-----------------------------------------------------------------*/
753 char *prompt = "(sdcdb) ";
754 char *sim_prompt = "(sim) ";
758 printf("%s",sim_prompt);
760 fprintf(stdout,"%s",prompt);
764 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
768 /* make a way to go into "ucSim" mode */
769 if (cmdbuff[0] == '$') {
770 if (sim_cmd_mode) sim_cmd_mode = 0;
771 else sim_cmd_mode = 1;
776 if (interpretCmd(cmdbuff))
781 /*-----------------------------------------------------------------*/
782 /* printVersionInfo - print the version information */
783 /*-----------------------------------------------------------------*/
784 static void printVersionInfo()
787 "SDCDB is free software and you are welcome to distribute copies of it\n"
788 "under certain conditions; type \"show copying\" to see the conditions.\n"
789 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
790 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
791 "Type ? for help\n");
795 /*-----------------------------------------------------------------*/
796 /* parseCmdLine - parse the commandline arguments */
797 /*-----------------------------------------------------------------*/
798 static void parseCmdLine (int argc, char **argv)
801 char *filename = NULL;
802 int passon_args_flag = 0; /* if true, pass on args to simulator */
804 Dprintf(D_sdcdb, ("sdcdb: parseCmdLine\n"));
806 for ( i = 1; i < argc ; i++) {
807 //fprintf(stdout,"%s\n",argv[i]);
809 if (passon_args_flag) { /* if true, pass on args to simulator */
810 simArgs[nsimArgs++] = strdup(argv[i]);
814 /* if this is an option */
815 if (argv[i][0] == '-') {
817 /* if directory then mark directory */
818 if (strncmp(argv[i],"--directory=",12) == 0) {
820 ssdirl = &argv[i][12];
822 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
823 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
829 if (strncmp(argv[i],"-fullname",9) == 0) {
834 if (strcmp(argv[i],"-cd") == 0) {
840 if (strncmp(argv[i],"-cd=",4) == 0) {
846 if (strncmp(argv[i],"-d=",3) == 0) {
847 sdcdbDebug = strtol(&argv[i][3],0,0);
853 if (strncmp(argv[i],"-m",2) == 0) {
854 strncpy(model_str, &argv[i][2], 15);
855 if (strcmp(model_str,"avr") == 0)
857 else if (strcmp(model_str,"xa") == 0)
859 else if (strcmp(model_str,"z80") == 0)
864 /* -z all remaining options are for simulator */
865 if (strcmp(argv[i],"-z") == 0) {
866 passon_args_flag = 1;
870 /* the simulator arguments */
873 if (strcmp(argv[i],"-t") == 0 ||
874 strcmp(argv[i],"-cpu") == 0) {
876 simArgs[nsimArgs++] = "-t";
877 simArgs[nsimArgs++] = strdup(argv[++i]);
882 if (strcmp(argv[i],"-X") == 0 ||
883 strcmp(argv[i],"-frequency") == 0) {
884 simArgs[nsimArgs++] = "-X";
885 simArgs[nsimArgs++] = strdup(argv[++i]);
890 if ( (strcmp(argv[i],"-S") == 0) ||
891 (strcmp(argv[i],"-s") == 0)) {
892 simArgs[nsimArgs++] = "-s";
893 simArgs[nsimArgs++] = strdup(argv[++i]);
897 fprintf(stderr,"unknown option %s --- ignored\n",
901 /* must be file name */
903 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
908 filename = strtok(argv[i],".");
914 cmdFile(filename,NULL);
917 /*-----------------------------------------------------------------*/
918 /* setsignals - catch some signals */
919 /*-----------------------------------------------------------------*/
932 /* may be interrupt from user: stop debugger and also simulator */
937 /* the only child can be the simulator */
938 static void sigchld(int sig)
940 /* the only child can be the simulator */
942 retpid = wait ( &status );
943 /* if ( retpid == simPid ) */
950 signal(SIGHUP , bad_signal);
951 signal(SIGINT , sigintr );
952 signal(SIGTERM, bad_signal);
953 signal(SIGCHLD, sigchld );
955 signal(SIGABRT, bad_signal);
956 signal(SIGALRM, bad_signal);
957 signal(SIGFPE, bad_signal);
958 signal(SIGILL, bad_signal);
959 signal(SIGPIPE, bad_signal);
960 signal(SIGQUIT, bad_signal);
961 signal(SIGSEGV, bad_signal);
964 /*-----------------------------------------------------------------*/
966 /*-----------------------------------------------------------------*/
968 int main ( int argc, char **argv)
971 printf("WARNING: SDCDB is EXPERIMENTAL.\n");
973 simArgs[nsimArgs++] = "s51";
974 simArgs[nsimArgs++] = "-P";
975 simArgs[nsimArgs++] = "-r 9756";
976 /* parse command line */
979 parseCmdLine(argc,argv);