1 /* GNU/Linux on ARM native support. 2 Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 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 #include "regcache.h" 26 27 #include "arm-tdep.h" 28 29 #include <sys/user.h> 30 #include <sys/ptrace.h> 31 #include <sys/utsname.h> 32 #include <sys/procfs.h> 33 34 /* Prototypes for supply_gregset etc. */ 35 #include "gregset.h" 36 37 extern int arm_apcs_32; 38 39 #define typeNone 0x00 40 #define typeSingle 0x01 41 #define typeDouble 0x02 42 #define typeExtended 0x03 43 #define FPWORDS 28 44 #define ARM_CPSR_REGNUM 16 45 46 typedef union tagFPREG 47 { 48 unsigned int fSingle; 49 unsigned int fDouble[2]; 50 unsigned int fExtended[3]; 51 } 52 FPREG; 53 54 typedef struct tagFPA11 55 { 56 FPREG fpreg[8]; /* 8 floating point registers */ 57 unsigned int fpsr; /* floating point status register */ 58 unsigned int fpcr; /* floating point control register */ 59 unsigned char fType[8]; /* type of floating point value held in 60 floating point registers. */ 61 int initflag; /* NWFPE initialization flag. */ 62 } 63 FPA11; 64 65 /* The following variables are used to determine the version of the 66 underlying GNU/Linux operating system. Examples: 67 68 GNU/Linux 2.0.35 GNU/Linux 2.2.12 69 os_version = 0x00020023 os_version = 0x0002020c 70 os_major = 2 os_major = 2 71 os_minor = 0 os_minor = 2 72 os_release = 35 os_release = 12 73 74 Note: os_version = (os_major << 16) | (os_minor << 8) | os_release 75 76 These are initialized using get_linux_version() from 77 _initialize_arm_linux_nat(). */ 78 79 static unsigned int os_version, os_major, os_minor, os_release; 80 81 /* On GNU/Linux, threads are implemented as pseudo-processes, in which 82 case we may be tracing more than one process at a time. In that 83 case, inferior_ptid will contain the main process ID and the 84 individual thread (process) ID. get_thread_id () is used to get 85 the thread id if it's available, and the process id otherwise. */ 86 87 int 88 get_thread_id (ptid_t ptid) 89 { 90 int tid = TIDGET (ptid); 91 if (0 == tid) 92 tid = PIDGET (ptid); 93 return tid; 94 } 95 #define GET_THREAD_ID(PTID) get_thread_id ((PTID)); 96 97 static void 98 fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11) 99 { 100 unsigned int mem[3]; 101 102 mem[0] = fpa11->fpreg[fn].fSingle; 103 mem[1] = 0; 104 mem[2] = 0; 105 regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); 106 } 107 108 static void 109 fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11) 110 { 111 unsigned int mem[3]; 112 113 mem[0] = fpa11->fpreg[fn].fDouble[1]; 114 mem[1] = fpa11->fpreg[fn].fDouble[0]; 115 mem[2] = 0; 116 regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); 117 } 118 119 static void 120 fetch_nwfpe_none (unsigned int fn) 121 { 122 unsigned int mem[3] = 123 {0, 0, 0}; 124 125 regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); 126 } 127 128 static void 129 fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11) 130 { 131 unsigned int mem[3]; 132 133 mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */ 134 mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */ 135 mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */ 136 regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); 137 } 138 139 static void 140 fetch_nwfpe_register (int regno, FPA11 * fpa11) 141 { 142 int fn = regno - ARM_F0_REGNUM; 143 144 switch (fpa11->fType[fn]) 145 { 146 case typeSingle: 147 fetch_nwfpe_single (fn, fpa11); 148 break; 149 150 case typeDouble: 151 fetch_nwfpe_double (fn, fpa11); 152 break; 153 154 case typeExtended: 155 fetch_nwfpe_extended (fn, fpa11); 156 break; 157 158 default: 159 fetch_nwfpe_none (fn); 160 } 161 } 162 163 static void 164 store_nwfpe_single (unsigned int fn, FPA11 *fpa11) 165 { 166 unsigned int mem[3]; 167 168 regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, 169 (char *) &mem[0]); 170 fpa11->fpreg[fn].fSingle = mem[0]; 171 fpa11->fType[fn] = typeSingle; 172 } 173 174 static void 175 store_nwfpe_double (unsigned int fn, FPA11 *fpa11) 176 { 177 unsigned int mem[3]; 178 179 regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, 180 (char *) &mem[0]); 181 fpa11->fpreg[fn].fDouble[1] = mem[0]; 182 fpa11->fpreg[fn].fDouble[0] = mem[1]; 183 fpa11->fType[fn] = typeDouble; 184 } 185 186 void 187 store_nwfpe_extended (unsigned int fn, FPA11 *fpa11) 188 { 189 unsigned int mem[3]; 190 191 regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, 192 (char *) &mem[0]); 193 fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */ 194 fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */ 195 fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */ 196 fpa11->fType[fn] = typeDouble; 197 } 198 199 void 200 store_nwfpe_register (int regno, FPA11 * fpa11) 201 { 202 if (register_cached (regno)) 203 { 204 unsigned int fn = regno - ARM_F0_REGNUM; 205 switch (fpa11->fType[fn]) 206 { 207 case typeSingle: 208 store_nwfpe_single (fn, fpa11); 209 break; 210 211 case typeDouble: 212 store_nwfpe_double (fn, fpa11); 213 break; 214 215 case typeExtended: 216 store_nwfpe_extended (fn, fpa11); 217 break; 218 } 219 } 220 } 221 222 223 /* Get the value of a particular register from the floating point 224 state of the process and store it into regcache. */ 225 226 static void 227 fetch_fpregister (int regno) 228 { 229 int ret, tid; 230 FPA11 fp; 231 232 /* Get the thread id for the ptrace call. */ 233 tid = GET_THREAD_ID (inferior_ptid); 234 235 /* Read the floating point state. */ 236 ret = ptrace (PT_GETFPREGS, tid, 0, &fp); 237 if (ret < 0) 238 { 239 warning ("Unable to fetch floating point register."); 240 return; 241 } 242 243 /* Fetch fpsr. */ 244 if (ARM_FPS_REGNUM == regno) 245 regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); 246 247 /* Fetch the floating point register. */ 248 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) 249 { 250 int fn = regno - ARM_F0_REGNUM; 251 252 switch (fp.fType[fn]) 253 { 254 case typeSingle: 255 fetch_nwfpe_single (fn, &fp); 256 break; 257 258 case typeDouble: 259 fetch_nwfpe_double (fn, &fp); 260 break; 261 262 case typeExtended: 263 fetch_nwfpe_extended (fn, &fp); 264 break; 265 266 default: 267 fetch_nwfpe_none (fn); 268 } 269 } 270 } 271 272 /* Get the whole floating point state of the process and store it 273 into regcache. */ 274 275 static void 276 fetch_fpregs (void) 277 { 278 int ret, regno, tid; 279 FPA11 fp; 280 281 /* Get the thread id for the ptrace call. */ 282 tid = GET_THREAD_ID (inferior_ptid); 283 284 /* Read the floating point state. */ 285 ret = ptrace (PT_GETFPREGS, tid, 0, &fp); 286 if (ret < 0) 287 { 288 warning ("Unable to fetch the floating point registers."); 289 return; 290 } 291 292 /* Fetch fpsr. */ 293 regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); 294 295 /* Fetch the floating point registers. */ 296 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) 297 { 298 int fn = regno - ARM_F0_REGNUM; 299 300 switch (fp.fType[fn]) 301 { 302 case typeSingle: 303 fetch_nwfpe_single (fn, &fp); 304 break; 305 306 case typeDouble: 307 fetch_nwfpe_double (fn, &fp); 308 break; 309 310 case typeExtended: 311 fetch_nwfpe_extended (fn, &fp); 312 break; 313 314 default: 315 fetch_nwfpe_none (fn); 316 } 317 } 318 } 319 320 /* Save a particular register into the floating point state of the 321 process using the contents from regcache. */ 322 323 static void 324 store_fpregister (int regno) 325 { 326 int ret, tid; 327 FPA11 fp; 328 329 /* Get the thread id for the ptrace call. */ 330 tid = GET_THREAD_ID (inferior_ptid); 331 332 /* Read the floating point state. */ 333 ret = ptrace (PT_GETFPREGS, tid, 0, &fp); 334 if (ret < 0) 335 { 336 warning ("Unable to fetch the floating point registers."); 337 return; 338 } 339 340 /* Store fpsr. */ 341 if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM)) 342 regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); 343 344 /* Store the floating point register. */ 345 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) 346 { 347 store_nwfpe_register (regno, &fp); 348 } 349 350 ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp); 351 if (ret < 0) 352 { 353 warning ("Unable to store floating point register."); 354 return; 355 } 356 } 357 358 /* Save the whole floating point state of the process using 359 the contents from regcache. */ 360 361 static void 362 store_fpregs (void) 363 { 364 int ret, regno, tid; 365 FPA11 fp; 366 367 /* Get the thread id for the ptrace call. */ 368 tid = GET_THREAD_ID (inferior_ptid); 369 370 /* Read the floating point state. */ 371 ret = ptrace (PT_GETFPREGS, tid, 0, &fp); 372 if (ret < 0) 373 { 374 warning ("Unable to fetch the floating point registers."); 375 return; 376 } 377 378 /* Store fpsr. */ 379 if (register_cached (ARM_FPS_REGNUM)) 380 regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); 381 382 /* Store the floating point registers. */ 383 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) 384 { 385 fetch_nwfpe_register (regno, &fp); 386 } 387 388 ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp); 389 if (ret < 0) 390 { 391 warning ("Unable to store floating point registers."); 392 return; 393 } 394 } 395 396 /* Fetch a general register of the process and store into 397 regcache. */ 398 399 static void 400 fetch_register (int regno) 401 { 402 int ret, tid; 403 elf_gregset_t regs; 404 405 /* Get the thread id for the ptrace call. */ 406 tid = GET_THREAD_ID (inferior_ptid); 407 408 ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); 409 if (ret < 0) 410 { 411 warning ("Unable to fetch general register."); 412 return; 413 } 414 415 if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM) 416 regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]); 417 418 if (ARM_PS_REGNUM == regno) 419 { 420 if (arm_apcs_32) 421 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 422 (char *) ®s[ARM_CPSR_REGNUM]); 423 else 424 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 425 (char *) ®s[ARM_PC_REGNUM]); 426 } 427 428 if (ARM_PC_REGNUM == regno) 429 { 430 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]); 431 regcache_raw_supply (current_regcache, ARM_PC_REGNUM, 432 (char *) ®s[ARM_PC_REGNUM]); 433 } 434 } 435 436 /* Fetch all general registers of the process and store into 437 regcache. */ 438 439 static void 440 fetch_regs (void) 441 { 442 int ret, regno, tid; 443 elf_gregset_t regs; 444 445 /* Get the thread id for the ptrace call. */ 446 tid = GET_THREAD_ID (inferior_ptid); 447 448 ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); 449 if (ret < 0) 450 { 451 warning ("Unable to fetch general registers."); 452 return; 453 } 454 455 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) 456 regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]); 457 458 if (arm_apcs_32) 459 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 460 (char *) ®s[ARM_CPSR_REGNUM]); 461 else 462 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 463 (char *) ®s[ARM_PC_REGNUM]); 464 465 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]); 466 regcache_raw_supply (current_regcache, ARM_PC_REGNUM, 467 (char *) ®s[ARM_PC_REGNUM]); 468 } 469 470 /* Store all general registers of the process from the values in 471 regcache. */ 472 473 static void 474 store_register (int regno) 475 { 476 int ret, tid; 477 elf_gregset_t regs; 478 479 if (!register_cached (regno)) 480 return; 481 482 /* Get the thread id for the ptrace call. */ 483 tid = GET_THREAD_ID (inferior_ptid); 484 485 /* Get the general registers from the process. */ 486 ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); 487 if (ret < 0) 488 { 489 warning ("Unable to fetch general registers."); 490 return; 491 } 492 493 if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) 494 regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]); 495 496 ret = ptrace (PTRACE_SETREGS, tid, 0, ®s); 497 if (ret < 0) 498 { 499 warning ("Unable to store general register."); 500 return; 501 } 502 } 503 504 static void 505 store_regs (void) 506 { 507 int ret, regno, tid; 508 elf_gregset_t regs; 509 510 /* Get the thread id for the ptrace call. */ 511 tid = GET_THREAD_ID (inferior_ptid); 512 513 /* Fetch the general registers. */ 514 ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); 515 if (ret < 0) 516 { 517 warning ("Unable to fetch general registers."); 518 return; 519 } 520 521 for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++) 522 { 523 if (register_cached (regno)) 524 regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]); 525 } 526 527 ret = ptrace (PTRACE_SETREGS, tid, 0, ®s); 528 529 if (ret < 0) 530 { 531 warning ("Unable to store general registers."); 532 return; 533 } 534 } 535 536 /* Fetch registers from the child process. Fetch all registers if 537 regno == -1, otherwise fetch all general registers or all floating 538 point registers depending upon the value of regno. */ 539 540 void 541 fetch_inferior_registers (int regno) 542 { 543 if (-1 == regno) 544 { 545 fetch_regs (); 546 fetch_fpregs (); 547 } 548 else 549 { 550 if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) 551 fetch_register (regno); 552 553 if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM) 554 fetch_fpregister (regno); 555 } 556 } 557 558 /* Store registers back into the inferior. Store all registers if 559 regno == -1, otherwise store all general registers or all floating 560 point registers depending upon the value of regno. */ 561 562 void 563 store_inferior_registers (int regno) 564 { 565 if (-1 == regno) 566 { 567 store_regs (); 568 store_fpregs (); 569 } 570 else 571 { 572 if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM)) 573 store_register (regno); 574 575 if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM)) 576 store_fpregister (regno); 577 } 578 } 579 580 /* Fill register regno (if it is a general-purpose register) in 581 *gregsetp with the appropriate value from GDB's register array. 582 If regno is -1, do this for all registers. */ 583 584 void 585 fill_gregset (gdb_gregset_t *gregsetp, int regno) 586 { 587 if (-1 == regno) 588 { 589 int regnum; 590 for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++) 591 regcache_raw_collect (current_regcache, regnum, 592 (char *) &(*gregsetp)[regnum]); 593 } 594 else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) 595 regcache_raw_collect (current_regcache, regno, 596 (char *) &(*gregsetp)[regno]); 597 598 if (ARM_PS_REGNUM == regno || -1 == regno) 599 { 600 if (arm_apcs_32) 601 regcache_raw_collect (current_regcache, ARM_PS_REGNUM, 602 (char *) &(*gregsetp)[ARM_CPSR_REGNUM]); 603 else 604 regcache_raw_collect (current_regcache, ARM_PC_REGNUM, 605 (char *) &(*gregsetp)[ARM_PC_REGNUM]); 606 } 607 } 608 609 /* Fill GDB's register array with the general-purpose register values 610 in *gregsetp. */ 611 612 void 613 supply_gregset (gdb_gregset_t *gregsetp) 614 { 615 int regno, reg_pc; 616 617 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) 618 regcache_raw_supply (current_regcache, regno, 619 (char *) &(*gregsetp)[regno]); 620 621 if (arm_apcs_32) 622 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 623 (char *) &(*gregsetp)[ARM_CPSR_REGNUM]); 624 else 625 regcache_raw_supply (current_regcache, ARM_PS_REGNUM, 626 (char *) &(*gregsetp)[ARM_PC_REGNUM]); 627 628 reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]); 629 regcache_raw_supply (current_regcache, ARM_PC_REGNUM, (char *) ®_pc); 630 } 631 632 /* Fill register regno (if it is a floating-point register) in 633 *fpregsetp with the appropriate value from GDB's register array. 634 If regno is -1, do this for all registers. */ 635 636 void 637 fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) 638 { 639 FPA11 *fp = (FPA11 *) fpregsetp; 640 641 if (-1 == regno) 642 { 643 int regnum; 644 for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++) 645 store_nwfpe_register (regnum, fp); 646 } 647 else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) 648 { 649 store_nwfpe_register (regno, fp); 650 return; 651 } 652 653 /* Store fpsr. */ 654 if (ARM_FPS_REGNUM == regno || -1 == regno) 655 regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, 656 (char *) &fp->fpsr); 657 } 658 659 /* Fill GDB's register array with the floating-point register values 660 in *fpregsetp. */ 661 662 void 663 supply_fpregset (gdb_fpregset_t *fpregsetp) 664 { 665 int regno; 666 FPA11 *fp = (FPA11 *) fpregsetp; 667 668 /* Fetch fpsr. */ 669 regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp->fpsr); 670 671 /* Fetch the floating point registers. */ 672 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) 673 { 674 fetch_nwfpe_register (regno, fp); 675 } 676 } 677 678 int 679 arm_linux_kernel_u_size (void) 680 { 681 return (sizeof (struct user)); 682 } 683 684 static unsigned int 685 get_linux_version (unsigned int *vmajor, 686 unsigned int *vminor, 687 unsigned int *vrelease) 688 { 689 struct utsname info; 690 char *pmajor, *pminor, *prelease, *tail; 691 692 if (-1 == uname (&info)) 693 { 694 warning ("Unable to determine GNU/Linux version."); 695 return -1; 696 } 697 698 pmajor = strtok (info.release, "."); 699 pminor = strtok (NULL, "."); 700 prelease = strtok (NULL, "."); 701 702 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0); 703 *vminor = (unsigned int) strtoul (pminor, &tail, 0); 704 *vrelease = (unsigned int) strtoul (prelease, &tail, 0); 705 706 return ((*vmajor << 16) | (*vminor << 8) | *vrelease); 707 } 708 709 void 710 _initialize_arm_linux_nat (void) 711 { 712 os_version = get_linux_version (&os_major, &os_minor, &os_release); 713 } 714