Cygwin: dirent.h: fix a comment
[newlib-cygwin.git] / libgloss / mep / mep-bb.c
blob191da169623cea437441998a5f5f596fdbe23b06
1 /*
2 * Copyright (c) 2000-2001 Red Hat, Inc. All rights reserved.
4 * This copyrighted material is made available to anyone wishing to use, modify,
5 * copy, or redistribute it subject to the terms and conditions of the BSD
6 * License. This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY expressed or implied, including the implied
8 * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. A copy
9 * of this license is available at http://www.opensource.org/licenses. Any
10 * Red Hat trademarks that are incorporated in the source code or documentation
11 * are not subject to the BSD License and may only be used or replicated with
12 * the express permission of Red Hat, Inc.
15 /* Structure emitted by -a */
16 struct bb
18 long zero_word;
19 const char *filename;
20 long *counts;
21 long ncounts;
22 struct bb *next;
23 const unsigned long *addresses;
25 /* Older GCC's did not emit these fields. */
26 long nwords;
27 const char **functions;
28 const long *line_nums;
29 const char **filenames;
30 char *flags;
33 /* Simple minded basic block profiling output dumper for
34 systems that don't provide tcov support. At present,
35 it requires atexit and stdio. */
37 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
38 #include <stdio.h>
39 #include <time.h>
40 char *ctime (const time_t *);
42 /*#include "gbl-ctors.h"*/
43 #include "gcov-io.h"
44 #include <string.h>
46 static struct bb *bb_head;
48 static int num_digits (long value, int base) __attribute__ ((const));
50 /* Return the number of digits needed to print a value */
51 /* __inline__ */ static int num_digits (long value, int base)
53 int minus = (value < 0 && base != 16);
54 unsigned long v = (minus) ? -value : value;
55 int ret = minus;
59 v /= base;
60 ret++;
62 while (v);
64 return ret;
67 void
68 __bb_exit_func (void)
70 FILE *da_file, *file;
71 long time_value;
72 int i;
74 if (bb_head == 0)
75 return;
77 i = strlen (bb_head->filename) - 3;
79 if (!strcmp (bb_head->filename+i, ".da"))
81 /* Must be -fprofile-arcs not -a.
82 Dump data in a form that gcov expects. */
84 struct bb *ptr;
86 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
88 int firstchar;
90 /* Make sure the output file exists -
91 but don't clobber exiting data. */
92 if ((da_file = fopen (ptr->filename, "a")) != 0)
93 fclose (da_file);
95 /* Need to re-open in order to be able to write from the start. */
96 da_file = fopen (ptr->filename, "r+b");
97 /* Some old systems might not allow the 'b' mode modifier.
98 Therefore, try to open without it. This can lead to a race
99 condition so that when you delete and re-create the file, the
100 file might be opened in text mode, but then, you shouldn't
101 delete the file in the first place. */
102 if (da_file == 0)
103 da_file = fopen (ptr->filename, "r+");
104 if (da_file == 0)
106 fprintf (stderr, "arc profiling: Can't open output file %s.\n",
107 ptr->filename);
108 continue;
111 /* After a fork, another process might try to read and/or write
112 the same file simultanously. So if we can, lock the file to
113 avoid race conditions. */
115 /* If the file is not empty, and the number of counts in it is the
116 same, then merge them in. */
117 firstchar = fgetc (da_file);
118 if (firstchar == EOF)
120 if (ferror (da_file))
122 fprintf (stderr, "arc profiling: Can't read output file ");
123 perror (ptr->filename);
126 else
128 long n_counts = 0;
130 if (ungetc (firstchar, da_file) == EOF)
131 rewind (da_file);
132 if (__read_long (&n_counts, da_file, 8) != 0)
134 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
135 ptr->filename);
136 continue;
139 if (n_counts == ptr->ncounts)
141 int i;
143 for (i = 0; i < n_counts; i++)
145 long v = 0;
147 if (__read_long (&v, da_file, 8) != 0)
149 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
150 ptr->filename);
151 break;
153 ptr->counts[i] += v;
159 rewind (da_file);
161 /* ??? Should first write a header to the file. Preferably, a 4 byte
162 magic number, 4 bytes containing the time the program was
163 compiled, 4 bytes containing the last modification time of the
164 source file, and 4 bytes indicating the compiler options used.
166 That way we can easily verify that the proper source/executable/
167 data file combination is being used from gcov. */
169 if (__write_long (ptr->ncounts, da_file, 8) != 0)
172 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
173 ptr->filename);
175 else
177 int j;
178 long *count_ptr = ptr->counts;
179 int ret = 0;
180 for (j = ptr->ncounts; j > 0; j--)
182 if (__write_long (*count_ptr, da_file, 8) != 0)
184 ret=1;
185 break;
187 count_ptr++;
189 if (ret)
190 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
191 ptr->filename);
194 if (fclose (da_file) == EOF)
195 fprintf (stderr, "arc profiling: Error closing output file %s.\n",
196 ptr->filename);
199 return;
202 /* Must be basic block profiling. Emit a human readable output file. */
204 file = fopen ("bb.out", "a");
206 if (!file)
207 perror ("bb.out");
209 else
211 struct bb *ptr;
213 /* This is somewhat type incorrect, but it avoids worrying about
214 exactly where time.h is included from. It should be ok unless
215 a void * differs from other pointer formats, or if sizeof (long)
216 is < sizeof (time_t). It would be nice if we could assume the
217 use of rationale standards here. */
219 time ((void *) &time_value);
220 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
222 /* We check the length field explicitly in order to allow compatibility
223 with older GCC's which did not provide it. */
225 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
227 int i;
228 int func_p = (ptr->nwords >= (long) sizeof (struct bb)
229 && ptr->nwords <= 1000
230 && ptr->functions);
231 int line_p = (func_p && ptr->line_nums);
232 int file_p = (func_p && ptr->filenames);
233 int addr_p = (ptr->addresses != 0);
234 long ncounts = ptr->ncounts;
235 long cnt_max = 0;
236 long line_max = 0;
237 long addr_max = 0;
238 int file_len = 0;
239 int func_len = 0;
240 int blk_len = num_digits (ncounts, 10);
241 int cnt_len;
242 int line_len;
243 int addr_len;
245 fprintf (file, "File %s, %ld basic blocks \n\n",
246 ptr->filename, ncounts);
248 /* Get max values for each field. */
249 for (i = 0; i < ncounts; i++)
251 const char *p;
252 int len;
254 if (cnt_max < ptr->counts[i])
255 cnt_max = ptr->counts[i];
257 if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
258 addr_max = ptr->addresses[i];
260 if (line_p && line_max < ptr->line_nums[i])
261 line_max = ptr->line_nums[i];
263 if (func_p)
265 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
266 len = strlen (p);
267 if (func_len < len)
268 func_len = len;
271 if (file_p)
273 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
274 len = strlen (p);
275 if (file_len < len)
276 file_len = len;
280 addr_len = num_digits (addr_max, 16);
281 cnt_len = num_digits (cnt_max, 10);
282 line_len = num_digits (line_max, 10);
284 /* Now print out the basic block information. */
285 for (i = 0; i < ncounts; i++)
287 fprintf (file,
288 " Block #%*d: executed %*ld time(s)",
289 blk_len, i+1,
290 cnt_len, ptr->counts[i]);
292 if (addr_p)
293 fprintf (file, " address= 0x%.*lx", addr_len,
294 ptr->addresses[i]);
296 if (func_p)
297 fprintf (file, " function= %-*s", func_len,
298 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
300 if (line_p)
301 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
303 if (file_p)
304 fprintf (file, " file= %s",
305 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
307 fprintf (file, "\n");
310 fprintf (file, "\n");
311 fflush (file);
314 fprintf (file, "\n\n");
315 fclose (file);
319 void
320 __bb_init_func (struct bb *blocks)
322 /* User is supposed to check whether the first word is non-0,
323 but just in case.... */
325 if (blocks->zero_word)
326 return;
328 /* Initialize destructor. */
329 if (!bb_head)
330 atexit (__bb_exit_func);
332 /* Set up linked list. */
333 blocks->zero_word = 1;
334 blocks->next = bb_head;
335 bb_head = blocks;
338 /* Called before fork or exec - write out profile information gathered so
339 far and reset it to zero. This avoids duplication or loss of the
340 profile information gathered so far. */
341 void
342 __bb_fork_func (void)
344 struct bb *ptr;
346 __bb_exit_func ();
347 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
349 long i;
350 for (i = ptr->ncounts - 1; i >= 0; i--)
351 ptr->counts[i] = 0;
355 #ifndef MACHINE_STATE_SAVE
356 #define MACHINE_STATE_SAVE(ID)
357 #endif
358 #ifndef MACHINE_STATE_RESTORE
359 #define MACHINE_STATE_RESTORE(ID)
360 #endif
362 /* Number of buckets in hashtable of basic block addresses. */
364 #define BB_BUCKETS 311
366 /* Maximum length of string in file bb.in. */
368 #define BBINBUFSIZE 500
370 struct bb_edge
372 struct bb_edge *next;
373 unsigned long src_addr;
374 unsigned long dst_addr;
375 unsigned long count;
378 enum bb_func_mode
380 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
383 struct bb_func
385 struct bb_func *next;
386 char *funcname;
387 char *filename;
388 enum bb_func_mode mode;
391 /* This is the connection to the outside world.
392 The BLOCK_PROFILER macro must set __bb.blocks
393 and __bb.blockno. */
395 struct {
396 unsigned long blockno;
397 struct bb *blocks;
398 } __bb;
400 /* Vars to store addrs of source and destination basic blocks
401 of a jump. */
403 static unsigned long bb_src = 0;
404 static unsigned long bb_dst = 0;
406 static FILE *bb_tracefile = (FILE *) 0;
407 static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
408 static struct bb_func *bb_func_head = (struct bb_func *) 0;
409 static unsigned long bb_callcount = 0;
410 static int bb_mode = 0;
412 static unsigned long *bb_stack = (unsigned long *) 0;
413 static size_t bb_stacksize = 0;
415 static int reported = 0;
417 /* Trace modes:
418 Always : Print execution frequencies of basic blocks
419 to file bb.out.
420 bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
421 bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
422 bb_mode & 4 != 0 : Cut call instructions from basic block flow.
423 bb_mode & 8 != 0 : Insert return instructions in basic block flow.
426 #ifdef HAVE_POPEN
428 /*#include <sys/types.h>*/
429 #include <sys/stat.h>
430 /*#include <malloc.h>*/
432 /* Commands executed by gopen. */
434 #define GOPENDECOMPRESS "gzip -cd "
435 #define GOPENCOMPRESS "gzip -c >"
437 /* Like fopen but pipes through gzip. mode may only be "r" or "w".
438 If it does not compile, simply replace gopen by fopen and delete
439 '.gz' from any first parameter to gopen. */
441 static FILE *
442 gopen (char *fn, char *mode)
444 int use_gzip;
445 char *p;
447 if (mode[1])
448 return (FILE *) 0;
450 if (mode[0] != 'r' && mode[0] != 'w')
451 return (FILE *) 0;
453 p = fn + strlen (fn)-1;
454 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
455 || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
457 if (use_gzip)
459 if (mode[0]=='r')
461 FILE *f;
462 char *s = (char *) malloc (sizeof (char) * strlen (fn)
463 + sizeof (GOPENDECOMPRESS));
464 strcpy (s, GOPENDECOMPRESS);
465 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
466 f = popen (s, mode);
467 free (s);
468 return f;
471 else
473 FILE *f;
474 char *s = (char *) malloc (sizeof (char) * strlen (fn)
475 + sizeof (GOPENCOMPRESS));
476 strcpy (s, GOPENCOMPRESS);
477 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
478 if (!(f = popen (s, mode)))
479 f = fopen (s, mode);
480 free (s);
481 return f;
485 else
486 return fopen (fn, mode);
489 static int
490 gclose (FILE *f)
492 struct stat buf;
494 if (f != 0)
496 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
497 return pclose (f);
499 return fclose (f);
501 return 0;
504 #endif /* HAVE_POPEN */
506 /* Called once per program. */
508 static void
509 __bb_exit_trace_func (void)
511 FILE *file = fopen ("bb.out", "a");
512 struct bb_func *f;
513 struct bb *b;
515 if (!file)
516 perror ("bb.out");
518 if (bb_mode & 1)
520 if (!bb_tracefile)
521 perror ("bbtrace");
522 else
523 #ifdef HAVE_POPEN
524 gclose (bb_tracefile);
525 #else
526 fclose (bb_tracefile);
527 #endif /* HAVE_POPEN */
530 /* Check functions in `bb.in'. */
532 if (file)
534 long time_value;
535 const struct bb_func *p;
536 int printed_something = 0;
537 struct bb *ptr;
538 long blk;
540 /* This is somewhat type incorrect. */
541 time ((void *) &time_value);
543 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
545 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
547 if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
548 continue;
549 for (blk = 0; blk < ptr->ncounts; blk++)
551 if (!strcmp (p->funcname, ptr->functions[blk]))
552 goto found;
556 if (!printed_something)
558 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
559 printed_something = 1;
562 fprintf (file, "\tFunction %s", p->funcname);
563 if (p->filename)
564 fprintf (file, " of file %s", p->filename);
565 fprintf (file, "\n" );
567 found: ;
570 if (printed_something)
571 fprintf (file, "\n");
575 if (bb_mode & 2)
577 if (!bb_hashbuckets)
579 if (!reported)
581 fprintf (stderr, "Profiler: out of memory\n");
582 reported = 1;
584 return;
587 else if (file)
589 long time_value;
590 int i;
591 unsigned long addr_max = 0;
592 unsigned long cnt_max = 0;
593 int cnt_len;
594 int addr_len;
596 /* This is somewhat type incorrect, but it avoids worrying about
597 exactly where time.h is included from. It should be ok unless
598 a void * differs from other pointer formats, or if sizeof (long)
599 is < sizeof (time_t). It would be nice if we could assume the
600 use of rationale standards here. */
602 time ((void *) &time_value);
603 fprintf (file, "Basic block jump tracing");
605 switch (bb_mode & 12)
607 case 0:
608 fprintf (file, " (with call)");
609 break;
611 case 4:
612 /* Print nothing. */
613 break;
615 case 8:
616 fprintf (file, " (with call & ret)");
617 break;
619 case 12:
620 fprintf (file, " (with ret)");
621 break;
624 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
626 for (i = 0; i < BB_BUCKETS; i++)
628 struct bb_edge *bucket = bb_hashbuckets[i];
629 for ( ; bucket; bucket = bucket->next )
631 if (addr_max < bucket->src_addr)
632 addr_max = bucket->src_addr;
633 if (addr_max < bucket->dst_addr)
634 addr_max = bucket->dst_addr;
635 if (cnt_max < bucket->count)
636 cnt_max = bucket->count;
639 addr_len = num_digits (addr_max, 16);
640 cnt_len = num_digits (cnt_max, 10);
642 for ( i = 0; i < BB_BUCKETS; i++)
644 struct bb_edge *bucket = bb_hashbuckets[i];
645 for ( ; bucket; bucket = bucket->next )
647 fprintf (file,
648 "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
649 addr_len, bucket->src_addr,
650 addr_len, bucket->dst_addr,
651 cnt_len, bucket->count);
655 fprintf (file, "\n");
660 if (file)
661 fclose (file);
663 /* Free allocated memory. */
665 f = bb_func_head;
666 while (f)
668 struct bb_func *old = f;
670 f = f->next;
671 if (old->funcname) free (old->funcname);
672 if (old->filename) free (old->filename);
673 free (old);
676 if (bb_stack)
677 free (bb_stack);
679 if (bb_hashbuckets)
681 int i;
683 for (i = 0; i < BB_BUCKETS; i++)
685 struct bb_edge *old, *bucket = bb_hashbuckets[i];
687 while (bucket)
689 old = bucket;
690 bucket = bucket->next;
691 free (old);
694 free (bb_hashbuckets);
697 for (b = bb_head; b; b = b->next)
698 if (b->flags) free (b->flags);
701 /* Called once per program. */
703 static void
704 __bb_init_prg (void)
706 FILE *file;
707 char buf[BBINBUFSIZE];
708 const char *p;
709 const char *pos;
710 enum bb_func_mode m;
711 int i;
713 /* Initialize destructor. */
714 atexit (__bb_exit_func);
716 if (!(file = fopen ("bb.in", "r")))
717 return;
719 while(fgets (buf, BBINBUFSIZE, file) != 0)
721 i = strlen (buf);
722 if (buf[i-1] == '\n')
723 buf[--i] = '\0';
725 p = buf;
726 if (*p == '-')
728 m = TRACE_OFF;
729 p++;
731 else
733 m = TRACE_ON;
735 if (!strcmp (p, "__bb_trace__"))
736 bb_mode |= 1;
737 else if (!strcmp (p, "__bb_jumps__"))
738 bb_mode |= 2;
739 else if (!strcmp (p, "__bb_hidecall__"))
740 bb_mode |= 4;
741 else if (!strcmp (p, "__bb_showret__"))
742 bb_mode |= 8;
743 else
745 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
746 if (f)
748 unsigned long l;
749 f->next = bb_func_head;
750 if ((pos = strchr (p, ':')))
752 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
753 continue;
754 strcpy (f->funcname, pos+1);
755 l = pos-p;
756 if ((f->filename = (char *) malloc (l+1)))
758 strncpy (f->filename, p, l);
759 f->filename[l] = '\0';
761 else
762 f->filename = (char *) 0;
764 else
766 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
767 continue;
768 strcpy (f->funcname, p);
769 f->filename = (char *) 0;
771 f->mode = m;
772 bb_func_head = f;
776 fclose (file);
778 #ifdef HAVE_POPEN
780 if (bb_mode & 1)
781 bb_tracefile = gopen ("bbtrace.gz", "w");
783 #else
785 if (bb_mode & 1)
786 bb_tracefile = fopen ("bbtrace", "w");
788 #endif /* HAVE_POPEN */
790 if (bb_mode & 2)
792 bb_hashbuckets = (struct bb_edge **)
793 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
794 if (bb_hashbuckets)
795 /* Use a loop here rather than calling bzero to avoid having to
796 conditionalize its existance. */
797 for (i = 0; i < BB_BUCKETS; i++)
798 bb_hashbuckets[i] = 0;
801 if (bb_mode & 12)
803 bb_stacksize = 10;
804 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
807 /* Initialize destructor. */
808 atexit (__bb_exit_trace_func);
811 /* Called upon entering a basic block. */
813 void
814 __bb_trace_func (void)
816 struct bb_edge *bucket;
818 MACHINE_STATE_SAVE("1")
820 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
821 goto skip;
823 bb_dst = __bb.blocks->addresses[__bb.blockno];
824 __bb.blocks->counts[__bb.blockno]++;
826 if (bb_tracefile)
828 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
831 if (bb_hashbuckets)
833 struct bb_edge **startbucket, **oldnext;
835 oldnext = startbucket
836 = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
837 bucket = *startbucket;
839 for (bucket = *startbucket; bucket;
840 oldnext = &(bucket->next), bucket = *oldnext)
842 if (bucket->src_addr == bb_src
843 && bucket->dst_addr == bb_dst)
845 bucket->count++;
846 *oldnext = bucket->next;
847 bucket->next = *startbucket;
848 *startbucket = bucket;
849 goto ret;
853 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
855 if (!bucket)
857 if (!reported)
859 fprintf (stderr, "Profiler: out of memory\n");
860 reported = 1;
864 else
866 bucket->src_addr = bb_src;
867 bucket->dst_addr = bb_dst;
868 bucket->next = *startbucket;
869 *startbucket = bucket;
870 bucket->count = 1;
874 ret:
875 bb_src = bb_dst;
877 skip:
880 MACHINE_STATE_RESTORE("1")
884 /* Called when returning from a function and `__bb_showret__' is set. */
886 static void
887 __bb_trace_func_ret (void)
889 struct bb_edge *bucket;
891 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
892 goto skip;
894 if (bb_hashbuckets)
896 struct bb_edge **startbucket, **oldnext;
898 oldnext = startbucket
899 = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
900 bucket = *startbucket;
902 for (bucket = *startbucket; bucket;
903 oldnext = &(bucket->next), bucket = *oldnext)
905 if (bucket->src_addr == bb_dst
906 && bucket->dst_addr == bb_src)
908 bucket->count++;
909 *oldnext = bucket->next;
910 bucket->next = *startbucket;
911 *startbucket = bucket;
912 goto ret;
916 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
918 if (!bucket)
920 if (!reported)
922 fprintf (stderr, "Profiler: out of memory\n");
923 reported = 1;
927 else
929 bucket->src_addr = bb_dst;
930 bucket->dst_addr = bb_src;
931 bucket->next = *startbucket;
932 *startbucket = bucket;
933 bucket->count = 1;
937 ret:
938 bb_dst = bb_src;
940 skip:
945 /* Called upon entering the first function of a file. */
947 static void
948 __bb_init_file (struct bb *blocks)
951 const struct bb_func *p;
952 long blk, ncounts = blocks->ncounts;
953 const char **functions = blocks->functions;
955 /* Set up linked list. */
956 blocks->zero_word = 1;
957 blocks->next = bb_head;
958 bb_head = blocks;
960 blocks->flags = 0;
961 if (!bb_func_head
962 || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
963 return;
965 for (blk = 0; blk < ncounts; blk++)
966 blocks->flags[blk] = 0;
968 for (blk = 0; blk < ncounts; blk++)
970 for (p = bb_func_head; p; p = p->next)
972 if (!strcmp (p->funcname, functions[blk])
973 && (!p->filename || !strcmp (p->filename, blocks->filename)))
975 blocks->flags[blk] |= p->mode;
982 /* Called when exiting from a function. */
984 void
985 __bb_trace_ret (void)
988 MACHINE_STATE_SAVE("2")
990 if (bb_callcount)
992 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
994 bb_src = bb_stack[bb_callcount];
995 if (bb_mode & 8)
996 __bb_trace_func_ret ();
999 bb_callcount -= 1;
1002 MACHINE_STATE_RESTORE("2")
1006 /* Called when entering a function. */
1008 void
1009 __bb_init_trace_func (struct bb *blocks, unsigned long blockno)
1011 static int trace_init = 0;
1013 MACHINE_STATE_SAVE("3")
1015 if (!blocks->zero_word)
1017 if (!trace_init)
1019 trace_init = 1;
1020 __bb_init_prg ();
1022 __bb_init_file (blocks);
1025 if (bb_callcount)
1028 bb_callcount += 1;
1030 if (bb_mode & 12)
1032 if (bb_callcount >= bb_stacksize)
1034 size_t newsize = bb_callcount + 100;
1036 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
1037 if (! bb_stack)
1039 if (!reported)
1041 fprintf (stderr, "Profiler: out of memory\n");
1042 reported = 1;
1044 bb_stacksize = 0;
1045 goto stack_overflow;
1047 bb_stacksize = newsize;
1049 bb_stack[bb_callcount] = bb_src;
1051 if (bb_mode & 4)
1052 bb_src = 0;
1056 stack_overflow:;
1060 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
1062 bb_callcount = 1;
1063 bb_src = 0;
1065 if (bb_stack)
1066 bb_stack[bb_callcount] = bb_src;
1069 MACHINE_STATE_RESTORE("3")