1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2003 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 #include <sys/types.h>
39 #include "vgstrpool.h"
44 static const char *vg_caller_types
[] = { "fun", "obj", NULL
};
48 vg_caller_type_to_name (vgcaller_t type
)
50 return vg_caller_types
[type
];
55 vg_caller_type_from_name (const char *name
)
59 for (i
= 0; i
< VG_CALLER_LAST
; i
++) {
60 if (!strcmp (vg_caller_types
[i
], name
))
69 vg_caller_new (vgcaller_t type
, const char *name
)
73 caller
= g_new (VgCaller
, 1);
76 caller
->name
= g_strdup (name
);
83 vg_caller_free (VgCaller
*caller
)
88 g_free (caller
->name
);
93 static const char *vg_rule_types
[] = {
94 "Addr1", "Addr2", "Addr4", "Addr8", "Cond", "Free", "Leak",
95 "Param", "PThread", "Value1", "Value2", "Value4", "Value8", NULL
100 vg_rule_type_to_name (vgrule_t type
)
102 return vg_rule_types
[type
];
107 vg_rule_type_from_name (const char *name
)
111 for (i
= 0; i
< VG_RULE_LAST
; i
++) {
112 if (!strcmp (vg_rule_types
[i
], name
))
121 vg_rule_type_from_report (const char *report
, vgrule_t
*type
, char **syscall
)
123 const char *inptr
, *call
;
130 /* FIXME: How can we auto-detect PThread errors? */
131 if (!strncmp (report
, "Conditional ", 12)) {
132 *type
= VG_RULE_COND
;
134 } else if (!strncmp (report
, "Syscall param ", 14)) {
135 *type
= VG_RULE_PARAM
;
139 if ((inptr
= strchr (call
, ' ')) != NULL
)
140 *syscall
= g_strndup (call
, (inptr
- call
));
144 } else if (!strcmp (report
, "Invalid free() / delete / delete[]")) {
145 *type
= VG_RULE_FREE
;
147 } else if ((inptr
= strstr (report
, " are still reachable in loss record "))) {
148 *type
= VG_RULE_LEAK
;
150 } else if (!strncmp (report
, "Invalid read of size ", 21)) {
152 size
= strtoul (inptr
, &end
, 10);
155 *type
= VG_RULE_ADDR1
;
158 *type
= VG_RULE_ADDR2
;
161 *type
= VG_RULE_ADDR4
;
164 *type
= VG_RULE_ADDR8
;
171 } else if ((inptr
= strstr (report
, "value of size "))) {
172 /* only reason we strstr here instead of strncmp'ing
173 * against "Use of uninitialised value of size " is
174 * that someone may eventually convince the valgrind
175 * authors to use the Americanised spelling and then
176 * our strncmp would fail */
178 size
= strtoul (inptr
, &end
, 10);
181 *type
= VG_RULE_VALUE1
;
184 *type
= VG_RULE_VALUE2
;
187 *type
= VG_RULE_VALUE4
;
190 *type
= VG_RULE_VALUE8
;
204 vg_rule_new (vgrule_t type
, const char *name
)
208 rule
= g_new (VgRule
, 1);
209 rule
->name
= g_strdup (name
);
212 rule
->syscall
= NULL
;
213 rule
->callers
= NULL
;
220 parse_tool_list (unsigned char *tool_list
)
222 VgTool
*tail
, *n
, *list
= NULL
;
223 register unsigned char *inptr
;
224 unsigned char *start
;
226 tail
= (VgTool
*) &list
;
228 start
= inptr
= tool_list
;
230 while (*inptr
&& *inptr
!= ',')
236 n
= g_new (VgTool
, 1);
238 n
->name
= vg_strdup ((char *)start
);
251 vg_rule_add_tool (VgRule
*rule
, const char *tool
)
255 n
= g_new (VgTool
, 1);
257 n
->name
= vg_strdup (tool
);
259 tail
= (VgTool
*) &rule
->tools
;
260 while (tail
->next
!= NULL
)
268 vg_rule_free (VgRule
*rule
)
277 g_free (rule
->syscall
);
282 vg_strfree (s
->name
);
299 VG_RULE_PARSER_STATE_INIT
= 0,
300 VG_RULE_PARSER_STATE_COMMENT
= (1 << 0),
301 VG_RULE_PARSER_STATE_RULE_NAME
= (1 << 1),
302 VG_RULE_PARSER_STATE_RULE_TYPE
= (1 << 2),
303 VG_RULE_PARSER_STATE_RULE_SYSCALL
= (1 << 3),
304 VG_RULE_PARSER_STATE_RULE_CALLER
= (1 << 4),
308 vg_rule_parser_new (int fd
, VgRuleParserRuleCallback rule_cb
, void *user_data
)
310 VgRuleParser
*parser
;
312 parser
= g_new (VgRuleParser
, 1);
313 parser_init ((Parser
*) parser
, fd
);
315 parser
->linebuf
= g_malloc (128);
316 parser
->lineptr
= parser
->linebuf
;
317 parser
->lineleft
= 128;
319 parser
->current
= NULL
;
322 parser
->rule_cb
= rule_cb
;
323 parser
->user_data
= user_data
;
325 parser
->state
= VG_RULE_PARSER_STATE_INIT
;
331 vg_rule_parser_free (VgRuleParser
*parser
)
336 g_free (parser
->linebuf
);
341 #define backup_linebuf(parser, start, len) G_STMT_START { \
342 if (parser->lineleft <= len) { \
343 unsigned int llen, loff; \
345 llen = loff = parser->lineptr - parser->linebuf; \
346 llen = llen ? llen : 1; \
348 while (llen < (loff + len + 1)) \
351 parser->linebuf = g_realloc (parser->linebuf, llen); \
352 parser->lineptr = parser->linebuf + loff; \
353 parser->lineleft = llen - loff; \
356 memcpy (parser->lineptr, start, len); \
357 parser->lineptr += len; \
358 parser->lineleft -= len; \
362 vg_parser_parse_caller (VgRuleParser
*parser
)
364 register unsigned char *inptr
;
368 *parser
->lineptr
= ':';
369 inptr
= parser
->linebuf
;
370 while (*inptr
!= ':')
373 if (inptr
== parser
->lineptr
) {
374 *parser
->lineptr
= '\0';
375 fprintf (stderr
, "Invalid caller field encountered: '%s'\n", parser
->linebuf
);
380 if ((type
= vg_caller_type_from_name ((char *)parser
->linebuf
)) == VG_CALLER_LAST
) {
381 fprintf (stderr
, "Invalid caller type encountered: '%s'\n", parser
->linebuf
);
385 *parser
->lineptr
= '\0';
386 caller
= vg_caller_new (type
, (char *)inptr
);
388 parser
->tail
->next
= caller
;
389 parser
->tail
= caller
;
393 vg_rule_parser_step (VgRuleParser
*parser
)
395 register unsigned char *inptr
;
396 unsigned char *start
;
400 priv
= (Parser
*) parser
;
402 if ((ret
= parser_fill (priv
)) == 0) {
404 } else if (ret
== -1) {
408 start
= inptr
= priv
->inptr
;
411 while (inptr
< priv
->inend
) {
412 if (parser
->state
== VG_RULE_PARSER_STATE_INIT
) {
414 parser
->state
= VG_RULE_PARSER_STATE_COMMENT
;
416 } else if (*inptr
== '{') {
417 parser
->state
= VG_RULE_PARSER_STATE_RULE_NAME
;
418 parser
->current
= vg_rule_new (0, NULL
);
419 parser
->tail
= (VgCaller
*) &parser
->current
->callers
;
422 /* eat any whitespace?? */
423 while (*inptr
== ' ' || *inptr
== '\t')
426 if (*inptr
== '#' || *inptr
== '{')
429 /* unknown, skip this line??? */
431 while (*inptr
!= '\n')
434 if (inptr
== priv
->inend
)
444 if (parser
->state
& VG_RULE_PARSER_STATE_COMMENT
) {
445 /* eat this line... in the future we may want to save comment lines? */
447 while (*inptr
!= '\n')
450 if (inptr
== priv
->inend
)
455 parser
->state
&= ~VG_RULE_PARSER_STATE_COMMENT
;
457 if (parser
->state
== VG_RULE_PARSER_STATE_INIT
)
461 if (parser
->lineptr
== parser
->linebuf
) {
462 /* haven't come to the start of the actual rule data line yet */
466 while (isspace ((int) *inptr
))
469 if (inptr
== priv
->inend
)
473 /* comment within the rule brackets */
474 parser
->state
|= VG_RULE_PARSER_STATE_COMMENT
;
484 if (parser
->state
== VG_RULE_PARSER_STATE_RULE_CALLER
) {
485 parser
->rule_cb (parser
, parser
->current
, parser
->user_data
);
487 fprintf (stderr
, "Encountered unexpected '}'\n");
488 vg_rule_free (parser
->current
);
491 parser
->state
= VG_RULE_PARSER_STATE_INIT
;
493 parser
->current
= NULL
;
496 parser
->lineleft
+= (parser
->lineptr
- parser
->linebuf
);
497 parser
->lineptr
= parser
->linebuf
;
504 while (*inptr
!= '\n')
507 backup_linebuf (parser
, start
, (inptr
- start
));
509 if (inptr
== priv
->inend
)
512 switch (parser
->state
) {
513 case VG_RULE_PARSER_STATE_RULE_NAME
:
514 *parser
->lineptr
= '\0';
515 parser
->current
->name
= g_strdup ((char *)parser
->linebuf
);
516 parser
->state
= VG_RULE_PARSER_STATE_RULE_TYPE
;
518 case VG_RULE_PARSER_STATE_RULE_TYPE
:
519 /* The newer valgrind (1.9.5) suppression format contains
520 * a list of tool names preceeding the suppression type:
522 * Memcheck,Addrcheck:Param
524 * The older format (1.0.x) contained just the type name.
527 /* trim tailing whitespc */
528 start
= parser
->lineptr
- 1;
529 while (start
> parser
->linebuf
&& isspace ((int) *start
))
534 /* does this suppression rule contain a list
535 of tools that it is meant for? */
536 while (start
> parser
->linebuf
&& *start
!= ':')
540 /* why yes, yes it does... */
542 parser
->current
->tools
= parse_tool_list (parser
->linebuf
);
545 parser
->current
->type
= vg_rule_type_from_name ((char *)start
);
546 g_assert (parser
->current
->type
!= VG_RULE_LAST
);
547 if (parser
->current
->type
== VG_RULE_PARAM
)
548 parser
->state
= VG_RULE_PARSER_STATE_RULE_SYSCALL
;
550 parser
->state
= VG_RULE_PARSER_STATE_RULE_CALLER
;
552 case VG_RULE_PARSER_STATE_RULE_SYSCALL
:
553 parser
->current
->syscall
= g_strndup ((char *)start
, (inptr
- start
));
554 parser
->state
= VG_RULE_PARSER_STATE_RULE_CALLER
;
556 case VG_RULE_PARSER_STATE_RULE_CALLER
:
557 vg_parser_parse_caller (parser
);
561 parser
->lineleft
+= (parser
->lineptr
- parser
->linebuf
);
562 parser
->lineptr
= parser
->linebuf
;
574 vg_rule_parser_flush (VgRuleParser
*parser
)
581 vg_suppressions_file_write_header (int fd
, const char *summary
)
585 string
= g_string_new ("##----------------------------------------------------------------------##\n\n");
586 g_string_append (string
, "# ");
587 g_string_append (string
, summary
);
588 g_string_append (string
, "\n\n");
590 /* format specification header */
591 g_string_append (string
, "# Format of this file is:\n");
592 g_string_append (string
, "# {\n");
593 g_string_append (string
, "# name_of_suppression\n");
594 g_string_append (string
, "# tool_name:supp_kind\n");
595 g_string_append (string
, "# (optional extra info for some suppression types)\n");
596 g_string_append (string
, "# caller0 name, or /name/of/so/file.so\n");
597 g_string_append (string
, "# caller1 name, or ditto\n");
598 g_string_append (string
, "# (optionally: caller2 name)\n");
599 g_string_append (string
, "# (optionally: caller3 name)\n");
600 g_string_append (string
, "# }\n");
601 g_string_append (string
, "#\n");
602 g_string_append (string
, "# For Memcheck, the supp_kinds are:\n");
603 g_string_append (string
, "#\n");
604 g_string_append (string
, "# Param Value1 Value2 Value4 Value8\n");
605 g_string_append (string
, "# Free Addr1 Addr2 Addr4 Addr8 Leak\n");
606 g_string_append (string
, "# Cond (previously known as Value0)\n");
607 g_string_append (string
, "#\n");
608 g_string_append (string
, "# and the optional extra info is:\n");
609 g_string_append (string
, "# if Param: name of system call param\n");
610 g_string_append (string
, "# if Free: name of free-ing fn)\n\n");
612 if (vg_write (fd
, string
->str
, string
->len
) == -1) {
613 g_string_free (string
, TRUE
);
617 g_string_free (string
, TRUE
);
624 vg_suppressions_file_append_rule (int fd
, VgRule
*rule
)
630 string
= g_string_new ("{\n ");
631 g_string_append (string
, rule
->name
);
632 g_string_append (string
, "\n ");
636 while (tool
!= NULL
) {
637 g_string_append (string
, tool
->name
);
639 g_string_append_c (string
, ',');
643 g_string_append_c (string
, ':');
646 g_string_append (string
, vg_rule_types
[rule
->type
]);
648 if (rule
->type
== VG_RULE_PARAM
) {
649 g_string_append (string
, "\n ");
650 g_string_append (string
, rule
->syscall
);
653 caller
= rule
->callers
;
654 while (caller
!= NULL
) {
655 g_string_append_printf (string
, "\n %s:%s", vg_caller_types
[caller
->type
], caller
->name
);
656 caller
= caller
->next
;
659 g_string_append (string
, "\n}\n");
661 if (vg_write (fd
, string
->str
, string
->len
) == -1) {
662 g_string_free (string
, TRUE
);
666 g_string_free (string
, TRUE
);
674 my_rule_cb (VgRuleParser
*parser
, VgRule
*rule
, void *user_data
)
676 vg_suppressions_file_append_rule (1, rule
);
679 int main (int argc
, char **argv
)
681 VgRuleParser
*parser
;
684 if ((fd
= open (argv
[1], O_RDONLY
)) == -1)
687 vg_suppressions_file_write_header (1, "Errors to suppress by default for glibc 2.1.3");
689 parser
= vg_rule_parser_new (fd
, my_rule_cb
, NULL
);
691 while (vg_rule_parser_step (parser
) > 0)
694 vg_rule_parser_free (parser
);