Initial revision
[external/binutils.git] / gdb / arm-tdep.c
1 /* Copyright (C) 1988, 1989 Free Software Foundation, Inc.
2
3 This file is part of GDB.
4
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)
8 any later version.
9
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.
14
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.  */
18
19 #include "defs.h"
20 #include "param.h"
21 #include "frame.h"
22 #include "inferior.h"
23 #include "arm-opcode.h"
24
25 #include <stdio.h>
26 #include <sys/param.h>
27 #include <sys/dir.h>
28 #include <signal.h>
29 #include <sys/ioctl.h>
30 #include <sys/ptrace.h>
31 #include <machine/reg.h>
32
33 #define N_TXTADDR(hdr) 0x8000
34 #define N_DATADDR(hdr) (hdr.a_text + 0x8000)
35
36 #include "gdbcore.h"
37 #include <sys/user.h>           /* After a.out.h  */
38 #include <sys/file.h>
39 #include <sys/stat.h>
40
41 #include <errno.h>
42
43 \f
44 /* Work with core dump and executable files, for GDB. 
45    This code would be in core.c if it weren't machine-dependent. */
46
47 /* Structure to describe the chain of shared libraries used
48    by the execfile.
49    e.g. prog shares Xt which shares X11 which shares c. */
50
51 struct shared_library {
52     struct exec_header header;
53     char name[SHLIBLEN];
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 */
58 };
59 static struct shared_library *shlib = 0;
60
61 /* Hook for `exec_file_command' command to call.  */
62
63 extern void (*exec_file_display_hook) ();
64    
65 static CORE_ADDR unshared_text_start;
66
67 /* extended header from exec file (for shared library info) */
68
69 static struct exec_header exec_header;
70
71 void
72 exec_file_command (filename, from_tty)
73      char *filename;
74      int from_tty;
75 {
76   int val;
77
78   /* Eliminate all traces of old exec file.
79      Mark text segment as empty.  */
80
81   if (execfile)
82     free (execfile);
83   execfile = 0;
84   data_start = 0;
85   data_end -= exec_data_start;
86   text_start = 0;
87   unshared_text_start = 0;
88   text_end = 0;
89   exec_data_start = 0;
90   exec_data_end = 0;
91   if (execchan >= 0)
92     close (execchan);
93   execchan = -1;
94   if (shlib) {
95       close_shared_library(shlib);
96       shlib = 0;
97   }
98
99   /* Now open and digest the file the user requested, if any.  */
100
101   if (filename)
102     {
103       filename = tilde_expand (filename);
104       make_cleanup (free, filename);
105
106       execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
107                         &execfile);
108       if (execchan < 0)
109         perror_with_name (filename);
110
111       {
112         struct stat st_exec;
113
114 #ifdef HEADER_SEEK_FD
115         HEADER_SEEK_FD (execchan);
116 #endif
117         
118         val = myread (execchan, &exec_header, sizeof exec_header);
119         exec_aouthdr = exec_header.a_exec;
120
121         if (val < 0)
122           perror_with_name (filename);
123
124         text_start = 0x8000;
125
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);
129
130         text_offset = N_TXTOFF (exec_aouthdr);
131         exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
132
133         if (shlib) {
134             unshared_text_start = shared_text_end(shlib) & ~0x7fff;
135             stack_start = shlib->header.a_exec.a_sldatabase;
136             stack_end = STACK_END_ADDR;
137         } else
138             unshared_text_start = 0x8000;
139         text_end = unshared_text_start + exec_aouthdr.a_text;
140
141         exec_data_start = unshared_text_start + exec_aouthdr.a_text;
142         exec_data_end = exec_data_start + exec_aouthdr.a_data;
143
144         data_start = exec_data_start;
145         data_end += exec_data_start;
146
147         fstat (execchan, &st_exec);
148         exec_mtime = st_exec.st_mtime;
149       }
150
151       validate_files ();
152     }
153   else if (from_tty)
154     printf ("No exec file now.\n");
155
156   /* Tell display code (if any) about the changed file name.  */
157   if (exec_file_display_hook)
158     (*exec_file_display_hook) (filename);
159 }
160
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.
164
165    It should be extended to write as well as read, FIXME, for patching files.
166
167    Return 0 if address could be read, EIO if addresss out of bounds.  */
168
169 int
170 xfer_core_file (memaddr, myaddr, len)
171      CORE_ADDR memaddr;
172      char *myaddr;
173      int len;
174 {
175   register int i;
176   register int val;
177   int xferchan;
178   char **xferfile;
179   int fileptr;
180   int returnval = 0;
181
182   while (len > 0)
183     {
184       xferfile = 0;
185       xferchan = 0;
186
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.
191
192          If desired address is nonexistent, leave them zero.
193
194          i is set to the number of bytes that can be handled
195          along with the next address.
196
197          We put the most likely tests first for efficiency.  */
198
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)
202         {
203           i = min (len, data_end - memaddr);
204           fileptr = memaddr - data_start + data_offset;
205           xferfile = &corefile;
206           xferchan = corechan;
207         }
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)
211         {
212             if (corechan < 0) {
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)
218                         break;
219                 if (lib) {
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;
224                     xferfile = execfile;
225                     xferchan = lib->chan;
226                 }
227             } else {
228                 i = min (len, stack_end - memaddr);
229                 fileptr = memaddr - stack_start + stack_offset;
230                 xferfile = &corefile;
231                 xferchan = corechan;
232             }
233         }
234       else if (corechan < 0
235                && memaddr >= exec_data_start && memaddr < exec_data_end)
236         {
237           i = min (len, exec_data_end - memaddr);
238           fileptr = memaddr - exec_data_start + exec_data_offset;
239           xferfile = &execfile;
240           xferchan = execchan;
241         }
242       else if (memaddr >= text_start && memaddr < text_end)
243         {
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)
248                     break;
249             if (lib) {
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;
255             } else {
256                 i = min (len, text_end - memaddr);
257                 fileptr = memaddr - unshared_text_start + text_offset;
258                 xferfile = &execfile;
259                 xferchan = execchan;
260             }
261         }
262       else if (memaddr < text_start)
263         {
264           i = min (len, text_start - memaddr);
265         }
266       else if (memaddr >= text_end
267                && memaddr < (corechan >= 0? data_start : exec_data_start))
268         {
269           i = min (len, data_start - memaddr);
270         }
271       else if (corechan >= 0
272                && memaddr >= data_end && memaddr < stack_start)
273         {
274           i = min (len, stack_start - memaddr);
275         }
276       else if (corechan < 0 && memaddr >= exec_data_end)
277         {
278           i = min (len, - memaddr);
279         }
280       else if (memaddr >= stack_end && stack_end != 0)
281         {
282           i = min (len, - memaddr);
283         }
284       else
285         {
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.");
289         }
290
291       /* Now we know which file to use.
292          Set up its pointer and transfer the data.  */
293       if (xferfile)
294         {
295           if (*xferfile == 0)
296             if (xferfile == &execfile)
297               error ("No program file to examine.");
298             else
299               error ("No core dump file or running program to examine.");
300           val = lseek (xferchan, fileptr, 0);
301           if (val < 0)
302             perror_with_name (*xferfile);
303           val = myread (xferchan, myaddr, i);
304           if (val < 0)
305             perror_with_name (*xferfile);
306         }
307       /* If this address is for nonexistent memory,
308          read zeros if reading, or do nothing if writing.
309          Actually, we never right.  */
310       else
311         {
312           bzero (myaddr, i);
313           returnval = EIO;
314         }
315
316       memaddr += i;
317       myaddr += i;
318       len -= i;
319     }
320   return returnval;
321 }
322 \f
323 /* APCS (ARM procedure call standard) defines the following prologue:
324
325    mov          ip, sp
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
333 */
334
335 CORE_ADDR
336 skip_prologue(pc)
337 CORE_ADDR pc;
338 {
339     union insn_fmt op;
340     CORE_ADDR skip_pc = pc;
341
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;
348     skip_pc += 4;
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;
370     skip_pc += 4;
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;
377     return skip_pc + 4;
378 }
379
380 static void
381 print_fpu_flags(flags)
382 int flags;
383 {
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);
389     putchar('\n');
390 }
391
392 void
393 arm_float_info()
394 {
395     register unsigned long status = read_register(FPS_REGNUM);
396     int type;
397
398     type = (status >> 24) & 127;
399     printf("%s FPU type %d\n",
400            (status & (1<<31)) ? "Hardware" : "Software",
401            type);
402     fputs("mask: ", stdout);
403     print_fpu_flags(status >> 16);
404     fputs("flags: ", stdout);
405     print_fpu_flags(status);
406 }