aarch64 multi-arch (part 3): get thread area
[external/binutils.git] / gdb / nat / aarch64-linux.c
1 /* Copyright (C) 2009-2015 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 "common-defs.h"
20 #include "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
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_get_lwp (ptid);
49       struct aarch64_debug_reg_state *state
50         = aarch64_get_debug_reg_state (ptid_get_pid (ptid));
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
74 aarch64_linux_new_thread (struct lwp_info *lwp)
75 {
76   struct arch_lwp_info *info = XNEW (struct arch_lwp_info);
77
78   /* Mark that all the hardware breakpoint/watchpoint register pairs
79      for this thread need to be initialized (with data from
80      aarch_process_info.debug_reg_state).  */
81   DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
82   DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
83
84   lwp_set_arch_private_info (lwp, info);
85 }
86
87 /* Convert native siginfo FROM to the siginfo in the layout of the
88    inferior's architecture TO.  */
89
90 void
91 aarch64_compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from)
92 {
93   memset (to, 0, sizeof (*to));
94
95   to->si_signo = from->si_signo;
96   to->si_errno = from->si_errno;
97   to->si_code = from->si_code;
98
99   if (to->si_code == SI_TIMER)
100     {
101       to->cpt_si_timerid = from->si_timerid;
102       to->cpt_si_overrun = from->si_overrun;
103       to->cpt_si_ptr = (intptr_t) from->si_ptr;
104     }
105   else if (to->si_code == SI_USER)
106     {
107       to->cpt_si_pid = from->si_pid;
108       to->cpt_si_uid = from->si_uid;
109     }
110   else if (to->si_code < 0)
111     {
112       to->cpt_si_pid = from->si_pid;
113       to->cpt_si_uid = from->si_uid;
114       to->cpt_si_ptr = (intptr_t) from->si_ptr;
115     }
116   else
117     {
118       switch (to->si_signo)
119         {
120         case SIGCHLD:
121           to->cpt_si_pid = from->si_pid;
122           to->cpt_si_uid = from->si_uid;
123           to->cpt_si_status = from->si_status;
124           to->cpt_si_utime = from->si_utime;
125           to->cpt_si_stime = from->si_stime;
126           break;
127         case SIGILL:
128         case SIGFPE:
129         case SIGSEGV:
130         case SIGBUS:
131           to->cpt_si_addr = (intptr_t) from->si_addr;
132           break;
133         case SIGPOLL:
134           to->cpt_si_band = from->si_band;
135           to->cpt_si_fd = from->si_fd;
136           break;
137         default:
138           to->cpt_si_pid = from->si_pid;
139           to->cpt_si_uid = from->si_uid;
140           to->cpt_si_ptr = (intptr_t) from->si_ptr;
141           break;
142         }
143     }
144 }
145
146 /* Convert inferior's architecture siginfo FROM to native siginfo TO.  */
147
148 void
149 aarch64_siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
150 {
151   memset (to, 0, sizeof (*to));
152
153   to->si_signo = from->si_signo;
154   to->si_errno = from->si_errno;
155   to->si_code = from->si_code;
156
157   if (to->si_code == SI_TIMER)
158     {
159       to->si_timerid = from->cpt_si_timerid;
160       to->si_overrun = from->cpt_si_overrun;
161       to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
162     }
163   else if (to->si_code == SI_USER)
164     {
165       to->si_pid = from->cpt_si_pid;
166       to->si_uid = from->cpt_si_uid;
167     }
168   if (to->si_code < 0)
169     {
170       to->si_pid = from->cpt_si_pid;
171       to->si_uid = from->cpt_si_uid;
172       to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
173     }
174   else
175     {
176       switch (to->si_signo)
177         {
178         case SIGCHLD:
179           to->si_pid = from->cpt_si_pid;
180           to->si_uid = from->cpt_si_uid;
181           to->si_status = from->cpt_si_status;
182           to->si_utime = from->cpt_si_utime;
183           to->si_stime = from->cpt_si_stime;
184           break;
185         case SIGILL:
186         case SIGFPE:
187         case SIGSEGV:
188         case SIGBUS:
189           to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
190           break;
191         case SIGPOLL:
192           to->si_band = from->cpt_si_band;
193           to->si_fd = from->cpt_si_fd;
194           break;
195         default:
196           to->si_pid = from->cpt_si_pid;
197           to->si_uid = from->cpt_si_uid;
198           to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
199           break;
200         }
201     }
202 }
203
204 /* Called by libthread_db.  Returns a pointer to the thread local
205    storage (or its descriptor).  */
206
207 ps_err_e
208 aarch64_ps_get_thread_area (const struct ps_prochandle *ph,
209                             lwpid_t lwpid, int idx, void **base,
210                             int is_64bit_p)
211 {
212   struct iovec iovec;
213   uint64_t reg64;
214   uint32_t reg32;
215
216   if (is_64bit_p)
217     {
218       iovec.iov_base = &reg64;
219       iovec.iov_len = sizeof (reg64);
220     }
221   else
222     {
223       iovec.iov_base = &reg32;
224       iovec.iov_len = sizeof (reg32);
225     }
226
227   if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
228     return PS_ERR;
229
230   /* IDX is the bias from the thread pointer to the beginning of the
231      thread descriptor.  It has to be subtracted due to implementation
232      quirks in libthread_db.  */
233   if (is_64bit_p)
234     *base = (void *) (reg64 - idx);
235   else
236     *base = (void *) (uintptr_t) (reg32 - idx);
237
238   return PS_OK;
239 }