1/* FreeBSD/ARM specific low level interface, for the remote server for GDB.
2   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
3   Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.  */
21
22#include <sys/cdefs.h>
23__FBSDID("$FreeBSD$");
24
25#include "server.h"
26#include "fbsd-low.h"
27
28#ifdef HAVE_SYS_REG_H
29#include <sys/reg.h>
30#endif
31
32#include <sys/procfs.h>
33#include <sys/ptrace.h>
34
35#define arm_num_regs 26
36
37static int arm_regmap[] = {
38  0, 4, 8, 12, 16, 20, 24, 28,
39  32, 36, 40, 44, 48, 52, 56, 60,
40  -1, -1, -1, -1, -1, -1, -1, -1, -1,
41  64
42};
43
44static int
45arm_cannot_store_register (int regno)
46{
47  return (regno >= arm_num_regs);
48}
49
50static int
51arm_cannot_fetch_register (int regno)
52{
53  return (regno >= arm_num_regs);
54}
55
56extern int debug_threads;
57
58static CORE_ADDR
59arm_get_pc ()
60{
61  unsigned long pc;
62  collect_register_by_name ("pc", &pc);
63  if (debug_threads)
64    fprintf (stderr, "stop pc is %08lx\n", pc);
65  return pc;
66}
67
68static void
69arm_set_pc (CORE_ADDR pc)
70{
71  unsigned long newpc = pc;
72  supply_register_by_name ("pc", &newpc);
73}
74
75/* Correct in either endianness.  We do not support Thumb yet.  */
76static const unsigned long arm_breakpoint = 0xef9f0001;
77#define arm_breakpoint_len 4
78
79static int
80arm_breakpoint_at (CORE_ADDR where)
81{
82  unsigned long insn;
83
84  (*the_target->read_memory) (where, (char *) &insn, 4);
85  if (insn == arm_breakpoint)
86    return 1;
87
88  /* If necessary, recognize more trap instructions here.  GDB only uses the
89     one.  */
90  return 0;
91}
92
93/* We only place breakpoints in empty marker functions, and thread locking
94   is outside of the function.  So rather than importing software single-step,
95   we can just run until exit.  */
96static CORE_ADDR
97arm_reinsert_addr ()
98{
99  unsigned long pc;
100  collect_register_by_name ("lr", &pc);
101  return pc;
102}
103
104static void
105arm_fill_gregset (void *buf)
106{
107  int i;
108
109  for (i = 0; i < arm_num_regs; i++)
110	if (arm_regmap[i] != -1)
111		collect_register (i, ((char *) buf) + arm_regmap[i]);
112
113}
114
115static void
116arm_store_gregset (const void *buf)
117{
118  int i;
119
120  for (i = 0; i < arm_num_regs; i++)
121	if (arm_regmap[i] != -1)
122		supply_register (i, ((char *) buf) + arm_regmap[i]);
123
124}
125
126
127struct regset_info target_regsets[] = {
128    {PT_GETREGS, PT_SETREGS, sizeof (struct reg),
129    GENERAL_REGS,
130    arm_fill_gregset, arm_store_gregset },
131    { 0, 0, -1, -1, NULL, NULL }
132};
133
134struct fbsd_target_ops the_low_target = {
135  arm_num_regs,
136  arm_regmap,
137  arm_cannot_fetch_register,
138  arm_cannot_store_register,
139  arm_get_pc,
140  arm_set_pc,
141  (const char *) &arm_breakpoint,
142  arm_breakpoint_len,
143  arm_reinsert_addr,
144  0,
145  arm_breakpoint_at,
146};
147