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;
43 short userinterrupt = 0;
44 char *ssdirl = DATADIR LIB_DIR_SUFFIX ":" DATADIR LIB_DIR_SUFFIX "/small" ;
49 /* fake filename & lineno to make linker */
57 char *cmd ; /* command the user will enter */
58 int (*cmdfunc)(char *,context *); /* function to execute when command is entered */
59 char *htxt ; /* short help text */
62 /* NOTE:- the search is done from the top, so "break" should
63 precede the synonym "b" */
65 { "break" , cmdSetUserBp ,
66 "{b}reak\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
68 { "b" , cmdSetUserBp , NULL },
70 { "clear" , cmdClrUserBp ,
71 "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
73 { "cl" , cmdClrUserBp , NULL },
75 { "continue" , cmdContinue ,
76 "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
78 { "c" , cmdContinue , NULL },
80 { "disassemble",cmdDisasmF , "x disassemble asm commands\n" },
81 { "delete" , cmdDelUserBp ,
82 "{d}elete n\t\t clears break point number n\n"
84 { "display" , cmdDisplay ,
85 "display [<variable>]\t print value of given variable each time the program stops\n"
87 { "undisplay" , cmdUnDisplay ,
88 "undisplay [<variable>]\t dont display this variable or all\n"
90 { "d" , cmdDelUserBp , NULL },
93 "info <break stack frame registers all-registers>\n"
94 "\t list all break points, call-stack, frame or register information\n"
97 { "listasm" , cmdListAsm ,
98 "listasm {la}\t\t list assembler code for the current C line\n"
100 { "la" , cmdListAsm , NULL },
101 { "ls" , cmdListSymbols , "ls,lf,lm\t\t list symbols,functions,modules\n" },
102 { "lf" , cmdListFunctions, NULL },
103 { "lm" , cmdListModules , NULL },
104 { "list" , cmdListSrc ,
105 "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
107 { "l" , cmdListSrc , NULL },
110 " <copying warranty>\t copying & distribution terms, warranty\n"
112 { "set" , cmdSetOption , "set <srcmode>\t\t toggle between c/asm.\nset variable <var> = >value\t\tset variable to new value\n" },
114 "{s}tep\t\t\t Step program until it reaches a different source line.\n"
116 { "s" , cmdStep , NULL },
118 "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
120 { "n" , cmdNext , NULL },
122 "{r}un\t\t\t Start debugged program. \n"
124 { "r" , cmdRun , NULL },
125 { "ptype" , cmdPrintType ,
126 "{pt}ype <variable>\t print type information of a variable\n"
128 { "pt" , cmdPrintType , NULL },
129 { "print" , cmdPrint ,
130 "{p}rint <variable>\t print value of given variable\n"
132 { "output" , cmdOutput ,
133 "output <variable>\t print value of given variable without $ and newline \n"
135 { "p" , cmdPrint , NULL },
137 "file <filename>\t\t load symbolic information from <filename>\n"
139 { "frame" , cmdFrame ,
140 "{fr}ame\t\t\t print information about the current Stack\n"
142 { "finish" , cmdFinish ,
143 "{fi}nish\t\t execute till return of current function\n"
145 { "fi" , cmdFinish , NULL },
146 { "where" , cmdWhere , "where\t\t\t print stack\n" },
147 { "fr" , cmdFrame , NULL },
148 { "f" , cmdFrame , NULL },
149 { "x /i" , cmdDisasm1 , "x\t\t disassemble one asm command\n" },
150 { "!" , cmdSimulator ,
151 "!<simulator command>\t send a command directly to the simulator\n"
153 { "." , cmdSimulator ,
154 ".{cmd}\t switch from simulator or debugger command mode\n"
157 "{h|?}elp\t [CMD_NAME | 0,1,2,3(help page)] (general help or specific help)\n"
159 { "?" , cmdHelp , NULL },
160 { "h" , cmdHelp , NULL },
163 "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
165 { "q" , cmdQuit , NULL }
168 /*-----------------------------------------------------------------*/
169 /* gc_strdup - make a string duplicate garbage collector aware */
170 /*-----------------------------------------------------------------*/
171 char *gc_strdup(const char *s)
174 ret = Safe_malloc(strlen(s)+1);
179 /*-----------------------------------------------------------------*/
180 /* alloccpy - allocate copy and return a new string */
181 /*-----------------------------------------------------------------*/
182 char *alloccpy ( char *s, int size)
189 d = Safe_malloc(size+1);
196 /*-----------------------------------------------------------------*/
197 /* resize - resizes array of type with new size */
198 /*-----------------------------------------------------------------*/
199 void **resize (void **array, int newSize)
204 vptr = Safe_realloc(array,newSize*(sizeof(void **)));
206 vptr = calloc(1, sizeof(void **));
209 fprintf(stderr,"sdcdb: out of memory \n");
217 /*-----------------------------------------------------------------*/
218 /* readCdb - reads the cdb files & puts the records into cdbLine */
220 /*-----------------------------------------------------------------*/
221 static int readCdb (FILE *file)
227 if (!(bp = fgets(buffer,sizeof(buffer),file)))
230 currl = Safe_calloc(1,sizeof(cdbrecs));
235 /* make sure this is a cdb record */
236 if (strchr("STLFM",*bp) && *(bp+1) == ':') {
237 /* depending on the record type */
242 currl->type = SYM_REC;
245 currl->type = STRUCT_REC;
248 currl->type = LNK_REC;
251 currl->type = FUNC_REC;
254 currl->type = MOD_REC ;
258 currl->line = Safe_malloc(strlen(bp));
259 strncpy(currl->line,bp,strlen(bp)-1);
260 currl->line[strlen(bp)-1] = '\0';
263 if (!(bp = fgets(buffer,sizeof(buffer),file)))
269 currl->next = Safe_calloc(1,sizeof(cdbrecs));
273 return (recsRoot->line ? 1 : 0);
276 /*-----------------------------------------------------------------*/
277 /* searchDirsFname - search directory list & return the filename */
278 /*-----------------------------------------------------------------*/
279 char *searchDirsFname (char *fname)
285 /* first try the current directory */
286 if ((rfile = fopen(fname,"r"))) {
288 return strdup(fname) ;
292 return strdup(fname);
294 /* make a copy of the source directories */
295 dirs = sdirs = strdup(ssdirl);
297 /* assume that the separator is ':'
298 and try for each directory in the search list */
299 dirs = strtok(dirs,":");
301 if (dirs[strlen(dirs)] == '/')
302 sprintf(buffer,"%s%s",dirs,fname);
304 sprintf(buffer,"%s/%s",dirs,fname);
305 if ((rfile = fopen(buffer,"r")))
307 dirs = strtok(NULL,":");
313 return strdup(buffer);
315 return strdup(fname);
318 /*-----------------------------------------------------------------*/
319 /* searchDirsFopen - go thru list of directories for filename given*/
320 /*-----------------------------------------------------------------*/
321 FILE *searchDirsFopen(char *fname)
327 /* first try the current directory */
328 if ((rfile = fopen(fname,"r")))
333 /* make a copy of the source directories */
334 dirs = sdirs = strdup(ssdirl);
336 /* assume that the separator is ':'
337 and try for each directory in the search list */
338 dirs = strtok(dirs,":");
340 sprintf(buffer,"%s/%s",dirs,fname);
341 if ((rfile = fopen(buffer,"r")))
343 dirs = strtok(NULL,":");
351 /*-----------------------------------------------------------------*/
352 /* loadFile - loads a file into module buffer */
353 /*-----------------------------------------------------------------*/
354 srcLine **loadFile (char *name, int *nlines)
359 srcLine **slines = NULL;
362 if (!(mfile = searchDirsFopen(name))) {
363 fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
367 while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
370 slines = (srcLine **)resize((void **)slines,*nlines);
372 slines[(*nlines)-1] = Safe_calloc(1,sizeof(srcLine));
373 slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));
381 /*-----------------------------------------------------------------*/
382 /* loadModules - reads the source files into module structure */
383 /*-----------------------------------------------------------------*/
384 static void loadModules ()
390 /* go thru the records & find out the module
391 records & load the modules specified */
392 for ( loop = recsRoot ; loop ; loop = loop->next ) {
394 switch (loop->type) {
395 /* for module records do */
397 currMod = parseModule(loop->line,TRUE);
398 currModName = currMod->name ;
400 currMod->cfullname = searchDirsFname(currMod->c_name);
402 /* load it into buffer */
403 currMod->cLines = loadFile (currMod->c_name,
406 /* do the same for the assembler file */
407 currMod->afullname = searchDirsFname(currMod->asm_name);
408 currMod->asmLines=loadFile (currMod->asm_name,
409 &currMod->nasmLines);
412 /* if this is a function record */
414 parseFunc(loop->line);
417 /* if this is a structure record */
419 parseStruct(loop->line);
422 /* if symbol then parse the symbol */
424 parseSymbol(loop->line,&rs);
428 parseLnkRec(loop->line);
434 /*-----------------------------------------------------------------*/
435 /* functionPoints - determine the execution points within a func */
436 /*-----------------------------------------------------------------*/
437 static void functionPoints ()
442 /* for all functions do */
443 for ( func = setFirstItem(functions); func;
444 func = setNextItem(functions)) {
450 Dprintf(D_sdcdb, ("func '%s' has entry '%x' exit '%x'\n",
455 if (!func->sym->addr && !func->sym->eaddr)
458 /* for all source lines in the module find
459 the ones with address >= start and <= end
460 and put them in the point */
462 if (! applyToSet(modules,moduleWithName,func->modName,&mod))
465 func->entryline= INT_MAX;
467 func->aentryline = INT_MAX ;
470 /* do it for the C Lines first */
471 for ( j = 0 ; j < mod->ncLines ; j++ ) {
472 if (mod->cLines[j]->addr >= sym->addr &&
473 mod->cLines[j]->addr <= sym->eaddr ) {
477 /* add it to the execution point */
478 if (func->entryline > j)
481 if (func->exitline < j)
484 ep = Safe_calloc(1,sizeof(exePoint));
485 ep->addr = mod->cLines[j]->addr ;
487 ep->block= mod->cLines[j]->block;
488 ep->level= mod->cLines[j]->level;
489 addSet(&func->cfpoints,ep);
493 /* do the same for asm execution points */
494 for ( j = 0 ; j < mod->nasmLines ; j++ ) {
495 if (mod->asmLines[j]->addr >= sym->addr &&
496 mod->asmLines[j]->addr <= sym->eaddr ) {
499 /* add it to the execution point */
500 if (func->aentryline > j)
501 func->aentryline = j;
503 if (func->aexitline < j)
506 /* add it to the execution point */
507 ep = Safe_calloc(1,sizeof(exePoint));
508 ep->addr = mod->asmLines[j]->addr ;
510 addSet(&func->afpoints,ep);
515 Dprintf(D_sdcdb, ("function '%s' has the following C exePoints\n",
520 for (ep = setFirstItem(func->cfpoints); ep;
521 ep = setNextItem(func->cfpoints))
522 Dprintf(D_sdcdb, ("{%x,%d} %s",
523 ep->addr,ep->line,mod->cLines[ep->line]->src));
525 Dprintf(D_sdcdb, (" and the following ASM exePoints\n"));
526 for (ep = setFirstItem(func->afpoints); ep;
527 ep = setNextItem(func->afpoints))
528 Dprintf (D_sdcdb, ("{%x,%d} %s",
529 ep->addr,ep->line,mod->asmLines[ep->line]->src));
536 /*-----------------------------------------------------------------*/
537 /* setEntryExitBP - set the entry & exit Break Points for functions*/
538 /*-----------------------------------------------------------------*/
539 DEFSETFUNC(setEntryExitBP)
541 function *func = item;
543 if (func->sym && func->sym->addr && func->sym->eaddr) {
545 /* set the entry break point */
546 setBreakPoint (func->sym->addr , CODE , FENTRY ,
547 fentryCB ,func->mod->c_name , func->entryline);
549 /* set the exit break point */
550 setBreakPoint (func->sym->eaddr , CODE , FEXIT ,
551 fexitCB ,func->mod->c_name , func->exitline );
557 /*-----------------------------------------------------------------*/
558 /* cmdFile - load file into the debugger */
559 /*-----------------------------------------------------------------*/
560 int cmdFile (char *s,context *cctxt)
566 while (isspace(*s)) s++;
568 fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
572 sprintf(buffer,"%s.cdb",s);
573 /* try creating the cdbfile */
574 if (!(cdbFile = searchDirsFopen(buffer))) {
575 fprintf(stdout,"Cannot open file\"%s\", no symbolic information loaded\n",buffer);
579 /* allocate for context */
580 currCtxt = Safe_calloc(1,sizeof(context));
583 /* readin the debug information */
584 if (!readCdb (cdbFile)) {
585 fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
590 /* parse and load the modules required */
593 /* determine the execution points for this
597 /* start the simulator & setup connection to it */
599 openSimulator((char **)simArgs,nsimArgs);
600 fprintf(stdout,"%s",simResponse());
601 /* now send the filename to be loaded to the simulator */
602 sprintf(buffer,"%s.ihx",s);
603 bp=searchDirsFname(buffer);
607 /*set the break points
608 required by the debugger . i.e. the function entry
609 and function exit break points */
610 applyToSet(functions,setEntryExitBP);
616 /*-----------------------------------------------------------------*/
617 /* cmdHelp - help command */
618 /*-----------------------------------------------------------------*/
619 int cmdHelp (char *s, context *cctxt)
628 endline = ((*s - '0') * 20) + 20;
630 startline = endline - 20;
634 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++)
636 if ((cmdTab[i].htxt) && !strcmp(cmdTab[i].cmd,s))
637 fprintf(stdout,"%s",cmdTab[i].htxt);
642 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
644 /* command string matches */
646 if ((cmdTab[i].htxt) && (i >= startline))
647 fprintf(stdout,"%s",cmdTab[i].htxt);
655 #define MAX_CMD_LEN 512
656 static char cmdbuff[MAX_CMD_LEN];
657 static int sim_cmd_mode = 0;
659 /*-----------------------------------------------------------------
660 interpretCmd - interpret and do the command. Return 0 to continue,
661 return 1 to exit program.
662 |-----------------------------------------------------------------*/
663 int interpretCmd (char *s)
665 static char *pcmd = NULL;
669 /* if nothing & previous command exists then
670 execute the previous command again */
671 if (*s == '\n' && pcmd)
674 /* if previous command exists & is different
675 from the current command then copy it */
677 if (strcmp(pcmd,s)) {
684 /* lookup the command table and do the task required */
688 if (strcmp(s,".") == 0) {
692 else if (s[0] == '.') {
693 /* kill the preceeding '.' and pass on as SDCDB command */
700 cmdSimulator (s, currCtxt);
704 if (strcmp(s,".") ==0) {
710 for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
712 /* command string matches */
713 if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
714 if (!cmdTab[i].cmdfunc)
717 rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
719 /* if full name then give the file name & position */
720 if (fullname && showfull && currCtxt && currCtxt->func) {
722 if (srcMode == SRC_CMODE)
723 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
724 currCtxt->func->mod->cfullname,
725 currCtxt->cline,currCtxt->addr);
727 fprintf(stdout,"\032\032%s:%d:1:beg:0x%08x\n",
728 currCtxt->func->mod->afullname,
729 currCtxt->asmline,currCtxt->addr);
730 displayAll(currCtxt);
736 fprintf(stdout,"Undefined command: \"%s\". Try \"help\".\n",s);
741 /*-----------------------------------------------------------------*/
742 /* commandLoop - the main command loop */
743 /*-----------------------------------------------------------------*/
746 char *prompt = "(sdcdb) ";
747 char *sim_prompt = "(sim) ";
751 printf("%s",sim_prompt);
753 fprintf(stdout,"%s",prompt);
757 if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
761 /* make a way to go into "ucSim" mode */
762 if (cmdbuff[0] == '$') {
763 if (sim_cmd_mode) sim_cmd_mode = 0;
764 else sim_cmd_mode = 1;
769 if (interpretCmd(cmdbuff))
774 /*-----------------------------------------------------------------*/
775 /* printVersionInfo - print the version information */
776 /*-----------------------------------------------------------------*/
777 static void printVersionInfo()
780 "SDCDB is free software and you are welcome to distribute copies of it\n"
781 "under certain conditions; type \"show copying\" to see the conditions.\n"
782 "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
783 "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
784 "Type ? for help\n");
788 /*-----------------------------------------------------------------*/
789 /* parseCmdLine - parse the commandline arguments */
790 /*-----------------------------------------------------------------*/
791 static void parseCmdLine (int argc, char **argv)
794 char *filename = NULL;
795 int passon_args_flag = 0; /* if true, pass on args to simulator */
797 Dprintf(D_sdcdb, ("parseCmdLine\n"));
799 for ( i = 1; i < argc ; i++) {
800 //fprintf(stdout,"%s\n",argv[i]);
802 if (passon_args_flag) { /* if true, pass on args to simulator */
803 simArgs[nsimArgs++] = strdup(argv[i]);
807 /* if this is an option */
808 if (argv[i][0] == '-') {
810 /* if directory then mark directory */
811 if (strncmp(argv[i],"--directory=",12) == 0) {
813 ssdirl = &argv[i][12];
815 char *p = Safe_malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
816 strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
822 if (strncmp(argv[i],"-fullname",9) == 0) {
827 if (strcmp(argv[i],"-cd") == 0) {
833 if (strncmp(argv[i],"-cd=",4) == 0) {
839 if (strncmp(argv[i],"-m",2) == 0) {
840 strncpy(model_str, &argv[i][2], 15);
841 if (strcmp(model_str,"avr") == 0)
843 else if (strcmp(model_str,"xa") == 0)
845 else if (strcmp(model_str,"z80") == 0)
850 /* -z all remaining options are for simulator */
851 if (strcmp(argv[i],"-z") == 0) {
852 passon_args_flag = 1;
856 /* the simulator arguments */
859 if (strcmp(argv[i],"-t") == 0 ||
860 strcmp(argv[i],"-cpu") == 0) {
862 simArgs[nsimArgs++] = "-t";
863 simArgs[nsimArgs++] = strdup(argv[++i]);
868 if (strcmp(argv[i],"-X") == 0 ||
869 strcmp(argv[i],"-frequency") == 0) {
870 simArgs[nsimArgs++] = "-X";
871 simArgs[nsimArgs++] = strdup(argv[++i]);
876 if ( (strcmp(argv[i],"-S") == 0) ||
877 (strcmp(argv[i],"-s") == 0)) {
878 simArgs[nsimArgs++] = "-s";
879 simArgs[nsimArgs++] = strdup(argv[++i]);
883 fprintf(stderr,"unknown option %s --- ignored\n",
887 /* must be file name */
889 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
894 filename = strtok(argv[i],".");
900 cmdFile(filename,NULL);
903 /*-----------------------------------------------------------------*/
904 /* setsignals - catch some signals */
905 /*-----------------------------------------------------------------*/
918 /* may be interrupt from user: stop debugger ( also simulator ??) */
922 /* the only child can be the simulator */
923 static void sigchld(int sig)
925 /* the only child can be the simulator */
927 retpid = wait ( &status );
928 /* if ( retpid == simPid ) */
935 signal(SIGHUP , bad_signal);
936 signal(SIGINT , sigintr );
937 signal(SIGTERM, bad_signal);
938 signal(SIGCHLD, sigchld );
940 signal(SIGPIPE, SIG_IGN);
941 signal(SIGABRT, bad_signal);
942 signal(SIGALRM, bad_signal);
943 signal(SIGFPE, bad_signal);
944 signal(SIGILL, bad_signal);
945 signal(SIGPIPE, bad_signal);
946 signal(SIGQUIT, bad_signal);
947 signal(SIGSEGV, bad_signal);
950 /*-----------------------------------------------------------------*/
952 /*-----------------------------------------------------------------*/
954 int main ( int argc, char **argv)
957 printf("WARNING: SDCDB is EXPERIMENTAL and NOT A FULLY FUNCTIONING TOOL.\n");
959 simArgs[nsimArgs++] = "s51";
960 simArgs[nsimArgs++] = "-P";
961 simArgs[nsimArgs++] = "-r 9756";
962 /* parse command line */
965 parseCmdLine(argc,argv);