Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

debug.c

Go to the documentation of this file.
00001 #include "define.h"
00002 
00003 struct pst_debug_item {
00004     int type;
00005     char * function;
00006     unsigned int line;
00007     char * file;
00008     char * text;
00009     struct pst_debug_item *next;
00010 } *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL;
00011 
00012 
00013 struct pst_debug_func {
00014     char * name;
00015     struct pst_debug_func *next;
00016 } *func_head=NULL, *func_ptr=NULL;
00017 
00018 
00019 void pst_debug_write_msg(struct pst_debug_item *item, const char *fmt, va_list *ap, int size);
00020 void pst_debug_write_hex(struct pst_debug_item *item, char *buf, size_t size, int col);
00021 void * xmalloc(size_t size);
00022 
00023 size_t pst_debug_fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream) {
00024     return fwrite(ptr, size, nitems, stream);
00025 }
00026 
00027 
00028 // the largest text size we will store in memory. Otherwise we
00029 // will do a debug_write, then create a new record, and write the
00030 // text body directly to the file
00031 #define MAX_MESSAGE_SIZE 4096
00032 
00033 void pst_debug(const char *fmt, ...) {
00034     va_list ap;
00035     va_start(ap,fmt);
00036     vfprintf(stderr, fmt, ap);
00037     va_end(ap);
00038 }
00039 
00040 
00041 #define NUM_COL 30
00042 void pst_debug_hexdumper(FILE *out, char *buf, size_t size, int col, int delta) {
00043     size_t off = 0, toff;
00044     int count = 0;
00045 
00046     if (!out) return;   // no file
00047     if (col == -1) col = NUM_COL;
00048     fprintf(out, "\n");
00049     while (off < size) {
00050         fprintf(out, "%06"PRIx64"\t:", (int64_t)(off+delta));
00051         toff = off;
00052         while (count < col && off < size) {
00053             fprintf(out, "%02hhx ", (unsigned char)buf[off]);
00054             off++; count++;
00055         }
00056         off = toff;
00057         while (count < col) {
00058             // only happens at end of block to pad the text over to the text column
00059             fprintf(out, "   ");
00060             count++;
00061         }
00062         count = 0;
00063         fprintf(out, ":");
00064         while (count < col && off < size) {
00065             fprintf(out, "%c", isgraph(buf[off])?buf[off]:'.');
00066             off++; count ++;
00067         }
00068 
00069         fprintf(out, "\n");
00070         count=0;
00071     }
00072 
00073     fprintf(out, "\n");
00074 }
00075 
00076 
00077 FILE *debug_fp = NULL;
00078 unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0;
00079 
00080 
00081 void pst_debug_init(const char* fname) {
00082     unsigned char version = DEBUG_VERSION;
00083     item_head = item_tail = NULL;
00084     curr_items = 0;
00085     if (debug_fp) pst_debug_close();
00086     if (!fname) return;
00087     if ((debug_fp = fopen(fname, "wb")) == NULL) {
00088       fprintf(stderr, "Opening of file %s failed\n", fname);
00089       exit(1);
00090     }
00091     pst_debug_fwrite(&version, sizeof(char), 1, debug_fp);
00092 }
00093 
00094 
00095 // function must be called before pst_debug_msg. It sets up the
00096 // structure for the function that follows
00097 void pst_debug_msg_info(int line, const char* file, int type) {
00098     char *x;
00099     if (!debug_fp) return;  // no file
00100     info_ptr = (struct pst_debug_item*) xmalloc(sizeof(struct pst_debug_item));
00101     info_ptr->type = type;
00102     info_ptr->line = line;
00103     x = (func_head==NULL?"No Function":func_head->name);
00104     info_ptr->function = (char*) xmalloc(strlen(x)+1);
00105     strcpy(info_ptr->function, x);
00106 
00107     info_ptr->file = (char*) xmalloc(strlen(file)+1);
00108     strcpy(info_ptr->file, file);
00109 
00110     //put the current record on a temp linked list
00111     info_ptr->next = temp_list;
00112     temp_list = info_ptr;
00113 }
00114 
00115 
00116 void pst_debug_msg_text(const char* fmt, ...) {
00117     va_list ap;
00118     int f, g;
00119     char x[2];
00120     #ifdef _WIN32
00121         char *buf = NULL;
00122     #endif
00123     struct pst_debug_item *temp;
00124     if (!debug_fp) return;  // no file
00125     // get the record off of the temp_list
00126     info_ptr = temp_list;
00127     if (info_ptr)
00128         temp_list = info_ptr->next;
00129     else {
00130         fprintf(stderr, "NULL info_ptr. ERROR!!\n");
00131         exit(-2);
00132     }
00133 
00134     #ifdef _WIN32
00135         // vsnprintf trick doesn't work on msvc.
00136         g = 2000;
00137         f = -1;
00138         while (f < 0) {
00139             buf = realloc(buf, g+1);
00140             va_start(ap, fmt);
00141             f = vsnprintf(buf, g, fmt, ap);
00142             va_end(ap);
00143             g += g/2;
00144         }
00145         free(buf);
00146     #else
00147         // according to glibc 2.1, this should return the req. number of bytes for
00148         // the string
00149         va_start(ap, fmt);
00150         f = vsnprintf(x, 1, fmt, ap);
00151         va_end(ap);
00152     #endif
00153 
00154     if (f > 0 && f < MAX_MESSAGE_SIZE) {
00155         info_ptr->text = (char*) xmalloc(f+1);
00156         va_start(ap, fmt);
00157         if ((g = vsnprintf(info_ptr->text, f, fmt, ap)) == -1) {
00158             fprintf(stderr, "_debug_msg: Dying! vsnprintf returned -1 for format \"%s\"\n", fmt);
00159             exit(-2);
00160         }
00161         va_end(ap);
00162         info_ptr->text[g] = '\0';
00163         if (f != g) {
00164             fprintf(stderr, "_debug_msg: f != g\n");
00165         }
00166     } else if (f > 0) { // it is over the max_message_size then
00167         f += strlen(info_ptr->file)+strlen(info_ptr->function);
00168         temp = info_ptr;
00169         pst_debug_write(); // dump the current messages
00170         info_ptr = temp;
00171         va_start(ap, fmt);
00172         pst_debug_write_msg(info_ptr, fmt, &ap, f);
00173         va_end(ap);
00174         free(info_ptr->function);
00175         free(info_ptr->file);
00176         free(info_ptr);
00177         info_ptr = NULL;
00178         return;
00179     } else {
00180         fprintf(stderr, "_debug_msg: error getting requested size of debug message\n");
00181         info_ptr->text = "ERROR Saving\n";
00182     }
00183 
00184     // add to the linked list of pending items
00185     if (!item_head) item_head = info_ptr;
00186     info_ptr->next = NULL;
00187     if (item_tail) item_tail->next = info_ptr;
00188     item_tail = info_ptr;
00189 
00190     if (++curr_items == max_items) {
00191         // here we will jump off and save the contents
00192         pst_debug_write();
00193         info_ptr = NULL;
00194     }
00195 }
00196 
00197 
00198 void pst_debug_hexdump(char *x, size_t y, int cols, int delta) {
00199     struct pst_debug_item *temp;
00200     if (!debug_fp) return;  // no file
00201     info_ptr = temp_list;
00202     if (info_ptr) temp_list = info_ptr->next;
00203     temp = info_ptr;
00204     pst_debug_write();
00205     info_ptr = temp;
00206     pst_debug_write_hex(info_ptr, x, y, cols);
00207     free(info_ptr->function);
00208     free(info_ptr->file);
00209     free(info_ptr);
00210     info_ptr = NULL;
00211 }
00212 
00213 
00214 void pst_debug_func(const char *function) {
00215     func_ptr = xmalloc (sizeof(struct pst_debug_func));
00216     func_ptr->name = xmalloc(strlen(function)+1);
00217     strcpy(func_ptr->name, function);
00218     func_ptr->next = func_head;
00219     func_head = func_ptr;
00220 }
00221 
00222 
00223 void pst_debug_func_ret() {
00224     //remove the head item
00225     func_ptr = func_head;
00226     if (func_head) {
00227         func_head = func_head->next;
00228         free(func_ptr->name);
00229         free(func_ptr);
00230     } else {
00231         DIE(("function list is empty!\n"));
00232     }
00233 }
00234 
00235 
00236 void pst_debug_close(void) {
00237     pst_debug_write();
00238     while (func_head) {
00239         func_ptr = func_head;
00240         func_head = func_head->next;
00241         free(func_ptr->name);
00242         free(func_ptr);
00243     }
00244     if (debug_fp) fclose(debug_fp);
00245     debug_fp = NULL;
00246 }
00247 
00248 
00249 void pst_debug_write() {
00250     size_t size, ptr, funcname, filename, text, end;
00251     char *buf = NULL, rec_type;
00252     if (!debug_fp) return;  // no file
00253     int64_t index_pos = ftello(debug_fp);
00254     int64_t file_pos  = index_pos;
00255     // add 2. One for the pointer to the next index,
00256     // one for the count of this index
00257     int index_size = ((curr_items+2) * sizeof(int64_t));
00258     int64_t *index;
00259     int index_ptr = 0;
00260     struct pst_debug_file_rec_m mfile_rec;
00261     struct pst_debug_file_rec_l lfile_rec;
00262 
00263     if (curr_items == 0) return;    // no items to write.
00264 
00265     index = (int64_t*)xmalloc(index_size);
00266     memset(index, 0, index_size);   // valgrind, avoid writing uninitialized data
00267     file_pos += index_size;
00268     // write the index first, we will re-write it later, but
00269     // we want to allocate the space
00270     pst_debug_fwrite(index, index_size, 1, debug_fp);
00271     index[index_ptr++] = curr_items;
00272 
00273     item_ptr = item_head;
00274     while (item_ptr) {
00275         file_pos = ftello(debug_fp);
00276         index[index_ptr++] = file_pos;
00277         size = strlen(item_ptr->function) +
00278                strlen(item_ptr->file)     +
00279                strlen(item_ptr->text)     + 3; //for the three \0s
00280         if (buf) free(buf);
00281         buf = xmalloc(size+1);
00282         ptr = 0;
00283         funcname=ptr;
00284         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1;
00285         filename=ptr;
00286         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1;
00287         text=ptr;
00288         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1;
00289         end=ptr;
00290         if (end > USHRT_MAX) { // bigger than can be stored in a short
00291             rec_type = 'L';
00292             pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00293             lfile_rec.type     = item_ptr->type;
00294             lfile_rec.line     = item_ptr->line;
00295             lfile_rec.funcname = funcname;
00296             lfile_rec.filename = filename;
00297             lfile_rec.text     = text;
00298             lfile_rec.end      = end;
00299             pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00300         } else {
00301             rec_type = 'M';
00302             pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00303             mfile_rec.type     = item_ptr->type;
00304             mfile_rec.line     = item_ptr->line;
00305             mfile_rec.funcname = funcname;
00306             mfile_rec.filename = filename;
00307             mfile_rec.text     = text;
00308             mfile_rec.end      = end;
00309             pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00310         }
00311         pst_debug_fwrite(buf, ptr, 1, debug_fp);
00312         if (buf) free(buf); buf = NULL;
00313         item_head = item_ptr->next;
00314         free(item_ptr->function);
00315         free(item_ptr->file);
00316         free(item_ptr->text);
00317         free(item_ptr);
00318         item_ptr = item_head;
00319     }
00320     curr_items = 0;
00321     index[index_ptr] = ftello(debug_fp);
00322 
00323     // we should now have a complete index
00324     fseeko(debug_fp, index_pos, SEEK_SET);
00325     pst_debug_fwrite(index, index_size, 1, debug_fp);
00326     fseeko(debug_fp, 0, SEEK_END);
00327     item_ptr = item_head = item_tail = NULL;
00328     free(index);
00329     if (buf) free(buf);
00330 }
00331 
00332 
00333 void pst_debug_write_msg(struct pst_debug_item *item, const char *fmt, va_list *ap, int size) {
00334     struct pst_debug_file_rec_l lfile_rec;
00335     struct pst_debug_file_rec_m mfile_rec;
00336     unsigned char rec_type;
00337     int index_size = 3 * sizeof(int64_t);
00338     int64_t index[3];
00339     int64_t index_pos, file_pos;
00340     char zero = '\0';
00341     unsigned int end;
00342     if (!debug_fp) return;  // no file
00343     index[0] = 1; // only one item in this index
00344     index[1] = 0; // valgrind, avoid writing uninitialized data
00345     index[2] = 0; // ""
00346     index_pos = ftello(debug_fp);
00347     pst_debug_fwrite(index, index_size, 1, debug_fp);
00348 
00349     index[1] = ftello(debug_fp);
00350 
00351     if (size > USHRT_MAX) { // bigger than can be stored in a short
00352         rec_type = 'L';
00353         pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00354         lfile_rec.type     = item->type;
00355         lfile_rec.line     = item->line;
00356         lfile_rec.funcname = 0;
00357         lfile_rec.filename = strlen(item->function)+1;
00358         lfile_rec.text     = lfile_rec.filename+strlen(item->file)+1;
00359         lfile_rec.end      = 0; // valgrind, avoid writing uninitialized data
00360         pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00361     } else {
00362         rec_type = 'M';
00363         pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00364         mfile_rec.type     = item->type;
00365         mfile_rec.line     = item->line;
00366         mfile_rec.funcname = 0;
00367         mfile_rec.filename = strlen(item->function)+1;
00368         mfile_rec.text     = mfile_rec.filename+strlen(item->file)+1;
00369         mfile_rec.end      = 0; // valgrind, avoid writing uninitialized data
00370         pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00371     }
00372     file_pos = ftello(debug_fp);
00373     pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
00374     pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);
00375     vfprintf(debug_fp, fmt, *ap);
00376     pst_debug_fwrite(&zero, 1, 1, debug_fp);
00377 
00378     end = (unsigned int) (ftello(debug_fp) - file_pos);
00379 
00380     index[2] = ftello(debug_fp);
00381     fseeko(debug_fp, index_pos, SEEK_SET);
00382     pst_debug_fwrite(index, index_size, 1, debug_fp);
00383     if (size > USHRT_MAX) {
00384         pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00385         lfile_rec.end = end;
00386         pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00387     } else {
00388         pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00389         mfile_rec.end = end;
00390         pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00391     }
00392     fseeko(debug_fp, 0, SEEK_END);
00393 }
00394 
00395 
00396 void pst_debug_write_hex(struct pst_debug_item *item, char *buf, size_t size, int col) {
00397     struct pst_debug_file_rec_l lfile_rec;
00398     unsigned char rec_type;
00399     int index_size = 3 * sizeof(int64_t);
00400     int64_t index_pos, file_pos, index[3];
00401     char zero='\0';
00402     if (!debug_fp) return;  // no file
00403     index[0] = 1; // only one item in this index run
00404     index[1] = 0; // valgrind, avoid writing uninitialized data
00405     index[2] = 0; // ""
00406     index_pos = ftello(debug_fp);
00407     pst_debug_fwrite(index, index_size, 1, debug_fp);
00408     index[1] = ftello(debug_fp);
00409 
00410     // always use the long
00411     rec_type = 'L';
00412     pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00413     lfile_rec.funcname = 0;
00414     lfile_rec.filename = strlen(item->function)+1;
00415     lfile_rec.text = lfile_rec.filename+strlen(item->file)+1;
00416     lfile_rec.end  = 0; // valgrind, avoid writing uninitialized data
00417     lfile_rec.line = item->line;
00418     lfile_rec.type = item->type;
00419     pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00420 
00421     file_pos = ftello(debug_fp);
00422     pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
00423     pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);
00424 
00425     pst_debug_hexdumper(debug_fp, buf, size, col, 0);
00426     pst_debug_fwrite(&zero, 1, 1, debug_fp);
00427     lfile_rec.end = ftello(debug_fp) - file_pos;
00428 
00429     index[2] = ftello(debug_fp);
00430     fseeko(debug_fp, index_pos, SEEK_SET);
00431     pst_debug_fwrite(index, index_size, 1, debug_fp);
00432     pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
00433     pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00434     fseeko(debug_fp, 0, SEEK_END);
00435 }
00436 
00437 
00438 void *xmalloc(size_t size) {
00439     void *mem = malloc(size);
00440     if (!mem) {
00441         fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size);
00442         exit(1);
00443     }
00444     return mem;
00445 }
00446 

Generated on Sat Feb 7 10:22:05 2009 for 'LibPst' by  doxygen 1.3.9.1