Mercurial > libpst
diff src/debug.c @ 16:c508ee15dfca
switch to automake/autoconf
author | carl |
---|---|
date | Sun, 19 Feb 2006 18:47:46 -0800 |
parents | |
children | b88ceb81dba2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/debug.c Sun Feb 19 18:47:46 2006 -0800 @@ -0,0 +1,443 @@ +/* Contains the debug functions */ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> +#include "define.h" + +#ifdef _WIN32 +# define vsnprintf _vsnprintf +#endif + +struct _debug_item { + int type; + char * function; + unsigned int line; + char * file; + char * text; + struct _debug_item *next; +} *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL; + +struct _debug_func { + char * name; + struct _debug_func *next; +} *func_head=NULL, *func_ptr=NULL; + + +void _debug_init(char *fname); +void _debug_msg_info (int line, char *file, int type); +void _debug_msg(char* fmt, ...); +void _debug_hexdump(char *x, int y, int cols); +void _debug_func(char *function); +void _debug_func_ret(); +void _debug_close(); +void _debug_write(); +void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size); +void _debug_write_hex(struct _debug_item *item, char *buf, int 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_hexdump(FILE *out, unsigned char *buf, size_t size, int col) { + int off = 0, toff; + int count = 0; + + if (col == -1) { + col = NUM_COL; + } + fprintf(out, "\n"); + while (off < size) { + fprintf(out, "%X\t:", off); + 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"); +} + +void _pst_debug_hexprint(char *data, int size) { + int i = 0; + while (i < size) { + fprintf(stderr, "%02hhX", data[i]); + i++; + } +} + +FILE *debug_fp = NULL; +unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0; + +void _debug_init(char* fname) { + unsigned char version = DEBUG_VERSION; + item_head = item_tail = NULL; + curr_items = 0; + if (debug_fp != NULL) + _debug_close(); + 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 _debug_msg. It sets up the +// structure for the function that follows +void _debug_msg_info(int line, char* file, int type) { + char *x; + if (debug_fp == NULL) { + fprintf(stderr, "debug_fp is NULL\n"); + return; + } + info_ptr = (struct _debug_item*) xmalloc(sizeof(struct _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 _debug_msg_text(char* fmt, ...) { + va_list ap; + int f, g; + char x[2]; + struct _debug_item *temp; + if (debug_fp == NULL) + return; + va_start(ap, fmt); + // get the record off of the temp_list + info_ptr = temp_list; + if (info_ptr != NULL) + 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 + + if (f > 0 && f < MAX_MESSAGE_SIZE) { + info_ptr->text = (char*) xmalloc(f+1); + 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); + } + 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; + _debug_write(); // dump the current messages + info_ptr = temp; + _debug_write_msg(info_ptr, fmt, &ap, f); + 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"; + } + va_end(ap); + + if (item_head == NULL) + item_head = info_ptr; + + info_ptr->next = NULL; + if (item_tail != NULL) + item_tail->next = info_ptr; + item_tail = info_ptr; + + if (++curr_items == max_items) { + // here we will jump off and save the contents + _debug_write(); + info_ptr = NULL; + } +} + +void _debug_hexdump(char *x, int y, int cols) { + struct _debug_item *temp; + if (debug_fp == NULL) + return; + info_ptr = temp_list; + if (info_ptr != NULL) + temp_list = info_ptr->next; + temp = info_ptr; + _debug_write(); + info_ptr = temp; + _debug_write_hex(info_ptr, x, y, cols); + free(info_ptr->function); + free(info_ptr->file); + free(info_ptr); + info_ptr = NULL; +} + +void _debug_func(char *function) { + func_ptr = xmalloc (sizeof(struct _debug_func)); + func_ptr->name = xmalloc(strlen(function)+1); + strcpy(func_ptr->name, function); + func_ptr->next = func_head; + func_head = func_ptr; +} + +void _debug_func_ret() { + //remove the head item + func_ptr = func_head; + if (func_head != NULL) { + func_head = func_head->next; + free(func_ptr->name); + free(func_ptr); + } else { + DIE(("function list is empty!\n")); + } +} + +void _debug_close(void) { + _debug_write(); + while (func_head != NULL) { + func_ptr = func_head; + func_head = func_head->next; + free(func_ptr->name); + free(func_ptr); + } + + if (debug_fp != NULL) + fclose(debug_fp); + debug_fp = NULL; + + if (func_head != NULL) + while (func_head != NULL) { + printf("function '%s' still on stack\n", func_head->name); + func_head = func_head->next; + } +} + +void _debug_write() { + size_t size, ptr, funcname, filename, text, end; + char *buf, rec_type; + long index_pos = ftell (debug_fp), 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(int)); + int *index; + int index_ptr = 0; + struct _debug_file_rec_m mfile_rec; + struct _debug_file_rec_l lfile_rec; + + if (curr_items == 0) + // no items to write. + return; + index = (int*) xmalloc(index_size); + 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 != NULL) { + 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 + 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); + 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); +} + +void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size) { + struct _debug_file_rec_l lfile_rec; + struct _debug_file_rec_m mfile_rec; + unsigned char rec_type; + int index_size = 3 * sizeof(int); + int *index = malloc(index_size); + int index_pos, file_pos; + char zero='\0'; + unsigned int end; + 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); + // that should do it... +} + +void _debug_write_hex(struct _debug_item *item, char *buf, int size, int col) { + struct _debug_file_rec_l lfile_rec; + unsigned char rec_type; + int index_size = 3 * sizeof(int); + int *index = malloc(index_size); + int index_pos, file_pos; + char zero='\0'; + index[0] = 1; // only one item in this index run + 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.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); + + 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_hexdump(debug_fp, buf, size, col); + 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 == NULL) { + fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); + exit(1); + } + return mem; +} +