1*883c4be3SJerome Forissier /* 2*883c4be3SJerome Forissier * Copyright (c) 2016, Linaro Limited 3*883c4be3SJerome Forissier * All rights reserved. 4*883c4be3SJerome Forissier * 5*883c4be3SJerome Forissier * Redistribution and use in source and binary forms, with or without 6*883c4be3SJerome Forissier * modification, are permitted provided that the following conditions are met: 7*883c4be3SJerome Forissier * 8*883c4be3SJerome Forissier * 1. Redistributions of source code must retain the above copyright notice, 9*883c4be3SJerome Forissier * this list of conditions and the following disclaimer. 10*883c4be3SJerome Forissier * 11*883c4be3SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright notice, 12*883c4be3SJerome Forissier * this list of conditions and the following disclaimer in the documentation 13*883c4be3SJerome Forissier * and/or other materials provided with the distribution. 14*883c4be3SJerome Forissier * 15*883c4be3SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*883c4be3SJerome Forissier * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*883c4be3SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*883c4be3SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19*883c4be3SJerome Forissier * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*883c4be3SJerome Forissier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*883c4be3SJerome Forissier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*883c4be3SJerome Forissier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*883c4be3SJerome Forissier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*883c4be3SJerome Forissier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*883c4be3SJerome Forissier * POSSIBILITY OF SUCH DAMAGE. 26*883c4be3SJerome Forissier */ 27*883c4be3SJerome Forissier 28*883c4be3SJerome Forissier /* 29*883c4be3SJerome Forissier * Portions of this file are adapted from glibc: 30*883c4be3SJerome Forissier * gmon/gmon.c 31*883c4be3SJerome Forissier * gmon/mcount.c 32*883c4be3SJerome Forissier * 33*883c4be3SJerome Forissier *- 34*883c4be3SJerome Forissier * Copyright (c) 1983, 1992, 1993, 2011 35*883c4be3SJerome Forissier * The Regents of the University of California. All rights reserved. 36*883c4be3SJerome Forissier * 37*883c4be3SJerome Forissier * Redistribution and use in source and binary forms, with or without 38*883c4be3SJerome Forissier * modification, are permitted provided that the following conditions 39*883c4be3SJerome Forissier * are met: 40*883c4be3SJerome Forissier * 1. Redistributions of source code must retain the above copyright 41*883c4be3SJerome Forissier * notice, this list of conditions and the following disclaimer. 42*883c4be3SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright 43*883c4be3SJerome Forissier * notice, this list of conditions and the following disclaimer in the 44*883c4be3SJerome Forissier * documentation and/or other materials provided with the distribution. 45*883c4be3SJerome Forissier * 4. Neither the name of the University nor the names of its contributors 46*883c4be3SJerome Forissier * may be used to endorse or promote products derived from this software 47*883c4be3SJerome Forissier * without specific prior written permission. 48*883c4be3SJerome Forissier * 49*883c4be3SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50*883c4be3SJerome Forissier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51*883c4be3SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52*883c4be3SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53*883c4be3SJerome Forissier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54*883c4be3SJerome Forissier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55*883c4be3SJerome Forissier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56*883c4be3SJerome Forissier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57*883c4be3SJerome Forissier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58*883c4be3SJerome Forissier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59*883c4be3SJerome Forissier * SUCH DAMAGE. 60*883c4be3SJerome Forissier */ 61*883c4be3SJerome Forissier 62*883c4be3SJerome Forissier #include <assert.h> 63*883c4be3SJerome Forissier #include <compiler.h> 64*883c4be3SJerome Forissier #include <inttypes.h> 65*883c4be3SJerome Forissier #include <malloc.h> 66*883c4be3SJerome Forissier #include <stdint.h> 67*883c4be3SJerome Forissier #include <string.h> 68*883c4be3SJerome Forissier #include <tee_api_private.h> 69*883c4be3SJerome Forissier #include <trace.h> 70*883c4be3SJerome Forissier #include <user_ta_header.h> 71*883c4be3SJerome Forissier #include <utee_types.h> 72*883c4be3SJerome Forissier #include "gmon.h" 73*883c4be3SJerome Forissier #include "gmon_out.h" 74*883c4be3SJerome Forissier #include "gprof_pta.h" 75*883c4be3SJerome Forissier 76*883c4be3SJerome Forissier /* Defined by the linker script */ 77*883c4be3SJerome Forissier extern uint8_t __gprof_buf_end[]; 78*883c4be3SJerome Forissier extern uint8_t __gprof_buf_start[]; 79*883c4be3SJerome Forissier 80*883c4be3SJerome Forissier static bool ta_instrumented(void) 81*883c4be3SJerome Forissier { 82*883c4be3SJerome Forissier return (__gprof_buf_end != __gprof_buf_start); 83*883c4be3SJerome Forissier } 84*883c4be3SJerome Forissier 85*883c4be3SJerome Forissier static void *gprof_alloc(size_t len) 86*883c4be3SJerome Forissier { 87*883c4be3SJerome Forissier if (len > (size_t)(__gprof_buf_end - __gprof_buf_start)) 88*883c4be3SJerome Forissier return NULL; 89*883c4be3SJerome Forissier return __gprof_buf_start; 90*883c4be3SJerome Forissier } 91*883c4be3SJerome Forissier 92*883c4be3SJerome Forissier static struct gmonparam _gmonparam = { GMON_PROF_OFF }; 93*883c4be3SJerome Forissier 94*883c4be3SJerome Forissier static uint32_t _gprof_file_id; /* File id returned by tee-supplicant */ 95*883c4be3SJerome Forissier 96*883c4be3SJerome Forissier static int _gprof_s_scale; 97*883c4be3SJerome Forissier #define SCALE_1_TO_1 0x10000L 98*883c4be3SJerome Forissier 99*883c4be3SJerome Forissier /* Adjust PC so that gprof can locate it in the TA ELF file */ 100*883c4be3SJerome Forissier static unsigned long __noprof adjust_pc(unsigned long pc) 101*883c4be3SJerome Forissier { 102*883c4be3SJerome Forissier return pc - (unsigned long)__text_start + sizeof(struct ta_head); 103*883c4be3SJerome Forissier } 104*883c4be3SJerome Forissier 105*883c4be3SJerome Forissier void __utee_gprof_init(void) 106*883c4be3SJerome Forissier { 107*883c4be3SJerome Forissier unsigned long lowpc; 108*883c4be3SJerome Forissier unsigned long highpc; 109*883c4be3SJerome Forissier struct gmonparam *p = &_gmonparam; 110*883c4be3SJerome Forissier size_t bufsize; 111*883c4be3SJerome Forissier TEE_Result res; 112*883c4be3SJerome Forissier char *cp; 113*883c4be3SJerome Forissier 114*883c4be3SJerome Forissier if (!ta_instrumented()) 115*883c4be3SJerome Forissier return; 116*883c4be3SJerome Forissier 117*883c4be3SJerome Forissier lowpc = adjust_pc((unsigned long)__text_start); 118*883c4be3SJerome Forissier highpc = adjust_pc((unsigned long)__text_end); 119*883c4be3SJerome Forissier 120*883c4be3SJerome Forissier /* 121*883c4be3SJerome Forissier * Round lowpc and highpc to multiples of the density we're using 122*883c4be3SJerome Forissier * so the rest of the scaling (here and in gprof) stays in ints. 123*883c4be3SJerome Forissier */ 124*883c4be3SJerome Forissier p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 125*883c4be3SJerome Forissier p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 126*883c4be3SJerome Forissier p->textsize = p->highpc - p->lowpc; 127*883c4be3SJerome Forissier p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); 128*883c4be3SJerome Forissier p->hashfraction = HASHFRACTION; 129*883c4be3SJerome Forissier p->log_hashfraction = -1; 130*883c4be3SJerome Forissier /* 131*883c4be3SJerome Forissier * The following test must be kept in sync with the corresponding 132*883c4be3SJerome Forissier * test in __mcount_internal 133*883c4be3SJerome Forissier */ 134*883c4be3SJerome Forissier if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { 135*883c4be3SJerome Forissier /* 136*883c4be3SJerome Forissier * If HASHFRACTION is a power of two, mcount can use shifting 137*883c4be3SJerome Forissier * instead of integer division. Precompute shift amount. 138*883c4be3SJerome Forissier */ 139*883c4be3SJerome Forissier p->log_hashfraction = __builtin_ffs(p->hashfraction * 140*883c4be3SJerome Forissier sizeof(*p->froms)) - 1; 141*883c4be3SJerome Forissier } 142*883c4be3SJerome Forissier p->fromssize = p->textsize / HASHFRACTION; 143*883c4be3SJerome Forissier p->tolimit = p->textsize * ARCDENSITY / 100; 144*883c4be3SJerome Forissier if (p->tolimit < MINARCS) 145*883c4be3SJerome Forissier p->tolimit = MINARCS; 146*883c4be3SJerome Forissier else if (p->tolimit > MAXARCS) 147*883c4be3SJerome Forissier p->tolimit = MAXARCS; 148*883c4be3SJerome Forissier p->tossize = p->tolimit * sizeof(struct tostruct); 149*883c4be3SJerome Forissier 150*883c4be3SJerome Forissier bufsize = p->kcountsize + p->fromssize + p->tossize; 151*883c4be3SJerome Forissier 152*883c4be3SJerome Forissier IMSG("gprof: initializing"); 153*883c4be3SJerome Forissier DMSG("TA text size: %zu, gprof buffer size: %zu", 154*883c4be3SJerome Forissier __text_end - __text_start, bufsize); 155*883c4be3SJerome Forissier 156*883c4be3SJerome Forissier cp = gprof_alloc(bufsize); 157*883c4be3SJerome Forissier if (!cp) { 158*883c4be3SJerome Forissier EMSG("gprof: could not allocate profiling buffer"); 159*883c4be3SJerome Forissier p->tos = NULL; 160*883c4be3SJerome Forissier p->state = GMON_PROF_ERROR; 161*883c4be3SJerome Forissier return; 162*883c4be3SJerome Forissier } 163*883c4be3SJerome Forissier 164*883c4be3SJerome Forissier p->tos = (struct tostruct *)cp; 165*883c4be3SJerome Forissier cp += p->tossize; 166*883c4be3SJerome Forissier p->kcount = (HISTCOUNTER *)cp; 167*883c4be3SJerome Forissier cp += p->kcountsize; 168*883c4be3SJerome Forissier p->froms = (ARCINDEX *)cp; 169*883c4be3SJerome Forissier 170*883c4be3SJerome Forissier p->tos[0].link = 0; 171*883c4be3SJerome Forissier 172*883c4be3SJerome Forissier if (p->kcountsize < p->textsize) 173*883c4be3SJerome Forissier _gprof_s_scale = ((float)p->kcountsize / p->textsize) * 174*883c4be3SJerome Forissier SCALE_1_TO_1; 175*883c4be3SJerome Forissier else 176*883c4be3SJerome Forissier _gprof_s_scale = SCALE_1_TO_1; 177*883c4be3SJerome Forissier 178*883c4be3SJerome Forissier res = __pta_gprof_pc_sampling_start(p->kcount, p->kcountsize, 179*883c4be3SJerome Forissier p->lowpc + 180*883c4be3SJerome Forissier ((unsigned long)__text_start - 181*883c4be3SJerome Forissier sizeof(struct ta_head)), 182*883c4be3SJerome Forissier _gprof_s_scale); 183*883c4be3SJerome Forissier if (res != TEE_SUCCESS) 184*883c4be3SJerome Forissier EMSG("gprof: could not start PC sampling (0x%08x)", res); 185*883c4be3SJerome Forissier 186*883c4be3SJerome Forissier p->state = GMON_PROF_ON; 187*883c4be3SJerome Forissier } 188*883c4be3SJerome Forissier 189*883c4be3SJerome Forissier static void _gprof_write_buf(void *buf, size_t size) 190*883c4be3SJerome Forissier { 191*883c4be3SJerome Forissier TEE_Result res; 192*883c4be3SJerome Forissier 193*883c4be3SJerome Forissier res = __pta_gprof_send(buf, size, &_gprof_file_id); 194*883c4be3SJerome Forissier if (res != TEE_SUCCESS) 195*883c4be3SJerome Forissier EMSG("gprof: could not send gprof data (0x%08x)", res); 196*883c4be3SJerome Forissier } 197*883c4be3SJerome Forissier 198*883c4be3SJerome Forissier static void _gprof_write_header(void) 199*883c4be3SJerome Forissier { 200*883c4be3SJerome Forissier struct gmon_hdr ghdr; 201*883c4be3SJerome Forissier size_t size = sizeof(struct gmon_hdr); 202*883c4be3SJerome Forissier 203*883c4be3SJerome Forissier memcpy(&ghdr.cookie[0], GMON_MAGIC, sizeof(ghdr.cookie)); 204*883c4be3SJerome Forissier ghdr.version = GMON_VERSION; 205*883c4be3SJerome Forissier memset(ghdr.spare, '\0', sizeof(ghdr.spare)); 206*883c4be3SJerome Forissier 207*883c4be3SJerome Forissier _gprof_write_buf(&ghdr, size); 208*883c4be3SJerome Forissier } 209*883c4be3SJerome Forissier 210*883c4be3SJerome Forissier static void _gprof_write_hist(void) 211*883c4be3SJerome Forissier { 212*883c4be3SJerome Forissier struct out_record { 213*883c4be3SJerome Forissier uint8_t tag; 214*883c4be3SJerome Forissier struct gmon_hist_hdr hist_hdr; 215*883c4be3SJerome Forissier } __packed out = { 216*883c4be3SJerome Forissier .tag = GMON_TAG_TIME_HIST, 217*883c4be3SJerome Forissier .hist_hdr = { 218*883c4be3SJerome Forissier .low_pc = _gmonparam.lowpc, 219*883c4be3SJerome Forissier .high_pc = _gmonparam.highpc, 220*883c4be3SJerome Forissier .hist_size = _gmonparam.kcountsize/sizeof(HISTCOUNTER), 221*883c4be3SJerome Forissier .prof_rate = _gmonparam.prof_rate, 222*883c4be3SJerome Forissier .dimen = "seconds", 223*883c4be3SJerome Forissier .dimen_abbrev = 's', 224*883c4be3SJerome Forissier } 225*883c4be3SJerome Forissier }; 226*883c4be3SJerome Forissier 227*883c4be3SJerome Forissier _gprof_write_buf(&out, sizeof(out)); 228*883c4be3SJerome Forissier _gprof_write_buf(_gmonparam.kcount, _gmonparam.kcountsize); 229*883c4be3SJerome Forissier } 230*883c4be3SJerome Forissier 231*883c4be3SJerome Forissier static void _gprof_write_call_graph(void) 232*883c4be3SJerome Forissier { 233*883c4be3SJerome Forissier #define NARCS_PER_WRITE 16 234*883c4be3SJerome Forissier struct out_record { 235*883c4be3SJerome Forissier uint8_t tag; 236*883c4be3SJerome Forissier uint8_t data[sizeof(struct gmon_cg_arc_record)]; 237*883c4be3SJerome Forissier } out[NARCS_PER_WRITE]; 238*883c4be3SJerome Forissier struct gmon_cg_arc_record arc; 239*883c4be3SJerome Forissier ARCINDEX from_index, to_index; 240*883c4be3SJerome Forissier unsigned long from_len; 241*883c4be3SJerome Forissier unsigned long frompc; 242*883c4be3SJerome Forissier int nfilled = 0; 243*883c4be3SJerome Forissier 244*883c4be3SJerome Forissier from_len = _gmonparam.fromssize / sizeof(*_gmonparam.froms); 245*883c4be3SJerome Forissier 246*883c4be3SJerome Forissier for (from_index = 0; from_index < from_len; ++from_index) { 247*883c4be3SJerome Forissier 248*883c4be3SJerome Forissier if (_gmonparam.froms[from_index] == 0) 249*883c4be3SJerome Forissier continue; 250*883c4be3SJerome Forissier 251*883c4be3SJerome Forissier frompc = _gmonparam.lowpc; 252*883c4be3SJerome Forissier frompc += (from_index * _gmonparam.hashfraction 253*883c4be3SJerome Forissier * sizeof(*_gmonparam.froms)); 254*883c4be3SJerome Forissier for (to_index = _gmonparam.froms[from_index]; 255*883c4be3SJerome Forissier to_index != 0; 256*883c4be3SJerome Forissier to_index = _gmonparam.tos[to_index].link) { 257*883c4be3SJerome Forissier 258*883c4be3SJerome Forissier arc.from_pc = frompc; 259*883c4be3SJerome Forissier arc.self_pc = _gmonparam.tos[to_index].selfpc; 260*883c4be3SJerome Forissier arc.count = _gmonparam.tos[to_index].count; 261*883c4be3SJerome Forissier 262*883c4be3SJerome Forissier out[nfilled].tag = GMON_TAG_CG_ARC; 263*883c4be3SJerome Forissier memcpy(out[nfilled].data, &arc, sizeof(arc)); 264*883c4be3SJerome Forissier 265*883c4be3SJerome Forissier if (++nfilled == NARCS_PER_WRITE) { 266*883c4be3SJerome Forissier _gprof_write_buf(out, sizeof(out)); 267*883c4be3SJerome Forissier nfilled = 0; 268*883c4be3SJerome Forissier } 269*883c4be3SJerome Forissier } 270*883c4be3SJerome Forissier } 271*883c4be3SJerome Forissier if (nfilled > 0) 272*883c4be3SJerome Forissier _gprof_write_buf(out, nfilled * sizeof(out[0])); 273*883c4be3SJerome Forissier } 274*883c4be3SJerome Forissier 275*883c4be3SJerome Forissier /* Stop profiling and send profile data in gmon.out format to Normal World */ 276*883c4be3SJerome Forissier void __utee_gprof_fini(void) 277*883c4be3SJerome Forissier { 278*883c4be3SJerome Forissier TEE_Result res; 279*883c4be3SJerome Forissier 280*883c4be3SJerome Forissier if (_gmonparam.state != GMON_PROF_ON) 281*883c4be3SJerome Forissier return; 282*883c4be3SJerome Forissier 283*883c4be3SJerome Forissier /* Stop call graph tracing */ 284*883c4be3SJerome Forissier _gmonparam.state = GMON_PROF_OFF_EXITING; 285*883c4be3SJerome Forissier 286*883c4be3SJerome Forissier /* Stop TA sampling */ 287*883c4be3SJerome Forissier res = __pta_gprof_pc_sampling_stop(&_gmonparam.prof_rate); 288*883c4be3SJerome Forissier 289*883c4be3SJerome Forissier _gprof_write_header(); 290*883c4be3SJerome Forissier if (res == TEE_SUCCESS) 291*883c4be3SJerome Forissier _gprof_write_hist(); 292*883c4be3SJerome Forissier _gprof_write_call_graph(); 293*883c4be3SJerome Forissier 294*883c4be3SJerome Forissier __pta_gprof_fini(); 295*883c4be3SJerome Forissier } 296*883c4be3SJerome Forissier 297*883c4be3SJerome Forissier /* 298*883c4be3SJerome Forissier * Called from the assembly stub (_mcount or __gnu_mcount_nc). 299*883c4be3SJerome Forissier * 300*883c4be3SJerome Forissier * __mcount_internal updates data structures that represent traversals of the 301*883c4be3SJerome Forissier * program's call graph edges. frompc and selfpc are the return 302*883c4be3SJerome Forissier * address and function address that represents the given call graph edge. 303*883c4be3SJerome Forissier */ 304*883c4be3SJerome Forissier void __noprof __mcount_internal(unsigned long frompc, unsigned long selfpc) 305*883c4be3SJerome Forissier { 306*883c4be3SJerome Forissier ARCINDEX *frompcindex; 307*883c4be3SJerome Forissier struct tostruct *top, *prevtop; 308*883c4be3SJerome Forissier struct gmonparam *p; 309*883c4be3SJerome Forissier ARCINDEX toindex; 310*883c4be3SJerome Forissier int i; 311*883c4be3SJerome Forissier 312*883c4be3SJerome Forissier p = &_gmonparam; 313*883c4be3SJerome Forissier 314*883c4be3SJerome Forissier /* 315*883c4be3SJerome Forissier * Check that we are profiling and that we aren't recursively invoked. 316*883c4be3SJerome Forissier */ 317*883c4be3SJerome Forissier if (p->state != GMON_PROF_ON) 318*883c4be3SJerome Forissier return; 319*883c4be3SJerome Forissier p->state = GMON_PROF_BUSY; 320*883c4be3SJerome Forissier 321*883c4be3SJerome Forissier frompc = adjust_pc(frompc); 322*883c4be3SJerome Forissier selfpc = adjust_pc(selfpc); 323*883c4be3SJerome Forissier 324*883c4be3SJerome Forissier /* Check that frompcindex is a reasonable pc value. */ 325*883c4be3SJerome Forissier frompc -= p->lowpc; 326*883c4be3SJerome Forissier if (frompc > p->textsize) 327*883c4be3SJerome Forissier goto done; 328*883c4be3SJerome Forissier 329*883c4be3SJerome Forissier /* Note: keep in sync. with the initialization function above */ 330*883c4be3SJerome Forissier if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { 331*883c4be3SJerome Forissier /* Avoid integer divide if possible */ 332*883c4be3SJerome Forissier i = frompc >> p->log_hashfraction; 333*883c4be3SJerome Forissier } else { 334*883c4be3SJerome Forissier i = frompc / (p->hashfraction * sizeof(*p->froms)); 335*883c4be3SJerome Forissier } 336*883c4be3SJerome Forissier frompcindex = &p->froms[i]; 337*883c4be3SJerome Forissier toindex = *frompcindex; 338*883c4be3SJerome Forissier if (toindex == 0) { 339*883c4be3SJerome Forissier /* First time traversing this arc */ 340*883c4be3SJerome Forissier toindex = ++p->tos[0].link; 341*883c4be3SJerome Forissier if (toindex >= p->tolimit) { 342*883c4be3SJerome Forissier /* Halt further profiling */ 343*883c4be3SJerome Forissier goto overflow; 344*883c4be3SJerome Forissier } 345*883c4be3SJerome Forissier 346*883c4be3SJerome Forissier *frompcindex = toindex; 347*883c4be3SJerome Forissier top = &p->tos[toindex]; 348*883c4be3SJerome Forissier top->selfpc = selfpc; 349*883c4be3SJerome Forissier top->count = 1; 350*883c4be3SJerome Forissier top->link = 0; 351*883c4be3SJerome Forissier goto done; 352*883c4be3SJerome Forissier } 353*883c4be3SJerome Forissier top = &p->tos[toindex]; 354*883c4be3SJerome Forissier if (top->selfpc == selfpc) { 355*883c4be3SJerome Forissier /* Arc at front of chain; usual case */ 356*883c4be3SJerome Forissier top->count++; 357*883c4be3SJerome Forissier goto done; 358*883c4be3SJerome Forissier } 359*883c4be3SJerome Forissier /* 360*883c4be3SJerome Forissier * Have to go looking down chain for it. 361*883c4be3SJerome Forissier * top points to what we are looking at, 362*883c4be3SJerome Forissier * prevtop points to previous top. 363*883c4be3SJerome Forissier * we know it is not at the head of the chain. 364*883c4be3SJerome Forissier */ 365*883c4be3SJerome Forissier for (;;) { 366*883c4be3SJerome Forissier if (top->link == 0) { 367*883c4be3SJerome Forissier /* 368*883c4be3SJerome Forissier * top is end of the chain and none of the chain 369*883c4be3SJerome Forissier * had top->selfpc == selfpc. 370*883c4be3SJerome Forissier * so we allocate a new tostruct 371*883c4be3SJerome Forissier * and link it to the head of the chain. 372*883c4be3SJerome Forissier */ 373*883c4be3SJerome Forissier toindex = ++p->tos[0].link; 374*883c4be3SJerome Forissier if (toindex >= p->tolimit) 375*883c4be3SJerome Forissier goto overflow; 376*883c4be3SJerome Forissier 377*883c4be3SJerome Forissier top = &p->tos[toindex]; 378*883c4be3SJerome Forissier top->selfpc = selfpc; 379*883c4be3SJerome Forissier top->count = 1; 380*883c4be3SJerome Forissier top->link = *frompcindex; 381*883c4be3SJerome Forissier *frompcindex = toindex; 382*883c4be3SJerome Forissier goto done; 383*883c4be3SJerome Forissier } 384*883c4be3SJerome Forissier /* 385*883c4be3SJerome Forissier * Otherwise, check the next arc on the chain. 386*883c4be3SJerome Forissier */ 387*883c4be3SJerome Forissier prevtop = top; 388*883c4be3SJerome Forissier top = &p->tos[top->link]; 389*883c4be3SJerome Forissier if (top->selfpc == selfpc) { 390*883c4be3SJerome Forissier /* 391*883c4be3SJerome Forissier * There it is. Increment its count, move it to the 392*883c4be3SJerome Forissier * head of the chain. 393*883c4be3SJerome Forissier */ 394*883c4be3SJerome Forissier top->count++; 395*883c4be3SJerome Forissier toindex = prevtop->link; 396*883c4be3SJerome Forissier prevtop->link = top->link; 397*883c4be3SJerome Forissier top->link = *frompcindex; 398*883c4be3SJerome Forissier *frompcindex = toindex; 399*883c4be3SJerome Forissier goto done; 400*883c4be3SJerome Forissier } 401*883c4be3SJerome Forissier } 402*883c4be3SJerome Forissier done: 403*883c4be3SJerome Forissier p->state = GMON_PROF_ON; 404*883c4be3SJerome Forissier return; 405*883c4be3SJerome Forissier overflow: 406*883c4be3SJerome Forissier p->state = GMON_PROF_ERROR; 407*883c4be3SJerome Forissier } 408