]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/arm-tdep.c
Wed May 24 15:49:47 1995 Steve Chamberlain <sac@slash.cygnus.com>
[thirdparty/binutils-gdb.git] / gdb / arm-tdep.c
1 /* Target-dependent code for the Acorn Risc Machine, for GDB, the GNU Debugger.
2 Copyright 1988, 1989, 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "defs.h"
21 #include "frame.h"
22 #include "inferior.h"
23
24 #if 0
25 #include "gdbcore.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 <sys/user.h> /* After a.out.h */
37 #include <sys/file.h>
38 #include <sys/stat.h>
39
40 #include <errno.h>
41 #endif
42
43 \f
44 #if 0
45 /* Work with core dump and executable files, for GDB.
46 This code would be in core.c if it weren't machine-dependent. */
47
48 /* Structure to describe the chain of shared libraries used
49 by the execfile.
50 e.g. prog shares Xt which shares X11 which shares c. */
51
52 struct shared_library {
53 struct exec_header header;
54 char name[SHLIBLEN];
55 CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */
56 long data_offset; /* offset of data section in file */
57 int chan; /* file descriptor for the file */
58 struct shared_library *shares; /* library this one shares */
59 };
60 static struct shared_library *shlib = 0;
61
62 /* Hook for `exec_file_command' command to call. */
63
64 extern void (*exec_file_display_hook) ();
65
66 static CORE_ADDR unshared_text_start;
67
68 /* extended header from exec file (for shared library info) */
69
70 static struct exec_header exec_header;
71
72 void
73 exec_file_command (filename, from_tty)
74 char *filename;
75 int from_tty;
76 {
77 int val;
78
79 /* Eliminate all traces of old exec file.
80 Mark text segment as empty. */
81
82 if (execfile)
83 free (execfile);
84 execfile = 0;
85 data_start = 0;
86 data_end -= exec_data_start;
87 text_start = 0;
88 unshared_text_start = 0;
89 text_end = 0;
90 exec_data_start = 0;
91 exec_data_end = 0;
92 if (execchan >= 0)
93 close (execchan);
94 execchan = -1;
95 if (shlib) {
96 close_shared_library(shlib);
97 shlib = 0;
98 }
99
100 /* Now open and digest the file the user requested, if any. */
101
102 if (filename)
103 {
104 filename = tilde_expand (filename);
105 make_cleanup (free, filename);
106
107 execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
108 &execfile);
109 if (execchan < 0)
110 perror_with_name (filename);
111
112 {
113 struct stat st_exec;
114
115 #ifdef HEADER_SEEK_FD
116 HEADER_SEEK_FD (execchan);
117 #endif
118
119 val = myread (execchan, &exec_header, sizeof exec_header);
120 exec_aouthdr = exec_header.a_exec;
121
122 if (val < 0)
123 perror_with_name (filename);
124
125 text_start = 0x8000;
126
127 /* Look for shared library if needed */
128 if (exec_header.a_exec.a_magic & MF_USES_SL)
129 shlib = open_shared_library(exec_header.a_shlibname, text_start);
130
131 text_offset = N_TXTOFF (exec_aouthdr);
132 exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
133
134 if (shlib) {
135 unshared_text_start = shared_text_end(shlib) & ~0x7fff;
136 stack_start = shlib->header.a_exec.a_sldatabase;
137 stack_end = STACK_END_ADDR;
138 } else
139 unshared_text_start = 0x8000;
140 text_end = unshared_text_start + exec_aouthdr.a_text;
141
142 exec_data_start = unshared_text_start + exec_aouthdr.a_text;
143 exec_data_end = exec_data_start + exec_aouthdr.a_data;
144
145 data_start = exec_data_start;
146 data_end += exec_data_start;
147
148 fstat (execchan, &st_exec);
149 exec_mtime = st_exec.st_mtime;
150 }
151
152 validate_files ();
153 }
154 else if (from_tty)
155 printf ("No exec file now.\n");
156
157 /* Tell display code (if any) about the changed file name. */
158 if (exec_file_display_hook)
159 (*exec_file_display_hook) (filename);
160 }
161 #endif
162
163 #if 0
164 /* Read from the program's memory (except for inferior processes).
165 This function is misnamed, since it only reads, never writes; and
166 since it will use the core file and/or executable file as necessary.
167
168 It should be extended to write as well as read, FIXME, for patching files.
169
170 Return 0 if address could be read, EIO if addresss out of bounds. */
171
172 int
173 xfer_core_file (memaddr, myaddr, len)
174 CORE_ADDR memaddr;
175 char *myaddr;
176 int len;
177 {
178 register int i;
179 register int val;
180 int xferchan;
181 char **xferfile;
182 int fileptr;
183 int returnval = 0;
184
185 while (len > 0)
186 {
187 xferfile = 0;
188 xferchan = 0;
189
190 /* Determine which file the next bunch of addresses reside in,
191 and where in the file. Set the file's read/write pointer
192 to point at the proper place for the desired address
193 and set xferfile and xferchan for the correct file.
194
195 If desired address is nonexistent, leave them zero.
196
197 i is set to the number of bytes that can be handled
198 along with the next address.
199
200 We put the most likely tests first for efficiency. */
201
202 /* Note that if there is no core file
203 data_start and data_end are equal. */
204 if (memaddr >= data_start && memaddr < data_end)
205 {
206 i = min (len, data_end - memaddr);
207 fileptr = memaddr - data_start + data_offset;
208 xferfile = &corefile;
209 xferchan = corechan;
210 }
211 /* Note that if there is no core file
212 stack_start and stack_end define the shared library data. */
213 else if (memaddr >= stack_start && memaddr < stack_end)
214 {
215 if (corechan < 0) {
216 struct shared_library *lib;
217 for (lib = shlib; lib; lib = lib->shares)
218 if (memaddr >= lib->header.a_exec.a_sldatabase &&
219 memaddr < lib->header.a_exec.a_sldatabase +
220 lib->header.a_exec.a_data)
221 break;
222 if (lib) {
223 i = min (len, lib->header.a_exec.a_sldatabase +
224 lib->header.a_exec.a_data - memaddr);
225 fileptr = lib->data_offset + memaddr -
226 lib->header.a_exec.a_sldatabase;
227 xferfile = execfile;
228 xferchan = lib->chan;
229 }
230 } else {
231 i = min (len, stack_end - memaddr);
232 fileptr = memaddr - stack_start + stack_offset;
233 xferfile = &corefile;
234 xferchan = corechan;
235 }
236 }
237 else if (corechan < 0
238 && memaddr >= exec_data_start && memaddr < exec_data_end)
239 {
240 i = min (len, exec_data_end - memaddr);
241 fileptr = memaddr - exec_data_start + exec_data_offset;
242 xferfile = &execfile;
243 xferchan = execchan;
244 }
245 else if (memaddr >= text_start && memaddr < text_end)
246 {
247 struct shared_library *lib;
248 for (lib = shlib; lib; lib = lib->shares)
249 if (memaddr >= lib->text_start &&
250 memaddr < lib->text_start + lib->header.a_exec.a_text)
251 break;
252 if (lib) {
253 i = min (len, lib->header.a_exec.a_text +
254 lib->text_start - memaddr);
255 fileptr = memaddr - lib->text_start + text_offset;
256 xferfile = &execfile;
257 xferchan = lib->chan;
258 } else {
259 i = min (len, text_end - memaddr);
260 fileptr = memaddr - unshared_text_start + text_offset;
261 xferfile = &execfile;
262 xferchan = execchan;
263 }
264 }
265 else if (memaddr < text_start)
266 {
267 i = min (len, text_start - memaddr);
268 }
269 else if (memaddr >= text_end
270 && memaddr < (corechan >= 0? data_start : exec_data_start))
271 {
272 i = min (len, data_start - memaddr);
273 }
274 else if (corechan >= 0
275 && memaddr >= data_end && memaddr < stack_start)
276 {
277 i = min (len, stack_start - memaddr);
278 }
279 else if (corechan < 0 && memaddr >= exec_data_end)
280 {
281 i = min (len, - memaddr);
282 }
283 else if (memaddr >= stack_end && stack_end != 0)
284 {
285 i = min (len, - memaddr);
286 }
287 else
288 {
289 /* Address did not classify into one of the known ranges.
290 This shouldn't happen; we catch the endpoints. */
291 fatal ("Internal: Bad case logic in xfer_core_file.");
292 }
293
294 /* Now we know which file to use.
295 Set up its pointer and transfer the data. */
296 if (xferfile)
297 {
298 if (*xferfile == 0)
299 if (xferfile == &execfile)
300 error ("No program file to examine.");
301 else
302 error ("No core dump file or running program to examine.");
303 val = lseek (xferchan, fileptr, 0);
304 if (val < 0)
305 perror_with_name (*xferfile);
306 val = myread (xferchan, myaddr, i);
307 if (val < 0)
308 perror_with_name (*xferfile);
309 }
310 /* If this address is for nonexistent memory,
311 read zeros if reading, or do nothing if writing.
312 Actually, we never right. */
313 else
314 {
315 memset (myaddr, '\0', i);
316 returnval = EIO;
317 }
318
319 memaddr += i;
320 myaddr += i;
321 len -= i;
322 }
323 return returnval;
324 }
325 #endif
326 \f
327 /* APCS (ARM procedure call standard) defines the following prologue:
328
329 mov ip, sp
330 [stmfd sp!, {a1,a2,a3,a4}]
331 stmfd sp!, {...,fp,ip,lr,pc}
332 [stfe f7, [sp, #-12]!]
333 [stfe f6, [sp, #-12]!]
334 [stfe f5, [sp, #-12]!]
335 [stfe f4, [sp, #-12]!]
336 sub fp, ip, #nn // nn == 20 or 4 depending on second ins
337 */
338
339 CORE_ADDR
340 skip_prologue(pc)
341 CORE_ADDR pc;
342 {
343 CORE_ADDR skip_pc = pc;
344 #if 0
345 union insn_fmt op;
346
347 op.ins = read_memory_integer(skip_pc, 4);
348 /* look for the "mov ip,sp" */
349 if (op.generic.type != TYPE_ARITHMETIC ||
350 op.arith.opcode != OPCODE_MOV ||
351 op.arith.dest != SPTEMP ||
352 op.arith.operand2 != SP) return pc;
353 skip_pc += 4;
354 /* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */
355 op.ins = read_memory_integer(skip_pc, 4);
356 if (op.generic.type == TYPE_BLOCK_BRANCH &&
357 op.generic.subtype == SUBTYPE_BLOCK &&
358 op.block.mask == 0xf &&
359 op.block.base == SP &&
360 op.block.is_load == 0 &&
361 op.block.writeback == 1 &&
362 op.block.increment == 0 &&
363 op.block.before == 1) skip_pc += 4;
364 /* skip the "stmfd sp!,{...,fp,ip,lr,pc} */
365 op.ins = read_memory_integer(skip_pc, 4);
366 if (op.generic.type != TYPE_BLOCK_BRANCH ||
367 op.generic.subtype != SUBTYPE_BLOCK ||
368 /* the mask should look like 110110xxxxxx0000 */
369 (op.block.mask & 0xd800) != 0xd800 ||
370 op.block.base != SP ||
371 op.block.is_load != 0 ||
372 op.block.writeback != 1 ||
373 op.block.increment != 0 ||
374 op.block.before != 1) return pc;
375 skip_pc += 4;
376 /* check for "sub fp,ip,#nn" */
377 op.ins = read_memory_integer(skip_pc, 4);
378 if (op.generic.type != TYPE_ARITHMETIC ||
379 op.arith.opcode != OPCODE_SUB ||
380 op.arith.dest != FP ||
381 op.arith.operand1 != SPTEMP) return pc;
382 #endif
383 return skip_pc + 4;
384 }
385
386 void
387 arm_frame_find_saved_regs (frame_info, saved_regs_addr)
388 struct frame_info *frame_info;
389 struct frame_saved_regs *saved_regs_addr;
390 {
391 register int regnum;
392 register int frame;
393 register int next_addr;
394 register int return_data_save;
395 register int saved_register_mask;
396
397 memset (saved_regs_addr, '\0', sizeof (*saved_regs_addr));
398 frame = frame_info->frame;
399 return_data_save = read_memory_integer (frame, 4) & 0x03fffffc - 12;
400 saved_register_mask = read_memory_integer (return_data_save, 4);
401 next_addr = frame - 12;
402 for (regnum = 4; regnum < 10; regnum++)
403 if (saved_register_mask & (1 << regnum))
404 {
405 next_addr -= 4;
406 saved_regs_addr->regs[regnum] = next_addr;
407 }
408 if (read_memory_integer (return_data_save + 4, 4) == 0xed6d7103)
409 {
410 next_addr -= 12;
411 saved_regs_addr->regs[F0_REGNUM + 7] = next_addr;
412 }
413 if (read_memory_integer (return_data_save + 8, 4) == 0xed6d6103)
414 {
415 next_addr -= 12;
416 saved_regs_addr->regs[F0_REGNUM + 6] = next_addr;
417 }
418 if (read_memory_integer (return_data_save + 12, 4) == 0xed6d5103)
419 {
420 next_addr -= 12;
421 saved_regs_addr->regs[F0_REGNUM + 5] = next_addr;
422 }
423 if (read_memory_integer(return_data_save + 16, 4) == 0xed6d4103)
424 {
425 next_addr -= 12;
426 saved_regs_addr->regs[F0_REGNUM + 4] = next_addr;
427 }
428 saved_regs_addr->regs[SP_REGNUM] = next_addr;
429 saved_regs_addr->regs[PC_REGNUM] = frame - 4;
430 saved_regs_addr->regs[PS_REGNUM] = frame - 4;
431 saved_regs_addr->regs[FP_REGNUM] = frame - 12;
432 }
433
434 static void
435 print_fpu_flags(flags)
436 int flags;
437 {
438 if (flags & (1 << 0)) fputs("IVO ", stdout);
439 if (flags & (1 << 1)) fputs("DVZ ", stdout);
440 if (flags & (1 << 2)) fputs("OFL ", stdout);
441 if (flags & (1 << 3)) fputs("UFL ", stdout);
442 if (flags & (1 << 4)) fputs("INX ", stdout);
443 putchar('\n');
444 }
445
446 void
447 arm_float_info()
448 {
449 register unsigned long status = read_register(FPS_REGNUM);
450 int type;
451
452 type = (status >> 24) & 127;
453 printf("%s FPU type %d\n",
454 (status & (1<<31)) ? "Hardware" : "Software",
455 type);
456 fputs("mask: ", stdout);
457 print_fpu_flags(status >> 16);
458 fputs("flags: ", stdout);
459 print_fpu_flags(status);
460 }
461
462 void
463 _initialize_arm_tdep ()
464 {
465 tm_print_insn = print_insn_arm;
466 }
467
468
469 /* FIXME: Fill in with the 'right thing', see asm
470 template in arm-convert.s */
471
472 void
473 convert_from_extended (ptr, dbl)
474 void *ptr;
475 double *dbl;
476 {
477 *dbl = *(double*)ptr;
478 }
479
480
481 void
482 convert_to_extended (dbl, ptr)
483 void *ptr;
484 double *dbl;
485 {
486 *(double*)ptr = *dbl;
487 }
488