Commit | Line | Data |
---|---|---|
69517000 AC |
1 | /* Caching code for GDB, the GNU debugger. |
2 | ||
9b254dd1 | 3 | Copyright (C) 1992, 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2007, |
0fb0cc75 | 4 | 2008, 2009 Free Software Foundation, Inc. |
c906108c SS |
5 | |
6 | This file is part of GDB. | |
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 | |
a9762ec7 | 10 | the Free Software Foundation; either version 3 of the License, or |
c906108c SS |
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 | |
a9762ec7 | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
c906108c SS |
20 | |
21 | #include "defs.h" | |
22 | #include "dcache.h" | |
23 | #include "gdbcmd.h" | |
24 | #include "gdb_string.h" | |
25 | #include "gdbcore.h" | |
4930751a | 26 | #include "target.h" |
25f122dc | 27 | #include "splay-tree.h" |
c906108c | 28 | |
29e57380 C |
29 | /* The data cache could lead to incorrect results because it doesn't |
30 | know about volatile variables, thus making it impossible to debug | |
31 | functions which use memory mapped I/O devices. Set the nocache | |
32 | memory region attribute in those cases. | |
c906108c | 33 | |
25f122dc | 34 | In general the dcache speeds up performance. Some speed improvement |
c906108c SS |
35 | comes from the actual caching mechanism, but the major gain is in |
36 | the reduction of the remote protocol overhead; instead of reading | |
37 | or writing a large area of memory in 4 byte requests, the cache | |
25f122dc DE |
38 | bundles up the requests into LINE_SIZE chunks, reducing overhead |
39 | significantly. This is most useful when accessing a large amount | |
40 | of data, such as when performing a backtrace. | |
41 | ||
42 | The cache is a splay tree along with a linked list for replacement. | |
43 | Each block caches a LINE_SIZE area of memory. Wtihin each line we remember | |
44 | the address of the line (which must be a multiple of LINE_SIZE) and the | |
45 | actual data block. | |
46 | ||
47 | Lines are only allocated as needed, so DCACHE_SIZE really specifies the | |
48 | *maximum* number of lines in the cache. | |
49 | ||
50 | At present, the cache is write-through rather than writeback: as soon | |
51 | as data is written to the cache, it is also immediately written to | |
52 | the target. Therefore, cache lines are never "dirty". Whether a given | |
53 | line is valid or not depends on where it is stored in the dcache_struct; | |
54 | there is no per-block valid flag. */ | |
c906108c | 55 | |
29e57380 | 56 | /* NOTE: Interaction of dcache and memory region attributes |
c906108c | 57 | |
29e57380 C |
58 | As there is no requirement that memory region attributes be aligned |
59 | to or be a multiple of the dcache page size, dcache_read_line() and | |
60 | dcache_write_line() must break up the page by memory region. If a | |
61 | chunk does not have the cache attribute set, an invalid memory type | |
62 | is set, etc., then the chunk is skipped. Those chunks are handled | |
63 | in target_xfer_memory() (or target_xfer_memory_partial()). | |
c906108c | 64 | |
29e57380 C |
65 | This doesn't occur very often. The most common occurance is when |
66 | the last bit of the .text segment and the first bit of the .data | |
67 | segment fall within the same dcache page with a ro/cacheable memory | |
68 | region defined for the .text segment and a rw/non-cacheable memory | |
25f122dc | 69 | region defined for the .data segment. */ |
c906108c | 70 | |
25f122dc DE |
71 | /* The maximum number of lines stored. The total size of the cache is |
72 | equal to DCACHE_SIZE times LINE_SIZE. */ | |
73 | #define DCACHE_SIZE 4096 | |
c906108c | 74 | |
25f122dc DE |
75 | /* The size of a cache line. Smaller values reduce the time taken to |
76 | read a single byte and make the cache more granular, but increase | |
77 | overhead and reduce the effectiveness of the cache as a prefetcher. */ | |
78 | #define LINE_SIZE_POWER 6 | |
c906108c SS |
79 | #define LINE_SIZE (1 << LINE_SIZE_POWER) |
80 | ||
81 | /* Each cache block holds LINE_SIZE bytes of data | |
82 | starting at a multiple-of-LINE_SIZE address. */ | |
83 | ||
c5aa993b | 84 | #define LINE_SIZE_MASK ((LINE_SIZE - 1)) |
c906108c SS |
85 | #define XFORM(x) ((x) & LINE_SIZE_MASK) |
86 | #define MASK(x) ((x) & ~LINE_SIZE_MASK) | |
87 | ||
c906108c | 88 | struct dcache_block |
25f122dc DE |
89 | { |
90 | struct dcache_block *newer; /* for LRU and free list */ | |
91 | CORE_ADDR addr; /* address of data */ | |
92 | gdb_byte data[LINE_SIZE]; /* bytes at given address */ | |
93 | int refs; /* # hits */ | |
94 | }; | |
29e57380 | 95 | |
c5aa993b | 96 | struct dcache_struct |
25f122dc DE |
97 | { |
98 | splay_tree tree; | |
99 | struct dcache_block *oldest; | |
100 | struct dcache_block *newest; | |
c906108c | 101 | |
25f122dc | 102 | struct dcache_block *freelist; |
c906108c | 103 | |
25f122dc DE |
104 | /* The number of in-use lines in the cache. */ |
105 | int size; | |
106 | }; | |
c906108c | 107 | |
8edbea78 | 108 | static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr); |
c906108c | 109 | |
8edbea78 | 110 | static int dcache_write_line (DCACHE *dcache, struct dcache_block *db); |
c906108c | 111 | |
8edbea78 | 112 | static int dcache_read_line (DCACHE *dcache, struct dcache_block *db); |
c906108c | 113 | |
8edbea78 C |
114 | static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr); |
115 | ||
a14ed312 | 116 | static void dcache_info (char *exp, int tty); |
c906108c | 117 | |
a14ed312 | 118 | void _initialize_dcache (void); |
c906108c | 119 | |
917317f4 | 120 | static int dcache_enabled_p = 0; |
07128da0 | 121 | |
920d2a44 AC |
122 | static void |
123 | show_dcache_enabled_p (struct ui_file *file, int from_tty, | |
124 | struct cmd_list_element *c, const char *value) | |
125 | { | |
126 | fprintf_filtered (file, _("Cache use for remote targets is %s.\n"), value); | |
127 | } | |
128 | ||
c906108c | 129 | |
25f122dc | 130 | static DCACHE *last_cache; /* Used by info dcache */ |
c906108c SS |
131 | |
132 | /* Free all the data cache blocks, thus discarding all cached data. */ | |
133 | ||
134 | void | |
4930751a | 135 | dcache_invalidate (DCACHE *dcache) |
c906108c | 136 | { |
25f122dc | 137 | struct dcache_block *block, *next; |
c906108c | 138 | |
25f122dc | 139 | block = dcache->oldest; |
c906108c | 140 | |
25f122dc | 141 | while (block) |
c906108c | 142 | { |
25f122dc DE |
143 | splay_tree_remove (dcache->tree, (splay_tree_key) block->addr); |
144 | next = block->newer; | |
c906108c | 145 | |
25f122dc DE |
146 | block->newer = dcache->freelist; |
147 | dcache->freelist = block; | |
148 | ||
149 | block = next; | |
c906108c SS |
150 | } |
151 | ||
25f122dc DE |
152 | dcache->oldest = NULL; |
153 | dcache->newest = NULL; | |
154 | dcache->size = 0; | |
c906108c SS |
155 | } |
156 | ||
157 | /* If addr is present in the dcache, return the address of the block | |
25f122dc | 158 | containing it. */ |
c906108c SS |
159 | |
160 | static struct dcache_block * | |
fba45db2 | 161 | dcache_hit (DCACHE *dcache, CORE_ADDR addr) |
c906108c | 162 | { |
52f0bd74 | 163 | struct dcache_block *db; |
c906108c | 164 | |
25f122dc DE |
165 | splay_tree_node node = splay_tree_lookup (dcache->tree, |
166 | (splay_tree_key) MASK (addr)); | |
c906108c | 167 | |
25f122dc DE |
168 | if (!node) |
169 | return NULL; | |
c906108c | 170 | |
25f122dc DE |
171 | db = (struct dcache_block *) node->value; |
172 | db->refs++; | |
173 | return db; | |
c906108c SS |
174 | } |
175 | ||
25f122dc | 176 | /* Fill a cache line from target memory. */ |
c906108c | 177 | |
8edbea78 C |
178 | static int |
179 | dcache_read_line (DCACHE *dcache, struct dcache_block *db) | |
180 | { | |
181 | CORE_ADDR memaddr; | |
6c932e54 | 182 | gdb_byte *myaddr; |
8edbea78 C |
183 | int len; |
184 | int res; | |
29e57380 C |
185 | int reg_len; |
186 | struct mem_region *region; | |
8edbea78 | 187 | |
8edbea78 C |
188 | len = LINE_SIZE; |
189 | memaddr = db->addr; | |
190 | myaddr = db->data; | |
191 | ||
192 | while (len > 0) | |
193 | { | |
25f122dc DE |
194 | /* Don't overrun if this block is right at the end of the region. */ |
195 | region = lookup_mem_region (memaddr); | |
196 | if (region->hi == 0 || memaddr + len < region->hi) | |
29e57380 C |
197 | reg_len = len; |
198 | else | |
199 | reg_len = region->hi - memaddr; | |
200 | ||
25f122dc | 201 | /* Skip non-cacheable/non-readable regions. */ |
29e57380 C |
202 | if (!region->attrib.cache || region->attrib.mode == MEM_WO) |
203 | { | |
204 | memaddr += reg_len; | |
205 | myaddr += reg_len; | |
206 | len -= reg_len; | |
207 | continue; | |
208 | } | |
209 | ||
cf7a04e8 DJ |
210 | res = target_read (¤t_target, TARGET_OBJECT_RAW_MEMORY, |
211 | NULL, myaddr, memaddr, reg_len); | |
212 | if (res < reg_len) | |
213 | return 0; | |
8edbea78 | 214 | |
cf7a04e8 DJ |
215 | memaddr += res; |
216 | myaddr += res; | |
217 | len -= res; | |
8edbea78 C |
218 | } |
219 | ||
8edbea78 C |
220 | return 1; |
221 | } | |
222 | ||
c906108c | 223 | /* Get a free cache block, put or keep it on the valid list, |
f1d7622b | 224 | and return its address. */ |
c906108c SS |
225 | |
226 | static struct dcache_block * | |
f1d7622b | 227 | dcache_alloc (DCACHE *dcache, CORE_ADDR addr) |
c906108c | 228 | { |
52f0bd74 | 229 | struct dcache_block *db; |
c906108c | 230 | |
25f122dc | 231 | if (dcache->size >= DCACHE_SIZE) |
c906108c | 232 | { |
25f122dc DE |
233 | /* Evict the least recently used line. */ |
234 | db = dcache->oldest; | |
235 | dcache->oldest = db->newer; | |
236 | ||
237 | splay_tree_remove (dcache->tree, (splay_tree_key) db->addr); | |
c906108c SS |
238 | } |
239 | else | |
240 | { | |
25f122dc DE |
241 | db = dcache->freelist; |
242 | if (db) | |
243 | dcache->freelist = db->newer; | |
244 | else | |
245 | db = xmalloc (sizeof (struct dcache_block)); | |
c906108c | 246 | |
25f122dc | 247 | dcache->size++; |
c906108c SS |
248 | } |
249 | ||
25f122dc DE |
250 | db->addr = MASK (addr); |
251 | db->newer = NULL; | |
f1d7622b | 252 | db->refs = 0; |
f1d7622b | 253 | |
25f122dc DE |
254 | if (dcache->newest) |
255 | dcache->newest->newer = db; | |
c906108c | 256 | |
25f122dc | 257 | dcache->newest = db; |
c906108c | 258 | |
25f122dc DE |
259 | if (!dcache->oldest) |
260 | dcache->oldest = db; | |
c906108c | 261 | |
25f122dc DE |
262 | splay_tree_insert (dcache->tree, (splay_tree_key) db->addr, |
263 | (splay_tree_value) db); | |
c906108c | 264 | |
25f122dc | 265 | return db; |
c906108c SS |
266 | } |
267 | ||
8edbea78 C |
268 | /* Using the data cache DCACHE return the contents of the byte at |
269 | address ADDR in the remote machine. | |
270 | ||
25f122dc | 271 | Returns 1 for success, 0 for error. */ |
8edbea78 C |
272 | |
273 | static int | |
6c932e54 | 274 | dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) |
8edbea78 | 275 | { |
52f0bd74 | 276 | struct dcache_block *db = dcache_hit (dcache, addr); |
8edbea78 C |
277 | |
278 | if (!db) | |
279 | { | |
280 | db = dcache_alloc (dcache, addr); | |
25f122dc DE |
281 | |
282 | if (!dcache_read_line (dcache, db)) | |
8edbea78 C |
283 | return 0; |
284 | } | |
285 | ||
286 | *ptr = db->data[XFORM (addr)]; | |
287 | return 1; | |
288 | } | |
289 | ||
c906108c | 290 | /* Write the byte at PTR into ADDR in the data cache. |
25f122dc DE |
291 | |
292 | The caller is responsible for also promptly writing the data | |
293 | through to target memory. | |
294 | ||
295 | If addr is not in cache, this function does nothing; writing to | |
296 | an area of memory which wasn't present in the cache doesn't cause | |
297 | it to be loaded in. | |
298 | ||
299 | Always return 1 to simplify dcache_xfer_memory. */ | |
c906108c SS |
300 | |
301 | static int | |
6c932e54 | 302 | dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) |
c906108c | 303 | { |
52f0bd74 | 304 | struct dcache_block *db = dcache_hit (dcache, addr); |
c906108c | 305 | |
25f122dc DE |
306 | if (db) |
307 | db->data[XFORM (addr)] = *ptr; | |
c906108c | 308 | |
c906108c SS |
309 | return 1; |
310 | } | |
311 | ||
25f122dc DE |
312 | static int |
313 | dcache_splay_tree_compare (splay_tree_key a, splay_tree_key b) | |
314 | { | |
315 | if (a > b) | |
316 | return 1; | |
317 | else if (a == b) | |
318 | return 0; | |
319 | else | |
320 | return -1; | |
321 | } | |
322 | ||
c906108c | 323 | /* Initialize the data cache. */ |
25f122dc | 324 | |
c906108c | 325 | DCACHE * |
4930751a | 326 | dcache_init (void) |
c906108c | 327 | { |
c906108c | 328 | DCACHE *dcache; |
25f122dc | 329 | int i; |
c906108c SS |
330 | |
331 | dcache = (DCACHE *) xmalloc (sizeof (*dcache)); | |
c906108c | 332 | |
25f122dc DE |
333 | dcache->tree = splay_tree_new (dcache_splay_tree_compare, |
334 | NULL, | |
335 | NULL); | |
c906108c | 336 | |
25f122dc DE |
337 | dcache->oldest = NULL; |
338 | dcache->newest = NULL; | |
339 | dcache->freelist = NULL; | |
340 | dcache->size = 0; | |
c906108c | 341 | last_cache = dcache; |
25f122dc | 342 | |
c906108c SS |
343 | return dcache; |
344 | } | |
345 | ||
25f122dc DE |
346 | /* Free a data cache. */ |
347 | ||
e99586d5 C |
348 | void |
349 | dcache_free (DCACHE *dcache) | |
350 | { | |
25f122dc DE |
351 | struct dcache_block *db, *next; |
352 | ||
e99586d5 C |
353 | if (last_cache == dcache) |
354 | last_cache = NULL; | |
355 | ||
25f122dc DE |
356 | splay_tree_delete (dcache->tree); |
357 | for (db = dcache->freelist; db != NULL; db = next) | |
358 | { | |
359 | next = db->newer; | |
360 | xfree (db); | |
361 | } | |
b8c9b27d | 362 | xfree (dcache); |
e99586d5 C |
363 | } |
364 | ||
c906108c SS |
365 | /* Read or write LEN bytes from inferior memory at MEMADDR, transferring |
366 | to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is | |
367 | nonzero. | |
368 | ||
25f122dc | 369 | Returns length of data written or read; 0 for error. */ |
c906108c SS |
370 | |
371 | int | |
25f122dc DE |
372 | dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, |
373 | CORE_ADDR memaddr, gdb_byte *myaddr, | |
1b0ba102 | 374 | int len, int should_write) |
c906108c SS |
375 | { |
376 | int i; | |
25f122dc | 377 | int res; |
6c932e54 | 378 | int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr); |
29e57380 | 379 | xfunc = should_write ? dcache_poke_byte : dcache_peek_byte; |
c906108c | 380 | |
25f122dc DE |
381 | /* Do write-through first, so that if it fails, we don't write to |
382 | the cache at all. */ | |
383 | ||
384 | if (should_write) | |
385 | { | |
386 | res = target_write (ops, TARGET_OBJECT_RAW_MEMORY, | |
387 | NULL, myaddr, memaddr, len); | |
388 | if (res < len) | |
389 | return 0; | |
390 | } | |
391 | ||
29e57380 | 392 | for (i = 0; i < len; i++) |
c906108c | 393 | { |
29e57380 C |
394 | if (!xfunc (dcache, memaddr + i, myaddr + i)) |
395 | return 0; | |
c906108c | 396 | } |
25f122dc DE |
397 | |
398 | return len; | |
399 | } | |
c906108c | 400 | |
25f122dc DE |
401 | /* FIXME: There would be some benefit to making the cache write-back and |
402 | moving the writeback operation to a higher layer, as it could occur | |
403 | after a sequence of smaller writes have been completed (as when a stack | |
404 | frame is constructed for an inferior function call). Note that only | |
405 | moving it up one level to target_xfer_memory[_partial]() is not | |
406 | sufficient since we want to coalesce memory transfers that are | |
407 | "logically" connected but not actually a single call to one of the | |
408 | memory transfer functions. */ | |
29e57380 | 409 | |
25f122dc DE |
410 | static void |
411 | dcache_print_line (int index) | |
412 | { | |
413 | splay_tree_node n; | |
414 | struct dcache_block *db; | |
415 | int i, j; | |
416 | ||
417 | if (!last_cache) | |
418 | { | |
419 | printf_filtered (_("No data cache available.\n")); | |
420 | return; | |
421 | } | |
422 | ||
423 | n = splay_tree_min (last_cache->tree); | |
424 | ||
425 | for (i = index; i > 0; --i) | |
426 | { | |
427 | if (!n) | |
428 | break; | |
429 | n = splay_tree_successor (last_cache->tree, n->key); | |
430 | } | |
431 | ||
432 | if (!n) | |
433 | { | |
434 | printf_filtered (_("No such cache line exists.\n")); | |
435 | return; | |
436 | } | |
29e57380 | 437 | |
25f122dc DE |
438 | db = (struct dcache_block *) n->value; |
439 | ||
51939b3d DE |
440 | printf_filtered (_("Line %d: address %s [%d hits]\n"), |
441 | index, paddress (target_gdbarch, db->addr), db->refs); | |
25f122dc DE |
442 | |
443 | for (j = 0; j < LINE_SIZE; j++) | |
444 | { | |
445 | printf_filtered ("%02x ", db->data[j]); | |
446 | ||
447 | /* Print a newline every 16 bytes (48 characters) */ | |
448 | if ((j % 16 == 15) && (j != LINE_SIZE - 1)) | |
449 | printf_filtered ("\n"); | |
450 | } | |
451 | printf_filtered ("\n"); | |
c906108c SS |
452 | } |
453 | ||
c5aa993b | 454 | static void |
fba45db2 | 455 | dcache_info (char *exp, int tty) |
c906108c | 456 | { |
25f122dc DE |
457 | splay_tree_node n; |
458 | int i, refcount, lineno; | |
459 | ||
460 | if (exp) | |
461 | { | |
462 | char *linestart; | |
463 | i = strtol (exp, &linestart, 10); | |
464 | if (linestart == exp || i < 0) | |
465 | { | |
466 | printf_filtered (_("Usage: info dcache [linenumber]\n")); | |
467 | return; | |
468 | } | |
c906108c | 469 | |
25f122dc DE |
470 | dcache_print_line (i); |
471 | return; | |
472 | } | |
473 | ||
474 | printf_filtered (_("Dcache line width %d, maximum size %d\n"), | |
c906108c SS |
475 | LINE_SIZE, DCACHE_SIZE); |
476 | ||
25f122dc | 477 | if (!last_cache) |
c906108c | 478 | { |
25f122dc DE |
479 | printf_filtered (_("No data cache available.\n")); |
480 | return; | |
481 | } | |
5e2039ea | 482 | |
25f122dc | 483 | refcount = 0; |
c906108c | 484 | |
25f122dc DE |
485 | n = splay_tree_min (last_cache->tree); |
486 | i = 0; | |
c906108c | 487 | |
25f122dc DE |
488 | while (n) |
489 | { | |
490 | struct dcache_block *db = (struct dcache_block *) n->value; | |
491 | ||
51939b3d DE |
492 | printf_filtered (_("Line %d: address %s [%d hits]\n"), |
493 | i, paddress (target_gdbarch, db->addr), db->refs); | |
25f122dc DE |
494 | i++; |
495 | refcount += db->refs; | |
496 | ||
497 | n = splay_tree_successor (last_cache->tree, n->key); | |
c906108c | 498 | } |
25f122dc DE |
499 | |
500 | printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount); | |
c906108c SS |
501 | } |
502 | ||
503 | void | |
fba45db2 | 504 | _initialize_dcache (void) |
c906108c | 505 | { |
5bf193a2 AC |
506 | add_setshow_boolean_cmd ("remotecache", class_support, |
507 | &dcache_enabled_p, _("\ | |
508 | Set cache use for remote targets."), _("\ | |
509 | Show cache use for remote targets."), _("\ | |
c906108c SS |
510 | When on, use data caching for remote targets. For many remote targets\n\ |
511 | this option can offer better throughput for reading target memory.\n\ | |
512 | Unfortunately, gdb does not currently know anything about volatile\n\ | |
513 | registers and thus data caching will produce incorrect results with\n\ | |
5bf193a2 AC |
514 | volatile registers are in use. By default, this option is off."), |
515 | NULL, | |
920d2a44 | 516 | show_dcache_enabled_p, |
5bf193a2 | 517 | &setlist, &showlist); |
c906108c SS |
518 | |
519 | add_info ("dcache", dcache_info, | |
07128da0 DE |
520 | _("\ |
521 | Print information on the dcache performance.\n\ | |
25f122dc DE |
522 | With no arguments, this command prints the cache configuration and a\n\ |
523 | summary of each line in the cache. Use \"info dcache <lineno> to dump\"\n\ | |
524 | the contents of a given line.")); | |
c906108c | 525 | } |