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

Last change on this file since 4670 was 4670, checked in by Sam Hocevar, 10 years ago

Fix the printf reimplementation to properly handle INT_MIN.

  • Property svn:keywords set to Id
File size: 5.9 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 = -i) ? "-" : "0", 1); /* XXX: hack here */ \
50        if (i <= 0) \
51        { \
52            i = -(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            int i = va_arg(args, int);
160            append("WHUT", 4);
161            WRITE_INT(i, 10);
162        }
163        else if(f[0] == 'l' && (f[1] == 'i' || f[1] == 'd'))
164        {
165            long int i = va_arg(args, long int);
166            WRITE_INT(i, 10);
167            f++;
168        }
169        else if(f[0] == 'l' && f[1] == 'l' && (f[2] == 'i' || f[1] == 'd'))
170        {
171            long long int i = va_arg(args, long long int);
172            WRITE_INT(i, 10);
173            f += 2;
174        }
175        else if(f[0] == 'g')
176        {
177            double g = va_arg(args, double), h = 0.0000001;
178            int i = (int)g;
179            WRITE_INT(i, 10);
180            for(i = 0; i < 7; i++)
181            {
182                g = (g - (int)g) * 10;
183                h *= 10;
184                if(g < h)
185                    break;
186                if(i == 0)
187                    append(".", 1);
188                append(hex2char + (int)g, 1);
189            }
190        }
191        else if(f[0] == 'p')
192        {
193            uintptr_t i = va_arg(args, uintptr_t);
194            if(!i)
195                append("NULL", 4);
196            else
197            {
198                append("0x", 2);
199                WRITE_INT(i, 16);
200            }
201        }
202        else if(f[0] == 's')
203        {
204            char *s = va_arg(args, char *);
205            if(!s)
206                append("(nil)", 5);
207            else
208            {
209                int l = 0;
210                while(s[l])
211                    l++;
212                append(s, l);
213            }
214        }
215        else if(f[0] == '0' && f[1] == '2' && f[2] == 'x')
216        {
217            int i = va_arg(args, int);
218            append(hex2char + ((i & 0xf0) >> 4), 1);
219            append(hex2char + (i & 0x0f), 1);
220            f += 2;
221        }
222        else
223        {
224            append(f - 1, 2);
225        }
226    }
227    append("\n", 1);
228
229    /* If the debug fd is open, we send the data */
230    if (_zz_debugfd >= 0)
231    {
232        write(_zz_debugfd, debugbuffer, debugcount);
233        debugcount = 0;
234    }
235
236    errno = saved_errno;
237}
238
Note: See TracBrowser for help on using the repository browser.