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.
4 This file is part of GDB.
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.
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.
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. */
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)
36 #include <sys/user.h> /* After a.out.h */
45 /* Work with core dump and executable files, for GDB.
46 This code would be in core.c if it weren't machine-dependent. */
48 /* Structure to describe the chain of shared libraries used
50 e.g. prog shares Xt which shares X11 which shares c. */
52 struct shared_library {
53 struct exec_header header;
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 */
60 static struct shared_library *shlib = 0;
62 /* Hook for `exec_file_command' command to call. */
64 extern void (*exec_file_display_hook) ();
66 static CORE_ADDR unshared_text_start;
68 /* extended header from exec file (for shared library info) */
70 static struct exec_header exec_header;
73 exec_file_command (filename, from_tty)
79 /* Eliminate all traces of old exec file.
80 Mark text segment as empty. */
86 data_end -= exec_data_start;
88 unshared_text_start = 0;
96 close_shared_library(shlib);
100 /* Now open and digest the file the user requested, if any. */
104 filename = tilde_expand (filename);
105 make_cleanup (free, filename);
107 execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
110 perror_with_name (filename);
115 #ifdef HEADER_SEEK_FD
116 HEADER_SEEK_FD (execchan);
119 val = myread (execchan, &exec_header, sizeof exec_header);
120 exec_aouthdr = exec_header.a_exec;
123 perror_with_name (filename);
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);
131 text_offset = N_TXTOFF (exec_aouthdr);
132 exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
135 unshared_text_start = shared_text_end(shlib) & ~0x7fff;
136 stack_start = shlib->header.a_exec.a_sldatabase;
137 stack_end = STACK_END_ADDR;
139 unshared_text_start = 0x8000;
140 text_end = unshared_text_start + exec_aouthdr.a_text;
142 exec_data_start = unshared_text_start + exec_aouthdr.a_text;
143 exec_data_end = exec_data_start + exec_aouthdr.a_data;
145 data_start = exec_data_start;
146 data_end += exec_data_start;
148 fstat (execchan, &st_exec);
149 exec_mtime = st_exec.st_mtime;
155 printf ("No exec file now.\n");
157 /* Tell display code (if any) about the changed file name. */
158 if (exec_file_display_hook)
159 (*exec_file_display_hook) (filename);
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.
168 It should be extended to write as well as read, FIXME, for patching files.
170 Return 0 if address could be read, EIO if addresss out of bounds. */
173 xfer_core_file (memaddr, myaddr, len)
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.
195 If desired address is nonexistent, leave them zero.
197 i is set to the number of bytes that can be handled
198 along with the next address.
200 We put the most likely tests first for efficiency. */
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)
206 i = min (len, data_end - memaddr);
207 fileptr = memaddr - data_start + data_offset;
208 xferfile = &corefile;
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)
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)
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;
228 xferchan = lib->chan;
231 i = min (len, stack_end - memaddr);
232 fileptr = memaddr - stack_start + stack_offset;
233 xferfile = &corefile;
237 else if (corechan < 0
238 && memaddr >= exec_data_start && memaddr < exec_data_end)
240 i = min (len, exec_data_end - memaddr);
241 fileptr = memaddr - exec_data_start + exec_data_offset;
242 xferfile = &execfile;
245 else if (memaddr >= text_start && memaddr < text_end)
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)
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;
259 i = min (len, text_end - memaddr);
260 fileptr = memaddr - unshared_text_start + text_offset;
261 xferfile = &execfile;
265 else if (memaddr < text_start)
267 i = min (len, text_start - memaddr);
269 else if (memaddr >= text_end
270 && memaddr < (corechan >= 0? data_start : exec_data_start))
272 i = min (len, data_start - memaddr);
274 else if (corechan >= 0
275 && memaddr >= data_end && memaddr < stack_start)
277 i = min (len, stack_start - memaddr);
279 else if (corechan < 0 && memaddr >= exec_data_end)
281 i = min (len, - memaddr);
283 else if (memaddr >= stack_end && stack_end != 0)
285 i = min (len, - memaddr);
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.");
294 /* Now we know which file to use.
295 Set up its pointer and transfer the data. */
299 if (xferfile == &execfile)
300 error ("No program file to examine.");
302 error ("No core dump file or running program to examine.");
303 val = lseek (xferchan, fileptr, 0);
305 perror_with_name (*xferfile);
306 val = myread (xferchan, myaddr, i);
308 perror_with_name (*xferfile);
310 /* If this address is for nonexistent memory,
311 read zeros if reading, or do nothing if writing.
312 Actually, we never right. */
315 memset (myaddr, '\0', i);
327 /* APCS (ARM procedure call standard) defines the following prologue:
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
343 CORE_ADDR skip_pc = pc;
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;
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;
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;
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;
393 register int next_addr;
394 register int return_data_save;
395 register int saved_register_mask;
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))
406 saved_regs_addr->regs[regnum] = next_addr;
408 if (read_memory_integer (return_data_save + 4, 4) == 0xed6d7103)
411 saved_regs_addr->regs[F0_REGNUM + 7] = next_addr;
413 if (read_memory_integer (return_data_save + 8, 4) == 0xed6d6103)
416 saved_regs_addr->regs[F0_REGNUM + 6] = next_addr;
418 if (read_memory_integer (return_data_save + 12, 4) == 0xed6d5103)
421 saved_regs_addr->regs[F0_REGNUM + 5] = next_addr;
423 if (read_memory_integer(return_data_save + 16, 4) == 0xed6d4103)
426 saved_regs_addr->regs[F0_REGNUM + 4] = next_addr;
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;
435 print_fpu_flags(flags)
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);
449 register unsigned long status = read_register(FPS_REGNUM);
452 type = (status >> 24) & 127;
453 printf("%s FPU type %d\n",
454 (status & (1<<31)) ? "Hardware" : "Software",
456 fputs("mask: ", stdout);
457 print_fpu_flags(status >> 16);
458 fputs("flags: ", stdout);
459 print_fpu_flags(status);
463 _initialize_arm_tdep ()
465 tm_print_insn = print_insn_little_arm;
469 /* FIXME: Fill in with the 'right thing', see asm
470 template in arm-convert.s */
473 convert_from_extended (ptr, dbl)
477 *dbl = *(double*)ptr;
482 convert_to_extended (dbl, ptr)
486 *(double*)ptr = *dbl;