1 /* Copyright (C) 2009-2020 Free Software Foundation, Inc.
2    Contributed by ARM Ltd.
3 
4    This file is part of GDB.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "gdbsupport/common-defs.h"
20 #include "gdbsupport/break-common.h"
21 #include "nat/linux-nat.h"
22 #include "nat/aarch64-linux-hw-point.h"
23 #include "nat/aarch64-linux.h"
24 
25 #include "elf/common.h"
26 #include "nat/gdb_ptrace.h"
27 #include <asm/ptrace.h>
28 #include <sys/uio.h>
29 
30 /* Called when resuming a thread LWP.
31    The hardware debug registers are updated when there is any change.  */
32 
33 void
aarch64_linux_prepare_to_resume(struct lwp_info * lwp)34 aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
35 {
36   struct arch_lwp_info *info = lwp_arch_private_info (lwp);
37 
38   /* NULL means this is the main thread still going through the shell,
39      or, no watchpoint has been set yet.  In that case, there's
40      nothing to do.  */
41   if (info == NULL)
42     return;
43 
44   if (DR_HAS_CHANGED (info->dr_changed_bp)
45       || DR_HAS_CHANGED (info->dr_changed_wp))
46     {
47       ptid_t ptid = ptid_of_lwp (lwp);
48       int tid = ptid.lwp ();
49       struct aarch64_debug_reg_state *state
50 	= aarch64_get_debug_reg_state (ptid.pid ());
51 
52       if (show_debug_regs)
53 	debug_printf ("prepare_to_resume thread %d\n", tid);
54 
55       /* Watchpoints.  */
56       if (DR_HAS_CHANGED (info->dr_changed_wp))
57 	{
58 	  aarch64_linux_set_debug_regs (state, tid, 1);
59 	  DR_CLEAR_CHANGED (info->dr_changed_wp);
60 	}
61 
62       /* Breakpoints.  */
63       if (DR_HAS_CHANGED (info->dr_changed_bp))
64 	{
65 	  aarch64_linux_set_debug_regs (state, tid, 0);
66 	  DR_CLEAR_CHANGED (info->dr_changed_bp);
67 	}
68     }
69 }
70 
71 /* Function to call when a new thread is detected.  */
72 
73 void
aarch64_linux_new_thread(struct lwp_info * lwp)74 aarch64_linux_new_thread (struct lwp_info *lwp)
75 {
76   ptid_t ptid = ptid_of_lwp (lwp);
77   struct aarch64_debug_reg_state *state
78     = aarch64_get_debug_reg_state (ptid.pid ());
79   struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
80 
81   /* If there are hardware breakpoints/watchpoints in the process then mark that
82      all the hardware breakpoint/watchpoint register pairs for this thread need
83      to be initialized (with data from aarch_process_info.debug_reg_state).  */
84   if (aarch64_linux_any_set_debug_regs_state (state, false))
85     DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
86   if (aarch64_linux_any_set_debug_regs_state (state, true))
87     DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
88 
89   lwp_set_arch_private_info (lwp, info);
90 }
91 
92 /* See nat/aarch64-linux.h.  */
93 
94 void
aarch64_linux_delete_thread(struct arch_lwp_info * arch_lwp)95 aarch64_linux_delete_thread (struct arch_lwp_info *arch_lwp)
96 {
97   xfree (arch_lwp);
98 }
99 
100 /* Convert native siginfo FROM to the siginfo in the layout of the
101    inferior's architecture TO.  */
102 
103 void
aarch64_compat_siginfo_from_siginfo(compat_siginfo_t * to,siginfo_t * from)104 aarch64_compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from)
105 {
106   memset (to, 0, sizeof (*to));
107 
108   to->si_signo = from->si_signo;
109   to->si_errno = from->si_errno;
110   to->si_code = from->si_code;
111 
112   if (to->si_code == SI_TIMER)
113     {
114       to->cpt_si_timerid = from->si_timerid;
115       to->cpt_si_overrun = from->si_overrun;
116       to->cpt_si_ptr = (intptr_t) from->si_ptr;
117     }
118   else if (to->si_code == SI_USER)
119     {
120       to->cpt_si_pid = from->si_pid;
121       to->cpt_si_uid = from->si_uid;
122     }
123   else if (to->si_code < 0)
124     {
125       to->cpt_si_pid = from->si_pid;
126       to->cpt_si_uid = from->si_uid;
127       to->cpt_si_ptr = (intptr_t) from->si_ptr;
128     }
129   else
130     {
131       switch (to->si_signo)
132 	{
133 	case SIGCHLD:
134 	  to->cpt_si_pid = from->si_pid;
135 	  to->cpt_si_uid = from->si_uid;
136 	  to->cpt_si_status = from->si_status;
137 	  to->cpt_si_utime = from->si_utime;
138 	  to->cpt_si_stime = from->si_stime;
139 	  break;
140 	case SIGILL:
141 	case SIGFPE:
142 	case SIGSEGV:
143 	case SIGBUS:
144 	  to->cpt_si_addr = (intptr_t) from->si_addr;
145 	  break;
146 	case SIGPOLL:
147 	  to->cpt_si_band = from->si_band;
148 	  to->cpt_si_fd = from->si_fd;
149 	  break;
150 	default:
151 	  to->cpt_si_pid = from->si_pid;
152 	  to->cpt_si_uid = from->si_uid;
153 	  to->cpt_si_ptr = (intptr_t) from->si_ptr;
154 	  break;
155 	}
156     }
157 }
158 
159 /* Convert inferior's architecture siginfo FROM to native siginfo TO.  */
160 
161 void
aarch64_siginfo_from_compat_siginfo(siginfo_t * to,compat_siginfo_t * from)162 aarch64_siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
163 {
164   memset (to, 0, sizeof (*to));
165 
166   to->si_signo = from->si_signo;
167   to->si_errno = from->si_errno;
168   to->si_code = from->si_code;
169 
170   if (to->si_code == SI_TIMER)
171     {
172       to->si_timerid = from->cpt_si_timerid;
173       to->si_overrun = from->cpt_si_overrun;
174       to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
175     }
176   else if (to->si_code == SI_USER)
177     {
178       to->si_pid = from->cpt_si_pid;
179       to->si_uid = from->cpt_si_uid;
180     }
181   if (to->si_code < 0)
182     {
183       to->si_pid = from->cpt_si_pid;
184       to->si_uid = from->cpt_si_uid;
185       to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
186     }
187   else
188     {
189       switch (to->si_signo)
190 	{
191 	case SIGCHLD:
192 	  to->si_pid = from->cpt_si_pid;
193 	  to->si_uid = from->cpt_si_uid;
194 	  to->si_status = from->cpt_si_status;
195 	  to->si_utime = from->cpt_si_utime;
196 	  to->si_stime = from->cpt_si_stime;
197 	  break;
198 	case SIGILL:
199 	case SIGFPE:
200 	case SIGSEGV:
201 	case SIGBUS:
202 	  to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
203 	  break;
204 	case SIGPOLL:
205 	  to->si_band = from->cpt_si_band;
206 	  to->si_fd = from->cpt_si_fd;
207 	  break;
208 	default:
209 	  to->si_pid = from->cpt_si_pid;
210 	  to->si_uid = from->cpt_si_uid;
211 	  to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
212 	  break;
213 	}
214     }
215 }
216 
217 /* Called by libthread_db.  Returns a pointer to the thread local
218    storage (or its descriptor).  */
219 
220 ps_err_e
aarch64_ps_get_thread_area(struct ps_prochandle * ph,lwpid_t lwpid,int idx,void ** base,int is_64bit_p)221 aarch64_ps_get_thread_area (struct ps_prochandle *ph,
222 			    lwpid_t lwpid, int idx, void **base,
223 			    int is_64bit_p)
224 {
225   struct iovec iovec;
226   uint64_t reg64;
227   uint32_t reg32;
228 
229   if (is_64bit_p)
230     {
231       iovec.iov_base = &reg64;
232       iovec.iov_len = sizeof (reg64);
233     }
234   else
235     {
236       iovec.iov_base = &reg32;
237       iovec.iov_len = sizeof (reg32);
238     }
239 
240   if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
241     return PS_ERR;
242 
243   /* IDX is the bias from the thread pointer to the beginning of the
244      thread descriptor.  It has to be subtracted due to implementation
245      quirks in libthread_db.  */
246   if (is_64bit_p)
247     *base = (void *) (reg64 - idx);
248   else
249     *base = (void *) (uintptr_t) (reg32 - idx);
250 
251   return PS_OK;
252 }
253