view src/readpstlog.c @ 42:7a97f50c39c5 stable-0-5-12 **FUNKY**

security fix for potential buffer overrun in lz decompress
author carl
date Tue, 02 Oct 2007 16:10:36 -0700
parents 6fe121a971c9
children f6db1f060a95
line wrap: on
line source

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#ifndef _WIN32
# include <unistd.h>
#endif

#ifndef __GNUC__
# include "XGetopt.h"
#endif

#include "define.h"

#define BUF_SIZE 4096

int usage();
size_t get(void * buf, int size, unsigned int count, FILE *fp);
int split_args(char *args, int **targ);
int is_in(int a, int *b, int c);

int main(int argc, char** argv) {
	int level = 0;
	int *i=NULL, x, ptr, stop=0, flag;
	char *fname, *buf, rec_type;
	unsigned char version;
	int *show_type=NULL, show_size=0;
	int *ex_type=NULL, ex_size=0;
	unsigned int funcname, filename, text, end, dtype, line, c;
	FILE *fp;
	struct _debug_file_rec_m mfile_rec;
	struct _debug_file_rec_l lfile_rec;
	char format = 'D';  // default
	while ((c = getopt(argc, argv, "f:t:x:")) != -1) {
		switch(c) {
			case 'f':
				// change the output format
				format = toupper(optarg[0]);
				break;
			case 't':
				//change the type of statements shown
				show_size = split_args(optarg, &show_type);
				//		type = atoi(optarg);
				break;
			case 'x':
				// change the type of statements excluded
				ex_size = split_args(optarg, &ex_type);
				break;
		}
	}
	if (argc > optind) {
		fname = argv[optind++];
	} else {
		usage();
		exit(2);
	}

	fp = fopen(fname, "rb");
	if (fp == NULL) {
		printf("Error. couldn't open debug file\n");
		return 2;
	}
	if (get(&version, sizeof(char), 1, fp)==0) {
		printf("Error. could not read version byte from front of file");
		return 3;
	}

	if (version > DEBUG_VERSION) {
		printf("Version number is higher than the format I know about.");
		return 4;
	}

	buf = (char*) xmalloc(BUF_SIZE);

	while (!stop) {
		if (fread(&x, sizeof(int), 1, fp)<=0) break;
		ptr = 0;
		if (x > 0) {
			if (i) free(i);
			i = (int*)xmalloc(sizeof(int)*(x+1));
			// plus 1 cause we want to read the offset of the next index
			if (get(i, sizeof(int), x+1, fp)==0) {
				// we have reached the end of the debug file
				printf("oh dear. we must now end\n");
				break;
			}
			while (ptr < x) {
				fseek(fp,i[ptr++], SEEK_SET);
				get(&rec_type, 1, sizeof(char), fp);
				if (rec_type == 'L') {
					get(&lfile_rec, sizeof(lfile_rec), 1, fp);
					funcname=lfile_rec.funcname;
					filename=lfile_rec.filename;
					text = lfile_rec.text;
					end = lfile_rec.end;
					dtype = lfile_rec.type;
					line = lfile_rec.line;
				} else if (rec_type == 'M') {
					get(&mfile_rec, sizeof(mfile_rec), 1, fp);
					funcname = mfile_rec.funcname;
					filename = mfile_rec.filename;
					text = mfile_rec.text;
					end = mfile_rec.end;
					dtype = mfile_rec.type;
					line = mfile_rec.line;
				}
				if (dtype == DEBUG_FUNCENT_NO) level++;
				if ((show_type == NULL || is_in(dtype, show_type, show_size)) &&
					(ex_type == NULL   || !is_in(dtype, ex_type, ex_size))) {
					c = 0; flag = 0;
					while (c < end) {
						int ii = (level-1) * 4;
						if (ii < 0) ii = 0;
						if (ii > 64) ii = 64;
						char indent[ii+1];
						memset(indent, ' ', ii);
						indent[ii] = '\0';
						if (c + (BUF_SIZE-1) < end) {
							get(buf, 1, BUF_SIZE-1, fp);
							buf[BUF_SIZE-1] = '\0';
							c += BUF_SIZE-1;
						} else {
							get(buf, 1, end-c, fp);
							buf[end-c] = '\0';
							c = end;
						}
						if (flag == 0) {
							if (format == 'I') { // indented text format
								char *b = buf+text;
								printf("%s %s/%s[%d]: ", indent, &buf[filename], &buf[funcname], line);
								while (b) {
									char *p = strchr(b, '\n');
									if (p) {
										*p = '\0';
										printf("%s\n%s ", b, indent);
										b = p + 1;
									}
									else {
										printf("%s", b);
										b = NULL;
									}
								}
							}
							else if (format == 'T') { // text format
								printf("%s/%s[%d]: %s", &buf[filename], &buf[funcname], line, &buf[text]);
							} else {
								printf("Type: %d\nFile[line]: %s[%d]\nFunction:%s\nText:%s", dtype,
									   &buf[filename], line, &buf[funcname], &buf[text]);
							}
							flag = 1;
						} else {
							if (format == 'I') {
								char *b = buf;
								while (b) {
									char *p = strchr(b, '\n');
									if (p) {
										*p = '\0';
										printf("%s\n%s ", b, indent);
										b = p + 1;
									}
									else {
										printf("%s", b);
										b = NULL;
									}
								}
							}
							else printf("%s", buf);
						}
					}
					printf("\n");
				}
				if (dtype == DEBUG_FUNCRET_NO) level--;
			}
			if (fseek(fp, i[ptr], SEEK_SET)==-1) {
				printf("finished\n");
				break;
			}
		} else {
			printf("...no more items\n");
			break;
		}
	}
	free(buf);
	fclose(fp);
	return 0;
}

size_t get(void * buf, int size, unsigned int  count, FILE *fp) {
	size_t z;
	if ((z=fread(buf,size, count, fp)) < count) {
		printf("Read Failed! (size=%d, count=%d,z=%ld)\n", size, count, (long)z);
		exit(1);
	}
	return z;
}

int usage() {
	printf("readlog -t[show_type] -x[exclude_type] -f[format] filename\n");
	printf("\tformat:\n\t\tt: text log format\n");
	printf("\t\ti: indented text log format\n");
	printf("\tshow_type:\n\t\tcomma separated list of types to show "
	   "[ie, 2,4,1,6]\n");
	printf("\texclude_type:\n\t\tcomma separated list of types to exclude "
	   "[ie, 1,5,3,7]\n");
	return 0;
}


int split_args(char *args, int **targ) {
	int count = 1, *i, x, z;
	char *tmp = args, *y;
	if (*targ != NULL) {
	  free(*targ);
	}
	// find the number of tokens in the string. Starting
	// from 1 cause there will always be one
	while ((tmp = strchr(tmp, ',')) != NULL) {
		tmp++; count++;
	}
	*targ = (int*)xmalloc(count * sizeof(int));
	i = *targ; // for convienience
	tmp = args;
	z = 0;
	for (x = 0; x < count; x++) {
		y = strtok(tmp, ",");
		tmp = NULL; // must be done after first call
		if (y != NULL) {
			i[x] = atoi(y);
			z++;
		}
	}
	return z;
}


// checks to see if the first arg is in the array of the second arg,
// the size of which is specified with the third arg. If the second
// arg is NULL, then it is obvious that it is not there.
int is_in(int a, int *b, int c){
	int d = 0;
	if (b == NULL || c == 0) { // no array or no items in array
		return 0;
	}
	while (d < c) {
		if (a == b[d]) return 1;
		d++;
	}
	return 0;
}