1147191Sjkoshy/*- 2147191Sjkoshy * Copyright (c) 2005, Joseph Koshy 3147191Sjkoshy * All rights reserved. 4147191Sjkoshy * 5147191Sjkoshy * Redistribution and use in source and binary forms, with or without 6147191Sjkoshy * modification, are permitted provided that the following conditions 7147191Sjkoshy * are met: 8147191Sjkoshy * 1. Redistributions of source code must retain the above copyright 9147191Sjkoshy * notice, this list of conditions and the following disclaimer. 10147191Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11147191Sjkoshy * notice, this list of conditions and the following disclaimer in the 12147191Sjkoshy * documentation and/or other materials provided with the distribution. 13147191Sjkoshy * 14147191Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15147191Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16147191Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17147191Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18147191Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19147191Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20147191Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21147191Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22147191Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23147191Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24147191Sjkoshy * SUCH DAMAGE. 25147191Sjkoshy * 26147191Sjkoshy */ 27147191Sjkoshy 28147191Sjkoshy#include <sys/cdefs.h> 29147191Sjkoshy__FBSDID("$FreeBSD$"); 30147191Sjkoshy 31147191Sjkoshy#include <sys/param.h> 32147191Sjkoshy#include <sys/pmc.h> 33236997Sfabient#include <sys/proc.h> 34200928Srpaulo#include <sys/systm.h> 35147191Sjkoshy 36236997Sfabient#include <machine/cpu.h> 37236997Sfabient#include <machine/md_var.h> 38147191Sjkoshy#include <machine/pmc_mdep.h> 39147191Sjkoshy 40236997Sfabient#include <vm/vm.h> 41236997Sfabient#include <vm/vm_param.h> 42236997Sfabient#include <vm/pmap.h> 43236997Sfabient 44147191Sjkoshystruct pmc_mdep * 45147191Sjkoshypmc_md_initialize() 46147191Sjkoshy{ 47235831Sfabient#ifdef CPU_XSCALE_IXP425 48200928Srpaulo if (cpu_class == CPU_CLASS_XSCALE) 49200928Srpaulo return pmc_xscale_initialize(); 50200928Srpaulo else 51235831Sfabient#endif 52200928Srpaulo return NULL; 53147191Sjkoshy} 54174410Sjkoshy 55185168Sjkoshyvoid 56185168Sjkoshypmc_md_finalize(struct pmc_mdep *md) 57185168Sjkoshy{ 58235831Sfabient#ifdef CPU_XSCALE_IXP425 59200928Srpaulo if (cpu_class == CPU_CLASS_XSCALE) 60200928Srpaulo pmc_xscale_finalize(md); 61200928Srpaulo else 62200928Srpaulo KASSERT(0, ("[arm,%d] Unknown CPU Class 0x%x", __LINE__, 63200928Srpaulo cpu_class)); 64235831Sfabient#endif 65185168Sjkoshy} 66185168Sjkoshy 67174410Sjkoshyint 68174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, 69174410Sjkoshy struct trapframe *tf) 70174410Sjkoshy{ 71236997Sfabient uintptr_t pc, r, stackstart, stackend, fp; 72236997Sfabient struct thread *td; 73236997Sfabient int count; 74235831Sfabient 75236997Sfabient KASSERT(TRAPF_USERMODE(tf) == 0,("[arm,%d] not a kernel backtrace", 76236997Sfabient __LINE__)); 77236997Sfabient 78240475Sattilio td = curthread; 79236997Sfabient pc = PMC_TRAPFRAME_TO_PC(tf); 80236997Sfabient *cc++ = pc; 81236997Sfabient 82236997Sfabient if (maxsamples <= 1) 83236997Sfabient return (1); 84236997Sfabient 85236997Sfabient stackstart = (uintptr_t) td->td_kstack; 86236997Sfabient stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE; 87236997Sfabient fp = PMC_TRAPFRAME_TO_FP(tf); 88236997Sfabient 89236997Sfabient if (!PMC_IN_KERNEL(pc) || 90236997Sfabient !PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) 91236997Sfabient return (1); 92236997Sfabient 93236997Sfabient for (count = 1; count < maxsamples; count++) { 94236997Sfabient /* Use saved lr as pc. */ 95236997Sfabient r = fp - sizeof(uintptr_t); 96236997Sfabient if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend)) 97236997Sfabient break; 98236997Sfabient pc = *(uintptr_t *)r; 99236997Sfabient if (!PMC_IN_KERNEL(pc)) 100236997Sfabient break; 101236997Sfabient 102236997Sfabient *cc++ = pc; 103236997Sfabient 104236997Sfabient /* Switch to next frame up */ 105236997Sfabient r = fp - 3 * sizeof(uintptr_t); 106236997Sfabient if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend)) 107236997Sfabient break; 108236997Sfabient fp = *(uintptr_t *)r; 109236997Sfabient if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) 110236997Sfabient break; 111236997Sfabient } 112236997Sfabient 113236997Sfabient return (count); 114174410Sjkoshy} 115174410Sjkoshy 116174410Sjkoshyint 117174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples, 118174410Sjkoshy struct trapframe *tf) 119174410Sjkoshy{ 120236997Sfabient uintptr_t pc, r, oldfp, fp; 121236997Sfabient struct thread *td; 122236997Sfabient int count; 123235831Sfabient 124236997Sfabient KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p", 125236997Sfabient __LINE__, (void *) tf)); 126236997Sfabient 127240475Sattilio td = curthread; 128236997Sfabient pc = PMC_TRAPFRAME_TO_PC(tf); 129236997Sfabient *cc++ = pc; 130236997Sfabient 131236997Sfabient if (maxsamples <= 1) 132236997Sfabient return (1); 133236997Sfabient 134236997Sfabient oldfp = fp = PMC_TRAPFRAME_TO_FP(tf); 135236997Sfabient 136236997Sfabient if (!PMC_IN_USERSPACE(pc) || 137236997Sfabient !PMC_IN_USERSPACE(fp)) 138236997Sfabient return (1); 139236997Sfabient 140236997Sfabient for (count = 1; count < maxsamples; count++) { 141236997Sfabient /* Use saved lr as pc. */ 142236997Sfabient r = fp - sizeof(uintptr_t); 143236997Sfabient if (copyin((void *)r, &pc, sizeof(pc)) != 0) 144236997Sfabient break; 145236997Sfabient if (!PMC_IN_USERSPACE(pc)) 146236997Sfabient break; 147236997Sfabient 148236997Sfabient *cc++ = pc; 149236997Sfabient 150236997Sfabient /* Switch to next frame up */ 151236997Sfabient oldfp = fp; 152236997Sfabient r = fp - 3 * sizeof(uintptr_t); 153236997Sfabient if (copyin((void *)r, &fp, sizeof(fp)) != 0) 154236997Sfabient break; 155236997Sfabient if (fp < oldfp || !PMC_IN_USERSPACE(fp)) 156236997Sfabient break; 157236997Sfabient } 158236997Sfabient 159236997Sfabient return (count); 160174410Sjkoshy} 161