OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [gmon-sol2.c] - Blame information for rev 849

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 734 jeremybenn
/*-
2
 * Copyright (c) 1991 The Regents of the University of California.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. [rescinded 22 July 1999]
14
 * 4. Neither the name of the University nor the names of its contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
 
31
/* Mangled into a form that works on Solaris 2/SPARC by Mark Eichin
32
 * for Cygnus Support, July 1992.
33
 *
34
 * Modified to support Solaris 2/x86 by J.W.Hawtin <oolon@ankh.org>, 14/8/96.
35
 *
36
 * It must be used in conjunction with sol2-gc1.S, which is used to start
37
 * and stop process monitoring.
38
 */
39
 
40
#include "tconfig.h"
41
#include "tsystem.h"
42
#include <fcntl.h>              /* For creat.  */
43
 
44
extern void monstartup (char *, char *);
45
extern void _mcleanup (void);
46
#ifdef __i386__
47
static void internal_mcount (void) __attribute__ ((used));
48
#else
49
static void internal_mcount (char *, unsigned short *) __attribute__ ((used));
50
#endif
51
static void moncontrol (int);
52
 
53
struct phdr {
54
  char *lpc;
55
  char *hpc;
56
  int ncnt;
57
};
58
 
59
#define HISTFRACTION    2
60
#define HISTCOUNTER     unsigned short
61
#define HASHFRACTION    1
62
#define ARCDENSITY      2
63
#define MINARCS         50
64
 
65
struct tostruct {
66
  char *selfpc;
67
  long count;
68
  unsigned short link;
69
};
70
 
71
struct rawarc {
72
  unsigned long raw_frompc;
73
  unsigned long raw_selfpc;
74
  long raw_count;
75
};
76
 
77
#define ROUNDDOWN(x, y) (((x) / (y)) * (y))
78
#define ROUNDUP(x, y)   ((((x) + (y) - 1) / (y)) * (y))
79
 
80
/* froms is actually a bunch of unsigned shorts indexing tos.  */
81
static int profiling = 3;
82
static unsigned short *froms;
83
static struct tostruct *tos = NULL;
84
static long tolimit = 0;
85
static char *s_lowpc = NULL;
86
static char *s_highpc = NULL;
87
static size_t s_textsize = 0;
88
 
89
static int ssiz;
90
static char *sbuf;
91
static int s_scale;
92
/* See profil(2) where this is describe (incorrectly).  */
93
#define SCALE_1_TO_1    0x10000L
94
 
95
#define MSG "No space for profiling buffer(s)\n"
96
 
97
void
98
monstartup (char *lowpc, char *highpc)
99
{
100
  size_t monsize;
101
  char *buffer;
102
  size_t o;
103
 
104
  /* Round lowpc and highpc to multiples of the density we're using
105
     so the rest of the scaling (here and in gprof) stays in ints.  */
106
  lowpc = (char *) ROUNDDOWN ((size_t) lowpc,
107
                              HISTFRACTION * sizeof (HISTCOUNTER));
108
  s_lowpc = lowpc;
109
  highpc = (char *) ROUNDUP ((size_t) highpc,
110
                             HISTFRACTION * sizeof (HISTCOUNTER));
111
  s_highpc = highpc;
112
  s_textsize = highpc - lowpc;
113
  monsize = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
114
  buffer = sbrk (monsize);
115
  if (buffer == (void *) -1) {
116
    write (STDERR_FILENO, MSG, sizeof (MSG));
117
    return;
118
  }
119
  froms = sbrk (s_textsize / HASHFRACTION);
120
  if (froms == (void *) -1) {
121
    write (STDERR_FILENO, MSG, sizeof (MSG));
122
    froms = NULL;
123
    return;
124
  }
125
  tolimit = s_textsize * ARCDENSITY / 100;
126
  if (tolimit < MINARCS) {
127
    tolimit = MINARCS;
128
  } else if (tolimit > 65534) {
129
    tolimit = 65534;
130
  }
131
  tos = sbrk (tolimit * sizeof (struct tostruct));
132
  if (tos == (void *) -1) {
133
    write (STDERR_FILENO, MSG, sizeof (MSG));
134
    froms = NULL;
135
    tos = NULL;
136
    return;
137
  }
138
  tos[0].link = 0;
139
  sbuf = buffer;
140
  ssiz = monsize;
141
  ((struct phdr *) buffer)->lpc = lowpc;
142
  ((struct phdr *) buffer)->hpc = highpc;
143
  ((struct phdr *) buffer)->ncnt = ssiz;
144
  monsize -= sizeof (struct phdr);
145
  if (monsize <= 0)
146
    return;
147
  o = highpc - lowpc;
148
  if(monsize < o)
149
    s_scale = ((float) monsize / o) * SCALE_1_TO_1;
150
  else
151
    s_scale = SCALE_1_TO_1;
152
  moncontrol (1);
153
}
154
 
