source: zzuf/trunk/src/libzzuf/debug.c @ 4151

Last change on this file since 4151 was 4151, checked in by Sam Hocevar, 11 years ago

Buffer debug output to reduce the number of write() calls and allow to
output information that was logged before the library was initialised.

  • Property svn:keywords set to Id
File size: 5.7 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id: debug.c 4151 2009-12-20 12:24:50Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  debug.c: debugging support
17 */
18
19#include "config.h"
20
21#if defined HAVE_STDINT_H
22#   include <stdint.h>
23#elif defined HAVE_INTTYPES_H
24#   include <inttypes.h>
25#endif
26#include <stdio.h>
27#include <string.h>
28#if defined HAVE_UNISTD_H
29#   include <unistd.h>
30#endif
31#if defined HAVE_IO_H
32#   include <io.h>
33#endif
34#include <errno.h>
35#include <stdarg.h>
36
37#include "debug.h"
38#include "libzzuf.h"
39
40static void mydebug(char const *format, va_list args);
41
42/**
43 * Helper macro to write an integer value to a given file descriptor,
44 * either in base 10 or in hexadecimal.
45 */
46#define WRITE_INT(i, base) \
47    do \
48    { \
49        char buf[128], *b = buf + 127; \
50        if(i <= 0) \
51            append((i = -i) ? "-" : "0", 1); /* XXX: hack here */ \
52        while(i) \
53        { \
54            *b-- = hex2char[i % base]; \
55            i /= base; \
56        } \
57        append(b + 1, (int)(buf + 127 - b)); \
58    } while(0)
59
60/* Temporary buffer for deferred output */
61char debugbuffer[BUFSIZ];
62size_t debugcount = 1;
63
64void _zz_debug(char const *format, ...)
65{
66    va_list args;
67    va_start(args, format);
68    if (_zz_debuglevel >= 1)
69        mydebug(format, args);
70    va_end(args);
71}
72
73void _zz_debug2(char const *format, ...)
74{
75    va_list args;
76    va_start(args, format);
77    if (_zz_debuglevel >= 2)
78        mydebug(format, args);
79    va_end(args);
80}
81
82/**
83 * Format a string, printf-like, and write the resulting data to zzuf's
84 * debug file descriptor _zz_debugfd. If the debug file descriptor is
85 * still -1, this function does nothing.
86 *
87 * This function's code is roughly equivalent to the following *printf
88 * calls, except it only uses signal-safe functions:
89 *  - fprintf(stderr, "** zzuf debug ** ");
90 *  - vfprintf(stderr, format, args);
91 *  - fprintf(stderr, "\n");
92 */
93static inline void append(void const *data, size_t count)
94{
95    if (debugcount + count <= sizeof(debugbuffer))
96    {
97        memcpy(debugbuffer + debugcount, data, count);
98        debugcount += count;
99    }
100}
101
102static void mydebug(char const *format, va_list args)
103{
104    static char const *hex2char = "0123456789abcdef";
105    char const *f;
106    int saved_errno;
107
108    saved_errno = errno;
109
110    /* If there is spare data and the debug fd is open, we send the data */
111    if (debugcount && _zz_debugfd >= 0)
112    {
113        write(_zz_debugfd, debugbuffer, debugcount);
114        debugcount = 0;
115    }
116
117    append("** zzuf debug ** ", 17);
118    for(f = format; *f; f++)
119    {
120        if(*f != '%')
121        {
122            append(f, 1);
123            continue;
124        }
125
126        f++;
127        if(!*f)
128            break;
129
130        if(*f == 'c')
131        {
132            char i = (char)(unsigned char)va_arg(args, int);
133            if(i >= 0x20 && i < 0x7f)
134                append(&i, 1);
135            else if(i == '\n')
136                append("\\n", 2);
137            else if(i == '\t')
138                append("\\t", 2);
139            else if(i == '\r')
140                append("\\r", 2);
141            else
142            {
143                append("\\x", 2);
144                append(hex2char + ((i & 0xf0) >> 4), 1);
145                append(hex2char + (i & 0x0f), 1);
146            }
147        }
148        else if(*f == 'i' || *f == 'd')
149        {
150            int i = va_arg(args, int);
151            WRITE_INT(i, 10);
152        }
153        else if(*f == 'x')
154        {
155            int i = va_arg(args, int);
156            WRITE_INT(i, 16);
157        }
158        else if(f[0] == 'l' && (f[1] == 'i' || f[1] == 'd'))
159        {
160            long int i = va_arg(args, long int);
161            WRITE_INT(i, 10);
162            f++;
163        }
164        else if(f[0] == 'l' && f[1] == 'l' && (f[2] == 'i' || f[1] == 'd'))
165        {
166            long long int i = va_arg(args, long long int);
167            WRITE_INT(i, 10);
168            f += 2;
169        }
170        else if(f[0] == 'g')
171        {
172            double g = va_arg(args, double), h = 0.0000001;
173            int i = (int)g;
174            WRITE_INT(i, 10);
175            for(i = 0; i < 7; i++)
176            {
177                g = (g - (int)g) * 10;
178                h *= 10;
179                if(g < h)
180                    break;
181                if(i == 0)
182                    append(".", 1);
183                append(hex2char + (int)g, 1);
184            }
185        }
186        else if(f[0] == 'p')
187        {
188            uintptr_t i = va_arg(args, uintptr_t);
189            if(!i)
190                append("NULL", 5);
191            else
192            {
193                append("0x", 2);
194                WRITE_INT(i, 16);
195            }
196        }
197        else if(f[0] == 's')
198        {
199            char *s = va_arg(args, char *);
200            if(!s)
201                append("(nil)", 5);
202            else
203            {
204                int l = 0;
205                while(s[l])
206                    l++;
207                append(s, l);
208            }
209        }
210        else if(f[0] == '0' && f[1] == '2' && f[2] == 'x')
211        {
212            int i = va_arg(args, int);
213            append(hex2char + ((i & 0xf0) >> 4), 1);
214            append(hex2char + (i & 0x0f), 1);
215            f += 2;
216        }
217        else
218        {
219            append(f - 1, 2);
220        }
221    }
222    append("\n", 1);
223
224    /* If the debug fd is open, we send the data */
225    if (_zz_debugfd >= 0)
226    {
227        write(_zz_debugfd, debugbuffer, debugcount);
228        debugcount = 0;
229    }
230
231    errno = saved_errno;
232}
233
Note: See TracBrowser for help on using the repository browser.