Answers/Solutions to Exercises in Chapter 10, Exercise 6
E6: Extend the program from exercise 5 to include localization tracing using a stack for function names (see Appendix C.).
A6: A sample program is below. Note that we have to make sure that the allocation/deallocation in the tracing functions is not included in our tracing. The best is to have it in a separate file, compile it separately, and link it with the program being traced. But here we included it in one program.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> void sys_exit(char *fmt, ...); void sys(char *fmt, ...); void msg_exit(char *fmt, ...); void msg(char *fmt, ...); void Sys_exit(char *fmt, ...); void Msg_exit(char *fmt, ...); void Sys(char *fmt, ...); void Msg(char *fmt, ...); void print_msg(char *fmt,va_list ap,char* where); void open_log(char* name); char logpath[500] = ""; char buf[500]; #define TRACE(a) PUSH_TRACE(#a); #define RETURN {POP_TRACE(); return; } #define RETURN1(a) {POP_TRACE(); return(a); } #define REPORT() REPORT_TRACE(3) //#include "trace.c" // the function trace stack is a simple linked list of // pointers to function identifiers // the head of the list is the op of the stack struct TRACE_NODE_STRUCT { char* floc; // ptr to function identifier struct TRACE_NODE_STRUCT* next; // ptr to next frama }; typedef struct TRACE_NODE_STRUCT TRACE_NODE; static TRACE_NODE* TRACETop = NULL; // ptr to the top of the stack /* function PUSH_TRACE ---------------------------------------------- */ void PUSH_TRACE(char* p) // push p on the stack { TRACE_NODE* tnode; static char glob[]="global"; if (TRACETop==NULL) { // initialize the stack with "global" identifier TRACETop=(TRACE_NODE*) malloc(sizeof(TRACE_NODE)); // no recovery needed if allocation failed, this is only // used in debugging, not in production if (TRACETop==NULL) { printf("PUSH_TRACE: memory allocation error\n"); exit(1); } TRACETop->floc = glob; TRACETop->next=NULL; } // now create the node for p tnode = (TRACE_NODE*) malloc(sizeof(TRACE_NODE)); // no recovery needed if allocation failed, this is only // used in debugging, not in production if (tnode==NULL) { printf("PUSH_TRACE: memory allocation error\n"); exit(1); } tnode->floc=p; tnode->next = TRACETop; // insert fnode as the first in the list TRACETop=tnode; // point TRACETop to the first node }/*end PUSH_TRACE*/ /* function POP_TRACE ---------------------------------------------- */ void POP_TRACE() // remove the op of the stack { TRACE_NODE* tnode; tnode = TRACETop; TRACETop = tnode->next; free(tnode); }/*end POP_TRACE*/ /* report `depth' top entries from the stack in the form fun1:fun2:fun3:....:funk meaning fun1 called from fun2 that was called from fun3 ... that was called from funk where k = depth The calling path may be up to 100 characters, if longer it is truncated */ /* function REPORT_TRACE ---------------------------------------------- */ char* REPORT_TRACE(int depth) { int i, length, j; TRACE_NODE* tnode; static char buf[100]; if (TRACETop==NULL) { // stack not initialized yet, so we are strcpy(buf,"global"); // still in the `global' area return buf; } /* peek at the depth top entries on the stactk, but do not go over 100 chars and do not go over the bottom of the stack */ sprintf(buf,"%s",TRACETop->floc); length = strlen(buf); // length of the string so far for(i=1, tnode=TRACETop->next; tnode!=NULL && i < depth; i++,tnode=tnode->next) { j = strlen(tnode->floc); // length of what we want to add if (length+j+1 < 100) { // total length is ok sprintf(buf+length,":%s",tnode->floc); length += j+1; }else // it would be too long break; } return buf; } #define TRACE_ON // function Realloc ----------------------------------------- void* Realloc(void* p,size_t t,char* file,int line) { msg("[file=\"%s\",line=%d,function=%s], reallocation segment at address %x to new size %d\n", file,line,REPORT(),p,t); p = realloc(p,t); msg("[file=\"%s\",line=%d,function=%s],segment reallocated to address %x\n", file,line,REPORT(),p); return p; } // function Malloc ------------------------------------------- void* Malloc(size_t t,char* file,int line) { void* p; p = malloc(t); msg("[file=\"%s\",line=%d,function=%s],segment of size %d allocated at address %x\n", file,line,REPORT(),t,p); return p; } // function Free ---------------------------------------------- void Free(void* p,char* file,int line) { free(p); msg("[file=\"%s\",line=%d,function=%s],segment at address %x deallocated\n", file,line,REPORT(),p); } #define realloc(a,b) Realloc(a,b,__FILE__,__LINE__) #define malloc(a) Malloc(a,__FILE__,__LINE__) #define free(a) Free(a,__FILE__,__LINE__) // function add_column ----------------------------------------- void add_column(int** array,int rows,int columns) { TRACE(add_column) int i; for(i=0; i<rows; i++) { array[i]=(int*) realloc(array[i],sizeof(int)*(columns+1)); array[i][columns]=10*i+columns; } RETURN }// end add_column // function doit ------------------------------------------ void doit() { TRACE(doit) int i, j, **array; array = (int**) malloc(sizeof(int*)*4); // 4 rows for(i=0; i<4; i++) { array[i]=(int*) malloc(sizeof(int)*3); // 3 columns for(j=0; j<3; j++) array[i][j]=10*i+j; } for(i=0; i<4; i++) for(j=0; j<3; j++) printf("array[%d][%d]=%d\n",i,j,array[i][j]); // and a new column add_column(array,4,3); // now display it again for(i=0; i<4; i++) for(j=0; j<4; j++) printf("array[%d][%d]=%d\n",i,j,array[i][j]); //now we are going to deallocate it for(i=0; i<4; i++) free((void*)array[i]); free((void*)array); RETURN }//end doit // function main ---------------------------------------------- int main() { TRACE(main) doit(); RETURN1(0) }// end main /* simplified logging functions --- without locking, without time, without multiprocessing, without multithreading */ /* function sys_exit ------------------------------------------- */ void sys_exit(char *fmt, ...) { va_list ap; printf("[system error] "); va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); exit(1); }/* end sys_exit */ /* function sys ------------------------------------------- */ void sys(char *fmt, ...) { va_list ap; printf("[system error] "); va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); }/* end sys */ /* function msg_exit ------------------------------------------- */ void msg_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); exit(1); }/* end msg_exit *//* function msg ------------------------------------------- */ void msg(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,0); va_end(ap); }/* end msg */ /* function Sys_exit ------------------------------------------- */ void Sys_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[system error] "); va_end(ap); exit(1); }/* end Sys_exit */ /* function Msg_exit ------------------------------------------- */ void Msg_exit(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); exit(1); }/* end Msg_exit */ /* function Sys ------------------------------------------- */ void Sys(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); }/* end Sys */ /* function Msg ------------------------------------------- */ void Msg(char *fmt, ...) { va_list ap; va_start(ap,fmt); print_msg(fmt,ap,"[]"); va_end(ap); }/* end Msg */ /* function print_msg ------------------------------------------- */ void print_msg(char *fmt,va_list ap,char* where) { FILE* fp; vsprintf(buf,fmt,ap); if (where==0) printf("%s\n",buf); else{ fp = fopen(logpath,"a"); if (fp == NULL) { printf("problem to open log\n"); exit(1); } fprintf(fp,"%s%s\n",where,buf); } }/* end print_msg */ /* function open_log ------------------------------------------ */ void open_log(char* name) { FILE* fp; strcpy(logpath,name); fp = fopen(logpath,"w"); if (fp == NULL) { printf("error opening log\n"); exit(1); } fprintf(fp,"log opened\n"); fclose(fp); }/* end open_log */
Output:
[file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=190,function=doit:main:global],segment of size 16 allocated at address 431f a0 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=192,function=doit:main:global],segment of size 12 allocated at address 431f 60 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=192,function=doit:main:global],segment of size 12 allocated at address 431f 20 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=192,function=doit:main:global],segment of size 12 allocated at address 431e e0 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=192,function=doit:main:global],segment of size 12 allocated at address 431e a0 array[0][0]=0 array[0][1]=1 array[0][2]=2 array[1][0]=10 array[1][1]=11 array[1][2]=12 array[2][0]=20 array[2][1]=21 array[2][2]=22 array[3][0]=30 array[3][1]=31 array[3][2]=32 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main], reallocation segment at address 431f60 to new size 16 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main],segment reallocated to address 431f60 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main], reallocation segment at address 431f20 to new size 16 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main],segment reallocated to address 431f20 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main], reallocation segment at address 431ee0 to new size 16 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main],segment reallocated to address 431ee0 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main], reallocation segment at address 431ea0 to new size 16 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=176,function=add_column:doit:main],segment reallocated to address 431ea0 array[0][0]=0 array[0][1]=1 array[0][2]=2 array[0][3]=3 array[1][0]=10 array[1][1]=11 array[1][2]=12 array[1][3]=13 array[2][0]=20 array[2][1]=21 array[2][2]=22 array[2][3]=23 array[3][0]=30 array[3][1]=31 array[3][2]=32 array[3][3]=33 [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=210,function=doit:main:global],segment at address 431f60 deallocated [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=210,function=doit:main:global],segment at address 431f20 deallocated [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=210,function=doit:main:global],segment at address 431ee0 deallocated [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=210,function=doit:main:global],segment at address 431ea0 deallocated [file="C:\Documents and Settings\Dr. F. Franek\Desktop\membook-programs\p1.cpp", line=211,function=doit:main:global],segment at address 431fa0 deallocated
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 10 Index