155
void
156
_mcleanup (void)
157
{
158
  int fd;
159
  int fromindex;
160
  int endfrom;
161
  char *frompc;
162
  int toindex;
163
  struct rawarc rawarc;
164
  char *profdir;
165
  const char *proffile;
166
  char *progname;
167
  char buf[PATH_MAX];
168
  extern char **___Argv;
169
 
170
  moncontrol (0);
171
 
172
  if ((profdir = getenv ("PROFDIR")) != NULL) {
173
    /* If PROFDIR contains a null value, no profiling output is produced.  */
174
    if (*profdir == '\0') {
175
      return;
176
    }
177
 
178
    progname = strrchr (___Argv[0], '/');
179
    if (progname == NULL)
180
      progname = ___Argv[0];
181
    else
182
      progname++;
183
 
184
    sprintf (buf, "%s/%ld.%s", profdir, (long) getpid (), progname);
185
    proffile = buf;
186
  } else {
187
    proffile = "gmon.out";
188
  }
189
 
190
  fd = creat (proffile, 0666);
191
  if (fd < 0) {
192
    perror (proffile);
193
    return;
194
  }
195
#ifdef DEBUG
196
  fprintf (stderr, "[mcleanup] sbuf %#x ssiz %d\n", sbuf, ssiz);
197
#endif /* DEBUG */
198
 
199
  write (fd, sbuf, ssiz);
200
  endfrom = s_textsize / (HASHFRACTION * sizeof (*froms));
201
  for (fromindex = 0; fromindex < endfrom; fromindex++) {
202
    if (froms[fromindex] == 0) {
203
      continue;
204
    }
205
    frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof (*froms));
206
    for (toindex = froms[fromindex];
207
         toindex != 0;
208
         toindex = tos[toindex].link) {
209
#ifdef DEBUG
210
      fprintf (stderr, "[mcleanup] frompc %#x selfpc %#x count %d\n",
211
               frompc, tos[toindex].selfpc, tos[toindex].count);
212
#endif /* DEBUG */
213
      rawarc.raw_frompc = (unsigned long) frompc;
214
      rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
215
      rawarc.raw_count = tos[toindex].count;
216
      write (fd, &rawarc, sizeof (rawarc));
217
    }
218
  }
219
  close (fd);
220
}
221
 
222
/* Solaris 2 libraries use _mcount.  */
223
#if defined __i386__
224
asm(".globl _mcount\n"
225
    "_mcount:\n"
226
    "   jmp     internal_mcount\n");
