]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/gdbserver/linux-aarch64-low.c
Move aarch64_linux_get_debug_reg_capacity to nat/aarch64-linux-hw-point.c
[thirdparty/binutils-gdb.git] / gdb / gdbserver / linux-aarch64-low.c
1 /* GNU/Linux/AArch64 specific low level interface, for the remote server for
2 GDB.
3
4 Copyright (C) 2009-2015 Free Software Foundation, Inc.
5 Contributed by ARM Ltd.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "server.h"
23 #include "linux-low.h"
24 #include "nat/aarch64-linux-hw-point.h"
25 #include "elf/common.h"
26
27 #include <signal.h>
28 #include <sys/user.h>
29 #include <sys/ptrace.h>
30 #include <asm/ptrace.h>
31 #include <sys/uio.h>
32
33 #include "gdb_proc_service.h"
34
35 /* Defined in auto-generated files. */
36 void init_registers_aarch64 (void);
37 extern const struct target_desc *tdesc_aarch64;
38
39 #ifdef HAVE_SYS_REG_H
40 #include <sys/reg.h>
41 #endif
42
43 #define AARCH64_X_REGS_NUM 31
44 #define AARCH64_V_REGS_NUM 32
45 #define AARCH64_X0_REGNO 0
46 #define AARCH64_SP_REGNO 31
47 #define AARCH64_PC_REGNO 32
48 #define AARCH64_CPSR_REGNO 33
49 #define AARCH64_V0_REGNO 34
50 #define AARCH64_FPSR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM)
51 #define AARCH64_FPCR_REGNO (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 1)
52
53 #define AARCH64_NUM_REGS (AARCH64_V0_REGNO + AARCH64_V_REGS_NUM + 2)
54
55 /* Per-process arch-specific data we want to keep. */
56
57 struct arch_process_info
58 {
59 /* Hardware breakpoint/watchpoint data.
60 The reason for them to be per-process rather than per-thread is
61 due to the lack of information in the gdbserver environment;
62 gdbserver is not told that whether a requested hardware
63 breakpoint/watchpoint is thread specific or not, so it has to set
64 each hw bp/wp for every thread in the current process. The
65 higher level bp/wp management in gdb will resume a thread if a hw
66 bp/wp trap is not expected for it. Since the hw bp/wp setting is
67 same for each thread, it is reasonable for the data to live here.
68 */
69 struct aarch64_debug_reg_state debug_reg_state;
70 };
71
72 /* Implementation of linux_target_ops method "cannot_store_register". */
73
74 static int
75 aarch64_cannot_store_register (int regno)
76 {
77 return regno >= AARCH64_NUM_REGS;
78 }
79
80 /* Implementation of linux_target_ops method "cannot_fetch_register". */
81
82 static int
83 aarch64_cannot_fetch_register (int regno)
84 {
85 return regno >= AARCH64_NUM_REGS;
86 }
87
88 static void
89 aarch64_fill_gregset (struct regcache *regcache, void *buf)
90 {
91 struct user_pt_regs *regset = buf;
92 int i;
93
94 for (i = 0; i < AARCH64_X_REGS_NUM; i++)
95 collect_register (regcache, AARCH64_X0_REGNO + i, &regset->regs[i]);
96 collect_register (regcache, AARCH64_SP_REGNO, &regset->sp);
97 collect_register (regcache, AARCH64_PC_REGNO, &regset->pc);
98 collect_register (regcache, AARCH64_CPSR_REGNO, &regset->pstate);
99 }
100
101 static void
102 aarch64_store_gregset (struct regcache *regcache, const void *buf)
103 {
104 const struct user_pt_regs *regset = buf;
105 int i;
106
107 for (i = 0; i < AARCH64_X_REGS_NUM; i++)
108 supply_register (regcache, AARCH64_X0_REGNO + i, &regset->regs[i]);
109 supply_register (regcache, AARCH64_SP_REGNO, &regset->sp);
110 supply_register (regcache, AARCH64_PC_REGNO, &regset->pc);
111 supply_register (regcache, AARCH64_CPSR_REGNO, &regset->pstate);
112 }
113
114 static void
115 aarch64_fill_fpregset (struct regcache *regcache, void *buf)
116 {
117 struct user_fpsimd_state *regset = buf;
118 int i;
119
120 for (i = 0; i < AARCH64_V_REGS_NUM; i++)
121 collect_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
122 collect_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
123 collect_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
124 }
125
126 static void
127 aarch64_store_fpregset (struct regcache *regcache, const void *buf)
128 {
129 const struct user_fpsimd_state *regset = buf;
130 int i;
131
132 for (i = 0; i < AARCH64_V_REGS_NUM; i++)
133 supply_register (regcache, AARCH64_V0_REGNO + i, &regset->vregs[i]);
134 supply_register (regcache, AARCH64_FPSR_REGNO, &regset->fpsr);
135 supply_register (regcache, AARCH64_FPCR_REGNO, &regset->fpcr);
136 }
137
138 /* Enable miscellaneous debugging output. The name is historical - it
139 was originally used to debug LinuxThreads support. */
140 extern int debug_threads;
141
142 /* Implementation of linux_target_ops method "get_pc". */
143
144 static CORE_ADDR
145 aarch64_get_pc (struct regcache *regcache)
146 {
147 unsigned long pc;
148
149 collect_register_by_name (regcache, "pc", &pc);
150 if (debug_threads)
151 debug_printf ("stop pc is %08lx\n", pc);
152 return pc;
153 }
154
155 /* Implementation of linux_target_ops method "set_pc". */
156
157 static void
158 aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc)
159 {
160 unsigned long newpc = pc;
161 supply_register_by_name (regcache, "pc", &newpc);
162 }
163
164 #define aarch64_breakpoint_len 4
165
166 /* AArch64 BRK software debug mode instruction.
167 This instruction needs to match gdb/aarch64-tdep.c
168 (aarch64_default_breakpoint). */
169 static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4};
170
171 /* Implementation of linux_target_ops method "breakpoint_at". */
172
173 static int
174 aarch64_breakpoint_at (CORE_ADDR where)
175 {
176 gdb_byte insn[aarch64_breakpoint_len];
177
178 (*the_target->read_memory) (where, (unsigned char *) &insn,
179 aarch64_breakpoint_len);
180 if (memcmp (insn, aarch64_breakpoint, aarch64_breakpoint_len) == 0)
181 return 1;
182
183 return 0;
184 }
185
186 static void
187 aarch64_init_debug_reg_state (struct aarch64_debug_reg_state *state)
188 {
189 int i;
190
191 for (i = 0; i < AARCH64_HBP_MAX_NUM; ++i)
192 {
193 state->dr_addr_bp[i] = 0;
194 state->dr_ctrl_bp[i] = 0;
195 state->dr_ref_count_bp[i] = 0;
196 }
197
198 for (i = 0; i < AARCH64_HWP_MAX_NUM; ++i)
199 {
200 state->dr_addr_wp[i] = 0;
201 state->dr_ctrl_wp[i] = 0;
202 state->dr_ref_count_wp[i] = 0;
203 }
204 }
205
206 struct aarch64_dr_update_callback_param
207 {
208 int pid;
209 int is_watchpoint;
210 unsigned int idx;
211 };
212
213 /* Callback function which records the information about the change of
214 one hardware breakpoint/watchpoint setting for the thread ENTRY.
215 The information is passed in via PTR.
216 N.B. The actual updating of hardware debug registers is not
217 carried out until the moment the thread is resumed. */
218
219 static int
220 debug_reg_change_callback (struct inferior_list_entry *entry, void *ptr)
221 {
222 struct thread_info *thread = (struct thread_info *) entry;
223 struct lwp_info *lwp = get_thread_lwp (thread);
224 struct aarch64_dr_update_callback_param *param_p
225 = (struct aarch64_dr_update_callback_param *) ptr;
226 int pid = param_p->pid;
227 int idx = param_p->idx;
228 int is_watchpoint = param_p->is_watchpoint;
229 struct arch_lwp_info *info = lwp->arch_private;
230 dr_changed_t *dr_changed_ptr;
231 dr_changed_t dr_changed;
232
233 if (show_debug_regs)
234 {
235 fprintf (stderr, "debug_reg_change_callback: \n\tOn entry:\n");
236 fprintf (stderr, "\tpid%d, tid: %ld, dr_changed_bp=0x%llx, "
237 "dr_changed_wp=0x%llx\n",
238 pid, lwpid_of (thread), info->dr_changed_bp,
239 info->dr_changed_wp);
240 }
241
242 dr_changed_ptr = is_watchpoint ? &info->dr_changed_wp
243 : &info->dr_changed_bp;
244 dr_changed = *dr_changed_ptr;
245
246 /* Only update the threads of this process. */
247 if (pid_of (thread) == pid)
248 {
249 gdb_assert (idx >= 0
250 && (idx <= (is_watchpoint ? aarch64_num_wp_regs
251 : aarch64_num_bp_regs)));
252
253 /* The following assertion is not right, as there can be changes
254 that have not been made to the hardware debug registers
255 before new changes overwrite the old ones. This can happen,
256 for instance, when the breakpoint/watchpoint hit one of the
257 threads and the user enters continue; then what happens is:
258 1) all breakpoints/watchpoints are removed for all threads;
259 2) a single step is carried out for the thread that was hit;
260 3) all of the points are inserted again for all threads;
261 4) all threads are resumed.
262 The 2nd step will only affect the one thread in which the
263 bp/wp was hit, which means only that one thread is resumed;
264 remember that the actual updating only happen in
265 aarch64_linux_prepare_to_resume, so other threads remain
266 stopped during the removal and insertion of bp/wp. Therefore
267 for those threads, the change of insertion of the bp/wp
268 overwrites that of the earlier removals. (The situation may
269 be different when bp/wp is steppable, or in the non-stop
270 mode.) */
271 /* gdb_assert (DR_N_HAS_CHANGED (dr_changed, idx) == 0); */
272
273 /* The actual update is done later just before resuming the lwp,
274 we just mark that one register pair needs updating. */
275 DR_MARK_N_CHANGED (dr_changed, idx);
276 *dr_changed_ptr = dr_changed;
277
278 /* If the lwp isn't stopped, force it to momentarily pause, so
279 we can update its debug registers. */
280 if (!lwp->stopped)
281 linux_stop_lwp (lwp);
282 }
283
284 if (show_debug_regs)
285 {
286 fprintf (stderr, "\tOn exit:\n\tpid%d, tid: %ld, dr_changed_bp=0x%llx, "
287 "dr_changed_wp=0x%llx\n",
288 pid, lwpid_of (thread), info->dr_changed_bp,
289 info->dr_changed_wp);
290 }
291
292 return 0;
293 }
294
295 /* Notify each thread that their IDXth breakpoint/watchpoint register
296 pair needs to be updated. The message will be recorded in each
297 thread's arch-specific data area, the actual updating will be done
298 when the thread is resumed. */
299
300 void
301 aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state,
302 int is_watchpoint, unsigned int idx)
303 {
304 struct aarch64_dr_update_callback_param param;
305
306 /* Only update the threads of this process. */
307 param.pid = pid_of (current_thread);
308
309 param.is_watchpoint = is_watchpoint;
310 param.idx = idx;
311
312 find_inferior (&all_threads, debug_reg_change_callback, (void *) &param);
313 }
314
315
316 /* Return the pointer to the debug register state structure in the
317 current process' arch-specific data area. */
318
319 static struct aarch64_debug_reg_state *
320 aarch64_get_debug_reg_state ()
321 {
322 struct process_info *proc;
323
324 proc = current_process ();
325 return &proc->priv->arch_private->debug_reg_state;
326 }
327
328 /* Implementation of linux_target_ops method "supports_z_point_type". */
329
330 static int
331 aarch64_supports_z_point_type (char z_type)
332 {
333 switch (z_type)
334 {
335 case Z_PACKET_SW_BP:
336 case Z_PACKET_HW_BP:
337 case Z_PACKET_WRITE_WP:
338 case Z_PACKET_READ_WP:
339 case Z_PACKET_ACCESS_WP:
340 return 1;
341 default:
342 return 0;
343 }
344 }
345
346 /* Implementation of linux_target_ops method "insert_point".
347
348 It actually only records the info of the to-be-inserted bp/wp;
349 the actual insertion will happen when threads are resumed. */
350
351 static int
352 aarch64_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
353 int len, struct raw_breakpoint *bp)
354 {
355 int ret;
356 enum target_hw_bp_type targ_type;
357 struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state ();
358
359 if (show_debug_regs)
360 fprintf (stderr, "insert_point on entry (addr=0x%08lx, len=%d)\n",
361 (unsigned long) addr, len);
362
363 /* Determine the type from the raw breakpoint type. */
364 targ_type = raw_bkpt_type_to_target_hw_bp_type (type);
365
366 if (targ_type != hw_execute)
367 ret =
368 aarch64_handle_watchpoint (targ_type, addr, len, 1 /* is_insert */,
369 state);
370 else
371 ret =
372 aarch64_handle_breakpoint (targ_type, addr, len, 1 /* is_insert */,
373 state);
374
375 if (show_debug_regs)
376 aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (),
377 "insert_point", addr, len, targ_type);
378
379 return ret;
380 }
381
382 /* Implementation of linux_target_ops method "remove_point".
383
384 It actually only records the info of the to-be-removed bp/wp,
385 the actual removal will be done when threads are resumed. */
386
387 static int
388 aarch64_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
389 int len, struct raw_breakpoint *bp)
390 {
391 int ret;
392 enum target_hw_bp_type targ_type;
393 struct aarch64_debug_reg_state *state = aarch64_get_debug_reg_state ();
394
395 if (show_debug_regs)
396 fprintf (stderr, "remove_point on entry (addr=0x%08lx, len=%d)\n",
397 (unsigned long) addr, len);
398
399 /* Determine the type from the raw breakpoint type. */
400 targ_type = raw_bkpt_type_to_target_hw_bp_type (type);
401
402 /* Set up state pointers. */
403 if (targ_type != hw_execute)
404 ret =
405 aarch64_handle_watchpoint (targ_type, addr, len, 0 /* is_insert */,
406 state);
407 else
408 ret =
409 aarch64_handle_breakpoint (targ_type, addr, len, 0 /* is_insert */,
410 state);
411
412 if (show_debug_regs)
413 aarch64_show_debug_reg_state (aarch64_get_debug_reg_state (),
414 "remove_point", addr, len, targ_type);
415
416 return ret;
417 }
418
419 /* Implementation of linux_target_ops method "stopped_data_address". */
420
421 static CORE_ADDR
422 aarch64_stopped_data_address (void)
423 {
424 siginfo_t siginfo;
425 int pid, i;
426 struct aarch64_debug_reg_state *state;
427
428 pid = lwpid_of (current_thread);
429
430 /* Get the siginfo. */
431 if (ptrace (PTRACE_GETSIGINFO, pid, NULL, &siginfo) != 0)
432 return (CORE_ADDR) 0;
433
434 /* Need to be a hardware breakpoint/watchpoint trap. */
435 if (siginfo.si_signo != SIGTRAP
436 || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
437 return (CORE_ADDR) 0;
438
439 /* Check if the address matches any watched address. */
440 state = aarch64_get_debug_reg_state ();
441 for (i = aarch64_num_wp_regs - 1; i >= 0; --i)
442 {
443 const unsigned int len = aarch64_watchpoint_length (state->dr_ctrl_wp[i]);
444 const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr;
445 const CORE_ADDR addr_watch = state->dr_addr_wp[i];
446 if (state->dr_ref_count_wp[i]
447 && DR_CONTROL_ENABLED (state->dr_ctrl_wp[i])
448 && addr_trap >= addr_watch
449 && addr_trap < addr_watch + len)
450 return addr_trap;
451 }
452
453 return (CORE_ADDR) 0;
454 }
455
456 /* Implementation of linux_target_ops method "stopped_by_watchpoint". */
457
458 static int
459 aarch64_stopped_by_watchpoint (void)
460 {
461 if (aarch64_stopped_data_address () != 0)
462 return 1;
463 else
464 return 0;
465 }
466
467 /* Fetch the thread-local storage pointer for libthread_db. */
468
469 ps_err_e
470 ps_get_thread_area (const struct ps_prochandle *ph,
471 lwpid_t lwpid, int idx, void **base)
472 {
473 struct iovec iovec;
474 uint64_t reg;
475
476 iovec.iov_base = &reg;
477 iovec.iov_len = sizeof (reg);
478
479 if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
480 return PS_ERR;
481
482 /* IDX is the bias from the thread pointer to the beginning of the
483 thread descriptor. It has to be subtracted due to implementation
484 quirks in libthread_db. */
485 *base = (void *) (reg - idx);
486
487 return PS_OK;
488 }
489
490 /* Implementation of linux_target_ops method "linux_new_process". */
491
492 static struct arch_process_info *
493 aarch64_linux_new_process (void)
494 {
495 struct arch_process_info *info = xcalloc (1, sizeof (*info));
496
497 aarch64_init_debug_reg_state (&info->debug_reg_state);
498
499 return info;
500 }
501
502 /* Implementation of linux_target_ops method "linux_new_thread". */
503
504 static void
505 aarch64_linux_new_thread (struct lwp_info *lwp)
506 {
507 struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
508
509 /* Mark that all the hardware breakpoint/watchpoint register pairs
510 for this thread need to be initialized (with data from
511 aarch_process_info.debug_reg_state). */
512 DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
513 DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
514
515 lwp->arch_private = info;
516 }
517
518 /* Implementation of linux_target_ops method "linux_new_fork". */
519
520 static void
521 aarch64_linux_new_fork (struct process_info *parent,
522 struct process_info *child)
523 {
524 /* These are allocated by linux_add_process. */
525 gdb_assert (parent->priv != NULL
526 && parent->priv->arch_private != NULL);
527 gdb_assert (child->priv != NULL
528 && child->priv->arch_private != NULL);
529
530 /* Linux kernel before 2.6.33 commit
531 72f674d203cd230426437cdcf7dd6f681dad8b0d
532 will inherit hardware debug registers from parent
533 on fork/vfork/clone. Newer Linux kernels create such tasks with
534 zeroed debug registers.
535
536 GDB core assumes the child inherits the watchpoints/hw
537 breakpoints of the parent, and will remove them all from the
538 forked off process. Copy the debug registers mirrors into the
539 new process so that all breakpoints and watchpoints can be
540 removed together. The debug registers mirror will become zeroed
541 in the end before detaching the forked off process, thus making
542 this compatible with older Linux kernels too. */
543
544 *child->priv->arch_private = *parent->priv->arch_private;
545 }
546
547 /* Implementation of linux_target_ops method "linux_prepare_to_resume".
548
549 If the debug regs have changed, update the thread's copies. */
550
551 static void
552 aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
553 {
554 struct thread_info *thread = get_lwp_thread (lwp);
555 ptid_t ptid = ptid_of (thread);
556 struct arch_lwp_info *info = lwp->arch_private;
557
558 if (DR_HAS_CHANGED (info->dr_changed_bp)
559 || DR_HAS_CHANGED (info->dr_changed_wp))
560 {
561 int tid = ptid_get_lwp (ptid);
562 struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
563 struct aarch64_debug_reg_state *state
564 = &proc->priv->arch_private->debug_reg_state;
565
566 if (show_debug_regs)
567 fprintf (stderr, "prepare_to_resume thread %ld\n", lwpid_of (thread));
568
569 /* Watchpoints. */
570 if (DR_HAS_CHANGED (info->dr_changed_wp))
571 {
572 aarch64_linux_set_debug_regs (state, tid, 1);
573 DR_CLEAR_CHANGED (info->dr_changed_wp);
574 }
575
576 /* Breakpoints. */
577 if (DR_HAS_CHANGED (info->dr_changed_bp))
578 {
579 aarch64_linux_set_debug_regs (state, tid, 0);
580 DR_CLEAR_CHANGED (info->dr_changed_bp);
581 }
582 }
583 }
584
585 /* Implementation of linux_target_ops method "arch_setup". */
586
587 static void
588 aarch64_arch_setup (void)
589 {
590 current_process ()->tdesc = tdesc_aarch64;
591
592 aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
593 }
594
595 static struct regset_info aarch64_regsets[] =
596 {
597 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
598 sizeof (struct user_pt_regs), GENERAL_REGS,
599 aarch64_fill_gregset, aarch64_store_gregset },
600 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
601 sizeof (struct user_fpsimd_state), FP_REGS,
602 aarch64_fill_fpregset, aarch64_store_fpregset
603 },
604 { 0, 0, 0, -1, -1, NULL, NULL }
605 };
606
607 static struct regsets_info aarch64_regsets_info =
608 {
609 aarch64_regsets, /* regsets */
610 0, /* num_regsets */
611 NULL, /* disabled_regsets */
612 };
613
614 static struct regs_info regs_info =
615 {
616 NULL, /* regset_bitmap */
617 NULL, /* usrregs */
618 &aarch64_regsets_info,
619 };
620
621 /* Implementation of linux_target_ops method "regs_info". */
622
623 static const struct regs_info *
624 aarch64_regs_info (void)
625 {
626 return &regs_info;
627 }
628
629 /* Implementation of linux_target_ops method "supports_tracepoints". */
630
631 static int
632 aarch64_supports_tracepoints (void)
633 {
634 return 1;
635 }
636
637 /* Implementation of linux_target_ops method "supports_range_stepping". */
638
639 static int
640 aarch64_supports_range_stepping (void)
641 {
642 return 1;
643 }
644
645 struct linux_target_ops the_low_target =
646 {
647 aarch64_arch_setup,
648 aarch64_regs_info,
649 aarch64_cannot_fetch_register,
650 aarch64_cannot_store_register,
651 NULL, /* fetch_register */
652 aarch64_get_pc,
653 aarch64_set_pc,
654 (const unsigned char *) &aarch64_breakpoint,
655 aarch64_breakpoint_len,
656 NULL, /* breakpoint_reinsert_addr */
657 0, /* decr_pc_after_break */
658 aarch64_breakpoint_at,
659 aarch64_supports_z_point_type,
660 aarch64_insert_point,
661 aarch64_remove_point,
662 aarch64_stopped_by_watchpoint,
663 aarch64_stopped_data_address,
664 NULL, /* collect_ptrace_register */
665 NULL, /* supply_ptrace_register */
666 NULL, /* siginfo_fixup */
667 aarch64_linux_new_process,
668 aarch64_linux_new_thread,
669 aarch64_linux_new_fork,
670 aarch64_linux_prepare_to_resume,
671 NULL, /* process_qsupported */
672 aarch64_supports_tracepoints,
673 NULL, /* get_thread_area */
674 NULL, /* install_fast_tracepoint_jump_pad */
675 NULL, /* emit_ops */
676 NULL, /* get_min_fast_tracepoint_insn_len */
677 aarch64_supports_range_stepping,
678 };
679
680 void
681 initialize_low_arch (void)
682 {
683 init_registers_aarch64 ();
684
685 initialize_regsets_info (&aarch64_regsets_info);
686 }