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

debug.c

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

Generated on Thu Dec 11 11:58:49 2008 for 'LibPst' by  doxygen 1.3.9.1