source: trunk/libs/newlib/src/libgloss/mep/mep-bb.c @ 500

Last change on this file since 500 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 24.8 KB
RevLine 
[444]1/*
2 * Copyright (c) 2000-2001  Red Hat, Inc. All rights reserved.
3 *
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.
13 */
14
15/* Structure emitted by -a  */
16struct bb
17{
18  long zero_word;
19  const char *filename;
20  long *counts;
21  long ncounts;
22  struct bb *next;
23  const unsigned long *addresses;
24
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;
31};
32
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.  */
36
37#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
38#include <stdio.h>
39#include <time.h>
40char *ctime (const time_t *);
41
42/*#include "gbl-ctors.h"*/
43#include "gcov-io.h"
44#include <string.h>
45
46static struct bb *bb_head;
47
48static int num_digits (long value, int base) __attribute__ ((const));
49
50/* Return the number of digits needed to print a value */
51/* __inline__ */ static int num_digits (long value, int base)
52{
53  int minus = (value < 0 && base != 16);
54  unsigned long v = (minus) ? -value : value;
55  int ret = minus;
56
57  do
58    {
59      v /= base;
60      ret++;
61    }
62  while (v);
63
64  return ret;
65}
66
67void
68__bb_exit_func (void)
69{
70  FILE *da_file, *file;
71  long time_value;
72  int i;
73
74  if (bb_head == 0)
75    return;
76
77  i = strlen (bb_head->filename) - 3;
78
79  if (!strcmp (bb_head->filename+i, ".da"))
80    {
81      /* Must be -fprofile-arcs not -a.
82         Dump data in a form that gcov expects.  */
83
84      struct bb *ptr;
85
86      for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
87        {
88          int firstchar;
89
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);
94
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)
105            {
106              fprintf (stderr, "arc profiling: Can't open output file %s.\n",
107                       ptr->filename);
108              continue;
109            }
110
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.  */
114
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)
119            {
120              if (ferror (da_file))
121                {
122                  fprintf (stderr, "arc profiling: Can't read output file ");
123                  perror (ptr->filename);
124                }
125            }
126          else
127            {
128              long n_counts = 0;
129             
130              if (ungetc (firstchar, da_file) == EOF)
131                rewind (da_file);
132              if (__read_long (&n_counts, da_file, 8) != 0)
133                {
134                  fprintf (stderr, "arc profiling: Can't read output file %s.\n",
135                           ptr->filename);
136                  continue;
137                }
138
139              if (n_counts == ptr->ncounts)
140                {
141                  int i;
142
143                  for (i = 0; i < n_counts; i++)
144                    {
145                      long v = 0;
146
147                      if (__read_long (&v, da_file, 8) != 0)
148                        {
149                          fprintf (stderr, "arc profiling: Can't read output file %s.\n",
150                                   ptr->filename);
151                          break;
152                        }
153                      ptr->counts[i] += v;
154                    }
155                }
156
157            }
158
159          rewind (da_file);
160
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.
165
166             That way we can easily verify that the proper source/executable/
167             data file combination is being used from gcov.  */
168
169          if (__write_long (ptr->ncounts, da_file, 8) != 0)
170            {
171             
172              fprintf (stderr, "arc profiling: Error writing output file %s.\n",
173                       ptr->filename);
174            }
175          else
176            {
177              int j;
178              long *count_ptr = ptr->counts;
179              int ret = 0;
180              for (j = ptr->ncounts; j > 0; j--)
181                {
182                  if (__write_long (*count_ptr, da_file, 8) != 0)
183                    {
184                      ret=1;
185                      break;
186                    }
187                  count_ptr++;
188                }
189              if (ret)
190                fprintf (stderr, "arc profiling: Error writing output file %s.\n",
191                         ptr->filename);
192            }
193         
194          if (fclose (da_file) == EOF)
195            fprintf (stderr, "arc profiling: Error closing output file %s.\n",
196                     ptr->filename);
197        }
198
199      return;
200    }
201
202  /* Must be basic block profiling.  Emit a human readable output file.  */
203
204  file = fopen ("bb.out", "a");
205
206  if (!file)
207    perror ("bb.out");
208
209  else
210    {
211      struct bb *ptr;
212
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.  */
218
219      time ((void *) &time_value);
220      fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
221
222      /* We check the length field explicitly in order to allow compatibility
223         with older GCC's which did not provide it.  */
224
225      for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
226        {
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;
244
245          fprintf (file, "File %s, %ld basic blocks \n\n",
246                   ptr->filename, ncounts);
247
248          /* Get max values for each field.  */
249          for (i = 0; i < ncounts; i++)
250            {
251              const char *p;
252              int len;
253
254              if (cnt_max < ptr->counts[i])
255                cnt_max = ptr->counts[i];
256
257              if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
258                addr_max = ptr->addresses[i];
259
260              if (line_p && line_max < ptr->line_nums[i])
261                line_max = ptr->line_nums[i];
262
263              if (func_p)
264                {
265                  p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
266                  len = strlen (p);
267                  if (func_len < len)
268                    func_len = len;
269                }
270
271              if (file_p)
272                {
273                  p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
274                  len = strlen (p);
275                  if (file_len < len)
276                    file_len = len;
277                }
278            }
279
280          addr_len = num_digits (addr_max, 16);
281          cnt_len  = num_digits (cnt_max, 10);
282          line_len = num_digits (line_max, 10);
283
284          /* Now print out the basic block information.  */
285          for (i = 0; i < ncounts; i++)
286            {
287              fprintf (file,
288                       "    Block #%*d: executed %*ld time(s)",
289                       blk_len, i+1,
290                       cnt_len, ptr->counts[i]);
291
292              if (addr_p)
293                fprintf (file, " address= 0x%.*lx", addr_len,
294                         ptr->addresses[i]);
295
296              if (func_p)
297                fprintf (file, " function= %-*s", func_len,
298                         (ptr->functions[i]) ? ptr->functions[i] : "<none>");
299
300              if (line_p)
301                fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
302
303              if (file_p)
304                fprintf (file, " file= %s",
305                         (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
306
307              fprintf (file, "\n");
308            }
309
310          fprintf (file, "\n");
311          fflush (file);
312        }
313
314      fprintf (file, "\n\n");
315      fclose (file);
316    }
317}
318
319void
320__bb_init_func (struct bb *blocks)
321{
322  /* User is supposed to check whether the first word is non-0,
323     but just in case....  */
324
325  if (blocks->zero_word)
326    return;
327
328  /* Initialize destructor.  */
329  if (!bb_head)
330    atexit (__bb_exit_func);
331
332  /* Set up linked list.  */
333  blocks->zero_word = 1;
334  blocks->next = bb_head;
335  bb_head = blocks;
336}
337
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.  */
341void
342__bb_fork_func (void)
343{
344  struct bb *ptr;
345
346  __bb_exit_func ();
347  for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
348    {
349      long i;
350      for (i = ptr->ncounts - 1; i >= 0; i--)
351        ptr->counts[i] = 0;
352    }
353}
354
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
361
362/* Number of buckets in hashtable of basic block addresses.  */
363
364#define BB_BUCKETS 311
365
366/* Maximum length of string in file bb.in.  */
367
368#define BBINBUFSIZE 500
369
370struct bb_edge
371{
372  struct bb_edge *next;
373  unsigned long src_addr;
374  unsigned long dst_addr;
375  unsigned long count;
376};
377
378enum bb_func_mode
379{
380  TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
381};
382
383struct bb_func
384{
385  struct bb_func *next;
386  char *funcname;
387  char *filename;
388  enum bb_func_mode mode;
389};
390
391/* This is the connection to the outside world.
392   The BLOCK_PROFILER macro must set __bb.blocks
393   and __bb.blockno.  */
394
395struct {
396  unsigned long blockno;
397  struct bb *blocks;
398} __bb;
399
400/* Vars to store addrs of source and destination basic blocks
401   of a jump.  */
402
403static unsigned long bb_src = 0;
404static unsigned long bb_dst = 0;
405
406static FILE *bb_tracefile = (FILE *) 0;
407static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
408static struct bb_func *bb_func_head = (struct bb_func *) 0;
409static unsigned long bb_callcount = 0;
410static int bb_mode = 0;
411
412static unsigned long *bb_stack = (unsigned long *) 0;
413static size_t bb_stacksize = 0;
414
415static int reported = 0;
416
417/* Trace modes:
418Always             :   Print execution frequencies of basic blocks
419                       to file bb.out.
420bb_mode & 1 != 0   :   Dump trace of basic blocks to file bbtrace[.gz]
421bb_mode & 2 != 0   :   Print jump frequencies to file bb.out.
422bb_mode & 4 != 0   :   Cut call instructions from basic block flow.
423bb_mode & 8 != 0   :   Insert return instructions in basic block flow.
424*/
425
426#ifdef HAVE_POPEN
427
428/*#include <sys/types.h>*/
429#include <sys/stat.h>
430/*#include <malloc.h>*/
431
432/* Commands executed by gopen.  */
433
434#define GOPENDECOMPRESS "gzip -cd "
435#define GOPENCOMPRESS "gzip -c >"
436
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.  */
440
441static FILE *
442gopen (char *fn, char *mode)
443{
444  int use_gzip;
445  char *p;
446
447  if (mode[1])
448    return (FILE *) 0;
449
450  if (mode[0] != 'r' && mode[0] != 'w') 
451    return (FILE *) 0;
452
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'));
456
457  if (use_gzip)
458    {
459      if (mode[0]=='r')
460        {
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;
469        }
470
471      else
472        {
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;
482        }
483    }
484
485  else
486    return fopen (fn, mode);
487}
488
489static int
490gclose (FILE *f)
491{
492  struct stat buf;
493
494  if (f != 0)
495    {
496      if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
497        return pclose (f);
498
499      return fclose (f);
500    }
501  return 0;
502}
503
504#endif /* HAVE_POPEN */
505
506/* Called once per program.  */
507
508static void
509__bb_exit_trace_func (void)
510{
511  FILE *file = fopen ("bb.out", "a");
512  struct bb_func *f;
513  struct bb *b;
514       
515  if (!file)
516    perror ("bb.out");
517
518  if (bb_mode & 1)
519    {
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 */
528    }
529
530  /* Check functions in `bb.in'.  */
531
532  if (file)
533    {
534      long time_value;
535      const struct bb_func *p;
536      int printed_something = 0;
537      struct bb *ptr;
538      long blk;
539
540      /* This is somewhat type incorrect.  */
541      time ((void *) &time_value);
542
543      for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
544        {
545          for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
546            {
547              if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
548                continue;
549              for (blk = 0; blk < ptr->ncounts; blk++)
550                {
551                  if (!strcmp (p->funcname, ptr->functions[blk]))
552                    goto found;
553                }
554            }
555 
556          if (!printed_something)
557            {
558              fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
559              printed_something = 1;
560            }
561
562          fprintf (file, "\tFunction %s", p->funcname);
563          if (p->filename)
564              fprintf (file, " of file %s", p->filename);
565          fprintf (file, "\n" );
566 
567found:        ;
568        }
569
570      if (printed_something)
571       fprintf (file, "\n");
572
573    }
574
575  if (bb_mode & 2)
576    {
577      if (!bb_hashbuckets)
578        {
579          if (!reported)
580            {
581              fprintf (stderr, "Profiler: out of memory\n");
582              reported = 1;
583            }
584          return;
585        }
586   
587      else if (file)
588        {
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;
595   
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.  */
601   
602          time ((void *) &time_value);
603          fprintf (file, "Basic block jump tracing");
604
605          switch (bb_mode & 12)
606            {
607              case 0:
608                fprintf (file, " (with call)");
609              break;
610
611              case 4:
612                /* Print nothing.  */
613              break;
614
615              case 8:
616                fprintf (file, " (with call & ret)");
617              break;
618
619              case 12:
620                fprintf (file, " (with ret)");
621              break;
622            }
623
624          fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
625   
626          for (i = 0; i < BB_BUCKETS; i++)
627            {
628               struct bb_edge *bucket = bb_hashbuckets[i];
629               for ( ; bucket; bucket = bucket->next )
630                 {
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;
637                 }
638            }
639          addr_len = num_digits (addr_max, 16);
640          cnt_len  = num_digits (cnt_max, 10);
641   
642          for ( i = 0; i < BB_BUCKETS; i++)
643            {
644               struct bb_edge *bucket = bb_hashbuckets[i];
645               for ( ; bucket; bucket = bucket->next )
646                 {
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);
652                 }
653            }
654 
655          fprintf (file, "\n");
656
657        }
658    }
659
660   if (file)
661     fclose (file);
662
663   /* Free allocated memory.  */
664
665   f = bb_func_head;
666   while (f)
667     {
668       struct bb_func *old = f;
669
670       f = f->next;
671       if (old->funcname) free (old->funcname);
672       if (old->filename) free (old->filename);
673       free (old);
674     }
675
676   if (bb_stack)
677     free (bb_stack);
678
679   if (bb_hashbuckets)
680     {
681       int i;
682
683       for (i = 0; i < BB_BUCKETS; i++)
684         {
685           struct bb_edge *old, *bucket = bb_hashbuckets[i];
686
687           while (bucket)
688             {
689               old = bucket;
690               bucket = bucket->next;
691               free (old);
692             }
693         }
694       free (bb_hashbuckets);
695     }
696
697   for (b = bb_head; b; b = b->next)
698     if (b->flags) free (b->flags);
699}
700
701/* Called once per program.  */
702
703static void
704__bb_init_prg (void)
705{
706  FILE *file;
707  char buf[BBINBUFSIZE];
708  const char *p;
709  const char *pos;
710  enum bb_func_mode m;
711  int i;
712
713  /* Initialize destructor.  */
714  atexit (__bb_exit_func);
715
716  if (!(file = fopen ("bb.in", "r")))
717    return;
718
719  while(fgets (buf, BBINBUFSIZE, file) != 0)
720    {
721      i = strlen (buf);
722      if (buf[i-1] == '\n')
723        buf[--i] = '\0';
724
725      p = buf;
726      if (*p == '-') 
727        { 
728          m = TRACE_OFF; 
729          p++; 
730        }
731      else 
732        { 
733          m = TRACE_ON; 
734        }
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 
744        {
745          struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
746          if (f)
747            {
748              unsigned long l;
749              f->next = bb_func_head;
750              if ((pos = strchr (p, ':')))
751                {
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)))
757                    {
758                      strncpy (f->filename, p, l);
759                      f->filename[l] = '\0';
760                    }
761                  else
762                    f->filename = (char *) 0;
763                }
764              else
765                {
766                  if (!(f->funcname = (char *) malloc (strlen (p)+1)))
767                    continue;
768                  strcpy (f->funcname, p);
769                  f->filename = (char *) 0;
770                }
771              f->mode = m;
772              bb_func_head = f;
773            }
774         }
775    }
776  fclose (file);
777
778#ifdef HAVE_POPEN
779
780  if (bb_mode & 1)
781      bb_tracefile = gopen ("bbtrace.gz", "w");
782
783#else
784
785  if (bb_mode & 1)
786      bb_tracefile = fopen ("bbtrace", "w");
787
788#endif /* HAVE_POPEN */
789
790  if (bb_mode & 2)
791    {
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;
799    }
800
801  if (bb_mode & 12)
802    {
803      bb_stacksize = 10;
804      bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
805    }
806
807  /* Initialize destructor.  */
808  atexit (__bb_exit_trace_func);
809}
810
811/* Called upon entering a basic block.  */
812
813void
814__bb_trace_func (void)
815{
816  struct bb_edge *bucket;
817
818  MACHINE_STATE_SAVE("1")
819
820  if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
821    goto skip;
822
823  bb_dst = __bb.blocks->addresses[__bb.blockno];
824  __bb.blocks->counts[__bb.blockno]++;
825
826  if (bb_tracefile)
827    {
828      fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
829    }
830
831  if (bb_hashbuckets)
832    {
833      struct bb_edge **startbucket, **oldnext;
834
835      oldnext = startbucket
836        = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
837      bucket = *startbucket;
838
839      for (bucket = *startbucket; bucket; 
840           oldnext = &(bucket->next), bucket = *oldnext)
841        {
842          if (bucket->src_addr == bb_src
843              && bucket->dst_addr == bb_dst)
844            {
845              bucket->count++;
846              *oldnext = bucket->next;
847              bucket->next = *startbucket;
848              *startbucket = bucket;
849              goto ret;
850            }
851        }
852
853      bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
854
855      if (!bucket)
856        {
857          if (!reported)
858            {
859              fprintf (stderr, "Profiler: out of memory\n");
860              reported = 1;
861            }
862        }
863
864      else
865        {
866          bucket->src_addr = bb_src;
867          bucket->dst_addr = bb_dst;
868          bucket->next = *startbucket;
869          *startbucket = bucket;
870          bucket->count = 1;
871        }
872    }
873
874ret:
875  bb_src = bb_dst;
876
877skip:
878  ;
879
880  MACHINE_STATE_RESTORE("1")
881
882}
883
884/* Called when returning from a function and `__bb_showret__' is set.  */
885
886static void
887__bb_trace_func_ret (void)
888{
889  struct bb_edge *bucket;
890
891  if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
892    goto skip;
893
894  if (bb_hashbuckets)
895    {
896      struct bb_edge **startbucket, **oldnext;
897
898      oldnext = startbucket
899        = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
900      bucket = *startbucket;
901
902      for (bucket = *startbucket; bucket; 
903           oldnext = &(bucket->next), bucket = *oldnext)
904        {
905          if (bucket->src_addr == bb_dst
906               && bucket->dst_addr == bb_src)
907            {
908              bucket->count++;
909              *oldnext = bucket->next;
910              bucket->next = *startbucket;
911              *startbucket = bucket;
912              goto ret;
913            }
914        }
915
916      bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
917
918      if (!bucket)
919        {
920          if (!reported)
921            {
922              fprintf (stderr, "Profiler: out of memory\n");
923              reported = 1;
924            }
925        }
926
927      else
928        {
929          bucket->src_addr = bb_dst;
930          bucket->dst_addr = bb_src;
931          bucket->next = *startbucket;
932          *startbucket = bucket;
933          bucket->count = 1;
934        }
935    }
936
937ret:
938  bb_dst = bb_src;
939
940skip:
941  ;
942
943}
944
945/* Called upon entering the first function of a file.  */
946
947static void
948__bb_init_file (struct bb *blocks)
949{
950
951  const struct bb_func *p;
952  long blk, ncounts = blocks->ncounts;
953  const char **functions = blocks->functions;
954
955  /* Set up linked list.  */
956  blocks->zero_word = 1;
957  blocks->next = bb_head;
958  bb_head = blocks;
959
960  blocks->flags = 0;
961  if (!bb_func_head
962      || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
963    return;
964
965  for (blk = 0; blk < ncounts; blk++)
966    blocks->flags[blk] = 0;
967
968  for (blk = 0; blk < ncounts; blk++)
969    {
970      for (p = bb_func_head; p; p = p->next)
971        {
972          if (!strcmp (p->funcname, functions[blk])
973              && (!p->filename || !strcmp (p->filename, blocks->filename)))
974            {
975              blocks->flags[blk] |= p->mode;
976            }
977        }
978    }
979
980}
981
982/* Called when exiting from a function.  */
983
984void
985__bb_trace_ret (void)
986{
987
988  MACHINE_STATE_SAVE("2")
989
990  if (bb_callcount)
991    {
992      if ((bb_mode & 12) && bb_stacksize > bb_callcount)
993        {
994          bb_src = bb_stack[bb_callcount];
995          if (bb_mode & 8)
996            __bb_trace_func_ret ();
997        }
998
999      bb_callcount -= 1;
1000    }
1001
1002  MACHINE_STATE_RESTORE("2")
1003
1004}
1005
1006/* Called when entering a function.  */
1007
1008void
1009__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
1010{
1011  static int trace_init = 0;
1012
1013  MACHINE_STATE_SAVE("3")
1014
1015  if (!blocks->zero_word)
1016    { 
1017      if (!trace_init)
1018        { 
1019          trace_init = 1;
1020          __bb_init_prg ();
1021        }
1022      __bb_init_file (blocks);
1023    }
1024
1025  if (bb_callcount)
1026    {
1027
1028      bb_callcount += 1;
1029
1030      if (bb_mode & 12)
1031        {
1032          if (bb_callcount >= bb_stacksize)
1033            {
1034              size_t newsize = bb_callcount + 100;
1035
1036              bb_stack = (unsigned long *) realloc (bb_stack, newsize);
1037              if (! bb_stack)
1038                {
1039                  if (!reported)
1040                    {
1041                      fprintf (stderr, "Profiler: out of memory\n");
1042                      reported = 1;
1043                    }
1044                  bb_stacksize = 0;
1045                  goto stack_overflow;
1046                }
1047              bb_stacksize = newsize;
1048            }
1049          bb_stack[bb_callcount] = bb_src;
1050
1051          if (bb_mode & 4)
1052            bb_src = 0;
1053
1054        }
1055
1056stack_overflow:;
1057
1058    }
1059
1060  else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
1061    {
1062      bb_callcount = 1;
1063      bb_src = 0;
1064
1065      if (bb_stack)
1066          bb_stack[bb_callcount] = bb_src;
1067    }
1068
1069  MACHINE_STATE_RESTORE("3")
1070}
1071
Note: See TracBrowser for help on using the repository browser.