Mercurial > libpst
comparison src/debug.c @ 16:c508ee15dfca
switch to automake/autoconf
author | carl |
---|---|
date | Sun, 19 Feb 2006 18:47:46 -0800 |
parents | |
children | b88ceb81dba2 |
comparison
equal
deleted
inserted
replaced
15:ac98f448b6ab | 16:c508ee15dfca |
---|---|
1 /* Contains the debug functions */ | |
2 #include <stdio.h> | |
3 #include <stdlib.h> | |
4 #include <stdarg.h> | |
5 #include <ctype.h> | |
6 #include <string.h> | |
7 #include <limits.h> | |
8 #include "define.h" | |
9 | |
10 #ifdef _WIN32 | |
11 # define vsnprintf _vsnprintf | |
12 #endif | |
13 | |
14 struct _debug_item { | |
15 int type; | |
16 char * function; | |
17 unsigned int line; | |
18 char * file; | |
19 char * text; | |
20 struct _debug_item *next; | |
21 } *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL; | |
22 | |
23 struct _debug_func { | |
24 char * name; | |
25 struct _debug_func *next; | |
26 } *func_head=NULL, *func_ptr=NULL; | |
27 | |
28 | |
29 void _debug_init(char *fname); | |
30 void _debug_msg_info (int line, char *file, int type); | |
31 void _debug_msg(char* fmt, ...); | |
32 void _debug_hexdump(char *x, int y, int cols); | |
33 void _debug_func(char *function); | |
34 void _debug_func_ret(); | |
35 void _debug_close(); | |
36 void _debug_write(); | |
37 void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size); | |
38 void _debug_write_hex(struct _debug_item *item, char *buf, int size, int col); | |
39 void * xmalloc(size_t size); | |
40 | |
41 // the largest text size we will store in memory. Otherwise we | |
42 // will do a debug_write, then create a new record, and write the | |
43 // text body directly to the file | |
44 #define MAX_MESSAGE_SIZE 4096 | |
45 | |
46 void _pst_debug(char *fmt, ...) { | |
47 va_list ap; | |
48 va_start(ap,fmt); | |
49 vfprintf(stderr, fmt, ap); | |
50 va_end(ap); | |
51 } | |
52 | |
53 #define NUM_COL 30 | |
54 void _pst_debug_hexdump(FILE *out, unsigned char *buf, size_t size, int col) { | |
55 int off = 0, toff; | |
56 int count = 0; | |
57 | |
58 if (col == -1) { | |
59 col = NUM_COL; | |
60 } | |
61 fprintf(out, "\n"); | |
62 while (off < size) { | |
63 fprintf(out, "%X\t:", off); | |
64 toff = off; | |
65 while (count < col && off < size) { | |
66 fprintf(out, "%02hhx ", buf[off]); | |
67 off++; count++; | |
68 } | |
69 off = toff; | |
70 while (count < col) { | |
71 // only happens at end of block to pad the text over to the text column | |
72 fprintf(out, " "); | |
73 count++; | |
74 } | |
75 count = 0; | |
76 fprintf(out, ":"); | |
77 while (count < col && off < size) { | |
78 fprintf(out, "%c", isgraph(buf[off])?buf[off]:'.'); | |
79 off++; count ++; | |
80 } | |
81 | |
82 fprintf(out, "\n"); | |
83 count=0; | |
84 } | |
85 | |
86 fprintf(out, "\n"); | |
87 } | |
88 | |
89 void _pst_debug_hexprint(char *data, int size) { | |
90 int i = 0; | |
91 while (i < size) { | |
92 fprintf(stderr, "%02hhX", data[i]); | |
93 i++; | |
94 } | |
95 } | |
96 | |
97 FILE *debug_fp = NULL; | |
98 unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0; | |
99 | |
100 void _debug_init(char* fname) { | |
101 unsigned char version = DEBUG_VERSION; | |
102 item_head = item_tail = NULL; | |
103 curr_items = 0; | |
104 if (debug_fp != NULL) | |
105 _debug_close(); | |
106 if ((debug_fp = fopen(fname, "wb")) == NULL) { | |
107 fprintf(stderr, "Opening of file %s failed\n", fname); | |
108 exit(1); | |
109 } | |
110 fwrite(&version, 1, sizeof(char), debug_fp); | |
111 } | |
112 | |
113 // function must be called before _debug_msg. It sets up the | |
114 // structure for the function that follows | |
115 void _debug_msg_info(int line, char* file, int type) { | |
116 char *x; | |
117 if (debug_fp == NULL) { | |
118 fprintf(stderr, "debug_fp is NULL\n"); | |
119 return; | |
120 } | |
121 info_ptr = (struct _debug_item*) xmalloc(sizeof(struct _debug_item)); | |
122 info_ptr->type = type; | |
123 info_ptr->line = line; | |
124 x = (func_head==NULL?"No Function":func_head->name); | |
125 info_ptr->function = (char*) xmalloc(strlen(x)+1); | |
126 strcpy(info_ptr->function, x); | |
127 | |
128 info_ptr->file = (char*) xmalloc(strlen(file)+1); | |
129 strcpy(info_ptr->file, file); | |
130 | |
131 //put the current record on a temp linked list | |
132 info_ptr->next = temp_list; | |
133 temp_list = info_ptr; | |
134 } | |
135 | |
136 void _debug_msg_text(char* fmt, ...) { | |
137 va_list ap; | |
138 int f, g; | |
139 char x[2]; | |
140 struct _debug_item *temp; | |
141 if (debug_fp == NULL) | |
142 return; | |
143 va_start(ap, fmt); | |
144 // get the record off of the temp_list | |
145 info_ptr = temp_list; | |
146 if (info_ptr != NULL) | |
147 temp_list = info_ptr->next; | |
148 else { | |
149 fprintf(stderr, "NULL info_ptr. ERROR!!\n"); | |
150 exit(-2); | |
151 } | |
152 // according to glibc 2.1, this should return the req. number of bytes for | |
153 // the string | |
154 #ifdef _WIN32 | |
155 // vsnprintf trick doesn't work. must use function called _vscprintf | |
156 // cannot find much documentation about this on internet or anywhere. | |
157 // I assume it isn't a standard function, but only in VisualC++ | |
158 f = _vscprintf(fmt, ap); | |
159 #else | |
160 f = vsnprintf(x, 1, fmt, ap); | |
161 #endif | |
162 | |
163 if (f > 0 && f < MAX_MESSAGE_SIZE) { | |
164 info_ptr->text = (char*) xmalloc(f+1); | |
165 if ((g = vsnprintf(info_ptr->text, f, fmt, ap)) == -1) { | |
166 fprintf(stderr, "_debug_msg: Dieing! vsnprintf returned -1 for format \"%s\"\n", fmt); | |
167 exit(-2); | |
168 } | |
169 info_ptr->text[g] = '\0'; | |
170 if (f != g) { | |
171 fprintf(stderr, "_debug_msg: f != g\n"); | |
172 } | |
173 } else if (f > 0) { // it is over the max_message_size then | |
174 f += strlen(info_ptr->file)+strlen(info_ptr->function); | |
175 temp = info_ptr; | |
176 _debug_write(); // dump the current messages | |
177 info_ptr = temp; | |
178 _debug_write_msg(info_ptr, fmt, &ap, f); | |
179 free(info_ptr->function); | |
180 free(info_ptr->file); | |
181 free(info_ptr); | |
182 info_ptr = NULL; | |
183 return; | |
184 } else { | |
185 fprintf(stderr, "_debug_msg: error getting requested size of debug message\n"); | |
186 info_ptr->text = "ERROR Saving\n"; | |
187 } | |
188 va_end(ap); | |
189 | |
190 if (item_head == NULL) | |
191 item_head = info_ptr; | |
192 | |
193 info_ptr->next = NULL; | |
194 if (item_tail != NULL) | |
195 item_tail->next = info_ptr; | |
196 item_tail = info_ptr; | |
197 | |
198 if (++curr_items == max_items) { | |
199 // here we will jump off and save the contents | |
200 _debug_write(); | |
201 info_ptr = NULL; | |
202 } | |
203 } | |
204 | |
205 void _debug_hexdump(char *x, int y, int cols) { | |
206 struct _debug_item *temp; | |
207 if (debug_fp == NULL) | |
208 return; | |
209 info_ptr = temp_list; | |
210 if (info_ptr != NULL) | |
211 temp_list = info_ptr->next; | |
212 temp = info_ptr; | |
213 _debug_write(); | |
214 info_ptr = temp; | |
215 _debug_write_hex(info_ptr, x, y, cols); | |
216 free(info_ptr->function); | |
217 free(info_ptr->file); | |
218 free(info_ptr); | |
219 info_ptr = NULL; | |
220 } | |
221 | |
222 void _debug_func(char *function) { | |
223 func_ptr = xmalloc (sizeof(struct _debug_func)); | |
224 func_ptr->name = xmalloc(strlen(function)+1); | |
225 strcpy(func_ptr->name, function); | |
226 func_ptr->next = func_head; | |
227 func_head = func_ptr; | |
228 } | |
229 | |
230 void _debug_func_ret() { | |
231 //remove the head item | |
232 func_ptr = func_head; | |
233 if (func_head != NULL) { | |
234 func_head = func_head->next; | |
235 free(func_ptr->name); | |
236 free(func_ptr); | |
237 } else { | |
238 DIE(("function list is empty!\n")); | |
239 } | |
240 } | |
241 | |
242 void _debug_close(void) { | |
243 _debug_write(); | |
244 while (func_head != NULL) { | |
245 func_ptr = func_head; | |
246 func_head = func_head->next; | |
247 free(func_ptr->name); | |
248 free(func_ptr); | |
249 } | |
250 | |
251 if (debug_fp != NULL) | |
252 fclose(debug_fp); | |
253 debug_fp = NULL; | |
254 | |
255 if (func_head != NULL) | |
256 while (func_head != NULL) { | |
257 printf("function '%s' still on stack\n", func_head->name); | |
258 func_head = func_head->next; | |
259 } | |
260 } | |
261 | |
262 void _debug_write() { | |
263 size_t size, ptr, funcname, filename, text, end; | |
264 char *buf, rec_type; | |
265 long index_pos = ftell (debug_fp), file_pos = index_pos; | |
266 // add 2. One for the pointer to the next index, | |
267 // one for the count of this index | |
268 int index_size = ((curr_items+2) * sizeof(int)); | |
269 int *index; | |
270 int index_ptr = 0; | |
271 struct _debug_file_rec_m mfile_rec; | |
272 struct _debug_file_rec_l lfile_rec; | |
273 | |
274 if (curr_items == 0) | |
275 // no items to write. | |
276 return; | |
277 index = (int*) xmalloc(index_size); | |
278 file_pos += index_size; | |
279 // write the index first, we will re-write it later, but | |
280 // we want to allocate the space | |
281 fwrite(index, index_size, 1, debug_fp); | |
282 index[index_ptr++] = curr_items; | |
283 | |
284 item_ptr = item_head; | |
285 while (item_ptr != NULL) { | |
286 file_pos = ftell(debug_fp); | |
287 index[index_ptr++] = file_pos; | |
288 size = strlen(item_ptr->function)+strlen(item_ptr->file)+ | |
289 strlen(item_ptr->text) + 3; //for the three \0s | |
290 buf = xmalloc(size+1); | |
291 ptr = 0; | |
292 funcname=ptr; | |
293 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1; | |
294 filename=ptr; | |
295 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1; | |
296 text=ptr; | |
297 ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1; | |
298 end=ptr; | |
299 if (end > USHRT_MAX) { // bigger than can be stored in a short | |
300 rec_type = 'L'; | |
301 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
302 lfile_rec.type = item_ptr->type; | |
303 lfile_rec.line = item_ptr->line; | |
304 lfile_rec.funcname = funcname; | |
305 lfile_rec.filename = filename; | |
306 lfile_rec.text = text; | |
307 lfile_rec.end = end; | |
308 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
309 } else { | |
310 rec_type = 'M'; | |
311 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
312 mfile_rec.type = item_ptr->type; | |
313 mfile_rec.line = item_ptr->line; | |
314 mfile_rec.funcname = funcname; | |
315 mfile_rec.filename = filename; | |
316 mfile_rec.text = text; | |
317 mfile_rec.end = end; | |
318 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
319 } | |
320 fwrite(buf, 1, ptr, debug_fp); | |
321 item_head = item_ptr->next; | |
322 free(item_ptr->function); | |
323 free(item_ptr->file); | |
324 free(item_ptr->text); | |
325 free(item_ptr); | |
326 item_ptr = item_head; | |
327 } | |
328 curr_items = 0; | |
329 index[index_ptr] = ftell(debug_fp); | |
330 | |
331 // we should now have a complete index | |
332 fseek(debug_fp, index_pos, SEEK_SET); | |
333 fwrite(index, index_size, 1, debug_fp); | |
334 fseek(debug_fp, 0, SEEK_END); | |
335 item_ptr = item_head = item_tail = NULL; | |
336 free(index); | |
337 } | |
338 | |
339 void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size) { | |
340 struct _debug_file_rec_l lfile_rec; | |
341 struct _debug_file_rec_m mfile_rec; | |
342 unsigned char rec_type; | |
343 int index_size = 3 * sizeof(int); | |
344 int *index = malloc(index_size); | |
345 int index_pos, file_pos; | |
346 char zero='\0'; | |
347 unsigned int end; | |
348 index[0] = 1; //only one item in this index | |
349 index_pos = ftell(debug_fp); | |
350 fwrite(index, index_size, 1, debug_fp); | |
351 | |
352 index[1] = ftell(debug_fp); | |
353 | |
354 if (size > USHRT_MAX) { // bigger than can be stored in a short | |
355 rec_type = 'L'; | |
356 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
357 lfile_rec.type = item->type; | |
358 lfile_rec.line = item->line; | |
359 lfile_rec.funcname = 0; | |
360 lfile_rec.filename = strlen(item->function)+1; | |
361 lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; | |
362 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
363 } else { | |
364 rec_type = 'M'; | |
365 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
366 mfile_rec.type = item->type; | |
367 mfile_rec.line = item->line; | |
368 mfile_rec.funcname = 0; | |
369 mfile_rec.filename = strlen(item->function)+1; | |
370 mfile_rec.text = mfile_rec.filename+strlen(item->file)+1; | |
371 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
372 } | |
373 file_pos = ftell(debug_fp); | |
374 fwrite(item->function, strlen(item->function)+1, 1, debug_fp); | |
375 fwrite(item->file, strlen(item->file)+1, 1, debug_fp); | |
376 vfprintf(debug_fp, fmt, *ap); | |
377 fwrite(&zero, 1, 1, debug_fp); | |
378 | |
379 end = ftell(debug_fp)-file_pos; | |
380 | |
381 index[2] = ftell(debug_fp); | |
382 fseek(debug_fp, index_pos, SEEK_SET); | |
383 fwrite(index, index_size, 1, debug_fp); | |
384 if (size > USHRT_MAX) { | |
385 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
386 lfile_rec.end = end; | |
387 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
388 } else { | |
389 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
390 mfile_rec.end = end; | |
391 fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); | |
392 } | |
393 fseek(debug_fp, 0, SEEK_END); | |
394 // that should do it... | |
395 } | |
396 | |
397 void _debug_write_hex(struct _debug_item *item, char *buf, int size, int col) { | |
398 struct _debug_file_rec_l lfile_rec; | |
399 unsigned char rec_type; | |
400 int index_size = 3 * sizeof(int); | |
401 int *index = malloc(index_size); | |
402 int index_pos, file_pos; | |
403 char zero='\0'; | |
404 index[0] = 1; // only one item in this index run | |
405 index_pos = ftell(debug_fp); | |
406 fwrite(index, index_size, 1, debug_fp); | |
407 index[1] = ftell(debug_fp); | |
408 | |
409 // always use the long | |
410 rec_type = 'L'; | |
411 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
412 lfile_rec.type = item->type; | |
413 lfile_rec.line = item->line; | |
414 lfile_rec.funcname = 0; | |
415 lfile_rec.filename = strlen(item->function)+1; | |
416 lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; | |
417 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
418 | |
419 file_pos = ftell(debug_fp); | |
420 fwrite(item->function, strlen(item->function)+1, 1, debug_fp); | |
421 fwrite(item->file, strlen(item->file)+1, 1, debug_fp); | |
422 | |
423 _pst_debug_hexdump(debug_fp, buf, size, col); | |
424 fwrite(&zero, 1, 1, debug_fp); | |
425 lfile_rec.end = ftell(debug_fp)-file_pos; | |
426 | |
427 index[2] = ftell(debug_fp); | |
428 fseek(debug_fp, index_pos, SEEK_SET); | |
429 fwrite(index, index_size, 1, debug_fp); | |
430 fwrite(&rec_type, 1, sizeof(char), debug_fp); | |
431 fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); | |
432 fseek(debug_fp, 0, SEEK_END); | |
433 } | |
434 | |
435 void * xmalloc(size_t size) { | |
436 void *mem = malloc(size); | |
437 if (mem == NULL) { | |
438 fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); | |
439 exit(1); | |
440 } | |
441 return mem; | |
442 } | |
443 |