1*1bb92983SJerome Forissier // SPDX-License-Identifier: (BSD-2-Clause AND BSD-3-Clause) 2883c4be3SJerome Forissier /* 3883c4be3SJerome Forissier * Copyright (c) 2016, Linaro Limited 4883c4be3SJerome Forissier * All rights reserved. 5883c4be3SJerome Forissier * 6883c4be3SJerome Forissier * Redistribution and use in source and binary forms, with or without 7883c4be3SJerome Forissier * modification, are permitted provided that the following conditions are met: 8883c4be3SJerome Forissier * 9883c4be3SJerome Forissier * 1. Redistributions of source code must retain the above copyright notice, 10883c4be3SJerome Forissier * this list of conditions and the following disclaimer. 11883c4be3SJerome Forissier * 12883c4be3SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright notice, 13883c4be3SJerome Forissier * this list of conditions and the following disclaimer in the documentation 14883c4be3SJerome Forissier * and/or other materials provided with the distribution. 15883c4be3SJerome Forissier * 16883c4be3SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17883c4be3SJerome Forissier * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18883c4be3SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19883c4be3SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20883c4be3SJerome Forissier * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21883c4be3SJerome Forissier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22883c4be3SJerome Forissier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23883c4be3SJerome Forissier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24883c4be3SJerome Forissier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25883c4be3SJerome Forissier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26883c4be3SJerome Forissier * POSSIBILITY OF SUCH DAMAGE. 27883c4be3SJerome Forissier */ 28883c4be3SJerome Forissier 29883c4be3SJerome Forissier /* 30883c4be3SJerome Forissier * Portions of this file are adapted from glibc: 31883c4be3SJerome Forissier * gmon/gmon.c 32883c4be3SJerome Forissier * gmon/mcount.c 33883c4be3SJerome Forissier * 34883c4be3SJerome Forissier *- 35883c4be3SJerome Forissier * Copyright (c) 1983, 1992, 1993, 2011 36883c4be3SJerome Forissier * The Regents of the University of California. All rights reserved. 37883c4be3SJerome Forissier * 38883c4be3SJerome Forissier * Redistribution and use in source and binary forms, with or without 39883c4be3SJerome Forissier * modification, are permitted provided that the following conditions 40883c4be3SJerome Forissier * are met: 41883c4be3SJerome Forissier * 1. Redistributions of source code must retain the above copyright 42883c4be3SJerome Forissier * notice, this list of conditions and the following disclaimer. 43883c4be3SJerome Forissier * 2. Redistributions in binary form must reproduce the above copyright 44883c4be3SJerome Forissier * notice, this list of conditions and the following disclaimer in the 45883c4be3SJerome Forissier * documentation and/or other materials provided with the distribution. 46883c4be3SJerome Forissier * 4. Neither the name of the University nor the names of its contributors 47883c4be3SJerome Forissier * may be used to endorse or promote products derived from this software 48883c4be3SJerome Forissier * without specific prior written permission. 49883c4be3SJerome Forissier * 50883c4be3SJerome Forissier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51883c4be3SJerome Forissier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52883c4be3SJerome Forissier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53883c4be3SJerome Forissier * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54883c4be3SJerome Forissier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55883c4be3SJerome Forissier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56883c4be3SJerome Forissier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57883c4be3SJerome Forissier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58883c4be3SJerome Forissier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59883c4be3SJerome Forissier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60883c4be3SJerome Forissier * SUCH DAMAGE. 61883c4be3SJerome Forissier */ 62883c4be3SJerome Forissier 63883c4be3SJerome Forissier #include <assert.h> 64883c4be3SJerome Forissier #include <compiler.h> 65883c4be3SJerome Forissier #include <inttypes.h> 66883c4be3SJerome Forissier #include <malloc.h> 67883c4be3SJerome Forissier #include <stdint.h> 68883c4be3SJerome Forissier #include <string.h> 69883c4be3SJerome Forissier #include <tee_api_private.h> 70883c4be3SJerome Forissier #include <trace.h> 71883c4be3SJerome Forissier #include <user_ta_header.h> 72883c4be3SJerome Forissier #include <utee_types.h> 73883c4be3SJerome Forissier #include "gmon.h" 74883c4be3SJerome Forissier #include "gmon_out.h" 75883c4be3SJerome Forissier #include "gprof_pta.h" 76883c4be3SJerome Forissier 77883c4be3SJerome Forissier /* Defined by the linker script */ 78883c4be3SJerome Forissier extern uint8_t __gprof_buf_end[]; 79883c4be3SJerome Forissier extern uint8_t __gprof_buf_start[]; 80883c4be3SJerome Forissier 81883c4be3SJerome Forissier static bool ta_instrumented(void) 82883c4be3SJerome Forissier { 83883c4be3SJerome Forissier return (__gprof_buf_end != __gprof_buf_start); 84883c4be3SJerome Forissier } 85883c4be3SJerome Forissier 86883c4be3SJerome Forissier static void *gprof_alloc(size_t len) 87883c4be3SJerome Forissier { 88883c4be3SJerome Forissier if (len > (size_t)(__gprof_buf_end - __gprof_buf_start)) 89883c4be3SJerome Forissier return NULL; 90883c4be3SJerome Forissier return __gprof_buf_start; 91883c4be3SJerome Forissier } 92883c4be3SJerome Forissier 93883c4be3SJerome Forissier static struct gmonparam _gmonparam = { GMON_PROF_OFF }; 94883c4be3SJerome Forissier 95883c4be3SJerome Forissier static uint32_t _gprof_file_id; /* File id returned by tee-supplicant */ 96883c4be3SJerome Forissier 97883c4be3SJerome Forissier static int _gprof_s_scale; 98883c4be3SJerome Forissier #define SCALE_1_TO_1 0x10000L 99883c4be3SJerome Forissier 100883c4be3SJerome Forissier /* Adjust PC so that gprof can locate it in the TA ELF file */ 101883c4be3SJerome Forissier static unsigned long __noprof adjust_pc(unsigned long pc) 102883c4be3SJerome Forissier { 103883c4be3SJerome Forissier return pc - (unsigned long)__text_start + sizeof(struct ta_head); 104883c4be3SJerome Forissier } 105883c4be3SJerome Forissier 106883c4be3SJerome Forissier void __utee_gprof_init(void) 107883c4be3SJerome Forissier { 108883c4be3SJerome Forissier unsigned long lowpc; 109883c4be3SJerome Forissier unsigned long highpc; 110883c4be3SJerome Forissier struct gmonparam *p = &_gmonparam; 111883c4be3SJerome Forissier size_t bufsize; 112883c4be3SJerome Forissier TEE_Result res; 113883c4be3SJerome Forissier char *cp; 114883c4be3SJerome Forissier 115883c4be3SJerome Forissier if (!ta_instrumented()) 116883c4be3SJerome Forissier return; 117883c4be3SJerome Forissier 118883c4be3SJerome Forissier lowpc = adjust_pc((unsigned long)__text_start); 119883c4be3SJerome Forissier highpc = adjust_pc((unsigned long)__text_end); 120883c4be3SJerome Forissier 121883c4be3SJerome Forissier /* 122883c4be3SJerome Forissier * Round lowpc and highpc to multiples of the density we're using 123883c4be3SJerome Forissier * so the rest of the scaling (here and in gprof) stays in ints. 124883c4be3SJerome Forissier */ 125883c4be3SJerome Forissier p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 126883c4be3SJerome Forissier p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 127883c4be3SJerome Forissier p->textsize = p->highpc - p->lowpc; 128883c4be3SJerome Forissier p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); 129883c4be3SJerome Forissier p->hashfraction = HASHFRACTION; 130883c4be3SJerome Forissier p->log_hashfraction = -1; 131883c4be3SJerome Forissier /* 132883c4be3SJerome Forissier * The following test must be kept in sync with the corresponding 133883c4be3SJerome Forissier * test in __mcount_internal 134883c4be3SJerome Forissier */ 135883c4be3SJerome Forissier if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { 136883c4be3SJerome Forissier /* 137883c4be3SJerome Forissier * If HASHFRACTION is a power of two, mcount can use shifting 138883c4be3SJerome Forissier * instead of integer division. Precompute shift amount. 139883c4be3SJerome Forissier */ 140883c4be3SJerome Forissier p->log_hashfraction = __builtin_ffs(p->hashfraction * 141883c4be3SJerome Forissier sizeof(*p->froms)) - 1; 142883c4be3SJerome Forissier } 143883c4be3SJerome Forissier p->fromssize = p->textsize / HASHFRACTION; 144883c4be3SJerome Forissier p->tolimit = p->textsize * ARCDENSITY / 100; 145883c4be3SJerome Forissier if (p->tolimit < MINARCS) 146883c4be3SJerome Forissier p->tolimit = MINARCS; 147883c4be3SJerome Forissier else if (p->tolimit > MAXARCS) 148883c4be3SJerome Forissier p->tolimit = MAXARCS; 149883c4be3SJerome Forissier p->tossize = p->tolimit * sizeof(struct tostruct); 150883c4be3SJerome Forissier 151883c4be3SJerome Forissier bufsize = p->kcountsize + p->fromssize + p->tossize; 152883c4be3SJerome Forissier 153883c4be3SJerome Forissier IMSG("gprof: initializing"); 154883c4be3SJerome Forissier DMSG("TA text size: %zu, gprof buffer size: %zu", 155883c4be3SJerome Forissier __text_end - __text_start, bufsize); 156883c4be3SJerome Forissier 157883c4be3SJerome Forissier cp = gprof_alloc(bufsize); 158883c4be3SJerome Forissier if (!cp) { 159883c4be3SJerome Forissier EMSG("gprof: could not allocate profiling buffer"); 160883c4be3SJerome Forissier p->tos = NULL; 161883c4be3SJerome Forissier p->state = GMON_PROF_ERROR; 162883c4be3SJerome Forissier return; 163883c4be3SJerome Forissier } 164883c4be3SJerome Forissier 165883c4be3SJerome Forissier p->tos = (struct tostruct *)cp; 166883c4be3SJerome Forissier cp += p->tossize; 167883c4be3SJerome Forissier p->kcount = (HISTCOUNTER *)cp; 168883c4be3SJerome Forissier cp += p->kcountsize; 169883c4be3SJerome Forissier p->froms = (ARCINDEX *)cp; 170883c4be3SJerome Forissier 171883c4be3SJerome Forissier p->tos[0].link = 0; 172883c4be3SJerome Forissier 173883c4be3SJerome Forissier if (p->kcountsize < p->textsize) 174883c4be3SJerome Forissier _gprof_s_scale = ((float)p->kcountsize / p->textsize) * 175883c4be3SJerome Forissier SCALE_1_TO_1; 176883c4be3SJerome Forissier else 177883c4be3SJerome Forissier _gprof_s_scale = SCALE_1_TO_1; 178883c4be3SJerome Forissier 179883c4be3SJerome Forissier res = __pta_gprof_pc_sampling_start(p->kcount, p->kcountsize, 180883c4be3SJerome Forissier p->lowpc + 181883c4be3SJerome Forissier ((unsigned long)__text_start - 182883c4be3SJerome Forissier sizeof(struct ta_head)), 183883c4be3SJerome Forissier _gprof_s_scale); 184883c4be3SJerome Forissier if (res != TEE_SUCCESS) 185883c4be3SJerome Forissier EMSG("gprof: could not start PC sampling (0x%08x)", res); 186883c4be3SJerome Forissier 187883c4be3SJerome Forissier p->state = GMON_PROF_ON; 188883c4be3SJerome Forissier } 189883c4be3SJerome Forissier 190883c4be3SJerome Forissier static void _gprof_write_buf(void *buf, size_t size) 191883c4be3SJerome Forissier { 192883c4be3SJerome Forissier TEE_Result res; 193883c4be3SJerome Forissier 194883c4be3SJerome Forissier res = __pta_gprof_send(buf, size, &_gprof_file_id); 195883c4be3SJerome Forissier if (res != TEE_SUCCESS) 196883c4be3SJerome Forissier EMSG("gprof: could not send gprof data (0x%08x)", res); 197883c4be3SJerome Forissier } 198883c4be3SJerome Forissier 199883c4be3SJerome Forissier static void _gprof_write_header(void) 200883c4be3SJerome Forissier { 201883c4be3SJerome Forissier struct gmon_hdr ghdr; 202883c4be3SJerome Forissier size_t size = sizeof(struct gmon_hdr); 203883c4be3SJerome Forissier 204883c4be3SJerome Forissier memcpy(&ghdr.cookie[0], GMON_MAGIC, sizeof(ghdr.cookie)); 205883c4be3SJerome Forissier ghdr.version = GMON_VERSION; 206883c4be3SJerome Forissier memset(ghdr.spare, '\0', sizeof(ghdr.spare)); 207883c4be3SJerome Forissier 208883c4be3SJerome Forissier _gprof_write_buf(&ghdr, size); 209883c4be3SJerome Forissier } 210883c4be3SJerome Forissier 211883c4be3SJerome Forissier static void _gprof_write_hist(void) 212883c4be3SJerome Forissier { 213883c4be3SJerome Forissier struct out_record { 214883c4be3SJerome Forissier uint8_t tag; 215883c4be3SJerome Forissier struct gmon_hist_hdr hist_hdr; 216883c4be3SJerome Forissier } __packed out = { 217883c4be3SJerome Forissier .tag = GMON_TAG_TIME_HIST, 218883c4be3SJerome Forissier .hist_hdr = { 219883c4be3SJerome Forissier .low_pc = _gmonparam.lowpc, 220883c4be3SJerome Forissier .high_pc = _gmonparam.highpc, 221883c4be3SJerome Forissier .hist_size = _gmonparam.kcountsize/sizeof(HISTCOUNTER), 222883c4be3SJerome Forissier .prof_rate = _gmonparam.prof_rate, 223883c4be3SJerome Forissier .dimen = "seconds", 224883c4be3SJerome Forissier .dimen_abbrev = 's', 225883c4be3SJerome Forissier } 226883c4be3SJerome Forissier }; 227883c4be3SJerome Forissier 228883c4be3SJerome Forissier _gprof_write_buf(&out, sizeof(out)); 229883c4be3SJerome Forissier _gprof_write_buf(_gmonparam.kcount, _gmonparam.kcountsize); 230883c4be3SJerome Forissier } 231883c4be3SJerome Forissier 232883c4be3SJerome Forissier static void _gprof_write_call_graph(void) 233883c4be3SJerome Forissier { 234883c4be3SJerome Forissier #define NARCS_PER_WRITE 16 235883c4be3SJerome Forissier struct out_record { 236883c4be3SJerome Forissier uint8_t tag; 237883c4be3SJerome Forissier uint8_t data[sizeof(struct gmon_cg_arc_record)]; 238883c4be3SJerome Forissier } out[NARCS_PER_WRITE]; 239883c4be3SJerome Forissier struct gmon_cg_arc_record arc; 240883c4be3SJerome Forissier ARCINDEX from_index, to_index; 241883c4be3SJerome Forissier unsigned long from_len; 242883c4be3SJerome Forissier unsigned long frompc; 243883c4be3SJerome Forissier int nfilled = 0; 244883c4be3SJerome Forissier 245883c4be3SJerome Forissier from_len = _gmonparam.fromssize / sizeof(*_gmonparam.froms); 246883c4be3SJerome Forissier 247883c4be3SJerome Forissier for (from_index = 0; from_index < from_len; ++from_index) { 248883c4be3SJerome Forissier 249883c4be3SJerome Forissier if (_gmonparam.froms[from_index] == 0) 250883c4be3SJerome Forissier continue; 251883c4be3SJerome Forissier 252883c4be3SJerome Forissier frompc = _gmonparam.lowpc; 253883c4be3SJerome Forissier frompc += (from_index * _gmonparam.hashfraction 254883c4be3SJerome Forissier * sizeof(*_gmonparam.froms)); 255883c4be3SJerome Forissier for (to_index = _gmonparam.froms[from_index]; 256883c4be3SJerome Forissier to_index != 0; 257883c4be3SJerome Forissier to_index = _gmonparam.tos[to_index].link) { 258883c4be3SJerome Forissier 259883c4be3SJerome Forissier arc.from_pc = frompc; 260883c4be3SJerome Forissier arc.self_pc = _gmonparam.tos[to_index].selfpc; 261883c4be3SJerome Forissier arc.count = _gmonparam.tos[to_index].count; 262883c4be3SJerome Forissier 263883c4be3SJerome Forissier out[nfilled].tag = GMON_TAG_CG_ARC; 264883c4be3SJerome Forissier memcpy(out[nfilled].data, &arc, sizeof(arc)); 265883c4be3SJerome Forissier 266883c4be3SJerome Forissier if (++nfilled == NARCS_PER_WRITE) { 267883c4be3SJerome Forissier _gprof_write_buf(out, sizeof(out)); 268883c4be3SJerome Forissier nfilled = 0; 269883c4be3SJerome Forissier } 270883c4be3SJerome Forissier } 271883c4be3SJerome Forissier } 272883c4be3SJerome Forissier if (nfilled > 0) 273883c4be3SJerome Forissier _gprof_write_buf(out, nfilled * sizeof(out[0])); 274883c4be3SJerome Forissier } 275883c4be3SJerome Forissier 276883c4be3SJerome Forissier /* Stop profiling and send profile data in gmon.out format to Normal World */ 277883c4be3SJerome Forissier void __utee_gprof_fini(void) 278883c4be3SJerome Forissier { 279883c4be3SJerome Forissier TEE_Result res; 280883c4be3SJerome Forissier 281883c4be3SJerome Forissier if (_gmonparam.state != GMON_PROF_ON) 282883c4be3SJerome Forissier return; 283883c4be3SJerome Forissier 284883c4be3SJerome Forissier /* Stop call graph tracing */ 285883c4be3SJerome Forissier _gmonparam.state = GMON_PROF_OFF_EXITING; 286883c4be3SJerome Forissier 287883c4be3SJerome Forissier /* Stop TA sampling */ 288883c4be3SJerome Forissier res = __pta_gprof_pc_sampling_stop(&_gmonparam.prof_rate); 289883c4be3SJerome Forissier 290883c4be3SJerome Forissier _gprof_write_header(); 291883c4be3SJerome Forissier if (res == TEE_SUCCESS) 292883c4be3SJerome Forissier _gprof_write_hist(); 293883c4be3SJerome Forissier _gprof_write_call_graph(); 294883c4be3SJerome Forissier 295883c4be3SJerome Forissier __pta_gprof_fini(); 296883c4be3SJerome Forissier } 297883c4be3SJerome Forissier 298883c4be3SJerome Forissier /* 299883c4be3SJerome Forissier * Called from the assembly stub (_mcount or __gnu_mcount_nc). 300883c4be3SJerome Forissier * 301883c4be3SJerome Forissier * __mcount_internal updates data structures that represent traversals of the 302883c4be3SJerome Forissier * program's call graph edges. frompc and selfpc are the return 303883c4be3SJerome Forissier * address and function address that represents the given call graph edge. 304883c4be3SJerome Forissier */ 305883c4be3SJerome Forissier void __noprof __mcount_internal(unsigned long frompc, unsigned long selfpc) 306883c4be3SJerome Forissier { 307883c4be3SJerome Forissier ARCINDEX *frompcindex; 308883c4be3SJerome Forissier struct tostruct *top, *prevtop; 309883c4be3SJerome Forissier struct gmonparam *p; 310883c4be3SJerome Forissier ARCINDEX toindex; 311883c4be3SJerome Forissier int i; 312883c4be3SJerome Forissier 313883c4be3SJerome Forissier p = &_gmonparam; 314883c4be3SJerome Forissier 315883c4be3SJerome Forissier /* 316883c4be3SJerome Forissier * Check that we are profiling and that we aren't recursively invoked. 317883c4be3SJerome Forissier */ 318883c4be3SJerome Forissier if (p->state != GMON_PROF_ON) 319883c4be3SJerome Forissier return; 320883c4be3SJerome Forissier p->state = GMON_PROF_BUSY; 321883c4be3SJerome Forissier 322883c4be3SJerome Forissier frompc = adjust_pc(frompc); 323883c4be3SJerome Forissier selfpc = adjust_pc(selfpc); 324883c4be3SJerome Forissier 325883c4be3SJerome Forissier /* Check that frompcindex is a reasonable pc value. */ 326883c4be3SJerome Forissier frompc -= p->lowpc; 327883c4be3SJerome Forissier if (frompc > p->textsize) 328883c4be3SJerome Forissier goto done; 329883c4be3SJerome Forissier 330883c4be3SJerome Forissier /* Note: keep in sync. with the initialization function above */ 331883c4be3SJerome Forissier if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { 332883c4be3SJerome Forissier /* Avoid integer divide if possible */ 333883c4be3SJerome Forissier i = frompc >> p->log_hashfraction; 334883c4be3SJerome Forissier } else { 335883c4be3SJerome Forissier i = frompc / (p->hashfraction * sizeof(*p->froms)); 336883c4be3SJerome Forissier } 337883c4be3SJerome Forissier frompcindex = &p->froms[i]; 338883c4be3SJerome Forissier toindex = *frompcindex; 339883c4be3SJerome Forissier if (toindex == 0) { 340883c4be3SJerome Forissier /* First time traversing this arc */ 341883c4be3SJerome Forissier toindex = ++p->tos[0].link; 342883c4be3SJerome Forissier if (toindex >= p->tolimit) { 343883c4be3SJerome Forissier /* Halt further profiling */ 344883c4be3SJerome Forissier goto overflow; 345883c4be3SJerome Forissier } 346883c4be3SJerome Forissier 347883c4be3SJerome Forissier *frompcindex = toindex; 348883c4be3SJerome Forissier top = &p->tos[toindex]; 349883c4be3SJerome Forissier top->selfpc = selfpc; 350883c4be3SJerome Forissier top->count = 1; 351883c4be3SJerome Forissier top->link = 0; 352883c4be3SJerome Forissier goto done; 353883c4be3SJerome Forissier } 354883c4be3SJerome Forissier top = &p->tos[toindex]; 355883c4be3SJerome Forissier if (top->selfpc == selfpc) { 356883c4be3SJerome Forissier /* Arc at front of chain; usual case */ 357883c4be3SJerome Forissier top->count++; 358883c4be3SJerome Forissier goto done; 359883c4be3SJerome Forissier } 360883c4be3SJerome Forissier /* 361883c4be3SJerome Forissier * Have to go looking down chain for it. 362883c4be3SJerome Forissier * top points to what we are looking at, 363883c4be3SJerome Forissier * prevtop points to previous top. 364883c4be3SJerome Forissier * we know it is not at the head of the chain. 365883c4be3SJerome Forissier */ 366883c4be3SJerome Forissier for (;;) { 367883c4be3SJerome Forissier if (top->link == 0) { 368883c4be3SJerome Forissier /* 369883c4be3SJerome Forissier * top is end of the chain and none of the chain 370883c4be3SJerome Forissier * had top->selfpc == selfpc. 371883c4be3SJerome Forissier * so we allocate a new tostruct 372883c4be3SJerome Forissier * and link it to the head of the chain. 373883c4be3SJerome Forissier */ 374883c4be3SJerome Forissier toindex = ++p->tos[0].link; 375883c4be3SJerome Forissier if (toindex >= p->tolimit) 376883c4be3SJerome Forissier goto overflow; 377883c4be3SJerome Forissier 378883c4be3SJerome Forissier top = &p->tos[toindex]; 379883c4be3SJerome Forissier top->selfpc = selfpc; 380883c4be3SJerome Forissier top->count = 1; 381883c4be3SJerome Forissier top->link = *frompcindex; 382883c4be3SJerome Forissier *frompcindex = toindex; 383883c4be3SJerome Forissier goto done; 384883c4be3SJerome Forissier } 385883c4be3SJerome Forissier /* 386883c4be3SJerome Forissier * Otherwise, check the next arc on the chain. 387883c4be3SJerome Forissier */ 388883c4be3SJerome Forissier prevtop = top; 389883c4be3SJerome Forissier top = &p->tos[top->link]; 390883c4be3SJerome Forissier if (top->selfpc == selfpc) { 391883c4be3SJerome Forissier /* 392883c4be3SJerome Forissier * There it is. Increment its count, move it to the 393883c4be3SJerome Forissier * head of the chain. 394883c4be3SJerome Forissier */ 395883c4be3SJerome Forissier top->count++; 396883c4be3SJerome Forissier toindex = prevtop->link; 397883c4be3SJerome Forissier prevtop->link = top->link; 398883c4be3SJerome Forissier top->link = *frompcindex; 399883c4be3SJerome Forissier *frompcindex = toindex; 400883c4be3SJerome Forissier goto done; 401883c4be3SJerome Forissier } 402883c4be3SJerome Forissier } 403883c4be3SJerome Forissier done: 404883c4be3SJerome Forissier p->state = GMON_PROF_ON; 405883c4be3SJerome Forissier return; 406883c4be3SJerome Forissier overflow: 407883c4be3SJerome Forissier p->state = GMON_PROF_ERROR; 408883c4be3SJerome Forissier } 409