1e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata/*
2e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * This file is part of ltrace.
39fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata * Copyright (C) 2013 Petr Machata, Red Hat Inc.
4e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
5e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * Copyright (C) 2009 Juan Cespedes
6e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata *
7e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * This program is free software; you can redistribute it and/or
8e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * modify it under the terms of the GNU General Public License as
9e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * published by the Free Software Foundation; either version 2 of the
10e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * License, or (at your option) any later version.
11e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata *
12e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * This program is distributed in the hope that it will be useful, but
13e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * WITHOUT ANY WARRANTY; without even the implied warranty of
14e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * General Public License for more details.
16e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata *
17e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * You should have received a copy of the GNU General Public License
18e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * along with this program; if not, write to the Free Software
19e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata * 02110-1301 USA
21e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata */
22e99af270a60891e68d465c4cd97dbe29cd1a05e4Petr Machata
23d44c6b8b090b8b7aa9d971d9e0bfd848732a3071Juan Cespedes#include "config.h"
24d44c6b8b090b8b7aa9d971d9e0bfd848732a3071Juan Cespedes
258e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#include <sys/types.h>
268e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#include <sys/ptrace.h>
278e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#include <asm/ptrace.h>
289fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata#include <errno.h>
298e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
30366c2f46d844f040458df9b7e35fc3b8527ed2d3Petr Machata#include "proc.h"
31f728123bd75a65a6a1536e198c3c30719e494e71Juan Cespedes#include "common.h"
329fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata#include "regs.h"
335c3fe0697b202cc7d95e90459de0fb312b297b27Juan Cespedes
348e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
358e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes# define PTRACE_PEEKUSER PTRACE_PEEKUSR
368e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#endif
378e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
388e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
398e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes# define PTRACE_POKEUSER PTRACE_POKEUSR
408e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes#endif
418e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
429fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
439fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp)
449fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
459fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	errno = 0;
466b9664af2e87596055eaab59492e79bfd1527dabPetr Machata	long l = ptrace(PTRACE_PEEKUSER, proc->pid, (void *)(reg * 4L), 0);
479fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (l == -1 && errno != 0)
489fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
499fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	*lp = (uint32_t)l;
509fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
519fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
529fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
539fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
54f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataarm_set_register(struct process *proc, enum arm_register reg, uint32_t lp)
55f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata{
56f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	return ptrace(PTRACE_PEEKUSER, proc->pid,
57f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata		      (void *)(reg * 4L), (void *)lp);
58f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata}
59f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata
60f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataint
619fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_register_offpc(struct process *proc, enum arm_register reg,
629fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		       uint32_t *lp)
639fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
649fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (arm_get_register(proc, reg, lp) < 0)
659fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
669fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (reg == ARM_REG_PC)
679fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		*lp += 8;
689fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
699fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
709fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
719fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
729fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
739fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			 arch_addr_t pc_val, uint32_t *lp)
749fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
759fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	enum arm_register rm = BITS(inst, 0, 3);
769fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	unsigned long shifttype = BITS(inst, 5, 6);
779fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
789fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t shift;
799fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (BIT(inst, 4)) {
809fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (arm_get_register_offpc(proc, BITS(inst, 8, 11), &shift) < 0)
819fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			return -1;
829fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift &= 0xff;
839fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	} else {
849fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift = BITS(inst, 7, 11);
859fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	}
869fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
879fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t res;
889fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (rm == ARM_REG_PC)
899fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		/* xxx double cast */
909fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = (uintptr_t)pc_val + (BIT(inst, 4) ? 12 : 8);
919fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	else if (arm_get_register(proc, rm, &res) < 0)
929fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
939fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
949fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	switch (shifttype) {
959fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 0:			/* LSL */
969fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = shift >= 32 ? 0 : res << shift;
979fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
989fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
999fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 1:			/* LSR */
1009fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = shift >= 32 ? 0 : res >> shift;
1019fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
1029fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1039fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 2:			/* ASR */
1049fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (shift >= 32)
1059fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			shift = 31;
1069fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = ((res & 0x80000000L)
1079fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		       ? ~((~res) >> shift) : res >> shift);
1089fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
1099fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1109fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 3:			/* ROR/RRX */
1119fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift &= 31;
1129fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (shift == 0)
1139fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			res = (res >> 1) | (carry ? 0x80000000L : 0);
1149fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		else
1159fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			res = (res >> shift) | (res << (32 - shift));
1169fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
1179fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	}
1189fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1199fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	*lp = res & 0xffffffff;
1209fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
1219fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
1229fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
123f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machatastatic arch_addr_t
124f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataget_register_nocheck(struct process *proc, enum arm_register r)
125929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
1269fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t reg;
127f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	if (arm_get_register(proc, r, &reg) < 0)
1289fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		/* XXX double cast. */
1299fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return (arch_addr_t)-1;
1309fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	/* XXX double cast.  */
1319fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return (arch_addr_t)(uintptr_t)reg;
1328e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
1338e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
134f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataarch_addr_t
135f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataget_instruction_pointer(struct process *proc)
136f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata{
137f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	return get_register_nocheck(proc, ARM_REG_PC);
138f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata}
139f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata
140f13505251e6402460f6cc7ec84e0d8ca91607b4fJuan Cespedesvoid
141f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machataset_instruction_pointer(struct process *proc, arch_addr_t addr)
142929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
143f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	/* XXX double cast.  */
144f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	arm_set_register(proc, ARM_REG_PC, (uint32_t)addr);
1458f8282f72eaeadc5419cd5470100e8dcaba5b7fdJuan Cespedes}
1468f8282f72eaeadc5419cd5470100e8dcaba5b7fdJuan Cespedes
147f13505251e6402460f6cc7ec84e0d8ca91607b4fJuan Cespedesvoid *
148929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataget_stack_pointer(struct process *proc)
149929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
150f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	return get_register_nocheck(proc, ARM_REG_SP);
1518e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
1528e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
153f9d93c50bd246ea7fd42e0c8ad24aa01467e76acPetr Machataarch_addr_t
154f9d93c50bd246ea7fd42e0c8ad24aa01467e76acPetr Machataget_return_addr(struct process *proc, arch_addr_t stack_pointer)
155929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
156f25af517a06521f69fbc53eaf3c245a7a2298c75Petr Machata	return get_register_nocheck(proc, ARM_REG_LR);
1578e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
158