/* 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). */ static void usr_store_inferior_registers (int regno) { CORE_ADDR regaddr; int i, size; char *buf; if (regno >= 0) { if (regno >= the_low_target.num_regs) return; if ((*the_low_target.cannot_store_register) (regno) == 1) return; regaddr = register_addr (regno); if (regaddr == -1) return; errno = 0; size = (register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) & - sizeof (PTRACE_XFER_TYPE); buf = alloca (size); memset (buf, 0, size); if (the_low_target.left_pad_xfer && register_size (regno) < sizeof (PTRACE_XFER_TYPE)) collect_register (regno, (buf + sizeof (PTRACE_XFER_TYPE) - register_size (regno))); else collect_register (regno, buf); for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, *(PTRACE_XFER_TYPE *) (buf + i)); if (errno != 0) { if ((*the_low_target.cannot_store_register) (regno) == 0) { char *err = strerror (errno); char *msg = alloca (strlen (err) + 128); sprintf (msg, "writing register %d: %s", regno, err); error (msg); return; } } regaddr += sizeof (PTRACE_XFER_TYPE); } } else for (regno = 0; regno < the_low_target.num_regs; regno++) usr_store_inferior_registers (regno); }
void linux_store_registers (int regno) { #ifdef HAVE_LINUX_REGSETS if (use_regsets_p) { if (regsets_store_inferior_registers () == 0) return; } #endif #ifdef HAVE_LINUX_USRREGS usr_store_inferior_registers (regno); #endif }
void valgrind_store_registers (int regno) { usr_store_inferior_registers (regno); }
/* 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). */ static void usr_store_inferior_registers (int regno) { int size; ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior); ThreadId tid = tst->tid; if (regno >= 0) { if (regno >= the_low_target.num_regs) { dlog(0, "error store_register regno %d max %d\n", regno, the_low_target.num_regs); return; } size = register_size (regno); if (size > 0) { Bool mod; Addr old_SP, new_SP; char buf[size]; if (regno == the_low_target.stack_pointer_regno) { /* When the stack pointer register is changed such that the stack is extended, we better inform the tool of the stack increase. This is needed in particular to avoid spurious Memcheck errors during Inferior calls. So, we save in old_SP the SP before the change. A change of stack pointer is also assumed to have initialised this new stack space. For the typical example of an inferior call, gdb writes arguments on the stack, and then changes the stack pointer. As the stack increase tool function might mark it as undefined, we have to call it at the good moment. */ VG_(memset) ((void *) &old_SP, 0, size); (*the_low_target.transfer_register) (tid, regno, (void *) &old_SP, valgrind_to_gdbserver, size, &mod); } VG_(memset) (buf, 0, size); collect_register (regno, buf); (*the_low_target.transfer_register) (tid, regno, buf, gdbserver_to_valgrind, size, &mod); if (mod && VG_(debugLog_getLevel)() > 1) { char bufimage [2*size + 1]; heximage (bufimage, buf, size); dlog(2, "stored register %d size %d name %s value %s " "tid %d status %s\n", regno, size, the_low_target.reg_defs[regno].name, bufimage, tid, VG_(name_of_ThreadStatus) (tst->status)); } if (regno == the_low_target.stack_pointer_regno) { VG_(memcpy) (&new_SP, buf, size); if (old_SP > new_SP) { Word delta = (Word)new_SP - (Word)old_SP; dlog(1, " stack increase by stack pointer changed from %p to %p " "delta %ld\n", (void*) old_SP, (void *) new_SP, delta); VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, 0 ); VG_TRACK( new_mem_stack, new_SP, -delta ); VG_TRACK( post_mem_write, Vg_CoreClientReq, tid, new_SP, -delta); } } } } else { for (regno = 0; regno < the_low_target.num_regs; regno++) usr_store_inferior_registers (regno); } }