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

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

Fix a bug in the %i formatting and implement %S.

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