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 char *currModName = NULL;
31 cdbrecs *recsRoot = NULL ;
32 set *modules = NULL; /* set of all modules */
33 set *functions = NULL ; /* set of functions */
34 set *symbols = NULL ; /* set of symbols */
36 structdef **structs = NULL ; /* all structures */
38 linkrec **linkrecs = NULL; /* all linkage editor records */
39 context *currCtxt = NULL;
41 char *ssdirl = SDCC_LIB_DIR ":" SDCC_LIB_DIR "/small" ;
45 /* fake filename & lineno to make linker */
53 char *cmd ; /* command the user will enter */
54 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
55 char *htxt ; /* short help text */
58 /* NOTE:- the search is done from the top, so "break" should
59 precede the synonym "b" */
61 { "break" , cmdSetUserBp ,
62 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
64 { "b" , cmdSetUserBp , NULL },
66 { "clear" , cmdClrUserBp ,
67 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
69 { "cl" , cmdClrUserBp , NULL },
71 { "continue" , cmdContinue ,
72 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
74 { "c" , cmdContinue , NULL },
76 { "delete" , cmdDelUserBp ,
77 "{d}elete n\t\t clears break point number n\n"
79 { "d" , cmdDelUserBp , NULL },
82 "{h|?}elp\t\t this message\n"
84 { "?" , cmdHelp , NULL },
85 { "h" , cmdHelp , NULL },
89 "\t {break}\t list all break points\n"
90 "\t {stack}\t information about call stack\n"
91 "\t {frame}\t current frame information\n"
92 "\t {registers}\t display value of all registers\n"
95 { "listasm" , cmdListAsm ,
96 "listasm {la}\t\t list assembler code for the current C line\n"
98 { "la" , cmdListAsm , NULL },
99 { "list" , cmdListSrc ,
100 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
102 { "l" , cmdListSrc , NULL },
105 "\t {copying}\t copying & distribution terms\n"
106 "\t {warranty}\t warranty information\n"
108 { "set" , cmdSetOption , NULL },
110 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
112 { "s" , cmdStep , NULL },
114 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
116 { "n" , cmdNext , NULL },
118 "{r}un\t\t\t Start debugged program. \n"
120 { "r" , cmdRun , NULL },
121 { "ptype" , cmdPrintType ,
122 "{pt}ype <variable>\t print type information of a variable\n"
124 { "pt" , cmdPrintType , NULL },
125 { "print" , cmdPrint ,
126 "{p}rint <variable>\t print value of given variable\n"
128 { "p" , cmdPrint , NULL },
130 "file <filename>\t\t load symbolic information from <filename>\n"
132 { "frame" , cmdFrame ,
133 "{fr}ame\t\t\t print information about the current Stack\n"
135 { "finish" , cmdFinish ,
136 "{fi}nish\t\t execute till return of current function\n"
138 { "fi" , cmdFinish , NULL },
139 { "fr" , cmdFrame , NULL },
140 { "f" , cmdFrame , NULL },
141 { "!" , cmdSimulator ,
142 "!<simulator command>\t send a command directly to the simulator\n"
145 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
147 { "q" , cmdQuit , NULL }
150 /*-----------------------------------------------------------------*/
151 /* gc_strdup - make a string duplicate garbage collector aware */
152 /*-----------------------------------------------------------------*/
153 char *gc_strdup(const char *s)
156 ALLOC_ATOMIC(ret, strlen(s)+1);
161 /*-----------------------------------------------------------------*/
162 /* alloccpy - allocate copy and return a new string */
163 /*-----------------------------------------------------------------*/
164 char *alloccpy ( char *s, int size)
178 /*-----------------------------------------------------------------*/
179 /* resize - resizes array of type with new size */
180 /*-----------------------------------------------------------------*/
181 void **resize (void **array, int newSize)
186 vptr = GC_realloc(array,newSize*(sizeof(void **)));
188 vptr = GC_malloc(sizeof(void **));
191 fprintf(stderr,"sdcdb: out of memory \n");
199 /*-----------------------------------------------------------------*/
200 /* readCdb - reads the cdb files & puts the records into cdbLine */
202 /*-----------------------------------------------------------------*/
203 static int readCdb (FILE *file)
209 if (!(bp = fgets(buffer,sizeof(buffer),file)))
212 ALLOC(currl,sizeof(cdbrecs));
217 /* make sure this is a cdb record */
218 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
219 /* depending on the record type */
224 currl->type = SYM_REC;
227 currl->type = STRUCT_REC;
230 currl->type = LNK_REC;
233 currl->type = FUNC_REC;
236 currl->type = MOD_REC ;
240 ALLOC(currl->line,strlen(bp));
241 strncpy(currl->line,bp,strlen(bp)-1);
242 currl->line[strlen(bp)-1] = '\0';
245 if (!(bp = fgets(buffer,sizeof(buffer),file)))
251 ALLOC(currl->next,sizeof(cdbrecs));
255 return (recsRoot->line ? 1 : 0);
258 /*-----------------------------------------------------------------*/
259 /* searchDirsFname - search directory list & return the filename */
260 /*-----------------------------------------------------------------*/
261 char *searchDirsFname (char *fname)
267 /* first try the current directory */
268 if ((rfile = fopen(fname,"r"))) {
270 return strdup(fname) ;
274 return strdup(fname);
276 /* make a copy of the source directories */
277 dirs = sdirs = strdup(ssdirl);
279 /* assume that the separator is ':'
280 and try for each directory in the search list */
281 dirs = strtok(dirs,":");
283 if (dirs[strlen(dirs)] == '/')
284 sprintf(buffer,"%s%s",dirs,fname);
286 sprintf(buffer,"%s/%s",dirs,fname);
287 if ((rfile = fopen(buffer,"r")))
289 dirs = strtok(NULL,":");
295 return strdup(buffer);
297 return strdup(fname);
300 /*-----------------------------------------------------------------*/
301 /* searchDirsFopen - go thru list of directories for filename given*/
302 /*-----------------------------------------------------------------*/
303 FILE *searchDirsFopen(char *fname)
309 /* first try the current directory */
310 if ((rfile = fopen(fname,"r")))
315 /* make a copy of the source directories */
316 dirs = sdirs = strdup(ssdirl);
318 /* assume that the separator is ':'
319 and try for each directory in the search list */
320 dirs = strtok(dirs,":");
322 sprintf(buffer,"%s/%s",dirs,fname);
323 if ((rfile = fopen(buffer,"r")))
325 dirs = strtok(NULL,":");
333 /*-----------------------------------------------------------------*/
334 /* loadFile - loads a file into module buffer */
335 /*-----------------------------------------------------------------*/
336 srcLine **loadFile (char *name, int *nlines)
341 srcLine **slines = NULL;
344 if (!(mfile = searchDirsFopen(name))) {
345 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
349 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
352 slines = (srcLine **)resize((void **)slines,*nlines);
354 ALLOC(slines[(*nlines)-1],sizeof(srcLine));
355 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
363 /*-----------------------------------------------------------------*/
364 /* loadModules - reads the source files into module structure */
365 /*-----------------------------------------------------------------*/
366 static void loadModules ()
372 /* go thru the records & find out the module
373 records & load the modules specified */
374 for ( loop = recsRoot ; loop ; loop = loop->next ) {
376 switch (loop->type) {
377 /* for module records do */
379 currMod = parseModule(loop->line,TRUE);
380 currModName = currMod->name ;
382 currMod->cfullname = searchDirsFname(currMod->c_name);
384 /* load it into buffer */
385 currMod->cLines = loadFile (currMod->c_name,
388 /* do the same for the assembler file */
389 currMod->afullname = searchDirsFname(currMod->asm_name);
390 currMod->asmLines=loadFile (currMod->asm_name,
391 &currMod->nasmLines);
394 /* if this is a function record */
396 parseFunc(loop->line);
399 /* if this is a structure record */
401 parseStruct(loop->line);
404 /* if symbol then parse the symbol */
406 parseSymbol(loop->line,&rs);
410 parseLnkRec(loop->line);
416 /*-----------------------------------------------------------------*/
417 /* functionPoints - determine the execution points within a func */
418 /*-----------------------------------------------------------------*/
419 static void functionPoints ()
424 /* for all functions do */
425 for ( func = setFirstItem(functions); func;
426 func = setNextItem(functions)) {
433 printf("func '%s' has entry '%x' exit '%x'\n",
438 if (!func->sym->addr && !func->sym->eaddr)
441 /* for all source lines in the module find
442 the ones with address >= start and <= end
443 and put them in the point */
445 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
448 func->entryline= INT_MAX;
450 func->aentryline = INT_MAX ;
453 /* do it for the C Lines first */
454 for ( j = 0 ; j < mod->ncLines ; j++ ) {
455 if (mod->cLines[j]->addr >= sym->addr &&
456 mod->cLines[j]->addr <= sym->eaddr ) {
460 /* add it to the execution point */
461 if (func->entryline > j)
464 if (func->exitline < j)
467 ALLOC(ep,sizeof(exePoint));
468 ep->addr = mod->cLines[j]->addr ;
470 ep->block= mod->cLines[j]->block;
471 ep->level= mod->cLines[j]->level;
472 addSet(&func->cfpoints,ep);
476 /* do the same for asm execution points */
477 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
478 if (mod->asmLines[j]->addr >= sym->addr &&
479 mod->asmLines[j]->addr <= sym->eaddr ) {
482 /* add it to the execution point */
483 if (func->aentryline > j)
484 func->aentryline = j;
486 if (func->aexitline < j)
489 /* add it to the execution point */
490 ALLOC(ep,sizeof(exePoint));
491 ep->addr = mod->asmLines[j]->addr ;
493 addSet(&func->afpoints,ep);
498 printf("function '%s' has the following C exePoints\n",
503 for (ep = setFirstItem(func->cfpoints); ep;
504 ep = setNextItem(func->cfpoints))
505 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->cLines[ep->line]->src);
507 fprintf(stdout," and the following ASM exePoints\n");
508 for (ep = setFirstItem(func->afpoints); ep;
509 ep = setNextItem(func->afpoints))
510 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->asmLines[ep->line]->src);
518 /*-----------------------------------------------------------------*/
519 /* setEntryExitBP - set the entry & exit Break Points for functions*/
520 /*-----------------------------------------------------------------*/
521 DEFSETFUNC(setEntryExitBP)
523 function *func = item;
525 if (func->sym && func->sym->addr && func->sym->eaddr) {
527 /* set the entry break point */
528 setBreakPoint (func->sym->addr , CODE , FENTRY ,
529 fentryCB ,func->mod->c_name , func->entryline);
531 /* set the exit break point */
532 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
533 fexitCB ,func->mod->c_name , func->exitline );
539 /*-----------------------------------------------------------------*/
540 /* cmdFile - load file into the debugger */
541 /*-----------------------------------------------------------------*/
542 int cmdFile (char *s,context *cctxt)
548 while (isspace(*s)) s++;
550 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
554 sprintf(buffer,"%s.cdb",s);
555 /* try creating the cdbfile */
556 if (!(cdbFile = searchDirsFopen(buffer))) {
557 fprintf(stdout,"Cannot open file\"%s\"",buffer);
561 /* allocate for context */
562 ALLOC(currCtxt ,sizeof(context));
564 /* readin the debug information */
565 if (!readCdb (cdbFile)) {
566 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
570 /* parse and load the modules required */
573 /* determine the execution points for this
577 /* start the simulator & setup connection to it */
578 openSimulator((char **)simArgs,nsimArgs);
579 fprintf(stdout,"%s",simResponse());
580 /* now send the filename to be loaded to the simulator */
581 sprintf(buffer,"%s.ihx",s);
582 bp=searchDirsFname(buffer);
586 /*set the break points
587 required by the debugger . i.e. the function entry
588 and function exit break points */
589 applyToSet(functions,setEntryExitBP);
595 /*-----------------------------------------------------------------*/
596 /* cmdHelp - help command */
597 /*-----------------------------------------------------------------*/
598 int cmdHelp (char *s, context *cctxt)
602 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
604 /* command string matches */
606 fprintf(stdout,"%s",cmdTab[i].htxt);
612 #define MAX_CMD_LEN 512
613 char *prompt = "(sdcdb) ";
614 char cmdbuff[MAX_CMD_LEN];
616 /*-----------------------------------------------------------------*/
617 /* interpretCmd - interpret and do the command */
618 /*-----------------------------------------------------------------*/
619 int interpretCmd (char *s)
621 static char *pcmd = NULL;
624 /* if nothing & previous command exists then
625 execute the previous command again */
626 if (*s == '\n' && pcmd)
628 /* if previous command exists & is different
629 from the current command then copy it */
631 if (strcmp(pcmd,s)) {
637 /* lookup the command table and do the
641 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
643 /* command string matches */
644 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
645 if (!cmdTab[i].cmdfunc)
647 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
649 /* if full name then give the file name & position */
650 if (fullname && currCtxt && currCtxt->func) {
651 if (srcMode == SRC_CMODE)
652 fprintf(stdout,"\032\032%s:%d:1\n",
653 currCtxt->func->mod->cfullname,
656 fprintf(stdout,"\032\032%s:%d:1\n",
657 currCtxt->func->mod->afullname,
658 currCtxt->asmline+1);
664 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
669 /*-----------------------------------------------------------------*/
670 /* commandLoop - the main command loop */
671 /*-----------------------------------------------------------------*/
676 fprintf(stdout,"%s",prompt);
679 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
682 if (interpretCmd(cmdbuff))
688 /*-----------------------------------------------------------------*/
689 /* printVersionInfo - print the version information */
690 /*-----------------------------------------------------------------*/
691 static void printVersionInfo()
694 "SDCDB is free software and you are welcome to distribute copies of it\n"
695 "under certain conditions; type \"show copying\" to see the conditions.\n"
696 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
697 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
698 "Type ? for help\n");
702 /*-----------------------------------------------------------------*/
703 /* parseCmdLine - parse the commandline arguments */
704 /*-----------------------------------------------------------------*/
705 static void parseCmdLine (int argc, char **argv)
708 char *filename = NULL;
710 for ( i = 1; i < argc ; i++) {
711 fprintf(stdout,"%s\n",argv[i]);
713 /* if this is an option */
714 if (argv[i][0] == '-') {
716 /* if directory then mark directory */
717 if (strncmp(argv[i],"--directory=",12) == 0) {
719 ssdirl = &argv[i][12];
721 char *p = malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
722 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
728 if (strncmp(argv[i],"-fullname",9) == 0) {
733 if (strcmp(argv[i],"-cd") == 0) {
739 if (strncmp(argv[i],"-cd=",4) == 0) {
744 /* the simulator arguments */
747 if (strcmp(argv[i],"-t") == 0 ||
748 strcmp(argv[i],"-cpu") == 0) {
750 simArgs[nsimArgs++] = "-t";
751 simArgs[nsimArgs++] = strdup(argv[++i]);
756 if (strcmp(argv[i],"-X") == 0 ||
757 strcmp(argv[i],"-frequency") == 0) {
758 simArgs[nsimArgs++] = "-X";
759 simArgs[nsimArgs++] = strdup(argv[++i]);
764 if (strcmp(argv[i],"-s") == 0) {
765 simArgs[nsimArgs++] = "-s";
766 simArgs[nsimArgs++] = strdup(argv[++i]);
770 if (strcmp(argv[i],"-S") == 0) {
771 simArgs[nsimArgs++] = "-s";
772 simArgs[nsimArgs++] = strdup(argv[++i]);
776 fprintf(stderr,"unknown option %s --- ignored\n",
779 /* must be file name */
781 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
786 filename = strtok(argv[i],".");
792 cmdFile(filename,NULL);
795 /*-----------------------------------------------------------------*/
797 /*-----------------------------------------------------------------*/
799 int main ( int argc, char **argv)
802 /* parse command line */
803 parseCmdLine(argc,argv);