Commit | Line | Data |
---|---|---|
ed9a39eb | 1 | /* GNU/Linux on ARM native support. |
f973ed9c | 2 | Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 |
10d6c8cd | 3 | Free Software Foundation, Inc. |
ed9a39eb JM |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
197e01b6 EZ |
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | Boston, MA 02110-1301, USA. */ | |
ed9a39eb JM |
21 | |
22 | #include "defs.h" | |
23 | #include "inferior.h" | |
24 | #include "gdbcore.h" | |
25 | #include "gdb_string.h" | |
4e052eda | 26 | #include "regcache.h" |
10d6c8cd DJ |
27 | #include "target.h" |
28 | #include "linux-nat.h" | |
ed9a39eb | 29 | |
aeb98c60 | 30 | #include "arm-tdep.h" |
cb587d83 | 31 | #include "arm-linux-tdep.h" |
aeb98c60 | 32 | |
ed9a39eb JM |
33 | #include <sys/user.h> |
34 | #include <sys/ptrace.h> | |
35 | #include <sys/utsname.h> | |
41c49b06 | 36 | #include <sys/procfs.h> |
ed9a39eb | 37 | |
c60c0f5f MS |
38 | /* Prototypes for supply_gregset etc. */ |
39 | #include "gregset.h" | |
40 | ||
9308fc88 DJ |
41 | /* Defines ps_err_e, struct ps_prochandle. */ |
42 | #include "gdb_proc_service.h" | |
43 | ||
44 | #ifndef PTRACE_GET_THREAD_AREA | |
45 | #define PTRACE_GET_THREAD_AREA 22 | |
46 | #endif | |
47 | ||
ed9a39eb JM |
48 | extern int arm_apcs_32; |
49 | ||
ed9a39eb | 50 | /* The following variables are used to determine the version of the |
fdf39c9a | 51 | underlying GNU/Linux operating system. Examples: |
ed9a39eb | 52 | |
fdf39c9a | 53 | GNU/Linux 2.0.35 GNU/Linux 2.2.12 |
ed9a39eb JM |
54 | os_version = 0x00020023 os_version = 0x0002020c |
55 | os_major = 2 os_major = 2 | |
56 | os_minor = 0 os_minor = 2 | |
57 | os_release = 35 os_release = 12 | |
58 | ||
59 | Note: os_version = (os_major << 16) | (os_minor << 8) | os_release | |
60 | ||
61 | These are initialized using get_linux_version() from | |
62 | _initialize_arm_linux_nat(). */ | |
63 | ||
64 | static unsigned int os_version, os_major, os_minor, os_release; | |
65 | ||
fdf39c9a | 66 | /* On GNU/Linux, threads are implemented as pseudo-processes, in which |
41c49b06 | 67 | case we may be tracing more than one process at a time. In that |
39f77062 | 68 | case, inferior_ptid will contain the main process ID and the |
fdf39c9a RE |
69 | individual thread (process) ID. get_thread_id () is used to get |
70 | the thread id if it's available, and the process id otherwise. */ | |
41c49b06 SB |
71 | |
72 | int | |
39f77062 | 73 | get_thread_id (ptid_t ptid) |
41c49b06 | 74 | { |
39f77062 KB |
75 | int tid = TIDGET (ptid); |
76 | if (0 == tid) | |
77 | tid = PIDGET (ptid); | |
41c49b06 SB |
78 | return tid; |
79 | } | |
39f77062 | 80 | #define GET_THREAD_ID(PTID) get_thread_id ((PTID)); |
41c49b06 | 81 | |
41c49b06 | 82 | /* Get the value of a particular register from the floating point |
c6b92abd | 83 | state of the process and store it into regcache. */ |
41c49b06 SB |
84 | |
85 | static void | |
86 | fetch_fpregister (int regno) | |
87 | { | |
88 | int ret, tid; | |
cb587d83 | 89 | gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; |
41c49b06 SB |
90 | |
91 | /* Get the thread id for the ptrace call. */ | |
39f77062 | 92 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
93 | |
94 | /* Read the floating point state. */ | |
cb587d83 | 95 | ret = ptrace (PT_GETFPREGS, tid, 0, fp); |
41c49b06 SB |
96 | if (ret < 0) |
97 | { | |
edefbb7c | 98 | warning (_("Unable to fetch floating point register.")); |
41c49b06 SB |
99 | return; |
100 | } | |
101 | ||
102 | /* Fetch fpsr. */ | |
34e8f22d | 103 | if (ARM_FPS_REGNUM == regno) |
cb587d83 DJ |
104 | regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, |
105 | fp + NWFPE_FPSR_OFFSET); | |
41c49b06 SB |
106 | |
107 | /* Fetch the floating point register. */ | |
34e8f22d | 108 | if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) |
cb587d83 | 109 | supply_nwfpe_register (current_regcache, regno, fp); |
41c49b06 SB |
110 | } |
111 | ||
112 | /* Get the whole floating point state of the process and store it | |
c6b92abd | 113 | into regcache. */ |
ed9a39eb JM |
114 | |
115 | static void | |
116 | fetch_fpregs (void) | |
117 | { | |
41c49b06 | 118 | int ret, regno, tid; |
cb587d83 | 119 | gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; |
ed9a39eb | 120 | |
41c49b06 | 121 | /* Get the thread id for the ptrace call. */ |
39f77062 | 122 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 | 123 | |
ed9a39eb | 124 | /* Read the floating point state. */ |
cb587d83 | 125 | ret = ptrace (PT_GETFPREGS, tid, 0, fp); |
ed9a39eb JM |
126 | if (ret < 0) |
127 | { | |
edefbb7c | 128 | warning (_("Unable to fetch the floating point registers.")); |
ed9a39eb JM |
129 | return; |
130 | } | |
131 | ||
132 | /* Fetch fpsr. */ | |
cb587d83 DJ |
133 | regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, |
134 | fp + NWFPE_FPSR_OFFSET); | |
ed9a39eb JM |
135 | |
136 | /* Fetch the floating point registers. */ | |
34e8f22d | 137 | for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) |
cb587d83 | 138 | supply_nwfpe_register (current_regcache, regno, fp); |
ed9a39eb JM |
139 | } |
140 | ||
41c49b06 | 141 | /* Save a particular register into the floating point state of the |
c6b92abd | 142 | process using the contents from regcache. */ |
41c49b06 SB |
143 | |
144 | static void | |
145 | store_fpregister (int regno) | |
146 | { | |
147 | int ret, tid; | |
cb587d83 | 148 | gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; |
41c49b06 SB |
149 | |
150 | /* Get the thread id for the ptrace call. */ | |
39f77062 | 151 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
152 | |
153 | /* Read the floating point state. */ | |
cb587d83 | 154 | ret = ptrace (PT_GETFPREGS, tid, 0, fp); |
41c49b06 SB |
155 | if (ret < 0) |
156 | { | |
edefbb7c | 157 | warning (_("Unable to fetch the floating point registers.")); |
41c49b06 SB |
158 | return; |
159 | } | |
160 | ||
161 | /* Store fpsr. */ | |
34e8f22d | 162 | if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM)) |
cb587d83 DJ |
163 | regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, |
164 | fp + NWFPE_FPSR_OFFSET); | |
41c49b06 SB |
165 | |
166 | /* Store the floating point register. */ | |
34e8f22d | 167 | if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) |
cb587d83 | 168 | collect_nwfpe_register (current_regcache, regno, fp); |
41c49b06 | 169 | |
cb587d83 | 170 | ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp); |
41c49b06 SB |
171 | if (ret < 0) |
172 | { | |
edefbb7c | 173 | warning (_("Unable to store floating point register.")); |
41c49b06 SB |
174 | return; |
175 | } | |
176 | } | |
177 | ||
ed9a39eb | 178 | /* Save the whole floating point state of the process using |
c6b92abd | 179 | the contents from regcache. */ |
ed9a39eb JM |
180 | |
181 | static void | |
182 | store_fpregs (void) | |
183 | { | |
41c49b06 | 184 | int ret, regno, tid; |
cb587d83 | 185 | gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; |
ed9a39eb | 186 | |
41c49b06 | 187 | /* Get the thread id for the ptrace call. */ |
39f77062 | 188 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
189 | |
190 | /* Read the floating point state. */ | |
cb587d83 | 191 | ret = ptrace (PT_GETFPREGS, tid, 0, fp); |
41c49b06 SB |
192 | if (ret < 0) |
193 | { | |
edefbb7c | 194 | warning (_("Unable to fetch the floating point registers.")); |
41c49b06 SB |
195 | return; |
196 | } | |
197 | ||
ed9a39eb | 198 | /* Store fpsr. */ |
34e8f22d | 199 | if (register_cached (ARM_FPS_REGNUM)) |
cb587d83 DJ |
200 | regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, |
201 | fp + NWFPE_FPSR_OFFSET); | |
ed9a39eb JM |
202 | |
203 | /* Store the floating point registers. */ | |
34e8f22d | 204 | for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) |
cb587d83 DJ |
205 | if (register_cached (regno)) |
206 | collect_nwfpe_register (current_regcache, regno, fp); | |
ed9a39eb | 207 | |
cb587d83 | 208 | ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp); |
ed9a39eb JM |
209 | if (ret < 0) |
210 | { | |
edefbb7c | 211 | warning (_("Unable to store floating point registers.")); |
ed9a39eb JM |
212 | return; |
213 | } | |
214 | } | |
215 | ||
41c49b06 | 216 | /* Fetch a general register of the process and store into |
c6b92abd | 217 | regcache. */ |
41c49b06 SB |
218 | |
219 | static void | |
220 | fetch_register (int regno) | |
221 | { | |
222 | int ret, tid; | |
c2152441 | 223 | elf_gregset_t regs; |
41c49b06 SB |
224 | |
225 | /* Get the thread id for the ptrace call. */ | |
39f77062 | 226 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
227 | |
228 | ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); | |
229 | if (ret < 0) | |
230 | { | |
edefbb7c | 231 | warning (_("Unable to fetch general register.")); |
41c49b06 SB |
232 | return; |
233 | } | |
234 | ||
34e8f22d | 235 | if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM) |
23a6d369 | 236 | regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]); |
41c49b06 | 237 | |
34e8f22d | 238 | if (ARM_PS_REGNUM == regno) |
41c49b06 SB |
239 | { |
240 | if (arm_apcs_32) | |
23a6d369 AC |
241 | regcache_raw_supply (current_regcache, ARM_PS_REGNUM, |
242 | (char *) ®s[ARM_CPSR_REGNUM]); | |
41c49b06 | 243 | else |
23a6d369 AC |
244 | regcache_raw_supply (current_regcache, ARM_PS_REGNUM, |
245 | (char *) ®s[ARM_PC_REGNUM]); | |
41c49b06 SB |
246 | } |
247 | ||
34e8f22d | 248 | if (ARM_PC_REGNUM == regno) |
41c49b06 | 249 | { |
34e8f22d | 250 | regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]); |
23a6d369 AC |
251 | regcache_raw_supply (current_regcache, ARM_PC_REGNUM, |
252 | (char *) ®s[ARM_PC_REGNUM]); | |
41c49b06 SB |
253 | } |
254 | } | |
255 | ||
ed9a39eb | 256 | /* Fetch all general registers of the process and store into |
c6b92abd | 257 | regcache. */ |
ed9a39eb JM |
258 | |
259 | static void | |
260 | fetch_regs (void) | |
261 | { | |
41c49b06 | 262 | int ret, regno, tid; |
c2152441 | 263 | elf_gregset_t regs; |
ed9a39eb | 264 | |
41c49b06 | 265 | /* Get the thread id for the ptrace call. */ |
39f77062 | 266 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
267 | |
268 | ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); | |
ed9a39eb JM |
269 | if (ret < 0) |
270 | { | |
edefbb7c | 271 | warning (_("Unable to fetch general registers.")); |
ed9a39eb JM |
272 | return; |
273 | } | |
274 | ||
34e8f22d | 275 | for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) |
23a6d369 | 276 | regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]); |
ed9a39eb JM |
277 | |
278 | if (arm_apcs_32) | |
23a6d369 AC |
279 | regcache_raw_supply (current_regcache, ARM_PS_REGNUM, |
280 | (char *) ®s[ARM_CPSR_REGNUM]); | |
ed9a39eb | 281 | else |
23a6d369 AC |
282 | regcache_raw_supply (current_regcache, ARM_PS_REGNUM, |
283 | (char *) ®s[ARM_PC_REGNUM]); | |
ed9a39eb | 284 | |
34e8f22d | 285 | regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]); |
23a6d369 AC |
286 | regcache_raw_supply (current_regcache, ARM_PC_REGNUM, |
287 | (char *) ®s[ARM_PC_REGNUM]); | |
ed9a39eb JM |
288 | } |
289 | ||
290 | /* Store all general registers of the process from the values in | |
c6b92abd | 291 | regcache. */ |
ed9a39eb | 292 | |
41c49b06 SB |
293 | static void |
294 | store_register (int regno) | |
295 | { | |
296 | int ret, tid; | |
c2152441 | 297 | elf_gregset_t regs; |
41c49b06 | 298 | |
c6b92abd | 299 | if (!register_cached (regno)) |
41c49b06 SB |
300 | return; |
301 | ||
302 | /* Get the thread id for the ptrace call. */ | |
39f77062 | 303 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
304 | |
305 | /* Get the general registers from the process. */ | |
306 | ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); | |
307 | if (ret < 0) | |
308 | { | |
edefbb7c | 309 | warning (_("Unable to fetch general registers.")); |
41c49b06 SB |
310 | return; |
311 | } | |
312 | ||
34e8f22d | 313 | if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) |
822c9732 | 314 | regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]); |
adb8a87c DJ |
315 | else if (arm_apcs_32 && regno == ARM_PS_REGNUM) |
316 | regcache_raw_collect (current_regcache, regno, | |
317 | (char *) ®s[ARM_CPSR_REGNUM]); | |
318 | else if (!arm_apcs_32 && regno == ARM_PS_REGNUM) | |
319 | regcache_raw_collect (current_regcache, ARM_PC_REGNUM, | |
320 | (char *) ®s[ARM_PC_REGNUM]); | |
41c49b06 SB |
321 | |
322 | ret = ptrace (PTRACE_SETREGS, tid, 0, ®s); | |
323 | if (ret < 0) | |
324 | { | |
edefbb7c | 325 | warning (_("Unable to store general register.")); |
41c49b06 SB |
326 | return; |
327 | } | |
328 | } | |
329 | ||
ed9a39eb JM |
330 | static void |
331 | store_regs (void) | |
332 | { | |
41c49b06 | 333 | int ret, regno, tid; |
c2152441 | 334 | elf_gregset_t regs; |
ed9a39eb | 335 | |
41c49b06 | 336 | /* Get the thread id for the ptrace call. */ |
39f77062 | 337 | tid = GET_THREAD_ID (inferior_ptid); |
41c49b06 SB |
338 | |
339 | /* Fetch the general registers. */ | |
340 | ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); | |
ed9a39eb JM |
341 | if (ret < 0) |
342 | { | |
edefbb7c | 343 | warning (_("Unable to fetch general registers.")); |
ed9a39eb JM |
344 | return; |
345 | } | |
346 | ||
34e8f22d | 347 | for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++) |
ed9a39eb | 348 | { |
c6b92abd | 349 | if (register_cached (regno)) |
822c9732 | 350 | regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]); |
ed9a39eb JM |
351 | } |
352 | ||
adb8a87c DJ |
353 | if (arm_apcs_32 && register_cached (ARM_PS_REGNUM)) |
354 | regcache_raw_collect (current_regcache, ARM_PS_REGNUM, | |
355 | (char *) ®s[ARM_CPSR_REGNUM]); | |
356 | ||
41c49b06 | 357 | ret = ptrace (PTRACE_SETREGS, tid, 0, ®s); |
ed9a39eb JM |
358 | |
359 | if (ret < 0) | |
360 | { | |
edefbb7c | 361 | warning (_("Unable to store general registers.")); |
ed9a39eb JM |
362 | return; |
363 | } | |
364 | } | |
365 | ||
366 | /* Fetch registers from the child process. Fetch all registers if | |
367 | regno == -1, otherwise fetch all general registers or all floating | |
368 | point registers depending upon the value of regno. */ | |
369 | ||
10d6c8cd DJ |
370 | static void |
371 | arm_linux_fetch_inferior_registers (int regno) | |
ed9a39eb | 372 | { |
41c49b06 SB |
373 | if (-1 == regno) |
374 | { | |
375 | fetch_regs (); | |
376 | fetch_fpregs (); | |
377 | } | |
378 | else | |
379 | { | |
34e8f22d | 380 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) |
41c49b06 | 381 | fetch_register (regno); |
ed9a39eb | 382 | |
34e8f22d | 383 | if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM) |
41c49b06 SB |
384 | fetch_fpregister (regno); |
385 | } | |
ed9a39eb JM |
386 | } |
387 | ||
388 | /* Store registers back into the inferior. Store all registers if | |
389 | regno == -1, otherwise store all general registers or all floating | |
390 | point registers depending upon the value of regno. */ | |
391 | ||
10d6c8cd DJ |
392 | static void |
393 | arm_linux_store_inferior_registers (int regno) | |
ed9a39eb | 394 | { |
41c49b06 SB |
395 | if (-1 == regno) |
396 | { | |
397 | store_regs (); | |
398 | store_fpregs (); | |
399 | } | |
400 | else | |
401 | { | |
34e8f22d | 402 | if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM)) |
41c49b06 | 403 | store_register (regno); |
ed9a39eb | 404 | |
34e8f22d | 405 | if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM)) |
41c49b06 SB |
406 | store_fpregister (regno); |
407 | } | |
ed9a39eb JM |
408 | } |
409 | ||
cb587d83 DJ |
410 | /* Wrapper functions for the standard regset handling, used by |
411 | thread debugging. */ | |
41c49b06 SB |
412 | |
413 | void | |
713f0374 | 414 | fill_gregset (gdb_gregset_t *gregsetp, int regno) |
41c49b06 | 415 | { |
cb587d83 | 416 | arm_linux_collect_gregset (NULL, current_regcache, regno, gregsetp, 0); |
41c49b06 SB |
417 | } |
418 | ||
41c49b06 | 419 | void |
713f0374 | 420 | supply_gregset (gdb_gregset_t *gregsetp) |
41c49b06 | 421 | { |
cb587d83 | 422 | arm_linux_supply_gregset (NULL, current_regcache, -1, gregsetp, 0); |
41c49b06 SB |
423 | } |
424 | ||
41c49b06 | 425 | void |
713f0374 | 426 | fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) |
41c49b06 | 427 | { |
cb587d83 | 428 | arm_linux_collect_nwfpe (NULL, current_regcache, regno, fpregsetp, 0); |
41c49b06 SB |
429 | } |
430 | ||
431 | /* Fill GDB's register array with the floating-point register values | |
432 | in *fpregsetp. */ | |
433 | ||
434 | void | |
713f0374 | 435 | supply_fpregset (gdb_fpregset_t *fpregsetp) |
ed9a39eb | 436 | { |
cb587d83 | 437 | arm_linux_supply_nwfpe (NULL, current_regcache, -1, fpregsetp, 0); |
ed9a39eb JM |
438 | } |
439 | ||
440 | int | |
441 | arm_linux_kernel_u_size (void) | |
442 | { | |
443 | return (sizeof (struct user)); | |
444 | } | |
445 | ||
9308fc88 DJ |
446 | /* Fetch the thread-local storage pointer for libthread_db. */ |
447 | ||
448 | ps_err_e | |
449 | ps_get_thread_area (const struct ps_prochandle *ph, | |
450 | lwpid_t lwpid, int idx, void **base) | |
451 | { | |
452 | if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) | |
453 | return PS_ERR; | |
454 | ||
455 | /* IDX is the bias from the thread pointer to the beginning of the | |
456 | thread descriptor. It has to be subtracted due to implementation | |
457 | quirks in libthread_db. */ | |
458 | *base = (void *) ((char *)*base - idx); | |
459 | ||
460 | return PS_OK; | |
461 | } | |
462 | ||
ed9a39eb JM |
463 | static unsigned int |
464 | get_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 | { | |
edefbb7c | 473 | warning (_("Unable to determine GNU/Linux version.")); |
ed9a39eb JM |
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 | ||
10d6c8cd DJ |
488 | void _initialize_arm_linux_nat (void); |
489 | ||
ed9a39eb JM |
490 | void |
491 | _initialize_arm_linux_nat (void) | |
492 | { | |
10d6c8cd DJ |
493 | struct target_ops *t; |
494 | ||
ed9a39eb | 495 | os_version = get_linux_version (&os_major, &os_minor, &os_release); |
10d6c8cd DJ |
496 | |
497 | /* Fill in the generic GNU/Linux methods. */ | |
498 | t = linux_target (); | |
499 | ||
500 | /* Add our register access methods. */ | |
501 | t->to_fetch_registers = arm_linux_fetch_inferior_registers; | |
502 | t->to_store_registers = arm_linux_store_inferior_registers; | |
503 | ||
504 | /* Register the target. */ | |
f973ed9c | 505 | linux_nat_add_target (t); |
ed9a39eb | 506 | } |