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;
+}
+