Watchpoint interface.
[external/binutils.git] / sim / common / sim-watch.c
1 /* Mips simulator watchpoint support.
2    Copyright (C) 1997 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.
4
5 This file is part of GDB, the GNU debugger.
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, or (at your option)
10 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 along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "sim-main.h"
22 #include "sim-options.h"
23
24 #include "sim-assert.h"
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37
38 #include <signal.h>
39
40 static DECLARE_OPTION_HANDLER (watch_option_handler);
41
42 enum {
43   OPTION_WATCH_DELETE                      = OPTION_START,
44
45   OPTION_WATCH_PC,
46   OPTION_WATCH_CLOCK,
47   OPTION_WATCH_CYCLES,
48
49   OPTION_ACTION_PC,
50   OPTION_ACTION_CLOCK,
51   OPTION_ACTION_CYCLES,
52 };
53
54
55 static void
56 delete_watchpoint (SIM_DESC sd, watchpoint_type type)
57 {
58   sim_watch_point *point = &STATE_WATCHPOINTS (sd)->points[type];
59   if (point->event != NULL)
60     sim_events_deschedule (sd, point->event);
61   point->action = invalid_watchpoint_action;
62   point->event = NULL;
63 }
64
65
66 static sim_event_handler handle_watchpoint;
67
68 static SIM_RC
69 schedule_watchpoint (SIM_DESC sd,
70                      watchpoint_type type,
71                      unsigned long arg,
72                      int is_command)
73 {
74   sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
75   sim_watch_point *point = &watch->points[type];
76   if (point->event != NULL)
77     delete_watchpoint (sd, type);
78   point->arg = arg;
79   if (point->action == invalid_watchpoint_action)
80     point->action = break_watchpoint_action;
81   if (is_command)
82     switch (type)
83       {
84       case pc_watchpoint:
85         point->event = sim_events_watch_sim (sd, watch->pc, watch->sizeof_pc,
86                                              0/* host-endian */,
87                                              point->arg, point->arg, /* PC == arg? */
88                                              handle_watchpoint,
89                                              point);
90         return SIM_RC_OK;
91       case clock_watchpoint:
92         point->event = sim_events_watch_clock (sd,
93                                                point->arg, /* ms time */
94                                                handle_watchpoint,
95                                                point);
96         return SIM_RC_OK;
97       case cycles_watchpoint:
98         point->event = sim_events_schedule (sd, point->arg, /* time */
99                                             handle_watchpoint,
100                                             point);
101         return SIM_RC_OK;
102       default:
103         sim_engine_abort (sd, NULL, NULL_CIA,
104                           "handle_watchpoint - internal error - bad switch");
105         return SIM_RC_FAIL;
106       }
107   return SIM_RC_OK;
108 }
109
110
111 static void
112 handle_watchpoint (SIM_DESC sd, void *data)
113 {
114   sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
115   sim_watch_point *point = data;
116   watchpoint_type type = point - watch->points;
117
118   switch (point->action)
119     {
120
121     case break_watchpoint_action:
122       point->event = NULL; /* gone */
123       sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIGINT);
124       break;
125
126     case n_interrupt_watchpoint_action:
127       /* First reschedule this event */
128       schedule_watchpoint (sd, type, point->arg, 1/*is-command*/);
129       /* FALL-THROUGH */
130
131     case interrupt_watchpoint_action:
132       watch->interrupt_handler (sd, NULL);
133       break;
134
135     default:
136           sim_engine_abort (sd, NULL, NULL_CIA,
137                             "handle_watchpoint - internal error - bad switch");
138
139     }
140 }
141
142
143 static SIM_RC
144 action_watchpoint (SIM_DESC sd, watchpoint_type type, const char *arg)
145 {
146   sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
147   sim_watch_point *point = &watch->points[type];
148   if (strcmp (arg, "break") == NULL)
149     {
150       point->action = break_watchpoint_action;
151     }
152   else if (strcmp (arg, "int") == NULL)
153     {
154       if (watch->interrupt_handler == NULL)
155         {
156           sim_io_eprintf (sd, "This simulator does not support int watchpoints\n");
157           return SIM_RC_FAIL;
158         }
159       point->action = interrupt_watchpoint_action;
160     }
161   else if (strcmp (arg, "+int") == 0)
162     {
163       if (watch->interrupt_handler == NULL)
164         {
165           sim_io_eprintf (sd, "This simulator does not support int watchpoints\n");
166           return SIM_RC_FAIL;
167         }
168       point->action = n_interrupt_watchpoint_action;
169     }
170   else
171     {
172       sim_io_eprintf (sd, "Interrupts other than `int' currently unsuported\n");
173       return SIM_RC_FAIL;
174     }
175   return SIM_RC_OK;
176 }
177
178
179 static const OPTION watch_options[] =
180 {
181   { {"watch-delete", required_argument, NULL, OPTION_WATCH_DELETE },
182       '\0', "all|pc|cycles|clock", "Delete a watchpoint",
183       watch_option_handler },
184
185   { {"watch-pc", required_argument, NULL, OPTION_WATCH_PC },
186       '\0', "VALUE", "Watch the PC (break)",
187       watch_option_handler },
188   { {"watch-clock", required_argument, NULL, OPTION_WATCH_CLOCK },
189       '\0', "TIME-IN-MS", "Watch the clock (break)",
190       watch_option_handler },
191   { {"watch-cycles", required_argument, NULL, OPTION_WATCH_CYCLES },
192       '\0', "CYCLES", "Watch the cycles (break)",
193       watch_option_handler },
194
195   { {"action-pc", required_argument, NULL, OPTION_ACTION_PC },
196       '\0', "break|int|+int", "Action taken by PC watchpoint",
197       watch_option_handler },
198   { {"action-clock", required_argument, NULL, OPTION_ACTION_CLOCK },
199       '\0', "break|int|+int", "Action taken by CLOCK watchpoint",
200       watch_option_handler },
201   { {"action-cycles", required_argument, NULL, OPTION_ACTION_CYCLES },
202       '\0', "break|int|+int", "Action taken by CYCLES watchpoint",
203       watch_option_handler },
204
205   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
206 };
207
208
209 static SIM_RC
210 watch_option_handler (sd, opt, arg, is_command)
211      SIM_DESC sd;
212      int opt;
213      char *arg;
214      int is_command;
215 {
216   switch (opt)
217     {
218
219     case OPTION_WATCH_DELETE:
220       if (strcmp (arg, "all") == 0
221           || strcmp (arg, "pc") == 0)
222         {
223           delete_watchpoint (sd, pc_watchpoint);
224           return SIM_RC_OK;
225         }
226       if (strcmp (arg, "all") == 0
227           || strcmp (arg, "clock") == 0)
228         {
229           delete_watchpoint (sd, clock_watchpoint);
230           return SIM_RC_OK;
231         }
232       if (strcmp (arg, "all") == 0
233           || strcmp (arg, "cycles") == 0)
234         {
235           delete_watchpoint (sd, cycles_watchpoint);
236           return SIM_RC_OK;
237         }
238       sim_io_eprintf (sd, "Unknown watchpoint type `%s'\n", arg);
239       return SIM_RC_FAIL;
240
241     case OPTION_WATCH_PC:
242       if (STATE_WATCHPOINTS (sd)->pc == NULL)
243         {
244           sim_io_eprintf (sd, "PC watchpoints are not supported for this simulator\n");
245           return SIM_RC_FAIL;
246         }
247       return schedule_watchpoint (sd, pc_watchpoint, strtoul (arg, NULL, 0), is_command);
248
249     case OPTION_WATCH_CLOCK:
250       return schedule_watchpoint (sd, clock_watchpoint, strtoul (arg, NULL, 0), is_command);
251
252     case OPTION_WATCH_CYCLES:
253       return schedule_watchpoint (sd, cycles_watchpoint, strtoul (arg, NULL, 0), is_command);
254
255     case OPTION_ACTION_PC:
256       return action_watchpoint (sd, cycles_watchpoint, arg);
257
258     case OPTION_ACTION_CLOCK:
259       return action_watchpoint (sd, cycles_watchpoint, arg);
260
261     case OPTION_ACTION_CYCLES:
262       return action_watchpoint (sd, cycles_watchpoint, arg);
263
264
265     default:
266       sim_io_eprintf (sd, "Unknown watch option %d\n", opt);
267       return SIM_RC_FAIL;
268
269     }
270
271 }
272
273 static SIM_RC
274 sim_watchpoint_init (SIM_DESC sd)
275 {
276   /* schedule any watchpoints enabled by command line options */
277   sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
278   watchpoint_type type;
279   for (type = 0; type < nr_watchpoint_types; type++)
280     {
281       if (watch->points[type].action != invalid_watchpoint_action)
282         schedule_watchpoint (sd, type, watch->points[type].arg, 1/*is-command*/);
283     }
284   return SIM_RC_OK;
285 }
286
287
288 SIM_RC
289 sim_watchpoint_install (SIM_DESC sd)
290 {
291   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
292   sim_add_option_table (sd, watch_options);
293   sim_module_add_init_fn (sd, sim_watchpoint_init);
294   return SIM_RC_OK;
295 }