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 -------------------------------------------------------------------------*/
31 char *currModName = NULL;
32 cdbrecs *recsRoot = NULL ;
33 set *modules = NULL; /* set of all modules */
34 set *functions = NULL ; /* set of functions */
35 set *symbols = NULL ; /* set of symbols */
37 structdef **structs = NULL ; /* all structures */
39 linkrec **linkrecs = NULL; /* all linkage editor records */
40 context *currCtxt = NULL;
42 char *ssdirl = SDCC_LIB_DIR ":" SDCC_LIB_DIR "/small" ;
46 /* fake filename & lineno to make linker */
54 char *cmd ; /* command the user will enter */
55 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
56 char *htxt ; /* short help text */
59 /* NOTE:- the search is done from the top, so "break" should
60 precede the synonym "b" */
62 { "break" , cmdSetUserBp ,
63 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
65 { "b" , cmdSetUserBp , NULL },
67 { "clear" , cmdClrUserBp ,
68 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
70 { "cl" , cmdClrUserBp , NULL },
72 { "continue" , cmdContinue ,
73 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
75 { "c" , cmdContinue , NULL },
77 { "delete" , cmdDelUserBp ,
78 "{d}elete n\t\t clears break point number n\n"
80 { "d" , cmdDelUserBp , NULL },
83 "{h|?}elp\t\t this message\n"
85 { "?" , cmdHelp , NULL },
86 { "h" , cmdHelp , NULL },
90 "\t {break}\t list all break points\n"
91 "\t {stack}\t information about call stack\n"
92 "\t {frame}\t current frame information\n"
93 "\t {registers}\t display value of all registers\n"
96 { "listasm" , cmdListAsm ,
97 "listasm {la}\t\t list assembler code for the current C line\n"
99 { "la" , cmdListAsm , NULL },
100 { "list" , cmdListSrc ,
101 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
103 { "l" , cmdListSrc , NULL },
106 "\t {copying}\t copying & distribution terms\n"
107 "\t {warranty}\t warranty information\n"
109 { "set" , cmdSetOption , NULL },
111 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
113 { "s" , cmdStep , NULL },
115 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
117 { "n" , cmdNext , NULL },
119 "{r}un\t\t\t Start debugged program. \n"
121 { "r" , cmdRun , NULL },
122 { "ptype" , cmdPrintType ,
123 "{pt}ype <variable>\t print type information of a variable\n"
125 { "pt" , cmdPrintType , NULL },
126 { "print" , cmdPrint ,
127 "{p}rint <variable>\t print value of given variable\n"
129 { "p" , cmdPrint , NULL },
131 "file <filename>\t\t load symbolic information from <filename>\n"
133 { "frame" , cmdFrame ,
134 "{fr}ame\t\t\t print information about the current Stack\n"
136 { "finish" , cmdFinish ,
137 "{fi}nish\t\t execute till return of current function\n"
139 { "fi" , cmdFinish , NULL },
140 { "fr" , cmdFrame , NULL },
141 { "f" , cmdFrame , NULL },
142 { "!" , cmdSimulator ,
143 "!<simulator command>\t send a command directly to the simulator\n"
146 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
148 { "q" , cmdQuit , NULL }
151 /*-----------------------------------------------------------------*/
152 /* gc_strdup - make a string duplicate garbage collector aware */
153 /*-----------------------------------------------------------------*/
154 char *gc_strdup(const char *s)
157 ret = Safe_malloc(strlen(s)+1);
162 /*-----------------------------------------------------------------*/
163 /* alloccpy - allocate copy and return a new string */
164 /*-----------------------------------------------------------------*/
165 char *alloccpy ( char *s, int size)
172 d = Safe_malloc(size+1);
179 /*-----------------------------------------------------------------*/
180 /* resize - resizes array of type with new size */
181 /*-----------------------------------------------------------------*/
182 void **resize (void **array, int newSize)
187 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
189 vptr = calloc(1, sizeof(void **));
192 fprintf(stderr,"sdcdb: out of memory \n");
200 /*-----------------------------------------------------------------*/
201 /* readCdb - reads the cdb files & puts the records into cdbLine */
203 /*-----------------------------------------------------------------*/
204 static int readCdb (FILE *file)
210 if (!(bp = fgets(buffer,sizeof(buffer),file)))
213 currl = Safe_calloc(1,sizeof(cdbrecs));
218 /* make sure this is a cdb record */
219 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
220 /* depending on the record type */
225 currl->type = SYM_REC;
228 currl->type = STRUCT_REC;
231 currl->type = LNK_REC;
234 currl->type = FUNC_REC;
237 currl->type = MOD_REC ;
241 currl->line = Safe_calloc(1,strlen(bp));
242 strncpy(currl->line,bp,strlen(bp)-1);
243 currl->line[strlen(bp)-1] = '\0';
246 if (!(bp = fgets(buffer,sizeof(buffer),file)))
252 currl->next = Safe_calloc(1,sizeof(cdbrecs));
256 return (recsRoot->line ? 1 : 0);
259 /*-----------------------------------------------------------------*/
260 /* searchDirsFname - search directory list & return the filename */
261 /*-----------------------------------------------------------------*/
262 char *searchDirsFname (char *fname)
268 /* first try the current directory */
269 if ((rfile = fopen(fname,"r"))) {
271 return strdup(fname) ;
275 return strdup(fname);
277 /* make a copy of the source directories */
278 dirs = sdirs = strdup(ssdirl);
280 /* assume that the separator is ':'
281 and try for each directory in the search list */
282 dirs = strtok(dirs,":");
284 if (dirs[strlen(dirs)] == '/')
285 sprintf(buffer,"%s%s",dirs,fname);
287 sprintf(buffer,"%s/%s",dirs,fname);
288 if ((rfile = fopen(buffer,"r")))
290 dirs = strtok(NULL,":");
296 return strdup(buffer);
298 return strdup(fname);
301 /*-----------------------------------------------------------------*/
302 /* searchDirsFopen - go thru list of directories for filename given*/
303 /*-----------------------------------------------------------------*/
304 FILE *searchDirsFopen(char *fname)
310 /* first try the current directory */
311 if ((rfile = fopen(fname,"r")))
316 /* make a copy of the source directories */
317 dirs = sdirs = strdup(ssdirl);
319 /* assume that the separator is ':'
320 and try for each directory in the search list */
321 dirs = strtok(dirs,":");
323 sprintf(buffer,"%s/%s",dirs,fname);
324 if ((rfile = fopen(buffer,"r")))
326 dirs = strtok(NULL,":");
334 /*-----------------------------------------------------------------*/
335 /* loadFile - loads a file into module buffer */
336 /*-----------------------------------------------------------------*/
337 srcLine **loadFile (char *name, int *nlines)
342 srcLine **slines = NULL;
345 if (!(mfile = searchDirsFopen(name))) {
346 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
350 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
353 slines = (srcLine **)resize((void **)slines,*nlines);
355 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
356 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
364 /*-----------------------------------------------------------------*/
365 /* loadModules - reads the source files into module structure */
366 /*-----------------------------------------------------------------*/
367 static void loadModules ()
373 /* go thru the records & find out the module
374 records & load the modules specified */
375 for ( loop = recsRoot ; loop ; loop = loop->next ) {
377 switch (loop->type) {
378 /* for module records do */
380 currMod = parseModule(loop->line,TRUE);
381 currModName = currMod->name ;
383 currMod->cfullname = searchDirsFname(currMod->c_name);
385 /* load it into buffer */
386 currMod->cLines = loadFile (currMod->c_name,
389 /* do the same for the assembler file */
390 currMod->afullname = searchDirsFname(currMod->asm_name);
391 currMod->asmLines=loadFile (currMod->asm_name,
392 &currMod->nasmLines);
395 /* if this is a function record */
397 parseFunc(loop->line);
400 /* if this is a structure record */
402 parseStruct(loop->line);
405 /* if symbol then parse the symbol */
407 parseSymbol(loop->line,&rs);
411 parseLnkRec(loop->line);
417 /*-----------------------------------------------------------------*/
418 /* functionPoints - determine the execution points within a func */
419 /*-----------------------------------------------------------------*/
420 static void functionPoints ()
425 /* for all functions do */
426 for ( func = setFirstItem(functions); func;
427 func = setNextItem(functions)) {
434 printf("func '%s' has entry '%x' exit '%x'\n",
439 if (!func->sym->addr && !func->sym->eaddr)
442 /* for all source lines in the module find
443 the ones with address >= start and <= end
444 and put them in the point */
446 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
449 func->entryline= INT_MAX;
451 func->aentryline = INT_MAX ;
454 /* do it for the C Lines first */
455 for ( j = 0 ; j < mod->ncLines ; j++ ) {
456 if (mod->cLines[j]->addr >= sym->addr &&
457 mod->cLines[j]->addr <= sym->eaddr ) {
461 /* add it to the execution point */
462 if (func->entryline > j)
465 if (func->exitline < j)
468 ep = Safe_calloc(1,sizeof(exePoint));
469 ep->addr = mod->cLines[j]->addr ;
471 ep->block= mod->cLines[j]->block;
472 ep->level= mod->cLines[j]->level;
473 addSet(&func->cfpoints,ep);
477 /* do the same for asm execution points */
478 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
479 if (mod->asmLines[j]->addr >= sym->addr &&
480 mod->asmLines[j]->addr <= sym->eaddr ) {
483 /* add it to the execution point */
484 if (func->aentryline > j)
485 func->aentryline = j;
487 if (func->aexitline < j)
490 /* add it to the execution point */
491 ep = Safe_calloc(1,sizeof(exePoint));
492 ep->addr = mod->asmLines[j]->addr ;
494 addSet(&func->afpoints,ep);
499 printf("function '%s' has the following C exePoints\n",
504 for (ep = setFirstItem(func->cfpoints); ep;
505 ep = setNextItem(func->cfpoints))
506 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->cLines[ep->line]->src);
508 fprintf(stdout," and the following ASM exePoints\n");
509 for (ep = setFirstItem(func->afpoints); ep;
510 ep = setNextItem(func->afpoints))
511 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->asmLines[ep->line]->src);
519 /*-----------------------------------------------------------------*/
520 /* setEntryExitBP - set the entry & exit Break Points for functions*/
521 /*-----------------------------------------------------------------*/
522 DEFSETFUNC(setEntryExitBP)
524 function *func = item;
526 if (func->sym && func->sym->addr && func->sym->eaddr) {
528 /* set the entry break point */
529 setBreakPoint (func->sym->addr , CODE , FENTRY ,
530 fentryCB ,func->mod->c_name , func->entryline);
532 /* set the exit break point */
533 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
534 fexitCB ,func->mod->c_name , func->exitline );
540 /*-----------------------------------------------------------------*/
541 /* cmdFile - load file into the debugger */
542 /*-----------------------------------------------------------------*/
543 int cmdFile (char *s,context *cctxt)
549 while (isspace(*s)) s++;
551 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
555 sprintf(buffer,"%s.cdb",s);
556 /* try creating the cdbfile */
557 if (!(cdbFile = searchDirsFopen(buffer))) {
558 fprintf(stdout,"Cannot open file\"%s\"",buffer);
562 /* allocate for context */
563 currCtxt = Safe_calloc(1,sizeof(context));
565 /* readin the debug information */
566 if (!readCdb (cdbFile)) {
567 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
571 /* parse and load the modules required */
574 /* determine the execution points for this
578 /* start the simulator & setup connection to it */
579 openSimulator((char **)simArgs,nsimArgs);
580 fprintf(stdout,"%s",simResponse());
581 /* now send the filename to be loaded to the simulator */
582 sprintf(buffer,"%s.ihx",s);
583 bp=searchDirsFname(buffer);
587 /*set the break points
588 required by the debugger . i.e. the function entry
589 and function exit break points */
590 applyToSet(functions,setEntryExitBP);
596 /*-----------------------------------------------------------------*/
597 /* cmdHelp - help command */
598 /*-----------------------------------------------------------------*/
599 int cmdHelp (char *s, context *cctxt)
603 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
605 /* command string matches */
607 fprintf(stdout,"%s",cmdTab[i].htxt);
613 #define MAX_CMD_LEN 512
614 char *prompt = "(sdcdb) ";
615 char cmdbuff[MAX_CMD_LEN];
617 /*-----------------------------------------------------------------*/
618 /* interpretCmd - interpret and do the command */
619 /*-----------------------------------------------------------------*/
620 int interpretCmd (char *s)
622 static char *pcmd = NULL;
625 /* if nothing & previous command exists then
626 execute the previous command again */
627 if (*s == '\n' && pcmd)
629 /* if previous command exists & is different
630 from the current command then copy it */
632 if (strcmp(pcmd,s)) {
638 /* lookup the command table and do the
642 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
644 /* command string matches */
645 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
646 if (!cmdTab[i].cmdfunc)
648 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
650 /* if full name then give the file name & position */
651 if (fullname && currCtxt && currCtxt->func) {
652 if (srcMode == SRC_CMODE)
653 fprintf(stdout,"\032\032%s:%d:1\n",
654 currCtxt->func->mod->cfullname,
657 fprintf(stdout,"\032\032%s:%d:1\n",
658 currCtxt->func->mod->afullname,
659 currCtxt->asmline+1);
665 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
670 /*-----------------------------------------------------------------*/
671 /* commandLoop - the main command loop */
672 /*-----------------------------------------------------------------*/
677 fprintf(stdout,"%s",prompt);
680 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
683 if (interpretCmd(cmdbuff))
689 /*-----------------------------------------------------------------*/
690 /* printVersionInfo - print the version information */
691 /*-----------------------------------------------------------------*/
692 static void printVersionInfo()
695 "SDCDB is free software and you are welcome to distribute copies of it\n"
696 "under certain conditions; type \"show copying\" to see the conditions.\n"
697 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
698 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
699 "Type ? for help\n");
703 /*-----------------------------------------------------------------*/
704 /* parseCmdLine - parse the commandline arguments */
705 /*-----------------------------------------------------------------*/
706 static void parseCmdLine (int argc, char **argv)
709 char *filename = NULL;
711 for ( i = 1; i < argc ; i++) {
712 fprintf(stdout,"%s\n",argv[i]);
714 /* if this is an option */
715 if (argv[i][0] == '-') {
717 /* if directory then mark directory */
718 if (strncmp(argv[i],"--directory=",12) == 0) {
720 ssdirl = &argv[i][12];
722 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
723 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
729 if (strncmp(argv[i],"-fullname",9) == 0) {
734 if (strcmp(argv[i],"-cd") == 0) {
740 if (strncmp(argv[i],"-cd=",4) == 0) {
745 /* the simulator arguments */
748 if (strcmp(argv[i],"-t") == 0 ||
749 strcmp(argv[i],"-cpu") == 0) {
751 simArgs[nsimArgs++] = "-t";
752 simArgs[nsimArgs++] = strdup(argv[++i]);
757 if (strcmp(argv[i],"-X") == 0 ||
758 strcmp(argv[i],"-frequency") == 0) {
759 simArgs[nsimArgs++] = "-X";
760 simArgs[nsimArgs++] = strdup(argv[++i]);
765 if (strcmp(argv[i],"-s") == 0) {
766 simArgs[nsimArgs++] = "-s";
767 simArgs[nsimArgs++] = strdup(argv[++i]);
771 if (strcmp(argv[i],"-S") == 0) {
772 simArgs[nsimArgs++] = "-s";
773 simArgs[nsimArgs++] = strdup(argv[++i]);
777 fprintf(stderr,"unknown option %s --- ignored\n",
780 /* must be file name */
782 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
787 filename = strtok(argv[i],".");
793 cmdFile(filename,NULL);
796 /*-----------------------------------------------------------------*/
798 /*-----------------------------------------------------------------*/
800 int main ( int argc, char **argv)
803 /* parse command line */
804 parseCmdLine(argc,argv);