blob: f7467f9b9e08731e38b285e03597dda0602cc880 [file] [log] [blame]
sewardj1cf558c2005-04-25 01:36:56 +00001
2/*--------------------------------------------------------------------*/
3/*--- Debug (not-for-user) logging; also vprintf. m_debuglog.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2005 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31
32/* Performs low-level debug logging that can safely run immediately
33 after startup. To minimise the dependencies on any other parts of
34 the system, the only place the debug output may go is file
35 descriptor 2 (stderr).
36*/
37/* This is the first-initialised module in the entire system!
38 Therefore it is CRITICAL that it does not depend on any other code
39 running first. Hence only the following very limited includes. We
40 cannot depend (directly or indirectly) on any dynamic memory
41 allocation facilities, nor on the m_libc facilities, since the
42 latter depend on this module. DO NOT MESS WITH THESE INCLUDES
43 UNLESS YOU ARE 100% CERTAIN YOU UNDERSTAND THE CONSEQUENCES.
44*/
45/* This module is also different from all others in the sense that it
46 is linked into both stage1 and stage2.
47*/
48#include "basic_types.h" /* basic types */
49#include "pub_core_debuglog.h" /* our own iface */
50
51
52/*------------------------------------------------------------*/
53/*--- Stuff to make us completely independent. ---*/
54/*------------------------------------------------------------*/
55
56/* ----- x86-linux specifics ----- */
57
sewardj21c6d0f2005-05-02 10:33:44 +000058#if defined(VGP_x86_linux)
sewardj1cf558c2005-04-25 01:36:56 +000059
60static UInt local_sys_write_stderr ( HChar* buf, Int n )
61{
62 UInt __res;
tom311400b2005-04-27 08:58:53 +000063 __asm__ volatile (
sewardjd485d692005-04-28 09:40:53 +000064 "movl $4, %%eax\n" /* %eax = __NR_write */
65 "movl $2, %%edi\n" /* %edi = stderr */
66 "movl %1, %%ecx\n" /* %ecx = buf */
67 "movl %2, %%edx\n" /* %edx = n */
68 "pushl %%ebx\n"
69 "movl %%edi, %%ebx\n"
70 "int $0x80\n" /* write(stderr, buf, n) */
71 "popl %%ebx\n"
72 "movl %%eax, %0\n" /* __res = eax */
tom311400b2005-04-27 08:58:53 +000073 : "=mr" (__res)
sewardjd4d203b2005-04-27 23:17:48 +000074 : "g" (buf), "g" (n)
sewardjd485d692005-04-28 09:40:53 +000075 : "eax", "edi", "ecx", "edx"
sewardjd4d203b2005-04-27 23:17:48 +000076 );
sewardj1cf558c2005-04-25 01:36:56 +000077 if (__res < 0)
78 __res = -1;
79 return __res;
80}
81
82static UInt local_sys_getpid ( void )
83{
84 UInt __res;
tom311400b2005-04-27 08:58:53 +000085 __asm__ volatile (
86 "movl $20, %%eax\n" /* set %eax = __NR_getpid */
87 "int $0x80\n" /* getpid() */
88 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +000089 : "=mr" (__res)
90 :
91 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +000092 return __res;
93}
94
sewardj21c6d0f2005-05-02 10:33:44 +000095#elif defined(VGP_amd64_linux)
sewardj601371a2005-04-25 16:21:17 +000096
97static UInt local_sys_write_stderr ( HChar* buf, Int n )
98{
tomc6121862005-04-27 09:23:02 +000099 UInt __res;
100 __asm__ volatile (
101 "movq $1, %%rax\n" /* set %rax = __NR_write */
102 "movq $2, %%rdi\n" /* set %rdi = stderr */
103 "movq %1, %%rsi\n" /* set %rsi = buf */
sewardjd4d203b2005-04-27 23:17:48 +0000104 "movl %2, %%edx\n" /* set %edx = n */
tomc6121862005-04-27 09:23:02 +0000105 "syscall\n" /* write(stderr, buf, n) */
106 "movl %%eax, %0\n" /* set __res = %eax */
107 : "=mr" (__res)
108 : "g" (buf), "g" (n)
109 : "rax", "rdi", "rsi", "rdx" );
110 if (__res < 0)
111 __res = -1;
112 return __res;
sewardj601371a2005-04-25 16:21:17 +0000113}
114
115static UInt local_sys_getpid ( void )
116{
tomc6121862005-04-27 09:23:02 +0000117 UInt __res;
118 __asm__ volatile (
119 "movq $39, %%rax\n" /* set %rax = __NR_getpid */
120 "syscall\n" /* getpid() */
121 "movl %%eax, %0\n" /* set __res = %eax */
122 : "=mr" (__res)
123 :
124 : "rax" );
125 return __res;
sewardj601371a2005-04-25 16:21:17 +0000126}
sewardj1cf558c2005-04-25 01:36:56 +0000127
128#else
sewardj21c6d0f2005-05-02 10:33:44 +0000129# error Unknown platform
sewardj1cf558c2005-04-25 01:36:56 +0000130#endif
131
132
133/* ----- generic ----- */
134
135/* strlen, so we don't need m_libc */
136static Int local_strlen ( const HChar* str )
137{
138 Int i = 0;
139 while (str[i] != 0) i++;
140 return i;
141}
142
143static HChar local_toupper ( HChar c )
144{
145 if (c >= 'a' && c <= 'z')
146 return c + ('A' - 'a');
147 else
148 return c;
149}
150
151/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
152*/
153static void emit ( HChar* buf, Int n )
154{
155 if (n >= 1)
156 (void)local_sys_write_stderr(buf, n);
157}
158
159
160/*------------------------------------------------------------*/
161/*--- A simple, generic, vprintf implementation. ---*/
162/*------------------------------------------------------------*/
163
164/* -----------------------------------------------
165 Distantly derived from:
166
167 vprintf replacement for Checker.
168 Copyright 1993, 1994, 1995 Tristan Gingold
169 Written September 1993 Tristan Gingold
170 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
171
172 (Checker itself was GPL'd.)
173 ----------------------------------------------- */
174
175/* Some flags. */
176#define VG_MSG_SIGNED 1 /* The value is signed. */
177#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
178#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
179#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
180#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
181
182
183/* Copy a string into the buffer. */
184static
185UInt myvprintf_str ( void(*send)(HChar,void*),
186 void* send_arg2,
187 Int flags,
188 Int width,
189 HChar* str,
190 Bool capitalise )
191{
192# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
193 UInt ret = 0;
194 Int i, extra;
195 Int len = local_strlen(str);
196
197 if (width == 0) {
198 ret += len;
199 for (i = 0; i < len; i++)
200 send(MAYBE_TOUPPER(str[i]), send_arg2);
201 return ret;
202 }
203
204 if (len > width) {
205 ret += width;
206 for (i = 0; i < width; i++)
207 send(MAYBE_TOUPPER(str[i]), send_arg2);
208 return ret;
209 }
210
211 extra = width - len;
212 if (flags & VG_MSG_LJUSTIFY) {
213 ret += extra;
214 for (i = 0; i < extra; i++)
215 send(' ', send_arg2);
216 }
217 ret += len;
218 for (i = 0; i < len; i++)
219 send(MAYBE_TOUPPER(str[i]), send_arg2);
220 if (!(flags & VG_MSG_LJUSTIFY)) {
221 ret += extra;
222 for (i = 0; i < extra; i++)
223 send(' ', send_arg2);
224 }
225
226# undef MAYBE_TOUPPER
227 return ret;
228}
229
230
231/* Write P into the buffer according to these args:
232 * If SIGN is true, p is a signed.
233 * BASE is the base.
234 * If WITH_ZERO is true, '0' must be added.
235 * WIDTH is the width of the field.
236 */
237static
238UInt myvprintf_int64 ( void(*send)(HChar,void*),
239 void* send_arg2,
240 Int flags,
241 Int base,
242 Int width,
243 ULong p )
244{
245 HChar buf[40];
246 Int ind = 0;
247 Int i, nc = 0;
248 Bool neg = False;
249 HChar* digits = "0123456789ABCDEF";
250 UInt ret = 0;
251
252 if (base < 2 || base > 16)
253 return ret;
254
255 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
256 p = - (Long)p;
257 neg = True;
258 }
259
260 if (p == 0)
261 buf[ind++] = '0';
262 else {
263 while (p > 0) {
264 if (flags & VG_MSG_COMMA && 10 == base &&
265 0 == (ind-nc) % 3 && 0 != ind)
266 {
267 buf[ind++] = ',';
268 nc++;
269 }
270 buf[ind++] = digits[p % base];
271 p /= base;
272 }
273 }
274
275 if (neg)
276 buf[ind++] = '-';
277
278 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
279 for(; ind < width; ind++) {
280 /* vg_assert(ind < 39); */
281 if (ind > 39) {
282 buf[39] = 0;
283 break;
284 }
285 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
286 }
287 }
288
289 /* Reverse copy to buffer. */
290 ret += ind;
291 for (i = ind -1; i >= 0; i--) {
292 send(buf[i], send_arg2);
293 }
294 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
295 for(; ind < width; ind++) {
296 ret++;
297 /* Never pad with zeroes on RHS -- changes the value! */
298 send(' ', send_arg2);
299 }
300 }
301 return ret;
302}
303
304
305/* A simple vprintf(). */
306/* EXPORTED */
307UInt
308VG_(debugLog_vprintf) (
309 void(*send)(HChar,void*),
310 void* send_arg2,
311 const HChar* format,
312 va_list vargs
313)
314{
315 UInt ret = 0;
316 Int i;
317 Int flags;
318 Int width;
319 Bool is_long;
320
321 /* We assume that vargs has already been initialised by the
322 caller, using va_start, and that the caller will similarly
323 clean up with va_end.
324 */
325
326 for (i = 0; format[i] != 0; i++) {
327 if (format[i] != '%') {
328 send(format[i], send_arg2);
329 ret++;
330 continue;
331 }
332 i++;
333 /* A '%' has been found. Ignore a trailing %. */
334 if (format[i] == 0)
335 break;
336 if (format[i] == '%') {
337 /* `%%' is replaced by `%'. */
338 send('%', send_arg2);
339 ret++;
340 continue;
341 }
342 flags = 0;
343 is_long = False;
344 width = 0; /* length of the field. */
345 if (format[i] == '(') {
346 flags |= VG_MSG_PAREN;
347 i++;
348 }
349 /* If ',' follows '%', commas will be inserted. */
350 if (format[i] == ',') {
351 flags |= VG_MSG_COMMA;
352 i++;
353 }
354 /* If '-' follows '%', justify on the left. */
355 if (format[i] == '-') {
356 flags |= VG_MSG_LJUSTIFY;
357 i++;
358 }
359 /* If '0' follows '%', pads will be inserted. */
360 if (format[i] == '0') {
361 flags |= VG_MSG_ZJUSTIFY;
362 i++;
363 }
364 /* Compute the field length. */
365 while (format[i] >= '0' && format[i] <= '9') {
366 width *= 10;
367 width += format[i++] - '0';
368 }
369 while (format[i] == 'l') {
370 i++;
371 is_long = True;
372 }
373
374 switch (format[i]) {
375 case 'd': /* %d */
376 flags |= VG_MSG_SIGNED;
377 if (is_long)
378 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
379 (ULong)(va_arg (vargs, Long)));
380 else
381 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
382 (ULong)(va_arg (vargs, Int)));
383 break;
384 case 'u': /* %u */
385 if (is_long)
386 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
387 (ULong)(va_arg (vargs, ULong)));
388 else
389 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
390 (ULong)(va_arg (vargs, UInt)));
391 break;
392 case 'p': /* %p */
393 ret += 2;
394 send('0',send_arg2);
395 send('x',send_arg2);
396 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
397 (ULong)((UWord)va_arg (vargs, void *)));
398 break;
399 case 'x': /* %x */
400 if (is_long)
401 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
402 (ULong)(va_arg (vargs, ULong)));
403 else
404 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
405 (ULong)(va_arg (vargs, UInt)));
406 break;
407 case 'c': /* %c */
408 ret++;
409 send(va_arg (vargs, int), send_arg2);
410 break;
411 case 's': case 'S': { /* %s */
412 char *str = va_arg (vargs, char *);
413 if (str == (char*) 0) str = "(null)";
414 ret += myvprintf_str(send, send_arg2,
415 flags, width, str, format[i]=='S');
416 break;
417 }
418// case 'y': { /* %y - print symbol */
419// Char buf[100];
420// Char *cp = buf;
421// Addr a = va_arg(vargs, Addr);
422//
423// if (flags & VG_MSG_PAREN)
424// *cp++ = '(';
425// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
426// if (flags & VG_MSG_PAREN) {
427// cp += VG_(strlen)(cp);
428// *cp++ = ')';
429// *cp = '\0';
430// }
431// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
432// }
433// break;
434// }
435 default:
436 break;
437 }
438 }
439 return ret;
440}
441
442
443/*------------------------------------------------------------*/
444/*--- Debuglog stuff. ---*/
445/*------------------------------------------------------------*/
446
447/* Only print messages whose stated level is less than or equal to
448 this. By default, it makes this entire subsystem silent. */
449
450static Int loglevel = 0;
451
452/* EXPORTED */
453/* Module startup. */
454void VG_(debugLog_startup) ( Int level, HChar* who )
455{
456 if (level < 0) level = 0;
457 if (level > 10) level = 10;
458 loglevel = level;
459 VG_(debugLog)(1, "debuglog",
460 "DebugLog system started by %s, "
461 "level %d logging requested\n",
462 who, loglevel);
463}
464
465/* ------------ */
466
467typedef
468 struct {
469 HChar buf[100];
470 Int n;
471 }
472 printf_buf;
473
474static void add_to_buf ( HChar c, void* p )
475{
476 printf_buf* buf = (printf_buf*)p;
477
478 if (buf->n >= 100-10 /*paranoia*/ ) {
479 emit( buf->buf, local_strlen(buf->buf) );
480 buf->n = 0;
481 buf->buf[buf->n] = 0;
482 }
483 buf->buf[buf->n++] = c;
484 buf->buf[buf->n] = 0;
485}
486
487/* Send a logging message. Nothing is output unless 'level'
488 is <= the current loglevel. */
489/* EXPORTED */
490__attribute__((format(__printf__, 3, 4)))
491void VG_(debugLog) ( Int level, const HChar* modulename,
492 const HChar* format, ... )
493{
494 UInt ret, pid;
sewardja5ebfa92005-04-25 02:04:54 +0000495 Int indent;
sewardj1cf558c2005-04-25 01:36:56 +0000496 va_list vargs;
497 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000498
sewardj1cf558c2005-04-25 01:36:56 +0000499
500 if (level > loglevel)
501 return;
502
sewardjd85feff2005-04-25 02:37:56 +0000503 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000504 if (indent < 1) indent = 1;
505
sewardj1cf558c2005-04-25 01:36:56 +0000506 buf.n = 0;
507 buf.buf[0] = 0;
508 pid = local_sys_getpid();
sewardja5ebfa92005-04-25 02:04:54 +0000509 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
510 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
511 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000512 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000513 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000514 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000515 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000516
517 va_start(vargs,format);
518
519 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
520
521 if (buf.n > 0) {
522 emit( buf.buf, local_strlen(buf.buf) );
523 }
524
525 va_end(vargs);
526}
527
528
529
530/*--------------------------------------------------------------------*/
531/*--- end m_debuglog.c ---*/
532/*--------------------------------------------------------------------*/