]>
Commit | Line | Data |
---|---|---|
07d021a6 JG |
1 | /* Sequent Symmetry target interface, for GDB when running under Unix. |
2 | Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GDB. | |
5 | ||
99a7de40 | 6 | This program is free software; you can redistribute it and/or modify |
07d021a6 | 7 | it under the terms of the GNU General Public License as published by |
99a7de40 JG |
8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | |
07d021a6 | 10 | |
99a7de40 | 11 | This program is distributed in the hope that it will be useful, |
07d021a6 JG |
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 | |
99a7de40 JG |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
07d021a6 JG |
19 | |
20 | /* many 387-specific items of use taken from i386-dep.c */ | |
21 | ||
07d021a6 | 22 | #include "defs.h" |
07d021a6 JG |
23 | #include "frame.h" |
24 | #include "inferior.h" | |
25 | #include "symtab.h" | |
26 | ||
27 | #include <signal.h> | |
28 | #include <sys/param.h> | |
29 | #include <sys/user.h> | |
30 | #include <sys/dir.h> | |
31 | #include <sys/ioctl.h> | |
32 | #include <sys/stat.h> | |
33 | #include "gdbcore.h" | |
34 | #include <fcntl.h> | |
35 | ||
36 | static long i386_get_frame_setup (); | |
37 | static i386_follow_jump (); | |
38 | ||
39 | #include <sgtty.h> | |
40 | #define TERMINAL struct sgttyb | |
41 | ||
07d021a6 JG |
42 | /* rounds 'one' up to divide evenly by 'two' */ |
43 | ||
44 | int | |
45 | round(one,two) | |
46 | register int one, two; | |
47 | ||
48 | { | |
49 | register int temp; | |
50 | temp = (one/two)*two; | |
51 | if (one != temp) { | |
52 | temp += two; | |
53 | } | |
54 | return temp; | |
55 | } | |
56 | ||
57 | ||
58 | static CORE_ADDR codestream_next_addr; | |
59 | static CORE_ADDR codestream_addr; | |
60 | static unsigned char codestream_buf[sizeof (int)]; | |
61 | static int codestream_off; | |
62 | static int codestream_cnt; | |
63 | ||
64 | #define codestream_tell() (codestream_addr + codestream_off) | |
65 | #define codestream_peek() (codestream_cnt == 0 ? \ | |
66 | codestream_fill(1): codestream_buf[codestream_off]) | |
67 | #define codestream_get() (codestream_cnt-- == 0 ? \ | |
68 | codestream_fill(0) : codestream_buf[codestream_off++]) | |
69 | ||
70 | ||
71 | static unsigned char | |
72 | codestream_fill (peek_flag) | |
73 | { | |
74 | codestream_addr = codestream_next_addr; | |
75 | codestream_next_addr += sizeof (int); | |
76 | codestream_off = 0; | |
77 | codestream_cnt = sizeof (int); | |
78 | read_memory (codestream_addr, | |
79 | (unsigned char *)codestream_buf, | |
80 | sizeof (int)); | |
81 | ||
82 | if (peek_flag) | |
83 | return (codestream_peek()); | |
84 | else | |
85 | return (codestream_get()); | |
86 | } | |
87 | ||
88 | static void | |
89 | codestream_seek (place) | |
90 | { | |
91 | codestream_next_addr = place & -sizeof (int); | |
92 | codestream_cnt = 0; | |
93 | codestream_fill (1); | |
94 | while (codestream_tell() != place) | |
95 | codestream_get (); | |
96 | } | |
97 | ||
98 | static void | |
99 | codestream_read (buf, count) | |
100 | unsigned char *buf; | |
101 | { | |
102 | unsigned char *p; | |
103 | int i; | |
104 | p = buf; | |
105 | for (i = 0; i < count; i++) | |
106 | *p++ = codestream_get (); | |
107 | } | |
108 | ||
109 | /* | |
110 | * Following macro translates i386 opcode register numbers to Symmetry | |
111 | * register numbers. This is used by FRAME_FIND_SAVED_REGS. | |
112 | * | |
113 | * %eax %ecx %edx %ebx %esp %ebp %esi %edi | |
114 | * i386 0 1 2 3 4 5 6 7 | |
115 | * Symmetry 0 2 1 5 14 15 6 7 | |
116 | * | |
117 | */ | |
118 | #define I386_REGNO_TO_SYMMETRY(n) \ | |
119 | ((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?5 :(n)==4?14 :(n)==5?15 :(n)) | |
120 | ||
121 | /* from i386-dep.c */ | |
122 | i386_frame_find_saved_regs (fip, fsrp) | |
123 | struct frame_info *fip; | |
124 | struct frame_saved_regs *fsrp; | |
125 | { | |
126 | unsigned long locals; | |
127 | unsigned char *p; | |
128 | unsigned char op; | |
129 | CORE_ADDR dummy_bottom; | |
130 | CORE_ADDR adr; | |
131 | int i; | |
132 | ||
56eec3c7 | 133 | memset (fsrp, 0, sizeof *fsrp); |
07d021a6 JG |
134 | |
135 | /* if frame is the end of a dummy, compute where the | |
136 | * beginning would be | |
137 | */ | |
138 | dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH; | |
139 | ||
140 | /* check if the PC is in the stack, in a dummy frame */ | |
141 | if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) | |
142 | { | |
143 | /* all regs were saved by push_call_dummy () */ | |
144 | adr = fip->frame - 4; | |
145 | for (i = 0; i < NUM_REGS; i++) | |
146 | { | |
147 | fsrp->regs[i] = adr; | |
148 | adr -= 4; | |
149 | } | |
150 | return; | |
151 | } | |
152 | ||
153 | locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); | |
154 | ||
155 | if (locals >= 0) | |
156 | { | |
157 | adr = fip->frame - 4 - locals; | |
158 | for (i = 0; i < 8; i++) | |
159 | { | |
160 | op = codestream_get (); | |
161 | if (op < 0x50 || op > 0x57) | |
162 | break; | |
163 | fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; | |
164 | adr -= 4; | |
165 | } | |
166 | } | |
167 | ||
168 | fsrp->regs[PC_REGNUM] = fip->frame + 4; | |
169 | fsrp->regs[FP_REGNUM] = fip->frame; | |
170 | } | |
171 | ||
172 | static long | |
173 | i386_get_frame_setup (pc) | |
174 | { | |
175 | unsigned char op; | |
176 | ||
177 | codestream_seek (pc); | |
178 | ||
179 | i386_follow_jump (); | |
180 | ||
181 | op = codestream_get (); | |
182 | ||
183 | if (op == 0x58) /* popl %eax */ | |
184 | { | |
185 | /* | |
186 | * this function must start with | |
187 | * | |
188 | * popl %eax 0x58 | |
189 | * xchgl %eax, (%esp) 0x87 0x04 0x24 | |
190 | * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 | |
191 | * | |
192 | * (the system 5 compiler puts out the second xchg | |
193 | * inst, and the assembler doesn't try to optimize it, | |
194 | * so the 'sib' form gets generated) | |
195 | * | |
196 | * this sequence is used to get the address of the return | |
197 | * buffer for a function that returns a structure | |
198 | */ | |
199 | int pos; | |
200 | unsigned char buf[4]; | |
201 | static unsigned char proto1[3] = { 0x87,0x04,0x24 }; | |
202 | static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; | |
203 | pos = codestream_tell (); | |
204 | codestream_read (buf, 4); | |
56eec3c7 | 205 | if (memcmp (buf, proto1, 3) == 0) |
07d021a6 | 206 | pos += 3; |
56eec3c7 | 207 | else if (memcmp (buf, proto2, 4) == 0) |
07d021a6 JG |
208 | pos += 4; |
209 | ||
210 | codestream_seek (pos); | |
211 | op = codestream_get (); /* update next opcode */ | |
212 | } | |
213 | ||
214 | if (op == 0x55) /* pushl %esp */ | |
215 | { | |
216 | if (codestream_get () != 0x8b) /* movl %esp, %ebp (2bytes) */ | |
217 | return (-1); | |
218 | if (codestream_get () != 0xec) | |
219 | return (-1); | |
220 | /* | |
221 | * check for stack adjustment | |
222 | * | |
223 | * subl $XXX, %esp | |
224 | * | |
225 | * note: you can't subtract a 16 bit immediate | |
226 | * from a 32 bit reg, so we don't have to worry | |
227 | * about a data16 prefix | |
228 | */ | |
229 | op = codestream_peek (); | |
230 | if (op == 0x83) /* subl with 8 bit immed */ | |
231 | { | |
232 | codestream_get (); | |
233 | if (codestream_get () != 0xec) | |
234 | return (-1); | |
235 | /* subl with signed byte immediate | |
236 | * (though it wouldn't make sense to be negative) | |
237 | */ | |
238 | return (codestream_get()); | |
239 | } | |
240 | else if (op == 0x81) /* subl with 32 bit immed */ | |
241 | { | |
242 | int locals; | |
243 | if (codestream_get () != 0xec) | |
244 | return (-1); | |
245 | /* subl with 32 bit immediate */ | |
246 | codestream_read ((unsigned char *)&locals, 4); | |
247 | return (locals); | |
248 | } | |
249 | else | |
250 | { | |
251 | return (0); | |
252 | } | |
253 | } | |
254 | else if (op == 0xc8) | |
255 | { | |
256 | /* enter instruction: arg is 16 unsigned immed */ | |
257 | unsigned short slocals; | |
258 | codestream_read ((unsigned char *)&slocals, 2); | |
259 | codestream_get (); /* flush final byte of enter instruction */ | |
260 | return (slocals); | |
261 | } | |
262 | return (-1); | |
263 | } | |
264 | ||
265 | /* next instruction is a jump, move to target */ | |
266 | static | |
267 | i386_follow_jump () | |
268 | { | |
269 | int long_delta; | |
270 | short short_delta; | |
271 | char byte_delta; | |
272 | int data16; | |
273 | int pos; | |
274 | ||
275 | pos = codestream_tell (); | |
276 | ||
277 | data16 = 0; | |
278 | if (codestream_peek () == 0x66) | |
279 | { | |
280 | codestream_get (); | |
281 | data16 = 1; | |
282 | } | |
283 | ||
284 | switch (codestream_get ()) | |
285 | { | |
286 | case 0xe9: | |
287 | /* relative jump: if data16 == 0, disp32, else disp16 */ | |
288 | if (data16) | |
289 | { | |
290 | codestream_read ((unsigned char *)&short_delta, 2); | |
291 | pos += short_delta + 3; /* include size of jmp inst */ | |
292 | } | |
293 | else | |
294 | { | |
295 | codestream_read ((unsigned char *)&long_delta, 4); | |
296 | pos += long_delta + 5; | |
297 | } | |
298 | break; | |
299 | case 0xeb: | |
300 | /* relative jump, disp8 (ignore data16) */ | |
301 | codestream_read ((unsigned char *)&byte_delta, 1); | |
302 | pos += byte_delta + 2; | |
303 | break; | |
304 | } | |
305 | codestream_seek (pos + data16); | |
306 | } | |
307 | ||
308 | /* return pc of first real instruction */ | |
309 | /* from i386-dep.c */ | |
310 | ||
311 | i386_skip_prologue (pc) | |
312 | { | |
313 | unsigned char op; | |
314 | int i; | |
315 | ||
316 | if (i386_get_frame_setup (pc) < 0) | |
317 | return (pc); | |
318 | ||
319 | /* found valid frame setup - codestream now points to | |
320 | * start of push instructions for saving registers | |
321 | */ | |
322 | ||
323 | /* skip over register saves */ | |
324 | for (i = 0; i < 8; i++) | |
325 | { | |
326 | op = codestream_peek (); | |
327 | /* break if not pushl inst */ | |
328 | if (op < 0x50 || op > 0x57) | |
329 | break; | |
330 | codestream_get (); | |
331 | } | |
332 | ||
333 | i386_follow_jump (); | |
334 | ||
335 | return (codestream_tell ()); | |
336 | } | |
337 | ||
56eec3c7 | 338 | void |
07d021a6 JG |
339 | symmetry_extract_return_value(type, regbuf, valbuf) |
340 | struct type *type; | |
341 | char *regbuf; | |
342 | char *valbuf; | |
343 | { | |
344 | union { | |
345 | double d; | |
346 | int l[2]; | |
347 | } xd; | |
1ab3bf1b | 348 | struct minimal_symbol *msymbol; |
07d021a6 JG |
349 | float f; |
350 | ||
351 | if (TYPE_CODE_FLT == TYPE_CODE(type)) { | |
1ab3bf1b JG |
352 | msymbol = lookup_minimal_symbol ("1167_flt", (struct objfile *) NULL); |
353 | if (msymbol != NULL) { | |
07d021a6 JG |
354 | /* found "1167_flt" means 1167, %fp2-%fp3 */ |
355 | /* float & double; 19= %fp2, 20= %fp3 */ | |
356 | /* no single precision on 1167 */ | |
357 | xd.l[1] = *((int *)®buf[REGISTER_BYTE(19)]); | |
358 | xd.l[0] = *((int *)®buf[REGISTER_BYTE(20)]); | |
359 | switch (TYPE_LENGTH(type)) { | |
360 | case 4: | |
56eec3c7 | 361 | /* FIXME: broken for cross-debugging. */ |
07d021a6 | 362 | f = (float) xd.d; |
56eec3c7 | 363 | memcpy (valbuf, &f, TYPE_LENGTH(type)); |
07d021a6 JG |
364 | break; |
365 | case 8: | |
56eec3c7 JK |
366 | /* FIXME: broken for cross-debugging. */ |
367 | memcpy (valbuf, &xd.d, TYPE_LENGTH(type)); | |
07d021a6 JG |
368 | break; |
369 | default: | |
370 | error("Unknown floating point size"); | |
371 | break; | |
372 | } | |
373 | } else { | |
374 | /* 387 %st(0), gcc uses this */ | |
375 | i387_to_double(((int *)®buf[REGISTER_BYTE(3)]), | |
376 | &xd.d); | |
377 | switch (TYPE_LENGTH(type)) { | |
378 | case 4: /* float */ | |
379 | f = (float) xd.d; | |
56eec3c7 JK |
380 | /* FIXME: broken for cross-debugging. */ |
381 | memcpy (valbuf, &f, 4); | |
07d021a6 JG |
382 | break; |
383 | case 8: /* double */ | |
56eec3c7 JK |
384 | /* FIXME: broken for cross-debugging. */ |
385 | memcpy (valbuf, &xd.d, 8); | |
07d021a6 JG |
386 | break; |
387 | default: | |
388 | error("Unknown floating point size"); | |
389 | break; | |
390 | } | |
391 | } | |
56eec3c7 JK |
392 | } else { |
393 | memcpy (valbuf, regbuf, TYPE_LENGTH (type)); | |
394 | } | |
395 | } | |
396 | ||
397 | #ifdef _SEQUENT_ /* ptx, not dynix */ | |
398 | /* | |
399 | * Convert compiler register number to gdb internal | |
400 | * register number. The PTX C compiler only really | |
401 | * puts things in %edi, %esi and %ebx, but it can't hurt | |
402 | * to be complete here. | |
403 | */ | |
404 | int | |
405 | ptx_coff_regno_to_gdb(regno) | |
406 | int regno; | |
407 | { | |
408 | return I386_REGNO_TO_SYMMETRY(regno); | |
409 | } | |
410 | ||
411 | /* For ptx, the value in blockend will be meaningless. This function | |
412 | merely returns the proper offset given the register number. This | |
413 | is much easier, because under ptx, the upage is set up with the | |
414 | user struct on "top", and the registers "beneath" it (and thus defines | |
415 | TRAD_CORE_USER_OFFSET in bfd). */ | |
416 | ||
417 | /* The following table is for ptx 1.3. In theory it should not change with | |
418 | the OS version, but if it does we should (if possible) figure out a way | |
419 | to accept both the old and the new formats. */ | |
420 | ||
421 | static unsigned int reg_offsets[NUM_REGS] = { | |
422 | /* | |
423 | * u.u_ar0 = 0xfffff8d0 | |
424 | * VA_UBLOCK = 0xffffe000 | |
425 | * VA_UAREA = 0xfffff8e8 | |
426 | * struct user at ublock offset 0x18e8 | |
427 | * registers at ublock offset 0x18d0 | |
428 | */ | |
429 | 0x18d0, /* eax */ | |
430 | 0x18c8, /* eax */ | |
431 | 0x18cc, /* eax */ | |
432 | 0x1be0, /* st0 */ | |
433 | 0x1bea, /* st1 */ | |
434 | 0x18c4, /* ebx */ | |
435 | 0x18b8, /* esi */ | |
436 | 0x18b4, /* edi */ | |
437 | 0x1bf4, /* st2 */ | |
438 | 0x1bfe, /* st3 */ | |
439 | 0x1c08, /* st4 */ | |
440 | 0x1c12, /* st5 */ | |
441 | 0x1c1c, /* st6 */ | |
442 | 0x1c26, /* st7 */ | |
443 | 0x18e0, /* esp */ | |
444 | 0x18bc, /* ebp */ | |
445 | 0x18d4, /* eip */ | |
446 | 0x18dc, /* flags */ | |
447 | 0x1c38, /* fp1 */ | |
448 | 0x1c3c, /* fp2 */ | |
449 | 0x1c40, /* fp3 */ | |
450 | 0x1c44, /* fp4 */ | |
451 | 0x1c48, /* fp5 */ | |
452 | 0x1c4c, /* fp6 */ | |
453 | 0x1c50, /* fp7 */ | |
454 | 0x1c54, /* fp8 */ | |
455 | 0x1c58, /* fp9 */ | |
456 | 0x1c5c, /* fp10 */ | |
457 | 0x1c60, /* fp11 */ | |
458 | 0x1c64, /* fp12 */ | |
459 | 0x1c68, /* fp13 */ | |
460 | 0x1c6c, /* fp14 */ | |
461 | 0x1c70, /* fp15 */ | |
462 | 0x1c74, /* fp16 */ | |
463 | 0x1c78, /* fp17 */ | |
464 | 0x1c7c, /* fp18 */ | |
465 | 0x1c80, /* fp19 */ | |
466 | 0x1c84, /* fp20 */ | |
467 | 0x1c88, /* fp21 */ | |
468 | 0x1c8c, /* fp22 */ | |
469 | 0x1c90, /* fp23 */ | |
470 | 0x1c94, /* fp24 */ | |
471 | 0x1c98, /* fp25 */ | |
472 | 0x1c9c, /* fp26 */ | |
473 | 0x1ca0, /* fp27 */ | |
474 | 0x1ca4, /* fp28 */ | |
475 | 0x1ca8, /* fp29 */ | |
476 | 0x1cac, /* fp30 */ | |
477 | 0x1cb0, /* fp31 */ | |
478 | }; | |
479 | ||
480 | unsigned int | |
481 | register_addr (regno, blockend) | |
482 | int regno, blockend; | |
483 | { | |
484 | if ((regno < 0) || (regno >= NUM_REGS)) { | |
485 | error("Invalid register number %d.", regno); | |
07d021a6 | 486 | } |
56eec3c7 | 487 | return reg_offsets[regno]; |
07d021a6 | 488 | } |
56eec3c7 | 489 | #endif /* _SEQUENT_ */ |