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, 1, sizeof(char), 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     if (!item_head)
00195       item_head = info_ptr;
00196 
00197     info_ptr->next = NULL;
00198     if (item_tail) item_tail->next = info_ptr;
00199     item_tail = info_ptr;
00200 
00201     if (++curr_items == max_items) {
00202         // here we will jump off and save the contents
00203         pst_debug_write();
00204         info_ptr = NULL;
00205     }
00206 }
00207 
00208 
00209 void pst_debug_hexdump(char *x, size_t y, int cols, int delta) {
00210     struct pst_debug_item *temp;
00211     if (!debug_fp) return;  // no file
00212     info_ptr = temp_list;
00213     if (info_ptr) temp_list = info_ptr->next;
00214     temp = info_ptr;
00215     pst_debug_write();
00216     info_ptr = temp;
00217     pst_debug_write_hex(info_ptr, x, y, cols);
00218     free(info_ptr->function);
00219     free(info_ptr->file);
00220     free(info_ptr);
00221     info_ptr = NULL;
00222 }
00223 
00224 
00225 void pst_debug_func(const char *function) {
00226     func_ptr = xmalloc (sizeof(struct pst_debug_func));
00227     func_ptr->name = xmalloc(strlen(function)+1);
00228     strcpy(func_ptr->name, function);
00229     func_ptr->next = func_head;
00230     func_head = func_ptr;
00231 }
00232 
00233 
00234 void pst_debug_func_ret() {
00235     //remove the head item
00236     func_ptr = func_head;
00237     if (func_head) {
00238         func_head = func_head->next;
00239         free(func_ptr->name);
00240         free(func_ptr);
00241     } else {
00242         DIE(("function list is empty!\n"));
00243     }
00244 }
00245 
00246 
00247 void pst_debug_close(void) {
00248     pst_debug_write();
00249     while (func_head) {
00250         func_ptr = func_head;
00251         func_head = func_head->next;
00252         free(func_ptr->name);
00253         free(func_ptr);
00254     }
00255     if (debug_fp) fclose(debug_fp);
00256     debug_fp = NULL;
00257 }
00258 
00259 
00260 void pst_debug_write() {
00261     size_t size, ptr, funcname, filename, text, end;
00262     char *buf = NULL, rec_type;
00263     if (!debug_fp) return;  // no file
00264     off_t index_pos = ftello(debug_fp);
00265     off_t file_pos  = index_pos;
00266     // add 2. One for the pointer to the next index,
00267     // one for the count of this index
00268     int index_size = ((curr_items+2) * sizeof(off_t));
00269     off_t *index;
00270     int index_ptr = 0;
00271     struct pst_debug_file_rec_m mfile_rec;
00272     struct pst_debug_file_rec_l lfile_rec;
00273 
00274     if (curr_items == 0) return;    // no items to write.
00275 
00276     index = (off_t*)xmalloc(index_size);
00277     memset(index, 0, index_size);   // valgrind, avoid writing uninitialized data
00278     file_pos += index_size;
00279     // write the index first, we will re-write it later, but
00280     // we want to allocate the space
00281     pst_debug_fwrite(index, index_size, 1, debug_fp);
00282     index[index_ptr++] = curr_items;
00283 
00284     item_ptr = item_head;
00285     while (item_ptr) {
00286         file_pos = ftello(debug_fp);
00287         index[index_ptr++] = file_pos;
00288         size = strlen(item_ptr->function) +
00289                strlen(item_ptr->file)     +
00290                strlen(item_ptr->text)     + 3; //for the three \0s
00291         if (buf) free(buf);
00292         buf = xmalloc(size+1);
00293         ptr = 0;
00294         funcname=ptr;
00295         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1;
00296         filename=ptr;
00297         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1;
00298         text=ptr;
00299         ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1;
00300         end=ptr;
00301         if (end > USHRT_MAX) { // bigger than can be stored in a short
00302             rec_type = 'L';
00303             pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00304             lfile_rec.type = item_ptr->type;
00305             lfile_rec.line = item_ptr->line;
00306             lfile_rec.funcname = funcname;
00307             lfile_rec.filename = filename;
00308             lfile_rec.text = text;
00309             lfile_rec.end = end;
00310             pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00311         } else {
00312             rec_type = 'M';
00313             pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00314             mfile_rec.type = item_ptr->type;
00315             mfile_rec.line = item_ptr->line;
00316             mfile_rec.funcname = funcname;
00317             mfile_rec.filename = filename;
00318             mfile_rec.text = text;
00319             mfile_rec.end = end;
00320             pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00321         }
00322         pst_debug_fwrite(buf, 1, ptr, debug_fp);
00323         if (buf) free(buf); buf = NULL;
00324         item_head = item_ptr->next;
00325         free(item_ptr->function);
00326         free(item_ptr->file);
00327         free(item_ptr->text);
00328         free(item_ptr);
00329         item_ptr = item_head;
00330     }
00331     curr_items = 0;
00332     index[index_ptr] = ftello(debug_fp);
00333 
00334     // we should now have a complete index
00335     fseeko(debug_fp, index_pos, SEEK_SET);
00336     pst_debug_fwrite(index, index_size, 1, debug_fp);
00337     fseeko(debug_fp, 0, SEEK_END);
00338     item_ptr = item_head = item_tail = NULL;
00339     free(index);
00340     if (buf) free(buf);
00341 }
00342 
00343 
00344 void pst_debug_write_msg(struct pst_debug_item *item, const char *fmt, va_list *ap, int size) {
00345     struct pst_debug_file_rec_l lfile_rec;
00346     struct pst_debug_file_rec_m mfile_rec;
00347     unsigned char rec_type;
00348     int index_size = 3 * sizeof(off_t);
00349     off_t index[3];
00350     off_t index_pos, file_pos;
00351     char zero='\0';
00352     unsigned int end;
00353     if (!debug_fp) return;  // no file
00354     index[0] = 1; //only one item in this index
00355     index_pos = ftello(debug_fp);
00356     pst_debug_fwrite(index, index_size, 1, debug_fp);
00357 
00358     index[1] = ftello(debug_fp);
00359 
00360     if (size > USHRT_MAX) { // bigger than can be stored in a short
00361         rec_type = 'L';
00362         pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00363         lfile_rec.type = item->type;
00364         lfile_rec.line = item->line;
00365         lfile_rec.funcname = 0;
00366         lfile_rec.filename = strlen(item->function)+1;
00367         lfile_rec.text = lfile_rec.filename+strlen(item->file)+1;
00368         pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00369     } else {
00370         rec_type = 'M';
00371         pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00372         mfile_rec.type = item->type;
00373         mfile_rec.line = item->line;
00374         mfile_rec.funcname = 0;
00375         mfile_rec.filename = strlen(item->function)+1;
00376         mfile_rec.text = mfile_rec.filename+strlen(item->file)+1;
00377         pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00378     }
00379     file_pos = ftello(debug_fp);
00380     pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
00381     pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);
00382     vfprintf(debug_fp, fmt, *ap);
00383     pst_debug_fwrite(&zero, 1, 1, debug_fp);
00384 
00385     end = (unsigned int) (ftello(debug_fp) - file_pos);
00386 
00387     index[2] = ftello(debug_fp);
00388     fseeko(debug_fp, index_pos, SEEK_SET);
00389     pst_debug_fwrite(index, index_size, 1, debug_fp);
00390     if (size > USHRT_MAX) {
00391         pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00392         lfile_rec.end = end;
00393         pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00394     } else {
00395         pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00396         mfile_rec.end = end;
00397         pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
00398     }
00399     fseeko(debug_fp, 0, SEEK_END);
00400 }
00401 
00402 
00403 void pst_debug_write_hex(struct pst_debug_item *item, char *buf, size_t size, int col) {
00404     struct pst_debug_file_rec_l lfile_rec;
00405     unsigned char rec_type;
00406     int index_size = 3 * sizeof(off_t);
00407     off_t index_pos, file_pos, index[3];
00408     char zero='\0';
00409     if (!debug_fp) return;  // no file
00410     index[0] = 1; // only one item in this index run
00411     index[1] = 0; // valgrind, avoid writing uninitialized data
00412     index[2] = 0; // ""
00413     index_pos = ftello(debug_fp);
00414     pst_debug_fwrite(index, index_size, 1, debug_fp);
00415     index[1] = ftello(debug_fp);
00416 
00417     // always use the long
00418     rec_type = 'L';
00419     pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00420     lfile_rec.funcname = 0;
00421     lfile_rec.filename = strlen(item->function)+1;
00422     lfile_rec.text = lfile_rec.filename+strlen(item->file)+1;
00423     lfile_rec.end  = 0; // valgrind, avoid writing uninitialized data
00424     lfile_rec.line = item->line;
00425     lfile_rec.type = item->type;
00426     pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00427 
00428     file_pos = ftello(debug_fp);
00429     pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
00430     pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);
00431 
00432     pst_debug_hexdumper(debug_fp, buf, size, col, 0);
00433     pst_debug_fwrite(&zero, 1, 1, debug_fp);
00434     lfile_rec.end = ftello(debug_fp) - file_pos;
00435 
00436     index[2] = ftello(debug_fp);
00437     fseeko(debug_fp, index_pos, SEEK_SET);
00438     pst_debug_fwrite(index, index_size, 1, debug_fp);
00439     pst_debug_fwrite(&rec_type, 1, sizeof(char), debug_fp);
00440     pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
00441     fseeko(debug_fp, 0, SEEK_END);
00442 }
00443 
00444 
00445 void *xmalloc(size_t size) {
00446     void *mem = malloc(size);
00447     if (!mem) {
00448         fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size);
00449         exit(1);
00450     }
00451     return mem;
00452 }
00453 

Generated on Tue Aug 5 12:06:13 2008 for 'LibPst' by  doxygen 1.3.9.1