1/* $OpenBSD: db_prof.c,v 1.5 2021/09/03 16:45:45 jasper Exp $ */ 2 3/*- 4 * Copyright (c) 1983, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/proc.h> 34#include <sys/queue.h> 35#include <sys/exec_elf.h> 36#include <sys/malloc.h> 37#include <sys/gmon.h> 38 39#include <machine/db_machdep.h> 40#include <ddb/db_extern.h> 41#include <ddb/db_sym.h> 42 43#include "dt.h" /* for NDT */ 44 45#if NDT > 0 46#include <dev/dt/dtvar.h> 47#endif 48 49extern int db_profile; /* Allow dynamic profiling */ 50int db_prof_on; /* Profiling state On/Off */ 51 52void dt_prov_kprobe_patch_all_entry(void); 53void dt_prov_kprobe_depatch_all_entry(void); 54 55vaddr_t db_get_probe_addr(struct trapframe *); 56vaddr_t db_get_pc(struct trapframe *); 57 58int 59db_prof_enable(void) 60{ 61#if NDT > 0 62 if (!db_profile) 63 return EPERM; 64 65 dt_prov_kprobe_patch_all_entry(); 66 db_prof_on = 1; 67 return 0; 68#else 69 return ENOENT; 70#endif /* NDT > 0 */ 71} 72 73void 74db_prof_disable(void) 75{ 76#if NDT > 0 77 db_prof_on = 0; 78 dt_prov_kprobe_depatch_all_entry(); 79#endif /* NDT > 0 */ 80} 81 82/* 83 * Equivalent to mcount(), must be called with interrupt disabled. 84 */ 85void 86db_prof_count(struct trapframe *frame) 87{ 88 unsigned short *frompcindex; 89 struct tostruct *top, *prevtop; 90 struct gmonparam *p; 91 long toindex; 92 unsigned long frompc, selfpc; 93 94 if ((p = curcpu()->ci_gmon) == NULL) 95 return; 96 97 /* 98 * check that we are profiling 99 * and that we aren't recursively invoked. 100 */ 101 if (p->state != GMON_PROF_ON) 102 return; 103 104 frompc = db_get_pc(frame); 105 selfpc = db_get_probe_addr(frame); 106 107 /* 108 * check that frompcindex is a reasonable pc value. 109 * for example: signal catchers get called from the stack, 110 * not from text space. too bad. 111 */ 112 frompc -= p->lowpc; 113 if (frompc > p->textsize) 114 return; 115 116#if (HASHFRACTION & (HASHFRACTION - 1)) == 0 117 if (p->hashfraction == HASHFRACTION) 118 frompcindex = 119 &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; 120 else 121#endif 122 frompcindex = 123 &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; 124 toindex = *frompcindex; 125 if (toindex == 0) { 126 /* 127 * first time traversing this arc 128 */ 129 toindex = ++p->tos[0].link; 130 if (toindex >= p->tolimit) 131 /* halt further profiling */ 132 goto overflow; 133 134 *frompcindex = toindex; 135 top = &p->tos[toindex]; 136 top->selfpc = selfpc; 137 top->count = 1; 138 top->link = 0; 139 return; 140 } 141 top = &p->tos[toindex]; 142 if (top->selfpc == selfpc) { 143 /* 144 * arc at front of chain; usual case. 145 */ 146 top->count++; 147 return; 148 } 149 /* 150 * have to go looking down chain for it. 151 * top points to what we are looking at, 152 * prevtop points to previous top. 153 * we know it is not at the head of the chain. 154 */ 155 for (; /* return */; ) { 156 if (top->link == 0) { 157 /* 158 * top is end of the chain and none of the chain 159 * had top->selfpc == selfpc. 160 * so we allocate a new tostruct 161 * and link it to the head of the chain. 162 */ 163 toindex = ++p->tos[0].link; 164 if (toindex >= p->tolimit) 165 goto overflow; 166 167 top = &p->tos[toindex]; 168 top->selfpc = selfpc; 169 top->count = 1; 170 top->link = *frompcindex; 171 *frompcindex = toindex; 172 return; 173 } 174 /* 175 * otherwise, check the next arc on the chain. 176 */ 177 prevtop = top; 178 top = &p->tos[top->link]; 179 if (top->selfpc == selfpc) { 180 /* 181 * there it is. 182 * increment its count 183 * move it to the head of the chain. 184 */ 185 top->count++; 186 toindex = prevtop->link; 187 prevtop->link = top->link; 188 top->link = *frompcindex; 189 *frompcindex = toindex; 190 return; 191 } 192 } 193 194overflow: 195 p->state = GMON_PROF_ERROR; 196} 197