view src/debug.c @ 60:97b7706bdda2

Work around bogus 7c.b5 blocks in some messages that have been read. They appear to have attachments, but of some unknown format. Before the message was read, it did not have any attachments. Use autoscan to cleanup our autoconf system. Use autoconf to detect when we need to use our XGetopt files and other header files. More fields, including BCC. Fix missing LE32_CPU byte swapping for FILETIME types.
author Carl Byington <carl@five-ten-sg.com>
date Sat, 16 Feb 2008 12:26:35 -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;
}