#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#include "gdbarch.h"
#include "gdbcmd.h"
char *registers;
signed char *register_valid;
static int registers_pid = -1;
int
register_cached (int regnum)
{
return register_valid[regnum];
}
void
register_changed (int regnum)
{
register_valid[regnum] = 0;
}
CORE_ADDR
find_saved_register (struct frame_info *frame, int regnum)
{
register struct frame_info *frame1 = NULL;
register CORE_ADDR addr = 0;
if (frame == NULL)
return 0;
#ifdef HAVE_REGISTER_WINDOWS
if (REGISTER_IN_WINDOW_P (regnum))
{
frame1 = get_next_frame (frame);
if (!frame1)
return 0;
if (regnum != SP_REGNUM)
frame1 = frame;
FRAME_INIT_SAVED_REGS (frame1);
return frame1->saved_regs[regnum];
}
#endif
while (1)
{
QUIT;
frame1 = get_prev_frame (frame1);
if (frame1 == 0 || frame1 == frame)
break;
FRAME_INIT_SAVED_REGS (frame1);
if (frame1->saved_regs[regnum])
addr = frame1->saved_regs[regnum];
}
return addr;
}
static void
default_get_saved_register (char *raw_buffer,
int *optimized,
CORE_ADDR *addrp,
struct frame_info *frame,
int regnum,
enum lval_type *lval)
{
CORE_ADDR addr;
if (!target_has_registers)
error ("No registers.");
if (optimized != NULL)
*optimized = 0;
addr = find_saved_register (frame, regnum);
if (addr != 0)
{
if (lval != NULL)
*lval = lval_memory;
if (regnum == SP_REGNUM)
{
if (raw_buffer != NULL)
{
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
(LONGEST) addr);
}
if (addrp != NULL)
*addrp = 0;
return;
}
if (raw_buffer != NULL)
target_read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
}
else
{
if (lval != NULL)
*lval = lval_register;
addr = REGISTER_BYTE (regnum);
if (raw_buffer != NULL)
read_register_gen (regnum, raw_buffer);
}
if (addrp != NULL)
*addrp = addr;
}
#if !defined (GET_SAVED_REGISTER)
#define GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) \
default_get_saved_register(raw_buffer, optimized, addrp, frame, regnum, lval)
#endif
void
get_saved_register (char *raw_buffer,
int *optimized,
CORE_ADDR *addrp,
struct frame_info *frame,
int regnum,
enum lval_type *lval)
{
GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval);
}
static int
read_relative_register_raw_bytes_for_frame (int regnum,
char *myaddr,
struct frame_info *frame)
{
int optim;
if (regnum == FP_REGNUM && frame)
{
store_address (myaddr, REGISTER_RAW_SIZE (FP_REGNUM),
(LONGEST) FRAME_FP (frame));
return 0;
}
get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, frame,
regnum, (enum lval_type *) NULL);
if (register_valid[regnum] < 0)
return 1;
return optim;
}
int
read_relative_register_raw_bytes (int regnum, char *myaddr)
{
return read_relative_register_raw_bytes_for_frame (regnum, myaddr,
selected_frame);
}
void
registers_changed (void)
{
int i;
registers_pid = -1;
alloca (0);
for (i = 0; i < ARCH_NUM_REGS; i++)
register_valid[i] = 0;
for (i = NUM_REGS; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
register_valid[i] = 0;
if (registers_changed_hook)
registers_changed_hook ();
}
void
registers_fetched (void)
{
int i;
for (i = 0; i < ARCH_NUM_REGS; i++)
register_valid[i] = 1;
}
void
read_register_bytes (int inregbyte, char *myaddr, int inlen)
{
int inregend = inregbyte + inlen;
int regno;
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
for (regno = 0; regno < NUM_REGS + NUM_PSEUDO_REGS; regno++)
{
int regstart, regend;
if (register_valid[regno])
continue;
if (REGISTER_NAME (regno) == NULL || *REGISTER_NAME (regno) == '\0')
continue;
regstart = REGISTER_BYTE (regno);
regend = regstart + REGISTER_RAW_SIZE (regno);
if (regend <= inregbyte || inregend <= regstart)
continue;
if (regno < NUM_REGS)
target_fetch_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
FETCH_PSEUDO_REGISTER (regno);
if (!register_valid[regno])
error ("read_register_bytes: Couldn't update register %d.", regno);
}
if (myaddr != NULL)
memcpy (myaddr, ®isters[inregbyte], inlen);
}
void
read_register_gen (int regno, char *myaddr)
{
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
if (!register_valid[regno])
{
if (regno < NUM_REGS)
target_fetch_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
FETCH_PSEUDO_REGISTER (regno);
}
memcpy (myaddr, ®isters[REGISTER_BYTE (regno)],
REGISTER_RAW_SIZE (regno));
}
#if !defined (CANNOT_STORE_REGISTER)
#define CANNOT_STORE_REGISTER(regno) 0
#endif
void
write_register_gen (int regno, char *myaddr)
{
int size;
if (CANNOT_STORE_REGISTER (regno))
return;
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
size = REGISTER_RAW_SIZE (regno);
if (register_valid[regno]
&& memcmp (®isters[REGISTER_BYTE (regno)], myaddr, size) == 0)
return;
if (regno < NUM_REGS)
target_prepare_to_store ();
memcpy (®isters[REGISTER_BYTE (regno)], myaddr, size);
register_valid[regno] = 1;
if (regno < NUM_REGS)
target_store_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
STORE_PSEUDO_REGISTER (regno);
}
void
write_register_bytes (int myregstart, char *myaddr, int inlen)
{
int myregend = myregstart + inlen;
int regno;
target_prepare_to_store ();
for (regno = 0; regno < NUM_REGS + NUM_PSEUDO_REGS; regno++)
{
int regstart, regend;
regstart = REGISTER_BYTE (regno);
regend = regstart + REGISTER_RAW_SIZE (regno);
if (myregend <= regstart || regend <= myregstart)
;
else if (myregstart <= regstart && regend <= myregend)
write_register_gen (regno, myaddr + (regstart - myregstart));
else
{
char regbuf[MAX_REGISTER_RAW_SIZE];
int overlapstart = max (regstart, myregstart);
int overlapend = min (regend, myregend);
read_register_gen (regno, regbuf);
memcpy (registers + overlapstart,
myaddr + (overlapstart - myregstart),
overlapend - overlapstart);
if (regno < NUM_REGS)
target_store_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
STORE_PSEUDO_REGISTER (regno);
}
}
}
ULONGEST
read_register (int regno)
{
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
if (!register_valid[regno])
{
if (regno < NUM_REGS)
target_fetch_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
FETCH_PSEUDO_REGISTER (regno);
}
return (extract_unsigned_integer (®isters[REGISTER_BYTE (regno)],
REGISTER_RAW_SIZE (regno)));
}
ULONGEST
read_register_pid (int regno, int pid)
{
int save_pid;
CORE_ADDR retval;
if (pid == inferior_pid)
return read_register (regno);
save_pid = inferior_pid;
inferior_pid = pid;
retval = read_register (regno);
inferior_pid = save_pid;
return retval;
}
LONGEST
read_signed_register (int regno)
{
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
if (!register_valid[regno])
target_fetch_registers (regno);
return (extract_signed_integer (®isters[REGISTER_BYTE (regno)],
REGISTER_RAW_SIZE (regno)));
}
LONGEST
read_signed_register_pid (int regno, int pid)
{
int save_pid;
LONGEST retval;
if (pid == inferior_pid)
return read_signed_register (regno);
save_pid = inferior_pid;
inferior_pid = pid;
retval = read_signed_register (regno);
inferior_pid = save_pid;
return retval;
}
void
write_register (int regno, LONGEST val)
{
PTR buf;
int size;
if (CANNOT_STORE_REGISTER (regno))
return;
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
size = REGISTER_RAW_SIZE (regno);
buf = alloca (size);
store_signed_integer (buf, size, (LONGEST) val);
if (register_valid[regno]
&& memcmp (®isters[REGISTER_BYTE (regno)], buf, size) == 0)
return;
if (regno < NUM_REGS)
target_prepare_to_store ();
memcpy (®isters[REGISTER_BYTE (regno)], buf, size);
register_valid[regno] = 1;
if (regno < NUM_REGS)
target_store_registers (regno);
else if (regno < NUM_REGS + NUM_PSEUDO_REGS)
STORE_PSEUDO_REGISTER (regno);
}
void
write_register_pid (int regno, CORE_ADDR val, int pid)
{
int save_pid;
if (pid == inferior_pid)
{
write_register (regno, val);
return;
}
save_pid = inferior_pid;
inferior_pid = pid;
write_register (regno, val);
inferior_pid = save_pid;
}
void
supply_register (int regno, char *val)
{
#if 1
if (registers_pid != inferior_pid)
{
registers_changed ();
registers_pid = inferior_pid;
}
#endif
register_valid[regno] = 1;
if (val)
memcpy (®isters[REGISTER_BYTE (regno)], val,
REGISTER_RAW_SIZE (regno));
else
memset (®isters[REGISTER_BYTE (regno)], '\000',
REGISTER_RAW_SIZE (regno));
#ifdef CLEAN_UP_REGISTER_VALUE
CLEAN_UP_REGISTER_VALUE (regno, ®isters[REGISTER_BYTE (regno)]);
#endif
}
CORE_ADDR
generic_target_read_pc (int pid)
{
#ifdef PC_REGNUM
if (PC_REGNUM >= 0)
{
CORE_ADDR pc_val = ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, pid));
return pc_val;
}
#endif
internal_error ("generic_target_read_pc");
return 0;
}
CORE_ADDR
read_pc_pid (int pid)
{
int saved_inferior_pid;
CORE_ADDR pc_val;
saved_inferior_pid = inferior_pid;
inferior_pid = pid;
pc_val = TARGET_READ_PC (pid);
inferior_pid = saved_inferior_pid;
return pc_val;
}
CORE_ADDR
read_pc (void)
{
return read_pc_pid (inferior_pid);
}
void
generic_target_write_pc (CORE_ADDR pc, int pid)
{
#ifdef PC_REGNUM
if (PC_REGNUM >= 0)
write_register_pid (PC_REGNUM, pc, pid);
if (NPC_REGNUM >= 0)
write_register_pid (NPC_REGNUM, pc + 4, pid);
if (NNPC_REGNUM >= 0)
write_register_pid (NNPC_REGNUM, pc + 8, pid);
#else
internal_error ("generic_target_write_pc");
#endif
}
void
write_pc_pid (CORE_ADDR pc, int pid)
{
int saved_inferior_pid;
saved_inferior_pid = inferior_pid;
inferior_pid = pid;
TARGET_WRITE_PC (pc, pid);
inferior_pid = saved_inferior_pid;
}
void
write_pc (CORE_ADDR pc)
{
write_pc_pid (pc, inferior_pid);
}
CORE_ADDR
generic_target_read_sp (void)
{
#ifdef SP_REGNUM
if (SP_REGNUM >= 0)
return read_register (SP_REGNUM);
#endif
internal_error ("generic_target_read_sp");
}
CORE_ADDR
read_sp (void)
{
return TARGET_READ_SP ();
}
void
generic_target_write_sp (CORE_ADDR val)
{
#ifdef SP_REGNUM
if (SP_REGNUM >= 0)
{
write_register (SP_REGNUM, val);
return;
}
#endif
internal_error ("generic_target_write_sp");
}
void
write_sp (CORE_ADDR val)
{
TARGET_WRITE_SP (val);
}
CORE_ADDR
generic_target_read_fp (void)
{
#ifdef FP_REGNUM
if (FP_REGNUM >= 0)
return read_register (FP_REGNUM);
#endif
internal_error ("generic_target_read_fp");
}
CORE_ADDR
read_fp (void)
{
return TARGET_READ_FP ();
}
void
generic_target_write_fp (CORE_ADDR val)
{
#ifdef FP_REGNUM
if (FP_REGNUM >= 0)
{
write_register (FP_REGNUM, val);
return;
}
#endif
internal_error ("generic_target_write_fp");
}
void
write_fp (CORE_ADDR val)
{
TARGET_WRITE_FP (val);
}
static void
reg_flush_command (char *command, int from_tty)
{
registers_changed ();
if (from_tty)
printf_filtered ("Register cache flushed.\n");
}
static void
build_regcache (void)
{
int sizeof_registers = REGISTER_BYTES + 256;
int sizeof_register_valid =
(NUM_REGS + NUM_PSEUDO_REGS) * sizeof (*register_valid);
registers = xmalloc (sizeof_registers);
memset (registers, 0, sizeof_registers);
register_valid = xmalloc (sizeof_register_valid);
memset (register_valid, 0, sizeof_register_valid);
}
void
_initialize_regcache (void)
{
build_regcache ();
register_gdbarch_swap (®isters, sizeof (registers), NULL);
register_gdbarch_swap (®ister_valid, sizeof (register_valid), NULL);
register_gdbarch_swap (NULL, 0, build_regcache);
add_com ("flushregs", class_maintenance, reg_flush_command,
"Force gdb to flush its register cache (maintainer command)");
}