227
#elif defined __x86_64__
228
/* See GLIBC for additional information about this technique.  */
229
asm(".globl _mcount\n"
230
    "   .type   _mcount, @function\n"
231
    "_mcount:\n"
232
    /* The compiler calls _mcount after the prologue, and does not
233
       save any of the registers.  Therefore we must preserve all
234
       seven registers which may contain function arguments.  */
235
    "   subq    $0x38, %rsp\n"
236
    "   movq    %rax, (%rsp)\n"
237
    "   movq    %rcx, 0x08(%rsp)\n"
238
    "   movq    %rdx, 0x10(%rsp)\n"
239
    "   movq    %rsi, 0x18(%rsp)\n"
240
    "   movq    %rdi, 0x20(%rsp)\n"
241
    "   movq    %r8, 0x28(%rsp)\n"
242
    "   movq    %r9, 0x30(%rsp)\n"
243
    /* Get SELFPC (pushed by the call to this function) and
244
       FROMPCINDEX (via the frame pointer).  */
245
    "   movq    0x38(%rsp), %rdi\n"
246
    "   movq    0x8(%rbp), %rsi\n"
247
    "   call    internal_mcount\n"
248
    /* Restore the saved registers.  */
249
    "   movq    0x30(%rsp), %r9\n"
250
    "   movq    0x28(%rsp), %r8\n"
251
    "   movq    0x20(%rsp), %rdi\n"
252
    "   movq    0x18(%rsp), %rsi\n"
253
    "   movq    0x10(%rsp), %rdx\n"
254
    "   movq    0x08(%rsp), %rcx\n"
255
    "   movq    (%rsp), %rax\n"
256
    "   addq    $0x38, %rsp\n"
257
    "   retq\n");
258
#elif defined __sparc__
259
/* The SPARC stack frame is only held together by the frame pointers
260
   in the register windows. According to the SVR4 SPARC ABI
261
   Supplement, Low Level System Information/Operating System
262
   Interface/Software Trap Types, a type 3 trap will flush all of the
263
   register windows to the stack, which will make it possible to walk
264
   the frames and find the return addresses.
265
        However, it seems awfully expensive to incur a trap (system
266
   call) for every function call. It turns out that "call" simply puts
267
   the return address in %o7 expecting the "save" in the procedure to
268
   shift it into %i7; this means that before the "save" occurs, %o7
269
   contains the address of the call to mcount, and %i7 still contains
270
   the caller above that. The asm mcount here simply saves those
271
   registers in argument registers and branches to internal_mcount,
272
   simulating a call with arguments.
273
        Kludges:
274
        1) the branch to internal_mcount is hard coded; it should be
275
   possible to tell asm to use the assembler-name of a symbol.
276
        2) in theory, the function calling mcount could have saved %i7
277
   somewhere and reused the register; in practice, I *think* this will
278
   break longjmp (and maybe the debugger) but I'm not certain. (I take
279
   some comfort in the knowledge that it will break the native mcount
280
   as well.)
281
        3) if builtin_return_address worked, this could be portable.
282
   However, it would really have to be optimized for arguments of 0
283
   and 1 and do something like what we have here in order to avoid the
284
   trap per function call performance hit.
285
        4) the atexit and monsetup calls prevent this from simply
286
   being a leaf routine that doesn't do a "save" (and would thus have
287
   access to %o7 and %i7 directly) but the call to write() at the end
288
   would have also prevented this.
289
 
290
   -- [eichin:19920702.1107EST]  */
291
asm(".global _mcount\n"
292
    "_mcount:\n"
293
    /* i7 == last ret, -> frompcindex.  */
294
    "   mov     %i7, %o1\n"
295
    /* o7 == current ret, -> selfpc.  */
296
    "   mov     %o7, %o0\n"
297
    "   b,a     internal_mcount\n");
298
#endif
299
 
