regs.c revision 912a0f75b3521803fa724a55f0e883c134c7b4e9
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2014 Petr Machata, Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21#include <sys/ptrace.h>
22#include <asm/ptrace.h>
23#include <linux/uio.h>
24#include <assert.h>
25#include <stdlib.h>
26
27#include "backend.h"
28#include "proc.h"
29
30#define PC_OFF (32 * 4)
31
32int
33aarch64_read_gregs(struct process *proc, struct user_pt_regs *regs)
34{
35	*regs = (struct user_pt_regs) {};
36	struct iovec iovec;
37	iovec.iov_base = regs;
38	iovec.iov_len = sizeof *regs;
39	return ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, &iovec) < 0
40		? -1 : 0;
41}
42
43int
44aarch64_write_gregs(struct process *proc, struct user_pt_regs *regs)
45{
46	struct iovec iovec;
47	iovec.iov_base = regs;
48	iovec.iov_len = sizeof *regs;
49	return ptrace(PTRACE_SETREGSET, proc->pid, NT_PRSTATUS, &iovec) < 0
50		? -1 : 0;
51}
52
53int
54aarch64_read_fregs(struct process *proc, struct user_fpsimd_state *regs)
55{
56	*regs = (struct user_fpsimd_state) {};
57	struct iovec iovec;
58	iovec.iov_base = regs;
59	iovec.iov_len = sizeof *regs;
60	return ptrace(PTRACE_GETREGSET, proc->pid, NT_FPREGSET, &iovec) < 0
61		? -1 : 0;
62}
63
64arch_addr_t
65get_instruction_pointer(struct process *proc)
66{
67	struct user_pt_regs regs;
68	if (aarch64_read_gregs(proc, &regs) < 0) {
69		fprintf(stderr, "get_instruction_pointer: "
70			"Couldn't read registers of %d.\n", proc->pid);
71		return 0;
72	}
73
74	/*
75	char buf[128];
76	sprintf(buf, "cat /proc/%d/maps", proc->pid);
77	system(buf);
78	*/
79
80	/* XXX double cast */
81	return (arch_addr_t) (uintptr_t) regs.pc;
82}
83
84void
85set_instruction_pointer(struct process *proc, arch_addr_t addr)
86{
87	struct user_pt_regs regs;
88	if (aarch64_read_gregs(proc, &regs) < 0) {
89		fprintf(stderr, "get_instruction_pointer: "
90			"Couldn't read registers of %d.\n", proc->pid);
91		return;
92	}
93
94	/* XXX double cast */
95	regs.pc = (uint64_t) (uintptr_t) addr;
96
97	if (aarch64_write_gregs(proc, &regs) < 0) {
98		fprintf(stderr, "get_instruction_pointer: "
99			"Couldn't write registers of %d.\n", proc->pid);
100		return;
101	}
102}
103
104arch_addr_t
105get_stack_pointer(struct process *proc)
106{
107	struct user_pt_regs regs;
108	if (aarch64_read_gregs(proc, &regs) < 0) {
109		fprintf(stderr, "get_stack_pointer: "
110			"Couldn't read registers of %d.\n", proc->pid);
111		return 0;
112	}
113
114	/* XXX double cast */
115	return (arch_addr_t) (uintptr_t) regs.sp;
116}
117
118arch_addr_t
119get_return_addr(struct process *proc, arch_addr_t stack_pointer)
120{
121	struct user_pt_regs regs;
122	if (aarch64_read_gregs(proc, &regs) < 0) {
123		fprintf(stderr, "get_return_addr: "
124			"Couldn't read registers of %d.\n", proc->pid);
125		return 0;
126	}
127
128	/* XXX double cast */
129	return (arch_addr_t) (uintptr_t) regs.regs[30];
130}
131