1/* Register support routines for the remote server for GDB.
2   Copyright (C) 2001, 2002, 2004, 2005, 2011
3   Free Software Foundation, Inc.
4
5   This file is part of GDB.
6   It has been modified to integrate it in valgrind
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street, Fifth Floor,
21   Boston, MA 02110-1301, USA.  */
22
23#include "server.h"
24#include "regdef.h"
25
26/* The private data for the register cache.  Note that we have one
27   per inferior; this is primarily for simplicity, as the performance
28   benefit is minimal.  */
29
30struct inferior_regcache_data
31{
32   int registers_valid;
33   unsigned char *registers;
34   Bool *register_supplied; /* set to True once it has been supplied */
35};
36
37static int register_bytes;
38
39static struct reg *reg_defs;
40static int num_registers;
41
42const char **gdbserver_expedite_regs;
43
44static
45struct inferior_regcache_data * get_regcache (struct thread_info *inf,
46                                              int fetch)
47{
48   struct inferior_regcache_data *regcache;
49
50   regcache = (struct inferior_regcache_data *) inferior_regcache_data (inf);
51
52   if (regcache == NULL)
53      fatal ("no register cache\n");
54
55   /* FIXME - fetch registers for INF */
56   if (fetch && regcache->registers_valid == 0) {
57      valgrind_fetch_registers (0);
58      regcache->registers_valid = 1;
59   }
60
61   return regcache;
62}
63
64void regcache_invalidate_one (struct inferior_list_entry *entry)
65{
66   struct thread_info *thread = (struct thread_info *) entry;
67   struct inferior_regcache_data *regcache;
68
69   regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
70
71   if (regcache->registers_valid) {
72      struct thread_info *saved_inferior = current_inferior;
73
74      current_inferior = thread;
75      valgrind_store_registers (-1);
76      current_inferior = saved_inferior;
77   }
78
79   regcache->registers_valid = 0;
80}
81
82void regcache_invalidate ()
83{
84   for_each_inferior (&all_threads, regcache_invalidate_one);
85}
86
87int registers_length (void)
88{
89   return 2 * register_bytes;
90}
91
92void *new_register_cache (void)
93{
94   struct inferior_regcache_data *regcache;
95
96   regcache = malloc (sizeof (*regcache));
97
98   /* Make sure to zero-initialize the register cache when it is created,
99      in case there are registers the target never fetches.  This way they'll
100      read as zero instead of garbage.  */
101   regcache->registers = calloc (1, register_bytes);
102   if (regcache->registers == NULL)
103      fatal ("Could not allocate register cache.\n");
104
105   regcache->register_supplied = calloc (1, num_registers);
106   if (regcache->register_supplied == NULL)
107      fatal ("Could not allocate register_supplied cache.\n");
108
109   regcache->registers_valid = 0;
110
111   return regcache;
112}
113
114void free_register_cache (void *regcache_p)
115{
116   struct inferior_regcache_data *regcache
117      = (struct inferior_regcache_data *) regcache_p;
118
119   free (regcache->registers);
120   free (regcache->register_supplied);
121   free (regcache);
122}
123
124/* if a regcache exists for entry, reallocate it.
125   This is needed if the shadow registers are added.
126   In such a case, a 2nd call to set_register_cache is done
127   which will cause the reallocation of already created caches. */
128static
129void regcache_realloc_one (struct inferior_list_entry *entry)
130{
131   struct thread_info *thread = (struct thread_info *) entry;
132   struct inferior_regcache_data *regcache;
133
134   regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
135
136   if (regcache) {
137      free_register_cache (regcache);
138      set_inferior_regcache_data (thread, new_register_cache ());
139   }
140}
141
142void set_register_cache (struct reg *regs, int n)
143{
144   int offset, i;
145
146   reg_defs = regs;
147   num_registers = n;
148
149   offset = 0;
150   for (i = 0; i < n; i++) {
151      regs[i].offset = offset;
152      offset += regs[i].size;
153   }
154
155   register_bytes = offset / 8;
156
157   for_each_inferior (&all_threads, regcache_realloc_one);
158}
159
160void registers_to_string (char *buf)
161{
162   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
163
164   convert_int_to_ascii (registers, buf, register_bytes);
165}
166
167void registers_from_string (char *buf)
168{
169   int len = strlen (buf);
170   unsigned char *registers = get_regcache (current_inferior, 1)->registers;
171
172   if (len != register_bytes * 2) {
173      warning ("Wrong sized register packet (expected %d bytes, got %d)\n",
174               2*register_bytes, len);
175      if (len > register_bytes * 2)
176         len = register_bytes * 2;
177   }
178   convert_ascii_to_int (buf, registers, len / 2);
179}
180
181int find_regno (const char *name)
182{
183   int i;
184
185   for (i = 0; i < num_registers; i++)
186      if (!strcmp (name, reg_defs[i].name))
187         return i;
188   fatal ("Unknown register %s requested\n", name);
189   return -1;
190}
191
192struct reg *find_register_by_number (int n)
193{
194   return &reg_defs[n];
195}
196
197int register_size (int n)
198{
199   return reg_defs[n].size / 8;
200}
201
202static
203unsigned char *register_data (int n, int fetch)
204{
205   unsigned char *registers
206      = get_regcache (current_inferior, fetch)->registers;
207
208   return registers + (reg_defs[n].offset / 8);
209}
210static
211unsigned char *register_data_for_supply (int n, int fetch, Bool *mod)
212{
213   struct inferior_regcache_data * cache
214      = get_regcache (current_inferior, fetch);
215   unsigned char *registers = cache->registers;
216
217   if (cache->register_supplied[n])
218      *mod = False;
219   else
220      *mod = True;
221   cache->register_supplied[n] = True;
222   return registers + (reg_defs[n].offset / 8);
223}
224
225void supply_register (int n, const void *buf, Bool *mod)
226{
227   Bool new;
228   VG_(dmemcpy) (register_data_for_supply (n, 0, &new),
229                 buf, register_size (n), mod);
230   if (new)
231      *mod = True;
232}
233
234void supply_register_from_string (int n, const char *buf, Bool *mod)
235{
236   Bool new;
237   unsigned char bytes_register[register_size (n)];
238   convert_ascii_to_int ((char *) buf, bytes_register, register_size (n));
239   VG_(dmemcpy) (register_data_for_supply (n, 0, &new),
240                 bytes_register, register_size (n), mod);
241   if (new)
242      *mod = True;
243}
244
245void supply_register_by_name (const char *name, const void *buf, Bool *mod)
246{
247   supply_register (find_regno (name), buf, mod);
248}
249
250void collect_register (int n, void *buf)
251{
252   VG_(memcpy) (buf, register_data (n, 1), register_size (n));
253}
254
255void collect_register_as_string (int n, char *buf)
256{
257   convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
258}
259
260void collect_register_by_name (const char *name, void *buf)
261{
262   collect_register (find_regno (name), buf);
263}
264