300
static void
301
#ifdef __i386__
302
internal_mcount (void)
303
#else
304
internal_mcount (char *selfpc, unsigned short *frompcindex)
305
#endif
306
{
307
  struct tostruct *top;
308
  struct tostruct *prevtop;
309
  long toindex;
310
  static char already_setup;
311
 
312
#ifdef __i386__
313
  char *selfpc;
314
  unsigned short *frompcindex;
315
 
316
  /* Find the return address for mcount and the return address for mcount's
317
     caller.  */
318
 
319
  /* selfpc = pc pushed by mcount call.
320
     This identifies the function that was just entered.  */
321
  selfpc = (void *) __builtin_return_address (0);
322
  /* frompcindex = pc in preceding frame.
323
     This identifies the caller of the function just entered.  */
324
  frompcindex = (void *) __builtin_return_address (1);
325
#endif
326
 
327
  if(!already_setup) {
328
    extern char etext[];
329
 
330
    already_setup = 1;
331
 
332
#if defined __i386__
333
    /* <sys/vmparam.h> USERSTACK.  */
334
    monstartup ((char *) 0x8048000, etext);
335
#elif defined __x86_64__
336
    monstartup (NULL, etext);
337
#elif defined __sparc__
338
    {
339
      extern char _start[];
340
      extern char _init[];
341
 
342
      monstartup (_start < _init ? _start : _init, etext);
343
    }
344
#endif
345
    atexit (_mcleanup);
346
  }
347
  /* Check that we are profiling and that we aren't recursively invoked.  */
348
  if (profiling) {
349
    goto out;
350
  }
351
  profiling++;
352
  /* Check that frompcindex is a reasonable pc value.  For example: signal
353
     catchers get called from the stack, not from text space.  too bad.  */
354
  frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc);
355
  if ((unsigned long) frompcindex > s_textsize) {
356
    goto done;
357
  }
358
  frompcindex = &froms[((long) frompcindex) / (HASHFRACTION * sizeof (*froms))];
359
  toindex = *frompcindex;
360
  if (toindex == 0) {
361
    /* First time traversing this arc.  */
362
    toindex = ++tos[0].link;
363
    if (toindex >= tolimit) {
364
      goto overflow;
365
    }
366
    *frompcindex = toindex;
367
    top = &tos[toindex];
368
    top->selfpc = selfpc;
369
    top->count = 1;
370
    top->link = 0;
371
    goto done;
372
  }
373
  top = &tos[toindex];
374
  if (top->selfpc == selfpc) {
375
    /* arc at front of chain; usual case.  */
376
    top->count++;
377
    goto done;
378
  }
379
  /* Have to go looking down chain for it.  Top points to what we are
380
     looking at, prevtop points to previous top.  We know it is not at the
381
     head of the chain.  */
382
  for (; /* goto done */; ) {
383
    if (top->link == 0) {
384
      /* top is end of the chain and none of the chain had top->selfpc ==
385
         selfpc, so we allocate a new tostruct and link it to the head of
386
         the chain.  */
387
      toindex = ++tos[0].link;
388
      if (toindex >= tolimit) {
389
        goto overflow;
390
      }
391
      top = &tos[toindex];
392
      top->selfpc = selfpc;
393
      top->count = 1;
394
      top->link = *frompcindex;
395
      *frompcindex = toindex;
396
      goto done;
397
    }
398
    /* Otherwise, check the next arc on the chain.  */
399
    prevtop = top;
400
    top = &tos[top->link];
401
    if (top->selfpc == selfpc) {
402
      /* There it is.  Increment its count move it to the head of the
403
         chain.  */
404
      top->count++;
405
      toindex = prevtop->link;
406
      prevtop->link = top->link;
407
      top->link = *frompcindex;
408
      *frompcindex = toindex;
409
      goto done;
410
    }
411
 
412
  }
413
 done:
414
  profiling--;
415
  /* ... and fall through. */
416
 out:
417
  /* Normal return restores saved registers.  */
418
  return;
419
 
420
 overflow:
421
  /* Halt further profiling.  */
422
  profiling++;
423
 
424
#define TOLIMIT "mcount: tos overflow\n"
425
  write (STDERR_FILENO, TOLIMIT, sizeof (TOLIMIT));
426
  goto out;
427
}
428
 
429
/* Control profiling.  Profiling is what mcount checks to see if all the
430
   data structures are ready.  */
431
static void
432
moncontrol (int mode)
433
{
434
  if (mode) {
435
    /* Start.  */
436
    profil ((unsigned short *) (sbuf + sizeof (struct phdr)),
437
            ssiz - sizeof (struct phdr), (size_t) s_lowpc, s_scale);
438
    profiling = 0;
439
  } else {
440
    /* Stop.  */
441
    profil ((unsigned short *) 0, 0, 0, 0);
442
    profiling = 3;
443
  }
444
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.