Commit | Line | Data |
---|---|---|
595dc9a4 DE |
1 | /* Generic remote debugging interface for simulators. |
2 | Copyright 1993 Free Software Foundation, Inc. | |
b562a186 DE |
3 | Contributed by Cygnus Support. |
4 | Steve Chamberlain (sac@cygnus.com) and Doug Evans (dje@cygnus.com). | |
cb747ec5 DE |
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" | |
b562a186 | 35 | #include "remote-sim.h" |
cb747ec5 DE |
36 | |
37 | /* Naming conventions: | |
38 | ||
b562a186 DE |
39 | simif_xxx are internal objects that describe top level interfaces to the |
40 | simulator (simif for SIMulator InterFace, duh...). | |
cb747ec5 | 41 | |
b562a186 DE |
42 | sim_xxx are external counterparts to the simif_xxx objects that must be |
43 | provided by the simulator. | |
595dc9a4 | 44 | |
b562a186 | 45 | See simif.h for a description. */ |
cb747ec5 DE |
46 | |
47 | /* Forward data declarations */ | |
b562a186 | 48 | extern struct target_ops simif_ops; |
cb747ec5 | 49 | |
595dc9a4 | 50 | int sim_verbose = 0; /* available to the simulator to use */ |
cb747ec5 DE |
51 | |
52 | static int program_loaded = 0; | |
53 | ||
54 | static void dump_mem (); | |
55 | ||
56 | static void | |
b562a186 | 57 | simif_fetch_register (regno) |
cb747ec5 DE |
58 | int regno; |
59 | { | |
60 | if (regno == -1) | |
61 | { | |
b562a186 DE |
62 | for (regno = 0; regno < NUM_REGS; regno++) |
63 | simif_fetch_register (regno); | |
cb747ec5 DE |
64 | } |
65 | else | |
66 | { | |
67 | char buf[MAX_REGISTER_RAW_SIZE]; | |
68 | ||
b562a186 | 69 | sim_fetch_register (regno, buf); |
cb747ec5 | 70 | supply_register (regno, buf); |
595dc9a4 | 71 | if (sim_verbose) |
cb747ec5 | 72 | { |
b562a186 DE |
73 | printf_filtered ("simif_fetch_register: %d", regno); |
74 | /* FIXME: We could print something more intelligible. */ | |
75 | dump_mem (buf, REGISTER_RAW_SIZE (regno)); | |
cb747ec5 DE |
76 | } |
77 | } | |
78 | } | |
79 | ||
80 | static void | |
b562a186 | 81 | simif_store_register (regno) |
cb747ec5 DE |
82 | int regno; |
83 | { | |
84 | if (regno == -1) | |
85 | { | |
b562a186 DE |
86 | for (regno = 0; regno < NUM_REGS; regno++) |
87 | simif_store_register (regno); | |
cb747ec5 | 88 | } |
595dc9a4 | 89 | else |
cb747ec5 | 90 | { |
b562a186 DE |
91 | /* FIXME: Until read_register() returns LONGEST, we have this. */ |
92 | char value[MAX_REGISTER_RAW_SIZE]; | |
cb747ec5 DE |
93 | |
94 | read_register_gen (regno, value); | |
b562a186 DE |
95 | SWAP_TARGET_AND_HOST (value, REGISTER_RAW_SIZE (regno)); |
96 | sim_store_register (regno, value); | |
595dc9a4 | 97 | if (sim_verbose) |
cb747ec5 | 98 | { |
b562a186 DE |
99 | printf_filtered ("simif_store_register: %d", regno); |
100 | /* FIXME: We could print something more intelligible. */ | |
101 | dump_mem (value, REGISTER_RAW_SIZE (regno)); | |
cb747ec5 DE |
102 | } |
103 | } | |
104 | } | |
105 | ||
106 | static void | |
b562a186 | 107 | simif_kill () |
cb747ec5 | 108 | { |
595dc9a4 | 109 | if (sim_verbose) |
b562a186 | 110 | printf_filtered ("simif_kill\n"); |
cb747ec5 | 111 | |
b562a186 | 112 | sim_kill (); /* close fd's, remove mappings */ |
cb747ec5 DE |
113 | inferior_pid = 0; |
114 | } | |
115 | ||
b562a186 DE |
116 | /* Load an executable file into the target process. This is expected to |
117 | not only bring new code into the target process, but also to update | |
118 | GDB's symbol tables to match. */ | |
cb747ec5 DE |
119 | |
120 | static void | |
b562a186 | 121 | simif_load (prog, fromtty) |
595dc9a4 | 122 | char *prog; |
cb747ec5 DE |
123 | int fromtty; |
124 | { | |
125 | bfd *abfd; | |
126 | ||
595dc9a4 | 127 | if (sim_verbose) |
b562a186 | 128 | printf_filtered ("simif_load: prog \"%s\"\n", prog); |
cb747ec5 DE |
129 | |
130 | inferior_pid = 0; | |
131 | program_loaded = 0; | |
595dc9a4 | 132 | abfd = bfd_openr (prog, (char *) 0); |
cb747ec5 DE |
133 | |
134 | if (!abfd) | |
595dc9a4 | 135 | error ("Unable to open file %s.", prog); |
cb747ec5 | 136 | |
b562a186 | 137 | if (bfd_check_format (abfd, bfd_object) == 0) |
cb747ec5 DE |
138 | error ("File is not an object file."); |
139 | ||
b562a186 | 140 | if (sim_load (abfd, prog) != 0) |
cb747ec5 DE |
141 | return; |
142 | ||
143 | program_loaded = 1; | |
144 | ||
b562a186 DE |
145 | sim_set_pc (abfd->start_address); |
146 | } | |
147 | ||
148 | /* | |
149 | * This is a utility routine that sim_load() can call to do the work. | |
150 | * The result is 0 for success, non-zero for failure. | |
151 | * | |
152 | * Eg: int sim_load (bfd *bfd, char *prog) { return sim_load_standard (bfd); } | |
153 | */ | |
154 | ||
155 | sim_load_standard (abfd) | |
156 | bfd *abfd; | |
157 | { | |
158 | asection *s; | |
159 | ||
160 | s = abfd->sections; | |
161 | while (s != (asection *)NULL) | |
162 | { | |
163 | if (s->flags & SEC_LOAD) | |
164 | { | |
165 | int i; | |
166 | int delta = 4096; | |
167 | char *buffer = xmalloc (delta); | |
168 | printf_filtered ("%s\t: 0x%4x .. 0x%4x ", | |
169 | s->name, s->vma, s->vma + s->_raw_size); | |
170 | for (i = 0; i < s->_raw_size; i+= delta) | |
171 | { | |
172 | int sub_delta = delta; | |
173 | if (sub_delta > s->_raw_size - i) | |
174 | sub_delta = s->_raw_size - i ; | |
175 | ||
176 | bfd_get_section_contents (abfd, s, buffer, i, sub_delta); | |
177 | sim_write (s->vma + i, buffer, sub_delta); | |
178 | printf_filtered ("*"); | |
179 | fflush (stdout); | |
180 | } | |
181 | printf_filtered ("\n"); | |
182 | free (buffer); | |
183 | } | |
184 | s = s->next; | |
185 | } | |
186 | ||
187 | return 0; | |
cb747ec5 DE |
188 | } |
189 | ||
b562a186 DE |
190 | /* Start an inferior process and set inferior_pid to its pid. |
191 | EXEC_FILE is the file to run. | |
192 | ALLARGS is a string containing the arguments to the program. | |
193 | ENV is the environment vector to pass. Errors reported with error(). | |
194 | On VxWorks and various standalone systems, we ignore exec_file. */ | |
cb747ec5 DE |
195 | /* This is called not only when we first attach, but also when the |
196 | user types "run" after having attached. */ | |
197 | ||
198 | static void | |
b562a186 | 199 | simif_create_inferior (exec_file, args, env) |
cb747ec5 DE |
200 | char *exec_file; |
201 | char *args; | |
202 | char **env; | |
203 | { | |
204 | int len,entry_pt; | |
205 | char *arg_buf,**argv; | |
206 | ||
207 | if (! program_loaded) | |
208 | error ("No program loaded."); | |
209 | ||
595dc9a4 | 210 | if (sim_verbose) |
b562a186 | 211 | printf_filtered ("simif_create_inferior: exec_file \"%s\", args \"%s\"\n", |
cb747ec5 DE |
212 | exec_file, args); |
213 | ||
214 | if (exec_file == 0 || exec_bfd == 0) | |
215 | error ("No exec file specified."); | |
216 | ||
217 | entry_pt = (int) bfd_get_start_address (exec_bfd); | |
218 | ||
b562a186 | 219 | simif_kill (NULL, NULL); |
cb747ec5 DE |
220 | remove_breakpoints (); |
221 | init_wait_for_inferior (); | |
222 | ||
223 | len = 5 + strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10; | |
224 | arg_buf = (char *) alloca (len); | |
225 | arg_buf[0] = '\0'; | |
226 | strcat (arg_buf, exec_file); | |
227 | strcat (arg_buf, " "); | |
228 | strcat (arg_buf, args); | |
229 | argv = buildargv (arg_buf); | |
230 | make_cleanup (freeargv, (char *) argv); | |
6eb0b283 DE |
231 | /* FIXME: remote-sim.h says targets that don't support this return |
232 | non-zero. Perhaps distinguish between "not supported" and other errors? | |
233 | Or maybe that can be the only error. */ | |
b562a186 DE |
234 | if (sim_set_args (argv, env) != 0) |
235 | return; | |
cb747ec5 DE |
236 | |
237 | inferior_pid = 42; | |
238 | insert_breakpoints (); /* Needed to get correct instruction in cache */ | |
239 | proceed (entry_pt, -1, 0); | |
240 | } | |
241 | ||
b562a186 DE |
242 | /* The open routine takes the rest of the parameters from the command, |
243 | and (if successful) pushes a new target onto the stack. | |
244 | Targets should supply this routine, if only to provide an error message. */ | |
595dc9a4 | 245 | /* Called when selecting the simulator. EG: (gdb) target sim name. */ |
cb747ec5 DE |
246 | |
247 | static void | |
b562a186 | 248 | simif_open (args, from_tty) |
595dc9a4 | 249 | char *args; |
cb747ec5 DE |
250 | int from_tty; |
251 | { | |
595dc9a4 | 252 | if (sim_verbose) |
b562a186 | 253 | printf_filtered ("simif_open: args \"%s\"\n", args); |
cb747ec5 | 254 | |
b562a186 | 255 | if (sim_open (args) != 0) |
cb747ec5 DE |
256 | { |
257 | error ("Unable to initialize simulator (insufficient memory?)."); | |
258 | return; | |
259 | } | |
260 | ||
b562a186 | 261 | push_target (&simif_ops); |
cb747ec5 DE |
262 | target_fetch_registers (-1); |
263 | ||
b562a186 | 264 | /* FIXME: check from_tty here? */ |
cb747ec5 DE |
265 | printf_filtered ("Connected to the simulator.\n"); |
266 | } | |
267 | ||
b562a186 DE |
268 | /* Does whatever cleanup is required for a target that we are no longer |
269 | going to be calling. Argument says whether we are quitting gdb and | |
270 | should not get hung in case of errors, or whether we want a clean | |
271 | termination even if it takes a while. This routine is automatically | |
272 | always called just before a routine is popped off the target stack. | |
273 | Closing file descriptors and freeing memory are typical things it should | |
274 | do. */ | |
cb747ec5 DE |
275 | /* Close out all files and local state before this target loses control. */ |
276 | ||
277 | static void | |
b562a186 | 278 | simif_close (quitting) |
cb747ec5 DE |
279 | int quitting; |
280 | { | |
595dc9a4 | 281 | if (sim_verbose) |
b562a186 | 282 | printf_filtered ("simif_close: quitting %d\n", quitting); |
cb747ec5 DE |
283 | |
284 | program_loaded = 0; | |
285 | ||
b562a186 | 286 | /* FIXME: Need to call sim_close() to close all files and |
cb747ec5 DE |
287 | delete all mappings. */ |
288 | } | |
289 | ||
b562a186 DE |
290 | /* Takes a program previously attached to and detaches it. |
291 | The program may resume execution (some targets do, some don't) and will | |
292 | no longer stop on signals, etc. We better not have left any breakpoints | |
293 | in the program or it'll die when it hits one. ARGS is arguments | |
294 | typed by the user (e.g. a signal to send the process). FROM_TTY | |
295 | says whether to be verbose or not. */ | |
cb747ec5 | 296 | /* Terminate the open connection to the remote debugger. |
b562a186 | 297 | Use this when you want to detach and do something else with your gdb. */ |
cb747ec5 DE |
298 | |
299 | static void | |
b562a186 | 300 | simif_detach (args,from_tty) |
cb747ec5 DE |
301 | char *args; |
302 | int from_tty; | |
303 | { | |
595dc9a4 | 304 | if (sim_verbose) |
b562a186 | 305 | printf_filtered ("simif_detach: args \"%s\"\n", args); |
cb747ec5 | 306 | |
b562a186 | 307 | pop_target (); /* calls simif_close to do the real work */ |
cb747ec5 DE |
308 | if (from_tty) |
309 | printf_filtered ("Ending simulator %s debugging\n", target_shortname); | |
310 | } | |
311 | ||
b562a186 DE |
312 | /* Resume execution of the target process. STEP says whether to single-step |
313 | or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given | |
314 | to the target, or zero for no signal. */ | |
cb747ec5 DE |
315 | |
316 | static void | |
25286543 SG |
317 | simif_resume (pid, step, siggnal) |
318 | int pid, step, siggnal; | |
cb747ec5 | 319 | { |
595dc9a4 | 320 | if (sim_verbose) |
b562a186 | 321 | printf_filtered ("simif_resume: step %d, signal %d\n", step, siggnal); |
cb747ec5 | 322 | |
b562a186 | 323 | sim_resume (step, siggnal); |
cb747ec5 DE |
324 | } |
325 | ||
b562a186 DE |
326 | /* Wait for inferior process to do something. Return pid of child, |
327 | or -1 in case of error; store status through argument pointer STATUS, | |
328 | just as `wait' would. */ | |
cb747ec5 DE |
329 | |
330 | static int | |
b562a186 | 331 | simif_wait (status) |
cb747ec5 DE |
332 | WAITTYPE *status; |
333 | { | |
595dc9a4 | 334 | if (sim_verbose) |
b562a186 | 335 | printf_filtered ("simif_wait: "); |
cb747ec5 | 336 | #if 1 |
b562a186 | 337 | *status = sim_stop_signal (); |
cb747ec5 | 338 | #else |
b562a186 | 339 | WSETSTOP (*status, sim_stop_signal ()); |
cb747ec5 | 340 | #endif |
595dc9a4 | 341 | if (sim_verbose) |
cb747ec5 DE |
342 | printf_filtered ("status %d\n", *status); |
343 | return 0; | |
344 | } | |
345 | ||
346 | /* Get ready to modify the registers array. On machines which store | |
347 | individual registers, this doesn't need to do anything. On machines | |
348 | which store all the registers in one fell swoop, this makes sure | |
349 | that registers contains all the registers from the program being | |
350 | debugged. */ | |
351 | ||
352 | static void | |
b562a186 | 353 | simif_prepare_to_store () |
cb747ec5 DE |
354 | { |
355 | /* Do nothing, since we can store individual regs */ | |
356 | } | |
357 | ||
358 | static int | |
b562a186 | 359 | simif_xfer_inferior_memory (memaddr, myaddr, len, write, target) |
cb747ec5 DE |
360 | CORE_ADDR memaddr; |
361 | char *myaddr; | |
362 | int len; | |
363 | int write; | |
364 | struct target_ops *target; /* ignored */ | |
365 | { | |
b562a186 DE |
366 | if (! program_loaded) |
367 | error ("No program loaded."); | |
368 | ||
595dc9a4 DE |
369 | if (sim_verbose) |
370 | { | |
b562a186 | 371 | printf_filtered ("simif_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n", |
595dc9a4 DE |
372 | myaddr, memaddr, len, write); |
373 | if (sim_verbose && write) | |
374 | dump_mem(myaddr, len); | |
375 | } | |
cb747ec5 | 376 | |
cb747ec5 | 377 | if (write) |
595dc9a4 | 378 | { |
b562a186 | 379 | len = sim_write (memaddr, myaddr, len); |
595dc9a4 | 380 | } |
cb747ec5 | 381 | else |
595dc9a4 | 382 | { |
b562a186 DE |
383 | len = sim_read (memaddr, myaddr, len); |
384 | if (sim_verbose && len > 0) | |
595dc9a4 DE |
385 | dump_mem(myaddr, len); |
386 | } | |
cb747ec5 DE |
387 | return len; |
388 | } | |
389 | ||
390 | static void | |
b562a186 DE |
391 | simif_files_info (target) |
392 | struct target_ops *target; | |
cb747ec5 DE |
393 | { |
394 | char *file = "nothing"; | |
395 | ||
396 | if (exec_bfd) | |
397 | file = bfd_get_filename (exec_bfd); | |
398 | ||
595dc9a4 | 399 | if (sim_verbose) |
b562a186 | 400 | printf_filtered ("simif_files_info: file \"%s\"\n", file); |
cb747ec5 DE |
401 | |
402 | if (exec_bfd) | |
b562a186 DE |
403 | { |
404 | printf_filtered ("\tAttached to %s running program %s\n", | |
405 | target_shortname, file); | |
406 | sim_info (); | |
407 | } | |
cb747ec5 DE |
408 | } |
409 | ||
b562a186 DE |
410 | /* Clear the sims notion of what the break points are. */ |
411 | ||
cb747ec5 | 412 | static void |
b562a186 | 413 | simif_mourn_inferior () |
cb747ec5 | 414 | { |
595dc9a4 | 415 | if (sim_verbose) |
b562a186 | 416 | printf_filtered ("simif_mourn_inferior:\n"); |
cb747ec5 DE |
417 | |
418 | remove_breakpoints (); | |
419 | generic_mourn_inferior (); | |
420 | } | |
421 | ||
422 | /* Define the target subroutine names */ | |
423 | ||
b562a186 | 424 | struct target_ops simif_ops = |
cb747ec5 | 425 | { |
b562a186 DE |
426 | "sim", "simulator", |
427 | "Use the simulator", | |
428 | simif_open, simif_close, | |
429 | 0, simif_detach, simif_resume, simif_wait, /* attach */ | |
430 | simif_fetch_register, simif_store_register, | |
431 | simif_prepare_to_store, | |
432 | simif_xfer_inferior_memory, | |
433 | simif_files_info, | |
cb747ec5 DE |
434 | 0, 0, /* Breakpoints */ |
435 | 0, 0, 0, 0, 0, /* Terminal handling */ | |
b562a186 DE |
436 | simif_kill, /* FIXME, kill */ |
437 | simif_load, | |
cb747ec5 | 438 | 0, /* lookup_symbol */ |
b562a186 DE |
439 | simif_create_inferior, /* create_inferior */ |
440 | simif_mourn_inferior, /* mourn_inferior FIXME */ | |
cb747ec5 DE |
441 | 0, /* can_run */ |
442 | 0, /* notice_signals */ | |
443 | process_stratum, 0, /* next */ | |
444 | 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ | |
445 | 0, 0, /* Section pointers */ | |
446 | OPS_MAGIC, /* Always the last thing */ | |
447 | }; | |
448 | ||
449 | static void | |
b562a186 | 450 | simif_snoop () |
cb747ec5 | 451 | { |
595dc9a4 DE |
452 | sim_verbose = ! sim_verbose; |
453 | if (sim_verbose) | |
cb747ec5 DE |
454 | printf_filtered ("Snoop enabled\n"); |
455 | else | |
456 | printf_filtered ("Snoop disabled\n"); | |
457 | ||
458 | } | |
459 | ||
460 | /***********************************************************************/ | |
461 | ||
462 | void | |
463 | _initialize_remote_sim () | |
464 | { | |
b562a186 DE |
465 | add_target (&simif_ops); |
466 | add_com ("snoop", class_obscure, simif_snoop, | |
cb747ec5 DE |
467 | "Show what commands are going to the simulator"); |
468 | } | |
469 | ||
470 | static void | |
471 | dump_mem (buf, len) | |
472 | char *buf; | |
473 | int len; | |
474 | { | |
475 | if (len <= 8) | |
cb747ec5 | 476 | { |
595dc9a4 DE |
477 | if (len == 8 || len == 4) |
478 | { | |
479 | long l[2]; | |
480 | memcpy (l, buf, len); | |
481 | printf_filtered ("\t0x%x", l[0]); | |
482 | printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]); | |
483 | } | |
484 | else | |
485 | { | |
486 | int i; | |
487 | printf_filtered ("\t"); | |
488 | for (i = 0; i < len; i++) | |
489 | printf_filtered ("0x%x ", buf[i]); | |
490 | printf_filtered ("\n"); | |
491 | } | |
cb747ec5 | 492 | } |
cb747ec5 | 493 | } |