4187119d |
1 | /* Low level interface to ptrace, for GDB when running under Unix. |
2 | Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GDB. |
5 | |
6 | GDB 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 1, or (at your option) |
9 | any later version. |
10 | |
11 | GDB 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 GDB; see the file COPYING. If not, write to |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
19 | |
20 | /* many 387-specific items of use taken from i386-dep.c */ |
21 | |
7a67dd45 |
22 | #include <stdio.h> |
4187119d |
23 | #include "defs.h" |
24 | #include "param.h" |
25 | #include "frame.h" |
26 | #include "inferior.h" |
27 | #include "symtab.h" |
28 | |
4187119d |
29 | #include <signal.h> |
30 | #include <sys/param.h> |
31 | #include <sys/user.h> |
32 | #include <sys/dir.h> |
33 | #include <sys/ioctl.h> |
34 | #include <sys/stat.h> |
35 | #include <a.out.h> |
36 | #include <fcntl.h> |
37 | |
38 | static long i386_get_frame_setup (); |
39 | static i386_follow_jump (); |
40 | |
41 | /* XPT_DEBUG doesn't work yet under Dynix 3.0.12, but UNDEBUG does... */ |
42 | #define PTRACE_ATTACH XPT_DEBUG |
43 | #define PTRACE_DETACH XPT_UNDEBUG |
44 | |
45 | #include <sgtty.h> |
46 | #define TERMINAL struct sgttyb |
47 | |
48 | extern int errno; |
49 | |
50 | /* Nonzero if we are debugging an attached outside process |
51 | rather than an inferior. */ |
52 | |
53 | static int attach_flag; |
54 | |
55 | /* This function simply calls ptrace with the given arguments. |
56 | It exists so that all calls to ptrace are isolated in this |
57 | machine-dependent file. */ |
58 | int |
59 | call_ptrace (request, pid, arg3, arg4) |
60 | int request, pid, arg3, arg4; |
61 | { |
62 | return ptrace (request, pid, arg3, arg4); |
63 | } |
64 | |
65 | |
66 | |
67 | kill_inferior () |
68 | { |
69 | if (remote_debugging) |
70 | return; |
71 | if (inferior_pid == 0) |
72 | return; |
73 | ptrace (8, inferior_pid, 0, 0); |
74 | wait (0); |
75 | inferior_died (); |
76 | } |
77 | |
78 | /* This is used when GDB is exiting. It gives less chance of error.*/ |
79 | |
80 | kill_inferior_fast () |
81 | { |
82 | if (remote_debugging) |
83 | return; |
84 | if (inferior_pid == 0) |
85 | return; |
86 | ptrace (8, inferior_pid, 0, 0); |
87 | wait (0); |
88 | } |
89 | |
90 | /* Resume execution of the inferior process. |
91 | If STEP is nonzero, single-step it. |
92 | If SIGNAL is nonzero, give it that signal. */ |
93 | |
94 | void |
95 | resume (step, signal) |
96 | int step; |
97 | int signal; |
98 | { |
99 | errno = 0; |
100 | if (remote_debugging) |
101 | remote_resume (step, signal); |
102 | else |
103 | { |
104 | ptrace (step ? 9 : 7, inferior_pid, 1, signal); |
105 | if (errno) |
106 | perror_with_name ("ptrace"); |
107 | } |
108 | } |
109 | \f |
110 | #ifdef ATTACH_DETACH |
111 | |
112 | /* Start debugging the process whose number is PID. */ |
113 | |
114 | attach (pid) |
115 | int pid; |
116 | { |
117 | errno = 0; |
118 | ptrace (PTRACE_ATTACH, pid, 0, 0); |
119 | if (errno) |
120 | perror_with_name ("ptrace"); |
121 | attach_flag = 1; |
122 | return pid; |
123 | } |
124 | |
125 | /* Stop debugging the process whose number is PID |
126 | and continue it with signal number SIGNAL. |
127 | SIGNAL = 0 means just continue it. */ |
128 | |
129 | void |
130 | detach (signal) |
131 | int signal; |
132 | { |
133 | errno = 0; |
134 | ptrace (PTRACE_DETACH, inferior_pid, 1, signal); |
135 | if (errno) |
136 | perror_with_name ("ptrace"); |
137 | attach_flag = 0; |
138 | } |
139 | #endif /* ATTACH_DETACH */ |
140 | \f |
141 | |
142 | store_inferior_registers(regno) |
143 | int regno; |
144 | { |
145 | struct pt_regset regs; |
146 | int reg_tmp, i; |
147 | extern char registers[]; |
148 | |
149 | if (-1 == regno) |
150 | { |
151 | regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; |
152 | regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; |
153 | regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; |
154 | regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; |
155 | regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; |
156 | regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; |
157 | regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; |
158 | regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; |
159 | regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; |
160 | regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; |
161 | for (i = 0; i < 31; i++) { |
162 | regs.pr_fpa.fpa_regs[i] = |
163 | *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)]; |
164 | } |
165 | } |
166 | else |
167 | { |
168 | reg_tmp = *(int *)®isters[REGISTER_BYTE(regno)]; |
169 | ptrace(XPT_RREGS, inferior_pid, ®s, 0); |
170 | switch (regno) |
171 | { |
172 | case 0: |
173 | regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; |
174 | break; |
175 | case 5: |
176 | regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; |
177 | break; |
178 | case 2: |
179 | regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; |
180 | break; |
181 | case 1: |
182 | regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; |
183 | break; |
184 | case 6: |
185 | regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; |
186 | break; |
187 | case 7: |
188 | regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; |
189 | break; |
190 | case 15: |
191 | regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; |
192 | break; |
193 | case 14: |
194 | regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; |
195 | break; |
196 | case 16: |
197 | regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; |
198 | break; |
199 | case 17: |
200 | regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; |
201 | break; |
202 | } |
203 | } |
204 | ptrace(XPT_WREGS, inferior_pid, ®s, 0); |
205 | } |
206 | |
207 | void |
208 | fetch_inferior_registers() |
209 | { |
210 | int i; |
211 | struct pt_regset regs; |
212 | extern char registers[]; |
213 | |
214 | ptrace(XPT_RREGS, inferior_pid, ®s, 0); |
215 | *(int *)®isters[REGISTER_BYTE(0)] = regs.pr_eax; |
216 | *(int *)®isters[REGISTER_BYTE(5)] = regs.pr_ebx; |
217 | *(int *)®isters[REGISTER_BYTE(2)] = regs.pr_ecx; |
218 | *(int *)®isters[REGISTER_BYTE(1)] = regs.pr_edx; |
219 | *(int *)®isters[REGISTER_BYTE(6)] = regs.pr_esi; |
220 | *(int *)®isters[REGISTER_BYTE(7)] = regs.pr_edi; |
221 | *(int *)®isters[REGISTER_BYTE(15)] = regs.pr_ebp; |
222 | *(int *)®isters[REGISTER_BYTE(14)] = regs.pr_esp; |
223 | *(int *)®isters[REGISTER_BYTE(16)] = regs.pr_eip; |
224 | *(int *)®isters[REGISTER_BYTE(17)] = regs.pr_flags; |
225 | for (i = 0; i < FPA_NREGS; i++) { |
226 | *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)] = regs.pr_fpa.fpa_regs[i]; |
227 | } |
228 | bcopy(regs.pr_fpu.fpu_stack[0], ®isters[REGISTER_BYTE(3)], 10); |
229 | bcopy(regs.pr_fpu.fpu_stack[1], ®isters[REGISTER_BYTE(4)], 10); |
230 | bcopy(regs.pr_fpu.fpu_stack[2], ®isters[REGISTER_BYTE(8)], 10); |
231 | bcopy(regs.pr_fpu.fpu_stack[3], ®isters[REGISTER_BYTE(9)], 10); |
232 | bcopy(regs.pr_fpu.fpu_stack[4], ®isters[REGISTER_BYTE(10)], 10); |
233 | bcopy(regs.pr_fpu.fpu_stack[5], ®isters[REGISTER_BYTE(11)], 10); |
234 | bcopy(regs.pr_fpu.fpu_stack[6], ®isters[REGISTER_BYTE(12)], 10); |
235 | bcopy(regs.pr_fpu.fpu_stack[7], ®isters[REGISTER_BYTE(13)], 10); |
236 | } |
237 | |
238 | |
239 | /* Copy LEN bytes from inferior's memory starting at MEMADDR |
240 | to debugger memory starting at MYADDR. */ |
241 | |
242 | read_inferior_memory (memaddr, myaddr, len) |
243 | CORE_ADDR memaddr; |
244 | char *myaddr; |
245 | int len; |
246 | { |
247 | register int i; |
248 | /* Round starting address down to longword boundary. */ |
249 | register CORE_ADDR addr = memaddr & - sizeof (int); |
250 | /* Round ending address up; get number of longwords that makes. */ |
251 | register int count |
252 | = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); |
253 | /* Allocate buffer of that many longwords. */ |
254 | register int *buffer = (int *) alloca (count * sizeof (int)); |
255 | |
256 | /* Read all the longwords */ |
257 | for (i = 0; i < count; i++, addr += sizeof (int)) { |
258 | errno = 0; |
259 | if (remote_debugging) |
260 | buffer[i] = remote_fetch_word (addr); |
261 | else |
262 | buffer[i] = ptrace (1, inferior_pid, addr, 0); |
263 | if (errno) |
264 | return errno; |
265 | } |
266 | |
267 | /* Copy appropriate bytes out of the buffer. */ |
268 | bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); |
269 | return 0; |
270 | } |
271 | |
272 | /* Copy LEN bytes of data from debugger memory at MYADDR |
273 | to inferior's memory at MEMADDR. |
274 | On failure (cannot write the inferior) |
275 | returns the value of errno. */ |
276 | |
277 | int |
278 | write_inferior_memory (memaddr, myaddr, len) |
279 | CORE_ADDR memaddr; |
280 | char *myaddr; |
281 | int len; |
282 | { |
283 | register int i; |
284 | /* Round starting address down to longword boundary. */ |
285 | register CORE_ADDR addr = memaddr & - sizeof (int); |
286 | /* Round ending address up; get number of longwords that makes. */ |
287 | register int count |
288 | = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); |
289 | /* Allocate buffer of that many longwords. */ |
290 | register int *buffer = (int *) alloca (count * sizeof (int)); |
291 | extern int errno; |
292 | |
293 | /* Fill start and end extra bytes of buffer with existing memory data. */ |
294 | |
295 | if (remote_debugging) |
296 | buffer[0] = remote_fetch_word (addr); |
297 | else |
298 | buffer[0] = ptrace (1, inferior_pid, addr, 0); |
299 | |
300 | if (count > 1) |
301 | { |
302 | if (remote_debugging) |
303 | buffer[count - 1] |
304 | = remote_fetch_word (addr + (count - 1) * sizeof (int)); |
305 | else |
306 | buffer[count - 1] |
307 | = ptrace (1, inferior_pid, |
308 | addr + (count - 1) * sizeof (int), 0); |
309 | } |
310 | |
311 | /* Copy data to be written over corresponding part of buffer */ |
312 | |
313 | bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); |
314 | |
315 | /* Write the entire buffer. */ |
316 | |
317 | for (i = 0; i < count; i++, addr += sizeof (int)) |
318 | { |
319 | errno = 0; |
320 | if (remote_debugging) |
321 | remote_store_word (addr, buffer[i]); |
322 | else |
323 | ptrace (4, inferior_pid, addr, buffer[i]); |
324 | if (errno) |
325 | return errno; |
326 | } |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | |
332 | /* Recognize COFF format systems because a.out.h defines AOUTHDR. */ |
333 | #ifdef AOUTHDR |
334 | #define COFF_FORMAT |
335 | #endif |
336 | |
337 | |
338 | #ifndef N_TXTADDR |
339 | #define N_TXTADDR(hdr) 0 |
340 | #endif /* no N_TXTADDR */ |
341 | |
342 | #ifndef N_DATADDR |
343 | #define N_DATADDR(hdr) hdr.a_text |
344 | #endif /* no N_DATADDR */ |
345 | |
346 | /* Make COFF and non-COFF names for things a little more compatible |
347 | to reduce conditionals later. */ |
348 | |
349 | #ifdef COFF_FORMAT |
350 | #define a_magic magic |
351 | #endif |
352 | |
353 | #ifndef COFF_FORMAT |
354 | #define AOUTHDR struct exec |
355 | #endif |
356 | |
357 | extern char *sys_siglist[]; |
358 | |
359 | /* Hook for `exec_file_command' command to call. */ |
360 | |
361 | void (*exec_file_display_hook) (); |
362 | |
363 | /* File names of core file and executable file. */ |
364 | |
365 | extern char *corefile; |
366 | extern char *execfile; |
367 | |
368 | /* Descriptors on which core file and executable file are open. |
369 | Note that the execchan is closed when an inferior is created |
370 | and reopened if the inferior dies or is killed. */ |
371 | |
372 | extern int corechan; |
373 | extern int execchan; |
374 | |
375 | /* Last modification time of executable file. |
376 | Also used in source.c to compare against mtime of a source file. */ |
377 | |
378 | int exec_mtime; |
379 | |
380 | /* Virtual addresses of bounds of the two areas of memory in the core file. */ |
381 | |
382 | extern CORE_ADDR data_start; |
383 | extern CORE_ADDR data_end; |
384 | extern CORE_ADDR stack_start; |
385 | extern CORE_ADDR stack_end; |
386 | |
387 | /* Virtual addresses of bounds of two areas of memory in the exec file. |
388 | Note that the data area in the exec file is used only when there is no core file. */ |
389 | |
390 | extern CORE_ADDR text_start; |
391 | extern CORE_ADDR text_end; |
392 | |
393 | extern CORE_ADDR exec_data_start; |
394 | extern CORE_ADDR exec_data_end; |
395 | |
396 | /* Address in executable file of start of text area data. */ |
397 | |
398 | extern int text_offset; |
399 | |
400 | /* Address in executable file of start of data area data. */ |
401 | |
402 | extern int exec_data_offset; |
403 | |
404 | /* Address in core file of start of data area data. */ |
405 | |
406 | extern int data_offset; |
407 | |
408 | /* Address in core file of start of stack area data. */ |
409 | |
410 | extern int stack_offset; |
411 | |
412 | #ifdef COFF_FORMAT |
413 | /* various coff data structures */ |
414 | |
415 | extern FILHDR file_hdr; |
416 | extern SCNHDR text_hdr; |
417 | extern SCNHDR data_hdr; |
418 | |
419 | #endif /* not COFF_FORMAT */ |
420 | |
421 | /* a.out header saved in core file. */ |
422 | |
423 | extern AOUTHDR core_aouthdr; |
424 | |
425 | /* a.out header of exec file. */ |
426 | |
427 | extern AOUTHDR exec_aouthdr; |
428 | |
429 | extern void validate_files (); |
430 | unsigned int register_addr (); |
431 | |
432 | core_file_command (filename, from_tty) |
433 | char *filename; |
434 | int from_tty; |
435 | { |
436 | int val; |
437 | extern char registers[]; |
438 | |
439 | /* Discard all vestiges of any previous core file |
440 | and mark data and stack spaces as empty. */ |
441 | |
442 | if (corefile) |
443 | free (corefile); |
444 | corefile = 0; |
445 | |
446 | if (corechan >= 0) |
447 | close (corechan); |
448 | corechan = -1; |
449 | |
450 | data_start = 0; |
451 | data_end = 0; |
452 | stack_start = STACK_END_ADDR; |
453 | stack_end = STACK_END_ADDR; |
454 | |
455 | /* Now, if a new core file was specified, open it and digest it. */ |
456 | |
457 | if (filename) |
458 | { |
459 | filename = tilde_expand (filename); |
460 | make_cleanup (free, filename); |
461 | |
462 | if (have_inferior_p ()) |
463 | error ("To look at a core file, you must kill the inferior with \"kill\"."); |
464 | corechan = open (filename, O_RDONLY, 0); |
465 | if (corechan < 0) |
466 | perror_with_name (filename); |
467 | /* 4.2-style (and perhaps also sysV-style) core dump file. */ |
468 | { |
469 | struct user u; |
470 | int reg_offset; |
471 | |
472 | val = myread (corechan, &u, sizeof u); |
473 | if (val < 0) |
474 | perror_with_name (filename); |
475 | data_start = exec_data_start; |
476 | |
477 | data_end = data_start + NBPG * (u.u_dsize - u.u_tsize); |
478 | stack_start = stack_end - NBPG * u.u_ssize; |
479 | data_offset = NBPG * UPAGES; |
480 | stack_offset = ctob(UPAGES + u.u_dsize - u.u_tsize); |
481 | reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; |
482 | printf("u.u_tsize= %#x, u.u_dsize= %#x, u.u_ssize= %#x, stack_off= %#x\n", |
483 | u.u_tsize, u.u_dsize, u.u_ssize, stack_offset); |
484 | |
485 | core_aouthdr.a_magic = 0; |
486 | |
487 | /* Read the register values out of the core file and store |
488 | them where `read_register' will find them. */ |
489 | |
490 | { |
491 | register int regno; |
492 | |
493 | for (regno = 0; regno < NUM_REGS; regno++) |
494 | { |
495 | char buf[MAX_REGISTER_RAW_SIZE]; |
496 | |
497 | val = lseek (corechan, register_addr (regno, reg_offset), 0); |
498 | if (val < 0) |
499 | perror_with_name (filename); |
500 | |
501 | val = myread (corechan, buf, sizeof buf); |
502 | if (val < 0) |
503 | perror_with_name (filename); |
504 | supply_register (regno, buf); |
505 | } |
506 | } |
507 | } |
508 | if (filename[0] == '/') |
509 | corefile = savestring (filename, strlen (filename)); |
510 | else |
511 | { |
512 | corefile = concat (current_directory, "/", filename); |
513 | } |
514 | |
515 | set_current_frame(create_new_frame(read_register(FP_REGNUM), |
516 | read_pc())); |
517 | /* set_current_frame (read_register (FP_REGNUM));*/ |
518 | select_frame (get_current_frame (), 0); |
519 | validate_files (); |
520 | } |
521 | else if (from_tty) |
522 | printf ("No core file now.\n"); |
523 | } |
524 | |
525 | exec_file_command (filename, from_tty) |
526 | char *filename; |
527 | int from_tty; |
528 | { |
529 | int val; |
530 | |
531 | /* Eliminate all traces of old exec file. |
532 | Mark text segment as empty. */ |
533 | |
534 | if (execfile) |
535 | free (execfile); |
536 | execfile = 0; |
537 | data_start = 0; |
538 | data_end -= exec_data_start; |
539 | text_start = 0; |
540 | text_end = 0; |
541 | exec_data_start = 0; |
542 | exec_data_end = 0; |
543 | if (execchan >= 0) |
544 | close (execchan); |
545 | execchan = -1; |
546 | |
547 | /* Now open and digest the file the user requested, if any. */ |
548 | |
549 | if (filename) |
550 | { |
551 | filename = tilde_expand (filename); |
552 | make_cleanup (free, filename); |
553 | |
554 | execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, |
555 | &execfile); |
556 | if (execchan < 0) |
557 | perror_with_name (filename); |
558 | |
559 | #ifdef COFF_FORMAT |
560 | { |
561 | int aout_hdrsize; |
562 | int num_sections; |
563 | |
564 | if (read_file_hdr (execchan, &file_hdr) < 0) |
565 | error ("\"%s\": not in executable format.", execfile); |
566 | |
567 | aout_hdrsize = file_hdr.f_opthdr; |
568 | num_sections = file_hdr.f_nscns; |
569 | |
570 | if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) |
571 | error ("\"%s\": can't read optional aouthdr", execfile); |
572 | |
7a67dd45 |
573 | if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, |
574 | aout_hdrsize) < 0) |
4187119d |
575 | error ("\"%s\": can't read text section header", execfile); |
576 | |
7a67dd45 |
577 | if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, |
578 | aout_hdrsize) < 0) |
4187119d |
579 | error ("\"%s\": can't read data section header", execfile); |
580 | |
581 | text_start = exec_aouthdr.text_start; |
582 | text_end = text_start + exec_aouthdr.tsize; |
583 | text_offset = text_hdr.s_scnptr; |
584 | exec_data_start = exec_aouthdr.data_start; |
585 | exec_data_end = exec_data_start + exec_aouthdr.dsize; |
586 | exec_data_offset = data_hdr.s_scnptr; |
587 | data_start = exec_data_start; |
588 | data_end += exec_data_start; |
589 | exec_mtime = file_hdr.f_timdat; |
590 | } |
591 | #else /* not COFF_FORMAT */ |
592 | { |
593 | struct stat st_exec; |
594 | |
595 | val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); |
596 | |
597 | if (val < 0) |
598 | perror_with_name (filename); |
599 | |
600 | text_start = N_ADDRADJ(exec_aouthdr); |
601 | exec_data_start = round(exec_aouthdr.a_text, NBPG*CLSIZE); |
602 | text_offset = N_TXTOFF (exec_aouthdr); |
603 | exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; |
604 | text_end = exec_aouthdr.a_text; |
605 | exec_data_end = exec_data_start + exec_aouthdr.a_data; |
606 | data_start = exec_data_start; |
607 | data_end = data_start + exec_aouthdr.a_data; |
608 | exec_data_offset = N_TXTOFF(exec_aouthdr); |
609 | fstat (execchan, &st_exec); |
610 | exec_mtime = st_exec.st_mtime; |
611 | } |
612 | #endif /* not COFF_FORMAT */ |
613 | |
614 | validate_files (); |
615 | } |
616 | else if (from_tty) |
617 | printf ("No exec file now.\n"); |
618 | |
619 | /* Tell display code (if any) about the changed file name. */ |
620 | if (exec_file_display_hook) |
621 | (*exec_file_display_hook) (filename); |
622 | } |
623 | |
624 | /* rounds 'one' up to divide evenly by 'two' */ |
625 | |
626 | int |
627 | round(one,two) |
628 | register int one, two; |
629 | |
630 | { |
631 | register int temp; |
632 | temp = (one/two)*two; |
633 | if (one != temp) { |
634 | temp += two; |
635 | } |
636 | return temp; |
637 | } |
638 | |
639 | |
640 | static CORE_ADDR codestream_next_addr; |
641 | static CORE_ADDR codestream_addr; |
642 | static unsigned char codestream_buf[sizeof (int)]; |
643 | static int codestream_off; |
644 | static int codestream_cnt; |
645 | |
646 | #define codestream_tell() (codestream_addr + codestream_off) |
647 | #define codestream_peek() (codestream_cnt == 0 ? \ |
648 | codestream_fill(1): codestream_buf[codestream_off]) |
649 | #define codestream_get() (codestream_cnt-- == 0 ? \ |
650 | codestream_fill(0) : codestream_buf[codestream_off++]) |
651 | |
652 | |
653 | static unsigned char |
654 | codestream_fill (peek_flag) |
655 | { |
656 | codestream_addr = codestream_next_addr; |
657 | codestream_next_addr += sizeof (int); |
658 | codestream_off = 0; |
659 | codestream_cnt = sizeof (int); |
660 | read_memory (codestream_addr, |
661 | (unsigned char *)codestream_buf, |
662 | sizeof (int)); |
663 | |
664 | if (peek_flag) |
665 | return (codestream_peek()); |
666 | else |
667 | return (codestream_get()); |
668 | } |
669 | |
670 | static void |
671 | codestream_seek (place) |
672 | { |
673 | codestream_next_addr = place & -sizeof (int); |
674 | codestream_cnt = 0; |
675 | codestream_fill (1); |
676 | while (codestream_tell() != place) |
677 | codestream_get (); |
678 | } |
679 | |
680 | static void |
681 | codestream_read (buf, count) |
682 | unsigned char *buf; |
683 | { |
684 | unsigned char *p; |
685 | int i; |
686 | p = buf; |
687 | for (i = 0; i < count; i++) |
688 | *p++ = codestream_get (); |
689 | } |
690 | |
691 | /* |
692 | * Following macro translates i386 opcode register numbers to Symmetry |
693 | * register numbers. This is used by FRAME_FIND_SAVED_REGS. |
694 | * |
695 | * %eax %ecx %edx %ebx %esp %ebp %esi %edi |
696 | * i386 0 1 2 3 4 5 6 7 |
697 | * Symmetry 0 2 1 5 14 15 6 7 |
698 | * |
699 | */ |
700 | #define I386_REGNO_TO_SYMMETRY(n) \ |
701 | ((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?5 :(n)==4?14 :(n)==5?15 :(n)) |
702 | |
703 | /* from i386-dep.c */ |
704 | i386_frame_find_saved_regs (fip, fsrp) |
705 | struct frame_info *fip; |
706 | struct frame_saved_regs *fsrp; |
707 | { |
708 | unsigned long locals; |
709 | unsigned char *p; |
710 | unsigned char op; |
711 | CORE_ADDR dummy_bottom; |
712 | CORE_ADDR adr; |
713 | int i; |
714 | |
715 | bzero (fsrp, sizeof *fsrp); |
716 | |
717 | /* if frame is the end of a dummy, compute where the |
718 | * beginning would be |
719 | */ |
720 | dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH; |
721 | |
722 | /* check if the PC is in the stack, in a dummy frame */ |
723 | if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) |
724 | { |
725 | /* all regs were saved by push_call_dummy () */ |
726 | adr = fip->frame - 4; |
727 | for (i = 0; i < NUM_REGS; i++) |
728 | { |
729 | fsrp->regs[i] = adr; |
730 | adr -= 4; |
731 | } |
732 | return; |
733 | } |
734 | |
735 | locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); |
736 | |
737 | if (locals >= 0) |
738 | { |
739 | adr = fip->frame - 4 - locals; |
740 | for (i = 0; i < 8; i++) |
741 | { |
742 | op = codestream_get (); |
743 | if (op < 0x50 || op > 0x57) |
744 | break; |
745 | fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; |
746 | adr -= 4; |
747 | } |
748 | } |
749 | |
750 | fsrp->regs[PC_REGNUM] = fip->frame + 4; |
751 | fsrp->regs[FP_REGNUM] = fip->frame; |
752 | } |
753 | |
754 | /* from i386-dep.c */ |
755 | static |
756 | print_387_control_word (control) |
757 | unsigned short control; |
758 | { |
759 | printf ("control 0x%04x: ", control); |
760 | printf ("compute to "); |
761 | switch ((control >> 8) & 3) |
762 | { |
763 | case 0: printf ("24 bits; "); break; |
764 | case 1: printf ("(bad); "); break; |
765 | case 2: printf ("53 bits; "); break; |
766 | case 3: printf ("64 bits; "); break; |
767 | } |
768 | printf ("round "); |
769 | switch ((control >> 10) & 3) |
770 | { |
771 | case 0: printf ("NEAREST; "); break; |
772 | case 1: printf ("DOWN; "); break; |
773 | case 2: printf ("UP; "); break; |
774 | case 3: printf ("CHOP; "); break; |
775 | } |
776 | if (control & 0x3f) |
777 | { |
778 | printf ("mask:"); |
779 | if (control & 0x0001) printf (" INVALID"); |
780 | if (control & 0x0002) printf (" DENORM"); |
781 | if (control & 0x0004) printf (" DIVZ"); |
782 | if (control & 0x0008) printf (" OVERF"); |
783 | if (control & 0x0010) printf (" UNDERF"); |
784 | if (control & 0x0020) printf (" LOS"); |
785 | printf (";"); |
786 | } |
787 | printf ("\n"); |
788 | if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", |
789 | control & 0xe080); |
790 | } |
791 | |
792 | static |
793 | print_387_status_word (status) |
794 | unsigned short status; |
795 | { |
796 | printf ("status %#04x: ", status); |
797 | if (status & 0xff) { |
798 | printf ("exceptions:"); /* exception names match <machine/fpu.h> */ |
799 | if (status & 0x0001) printf (" FLTINV"); |
800 | if (status & 0x0002) printf (" FLTDEN"); |
801 | if (status & 0x0004) printf (" FLTDIV"); |
802 | if (status & 0x0008) printf (" FLTOVF"); |
803 | if (status & 0x0010) printf (" FLTUND"); |
804 | if (status & 0x0020) printf (" FLTPRE"); |
805 | if (status & 0x0040) printf (" FLTSTK"); |
806 | printf ("; "); |
807 | } |
808 | printf ("flags: %d%d%d%d; ", |
809 | (status & 0x4000) != 0, |
810 | (status & 0x0400) != 0, |
811 | (status & 0x0200) != 0, |
812 | (status & 0x0100) != 0); |
813 | |
814 | printf ("top %d\n", (status >> 11) & 7); |
815 | } |
816 | |
817 | static |
818 | print_fpu_status(ep) |
819 | struct pt_regset ep; |
820 | |
821 | { |
822 | int i; |
823 | int bothstatus; |
824 | int top; |
825 | int fpreg; |
826 | unsigned char *p; |
827 | |
828 | printf("80387:"); |
829 | if (ep.pr_fpu.fpu_ip == 0) { |
830 | printf(" not in use.\n"); |
831 | return; |
832 | } else { |
833 | printf("\n"); |
834 | } |
835 | if (ep.pr_fpu.fpu_status != 0) { |
836 | print_387_status_word (ep.pr_fpu.fpu_status); |
837 | } |
838 | print_387_control_word (ep.pr_fpu.fpu_control); |
839 | printf ("last exception: "); |
840 | printf ("opcode 0x%x; ", ep.pr_fpu.fpu_rsvd4); |
841 | printf ("pc 0x%x:0x%x; ", ep.pr_fpu.fpu_cs, ep.pr_fpu.fpu_ip); |
842 | printf ("operand 0x%x:0x%x\n", ep.pr_fpu.fpu_data_offset, ep.pr_fpu.fpu_op_sel); |
843 | |
844 | top = (ep.pr_fpu.fpu_status >> 11) & 7; |
845 | |
846 | printf ("regno tag msb lsb value\n"); |
847 | for (fpreg = 7; fpreg >= 0; fpreg--) |
848 | { |
849 | double val; |
850 | |
851 | printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); |
852 | |
853 | switch ((ep.pr_fpu.fpu_tag >> (fpreg * 2)) & 3) |
854 | { |
855 | case 0: printf ("valid "); break; |
856 | case 1: printf ("zero "); break; |
857 | case 2: printf ("trap "); break; |
858 | case 3: printf ("empty "); break; |
859 | } |
860 | for (i = 9; i >= 0; i--) |
861 | printf ("%02x", ep.pr_fpu.fpu_stack[fpreg][i]); |
862 | |
863 | i387_to_double (ep.pr_fpu.fpu_stack[fpreg], (char *)&val); |
864 | printf (" %g\n", val); |
865 | } |
866 | if (ep.pr_fpu.fpu_rsvd1) |
867 | printf ("warning: rsvd1 is 0x%x\n", ep.pr_fpu.fpu_rsvd1); |
868 | if (ep.pr_fpu.fpu_rsvd2) |
869 | printf ("warning: rsvd2 is 0x%x\n", ep.pr_fpu.fpu_rsvd2); |
870 | if (ep.pr_fpu.fpu_rsvd3) |
871 | printf ("warning: rsvd3 is 0x%x\n", ep.pr_fpu.fpu_rsvd3); |
872 | if (ep.pr_fpu.fpu_rsvd5) |
873 | printf ("warning: rsvd5 is 0x%x\n", ep.pr_fpu.fpu_rsvd5); |
874 | } |
875 | |
876 | |
877 | print_1167_control_word(pcr) |
878 | unsigned int pcr; |
879 | |
880 | { |
881 | int pcr_tmp; |
882 | |
883 | pcr_tmp = pcr & FPA_PCR_MODE; |
884 | printf("\tMODE= %#x; RND= %#x ", pcr_tmp, pcr_tmp & 12); |
885 | switch (pcr_tmp & 12) { |
886 | case 0: |
887 | printf("RN (Nearest Value)"); |
888 | break; |
889 | case 1: |
890 | printf("RZ (Zero)"); |
891 | break; |
892 | case 2: |
893 | printf("RP (Positive Infinity)"); |
894 | break; |
895 | case 3: |
896 | printf("RM (Negative Infinity)"); |
897 | break; |
898 | } |
899 | printf("; IRND= %d ", pcr_tmp & 2); |
900 | if (0 == pcr_tmp & 2) { |
901 | printf("(same as RND)\n"); |
902 | } else { |
903 | printf("(toward zero)\n"); |
904 | } |
905 | pcr_tmp = pcr & FPA_PCR_EM; |
906 | printf("\tEM= %#x", pcr_tmp); |
907 | if (pcr_tmp & FPA_PCR_EM_DM) printf(" DM"); |
908 | if (pcr_tmp & FPA_PCR_EM_UOM) printf(" UOM"); |
909 | if (pcr_tmp & FPA_PCR_EM_PM) printf(" PM"); |
910 | if (pcr_tmp & FPA_PCR_EM_UM) printf(" UM"); |
911 | if (pcr_tmp & FPA_PCR_EM_OM) printf(" OM"); |
912 | if (pcr_tmp & FPA_PCR_EM_ZM) printf(" ZM"); |
913 | if (pcr_tmp & FPA_PCR_EM_IM) printf(" IM"); |
914 | printf("\n"); |
915 | pcr_tmp = FPA_PCR_CC; |
916 | printf("\tCC= %#x", pcr_tmp); |
917 | if (pcr_tmp & FPA_PCR_20MHZ) printf(" 20MHZ"); |
918 | if (pcr_tmp & FPA_PCR_CC_Z) printf(" Z"); |
919 | if (pcr_tmp & FPA_PCR_CC_C2) printf(" C2"); |
920 | if (pcr_tmp & FPA_PCR_CC_C1) printf(" C1"); |
921 | switch (pcr_tmp) { |
922 | case FPA_PCR_CC_Z: |
923 | printf(" (Equal)"); |
924 | break; |
925 | case FPA_PCR_CC_C1: |
926 | printf(" (Less than)"); |
927 | break; |
928 | case 0: |
929 | printf(" (Greater than)"); |
930 | break; |
931 | case FPA_PCR_CC_Z | FPA_PCR_CC_C1 | FPA_PCR_CC_C2: |
932 | printf(" (Unordered)"); |
933 | break; |
934 | default: |
935 | printf(" (Undefined)"); |
936 | break; |
937 | } |
938 | printf("\n"); |
939 | pcr_tmp = pcr & FPA_PCR_AE; |
940 | printf("\tAE= %#x", pcr_tmp); |
941 | if (pcr_tmp & FPA_PCR_AE_DE) printf(" DE"); |
942 | if (pcr_tmp & FPA_PCR_AE_UOE) printf(" UOE"); |
943 | if (pcr_tmp & FPA_PCR_AE_PE) printf(" PE"); |
944 | if (pcr_tmp & FPA_PCR_AE_UE) printf(" UE"); |
945 | if (pcr_tmp & FPA_PCR_AE_OE) printf(" OE"); |
946 | if (pcr_tmp & FPA_PCR_AE_ZE) printf(" ZE"); |
947 | if (pcr_tmp & FPA_PCR_AE_EE) printf(" EE"); |
948 | if (pcr_tmp & FPA_PCR_AE_IE) printf(" IE"); |
949 | printf("\n"); |
950 | } |
951 | |
952 | print_1167_regs(regs) |
953 | long regs[FPA_NREGS]; |
954 | |
955 | { |
956 | int i; |
957 | |
958 | union { |
959 | double d; |
960 | long l[2]; |
961 | } xd; |
962 | union { |
963 | float f; |
964 | long l; |
965 | } xf; |
966 | |
967 | |
968 | for (i = 0; i < FPA_NREGS; i++) { |
969 | xf.l = regs[i]; |
970 | printf("%%fp%d: raw= %#x, single= %f", i+1, regs[i], xf.f); |
971 | if (!(i & 1)) { |
972 | printf("\n"); |
973 | } else { |
974 | xd.l[1] = regs[i]; |
975 | xd.l[0] = regs[i+1]; |
976 | printf(", double= %f\n", xd.d); |
977 | } |
978 | } |
979 | } |
980 | |
981 | print_fpa_status(ep) |
982 | struct pt_regset ep; |
983 | |
984 | { |
985 | |
986 | printf("WTL 1167:"); |
987 | if (ep.pr_fpa.fpa_pcr !=0) { |
988 | printf("\n"); |
989 | print_1167_control_word(ep.pr_fpa.fpa_pcr); |
990 | print_1167_regs(ep.pr_fpa.fpa_regs); |
991 | } else { |
992 | printf(" not in use.\n"); |
993 | } |
994 | } |
995 | |
996 | i386_float_info () |
997 | |
998 | { |
999 | char ubuf[UPAGES*NBPG]; |
1000 | struct pt_regset regset; |
1001 | extern int corechan; |
1002 | |
1003 | if (have_inferior_p()) { |
1004 | call_ptrace(XPT_RREGS, inferior_pid, ®set, 0); |
1005 | } else { |
1006 | if (lseek (corechan, 0, 0) < 0) { |
1007 | perror ("seek on core file"); |
1008 | } |
1009 | if (myread (corechan, ubuf, UPAGES*NBPG) < 0) { |
1010 | perror ("read on core file"); |
1011 | } |
1012 | /* only interested in the floating point registers */ |
1013 | regset.pr_fpu = ((struct user *) ubuf)->u_fpusave; |
1014 | regset.pr_fpa = ((struct user *) ubuf)->u_fpasave; |
1015 | } |
1016 | print_fpu_status(regset); |
1017 | print_fpa_status(regset); |
1018 | } |
1019 | |
1020 | i387_to_double (from, to) |
1021 | char *from; |
1022 | char *to; |
1023 | { |
1024 | long *lp; |
1025 | /* push extended mode on 387 stack, then pop in double mode |
1026 | * |
1027 | * first, set exception masks so no error is generated - |
1028 | * number will be rounded to inf or 0, if necessary |
1029 | */ |
1030 | asm ("pushl %eax"); /* grab a stack slot */ |
1031 | asm ("fstcw (%esp)"); /* get 387 control word */ |
1032 | asm ("movl (%esp),%eax"); /* save old value */ |
1033 | asm ("orl $0x3f,%eax"); /* mask all exceptions */ |
1034 | asm ("pushl %eax"); |
1035 | asm ("fldcw (%esp)"); /* load new value into 387 */ |
1036 | |
1037 | asm ("movl 8(%ebp),%eax"); |
1038 | asm ("fldt (%eax)"); /* push extended number on 387 stack */ |
1039 | asm ("fwait"); |
1040 | asm ("movl 12(%ebp),%eax"); |
1041 | asm ("fstpl (%eax)"); /* pop double */ |
1042 | asm ("fwait"); |
1043 | |
1044 | asm ("popl %eax"); /* flush modified control word */ |
1045 | asm ("fnclex"); /* clear exceptions */ |
1046 | asm ("fldcw (%esp)"); /* restore original control word */ |
1047 | asm ("popl %eax"); /* flush saved copy */ |
1048 | } |
1049 | |
1050 | double_to_i387 (from, to) |
1051 | char *from; |
1052 | char *to; |
1053 | { |
1054 | /* push double mode on 387 stack, then pop in extended mode |
1055 | * no errors are possible because every 64-bit pattern |
1056 | * can be converted to an extended |
1057 | */ |
1058 | asm ("movl 8(%ebp),%eax"); |
1059 | asm ("fldl (%eax)"); |
1060 | asm ("fwait"); |
1061 | asm ("movl 12(%ebp),%eax"); |
1062 | asm ("fstpt (%eax)"); |
1063 | asm ("fwait"); |
1064 | } |
1065 | |
1066 | static long |
1067 | i386_get_frame_setup (pc) |
1068 | { |
1069 | unsigned char op; |
1070 | |
1071 | codestream_seek (pc); |
1072 | |
1073 | i386_follow_jump (); |
1074 | |
1075 | op = codestream_get (); |
1076 | |
1077 | if (op == 0x58) /* popl %eax */ |
1078 | { |
1079 | /* |
1080 | * this function must start with |
1081 | * |
1082 | * popl %eax 0x58 |
1083 | * xchgl %eax, (%esp) 0x87 0x04 0x24 |
1084 | * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 |
1085 | * |
1086 | * (the system 5 compiler puts out the second xchg |
1087 | * inst, and the assembler doesn't try to optimize it, |
1088 | * so the 'sib' form gets generated) |
1089 | * |
1090 | * this sequence is used to get the address of the return |
1091 | * buffer for a function that returns a structure |
1092 | */ |
1093 | int pos; |
1094 | unsigned char buf[4]; |
1095 | static unsigned char proto1[3] = { 0x87,0x04,0x24 }; |
1096 | static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; |
1097 | pos = codestream_tell (); |
1098 | codestream_read (buf, 4); |
1099 | if (bcmp (buf, proto1, 3) == 0) |
1100 | pos += 3; |
1101 | else if (bcmp (buf, proto2, 4) == 0) |
1102 | pos += 4; |
1103 | |
1104 | codestream_seek (pos); |
1105 | op = codestream_get (); /* update next opcode */ |
1106 | } |
1107 | |
1108 | if (op == 0x55) /* pushl %esp */ |
1109 | { |
1110 | if (codestream_get () != 0x8b) /* movl %esp, %ebp (2bytes) */ |
1111 | return (-1); |
1112 | if (codestream_get () != 0xec) |
1113 | return (-1); |
1114 | /* |
1115 | * check for stack adjustment |
1116 | * |
1117 | * subl $XXX, %esp |
1118 | * |
1119 | * note: you can't subtract a 16 bit immediate |
1120 | * from a 32 bit reg, so we don't have to worry |
1121 | * about a data16 prefix |
1122 | */ |
1123 | op = codestream_peek (); |
1124 | if (op == 0x83) /* subl with 8 bit immed */ |
1125 | { |
1126 | codestream_get (); |
1127 | if (codestream_get () != 0xec) |
1128 | return (-1); |
1129 | /* subl with signed byte immediate |
1130 | * (though it wouldn't make sense to be negative) |
1131 | */ |
1132 | return (codestream_get()); |
1133 | } |
1134 | else if (op == 0x81) /* subl with 32 bit immed */ |
1135 | { |
1136 | int locals; |
1137 | if (codestream_get () != 0xec) |
1138 | return (-1); |
1139 | /* subl with 32 bit immediate */ |
1140 | codestream_read ((unsigned char *)&locals, 4); |
1141 | return (locals); |
1142 | } |
1143 | else |
1144 | { |
1145 | return (0); |
1146 | } |
1147 | } |
1148 | else if (op == 0xc8) |
1149 | { |
1150 | /* enter instruction: arg is 16 unsigned immed */ |
1151 | unsigned short slocals; |
1152 | codestream_read ((unsigned char *)&slocals, 2); |
1153 | codestream_get (); /* flush final byte of enter instruction */ |
1154 | return (slocals); |
1155 | } |
1156 | return (-1); |
1157 | } |
1158 | |
1159 | /* next instruction is a jump, move to target */ |
1160 | static |
1161 | i386_follow_jump () |
1162 | { |
1163 | int long_delta; |
1164 | short short_delta; |
1165 | char byte_delta; |
1166 | int data16; |
1167 | int pos; |
1168 | |
1169 | pos = codestream_tell (); |
1170 | |
1171 | data16 = 0; |
1172 | if (codestream_peek () == 0x66) |
1173 | { |
1174 | codestream_get (); |
1175 | data16 = 1; |
1176 | } |
1177 | |
1178 | switch (codestream_get ()) |
1179 | { |
1180 | case 0xe9: |
1181 | /* relative jump: if data16 == 0, disp32, else disp16 */ |
1182 | if (data16) |
1183 | { |
1184 | codestream_read ((unsigned char *)&short_delta, 2); |
1185 | pos += short_delta + 3; /* include size of jmp inst */ |
1186 | } |
1187 | else |
1188 | { |
1189 | codestream_read ((unsigned char *)&long_delta, 4); |
1190 | pos += long_delta + 5; |
1191 | } |
1192 | break; |
1193 | case 0xeb: |
1194 | /* relative jump, disp8 (ignore data16) */ |
1195 | codestream_read ((unsigned char *)&byte_delta, 1); |
1196 | pos += byte_delta + 2; |
1197 | break; |
1198 | } |
1199 | codestream_seek (pos + data16); |
1200 | } |
1201 | |
1202 | /* return pc of first real instruction */ |
1203 | /* from i386-dep.c */ |
1204 | |
1205 | i386_skip_prologue (pc) |
1206 | { |
1207 | unsigned char op; |
1208 | int i; |
1209 | |
1210 | if (i386_get_frame_setup (pc) < 0) |
1211 | return (pc); |
1212 | |
1213 | /* found valid frame setup - codestream now points to |
1214 | * start of push instructions for saving registers |
1215 | */ |
1216 | |
1217 | /* skip over register saves */ |
1218 | for (i = 0; i < 8; i++) |
1219 | { |
1220 | op = codestream_peek (); |
1221 | /* break if not pushl inst */ |
1222 | if (op < 0x50 || op > 0x57) |
1223 | break; |
1224 | codestream_get (); |
1225 | } |
1226 | |
1227 | i386_follow_jump (); |
1228 | |
1229 | return (codestream_tell ()); |
1230 | } |
1231 | |
1232 | symmetry_extract_return_value(type, regbuf, valbuf) |
1233 | struct type *type; |
1234 | char *regbuf; |
1235 | char *valbuf; |
1236 | { |
1237 | union { |
1238 | double d; |
1239 | int l[2]; |
1240 | } xd; |
1241 | int i; |
1242 | float f; |
1243 | |
1244 | if (TYPE_CODE_FLT == TYPE_CODE(type)) { |
1245 | for (i = 0; i < misc_function_count; i++) { |
1246 | if (!strcmp(misc_function_vector[i].name, "1167_flt")) |
1247 | break; |
1248 | } |
1249 | if (i < misc_function_count) { |
1250 | /* found "1167_flt" means 1167, %fp2-%fp3 */ |
1251 | /* float & double; 19= %fp2, 20= %fp3 */ |
1252 | /* no single precision on 1167 */ |
1253 | xd.l[1] = *((int *)®buf[REGISTER_BYTE(19)]); |
1254 | xd.l[0] = *((int *)®buf[REGISTER_BYTE(20)]); |
1255 | switch (TYPE_LENGTH(type)) { |
1256 | case 4: |
1257 | f = (float) xd.d; |
1258 | bcopy(&f, valbuf, TYPE_LENGTH(type)); |
1259 | break; |
1260 | case 8: |
1261 | bcopy(&xd.d, valbuf, TYPE_LENGTH(type)); |
1262 | break; |
1263 | default: |
1264 | error("Unknown floating point size"); |
1265 | break; |
1266 | } |
1267 | } else { |
1268 | /* 387 %st(0), gcc uses this */ |
1269 | i387_to_double(((int *)®buf[REGISTER_BYTE(3)]), |
1270 | &xd.d); |
1271 | switch (TYPE_LENGTH(type)) { |
1272 | case 4: /* float */ |
1273 | f = (float) xd.d; |
1274 | bcopy(&f, valbuf, 4); |
1275 | break; |
1276 | case 8: /* double */ |
1277 | bcopy(&xd.d, valbuf, 8); |
1278 | break; |
1279 | default: |
1280 | error("Unknown floating point size"); |
1281 | break; |
1282 | } |
1283 | } |
1284 | } else { |
1285 | bcopy (regbuf, valbuf, TYPE_LENGTH (type)); |
1286 | } |
1287 | } |