1d0317114Schristos /* Common target dependent code for GNU/Linux on ARM systems.
2d0317114Schristos 
3*56bb7041Schristos    Copyright (C) 1999-2020 Free Software Foundation, Inc.
4d0317114Schristos 
5d0317114Schristos    This file is part of GDB.
6d0317114Schristos 
7d0317114Schristos    This program is free software; you can redistribute it and/or modify
8d0317114Schristos    it under the terms of the GNU General Public License as published by
9d0317114Schristos    the Free Software Foundation; either version 3 of the License, or
10d0317114Schristos    (at your option) any later version.
11d0317114Schristos 
12d0317114Schristos    This program is distributed in the hope that it will be useful,
13d0317114Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
14d0317114Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15d0317114Schristos    GNU General Public License for more details.
16d0317114Schristos 
17d0317114Schristos    You should have received a copy of the GNU General Public License
18d0317114Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19d0317114Schristos 
20*56bb7041Schristos #include "gdbsupport/common-defs.h"
21*56bb7041Schristos #include "gdbsupport/common-regcache.h"
22d0317114Schristos #include "arch/arm.h"
23d0317114Schristos #include "arm-linux.h"
24d0317114Schristos #include "arch/arm-get-next-pcs.h"
25d0317114Schristos 
26d0317114Schristos /* Calculate the offset from stack pointer of the pc register on the stack
27d0317114Schristos    in the case of a sigreturn or sigreturn_rt syscall.  */
28d0317114Schristos int
arm_linux_sigreturn_next_pc_offset(unsigned long sp,unsigned long sp_data,unsigned long svc_number,int is_sigreturn)29d0317114Schristos arm_linux_sigreturn_next_pc_offset (unsigned long sp,
30d0317114Schristos 				    unsigned long sp_data,
31d0317114Schristos 				    unsigned long svc_number,
32d0317114Schristos 				    int is_sigreturn)
33d0317114Schristos {
34d0317114Schristos   /* Offset of R0 register.  */
35d0317114Schristos   int r0_offset = 0;
36d0317114Schristos   /* Offset of PC register.  */
37d0317114Schristos   int pc_offset = 0;
38d0317114Schristos 
39d0317114Schristos   if (is_sigreturn)
40d0317114Schristos     {
41d0317114Schristos       if (sp_data == ARM_NEW_SIGFRAME_MAGIC)
42d0317114Schristos 	r0_offset = ARM_UCONTEXT_SIGCONTEXT + ARM_SIGCONTEXT_R0;
43d0317114Schristos       else
44d0317114Schristos 	r0_offset = ARM_SIGCONTEXT_R0;
45d0317114Schristos     }
46d0317114Schristos   else
47d0317114Schristos     {
48d0317114Schristos       if (sp_data == sp + ARM_OLD_RT_SIGFRAME_SIGINFO)
49d0317114Schristos 	r0_offset = ARM_OLD_RT_SIGFRAME_UCONTEXT;
50d0317114Schristos       else
51d0317114Schristos 	r0_offset = ARM_NEW_RT_SIGFRAME_UCONTEXT;
52d0317114Schristos 
53d0317114Schristos       r0_offset += ARM_UCONTEXT_SIGCONTEXT + ARM_SIGCONTEXT_R0;
54d0317114Schristos     }
55d0317114Schristos 
56*56bb7041Schristos   pc_offset = r0_offset + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM;
57d0317114Schristos 
58d0317114Schristos   return pc_offset;
59d0317114Schristos }
60d0317114Schristos 
61d0317114Schristos /* Implementation of "fixup" method of struct arm_get_next_pcs_ops
62d0317114Schristos    for arm-linux.  */
63d0317114Schristos 
64d0317114Schristos CORE_ADDR
arm_linux_get_next_pcs_fixup(struct arm_get_next_pcs * self,CORE_ADDR nextpc)65d0317114Schristos arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
66d0317114Schristos 			      CORE_ADDR nextpc)
67d0317114Schristos {
68d0317114Schristos   /* The Linux kernel offers some user-mode helpers in a high page.  We can
69d0317114Schristos      not read this page (as of 2.6.23), and even if we could then we
70d0317114Schristos      couldn't set breakpoints in it, and even if we could then the atomic
71d0317114Schristos      operations would fail when interrupted.  They are all (tail) called
72d0317114Schristos      as functions and return to the address in LR.  However, when GDB single
73d0317114Schristos      step this instruction, this instruction isn't executed yet, and LR
74d0317114Schristos      may not be updated yet.  In other words, GDB can get the target
75d0317114Schristos      address from LR if this instruction isn't BL or BLX.  */
76d0317114Schristos   if (nextpc > 0xffff0000)
77d0317114Schristos     {
78d0317114Schristos       int bl_blx_p = 0;
79d0317114Schristos       CORE_ADDR pc = regcache_read_pc (self->regcache);
80d0317114Schristos       int pc_incr = 0;
81d0317114Schristos 
82d0317114Schristos       if (self->ops->is_thumb (self))
83d0317114Schristos 	{
84d0317114Schristos 	  unsigned short inst1
85d0317114Schristos 	    = self->ops->read_mem_uint (pc, 2, self->byte_order_for_code);
86d0317114Schristos 
87d0317114Schristos 	  if (bits (inst1, 8, 15) == 0x47 && bit (inst1, 7))
88d0317114Schristos 	    {
89d0317114Schristos 	      /* BLX Rm */
90d0317114Schristos 	      bl_blx_p = 1;
91d0317114Schristos 	      pc_incr = 2;
92d0317114Schristos 	    }
93d0317114Schristos 	  else if (thumb_insn_size (inst1) == 4)
94d0317114Schristos 	    {
95d0317114Schristos 	      unsigned short inst2;
96d0317114Schristos 
97d0317114Schristos 	      inst2 = self->ops->read_mem_uint (pc + 2, 2,
98d0317114Schristos 						self->byte_order_for_code);
99d0317114Schristos 
100d0317114Schristos 	      if ((inst1 & 0xf800) == 0xf000 && bits (inst2, 14, 15) == 0x3)
101d0317114Schristos 		{
102d0317114Schristos 		  /* BL <label> and BLX <label> */
103d0317114Schristos 		  bl_blx_p = 1;
104d0317114Schristos 		  pc_incr = 4;
105d0317114Schristos 		}
106d0317114Schristos 	    }
107d0317114Schristos 
108d0317114Schristos 	  pc_incr = MAKE_THUMB_ADDR (pc_incr);
109d0317114Schristos 	}
110d0317114Schristos       else
111d0317114Schristos 	{
112d0317114Schristos 	  unsigned int insn
113d0317114Schristos 	    = self->ops->read_mem_uint (pc, 4, self->byte_order_for_code);
114d0317114Schristos 
115d0317114Schristos 	  if (bits (insn, 28, 31) == INST_NV)
116d0317114Schristos 	    {
117d0317114Schristos 	      if (bits (insn, 25, 27) == 0x5) /* BLX <label> */
118d0317114Schristos 		bl_blx_p = 1;
119d0317114Schristos 	    }
120d0317114Schristos 	  else
121d0317114Schristos 	    {
122d0317114Schristos 	      if (bits (insn, 24, 27) == 0xb  /* BL <label> */
123d0317114Schristos 		  || bits (insn, 4, 27) == 0x12fff3 /* BLX Rm */)
124d0317114Schristos 		bl_blx_p = 1;
125d0317114Schristos 	    }
126d0317114Schristos 
127d0317114Schristos 	  pc_incr = 4;
128d0317114Schristos 	}
129d0317114Schristos 
130d0317114Schristos       /* If the instruction BL or BLX, the target address is the following
131d0317114Schristos 	 instruction of BL or BLX, otherwise, the target address is in LR
132d0317114Schristos 	 already.  */
133d0317114Schristos       if (bl_blx_p)
134d0317114Schristos 	nextpc = pc + pc_incr;
135d0317114Schristos       else
136d0317114Schristos 	nextpc = regcache_raw_get_unsigned (self->regcache, ARM_LR_REGNUM);
137d0317114Schristos     }
138d0317114Schristos   return nextpc;
139d0317114Schristos }
140