1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright (c) 1990-1998 by Sun Microsystems, Inc. 24*0Sstevel@tonic-gate * All rights reserved. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <ctype.h> 30*0Sstevel@tonic-gate #include <string.h> 31*0Sstevel@tonic-gate #include <sys/param.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include "gprof.h" 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate extern int find_run_directory(char *, char *, char *, char **, char *); 36*0Sstevel@tonic-gate void print_demangled_name(int, nltype *); 37*0Sstevel@tonic-gate void striped_name(char *, nltype **); 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate extern char *demangle(); 41*0Sstevel@tonic-gate char *strstr(); 42*0Sstevel@tonic-gate char *parsename(); 43*0Sstevel@tonic-gate char name_buffer[512]; 44*0Sstevel@tonic-gate extern long hz; 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * Symbols that must never be printed, no matter what. 48*0Sstevel@tonic-gate */ 49*0Sstevel@tonic-gate char *splsym[] = { 50*0Sstevel@tonic-gate PRF_ETEXT, 51*0Sstevel@tonic-gate PRF_EXTSYM, 52*0Sstevel@tonic-gate PRF_MEMTERM, 53*0Sstevel@tonic-gate 0 54*0Sstevel@tonic-gate }; 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate char * 57*0Sstevel@tonic-gate demangled_name(nltype *selfp) 58*0Sstevel@tonic-gate { 59*0Sstevel@tonic-gate char *name; 60*0Sstevel@tonic-gate if (!Cflag) 61*0Sstevel@tonic-gate return (selfp->name); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate name = (char *) sgs_demangle(selfp->name); 64*0Sstevel@tonic-gate return (name); 65*0Sstevel@tonic-gate } 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate void 68*0Sstevel@tonic-gate printprof() 69*0Sstevel@tonic-gate { 70*0Sstevel@tonic-gate nltype *np; 71*0Sstevel@tonic-gate nltype **sortednlp; 72*0Sstevel@tonic-gate int i, index; 73*0Sstevel@tonic-gate int print_count = number_funcs_toprint; 74*0Sstevel@tonic-gate bool print_flag = TRUE; 75*0Sstevel@tonic-gate mod_info_t *mi; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate actime = 0.0; 78*0Sstevel@tonic-gate printf("\f\n"); 79*0Sstevel@tonic-gate flatprofheader(); 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate /* 82*0Sstevel@tonic-gate * Sort the symbol table in by time 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate sortednlp = (nltype **) calloc(total_names, sizeof (nltype *)); 85*0Sstevel@tonic-gate if (sortednlp == (nltype **) 0) { 86*0Sstevel@tonic-gate fprintf(stderr, 87*0Sstevel@tonic-gate "[printprof] ran out of memory for time sorting\n"); 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate index = 0; 91*0Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 92*0Sstevel@tonic-gate for (i = 0; i < mi->nname; i++) 93*0Sstevel@tonic-gate sortednlp[index++] = &(mi->nl[i]); 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate qsort(sortednlp, total_names, sizeof (nltype *), 97*0Sstevel@tonic-gate (int(*)(const void *, const void *))timecmp); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate for (index = 0; (index < total_names) && print_flag; index += 1) { 100*0Sstevel@tonic-gate np = sortednlp[index]; 101*0Sstevel@tonic-gate flatprofline(np); 102*0Sstevel@tonic-gate if (nflag) { 103*0Sstevel@tonic-gate if (--print_count == 0) 104*0Sstevel@tonic-gate print_flag = FALSE; 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate actime = 0.0; 108*0Sstevel@tonic-gate free(sortednlp); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate int 112*0Sstevel@tonic-gate timecmp(nltype **npp1, nltype **npp2) 113*0Sstevel@tonic-gate { 114*0Sstevel@tonic-gate double timediff; 115*0Sstevel@tonic-gate long calldiff; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate timediff = (*npp2)->time - (*npp1)->time; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if (timediff > 0.0) 120*0Sstevel@tonic-gate return (1); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate if (timediff < 0.0) 123*0Sstevel@tonic-gate return (-1); 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate calldiff = (*npp2)->ncall - (*npp1)->ncall; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if (calldiff > 0) 128*0Sstevel@tonic-gate return (1); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate if (calldiff < 0) 131*0Sstevel@tonic-gate return (-1); 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate return (strcmp((*npp1)->name, (*npp2)->name)); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * header for flatprofline 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate void 140*0Sstevel@tonic-gate flatprofheader() 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate if (bflag) 144*0Sstevel@tonic-gate printblurb(FLAT_BLURB); 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (old_style) { 147*0Sstevel@tonic-gate printf("\ngranularity: each sample hit covers %d byte(s)", 148*0Sstevel@tonic-gate (long)scale * sizeof (UNIT)); 149*0Sstevel@tonic-gate if (totime > 0.0) { 150*0Sstevel@tonic-gate printf(" for %.2f%% of %.2f seconds\n\n", 151*0Sstevel@tonic-gate 100.0/totime, totime / hz); 152*0Sstevel@tonic-gate } else { 153*0Sstevel@tonic-gate printf(" no time accumulated\n\n"); 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * this doesn't hurt since all the numerators will 156*0Sstevel@tonic-gate * be zero. 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate totime = 1.0; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", 163*0Sstevel@tonic-gate "% ", "cumulative", "self ", "", "self ", "total ", ""); 164*0Sstevel@tonic-gate printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n", 165*0Sstevel@tonic-gate "time", "seconds ", "seconds", "calls", 166*0Sstevel@tonic-gate "ms/call", "ms/call", "name"); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate void 170*0Sstevel@tonic-gate flatprofline(nltype *np) 171*0Sstevel@tonic-gate { 172*0Sstevel@tonic-gate if (zflag == 0 && np->ncall == 0 && np->time == 0) 173*0Sstevel@tonic-gate return; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* 176*0Sstevel@tonic-gate * Do not print certain special symbols, like PRF_EXTSYM, etc. 177*0Sstevel@tonic-gate * even if zflag was on. 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate if (is_special_sym(np)) 180*0Sstevel@tonic-gate return; 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate actime += np->time; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate printf("%5.1f %10.2f %8.2f", 185*0Sstevel@tonic-gate 100 * np->time / totime, actime / hz, np->time / hz); 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate if (np->ncall != 0) { 188*0Sstevel@tonic-gate printf(" %8lld %8.2f %8.2f ", np->ncall, 189*0Sstevel@tonic-gate 1000 * np->time / hz / np->ncall, 190*0Sstevel@tonic-gate 1000 * (np->time + np->childtime) / hz / np->ncall); 191*0Sstevel@tonic-gate } else { 192*0Sstevel@tonic-gate if (!Cflag) 193*0Sstevel@tonic-gate printf(" %8.8s %8.8s %8.8s ", "", "", ""); 194*0Sstevel@tonic-gate else 195*0Sstevel@tonic-gate printf(" %8.8s %8.8s %8.8s ", "", "", ""); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate printname(np); 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if (Cflag) 201*0Sstevel@tonic-gate print_demangled_name(55, np); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate printf("\n"); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate void 207*0Sstevel@tonic-gate gprofheader() 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate if (bflag) 211*0Sstevel@tonic-gate printblurb(CALLG_BLURB); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate if (old_style) { 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate printf("\ngranularity: each sample hit covers %d byte(s)", 216*0Sstevel@tonic-gate (long)scale * sizeof (UNIT)); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate if (printtime > 0.0) { 219*0Sstevel@tonic-gate printf(" for %.2f%% of %.2f seconds\n\n", 220*0Sstevel@tonic-gate 100.0/printtime, printtime / hz); 221*0Sstevel@tonic-gate } else { 222*0Sstevel@tonic-gate printf(" no time propagated\n\n"); 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * this doesn't hurt, since all the numerators 225*0Sstevel@tonic-gate * will be 0.0 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate printtime = 1.0; 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate } else { 230*0Sstevel@tonic-gate printf("\ngranularity: each pc-hit is considered 1 tick"); 231*0Sstevel@tonic-gate if (hz != 1) { 232*0Sstevel@tonic-gate printf(" (@ %4.3f seconds per tick)", 233*0Sstevel@tonic-gate (double) 1.0 / hz); 234*0Sstevel@tonic-gate } 235*0Sstevel@tonic-gate puts("\n\n"); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", 239*0Sstevel@tonic-gate "", "", "", "", "called", "total", "parents"); 240*0Sstevel@tonic-gate printf("%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n", 241*0Sstevel@tonic-gate "index", "%time", "self", "descendents", 242*0Sstevel@tonic-gate "called", "self", "name", "index"); 243*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n", 244*0Sstevel@tonic-gate "", "", "", "", "called", "total", "children"); 245*0Sstevel@tonic-gate printf("\n"); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate void 249*0Sstevel@tonic-gate gprofline(nltype *np) 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate char kirkbuffer[BUFSIZ]; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate sprintf(kirkbuffer, "[%d]", np->index); 254*0Sstevel@tonic-gate printf("%-6.6s %5.1f %7.2f %11.2f", kirkbuffer, 255*0Sstevel@tonic-gate 100 * (np->propself + np->propchild) / printtime, 256*0Sstevel@tonic-gate np->propself / hz, np->propchild / hz); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if ((np->ncall + np->selfcalls) != 0) { 259*0Sstevel@tonic-gate printf(" %7lld", np->ncall); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate if (np->selfcalls != 0) 262*0Sstevel@tonic-gate printf("+%-7lld ", np->selfcalls); 263*0Sstevel@tonic-gate else 264*0Sstevel@tonic-gate printf(" %7.7s ", ""); 265*0Sstevel@tonic-gate } else { 266*0Sstevel@tonic-gate printf(" %7.7s %7.7s ", "", ""); 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate printname(np); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if (Cflag) 272*0Sstevel@tonic-gate print_demangled_name(50, np); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate printf("\n"); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate static bool 278*0Sstevel@tonic-gate is_special_sym(nltype *nlp) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate int i; 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (nlp->name == NULL) 283*0Sstevel@tonic-gate return (FALSE); 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate for (i = 0; splsym[i]; i++) 286*0Sstevel@tonic-gate if (strcmp(splsym[i], nlp->name) == 0) 287*0Sstevel@tonic-gate return (TRUE); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate return (FALSE); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate void 293*0Sstevel@tonic-gate printgprof(nltype **timesortnlp) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate int index; 296*0Sstevel@tonic-gate nltype *parentp; 297*0Sstevel@tonic-gate int print_count = number_funcs_toprint; 298*0Sstevel@tonic-gate bool count_flag = TRUE; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Print out the structured profiling list 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate gprofheader(); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate for (index = 0; index < total_names + ncycle && count_flag; index++) { 306*0Sstevel@tonic-gate parentp = timesortnlp[index]; 307*0Sstevel@tonic-gate if (zflag == 0 && parentp->ncall == 0 && 308*0Sstevel@tonic-gate parentp->selfcalls == 0 && parentp->propself == 0 && 309*0Sstevel@tonic-gate parentp -> propchild == 0) 310*0Sstevel@tonic-gate continue; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (!parentp->printflag) 313*0Sstevel@tonic-gate continue; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * Do not print certain special symbols, like PRF_EXTSYM, etc. 317*0Sstevel@tonic-gate * even if zflag was on. 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate if (is_special_sym(parentp)) 320*0Sstevel@tonic-gate continue; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate if (parentp->name == 0 && parentp->cycleno != 0) { 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * cycle header 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate printcycle(parentp); 327*0Sstevel@tonic-gate printmembers(parentp); 328*0Sstevel@tonic-gate } else { 329*0Sstevel@tonic-gate printparents(parentp); 330*0Sstevel@tonic-gate gprofline(parentp); 331*0Sstevel@tonic-gate printchildren(parentp); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate printf("\n"); 335*0Sstevel@tonic-gate printf("-----------------------------------------------\n"); 336*0Sstevel@tonic-gate printf("\n"); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate if (nflag) { 339*0Sstevel@tonic-gate --print_count; 340*0Sstevel@tonic-gate if (print_count == 0) 341*0Sstevel@tonic-gate count_flag = FALSE; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate free(timesortnlp); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* 348*0Sstevel@tonic-gate * sort by decreasing propagated time 349*0Sstevel@tonic-gate * if times are equal, but one is a cycle header, 350*0Sstevel@tonic-gate * say that's first (e.g. less, i.e. -1). 351*0Sstevel@tonic-gate * if one's name doesn't have an underscore and the other does, 352*0Sstevel@tonic-gate * say the one is first. 353*0Sstevel@tonic-gate * all else being equal, sort by names. 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate int 356*0Sstevel@tonic-gate totalcmp(nltype **npp1, nltype **npp2) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate nltype *np1 = *npp1; 359*0Sstevel@tonic-gate nltype *np2 = *npp2; 360*0Sstevel@tonic-gate double diff; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate diff = (np1->propself + np1->propchild) - 363*0Sstevel@tonic-gate (np2->propself + np2->propchild); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (diff < 0.0) 366*0Sstevel@tonic-gate return (1); 367*0Sstevel@tonic-gate if (diff > 0.0) 368*0Sstevel@tonic-gate return (-1); 369*0Sstevel@tonic-gate if (np1->name == 0 && np1->cycleno != 0) 370*0Sstevel@tonic-gate return (-1); 371*0Sstevel@tonic-gate if (np2->name == 0 && np2->cycleno != 0) 372*0Sstevel@tonic-gate return (1); 373*0Sstevel@tonic-gate if (np1->name == 0) 374*0Sstevel@tonic-gate return (-1); 375*0Sstevel@tonic-gate if (np2->name == 0) 376*0Sstevel@tonic-gate return (1); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate if (*(np1->name) != '_' && *(np2->name) == '_') 379*0Sstevel@tonic-gate return (-1); 380*0Sstevel@tonic-gate if (*(np1->name) == '_' && *(np2->name) != '_') 381*0Sstevel@tonic-gate return (1); 382*0Sstevel@tonic-gate if (np1->ncall > np2->ncall) 383*0Sstevel@tonic-gate return (-1); 384*0Sstevel@tonic-gate if (np1->ncall < np2->ncall) 385*0Sstevel@tonic-gate return (1); 386*0Sstevel@tonic-gate return (strcmp(np1->name, np2->name)); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate void 390*0Sstevel@tonic-gate printparents(nltype *childp) 391*0Sstevel@tonic-gate { 392*0Sstevel@tonic-gate nltype *parentp; 393*0Sstevel@tonic-gate arctype *arcp; 394*0Sstevel@tonic-gate nltype *cycleheadp; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate if (childp->cyclehead != 0) 397*0Sstevel@tonic-gate cycleheadp = childp -> cyclehead; 398*0Sstevel@tonic-gate else 399*0Sstevel@tonic-gate cycleheadp = childp; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate if (childp->parents == 0) { 402*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s" 403*0Sstevel@tonic-gate " <spontaneous>\n", "", "", "", "", "", ""); 404*0Sstevel@tonic-gate return; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate sortparents(childp); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate for (arcp = childp->parents; arcp; arcp = arcp->arc_parentlist) { 410*0Sstevel@tonic-gate parentp = arcp -> arc_parentp; 411*0Sstevel@tonic-gate if (childp == parentp || (childp->cycleno != 0 && 412*0Sstevel@tonic-gate parentp->cycleno == childp->cycleno)) { 413*0Sstevel@tonic-gate /* 414*0Sstevel@tonic-gate * selfcall or call among siblings 415*0Sstevel@tonic-gate */ 416*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ", 417*0Sstevel@tonic-gate "", "", "", "", arcp->arc_count, ""); 418*0Sstevel@tonic-gate printname(parentp); 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate if (Cflag) 421*0Sstevel@tonic-gate print_demangled_name(54, parentp); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate printf("\n"); 424*0Sstevel@tonic-gate } else { 425*0Sstevel@tonic-gate /* 426*0Sstevel@tonic-gate * regular parent of child 427*0Sstevel@tonic-gate */ 428*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.2f %11.2f %7lld/%-7lld ", "", 429*0Sstevel@tonic-gate "", arcp->arc_time / hz, arcp->arc_childtime / hz, 430*0Sstevel@tonic-gate arcp->arc_count, cycleheadp->ncall); 431*0Sstevel@tonic-gate printname(parentp); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if (Cflag) 434*0Sstevel@tonic-gate print_demangled_name(54, parentp); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate printf("\n"); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate void 442*0Sstevel@tonic-gate printchildren(nltype *parentp) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate nltype *childp; 445*0Sstevel@tonic-gate arctype *arcp; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate sortchildren(parentp); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate for (arcp = parentp->children; arcp; arcp = arcp->arc_childlist) { 450*0Sstevel@tonic-gate childp = arcp->arc_childp; 451*0Sstevel@tonic-gate if (childp == parentp || (childp->cycleno != 0 && 452*0Sstevel@tonic-gate childp->cycleno == parentp->cycleno)) { 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * self call or call to sibling 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.7s %11.11s %7lld %7.7s ", 457*0Sstevel@tonic-gate "", "", "", "", arcp->arc_count, ""); 458*0Sstevel@tonic-gate printname(childp); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (Cflag) 461*0Sstevel@tonic-gate print_demangled_name(54, childp); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate printf("\n"); 464*0Sstevel@tonic-gate } else { 465*0Sstevel@tonic-gate /* 466*0Sstevel@tonic-gate * regular child of parent 467*0Sstevel@tonic-gate */ 468*0Sstevel@tonic-gate if (childp->cyclehead) 469*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.2f %11.2f " 470*0Sstevel@tonic-gate "%7lld/%-7lld ", "", "", 471*0Sstevel@tonic-gate arcp->arc_time / hz, 472*0Sstevel@tonic-gate arcp->arc_childtime / hz, arcp->arc_count, 473*0Sstevel@tonic-gate childp->cyclehead->ncall); 474*0Sstevel@tonic-gate else 475*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.2f %11.2f " 476*0Sstevel@tonic-gate "%7lld %7.7s ", 477*0Sstevel@tonic-gate "", "", arcp->arc_time / hz, 478*0Sstevel@tonic-gate arcp->arc_childtime / hz, arcp->arc_count, 479*0Sstevel@tonic-gate ""); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate printname(childp); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if (Cflag) 484*0Sstevel@tonic-gate print_demangled_name(54, childp); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate printf("\n"); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate void 492*0Sstevel@tonic-gate printname(nltype *selfp) 493*0Sstevel@tonic-gate { 494*0Sstevel@tonic-gate char *c; 495*0Sstevel@tonic-gate c = demangled_name(selfp); 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate if (selfp->name != 0) { 498*0Sstevel@tonic-gate if (!Cflag) 499*0Sstevel@tonic-gate printf("%s", selfp->name); 500*0Sstevel@tonic-gate else 501*0Sstevel@tonic-gate printf("%s", c); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate #ifdef DEBUG 504*0Sstevel@tonic-gate if (debug & DFNDEBUG) 505*0Sstevel@tonic-gate printf("{%d} ", selfp->toporder); 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate if (debug & PROPDEBUG) 508*0Sstevel@tonic-gate printf("%5.2f%% ", selfp->propfraction); 509*0Sstevel@tonic-gate #endif DEBUG 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if (selfp->cycleno != 0) 513*0Sstevel@tonic-gate printf("\t<cycle %d>", selfp->cycleno); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate if (selfp->index != 0) { 516*0Sstevel@tonic-gate if (selfp->printflag) 517*0Sstevel@tonic-gate printf(" [%d]", selfp->index); 518*0Sstevel@tonic-gate else 519*0Sstevel@tonic-gate printf(" (%d)", selfp->index); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate void 524*0Sstevel@tonic-gate print_demangled_name(int n, nltype *selfp) 525*0Sstevel@tonic-gate { 526*0Sstevel@tonic-gate char *c; 527*0Sstevel@tonic-gate int i; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate c = selfp->name; 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate if (strcmp(c, demangled_name(selfp)) == 0) 532*0Sstevel@tonic-gate return; 533*0Sstevel@tonic-gate else { 534*0Sstevel@tonic-gate printf("\n"); 535*0Sstevel@tonic-gate for (i = 1; i < n; i++) 536*0Sstevel@tonic-gate printf(" "); 537*0Sstevel@tonic-gate printf("[%s]", selfp->name); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate char *exotic(); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate void 544*0Sstevel@tonic-gate sortchildren(nltype *parentp) 545*0Sstevel@tonic-gate { 546*0Sstevel@tonic-gate arctype *arcp; 547*0Sstevel@tonic-gate arctype *detachedp; 548*0Sstevel@tonic-gate arctype sorted; 549*0Sstevel@tonic-gate arctype *prevp; 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate /* 552*0Sstevel@tonic-gate * unlink children from parent, 553*0Sstevel@tonic-gate * then insertion sort back on to sorted's children. 554*0Sstevel@tonic-gate * *arcp the arc you have detached and are inserting. 555*0Sstevel@tonic-gate * *detachedp the rest of the arcs to be sorted. 556*0Sstevel@tonic-gate * sorted arc list onto which you insertion sort. 557*0Sstevel@tonic-gate * *prevp arc before the arc you are comparing. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate sorted.arc_childlist = 0; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate for ((arcp = parentp->children) && (detachedp = arcp->arc_childlist); 562*0Sstevel@tonic-gate arcp; 563*0Sstevel@tonic-gate (arcp = detachedp) && (detachedp = detachedp->arc_childlist)) { 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * consider *arcp as disconnected 566*0Sstevel@tonic-gate * insert it into sorted 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate for (prevp = &sorted; prevp->arc_childlist; 569*0Sstevel@tonic-gate prevp = prevp->arc_childlist) { 570*0Sstevel@tonic-gate if (arccmp(arcp, prevp->arc_childlist) != LESSTHAN) 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate arcp->arc_childlist = prevp->arc_childlist; 575*0Sstevel@tonic-gate prevp->arc_childlist = arcp; 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* 579*0Sstevel@tonic-gate * reattach sorted children to parent 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate parentp->children = sorted.arc_childlist; 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate void 585*0Sstevel@tonic-gate sortparents(nltype *childp) 586*0Sstevel@tonic-gate { 587*0Sstevel@tonic-gate arctype *arcp; 588*0Sstevel@tonic-gate arctype *detachedp; 589*0Sstevel@tonic-gate arctype sorted; 590*0Sstevel@tonic-gate arctype *prevp; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * unlink parents from child, 594*0Sstevel@tonic-gate * then insertion sort back on to sorted's parents. 595*0Sstevel@tonic-gate * *arcp the arc you have detached and are inserting. 596*0Sstevel@tonic-gate * *detachedp the rest of the arcs to be sorted. 597*0Sstevel@tonic-gate * sorted arc list onto which you insertion sort. 598*0Sstevel@tonic-gate * *prevp arc before the arc you are comparing. 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate sorted.arc_parentlist = 0; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate for ((arcp = childp->parents) && (detachedp = arcp->arc_parentlist); 603*0Sstevel@tonic-gate arcp; 604*0Sstevel@tonic-gate (arcp = detachedp) && (detachedp = detachedp->arc_parentlist)) { 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * consider *arcp as disconnected 607*0Sstevel@tonic-gate * insert it into sorted 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate for (prevp = &sorted; prevp->arc_parentlist; 610*0Sstevel@tonic-gate prevp = prevp->arc_parentlist) { 611*0Sstevel@tonic-gate if (arccmp(arcp, prevp->arc_parentlist) != GREATERTHAN) 612*0Sstevel@tonic-gate break; 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate arcp->arc_parentlist = prevp->arc_parentlist; 615*0Sstevel@tonic-gate prevp->arc_parentlist = arcp; 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * reattach sorted arcs to child 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate childp->parents = sorted.arc_parentlist; 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate void 625*0Sstevel@tonic-gate printcycle(nltype *cyclep) 626*0Sstevel@tonic-gate { 627*0Sstevel@tonic-gate char kirkbuffer[BUFSIZ]; 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate sprintf(kirkbuffer, "[%d]", cyclep->index); 630*0Sstevel@tonic-gate printf("%-6.6s %5.1f %7.2f %11.2f %7lld", kirkbuffer, 631*0Sstevel@tonic-gate 100 * (cyclep->propself + cyclep->propchild) / printtime, 632*0Sstevel@tonic-gate cyclep -> propself / hz, cyclep -> propchild / hz, 633*0Sstevel@tonic-gate cyclep -> ncall); 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate if (cyclep->selfcalls != 0) 636*0Sstevel@tonic-gate printf("+%-7lld", cyclep->selfcalls); 637*0Sstevel@tonic-gate else 638*0Sstevel@tonic-gate printf(" %7.7s", ""); 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate printf(" <cycle %d as a whole>\t[%d]\n", cyclep->cycleno, 641*0Sstevel@tonic-gate cyclep->index); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * print the members of a cycle 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate void 648*0Sstevel@tonic-gate printmembers(nltype *cyclep) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate nltype *memberp; 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate sortmembers(cyclep); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate for (memberp = cyclep->cnext; memberp; memberp = memberp->cnext) { 655*0Sstevel@tonic-gate printf("%6.6s %5.5s %7.2f %11.2f %7lld", "", "", 656*0Sstevel@tonic-gate memberp->propself / hz, memberp->propchild / hz, 657*0Sstevel@tonic-gate memberp->ncall); 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate if (memberp->selfcalls != 0) 660*0Sstevel@tonic-gate printf("+%-7lld", memberp->selfcalls); 661*0Sstevel@tonic-gate else 662*0Sstevel@tonic-gate printf(" %7.7s", ""); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate printf(" "); 665*0Sstevel@tonic-gate printname(memberp); 666*0Sstevel@tonic-gate if (Cflag) 667*0Sstevel@tonic-gate print_demangled_name(54, memberp); 668*0Sstevel@tonic-gate printf("\n"); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * sort members of a cycle 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate void 676*0Sstevel@tonic-gate sortmembers(nltype *cyclep) 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate nltype *todo; 679*0Sstevel@tonic-gate nltype *doing; 680*0Sstevel@tonic-gate nltype *prev; 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate /* 683*0Sstevel@tonic-gate * detach cycle members from cyclehead, 684*0Sstevel@tonic-gate * and insertion sort them back on. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate todo = cyclep->cnext; 687*0Sstevel@tonic-gate cyclep->cnext = 0; 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate for ((doing = todo) && (todo = doing->cnext); 690*0Sstevel@tonic-gate doing; (doing = todo) && (todo = doing->cnext)) { 691*0Sstevel@tonic-gate for (prev = cyclep; prev->cnext; prev = prev->cnext) { 692*0Sstevel@tonic-gate if (membercmp(doing, prev->cnext) == GREATERTHAN) 693*0Sstevel@tonic-gate break; 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate doing->cnext = prev->cnext; 696*0Sstevel@tonic-gate prev->cnext = doing; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate /* 701*0Sstevel@tonic-gate * major sort is on propself + propchild, 702*0Sstevel@tonic-gate * next is sort on ncalls + selfcalls. 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate int 705*0Sstevel@tonic-gate membercmp(nltype *this, nltype *that) 706*0Sstevel@tonic-gate { 707*0Sstevel@tonic-gate double thistime = this->propself + this->propchild; 708*0Sstevel@tonic-gate double thattime = that->propself + that->propchild; 709*0Sstevel@tonic-gate actype thiscalls = this->ncall + this->selfcalls; 710*0Sstevel@tonic-gate actype thatcalls = that->ncall + that->selfcalls; 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate if (thistime > thattime) 713*0Sstevel@tonic-gate return (GREATERTHAN); 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate if (thistime < thattime) 716*0Sstevel@tonic-gate return (LESSTHAN); 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate if (thiscalls > thatcalls) 719*0Sstevel@tonic-gate return (GREATERTHAN); 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate if (thiscalls < thatcalls) 722*0Sstevel@tonic-gate return (LESSTHAN); 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate return (EQUALTO); 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate /* 728*0Sstevel@tonic-gate * compare two arcs to/from the same child/parent. 729*0Sstevel@tonic-gate * - if one arc is a self arc, it's least. 730*0Sstevel@tonic-gate * - if one arc is within a cycle, it's less than. 731*0Sstevel@tonic-gate * - if both arcs are within a cycle, compare arc counts. 732*0Sstevel@tonic-gate * - if neither arc is within a cycle, compare with 733*0Sstevel@tonic-gate * arc_time + arc_childtime as major key 734*0Sstevel@tonic-gate * arc count as minor key 735*0Sstevel@tonic-gate */ 736*0Sstevel@tonic-gate int 737*0Sstevel@tonic-gate arccmp(arctype *thisp, arctype *thatp) 738*0Sstevel@tonic-gate { 739*0Sstevel@tonic-gate nltype *thisparentp = thisp->arc_parentp; 740*0Sstevel@tonic-gate nltype *thischildp = thisp->arc_childp; 741*0Sstevel@tonic-gate nltype *thatparentp = thatp->arc_parentp; 742*0Sstevel@tonic-gate nltype *thatchildp = thatp->arc_childp; 743*0Sstevel@tonic-gate double thistime; 744*0Sstevel@tonic-gate double thattime; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate #ifdef DEBUG 747*0Sstevel@tonic-gate if (debug & TIMEDEBUG) { 748*0Sstevel@tonic-gate printf("[arccmp] "); 749*0Sstevel@tonic-gate printname(thisparentp); 750*0Sstevel@tonic-gate printf(" calls "); 751*0Sstevel@tonic-gate printname(thischildp); 752*0Sstevel@tonic-gate printf(" %f + %f %lld/%lld\n", thisp->arc_time, 753*0Sstevel@tonic-gate thisp->arc_childtime, thisp->arc_count, 754*0Sstevel@tonic-gate thischildp->ncall); 755*0Sstevel@tonic-gate printf("[arccmp] "); 756*0Sstevel@tonic-gate printname(thatparentp); 757*0Sstevel@tonic-gate printf(" calls "); 758*0Sstevel@tonic-gate printname(thatchildp); 759*0Sstevel@tonic-gate printf(" %f + %f %lld/%lld\n", thatp->arc_time, 760*0Sstevel@tonic-gate thatp->arc_childtime, thatp->arc_count, 761*0Sstevel@tonic-gate thatchildp->ncall); 762*0Sstevel@tonic-gate printf("\n"); 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate #endif DEBUG 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate if (thisparentp == thischildp) { 767*0Sstevel@tonic-gate /* 768*0Sstevel@tonic-gate * this is a self call 769*0Sstevel@tonic-gate */ 770*0Sstevel@tonic-gate return (LESSTHAN); 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate if (thatparentp == thatchildp) { 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * that is a self call 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate return (GREATERTHAN); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate if (thisparentp->cycleno != 0 && thischildp->cycleno != 0 && 781*0Sstevel@tonic-gate thisparentp->cycleno == thischildp->cycleno) { 782*0Sstevel@tonic-gate /* 783*0Sstevel@tonic-gate * this is a call within a cycle 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 && 786*0Sstevel@tonic-gate thatparentp->cycleno == thatchildp->cycleno) { 787*0Sstevel@tonic-gate /* 788*0Sstevel@tonic-gate * that is a call within the cycle, too 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate if (thisp->arc_count < thatp->arc_count) 791*0Sstevel@tonic-gate return (LESSTHAN); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate if (thisp->arc_count > thatp->arc_count) 794*0Sstevel@tonic-gate return (GREATERTHAN); 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate return (EQUALTO); 797*0Sstevel@tonic-gate } else { 798*0Sstevel@tonic-gate /* 799*0Sstevel@tonic-gate * that isn't a call within the cycle 800*0Sstevel@tonic-gate */ 801*0Sstevel@tonic-gate return (LESSTHAN); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate } else { 804*0Sstevel@tonic-gate /* 805*0Sstevel@tonic-gate * this isn't a call within a cycle 806*0Sstevel@tonic-gate */ 807*0Sstevel@tonic-gate if (thatparentp->cycleno != 0 && thatchildp->cycleno != 0 && 808*0Sstevel@tonic-gate thatparentp->cycleno == thatchildp->cycleno) { 809*0Sstevel@tonic-gate /* 810*0Sstevel@tonic-gate * that is a call within a cycle 811*0Sstevel@tonic-gate */ 812*0Sstevel@tonic-gate return (GREATERTHAN); 813*0Sstevel@tonic-gate } else { 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * neither is a call within a cycle 816*0Sstevel@tonic-gate */ 817*0Sstevel@tonic-gate thistime = thisp->arc_time + thisp->arc_childtime; 818*0Sstevel@tonic-gate thattime = thatp->arc_time + thatp->arc_childtime; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate if (thistime < thattime) 821*0Sstevel@tonic-gate return (LESSTHAN); 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate if (thistime > thattime) 824*0Sstevel@tonic-gate return (GREATERTHAN); 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate if (thisp->arc_count < thatp->arc_count) 827*0Sstevel@tonic-gate return (LESSTHAN); 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate if (thisp->arc_count > thatp->arc_count) 830*0Sstevel@tonic-gate return (GREATERTHAN); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate return (EQUALTO); 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate void 838*0Sstevel@tonic-gate printblurb(char *blurbname) 839*0Sstevel@tonic-gate { 840*0Sstevel@tonic-gate FILE *blurbfile; 841*0Sstevel@tonic-gate int input; 842*0Sstevel@tonic-gate char blurb_directory[MAXPATHLEN]; 843*0Sstevel@tonic-gate char cwd[MAXPATHLEN]; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate cwd[0] = '.'; 846*0Sstevel@tonic-gate cwd[1] = '\0'; 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate if (find_run_directory(prog_name, cwd, blurb_directory, 849*0Sstevel@tonic-gate NULL, getenv("PATH")) != 0) { 850*0Sstevel@tonic-gate (void) fprintf(stderr, "Error in finding run directory."); 851*0Sstevel@tonic-gate return; 852*0Sstevel@tonic-gate } else { 853*0Sstevel@tonic-gate strcat(blurb_directory, blurbname); 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate blurbfile = fopen(blurb_directory, "r"); 857*0Sstevel@tonic-gate if (blurbfile == NULL) { 858*0Sstevel@tonic-gate perror(blurb_directory); 859*0Sstevel@tonic-gate return; 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate while ((input = getc(blurbfile)) != EOF) 863*0Sstevel@tonic-gate putchar(input); 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate fclose(blurbfile); 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate char *s1, *s2; 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate int 871*0Sstevel@tonic-gate namecmp(nltype **npp1, nltype **npp2) 872*0Sstevel@tonic-gate { 873*0Sstevel@tonic-gate if (!Cflag) 874*0Sstevel@tonic-gate return (strcmp((*npp1)->name, (*npp2)->name)); 875*0Sstevel@tonic-gate else { 876*0Sstevel@tonic-gate striped_name(s1, npp1); 877*0Sstevel@tonic-gate striped_name(s2, npp2); 878*0Sstevel@tonic-gate return (strcmp(s1, s2)); 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate void 883*0Sstevel@tonic-gate striped_name(char *s, nltype **npp) 884*0Sstevel@tonic-gate { 885*0Sstevel@tonic-gate char *d, *c; 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate c = (char *)s; 888*0Sstevel@tonic-gate d = demangled_name(*npp); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate while ((*d != '(') && (*d != '\0')) { 891*0Sstevel@tonic-gate if (*d != ':') 892*0Sstevel@tonic-gate *c++ = *d++; 893*0Sstevel@tonic-gate else 894*0Sstevel@tonic-gate d++; 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate *c = '\0'; 897*0Sstevel@tonic-gate } 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate /* 900*0Sstevel@tonic-gate * Checks if the current symbol name is the same as its neighbour and 901*0Sstevel@tonic-gate * returns TRUE if it is. 902*0Sstevel@tonic-gate */ 903*0Sstevel@tonic-gate static bool 904*0Sstevel@tonic-gate does_clash(nltype **nlp, int ndx, int nnames) 905*0Sstevel@tonic-gate { 906*0Sstevel@tonic-gate /* 907*0Sstevel@tonic-gate * same as previous (if there's one) ? 908*0Sstevel@tonic-gate */ 909*0Sstevel@tonic-gate if (ndx && (strcmp(nlp[ndx]->name, nlp[ndx-1]->name) == 0)) 910*0Sstevel@tonic-gate return (TRUE); 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate /* 913*0Sstevel@tonic-gate * same as next (if there's one) ? 914*0Sstevel@tonic-gate */ 915*0Sstevel@tonic-gate if ((ndx < (nnames - 1)) && 916*0Sstevel@tonic-gate (strcmp(nlp[ndx]->name, nlp[ndx+1]->name) == 0)) { 917*0Sstevel@tonic-gate return (TRUE); 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate return (FALSE); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate void 924*0Sstevel@tonic-gate printmodules() 925*0Sstevel@tonic-gate { 926*0Sstevel@tonic-gate mod_info_t *mi; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate printf("\f\nObject modules\n\n"); 929*0Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) 930*0Sstevel@tonic-gate printf(" %d: %s\n", mi->id, mi->name); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate #define IDFMT(id) ((id) < 10 ? 1 : 2) 934*0Sstevel@tonic-gate #define NMFMT(id) ((id) < 10 ? 17 : 16) 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate void 937*0Sstevel@tonic-gate printindex() 938*0Sstevel@tonic-gate { 939*0Sstevel@tonic-gate nltype **namesortnlp; 940*0Sstevel@tonic-gate nltype *nlp; 941*0Sstevel@tonic-gate int index, nnames, todo, i, j; 942*0Sstevel@tonic-gate char peterbuffer[BUFSIZ]; 943*0Sstevel@tonic-gate mod_info_t *mi; 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate /* 946*0Sstevel@tonic-gate * Now, sort regular function name alphabetically 947*0Sstevel@tonic-gate * to create an index. 948*0Sstevel@tonic-gate */ 949*0Sstevel@tonic-gate namesortnlp = calloc(total_names + ncycle, sizeof (nltype *)); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate if (namesortnlp == NULL) 952*0Sstevel@tonic-gate fprintf(stderr, "%s: ran out of memory for sorting\n", whoami); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate nnames = 0; 955*0Sstevel@tonic-gate for (mi = &modules; mi; mi = mi->next) { 956*0Sstevel@tonic-gate for (index = 0; index < mi->nname; index++) { 957*0Sstevel@tonic-gate if (zflag == 0 && (mi->nl[index]).ncall == 0 && 958*0Sstevel@tonic-gate (mi->nl[index]).time == 0) { 959*0Sstevel@tonic-gate continue; 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate /* 963*0Sstevel@tonic-gate * Do not print certain special symbols, like 964*0Sstevel@tonic-gate * PRF_EXTSYM, etc. even if zflag was on. 965*0Sstevel@tonic-gate */ 966*0Sstevel@tonic-gate if (is_special_sym(&(mi->nl[index]))) 967*0Sstevel@tonic-gate continue; 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate namesortnlp[nnames++] = &(mi->nl[index]); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate if (Cflag) { 974*0Sstevel@tonic-gate s1 = malloc(500 * sizeof (char)); 975*0Sstevel@tonic-gate s2 = malloc(500 * sizeof (char)); 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate qsort(namesortnlp, nnames, sizeof (nltype *), 979*0Sstevel@tonic-gate (int(*)(const void *, const void *))namecmp); 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate for (index = 1, todo = nnames; index <= ncycle; index++) 982*0Sstevel@tonic-gate namesortnlp[todo++] = &cyclenl[index]; 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate printf("\f\nIndex by function name\n\n"); 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate if (!Cflag) 987*0Sstevel@tonic-gate index = (todo + 2) / 3; 988*0Sstevel@tonic-gate else 989*0Sstevel@tonic-gate index = todo; 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate for (i = 0; i < index; i++) { 992*0Sstevel@tonic-gate if (!Cflag) { 993*0Sstevel@tonic-gate for (j = i; j < todo; j += index) { 994*0Sstevel@tonic-gate nlp = namesortnlp[j]; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate if (nlp->printflag) { 997*0Sstevel@tonic-gate sprintf(peterbuffer, 998*0Sstevel@tonic-gate "[%d]", nlp->index); 999*0Sstevel@tonic-gate } else { 1000*0Sstevel@tonic-gate sprintf(peterbuffer, 1001*0Sstevel@tonic-gate "(%d)", nlp->index); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate if (j < nnames) { 1005*0Sstevel@tonic-gate if (does_clash(namesortnlp, 1006*0Sstevel@tonic-gate j, nnames)) { 1007*0Sstevel@tonic-gate printf("%6.6s %*d:%-*.*s", 1008*0Sstevel@tonic-gate peterbuffer, 1009*0Sstevel@tonic-gate IDFMT(nlp->module->id), 1010*0Sstevel@tonic-gate nlp->module->id, 1011*0Sstevel@tonic-gate NMFMT(nlp->module->id), 1012*0Sstevel@tonic-gate NMFMT(nlp->module->id), 1013*0Sstevel@tonic-gate nlp->name); 1014*0Sstevel@tonic-gate } else { 1015*0Sstevel@tonic-gate printf("%6.6s %-19.19s", 1016*0Sstevel@tonic-gate peterbuffer, nlp->name); 1017*0Sstevel@tonic-gate } 1018*0Sstevel@tonic-gate } else { 1019*0Sstevel@tonic-gate printf("%6.6s ", peterbuffer); 1020*0Sstevel@tonic-gate sprintf(peterbuffer, 1021*0Sstevel@tonic-gate "<cycle %d>", nlp->cycleno); 1022*0Sstevel@tonic-gate printf("%-19.19s", peterbuffer); 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate } else { 1026*0Sstevel@tonic-gate nlp = namesortnlp[i]; 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate if (nlp->printflag) 1029*0Sstevel@tonic-gate sprintf(peterbuffer, "[%d]", nlp->index); 1030*0Sstevel@tonic-gate else 1031*0Sstevel@tonic-gate sprintf(peterbuffer, "(%d)", nlp->index); 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate if (i < nnames) { 1034*0Sstevel@tonic-gate char *d = demangled_name(nlp); 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate if (does_clash(namesortnlp, i, nnames)) { 1037*0Sstevel@tonic-gate printf("%6.6s %d:%s\n", peterbuffer, 1038*0Sstevel@tonic-gate nlp->module->id, d); 1039*0Sstevel@tonic-gate } else 1040*0Sstevel@tonic-gate printf("%6.6s %s\n", peterbuffer, d); 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate if (d != nlp->name) 1043*0Sstevel@tonic-gate printf("%6.6s [%s]", "", nlp->name); 1044*0Sstevel@tonic-gate } else { 1045*0Sstevel@tonic-gate printf("%6.6s ", peterbuffer); 1046*0Sstevel@tonic-gate sprintf(peterbuffer, "<cycle %d>", 1047*0Sstevel@tonic-gate nlp->cycleno); 1048*0Sstevel@tonic-gate printf("%-33.33s", peterbuffer); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate printf("\n"); 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate free(namesortnlp); 1054*0Sstevel@tonic-gate } 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate char dname[500]; 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate char * 1060*0Sstevel@tonic-gate exotic(char *s) 1061*0Sstevel@tonic-gate { 1062*0Sstevel@tonic-gate char *name; 1063*0Sstevel@tonic-gate int i = 0, j; 1064*0Sstevel@tonic-gate char *p, *s1 = "static constructor function for "; 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate name = malloc(500 * sizeof (char)); 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate if (strncmp(s, "__sti__", 7) == 0) { 1069*0Sstevel@tonic-gate i = 0; 1070*0Sstevel@tonic-gate s += 7; 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate if ((p = strstr(s, "_c_")) == NULL) { 1073*0Sstevel@tonic-gate if ((p = strstr(s, "_C_")) == NULL) { 1074*0Sstevel@tonic-gate if ((p = strstr(s, "_cc_")) == NULL) { 1075*0Sstevel@tonic-gate if ((p = strstr(s, "_cxx_")) == NULL) { 1076*0Sstevel@tonic-gate if ((p = 1077*0Sstevel@tonic-gate strstr(s, "_h_")) == NULL) 1078*0Sstevel@tonic-gate return (NULL); 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate } 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate } else { 1083*0Sstevel@tonic-gate p += 3; 1084*0Sstevel@tonic-gate *p = '\0'; 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate for (i = 0; s1[i] != '\0'; i++) 1088*0Sstevel@tonic-gate dname[i] = s1[i]; 1089*0Sstevel@tonic-gate j = i; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate for (i = 0; s[i] != '\0'; i++) 1092*0Sstevel@tonic-gate dname[j + i] = s[i]; 1093*0Sstevel@tonic-gate dname[j + i] = '\0'; 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate free(name); 1096*0Sstevel@tonic-gate return (dname); 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate if (strncmp(s, "__std__", 7) == 0) { 1100*0Sstevel@tonic-gate char *s1 = "static destructor function for "; 1101*0Sstevel@tonic-gate i = 0; 1102*0Sstevel@tonic-gate s += 7; 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate if ((p = strstr(s, "_c_")) == NULL) { 1105*0Sstevel@tonic-gate if ((p = strstr(s, "_C_")) == NULL) { 1106*0Sstevel@tonic-gate if ((p = strstr(s, "_cc_")) == NULL) { 1107*0Sstevel@tonic-gate if ((p = strstr(s, "_cxx_")) == NULL) { 1108*0Sstevel@tonic-gate if ((p = 1109*0Sstevel@tonic-gate strstr(s, "_h_")) == NULL) 1110*0Sstevel@tonic-gate return (NULL); 1111*0Sstevel@tonic-gate } 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate } else { 1115*0Sstevel@tonic-gate p += 3; 1116*0Sstevel@tonic-gate *p = '\0'; 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate for (i = 0; s1[i] != '\0'; i++) 1120*0Sstevel@tonic-gate dname[i] = s1[i]; 1121*0Sstevel@tonic-gate j = i; 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate for (i = 0; s[i] != '\0'; i++) 1124*0Sstevel@tonic-gate dname[j + i] = s[i]; 1125*0Sstevel@tonic-gate dname[j + i] = '\0'; 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate free(name); 1128*0Sstevel@tonic-gate return (dname); 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate if (strncmp(s, "__vtbl__", 8) == 0) { 1132*0Sstevel@tonic-gate char *s1 = "virtual table for "; 1133*0Sstevel@tonic-gate char *printname, *return_p = dname; 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate s += 8; 1136*0Sstevel@tonic-gate printname = parsename(s); 1137*0Sstevel@tonic-gate return_p = '\0'; 1138*0Sstevel@tonic-gate strcat(return_p, s1); 1139*0Sstevel@tonic-gate strcat(return_p, printname); 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate free(name); 1142*0Sstevel@tonic-gate return (dname); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate if (strncmp(s, "__ptbl__", 8) == 0) { 1146*0Sstevel@tonic-gate char *s1 = "pointer to the virtual table for "; 1147*0Sstevel@tonic-gate char *printname, *return_p = dname; 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate s += 8; 1150*0Sstevel@tonic-gate printname = parsename(s); 1151*0Sstevel@tonic-gate return_p = '\0'; 1152*0Sstevel@tonic-gate strcat(return_p, s1); 1153*0Sstevel@tonic-gate strcat(return_p, printname); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate free(name); 1156*0Sstevel@tonic-gate return (return_p); 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate free(name); 1160*0Sstevel@tonic-gate return (s); 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate char * 1164*0Sstevel@tonic-gate parsename(char *s) 1165*0Sstevel@tonic-gate { 1166*0Sstevel@tonic-gate char *d = name_buffer; 1167*0Sstevel@tonic-gate int len; 1168*0Sstevel@tonic-gate char c_init; 1169*0Sstevel@tonic-gate char *len_pointer = s; 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate *d = '\0'; 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate strcat(d, "class "); 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate while (isdigit(*s)) 1176*0Sstevel@tonic-gate s++; 1177*0Sstevel@tonic-gate c_init = *s; 1178*0Sstevel@tonic-gate *s = '\0'; 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate len = atoi(len_pointer); 1181*0Sstevel@tonic-gate *s = c_init; 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate /* 1184*0Sstevel@tonic-gate * only one class name 1185*0Sstevel@tonic-gate */ 1186*0Sstevel@tonic-gate if (*(s + len) == '\0') { 1187*0Sstevel@tonic-gate strcat(d, s); 1188*0Sstevel@tonic-gate return (d); 1189*0Sstevel@tonic-gate } else { 1190*0Sstevel@tonic-gate /* 1191*0Sstevel@tonic-gate * two classname %drootname__%dchildname 1192*0Sstevel@tonic-gate */ 1193*0Sstevel@tonic-gate char *child; 1194*0Sstevel@tonic-gate char *root; 1195*0Sstevel@tonic-gate int child_len; 1196*0Sstevel@tonic-gate char *child_len_p; 1197*0Sstevel@tonic-gate root = s; 1198*0Sstevel@tonic-gate child = s + len + 2; 1199*0Sstevel@tonic-gate child_len_p = child; 1200*0Sstevel@tonic-gate 1201*0Sstevel@tonic-gate if (!isdigit(*child)) { /* ptbl file name */ 1202*0Sstevel@tonic-gate c_init = *(root + len); 1203*0Sstevel@tonic-gate *(root + len) = '\0'; 1204*0Sstevel@tonic-gate strcat(d, root); 1205*0Sstevel@tonic-gate *(root + len) = c_init; 1206*0Sstevel@tonic-gate strcat(d, " in "); 1207*0Sstevel@tonic-gate strcat(d, child); 1208*0Sstevel@tonic-gate return (d); 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate while (isdigit(*child)) 1212*0Sstevel@tonic-gate child++; 1213*0Sstevel@tonic-gate c_init = *child; 1214*0Sstevel@tonic-gate *child = '\0'; 1215*0Sstevel@tonic-gate child_len = atoi(child_len_p); 1216*0Sstevel@tonic-gate *child = c_init; 1217*0Sstevel@tonic-gate if (*(child + child_len) == '\0') { 1218*0Sstevel@tonic-gate strcat(d, child); 1219*0Sstevel@tonic-gate strcat(d, " derived from "); 1220*0Sstevel@tonic-gate c_init = *(root + len); 1221*0Sstevel@tonic-gate *(root + len) = '\0'; 1222*0Sstevel@tonic-gate strcat(d, root); 1223*0Sstevel@tonic-gate *(root + len) = c_init; 1224*0Sstevel@tonic-gate return (d); 1225*0Sstevel@tonic-gate } else { /* %drootname__%dchildname__filename */ 1226*0Sstevel@tonic-gate c_init = *(child + child_len); 1227*0Sstevel@tonic-gate *(child + child_len) = '\0'; 1228*0Sstevel@tonic-gate strcat(d, child); 1229*0Sstevel@tonic-gate *(child+ child_len) = c_init; 1230*0Sstevel@tonic-gate strcat(d, " derived from "); 1231*0Sstevel@tonic-gate c_init = *(root + len); 1232*0Sstevel@tonic-gate *(root + len) = '\0'; 1233*0Sstevel@tonic-gate strcat(d, root); 1234*0Sstevel@tonic-gate *(root + len) = c_init; 1235*0Sstevel@tonic-gate strcat(d, " in "); 1236*0Sstevel@tonic-gate strcat(d, child + child_len + 2); 1237*0Sstevel@tonic-gate return (d); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate } 1241