1 /* Copyright (C) 1988, 1989 Free Software Foundation, Inc.
3 This file is part of GDB.
5 GDB is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 1, or (at your option)
10 GDB is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GDB; see the file COPYING. If not, write to
17 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "arm-opcode.h"
26 #include <sys/param.h>
29 #include <sys/ioctl.h>
30 #include <sys/ptrace.h>
31 #include <machine/reg.h>
33 #define N_TXTADDR(hdr) 0x8000
34 #define N_DATADDR(hdr) (hdr.a_text + 0x8000)
37 #include <sys/user.h> /* After a.out.h */
44 /* Work with core dump and executable files, for GDB.
45 This code would be in core.c if it weren't machine-dependent. */
47 /* Structure to describe the chain of shared libraries used
49 e.g. prog shares Xt which shares X11 which shares c. */
51 struct shared_library
{
52 struct exec_header header
;
54 CORE_ADDR text_start
; /* CORE_ADDR of 1st byte of text, this file */
55 long data_offset
; /* offset of data section in file */
56 int chan
; /* file descriptor for the file */
57 struct shared_library
*shares
; /* library this one shares */
59 static struct shared_library
*shlib
= 0;
61 /* Hook for `exec_file_command' command to call. */
63 extern void (*exec_file_display_hook
) ();
65 static CORE_ADDR unshared_text_start
;
67 /* extended header from exec file (for shared library info) */
69 static struct exec_header exec_header
;
72 exec_file_command (filename
, from_tty
)
78 /* Eliminate all traces of old exec file.
79 Mark text segment as empty. */
85 data_end
-= exec_data_start
;
87 unshared_text_start
= 0;
95 close_shared_library(shlib
);
99 /* Now open and digest the file the user requested, if any. */
103 filename
= tilde_expand (filename
);
104 make_cleanup (free
, filename
);
106 execchan
= openp (getenv ("PATH"), 1, filename
, O_RDONLY
, 0,
109 perror_with_name (filename
);
114 #ifdef HEADER_SEEK_FD
115 HEADER_SEEK_FD (execchan
);
118 val
= myread (execchan
, &exec_header
, sizeof exec_header
);
119 exec_aouthdr
= exec_header
.a_exec
;
122 perror_with_name (filename
);
126 /* Look for shared library if needed */
127 if (exec_header
.a_exec
.a_magic
& MF_USES_SL
)
128 shlib
= open_shared_library(exec_header
.a_shlibname
, text_start
);
130 text_offset
= N_TXTOFF (exec_aouthdr
);
131 exec_data_offset
= N_TXTOFF (exec_aouthdr
) + exec_aouthdr
.a_text
;
134 unshared_text_start
= shared_text_end(shlib
) & ~0x7fff;
135 stack_start
= shlib
->header
.a_exec
.a_sldatabase
;
136 stack_end
= STACK_END_ADDR
;
138 unshared_text_start
= 0x8000;
139 text_end
= unshared_text_start
+ exec_aouthdr
.a_text
;
141 exec_data_start
= unshared_text_start
+ exec_aouthdr
.a_text
;
142 exec_data_end
= exec_data_start
+ exec_aouthdr
.a_data
;
144 data_start
= exec_data_start
;
145 data_end
+= exec_data_start
;
147 fstat (execchan
, &st_exec
);
148 exec_mtime
= st_exec
.st_mtime
;
154 printf ("No exec file now.\n");
156 /* Tell display code (if any) about the changed file name. */
157 if (exec_file_display_hook
)
158 (*exec_file_display_hook
) (filename
);
161 /* Read from the program's memory (except for inferior processes).
162 This function is misnamed, since it only reads, never writes; and
163 since it will use the core file and/or executable file as necessary.
165 It should be extended to write as well as read, FIXME, for patching files.
167 Return 0 if address could be read, EIO if addresss out of bounds. */
170 xfer_core_file (memaddr
, myaddr
, len
)
187 /* Determine which file the next bunch of addresses reside in,
188 and where in the file. Set the file's read/write pointer
189 to point at the proper place for the desired address
190 and set xferfile and xferchan for the correct file.
192 If desired address is nonexistent, leave them zero.
194 i is set to the number of bytes that can be handled
195 along with the next address.
197 We put the most likely tests first for efficiency. */
199 /* Note that if there is no core file
200 data_start and data_end are equal. */
201 if (memaddr
>= data_start
&& memaddr
< data_end
)
203 i
= min (len
, data_end
- memaddr
);
204 fileptr
= memaddr
- data_start
+ data_offset
;
205 xferfile
= &corefile
;
208 /* Note that if there is no core file
209 stack_start and stack_end define the shared library data. */
210 else if (memaddr
>= stack_start
&& memaddr
< stack_end
)
213 struct shared_library
*lib
;
214 for (lib
= shlib
; lib
; lib
= lib
->shares
)
215 if (memaddr
>= lib
->header
.a_exec
.a_sldatabase
&&
216 memaddr
< lib
->header
.a_exec
.a_sldatabase
+
217 lib
->header
.a_exec
.a_data
)
220 i
= min (len
, lib
->header
.a_exec
.a_sldatabase
+
221 lib
->header
.a_exec
.a_data
- memaddr
);
222 fileptr
= lib
->data_offset
+ memaddr
-
223 lib
->header
.a_exec
.a_sldatabase
;
225 xferchan
= lib
->chan
;
228 i
= min (len
, stack_end
- memaddr
);
229 fileptr
= memaddr
- stack_start
+ stack_offset
;
230 xferfile
= &corefile
;
234 else if (corechan
< 0
235 && memaddr
>= exec_data_start
&& memaddr
< exec_data_end
)
237 i
= min (len
, exec_data_end
- memaddr
);
238 fileptr
= memaddr
- exec_data_start
+ exec_data_offset
;
239 xferfile
= &execfile
;
242 else if (memaddr
>= text_start
&& memaddr
< text_end
)
244 struct shared_library
*lib
;
245 for (lib
= shlib
; lib
; lib
= lib
->shares
)
246 if (memaddr
>= lib
->text_start
&&
247 memaddr
< lib
->text_start
+ lib
->header
.a_exec
.a_text
)
250 i
= min (len
, lib
->header
.a_exec
.a_text
+
251 lib
->text_start
- memaddr
);
252 fileptr
= memaddr
- lib
->text_start
+ text_offset
;
253 xferfile
= &execfile
;
254 xferchan
= lib
->chan
;
256 i
= min (len
, text_end
- memaddr
);
257 fileptr
= memaddr
- unshared_text_start
+ text_offset
;
258 xferfile
= &execfile
;
262 else if (memaddr
< text_start
)
264 i
= min (len
, text_start
- memaddr
);
266 else if (memaddr
>= text_end
267 && memaddr
< (corechan
>= 0? data_start
: exec_data_start
))
269 i
= min (len
, data_start
- memaddr
);
271 else if (corechan
>= 0
272 && memaddr
>= data_end
&& memaddr
< stack_start
)
274 i
= min (len
, stack_start
- memaddr
);
276 else if (corechan
< 0 && memaddr
>= exec_data_end
)
278 i
= min (len
, - memaddr
);
280 else if (memaddr
>= stack_end
&& stack_end
!= 0)
282 i
= min (len
, - memaddr
);
286 /* Address did not classify into one of the known ranges.
287 This shouldn't happen; we catch the endpoints. */
288 fatal ("Internal: Bad case logic in xfer_core_file.");
291 /* Now we know which file to use.
292 Set up its pointer and transfer the data. */
296 if (xferfile
== &execfile
)
297 error ("No program file to examine.");
299 error ("No core dump file or running program to examine.");
300 val
= lseek (xferchan
, fileptr
, 0);
302 perror_with_name (*xferfile
);
303 val
= myread (xferchan
, myaddr
, i
);
305 perror_with_name (*xferfile
);
307 /* If this address is for nonexistent memory,
308 read zeros if reading, or do nothing if writing.
309 Actually, we never right. */
323 /* APCS (ARM procedure call standard) defines the following prologue:
326 [stmfd sp!, {a1,a2,a3,a4}]
327 stmfd sp!, {...,fp,ip,lr,pc}
328 [stfe f7, [sp, #-12]!]
329 [stfe f6, [sp, #-12]!]
330 [stfe f5, [sp, #-12]!]
331 [stfe f4, [sp, #-12]!]
332 sub fp, ip, #nn // nn == 20 or 4 depending on second ins
340 CORE_ADDR skip_pc
= pc
;
342 op
.ins
= read_memory_integer(skip_pc
, 4);
343 /* look for the "mov ip,sp" */
344 if (op
.generic
.type
!= TYPE_ARITHMETIC
||
345 op
.arith
.opcode
!= OPCODE_MOV
||
346 op
.arith
.dest
!= SPTEMP
||
347 op
.arith
.operand2
!= SP
) return pc
;
349 /* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */
350 op
.ins
= read_memory_integer(skip_pc
, 4);
351 if (op
.generic
.type
== TYPE_BLOCK_BRANCH
&&
352 op
.generic
.subtype
== SUBTYPE_BLOCK
&&
353 op
.block
.mask
== 0xf &&
354 op
.block
.base
== SP
&&
355 op
.block
.is_load
== 0 &&
356 op
.block
.writeback
== 1 &&
357 op
.block
.increment
== 0 &&
358 op
.block
.before
== 1) skip_pc
+= 4;
359 /* skip the "stmfd sp!,{...,fp,ip,lr,pc} */
360 op
.ins
= read_memory_integer(skip_pc
, 4);
361 if (op
.generic
.type
!= TYPE_BLOCK_BRANCH
||
362 op
.generic
.subtype
!= SUBTYPE_BLOCK
||
363 /* the mask should look like 110110xxxxxx0000 */
364 (op
.block
.mask
& 0xd800) != 0xd800 ||
365 op
.block
.base
!= SP
||
366 op
.block
.is_load
!= 0 ||
367 op
.block
.writeback
!= 1 ||
368 op
.block
.increment
!= 0 ||
369 op
.block
.before
!= 1) return pc
;
371 /* check for "sub fp,ip,#nn" */
372 op
.ins
= read_memory_integer(skip_pc
, 4);
373 if (op
.generic
.type
!= TYPE_ARITHMETIC
||
374 op
.arith
.opcode
!= OPCODE_SUB
||
375 op
.arith
.dest
!= FP
||
376 op
.arith
.operand1
!= SPTEMP
) return pc
;
381 print_fpu_flags(flags
)
384 if (flags
& (1 << 0)) fputs("IVO ", stdout
);
385 if (flags
& (1 << 1)) fputs("DVZ ", stdout
);
386 if (flags
& (1 << 2)) fputs("OFL ", stdout
);
387 if (flags
& (1 << 3)) fputs("UFL ", stdout
);
388 if (flags
& (1 << 4)) fputs("INX ", stdout
);
395 register unsigned long status
= read_register(FPS_REGNUM
);
398 type
= (status
>> 24) & 127;
399 printf("%s FPU type %d\n",
400 (status
& (1<<31)) ? "Hardware" : "Software",
402 fputs("mask: ", stdout
);
403 print_fpu_flags(status
>> 16);
404 fputs("flags: ", stdout
);
405 print_fpu_flags(status
);