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" ;
47 /* fake filename & lineno to make linker */
55 char *cmd ; /* command the user will enter */
56 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
57 char *htxt ; /* short help text */
60 /* NOTE:- the search is done from the top, so "break" should
61 precede the synonym "b" */
63 { "break" , cmdSetUserBp ,
64 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
66 { "b" , cmdSetUserBp , NULL },
68 { "clear" , cmdClrUserBp ,
69 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
71 { "cl" , cmdClrUserBp , NULL },
73 { "continue" , cmdContinue ,
74 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
76 { "c" , cmdContinue , NULL },
78 { "delete" , cmdDelUserBp ,
79 "{d}elete n\t\t clears break point number n\n"
81 { "d" , cmdDelUserBp , NULL },
84 "{h|?}elp\t\t this message\n"
86 { "?" , cmdHelp , NULL },
87 { "h" , cmdHelp , NULL },
91 "\t {break}\t list all break points\n"
92 "\t {stack}\t information about call stack\n"
93 "\t {frame}\t current frame information\n"
94 "\t {registers}\t display value of all registers\n"
97 { "listasm" , cmdListAsm ,
98 "listasm {la}\t\t list assembler code for the current C line\n"
100 { "la" , cmdListAsm , NULL },
101 { "list" , cmdListSrc ,
102 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
104 { "l" , cmdListSrc , NULL },
107 "\t {copying}\t copying & distribution terms\n"
108 "\t {warranty}\t warranty information\n"
110 { "set" , cmdSetOption , NULL },
112 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
114 { "s" , cmdStep , NULL },
116 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
118 { "n" , cmdNext , NULL },
120 "{r}un\t\t\t Start debugged program. \n"
122 { "r" , cmdRun , NULL },
123 { "ptype" , cmdPrintType ,
124 "{pt}ype <variable>\t print type information of a variable\n"
126 { "pt" , cmdPrintType , NULL },
127 { "print" , cmdPrint ,
128 "{p}rint <variable>\t print value of given variable\n"
130 { "p" , cmdPrint , NULL },
132 "file <filename>\t\t load symbolic information from <filename>\n"
134 { "frame" , cmdFrame ,
135 "{fr}ame\t\t\t print information about the current Stack\n"
137 { "finish" , cmdFinish ,
138 "{fi}nish\t\t execute till return of current function\n"
140 { "fi" , cmdFinish , NULL },
141 { "fr" , cmdFrame , NULL },
142 { "f" , cmdFrame , NULL },
143 { "!" , cmdSimulator ,
144 "!<simulator command>\t send a command directly to the simulator\n"
147 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
149 { "q" , cmdQuit , NULL }
152 /*-----------------------------------------------------------------*/
153 /* gc_strdup - make a string duplicate garbage collector aware */
154 /*-----------------------------------------------------------------*/
155 char *gc_strdup(const char *s)
158 ret = Safe_malloc(strlen(s)+1);
163 /*-----------------------------------------------------------------*/
164 /* alloccpy - allocate copy and return a new string */
165 /*-----------------------------------------------------------------*/
166 char *alloccpy ( char *s, int size)
173 d = Safe_malloc(size+1);
180 /*-----------------------------------------------------------------*/
181 /* resize - resizes array of type with new size */
182 /*-----------------------------------------------------------------*/
183 void **resize (void **array, int newSize)
188 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
190 vptr = calloc(1, sizeof(void **));
193 fprintf(stderr,"sdcdb: out of memory \n");
201 /*-----------------------------------------------------------------*/
202 /* readCdb - reads the cdb files & puts the records into cdbLine */
204 /*-----------------------------------------------------------------*/
205 static int readCdb (FILE *file)
211 if (!(bp = fgets(buffer,sizeof(buffer),file)))
214 currl = Safe_calloc(1,sizeof(cdbrecs));
219 /* make sure this is a cdb record */
220 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
221 /* depending on the record type */
226 currl->type = SYM_REC;
229 currl->type = STRUCT_REC;
232 currl->type = LNK_REC;
235 currl->type = FUNC_REC;
238 currl->type = MOD_REC ;
242 currl->line = Safe_malloc(strlen(bp));
243 strncpy(currl->line,bp,strlen(bp)-1);
244 currl->line[strlen(bp)-1] = '\0';
247 if (!(bp = fgets(buffer,sizeof(buffer),file)))
253 currl->next = Safe_calloc(1,sizeof(cdbrecs));
257 return (recsRoot->line ? 1 : 0);
260 /*-----------------------------------------------------------------*/
261 /* searchDirsFname - search directory list & return the filename */
262 /*-----------------------------------------------------------------*/
263 char *searchDirsFname (char *fname)
269 /* first try the current directory */
270 if ((rfile = fopen(fname,"r"))) {
272 return strdup(fname) ;
276 return strdup(fname);
278 /* make a copy of the source directories */
279 dirs = sdirs = strdup(ssdirl);
281 /* assume that the separator is ':'
282 and try for each directory in the search list */
283 dirs = strtok(dirs,":");
285 if (dirs[strlen(dirs)] == '/')
286 sprintf(buffer,"%s%s",dirs,fname);
288 sprintf(buffer,"%s/%s",dirs,fname);
289 if ((rfile = fopen(buffer,"r")))
291 dirs = strtok(NULL,":");
297 return strdup(buffer);
299 return strdup(fname);
302 /*-----------------------------------------------------------------*/
303 /* searchDirsFopen - go thru list of directories for filename given*/
304 /*-----------------------------------------------------------------*/
305 FILE *searchDirsFopen(char *fname)
311 /* first try the current directory */
312 if ((rfile = fopen(fname,"r")))
317 /* make a copy of the source directories */
318 dirs = sdirs = strdup(ssdirl);
320 /* assume that the separator is ':'
321 and try for each directory in the search list */
322 dirs = strtok(dirs,":");
324 sprintf(buffer,"%s/%s",dirs,fname);
325 if ((rfile = fopen(buffer,"r")))
327 dirs = strtok(NULL,":");
335 /*-----------------------------------------------------------------*/
336 /* loadFile - loads a file into module buffer */
337 /*-----------------------------------------------------------------*/
338 srcLine **loadFile (char *name, int *nlines)
343 srcLine **slines = NULL;
346 if (!(mfile = searchDirsFopen(name))) {
347 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
351 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
354 slines = (srcLine **)resize((void **)slines,*nlines);
356 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
357 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
365 /*-----------------------------------------------------------------*/
366 /* loadModules - reads the source files into module structure */
367 /*-----------------------------------------------------------------*/
368 static void loadModules ()
374 /* go thru the records & find out the module
375 records & load the modules specified */
376 for ( loop = recsRoot ; loop ; loop = loop->next ) {
378 switch (loop->type) {
379 /* for module records do */
381 currMod = parseModule(loop->line,TRUE);
382 currModName = currMod->name ;
384 currMod->cfullname = searchDirsFname(currMod->c_name);
386 /* load it into buffer */
387 currMod->cLines = loadFile (currMod->c_name,
390 /* do the same for the assembler file */
391 currMod->afullname = searchDirsFname(currMod->asm_name);
392 currMod->asmLines=loadFile (currMod->asm_name,
393 &currMod->nasmLines);
396 /* if this is a function record */
398 parseFunc(loop->line);
401 /* if this is a structure record */
403 parseStruct(loop->line);
406 /* if symbol then parse the symbol */
408 parseSymbol(loop->line,&rs);
412 parseLnkRec(loop->line);
418 /*-----------------------------------------------------------------*/
419 /* functionPoints - determine the execution points within a func */
420 /*-----------------------------------------------------------------*/
421 static void functionPoints ()
426 /* for all functions do */
427 for ( func = setFirstItem(functions); func;
428 func = setNextItem(functions)) {
434 Dprintf(D_sdcdb, ("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 Dprintf(D_sdcdb, ("function '%s' has the following C exePoints\n",
504 for (ep = setFirstItem(func->cfpoints); ep;
505 ep = setNextItem(func->cfpoints))
506 Dprintf(D_sdcdb, ("{%x,%d} %s",
507 ep->addr,ep->line,mod->cLines[ep->line]->src));
509 Dprintf(D_sdcdb, (" and the following ASM exePoints\n"));
510 for (ep = setFirstItem(func->afpoints); ep;
511 ep = setNextItem(func->afpoints))
512 Dprintf (D_sdcdb, ("{%x,%d} %s",
513 ep->addr,ep->line,mod->asmLines[ep->line]->src));
520 /*-----------------------------------------------------------------*/
521 /* setEntryExitBP - set the entry & exit Break Points for functions*/
522 /*-----------------------------------------------------------------*/
523 DEFSETFUNC(setEntryExitBP)
525 function *func = item;
527 if (func->sym && func->sym->addr && func->sym->eaddr) {
529 /* set the entry break point */
530 setBreakPoint (func->sym->addr , CODE , FENTRY ,
531 fentryCB ,func->mod->c_name , func->entryline);
533 /* set the exit break point */
534 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
535 fexitCB ,func->mod->c_name , func->exitline );
541 /*-----------------------------------------------------------------*/
542 /* cmdFile - load file into the debugger */
543 /*-----------------------------------------------------------------*/
544 int cmdFile (char *s,context *cctxt)
550 while (isspace(*s)) s++;
552 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
556 sprintf(buffer,"%s.cdb",s);
557 /* try creating the cdbfile */
558 if (!(cdbFile = searchDirsFopen(buffer))) {
559 fprintf(stdout,"Cannot open file\"%s\"",buffer);
563 /* allocate for context */
564 currCtxt = Safe_calloc(1,sizeof(context));
566 /* readin the debug information */
567 if (!readCdb (cdbFile)) {
568 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
572 /* parse and load the modules required */
575 /* determine the execution points for this
579 /* start the simulator & setup connection to it */
580 openSimulator((char **)simArgs,nsimArgs);
581 fprintf(stdout,"%s",simResponse());
582 /* now send the filename to be loaded to the simulator */
583 sprintf(buffer,"%s.ihx",s);
584 bp=searchDirsFname(buffer);
588 /*set the break points
589 required by the debugger . i.e. the function entry
590 and function exit break points */
591 applyToSet(functions,setEntryExitBP);
597 /*-----------------------------------------------------------------*/
598 /* cmdHelp - help command */
599 /*-----------------------------------------------------------------*/
600 int cmdHelp (char *s, context *cctxt)
604 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
606 /* command string matches */
608 fprintf(stdout,"%s",cmdTab[i].htxt);
614 #define MAX_CMD_LEN 512
615 char *prompt = "(sdcdb) ";
616 char cmdbuff[MAX_CMD_LEN];
618 /*-----------------------------------------------------------------*/
619 /* interpretCmd - interpret and do the command */
620 /*-----------------------------------------------------------------*/
621 int interpretCmd (char *s)
623 static char *pcmd = NULL;
626 /* if nothing & previous command exists then
627 execute the previous command again */
628 if (*s == '\n' && pcmd)
630 /* if previous command exists & is different
631 from the current command then copy it */
633 if (strcmp(pcmd,s)) {
639 /* lookup the command table and do the
643 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
645 /* command string matches */
646 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
647 if (!cmdTab[i].cmdfunc)
649 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
651 /* if full name then give the file name & position */
652 if (fullname && currCtxt && currCtxt->func) {
653 if (srcMode == SRC_CMODE)
654 fprintf(stdout,"\032\032%s:%d:1\n",
655 currCtxt->func->mod->cfullname,
658 fprintf(stdout,"\032\032%s:%d:1\n",
659 currCtxt->func->mod->afullname,
660 currCtxt->asmline+1);
666 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
671 /*-----------------------------------------------------------------*/
672 /* commandLoop - the main command loop */
673 /*-----------------------------------------------------------------*/
678 fprintf(stdout,"%s",prompt);
681 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
684 if (interpretCmd(cmdbuff))
690 /*-----------------------------------------------------------------*/
691 /* printVersionInfo - print the version information */
692 /*-----------------------------------------------------------------*/
693 static void printVersionInfo()
696 "SDCDB is free software and you are welcome to distribute copies of it\n"
697 "under certain conditions; type \"show copying\" to see the conditions.\n"
698 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
699 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
700 "Type ? for help\n");
704 /*-----------------------------------------------------------------*/
705 /* parseCmdLine - parse the commandline arguments */
706 /*-----------------------------------------------------------------*/
707 static void parseCmdLine (int argc, char **argv)
710 char *filename = NULL;
712 for ( i = 1; i < argc ; i++) {
713 fprintf(stdout,"%s\n",argv[i]);
715 /* if this is an option */
716 if (argv[i][0] == '-') {
718 /* if directory then mark directory */
719 if (strncmp(argv[i],"--directory=",12) == 0) {
721 ssdirl = &argv[i][12];
723 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
724 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
730 if (strncmp(argv[i],"-fullname",9) == 0) {
735 if (strcmp(argv[i],"-cd") == 0) {
741 if (strncmp(argv[i],"-cd=",4) == 0) {
746 /* the simulator arguments */
749 if (strcmp(argv[i],"-t") == 0 ||
750 strcmp(argv[i],"-cpu") == 0) {
752 simArgs[nsimArgs++] = "-t";
753 simArgs[nsimArgs++] = strdup(argv[++i]);
758 if (strcmp(argv[i],"-X") == 0 ||
759 strcmp(argv[i],"-frequency") == 0) {
760 simArgs[nsimArgs++] = "-X";
761 simArgs[nsimArgs++] = strdup(argv[++i]);
766 if (strcmp(argv[i],"-s") == 0) {
767 simArgs[nsimArgs++] = "-s";
768 simArgs[nsimArgs++] = strdup(argv[++i]);
772 if (strcmp(argv[i],"-S") == 0) {
773 simArgs[nsimArgs++] = "-s";
774 simArgs[nsimArgs++] = strdup(argv[++i]);
779 if (strncmp(argv[i],"-m",2) == 0) {
780 strncpy(model_str, &argv[i][2], 15);
781 if (strcmp(model_str,"avr") == 0)
783 else if (strcmp(model_str,"rrz80") == 0)
784 simArgs[0] = "rrz80";
785 else if (strcmp(model_str,"xa") == 0)
787 else if (strcmp(model_str,"z80") == 0)
792 fprintf(stderr,"unknown option %s --- ignored\n",
795 /* must be file name */
797 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
802 filename = strtok(argv[i],".");
808 cmdFile(filename,NULL);
811 /*-----------------------------------------------------------------*/
813 /*-----------------------------------------------------------------*/
815 int main ( int argc, char **argv)
819 simArgs[nsimArgs++] = "s51";
820 simArgs[nsimArgs++] = "-P";
821 simArgs[nsimArgs++] = "-r 9756";
822 /* parse command line */
824 parseCmdLine(argc,argv);