regs.c revision ddd96a3fbc7c54146d1d831810fc9e29c9bc3c76
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012 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
50static target_address_t
51conv_32(target_address_t val)
52{
53	/* XXX Drop the multiple double casts when target_address_t
54	 * becomes integral.  */
55	return (target_address_t)(uintptr_t)(uint32_t)(uintptr_t)val;
56}
57
58void *
59get_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
67void
68set_instruction_pointer(struct Process *proc, target_address_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
75void *
76get_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 target_address_t
86	 * becomes integral.  */
87	target_address_t ret = (target_address_t)(uintptr_t)sp;
88	if (proc->e_machine == EM_386)
89		ret = conv_32(ret);
90	return ret;
91}
92
93void *
94get_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 target_address_t
104	 * becomes integral.  */
105	target_address_t ret = (target_address_t)(uintptr_t)a;
106	if (proc->e_machine == EM_386)
107		ret = conv_32(ret);
108	return ret;
109}
110
111void
112set_return_addr(Process *proc, void *addr) {
113	if (proc->e_machine == EM_386)
114		addr = (void *)((long int)addr & 0xffffffff);
115	ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
116}
117