17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*92ed1782Smike_s 237c478bd9Sstevel@tonic-gate /* 24*92ed1782Smike_s * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*92ed1782Smike_s * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include "gprof.h" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #define DFN_DEPTH 100 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate struct dfnstruct { 367c478bd9Sstevel@tonic-gate nltype *nlentryp; 377c478bd9Sstevel@tonic-gate int cycletop; 387c478bd9Sstevel@tonic-gate }; 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate typedef struct dfnstruct dfntype; 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate dfntype *dfn_stack = NULL; 437c478bd9Sstevel@tonic-gate int dfn_depth = 0; 447c478bd9Sstevel@tonic-gate int dfn_sz = 0; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate int dfn_counter = DFN_NAN; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * given this parent, depth first number its children. 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate void 527c478bd9Sstevel@tonic-gate dfn(nltype *parentp) 537c478bd9Sstevel@tonic-gate { 547c478bd9Sstevel@tonic-gate arctype *arcp; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #ifdef DEBUG 577c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 58*92ed1782Smike_s (void) printf("[dfn] dfn("); 597c478bd9Sstevel@tonic-gate printname(parentp); 60*92ed1782Smike_s (void) printf(")\n"); 617c478bd9Sstevel@tonic-gate } 627c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate if (!dfn_stack) { 657c478bd9Sstevel@tonic-gate dfn_sz = DFN_DEPTH; 667c478bd9Sstevel@tonic-gate dfn_stack = (dfntype *) malloc(dfn_sz * sizeof (dfntype)); 677c478bd9Sstevel@tonic-gate if (!dfn_stack) { 68*92ed1782Smike_s (void) fprintf(stderr, 697c478bd9Sstevel@tonic-gate "fatal: can't malloc %d objects\n", dfn_sz); 707c478bd9Sstevel@tonic-gate exit(1); 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * if we're already numbered, no need to look any furthur. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate if (dfn_numbered(parentp)) 787c478bd9Sstevel@tonic-gate return; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * if we're already busy, must be a cycle 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate if (dfn_busy(parentp)) { 847c478bd9Sstevel@tonic-gate dfn_findcycle(parentp); 857c478bd9Sstevel@tonic-gate return; 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * visit yourself before your children 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate dfn_pre_visit(parentp); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * visit children 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) 977c478bd9Sstevel@tonic-gate dfn(arcp->arc_childp); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * visit yourself after your children 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate dfn_post_visit(parentp); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * push a parent onto the stack and mark it busy 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate void 1097c478bd9Sstevel@tonic-gate dfn_pre_visit(nltype *parentp) 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate if (!dfn_stack) { 1137c478bd9Sstevel@tonic-gate dfn_sz = DFN_DEPTH; 1147c478bd9Sstevel@tonic-gate dfn_stack = (dfntype *) malloc(dfn_sz * sizeof (dfntype)); 1157c478bd9Sstevel@tonic-gate if (!dfn_stack) { 116*92ed1782Smike_s (void) printf("fatal: can't malloc %d objects\n", 117*92ed1782Smike_s dfn_sz); 1187c478bd9Sstevel@tonic-gate exit(1); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate dfn_depth += 1; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (dfn_depth >= dfn_sz) { 1257c478bd9Sstevel@tonic-gate dfn_sz += DFN_DEPTH; 1267c478bd9Sstevel@tonic-gate dfn_stack = (dfntype *) realloc(dfn_stack, 1277c478bd9Sstevel@tonic-gate dfn_sz * sizeof (dfntype)); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate if (!dfn_stack) { 130*92ed1782Smike_s (void) fprintf(stderr, 1317c478bd9Sstevel@tonic-gate "fatal: can't realloc %d objects\n", dfn_sz); 1327c478bd9Sstevel@tonic-gate exit(1); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate dfn_stack[dfn_depth].nlentryp = parentp; 1377c478bd9Sstevel@tonic-gate dfn_stack[dfn_depth].cycletop = dfn_depth; 1387c478bd9Sstevel@tonic-gate parentp->toporder = DFN_BUSY; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate #ifdef DEBUG 1417c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 142*92ed1782Smike_s (void) printf("[dfn_pre_visit]\t\t%d:", dfn_depth); 1437c478bd9Sstevel@tonic-gate printname(parentp); 144*92ed1782Smike_s (void) printf("\n"); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * are we already numbered? 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate bool 1537c478bd9Sstevel@tonic-gate dfn_numbered(nltype *childp) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate return (childp->toporder != DFN_NAN && childp->toporder != DFN_BUSY); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * are we already busy? 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate bool 1627c478bd9Sstevel@tonic-gate dfn_busy(nltype *childp) 1637c478bd9Sstevel@tonic-gate { 1647c478bd9Sstevel@tonic-gate if (childp->toporder == DFN_NAN) 1657c478bd9Sstevel@tonic-gate return (FALSE); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate return (TRUE); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate void 1717c478bd9Sstevel@tonic-gate dfn_findcycle(nltype *childp) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate int cycletop; 1747c478bd9Sstevel@tonic-gate nltype *cycleheadp; 1757c478bd9Sstevel@tonic-gate nltype *tailp; 1767c478bd9Sstevel@tonic-gate int index; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate for (cycletop = dfn_depth; cycletop > 0; cycletop -= 1) { 1797c478bd9Sstevel@tonic-gate cycleheadp = dfn_stack[cycletop].nlentryp; 1807c478bd9Sstevel@tonic-gate if (childp == cycleheadp) 1817c478bd9Sstevel@tonic-gate break; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (childp->cyclehead != childp && 1847c478bd9Sstevel@tonic-gate childp->cyclehead == cycleheadp) 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (cycletop <= 0) { 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * don't report non existent functions 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate if (childp->value) { 193*92ed1782Smike_s (void) fprintf(stderr, 194*92ed1782Smike_s "[dfn_findcycle] couldn't find head " 1957c478bd9Sstevel@tonic-gate "of cycle for %s\n", childp->name); 1967c478bd9Sstevel@tonic-gate return; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate #ifdef DEBUG 2017c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 202*92ed1782Smike_s (void) printf("[dfn_findcycle] dfn_depth %d cycletop %d ", 2037c478bd9Sstevel@tonic-gate dfn_depth, cycletop); 2047c478bd9Sstevel@tonic-gate printname(cycleheadp); 205*92ed1782Smike_s (void) printf("\n"); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (cycletop == dfn_depth) { 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * this is previous function, e.g. this calls itself 2127c478bd9Sstevel@tonic-gate * sort of boring 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate dfn_self_cycle(childp); 2157c478bd9Sstevel@tonic-gate } else { 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * glom intervening functions that aren't already 2187c478bd9Sstevel@tonic-gate * glommed into this cycle. 2197c478bd9Sstevel@tonic-gate * things have been glommed when their cyclehead field 2207c478bd9Sstevel@tonic-gate * points to the head of the cycle they are glommed into. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate for (tailp = cycleheadp; tailp->cnext; tailp = tailp->cnext) { 2237c478bd9Sstevel@tonic-gate /* void: chase down to tail of things already glommed */ 2247c478bd9Sstevel@tonic-gate #ifdef DEBUG 2257c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 226*92ed1782Smike_s (void) printf("[dfn_findcycle] tail "); 2277c478bd9Sstevel@tonic-gate printname(tailp); 228*92ed1782Smike_s (void) printf("\n"); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * if what we think is the top of the cycle 2357c478bd9Sstevel@tonic-gate * has a cyclehead field, then it's not really the 2367c478bd9Sstevel@tonic-gate * head of the cycle, which is really what we want 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate if (cycleheadp->cyclehead != cycleheadp) { 2397c478bd9Sstevel@tonic-gate cycleheadp = cycleheadp->cyclehead; 2407c478bd9Sstevel@tonic-gate #ifdef DEBUG 2417c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 242*92ed1782Smike_s (void) printf("[dfn_findcycle] new cyclehead "); 2437c478bd9Sstevel@tonic-gate printname(cycleheadp); 244*92ed1782Smike_s (void) printf("\n"); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate for (index = cycletop + 1; index <= dfn_depth; index += 1) { 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate childp = dfn_stack[index].nlentryp; 2527c478bd9Sstevel@tonic-gate if (childp->cyclehead == childp) { 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * not yet glommed anywhere, glom it 2557c478bd9Sstevel@tonic-gate * and fix any children it has glommed 2567c478bd9Sstevel@tonic-gate */ 2577c478bd9Sstevel@tonic-gate tailp->cnext = childp; 2587c478bd9Sstevel@tonic-gate childp->cyclehead = cycleheadp; 2597c478bd9Sstevel@tonic-gate #ifdef DEBUG 2607c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 261*92ed1782Smike_s (void) printf( 262*92ed1782Smike_s "[dfn_findcycle] glomming "); 2637c478bd9Sstevel@tonic-gate printname(childp); 264*92ed1782Smike_s (void) printf(" onto "); 2657c478bd9Sstevel@tonic-gate printname(cycleheadp); 266*92ed1782Smike_s (void) printf("\n"); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2697c478bd9Sstevel@tonic-gate for (tailp = childp; tailp->cnext; 2707c478bd9Sstevel@tonic-gate tailp = tailp->cnext) { 2717c478bd9Sstevel@tonic-gate tailp->cnext->cyclehead = cycleheadp; 2727c478bd9Sstevel@tonic-gate #ifdef DEBUG 2737c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 274*92ed1782Smike_s (void) printf("[dfn_findcycle]" 2757c478bd9Sstevel@tonic-gate " and its tail "); 2767c478bd9Sstevel@tonic-gate printname(tailp->cnext); 277*92ed1782Smike_s (void) printf(" onto "); 2787c478bd9Sstevel@tonic-gate printname(cycleheadp); 279*92ed1782Smike_s (void) printf("\n"); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate } else if (childp->cyclehead != cycleheadp) { 284*92ed1782Smike_s (void) fprintf(stderr, "[dfn_busy] glommed," 2857c478bd9Sstevel@tonic-gate " but not to cyclehead\n"); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * deal with self-cycles 2937c478bd9Sstevel@tonic-gate * for lint: ARGSUSED 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2967c478bd9Sstevel@tonic-gate void 2977c478bd9Sstevel@tonic-gate dfn_self_cycle(nltype *parentp) 2987c478bd9Sstevel@tonic-gate { 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate * since we are taking out self-cycles elsewhere 3017c478bd9Sstevel@tonic-gate * no need for the special case, here. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate #ifdef DEBUG 3047c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 305*92ed1782Smike_s (void) printf("[dfn_self_cycle] "); 3067c478bd9Sstevel@tonic-gate printname(parentp); 307*92ed1782Smike_s (void) printf("\n"); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * visit a node after all its children 3147c478bd9Sstevel@tonic-gate * [MISSING: an explanation] 3157c478bd9Sstevel@tonic-gate * and pop it off the stack 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate void 3187c478bd9Sstevel@tonic-gate dfn_post_visit(nltype *parentp) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate nltype *memberp; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate #ifdef DEBUG 3237c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 324*92ed1782Smike_s (void) printf("[dfn_post_visit]\t%d: ", dfn_depth); 3257c478bd9Sstevel@tonic-gate printname(parentp); 326*92ed1782Smike_s (void) printf("\n"); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * number functions and things in their cycles 3317c478bd9Sstevel@tonic-gate * unless the function is itself part of a cycle 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate if (parentp->cyclehead == parentp) { 3347c478bd9Sstevel@tonic-gate dfn_counter += 1; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate for (memberp = parentp; memberp; memberp = memberp->cnext) { 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate memberp->toporder = dfn_counter; 3397c478bd9Sstevel@tonic-gate #ifdef DEBUG 3407c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) { 341*92ed1782Smike_s (void) printf("[dfn_post_visit]\t\tmember "); 3427c478bd9Sstevel@tonic-gate printname(memberp); 343*92ed1782Smike_s (void) printf(" -> toporder = %d\n", 344*92ed1782Smike_s dfn_counter); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate #ifdef DEBUG 3497c478bd9Sstevel@tonic-gate } else { 3507c478bd9Sstevel@tonic-gate if (debug & DFNDEBUG) 351*92ed1782Smike_s (void) printf( 352*92ed1782Smike_s "[dfn_post_visit]\t\tis part of a cycle\n"); 3537c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate dfn_depth -= 1; 3567c478bd9Sstevel@tonic-gate } 357