2000-04-10 Fernando Nasser <fnasser@cygnus.com>
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
ef57c069 2 Copyright 1999, 2000 Free Software Foundation, Inc.
ed9a39eb
JM
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., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21#include "defs.h"
22#include "inferior.h"
23#include "gdbcore.h"
24#include "gdb_string.h"
25
26#include <sys/user.h>
27#include <sys/ptrace.h>
28#include <sys/utsname.h>
29
30extern int arm_apcs_32;
31
32#define typeNone 0x00
33#define typeSingle 0x01
34#define typeDouble 0x02
35#define typeExtended 0x03
36#define FPWORDS 28
37#define CPSR_REGNUM 16
38
39typedef union tagFPREG
40 {
41 unsigned int fSingle;
42 unsigned int fDouble[2];
43 unsigned int fExtended[3];
44 }
45FPREG;
46
47typedef struct tagFPA11
48 {
49 FPREG fpreg[8]; /* 8 floating point registers */
50 unsigned int fpsr; /* floating point status register */
51 unsigned int fpcr; /* floating point control register */
52 unsigned char fType[8]; /* type of floating point value held in
53 floating point registers. */
54 int initflag; /* NWFPE initialization flag. */
55 }
56FPA11;
57
58/* The following variables are used to determine the version of the
59 underlying Linux operating system. Examples:
60
61 Linux 2.0.35 Linux 2.2.12
62 os_version = 0x00020023 os_version = 0x0002020c
63 os_major = 2 os_major = 2
64 os_minor = 0 os_minor = 2
65 os_release = 35 os_release = 12
66
67 Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
68
69 These are initialized using get_linux_version() from
70 _initialize_arm_linux_nat(). */
71
72static unsigned int os_version, os_major, os_minor, os_release;
73
74static void
56624b0a 75fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
76{
77 unsigned int mem[3];
78
79 mem[0] = fpa11->fpreg[fn].fSingle;
80 mem[1] = 0;
81 mem[2] = 0;
82 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
83}
84
85static void
56624b0a 86fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
87{
88 unsigned int mem[3];
89
90 mem[0] = fpa11->fpreg[fn].fDouble[1];
91 mem[1] = fpa11->fpreg[fn].fDouble[0];
92 mem[2] = 0;
93 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
94}
95
96static void
56624b0a 97fetch_nwfpe_none (unsigned int fn)
ed9a39eb
JM
98{
99 unsigned int mem[3] =
100 {0, 0, 0};
101
102 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
103}
104
105static void
56624b0a 106fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
107{
108 unsigned int mem[3];
109
110 mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */
111 mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */
112 mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */
113 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
114}
115
116static void
56624b0a 117store_nwfpe_single (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
118{
119 unsigned int mem[3];
120
121 read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
122 fpa11->fpreg[fn].fSingle = mem[0];
123 fpa11->fType[fn] = typeSingle;
124}
125
126static void
56624b0a 127store_nwfpe_double (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
128{
129 unsigned int mem[3];
130
131 read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
132 fpa11->fpreg[fn].fDouble[1] = mem[0];
133 fpa11->fpreg[fn].fDouble[0] = mem[1];
134 fpa11->fType[fn] = typeDouble;
135}
136
137void
56624b0a 138store_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
139{
140 unsigned int mem[3];
141
142 read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
143 fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */
144 fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */
145 fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */
146 fpa11->fType[fn] = typeDouble;
147}
148
149/* Get the whole floating point state of the process and store the
150 floating point stack into registers[]. */
151
152static void
153fetch_fpregs (void)
154{
155 int ret, regno;
156 FPA11 fp;
157
158 /* Read the floating point state. */
159 ret = ptrace (PT_GETFPREGS, inferior_pid, 0, &fp);
160 if (ret < 0)
161 {
162 warning ("Unable to fetch the floating point state.");
163 return;
164 }
165
166 /* Fetch fpsr. */
167 supply_register (FPS_REGNUM, (char *) &fp.fpsr);
168
169 /* Fetch the floating point registers. */
170 for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
171 {
172 int fn = regno - F0_REGNUM;
ed9a39eb
JM
173
174 switch (fp.fType[fn])
175 {
176 case typeSingle:
56624b0a 177 fetch_nwfpe_single (fn, &fp);
ed9a39eb
JM
178 break;
179
180 case typeDouble:
56624b0a 181 fetch_nwfpe_double (fn, &fp);
ed9a39eb
JM
182 break;
183
184 case typeExtended:
56624b0a 185 fetch_nwfpe_extended (fn, &fp);
ed9a39eb
JM
186 break;
187
188 default:
56624b0a 189 fetch_nwfpe_none (fn);
ed9a39eb
JM
190 }
191 }
192}
193
194/* Save the whole floating point state of the process using
195 the contents from registers[]. */
196
197static void
198store_fpregs (void)
199{
200 int ret, regno;
ed9a39eb
JM
201 FPA11 fp;
202
203 /* Store fpsr. */
204 if (register_valid[FPS_REGNUM])
205 read_register_gen (FPS_REGNUM, (char *) &fp.fpsr);
206
207 /* Store the floating point registers. */
208 for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
209 {
210 if (register_valid[regno])
211 {
212 unsigned int fn = regno - F0_REGNUM;
213 switch (fp.fType[fn])
214 {
215 case typeSingle:
56624b0a 216 store_nwfpe_single (fn, &fp);
ed9a39eb
JM
217 break;
218
219 case typeDouble:
56624b0a 220 store_nwfpe_double (fn, &fp);
ed9a39eb
JM
221 break;
222
223 case typeExtended:
56624b0a 224 store_nwfpe_extended (fn, &fp);
ed9a39eb
JM
225 break;
226 }
227 }
228 }
229
230 ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, &fp);
231 if (ret < 0)
232 {
233 warning ("Unable to store floating point state.");
234 return;
235 }
236}
237
238/* Fetch all general registers of the process and store into
239 registers[]. */
240
241static void
242fetch_regs (void)
243{
244 int ret, regno;
245 struct pt_regs regs;
246
247 ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, &regs);
248 if (ret < 0)
249 {
250 warning ("Unable to fetch general registers.");
251 return;
252 }
253
254 for (regno = A1_REGNUM; regno < PC_REGNUM; regno++)
255 supply_register (regno, (char *) &regs.uregs[regno]);
256
257 if (arm_apcs_32)
258 supply_register (PS_REGNUM, (char *) &regs.uregs[CPSR_REGNUM]);
259 else
260 supply_register (PS_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
261
262 regs.uregs[PC_REGNUM] = ADDR_BITS_REMOVE (regs.uregs[PC_REGNUM]);
263 supply_register (PC_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
264}
265
266/* Store all general registers of the process from the values in
267 registers[]. */
268
269static void
270store_regs (void)
271{
272 int ret, regno;
273 struct pt_regs regs;
274
275 ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, &regs);
276 if (ret < 0)
277 {
278 warning ("Unable to fetch general registers.");
279 return;
280 }
281
282 for (regno = A1_REGNUM; regno <= PC_REGNUM; regno++)
283 {
284 if (register_valid[regno])
285 read_register_gen (regno, (char *) &regs.uregs[regno]);
286 }
287
288 ret = ptrace (PTRACE_SETREGS, inferior_pid, 0, &regs);
289
290 if (ret < 0)
291 {
292 warning ("Unable to store general registers.");
293 return;
294 }
295}
296
297/* Fetch registers from the child process. Fetch all registers if
298 regno == -1, otherwise fetch all general registers or all floating
299 point registers depending upon the value of regno. */
300
301void
302fetch_inferior_registers (int regno)
303{
304 if ((regno < F0_REGNUM) || (regno > FPS_REGNUM))
305 fetch_regs ();
306
307 if (((regno >= F0_REGNUM) && (regno <= FPS_REGNUM)) || (regno == -1))
308 fetch_fpregs ();
309}
310
311/* Store registers back into the inferior. Store all registers if
312 regno == -1, otherwise store all general registers or all floating
313 point registers depending upon the value of regno. */
314
315void
316store_inferior_registers (int regno)
317{
318 if ((regno < F0_REGNUM) || (regno > FPS_REGNUM))
319 store_regs ();
320
321 if (((regno >= F0_REGNUM) && (regno <= FPS_REGNUM)) || (regno == -1))
322 store_fpregs ();
323}
324
ed9a39eb
JM
325/*
326 Dynamic Linking on ARM Linux
327 ----------------------------
328
329 Note: PLT = procedure linkage table
330 GOT = global offset table
331
332 As much as possible, ELF dynamic linking defers the resolution of
333 jump/call addresses until the last minute. The technique used is
334 inspired by the i386 ELF design, and is based on the following
335 constraints.
336
337 1) The calling technique should not force a change in the assembly
338 code produced for apps; it MAY cause changes in the way assembly
339 code is produced for position independent code (i.e. shared
340 libraries).
341
342 2) The technique must be such that all executable areas must not be
343 modified; and any modified areas must not be executed.
344
345 To do this, there are three steps involved in a typical jump:
346
347 1) in the code
348 2) through the PLT
349 3) using a pointer from the GOT
350
351 When the executable or library is first loaded, each GOT entry is
352 initialized to point to the code which implements dynamic name
353 resolution and code finding. This is normally a function in the
354 program interpreter (on ARM Linux this is usually ld-linux.so.2,
355 but it does not have to be). On the first invocation, the function
356 is located and the GOT entry is replaced with the real function
357 address. Subsequent calls go through steps 1, 2 and 3 and end up
358 calling the real code.
359
360 1) In the code:
361
362 b function_call
363 bl function_call
364
365 This is typical ARM code using the 26 bit relative branch or branch
366 and link instructions. The target of the instruction
367 (function_call is usually the address of the function to be called.
368 In position independent code, the target of the instruction is
369 actually an entry in the PLT when calling functions in a shared
370 library. Note that this call is identical to a normal function
371 call, only the target differs.
372
373 2) In the PLT:
374
375 The PLT is a synthetic area, created by the linker. It exists in
376 both executables and libraries. It is an array of stubs, one per
377 imported function call. It looks like this:
378
379 PLT[0]:
380 str lr, [sp, #-4]! @push the return address (lr)
381 ldr lr, [pc, #16] @load from 6 words ahead
382 add lr, pc, lr @form an address for GOT[0]
383 ldr pc, [lr, #8]! @jump to the contents of that addr
384
385 The return address (lr) is pushed on the stack and used for
386 calculations. The load on the second line loads the lr with
387 &GOT[3] - . - 20. The addition on the third leaves:
388
389 lr = (&GOT[3] - . - 20) + (. + 8)
390 lr = (&GOT[3] - 12)
391 lr = &GOT[0]
392
393 On the fourth line, the pc and lr are both updated, so that:
394
395 pc = GOT[2]
396 lr = &GOT[0] + 8
397 = &GOT[2]
398
399 NOTE: PLT[0] borrows an offset .word from PLT[1]. This is a little
400 "tight", but allows us to keep all the PLT entries the same size.
401
402 PLT[n+1]:
403 ldr ip, [pc, #4] @load offset from gotoff
404 add ip, pc, ip @add the offset to the pc
405 ldr pc, [ip] @jump to that address
406 gotoff: .word GOT[n+3] - .
407
408 The load on the first line, gets an offset from the fourth word of
409 the PLT entry. The add on the second line makes ip = &GOT[n+3],
410 which contains either a pointer to PLT[0] (the fixup trampoline) or
411 a pointer to the actual code.
412
413 3) In the GOT:
414
415 The GOT contains helper pointers for both code (PLT) fixups and
416 data fixups. The first 3 entries of the GOT are special. The next
417 M entries (where M is the number of entries in the PLT) belong to
418 the PLT fixups. The next D (all remaining) entries belong to
419 various data fixups. The actual size of the GOT is 3 + M + D.
420
421 The GOT is also a synthetic area, created by the linker. It exists
422 in both executables and libraries. When the GOT is first
423 initialized , all the GOT entries relating to PLT fixups are
424 pointing to code back at PLT[0].
425
426 The special entries in the GOT are:
427
428 GOT[0] = linked list pointer used by the dynamic loader
429 GOT[1] = pointer to the reloc table for this module
430 GOT[2] = pointer to the fixup/resolver code
431
432 The first invocation of function call comes through and uses the
433 fixup/resolver code. On the entry to the fixup/resolver code:
434
435 ip = &GOT[n+3]
436 lr = &GOT[2]
437 stack[0] = return address (lr) of the function call
438 [r0, r1, r2, r3] are still the arguments to the function call
439
440 This is enough information for the fixup/resolver code to work
441 with. Before the fixup/resolver code returns, it actually calls
442 the requested function and repairs &GOT[n+3]. */
443
444CORE_ADDR
445arm_skip_solib_resolver (CORE_ADDR pc)
446{
447 /* FIXME */
448 return 0;
449}
450
451int
452arm_linux_register_u_addr (int blockend, int regnum)
453{
454 return blockend + REGISTER_BYTE (regnum);
455}
456
457int
458arm_linux_kernel_u_size (void)
459{
460 return (sizeof (struct user));
461}
462
ed9a39eb
JM
463static unsigned int
464get_linux_version (unsigned int *vmajor,
465 unsigned int *vminor,
466 unsigned int *vrelease)
467{
468 struct utsname info;
469 char *pmajor, *pminor, *prelease, *tail;
470
471 if (-1 == uname (&info))
472 {
473 warning ("Unable to determine Linux version.");
474 return -1;
475 }
476
477 pmajor = strtok (info.release, ".");
478 pminor = strtok (NULL, ".");
479 prelease = strtok (NULL, ".");
480
481 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
482 *vminor = (unsigned int) strtoul (pminor, &tail, 0);
483 *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
484
485 return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
486}
487
488void
489_initialize_arm_linux_nat (void)
490{
491 os_version = get_linux_version (&os_major, &os_minor, &os_release);
492}
This page took 0.051123 seconds and 4 git commands to generate.