xref: /freebsd/usr.bin/gprof/dfn.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if 0
33 #endif
34 
35 #include <sys/cdefs.h>
36 #include <err.h>
37 #include "gprof.h"
38 
39 #define	DFN_DEPTH	100
40 struct dfnstruct {
41     nltype	*nlentryp;
42     int		cycletop;
43 };
44 typedef struct dfnstruct	dfntype;
45 
46 dfntype	dfn_stack[ DFN_DEPTH ];
47 int	dfn_depth;
48 
49 int	dfn_counter;
50 
51 void
52 dfn_init(void)
53 {
54 
55     dfn_depth = 0;
56     dfn_counter = DFN_NAN;
57 }
58 
59     /*
60      *	given this parent, depth first number its children.
61      */
62 void
63 dfn(nltype *parentp)
64 {
65     arctype	*arcp;
66 
67 #   ifdef DEBUG
68 	if ( debug & DFNDEBUG ) {
69 	    printf( "[dfn] dfn(" );
70 	    printname( parentp );
71 	    printf( ")\n" );
72 	}
73 #   endif /* DEBUG */
74 	/*
75 	 *	if we're already numbered, no need to look any further.
76 	 */
77     if ( dfn_numbered( parentp ) ) {
78 	return;
79     }
80 	/*
81 	 *	if we're already busy, must be a cycle
82 	 */
83     if ( dfn_busy( parentp ) ) {
84 	dfn_findcycle( parentp );
85 	return;
86     }
87 	/*
88 	 *	visit yourself before your children
89 	 */
90     dfn_pre_visit( parentp );
91 	/*
92 	 *	visit children
93 	 */
94     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
95 	    if ( arcp -> arc_flags & DEADARC )
96 		continue;
97 	    dfn( arcp -> arc_childp );
98     }
99 	/*
100 	 *	visit yourself after your children
101 	 */
102     dfn_post_visit( parentp );
103 }
104 
105     /*
106      *	push a parent onto the stack and mark it busy
107      */
108 void
109 dfn_pre_visit(nltype *parentp)
110 {
111 
112     dfn_depth += 1;
113     if ( dfn_depth >= DFN_DEPTH )
114 	errx( 1 , "[dfn] out of my depth (dfn_stack overflow)" );
115     dfn_stack[ dfn_depth ].nlentryp = parentp;
116     dfn_stack[ dfn_depth ].cycletop = dfn_depth;
117     parentp -> toporder = DFN_BUSY;
118 #   ifdef DEBUG
119 	if ( debug & DFNDEBUG ) {
120 	    printf( "[dfn_pre_visit]\t\t%d:" , dfn_depth );
121 	    printname( parentp );
122 	    printf( "\n" );
123 	}
124 #   endif /* DEBUG */
125 }
126 
127     /*
128      *	are we already numbered?
129      */
130 bool
131 dfn_numbered(nltype *childp)
132 {
133 
134     return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY );
135 }
136 
137     /*
138      *	are we already busy?
139      */
140 bool
141 dfn_busy(nltype *childp)
142 {
143 
144     if ( childp -> toporder == DFN_NAN ) {
145 	return FALSE;
146     }
147     return TRUE;
148 }
149 
150     /*
151      *	MISSING: an explanation
152      */
153 void
154 dfn_findcycle(nltype *childp)
155 {
156     int		cycletop;
157     nltype	*cycleheadp;
158     nltype	*tailp;
159     int		index;
160 
161     for ( cycletop = dfn_depth ; cycletop > 0 ; cycletop -= 1 ) {
162 	cycleheadp = dfn_stack[ cycletop ].nlentryp;
163 	if ( childp == cycleheadp ) {
164 	    break;
165 	}
166 	if ( childp -> cyclehead != childp &&
167 	    childp -> cyclehead == cycleheadp ) {
168 	    break;
169 	}
170     }
171     if ( cycletop <= 0 )
172 	errx( 1 , "[dfn_findcycle] couldn't find head of cycle" );
173 #   ifdef DEBUG
174 	if ( debug & DFNDEBUG ) {
175 	    printf( "[dfn_findcycle] dfn_depth %d cycletop %d " ,
176 		    dfn_depth , cycletop  );
177 	    printname( cycleheadp );
178 	    printf( "\n" );
179 	}
180 #   endif /* DEBUG */
181     if ( cycletop == dfn_depth ) {
182 	    /*
183 	     *	this is previous function, e.g. this calls itself
184 	     *	sort of boring
185 	     */
186 	dfn_self_cycle( childp );
187     } else {
188 	    /*
189 	     *	glom intervening functions that aren't already
190 	     *	glommed into this cycle.
191 	     *	things have been glommed when their cyclehead field
192 	     *	points to the head of the cycle they are glommed into.
193 	     */
194 	for ( tailp = cycleheadp ; tailp -> cnext ; tailp = tailp -> cnext ) {
195 	    /* void: chase down to tail of things already glommed */
196 #	    ifdef DEBUG
197 		if ( debug & DFNDEBUG ) {
198 		    printf( "[dfn_findcycle] tail " );
199 		    printname( tailp );
200 		    printf( "\n" );
201 		}
202 #	    endif /* DEBUG */
203 	}
204 	    /*
205 	     *	if what we think is the top of the cycle
206 	     *	has a cyclehead field, then it's not really the
207 	     *	head of the cycle, which is really what we want
208 	     */
209 	if ( cycleheadp -> cyclehead != cycleheadp ) {
210 	    cycleheadp = cycleheadp -> cyclehead;
211 #	    ifdef DEBUG
212 		if ( debug & DFNDEBUG ) {
213 		    printf( "[dfn_findcycle] new cyclehead " );
214 		    printname( cycleheadp );
215 		    printf( "\n" );
216 		}
217 #	    endif /* DEBUG */
218 	}
219 	for ( index = cycletop + 1 ; index <= dfn_depth ; index += 1 ) {
220 	    childp = dfn_stack[ index ].nlentryp;
221 	    if ( childp -> cyclehead == childp ) {
222 		    /*
223 		     *	not yet glommed anywhere, glom it
224 		     *	and fix any children it has glommed
225 		     */
226 		tailp -> cnext = childp;
227 		childp -> cyclehead = cycleheadp;
228 #		ifdef DEBUG
229 		    if ( debug & DFNDEBUG ) {
230 			printf( "[dfn_findcycle] glomming " );
231 			printname( childp );
232 			printf( " onto " );
233 			printname( cycleheadp );
234 			printf( "\n" );
235 		    }
236 #		endif /* DEBUG */
237 		for ( tailp = childp ; tailp->cnext ; tailp = tailp->cnext ) {
238 		    tailp -> cnext -> cyclehead = cycleheadp;
239 #		    ifdef DEBUG
240 			if ( debug & DFNDEBUG ) {
241 			    printf( "[dfn_findcycle] and its tail " );
242 			    printname( tailp -> cnext );
243 			    printf( " onto " );
244 			    printname( cycleheadp );
245 			    printf( "\n" );
246 			}
247 #		    endif /* DEBUG */
248 		}
249 	    } else if ( childp -> cyclehead != cycleheadp /* firewall */ ) {
250 		fprintf( stderr ,
251 			"[dfn_busy] glommed, but not to cyclehead\n" );
252 	    }
253 	}
254     }
255 }
256 
257     /*
258      *	deal with self-cycles
259      *	for lint: ARGSUSED
260      */
261 void
262 dfn_self_cycle(nltype *parentp)
263 {
264 	/*
265 	 *	since we are taking out self-cycles elsewhere
266 	 *	no need for the special case, here.
267 	 */
268 #   ifdef DEBUG
269 	if ( debug & DFNDEBUG ) {
270 	    printf( "[dfn_self_cycle] " );
271 	    printname( parentp );
272 	    printf( "\n" );
273 	}
274 #   endif /* DEBUG */
275 }
276 
277     /*
278      *	visit a node after all its children
279      *	[MISSING: an explanation]
280      *	and pop it off the stack
281      */
282 void
283 dfn_post_visit(nltype *parentp)
284 {
285     nltype	*memberp;
286 
287 #   ifdef DEBUG
288 	if ( debug & DFNDEBUG ) {
289 	    printf( "[dfn_post_visit]\t%d: " , dfn_depth );
290 	    printname( parentp );
291 	    printf( "\n" );
292 	}
293 #   endif /* DEBUG */
294 	/*
295 	 *	number functions and things in their cycles
296 	 *	unless the function is itself part of a cycle
297 	 */
298     if ( parentp -> cyclehead == parentp ) {
299 	dfn_counter += 1;
300 	for ( memberp = parentp ; memberp ; memberp = memberp -> cnext ) {
301 	    memberp -> toporder = dfn_counter;
302 #	    ifdef DEBUG
303 		if ( debug & DFNDEBUG ) {
304 		    printf( "[dfn_post_visit]\t\tmember " );
305 		    printname( memberp );
306 		    printf( " -> toporder = %d\n" , dfn_counter );
307 		}
308 #	    endif /* DEBUG */
309 	}
310     } else {
311 #	ifdef DEBUG
312 	    if ( debug & DFNDEBUG ) {
313 		printf( "[dfn_post_visit]\t\tis part of a cycle\n" );
314 	    }
315 #	endif /* DEBUG */
316     }
317     dfn_depth -= 1;
318 }
319