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); | |
b562a186 DE |
231 | if (sim_set_args (argv, env) != 0) |
232 | return; | |
cb747ec5 DE |
233 | |
234 | inferior_pid = 42; | |
235 | insert_breakpoints (); /* Needed to get correct instruction in cache */ | |
236 | proceed (entry_pt, -1, 0); | |
237 | } | |
238 | ||
b562a186 DE |
239 | /* The open routine takes the rest of the parameters from the command, |
240 | and (if successful) pushes a new target onto the stack. | |
241 | Targets should supply this routine, if only to provide an error message. */ | |
595dc9a4 | 242 | /* Called when selecting the simulator. EG: (gdb) target sim name. */ |
cb747ec5 DE |
243 | |
244 | static void | |
b562a186 | 245 | simif_open (args, from_tty) |
595dc9a4 | 246 | char *args; |
cb747ec5 DE |
247 | int from_tty; |
248 | { | |
595dc9a4 | 249 | if (sim_verbose) |
b562a186 | 250 | printf_filtered ("simif_open: args \"%s\"\n", args); |
cb747ec5 | 251 | |
b562a186 | 252 | if (sim_open (args) != 0) |
cb747ec5 DE |
253 | { |
254 | error ("Unable to initialize simulator (insufficient memory?)."); | |
255 | return; | |
256 | } | |
257 | ||
b562a186 | 258 | push_target (&simif_ops); |
cb747ec5 DE |
259 | target_fetch_registers (-1); |
260 | ||
b562a186 | 261 | /* FIXME: check from_tty here? */ |
cb747ec5 DE |
262 | printf_filtered ("Connected to the simulator.\n"); |
263 | } | |
264 | ||
b562a186 DE |
265 | /* Does whatever cleanup is required for a target that we are no longer |
266 | going to be calling. Argument says whether we are quitting gdb and | |
267 | should not get hung in case of errors, or whether we want a clean | |
268 | termination even if it takes a while. This routine is automatically | |
269 | always called just before a routine is popped off the target stack. | |
270 | Closing file descriptors and freeing memory are typical things it should | |
271 | do. */ | |
cb747ec5 DE |
272 | /* Close out all files and local state before this target loses control. */ |
273 | ||
274 | static void | |
b562a186 | 275 | simif_close (quitting) |
cb747ec5 DE |
276 | int quitting; |
277 | { | |
595dc9a4 | 278 | if (sim_verbose) |
b562a186 | 279 | printf_filtered ("simif_close: quitting %d\n", quitting); |
cb747ec5 DE |
280 | |
281 | program_loaded = 0; | |
282 | ||
b562a186 | 283 | /* FIXME: Need to call sim_close() to close all files and |
cb747ec5 DE |
284 | delete all mappings. */ |
285 | } | |
286 | ||
b562a186 DE |
287 | /* Takes a program previously attached to and detaches it. |
288 | The program may resume execution (some targets do, some don't) and will | |
289 | no longer stop on signals, etc. We better not have left any breakpoints | |
290 | in the program or it'll die when it hits one. ARGS is arguments | |
291 | typed by the user (e.g. a signal to send the process). FROM_TTY | |
292 | says whether to be verbose or not. */ | |
cb747ec5 | 293 | /* Terminate the open connection to the remote debugger. |
b562a186 | 294 | Use this when you want to detach and do something else with your gdb. */ |
cb747ec5 DE |
295 | |
296 | static void | |
b562a186 | 297 | simif_detach (args,from_tty) |
cb747ec5 DE |
298 | char *args; |
299 | int from_tty; | |
300 | { | |
595dc9a4 | 301 | if (sim_verbose) |
b562a186 | 302 | printf_filtered ("simif_detach: args \"%s\"\n", args); |
cb747ec5 | 303 | |
b562a186 | 304 | pop_target (); /* calls simif_close to do the real work */ |
cb747ec5 DE |
305 | if (from_tty) |
306 | printf_filtered ("Ending simulator %s debugging\n", target_shortname); | |
307 | } | |
308 | ||
b562a186 DE |
309 | /* Resume execution of the target process. STEP says whether to single-step |
310 | or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given | |
311 | to the target, or zero for no signal. */ | |
cb747ec5 DE |
312 | |
313 | static void | |
25286543 SG |
314 | simif_resume (pid, step, siggnal) |
315 | int pid, step, siggnal; | |
cb747ec5 | 316 | { |
595dc9a4 | 317 | if (sim_verbose) |
b562a186 | 318 | printf_filtered ("simif_resume: step %d, signal %d\n", step, siggnal); |
cb747ec5 | 319 | |
b562a186 | 320 | sim_resume (step, siggnal); |
cb747ec5 DE |
321 | } |
322 | ||
b562a186 DE |
323 | /* Wait for inferior process to do something. Return pid of child, |
324 | or -1 in case of error; store status through argument pointer STATUS, | |
325 | just as `wait' would. */ | |
cb747ec5 DE |
326 | |
327 | static int | |
b562a186 | 328 | simif_wait (status) |
cb747ec5 DE |
329 | WAITTYPE *status; |
330 | { | |
595dc9a4 | 331 | if (sim_verbose) |
b562a186 | 332 | printf_filtered ("simif_wait: "); |
cb747ec5 | 333 | #if 1 |
b562a186 | 334 | *status = sim_stop_signal (); |
cb747ec5 | 335 | #else |
b562a186 | 336 | WSETSTOP (*status, sim_stop_signal ()); |
cb747ec5 | 337 | #endif |
595dc9a4 | 338 | if (sim_verbose) |
cb747ec5 DE |
339 | printf_filtered ("status %d\n", *status); |
340 | return 0; | |
341 | } | |
342 | ||
343 | /* Get ready to modify the registers array. On machines which store | |
344 | individual registers, this doesn't need to do anything. On machines | |
345 | which store all the registers in one fell swoop, this makes sure | |
346 | that registers contains all the registers from the program being | |
347 | debugged. */ | |
348 | ||
349 | static void | |
b562a186 | 350 | simif_prepare_to_store () |
cb747ec5 DE |
351 | { |
352 | /* Do nothing, since we can store individual regs */ | |
353 | } | |
354 | ||
355 | static int | |
b562a186 | 356 | simif_xfer_inferior_memory (memaddr, myaddr, len, write, target) |
cb747ec5 DE |
357 | CORE_ADDR memaddr; |
358 | char *myaddr; | |
359 | int len; | |
360 | int write; | |
361 | struct target_ops *target; /* ignored */ | |
362 | { | |
b562a186 DE |
363 | if (! program_loaded) |
364 | error ("No program loaded."); | |
365 | ||
595dc9a4 DE |
366 | if (sim_verbose) |
367 | { | |
b562a186 | 368 | printf_filtered ("simif_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n", |
595dc9a4 DE |
369 | myaddr, memaddr, len, write); |
370 | if (sim_verbose && write) | |
371 | dump_mem(myaddr, len); | |
372 | } | |
cb747ec5 | 373 | |
cb747ec5 | 374 | if (write) |
595dc9a4 | 375 | { |
b562a186 | 376 | len = sim_write (memaddr, myaddr, len); |
595dc9a4 | 377 | } |
cb747ec5 | 378 | else |
595dc9a4 | 379 | { |
b562a186 DE |
380 | len = sim_read (memaddr, myaddr, len); |
381 | if (sim_verbose && len > 0) | |
595dc9a4 DE |
382 | dump_mem(myaddr, len); |
383 | } | |
cb747ec5 DE |
384 | return len; |
385 | } | |
386 | ||
387 | static void | |
b562a186 DE |
388 | simif_files_info (target) |
389 | struct target_ops *target; | |
cb747ec5 DE |
390 | { |
391 | char *file = "nothing"; | |
392 | ||
393 | if (exec_bfd) | |
394 | file = bfd_get_filename (exec_bfd); | |
395 | ||
595dc9a4 | 396 | if (sim_verbose) |
b562a186 | 397 | printf_filtered ("simif_files_info: file \"%s\"\n", file); |
cb747ec5 DE |
398 | |
399 | if (exec_bfd) | |
b562a186 DE |
400 | { |
401 | printf_filtered ("\tAttached to %s running program %s\n", | |
402 | target_shortname, file); | |
403 | sim_info (); | |
404 | } | |
cb747ec5 DE |
405 | } |
406 | ||
b562a186 DE |
407 | /* Clear the sims notion of what the break points are. */ |
408 | ||
cb747ec5 | 409 | static void |
b562a186 | 410 | simif_mourn_inferior () |
cb747ec5 | 411 | { |
595dc9a4 | 412 | if (sim_verbose) |
b562a186 | 413 | printf_filtered ("simif_mourn_inferior:\n"); |
cb747ec5 DE |
414 | |
415 | remove_breakpoints (); | |
416 | generic_mourn_inferior (); | |
417 | } | |
418 | ||
419 | /* Define the target subroutine names */ | |
420 | ||
b562a186 | 421 | struct target_ops simif_ops = |
cb747ec5 | 422 | { |
b562a186 DE |
423 | "sim", "simulator", |
424 | "Use the simulator", | |
425 | simif_open, simif_close, | |
426 | 0, simif_detach, simif_resume, simif_wait, /* attach */ | |
427 | simif_fetch_register, simif_store_register, | |
428 | simif_prepare_to_store, | |
429 | simif_xfer_inferior_memory, | |
430 | simif_files_info, | |
cb747ec5 DE |
431 | 0, 0, /* Breakpoints */ |
432 | 0, 0, 0, 0, 0, /* Terminal handling */ | |
b562a186 DE |
433 | simif_kill, /* FIXME, kill */ |
434 | simif_load, | |
cb747ec5 | 435 | 0, /* lookup_symbol */ |
b562a186 DE |
436 | simif_create_inferior, /* create_inferior */ |
437 | simif_mourn_inferior, /* mourn_inferior FIXME */ | |
cb747ec5 DE |
438 | 0, /* can_run */ |
439 | 0, /* notice_signals */ | |
440 | process_stratum, 0, /* next */ | |
441 | 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ | |
442 | 0, 0, /* Section pointers */ | |
443 | OPS_MAGIC, /* Always the last thing */ | |
444 | }; | |
445 | ||
446 | static void | |
b562a186 | 447 | simif_snoop () |
cb747ec5 | 448 | { |
595dc9a4 DE |
449 | sim_verbose = ! sim_verbose; |
450 | if (sim_verbose) | |
cb747ec5 DE |
451 | printf_filtered ("Snoop enabled\n"); |
452 | else | |
453 | printf_filtered ("Snoop disabled\n"); | |
454 | ||
455 | } | |
456 | ||
457 | /***********************************************************************/ | |
458 | ||
459 | void | |
460 | _initialize_remote_sim () | |
461 | { | |
b562a186 DE |
462 | add_target (&simif_ops); |
463 | add_com ("snoop", class_obscure, simif_snoop, | |
cb747ec5 DE |
464 | "Show what commands are going to the simulator"); |
465 | } | |
466 | ||
467 | static void | |
468 | dump_mem (buf, len) | |
469 | char *buf; | |
470 | int len; | |
471 | { | |
472 | if (len <= 8) | |
cb747ec5 | 473 | { |
595dc9a4 DE |
474 | if (len == 8 || len == 4) |
475 | { | |
476 | long l[2]; | |
477 | memcpy (l, buf, len); | |
478 | printf_filtered ("\t0x%x", l[0]); | |
479 | printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]); | |
480 | } | |
481 | else | |
482 | { | |
483 | int i; | |
484 | printf_filtered ("\t"); | |
485 | for (i = 0; i < len; i++) | |
486 | printf_filtered ("0x%x ", buf[i]); | |
487 | printf_filtered ("\n"); | |
488 | } | |
cb747ec5 | 489 | } |
cb747ec5 | 490 | } |