diff options
Diffstat (limited to 'gdb/hppah-nat.c')
-rw-r--r-- | gdb/hppah-nat.c | 124 |
1 files changed, 93 insertions, 31 deletions
diff --git a/gdb/hppah-nat.c b/gdb/hppah-nat.c index 585ba71..11e9d02 100644 --- a/gdb/hppah-nat.c +++ b/gdb/hppah-nat.c @@ -46,6 +46,9 @@ fetch_inferior_registers (regno) fetch_register (regno); } +/* Our own version of the offsetof macro, since we can't assume ANSI C. */ +#define HPPAH_OFFSETOF(type, member) ((int) (&((type *) 0)->member)) + /* Store our register values back into the inferior. If REGNO is -1, do this for all registers. Otherwise, REGNO specifies which register (so we can save time). */ @@ -62,42 +65,104 @@ store_inferior_registers (regno) if (regno >= 0) { + unsigned int addr, len, offset; + if (CANNOT_STORE_REGISTER (regno)) return; - regaddr = register_addr (regno, offset); - errno = 0; - if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + + offset = 0; + len = REGISTER_RAW_SIZE (regno); + + /* Requests for register zero actually want the save_state's + ss_flags member. As RM says: "Oh, what a hack!" */ + if (regno == 0) { - scratch = *(int *) ®isters[REGISTER_BYTE (regno)] | 0x3; - call_ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - scratch); + save_state_t ss; + addr = HPPAH_OFFSETOF (save_state_t, ss_flags); + len = sizeof (ss.ss_flags); + + /* Note that ss_flags is always an int, no matter what + REGISTER_RAW_SIZE(0) says. Assuming all HP-UX PA machines + are big-endian, put it at the least significant end of the + value, and zap the rest of the buffer. */ + offset = REGISTER_RAW_SIZE (0) - len; + } + + /* Floating-point registers come from the ss_fpblock area. */ + else if (regno >= FP0_REGNUM) + addr = (HPPAH_OFFSETOF (save_state_t, ss_fpblock) + + (REGISTER_BYTE (regno) - REGISTER_BYTE (FP0_REGNUM))); + + /* Wide registers come from the ss_wide area. + I think it's more PC to test (ss_flags & SS_WIDEREGS) to select + between ss_wide and ss_narrow than to use the raw register size. + But checking ss_flags would require an extra ptrace call for + every register reference. Bleah. */ + else if (len == 8) + addr = (HPPAH_OFFSETOF (save_state_t, ss_wide) + + REGISTER_BYTE (regno)); + + /* Narrow registers come from the ss_narrow area. Note that + ss_narrow starts with gr1, not gr0. */ + else if (len == 4) + addr = (HPPAH_OFFSETOF (save_state_t, ss_narrow) + + (REGISTER_BYTE (regno) - REGISTER_BYTE (1))); + else + internal_error ("hppah-nat.c (write_register): unexpected register size"); + +#ifdef GDB_TARGET_IS_HPPA_20W + /* Unbelieveable. The PC head and tail must be written in 64bit hunks + or we will get an error. Worse yet, the oddball ptrace/ttrace + layering will not allow us to perform a 64bit register store. + + What a crock. */ + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM && len == 8) + { + CORE_ADDR temp; + + temp = *(CORE_ADDR *)®isters[REGISTER_BYTE (regno)]; + + /* Set the priv level (stored in the low two bits of the PC. */ + temp |= 0x3; + + ttrace_write_reg_64 (inferior_pid, (CORE_ADDR)addr, (CORE_ADDR)&temp); + + /* If we fail to write the PC, give a true error instead of + just a warning. */ if (errno != 0) { - /* Error, even if attached. Failing to write these two - registers is pretty serious. */ - sprintf (buf, "writing register number %d", regno); - perror_with_name (buf); + char *err = safe_strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "writing `%s' register: %s", + REGISTER_NAME (regno), err); + perror_with_name (msg); } + return; } - else - for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) - { - errno = 0; - call_ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, - *(int *) ®isters[REGISTER_BYTE (regno) + i]); - if (errno != 0) - { - /* Warning, not error, in case we are attached; sometimes the - kernel doesn't let us at the registers. */ - char *err = safe_strerror (errno); - char *msg = alloca (strlen (err) + 128); - sprintf (msg, "writing register %s: %s", - REGISTER_NAME (regno), err); +#endif + + for (i = 0; i < len; i += sizeof (int)) + { + errno = 0; + call_ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) addr + i, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes + the kernel doesn't let us at the registers. */ + char *err = safe_strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "reading `%s' register: %s", + REGISTER_NAME (regno), err); + /* If we fail to write the PC, give a true error instead of + just a warning. */ + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + perror_with_name (msg); + else warning (msg); - return; - } - regaddr += sizeof (int); - } + return; + } + } } else for (regno = 0; regno < NUM_REGS; regno++) @@ -105,9 +170,6 @@ store_inferior_registers (regno) } -/* Our own version of the offsetof macro, since we can't assume ANSI C. */ -#define HPPAH_OFFSETOF(type, member) ((int) (&((type *) 0)->member)) - /* Fetch a register's value from the process's U area. */ static void fetch_register (regno) |