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