* complaints.c: New file, code moved from utils.c.
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
CommitLineData
bd5635a1
RP
1/* Copyright (C) 1988, 1989 Free Software Foundation, Inc.
2
3This file is part of GDB.
4
5GDB is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 1, or (at your option)
8any later version.
9
10GDB is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with GDB; see the file COPYING. If not, write to
17the 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
51struct 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};
59static struct shared_library *shlib = 0;
60
61/* Hook for `exec_file_command' command to call. */
62
63extern void (*exec_file_display_hook) ();
64
65static CORE_ADDR unshared_text_start;
66
67/* extended header from exec file (for shared library info) */
68
69static struct exec_header exec_header;
70
71void
72exec_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
169int
170xfer_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
335CORE_ADDR
336skip_prologue(pc)
337CORE_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
380static void
381print_fpu_flags(flags)
382int 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
392void
393arm_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}
This page took 0.093126 seconds and 4 git commands to generate.