1*a9fa9459Szrj /* alloca.c -- allocate automatically reclaimed memory
2*a9fa9459Szrj (Mostly) portable public-domain implementation -- D A Gwyn
3*a9fa9459Szrj
4*a9fa9459Szrj This implementation of the PWB library alloca function,
5*a9fa9459Szrj which is used to allocate space off the run-time stack so
6*a9fa9459Szrj that it is automatically reclaimed upon procedure exit,
7*a9fa9459Szrj was inspired by discussions with J. Q. Johnson of Cornell.
8*a9fa9459Szrj J.Otto Tennant <jot@cray.com> contributed the Cray support.
9*a9fa9459Szrj
10*a9fa9459Szrj There are some preprocessor constants that can
11*a9fa9459Szrj be defined when compiling for your specific system, for
12*a9fa9459Szrj improved efficiency; however, the defaults should be okay.
13*a9fa9459Szrj
14*a9fa9459Szrj The general concept of this implementation is to keep
15*a9fa9459Szrj track of all alloca-allocated blocks, and reclaim any
16*a9fa9459Szrj that are found to be deeper in the stack than the current
17*a9fa9459Szrj invocation. This heuristic does not reclaim storage as
18*a9fa9459Szrj soon as it becomes invalid, but it will do so eventually.
19*a9fa9459Szrj
20*a9fa9459Szrj As a special case, alloca(0) reclaims storage without
21*a9fa9459Szrj allocating any. It is a good idea to use alloca(0) in
22*a9fa9459Szrj your main control loop, etc. to force garbage collection. */
23*a9fa9459Szrj
24*a9fa9459Szrj /*
25*a9fa9459Szrj
26*a9fa9459Szrj @deftypefn Replacement void* alloca (size_t @var{size})
27*a9fa9459Szrj
28*a9fa9459Szrj This function allocates memory which will be automatically reclaimed
29*a9fa9459Szrj after the procedure exits. The @libib{} implementation does not free
30*a9fa9459Szrj the memory immediately but will do so eventually during subsequent
31*a9fa9459Szrj calls to this function. Memory is allocated using @code{xmalloc} under
32*a9fa9459Szrj normal circumstances.
33*a9fa9459Szrj
34*a9fa9459Szrj The header file @file{alloca-conf.h} can be used in conjunction with the
35*a9fa9459Szrj GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
36*a9fa9459Szrj available this function. The @code{AC_FUNC_ALLOCA} test requires that
37*a9fa9459Szrj client code use a block of preprocessor code to be safe (see the Autoconf
38*a9fa9459Szrj manual for more); this header incorporates that logic and more, including
39*a9fa9459Szrj the possibility of a GCC built-in function.
40*a9fa9459Szrj
41*a9fa9459Szrj @end deftypefn
42*a9fa9459Szrj
43*a9fa9459Szrj */
44*a9fa9459Szrj
45*a9fa9459Szrj #ifdef HAVE_CONFIG_H
46*a9fa9459Szrj #include <config.h>
47*a9fa9459Szrj #endif
48*a9fa9459Szrj
49*a9fa9459Szrj #include <libiberty.h>
50*a9fa9459Szrj
51*a9fa9459Szrj #ifdef HAVE_STRING_H
52*a9fa9459Szrj #include <string.h>
53*a9fa9459Szrj #endif
54*a9fa9459Szrj #ifdef HAVE_STDLIB_H
55*a9fa9459Szrj #include <stdlib.h>
56*a9fa9459Szrj #endif
57*a9fa9459Szrj
58*a9fa9459Szrj /* These variables are used by the ASTRDUP implementation that relies
59*a9fa9459Szrj on C_alloca. */
60*a9fa9459Szrj #ifdef __cplusplus
61*a9fa9459Szrj extern "C" {
62*a9fa9459Szrj #endif /* __cplusplus */
63*a9fa9459Szrj const char *libiberty_optr;
64*a9fa9459Szrj char *libiberty_nptr;
65*a9fa9459Szrj unsigned long libiberty_len;
66*a9fa9459Szrj #ifdef __cplusplus
67*a9fa9459Szrj }
68*a9fa9459Szrj #endif /* __cplusplus */
69*a9fa9459Szrj
70*a9fa9459Szrj /* If your stack is a linked list of frames, you have to
71*a9fa9459Szrj provide an "address metric" ADDRESS_FUNCTION macro. */
72*a9fa9459Szrj
73*a9fa9459Szrj #if defined (CRAY) && defined (CRAY_STACKSEG_END)
74*a9fa9459Szrj static long i00afunc ();
75*a9fa9459Szrj #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
76*a9fa9459Szrj #else
77*a9fa9459Szrj #define ADDRESS_FUNCTION(arg) &(arg)
78*a9fa9459Szrj #endif
79*a9fa9459Szrj
80*a9fa9459Szrj #ifndef NULL
81*a9fa9459Szrj #define NULL 0
82*a9fa9459Szrj #endif
83*a9fa9459Szrj
84*a9fa9459Szrj /* Define STACK_DIRECTION if you know the direction of stack
85*a9fa9459Szrj growth for your system; otherwise it will be automatically
86*a9fa9459Szrj deduced at run-time.
87*a9fa9459Szrj
88*a9fa9459Szrj STACK_DIRECTION > 0 => grows toward higher addresses
89*a9fa9459Szrj STACK_DIRECTION < 0 => grows toward lower addresses
90*a9fa9459Szrj STACK_DIRECTION = 0 => direction of growth unknown */
91*a9fa9459Szrj
92*a9fa9459Szrj #ifndef STACK_DIRECTION
93*a9fa9459Szrj #define STACK_DIRECTION 0 /* Direction unknown. */
94*a9fa9459Szrj #endif
95*a9fa9459Szrj
96*a9fa9459Szrj #if STACK_DIRECTION != 0
97*a9fa9459Szrj
98*a9fa9459Szrj #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
99*a9fa9459Szrj
100*a9fa9459Szrj #else /* STACK_DIRECTION == 0; need run-time code. */
101*a9fa9459Szrj
102*a9fa9459Szrj static int stack_dir; /* 1 or -1 once known. */
103*a9fa9459Szrj #define STACK_DIR stack_dir
104*a9fa9459Szrj
105*a9fa9459Szrj static void
find_stack_direction(void)106*a9fa9459Szrj find_stack_direction (void)
107*a9fa9459Szrj {
108*a9fa9459Szrj static char *addr = NULL; /* Address of first `dummy', once known. */
109*a9fa9459Szrj auto char dummy; /* To get stack address. */
110*a9fa9459Szrj
111*a9fa9459Szrj if (addr == NULL)
112*a9fa9459Szrj { /* Initial entry. */
113*a9fa9459Szrj addr = ADDRESS_FUNCTION (dummy);
114*a9fa9459Szrj
115*a9fa9459Szrj find_stack_direction (); /* Recurse once. */
116*a9fa9459Szrj }
117*a9fa9459Szrj else
118*a9fa9459Szrj {
119*a9fa9459Szrj /* Second entry. */
120*a9fa9459Szrj if (ADDRESS_FUNCTION (dummy) > addr)
121*a9fa9459Szrj stack_dir = 1; /* Stack grew upward. */
122*a9fa9459Szrj else
123*a9fa9459Szrj stack_dir = -1; /* Stack grew downward. */
124*a9fa9459Szrj }
125*a9fa9459Szrj }
126*a9fa9459Szrj
127*a9fa9459Szrj #endif /* STACK_DIRECTION == 0 */
128*a9fa9459Szrj
129*a9fa9459Szrj /* An "alloca header" is used to:
130*a9fa9459Szrj (a) chain together all alloca'ed blocks;
131*a9fa9459Szrj (b) keep track of stack depth.
132*a9fa9459Szrj
133*a9fa9459Szrj It is very important that sizeof(header) agree with malloc
134*a9fa9459Szrj alignment chunk size. The following default should work okay. */
135*a9fa9459Szrj
136*a9fa9459Szrj #ifndef ALIGN_SIZE
137*a9fa9459Szrj #define ALIGN_SIZE sizeof(double)
138*a9fa9459Szrj #endif
139*a9fa9459Szrj
140*a9fa9459Szrj typedef union hdr
141*a9fa9459Szrj {
142*a9fa9459Szrj char align[ALIGN_SIZE]; /* To force sizeof(header). */
143*a9fa9459Szrj struct
144*a9fa9459Szrj {
145*a9fa9459Szrj union hdr *next; /* For chaining headers. */
146*a9fa9459Szrj char *deep; /* For stack depth measure. */
147*a9fa9459Szrj } h;
148*a9fa9459Szrj } header;
149*a9fa9459Szrj
150*a9fa9459Szrj static header *last_alloca_header = NULL; /* -> last alloca header. */
151*a9fa9459Szrj
152*a9fa9459Szrj /* Return a pointer to at least SIZE bytes of storage,
153*a9fa9459Szrj which will be automatically reclaimed upon exit from
154*a9fa9459Szrj the procedure that called alloca. Originally, this space
155*a9fa9459Szrj was supposed to be taken from the current stack frame of the
156*a9fa9459Szrj caller, but that method cannot be made to work for some
157*a9fa9459Szrj implementations of C, for example under Gould's UTX/32. */
158*a9fa9459Szrj
159*a9fa9459Szrj /* @undocumented C_alloca */
160*a9fa9459Szrj
161*a9fa9459Szrj PTR
C_alloca(size_t size)162*a9fa9459Szrj C_alloca (size_t size)
163*a9fa9459Szrj {
164*a9fa9459Szrj auto char probe; /* Probes stack depth: */
165*a9fa9459Szrj register char *depth = ADDRESS_FUNCTION (probe);
166*a9fa9459Szrj
167*a9fa9459Szrj #if STACK_DIRECTION == 0
168*a9fa9459Szrj if (STACK_DIR == 0) /* Unknown growth direction. */
169*a9fa9459Szrj find_stack_direction ();
170*a9fa9459Szrj #endif
171*a9fa9459Szrj
172*a9fa9459Szrj /* Reclaim garbage, defined as all alloca'd storage that
173*a9fa9459Szrj was allocated from deeper in the stack than currently. */
174*a9fa9459Szrj
175*a9fa9459Szrj {
176*a9fa9459Szrj register header *hp; /* Traverses linked list. */
177*a9fa9459Szrj
178*a9fa9459Szrj for (hp = last_alloca_header; hp != NULL;)
179*a9fa9459Szrj if ((STACK_DIR > 0 && hp->h.deep > depth)
180*a9fa9459Szrj || (STACK_DIR < 0 && hp->h.deep < depth))
181*a9fa9459Szrj {
182*a9fa9459Szrj register header *np = hp->h.next;
183*a9fa9459Szrj
184*a9fa9459Szrj free ((PTR) hp); /* Collect garbage. */
185*a9fa9459Szrj
186*a9fa9459Szrj hp = np; /* -> next header. */
187*a9fa9459Szrj }
188*a9fa9459Szrj else
189*a9fa9459Szrj break; /* Rest are not deeper. */
190*a9fa9459Szrj
191*a9fa9459Szrj last_alloca_header = hp; /* -> last valid storage. */
192*a9fa9459Szrj }
193*a9fa9459Szrj
194*a9fa9459Szrj if (size == 0)
195*a9fa9459Szrj return NULL; /* No allocation required. */
196*a9fa9459Szrj
197*a9fa9459Szrj /* Allocate combined header + user data storage. */
198*a9fa9459Szrj
199*a9fa9459Szrj {
200*a9fa9459Szrj register void *new_storage = XNEWVEC (char, sizeof (header) + size);
201*a9fa9459Szrj /* Address of header. */
202*a9fa9459Szrj
203*a9fa9459Szrj if (new_storage == 0)
204*a9fa9459Szrj abort();
205*a9fa9459Szrj
206*a9fa9459Szrj ((header *) new_storage)->h.next = last_alloca_header;
207*a9fa9459Szrj ((header *) new_storage)->h.deep = depth;
208*a9fa9459Szrj
209*a9fa9459Szrj last_alloca_header = (header *) new_storage;
210*a9fa9459Szrj
211*a9fa9459Szrj /* User storage begins just after header. */
212*a9fa9459Szrj
213*a9fa9459Szrj return (PTR) ((char *) new_storage + sizeof (header));
214*a9fa9459Szrj }
215*a9fa9459Szrj }
216*a9fa9459Szrj
217*a9fa9459Szrj #if defined (CRAY) && defined (CRAY_STACKSEG_END)
218*a9fa9459Szrj
219*a9fa9459Szrj #ifdef DEBUG_I00AFUNC
220*a9fa9459Szrj #include <stdio.h>
221*a9fa9459Szrj #endif
222*a9fa9459Szrj
223*a9fa9459Szrj #ifndef CRAY_STACK
224*a9fa9459Szrj #define CRAY_STACK
225*a9fa9459Szrj #ifndef CRAY2
226*a9fa9459Szrj /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
227*a9fa9459Szrj struct stack_control_header
228*a9fa9459Szrj {
229*a9fa9459Szrj long shgrow:32; /* Number of times stack has grown. */
230*a9fa9459Szrj long shaseg:32; /* Size of increments to stack. */
231*a9fa9459Szrj long shhwm:32; /* High water mark of stack. */
232*a9fa9459Szrj long shsize:32; /* Current size of stack (all segments). */
233*a9fa9459Szrj };
234*a9fa9459Szrj
235*a9fa9459Szrj /* The stack segment linkage control information occurs at
236*a9fa9459Szrj the high-address end of a stack segment. (The stack
237*a9fa9459Szrj grows from low addresses to high addresses.) The initial
238*a9fa9459Szrj part of the stack segment linkage control information is
239*a9fa9459Szrj 0200 (octal) words. This provides for register storage
240*a9fa9459Szrj for the routine which overflows the stack. */
241*a9fa9459Szrj
242*a9fa9459Szrj struct stack_segment_linkage
243*a9fa9459Szrj {
244*a9fa9459Szrj long ss[0200]; /* 0200 overflow words. */
245*a9fa9459Szrj long sssize:32; /* Number of words in this segment. */
246*a9fa9459Szrj long ssbase:32; /* Offset to stack base. */
247*a9fa9459Szrj long:32;
248*a9fa9459Szrj long sspseg:32; /* Offset to linkage control of previous
249*a9fa9459Szrj segment of stack. */
250*a9fa9459Szrj long:32;
251*a9fa9459Szrj long sstcpt:32; /* Pointer to task common address block. */
252*a9fa9459Szrj long sscsnm; /* Private control structure number for
253*a9fa9459Szrj microtasking. */
254*a9fa9459Szrj long ssusr1; /* Reserved for user. */
255*a9fa9459Szrj long ssusr2; /* Reserved for user. */
256*a9fa9459Szrj long sstpid; /* Process ID for pid based multi-tasking. */
257*a9fa9459Szrj long ssgvup; /* Pointer to multitasking thread giveup. */
258*a9fa9459Szrj long sscray[7]; /* Reserved for Cray Research. */
259*a9fa9459Szrj long ssa0;
260*a9fa9459Szrj long ssa1;
261*a9fa9459Szrj long ssa2;
262*a9fa9459Szrj long ssa3;
263*a9fa9459Szrj long ssa4;
264*a9fa9459Szrj long ssa5;
265*a9fa9459Szrj long ssa6;
266*a9fa9459Szrj long ssa7;
267*a9fa9459Szrj long sss0;
268*a9fa9459Szrj long sss1;
269*a9fa9459Szrj long sss2;
270*a9fa9459Szrj long sss3;
271*a9fa9459Szrj long sss4;
272*a9fa9459Szrj long sss5;
273*a9fa9459Szrj long sss6;
274*a9fa9459Szrj long sss7;
275*a9fa9459Szrj };
276*a9fa9459Szrj
277*a9fa9459Szrj #else /* CRAY2 */
278*a9fa9459Szrj /* The following structure defines the vector of words
279*a9fa9459Szrj returned by the STKSTAT library routine. */
280*a9fa9459Szrj struct stk_stat
281*a9fa9459Szrj {
282*a9fa9459Szrj long now; /* Current total stack size. */
283*a9fa9459Szrj long maxc; /* Amount of contiguous space which would
284*a9fa9459Szrj be required to satisfy the maximum
285*a9fa9459Szrj stack demand to date. */
286*a9fa9459Szrj long high_water; /* Stack high-water mark. */
287*a9fa9459Szrj long overflows; /* Number of stack overflow ($STKOFEN) calls. */
288*a9fa9459Szrj long hits; /* Number of internal buffer hits. */
289*a9fa9459Szrj long extends; /* Number of block extensions. */
290*a9fa9459Szrj long stko_mallocs; /* Block allocations by $STKOFEN. */
291*a9fa9459Szrj long underflows; /* Number of stack underflow calls ($STKRETN). */
292*a9fa9459Szrj long stko_free; /* Number of deallocations by $STKRETN. */
293*a9fa9459Szrj long stkm_free; /* Number of deallocations by $STKMRET. */
294*a9fa9459Szrj long segments; /* Current number of stack segments. */
295*a9fa9459Szrj long maxs; /* Maximum number of stack segments so far. */
296*a9fa9459Szrj long pad_size; /* Stack pad size. */
297*a9fa9459Szrj long current_address; /* Current stack segment address. */
298*a9fa9459Szrj long current_size; /* Current stack segment size. This
299*a9fa9459Szrj number is actually corrupted by STKSTAT to
300*a9fa9459Szrj include the fifteen word trailer area. */
301*a9fa9459Szrj long initial_address; /* Address of initial segment. */
302*a9fa9459Szrj long initial_size; /* Size of initial segment. */
303*a9fa9459Szrj };
304*a9fa9459Szrj
305*a9fa9459Szrj /* The following structure describes the data structure which trails
306*a9fa9459Szrj any stack segment. I think that the description in 'asdef' is
307*a9fa9459Szrj out of date. I only describe the parts that I am sure about. */
308*a9fa9459Szrj
309*a9fa9459Szrj struct stk_trailer
310*a9fa9459Szrj {
311*a9fa9459Szrj long this_address; /* Address of this block. */
312*a9fa9459Szrj long this_size; /* Size of this block (does not include
313*a9fa9459Szrj this trailer). */
314*a9fa9459Szrj long unknown2;
315*a9fa9459Szrj long unknown3;
316*a9fa9459Szrj long link; /* Address of trailer block of previous
317*a9fa9459Szrj segment. */
318*a9fa9459Szrj long unknown5;
319*a9fa9459Szrj long unknown6;
320*a9fa9459Szrj long unknown7;
321*a9fa9459Szrj long unknown8;
322*a9fa9459Szrj long unknown9;
323*a9fa9459Szrj long unknown10;
324*a9fa9459Szrj long unknown11;
325*a9fa9459Szrj long unknown12;
326*a9fa9459Szrj long unknown13;
327*a9fa9459Szrj long unknown14;
328*a9fa9459Szrj };
329*a9fa9459Szrj
330*a9fa9459Szrj #endif /* CRAY2 */
331*a9fa9459Szrj #endif /* not CRAY_STACK */
332*a9fa9459Szrj
333*a9fa9459Szrj #ifdef CRAY2
334*a9fa9459Szrj /* Determine a "stack measure" for an arbitrary ADDRESS.
335*a9fa9459Szrj I doubt that "lint" will like this much. */
336*a9fa9459Szrj
337*a9fa9459Szrj static long
i00afunc(long * address)338*a9fa9459Szrj i00afunc (long *address)
339*a9fa9459Szrj {
340*a9fa9459Szrj struct stk_stat status;
341*a9fa9459Szrj struct stk_trailer *trailer;
342*a9fa9459Szrj long *block, size;
343*a9fa9459Szrj long result = 0;
344*a9fa9459Szrj
345*a9fa9459Szrj /* We want to iterate through all of the segments. The first
346*a9fa9459Szrj step is to get the stack status structure. We could do this
347*a9fa9459Szrj more quickly and more directly, perhaps, by referencing the
348*a9fa9459Szrj $LM00 common block, but I know that this works. */
349*a9fa9459Szrj
350*a9fa9459Szrj STKSTAT (&status);
351*a9fa9459Szrj
352*a9fa9459Szrj /* Set up the iteration. */
353*a9fa9459Szrj
354*a9fa9459Szrj trailer = (struct stk_trailer *) (status.current_address
355*a9fa9459Szrj + status.current_size
356*a9fa9459Szrj - 15);
357*a9fa9459Szrj
358*a9fa9459Szrj /* There must be at least one stack segment. Therefore it is
359*a9fa9459Szrj a fatal error if "trailer" is null. */
360*a9fa9459Szrj
361*a9fa9459Szrj if (trailer == 0)
362*a9fa9459Szrj abort ();
363*a9fa9459Szrj
364*a9fa9459Szrj /* Discard segments that do not contain our argument address. */
365*a9fa9459Szrj
366*a9fa9459Szrj while (trailer != 0)
367*a9fa9459Szrj {
368*a9fa9459Szrj block = (long *) trailer->this_address;
369*a9fa9459Szrj size = trailer->this_size;
370*a9fa9459Szrj if (block == 0 || size == 0)
371*a9fa9459Szrj abort ();
372*a9fa9459Szrj trailer = (struct stk_trailer *) trailer->link;
373*a9fa9459Szrj if ((block <= address) && (address < (block + size)))
374*a9fa9459Szrj break;
375*a9fa9459Szrj }
376*a9fa9459Szrj
377*a9fa9459Szrj /* Set the result to the offset in this segment and add the sizes
378*a9fa9459Szrj of all predecessor segments. */
379*a9fa9459Szrj
380*a9fa9459Szrj result = address - block;
381*a9fa9459Szrj
382*a9fa9459Szrj if (trailer == 0)
383*a9fa9459Szrj {
384*a9fa9459Szrj return result;
385*a9fa9459Szrj }
386*a9fa9459Szrj
387*a9fa9459Szrj do
388*a9fa9459Szrj {
389*a9fa9459Szrj if (trailer->this_size <= 0)
390*a9fa9459Szrj abort ();
391*a9fa9459Szrj result += trailer->this_size;
392*a9fa9459Szrj trailer = (struct stk_trailer *) trailer->link;
393*a9fa9459Szrj }
394*a9fa9459Szrj while (trailer != 0);
395*a9fa9459Szrj
396*a9fa9459Szrj /* We are done. Note that if you present a bogus address (one
397*a9fa9459Szrj not in any segment), you will get a different number back, formed
398*a9fa9459Szrj from subtracting the address of the first block. This is probably
399*a9fa9459Szrj not what you want. */
400*a9fa9459Szrj
401*a9fa9459Szrj return (result);
402*a9fa9459Szrj }
403*a9fa9459Szrj
404*a9fa9459Szrj #else /* not CRAY2 */
405*a9fa9459Szrj /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
406*a9fa9459Szrj Determine the number of the cell within the stack,
407*a9fa9459Szrj given the address of the cell. The purpose of this
408*a9fa9459Szrj routine is to linearize, in some sense, stack addresses
409*a9fa9459Szrj for alloca. */
410*a9fa9459Szrj
411*a9fa9459Szrj static long
i00afunc(long address)412*a9fa9459Szrj i00afunc (long address)
413*a9fa9459Szrj {
414*a9fa9459Szrj long stkl = 0;
415*a9fa9459Szrj
416*a9fa9459Szrj long size, pseg, this_segment, stack;
417*a9fa9459Szrj long result = 0;
418*a9fa9459Szrj
419*a9fa9459Szrj struct stack_segment_linkage *ssptr;
420*a9fa9459Szrj
421*a9fa9459Szrj /* Register B67 contains the address of the end of the
422*a9fa9459Szrj current stack segment. If you (as a subprogram) store
423*a9fa9459Szrj your registers on the stack and find that you are past
424*a9fa9459Szrj the contents of B67, you have overflowed the segment.
425*a9fa9459Szrj
426*a9fa9459Szrj B67 also points to the stack segment linkage control
427*a9fa9459Szrj area, which is what we are really interested in. */
428*a9fa9459Szrj
429*a9fa9459Szrj stkl = CRAY_STACKSEG_END ();
430*a9fa9459Szrj ssptr = (struct stack_segment_linkage *) stkl;
431*a9fa9459Szrj
432*a9fa9459Szrj /* If one subtracts 'size' from the end of the segment,
433*a9fa9459Szrj one has the address of the first word of the segment.
434*a9fa9459Szrj
435*a9fa9459Szrj If this is not the first segment, 'pseg' will be
436*a9fa9459Szrj nonzero. */
437*a9fa9459Szrj
438*a9fa9459Szrj pseg = ssptr->sspseg;
439*a9fa9459Szrj size = ssptr->sssize;
440*a9fa9459Szrj
441*a9fa9459Szrj this_segment = stkl - size;
442*a9fa9459Szrj
443*a9fa9459Szrj /* It is possible that calling this routine itself caused
444*a9fa9459Szrj a stack overflow. Discard stack segments which do not
445*a9fa9459Szrj contain the target address. */
446*a9fa9459Szrj
447*a9fa9459Szrj while (!(this_segment <= address && address <= stkl))
448*a9fa9459Szrj {
449*a9fa9459Szrj #ifdef DEBUG_I00AFUNC
450*a9fa9459Szrj fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
451*a9fa9459Szrj #endif
452*a9fa9459Szrj if (pseg == 0)
453*a9fa9459Szrj break;
454*a9fa9459Szrj stkl = stkl - pseg;
455*a9fa9459Szrj ssptr = (struct stack_segment_linkage *) stkl;
456*a9fa9459Szrj size = ssptr->sssize;
457*a9fa9459Szrj pseg = ssptr->sspseg;
458*a9fa9459Szrj this_segment = stkl - size;
459*a9fa9459Szrj }
460*a9fa9459Szrj
461*a9fa9459Szrj result = address - this_segment;
462*a9fa9459Szrj
463*a9fa9459Szrj /* If you subtract pseg from the current end of the stack,
464*a9fa9459Szrj you get the address of the previous stack segment's end.
465*a9fa9459Szrj This seems a little convoluted to me, but I'll bet you save
466*a9fa9459Szrj a cycle somewhere. */
467*a9fa9459Szrj
468*a9fa9459Szrj while (pseg != 0)
469*a9fa9459Szrj {
470*a9fa9459Szrj #ifdef DEBUG_I00AFUNC
471*a9fa9459Szrj fprintf (stderr, "%011o %011o\n", pseg, size);
472*a9fa9459Szrj #endif
473*a9fa9459Szrj stkl = stkl - pseg;
474*a9fa9459Szrj ssptr = (struct stack_segment_linkage *) stkl;
475*a9fa9459Szrj size = ssptr->sssize;
476*a9fa9459Szrj pseg = ssptr->sspseg;
477*a9fa9459Szrj result += size;
478*a9fa9459Szrj }
479*a9fa9459Szrj return (result);
480*a9fa9459Szrj }
481*a9fa9459Szrj
482*a9fa9459Szrj #endif /* not CRAY2 */
483*a9fa9459Szrj #endif /* CRAY */
484