view src/debug.c @ 118:0f1492b7fe8b

patch from Fridrich Strba for building on mingw and general cleanup of autoconf files add processing for pst files of type 0x0f start adding support for properly building and installing libpst.so and the header files required to use it. remove version.h since the version number is now in config.h more const correctness issues regarding getopt()
author Carl Byington <carl@five-ten-sg.com>
date Sat, 31 Jan 2009 12:12:36 -0800
parents 1fc33da23175
children bdb38b434c0a
line wrap: on
line source


#include "define.h"
//#include <stdint.h>

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, const char *fmt, va_list *ap, int size);
void pst_debug_write_hex(struct pst_debug_item *item, char *buf, size_t size, int col);
void * xmalloc(size_t size);

size_t pst_debug_fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream) {
    return fwrite(ptr, size, nitems, stream);
}


// 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(const 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, char *buf, size_t size, int col, int delta) {
    size_t 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, "%06"PRIx64"\t:", (uint64_t)(off+delta));
        toff = off;
        while (count < col && off < size) {
            fprintf(out, "%02hhx ", (unsigned char)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(const 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);
    }
    pst_debug_fwrite(&version, sizeof(char), 1, 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, const 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(const char* fmt, ...) {
    va_list ap;
    int f, g;
    char x[2];
    #ifdef _WIN32
        char *buf = NULL;
    #endif
    struct pst_debug_item *temp;
    if (!debug_fp) return;  // no file
    // 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);
    }

    #ifdef _WIN32
        // vsnprintf trick doesn't work on msvc.
        g = 2000;
        f = -1;
        while (f < 0) {
            buf = realloc(buf, g+1);
            va_start(ap, fmt);
            f = vsnprintf(buf, g, fmt, ap);
            va_end(ap);
            g += g/2;
        }
        free(buf);
    #else
        // according to glibc 2.1, this should return the req. number of bytes for
        // the string
        va_start(ap, fmt);
        f = vsnprintf(x, 1, fmt, ap);
        va_end(ap);
    #endif

    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: Dying! 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";
    }

    // add to the linked list of pending items
    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(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(const 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 = ftello(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
    pst_debug_fwrite(index, index_size, 1, debug_fp);
    index[index_ptr++] = curr_items;

    item_ptr = item_head;
    while (item_ptr) {
        file_pos = ftello(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';
            pst_debug_fwrite(&rec_type, sizeof(char), 1, 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;
            pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
        } else {
            rec_type = 'M';
            pst_debug_fwrite(&rec_type, sizeof(char), 1, 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;
            pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
        }
        pst_debug_fwrite(buf, ptr, 1, 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] = ftello(debug_fp);

    // we should now have a complete index
    fseeko(debug_fp, index_pos, SEEK_SET);
    pst_debug_fwrite(index, index_size, 1, debug_fp);
    fseeko(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, const 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[1] = 0; // valgrind, avoid writing uninitialized data
    index[2] = 0; // ""
    index_pos = ftello(debug_fp);
    pst_debug_fwrite(index, index_size, 1, debug_fp);

    index[1] = ftello(debug_fp);

    if (size > USHRT_MAX) { // bigger than can be stored in a short
        rec_type = 'L';
        pst_debug_fwrite(&rec_type, sizeof(char), 1, 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;
        lfile_rec.end      = 0; // valgrind, avoid writing uninitialized data
        pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
    } else {
        rec_type = 'M';
        pst_debug_fwrite(&rec_type, sizeof(char), 1, 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;
        mfile_rec.end      = 0; // valgrind, avoid writing uninitialized data
        pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
    }
    file_pos = ftello(debug_fp);
    pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
    pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);
    vfprintf(debug_fp, fmt, *ap);
    pst_debug_fwrite(&zero, 1, 1, debug_fp);

    end = (unsigned int) (ftello(debug_fp) - file_pos);

    index[2] = ftello(debug_fp);
    fseeko(debug_fp, index_pos, SEEK_SET);
    pst_debug_fwrite(index, index_size, 1, debug_fp);
    if (size > USHRT_MAX) {
        pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
        lfile_rec.end = end;
        pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
    } else {
        pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
        mfile_rec.end = end;
        pst_debug_fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp);
    }
    fseeko(debug_fp, 0, SEEK_END);
}


void pst_debug_write_hex(struct pst_debug_item *item, 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 = ftello(debug_fp);
    pst_debug_fwrite(index, index_size, 1, debug_fp);
    index[1] = ftello(debug_fp);

    // always use the long
    rec_type = 'L';
    pst_debug_fwrite(&rec_type, sizeof(char), 1, 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;
    pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);

    file_pos = ftello(debug_fp);
    pst_debug_fwrite(item->function, strlen(item->function)+1, 1, debug_fp);
    pst_debug_fwrite(item->file, strlen(item->file)+1, 1, debug_fp);

    pst_debug_hexdumper(debug_fp, buf, size, col, 0);
    pst_debug_fwrite(&zero, 1, 1, debug_fp);
    lfile_rec.end = ftello(debug_fp) - file_pos;

    index[2] = ftello(debug_fp);
    fseeko(debug_fp, index_pos, SEEK_SET);
    pst_debug_fwrite(index, index_size, 1, debug_fp);
    pst_debug_fwrite(&rec_type, sizeof(char), 1, debug_fp);
    pst_debug_fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
    fseeko(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;
}