| /* Register support routines for the remote server for GDB. | |
| Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008, 2009, 2010 | |
| Free Software Foundation, Inc. | |
| This file is part of GDB. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| #include "server.h" | |
| #include "regdef.h" | |
| #include <stdlib.h> | |
| #include <string.h> | |
| static int register_bytes; | |
| static struct reg *reg_defs; | |
| static int num_registers; | |
| const char **gdbserver_expedite_regs; | |
| #ifndef IN_PROCESS_AGENT | |
| struct regcache * | |
| get_thread_regcache (struct thread_info *thread, int fetch) | |
| { | |
| struct regcache *regcache; | |
| regcache = (struct regcache *) inferior_regcache_data (thread); | |
| if (regcache == NULL) | |
| fatal ("no register cache"); | |
| if (fetch && regcache->registers_valid == 0) | |
| { | |
| struct thread_info *saved_inferior = current_inferior; | |
| current_inferior = thread; | |
| fetch_inferior_registers (regcache, -1); | |
| current_inferior = saved_inferior; | |
| regcache->registers_valid = 1; | |
| } | |
| return regcache; | |
| } | |
| void | |
| regcache_invalidate_one (struct inferior_list_entry *entry) | |
| { | |
| struct thread_info *thread = (struct thread_info *) entry; | |
| struct regcache *regcache; | |
| regcache = (struct regcache *) inferior_regcache_data (thread); | |
| if (regcache == NULL) | |
| return; | |
| if (regcache->registers_valid) | |
| { | |
| struct thread_info *saved_inferior = current_inferior; | |
| current_inferior = thread; | |
| store_inferior_registers (regcache, -1); | |
| current_inferior = saved_inferior; | |
| } | |
| regcache->registers_valid = 0; | |
| } | |
| void | |
| regcache_invalidate (void) | |
| { | |
| for_each_inferior (&all_threads, regcache_invalidate_one); | |
| } | |
| #endif | |
| struct regcache * | |
| init_register_cache (struct regcache *regcache, unsigned char *regbuf) | |
| { | |
| #ifndef IN_PROCESS_AGENT | |
| if (regbuf == NULL) | |
| { | |
| /* 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); | |
| regcache->registers_owned = 1; | |
| } | |
| else | |
| #else | |
| if (regbuf == NULL) | |
| fatal ("init_register_cache: can't allocate memory from the heap"); | |
| else | |
| #endif | |
| { | |
| regcache->registers = regbuf; | |
| regcache->registers_owned = 0; | |
| } | |
| regcache->registers_valid = 0; | |
| return regcache; | |
| } | |
| #ifndef IN_PROCESS_AGENT | |
| struct regcache * | |
| new_register_cache (void) | |
| { | |
| struct regcache *regcache; | |
| if (register_bytes == 0) | |
| return NULL; /* The architecture hasn't been initialized yet. */ | |
| regcache = xmalloc (sizeof (*regcache)); | |
| return init_register_cache (regcache, NULL); | |
| } | |
| void | |
| free_register_cache (struct regcache *regcache) | |
| { | |
| if (regcache) | |
| { | |
| if (regcache->registers_owned) | |
| free (regcache->registers); | |
| free (regcache); | |
| } | |
| } | |
| #endif | |
| void | |
| regcache_cpy (struct regcache *dst, struct regcache *src) | |
| { | |
| memcpy (dst->registers, src->registers, register_bytes); | |
| dst->registers_valid = src->registers_valid; | |
| } | |
| #ifndef IN_PROCESS_AGENT | |
| static void | |
| realloc_register_cache (struct inferior_list_entry *thread_p) | |
| { | |
| struct thread_info *thread = (struct thread_info *) thread_p; | |
| struct regcache *regcache | |
| = (struct regcache *) inferior_regcache_data (thread); | |
| if (regcache != NULL) | |
| regcache_invalidate_one (thread_p); | |
| free_register_cache (regcache); | |
| set_inferior_regcache_data (thread, new_register_cache ()); | |
| } | |
| #endif | |
| void | |
| set_register_cache (struct reg *regs, int n) | |
| { | |
| int offset, i; | |
| #ifndef IN_PROCESS_AGENT | |
| /* Before changing the register cache internal layout, flush the | |
| contents of valid caches back to the threads. */ | |
| regcache_invalidate (); | |
| #endif | |
| 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; | |
| /* Make sure PBUFSIZ is large enough to hold a full register packet. */ | |
| if (2 * register_bytes + 32 > PBUFSIZ) | |
| fatal ("Register packet size exceeds PBUFSIZ."); | |
| #ifndef IN_PROCESS_AGENT | |
| /* Re-allocate all pre-existing register caches. */ | |
| for_each_inferior (&all_threads, realloc_register_cache); | |
| #endif | |
| } | |
| int | |
| register_cache_size (void) | |
| { | |
| return register_bytes; | |
| } | |
| #ifndef IN_PROCESS_AGENT | |
| void | |
| registers_to_string (struct regcache *regcache, char *buf) | |
| { | |
| unsigned char *registers = regcache->registers; | |
| convert_int_to_ascii (registers, buf, register_bytes); | |
| } | |
| void | |
| registers_from_string (struct regcache *regcache, char *buf) | |
| { | |
| int len = strlen (buf); | |
| unsigned char *registers = regcache->registers; | |
| if (len != register_bytes * 2) | |
| { | |
| warning ("Wrong sized register packet (expected %d bytes, got %d)", | |
| 2*register_bytes, len); | |
| if (len > register_bytes * 2) | |
| len = register_bytes * 2; | |
| } | |
| convert_ascii_to_int (buf, registers, len / 2); | |
| } | |
| struct reg * | |
| find_register_by_name (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; | |
| } | |
| int | |
| find_regno (const char *name) | |
| { | |
| int i; | |
| for (i = 0; i < num_registers; i++) | |
| if (!strcmp (name, reg_defs[i].name)) | |
| return i; | |
| fatal ("Unknown register %s requested", name); | |
| return -1; | |
| } | |
| struct reg * | |
| find_register_by_number (int n) | |
| { | |
| return ®_defs[n]; | |
| } | |
| #endif | |
| int | |
| register_size (int n) | |
| { | |
| return reg_defs[n].size / 8; | |
| } | |
| static unsigned char * | |
| register_data (struct regcache *regcache, int n, int fetch) | |
| { | |
| return regcache->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 (n)); | |
| else | |
| memset (register_data (regcache, n, 0), 0, register_size (n)); | |
| } | |
| void | |
| supply_regblock (struct regcache *regcache, const void *buf) | |
| { | |
| if (buf) | |
| memcpy (regcache->registers, buf, register_bytes); | |
| else | |
| memset (regcache->registers, 0, register_bytes); | |
| } | |
| #ifndef IN_PROCESS_AGENT | |
| void | |
| supply_register_by_name (struct regcache *regcache, | |
| const char *name, const void *buf) | |
| { | |
| supply_register (regcache, find_regno (name), buf); | |
| } | |
| #endif | |
| void | |
| collect_register (struct regcache *regcache, int n, void *buf) | |
| { | |
| memcpy (buf, register_data (regcache, n, 1), register_size (n)); | |
| } | |
| #ifndef IN_PROCESS_AGENT | |
| void | |
| collect_register_as_string (struct regcache *regcache, int n, char *buf) | |
| { | |
| convert_int_to_ascii (register_data (regcache, n, 1), | |
| buf, register_size (n)); | |
| } | |
| void | |
| collect_register_by_name (struct regcache *regcache, | |
| const char *name, void *buf) | |
| { | |
| collect_register (regcache, find_regno (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 |