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" ;
48 char *cmd ; /* command the user will enter */
49 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
50 char *htxt ; /* short help text */
53 /* NOTE:- the search is done from the top, so "break" should
54 precede the synonym "b" */
56 { "break" , cmdSetUserBp ,
57 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
59 { "b" , cmdSetUserBp , NULL },
61 { "clear" , cmdClrUserBp ,
62 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
64 { "cl" , cmdClrUserBp , NULL },
66 { "continue" , cmdContinue ,
67 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
69 { "c" , cmdContinue , NULL },
71 { "delete" , cmdDelUserBp ,
72 "{d}elete n\t\t clears break point number n\n"
74 { "d" , cmdDelUserBp , NULL },
77 "{h|?}elp\t\t this message\n"
79 { "?" , cmdHelp , NULL },
80 { "h" , cmdHelp , NULL },
84 "\t {break}\t list all break points\n"
85 "\t {stack}\t information about call stack\n"
86 "\t {frame}\t current frame information\n"
87 "\t {registers}\t display value of all registers\n"
90 { "listasm" , cmdListAsm ,
91 "listasm {la}\t\t list assembler code for the current C line\n"
93 { "la" , cmdListAsm , NULL },
94 { "list" , cmdListSrc ,
95 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
97 { "l" , cmdListSrc , NULL },
100 "\t {copying}\t copying & distribution terms\n"
101 "\t {warranty}\t warranty information\n"
103 { "set" , cmdSetOption , NULL },
105 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
107 { "s" , cmdStep , NULL },
109 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
111 { "n" , cmdNext , NULL },
113 "{r}un\t\t\t Start debugged program. \n"
115 { "r" , cmdRun , NULL },
116 { "ptype" , cmdPrintType ,
117 "{pt}ype <variable>\t print type information of a variable\n"
119 { "pt" , cmdPrintType , NULL },
120 { "print" , cmdPrint ,
121 "{p}rint <variable>\t print value of given variable\n"
123 { "p" , cmdPrint , NULL },
125 "file <filename>\t\t load symbolic information from <filename>\n"
127 { "frame" , cmdFrame ,
128 "{fr}ame\t\t\t print information about the current Stack\n"
130 { "finish" , cmdFinish ,
131 "{fi}nish\t\t execute till return of current function\n"
133 { "fi" , cmdFinish , NULL },
134 { "fr" , cmdFrame , NULL },
135 { "f" , cmdFrame , NULL },
136 { "!" , cmdSimulator ,
137 "!<simulator command>\t send a command directly to the simulator\n"
140 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
142 { "q" , cmdQuit , NULL }
145 /*-----------------------------------------------------------------*/
146 /* alloccpy - allocate copy and return a new string */
147 /*-----------------------------------------------------------------*/
148 char *alloccpy ( char *s, int size)
162 /*-----------------------------------------------------------------*/
163 /* resize - resizes array of type with new size */
164 /*-----------------------------------------------------------------*/
165 void **resize (void **array, int newSize)
170 vptr = GC_realloc(array,newSize*(sizeof(void **)));
172 vptr = GC_malloc(sizeof(void **));
175 fprintf(stderr,"sdcdb: out of memory \n");
183 /*-----------------------------------------------------------------*/
184 /* readCdb - reads the cdb files & puts the records into cdbLine */
186 /*-----------------------------------------------------------------*/
187 static int readCdb (FILE *file)
193 if (!(bp = fgets(buffer,sizeof(buffer),file)))
196 ALLOC(currl,sizeof(cdbrecs));
201 /* make sure this is a cdb record */
202 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
203 /* depending on the record type */
208 currl->type = SYM_REC;
211 currl->type = STRUCT_REC;
214 currl->type = LNK_REC;
217 currl->type = FUNC_REC;
220 currl->type = MOD_REC ;
224 ALLOC(currl->line,strlen(bp));
225 strncpy(currl->line,bp,strlen(bp)-1);
226 currl->line[strlen(bp)-1] = '\0';
229 if (!(bp = fgets(buffer,sizeof(buffer),file)))
235 ALLOC(currl->next,sizeof(cdbrecs));
239 return (recsRoot->line ? 1 : 0);
242 /*-----------------------------------------------------------------*/
243 /* searchDirsFname - search directory list & return the filename */
244 /*-----------------------------------------------------------------*/
245 char *searchDirsFname (char *fname)
251 /* first try the current directory */
252 if ((rfile = fopen(fname,"r"))) {
254 return strdup(fname) ;
258 return strdup(fname);
260 /* make a copy of the source directories */
261 dirs = sdirs = strdup(ssdirl);
263 /* assume that the separator is ':'
264 and try for each directory in the search list */
265 dirs = strtok(dirs,":");
267 if (dirs[strlen(dirs)] == '/')
268 sprintf(buffer,"%s%s",dirs,fname);
270 sprintf(buffer,"%s/%s",dirs,fname);
271 if ((rfile = fopen(buffer,"r")))
273 dirs = strtok(NULL,":");
279 return strdup(buffer);
281 return strdup(fname);
284 /*-----------------------------------------------------------------*/
285 /* searchDirsFopen - go thru list of directories for filename given*/
286 /*-----------------------------------------------------------------*/
287 FILE *searchDirsFopen(char *fname)
293 /* first try the current directory */
294 if ((rfile = fopen(fname,"r")))
299 /* make a copy of the source directories */
300 dirs = sdirs = strdup(ssdirl);
302 /* assume that the separator is ':'
303 and try for each directory in the search list */
304 dirs = strtok(dirs,":");
306 sprintf(buffer,"%s/%s",dirs,fname);
307 if ((rfile = fopen(buffer,"r")))
309 dirs = strtok(NULL,":");
317 /*-----------------------------------------------------------------*/
318 /* loadFile - loads a file into module buffer */
319 /*-----------------------------------------------------------------*/
320 srcLine **loadFile (char *name, int *nlines)
325 srcLine **slines = NULL;
328 if (!(mfile = searchDirsFopen(name))) {
329 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
333 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
336 slines = (srcLine **)resize((void **)slines,*nlines);
338 ALLOC(slines[(*nlines)-1],sizeof(srcLine));
339 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
347 /*-----------------------------------------------------------------*/
348 /* loadModules - reads the source files into module structure */
349 /*-----------------------------------------------------------------*/
350 static void loadModules ()
356 /* go thru the records & find out the module
357 records & load the modules specified */
358 for ( loop = recsRoot ; loop ; loop = loop->next ) {
360 switch (loop->type) {
361 /* for module records do */
363 currMod = parseModule(loop->line,TRUE);
364 currModName = currMod->name ;
366 currMod->cfullname = searchDirsFname(currMod->c_name);
368 /* load it into buffer */
369 currMod->cLines = loadFile (currMod->c_name,
372 /* do the same for the assembler file */
373 currMod->afullname = searchDirsFname(currMod->asm_name);
374 currMod->asmLines=loadFile (currMod->asm_name,
375 &currMod->nasmLines);
378 /* if this is a function record */
380 parseFunc(loop->line);
383 /* if this is a structure record */
385 parseStruct(loop->line);
388 /* if symbol then parse the symbol */
390 parseSymbol(loop->line,&rs);
394 parseLnkRec(loop->line);
400 /*-----------------------------------------------------------------*/
401 /* functionPoints - determine the execution points within a func */
402 /*-----------------------------------------------------------------*/
403 static void functionPoints ()
408 /* for all functions do */
409 for ( func = setFirstItem(functions); func;
410 func = setNextItem(functions)) {
417 printf("func '%s' has entry '%x' exit '%x'\n",
422 if (!func->sym->addr && !func->sym->eaddr)
425 /* for all source lines in the module find
426 the ones with address >= start and <= end
427 and put them in the point */
429 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
432 func->entryline= INT_MAX;
434 func->aentryline = INT_MAX ;
437 /* do it for the C Lines first */
438 for ( j = 0 ; j < mod->ncLines ; j++ ) {
439 if (mod->cLines[j]->addr >= sym->addr &&
440 mod->cLines[j]->addr <= sym->eaddr ) {
444 /* add it to the execution point */
445 if (func->entryline > j)
448 if (func->exitline < j)
451 ALLOC(ep,sizeof(exePoint));
452 ep->addr = mod->cLines[j]->addr ;
454 ep->block= mod->cLines[j]->block;
455 ep->level= mod->cLines[j]->level;
456 addSet(&func->cfpoints,ep);
460 /* do the same for asm execution points */
461 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
462 if (mod->asmLines[j]->addr >= sym->addr &&
463 mod->asmLines[j]->addr <= sym->eaddr ) {
466 /* add it to the execution point */
467 if (func->aentryline > j)
468 func->aentryline = j;
470 if (func->aexitline < j)
473 /* add it to the execution point */
474 ALLOC(ep,sizeof(exePoint));
475 ep->addr = mod->asmLines[j]->addr ;
477 addSet(&func->afpoints,ep);
482 printf("function '%s' has the following C exePoints\n",
487 for (ep = setFirstItem(func->cfpoints); ep;
488 ep = setNextItem(func->cfpoints))
489 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->cLines[ep->line]->src);
491 fprintf(stdout," and the following ASM exePoints\n");
492 for (ep = setFirstItem(func->afpoints); ep;
493 ep = setNextItem(func->afpoints))
494 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->asmLines[ep->line]->src);
502 /*-----------------------------------------------------------------*/
503 /* setEntryExitBP - set the entry & exit Break Points for functions*/
504 /*-----------------------------------------------------------------*/
505 DEFSETFUNC(setEntryExitBP)
507 function *func = item;
509 if (func->sym && func->sym->addr && func->sym->eaddr) {
511 /* set the entry break point */
512 setBreakPoint (func->sym->addr , CODE , FENTRY ,
513 fentryCB ,func->mod->c_name , func->entryline);
515 /* set the exit break point */
516 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
517 fexitCB ,func->mod->c_name , func->exitline );
523 /*-----------------------------------------------------------------*/
524 /* cmdFile - load file into the debugger */
525 /*-----------------------------------------------------------------*/
526 int cmdFile (char *s,context *cctxt)
532 while (isspace(*s)) s++;
534 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
538 sprintf(buffer,"%s.cdb",s);
539 /* try creating the cdbfile */
540 if (!(cdbFile = searchDirsFopen(buffer))) {
541 fprintf(stdout,"Cannot open file\"%s\"",buffer);
545 /* allocate for context */
546 ALLOC(currCtxt ,sizeof(context));
548 /* readin the debug information */
549 if (!readCdb (cdbFile)) {
550 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
554 /* parse and load the modules required */
557 /* determine the execution points for this
561 /* start the simulator & setup connection to it */
562 openSimulator((char **)simArgs,nsimArgs);
563 fprintf(stdout,"%s",simResponse());
564 /* now send the filename to be loaded to the simulator */
565 sprintf(buffer,"%s.ihx",s);
566 bp=searchDirsFname(buffer);
570 /*set the break points
571 required by the debugger . i.e. the function entry
572 and function exit break points */
573 applyToSet(functions,setEntryExitBP);
579 /*-----------------------------------------------------------------*/
580 /* cmdHelp - help command */
581 /*-----------------------------------------------------------------*/
582 int cmdHelp (char *s, context *cctxt)
586 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
588 /* command string matches */
590 fprintf(stdout,"%s",cmdTab[i].htxt);
596 #define MAX_CMD_LEN 512
597 char *prompt = "(sdcdb) ";
598 char cmdbuff[MAX_CMD_LEN];
600 /*-----------------------------------------------------------------*/
601 /* interpretCmd - interpret and do the command */
602 /*-----------------------------------------------------------------*/
603 int interpretCmd (char *s)
605 static char *pcmd = NULL;
608 /* if nothing & previous command exists then
609 execute the previous command again */
610 if (*s == '\n' && pcmd)
612 /* if previous command exists & is different
613 from the current command then copy it */
615 if (strcmp(pcmd,s)) {
621 /* lookup the command table and do the
625 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
627 /* command string matches */
628 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
629 if (!cmdTab[i].cmdfunc)
631 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
633 /* if full name then give the file name & position */
634 if (fullname && currCtxt && currCtxt->func) {
635 if (srcMode == SRC_CMODE)
636 fprintf(stdout,"\032\032%s:%d:1\n",
637 currCtxt->func->mod->cfullname,
640 fprintf(stdout,"\032\032%s:%d:1\n",
641 currCtxt->func->mod->afullname,
642 currCtxt->asmline+1);
648 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
653 /*-----------------------------------------------------------------*/
654 /* commandLoop - the main command loop */
655 /*-----------------------------------------------------------------*/
660 fprintf(stdout,"%s",prompt);
663 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
666 if (interpretCmd(cmdbuff))
672 /*-----------------------------------------------------------------*/
673 /* printVersionInfo - print the version information */
674 /*-----------------------------------------------------------------*/
675 static void printVersionInfo()
678 "SDCDB is free software and you are welcome to distribute copies of it\n"
679 "under certain conditions; type \"show copying\" to see the conditions.\n"
680 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
681 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
682 "Type ? for help\n");
686 /*-----------------------------------------------------------------*/
687 /* parseCmdLine - parse the commandline arguments */
688 /*-----------------------------------------------------------------*/
689 static void parseCmdLine (int argc, char **argv)
692 char *filename = NULL;
694 for ( i = 1; i < argc ; i++) {
695 fprintf(stdout,"%s\n",argv[i]);
697 /* if this is an option */
698 if (argv[i][0] == '-') {
700 /* if directory then mark directory */
701 if (strncmp(argv[i],"--directory=",12) == 0) {
703 ssdirl = &argv[i][12];
705 char *p = malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
706 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
712 if (strncmp(argv[i],"-fullname",9) == 0) {
717 if (strcmp(argv[i],"-cd") == 0) {
723 if (strncmp(argv[i],"-cd=",4) == 0) {
728 /* the simulator arguments */
731 if (strcmp(argv[i],"-t") == 0 ||
732 strcmp(argv[i],"-cpu") == 0) {
734 simArgs[nsimArgs++] = "-t";
735 simArgs[nsimArgs++] = strdup(argv[++i]);
740 if (strcmp(argv[i],"-X") == 0 ||
741 strcmp(argv[i],"-frequency") == 0) {
742 simArgs[nsimArgs++] = "-X";
743 simArgs[nsimArgs++] = strdup(argv[++i]);
748 if (strcmp(argv[i],"-s") == 0) {
749 simArgs[nsimArgs++] = "-s";
750 simArgs[nsimArgs++] = strdup(argv[++i]);
754 if (strcmp(argv[i],"-S") == 0) {
755 simArgs[nsimArgs++] = "-s";
756 simArgs[nsimArgs++] = strdup(argv[++i]);
760 fprintf(stderr,"unknown option %s --- ignored\n",
763 /* must be file name */
765 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
770 filename = strtok(argv[i],".");
776 cmdFile(filename,NULL);
779 /*-----------------------------------------------------------------*/
781 /*-----------------------------------------------------------------*/
783 int main ( int argc, char **argv)
786 /* parse command line */
787 parseCmdLine(argc,argv);