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, ®) < 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