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
conv_32(arch_addr_t val)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 *
get_instruction_pointer(struct process * proc)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
set_instruction_pointer(struct process * proc,arch_addr_t addr)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 *
get_stack_pointer(struct process * proc)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 *
get_return_addr(struct process * proc,void * sp)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