hwpmc_x86.c (174071) | hwpmc_x86.c (174395) |
---|---|
1/*- 2 * Copyright (c) 2005, Joseph Koshy | 1/*- 2 * Copyright (c) 2005, Joseph Koshy |
3 * Copyright (c) 2007 The FreeBSD Foundation |
|
3 * All rights reserved. 4 * | 4 * All rights reserved. 5 * |
6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * |
|
5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. --- 7 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> | 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. --- 7 unchanged lines hidden (view full) --- 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 174071 2007-11-29 06:43:58Z jkoshy $"); | 32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_x86.c 174395 2007-12-07 08:20:17Z jkoshy $"); |
29 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/pmc.h> | 33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/pmc.h> |
37#include <sys/proc.h> |
|
33#include <sys/systm.h> 34 | 38#include <sys/systm.h> 39 |
40#include <machine/cpu.h> |
|
35#include <machine/apicreg.h> 36#include <machine/pmc_mdep.h> 37#include <machine/md_var.h> 38 | 41#include <machine/apicreg.h> 42#include <machine/pmc_mdep.h> 43#include <machine/md_var.h> 44 |
45#include <vm/vm.h> 46#include <vm/vm_param.h> 47#include <vm/pmap.h> 48 |
|
39extern volatile lapic_t *lapic; 40 41void 42pmc_x86_lapic_enable_pmc_interrupt(void) 43{ 44 uint32_t value; 45 46 value = lapic->lvt_pcint; 47 value &= ~APIC_LVT_M; 48 lapic->lvt_pcint = value; 49} 50 | 49extern volatile lapic_t *lapic; 50 51void 52pmc_x86_lapic_enable_pmc_interrupt(void) 53{ 54 uint32_t value; 55 56 value = lapic->lvt_pcint; 57 value &= ~APIC_LVT_M; 58 lapic->lvt_pcint = value; 59} 60 |
61/* 62 * Attempt to walk a user call stack using a too-simple algorithm. 63 * In the general case we need unwind information associated with 64 * the executable to be able to walk the user stack. 65 * 66 * We are handed a trap frame laid down at the time the PMC interrupt 67 * was taken. If the application is using frame pointers, the saved 68 * PC value could be: 69 * a. at the beginning of a function before the stack frame is laid 70 * down, 71 * b. just before a 'ret', after the stack frame has been taken off, 72 * c. somewhere else in the function with a valid stack frame being 73 * present, 74 * 75 * If the application is not using frame pointers, this algorithm will 76 * fail to yield an interesting call chain. 77 * 78 * TODO: figure out a way to use unwind information. 79 */ |
|
51 | 80 |
81int 82pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf) 83{ 84 int n; 85 uint32_t instr; 86 uintptr_t fp, oldfp, pc, r, sp; 87 88 KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p", 89 __LINE__, (void *) tf)); 90 91 pc = PMC_TRAPFRAME_TO_PC(tf); 92 oldfp = fp = PMC_TRAPFRAME_TO_FP(tf); 93 sp = PMC_TRAPFRAME_TO_SP(tf); 94 95 *cc++ = pc; n = 1; 96 97 r = fp + sizeof(uintptr_t); /* points to return address */ 98 99 if (!PMC_IN_USERSPACE(pc)) 100 return (n); 101 102 if (copyin((void *) pc, &instr, sizeof(instr)) != 0) 103 return (n); 104 105 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) || 106 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) { /* ret */ 107 if (copyin((void *) sp, &pc, sizeof(pc)) != 0) 108 return (n); 109 } else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) { 110 sp += sizeof(uintptr_t); 111 if (copyin((void *) sp, &pc, sizeof(pc)) != 0) 112 return (n); 113 } else if (copyin((void *) r, &pc, sizeof(pc)) != 0 || 114 copyin((void *) fp, &fp, sizeof(fp) != 0)) 115 return (n); 116 117 for (; n < nframes;) { 118 if (pc == 0 || !PMC_IN_USERSPACE(pc)) 119 break; 120 121 *cc++ = pc; n++; 122 123 if (fp < oldfp) 124 break; 125 126 r = fp + sizeof(uintptr_t); /* address of return address */ 127 oldfp = fp; 128 129 if (copyin((void *) r, &pc, sizeof(pc)) != 0 || 130 copyin((void *) fp, &fp, sizeof(fp)) != 0) 131 break; 132 } 133 134 return (n); 135} 136 137/* 138 * Walking the kernel call stack. 139 * 140 * We are handed the trap frame laid down at the time the PMC 141 * interrupt was taken. The saved PC could be: 142 * a. in the lowlevel trap handler, meaning that there isn't a C stack 143 * to traverse, 144 * b. at the beginning of a function before the stack frame is laid 145 * down, 146 * c. just before a 'ret', after the stack frame has been taken off, 147 * d. somewhere else in a function with a valid stack frame being 148 * present. 149 * 150 * In case (d), the previous frame pointer is at [%ebp]/[%rbp] and 151 * the return address is at [%ebp+4]/[%rbp+8]. 152 * 153 * For cases (b) and (c), the return address is at [%esp]/[%rsp] and 154 * the frame pointer doesn't need to be changed when going up one 155 * level in the stack. 156 * 157 * For case (a), we check if the PC lies in low-level trap handling 158 * code, and if so we terminate our trace. 159 */ 160 161int 162pmc_save_kernel_callchain(uintptr_t *cc, int nframes, struct trapframe *tf) 163{ 164 int n; 165 uint32_t instr; 166 uintptr_t fp, pc, r, sp, stackstart, stackend; 167 struct thread *td; 168 169 KASSERT(TRAPF_USERMODE(tf) == 0,("[x86,%d] not a kernel backtrace", 170 __LINE__)); 171 172 pc = PMC_TRAPFRAME_TO_PC(tf); 173 fp = PMC_TRAPFRAME_TO_FP(tf); 174 sp = PMC_TRAPFRAME_TO_SP(tf); 175 176 *cc++ = pc; 177 r = fp + sizeof(uintptr_t); /* points to return address */ 178 179 if ((td = curthread) == NULL) 180 return (1); 181 182 if (nframes <= 1) 183 return (1); 184 185 stackstart = (uintptr_t) td->td_kstack; 186 stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE; 187 188 if (PMC_IN_TRAP_HANDLER(pc) || 189 !PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL(r) || 190 !PMC_IN_KERNEL_STACK(sp, stackstart, stackend) || 191 !PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) 192 return (1); 193 194 instr = *(uint32_t *) pc; 195 196 /* 197 * Determine whether the interrupted function was in the 198 * processing of either laying down its stack frame or taking 199 * it off. 200 * 201 * If we haven't started laying down a stack frame, or are 202 * just about to return, then our caller's address is at 203 * *sp, and we don't have a frame to unwind. 204 */ 205 if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) || 206 PMC_AT_FUNCTION_EPILOGUE_RET(instr)) 207 pc = *(uintptr_t *) sp; 208 else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) { 209 /* 210 * The code was midway through laying down a frame. 211 * At this point sp[0] has a frame back pointer, 212 * and the caller's address is therefore at sp[1]. 213 */ 214 sp += sizeof(uintptr_t); 215 if (!PMC_IN_KERNEL_STACK(sp, stackstart, stackend)) 216 return (1); 217 pc = *(uintptr_t *) sp; 218 } else { 219 /* 220 * Not in the function prologue or epilogue. 221 */ 222 pc = *(uintptr_t *) r; 223 fp = *(uintptr_t *) fp; 224 } 225 226 for (n = 1; n < nframes; n++) { 227 *cc++ = pc; 228 229 if (PMC_IN_TRAP_HANDLER(pc)) 230 break; 231 232 r = fp + sizeof(uintptr_t); 233 if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend) || 234 !PMC_IN_KERNEL(r)) 235 break; 236 pc = *(uintptr_t *) r; 237 fp = *(uintptr_t *) fp; 238 } 239 240 return (n); 241} 242 |
|
52static struct pmc_mdep * 53pmc_intel_initialize(void) 54{ 55 struct pmc_mdep *pmc_mdep; 56 enum pmc_cputype cputype; 57 int error, model; 58 59 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0, --- 130 unchanged lines hidden --- | 243static struct pmc_mdep * 244pmc_intel_initialize(void) 245{ 246 struct pmc_mdep *pmc_mdep; 247 enum pmc_cputype cputype; 248 int error, model; 249 250 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0, --- 130 unchanged lines hidden --- |