-/* Commands executed by gopen. */
-
-#define GOPENDECOMPRESS "gzip -cd "
-#define GOPENCOMPRESS "gzip -c >"
-
-/* Like fopen but pipes through gzip. mode may only be "r" or "w".
- If it does not compile, simply replace gopen by fopen and delete
- '.gz' from any first parameter to gopen. */
-
-static FILE *
-gopen (char *fn, char *mode)
-{
- int use_gzip;
- char *p;
-
- if (mode[1])
- return (FILE *) 0;
-
- if (mode[0] != 'r' && mode[0] != 'w')
- return (FILE *) 0;
-
- p = fn + strlen (fn)-1;
- use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
- || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
-
- if (use_gzip)
- {
- if (mode[0]=='r')
- {
- FILE *f;
- char *s = (char *) malloc (sizeof (char) * strlen (fn)
- + sizeof (GOPENDECOMPRESS));
- strcpy (s, GOPENDECOMPRESS);
- strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
- f = popen (s, mode);
- free (s);
- return f;
- }
-
- else
- {
- FILE *f;
- char *s = (char *) malloc (sizeof (char) * strlen (fn)
- + sizeof (GOPENCOMPRESS));
- strcpy (s, GOPENCOMPRESS);
- strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
- if (!(f = popen (s, mode)))
- f = fopen (s, mode);
- free (s);
- return f;
- }
- }
-
- else
- return fopen (fn, mode);
-}
-
-static int
-gclose (FILE *f)
-{
- struct stat buf;
-
- if (f != 0)
- {
- if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
- return pclose (f);
-
- return fclose (f);
- }
- return 0;
-}
-
-#endif /* HAVE_POPEN */
-
-/* Called once per program. */
-
-static void
-__bb_exit_trace_func ()
-{
- FILE *file = fopen ("bb.out", "a");
- struct bb_func *f;
- struct bb *b;
-
- if (!file)
- perror ("bb.out");
-
- if (bb_mode & 1)
- {
- if (!bb_tracefile)
- perror ("bbtrace");
- else
-#ifdef HAVE_POPEN
- gclose (bb_tracefile);
-#else
- fclose (bb_tracefile);
-#endif /* HAVE_POPEN */
- }
-
- /* Check functions in `bb.in'. */
-
- if (file)
- {
- long time_value;
- const struct bb_func *p;
- int printed_something = 0;
- struct bb *ptr;
- long blk;
-
- /* This is somewhat type incorrect. */
- time ((void *) &time_value);
-
- for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
- {
- for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
- {
- if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
- continue;
- for (blk = 0; blk < ptr->ncounts; blk++)
- {
- if (!strcmp (p->funcname, ptr->functions[blk]))
- goto found;
- }
- }
-
- if (!printed_something)
- {
- fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
- printed_something = 1;
- }
-
- fprintf (file, "\tFunction %s", p->funcname);
- if (p->filename)
- fprintf (file, " of file %s", p->filename);
- fprintf (file, "\n" );
-
-found: ;
- }
-
- if (printed_something)
- fprintf (file, "\n");
-
- }
-
- if (bb_mode & 2)
- {
- if (!bb_hashbuckets)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- return;
- }
-
- else if (file)
- {
- long time_value;
- int i;
- unsigned long addr_max = 0;
- unsigned long cnt_max = 0;
- int cnt_len;
- int addr_len;
-
- /* This is somewhat type incorrect, but it avoids worrying about
- exactly where time.h is included from. It should be ok unless
- a void * differs from other pointer formats, or if sizeof (long)
- is < sizeof (time_t). It would be nice if we could assume the
- use of rationale standards here. */
-
- time ((void *) &time_value);
- fprintf (file, "Basic block jump tracing");
-
- switch (bb_mode & 12)
- {
- case 0:
- fprintf (file, " (with call)");
- break;
-
- case 4:
- /* Print nothing. */
- break;
-
- case 8:
- fprintf (file, " (with call & ret)");
- break;
-
- case 12:
- fprintf (file, " (with ret)");
- break;
- }
-
- fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
-
- for (i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *bucket = bb_hashbuckets[i];
- for ( ; bucket; bucket = bucket->next )
- {
- if (addr_max < bucket->src_addr)
- addr_max = bucket->src_addr;
- if (addr_max < bucket->dst_addr)
- addr_max = bucket->dst_addr;
- if (cnt_max < bucket->count)
- cnt_max = bucket->count;
- }
- }
- addr_len = num_digits (addr_max, 16);
- cnt_len = num_digits (cnt_max, 10);
-
- for ( i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *bucket = bb_hashbuckets[i];
- for ( ; bucket; bucket = bucket->next )
- {
- fprintf (file, "Jump from block 0x%.*lx to "
- "block 0x%.*lx executed %*lu time(s)\n",
- addr_len, bucket->src_addr,
- addr_len, bucket->dst_addr,
- cnt_len, bucket->count);
- }
- }
-
- fprintf (file, "\n");
-
- }
- }
-
- if (file)
- fclose (file);
-
- /* Free allocated memory. */
-
- f = bb_func_head;
- while (f)
- {
- struct bb_func *old = f;
-
- f = f->next;
- if (old->funcname) free (old->funcname);
- if (old->filename) free (old->filename);
- free (old);
- }
-
- if (bb_stack)
- free (bb_stack);
-
- if (bb_hashbuckets)
- {
- int i;
-
- for (i = 0; i < BB_BUCKETS; i++)
- {
- struct bb_edge *old, *bucket = bb_hashbuckets[i];
-
- while (bucket)
- {
- old = bucket;
- bucket = bucket->next;
- free (old);
- }
- }
- free (bb_hashbuckets);
- }
-
- for (b = bb_head; b; b = b->next)
- if (b->flags) free (b->flags);
-}
-
-/* Called once per program. */
-
-static void
-__bb_init_prg ()
-{
-
- FILE *file;
- char buf[BBINBUFSIZE];
- const char *p;
- const char *pos;
- enum bb_func_mode m;
-
-#ifdef ON_EXIT
- /* Initialize destructor. */
- ON_EXIT (__bb_exit_func, 0);
-#endif
-
- if (!(file = fopen ("bb.in", "r")))
- return;
-
- while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
- {
- p = buf;
- if (*p == '-')
- {
- m = TRACE_OFF;
- p++;
- }
- else
- {
- m = TRACE_ON;
- }
- if (!strcmp (p, "__bb_trace__"))
- bb_mode |= 1;
- else if (!strcmp (p, "__bb_jumps__"))
- bb_mode |= 2;
- else if (!strcmp (p, "__bb_hidecall__"))
- bb_mode |= 4;
- else if (!strcmp (p, "__bb_showret__"))
- bb_mode |= 8;
- else
- {
- struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
- if (f)
- {
- unsigned long l;
- f->next = bb_func_head;
- if ((pos = strchr (p, ':')))
- {
- if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
- continue;
- strcpy (f->funcname, pos+1);
- l = pos-p;
- if ((f->filename = (char *) malloc (l+1)))
- {
- strncpy (f->filename, p, l);
- f->filename[l] = '\0';
- }
- else
- f->filename = (char *) 0;
- }
- else
- {
- if (!(f->funcname = (char *) malloc (strlen (p)+1)))
- continue;
- strcpy (f->funcname, p);
- f->filename = (char *) 0;
- }
- f->mode = m;
- bb_func_head = f;
- }
- }
- }
- fclose (file);
-
-#ifdef HAVE_POPEN
-
- if (bb_mode & 1)
- bb_tracefile = gopen ("bbtrace.gz", "w");
-
-#else
-
- if (bb_mode & 1)
- bb_tracefile = fopen ("bbtrace", "w");
-
-#endif /* HAVE_POPEN */
-
- if (bb_mode & 2)
- {
- bb_hashbuckets = (struct bb_edge **)
- malloc (BB_BUCKETS * sizeof (struct bb_edge *));
- if (bb_hashbuckets)
- memset (bb_hashbuckets, 0, BB_BUCKETS * sizeof (struct bb_edge *));
- }
-
- if (bb_mode & 12)
- {
- bb_stacksize = 10;
- bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
- }
-
-#ifdef ON_EXIT
- /* Initialize destructor. */
- ON_EXIT (__bb_exit_trace_func, 0);
-#endif
-
-}
-
-/* Called upon entering a basic block. */
-
-void
-__bb_trace_func ()
-{
- struct bb_edge *bucket;
-
- MACHINE_STATE_SAVE("1")
-
- if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
- goto skip;
-
- bb_dst = __bb.blocks->addresses[__bb.blockno];
- __bb.blocks->counts[__bb.blockno]++;
-
- if (bb_tracefile)
- {
- fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
- }
-
- if (bb_hashbuckets)
- {
- struct bb_edge **startbucket, **oldnext;
-
- oldnext = startbucket
- = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
- bucket = *startbucket;
-
- for (bucket = *startbucket; bucket;
- oldnext = &(bucket->next), bucket = *oldnext)
- {
- if (bucket->src_addr == bb_src
- && bucket->dst_addr == bb_dst)
- {
- bucket->count++;
- *oldnext = bucket->next;
- bucket->next = *startbucket;
- *startbucket = bucket;
- goto ret;
- }
- }
-
- bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
-
- if (!bucket)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- }
-
- else
- {
- bucket->src_addr = bb_src;
- bucket->dst_addr = bb_dst;
- bucket->next = *startbucket;
- *startbucket = bucket;
- bucket->count = 1;
- }
- }
-
-ret:
- bb_src = bb_dst;
-
-skip:
- ;
-
- MACHINE_STATE_RESTORE("1")
-
-}
-
-/* Called when returning from a function and `__bb_showret__' is set. */
-
-static void
-__bb_trace_func_ret ()
-{
- struct bb_edge *bucket;
-
- if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
- goto skip;
-
- if (bb_hashbuckets)
- {
- struct bb_edge **startbucket, **oldnext;
-
- oldnext = startbucket
- = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
- bucket = *startbucket;
-
- for (bucket = *startbucket; bucket;
- oldnext = &(bucket->next), bucket = *oldnext)
- {
- if (bucket->src_addr == bb_dst
- && bucket->dst_addr == bb_src)
- {
- bucket->count++;
- *oldnext = bucket->next;
- bucket->next = *startbucket;
- *startbucket = bucket;
- goto ret;
- }
- }
-
- bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
-
- if (!bucket)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- }
-
- else
- {
- bucket->src_addr = bb_dst;
- bucket->dst_addr = bb_src;
- bucket->next = *startbucket;
- *startbucket = bucket;
- bucket->count = 1;
- }
- }
-
-ret:
- bb_dst = bb_src;
-
-skip:
- ;
-
-}
-
-/* Called upon entering the first function of a file. */
-
-static void
-__bb_init_file (struct bb *blocks)
-{
-
- const struct bb_func *p;
- long blk, ncounts = blocks->ncounts;
- const char **functions = blocks->functions;
-
- /* Set up linked list. */
- blocks->zero_word = 1;
- blocks->next = bb_head;
- bb_head = blocks;
-
- blocks->flags = 0;
- if (!bb_func_head
- || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
- return;
-
- for (blk = 0; blk < ncounts; blk++)
- blocks->flags[blk] = 0;
-
- for (blk = 0; blk < ncounts; blk++)
- {
- for (p = bb_func_head; p; p = p->next)
- {
- if (!strcmp (p->funcname, functions[blk])
- && (!p->filename || !strcmp (p->filename, blocks->filename)))
- {
- blocks->flags[blk] |= p->mode;
- }
- }
- }
-
-}
-
-/* Called when exiting from a function. */
-
-void
-__bb_trace_ret ()
-{
-
- MACHINE_STATE_SAVE("2")
-
- if (bb_callcount)
- {
- if ((bb_mode & 12) && bb_stacksize > bb_callcount)
- {
- bb_src = bb_stack[bb_callcount];
- if (bb_mode & 8)
- __bb_trace_func_ret ();
- }
-
- bb_callcount -= 1;
- }
-
- MACHINE_STATE_RESTORE("2")
-
-}
-
-/* Called when entering a function. */
-
-void
-__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
-{
- static int trace_init = 0;
-
- MACHINE_STATE_SAVE("3")
-
- if (!blocks->zero_word)
- {
- if (!trace_init)
- {
- trace_init = 1;
- __bb_init_prg ();
- }
- __bb_init_file (blocks);
- }
-
- if (bb_callcount)
- {
-
- bb_callcount += 1;
-
- if (bb_mode & 12)
- {
- if (bb_callcount >= bb_stacksize)
- {
- size_t newsize = bb_callcount + 100;
-
- bb_stack = (unsigned long *) realloc (bb_stack, newsize);
- if (! bb_stack)
- {
- if (!reported)
- {
- fprintf (stderr, "Profiler: out of memory\n");
- reported = 1;
- }
- bb_stacksize = 0;
- goto stack_overflow;
- }
- bb_stacksize = newsize;
- }
- bb_stack[bb_callcount] = bb_src;
-
- if (bb_mode & 4)
- bb_src = 0;
-
- }
-
-stack_overflow:;
-
- }
-
- else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
- {
- bb_callcount = 1;
- bb_src = 0;
-
- if (bb_stack)
- bb_stack[bb_callcount] = bb_src;
- }
-
- MACHINE_STATE_RESTORE("3")
-}
-
-#endif /* not inhibit_libc */
-#endif /* not BLOCK_PROFILER_CODE */
-#endif /* L_bb */
-\f
-#ifdef L_shtab
-unsigned int __shtab[] = {
- 0x00000001, 0x00000002, 0x00000004, 0x00000008,
- 0x00000010, 0x00000020, 0x00000040, 0x00000080,
- 0x00000100, 0x00000200, 0x00000400, 0x00000800,
- 0x00001000, 0x00002000, 0x00004000, 0x00008000,
- 0x00010000, 0x00020000, 0x00040000, 0x00080000,
- 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000
- };
-#endif
-\f
-#ifdef L_clear_cache
-/* Clear part of an instruction cache. */
-
-#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
-
-void
-__clear_cache (char *beg, char *end)
-{
-#ifdef CLEAR_INSN_CACHE
- CLEAR_INSN_CACHE (beg, end);
-#else
-#ifdef INSN_CACHE_SIZE
- static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
- static int initialized;
- int offset;
- void *start_addr
- void *end_addr;
- typedef (*function_ptr) ();
-
-#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
- /* It's cheaper to clear the whole cache.
- Put in a series of jump instructions so that calling the beginning
- of the cache will clear the whole thing. */
-
- if (! initialized)
- {
- int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
- int end_ptr = ptr + INSN_CACHE_SIZE;
-
- while (ptr < end_ptr)
- {
- *(INSTRUCTION_TYPE *)ptr
- = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
- *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
-
- initialized = 1;
- }
-
- /* Call the beginning of the sequence. */
- (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH))
- ());
-
-#else /* Cache is large. */
-
- if (! initialized)
- {
- int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
-
- while (ptr < (int) array + sizeof array)
- {
- *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
-
- initialized = 1;
- }
-
- /* Find the location in array that occupies the same cache line as BEG. */
-
- offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
- start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
- & -INSN_CACHE_PLANE_SIZE)
- + offset);