]>
Commit | Line | Data |
---|---|---|
e91b87a3 | 1 | /* Machine-dependent code which would otherwise be in inflow.c and core.c, |
2 | for GDB, the GNU debugger. | |
4187119d | 3 | Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. |
e91b87a3 | 4 | |
4187119d | 5 | This file is part of GDB. |
e91b87a3 | 6 | |
4187119d | 7 | GDB 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 1, or (at your option) | |
10 | any later version. | |
e91b87a3 | 11 | |
4187119d | 12 | GDB 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 | |
18 | along with GDB; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
e91b87a3 | 20 | |
7a67dd45 | 21 | #include <stdio.h> |
e91b87a3 | 22 | #include "defs.h" |
23 | #include "param.h" | |
24 | #include "frame.h" | |
25 | #include "inferior.h" | |
26 | ||
e91b87a3 | 27 | #include <sys/param.h> |
28 | #include <sys/dir.h> | |
29 | #include <sys/user.h> | |
30 | #include <signal.h> | |
31 | #include <sys/ioctl.h> | |
32 | #include <fcntl.h> | |
33 | ||
34 | #include <sys/ptrace.h> | |
35 | #include <machine/reg.h> | |
36 | ||
37 | #include <a.out.h> | |
38 | #include <sys/file.h> | |
39 | #include <sys/stat.h> | |
40 | #include <sys/core.h> | |
41 | ||
42 | extern int errno; | |
43 | extern int attach_flag; | |
44 | \f | |
45 | /* This function simply calls ptrace with the given arguments. | |
46 | It exists so that all calls to ptrace are isolated in this | |
47 | machine-dependent file. */ | |
48 | int | |
49 | call_ptrace (request, pid, arg3, arg4) | |
50 | int request, pid, arg3, arg4; | |
51 | { | |
52 | return ptrace (request, pid, arg3, arg4); | |
53 | } | |
54 | ||
55 | kill_inferior () | |
56 | { | |
57 | if (remote_debugging) | |
58 | return; | |
59 | if (inferior_pid == 0) | |
60 | return; | |
61 | ptrace (8, inferior_pid, 0, 0); | |
62 | wait (0); | |
63 | inferior_died (); | |
64 | } | |
65 | ||
66 | /* This is used when GDB is exiting. It gives less chance of error.*/ | |
67 | ||
68 | kill_inferior_fast () | |
69 | { | |
70 | if (remote_debugging) | |
71 | return; | |
72 | if (inferior_pid == 0) | |
73 | return; | |
74 | ptrace (8, inferior_pid, 0, 0); | |
75 | wait (0); | |
76 | } | |
77 | ||
78 | /* Resume execution of the inferior process. | |
79 | If STEP is nonzero, single-step it. | |
80 | If SIGNAL is nonzero, give it that signal. */ | |
81 | ||
82 | void | |
83 | resume (step, signal) | |
84 | int step; | |
85 | int signal; | |
86 | { | |
87 | errno = 0; | |
88 | if (remote_debugging) | |
89 | remote_resume (step, signal); | |
90 | else | |
91 | { | |
92 | ptrace (step ? 9 : 7, inferior_pid, 1, signal); | |
93 | if (errno) | |
94 | perror_with_name ("ptrace"); | |
95 | } | |
96 | } | |
97 | \f | |
98 | #ifdef ATTACH_DETACH | |
99 | ||
100 | /* Start debugging the process whose number is PID. */ | |
101 | ||
102 | attach (pid) | |
103 | int pid; | |
104 | { | |
105 | errno = 0; | |
106 | ptrace (PTRACE_ATTACH, pid, 0, 0); | |
107 | if (errno) | |
108 | perror_with_name ("ptrace"); | |
109 | attach_flag = 1; | |
110 | return pid; | |
111 | } | |
112 | ||
113 | /* Stop debugging the process whose number is PID | |
114 | and continue it with signal number SIGNAL. | |
115 | SIGNAL = 0 means just continue it. */ | |
116 | ||
117 | void | |
118 | detach (signal) | |
119 | int signal; | |
120 | { | |
121 | errno = 0; | |
122 | ptrace (PTRACE_DETACH, inferior_pid, 1, signal); | |
123 | if (errno) | |
124 | perror_with_name ("ptrace"); | |
125 | attach_flag = 0; | |
126 | } | |
127 | #endif /* ATTACH_DETACH */ | |
128 | \f | |
129 | void | |
130 | fetch_inferior_registers () | |
131 | { | |
132 | struct regs inferior_registers; | |
4187119d | 133 | #ifdef FP0_REGNUM |
e91b87a3 | 134 | struct fp_status inferior_fp_registers; |
4187119d | 135 | #endif |
e91b87a3 | 136 | extern char registers[]; |
137 | ||
138 | if (remote_debugging) | |
139 | remote_fetch_registers (registers); | |
140 | else | |
141 | { | |
142 | ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); | |
4187119d | 143 | #ifdef FP0_REGNUM |
e91b87a3 | 144 | ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); |
4187119d | 145 | #endif |
e91b87a3 | 146 | |
147 | bcopy (&inferior_registers, registers, 16 * 4); | |
4187119d | 148 | #ifdef FP0_REGNUM |
e91b87a3 | 149 | bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], |
150 | sizeof inferior_fp_registers.fps_regs); | |
4187119d | 151 | #endif |
e91b87a3 | 152 | *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; |
153 | *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; | |
4187119d | 154 | #ifdef FP0_REGNUM |
e91b87a3 | 155 | bcopy (&inferior_fp_registers.fps_control, |
156 | ®isters[REGISTER_BYTE (FPC_REGNUM)], | |
157 | sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); | |
4187119d | 158 | #endif |
e91b87a3 | 159 | } |
160 | } | |
161 | ||
162 | /* Store our register values back into the inferior. | |
163 | If REGNO is -1, do this for all registers. | |
164 | Otherwise, REGNO specifies which register (so we can save time). */ | |
165 | ||
166 | store_inferior_registers (regno) | |
167 | int regno; | |
168 | { | |
169 | struct regs inferior_registers; | |
170 | struct fp_status inferior_fp_registers; | |
171 | extern char registers[]; | |
172 | ||
173 | if (remote_debugging) | |
174 | remote_store_registers (registers); | |
175 | else | |
176 | { | |
177 | bcopy (registers, &inferior_registers, 16 * 4); | |
7a67dd45 | 178 | #ifdef FP0_REGNUM |
e91b87a3 | 179 | bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, |
180 | sizeof inferior_fp_registers.fps_regs); | |
7a67dd45 | 181 | #endif |
e91b87a3 | 182 | inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; |
183 | inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; | |
7a67dd45 | 184 | |
185 | #ifdef FP0_REGNUM | |
e91b87a3 | 186 | bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], |
187 | &inferior_fp_registers.fps_control, | |
188 | sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); | |
7a67dd45 | 189 | #endif |
e91b87a3 | 190 | |
191 | ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); | |
7a67dd45 | 192 | #if FP0_REGNUM |
e91b87a3 | 193 | ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); |
7a67dd45 | 194 | #endif |
e91b87a3 | 195 | } |
196 | } | |
197 | \f | |
198 | /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory | |
199 | in the NEW_SUN_PTRACE case. | |
200 | It ought to be straightforward. But it appears that writing did | |
201 | not write the data that I specified. I cannot understand where | |
202 | it got the data that it actually did write. */ | |
203 | ||
204 | /* Copy LEN bytes from inferior's memory starting at MEMADDR | |
205 | to debugger memory starting at MYADDR. | |
206 | On failure (cannot read from inferior, usually because address is out | |
207 | of bounds) returns the value of errno. */ | |
208 | ||
209 | int | |
210 | read_inferior_memory (memaddr, myaddr, len) | |
211 | CORE_ADDR memaddr; | |
212 | char *myaddr; | |
213 | int len; | |
214 | { | |
215 | register int i; | |
216 | /* Round starting address down to longword boundary. */ | |
217 | register CORE_ADDR addr = memaddr & - sizeof (int); | |
218 | /* Round ending address up; get number of longwords that makes. */ | |
219 | register int count | |
220 | = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); | |
221 | /* Allocate buffer of that many longwords. */ | |
222 | register int *buffer = (int *) alloca (count * sizeof (int)); | |
223 | extern int errno; | |
224 | ||
225 | /* Read all the longwords */ | |
226 | for (i = 0; i < count; i++, addr += sizeof (int)) | |
227 | { | |
228 | errno = 0; | |
229 | if (remote_debugging) | |
230 | buffer[i] = remote_fetch_word (addr); | |
231 | else | |
232 | buffer[i] = ptrace (1, inferior_pid, addr, 0); | |
233 | if (errno) | |
234 | return errno; | |
235 | } | |
236 | ||
237 | /* Copy appropriate bytes out of the buffer. */ | |
238 | bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); | |
239 | return 0; | |
240 | } | |
241 | ||
242 | /* Copy LEN bytes of data from debugger memory at MYADDR | |
243 | to inferior's memory at MEMADDR. | |
244 | On failure (cannot write the inferior) | |
245 | returns the value of errno. */ | |
246 | ||
247 | int | |
248 | write_inferior_memory (memaddr, myaddr, len) | |
249 | CORE_ADDR memaddr; | |
250 | char *myaddr; | |
251 | int len; | |
252 | { | |
253 | register int i; | |
254 | /* Round starting address down to longword boundary. */ | |
255 | register CORE_ADDR addr = memaddr & - sizeof (int); | |
256 | /* Round ending address up; get number of longwords that makes. */ | |
257 | register int count | |
258 | = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); | |
259 | /* Allocate buffer of that many longwords. */ | |
260 | register int *buffer = (int *) alloca (count * sizeof (int)); | |
261 | extern int errno; | |
262 | ||
263 | /* Fill start and end extra bytes of buffer with existing memory data. */ | |
264 | ||
265 | if (remote_debugging) | |
266 | buffer[0] = remote_fetch_word (addr); | |
267 | else | |
268 | buffer[0] = ptrace (1, inferior_pid, addr, 0); | |
269 | ||
270 | if (count > 1) | |
271 | { | |
272 | if (remote_debugging) | |
273 | buffer[count - 1] | |
274 | = remote_fetch_word (addr + (count - 1) * sizeof (int)); | |
275 | else | |
276 | buffer[count - 1] | |
277 | = ptrace (1, inferior_pid, | |
278 | addr + (count - 1) * sizeof (int), 0); | |
279 | } | |
280 | ||
281 | /* Copy data to be written over corresponding part of buffer */ | |
282 | ||
283 | bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); | |
284 | ||
285 | /* Write the entire buffer. */ | |
286 | ||
287 | for (i = 0; i < count; i++, addr += sizeof (int)) | |
288 | { | |
289 | errno = 0; | |
290 | if (remote_debugging) | |
291 | remote_store_word (addr, buffer[i]); | |
292 | else | |
293 | ptrace (4, inferior_pid, addr, buffer[i]); | |
294 | if (errno) | |
295 | return errno; | |
296 | } | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
301 | \f | |
302 | /* Machine-dependent code which would otherwise be in core.c */ | |
303 | /* Work with core dump and executable files, for GDB. */ | |
304 | ||
e91b87a3 | 305 | #ifndef N_TXTADDR |
306 | #define N_TXTADDR(hdr) 0 | |
307 | #endif /* no N_TXTADDR */ | |
308 | ||
309 | #ifndef N_DATADDR | |
310 | #define N_DATADDR(hdr) hdr.a_text | |
311 | #endif /* no N_DATADDR */ | |
312 | ||
4187119d | 313 | /* Non-zero if this is an object (.o) file, rather than an executable. |
314 | Distinguishing between the two is rarely necessary (and seems like | |
315 | a hack, but there is no other way to get the text and data | |
316 | addresses--N_TXTADDR should probably take care of | |
317 | this, but it doesn't). */ | |
318 | /* This definition will not work | |
319 | if someone decides to make ld preserve relocation info. */ | |
320 | #define IS_OBJECT_FILE(hdr) (hdr.a_trsize != 0) | |
321 | ||
e91b87a3 | 322 | /* Make COFF and non-COFF names for things a little more compatible |
323 | to reduce conditionals later. */ | |
324 | ||
325 | #ifdef COFF_FORMAT | |
326 | #define a_magic magic | |
327 | #endif | |
328 | ||
329 | #ifndef COFF_FORMAT | |
4187119d | 330 | #ifndef AOUTHDR |
e91b87a3 | 331 | #define AOUTHDR struct exec |
332 | #endif | |
4187119d | 333 | #endif |
e91b87a3 | 334 | |
335 | extern char *sys_siglist[]; | |
336 | ||
337 | /* Hook for `exec_file_command' command to call. */ | |
338 | ||
339 | extern void (*exec_file_display_hook) (); | |
340 | ||
341 | /* File names of core file and executable file. */ | |
342 | ||
343 | extern char *corefile; | |
344 | extern char *execfile; | |
345 | ||
346 | /* Descriptors on which core file and executable file are open. | |
347 | Note that the execchan is closed when an inferior is created | |
348 | and reopened if the inferior dies or is killed. */ | |
349 | ||
350 | extern int corechan; | |
351 | extern int execchan; | |
352 | ||
353 | /* Last modification time of executable file. | |
354 | Also used in source.c to compare against mtime of a source file. */ | |
355 | ||
356 | extern int exec_mtime; | |
357 | ||
358 | /* Virtual addresses of bounds of the two areas of memory in the core file. */ | |
359 | ||
360 | extern CORE_ADDR data_start; | |
361 | extern CORE_ADDR data_end; | |
362 | extern CORE_ADDR stack_start; | |
363 | extern CORE_ADDR stack_end; | |
364 | ||
365 | /* Virtual addresses of bounds of two areas of memory in the exec file. | |
366 | Note that the data area in the exec file is used only when there is no core file. */ | |
367 | ||
368 | extern CORE_ADDR text_start; | |
369 | extern CORE_ADDR text_end; | |
370 | ||
371 | extern CORE_ADDR exec_data_start; | |
372 | extern CORE_ADDR exec_data_end; | |
373 | ||
374 | /* Address in executable file of start of text area data. */ | |
375 | ||
376 | extern int text_offset; | |
377 | ||
378 | /* Address in executable file of start of data area data. */ | |
379 | ||
380 | extern int exec_data_offset; | |
381 | ||
382 | /* Address in core file of start of data area data. */ | |
383 | ||
384 | extern int data_offset; | |
385 | ||
386 | /* Address in core file of start of stack area data. */ | |
387 | ||
388 | extern int stack_offset; | |
389 | ||
390 | #ifdef COFF_FORMAT | |
391 | /* various coff data structures */ | |
392 | ||
393 | extern FILHDR file_hdr; | |
394 | extern SCNHDR text_hdr; | |
395 | extern SCNHDR data_hdr; | |
396 | ||
397 | #endif /* not COFF_FORMAT */ | |
398 | ||
399 | /* a.out header saved in core file. */ | |
400 | ||
401 | extern AOUTHDR core_aouthdr; | |
402 | ||
403 | /* a.out header of exec file. */ | |
404 | ||
405 | extern AOUTHDR exec_aouthdr; | |
406 | ||
407 | extern void validate_files (); | |
408 | \f | |
409 | core_file_command (filename, from_tty) | |
410 | char *filename; | |
411 | int from_tty; | |
412 | { | |
413 | int val; | |
414 | extern char registers[]; | |
415 | ||
416 | /* Discard all vestiges of any previous core file | |
417 | and mark data and stack spaces as empty. */ | |
418 | ||
419 | if (corefile) | |
420 | free (corefile); | |
421 | corefile = 0; | |
422 | ||
423 | if (corechan >= 0) | |
424 | close (corechan); | |
425 | corechan = -1; | |
426 | ||
427 | data_start = 0; | |
428 | data_end = 0; | |
429 | stack_start = STACK_END_ADDR; | |
430 | stack_end = STACK_END_ADDR; | |
431 | ||
432 | /* Now, if a new core file was specified, open it and digest it. */ | |
433 | ||
434 | if (filename) | |
435 | { | |
4187119d | 436 | filename = tilde_expand (filename); |
437 | make_cleanup (free, filename); | |
438 | ||
e91b87a3 | 439 | if (have_inferior_p ()) |
440 | error ("To look at a core file, you must kill the inferior with \"kill\"."); | |
441 | corechan = open (filename, O_RDONLY, 0); | |
442 | if (corechan < 0) | |
443 | perror_with_name (filename); | |
444 | ||
445 | { | |
446 | struct core corestr; | |
447 | ||
448 | val = myread (corechan, &corestr, sizeof corestr); | |
449 | if (val < 0) | |
450 | perror_with_name (filename); | |
451 | if (corestr.c_magic != CORE_MAGIC) | |
452 | error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", | |
453 | filename, corestr.c_magic, (int) CORE_MAGIC); | |
454 | else if (sizeof (struct core) != corestr.c_len) | |
455 | error ("\"%s\" has an invalid struct core length (%d, expected %d)", | |
456 | filename, corestr.c_len, (int) sizeof (struct core)); | |
457 | ||
458 | data_start = exec_data_start; | |
459 | data_end = data_start + corestr.c_dsize; | |
460 | stack_start = stack_end - corestr.c_ssize; | |
461 | data_offset = sizeof corestr; | |
462 | stack_offset = sizeof corestr + corestr.c_dsize; | |
463 | ||
464 | bcopy (&corestr.c_regs, registers, 16 * 4); | |
465 | *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; | |
466 | *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; | |
4187119d | 467 | #ifdef FP0_REGNUM |
e91b87a3 | 468 | #ifdef FPU |
469 | bcopy (corestr.c_fpu.f_fpstatus.fps_regs, | |
470 | ®isters[REGISTER_BYTE (FP0_REGNUM)], | |
471 | sizeof corestr.c_fpu.f_fpstatus.fps_regs); | |
472 | bcopy (&corestr.c_fpu.f_fpstatus.fps_control, | |
473 | ®isters[REGISTER_BYTE (FPC_REGNUM)], | |
474 | sizeof corestr.c_fpu.f_fpstatus - sizeof corestr.c_fpu.f_fpstatus.fps_regs); | |
475 | #else | |
476 | bcopy (corestr.c_fpstatus.fps_regs, | |
477 | ®isters[REGISTER_BYTE (FP0_REGNUM)], | |
478 | sizeof corestr.c_fpstatus.fps_regs); | |
479 | bcopy (&corestr.c_fpstatus.fps_control, | |
480 | ®isters[REGISTER_BYTE (FPC_REGNUM)], | |
481 | sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs); | |
4187119d | 482 | #endif |
e91b87a3 | 483 | #endif |
484 | bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); | |
485 | ||
486 | printf ("Core file is from \"%s\".\n", corestr.c_cmdname); | |
487 | if (corestr.c_signo > 0) | |
488 | printf ("Program terminated with signal %d, %s.\n", | |
489 | corestr.c_signo, | |
490 | corestr.c_signo < NSIG | |
491 | ? sys_siglist[corestr.c_signo] | |
492 | : "(undocumented)"); | |
493 | } | |
494 | if (filename[0] == '/') | |
495 | corefile = savestring (filename, strlen (filename)); | |
496 | else | |
497 | { | |
498 | corefile = concat (current_directory, "/", filename); | |
499 | } | |
500 | ||
501 | set_current_frame ( create_new_frame (read_register (FP_REGNUM), | |
502 | read_pc ())); | |
503 | select_frame (get_current_frame (), 0); | |
504 | validate_files (); | |
505 | } | |
506 | else if (from_tty) | |
507 | printf ("No core file now.\n"); | |
508 | } | |
509 | \f | |
510 | exec_file_command (filename, from_tty) | |
511 | char *filename; | |
512 | int from_tty; | |
513 | { | |
514 | int val; | |
515 | ||
516 | /* Eliminate all traces of old exec file. | |
517 | Mark text segment as empty. */ | |
518 | ||
519 | if (execfile) | |
520 | free (execfile); | |
521 | execfile = 0; | |
522 | data_start = 0; | |
523 | data_end -= exec_data_start; | |
524 | text_start = 0; | |
525 | text_end = 0; | |
526 | exec_data_start = 0; | |
527 | exec_data_end = 0; | |
528 | if (execchan >= 0) | |
529 | close (execchan); | |
530 | execchan = -1; | |
531 | ||
532 | /* Now open and digest the file the user requested, if any. */ | |
533 | ||
534 | if (filename) | |
535 | { | |
4187119d | 536 | filename = tilde_expand (filename); |
537 | make_cleanup (free, filename); | |
538 | ||
e91b87a3 | 539 | execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, |
540 | &execfile); | |
541 | if (execchan < 0) | |
542 | perror_with_name (filename); | |
543 | ||
544 | #ifdef COFF_FORMAT | |
545 | { | |
546 | int aout_hdrsize; | |
547 | int num_sections; | |
548 | ||
549 | if (read_file_hdr (execchan, &file_hdr) < 0) | |
550 | error ("\"%s\": not in executable format.", execfile); | |
551 | ||
552 | aout_hdrsize = file_hdr.f_opthdr; | |
553 | num_sections = file_hdr.f_nscns; | |
554 | ||
555 | if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) | |
556 | error ("\"%s\": can't read optional aouthdr", execfile); | |
557 | ||
7a67dd45 | 558 | if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, |
559 | aout_hdrsize) < 0) | |
e91b87a3 | 560 | error ("\"%s\": can't read text section header", execfile); |
561 | ||
7a67dd45 | 562 | if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, |
563 | aout_hdrsize) < 0) | |
e91b87a3 | 564 | error ("\"%s\": can't read data section header", execfile); |
565 | ||
566 | text_start = exec_aouthdr.text_start; | |
567 | text_end = text_start + exec_aouthdr.tsize; | |
568 | text_offset = text_hdr.s_scnptr; | |
569 | exec_data_start = exec_aouthdr.data_start; | |
570 | exec_data_end = exec_data_start + exec_aouthdr.dsize; | |
571 | exec_data_offset = data_hdr.s_scnptr; | |
572 | data_start = exec_data_start; | |
573 | data_end += exec_data_start; | |
574 | exec_mtime = file_hdr.f_timdat; | |
575 | } | |
576 | #else /* not COFF_FORMAT */ | |
577 | { | |
578 | struct stat st_exec; | |
579 | val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); | |
580 | ||
581 | if (val < 0) | |
582 | perror_with_name (filename); | |
583 | ||
4187119d | 584 | text_start = |
585 | IS_OBJECT_FILE (exec_aouthdr) ? 0 : N_TXTADDR (exec_aouthdr); | |
586 | exec_data_start = IS_OBJECT_FILE (exec_aouthdr) | |
587 | ? exec_aouthdr.a_text : N_DATADDR (exec_aouthdr); | |
e91b87a3 | 588 | text_offset = N_TXTOFF (exec_aouthdr); |
589 | exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; | |
590 | ||
591 | text_end = text_start + exec_aouthdr.a_text; | |
592 | exec_data_end = exec_data_start + exec_aouthdr.a_data; | |
593 | data_start = exec_data_start; | |
594 | data_end += exec_data_start; | |
595 | ||
596 | fstat (execchan, &st_exec); | |
597 | exec_mtime = st_exec.st_mtime; | |
598 | } | |
599 | #endif /* not COFF_FORMAT */ | |
600 | ||
601 | validate_files (); | |
602 | } | |
603 | else if (from_tty) | |
604 | printf ("No exec file now.\n"); | |
605 | ||
606 | /* Tell display code (if any) about the changed file name. */ | |
607 | if (exec_file_display_hook) | |
608 | (*exec_file_display_hook) (filename); | |
609 | } | |
610 |