]> gcc.gnu.org Git - gcc.git/blame - gcc/libgcc2.c
varasm.c (assemble_variable): Add cast to remove warning.
[gcc.git] / gcc / libgcc2.c
CommitLineData
203b91b9
RS
1/* More subroutines needed by GCC output code on some machines. */
2/* Compile this one with gcc. */
e09d24ff
R
3/* Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 1999, 2000
4 Free Software Foundation, Inc.
203b91b9
RS
5
6This file is part of GNU CC.
7
8GNU CC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13GNU CC is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU CC; see the file COPYING. If not, write to
a35311b0
RK
20the Free Software Foundation, 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
203b91b9 22
d5c88b0a
RK
23/* As a special exception, if you link this library with other files,
24 some of which are compiled with GCC, to produce an executable,
25 this library does not by itself cause the resulting executable
26 to be covered by the GNU General Public License.
203b91b9
RS
27 This exception does not however invalidate any other reasons why
28 the executable file might be covered by the GNU General Public License. */
29
30/* It is incorrect to include config.h here, because this file is being
31 compiled for the target, and hence definitions concerning only the host
32 do not apply. */
33
0dadecf6 34#include "tconfig.h"
2e39bdbe 35#include "tsystem.h"
2467749d 36
bfe655f9 37#include "machmode.h"
daefd78b 38#include "defaults.h"
203b91b9
RS
39
40/* Don't use `fancy_abort' here even if config.h says to use it. */
41#ifdef abort
42#undef abort
43#endif
44
956d6950
JL
45/* In a cross-compilation situation, default to inhibiting compilation
46 of routines that use libc. */
47
eff0f7ac 48#if defined(CROSS_COMPILE) && !defined(inhibit_libc)
956d6950
JL
49#define inhibit_libc
50#endif
51
299b83b7 52#include "libgcc2.h"
203b91b9
RS
53\f
54#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
55#if defined (L_divdi3) || defined (L_moddi3)
56static inline
57#endif
996ed075
JJ
58DWtype
59__negdi2 (DWtype u)
203b91b9 60{
996ed075
JJ
61 DWunion w;
62 DWunion uu;
203b91b9
RS
63
64 uu.ll = u;
65
66 w.s.low = -uu.s.low;
996ed075 67 w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
203b91b9
RS
68
69 return w.ll;
70}
71#endif
72\f
37ef1054
RK
73/* Unless shift functions are defined whith full ANSI prototypes,
74 parameter b will be promoted to int if word_type is smaller than an int. */
203b91b9 75#ifdef L_lshrdi3
996ed075
JJ
76DWtype
77__lshrdi3 (DWtype u, word_type b)
203b91b9 78{
996ed075 79 DWunion w;
b799cfc3 80 word_type bm;
996ed075 81 DWunion uu;
203b91b9
RS
82
83 if (b == 0)
84 return u;
85
86 uu.ll = u;
87
996ed075 88 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
89 if (bm <= 0)
90 {
91 w.s.high = 0;
996ed075 92 w.s.low = (UWtype)uu.s.high >> -bm;
203b91b9
RS
93 }
94 else
95 {
996ed075
JJ
96 UWtype carries = (UWtype)uu.s.high << bm;
97 w.s.high = (UWtype)uu.s.high >> b;
98 w.s.low = ((UWtype)uu.s.low >> b) | carries;
203b91b9
RS
99 }
100
101 return w.ll;
102}
103#endif
104
105#ifdef L_ashldi3
996ed075
JJ
106DWtype
107__ashldi3 (DWtype u, word_type b)
203b91b9 108{
996ed075 109 DWunion w;
b799cfc3 110 word_type bm;
996ed075 111 DWunion uu;
203b91b9
RS
112
113 if (b == 0)
114 return u;
115
116 uu.ll = u;
117
996ed075 118 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
119 if (bm <= 0)
120 {
121 w.s.low = 0;
996ed075 122 w.s.high = (UWtype)uu.s.low << -bm;
203b91b9
RS
123 }
124 else
125 {
996ed075
JJ
126 UWtype carries = (UWtype)uu.s.low >> bm;
127 w.s.low = (UWtype)uu.s.low << b;
128 w.s.high = ((UWtype)uu.s.high << b) | carries;
203b91b9
RS
129 }
130
131 return w.ll;
132}
133#endif
134
135#ifdef L_ashrdi3
996ed075
JJ
136DWtype
137__ashrdi3 (DWtype u, word_type b)
203b91b9 138{
996ed075 139 DWunion w;
b799cfc3 140 word_type bm;
996ed075 141 DWunion uu;
203b91b9
RS
142
143 if (b == 0)
144 return u;
145
146 uu.ll = u;
147
996ed075 148 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
149 if (bm <= 0)
150 {
151 /* w.s.high = 1..1 or 0..0 */
996ed075 152 w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
203b91b9
RS
153 w.s.low = uu.s.high >> -bm;
154 }
155 else
156 {
996ed075 157 UWtype carries = (UWtype)uu.s.high << bm;
203b91b9 158 w.s.high = uu.s.high >> b;
996ed075 159 w.s.low = ((UWtype)uu.s.low >> b) | carries;
203b91b9
RS
160 }
161
162 return w.ll;
163}
164#endif
165\f
aa66bd06 166#ifdef L_ffsdi2
996ed075
JJ
167DWtype
168__ffsdi2 (DWtype u)
aa66bd06 169{
996ed075 170 DWunion uu, w;
aa66bd06
RS
171 uu.ll = u;
172 w.s.high = 0;
173 w.s.low = ffs (uu.s.low);
174 if (w.s.low != 0)
de6cbba6 175 return w.ll;
aa66bd06
RS
176 w.s.low = ffs (uu.s.high);
177 if (w.s.low != 0)
178 {
996ed075 179 w.s.low += BITS_PER_UNIT * sizeof (Wtype);
de6cbba6 180 return w.ll;
aa66bd06 181 }
de6cbba6 182 return w.ll;
aa66bd06
RS
183}
184#endif
185\f
203b91b9 186#ifdef L_muldi3
996ed075
JJ
187DWtype
188__muldi3 (DWtype u, DWtype v)
203b91b9 189{
996ed075
JJ
190 DWunion w;
191 DWunion uu, vv;
203b91b9
RS
192
193 uu.ll = u,
194 vv.ll = v;
195
196 w.ll = __umulsidi3 (uu.s.low, vv.s.low);
996ed075
JJ
197 w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
198 + (UWtype) uu.s.high * (UWtype) vv.s.low);
203b91b9
RS
199
200 return w.ll;
201}
202#endif
203\f
3904131a 204#ifdef L_udiv_w_sdiv
ce13d15f 205#if defined (sdiv_qrnnd)
996ed075
JJ
206UWtype
207__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
431b1ee0 208{
996ed075
JJ
209 UWtype q, r;
210 UWtype c0, c1, b1;
431b1ee0 211
996ed075 212 if ((Wtype) d >= 0)
431b1ee0 213 {
996ed075 214 if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
431b1ee0
TG
215 {
216 /* dividend, divisor, and quotient are nonnegative */
217 sdiv_qrnnd (q, r, a1, a0, d);
218 }
219 else
220 {
221 /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
996ed075 222 sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
431b1ee0
TG
223 /* Divide (c1*2^32 + c0) by d */
224 sdiv_qrnnd (q, r, c1, c0, d);
225 /* Add 2^31 to quotient */
996ed075 226 q += (UWtype) 1 << (W_TYPE_SIZE - 1);
431b1ee0
TG
227 }
228 }
229 else
230 {
231 b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
232 c1 = a1 >> 1; /* A/2 */
996ed075 233 c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
431b1ee0
TG
234
235 if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
236 {
237 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
238
239 r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
240 if ((d & 1) != 0)
241 {
242 if (r >= q)
243 r = r - q;
244 else if (q - r <= d)
245 {
246 r = r - q + d;
247 q--;
248 }
249 else
250 {
251 r = r - q + 2*d;
252 q -= 2;
253 }
254 }
255 }
256 else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
257 {
258 c1 = (b1 - 1) - c1;
259 c0 = ~c0; /* logical NOT */
260
261 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
262
263 q = ~q; /* (A/2)/b1 */
264 r = (b1 - 1) - r;
265
266 r = 2*r + (a0 & 1); /* A/(2*b1) */
267
268 if ((d & 1) != 0)
269 {
270 if (r >= q)
271 r = r - q;
272 else if (q - r <= d)
273 {
274 r = r - q + d;
275 q--;
276 }
277 else
278 {
279 r = r - q + 2*d;
280 q -= 2;
281 }
282 }
283 }
284 else /* Implies c1 = b1 */
285 { /* Hence a1 = d - 1 = 2*b1 - 1 */
286 if (a0 >= -d)
287 {
288 q = -1;
289 r = a0 + d;
290 }
291 else
292 {
293 q = -2;
294 r = a0 + 2*d;
295 }
296 }
297 }
298
299 *rp = r;
300 return q;
301}
ce13d15f
RK
302#else
303/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
996ed075
JJ
304UWtype
305__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
306 UWtype a1 __attribute__ ((__unused__)),
307 UWtype a0 __attribute__ ((__unused__)),
308 UWtype d __attribute__ ((__unused__)))
081f5e7e
KG
309{
310 return 0;
311}
ce13d15f 312#endif
431b1ee0
TG
313#endif
314\f
536bfcd0
RK
315#if (defined (L_udivdi3) || defined (L_divdi3) || \
316 defined (L_umoddi3) || defined (L_moddi3))
317#define L_udivmoddi4
318#endif
319
203b91b9 320#ifdef L_udivmoddi4
ab495388 321static const UQItype __clz_tab[] =
203b91b9
RS
322{
323 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
324 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
325 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
326 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
327 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
328 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
329 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
330 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
331};
332
536bfcd0
RK
333#if (defined (L_udivdi3) || defined (L_divdi3) || \
334 defined (L_umoddi3) || defined (L_moddi3))
335static inline
336#endif
996ed075
JJ
337UDWtype
338__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
203b91b9 339{
996ed075
JJ
340 DWunion ww;
341 DWunion nn, dd;
342 DWunion rr;
343 UWtype d0, d1, n0, n1, n2;
344 UWtype q0, q1;
345 UWtype b, bm;
203b91b9
RS
346
347 nn.ll = n;
348 dd.ll = d;
349
350 d0 = dd.s.low;
351 d1 = dd.s.high;
352 n0 = nn.s.low;
353 n1 = nn.s.high;
354
355#if !UDIV_NEEDS_NORMALIZATION
356 if (d1 == 0)
357 {
358 if (d0 > n1)
359 {
360 /* 0q = nn / 0D */
361
362 udiv_qrnnd (q0, n0, n1, n0, d0);
363 q1 = 0;
364
365 /* Remainder in n0. */
366 }
367 else
368 {
369 /* qq = NN / 0d */
370
371 if (d0 == 0)
372 d0 = 1 / d0; /* Divide intentionally by zero. */
373
374 udiv_qrnnd (q1, n1, 0, n1, d0);
375 udiv_qrnnd (q0, n0, n1, n0, d0);
376
377 /* Remainder in n0. */
378 }
379
380 if (rp != 0)
381 {
382 rr.s.low = n0;
383 rr.s.high = 0;
384 *rp = rr.ll;
385 }
386 }
387
388#else /* UDIV_NEEDS_NORMALIZATION */
389
390 if (d1 == 0)
391 {
392 if (d0 > n1)
393 {
394 /* 0q = nn / 0D */
395
396 count_leading_zeros (bm, d0);
397
398 if (bm != 0)
399 {
400 /* Normalize, i.e. make the most significant bit of the
401 denominator set. */
402
403 d0 = d0 << bm;
996ed075 404 n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
203b91b9
RS
405 n0 = n0 << bm;
406 }
407
408 udiv_qrnnd (q0, n0, n1, n0, d0);
409 q1 = 0;
410
411 /* Remainder in n0 >> bm. */
412 }
413 else
414 {
415 /* qq = NN / 0d */
416
417 if (d0 == 0)
418 d0 = 1 / d0; /* Divide intentionally by zero. */
419
420 count_leading_zeros (bm, d0);
421
422 if (bm == 0)
423 {
424 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
425 conclude (the most significant bit of n1 is set) /\ (the
426 leading quotient digit q1 = 1).
427
428 This special case is necessary, not an optimization.
996ed075 429 (Shifts counts of W_TYPE_SIZE are undefined.) */
203b91b9
RS
430
431 n1 -= d0;
432 q1 = 1;
433 }
434 else
435 {
436 /* Normalize. */
437
996ed075 438 b = W_TYPE_SIZE - bm;
203b91b9
RS
439
440 d0 = d0 << bm;
441 n2 = n1 >> b;
442 n1 = (n1 << bm) | (n0 >> b);
443 n0 = n0 << bm;
444
445 udiv_qrnnd (q1, n1, n2, n1, d0);
446 }
447
0f41302f 448 /* n1 != d0... */
203b91b9
RS
449
450 udiv_qrnnd (q0, n0, n1, n0, d0);
451
452 /* Remainder in n0 >> bm. */
453 }
454
455 if (rp != 0)
456 {
457 rr.s.low = n0 >> bm;
458 rr.s.high = 0;
459 *rp = rr.ll;
460 }
461 }
462#endif /* UDIV_NEEDS_NORMALIZATION */
463
464 else
465 {
466 if (d1 > n1)
467 {
468 /* 00 = nn / DD */
469
470 q0 = 0;
471 q1 = 0;
472
473 /* Remainder in n1n0. */
474 if (rp != 0)
475 {
476 rr.s.low = n0;
477 rr.s.high = n1;
478 *rp = rr.ll;
479 }
480 }
481 else
482 {
483 /* 0q = NN / dd */
484
485 count_leading_zeros (bm, d1);
486 if (bm == 0)
487 {
488 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
489 conclude (the most significant bit of n1 is set) /\ (the
490 quotient digit q0 = 0 or 1).
491
492 This special case is necessary, not an optimization. */
493
494 /* The condition on the next line takes advantage of that
495 n1 >= d1 (true due to program flow). */
496 if (n1 > d1 || n0 >= d0)
497 {
498 q0 = 1;
499 sub_ddmmss (n1, n0, n1, n0, d1, d0);
500 }
501 else
502 q0 = 0;
503
504 q1 = 0;
505
506 if (rp != 0)
507 {
508 rr.s.low = n0;
509 rr.s.high = n1;
510 *rp = rr.ll;
511 }
512 }
513 else
514 {
996ed075 515 UWtype m1, m0;
203b91b9
RS
516 /* Normalize. */
517
996ed075 518 b = W_TYPE_SIZE - bm;
203b91b9
RS
519
520 d1 = (d1 << bm) | (d0 >> b);
521 d0 = d0 << bm;
522 n2 = n1 >> b;
523 n1 = (n1 << bm) | (n0 >> b);
524 n0 = n0 << bm;
525
526 udiv_qrnnd (q0, n1, n2, n1, d1);
527 umul_ppmm (m1, m0, q0, d0);
528
529 if (m1 > n1 || (m1 == n1 && m0 > n0))
530 {
531 q0--;
532 sub_ddmmss (m1, m0, m1, m0, d1, d0);
533 }
534
535 q1 = 0;
536
537 /* Remainder in (n1n0 - m1m0) >> bm. */
538 if (rp != 0)
539 {
540 sub_ddmmss (n1, n0, n1, n0, m1, m0);
541 rr.s.low = (n1 << b) | (n0 >> bm);
542 rr.s.high = n1 >> bm;
543 *rp = rr.ll;
544 }
545 }
546 }
547 }
548
549 ww.s.low = q0;
550 ww.s.high = q1;
551 return ww.ll;
552}
553#endif
554
555#ifdef L_divdi3
996ed075
JJ
556DWtype
557__divdi3 (DWtype u, DWtype v)
203b91b9 558{
b799cfc3 559 word_type c = 0;
996ed075
JJ
560 DWunion uu, vv;
561 DWtype w;
203b91b9
RS
562
563 uu.ll = u;
564 vv.ll = v;
565
566 if (uu.s.high < 0)
567 c = ~c,
568 uu.ll = __negdi2 (uu.ll);
569 if (vv.s.high < 0)
570 c = ~c,
571 vv.ll = __negdi2 (vv.ll);
572
996ed075 573 w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
203b91b9
RS
574 if (c)
575 w = __negdi2 (w);
576
577 return w;
578}
579#endif
580
581#ifdef L_moddi3
996ed075
JJ
582DWtype
583__moddi3 (DWtype u, DWtype v)
203b91b9 584{
b799cfc3 585 word_type c = 0;
996ed075
JJ
586 DWunion uu, vv;
587 DWtype w;
203b91b9
RS
588
589 uu.ll = u;
590 vv.ll = v;
591
592 if (uu.s.high < 0)
593 c = ~c,
594 uu.ll = __negdi2 (uu.ll);
595 if (vv.s.high < 0)
596 vv.ll = __negdi2 (vv.ll);
597
598 (void) __udivmoddi4 (uu.ll, vv.ll, &w);
599 if (c)
600 w = __negdi2 (w);
601
602 return w;
603}
604#endif
605
606#ifdef L_umoddi3
996ed075
JJ
607UDWtype
608__umoddi3 (UDWtype u, UDWtype v)
203b91b9 609{
996ed075 610 UDWtype w;
203b91b9
RS
611
612 (void) __udivmoddi4 (u, v, &w);
613
614 return w;
615}
616#endif
617
618#ifdef L_udivdi3
996ed075
JJ
619UDWtype
620__udivdi3 (UDWtype n, UDWtype d)
203b91b9 621{
996ed075 622 return __udivmoddi4 (n, d, (UDWtype *) 0);
203b91b9
RS
623}
624#endif
625\f
626#ifdef L_cmpdi2
4be7c28f 627word_type
996ed075 628__cmpdi2 (DWtype a, DWtype b)
203b91b9 629{
996ed075 630 DWunion au, bu;
203b91b9
RS
631
632 au.ll = a, bu.ll = b;
633
634 if (au.s.high < bu.s.high)
635 return 0;
636 else if (au.s.high > bu.s.high)
637 return 2;
996ed075 638 if ((UWtype) au.s.low < (UWtype) bu.s.low)
203b91b9 639 return 0;
996ed075 640 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
203b91b9
RS
641 return 2;
642 return 1;
643}
644#endif
645
646#ifdef L_ucmpdi2
4be7c28f 647word_type
996ed075 648__ucmpdi2 (DWtype a, DWtype b)
203b91b9 649{
996ed075 650 DWunion au, bu;
203b91b9
RS
651
652 au.ll = a, bu.ll = b;
653
996ed075 654 if ((UWtype) au.s.high < (UWtype) bu.s.high)
203b91b9 655 return 0;
996ed075 656 else if ((UWtype) au.s.high > (UWtype) bu.s.high)
203b91b9 657 return 2;
996ed075 658 if ((UWtype) au.s.low < (UWtype) bu.s.low)
203b91b9 659 return 0;
996ed075 660 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
203b91b9
RS
661 return 2;
662 return 1;
663}
664#endif
665\f
eaa4b44c 666#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075
JJ
667#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
668#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ab495388 669
996ed075 670DWtype
37ef1054 671__fixunstfdi (TFtype a)
ab495388
RS
672{
673 TFtype b;
996ed075 674 UDWtype v;
ab495388
RS
675
676 if (a < 0)
677 return 0;
678
679 /* Compute high word of result, as a flonum. */
680 b = (a / HIGH_WORD_COEFF);
996ed075 681 /* Convert that to fixed (but not to DWtype!),
ab495388 682 and shift it into the high word. */
996ed075 683 v = (UWtype) b;
ab495388
RS
684 v <<= WORD_SIZE;
685 /* Remove high part from the TFtype, leaving the low part as flonum. */
686 a -= (TFtype)v;
996ed075 687 /* Convert that to fixed (but not to DWtype!) and add it in.
ab495388
RS
688 Sometimes A comes out negative. This is significant, since
689 A has more bits than a long int does. */
690 if (a < 0)
996ed075 691 v -= (UWtype) (- a);
ab495388 692 else
996ed075 693 v += (UWtype) a;
ab495388
RS
694 return v;
695}
696#endif
697
eaa4b44c 698#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075 699DWtype
37ef1054 700__fixtfdi (TFtype a)
ab495388
RS
701{
702 if (a < 0)
703 return - __fixunstfdi (-a);
704 return __fixunstfdi (a);
705}
706#endif
707
eaa4b44c 708#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075
JJ
709#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
710#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
e0799b34 711
996ed075 712DWtype
37ef1054 713__fixunsxfdi (XFtype a)
e0799b34
RS
714{
715 XFtype b;
996ed075 716 UDWtype v;
e0799b34
RS
717
718 if (a < 0)
719 return 0;
720
721 /* Compute high word of result, as a flonum. */
722 b = (a / HIGH_WORD_COEFF);
996ed075 723 /* Convert that to fixed (but not to DWtype!),
e0799b34 724 and shift it into the high word. */
996ed075 725 v = (UWtype) b;
e0799b34
RS
726 v <<= WORD_SIZE;
727 /* Remove high part from the XFtype, leaving the low part as flonum. */
728 a -= (XFtype)v;
996ed075 729 /* Convert that to fixed (but not to DWtype!) and add it in.
e0799b34
RS
730 Sometimes A comes out negative. This is significant, since
731 A has more bits than a long int does. */
732 if (a < 0)
996ed075 733 v -= (UWtype) (- a);
e0799b34 734 else
996ed075 735 v += (UWtype) a;
e0799b34
RS
736 return v;
737}
738#endif
739
eaa4b44c 740#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075 741DWtype
37ef1054 742__fixxfdi (XFtype a)
e0799b34
RS
743{
744 if (a < 0)
745 return - __fixunsxfdi (-a);
746 return __fixunsxfdi (a);
747}
748#endif
749
203b91b9 750#ifdef L_fixunsdfdi
996ed075
JJ
751#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
752#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 753
996ed075 754DWtype
37ef1054 755__fixunsdfdi (DFtype a)
203b91b9 756{
ab495388 757 DFtype b;
996ed075 758 UDWtype v;
203b91b9
RS
759
760 if (a < 0)
761 return 0;
762
763 /* Compute high word of result, as a flonum. */
764 b = (a / HIGH_WORD_COEFF);
996ed075 765 /* Convert that to fixed (but not to DWtype!),
203b91b9 766 and shift it into the high word. */
996ed075 767 v = (UWtype) b;
203b91b9 768 v <<= WORD_SIZE;
ab495388
RS
769 /* Remove high part from the DFtype, leaving the low part as flonum. */
770 a -= (DFtype)v;
996ed075 771 /* Convert that to fixed (but not to DWtype!) and add it in.
203b91b9
RS
772 Sometimes A comes out negative. This is significant, since
773 A has more bits than a long int does. */
774 if (a < 0)
996ed075 775 v -= (UWtype) (- a);
203b91b9 776 else
996ed075 777 v += (UWtype) a;
203b91b9
RS
778 return v;
779}
780#endif
781
782#ifdef L_fixdfdi
996ed075 783DWtype
37ef1054 784__fixdfdi (DFtype a)
203b91b9
RS
785{
786 if (a < 0)
787 return - __fixunsdfdi (-a);
788 return __fixunsdfdi (a);
789}
790#endif
791
792#ifdef L_fixunssfdi
996ed075
JJ
793#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
794#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 795
996ed075 796DWtype
ab495388 797__fixunssfdi (SFtype original_a)
203b91b9 798{
ab495388 799 /* Convert the SFtype to a DFtype, because that is surely not going
203b91b9 800 to lose any bits. Some day someone else can write a faster version
ab495388
RS
801 that avoids converting to DFtype, and verify it really works right. */
802 DFtype a = original_a;
803 DFtype b;
996ed075 804 UDWtype v;
203b91b9
RS
805
806 if (a < 0)
807 return 0;
808
809 /* Compute high word of result, as a flonum. */
810 b = (a / HIGH_WORD_COEFF);
996ed075 811 /* Convert that to fixed (but not to DWtype!),
203b91b9 812 and shift it into the high word. */
996ed075 813 v = (UWtype) b;
203b91b9 814 v <<= WORD_SIZE;
ab495388
RS
815 /* Remove high part from the DFtype, leaving the low part as flonum. */
816 a -= (DFtype)v;
996ed075 817 /* Convert that to fixed (but not to DWtype!) and add it in.
203b91b9
RS
818 Sometimes A comes out negative. This is significant, since
819 A has more bits than a long int does. */
820 if (a < 0)
996ed075 821 v -= (UWtype) (- a);
203b91b9 822 else
996ed075 823 v += (UWtype) a;
203b91b9
RS
824 return v;
825}
826#endif
827
828#ifdef L_fixsfdi
996ed075 829DWtype
ab495388 830__fixsfdi (SFtype a)
203b91b9
RS
831{
832 if (a < 0)
833 return - __fixunssfdi (-a);
834 return __fixunssfdi (a);
835}
836#endif
837
eaa4b44c 838#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075
JJ
839#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
840#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
841#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
e0799b34
RS
842
843XFtype
996ed075 844__floatdixf (DWtype u)
e0799b34
RS
845{
846 XFtype d;
e0799b34 847
996ed075 848 d = (Wtype) (u >> WORD_SIZE);
e0799b34
RS
849 d *= HIGH_HALFWORD_COEFF;
850 d *= HIGH_HALFWORD_COEFF;
996ed075 851 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
e0799b34 852
e5e809f4 853 return d;
e0799b34
RS
854}
855#endif
856
eaa4b44c 857#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075
JJ
858#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
859#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
860#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ab495388
RS
861
862TFtype
996ed075 863__floatditf (DWtype u)
ab495388
RS
864{
865 TFtype d;
ab495388 866
996ed075 867 d = (Wtype) (u >> WORD_SIZE);
ab495388
RS
868 d *= HIGH_HALFWORD_COEFF;
869 d *= HIGH_HALFWORD_COEFF;
996ed075 870 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
ab495388 871
e5e809f4 872 return d;
ab495388
RS
873}
874#endif
875
203b91b9 876#ifdef L_floatdidf
996ed075
JJ
877#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
878#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
879#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 880
ab495388 881DFtype
996ed075 882__floatdidf (DWtype u)
203b91b9 883{
ab495388 884 DFtype d;
203b91b9 885
996ed075 886 d = (Wtype) (u >> WORD_SIZE);
203b91b9
RS
887 d *= HIGH_HALFWORD_COEFF;
888 d *= HIGH_HALFWORD_COEFF;
996ed075 889 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
203b91b9 890
e5e809f4 891 return d;
203b91b9
RS
892}
893#endif
894
895#ifdef L_floatdisf
996ed075
JJ
896#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
897#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
898#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
899#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
cac896d8
RK
900
901/* Define codes for all the float formats that we know of. Note
902 that this is copied from real.h. */
903
904#define UNKNOWN_FLOAT_FORMAT 0
905#define IEEE_FLOAT_FORMAT 1
906#define VAX_FLOAT_FORMAT 2
907#define IBM_FLOAT_FORMAT 3
908
909/* Default to IEEE float if not specified. Nearly all machines use it. */
910#ifndef HOST_FLOAT_FORMAT
911#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
912#endif
913
914#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
d9e1ab8d
RK
915#define DF_SIZE 53
916#define SF_SIZE 24
cac896d8
RK
917#endif
918
919#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
d9e1ab8d
RK
920#define DF_SIZE 56
921#define SF_SIZE 24
cac896d8
RK
922#endif
923
924#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
d9e1ab8d
RK
925#define DF_SIZE 56
926#define SF_SIZE 24
d9e1ab8d 927#endif
203b91b9 928
ab495388 929SFtype
996ed075 930__floatdisf (DWtype u)
203b91b9 931{
56b03d5f
RS
932 /* Do the calculation in DFmode
933 so that we don't lose any of the precision of the high word
934 while multiplying it. */
935 DFtype f;
203b91b9 936
d9e1ab8d
RK
937 /* Protect against double-rounding error.
938 Represent any low-order bits, that might be truncated in DFmode,
939 by a bit that won't be lost. The bit can go in anywhere below the
940 rounding position of the SFmode. A fixed mask and bit position
941 handles all usual configurations. It doesn't handle the case
942 of 128-bit DImode, however. */
943 if (DF_SIZE < DI_SIZE
944 && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
945 {
996ed075
JJ
946#define REP_BIT ((UWtype) 1 << (DI_SIZE - DF_SIZE))
947 if (! (- ((DWtype) 1 << DF_SIZE) < u
948 && u < ((DWtype) 1 << DF_SIZE)))
d9e1ab8d 949 {
996ed075 950 if ((UWtype) u & (REP_BIT - 1))
d9e1ab8d
RK
951 u |= REP_BIT;
952 }
953 }
996ed075 954 f = (Wtype) (u >> WORD_SIZE);
203b91b9
RS
955 f *= HIGH_HALFWORD_COEFF;
956 f *= HIGH_HALFWORD_COEFF;
996ed075 957 f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
203b91b9 958
e5e809f4 959 return (SFtype) f;
203b91b9
RS
960}
961#endif
962
eaa4b44c 963#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
3f3d2ec8
JW
964/* Reenable the normal types, in case limits.h needs them. */
965#undef char
966#undef short
967#undef int
968#undef long
969#undef unsigned
970#undef float
971#undef double
c07e26bd
RK
972#undef MIN
973#undef MAX
a99598c9 974#include <limits.h>
e0799b34 975
996ed075 976UWtype
37ef1054 977__fixunsxfsi (XFtype a)
e0799b34
RS
978{
979 if (a >= - (DFtype) LONG_MIN)
996ed075
JJ
980 return (Wtype) (a + LONG_MIN) - LONG_MIN;
981 return (Wtype) a;
e0799b34
RS
982}
983#endif
984
203b91b9 985#ifdef L_fixunsdfsi
3f3d2ec8
JW
986/* Reenable the normal types, in case limits.h needs them. */
987#undef char
988#undef short
989#undef int
990#undef long
991#undef unsigned
992#undef float
993#undef double
c07e26bd
RK
994#undef MIN
995#undef MAX
a99598c9 996#include <limits.h>
203b91b9 997
996ed075 998UWtype
37ef1054 999__fixunsdfsi (DFtype a)
203b91b9 1000{
ab495388 1001 if (a >= - (DFtype) LONG_MIN)
996ed075
JJ
1002 return (Wtype) (a + LONG_MIN) - LONG_MIN;
1003 return (Wtype) a;
203b91b9
RS
1004}
1005#endif
1006
1007#ifdef L_fixunssfsi
3f3d2ec8
JW
1008/* Reenable the normal types, in case limits.h needs them. */
1009#undef char
1010#undef short
1011#undef int
1012#undef long
1013#undef unsigned
1014#undef float
1015#undef double
c07e26bd
RK
1016#undef MIN
1017#undef MAX
a99598c9 1018#include <limits.h>
203b91b9 1019
996ed075 1020UWtype
ab495388 1021__fixunssfsi (SFtype a)
203b91b9 1022{
ab495388 1023 if (a >= - (SFtype) LONG_MIN)
996ed075
JJ
1024 return (Wtype) (a + LONG_MIN) - LONG_MIN;
1025 return (Wtype) a;
203b91b9
RS
1026}
1027#endif
1028\f
ab495388
RS
1029/* From here on down, the routines use normal data types. */
1030
1031#define SItype bogus_type
1032#define USItype bogus_type
1033#define DItype bogus_type
1034#define UDItype bogus_type
1035#define SFtype bogus_type
1036#define DFtype bogus_type
996ed075
JJ
1037#undef Wtype
1038#undef UWtype
1039#undef HWtype
1040#undef UHWtype
1041#undef DWtype
1042#undef UDWtype
ab495388
RS
1043
1044#undef char
1045#undef short
1046#undef int
1047#undef long
1048#undef unsigned
1049#undef float
1050#undef double
9bd23d2c
RS
1051\f
1052#ifdef L__gcc_bcmp
1053
1054/* Like bcmp except the sign is meaningful.
9faa82d8 1055 Result is negative if S1 is less than S2,
9bd23d2c
RS
1056 positive if S1 is greater, 0 if S1 and S2 are equal. */
1057
1058int
299b83b7 1059__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
9bd23d2c
RS
1060{
1061 while (size > 0)
1062 {
78e33213 1063 unsigned char c1 = *s1++, c2 = *s2++;
9bd23d2c
RS
1064 if (c1 != c2)
1065 return c1 - c2;
1066 size--;
1067 }
1068 return 0;
1069}
ab495388 1070
9bd23d2c
RS
1071#endif
1072\f\f
2e06e616
RK
1073#ifdef L__dummy
1074void
3e7d8ef1 1075__dummy (void) {}
2e06e616
RK
1076#endif
1077
203b91b9
RS
1078#ifdef L_varargs
1079#ifdef __i860__
600032fc 1080#if defined(__svr4__) || defined(__alliant__)
203b91b9
RS
1081 asm (" .text");
1082 asm (" .align 4");
1083
27d21d32 1084/* The Alliant needs the added underscore. */
203b91b9
RS
1085 asm (".globl __builtin_saveregs");
1086asm ("__builtin_saveregs:");
27d21d32
RS
1087 asm (".globl ___builtin_saveregs");
1088asm ("___builtin_saveregs:");
1089
1090 asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
203b91b9
RS
1091 asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save
1092 area and also for a new va_list
1093 structure */
1094 /* Save all argument registers in the arg reg save area. The
1095 arg reg save area must have the following layout (according
1096 to the svr4 ABI):
1097
1098 struct {
1099 union {
1100 float freg[8];
1101 double dreg[4];
1102 } float_regs;
1103 long ireg[12];
1104 };
1105 */
1106
1107 asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
1108 asm (" fst.q %f12,16(%sp)");
1109
1110 asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
1111 asm (" st.l %r17,36(%sp)");
1112 asm (" st.l %r18,40(%sp)");
1113 asm (" st.l %r19,44(%sp)");
1114 asm (" st.l %r20,48(%sp)");
1115 asm (" st.l %r21,52(%sp)");
1116 asm (" st.l %r22,56(%sp)");
1117 asm (" st.l %r23,60(%sp)");
1118 asm (" st.l %r24,64(%sp)");
1119 asm (" st.l %r25,68(%sp)");
1120 asm (" st.l %r26,72(%sp)");
1121 asm (" st.l %r27,76(%sp)");
1122
1123 asm (" adds 80,%sp,%r16"); /* compute the address of the new
1124 va_list structure. Put in into
1125 r16 so that it will be returned
1126 to the caller. */
1127
1128 /* Initialize all fields of the new va_list structure. This
1129 structure looks like:
1130
1131 typedef struct {
1132 unsigned long ireg_used;
1133 unsigned long freg_used;
1134 long *reg_base;
1135 long *mem_ptr;
1136 } va_list;
1137 */
1138
1139 asm (" st.l %r0, 0(%r16)"); /* nfixed */
1140 asm (" st.l %r0, 4(%r16)"); /* nfloating */
1141 asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */
1142 asm (" bri %r1"); /* delayed return */
1143 asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */
1144
24e4939e 1145#else /* not __svr4__ */
6aadf9c2
RS
1146#if defined(__PARAGON__)
1147 /*
1148 * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
1149 * and we stand a better chance of hooking into libraries
1150 * compiled by PGI. [andyp@ssd.intel.com]
1151 */
1152 asm (" .text");
1153 asm (" .align 4");
1154 asm (".globl __builtin_saveregs");
1155asm ("__builtin_saveregs:");
1156 asm (".globl ___builtin_saveregs");
1157asm ("___builtin_saveregs:");
1158
1159 asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */
1160 asm (" adds -96,sp,sp"); /* allocate stack space for reg save
1161 area and also for a new va_list
1162 structure */
1163 /* Save all argument registers in the arg reg save area. The
1164 arg reg save area must have the following layout (according
1165 to the svr4 ABI):
1166
1167 struct {
1168 union {
1169 float freg[8];
1170 double dreg[4];
1171 } float_regs;
1172 long ireg[12];
1173 };
1174 */
1175
1176 asm (" fst.q f8, 0(sp)");
1177 asm (" fst.q f12,16(sp)");
1178 asm (" st.l r16,32(sp)");
1179 asm (" st.l r17,36(sp)");
1180 asm (" st.l r18,40(sp)");
1181 asm (" st.l r19,44(sp)");
1182 asm (" st.l r20,48(sp)");
1183 asm (" st.l r21,52(sp)");
1184 asm (" st.l r22,56(sp)");
1185 asm (" st.l r23,60(sp)");
1186 asm (" st.l r24,64(sp)");
1187 asm (" st.l r25,68(sp)");
1188 asm (" st.l r26,72(sp)");
1189 asm (" st.l r27,76(sp)");
1190
1191 asm (" adds 80,sp,r16"); /* compute the address of the new
1192 va_list structure. Put in into
1193 r16 so that it will be returned
1194 to the caller. */
1195
1196 /* Initialize all fields of the new va_list structure. This
1197 structure looks like:
1198
1199 typedef struct {
1200 unsigned long ireg_used;
1201 unsigned long freg_used;
1202 long *reg_base;
1203 long *mem_ptr;
1204 } va_list;
1205 */
1206
1207 asm (" st.l r0, 0(r16)"); /* nfixed */
1208 asm (" st.l r0, 4(r16)"); /* nfloating */
1209 asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */
1210 asm (" bri r1"); /* delayed return */
1211 asm (" st.l r28,12(r16)"); /* pointer to overflow args */
1212#else /* not __PARAGON__ */
203b91b9
RS
1213 asm (" .text");
1214 asm (" .align 4");
1215
1216 asm (".globl ___builtin_saveregs");
1217 asm ("___builtin_saveregs:");
1218 asm (" mov sp,r30");
1219 asm (" andnot 0x0f,sp,sp");
1220 asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
1221
1222/* Fill in the __va_struct. */
1223 asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
1224 asm (" st.l r17, 4(sp)"); /* int fixed[12] */
1225 asm (" st.l r18, 8(sp)");
1226 asm (" st.l r19,12(sp)");
1227 asm (" st.l r20,16(sp)");
1228 asm (" st.l r21,20(sp)");
1229 asm (" st.l r22,24(sp)");
1230 asm (" st.l r23,28(sp)");
1231 asm (" st.l r24,32(sp)");
1232 asm (" st.l r25,36(sp)");
1233 asm (" st.l r26,40(sp)");
1234 asm (" st.l r27,44(sp)");
1235
1236 asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
1237 asm (" fst.q f12,64(sp)"); /* int floating[8] */
1238
1239/* Fill in the __va_ctl. */
1240 asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
1241 asm (" st.l r28,84(sp)"); /* pointer to more args */
1242 asm (" st.l r0, 88(sp)"); /* nfixed */
1243 asm (" st.l r0, 92(sp)"); /* nfloating */
1244
1245 asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
1246 asm (" bri r1");
1247 asm (" mov r30,sp");
1248 /* recover stack and pass address to start
1249 of data. */
6aadf9c2 1250#endif /* not __PARAGON__ */
24e4939e 1251#endif /* not __svr4__ */
203b91b9
RS
1252#else /* not __i860__ */
1253#ifdef __sparc__
b335c2cc
TW
1254 asm (".global __builtin_saveregs");
1255 asm ("__builtin_saveregs:");
203b91b9
RS
1256 asm (".global ___builtin_saveregs");
1257 asm ("___builtin_saveregs:");
b1166fae
RS
1258#ifdef NEED_PROC_COMMAND
1259 asm (".proc 020");
b335c2cc 1260#endif
203b91b9
RS
1261 asm ("st %i0,[%fp+68]");
1262 asm ("st %i1,[%fp+72]");
1263 asm ("st %i2,[%fp+76]");
1264 asm ("st %i3,[%fp+80]");
1265 asm ("st %i4,[%fp+84]");
1266 asm ("retl");
1267 asm ("st %i5,[%fp+88]");
b1166fae
RS
1268#ifdef NEED_TYPE_COMMAND
1269 asm (".type __builtin_saveregs,#function");
1270 asm (".size __builtin_saveregs,.-__builtin_saveregs");
1271#endif
203b91b9
RS
1272#else /* not __sparc__ */
1273#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
1274
1275 asm (" .text");
6003a6bf
JL
1276#ifdef __mips16
1277 asm (" .set nomips16");
1278#endif
203b91b9
RS
1279 asm (" .ent __builtin_saveregs");
1280 asm (" .globl __builtin_saveregs");
1281 asm ("__builtin_saveregs:");
1282 asm (" sw $4,0($30)");
1283 asm (" sw $5,4($30)");
1284 asm (" sw $6,8($30)");
1285 asm (" sw $7,12($30)");
1286 asm (" j $31");
1287 asm (" .end __builtin_saveregs");
0f41302f 1288#else /* not __mips__, etc. */
3bd4f3b8 1289
299b83b7 1290void * __attribute__ ((__noreturn__))
3e7d8ef1 1291__builtin_saveregs (void)
203b91b9
RS
1292{
1293 abort ();
1294}
3bd4f3b8 1295
203b91b9
RS
1296#endif /* not __mips__ */
1297#endif /* not __sparc__ */
1298#endif /* not __i860__ */
1299#endif
1300\f
1301#ifdef L_eprintf
c74d5583 1302#ifndef inhibit_libc
bba2431c 1303
203b91b9
RS
1304#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
1305#include <stdio.h>
1306/* This is used by the `assert' macro. */
1307void
37ef1054 1308__eprintf (const char *string, const char *expression,
10c301ac 1309 unsigned int line, const char *filename)
203b91b9
RS
1310{
1311 fprintf (stderr, string, expression, line, filename);
1312 fflush (stderr);
1313 abort ();
1314}
bba2431c
RS
1315
1316#endif
203b91b9
RS
1317#endif
1318
1319#ifdef L_bb
203b91b9 1320
92832bb5 1321/* Structure emitted by -a */
203b91b9
RS
1322struct bb
1323{
92832bb5
MM
1324 long zero_word;
1325 const char *filename;
1326 long *counts;
1327 long ncounts;
1328 struct bb *next;
1329 const unsigned long *addresses;
1330
1331 /* Older GCC's did not emit these fields. */
1332 long nwords;
1333 const char **functions;
1334 const long *line_nums;
1335 const char **filenames;
90b4a764 1336 char *flags;
203b91b9
RS
1337};
1338
92832bb5
MM
1339#ifdef BLOCK_PROFILER_CODE
1340BLOCK_PROFILER_CODE
1341#else
c7544ff7 1342#ifndef inhibit_libc
92832bb5
MM
1343
1344/* Simple minded basic block profiling output dumper for
9faa82d8 1345 systems that don't provide tcov support. At present,
92832bb5
MM
1346 it requires atexit and stdio. */
1347
ebd41309 1348#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
92832bb5 1349#include <stdio.h>
b077f3ac 1350char *ctime ();
203b91b9 1351
8b7677be 1352#include "gbl-ctors.h"
65f7a653 1353#include "gcov-io.h"
ac957f13 1354#include <string.h>
e09d24ff
R
1355#ifdef TARGET_HAS_F_SETLKW
1356#include <fcntl.h>
1357#include <errno.h>
1358#endif
92832bb5 1359
7e6f1890 1360static struct bb *bb_head;
92832bb5 1361
e8f38d1a
DN
1362static int num_digits (long value, int base) __attribute__ ((const));
1363
92832bb5
MM
1364/* Return the number of digits needed to print a value */
1365/* __inline__ */ static int num_digits (long value, int base)
203b91b9 1366{
92832bb5
MM
1367 int minus = (value < 0 && base != 16);
1368 unsigned long v = (minus) ? -value : value;
1369 int ret = minus;
203b91b9 1370
92832bb5
MM
1371 do
1372 {
1373 v /= base;
1374 ret++;
1375 }
1376 while (v);
1377
1378 return ret;
203b91b9
RS
1379}
1380
92832bb5
MM
1381void
1382__bb_exit_func (void)
1383{
65f7a653 1384 FILE *da_file, *file;
92832bb5 1385 long time_value;
65f7a653
DE
1386 int i;
1387
1388 if (bb_head == 0)
1389 return;
1390
1391 i = strlen (bb_head->filename) - 3;
1392
1393 if (!strcmp (bb_head->filename+i, ".da"))
1394 {
1395 /* Must be -fprofile-arcs not -a.
1396 Dump data in a form that gcov expects. */
1397
1398 struct bb *ptr;
1399
1400 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1401 {
e09d24ff
R
1402 int firstchar;
1403
1404 /* Make sure the output file exists -
1405 but don't clobber exiting data. */
1406 if ((da_file = fopen (ptr->filename, "a")) != 0)
1407 fclose (da_file);
1408
1409 /* Need to re-open in order to be able to write from the start. */
1410 da_file = fopen (ptr->filename, "r+b");
1411 /* Some old systems might not allow the 'b' mode modifier.
1412 Therefore, try to open without it. This can lead to a race
1413 condition so that when you delete and re-create the file, the
1414 file might be opened in text mode, but then, you shouldn't
1415 delete the file in the first place. */
1416 if (da_file == 0)
1417 da_file = fopen (ptr->filename, "r+");
1418 if (da_file == 0)
1419 {
1420 fprintf (stderr, "arc profiling: Can't open output file %s.\n",
1421 ptr->filename);
1422 continue;
1423 }
1424
1425 /* After a fork, another process might try to read and/or write
1426 the same file simultanously. So if we can, lock the file to
1427 avoid race conditions. */
1428#if defined (TARGET_HAS_F_SETLKW)
1429 {
1430 struct flock s_flock;
1431
1432 s_flock.l_type = F_WRLCK;
1433 s_flock.l_whence = SEEK_SET;
1434 s_flock.l_start = 0;
1435 s_flock.l_len = 1;
1436 s_flock.l_pid = getpid ();
1437
1438 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
1439 && errno == EINTR);
1440 }
1441#endif
1442
1443 /* If the file is not empty, and the number of counts in it is the
1444 same, then merge them in. */
1445 firstchar = fgetc (da_file);
1446 if (firstchar == EOF)
1447 {
1448 if (ferror (da_file))
1449 {
1450 fprintf (stderr, "arc profiling: Can't read output file ");
1451 perror (ptr->filename);
1452 }
1453 }
1454 else
65f7a653
DE
1455 {
1456 long n_counts = 0;
65f7a653 1457
e09d24ff
R
1458 if (ungetc (firstchar, da_file) == EOF)
1459 rewind (da_file);
65f7a653
DE
1460 if (__read_long (&n_counts, da_file, 8) != 0)
1461 {
1462 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1463 ptr->filename);
1464 continue;
1465 }
1466
1467 if (n_counts == ptr->ncounts)
1468 {
1469 int i;
1470
1471 for (i = 0; i < n_counts; i++)
1472 {
1473 long v = 0;
65f7a653
DE
1474
1475 if (__read_long (&v, da_file, 8) != 0)
1476 {
1477 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1478 ptr->filename);
1479 break;
1480 }
1481 ptr->counts[i] += v;
1482 }
1483 }
1484
65f7a653
DE
1485 }
1486
e09d24ff
R
1487 rewind (da_file);
1488
956d6950 1489 /* ??? Should first write a header to the file. Preferably, a 4 byte
65f7a653
DE
1490 magic number, 4 bytes containing the time the program was
1491 compiled, 4 bytes containing the last modification time of the
1492 source file, and 4 bytes indicating the compiler options used.
1493
1494 That way we can easily verify that the proper source/executable/
1495 data file combination is being used from gcov. */
1496
1497 if (__write_long (ptr->ncounts, da_file, 8) != 0)
1498 {
1499
1500 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1501 ptr->filename);
1502 }
1503 else
1504 {
1505 int j;
1506 long *count_ptr = ptr->counts;
1507 int ret = 0;
1508 for (j = ptr->ncounts; j > 0; j--)
1509 {
1510 if (__write_long (*count_ptr, da_file, 8) != 0)
1511 {
1512 ret=1;
1513 break;
1514 }
1515 count_ptr++;
1516 }
1517 if (ret)
1518 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1519 ptr->filename);
1520 }
1521
1522 if (fclose (da_file) == EOF)
1523 fprintf (stderr, "arc profiling: Error closing output file %s.\n",
1524 ptr->filename);
1525 }
1526
1527 return;
1528 }
1529
1530 /* Must be basic block profiling. Emit a human readable output file. */
1531
1532 file = fopen ("bb.out", "a");
92832bb5
MM
1533
1534 if (!file)
1535 perror ("bb.out");
1536
1537 else
1538 {
1539 struct bb *ptr;
1540
1541 /* This is somewhat type incorrect, but it avoids worrying about
1542 exactly where time.h is included from. It should be ok unless
90b4a764 1543 a void * differs from other pointer formats, or if sizeof (long)
92832bb5
MM
1544 is < sizeof (time_t). It would be nice if we could assume the
1545 use of rationale standards here. */
1546
90b4a764 1547 time ((void *) &time_value);
92832bb5
MM
1548 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
1549
1550 /* We check the length field explicitly in order to allow compatibility
1551 with older GCC's which did not provide it. */
1552
0f41302f 1553 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
92832bb5
MM
1554 {
1555 int i;
3e7d8ef1 1556 int func_p = (ptr->nwords >= (long) sizeof (struct bb)
65f7a653
DE
1557 && ptr->nwords <= 1000
1558 && ptr->functions);
92832bb5
MM
1559 int line_p = (func_p && ptr->line_nums);
1560 int file_p = (func_p && ptr->filenames);
65f7a653 1561 int addr_p = (ptr->addresses != 0);
92832bb5
MM
1562 long ncounts = ptr->ncounts;
1563 long cnt_max = 0;
1564 long line_max = 0;
1565 long addr_max = 0;
1566 int file_len = 0;
1567 int func_len = 0;
1568 int blk_len = num_digits (ncounts, 10);
1569 int cnt_len;
1570 int line_len;
1571 int addr_len;
1572
1573 fprintf (file, "File %s, %ld basic blocks \n\n",
1574 ptr->filename, ncounts);
1575
1576 /* Get max values for each field. */
1577 for (i = 0; i < ncounts; i++)
1578 {
1579 const char *p;
1580 int len;
1581
1582 if (cnt_max < ptr->counts[i])
1583 cnt_max = ptr->counts[i];
1584
3e7d8ef1 1585 if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
92832bb5
MM
1586 addr_max = ptr->addresses[i];
1587
1588 if (line_p && line_max < ptr->line_nums[i])
1589 line_max = ptr->line_nums[i];
1590
1591 if (func_p)
1592 {
1593 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
1594 len = strlen (p);
1595 if (func_len < len)
1596 func_len = len;
1597 }
1598
1599 if (file_p)
1600 {
1601 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
1602 len = strlen (p);
1603 if (file_len < len)
1604 file_len = len;
1605 }
1606 }
1607
1608 addr_len = num_digits (addr_max, 16);
1609 cnt_len = num_digits (cnt_max, 10);
1610 line_len = num_digits (line_max, 10);
1611
1612 /* Now print out the basic block information. */
1613 for (i = 0; i < ncounts; i++)
1614 {
1615 fprintf (file,
65f7a653 1616 " Block #%*d: executed %*ld time(s)",
92832bb5 1617 blk_len, i+1,
65f7a653
DE
1618 cnt_len, ptr->counts[i]);
1619
1620 if (addr_p)
1621 fprintf (file, " address= 0x%.*lx", addr_len,
1622 ptr->addresses[i]);
92832bb5
MM
1623
1624 if (func_p)
3cca99e8 1625 fprintf (file, " function= %-*s", func_len,
92832bb5
MM
1626 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
1627
1628 if (line_p)
1d42e1b7 1629 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
92832bb5
MM
1630
1631 if (file_p)
3cca99e8 1632 fprintf (file, " file= %s",
92832bb5
MM
1633 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
1634
1635 fprintf (file, "\n");
1636 }
1637
1638 fprintf (file, "\n");
1639 fflush (file);
1640 }
1641
1642 fprintf (file, "\n\n");
1643 fclose (file);
1644 }
1645}
1646
1647void
1648__bb_init_func (struct bb *blocks)
1649{
1650 /* User is supposed to check whether the first word is non-0,
0f41302f 1651 but just in case.... */
92832bb5
MM
1652
1653 if (blocks->zero_word)
1654 return;
1655
92832bb5
MM
1656 /* Initialize destructor. */
1657 if (!bb_head)
c063dc98 1658 atexit (__bb_exit_func);
92832bb5
MM
1659
1660 /* Set up linked list. */
1661 blocks->zero_word = 1;
1662 blocks->next = bb_head;
1663 bb_head = blocks;
1664}
1665
e09d24ff
R
1666/* Called before fork or exec - write out profile information gathered so
1667 far and reset it to zero. This avoids duplication or loss of the
1668 profile information gathered so far. */
1669void
1670__bb_fork_func (void)
1671{
1672 struct bb *ptr;
1673
1674 __bb_exit_func ();
1675 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1676 {
1677 long i;
1678 for (i = ptr->ncounts - 1; i >= 0; i--)
1679 ptr->counts[i] = 0;
1680 }
1681}
1682
90b4a764
RK
1683#ifndef MACHINE_STATE_SAVE
1684#define MACHINE_STATE_SAVE(ID)
1685#endif
1686#ifndef MACHINE_STATE_RESTORE
1687#define MACHINE_STATE_RESTORE(ID)
1688#endif
1689
0f41302f 1690/* Number of buckets in hashtable of basic block addresses. */
90b4a764
RK
1691
1692#define BB_BUCKETS 311
1693
0f41302f 1694/* Maximum length of string in file bb.in. */
90b4a764
RK
1695
1696#define BBINBUFSIZE 500
1697
90b4a764
RK
1698struct bb_edge
1699{
1700 struct bb_edge *next;
1701 unsigned long src_addr;
1702 unsigned long dst_addr;
1703 unsigned long count;
1704};
1705
1706enum bb_func_mode
1707{
1708 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
1709};
1710
1711struct bb_func
1712{
1713 struct bb_func *next;
1714 char *funcname;
1715 char *filename;
1716 enum bb_func_mode mode;
1717};
1718
1719/* This is the connection to the outside world.
1720 The BLOCK_PROFILER macro must set __bb.blocks
0f41302f 1721 and __bb.blockno. */
90b4a764
RK
1722
1723struct {
1724 unsigned long blockno;
1725 struct bb *blocks;
1726} __bb;
1727
1728/* Vars to store addrs of source and destination basic blocks
0f41302f 1729 of a jump. */
90b4a764
RK
1730
1731static unsigned long bb_src = 0;
1732static unsigned long bb_dst = 0;
1733
0f41302f
MS
1734static FILE *bb_tracefile = (FILE *) 0;
1735static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
1736static struct bb_func *bb_func_head = (struct bb_func *) 0;
90b4a764
RK
1737static unsigned long bb_callcount = 0;
1738static int bb_mode = 0;
1739
0f41302f 1740static unsigned long *bb_stack = (unsigned long *) 0;
90b4a764
RK
1741static size_t bb_stacksize = 0;
1742
1743static int reported = 0;
1744
1745/* Trace modes:
1746Always : Print execution frequencies of basic blocks
1747 to file bb.out.
1748bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
1749bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
1750bb_mode & 4 != 0 : Cut call instructions from basic block flow.
1751bb_mode & 8 != 0 : Insert return instructions in basic block flow.
1752*/
1753
1754#ifdef HAVE_POPEN
1755
1756/*#include <sys/types.h>*/
1757#include <sys/stat.h>
1758/*#include <malloc.h>*/
1759
0f41302f 1760/* Commands executed by gopen. */
90b4a764
RK
1761
1762#define GOPENDECOMPRESS "gzip -cd "
1763#define GOPENCOMPRESS "gzip -c >"
1764
1765/* Like fopen but pipes through gzip. mode may only be "r" or "w".
1766 If it does not compile, simply replace gopen by fopen and delete
0f41302f 1767 '.gz' from any first parameter to gopen. */
90b4a764
RK
1768
1769static FILE *
37ef1054 1770gopen (char *fn, char *mode)
90b4a764
RK
1771{
1772 int use_gzip;
1773 char *p;
1774
1775 if (mode[1])
0f41302f 1776 return (FILE *) 0;
90b4a764
RK
1777
1778 if (mode[0] != 'r' && mode[0] != 'w')
0f41302f 1779 return (FILE *) 0;
90b4a764
RK
1780
1781 p = fn + strlen (fn)-1;
db3cf6fb
MS
1782 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
1783 || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
90b4a764
RK
1784
1785 if (use_gzip)
1786 {
1787 if (mode[0]=='r')
1788 {
1789 FILE *f;
0f41302f
MS
1790 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1791 + sizeof (GOPENDECOMPRESS));
90b4a764
RK
1792 strcpy (s, GOPENDECOMPRESS);
1793 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
1794 f = popen (s, mode);
1795 free (s);
1796 return f;
1797 }
1798
1799 else
1800 {
1801 FILE *f;
0f41302f
MS
1802 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1803 + sizeof (GOPENCOMPRESS));
90b4a764
RK
1804 strcpy (s, GOPENCOMPRESS);
1805 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
1806 if (!(f = popen (s, mode)))
1807 f = fopen (s, mode);
1808 free (s);
1809 return f;
1810 }
1811 }
1812
1813 else
1814 return fopen (fn, mode);
1815}
1816
1817static int
37ef1054 1818gclose (FILE *f)
90b4a764
RK
1819{
1820 struct stat buf;
1821
920b13cc 1822 if (f != 0)
90b4a764
RK
1823 {
1824 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
1825 return pclose (f);
1826
1827 return fclose (f);
1828 }
1829 return 0;
1830}
1831
1832#endif /* HAVE_POPEN */
1833
0f41302f 1834/* Called once per program. */
90b4a764
RK
1835
1836static void
3e7d8ef1 1837__bb_exit_trace_func (void)
90b4a764
RK
1838{
1839 FILE *file = fopen ("bb.out", "a");
1840 struct bb_func *f;
90b4a764
RK
1841 struct bb *b;
1842
1843 if (!file)
1844 perror ("bb.out");
1845
1846 if (bb_mode & 1)
1847 {
1848 if (!bb_tracefile)
1849 perror ("bbtrace");
1850 else
1851#ifdef HAVE_POPEN
1852 gclose (bb_tracefile);
1853#else
1854 fclose (bb_tracefile);
1855#endif /* HAVE_POPEN */
1856 }
1857
0f41302f 1858 /* Check functions in `bb.in'. */
90b4a764
RK
1859
1860 if (file)
1861 {
1862 long time_value;
1863 const struct bb_func *p;
1864 int printed_something = 0;
1865 struct bb *ptr;
1866 long blk;
1867
0f41302f 1868 /* This is somewhat type incorrect. */
90b4a764
RK
1869 time ((void *) &time_value);
1870
0f41302f 1871 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
90b4a764 1872 {
0f41302f 1873 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
90b4a764 1874 {
51723711 1875 if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
90b4a764
RK
1876 continue;
1877 for (blk = 0; blk < ptr->ncounts; blk++)
1878 {
1879 if (!strcmp (p->funcname, ptr->functions[blk]))
1880 goto found;
1881 }
1882 }
1883
1884 if (!printed_something)
1885 {
1886 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
1887 printed_something = 1;
1888 }
1889
1890 fprintf (file, "\tFunction %s", p->funcname);
1891 if (p->filename)
1892 fprintf (file, " of file %s", p->filename);
1893 fprintf (file, "\n" );
1894
1895found: ;
1896 }
1897
1898 if (printed_something)
1899 fprintf (file, "\n");
1900
1901 }
1902
1903 if (bb_mode & 2)
1904 {
1905 if (!bb_hashbuckets)
1906 {
1907 if (!reported)
1908 {
1909 fprintf (stderr, "Profiler: out of memory\n");
1910 reported = 1;
1911 }
1912 return;
1913 }
1914
1915 else if (file)
1916 {
1917 long time_value;
1918 int i;
1919 unsigned long addr_max = 0;
1920 unsigned long cnt_max = 0;
1921 int cnt_len;
1922 int addr_len;
1923
1924 /* This is somewhat type incorrect, but it avoids worrying about
1925 exactly where time.h is included from. It should be ok unless
1926 a void * differs from other pointer formats, or if sizeof (long)
1927 is < sizeof (time_t). It would be nice if we could assume the
1928 use of rationale standards here. */
1929
1930 time ((void *) &time_value);
1931 fprintf (file, "Basic block jump tracing");
1932
1933 switch (bb_mode & 12)
1934 {
1935 case 0:
1936 fprintf (file, " (with call)");
1937 break;
1938
1939 case 4:
0f41302f 1940 /* Print nothing. */
90b4a764
RK
1941 break;
1942
1943 case 8:
1944 fprintf (file, " (with call & ret)");
1945 break;
1946
1947 case 12:
1948 fprintf (file, " (with ret)");
1949 break;
1950 }
1951
1952 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
1953
1954 for (i = 0; i < BB_BUCKETS; i++)
1955 {
1956 struct bb_edge *bucket = bb_hashbuckets[i];
1957 for ( ; bucket; bucket = bucket->next )
1958 {
1959 if (addr_max < bucket->src_addr)
1960 addr_max = bucket->src_addr;
1961 if (addr_max < bucket->dst_addr)
1962 addr_max = bucket->dst_addr;
1963 if (cnt_max < bucket->count)
1964 cnt_max = bucket->count;
1965 }
1966 }
1967 addr_len = num_digits (addr_max, 16);
1968 cnt_len = num_digits (cnt_max, 10);
1969
1970 for ( i = 0; i < BB_BUCKETS; i++)
1971 {
1972 struct bb_edge *bucket = bb_hashbuckets[i];
1973 for ( ; bucket; bucket = bucket->next )
1974 {
78a0d70c
ZW
1975 fprintf (file,
1976 "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
90b4a764
RK
1977 addr_len, bucket->src_addr,
1978 addr_len, bucket->dst_addr,
1979 cnt_len, bucket->count);
1980 }
1981 }
1982
1983 fprintf (file, "\n");
1984
1985 }
1986 }
1987
1988 if (file)
1989 fclose (file);
1990
0f41302f 1991 /* Free allocated memory. */
90b4a764
RK
1992
1993 f = bb_func_head;
1994 while (f)
1995 {
1996 struct bb_func *old = f;
1997
1998 f = f->next;
1999 if (old->funcname) free (old->funcname);
2000 if (old->filename) free (old->filename);
2001 free (old);
2002 }
2003
2004 if (bb_stack)
2005 free (bb_stack);
2006
2007 if (bb_hashbuckets)
2008 {
2009 int i;
2010
2011 for (i = 0; i < BB_BUCKETS; i++)
2012 {
2013 struct bb_edge *old, *bucket = bb_hashbuckets[i];
2014
2015 while (bucket)
2016 {
2017 old = bucket;
2018 bucket = bucket->next;
2019 free (old);
2020 }
2021 }
2022 free (bb_hashbuckets);
2023 }
2024
2025 for (b = bb_head; b; b = b->next)
2026 if (b->flags) free (b->flags);
2027}
2028
0f41302f 2029/* Called once per program. */
90b4a764
RK
2030
2031static void
3e7d8ef1 2032__bb_init_prg (void)
90b4a764 2033{
90b4a764
RK
2034 FILE *file;
2035 char buf[BBINBUFSIZE];
2036 const char *p;
2037 const char *pos;
2038 enum bb_func_mode m;
c5c76735 2039 int i;
90b4a764 2040
90b4a764 2041 /* Initialize destructor. */
c063dc98 2042 atexit (__bb_exit_func);
90b4a764
RK
2043
2044 if (!(file = fopen ("bb.in", "r")))
2045 return;
2046
78a0d70c 2047 while(fgets (buf, BBINBUFSIZE, file) != 0)
90b4a764 2048 {
78a0d70c
ZW
2049 i = strlen (buf);
2050 if (buf[i] == '\n')
2051 buf[i--] = '\0';
2052
90b4a764
RK
2053 p = buf;
2054 if (*p == '-')
2055 {
2056 m = TRACE_OFF;
2057 p++;
2058 }
2059 else
2060 {
2061 m = TRACE_ON;
2062 }
2063 if (!strcmp (p, "__bb_trace__"))
2064 bb_mode |= 1;
2065 else if (!strcmp (p, "__bb_jumps__"))
2066 bb_mode |= 2;
2067 else if (!strcmp (p, "__bb_hidecall__"))
2068 bb_mode |= 4;
2069 else if (!strcmp (p, "__bb_showret__"))
2070 bb_mode |= 8;
2071 else
2072 {
0f41302f 2073 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
90b4a764
RK
2074 if (f)
2075 {
2076 unsigned long l;
2077 f->next = bb_func_head;
51723711 2078 if ((pos = strchr (p, ':')))
90b4a764 2079 {
0f41302f 2080 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
90b4a764
RK
2081 continue;
2082 strcpy (f->funcname, pos+1);
2083 l = pos-p;
0f41302f 2084 if ((f->filename = (char *) malloc (l+1)))
90b4a764
RK
2085 {
2086 strncpy (f->filename, p, l);
2087 f->filename[l] = '\0';
2088 }
2089 else
0f41302f 2090 f->filename = (char *) 0;
90b4a764
RK
2091 }
2092 else
2093 {
0f41302f 2094 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
90b4a764
RK
2095 continue;
2096 strcpy (f->funcname, p);
0f41302f 2097 f->filename = (char *) 0;
90b4a764
RK
2098 }
2099 f->mode = m;
2100 bb_func_head = f;
2101 }
2102 }
2103 }
2104 fclose (file);
2105
2106#ifdef HAVE_POPEN
2107
2108 if (bb_mode & 1)
2109 bb_tracefile = gopen ("bbtrace.gz", "w");
2110
2111#else
2112
2113 if (bb_mode & 1)
2114 bb_tracefile = fopen ("bbtrace", "w");
2115
2116#endif /* HAVE_POPEN */
2117
2118 if (bb_mode & 2)
2119 {
2120 bb_hashbuckets = (struct bb_edge **)
2121 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
2122 if (bb_hashbuckets)
c5c76735
JL
2123 /* Use a loop here rather than calling bzero to avoid having to
2124 conditionalize its existance. */
2125 for (i = 0; i < BB_BUCKETS; i++)
2126 bb_hashbuckets[i] = 0;
90b4a764
RK
2127 }
2128
2129 if (bb_mode & 12)
2130 {
2131 bb_stacksize = 10;
2132 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
2133 }
2134
c063dc98
JM
2135 /* Initialize destructor. */
2136 atexit (__bb_exit_trace_func);
90b4a764
RK
2137}
2138
0f41302f 2139/* Called upon entering a basic block. */
90b4a764
RK
2140
2141void
3e7d8ef1 2142__bb_trace_func (void)
90b4a764
RK
2143{
2144 struct bb_edge *bucket;
2145
2146 MACHINE_STATE_SAVE("1")
2147
2148 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2149 goto skip;
2150
2151 bb_dst = __bb.blocks->addresses[__bb.blockno];
2152 __bb.blocks->counts[__bb.blockno]++;
2153
2154 if (bb_tracefile)
2155 {
2156 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
2157 }
2158
2159 if (bb_hashbuckets)
2160 {
2161 struct bb_edge **startbucket, **oldnext;
2162
db3cf6fb
MS
2163 oldnext = startbucket
2164 = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
90b4a764
RK
2165 bucket = *startbucket;
2166
2167 for (bucket = *startbucket; bucket;
2168 oldnext = &(bucket->next), bucket = *oldnext)
2169 {
db3cf6fb
MS
2170 if (bucket->src_addr == bb_src
2171 && bucket->dst_addr == bb_dst)
90b4a764
RK
2172 {
2173 bucket->count++;
2174 *oldnext = bucket->next;
2175 bucket->next = *startbucket;
2176 *startbucket = bucket;
2177 goto ret;
2178 }
2179 }
2180
2181 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2182
2183 if (!bucket)
2184 {
2185 if (!reported)
2186 {
2187 fprintf (stderr, "Profiler: out of memory\n");
2188 reported = 1;
2189 }
2190 }
2191
2192 else
2193 {
2194 bucket->src_addr = bb_src;
2195 bucket->dst_addr = bb_dst;
2196 bucket->next = *startbucket;
2197 *startbucket = bucket;
2198 bucket->count = 1;
2199 }
2200 }
2201
2202ret:
2203 bb_src = bb_dst;
2204
2205skip:
2206 ;
2207
2208 MACHINE_STATE_RESTORE("1")
2209
2210}
2211
0f41302f 2212/* Called when returning from a function and `__bb_showret__' is set. */
90b4a764
RK
2213
2214static void
3e7d8ef1 2215__bb_trace_func_ret (void)
90b4a764
RK
2216{
2217 struct bb_edge *bucket;
2218
2219 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2220 goto skip;
2221
2222 if (bb_hashbuckets)
2223 {
2224 struct bb_edge **startbucket, **oldnext;
2225
db3cf6fb
MS
2226 oldnext = startbucket
2227 = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
90b4a764
RK
2228 bucket = *startbucket;
2229
2230 for (bucket = *startbucket; bucket;
2231 oldnext = &(bucket->next), bucket = *oldnext)
2232 {
db3cf6fb
MS
2233 if (bucket->src_addr == bb_dst
2234 && bucket->dst_addr == bb_src)
90b4a764
RK
2235 {
2236 bucket->count++;
2237 *oldnext = bucket->next;
2238 bucket->next = *startbucket;
2239 *startbucket = bucket;
2240 goto ret;
2241 }
2242 }
2243
2244 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2245
2246 if (!bucket)
2247 {
2248 if (!reported)
2249 {
2250 fprintf (stderr, "Profiler: out of memory\n");
2251 reported = 1;
2252 }
2253 }
2254
2255 else
2256 {
2257 bucket->src_addr = bb_dst;
2258 bucket->dst_addr = bb_src;
2259 bucket->next = *startbucket;
2260 *startbucket = bucket;
2261 bucket->count = 1;
2262 }
2263 }
2264
2265ret:
2266 bb_dst = bb_src;
2267
2268skip:
2269 ;
2270
2271}
2272
0f41302f 2273/* Called upon entering the first function of a file. */
90b4a764
RK
2274
2275static void
37ef1054 2276__bb_init_file (struct bb *blocks)
90b4a764
RK
2277{
2278
2279 const struct bb_func *p;
2280 long blk, ncounts = blocks->ncounts;
2281 const char **functions = blocks->functions;
2282
2283 /* Set up linked list. */
2284 blocks->zero_word = 1;
2285 blocks->next = bb_head;
2286 bb_head = blocks;
2287
2288 blocks->flags = 0;
db3cf6fb
MS
2289 if (!bb_func_head
2290 || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
90b4a764
RK
2291 return;
2292
2293 for (blk = 0; blk < ncounts; blk++)
2294 blocks->flags[blk] = 0;
2295
2296 for (blk = 0; blk < ncounts; blk++)
2297 {
2298 for (p = bb_func_head; p; p = p->next)
2299 {
db3cf6fb
MS
2300 if (!strcmp (p->funcname, functions[blk])
2301 && (!p->filename || !strcmp (p->filename, blocks->filename)))
90b4a764
RK
2302 {
2303 blocks->flags[blk] |= p->mode;
2304 }
2305 }
2306 }
2307
2308}
2309
0f41302f 2310/* Called when exiting from a function. */
90b4a764
RK
2311
2312void
3e7d8ef1 2313__bb_trace_ret (void)
90b4a764
RK
2314{
2315
2316 MACHINE_STATE_SAVE("2")
2317
2318 if (bb_callcount)
2319 {
2320 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
2321 {
2322 bb_src = bb_stack[bb_callcount];
2323 if (bb_mode & 8)
2324 __bb_trace_func_ret ();
2325 }
2326
2327 bb_callcount -= 1;
2328 }
2329
2330 MACHINE_STATE_RESTORE("2")
2331
2332}
2333
0f41302f 2334/* Called when entering a function. */
90b4a764
RK
2335
2336void
37ef1054 2337__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
90b4a764
RK
2338{
2339 static int trace_init = 0;
2340
2341 MACHINE_STATE_SAVE("3")
2342
2343 if (!blocks->zero_word)
2344 {
2345 if (!trace_init)
2346 {
2347 trace_init = 1;
2348 __bb_init_prg ();
2349 }
2350 __bb_init_file (blocks);
2351 }
2352
2353 if (bb_callcount)
2354 {
2355
2356 bb_callcount += 1;
2357
2358 if (bb_mode & 12)
2359 {
2360 if (bb_callcount >= bb_stacksize)
2361 {
2362 size_t newsize = bb_callcount + 100;
2363
2364 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
2365 if (! bb_stack)
2366 {
2367 if (!reported)
2368 {
2369 fprintf (stderr, "Profiler: out of memory\n");
2370 reported = 1;
2371 }
2372 bb_stacksize = 0;
2373 goto stack_overflow;
2374 }
2375 bb_stacksize = newsize;
2376 }
2377 bb_stack[bb_callcount] = bb_src;
2378
2379 if (bb_mode & 4)
2380 bb_src = 0;
2381
2382 }
2383
2384stack_overflow:;
2385
2386 }
2387
2388 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
2389 {
2390 bb_callcount = 1;
2391 bb_src = 0;
2392
2393 if (bb_stack)
2394 bb_stack[bb_callcount] = bb_src;
2395 }
2396
2397 MACHINE_STATE_RESTORE("3")
2398}
2399
c7544ff7
RS
2400#endif /* not inhibit_libc */
2401#endif /* not BLOCK_PROFILER_CODE */
2402#endif /* L_bb */
203b91b9 2403\f
203b91b9
RS
2404#ifdef L_shtab
2405unsigned int __shtab[] = {
2406 0x00000001, 0x00000002, 0x00000004, 0x00000008,
2407 0x00000010, 0x00000020, 0x00000040, 0x00000080,
2408 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2409 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2410 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2411 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2412 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2413 0x10000000, 0x20000000, 0x40000000, 0x80000000
2414 };
2415#endif
2416\f
2417#ifdef L_clear_cache
2418/* Clear part of an instruction cache. */
2419
2420#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
2421
2422void
139fa6f8
MM
2423__clear_cache (char *beg __attribute__((__unused__)),
2424 char *end __attribute__((__unused__)))
203b91b9 2425{
e1178973
KKT
2426#ifdef CLEAR_INSN_CACHE
2427 CLEAR_INSN_CACHE (beg, end);
2428#else
203b91b9
RS
2429#ifdef INSN_CACHE_SIZE
2430 static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
7e6f1890 2431 static int initialized;
203b91b9 2432 int offset;
b6422cca
RS
2433 void *start_addr
2434 void *end_addr;
3e7d8ef1 2435 typedef (*function_ptr) (void);
203b91b9
RS
2436
2437#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
2438 /* It's cheaper to clear the whole cache.
2439 Put in a series of jump instructions so that calling the beginning
2440 of the cache will clear the whole thing. */
2441
2442 if (! initialized)
2443 {
2444 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2445 & -INSN_CACHE_LINE_WIDTH);
2446 int end_ptr = ptr + INSN_CACHE_SIZE;
2447
2448 while (ptr < end_ptr)
2449 {
2450 *(INSTRUCTION_TYPE *)ptr
2451 = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
2452 ptr += INSN_CACHE_LINE_WIDTH;
2453 }
0f41302f 2454 *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
203b91b9
RS
2455
2456 initialized = 1;
2457 }
2458
2459 /* Call the beginning of the sequence. */
2460 (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2461 & -INSN_CACHE_LINE_WIDTH))
2462 ());
2463
2464#else /* Cache is large. */
2465
2466 if (! initialized)
2467 {
2468 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2469 & -INSN_CACHE_LINE_WIDTH);
2470
2471 while (ptr < (int) array + sizeof array)
2472 {
2473 *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
2474 ptr += INSN_CACHE_LINE_WIDTH;
2475 }
2476
2477 initialized = 1;
2478 }
2479
2480 /* Find the location in array that occupies the same cache line as BEG. */
2481
2482 offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
2483 start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
2484 & -INSN_CACHE_PLANE_SIZE)
2485 + offset);
2486
2487 /* Compute the cache alignment of the place to stop clearing. */
2488#if 0 /* This is not needed for gcc's purposes. */
2489 /* If the block to clear is bigger than a cache plane,
2490 we clear the entire cache, and OFFSET is already correct. */
2491 if (end < beg + INSN_CACHE_PLANE_SIZE)
2492#endif
2493 offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
2494 & -INSN_CACHE_LINE_WIDTH)
2495 & (INSN_CACHE_PLANE_SIZE - 1));
2496
2497#if INSN_CACHE_DEPTH > 1
2498 end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
2499 if (end_addr <= start_addr)
2500 end_addr += INSN_CACHE_PLANE_SIZE;
2501
2502 for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
2503 {
2504 int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
2505 int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
2506
2507 while (addr != stop)
2508 {
2509 /* Call the return instruction at ADDR. */
2510 ((function_ptr) addr) ();
2511
2512 addr += INSN_CACHE_LINE_WIDTH;
2513 }
2514 }
2515#else /* just one plane */
2516 do
2517 {
2518 /* Call the return instruction at START_ADDR. */
2519 ((function_ptr) start_addr) ();
2520
2521 start_addr += INSN_CACHE_LINE_WIDTH;
2522 }
2523 while ((start_addr % INSN_CACHE_SIZE) != offset);
2524#endif /* just one plane */
2525#endif /* Cache is large */
2526#endif /* Cache exists */
e1178973 2527#endif /* CLEAR_INSN_CACHE */
203b91b9
RS
2528}
2529
2530#endif /* L_clear_cache */
2531\f
2532#ifdef L_trampoline
2533
2534/* Jump to a trampoline, loading the static chain address. */
2535
b27d2bd5 2536#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
e3367a77 2537
3e7d8ef1
KG
2538long
2539getpagesize (void)
f5ea9817
RK
2540{
2541#ifdef _ALPHA_
2542 return 8192;
2543#else
2544 return 4096;
2545#endif
2546}
2547
d7ebf9ea 2548#ifdef __i386__
e4b15106
RK
2549extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
2550#endif
2551
272e2587
RK
2552int
2553mprotect (char *addr, int len, int prot)
f5ea9817
RK
2554{
2555 int np, op;
2556
272e2587
RK
2557 if (prot == 7)
2558 np = 0x40;
2559 else if (prot == 5)
2560 np = 0x20;
2561 else if (prot == 4)
2562 np = 0x10;
2563 else if (prot == 3)
2564 np = 0x04;
2565 else if (prot == 1)
2566 np = 0x02;
2567 else if (prot == 0)
2568 np = 0x01;
f5ea9817
RK
2569
2570 if (VirtualProtect (addr, len, np, &op))
2571 return 0;
2572 else
2573 return -1;
f5ea9817
RK
2574}
2575
b27d2bd5 2576#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
f5ea9817 2577
203b91b9
RS
2578#ifdef TRANSFER_FROM_TRAMPOLINE
2579TRANSFER_FROM_TRAMPOLINE
2580#endif
2581
c1381fd3
KKT
2582#if defined (NeXT) && defined (__MACH__)
2583
2584/* Make stack executable so we can call trampolines on stack.
2585 This is called from INITIALIZE_TRAMPOLINE in next.h. */
c5df463e
RK
2586#ifdef NeXTStep21
2587 #include <mach.h>
2588#else
2589 #include <mach/mach.h>
2590#endif
c1381fd3
KKT
2591
2592void
37ef1054 2593__enable_execute_stack (char *addr)
c1381fd3
KKT
2594{
2595 kern_return_t r;
2596 char *eaddr = addr + TRAMPOLINE_SIZE;
2597 vm_address_t a = (vm_address_t) addr;
2598
2599 /* turn on execute access on stack */
2600 r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
2601 if (r != KERN_SUCCESS)
2602 {
2603 mach_error("vm_protect VM_PROT_ALL", r);
2604 exit(1);
2605 }
2606
2607 /* We inline the i-cache invalidation for speed */
2608
2609#ifdef CLEAR_INSN_CACHE
2610 CLEAR_INSN_CACHE (addr, eaddr);
2611#else
2612 __clear_cache ((int) addr, (int) eaddr);
2613#endif
2614}
2615
2616#endif /* defined (NeXT) && defined (__MACH__) */
2617
203b91b9
RS
2618#ifdef __convex__
2619
2620/* Make stack executable so we can call trampolines on stack.
2621 This is called from INITIALIZE_TRAMPOLINE in convex.h. */
2622
2623#include <sys/mman.h>
2624#include <sys/vmparam.h>
2625#include <machine/machparam.h>
2626
2627void
3e7d8ef1 2628__enable_execute_stack (void)
203b91b9
RS
2629{
2630 int fp;
2631 static unsigned lowest = USRSTACK;
2632 unsigned current = (unsigned) &fp & -NBPG;
2633
2634 if (lowest > current)
2635 {
2636 unsigned len = lowest - current;
2637 mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
2638 lowest = current;
2639 }
2640
0f41302f 2641 /* Clear instruction cache in case an old trampoline is in it. */
203b91b9
RS
2642 asm ("pich");
2643}
2644#endif /* __convex__ */
b335c2cc 2645
db87ec0b 2646#ifdef __sysV88__
0c8ae3d3 2647
0f41302f 2648/* Modified from the convex -code above. */
0c8ae3d3
RK
2649
2650#include <sys/param.h>
2651#include <errno.h>
2652#include <sys/m88kbcs.h>
2653
2654void
3e7d8ef1 2655__enable_execute_stack (void)
0c8ae3d3
RK
2656{
2657 int save_errno;
2658 static unsigned long lowest = USRSTACK;
2659 unsigned long current = (unsigned long) &save_errno & -NBPC;
2660
2661 /* Ignore errno being set. memctl sets errno to EINVAL whenever the
2662 address is seen as 'negative'. That is the case with the stack. */
2663
2664 save_errno=errno;
2665 if (lowest > current)
2666 {
2667 unsigned len=lowest-current;
2668 memctl(current,len,MCT_TEXT);
2669 lowest = current;
2670 }
2671 else
2672 memctl(current,NBPC,MCT_TEXT);
2673 errno=save_errno;
2674}
2675
db87ec0b 2676#endif /* __sysV88__ */
0c8ae3d3 2677
c85f7c16
JL
2678#ifdef __sysV68__
2679
2680#include <sys/signal.h>
2681#include <errno.h>
2682
2683/* Motorola forgot to put memctl.o in the libp version of libc881.a,
2684 so define it here, because we need it in __clear_insn_cache below */
3698f44e
MH
2685/* On older versions of this OS, no memctl or MCT_TEXT are defined;
2686 hence we enable this stuff only if MCT_TEXT is #define'd. */
c85f7c16 2687
3698f44e 2688#ifdef MCT_TEXT
c85f7c16
JL
2689asm("\n\
2690 global memctl\n\
2691memctl:\n\
2692 movq &75,%d0\n\
2693 trap &0\n\
2694 bcc.b noerror\n\
2695 jmp cerror%\n\
2696noerror:\n\
2697 movq &0,%d0\n\
2698 rts");
3698f44e 2699#endif
c85f7c16
JL
2700
2701/* Clear instruction cache so we can call trampolines on stack.
2702 This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
2703
2704void
3e7d8ef1 2705__clear_insn_cache (void)
c85f7c16 2706{
3698f44e 2707#ifdef MCT_TEXT
c85f7c16
JL
2708 int save_errno;
2709
2710 /* Preserve errno, because users would be surprised to have
2711 errno changing without explicitly calling any system-call. */
2712 save_errno = errno;
2713
2714 /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
2715 No need to use an address derived from _start or %sp, as 0 works also. */
2716 memctl(0, 4096, MCT_TEXT);
2717 errno = save_errno;
3698f44e 2718#endif
c85f7c16
JL
2719}
2720
2721#endif /* __sysV68__ */
2722
b335c2cc
TW
2723#ifdef __pyr__
2724
98126ed6 2725#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
b335c2cc
TW
2726#include <stdio.h>
2727#include <sys/mman.h>
2728#include <sys/types.h>
2729#include <sys/param.h>
2730#include <sys/vmmac.h>
2731
2732/* Modified from the convex -code above.
0f41302f 2733 mremap promises to clear the i-cache. */
b335c2cc
TW
2734
2735void
3e7d8ef1 2736__enable_execute_stack (void)
b335c2cc
TW
2737{
2738 int fp;
2739 if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
2740 PROT_READ|PROT_WRITE|PROT_EXEC))
2741 {
2742 perror ("mprotect in __enable_execute_stack");
2743 fflush (stderr);
2744 abort ();
2745 }
2746}
2747#endif /* __pyr__ */
7d41c411
RK
2748
2749#if defined (sony_news) && defined (SYSTYPE_BSD)
2750
2751#include <stdio.h>
2752#include <sys/types.h>
2753#include <sys/param.h>
2754#include <syscall.h>
2755#include <machine/sysnews.h>
2756
2757/* cacheflush function for NEWS-OS 4.2.
2758 This function is called from trampoline-initialize code
2759 defined in config/mips/mips.h. */
2760
2761void
37ef1054 2762cacheflush (char *beg, int size, int flag)
7d41c411
RK
2763{
2764 if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
2765 {
2766 perror ("cache_flush");
2767 fflush (stderr);
2768 abort ();
2769 }
2770}
2771
2772#endif /* sony_news */
203b91b9
RS
2773#endif /* L_trampoline */
2774\f
cae21ae8 2775#ifndef __CYGWIN__
203b91b9
RS
2776#ifdef L__main
2777
2778#include "gbl-ctors.h"
c06cff95
RS
2779/* Some systems use __main in a way incompatible with its use in gcc, in these
2780 cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
2781 give the same symbol without quotes for an alternative entry point. You
0f41302f 2782 must define both, or neither. */
c06cff95
RS
2783#ifndef NAME__MAIN
2784#define NAME__MAIN "__main"
2785#define SYMBOL__MAIN __main
2786#endif
203b91b9 2787
fe1fd353
JM
2788#ifdef INIT_SECTION_ASM_OP
2789#undef HAS_INIT_SECTION
2790#define HAS_INIT_SECTION
2791#endif
2792
2793#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
31cf0144
JM
2794
2795/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
2796 code to run constructors. In that case, we need to handle EH here, too. */
2797
2798#ifdef EH_FRAME_SECTION
2799#include "frame.h"
2800extern unsigned char __EH_FRAME_BEGIN__[];
2801#endif
2802
203b91b9
RS
2803/* Run all the global destructors on exit from the program. */
2804
2805void
3e7d8ef1 2806__do_global_dtors (void)
203b91b9 2807{
89cf554b
RS
2808#ifdef DO_GLOBAL_DTORS_BODY
2809 DO_GLOBAL_DTORS_BODY;
2810#else
b40b9d93
MS
2811 static func_ptr *p = __DTOR_LIST__ + 1;
2812 while (*p)
2813 {
2814 p++;
2815 (*(p-1)) ();
2816 }
89cf554b 2817#endif
bf279c4e 2818#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
a4ebb0e6
GRK
2819 {
2820 static int completed = 0;
2821 if (! completed)
2822 {
2823 completed = 1;
2824 __deregister_frame_info (__EH_FRAME_BEGIN__);
2825 }
2826 }
31cf0144 2827#endif
203b91b9 2828}
68d69835 2829#endif
203b91b9 2830
fe1fd353 2831#ifndef HAS_INIT_SECTION
203b91b9
RS
2832/* Run all the global constructors on entry to the program. */
2833
203b91b9 2834void
3e7d8ef1 2835__do_global_ctors (void)
203b91b9 2836{
31cf0144
JM
2837#ifdef EH_FRAME_SECTION
2838 {
2839 static struct object object;
2840 __register_frame_info (__EH_FRAME_BEGIN__, &object);
2841 }
2842#endif
203b91b9 2843 DO_GLOBAL_CTORS_BODY;
a218d5ba 2844 atexit (__do_global_dtors);
203b91b9 2845}
fe1fd353 2846#endif /* no HAS_INIT_SECTION */
203b91b9 2847
fe1fd353 2848#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
203b91b9
RS
2849/* Subroutine called automatically by `main'.
2850 Compiling a global function named `main'
2851 produces an automatic call to this function at the beginning.
2852
2853 For many systems, this routine calls __do_global_ctors.
2854 For systems which support a .init section we use the .init section
2855 to run __do_global_ctors, so we need not do anything here. */
2856
2857void
c06cff95 2858SYMBOL__MAIN ()
203b91b9
RS
2859{
2860 /* Support recursive calls to `main': run initializers just once. */
7e6f1890 2861 static int initialized;
203b91b9
RS
2862 if (! initialized)
2863 {
2864 initialized = 1;
2865 __do_global_ctors ();
2866 }
2867}
fe1fd353 2868#endif /* no HAS_INIT_SECTION or INVOKE__main */
203b91b9
RS
2869
2870#endif /* L__main */
cae21ae8 2871#endif /* __CYGWIN__ */
203b91b9 2872\f
ad38743d 2873#ifdef L_ctors
203b91b9
RS
2874
2875#include "gbl-ctors.h"
2876
2877/* Provide default definitions for the lists of constructors and
657be7af
JL
2878 destructors, so that we don't get linker errors. These symbols are
2879 intentionally bss symbols, so that gld and/or collect will provide
2880 the right values. */
203b91b9
RS
2881
2882/* We declare the lists here with two elements each,
657be7af
JL
2883 so that they are valid empty lists if no other definition is loaded.
2884
2885 If we are using the old "set" extensions to have the gnu linker
2886 collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
2887 must be in the bss/common section.
2888
2889 Long term no port should use those extensions. But many still do. */
b335c2cc 2890#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
657be7af 2891#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
d15d0264
RS
2892func_ptr __CTOR_LIST__[2] = {0, 0};
2893func_ptr __DTOR_LIST__[2] = {0, 0};
657be7af
JL
2894#else
2895func_ptr __CTOR_LIST__[2];
2896func_ptr __DTOR_LIST__[2];
2897#endif
b335c2cc 2898#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
ad38743d
RS
2899#endif /* L_ctors */
2900\f
2901#ifdef L_exit
2902
2903#include "gbl-ctors.h"
203b91b9 2904
8b7677be 2905#ifdef NEED_ATEXIT
8b7677be 2906
f75e8946 2907#ifndef ON_EXIT
203b91b9 2908
8b7677be
RK
2909# include <errno.h>
2910
920b13cc 2911static func_ptr *atexit_chain = 0;
8b7677be
RK
2912static long atexit_chain_length = 0;
2913static volatile long last_atexit_chain_slot = -1;
2914
c063dc98
JM
2915int
2916atexit (func_ptr func)
8b7677be
RK
2917{
2918 if (++last_atexit_chain_slot == atexit_chain_length)
2919 {
2920 atexit_chain_length += 32;
2921 if (atexit_chain)
a25cea96
RK
2922 atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
2923 * sizeof (func_ptr));
8b7677be 2924 else
a25cea96
RK
2925 atexit_chain = (func_ptr *) malloc (atexit_chain_length
2926 * sizeof (func_ptr));
8b7677be
RK
2927 if (! atexit_chain)
2928 {
2929 atexit_chain_length = 0;
2930 last_atexit_chain_slot = -1;
2931 errno = ENOMEM;
2932 return (-1);
2933 }
2934 }
2935 atexit_chain[last_atexit_chain_slot] = func;
2936 return (0);
2937}
8b7677be 2938
3e7d8ef1
KG
2939extern void _cleanup (void);
2940extern void _exit (int) __attribute__ ((__noreturn__));
203b91b9
RS
2941
2942void
37ef1054 2943exit (int status)
203b91b9 2944{
8b7677be
RK
2945 if (atexit_chain)
2946 {
2947 for ( ; last_atexit_chain_slot-- >= 0; )
2948 {
2949 (*atexit_chain[last_atexit_chain_slot + 1]) ();
920b13cc 2950 atexit_chain[last_atexit_chain_slot + 1] = 0;
8b7677be
RK
2951 }
2952 free (atexit_chain);
920b13cc 2953 atexit_chain = 0;
8b7677be 2954 }
203b91b9
RS
2955#ifdef EXIT_BODY
2956 EXIT_BODY;
2957#else
2958 _cleanup ();
2959#endif
2960 _exit (status);
2961}
2962
f75e8946 2963#else /* ON_EXIT */
bceb30e7 2964
c063dc98
JM
2965/* Simple; we just need a wrapper for ON_EXIT. */
2966int
2967atexit (func_ptr func)
bceb30e7 2968{
c063dc98 2969 return ON_EXIT (func);
bceb30e7 2970}
c063dc98 2971
f75e8946 2972#endif /* ON_EXIT */
c063dc98 2973#endif /* NEED_ATEXIT */
203b91b9
RS
2974
2975#endif /* L_exit */
2976\f
ad912eec 2977#ifdef L_eh
6adb4e3a 2978
f24af81b 2979#include "gthr.h"
6adb4e3a 2980
154bba13 2981/* Shared exception handling support routines. */
6adb4e3a 2982
e976b8b2 2983void
3e7d8ef1 2984__default_terminate (void)
e976b8b2
MS
2985{
2986 abort ();
2987}
2988
3e7d8ef1
KG
2989void (*__terminate_func)(void) __attribute__ ((__noreturn__)) =
2990 __default_terminate;
e976b8b2
MS
2991
2992void
3e7d8ef1 2993__terminate (void)
e976b8b2
MS
2994{
2995 (*__terminate_func)();
2996}
2997
ca55abae
JM
2998void *
2999__throw_type_match (void *catch_type, void *throw_type, void *obj)
3000{
3001#if 0
3002 printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
3003 catch_type, throw_type);
3004#endif
3005 if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
3006 return obj;
3007 return 0;
3008}
3009
3010void
3e7d8ef1 3011__empty (void)
ca55abae
JM
3012{
3013}
3014\f
154bba13 3015
9a0d1e1b
AM
3016/* Include definitions of EH context and table layout */
3017
3018#include "eh-common.h"
43566944 3019#ifndef inhibit_libc
7ac2148b 3020#include <stdio.h>
43566944 3021#endif
154bba13 3022
154bba13
TT
3023/* Allocate and return a new EH context structure. */
3024
3e7d8ef1 3025#if __GTHREADS
154bba13 3026static void *
3e7d8ef1 3027new_eh_context (void)
154bba13 3028{
d0b9a143
MS
3029 struct eh_full_context {
3030 struct eh_context c;
3031 void *top_elt[2];
3032 } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
3033
3034 if (! ehfc)
154bba13
TT
3035 __terminate ();
3036
d0b9a143 3037 memset (ehfc, 0, sizeof *ehfc);
154bba13 3038
d0b9a143 3039 ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
154bba13 3040
d0b9a143
MS
3041 /* This should optimize out entirely. This should always be true,
3042 but just in case it ever isn't, don't allow bogus code to be
3043 generated. */
3044
3045 if ((void*)(&ehfc->c) != (void*)ehfc)
3046 __terminate ();
3047
3048 return &ehfc->c;
154bba13
TT
3049}
3050
154bba13
TT
3051static __gthread_key_t eh_context_key;
3052
3053/* Destructor for struct eh_context. */
3054static void
3055eh_context_free (void *ptr)
3056{
f24af81b 3057 __gthread_key_dtor (eh_context_key, ptr);
154bba13
TT
3058 if (ptr)
3059 free (ptr);
3060}
3061#endif
3062
3063/* Pointer to function to return EH context. */
3064
3e7d8ef1
KG
3065static struct eh_context *eh_context_initialize (void);
3066static struct eh_context *eh_context_static (void);
154bba13 3067#if __GTHREADS
3e7d8ef1 3068static struct eh_context *eh_context_specific (void);
154bba13
TT
3069#endif
3070
3e7d8ef1 3071static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
154bba13
TT
3072
3073/* Routine to get EH context.
3074 This one will simply call the function pointer. */
3075
3076void *
3e7d8ef1 3077__get_eh_context (void)
154bba13
TT
3078{
3079 return (void *) (*get_eh_context) ();
3080}
3081
3082/* Get and set the language specific info pointer. */
3083
3084void **
3e7d8ef1 3085__get_eh_info (void)
154bba13
TT
3086{
3087 struct eh_context *eh = (*get_eh_context) ();
0776059e 3088 return &eh->info;
154bba13
TT
3089}
3090\f
d9d5c9de
BS
3091#ifdef DWARF2_UNWIND_INFO
3092static int dwarf_reg_size_table_initialized = 0;
7e259f25 3093static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
d9d5c9de
BS
3094
3095static void
3e7d8ef1 3096init_reg_size_table (void)
d9d5c9de
BS
3097{
3098 __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
3099 dwarf_reg_size_table_initialized = 1;
3100}
3101#endif
3102
154bba13
TT
3103#if __GTHREADS
3104static void
3e7d8ef1 3105eh_threads_initialize (void)
154bba13
TT
3106{
3107 /* Try to create the key. If it fails, revert to static method,
3108 otherwise start using thread specific EH contexts. */
3109 if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
3110 get_eh_context = &eh_context_specific;
3111 else
3112 get_eh_context = &eh_context_static;
3113}
3114#endif /* no __GTHREADS */
3115
3116/* Initialize EH context.
3117 This will be called only once, since we change GET_EH_CONTEXT
3118 pointer to another routine. */
3119
3120static struct eh_context *
3e7d8ef1 3121eh_context_initialize (void)
154bba13
TT
3122{
3123#if __GTHREADS
3124
3125 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
754d1a92
TT
3126 /* Make sure that get_eh_context does not point to us anymore.
3127 Some systems have dummy thread routines in their libc that
3128 return a success (Solaris 2.6 for example). */
3129 if (__gthread_once (&once, eh_threads_initialize) != 0
3130 || get_eh_context == &eh_context_initialize)
f24af81b
TT
3131 {
3132 /* Use static version of EH context. */
3133 get_eh_context = &eh_context_static;
3134 }
d9d5c9de
BS
3135#ifdef DWARF2_UNWIND_INFO
3136 {
3137 static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
3138 if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
3139 || ! dwarf_reg_size_table_initialized)
3140 init_reg_size_table ();
3141 }
3142#endif
154bba13
TT
3143
3144#else /* no __GTHREADS */
3145
3146 /* Use static version of EH context. */
3147 get_eh_context = &eh_context_static;
3148
d9d5c9de
BS
3149#ifdef DWARF2_UNWIND_INFO
3150 init_reg_size_table ();
3151#endif
3152
154bba13
TT
3153#endif /* no __GTHREADS */
3154
3155 return (*get_eh_context) ();
3156}
3157
3158/* Return a static EH context. */
3159
3160static struct eh_context *
3e7d8ef1 3161eh_context_static (void)
154bba13 3162{
c3cad221
JL
3163 static struct eh_context eh;
3164 static int initialized;
d0b9a143
MS
3165 static void *top_elt[2];
3166
c3cad221
JL
3167 if (! initialized)
3168 {
3169 initialized = 1;
3170 memset (&eh, 0, sizeof eh);
3171 eh.dynamic_handler_chain = top_elt;
3172 }
3173 return &eh;
154bba13
TT
3174}
3175
3176#if __GTHREADS
3177/* Return a thread specific EH context. */
3178
3179static struct eh_context *
3e7d8ef1 3180eh_context_specific (void)
154bba13
TT
3181{
3182 struct eh_context *eh;
3183 eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
3184 if (! eh)
3185 {
3186 eh = new_eh_context ();
3187 if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
3188 __terminate ();
3189 }
3190
3191 return eh;
3192}
3193#endif __GTHREADS
3194\f
ca55abae
JM
3195/* Support routines for setjmp/longjmp exception handling. */
3196
e976b8b2
MS
3197/* Calls to __sjthrow are generated by the compiler when an exception
3198 is raised when using the setjmp/longjmp exception handling codegen
3199 method. */
3200
154bba13 3201#ifdef DONT_USE_BUILTIN_SETJMP
6e6a07d2 3202extern void longjmp (void *, int);
154bba13 3203#endif
e976b8b2
MS
3204
3205/* Routine to get the head of the current thread's dynamic handler chain
154bba13 3206 use for exception handling. */
e976b8b2
MS
3207
3208void ***
3e7d8ef1 3209__get_dynamic_handler_chain (void)
e976b8b2 3210{
154bba13 3211 struct eh_context *eh = (*get_eh_context) ();
0776059e 3212 return &eh->dynamic_handler_chain;
e976b8b2
MS
3213}
3214
3215/* This is used to throw an exception when the setjmp/longjmp codegen
3216 method is used for exception handling.
3217
154bba13
TT
3218 We call __terminate if there are no handlers left. Otherwise we run the
3219 cleanup actions off the dynamic cleanup stack, and pop the top of the
3220 dynamic handler chain, and use longjmp to transfer back to the associated
3221 handler. */
e976b8b2
MS
3222
3223void
3e7d8ef1 3224__sjthrow (void)
e976b8b2 3225{
154bba13
TT
3226 struct eh_context *eh = (*get_eh_context) ();
3227 void ***dhc = &eh->dynamic_handler_chain;
e976b8b2
MS
3228 void *jmpbuf;
3229 void (*func)(void *, int);
3230 void *arg;
3e7d8ef1
KG
3231 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3232 void ***cleanup = (void***)&(*dhc)[1];
e976b8b2
MS
3233
3234 /* If there are any cleanups in the chain, run them now. */
3235 if (cleanup[0])
3236 {
3237 double store[200];
3238 void **buf = (void**)store;
3239 buf[1] = 0;
3240 buf[0] = (*dhc);
3241
3242 /* try { */
6e6a07d2 3243#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3244 if (! setjmp (&buf[2]))
6e6a07d2
MS
3245#else
3246 if (! __builtin_setjmp (&buf[2]))
3247#endif
e976b8b2
MS
3248 {
3249 *dhc = buf;
3250 while (cleanup[0])
3251 {
3252 func = (void(*)(void*, int))cleanup[0][1];
3253 arg = (void*)cleanup[0][2];
3254
3255 /* Update this before running the cleanup. */
3256 cleanup[0] = (void **)cleanup[0][0];
3257
3258 (*func)(arg, 2);
3259 }
3260 *dhc = buf[0];
3261 }
3262 /* catch (...) */
3263 else
3264 {
3265 __terminate ();
3266 }
3267 }
3268
3269 /* We must call terminate if we try and rethrow an exception, when
3270 there is no exception currently active and when there are no
3271 handlers left. */
d0b9a143 3272 if (! eh->info || (*dhc)[0] == 0)
e976b8b2
MS
3273 __terminate ();
3274
3275 /* Find the jmpbuf associated with the top element of the dynamic
3276 handler chain. The jumpbuf starts two words into the buffer. */
3277 jmpbuf = &(*dhc)[2];
3278
3279 /* Then we pop the top element off the dynamic handler chain. */
3280 *dhc = (void**)(*dhc)[0];
3281
3282 /* And then we jump to the handler. */
3283
6e6a07d2 3284#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3285 longjmp (jmpbuf, 1);
6e6a07d2
MS
3286#else
3287 __builtin_longjmp (jmpbuf, 1);
e976b8b2
MS
3288#endif
3289}
3290
3291/* Run cleanups on the dynamic cleanup stack for the current dynamic
3292 handler, then pop the handler off the dynamic handler stack, and
3293 then throw. This is used to skip the first handler, and transfer
3294 control to the next handler in the dynamic handler stack. */
3295
3296void
3e7d8ef1 3297__sjpopnthrow (void)
e976b8b2 3298{
154bba13
TT
3299 struct eh_context *eh = (*get_eh_context) ();
3300 void ***dhc = &eh->dynamic_handler_chain;
e976b8b2
MS
3301 void (*func)(void *, int);
3302 void *arg;
3e7d8ef1
KG
3303 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3304 void ***cleanup = (void***)&(*dhc)[1];
e976b8b2
MS
3305
3306 /* If there are any cleanups in the chain, run them now. */
3307 if (cleanup[0])
3308 {
3309 double store[200];
3310 void **buf = (void**)store;
3311 buf[1] = 0;
3312 buf[0] = (*dhc);
3313
3314 /* try { */
6e6a07d2 3315#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3316 if (! setjmp (&buf[2]))
6e6a07d2
MS
3317#else
3318 if (! __builtin_setjmp (&buf[2]))
3319#endif
e976b8b2
MS
3320 {
3321 *dhc = buf;
3322 while (cleanup[0])
3323 {
3324 func = (void(*)(void*, int))cleanup[0][1];
3325 arg = (void*)cleanup[0][2];
3326
3327 /* Update this before running the cleanup. */
3328 cleanup[0] = (void **)cleanup[0][0];
3329
3330 (*func)(arg, 2);
3331 }
3332 *dhc = buf[0];
3333 }
3334 /* catch (...) */
3335 else
3336 {
3337 __terminate ();
3338 }
3339 }
3340
3341 /* Then we pop the top element off the dynamic handler chain. */
3342 *dhc = (void**)(*dhc)[0];
3343
3344 __sjthrow ();
3345}
ca55abae
JM
3346\f
3347/* Support code for all exception region-based exception handling. */
3348
bf71cd2e
AM
3349int
3350__eh_rtime_match (void *rtime)
3351{
3352 void *info;
3353 __eh_matcher matcher;
3354 void *ret;
3355
3356 info = *(__get_eh_info ());
3357 matcher = ((__eh_info *)info)->match_function;
7ac2148b
AM
3358 if (! matcher)
3359 {
43566944 3360#ifndef inhibit_libc
7ac2148b 3361 fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
43566944 3362#endif
7ac2148b
AM
3363 return 0;
3364 }
bf71cd2e 3365 ret = (*matcher) (info, rtime, (void *)0);
7ac2148b 3366 return (ret != NULL);
bf71cd2e
AM
3367}
3368
ca55abae
JM
3369/* This value identifies the place from which an exception is being
3370 thrown. */
3371
ca55abae
JM
3372#ifdef EH_TABLE_LOOKUP
3373
3374EH_TABLE_LOOKUP
e976b8b2 3375
ca55abae
JM
3376#else
3377
d6f4ec51 3378#ifdef DWARF2_UNWIND_INFO
ad912eec 3379
48b24bcd
AM
3380/* Return the table version of an exception descriptor */
3381
3382short
3383__get_eh_table_version (exception_descriptor *table)
3384{
3385 return table->lang.version;
3386}
3387
3388/* Return the originating table language of an exception descriptor */
3389
3390short
3391__get_eh_table_language (exception_descriptor *table)
3392{
3393 return table->lang.language;
3394}
3395
ca55abae
JM
3396/* This routine takes a PC and a pointer to the exception region TABLE for
3397 its translation unit, and returns the address of the exception handler
3398 associated with the closest exception table handler entry associated
3399 with that PC, or 0 if there are no table entries the PC fits in.
3400
3401 In the advent of a tie, we have to give the last entry, as it represents
3402 an inner block. */
3403
a1622f83
AM
3404static void *
3405old_find_exception_handler (void *pc, old_exception_table *table)
3406{
3407 if (table)
3408 {
3409 int pos;
3410 int best = -1;
3411
3412 /* We can't do a binary search because the table isn't guaranteed
3413 to be sorted from function to function. */
3414 for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
3415 {
3416 if (table[pos].start_region <= pc && table[pos].end_region > pc)
3417 {
3418 /* This can apply. Make sure it is at least as small as
3419 the previous best. */
3420 if (best == -1 || (table[pos].end_region <= table[best].end_region
3421 && table[pos].start_region >= table[best].start_region))
3422 best = pos;
3423 }
3424 /* But it is sorted by starting PC within a function. */
3425 else if (best >= 0 && table[pos].start_region > pc)
3426 break;
3427 }
3428 if (best != -1)
3429 return table[best].exception_handler;
3430 }
3431
3432 return (void *) 0;
3433}
3434
e6cfb550
AM
3435/* find_exception_handler finds the correct handler, if there is one, to
3436 handle an exception.
3437 returns a pointer to the handler which controlled should be transferred
3438 to, or NULL if there is nothing left.
3439 Parameters:
3440 PC - pc where the exception originates. If this is a rethrow,
3441 then this starts out as a pointer to the exception table
3442 entry we wish to rethrow out of.
3443 TABLE - exception table for the current module.
3444 EH_INFO - eh info pointer for this exception.
3445 RETHROW - 1 if this is a rethrow. (see incoming value of PC).
3446 CLEANUP - returned flag indicating whether this is a cleanup handler.
3447*/
ca55abae 3448static void *
e6cfb550
AM
3449find_exception_handler (void *pc, exception_descriptor *table,
3450 __eh_info *eh_info, int rethrow, int *cleanup)
ca55abae 3451{
e6cfb550
AM
3452
3453 void *retval = NULL;
3454 *cleanup = 1;
ca55abae
JM
3455 if (table)
3456 {
e6cfb550 3457 int pos = 0;
9a0d1e1b
AM
3458 /* The new model assumed the table is sorted inner-most out so the
3459 first region we find which matches is the correct one */
3460
9a0d1e1b
AM
3461 exception_table *tab = &(table->table[0]);
3462
3463 /* Subtract 1 from the PC to avoid hitting the next region */
e6cfb550
AM
3464 if (rethrow)
3465 {
3466 /* pc is actually the region table entry to rethrow out of */
3467 pos = ((exception_table *) pc) - tab;
3468 pc = ((exception_table *) pc)->end_region - 1;
3469
3470 /* The label is always on the LAST handler entry for a region,
3471 so we know the next entry is a different region, even if the
3472 addresses are the same. Make sure its not end of table tho. */
3473 if (tab[pos].start_region != (void *) -1)
3474 pos++;
3475 }
3476 else
3477 pc--;
9a0d1e1b
AM
3478
3479 /* We can't do a binary search because the table is in inner-most
3480 to outermost address ranges within functions */
e6cfb550 3481 for ( ; tab[pos].start_region != (void *) -1; pos++)
9a0d1e1b
AM
3482 {
3483 if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
3484 {
3485 if (tab[pos].match_info)
3486 {
e6cfb550 3487 __eh_matcher matcher = eh_info->match_function;
9a0d1e1b
AM
3488 /* match info but no matcher is NOT a match */
3489 if (matcher)
3490 {
e6cfb550
AM
3491 void *ret = (*matcher)((void *) eh_info,
3492 tab[pos].match_info, table);
3493 if (ret)
3494 {
3495 if (retval == NULL)
3496 retval = tab[pos].exception_handler;
3497 *cleanup = 0;
3498 break;
3499 }
9a0d1e1b
AM
3500 }
3501 }
3502 else
e6cfb550
AM
3503 {
3504 if (retval == NULL)
3505 retval = tab[pos].exception_handler;
3506 }
9a0d1e1b
AM
3507 }
3508 }
ca55abae 3509 }
e6cfb550 3510 return retval;
ca55abae 3511}
d6f4ec51 3512#endif /* DWARF2_UNWIND_INFO */
ca55abae
JM
3513#endif /* EH_TABLE_LOOKUP */
3514\f
0776059e 3515#ifdef DWARF2_UNWIND_INFO
ca55abae
JM
3516/* Support code for exception handling using static unwind information. */
3517
3518#include "frame.h"
3519
3520/* This type is used in get_reg and put_reg to deal with ABIs where a void*
3521 is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
3522 avoid a warning about casting between int and pointer of different
3523 sizes. */
3524
3525typedef int ptr_type __attribute__ ((mode (pointer)));
3526
71038426
RH
3527#ifdef INCOMING_REGNO
3528/* Is the saved value for register REG in frame UDATA stored in a register
3529 window in the previous frame? */
3530
3531/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
3532 to use the macro here. One wonders, though, that perhaps TARGET_FLAT
3533 compiled functions won't work with the frame-unwind stuff here.
3534 Perhaps the entireity of in_reg_window should be conditional on having
3535 seen a DW_CFA_GNU_window_save? */
3536#define target_flags 0
3537
3538static int
3539in_reg_window (int reg, frame_state *udata)
3540{
3541 if (udata->saved[reg] == REG_SAVED_REG)
3542 return INCOMING_REGNO (reg) == reg;
3543 if (udata->saved[reg] != REG_SAVED_OFFSET)
3544 return 0;
3545
3546#ifdef STACK_GROWS_DOWNWARD
3547 return udata->reg_or_offset[reg] > 0;
3548#else
3549 return udata->reg_or_offset[reg] < 0;
3550#endif
3551}
3552#else
3e7d8ef1
KG
3553static inline int
3554in_reg_window (int reg __attribute__ ((__unused__)),
3555 frame_state *udata __attribute__ ((__unused__)))
3556{
3557 return 0;
3558}
71038426
RH
3559#endif /* INCOMING_REGNO */
3560
3561/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
ca55abae
JM
3562 frame called by UDATA or 0. */
3563
71038426
RH
3564static word_type *
3565get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
ca55abae 3566{
71038426
RH
3567 while (udata->saved[reg] == REG_SAVED_REG)
3568 {
3569 reg = udata->reg_or_offset[reg];
3570 if (in_reg_window (reg, udata))
3571 {
3572 udata = sub_udata;
3573 sub_udata = NULL;
3574 }
3575 }
ca55abae 3576 if (udata->saved[reg] == REG_SAVED_OFFSET)
71038426 3577 return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
ca55abae
JM
3578 else
3579 abort ();
3580}
3581
71038426
RH
3582/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
3583 frame called by UDATA or 0. */
3584
3585static inline void *
3586get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
3587{
3588 return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
3589}
3590
ca55abae
JM
3591/* Overwrite the saved value for register REG in frame UDATA with VAL. */
3592
71038426 3593static inline void
ca55abae
JM
3594put_reg (unsigned reg, void *val, frame_state *udata)
3595{
71038426 3596 *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
ca55abae
JM
3597}
3598
2f3ca9e7
JM
3599/* Copy the saved value for register REG from frame UDATA to frame
3600 TARGET_UDATA. Unlike the previous two functions, this can handle
3601 registers that are not one word large. */
3602
3603static void
3604copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
3605{
71038426
RH
3606 word_type *preg = get_reg_addr (reg, udata, NULL);
3607 word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
3608
d9d5c9de 3609 memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
2f3ca9e7
JM
3610}
3611
71038426 3612/* Retrieve the return address for frame UDATA. */
ca55abae
JM
3613
3614static inline void *
3615get_return_addr (frame_state *udata, frame_state *sub_udata)
3616{
3617 return __builtin_extract_return_addr
3618 (get_reg (udata->retaddr_column, udata, sub_udata));
3619}
3620
3621/* Overwrite the return address for frame UDATA with VAL. */
3622
3623static inline void
3624put_return_addr (void *val, frame_state *udata)
3625{
3626 val = __builtin_frob_return_addr (val);
3627 put_reg (udata->retaddr_column, val, udata);
3628}
3629
3630/* Given the current frame UDATA and its return address PC, return the
3631 information about the calling frame in CALLER_UDATA. */
3632
3633static void *
3634next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
3635{
3636 caller_udata = __frame_state_for (pc, caller_udata);
3637 if (! caller_udata)
3638 return 0;
3639
3640 /* Now go back to our caller's stack frame. If our caller's CFA register
3641 was saved in our stack frame, restore it; otherwise, assume the CFA
3642 register is SP and restore it to our CFA value. */
3643 if (udata->saved[caller_udata->cfa_reg])
3644 caller_udata->cfa = get_reg (caller_udata->cfa_reg, udata, 0);
3645 else
3646 caller_udata->cfa = udata->cfa;
3647 caller_udata->cfa += caller_udata->cfa_offset;
3648
3649 return caller_udata;
3650}
3651
e6cfb550
AM
3652/* Hook to call before __terminate if only cleanup handlers remain. */
3653void
3e7d8ef1 3654__unwinding_cleanup (void)
ca55abae 3655{
e6cfb550 3656}
ca55abae 3657
e6cfb550
AM
3658/* throw_helper performs some of the common grunt work for a throw. This
3659 routine is called by throw and rethrows. This is pretty much split
3660 out from the old __throw routine. An addition has been added which allows
3661 for a dummy call to a routine __unwinding_cleanup() when there are nothing
3662 but cleanups remaining. This allows a debugger to examine the state
3663 at which the throw was executed, before any cleanups, rather than
51980de6
JM
3664 at the terminate point after the stack has been unwound.
3665
3666 EH is the current eh_context structure.
3667 PC is the address of the call to __throw.
3668 MY_UDATA is the unwind information for __throw.
3669 OFFSET_P is where we return the SP adjustment offset. */
ca55abae 3670
e6cfb550 3671static void *
3e7d8ef1
KG
3672throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
3673 long *offset_p)
e6cfb550 3674{
51980de6 3675 frame_state ustruct2, *udata = &ustruct2;
e6cfb550
AM
3676 frame_state ustruct;
3677 frame_state *sub_udata = &ustruct;
3678 void *saved_pc = pc;
3679 void *handler;
3e7d8ef1
KG
3680 void *handler_p = 0;
3681 void *pc_p = 0;
e6cfb550
AM
3682 frame_state saved_ustruct;
3683 int new_eh_model;
3684 int cleanup = 0;
3685 int only_cleanup = 0;
3686 int rethrow = 0;
3687 int saved_state = 0;
51980de6 3688 long args_size;
e6cfb550
AM
3689 __eh_info *eh_info = (__eh_info *)eh->info;
3690
3691 /* Do we find a handler based on a re-throw PC? */
3692 if (eh->table_index != (void *) 0)
3693 rethrow = 1;
3694
51980de6
JM
3695 memcpy (udata, my_udata, sizeof (*udata));
3696
e6cfb550 3697 handler = (void *) 0;
ca55abae
JM
3698 for (;;)
3699 {
3700 frame_state *p = udata;
3701 udata = next_stack_level (pc, udata, sub_udata);
3702 sub_udata = p;
3703
3704 /* If we couldn't find the next frame, we lose. */
3705 if (! udata)
3706 break;
3707
a1622f83 3708 if (udata->eh_ptr == NULL)
e6cfb550 3709 new_eh_model = 0;
a1622f83 3710 else
e6cfb550 3711 new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
a1622f83
AM
3712 runtime_id_field == NEW_EH_RUNTIME);
3713
e6cfb550
AM
3714 if (rethrow)
3715 {
3716 rethrow = 0;
3717 handler = find_exception_handler (eh->table_index, udata->eh_ptr,
3718 eh_info, 1, &cleanup);
3719 eh->table_index = (void *)0;
3720 }
a1622f83 3721 else
e6cfb550
AM
3722 if (new_eh_model)
3723 handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
3724 0, &cleanup);
3725 else
3726 handler = old_find_exception_handler (pc, udata->eh_ptr);
3727
3728 /* If we found one, we can stop searching, if its not a cleanup.
3729 for cleanups, we save the state, and keep looking. This allows
3730 us to call a debug hook if there are nothing but cleanups left. */
ca55abae 3731 if (handler)
1b528097
JM
3732 {
3733 if (cleanup)
3734 {
3735 if (!saved_state)
3736 {
3737 saved_ustruct = *udata;
3738 handler_p = handler;
3739 pc_p = pc;
3740 saved_state = 1;
3741 only_cleanup = 1;
3742 }
3743 }
3744 else
3745 {
3746 only_cleanup = 0;
3747 break;
3748 }
3749 }
ca55abae 3750
6020d360
JM
3751 /* Otherwise, we continue searching. We subtract 1 from PC to avoid
3752 hitting the beginning of the next region. */
3753 pc = get_return_addr (udata, sub_udata) - 1;
ca55abae
JM
3754 }
3755
e6cfb550
AM
3756 if (saved_state)
3757 {
3758 udata = &saved_ustruct;
3759 handler = handler_p;
3760 pc = pc_p;
3761 if (only_cleanup)
3762 __unwinding_cleanup ();
3763 }
3764
ca55abae
JM
3765 /* If we haven't found a handler by now, this is an unhandled
3766 exception. */
e6cfb550
AM
3767 if (! handler)
3768 __terminate();
ca55abae 3769
9a0d1e1b 3770 eh->handler_label = handler;
9a0d1e1b 3771
51980de6
JM
3772 args_size = udata->args_size;
3773
154bba13 3774 if (pc == saved_pc)
ca55abae
JM
3775 /* We found a handler in the throw context, no need to unwind. */
3776 udata = my_udata;
3777 else
3778 {
3779 int i;
ca55abae
JM
3780
3781 /* Unwind all the frames between this one and the handler by copying
3782 their saved register values into our register save slots. */
3783
3784 /* Remember the PC where we found the handler. */
3785 void *handler_pc = pc;
3786
3787 /* Start from the throw context again. */
154bba13 3788 pc = saved_pc;
ca55abae
JM
3789 memcpy (udata, my_udata, sizeof (*udata));
3790
3791 while (pc != handler_pc)
3792 {
3793 frame_state *p = udata;
3794 udata = next_stack_level (pc, udata, sub_udata);
3795 sub_udata = p;
3796
7e259f25 3797 for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
d1485032 3798 if (i != udata->retaddr_column && udata->saved[i])
ca55abae 3799 {
ca55abae
JM
3800 /* If you modify the saved value of the return address
3801 register on the SPARC, you modify the return address for
3802 your caller's frame. Don't do that here, as it will
3803 confuse get_return_addr. */
3804 if (in_reg_window (i, udata)
3805 && udata->saved[udata->retaddr_column] == REG_SAVED_REG
3806 && udata->reg_or_offset[udata->retaddr_column] == i)
3807 continue;
2f3ca9e7 3808 copy_reg (i, udata, my_udata);
ca55abae
JM
3809 }
3810
6020d360 3811 pc = get_return_addr (udata, sub_udata) - 1;
ca55abae
JM
3812 }
3813
ca55abae
JM
3814 /* But we do need to update the saved return address register from
3815 the last frame we unwind, or the handler frame will have the wrong
3816 return address. */
3817 if (udata->saved[udata->retaddr_column] == REG_SAVED_REG)
3818 {
3819 i = udata->reg_or_offset[udata->retaddr_column];
3820 if (in_reg_window (i, udata))
f3447109 3821 copy_reg (i, udata, my_udata);
ca55abae 3822 }
ca55abae 3823 }
e6cfb550
AM
3824 /* udata now refers to the frame called by the handler frame. */
3825
51980de6
JM
3826 /* We adjust SP by the difference between __throw's CFA and the CFA for
3827 the frame called by the handler frame, because those CFAs correspond
3828 to the SP values at the two call sites. We need to further adjust by
3829 the args_size of the handler frame itself to get the handler frame's
3830 SP from before the args were pushed for that call. */
3831#ifdef STACK_GROWS_DOWNWARD
3832 *offset_p = udata->cfa - my_udata->cfa + args_size;
3833#else
3834 *offset_p = my_udata->cfa - udata->cfa - args_size;
3835#endif
3836
e6cfb550
AM
3837 return handler;
3838}
3839
3840
3841/* We first search for an exception handler, and if we don't find
3842 it, we call __terminate on the current stack frame so that we may
3843 use the debugger to walk the stack and understand why no handler
3844 was found.
3845
3846 If we find one, then we unwind the frames down to the one that
3847 has the handler and transfer control into the handler. */
3848
3849/*extern void __throw(void) __attribute__ ((__noreturn__));*/
3850
3851void
3e7d8ef1 3852__throw (void)
e6cfb550
AM
3853{
3854 struct eh_context *eh = (*get_eh_context) ();
3855 void *pc, *handler;
51980de6
JM
3856 long offset;
3857
3858 /* XXX maybe make my_ustruct static so we don't have to look it up for
3859 each throw. */
e6cfb550
AM
3860 frame_state my_ustruct, *my_udata = &my_ustruct;
3861
3862 /* This is required for C++ semantics. We must call terminate if we
3863 try and rethrow an exception, when there is no exception currently
3864 active. */
3865 if (! eh->info)
3866 __terminate ();
3867
3868 /* Start at our stack frame. */
3869label:
51980de6
JM
3870 my_udata = __frame_state_for (&&label, my_udata);
3871 if (! my_udata)
e6cfb550
AM
3872 __terminate ();
3873
3874 /* We need to get the value from the CFA register. */
51980de6 3875 my_udata->cfa = __builtin_dwarf_cfa ();
e6cfb550
AM
3876
3877 /* Do any necessary initialization to access arbitrary stack frames.
3878 On the SPARC, this means flushing the register windows. */
3879 __builtin_unwind_init ();
3880
3881 /* Now reset pc to the right throw point. */
3882 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
3883
51980de6 3884 handler = throw_helper (eh, pc, my_udata, &offset);
e6cfb550
AM
3885
3886 /* Now go! */
3887
51980de6 3888 __builtin_eh_return ((void *)eh, offset, handler);
e6cfb550
AM
3889
3890 /* Epilogue: restore the handler frame's register values and return
3891 to the stub. */
3892}
3893
3894/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
3895
3896void
3e7d8ef1 3897__rethrow (void *index)
e6cfb550
AM
3898{
3899 struct eh_context *eh = (*get_eh_context) ();
3900 void *pc, *handler;
51980de6
JM
3901 long offset;
3902
3903 /* XXX maybe make my_ustruct static so we don't have to look it up for
3904 each throw. */
e6cfb550
AM
3905 frame_state my_ustruct, *my_udata = &my_ustruct;
3906
3907 /* This is required for C++ semantics. We must call terminate if we
3908 try and rethrow an exception, when there is no exception currently
3909 active. */
3910 if (! eh->info)
3911 __terminate ();
3912
3913 /* This is the table index we want to rethrow from. The value of
3914 the END_REGION label is used for the PC of the throw, and the
3915 search begins with the next table entry. */
3916 eh->table_index = index;
3917
3918 /* Start at our stack frame. */
3919label:
51980de6
JM
3920 my_udata = __frame_state_for (&&label, my_udata);
3921 if (! my_udata)
e6cfb550
AM
3922 __terminate ();
3923
3924 /* We need to get the value from the CFA register. */
51980de6 3925 my_udata->cfa = __builtin_dwarf_cfa ();
e6cfb550
AM
3926
3927 /* Do any necessary initialization to access arbitrary stack frames.
3928 On the SPARC, this means flushing the register windows. */
3929 __builtin_unwind_init ();
3930
3931 /* Now reset pc to the right throw point. */
3932 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
3933
51980de6 3934 handler = throw_helper (eh, pc, my_udata, &offset);
ca55abae 3935
71038426 3936 /* Now go! */
9a0d1e1b 3937
51980de6 3938 __builtin_eh_return ((void *)eh, offset, handler);
ca55abae
JM
3939
3940 /* Epilogue: restore the handler frame's register values and return
3941 to the stub. */
3942}
0776059e 3943#endif /* DWARF2_UNWIND_INFO */
ca55abae 3944
ad912eec 3945#endif /* L_eh */
efc955c7
JM
3946\f
3947#ifdef L_pure
2c62c124
JM
3948#ifndef inhibit_libc
3949/* This gets us __GNU_LIBRARY__. */
3950#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
3951#include <stdio.h>
3952
3953#ifdef __GNU_LIBRARY__
3954 /* Avoid forcing the library's meaning of `write' on the user program
3955 by using the "internal" name (for use within the library) */
3956#define write(fd, buf, n) __write((fd), (buf), (n))
3957#endif
3958#endif /* inhibit_libc */
3959
efc955c7 3960#define MESSAGE "pure virtual method called\n"
2c62c124 3961
efc955c7 3962void
3e7d8ef1 3963__pure_virtual (void)
efc955c7 3964{
2c62c124 3965#ifndef inhibit_libc
efc955c7 3966 write (2, MESSAGE, sizeof (MESSAGE) - 1);
2c62c124 3967#endif
4f2905fb 3968 __terminate ();
efc955c7
JM
3969}
3970#endif
This page took 1.524441 seconds and 5 git commands to generate.