gdb-2.8.1
[binutils-gdb.git] / gdb / core.c
1 /* Work with core dump and executable files, for GDB.
2 Copyright (C) 1986, 1987 Free Software Foundation, Inc.
3
4 GDB is distributed in the hope that it will be useful, but WITHOUT ANY
5 WARRANTY. No author or distributor accepts responsibility to anyone
6 for the consequences of using it or for whether it serves any
7 particular purpose or works at all, unless he says so in writing.
8 Refer to the GDB General Public License for full details.
9
10 Everyone is granted permission to copy, modify and redistribute GDB,
11 but only under the conditions described in the GDB General Public
12 License. A copy of this license is supposed to have been given to you
13 along with GDB so you can know your rights and responsibilities. It
14 should be in a file named COPYING. Among other things, the copyright
15 notice and this notice must be preserved on all copies.
16
17 In other words, go ahead and share GDB, but don't try to stop
18 anyone else from sharing it farther. Help stamp out software hoarding!
19 */
20
21 #include "initialize.h"
22 #include "defs.h"
23 #include "param.h"
24
25 #include <a.out.h>
26 #include <stdio.h>
27 #include <signal.h>
28 #include <sys/param.h>
29 #include <sys/dir.h>
30 #include <sys/file.h>
31 #include <sys/stat.h>
32
33 /* Recognize COFF format systems because a.out.h defines AOUTHDR. */
34 #ifdef AOUTHDR
35 #define COFF_FORMAT
36 #endif
37
38 #ifdef NEW_SUN_CORE
39 #include <sys/core.h>
40 #else /* not NEW_SUN_CORE */
41 #ifdef UMAX_CORE
42 #include <sys/ptrace.h>
43 #else /* not UMAX_CORE */
44 #include <sys/user.h>
45 #ifdef HP9K320
46 #include <sys/reg.h>
47 #include <sys/trap.h>
48 #ifdef HPUX_VERSION_5
49 #define e_PS e_regs[PS]
50 #define e_PC e_regs[PC]
51 #endif /* HPUX_VERSION_5 */
52 #endif /* HP9K320 */
53 #endif /* not UMAX_CORE */
54 #endif /* not NEW_SUN_CORE */
55
56 #ifndef N_TXTADDR
57 #define N_TXTADDR(hdr) 0
58 #endif /* no N_TXTADDR */
59
60 #ifndef N_DATADDR
61 #define N_DATADDR(hdr) hdr.a_text
62 #endif /* no N_DATADDR */
63
64 /* Make COFF and non-COFF names for things a little more compatible
65 to reduce conditionals later. */
66
67 #ifdef COFF_FORMAT
68 #define a_magic magic
69 #endif
70
71 #ifndef COFF_FORMAT
72 #define AOUTHDR struct exec
73 #endif
74
75 extern char *sys_siglist[];
76
77 START_FILE
78
79 /* Hook for `exec_file_command' command to call. */
80
81 void (*exec_file_display_hook) ();
82
83 /* File names of core file and executable file. */
84
85 static char *corefile;
86 static char *execfile;
87
88 /* Descriptors on which core file and executable file are open.
89 Note that the execchan is closed when an inferior is created
90 and reopened if the inferior dies or is killed. */
91
92 static int corechan;
93 static int execchan;
94
95 /* Last modification time of executable file.
96 Also used in source.c to compare against mtime of a source file. */
97
98 int exec_mtime;
99
100 /* Virtual addresses of bounds of the two areas of memory in the core file. */
101
102 static CORE_ADDR data_start;
103 static CORE_ADDR data_end;
104 static CORE_ADDR stack_start;
105 static CORE_ADDR stack_end;
106
107 /* Virtual addresses of bounds of two areas of memory in the exec file.
108 Note that the data area in the exec file is used only when there is no core file. */
109
110 CORE_ADDR text_start;
111 CORE_ADDR text_end;
112
113 static CORE_ADDR exec_data_start;
114 static CORE_ADDR exec_data_end;
115
116 /* Address in executable file of start of text area data. */
117
118 static int text_offset;
119
120 /* Address in executable file of start of data area data. */
121
122 static int exec_data_offset;
123
124 /* Address in core file of start of data area data. */
125
126 static int data_offset;
127
128 /* Address in core file of start of stack area data. */
129
130 static int stack_offset;
131
132 #ifdef COFF_FORMAT
133 /* various coff data structures */
134
135 static FILHDR file_hdr;
136 static SCNHDR text_hdr;
137 static SCNHDR data_hdr;
138
139 #endif /* not COFF_FORMAT */
140
141 /* a.out header saved in core file. */
142
143 static AOUTHDR core_aouthdr;
144
145 /* a.out header of exec file. */
146
147 static AOUTHDR exec_aouthdr;
148
149 static void validate_files ();
150 unsigned int register_addr ();
151 \f
152 core_file_command (filename, from_tty)
153 char *filename;
154 int from_tty;
155 {
156 int val;
157 extern char registers[];
158
159 /* Discard all vestiges of any previous core file
160 and mark data and stack spaces as empty. */
161
162 if (corefile)
163 free (corefile);
164 corefile = 0;
165
166 if (corechan >= 0)
167 close (corechan);
168 corechan = -1;
169
170 data_start = 0;
171 data_end = 0;
172 stack_start = STACK_END_ADDR;
173 stack_end = STACK_END_ADDR;
174
175 /* Now, if a new core file was specified, open it and digest it. */
176
177 if (filename)
178 {
179 if (have_inferior_p ())
180 error ("To look at a core file, you must kill the inferior with \"kill\".");
181 corechan = open (filename, O_RDONLY, 0);
182 if (corechan < 0)
183 perror_with_name (filename);
184 #ifdef NEW_SUN_CORE
185 {
186 struct core corestr;
187
188 val = myread (corechan, &corestr, sizeof corestr);
189 if (val < 0)
190 perror_with_name (filename);
191 if (corestr.c_magic != CORE_MAGIC)
192 error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)",
193 filename, corestr.c_magic, (int) CORE_MAGIC);
194 else if (sizeof (struct core) != corestr.c_len)
195 error ("\"%s\" has an invalid struct core length (%d, expected %d)",
196 filename, corestr.c_len, (int) sizeof (struct core));
197
198 data_start = exec_data_start;
199 data_end = data_start + corestr.c_dsize;
200 stack_start = stack_end - corestr.c_ssize;
201 data_offset = sizeof corestr;
202 stack_offset = sizeof corestr + corestr.c_dsize;
203
204 #if defined(sun2) || defined(sun3)
205 bcopy (&corestr.c_regs, registers, 16 * 4);
206 *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
207 *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
208 bcopy (corestr.c_fpstatus.fps_regs,
209 &registers[REGISTER_BYTE (FP0_REGNUM)],
210 sizeof corestr.c_fpstatus.fps_regs);
211 bcopy (&corestr.c_fpstatus.fps_control,
212 &registers[REGISTER_BYTE (FPC_REGNUM)],
213 sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs);
214 #endif
215 #if defined(sun4)
216 /* G0 *always* holds 0. */
217 *(int *)&registers[REGISTER_BYTE (0)] = 0;
218 /* The globals and output registers. I don't know where
219 to get the locals and input registers from the core file. */
220 bcopy (&corestr.c_regs.r_g1, registers, 15 * 4);
221 *(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
222 *(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
223 *(int *)&registers[REGISTER_BYTE (NPC_REGNUM)] = corestr.c_regs.r_npc;
224 *(int *)&registers[REGISTER_BYTE (Y_REGNUM)] = corestr.c_regs.r_y;
225 bcopy (corestr.c_fpu.fpu_regs,
226 &registers[REGISTER_BYTE (FP0_REGNUM)],
227 sizeof corestr.c_fpu.fpu_regs);
228 #ifdef FPU
229 bcopy (&corestr.c_fpu.fpu_fsr,
230 &registers[REGISTER_BYTE (FPS_REGNUM)],
231 sizeof (FPU_FSR_TYPE));
232 #endif
233 #endif
234
235 bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec));
236
237 printf ("Core file is from \"%s\".\n", corestr.c_cmdname);
238 if (corestr.c_signo > 0)
239 printf ("Program terminated with signal %d, %s.\n",
240 corestr.c_signo,
241 corestr.c_signo < NSIG
242 ? sys_siglist[corestr.c_signo]
243 : "(undocumented)");
244 }
245 #else /* not NEW_SUN_CORE */
246 /* 4.2-style (and perhaps also sysV-style) core dump file. */
247 {
248 #ifdef UMAX_CORE
249 struct ptrace_user u;
250 #else
251 struct user u;
252 #endif
253 int reg_offset;
254
255 val = myread (corechan, &u, sizeof u);
256 if (val < 0)
257 perror_with_name (filename);
258 data_start = exec_data_start;
259
260 #ifdef UMAX_CORE
261 data_end = data_start + u.pt_dsize;
262 stack_start = stack_end - u.pt_ssize;
263 data_offset = sizeof u;
264 stack_offset = data_offset + u.pt_dsize;
265 reg_offset = 0;
266
267 bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR));
268 printf ("Core file is from \"%s\".\n", u.pt_comm);
269 if (u.pt_signal > 0)
270 printf ("Program terminated with signal %d, %s.\n",
271 u.pt_signal,
272 u.pt_signal < NSIG
273 ? sys_siglist[u.pt_signal]
274 : "(undocumented)");
275 #else /* not UMAX_CORE */
276 data_end = data_start + NBPG * u.u_dsize;
277 stack_start = stack_end - NBPG * u.u_ssize;
278 data_offset = NBPG * UPAGES;
279 stack_offset = NBPG * (UPAGES + u.u_dsize);
280 reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
281
282 /* I don't know where to find this info.
283 So, for now, mark it as not available. */
284 core_aouthdr.a_magic = 0;
285 #endif /* not UMAX_CORE */
286
287 /* Read the register values out of the core file and store
288 them where `read_register' will find them. */
289
290 #ifdef HP9K320
291 {
292 register int regno;
293 struct exception_stack es;
294 int val;
295
296 val = lseek (corechan, (REGISTER_ADDR (reg_offset, 0)), 0);
297 if (val < 0)
298 perror_with_name (filename);
299 val = myread (corechan, es,
300 ((char *) &es.e_regs[R0] - (char *) &es.e_offset));
301 if (val < 0)
302 perror_with_name (filename);
303 for (regno = 0; (regno < PS_REGNUM); regno++)
304 supply_register (regno, &es.e_regs[regno + R0]);
305 val = es.e_PS;
306 supply_register (regno++, &val);
307 supply_register (regno++, &es.e_PC);
308 for (; (regno < NUM_REGS); regno++)
309 {
310 char buf[MAX_REGISTER_RAW_SIZE];
311
312 val = lseek (corechan, (FP_REGISTER_ADDR (u, regno)), 0);
313 if (val < 0)
314 perror_with_name (filename);
315
316 val = myread (corechan, buf, sizeof buf);
317 if (val < 0)
318 perror_with_name (filename);
319 supply_register (regno, buf);
320 }
321 }
322 #else /* not HP9K320 */
323 {
324 register int regno;
325
326 for (regno = 0; regno < NUM_REGS; regno++)
327 {
328 char buf[MAX_REGISTER_RAW_SIZE];
329
330 val = lseek (corechan, register_addr (regno, reg_offset), 0);
331 if (val < 0)
332 perror_with_name (filename);
333
334 val = myread (corechan, buf, sizeof buf);
335 if (val < 0)
336 perror_with_name (filename);
337 supply_register (regno, buf);
338 }
339 }
340 #endif /* not HP9K320 */
341 }
342 #endif /* not NEW_SUN_CORE */
343 if (filename[0] == '/')
344 corefile = savestring (filename, strlen (filename));
345 else
346 {
347 corefile = concat (current_directory, "/", filename);
348 }
349
350 set_current_frame (read_register (FP_REGNUM));
351 select_frame (get_current_frame (), 0);
352 validate_files ();
353 }
354 else if (from_tty)
355 printf ("No core file now.\n");
356 }
357 \f
358 exec_file_command (filename, from_tty)
359 char *filename;
360 int from_tty;
361 {
362 int val;
363
364 /* Eliminate all traces of old exec file.
365 Mark text segment as empty. */
366
367 if (execfile)
368 free (execfile);
369 execfile = 0;
370 data_start = 0;
371 data_end -= exec_data_start;
372 text_start = 0;
373 text_end = 0;
374 exec_data_start = 0;
375 exec_data_end = 0;
376 if (execchan >= 0)
377 close (execchan);
378 execchan = -1;
379
380 /* Now open and digest the file the user requested, if any. */
381
382 if (filename)
383 {
384 execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
385 &execfile);
386 if (execchan < 0)
387 perror_with_name (filename);
388
389 #ifdef COFF_FORMAT
390 {
391 int aout_hdrsize;
392 int num_sections;
393
394 if (read_file_hdr (execchan, &file_hdr) < 0)
395 error ("\"%s\": not in executable format.", execfile);
396
397 aout_hdrsize = file_hdr.f_opthdr;
398 num_sections = file_hdr.f_nscns;
399
400 if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
401 error ("\"%s\": can't read optional aouthdr", execfile);
402
403 if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
404 error ("\"%s\": can't read text section header", execfile);
405
406 if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
407 error ("\"%s\": can't read data section header", execfile);
408
409 text_start = exec_aouthdr.text_start;
410 text_end = text_start + exec_aouthdr.tsize;
411 text_offset = text_hdr.s_scnptr;
412 exec_data_start = exec_aouthdr.data_start;
413 exec_data_end = exec_data_start + exec_aouthdr.dsize;
414 exec_data_offset = data_hdr.s_scnptr;
415 data_start = exec_data_start;
416 data_end += exec_data_start;
417 exec_mtime = file_hdr.f_timdat;
418 }
419 #else /* not COFF_FORMAT */
420 {
421 struct stat st_exec;
422
423 #ifdef gould
424 FILHDR exec_coffhdr;
425
426 val = myread (execchan, &exec_coffhdr, sizeof exec_coffhdr);
427 if (val < 0)
428 perror_with_name (filename);
429 #endif
430 val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
431
432 if (val < 0)
433 perror_with_name (filename);
434
435 text_start = N_TXTADDR (exec_aouthdr);
436 exec_data_start = N_DATADDR (exec_aouthdr);
437 #ifdef gould
438 text_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr);
439 exec_data_offset = N_TXTOFF (exec_coffhdr, exec_aouthdr)
440 + exec_aouthdr.a_text;
441 #else
442 text_offset = N_TXTOFF (exec_aouthdr);
443 exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
444 #endif
445 text_end = text_start + exec_aouthdr.a_text;
446 exec_data_end = exec_data_start + exec_aouthdr.a_data;
447 data_start = exec_data_start;
448 data_end += exec_data_start;
449
450 fstat (execchan, &st_exec);
451 exec_mtime = st_exec.st_mtime;
452 }
453 #endif /* not COFF_FORMAT */
454
455 validate_files ();
456 }
457 else if (from_tty)
458 printf ("No exec file now.\n");
459
460 /* Tell display code (if any) about the changed file name. */
461 if (exec_file_display_hook)
462 (*exec_file_display_hook) (filename);
463 }
464
465 /* Call this to specify the hook for exec_file_command to call back.
466 This is called from the x-window display code. */
467
468 specify_exec_file_hook (hook)
469 void (*hook) ();
470 {
471 exec_file_display_hook = hook;
472 }
473
474 /* The exec file must be closed before running an inferior.
475 If it is needed again after the inferior dies, it must
476 be reopened. */
477
478 close_exec_file ()
479 {
480 if (execchan >= 0)
481 close (execchan);
482 execchan = -1;
483 }
484
485 reopen_exec_file ()
486 {
487 if (execchan < 0 && execfile != 0)
488 {
489 char *filename = concat (execfile, "", "");
490 exec_file_command (filename, 0);
491 free (filename);
492 }
493 }
494 \f
495 /* If we have both a core file and an exec file,
496 print a warning if they don't go together.
497 This should really check that the core file came
498 from that exec file, but I don't know how to do it. */
499
500 static void
501 validate_files ()
502 {
503 if (execfile != 0 && corefile != 0)
504 {
505 struct stat st_core;
506
507 fstat (corechan, &st_core);
508
509 if (core_aouthdr.a_magic != 0
510 && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr))
511 printf ("Warning: core file does not match specified executable file.\n");
512 else if (exec_mtime > st_core.st_mtime)
513 printf ("Warning: exec file is newer than core file.\n");
514 }
515 }
516
517 /* Return the name of the executable file as a string.
518 ERR nonzero means get error if there is none specified;
519 otherwise return 0 in that case. */
520
521 char *
522 get_exec_file (err)
523 int err;
524 {
525 if (err && execfile == 0)
526 error ("No executable file specified.\n\
527 Use the \"exec-file\" and \"symbol-file\" commands.");
528 return execfile;
529 }
530
531 int
532 have_core_file_p ()
533 {
534 return corefile != 0;
535 }
536
537 static void
538 files_info ()
539 {
540 char *symfile;
541 extern char *get_sym_file ();
542
543 if (execfile)
544 printf ("Executable file \"%s\".\n", execfile);
545 else
546 printf ("No executable file\n");
547 if (corefile == 0)
548 printf ("No core dump file\n");
549 else
550 printf ("Core dump file \"%s\".\n", corefile);
551
552 if (have_inferior_p ())
553 printf ("Using the running image of the program, rather than these files.\n");
554
555 symfile = get_sym_file ();
556 if (symfile != 0)
557 printf ("Symbols loaded from \"%s\".\n", symfile);
558
559 if (! have_inferior_p ())
560 {
561 if (execfile)
562 {
563 printf ("Text segment from 0x%x to 0x%x.\n",
564 text_start, text_end);
565 }
566 if (corefile)
567 {
568 printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n",
569 data_start, data_end, stack_start, stack_end);
570 }
571 else
572 {
573 printf ("Data segment in executable from 0x%x to 0x%x.\n",
574 exec_data_start, exec_data_end);
575 }
576 }
577 }
578 \f
579 /* Read "memory data" from core file and/or executable file */
580
581 read_memory (memaddr, myaddr, len)
582 CORE_ADDR memaddr;
583 char *myaddr;
584 int len;
585 {
586 if (have_inferior_p ())
587 read_inferior_memory (memaddr, myaddr, len);
588 else
589 xfer_core_file (memaddr, myaddr, len, 0);
590 }
591
592 /* Write LEN bytes of data starting at address MYADDR
593 into debugged program memory at address MEMADDR.
594 Returns zero if successful, or an errno value if ptrace failed. */
595
596 int
597 write_memory (memaddr, myaddr, len)
598 CORE_ADDR memaddr;
599 char *myaddr;
600 int len;
601 {
602 if (have_inferior_p ())
603 return write_inferior_memory (memaddr, myaddr, len);
604 else
605 error ("Can write memory only when program being debugged is running.");
606 }
607
608 xfer_core_file (memaddr, myaddr, len)
609 CORE_ADDR memaddr;
610 char *myaddr;
611 int len;
612 {
613 register int i;
614 register int val;
615 int xferchan;
616 char **xferfile;
617 int fileptr;
618
619 while (len > 0)
620 {
621 xferfile = 0;
622 xferchan = 0;
623
624 /* Determine which file the next bunch of addresses reside in,
625 and where in the file. Set the file's read/write pointer
626 to point at the proper place for the desired address
627 and set xferfile and xferchan for the correct file.
628 If desired address is nonexistent, leave them zero.
629 i is set to the number of bytes that can be handled
630 along with the next address. */
631
632 if (memaddr < text_start)
633 {
634 i = min (len, text_start - memaddr);
635 }
636 else if (memaddr >= text_end && memaddr < data_start)
637 {
638 i = min (len, data_start - memaddr);
639 }
640 else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end)
641 && memaddr < stack_start)
642 {
643 i = min (len, stack_start - memaddr);
644 }
645 else if (memaddr >= stack_end && stack_end != 0)
646 {
647 i = min (len, - memaddr);
648 }
649 /* Note that if there is no core file
650 data_start and data_end are equal. */
651 else if (memaddr >= data_start && memaddr < data_end)
652 {
653 i = min (len, data_end - memaddr);
654 fileptr = memaddr - data_start + data_offset;
655 xferfile = &corefile;
656 xferchan = corechan;
657 }
658 /* Note that if there is no core file
659 stack_start and stack_end are equal. */
660 else if (memaddr >= stack_start && memaddr < stack_end)
661 {
662 i = min (len, stack_end - memaddr);
663 fileptr = memaddr - stack_start + stack_offset;
664 xferfile = &corefile;
665 xferchan = corechan;
666 }
667 else if (corechan < 0
668 && memaddr >= exec_data_start && memaddr < exec_data_end)
669 {
670 i = min (len, exec_data_end - memaddr);
671 fileptr = memaddr - exec_data_start + exec_data_offset;
672 xferfile = &execfile;
673 xferchan = execchan;
674 }
675 else if (memaddr >= text_start && memaddr < text_end)
676 {
677 i = min (len, text_end - memaddr);
678 fileptr = memaddr - text_start + text_offset;
679 xferfile = &execfile;
680 xferchan = execchan;
681 }
682
683 /* Now we know which file to use.
684 Set up its pointer and transfer the data. */
685 if (xferfile)
686 {
687 if (*xferfile == 0)
688 if (xferfile == &execfile)
689 error ("No program file to examine.");
690 else
691 error ("No core dump file or running program to examine.");
692 val = lseek (xferchan, fileptr, 0);
693 if (val < 0)
694 perror_with_name (*xferfile);
695 val = myread (xferchan, myaddr, i);
696 if (val < 0)
697 perror_with_name (*xferfile);
698 }
699 /* If this address is for nonexistent memory,
700 read zeros if reading, or do nothing if writing. */
701 else
702 bzero (myaddr, i);
703
704 memaddr += i;
705 myaddr += i;
706 len -= i;
707 }
708 }
709 \f
710 /* My replacement for the read system call.
711 Used like `read' but keeps going if `read' returns too soon. */
712
713 myread (desc, addr, len)
714 int desc;
715 char *addr;
716 int len;
717 {
718 register int val;
719 int orglen = len;
720
721 while (len > 0)
722 {
723 val = read (desc, addr, len);
724 if (val < 0)
725 return val;
726 if (val == 0)
727 return orglen - len;
728 len -= val;
729 addr += val;
730 }
731 return orglen;
732 }
733 \f
734 #ifdef REGISTER_U_ADDR
735
736 /* Return the address in the core dump or inferior of register REGNO.
737 BLOCKEND is the address of the end of the user structure. */
738
739 unsigned int
740 register_addr (regno, blockend)
741 int regno;
742 int blockend;
743 {
744 int addr;
745
746 if (regno < 0 || regno >= NUM_REGS)
747 error ("Invalid register number %d.", regno);
748
749 REGISTER_U_ADDR (addr, blockend, regno);
750
751 return addr;
752 }
753
754 #endif /* REGISTER_U_ADDR */
755 \f
756 static
757 initialize ()
758 {
759 corechan = -1;
760 execchan = -1;
761 corefile = 0;
762 execfile = 0;
763 exec_file_display_hook = 0;
764
765 text_start = 0;
766 text_end = 0;
767 data_start = 0;
768 data_end = 0;
769 exec_data_start = 0;
770 exec_data_end = 0;
771 stack_start = STACK_END_ADDR;
772 stack_end = STACK_END_ADDR;
773
774 add_com ("core-file", class_files, core_file_command,
775 "Use FILE as core dump for examining memory and registers.\n\
776 No arg means have no core file.");
777 add_com ("exec-file", class_files, exec_file_command,
778 "Use FILE as program for getting contents of pure memory.\n\
779 If FILE cannot be found as specified, your execution directory path\n\
780 is searched for a command of that name.\n\
781 No arg means have no executable file.");
782 add_info ("files", files_info, "Names of files being debugged.");
783 }
784
785 END_FILE