1 /* 2 * This file is part of ltrace. 3 * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc. 4 * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes 5 * Copyright (C) 2006 Ian Wienand 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 */ 22 #include "config.h" 23 24 #include <sys/types.h> 25 #include <sys/ptrace.h> 26 #include <sys/reg.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <string.h> 30 31 #include "backend.h" 32 #include "proc.h" 33 34 #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 35 # define PTRACE_PEEKUSER PTRACE_PEEKUSR 36 #endif 37 38 #if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 39 # define PTRACE_POKEUSER PTRACE_POKEUSR 40 #endif 41 42 #ifdef __x86_64__ 43 # define XIP (8 * RIP) 44 # define XSP (8 * RSP) 45 #else 46 # define XIP (4 * EIP) 47 # define XSP (4 * UESP) 48 #endif 49 50 static arch_addr_t 51 conv_32(arch_addr_t val) 52 { 53 /* XXX Drop the multiple double casts when arch_addr_t 54 * becomes integral. */ 55 return (arch_addr_t)(uintptr_t)(uint32_t)(uintptr_t)val; 56 } 57 58 void * 59 get_instruction_pointer(struct process *proc) 60 { 61 long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, XIP, 0); 62 if (proc->e_machine == EM_386) 63 ret &= 0xffffffff; 64 return (void *)ret; 65 } 66 67 void 68 set_instruction_pointer(struct process *proc, arch_addr_t addr) 69 { 70 if (proc->e_machine == EM_386) 71 addr = conv_32(addr); 72 ptrace(PTRACE_POKEUSER, proc->pid, XIP, addr); 73 } 74 75 void * 76 get_stack_pointer(struct process *proc) 77 { 78 long sp = ptrace(PTRACE_PEEKUSER, proc->pid, XSP, 0); 79 if (sp == -1 && errno) { 80 fprintf(stderr, "Couldn't read SP register: %s\n", 81 strerror(errno)); 82 return NULL; 83 } 84 85 /* XXX Drop the multiple double casts when arch_addr_t 86 * becomes integral. */ 87 arch_addr_t ret = (arch_addr_t)(uintptr_t)sp; 88 if (proc->e_machine == EM_386) 89 ret = conv_32(ret); 90 return ret; 91 } 92 93 void * 94 get_return_addr(struct process *proc, void *sp) 95 { 96 long a = ptrace(PTRACE_PEEKTEXT, proc->pid, sp, 0); 97 if (a == -1 && errno) { 98 fprintf(stderr, "Couldn't read return value: %s\n", 99 strerror(errno)); 100 return NULL; 101 } 102 103 /* XXX Drop the multiple double casts when arch_addr_t 104 * becomes integral. */ 105 arch_addr_t ret = (arch_addr_t)(uintptr_t)a; 106 if (proc->e_machine == EM_386) 107 ret = conv_32(ret); 108 return ret; 109 } 110