1*8eb20f36SRui Paulo /* 2*8eb20f36SRui Paulo * Copyright (c) 2010 The FreeBSD Foundation 3*8eb20f36SRui Paulo * All rights reserved. 4*8eb20f36SRui Paulo * 5*8eb20f36SRui Paulo * This software was developed by Rui Paulo under sponsorship from the 6*8eb20f36SRui Paulo * FreeBSD Foundation. 7*8eb20f36SRui Paulo * 8*8eb20f36SRui Paulo * Redistribution and use in source and binary forms, with or without 9*8eb20f36SRui Paulo * modification, are permitted provided that the following conditions 10*8eb20f36SRui Paulo * are met: 11*8eb20f36SRui Paulo * 1. Redistributions of source code must retain the above copyright 12*8eb20f36SRui Paulo * notice, this list of conditions and the following disclaimer. 13*8eb20f36SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 14*8eb20f36SRui Paulo * notice, this list of conditions and the following disclaimer in the 15*8eb20f36SRui Paulo * documentation and/or other materials provided with the distribution. 16*8eb20f36SRui Paulo * 17*8eb20f36SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*8eb20f36SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*8eb20f36SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*8eb20f36SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*8eb20f36SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*8eb20f36SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*8eb20f36SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*8eb20f36SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*8eb20f36SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*8eb20f36SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*8eb20f36SRui Paulo * SUCH DAMAGE. 28*8eb20f36SRui Paulo */ 29*8eb20f36SRui Paulo 30*8eb20f36SRui Paulo #include <sys/cdefs.h> 31*8eb20f36SRui Paulo __FBSDID("$FreeBSD$"); 32*8eb20f36SRui Paulo 33*8eb20f36SRui Paulo #include <sys/types.h> 34*8eb20f36SRui Paulo #include <sys/ptrace.h> 35*8eb20f36SRui Paulo #include <sys/wait.h> 36*8eb20f36SRui Paulo #include <machine/_inttypes.h> 37*8eb20f36SRui Paulo 38*8eb20f36SRui Paulo #include <assert.h> 39*8eb20f36SRui Paulo #include <err.h> 40*8eb20f36SRui Paulo #include <stdio.h> 41*8eb20f36SRui Paulo #include <errno.h> 42*8eb20f36SRui Paulo #include "_libproc.h" 43*8eb20f36SRui Paulo 44*8eb20f36SRui Paulo #if defined(__i386__) || defined(__amd64__) 45*8eb20f36SRui Paulo #define BREAKPOINT_INSTR 0xcc /* int 0x3 */ 46*8eb20f36SRui Paulo #define BREAKPOINT_INSTR_SZ 1 47*8eb20f36SRui Paulo #else 48*8eb20f36SRui Paulo #error "Add support for your architecture" 49*8eb20f36SRui Paulo #endif 50*8eb20f36SRui Paulo 51*8eb20f36SRui Paulo int 52*8eb20f36SRui Paulo proc_bkptset(struct proc_handle *phdl, uintptr_t address, 53*8eb20f36SRui Paulo unsigned long *saved) 54*8eb20f36SRui Paulo { 55*8eb20f36SRui Paulo struct ptrace_io_desc piod; 56*8eb20f36SRui Paulo unsigned long paddr, caddr; 57*8eb20f36SRui Paulo 58*8eb20f36SRui Paulo *saved = 0; 59*8eb20f36SRui Paulo if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || 60*8eb20f36SRui Paulo phdl->status == PS_IDLE) { 61*8eb20f36SRui Paulo errno = ENOENT; 62*8eb20f36SRui Paulo return (-1); 63*8eb20f36SRui Paulo } 64*8eb20f36SRui Paulo 65*8eb20f36SRui Paulo /* 66*8eb20f36SRui Paulo * Read the original instruction. 67*8eb20f36SRui Paulo */ 68*8eb20f36SRui Paulo caddr = address; 69*8eb20f36SRui Paulo paddr = 0; 70*8eb20f36SRui Paulo piod.piod_op = PIOD_READ_I; 71*8eb20f36SRui Paulo piod.piod_offs = (void *)caddr; 72*8eb20f36SRui Paulo piod.piod_addr = &paddr; 73*8eb20f36SRui Paulo piod.piod_len = BREAKPOINT_INSTR_SZ; 74*8eb20f36SRui Paulo if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { 75*8eb20f36SRui Paulo DPRINTF("ERROR: couldn't read instruction at address 0x%" PRIuPTR, 76*8eb20f36SRui Paulo address); 77*8eb20f36SRui Paulo return (-1); 78*8eb20f36SRui Paulo } 79*8eb20f36SRui Paulo *saved = paddr; 80*8eb20f36SRui Paulo /* 81*8eb20f36SRui Paulo * Write a breakpoint instruction to that address. 82*8eb20f36SRui Paulo */ 83*8eb20f36SRui Paulo caddr = address; 84*8eb20f36SRui Paulo paddr = BREAKPOINT_INSTR; 85*8eb20f36SRui Paulo piod.piod_op = PIOD_WRITE_I; 86*8eb20f36SRui Paulo piod.piod_offs = (void *)caddr; 87*8eb20f36SRui Paulo piod.piod_addr = &paddr; 88*8eb20f36SRui Paulo piod.piod_len = BREAKPOINT_INSTR_SZ; 89*8eb20f36SRui Paulo if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { 90*8eb20f36SRui Paulo warn("ERROR: couldn't write instruction at address 0x%" PRIuPTR, 91*8eb20f36SRui Paulo address); 92*8eb20f36SRui Paulo return (-1); 93*8eb20f36SRui Paulo } 94*8eb20f36SRui Paulo 95*8eb20f36SRui Paulo return (0); 96*8eb20f36SRui Paulo } 97*8eb20f36SRui Paulo 98*8eb20f36SRui Paulo int 99*8eb20f36SRui Paulo proc_bkptdel(struct proc_handle *phdl, uintptr_t address, 100*8eb20f36SRui Paulo unsigned long saved) 101*8eb20f36SRui Paulo { 102*8eb20f36SRui Paulo struct ptrace_io_desc piod; 103*8eb20f36SRui Paulo unsigned long paddr, caddr; 104*8eb20f36SRui Paulo 105*8eb20f36SRui Paulo if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || 106*8eb20f36SRui Paulo phdl->status == PS_IDLE) { 107*8eb20f36SRui Paulo errno = ENOENT; 108*8eb20f36SRui Paulo return (-1); 109*8eb20f36SRui Paulo } 110*8eb20f36SRui Paulo DPRINTF("removing breakpoint at 0x%lx\n", address); 111*8eb20f36SRui Paulo /* 112*8eb20f36SRui Paulo * Overwrite the breakpoint instruction that we setup previously. 113*8eb20f36SRui Paulo */ 114*8eb20f36SRui Paulo caddr = address; 115*8eb20f36SRui Paulo paddr = saved; 116*8eb20f36SRui Paulo piod.piod_op = PIOD_WRITE_I; 117*8eb20f36SRui Paulo piod.piod_offs = (void *)caddr; 118*8eb20f36SRui Paulo piod.piod_addr = &paddr; 119*8eb20f36SRui Paulo piod.piod_len = BREAKPOINT_INSTR_SZ; 120*8eb20f36SRui Paulo if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { 121*8eb20f36SRui Paulo DPRINTF("ERROR: couldn't write instruction at address 0x%" PRIuPTR, 122*8eb20f36SRui Paulo address); 123*8eb20f36SRui Paulo return (-1); 124*8eb20f36SRui Paulo } 125*8eb20f36SRui Paulo 126*8eb20f36SRui Paulo return (0); 127*8eb20f36SRui Paulo } 128*8eb20f36SRui Paulo 129*8eb20f36SRui Paulo /* 130*8eb20f36SRui Paulo * Decrement pc so that we delete the breakpoint at the correct 131*8eb20f36SRui Paulo * address, i.e. at the BREAKPOINT_INSTR address. 132*8eb20f36SRui Paulo */ 133*8eb20f36SRui Paulo void 134*8eb20f36SRui Paulo proc_bkptregadj(unsigned long *pc) 135*8eb20f36SRui Paulo { 136*8eb20f36SRui Paulo *pc = *pc - BREAKPOINT_INSTR_SZ; 137*8eb20f36SRui Paulo } 138*8eb20f36SRui Paulo 139*8eb20f36SRui Paulo /* 140*8eb20f36SRui Paulo * Step over the breakpoint. 141*8eb20f36SRui Paulo */ 142*8eb20f36SRui Paulo int 143*8eb20f36SRui Paulo proc_bkptexec(struct proc_handle *phdl, unsigned long saved) 144*8eb20f36SRui Paulo { 145*8eb20f36SRui Paulo unsigned long pc; 146*8eb20f36SRui Paulo unsigned long samesaved; 147*8eb20f36SRui Paulo int status; 148*8eb20f36SRui Paulo 149*8eb20f36SRui Paulo if (proc_regget(phdl, REG_PC, &pc) < 0) { 150*8eb20f36SRui Paulo warn("ERROR: couldn't get PC register"); 151*8eb20f36SRui Paulo return (-1); 152*8eb20f36SRui Paulo } 153*8eb20f36SRui Paulo proc_bkptregadj(&pc); 154*8eb20f36SRui Paulo if (proc_bkptdel(phdl, pc, saved) < 0) { 155*8eb20f36SRui Paulo warn("ERROR: couldn't delete breakpoint"); 156*8eb20f36SRui Paulo return (-1); 157*8eb20f36SRui Paulo } 158*8eb20f36SRui Paulo /* 159*8eb20f36SRui Paulo * Go back in time and step over the new instruction just 160*8eb20f36SRui Paulo * set up by proc_bkptdel(). 161*8eb20f36SRui Paulo */ 162*8eb20f36SRui Paulo proc_regset(phdl, REG_PC, pc); 163*8eb20f36SRui Paulo if (ptrace(PT_STEP, proc_getpid(phdl), (caddr_t)1, 0) < 0) { 164*8eb20f36SRui Paulo warn("ERROR: ptrace step failed"); 165*8eb20f36SRui Paulo return (-1); 166*8eb20f36SRui Paulo } 167*8eb20f36SRui Paulo status = proc_wstatus(phdl); 168*8eb20f36SRui Paulo if (!WIFSTOPPED(status)) { 169*8eb20f36SRui Paulo warn("ERROR: don't know why process stopped"); 170*8eb20f36SRui Paulo return (-1); 171*8eb20f36SRui Paulo } 172*8eb20f36SRui Paulo /* 173*8eb20f36SRui Paulo * Restore the breakpoint. The saved instruction should be 174*8eb20f36SRui Paulo * the same as the one that we were passed in. 175*8eb20f36SRui Paulo */ 176*8eb20f36SRui Paulo if (proc_bkptset(phdl, pc, &samesaved) < 0) { 177*8eb20f36SRui Paulo warn("ERROR: couldn't restore breakpoint"); 178*8eb20f36SRui Paulo return (-1); 179*8eb20f36SRui Paulo } 180*8eb20f36SRui Paulo assert(samesaved == saved); 181*8eb20f36SRui Paulo 182*8eb20f36SRui Paulo return (0); 183*8eb20f36SRui Paulo } 184