1185023Sraj/* FreeBSD/ARM specific low level interface, for the remote server for GDB.
2185023Sraj   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
3185023Sraj   Free Software Foundation, Inc.
4185023Sraj
5185023Sraj   This file is part of GDB.
6185023Sraj
7185023Sraj   This program is free software; you can redistribute it and/or modify
8185023Sraj   it under the terms of the GNU General Public License as published by
9185023Sraj   the Free Software Foundation; either version 2 of the License, or
10185023Sraj   (at your option) any later version.
11185023Sraj
12185023Sraj   This program is distributed in the hope that it will be useful,
13185023Sraj   but WITHOUT ANY WARRANTY; without even the implied warranty of
14185023Sraj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15185023Sraj   GNU General Public License for more details.
16185023Sraj
17185023Sraj   You should have received a copy of the GNU General Public License
18185023Sraj   along with this program; if not, write to the Free Software
19185023Sraj   Foundation, Inc., 59 Temple Place - Suite 330,
20185023Sraj   Boston, MA 02111-1307, USA.  */
21185023Sraj
22185023Sraj#include <sys/cdefs.h>
23185023Sraj__FBSDID("$FreeBSD: releng/11.0/gnu/usr.bin/gdb/gdbserver/fbsd-arm-low.c 185023 2008-11-17 16:32:57Z raj $");
24185023Sraj
25185023Sraj#include "server.h"
26185023Sraj#include "fbsd-low.h"
27185023Sraj
28185023Sraj#ifdef HAVE_SYS_REG_H
29185023Sraj#include <sys/reg.h>
30185023Sraj#endif
31185023Sraj
32185023Sraj#include <sys/procfs.h>
33185023Sraj#include <sys/ptrace.h>
34185023Sraj
35185023Sraj#define arm_num_regs 26
36185023Sraj
37185023Srajstatic int arm_regmap[] = {
38185023Sraj  0, 4, 8, 12, 16, 20, 24, 28,
39185023Sraj  32, 36, 40, 44, 48, 52, 56, 60,
40185023Sraj  -1, -1, -1, -1, -1, -1, -1, -1, -1,
41185023Sraj  64
42185023Sraj};
43185023Sraj
44185023Srajstatic int
45185023Srajarm_cannot_store_register (int regno)
46185023Sraj{
47185023Sraj  return (regno >= arm_num_regs);
48185023Sraj}
49185023Sraj
50185023Srajstatic int
51185023Srajarm_cannot_fetch_register (int regno)
52185023Sraj{
53185023Sraj  return (regno >= arm_num_regs);
54185023Sraj}
55185023Sraj
56185023Srajextern int debug_threads;
57185023Sraj
58185023Srajstatic CORE_ADDR
59185023Srajarm_get_pc ()
60185023Sraj{
61185023Sraj  unsigned long pc;
62185023Sraj  collect_register_by_name ("pc", &pc);
63185023Sraj  if (debug_threads)
64185023Sraj    fprintf (stderr, "stop pc is %08lx\n", pc);
65185023Sraj  return pc;
66185023Sraj}
67185023Sraj
68185023Srajstatic void
69185023Srajarm_set_pc (CORE_ADDR pc)
70185023Sraj{
71185023Sraj  unsigned long newpc = pc;
72185023Sraj  supply_register_by_name ("pc", &newpc);
73185023Sraj}
74185023Sraj
75185023Sraj/* Correct in either endianness.  We do not support Thumb yet.  */
76185023Srajstatic const unsigned long arm_breakpoint = 0xef9f0001;
77185023Sraj#define arm_breakpoint_len 4
78185023Sraj
79185023Srajstatic int
80185023Srajarm_breakpoint_at (CORE_ADDR where)
81185023Sraj{
82185023Sraj  unsigned long insn;
83185023Sraj
84185023Sraj  (*the_target->read_memory) (where, (char *) &insn, 4);
85185023Sraj  if (insn == arm_breakpoint)
86185023Sraj    return 1;
87185023Sraj
88185023Sraj  /* If necessary, recognize more trap instructions here.  GDB only uses the
89185023Sraj     one.  */
90185023Sraj  return 0;
91185023Sraj}
92185023Sraj
93185023Sraj/* We only place breakpoints in empty marker functions, and thread locking
94185023Sraj   is outside of the function.  So rather than importing software single-step,
95185023Sraj   we can just run until exit.  */
96185023Srajstatic CORE_ADDR
97185023Srajarm_reinsert_addr ()
98185023Sraj{
99185023Sraj  unsigned long pc;
100185023Sraj  collect_register_by_name ("lr", &pc);
101185023Sraj  return pc;
102185023Sraj}
103185023Sraj
104185023Srajstatic void
105185023Srajarm_fill_gregset (void *buf)
106185023Sraj{
107185023Sraj  int i;
108185023Sraj
109185023Sraj  for (i = 0; i < arm_num_regs; i++)
110185023Sraj	if (arm_regmap[i] != -1)
111185023Sraj		collect_register (i, ((char *) buf) + arm_regmap[i]);
112185023Sraj
113185023Sraj}
114185023Sraj
115185023Srajstatic void
116185023Srajarm_store_gregset (const void *buf)
117185023Sraj{
118185023Sraj  int i;
119185023Sraj
120185023Sraj  for (i = 0; i < arm_num_regs; i++)
121185023Sraj	if (arm_regmap[i] != -1)
122185023Sraj		supply_register (i, ((char *) buf) + arm_regmap[i]);
123185023Sraj
124185023Sraj}
125185023Sraj
126185023Sraj
127185023Srajstruct regset_info target_regsets[] = {
128185023Sraj    {PT_GETREGS, PT_SETREGS, sizeof (struct reg),
129185023Sraj    GENERAL_REGS,
130185023Sraj    arm_fill_gregset, arm_store_gregset },
131185023Sraj    { 0, 0, -1, -1, NULL, NULL }
132185023Sraj};
133185023Sraj
134185023Srajstruct fbsd_target_ops the_low_target = {
135185023Sraj  arm_num_regs,
136185023Sraj  arm_regmap,
137185023Sraj  arm_cannot_fetch_register,
138185023Sraj  arm_cannot_store_register,
139185023Sraj  arm_get_pc,
140185023Sraj  arm_set_pc,
141185023Sraj  (const char *) &arm_breakpoint,
142185023Sraj  arm_breakpoint_len,
143185023Sraj  arm_reinsert_addr,
144185023Sraj  0,
145185023Sraj  arm_breakpoint_at,
146185023Sraj};
147