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

Generated on Fri Apr 17 12:59:05 2009 for 'LibPst' by  doxygen 1.3.9.1