]>
Commit | Line | Data |
---|---|---|
595dc9a4 DE |
1 | /* Generic remote debugging interface for simulators. |
2 | Copyright 1993 Free Software Foundation, Inc. | |
cb747ec5 DE |
3 | Contributed by Cygnus Support. Hacked from Steve Chamberlain's Z8000 work |
4 | by Doug Evans. ([email protected]). | |
5 | ||
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
21 | ||
22 | #include "defs.h" | |
23 | #include "inferior.h" | |
24 | #include "wait.h" | |
25 | #include "value.h" | |
26 | #include <string.h> | |
27 | #include <ctype.h> | |
28 | #include <fcntl.h> | |
29 | #include <signal.h> | |
30 | #include <setjmp.h> | |
31 | #include <errno.h> | |
32 | #include "terminal.h" | |
33 | #include "target.h" | |
34 | #include "gdbcore.h" | |
595dc9a4 | 35 | #include "simif.h" |
cb747ec5 DE |
36 | |
37 | /* Naming conventions: | |
38 | ||
595dc9a4 DE |
39 | sim_xxx are internal objects that describe top level interfaces to the |
40 | simulator. | |
cb747ec5 | 41 | |
595dc9a4 DE |
42 | simif_xxx are external counterparts to the sim_xxx objects that must be |
43 | provided by the simulator (simif for SIMulator InterFace, duh...). | |
44 | ||
45 | A complete list of them is: | |
46 | ||
47 | --- Fetch one register and store the raw value in BUF. | |
48 | ||
49 | int simif_fetch_register (int regno, char *buf); | |
50 | ||
51 | --- Store VAL in one register. | |
52 | ||
53 | int simif_store_register (int regno, char *val); | |
54 | ||
55 | --- Complete terminate the simulator. This includes freeing all memory, | |
56 | closing all open files, and releasing all mmap'd memory. | |
57 | ||
58 | int simif_kill (void); | |
59 | ||
60 | --- Load program PROG into the simulator. | |
61 | ||
62 | int simif_load (bfd *abfd, char *prog); | |
63 | ||
64 | --- Set the arguments and environment for the program loaded into the | |
65 | simulator. ARGV and ENV are NULL terminated lists of pointers. | |
66 | ||
67 | int simif_set_args (char **argv, char **env); | |
68 | ||
69 | --- Initialize the simulator. This function is called when the simulator | |
70 | is selected from the command line. ARGS is passed from the command line | |
71 | and can be used to select whatever run time options the simulator provides. | |
72 | ARGS is the raw character string and must be parsed by the simulator. | |
73 | ||
74 | int simif_open (char *args); | |
75 | ||
76 | --- Start running the program, or resume it after a breakpoint. | |
77 | FIXME: What are A and B? | |
78 | ||
79 | int simif_resume (int a, int b); | |
80 | ||
81 | --- Fetch the reason why the program stopped running (breakpoint, signal, | |
82 | etc.) | |
83 | ||
84 | WAITTYPE simif_stop_signal (void); | |
85 | ||
86 | --- Write some data into the program's memory. | |
87 | Result is 0 for success, nonzero for failure. | |
88 | ||
89 | int simif_write (CORE_ADDR memaddr, char *myaddr, int len); | |
90 | ||
91 | --- Read some data from the program's memory. | |
92 | Result is 0 for success, nonzero for failure. | |
93 | ||
94 | int simif_read (CORE_ADDR memaddr, char *myaddr, int len); | |
95 | */ | |
cb747ec5 DE |
96 | |
97 | /* Forward data declarations */ | |
595dc9a4 | 98 | extern struct target_ops sim_ops; |
cb747ec5 | 99 | |
595dc9a4 | 100 | int sim_verbose = 0; /* available to the simulator to use */ |
cb747ec5 DE |
101 | |
102 | static int program_loaded = 0; | |
103 | ||
104 | static void dump_mem (); | |
105 | ||
106 | static void | |
595dc9a4 | 107 | sim_fetch_register (regno) |
cb747ec5 DE |
108 | int regno; |
109 | { | |
110 | if (regno == -1) | |
111 | { | |
595dc9a4 DE |
112 | if (sim_verbose) |
113 | printf_filtered ("sim_fetch_register: %d\n", regno); | |
114 | /* FIXME: Where did the 16 come from and what does it need to be? */ | |
cb747ec5 | 115 | for (regno = 0; regno < 16; regno++) |
595dc9a4 | 116 | sim_fetch_register (regno); |
cb747ec5 DE |
117 | } |
118 | else | |
119 | { | |
120 | char buf[MAX_REGISTER_RAW_SIZE]; | |
121 | ||
595dc9a4 | 122 | simif_fetch_register (regno, buf); |
cb747ec5 | 123 | supply_register (regno, buf); |
595dc9a4 | 124 | if (sim_verbose) |
cb747ec5 | 125 | { |
595dc9a4 | 126 | printf_filtered ("sim_fetch_register: %d", regno); |
cb747ec5 DE |
127 | dump_mem (buf, sizeof (REGISTER_TYPE)); |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | static void | |
595dc9a4 | 133 | sim_store_register (regno) |
cb747ec5 DE |
134 | int regno; |
135 | { | |
136 | if (regno == -1) | |
137 | { | |
595dc9a4 DE |
138 | if (sim_verbose) |
139 | printf_filtered ("sim_store_register: %d\n", regno); | |
140 | /* FIXME: 16? */ | |
cb747ec5 | 141 | for (regno = 0; regno < 16; regno++) |
595dc9a4 | 142 | sim_store_register (regno); |
cb747ec5 | 143 | } |
595dc9a4 | 144 | else |
cb747ec5 DE |
145 | { |
146 | char value[sizeof (REGISTER_TYPE)]; | |
147 | ||
148 | read_register_gen (regno, value); | |
149 | SWAP_TARGET_AND_HOST (value, sizeof (REGISTER_TYPE)); | |
595dc9a4 DE |
150 | simif_store_register (regno, value); |
151 | if (sim_verbose) | |
cb747ec5 | 152 | { |
595dc9a4 | 153 | printf_filtered ("sim_store_register: %d", regno); |
cb747ec5 DE |
154 | dump_mem (value, sizeof (REGISTER_TYPE)); |
155 | } | |
156 | } | |
157 | } | |
158 | ||
159 | static void | |
595dc9a4 | 160 | sim_kill (arg,from_tty) |
cb747ec5 DE |
161 | char *arg; |
162 | int from_tty; | |
163 | { | |
595dc9a4 DE |
164 | if (sim_verbose) |
165 | printf_filtered ("sim_kill: arg \"%s\"\n", arg); | |
cb747ec5 | 166 | |
595dc9a4 | 167 | simif_kill (); /* close fd's, remove mappings */ |
cb747ec5 DE |
168 | inferior_pid = 0; |
169 | } | |
170 | ||
595dc9a4 | 171 | /* Load program PROG into the sim. */ |
cb747ec5 DE |
172 | |
173 | static void | |
595dc9a4 DE |
174 | sim_load (prog, fromtty) |
175 | char *prog; | |
cb747ec5 DE |
176 | int fromtty; |
177 | { | |
178 | bfd *abfd; | |
179 | ||
595dc9a4 DE |
180 | if (sim_verbose) |
181 | printf_filtered ("sim_load: prog \"%s\"\n", prog); | |
cb747ec5 DE |
182 | |
183 | inferior_pid = 0; | |
184 | program_loaded = 0; | |
595dc9a4 | 185 | abfd = bfd_openr (prog, (char *) 0); |
cb747ec5 DE |
186 | |
187 | if (!abfd) | |
595dc9a4 | 188 | error ("Unable to open file %s.", prog); |
cb747ec5 DE |
189 | |
190 | if (bfd_check_format (abfd, bfd_object) ==0) | |
191 | error ("File is not an object file."); | |
192 | ||
595dc9a4 | 193 | if (simif_load (abfd, prog) != 0) |
cb747ec5 DE |
194 | return; |
195 | ||
196 | program_loaded = 1; | |
197 | ||
595dc9a4 | 198 | simif_set_pc (abfd->start_address); |
cb747ec5 DE |
199 | } |
200 | ||
201 | /* This is called not only when we first attach, but also when the | |
202 | user types "run" after having attached. */ | |
203 | ||
204 | static void | |
595dc9a4 | 205 | sim_create_inferior (exec_file, args, env) |
cb747ec5 DE |
206 | char *exec_file; |
207 | char *args; | |
208 | char **env; | |
209 | { | |
210 | int len,entry_pt; | |
211 | char *arg_buf,**argv; | |
212 | ||
213 | if (! program_loaded) | |
214 | error ("No program loaded."); | |
215 | ||
595dc9a4 DE |
216 | if (sim_verbose) |
217 | printf_filtered ("sim_create_inferior: exec_file \"%s\", args \"%s\"\n", | |
cb747ec5 DE |
218 | exec_file, args); |
219 | ||
220 | if (exec_file == 0 || exec_bfd == 0) | |
221 | error ("No exec file specified."); | |
222 | ||
223 | entry_pt = (int) bfd_get_start_address (exec_bfd); | |
224 | ||
595dc9a4 | 225 | sim_kill (NULL, NULL); |
cb747ec5 DE |
226 | remove_breakpoints (); |
227 | init_wait_for_inferior (); | |
228 | ||
229 | len = 5 + strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10; | |
230 | arg_buf = (char *) alloca (len); | |
231 | arg_buf[0] = '\0'; | |
232 | strcat (arg_buf, exec_file); | |
233 | strcat (arg_buf, " "); | |
234 | strcat (arg_buf, args); | |
235 | argv = buildargv (arg_buf); | |
236 | make_cleanup (freeargv, (char *) argv); | |
595dc9a4 | 237 | simif_set_args (argv, env); |
cb747ec5 DE |
238 | |
239 | inferior_pid = 42; | |
240 | insert_breakpoints (); /* Needed to get correct instruction in cache */ | |
241 | proceed (entry_pt, -1, 0); | |
242 | } | |
243 | ||
595dc9a4 | 244 | /* Called when selecting the simulator. EG: (gdb) target sim name. */ |
cb747ec5 DE |
245 | |
246 | static void | |
595dc9a4 DE |
247 | sim_open (args, from_tty) |
248 | char *args; | |
cb747ec5 DE |
249 | int from_tty; |
250 | { | |
595dc9a4 DE |
251 | if (sim_verbose) |
252 | printf_filtered ("sim_open: args \"%s\"\n", args); | |
cb747ec5 | 253 | |
595dc9a4 | 254 | if (simif_open (args) != 0) |
cb747ec5 DE |
255 | { |
256 | error ("Unable to initialize simulator (insufficient memory?)."); | |
257 | return; | |
258 | } | |
259 | ||
595dc9a4 | 260 | push_target (&sim_ops); |
cb747ec5 DE |
261 | target_fetch_registers (-1); |
262 | ||
263 | printf_filtered ("Connected to the simulator.\n"); | |
264 | } | |
265 | ||
266 | /* Close out all files and local state before this target loses control. */ | |
267 | ||
268 | static void | |
595dc9a4 | 269 | sim_close (quitting) |
cb747ec5 DE |
270 | int quitting; |
271 | { | |
595dc9a4 DE |
272 | if (sim_verbose) |
273 | printf_filtered ("sim_close: quitting %d\n", quitting); | |
cb747ec5 DE |
274 | |
275 | program_loaded = 0; | |
276 | ||
595dc9a4 | 277 | /* FIXME: Need to call simif_close() to close all files and |
cb747ec5 DE |
278 | delete all mappings. */ |
279 | } | |
280 | ||
281 | /* Terminate the open connection to the remote debugger. | |
282 | Use this when you want to detach and do something else | |
283 | with your gdb. */ | |
284 | ||
285 | static void | |
595dc9a4 | 286 | sim_detach (args,from_tty) |
cb747ec5 DE |
287 | char *args; |
288 | int from_tty; | |
289 | { | |
595dc9a4 DE |
290 | if (sim_verbose) |
291 | printf_filtered ("sim_detach: args \"%s\"\n", args); | |
cb747ec5 | 292 | |
595dc9a4 | 293 | pop_target (); /* calls sim_close to do the real work */ |
cb747ec5 DE |
294 | if (from_tty) |
295 | printf_filtered ("Ending simulator %s debugging\n", target_shortname); | |
296 | } | |
297 | ||
298 | /* Tell the remote machine to resume. */ | |
299 | /* FIXME: What are A and B? */ | |
300 | ||
301 | static void | |
595dc9a4 | 302 | sim_resume (a,b) |
cb747ec5 | 303 | { |
595dc9a4 DE |
304 | if (sim_verbose) |
305 | printf_filtered ("sim_resume: %d/%d\n", a, b); | |
cb747ec5 | 306 | |
595dc9a4 | 307 | simif_resume (a, b); |
cb747ec5 DE |
308 | } |
309 | ||
310 | /* Wait until the remote machine stops, then return, | |
311 | storing status in STATUS just as `wait' would. */ | |
312 | ||
313 | static int | |
595dc9a4 | 314 | sim_wait (status) |
cb747ec5 DE |
315 | WAITTYPE *status; |
316 | { | |
595dc9a4 DE |
317 | if (sim_verbose) |
318 | printf_filtered ("sim_wait: "); | |
cb747ec5 | 319 | #if 1 |
595dc9a4 | 320 | *status = simif_stop_signal (); |
cb747ec5 | 321 | #else |
595dc9a4 | 322 | WSETSTOP (*status, simif_stop_signal ()); |
cb747ec5 | 323 | #endif |
595dc9a4 | 324 | if (sim_verbose) |
cb747ec5 DE |
325 | printf_filtered ("status %d\n", *status); |
326 | return 0; | |
327 | } | |
328 | ||
329 | /* Get ready to modify the registers array. On machines which store | |
330 | individual registers, this doesn't need to do anything. On machines | |
331 | which store all the registers in one fell swoop, this makes sure | |
332 | that registers contains all the registers from the program being | |
333 | debugged. */ | |
334 | ||
335 | static void | |
595dc9a4 | 336 | sim_prepare_to_store () |
cb747ec5 DE |
337 | { |
338 | /* Do nothing, since we can store individual regs */ | |
339 | } | |
340 | ||
341 | static int | |
595dc9a4 | 342 | sim_xfer_inferior_memory (memaddr, myaddr, len, write, target) |
cb747ec5 DE |
343 | CORE_ADDR memaddr; |
344 | char *myaddr; | |
345 | int len; | |
346 | int write; | |
347 | struct target_ops *target; /* ignored */ | |
348 | { | |
595dc9a4 DE |
349 | if (sim_verbose) |
350 | { | |
351 | printf_filtered ("sim_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n", | |
352 | myaddr, memaddr, len, write); | |
353 | if (sim_verbose && write) | |
354 | dump_mem(myaddr, len); | |
355 | } | |
cb747ec5 DE |
356 | |
357 | if (! program_loaded) | |
358 | error ("No program loaded."); | |
359 | ||
360 | if (write) | |
595dc9a4 DE |
361 | { |
362 | len = simif_write (memaddr, myaddr, len); | |
363 | } | |
cb747ec5 | 364 | else |
595dc9a4 DE |
365 | { |
366 | len = simif_read (memaddr, myaddr, len); | |
367 | if (sim_verbose && len > 0) | |
368 | dump_mem(myaddr, len); | |
369 | } | |
cb747ec5 DE |
370 | return len; |
371 | } | |
372 | ||
373 | static void | |
595dc9a4 | 374 | sim_files_info () |
cb747ec5 DE |
375 | { |
376 | char *file = "nothing"; | |
377 | ||
378 | if (exec_bfd) | |
379 | file = bfd_get_filename (exec_bfd); | |
380 | ||
595dc9a4 DE |
381 | if (sim_verbose) |
382 | printf_filtered ("sim_files_info: file \"%s\"\n", file); | |
cb747ec5 DE |
383 | |
384 | if (exec_bfd) | |
385 | printf_filtered ("\tAttached to %s running program %s\n", | |
386 | target_shortname, file); | |
387 | } | |
388 | ||
389 | /* Clear the sims notion of what the break points are */ | |
390 | static void | |
595dc9a4 | 391 | sim_mourn () |
cb747ec5 | 392 | { |
595dc9a4 DE |
393 | if (sim_verbose) |
394 | printf_filtered ("sim_mourn:\n"); | |
cb747ec5 DE |
395 | |
396 | remove_breakpoints (); | |
397 | generic_mourn_inferior (); | |
398 | } | |
399 | ||
400 | /* Define the target subroutine names */ | |
401 | ||
595dc9a4 | 402 | struct target_ops sim_ops = |
cb747ec5 | 403 | { |
595dc9a4 DE |
404 | "sim", "Simulator", |
405 | "Use the Simulator", | |
406 | sim_open, sim_close, | |
407 | 0, sim_detach, sim_resume, sim_wait, /* attach */ | |
408 | sim_fetch_register, sim_store_register, | |
409 | sim_prepare_to_store, | |
410 | sim_xfer_inferior_memory, | |
411 | sim_files_info, | |
cb747ec5 DE |
412 | 0, 0, /* Breakpoints */ |
413 | 0, 0, 0, 0, 0, /* Terminal handling */ | |
595dc9a4 DE |
414 | sim_kill, /* FIXME, kill */ |
415 | sim_load, | |
cb747ec5 | 416 | 0, /* lookup_symbol */ |
595dc9a4 DE |
417 | sim_create_inferior, /* create_inferior */ |
418 | sim_mourn, /* mourn_inferior FIXME */ | |
cb747ec5 DE |
419 | 0, /* can_run */ |
420 | 0, /* notice_signals */ | |
421 | process_stratum, 0, /* next */ | |
422 | 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ | |
423 | 0, 0, /* Section pointers */ | |
424 | OPS_MAGIC, /* Always the last thing */ | |
425 | }; | |
426 | ||
427 | static void | |
595dc9a4 | 428 | sim_snoop () |
cb747ec5 | 429 | { |
595dc9a4 DE |
430 | sim_verbose = ! sim_verbose; |
431 | if (sim_verbose) | |
cb747ec5 DE |
432 | printf_filtered ("Snoop enabled\n"); |
433 | else | |
434 | printf_filtered ("Snoop disabled\n"); | |
435 | ||
436 | } | |
437 | ||
438 | /***********************************************************************/ | |
439 | ||
440 | void | |
441 | _initialize_remote_sim () | |
442 | { | |
595dc9a4 DE |
443 | add_target (&sim_ops); |
444 | add_com ("snoop", class_obscure, sim_snoop, | |
cb747ec5 DE |
445 | "Show what commands are going to the simulator"); |
446 | } | |
447 | ||
448 | static void | |
449 | dump_mem (buf, len) | |
450 | char *buf; | |
451 | int len; | |
452 | { | |
453 | if (len <= 8) | |
cb747ec5 | 454 | { |
595dc9a4 DE |
455 | if (len == 8 || len == 4) |
456 | { | |
457 | long l[2]; | |
458 | memcpy (l, buf, len); | |
459 | printf_filtered ("\t0x%x", l[0]); | |
460 | printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]); | |
461 | } | |
462 | else | |
463 | { | |
464 | int i; | |
465 | printf_filtered ("\t"); | |
466 | for (i = 0; i < len; i++) | |
467 | printf_filtered ("0x%x ", buf[i]); | |
468 | printf_filtered ("\n"); | |
469 | } | |
cb747ec5 | 470 | } |
cb747ec5 | 471 | } |