blob: 3808e60eaf28247e7abf8747fc95fe438a55118a [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
sewardj601371a2005-04-25 16:21:17 +000058/* Arse! Really I want to test VG_PLATFORM, but this does not
59 seem to be possible. */
60#if defined(__i386__) && defined(__linux__)
sewardj1cf558c2005-04-25 01:36:56 +000061
62static UInt local_sys_write_stderr ( HChar* buf, Int n )
63{
64 UInt __res;
tom311400b2005-04-27 08:58:53 +000065 __asm__ volatile (
66 "movl $4, %%eax\n" /* set %eax = __NR_write */
67 "movl $2, %%ebx\n" /* set %ebx = stderr */
68 "movl %1, %%ecx\n" /* set %ecx = buf */
sewardjd4d203b2005-04-27 23:17:48 +000069 "movl %2, %%edx\n" /* set %edx = n */
tom311400b2005-04-27 08:58:53 +000070 "int $0x80\n" /* write(stderr, buf, n) */
71 "movl %%eax, %0\n" /* set __res = eax */
72 : "=mr" (__res)
sewardjd4d203b2005-04-27 23:17:48 +000073 : "g" (buf), "g" (n)
74 : "eax", "ebx", "ecx", "edx"
75 );
sewardj1cf558c2005-04-25 01:36:56 +000076 if (__res < 0)
77 __res = -1;
78 return __res;
79}
80
81static UInt local_sys_getpid ( void )
82{
83 UInt __res;
tom311400b2005-04-27 08:58:53 +000084 __asm__ volatile (
85 "movl $20, %%eax\n" /* set %eax = __NR_getpid */
86 "int $0x80\n" /* getpid() */
87 "movl %%eax, %0\n" /* set __res = eax */
sewardjd4d203b2005-04-27 23:17:48 +000088 : "=mr" (__res)
89 :
90 : "eax" );
sewardj1cf558c2005-04-25 01:36:56 +000091 return __res;
92}
93
sewardj601371a2005-04-25 16:21:17 +000094#elif defined(__x86_64__) && defined(__linux__)
95
96static UInt local_sys_write_stderr ( HChar* buf, Int n )
97{
tomc6121862005-04-27 09:23:02 +000098 UInt __res;
99 __asm__ volatile (
100 "movq $1, %%rax\n" /* set %rax = __NR_write */
101 "movq $2, %%rdi\n" /* set %rdi = stderr */
102 "movq %1, %%rsi\n" /* set %rsi = buf */
sewardjd4d203b2005-04-27 23:17:48 +0000103 "movl %2, %%edx\n" /* set %edx = n */
tomc6121862005-04-27 09:23:02 +0000104 "syscall\n" /* write(stderr, buf, n) */
105 "movl %%eax, %0\n" /* set __res = %eax */
106 : "=mr" (__res)
107 : "g" (buf), "g" (n)
108 : "rax", "rdi", "rsi", "rdx" );
109 if (__res < 0)
110 __res = -1;
111 return __res;
sewardj601371a2005-04-25 16:21:17 +0000112}
113
114static UInt local_sys_getpid ( void )
115{
tomc6121862005-04-27 09:23:02 +0000116 UInt __res;
117 __asm__ volatile (
118 "movq $39, %%rax\n" /* set %rax = __NR_getpid */
119 "syscall\n" /* getpid() */
120 "movl %%eax, %0\n" /* set __res = %eax */
121 : "=mr" (__res)
122 :
123 : "rax" );
124 return __res;
sewardj601371a2005-04-25 16:21:17 +0000125}
sewardj1cf558c2005-04-25 01:36:56 +0000126
127#else
128#error Unknown VG_PLATFORM
129#endif
130
131
132/* ----- generic ----- */
133
134/* strlen, so we don't need m_libc */
135static Int local_strlen ( const HChar* str )
136{
137 Int i = 0;
138 while (str[i] != 0) i++;
139 return i;
140}
141
142static HChar local_toupper ( HChar c )
143{
144 if (c >= 'a' && c <= 'z')
145 return c + ('A' - 'a');
146 else
147 return c;
148}
149
150/* Emit buf[0 .. n-1] to stderr. Unfortunately platform-specific.
151*/
152static void emit ( HChar* buf, Int n )
153{
154 if (n >= 1)
155 (void)local_sys_write_stderr(buf, n);
156}
157
158
159/*------------------------------------------------------------*/
160/*--- A simple, generic, vprintf implementation. ---*/
161/*------------------------------------------------------------*/
162
163/* -----------------------------------------------
164 Distantly derived from:
165
166 vprintf replacement for Checker.
167 Copyright 1993, 1994, 1995 Tristan Gingold
168 Written September 1993 Tristan Gingold
169 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
170
171 (Checker itself was GPL'd.)
172 ----------------------------------------------- */
173
174/* Some flags. */
175#define VG_MSG_SIGNED 1 /* The value is signed. */
176#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
177#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
178#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
179#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
180
181
182/* Copy a string into the buffer. */
183static
184UInt myvprintf_str ( void(*send)(HChar,void*),
185 void* send_arg2,
186 Int flags,
187 Int width,
188 HChar* str,
189 Bool capitalise )
190{
191# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
192 UInt ret = 0;
193 Int i, extra;
194 Int len = local_strlen(str);
195
196 if (width == 0) {
197 ret += len;
198 for (i = 0; i < len; i++)
199 send(MAYBE_TOUPPER(str[i]), send_arg2);
200 return ret;
201 }
202
203 if (len > width) {
204 ret += width;
205 for (i = 0; i < width; i++)
206 send(MAYBE_TOUPPER(str[i]), send_arg2);
207 return ret;
208 }
209
210 extra = width - len;
211 if (flags & VG_MSG_LJUSTIFY) {
212 ret += extra;
213 for (i = 0; i < extra; i++)
214 send(' ', send_arg2);
215 }
216 ret += len;
217 for (i = 0; i < len; i++)
218 send(MAYBE_TOUPPER(str[i]), send_arg2);
219 if (!(flags & VG_MSG_LJUSTIFY)) {
220 ret += extra;
221 for (i = 0; i < extra; i++)
222 send(' ', send_arg2);
223 }
224
225# undef MAYBE_TOUPPER
226 return ret;
227}
228
229
230/* Write P into the buffer according to these args:
231 * If SIGN is true, p is a signed.
232 * BASE is the base.
233 * If WITH_ZERO is true, '0' must be added.
234 * WIDTH is the width of the field.
235 */
236static
237UInt myvprintf_int64 ( void(*send)(HChar,void*),
238 void* send_arg2,
239 Int flags,
240 Int base,
241 Int width,
242 ULong p )
243{
244 HChar buf[40];
245 Int ind = 0;
246 Int i, nc = 0;
247 Bool neg = False;
248 HChar* digits = "0123456789ABCDEF";
249 UInt ret = 0;
250
251 if (base < 2 || base > 16)
252 return ret;
253
254 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
255 p = - (Long)p;
256 neg = True;
257 }
258
259 if (p == 0)
260 buf[ind++] = '0';
261 else {
262 while (p > 0) {
263 if (flags & VG_MSG_COMMA && 10 == base &&
264 0 == (ind-nc) % 3 && 0 != ind)
265 {
266 buf[ind++] = ',';
267 nc++;
268 }
269 buf[ind++] = digits[p % base];
270 p /= base;
271 }
272 }
273
274 if (neg)
275 buf[ind++] = '-';
276
277 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
278 for(; ind < width; ind++) {
279 /* vg_assert(ind < 39); */
280 if (ind > 39) {
281 buf[39] = 0;
282 break;
283 }
284 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
285 }
286 }
287
288 /* Reverse copy to buffer. */
289 ret += ind;
290 for (i = ind -1; i >= 0; i--) {
291 send(buf[i], send_arg2);
292 }
293 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
294 for(; ind < width; ind++) {
295 ret++;
296 /* Never pad with zeroes on RHS -- changes the value! */
297 send(' ', send_arg2);
298 }
299 }
300 return ret;
301}
302
303
304/* A simple vprintf(). */
305/* EXPORTED */
306UInt
307VG_(debugLog_vprintf) (
308 void(*send)(HChar,void*),
309 void* send_arg2,
310 const HChar* format,
311 va_list vargs
312)
313{
314 UInt ret = 0;
315 Int i;
316 Int flags;
317 Int width;
318 Bool is_long;
319
320 /* We assume that vargs has already been initialised by the
321 caller, using va_start, and that the caller will similarly
322 clean up with va_end.
323 */
324
325 for (i = 0; format[i] != 0; i++) {
326 if (format[i] != '%') {
327 send(format[i], send_arg2);
328 ret++;
329 continue;
330 }
331 i++;
332 /* A '%' has been found. Ignore a trailing %. */
333 if (format[i] == 0)
334 break;
335 if (format[i] == '%') {
336 /* `%%' is replaced by `%'. */
337 send('%', send_arg2);
338 ret++;
339 continue;
340 }
341 flags = 0;
342 is_long = False;
343 width = 0; /* length of the field. */
344 if (format[i] == '(') {
345 flags |= VG_MSG_PAREN;
346 i++;
347 }
348 /* If ',' follows '%', commas will be inserted. */
349 if (format[i] == ',') {
350 flags |= VG_MSG_COMMA;
351 i++;
352 }
353 /* If '-' follows '%', justify on the left. */
354 if (format[i] == '-') {
355 flags |= VG_MSG_LJUSTIFY;
356 i++;
357 }
358 /* If '0' follows '%', pads will be inserted. */
359 if (format[i] == '0') {
360 flags |= VG_MSG_ZJUSTIFY;
361 i++;
362 }
363 /* Compute the field length. */
364 while (format[i] >= '0' && format[i] <= '9') {
365 width *= 10;
366 width += format[i++] - '0';
367 }
368 while (format[i] == 'l') {
369 i++;
370 is_long = True;
371 }
372
373 switch (format[i]) {
374 case 'd': /* %d */
375 flags |= VG_MSG_SIGNED;
376 if (is_long)
377 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
378 (ULong)(va_arg (vargs, Long)));
379 else
380 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
381 (ULong)(va_arg (vargs, Int)));
382 break;
383 case 'u': /* %u */
384 if (is_long)
385 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
386 (ULong)(va_arg (vargs, ULong)));
387 else
388 ret += myvprintf_int64(send, send_arg2, flags, 10, width,
389 (ULong)(va_arg (vargs, UInt)));
390 break;
391 case 'p': /* %p */
392 ret += 2;
393 send('0',send_arg2);
394 send('x',send_arg2);
395 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
396 (ULong)((UWord)va_arg (vargs, void *)));
397 break;
398 case 'x': /* %x */
399 if (is_long)
400 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
401 (ULong)(va_arg (vargs, ULong)));
402 else
403 ret += myvprintf_int64(send, send_arg2, flags, 16, width,
404 (ULong)(va_arg (vargs, UInt)));
405 break;
406 case 'c': /* %c */
407 ret++;
408 send(va_arg (vargs, int), send_arg2);
409 break;
410 case 's': case 'S': { /* %s */
411 char *str = va_arg (vargs, char *);
412 if (str == (char*) 0) str = "(null)";
413 ret += myvprintf_str(send, send_arg2,
414 flags, width, str, format[i]=='S');
415 break;
416 }
417// case 'y': { /* %y - print symbol */
418// Char buf[100];
419// Char *cp = buf;
420// Addr a = va_arg(vargs, Addr);
421//
422// if (flags & VG_MSG_PAREN)
423// *cp++ = '(';
424// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
425// if (flags & VG_MSG_PAREN) {
426// cp += VG_(strlen)(cp);
427// *cp++ = ')';
428// *cp = '\0';
429// }
430// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
431// }
432// break;
433// }
434 default:
435 break;
436 }
437 }
438 return ret;
439}
440
441
442/*------------------------------------------------------------*/
443/*--- Debuglog stuff. ---*/
444/*------------------------------------------------------------*/
445
446/* Only print messages whose stated level is less than or equal to
447 this. By default, it makes this entire subsystem silent. */
448
449static Int loglevel = 0;
450
451/* EXPORTED */
452/* Module startup. */
453void VG_(debugLog_startup) ( Int level, HChar* who )
454{
455 if (level < 0) level = 0;
456 if (level > 10) level = 10;
457 loglevel = level;
458 VG_(debugLog)(1, "debuglog",
459 "DebugLog system started by %s, "
460 "level %d logging requested\n",
461 who, loglevel);
462}
463
464/* ------------ */
465
466typedef
467 struct {
468 HChar buf[100];
469 Int n;
470 }
471 printf_buf;
472
473static void add_to_buf ( HChar c, void* p )
474{
475 printf_buf* buf = (printf_buf*)p;
476
477 if (buf->n >= 100-10 /*paranoia*/ ) {
478 emit( buf->buf, local_strlen(buf->buf) );
479 buf->n = 0;
480 buf->buf[buf->n] = 0;
481 }
482 buf->buf[buf->n++] = c;
483 buf->buf[buf->n] = 0;
484}
485
486/* Send a logging message. Nothing is output unless 'level'
487 is <= the current loglevel. */
488/* EXPORTED */
489__attribute__((format(__printf__, 3, 4)))
490void VG_(debugLog) ( Int level, const HChar* modulename,
491 const HChar* format, ... )
492{
493 UInt ret, pid;
sewardja5ebfa92005-04-25 02:04:54 +0000494 Int indent;
sewardj1cf558c2005-04-25 01:36:56 +0000495 va_list vargs;
496 printf_buf buf;
sewardja5ebfa92005-04-25 02:04:54 +0000497
sewardj1cf558c2005-04-25 01:36:56 +0000498
499 if (level > loglevel)
500 return;
501
sewardjd85feff2005-04-25 02:37:56 +0000502 indent = 2*level - 1;
sewardja5ebfa92005-04-25 02:04:54 +0000503 if (indent < 1) indent = 1;
504
sewardj1cf558c2005-04-25 01:36:56 +0000505 buf.n = 0;
506 buf.buf[0] = 0;
507 pid = local_sys_getpid();
sewardja5ebfa92005-04-25 02:04:54 +0000508 (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
509 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
510 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000511 (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)level );
sewardja5ebfa92005-04-25 02:04:54 +0000512 (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
sewardj1cf558c2005-04-25 01:36:56 +0000513 (void)myvprintf_str ( add_to_buf, &buf, 0, 8, (HChar*)modulename, False );
sewardja5ebfa92005-04-25 02:04:54 +0000514 (void)myvprintf_str ( add_to_buf, &buf, 0, indent, "", False );
sewardj1cf558c2005-04-25 01:36:56 +0000515
516 va_start(vargs,format);
517
518 ret = VG_(debugLog_vprintf) ( add_to_buf, &buf, format, vargs );
519
520 if (buf.n > 0) {
521 emit( buf.buf, local_strlen(buf.buf) );
522 }
523
524 va_end(vargs);
525}
526
527
528
529/*--------------------------------------------------------------------*/
530/*--- end m_debuglog.c ---*/
531/*--------------------------------------------------------------------*/