X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fregcache.c;h=8d7957b30e9f450414ef6e4713cf6eac6813495d;hb=514c533895543e246eea1771ea67f3c3486006a4;hp=6ec6816487549d3a0a99cc1985bbfa7d664ec6d8;hpb=4c38e0a4fcb69f8586d8db0b9cdb8dbab5980811;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 6ec6816487..8d7957b30e 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -1,6 +1,5 @@ /* Register support routines for the remote server for GDB. - Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. This file is part of GDB. @@ -19,235 +18,445 @@ #include "server.h" #include "regdef.h" +#include "gdbthread.h" +#include "tdesc.h" +#include "rsp-low.h" +#ifndef IN_PROCESS_AGENT -#include -#include - -/* The private data for the register cache. Note that we have one - per inferior; this is primarily for simplicity, as the performance - benefit is minimal. */ - -struct inferior_regcache_data +struct regcache * +get_thread_regcache (struct thread_info *thread, int fetch) { - int registers_valid; - unsigned char *registers; -}; - -static int register_bytes; - -static struct reg *reg_defs; -static int num_registers; + struct regcache *regcache; -const char **gdbserver_expedite_regs; + regcache = (struct regcache *) inferior_regcache_data (thread); -static struct inferior_regcache_data * -get_regcache (struct thread_info *inf, int fetch) -{ - struct inferior_regcache_data *regcache; + /* Threads' regcaches are created lazily, because biarch targets add + the main thread/lwp before seeing it stop for the first time, and + it is only after the target sees the thread stop for the first + time that the target has a chance of determining the process's + architecture. IOW, when we first add the process's main thread + we don't know which architecture/tdesc its regcache should + have. */ + if (regcache == NULL) + { + struct process_info *proc = get_thread_process (thread); - regcache = (struct inferior_regcache_data *) inferior_regcache_data (inf); + gdb_assert (proc->tdesc != NULL); - if (regcache == NULL) - fatal ("no register cache"); + regcache = new_register_cache (proc->tdesc); + set_inferior_regcache_data (thread, regcache); + } - /* FIXME - fetch registers for INF */ if (fetch && regcache->registers_valid == 0) { - fetch_inferior_registers (-1); + struct thread_info *saved_thread = current_thread; + + current_thread = thread; + /* Invalidate all registers, to prevent stale left-overs. */ + memset (regcache->register_status, REG_UNAVAILABLE, + regcache->tdesc->num_registers); + fetch_inferior_registers (regcache, -1); + current_thread = saved_thread; regcache->registers_valid = 1; } return regcache; } +/* See common/common-regcache.h. */ + +struct regcache * +get_thread_regcache_for_ptid (ptid_t ptid) +{ + return get_thread_regcache (find_thread_ptid (ptid), 1); +} + void -regcache_invalidate_one (struct inferior_list_entry *entry) +regcache_invalidate_thread (struct thread_info *thread) { - struct thread_info *thread = (struct thread_info *) entry; - struct inferior_regcache_data *regcache; + struct regcache *regcache; - regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread); + regcache = (struct regcache *) inferior_regcache_data (thread); + + if (regcache == NULL) + return; if (regcache->registers_valid) { - struct thread_info *saved_inferior = current_inferior; + struct thread_info *saved_thread = current_thread; - current_inferior = thread; - store_inferior_registers (-1); - current_inferior = saved_inferior; + current_thread = thread; + store_inferior_registers (regcache, -1); + current_thread = saved_thread; } regcache->registers_valid = 0; } -void -regcache_invalidate () +static int +regcache_invalidate_one (struct inferior_list_entry *entry, + void *pid_p) { - for_each_inferior (&all_threads, regcache_invalidate_one); + struct thread_info *thread = (struct thread_info *) entry; + int pid = *(int *) pid_p; + + /* Only invalidate the regcaches of threads of this process. */ + if (ptid_get_pid (entry->id) == pid) + regcache_invalidate_thread (thread); + + return 0; } -void * -new_register_cache (void) +void +regcache_invalidate (void) { - struct inferior_regcache_data *regcache; + /* Only update the threads of the current process. */ + int pid = ptid_get_pid (current_thread->entry.id); - if (register_bytes == 0) - return NULL; /* The architecture hasn't been initialized yet. */ + find_inferior (&all_threads, regcache_invalidate_one, &pid); +} - regcache = xmalloc (sizeof (*regcache)); +#endif - /* Make sure to zero-initialize the register cache when it is created, - in case there are registers the target never fetches. This way they'll - read as zero instead of garbage. */ - regcache->registers = xcalloc (1, register_bytes); +struct regcache * +init_register_cache (struct regcache *regcache, + const struct target_desc *tdesc, + unsigned char *regbuf) +{ + if (regbuf == NULL) + { +#ifndef IN_PROCESS_AGENT + /* Make sure to zero-initialize the register cache when it is + created, in case there are registers the target never + fetches. This way they'll read as zero instead of + garbage. */ + regcache->tdesc = tdesc; + regcache->registers = xcalloc (1, tdesc->registers_size); + regcache->registers_owned = 1; + regcache->register_status = xcalloc (1, tdesc->num_registers); + gdb_assert (REG_UNAVAILABLE == 0); +#else + gdb_assert_not_reached ("can't allocate memory from the heap"); +#endif + } + else + { + regcache->tdesc = tdesc; + regcache->registers = regbuf; + regcache->registers_owned = 0; +#ifndef IN_PROCESS_AGENT + regcache->register_status = NULL; +#endif + } regcache->registers_valid = 0; return regcache; } -void -free_register_cache (void *regcache_p) +#ifndef IN_PROCESS_AGENT + +struct regcache * +new_register_cache (const struct target_desc *tdesc) { - struct inferior_regcache_data *regcache - = (struct inferior_regcache_data *) regcache_p; + struct regcache *regcache; + + gdb_assert (tdesc->registers_size != 0); + + regcache = xmalloc (sizeof (*regcache)); + return init_register_cache (regcache, tdesc, NULL); +} +void +free_register_cache (struct regcache *regcache) +{ if (regcache) { - free (regcache->registers); + if (regcache->registers_owned) + free (regcache->registers); + free (regcache->register_status); free (regcache); } } -static void -realloc_register_cache (struct inferior_list_entry *thread_p) -{ - struct thread_info *thread = (struct thread_info *) thread_p; - - free_register_cache (inferior_regcache_data (thread)); - set_inferior_regcache_data (thread, new_register_cache ()); -} +#endif void -set_register_cache (struct reg *regs, int n) +regcache_cpy (struct regcache *dst, struct regcache *src) { - int offset, i; - - reg_defs = regs; - num_registers = n; - - offset = 0; - for (i = 0; i < n; i++) - { - regs[i].offset = offset; - offset += regs[i].size; - } - - register_bytes = offset / 8; + gdb_assert (src != NULL && dst != NULL); + gdb_assert (src->tdesc == dst->tdesc); + gdb_assert (src != dst); + + memcpy (dst->registers, src->registers, src->tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + if (dst->register_status != NULL && src->register_status != NULL) + memcpy (dst->register_status, src->register_status, + src->tdesc->num_registers); +#endif + dst->registers_valid = src->registers_valid; +} - /* Make sure PBUFSIZ is large enough to hold a full register packet. */ - if (2 * register_bytes + 32 > PBUFSIZ) - fatal ("Register packet size exceeds PBUFSIZ."); - /* Re-allocate all pre-existing register caches. */ - for_each_inferior (&all_threads, realloc_register_cache); -} +#ifndef IN_PROCESS_AGENT void -registers_to_string (char *buf) +registers_to_string (struct regcache *regcache, char *buf) { - unsigned char *registers = get_regcache (current_inferior, 1)->registers; + unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; + int i; - convert_int_to_ascii (registers, buf, register_bytes); + for (i = 0; i < tdesc->num_registers; i++) + { + if (regcache->register_status[i] == REG_VALID) + { + bin2hex (registers, buf, register_size (tdesc, i)); + buf += register_size (tdesc, i) * 2; + } + else + { + memset (buf, 'x', register_size (tdesc, i) * 2); + buf += register_size (tdesc, i) * 2; + } + registers += register_size (tdesc, i); + } + *buf = '\0'; } void -registers_from_string (char *buf) +registers_from_string (struct regcache *regcache, char *buf) { int len = strlen (buf); - unsigned char *registers = get_regcache (current_inferior, 1)->registers; + unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; - if (len != register_bytes * 2) + if (len != tdesc->registers_size * 2) { warning ("Wrong sized register packet (expected %d bytes, got %d)", - 2*register_bytes, len); - if (len > register_bytes * 2) - len = register_bytes * 2; + 2 * tdesc->registers_size, len); + if (len > tdesc->registers_size * 2) + len = tdesc->registers_size * 2; } - convert_ascii_to_int (buf, registers, len / 2); + hex2bin (buf, registers, len / 2); } struct reg * -find_register_by_name (const char *name) +find_register_by_name (const struct target_desc *tdesc, const char *name) { int i; - for (i = 0; i < num_registers; i++) - if (!strcmp (name, reg_defs[i].name)) - return ®_defs[i]; - fatal ("Unknown register %s requested", name); - return 0; + for (i = 0; i < tdesc->num_registers; i++) + if (strcmp (name, tdesc->reg_defs[i].name) == 0) + return &tdesc->reg_defs[i]; + internal_error (__FILE__, __LINE__, "Unknown register %s requested", + name); } int -find_regno (const char *name) +find_regno (const struct target_desc *tdesc, const char *name) { int i; - for (i = 0; i < num_registers; i++) - if (!strcmp (name, reg_defs[i].name)) + for (i = 0; i < tdesc->num_registers; i++) + if (strcmp (name, tdesc->reg_defs[i].name) == 0) return i; - fatal ("Unknown register %s requested", name); - return -1; + internal_error (__FILE__, __LINE__, "Unknown register %s requested", + name); } struct reg * -find_register_by_number (int n) +find_register_by_number (const struct target_desc *tdesc, int n) +{ + return &tdesc->reg_defs[n]; +} + +#endif + +#ifndef IN_PROCESS_AGENT +static void +free_register_cache_thread (struct thread_info *thread) +{ + struct regcache *regcache + = (struct regcache *) inferior_regcache_data (thread); + + if (regcache != NULL) + { + regcache_invalidate_thread (thread); + free_register_cache (regcache); + set_inferior_regcache_data (thread, NULL); + } +} + +static void +free_register_cache_thread_one (struct inferior_list_entry *entry) +{ + struct thread_info *thread = (struct thread_info *) entry; + + free_register_cache_thread (thread); +} + +void +regcache_release (void) { - return ®_defs[n]; + /* Flush and release all pre-existing register caches. */ + for_each_inferior (&all_threads, free_register_cache_thread_one); } +#endif int -register_size (int n) +register_cache_size (const struct target_desc *tdesc) { - return reg_defs[n].size / 8; + return tdesc->registers_size; +} + +int +register_size (const struct target_desc *tdesc, int n) +{ + return tdesc->reg_defs[n].size / 8; } static unsigned char * -register_data (int n, int fetch) +register_data (struct regcache *regcache, int n, int fetch) { - unsigned char *registers - = get_regcache (current_inferior, fetch)->registers; + return regcache->registers + regcache->tdesc->reg_defs[n].offset / 8; +} + +/* Supply register N, whose contents are stored in BUF, to REGCACHE. + If BUF is NULL, the register's value is recorded as + unavailable. */ - return registers + (reg_defs[n].offset / 8); +void +supply_register (struct regcache *regcache, int n, const void *buf) +{ + if (buf) + { + memcpy (register_data (regcache, n, 0), buf, + register_size (regcache->tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (regcache->register_status != NULL) + regcache->register_status[n] = REG_VALID; +#endif + } + else + { + memset (register_data (regcache, n, 0), 0, + register_size (regcache->tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (regcache->register_status != NULL) + regcache->register_status[n] = REG_UNAVAILABLE; +#endif + } } +/* Supply register N with value zero to REGCACHE. */ + void -supply_register (int n, const void *buf) +supply_register_zeroed (struct regcache *regcache, int n) { - memcpy (register_data (n, 0), buf, register_size (n)); + memset (register_data (regcache, n, 0), 0, + register_size (regcache->tdesc, n)); +#ifndef IN_PROCESS_AGENT + if (regcache->register_status != NULL) + regcache->register_status[n] = REG_VALID; +#endif } +/* Supply the whole register set whose contents are stored in BUF, to + REGCACHE. If BUF is NULL, all the registers' values are recorded + as unavailable. */ + void -supply_register_by_name (const char *name, const void *buf) +supply_regblock (struct regcache *regcache, const void *buf) { - supply_register (find_regno (name), buf); + if (buf) + { + const struct target_desc *tdesc = regcache->tdesc; + + memcpy (regcache->registers, buf, tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + { + int i; + + for (i = 0; i < tdesc->num_registers; i++) + regcache->register_status[i] = REG_VALID; + } +#endif + } + else + { + const struct target_desc *tdesc = regcache->tdesc; + + memset (regcache->registers, 0, tdesc->registers_size); +#ifndef IN_PROCESS_AGENT + { + int i; + + for (i = 0; i < tdesc->num_registers; i++) + regcache->register_status[i] = REG_UNAVAILABLE; + } +#endif + } } +#ifndef IN_PROCESS_AGENT + void -collect_register (int n, void *buf) +supply_register_by_name (struct regcache *regcache, + const char *name, const void *buf) { - memcpy (buf, register_data (n, 1), register_size (n)); + supply_register (regcache, find_regno (regcache->tdesc, name), buf); } +#endif + void -collect_register_as_string (int n, char *buf) +collect_register (struct regcache *regcache, int n, void *buf) { - convert_int_to_ascii (register_data (n, 1), buf, register_size (n)); + memcpy (buf, register_data (regcache, n, 1), + register_size (regcache->tdesc, n)); } +#ifndef IN_PROCESS_AGENT + void -collect_register_by_name (const char *name, void *buf) +collect_register_as_string (struct regcache *regcache, int n, char *buf) { - collect_register (find_regno (name), buf); + bin2hex (register_data (regcache, n, 1), buf, + register_size (regcache->tdesc, n)); } + +void +collect_register_by_name (struct regcache *regcache, + const char *name, void *buf) +{ + collect_register (regcache, find_regno (regcache->tdesc, name), buf); +} + +/* Special handling for register PC. */ + +CORE_ADDR +regcache_read_pc (struct regcache *regcache) +{ + CORE_ADDR pc_val; + + if (the_target->read_pc) + pc_val = the_target->read_pc (regcache); + else + internal_error (__FILE__, __LINE__, + "regcache_read_pc: Unable to find PC"); + + return pc_val; +} + +void +regcache_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + if (the_target->write_pc) + the_target->write_pc (regcache, pc); + else + internal_error (__FILE__, __LINE__, + "regcache_write_pc: Unable to update PC"); +} + +#endif