Mercurial > libpst
view src/debug.c @ 55:0cdbd066f65a stable-0-6-6
add missing news items, add reference to mercurial repository in the documentation
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 31 Jan 2008 22:15:29 -0800 |
parents | f66078abed38 |
children | b12f4e50e2e8 |
line wrap: on
line source
#include "define.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <ctype.h> #include <string.h> #include <limits.h> #ifdef _WIN32 # define vsnprintf _vsnprintf #endif struct pst_debug_item { int type; char * function; unsigned int line; char * file; char * text; struct pst_debug_item *next; } *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL; struct pst_debug_func { char * name; struct pst_debug_func *next; } *func_head=NULL, *func_ptr=NULL; void pst_debug_write_msg(struct pst_debug_item *item, char *fmt, va_list *ap, int size); void pst_debug_write_hex(struct pst_debug_item *item, unsigned char *buf, size_t size, int col); void * xmalloc(size_t size); // the largest text size we will store in memory. Otherwise we // will do a debug_write, then create a new record, and write the // text body directly to the file #define MAX_MESSAGE_SIZE 4096 void pst_debug(char *fmt, ...) { va_list ap; va_start(ap,fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #define NUM_COL 30 void pst_debug_hexdumper(FILE *out, unsigned char *buf, size_t size, int col, int delta) { int off = 0, toff; int count = 0; if (!out) return; // no file if (col == -1) col = NUM_COL; fprintf(out, "\n"); while (off < size) { fprintf(out, "%06X\t:", off+delta); toff = off; while (count < col && off < size) { fprintf(out, "%02hhx ", buf[off]); off++; count++; } off = toff; while (count < col) { // only happens at end of block to pad the text over to the text column fprintf(out, " "); count++; } count = 0; fprintf(out, ":"); while (count < col && off < size) { fprintf(out, "%c", isgraph(buf[off])?buf[off]:'.'); off++; count ++; } fprintf(out, "\n"); count=0; } fprintf(out, "\n"); } FILE *debug_fp = NULL; unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0; void pst_debug_init(char* fname) { unsigned char version = DEBUG_VERSION; item_head = item_tail = NULL; curr_items = 0; if (debug_fp) pst_debug_close(); if (!fname) return; if ((debug_fp = fopen(fname, "wb")) == NULL) { fprintf(stderr, "Opening of file %s failed\n", fname); exit(1); } fwrite(&version, 1, sizeof(char), debug_fp); } // function must be called before pst_debug_msg. It sets up the // structure for the function that follows void pst_debug_msg_info(int line, char* file, int type) { char *x; if (!debug_fp) return; // no file info_ptr = (struct pst_debug_item*) xmalloc(sizeof(struct pst_debug_item)); info_ptr->type = type; info_ptr->line = line; x = (func_head==NULL?"No Function":func_head->name); info_ptr->function = (char*) xmalloc(strlen(x)+1); strcpy(info_ptr->function, x); info_ptr->file = (char*) xmalloc(strlen(file)+1); strcpy(info_ptr->file, file); //put the current record on a temp linked list info_ptr->next = temp_list; temp_list = info_ptr; } void pst_debug_msg_text(char* fmt, ...) { va_list ap; int f, g; char x[2]; struct pst_debug_item *temp; if (!debug_fp) return; // no file va_start(ap, fmt); // get the record off of the temp_list info_ptr = temp_list; if (info_ptr) temp_list = info_ptr->next; else { fprintf(stderr, "NULL info_ptr. ERROR!!\n"); exit(-2); } // according to glibc 2.1, this should return the req. number of bytes for // the string #ifdef _WIN32 // vsnprintf trick doesn't work. must use function called _vscprintf // cannot find much documentation about this on internet or anywhere. // I assume it isn't a standard function, but only in VisualC++ f = _vscprintf(fmt, ap); #else f = vsnprintf(x, 1, fmt, ap); #endif va_end(ap); // must be called after vsnprintf() if (f > 0 && f < MAX_MESSAGE_SIZE) { info_ptr->text = (char*) xmalloc(f+1); va_start(ap, fmt); if ((g = vsnprintf(info_ptr->text, f, fmt, ap)) == -1) { fprintf(stderr, "_debug_msg: Dieing! vsnprintf returned -1 for format \"%s\"\n", fmt); exit(-2); } va_end(ap); info_ptr->text[g] = '\0'; if (f != g) { fprintf(stderr, "_debug_msg: f != g\n"); } } else if (f > 0) { // it is over the max_message_size then f += strlen(info_ptr->file)+strlen(info_ptr->function); temp = info_ptr; pst_debug_write(); // dump the current messages info_ptr = temp; va_start(ap, fmt); pst_debug_write_msg(info_ptr, fmt, &ap, f); va_end(ap); free(info_ptr->function); free(info_ptr->file); free(info_ptr); info_ptr = NULL; return; } else { fprintf(stderr, "_debug_msg: error getting requested size of debug message\n"); info_ptr->text = "ERROR Saving\n"; } if (!item_head) item_head = info_ptr; info_ptr->next = NULL; if (item_tail) item_tail->next = info_ptr; item_tail = info_ptr; if (++curr_items == max_items) { // here we will jump off and save the contents pst_debug_write(); info_ptr = NULL; } } void pst_debug_hexdump(unsigned char *x, size_t y, int cols, int delta) { struct pst_debug_item *temp; if (!debug_fp) return; // no file info_ptr = temp_list; if (info_ptr) temp_list = info_ptr->next; temp = info_ptr; pst_debug_write(); info_ptr = temp; pst_debug_write_hex(info_ptr, x, y, cols); free(info_ptr->function); free(info_ptr->file); free(info_ptr); info_ptr = NULL; } void pst_debug_func(char *function) { func_ptr = xmalloc (sizeof(struct pst_debug_func)); func_ptr->name = xmalloc(strlen(function)+1); strcpy(func_ptr->name, function); func_ptr->next = func_head; func_head = func_ptr; } void pst_debug_func_ret() { //remove the head item func_ptr = func_head; if (func_head) { func_head = func_head->next; free(func_ptr->name); free(func_ptr); } else { DIE(("function list is empty!\n")); } } void pst_debug_close(void) { pst_debug_write(); while (func_head) { func_ptr = func_head; func_head = func_head->next; free(func_ptr->name); free(func_ptr); } if (debug_fp) fclose(debug_fp); debug_fp = NULL; } void pst_debug_write() { size_t size, ptr, funcname, filename, text, end; char *buf = NULL, rec_type; if (!debug_fp) return; // no file off_t index_pos = ftell(debug_fp); off_t file_pos = index_pos; // add 2. One for the pointer to the next index, // one for the count of this index int index_size = ((curr_items+2) * sizeof(off_t)); off_t *index; int index_ptr = 0; struct pst_debug_file_rec_m mfile_rec; struct pst_debug_file_rec_l lfile_rec; if (curr_items == 0) return; // no items to write. index = (off_t*)xmalloc(index_size); memset(index, 0, index_size); // valgrind, avoid writing uninitialized data file_pos += index_size; // write the index first, we will re-write it later, but // we want to allocate the space fwrite(index, index_size, 1, debug_fp); index[index_ptr++] = curr_items; item_ptr = item_head; while (item_ptr) { file_pos = ftell(debug_fp); index[index_ptr++] = file_pos; size = strlen(item_ptr->function) + strlen(item_ptr->file) + strlen(item_ptr->text) + 3; //for the three \0s if (buf) free(buf); buf = xmalloc(size+1); ptr = 0; funcname=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1; filename=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1; text=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1; end=ptr; if (end > USHRT_MAX) { // bigger than can be stored in a short rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.type = item_ptr->type; lfile_rec.line = item_ptr->line; lfile_rec.funcname = funcname; lfile_rec.filename = filename; lfile_rec.text = text; lfile_rec.end = end; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { rec_type = 'M'; fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.type = item_ptr->type; mfile_rec.line = item_ptr->line; mfile_rec.funcname = funcname; mfile_rec.filename = filename; mfile_rec.text = text; mfile_rec.end = end; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } fwrite(buf, 1, ptr, debug_fp); if (buf) free(buf); buf = NULL; item_head = item_ptr->next; free(item_ptr->function); free(item_ptr->file); free(item_ptr->text); free(item_ptr); item_ptr = item_head; } curr_items = 0; index[index_ptr] = ftell(debug_fp); // we should now have a complete index fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); fseek(debug_fp, 0, SEEK_END); item_ptr = item_head = item_tail = NULL; free(index); if (buf) free(buf); } void pst_debug_write_msg(struct pst_debug_item *item, char *fmt, va_list *ap, int size) { struct pst_debug_file_rec_l lfile_rec; struct pst_debug_file_rec_m mfile_rec; unsigned char rec_type; int index_size = 3 * sizeof(off_t); off_t index[3]; off_t index_pos, file_pos; char zero='\0'; unsigned int end; if (!debug_fp) return; // no file index[0] = 1; //only one item in this index index_pos = ftell(debug_fp); fwrite(index, index_size, 1, debug_fp); index[1] = ftell(debug_fp); if (size > USHRT_MAX) { // bigger than can be stored in a short rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.type = item->type; lfile_rec.line = item->line; lfile_rec.funcname = 0; lfile_rec.filename = strlen(item->function)+1; lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { rec_type = 'M'; fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.type = item->type; mfile_rec.line = item->line; mfile_rec.funcname = 0; mfile_rec.filename = strlen(item->function)+1; mfile_rec.text = mfile_rec.filename+strlen(item->file)+1; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } file_pos = ftell(debug_fp); fwrite(item->function, strlen(item->function)+1, 1, debug_fp); fwrite(item->file, strlen(item->file)+1, 1, debug_fp); vfprintf(debug_fp, fmt, *ap); fwrite(&zero, 1, 1, debug_fp); end = ftell(debug_fp)-file_pos; index[2] = ftell(debug_fp); fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); if (size > USHRT_MAX) { fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.end = end; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.end = end; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } fseek(debug_fp, 0, SEEK_END); } void pst_debug_write_hex(struct pst_debug_item *item, unsigned char *buf, size_t size, int col) { struct pst_debug_file_rec_l lfile_rec; unsigned char rec_type; int index_size = 3 * sizeof(off_t); off_t index_pos, file_pos, index[3]; char zero='\0'; if (!debug_fp) return; // no file index[0] = 1; // only one item in this index run index[1] = 0; // valgrind, avoid writing uninitialized data index[2] = 0; // "" index_pos = ftell(debug_fp); fwrite(index, index_size, 1, debug_fp); index[1] = ftell(debug_fp); // always use the long rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.funcname = 0; lfile_rec.filename = strlen(item->function)+1; lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; lfile_rec.end = 0; // valgrind, avoid writing uninitialized data lfile_rec.line = item->line; lfile_rec.type = item->type; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); file_pos = ftell(debug_fp); fwrite(item->function, strlen(item->function)+1, 1, debug_fp); fwrite(item->file, strlen(item->file)+1, 1, debug_fp); pst_debug_hexdumper(debug_fp, buf, size, col, 0); fwrite(&zero, 1, 1, debug_fp); lfile_rec.end = ftell(debug_fp) - file_pos; index[2] = ftell(debug_fp); fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); fwrite(&rec_type, 1, sizeof(char), debug_fp); fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); fseek(debug_fp, 0, SEEK_END); } void *xmalloc(size_t size) { void *mem = malloc(size); if (!mem) { fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); exit(1); } return mem; }