regs.c revision 6b9664af2e87596055eaab59492e79bfd1527dab
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
42c897cb796dc4a7d256cbfbf0137ef7cdff9e8ecePetr Machata#define off_pc ((void *)60)
43c897cb796dc4a7d256cbfbf0137ef7cdff9e8ecePetr Machata#define off_lr ((void *)56)
44c897cb796dc4a7d256cbfbf0137ef7cdff9e8ecePetr Machata#define off_sp ((void *)52)
458e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
469fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
479fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp)
489fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
499fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	errno = 0;
506b9664af2e87596055eaab59492e79bfd1527dabPetr Machata	long l = ptrace(PTRACE_PEEKUSER, proc->pid, (void *)(reg * 4L), 0);
519fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (l == -1 && errno != 0)
529fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
539fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	*lp = (uint32_t)l;
549fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
559fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
569fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
579fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
589fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_register_offpc(struct process *proc, enum arm_register reg,
599fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		       uint32_t *lp)
609fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
619fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (arm_get_register(proc, reg, lp) < 0)
629fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
639fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (reg == ARM_REG_PC)
649fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		*lp += 8;
659fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
669fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
679fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
689fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataint
699fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
709fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			 arch_addr_t pc_val, uint32_t *lp)
719fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata{
729fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	enum arm_register rm = BITS(inst, 0, 3);
739fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	unsigned long shifttype = BITS(inst, 5, 6);
749fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
759fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t shift;
769fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (BIT(inst, 4)) {
779fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (arm_get_register_offpc(proc, BITS(inst, 8, 11), &shift) < 0)
789fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			return -1;
799fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift &= 0xff;
809fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	} else {
819fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift = BITS(inst, 7, 11);
829fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	}
839fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
849fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t res;
859fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (rm == ARM_REG_PC)
869fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		/* xxx double cast */
879fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = (uintptr_t)pc_val + (BIT(inst, 4) ? 12 : 8);
889fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	else if (arm_get_register(proc, rm, &res) < 0)
899fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return -1;
909fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
919fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	switch (shifttype) {
929fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 0:			/* LSL */
939fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = shift >= 32 ? 0 : res << shift;
949fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
959fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
969fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 1:			/* LSR */
979fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = shift >= 32 ? 0 : res >> shift;
989fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
999fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1009fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 2:			/* ASR */
1019fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (shift >= 32)
1029fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			shift = 31;
1039fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		res = ((res & 0x80000000L)
1049fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		       ? ~((~res) >> shift) : res >> shift);
1059fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
1069fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1079fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	case 3:			/* ROR/RRX */
1089fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		shift &= 31;
1099fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		if (shift == 0)
1109fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			res = (res >> 1) | (carry ? 0x80000000L : 0);
1119fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		else
1129fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata			res = (res >> shift) | (res << (32 - shift));
1139fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		break;
1149fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	}
1159fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1169fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	*lp = res & 0xffffffff;
1179fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return 0;
1189fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata}
1199fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata
1209fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machataarch_addr_t
121929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataget_instruction_pointer(struct process *proc)
122929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
1239fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	uint32_t reg;
1249fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	if (arm_get_register(proc, ARM_REG_PC, &reg) < 0)
1259fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		/* XXX double cast. */
1269fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata		return (arch_addr_t)-1;
1279fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	/* XXX double cast.  */
1289fa2b1850e664aa70a9559e41befca1a5975f08cPetr Machata	return (arch_addr_t)(uintptr_t)reg;
1298e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
1308e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
131f13505251e6402460f6cc7ec84e0d8ca91607b4fJuan Cespedesvoid
132929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataset_instruction_pointer(struct process *proc, void *addr)
133929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
1345c3fe0697b202cc7d95e90459de0fb312b297b27Juan Cespedes	ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
1358f8282f72eaeadc5419cd5470100e8dcaba5b7fdJuan Cespedes}
1368f8282f72eaeadc5419cd5470100e8dcaba5b7fdJuan Cespedes
137f13505251e6402460f6cc7ec84e0d8ca91607b4fJuan Cespedesvoid *
138929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataget_stack_pointer(struct process *proc)
139929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
1405c3fe0697b202cc7d95e90459de0fb312b297b27Juan Cespedes	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
1418e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
1428e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes
1438e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes/* really, this is given the *stack_pointer expecting
1448e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes * a CISC architecture; in our case, we don't need that */
145f13505251e6402460f6cc7ec84e0d8ca91607b4fJuan Cespedesvoid *
146929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataget_return_addr(struct process *proc, void *stack_pointer)
147929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
14863184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes	long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
14963184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes
1502b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata	/* Remember & unset the thumb mode bit.  XXX This is really a
1512b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata	 * bit of a hack, as we assume that the following
1522b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata	 * insert_breakpoint call will be related to this address.
1532b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata	 * This interface should really be get_return_breakpoint, or
1542b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata	 * maybe install_return_breakpoint.  */
15563184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes	proc->thumb_mode = addr & 1;
15663184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes	if (proc->thumb_mode)
15763184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes		addr &= ~1;
1582b46cfc1127d390eddd9593fe5ce5399c1f68130Petr Machata
15963184be8c577f5799e44db2a4e312a8240ad7751Juan Cespedes	return (void *)addr;
1608e3e082c27716245619721207cd5067d8c6271f9Juan Cespedes}
1612a61d19bd244dadcde5009f1632cf14b95623e3dJuan Cespedes
1622a61d19bd244dadcde5009f1632cf14b95623e3dJuan Cespedesvoid
163929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machataset_return_addr(struct process *proc, void *addr)
164929bd57ca202fd2f2e8485ebf65d683e664f67b5Petr Machata{
165ee87a9a06960ba44b2ff980a366b222ae0e3b6b3Zachary T Welch	long iaddr = (int)addr | proc->thumb_mode;
166ee87a9a06960ba44b2ff980a366b222ae0e3b6b3Zachary T Welch	ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr);
1672a61d19bd244dadcde5009f1632cf14b95623e3dJuan Cespedes}
168