/* Caching code for GDB, the GNU debugger.
- Copyright (C) 1992-2013 Free Software Foundation, Inc.
+ Copyright (C) 1992-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "dcache.h"
#include "gdbcmd.h"
-#include "gdb_string.h"
#include "gdbcore.h"
-#include "target.h"
+#include "target-dcache.h"
#include "inferior.h"
#include "splay-tree.h"
+#include "gdbarch.h"
/* Commands with a prefix of `{set,show} dcache'. */
static struct cmd_list_element *dcache_set_list = NULL;
static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
-static void dcache_info (char *exp, int tty);
-
-void _initialize_dcache (void);
-
static int dcache_enabled_p = 0; /* OBSOLETE */
static void
fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value);
}
-static DCACHE *last_cache; /* Used by info dcache. */
-
/* Add BLOCK to circular block list BLIST, behind the block at *BLIST.
*BLIST is not updated (unless it was previously NULL of course).
This is for the least-recently-allocated list's sake:
void
dcache_free (DCACHE *dcache)
{
- if (last_cache == dcache)
- last_cache = NULL;
-
splay_tree_delete (dcache->tree);
for_each_block (&dcache->oldest, free_block, NULL);
for_each_block (&dcache->freelist, free_block, NULL);
len -= reg_len;
continue;
}
-
- res = target_read (¤t_target, TARGET_OBJECT_RAW_MEMORY,
- NULL, myaddr, memaddr, reg_len);
- if (res < reg_len)
+
+ res = target_read_raw_memory (memaddr, myaddr, reg_len);
+ if (res != 0)
return 0;
- memaddr += res;
- myaddr += res;
- len -= res;
+ memaddr += reg_len;
+ myaddr += reg_len;
+ len -= reg_len;
}
return 1;
if (db)
remove_block (&dcache->freelist, db);
else
- db = xmalloc (offsetof (struct dcache_block, data) +
- dcache->line_size);
+ db = ((struct dcache_block *)
+ xmalloc (offsetof (struct dcache_block, data)
+ + dcache->line_size));
dcache->size++;
}
/* Write the byte at PTR into ADDR in the data cache.
- The caller is responsible for also promptly writing the data
- through to target memory.
-
- If addr is not in cache, this function does nothing; writing to
- an area of memory which wasn't present in the cache doesn't cause
- it to be loaded in.
+ The caller should have written the data through to target memory
+ already.
- Always return 1 (meaning success) to simplify dcache_xfer_memory. */
+ If ADDR is not in cache, this function does nothing; writing to an
+ area of memory which wasn't present in the cache doesn't cause it
+ to be loaded in. */
-static int
-dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
+static void
+dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, const gdb_byte *ptr)
{
struct dcache_block *db = dcache_hit (dcache, addr);
if (db)
db->data[XFORM (dcache, addr)] = *ptr;
-
- return 1;
}
static int
DCACHE *
dcache_init (void)
{
- DCACHE *dcache;
-
- dcache = (DCACHE *) xmalloc (sizeof (*dcache));
+ DCACHE *dcache = XNEW (DCACHE);
dcache->tree = splay_tree_new (dcache_splay_tree_compare,
NULL,
dcache->size = 0;
dcache->line_size = dcache_line_size;
dcache->ptid = null_ptid;
- last_cache = dcache;
return dcache;
}
-/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
- to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
- nonzero.
-
- Return the number of bytes actually transfered, or -1 if the
- transfer is not supported or otherwise fails. Return of a non-negative
- value less than LEN indicates that no further transfer is possible.
- NOTE: This is different than the to_xfer_partial interface, in which
- positive values less than LEN mean further transfers may be possible. */
+/* Read LEN bytes from dcache memory at MEMADDR, transferring to
+ debugger address MYADDR. If the data is presently cached, this
+ fills the cache. Arguments/return are like the target_xfer_partial
+ interface. */
-int
-dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache,
- CORE_ADDR memaddr, gdb_byte *myaddr,
- int len, int should_write)
+enum target_xfer_status
+dcache_read_memory_partial (struct target_ops *ops, DCACHE *dcache,
+ CORE_ADDR memaddr, gdb_byte *myaddr,
+ ULONGEST len, ULONGEST *xfered_len)
{
- int i;
- int res;
- int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr);
-
- xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
+ ULONGEST i;
/* If this is a different inferior from what we've recorded,
flush the cache. */
- if (! ptid_equal (inferior_ptid, dcache->ptid))
+ if (inferior_ptid != dcache->ptid)
{
dcache_invalidate (dcache);
dcache->ptid = inferior_ptid;
}
- /* Do write-through first, so that if it fails, we don't write to
- the cache at all. */
-
- if (should_write)
- {
- res = target_write (ops, TARGET_OBJECT_RAW_MEMORY,
- NULL, myaddr, memaddr, len);
- if (res <= 0)
- return res;
- /* Update LEN to what was actually written. */
- len = res;
- }
-
for (i = 0; i < len; i++)
{
- if (!xfunc (dcache, memaddr + i, myaddr + i))
+ if (!dcache_peek_byte (dcache, memaddr + i, myaddr + i))
{
/* That failed. Discard its cache line so we don't have a
partially read line. */
dcache_invalidate_line (dcache, memaddr + i);
- /* If we're writing, we still wrote LEN bytes. */
- if (should_write)
- return len;
- else
- return i;
+ break;
}
}
-
- return len;
+
+ if (i == 0)
+ {
+ /* Even though reading the whole line failed, we may be able to
+ read a piece starting where the caller wanted. */
+ return raw_memory_xfer_partial (ops, myaddr, NULL, memaddr, len,
+ xfered_len);
+ }
+ else
+ {
+ *xfered_len = i;
+ return TARGET_XFER_OK;
+ }
}
/* FIXME: There would be some benefit to making the cache write-back and
"logically" connected but not actually a single call to one of the
memory transfer functions. */
-/* Just update any cache lines which are already present. This is called
- by memory_xfer_partial in cases where the access would otherwise not go
- through the cache. */
+/* Just update any cache lines which are already present. This is
+ called by the target_xfer_partial machinery when writing raw
+ memory. */
void
-dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+dcache_update (DCACHE *dcache, enum target_xfer_status status,
+ CORE_ADDR memaddr, const gdb_byte *myaddr,
+ ULONGEST len)
{
- int i;
+ ULONGEST i;
for (i = 0; i < len; i++)
- dcache_poke_byte (dcache, memaddr + i, myaddr + i);
+ if (status == TARGET_XFER_OK)
+ dcache_poke_byte (dcache, memaddr + i, myaddr + i);
+ else
+ {
+ /* Discard the whole cache line so we don't have a partially
+ valid line. */
+ dcache_invalidate_line (dcache, memaddr + i);
+ }
}
+/* Print DCACHE line INDEX. */
+
static void
-dcache_print_line (int index)
+dcache_print_line (DCACHE *dcache, int index)
{
splay_tree_node n;
struct dcache_block *db;
int i, j;
- if (!last_cache)
+ if (dcache == NULL)
{
printf_filtered (_("No data cache available.\n"));
return;
}
- n = splay_tree_min (last_cache->tree);
+ n = splay_tree_min (dcache->tree);
for (i = index; i > 0; --i)
{
if (!n)
break;
- n = splay_tree_successor (last_cache->tree, n->key);
+ n = splay_tree_successor (dcache->tree, n->key);
}
if (!n)
printf_filtered (_("Line %d: address %s [%d hits]\n"),
index, paddress (target_gdbarch (), db->addr), db->refs);
- for (j = 0; j < last_cache->line_size; j++)
+ for (j = 0; j < dcache->line_size; j++)
{
printf_filtered ("%02x ", db->data[j]);
/* Print a newline every 16 bytes (48 characters). */
- if ((j % 16 == 15) && (j != last_cache->line_size - 1))
+ if ((j % 16 == 15) && (j != dcache->line_size - 1))
printf_filtered ("\n");
}
printf_filtered ("\n");
}
+/* Parse EXP and show the info about DCACHE. */
+
static void
-dcache_info (char *exp, int tty)
+dcache_info_1 (DCACHE *dcache, const char *exp)
{
splay_tree_node n;
int i, refcount;
i = strtol (exp, &linestart, 10);
if (linestart == exp || i < 0)
{
- printf_filtered (_("Usage: info dcache [linenumber]\n"));
+ printf_filtered (_("Usage: info dcache [LINENUMBER]\n"));
return;
}
- dcache_print_line (i);
+ dcache_print_line (dcache, i);
return;
}
printf_filtered (_("Dcache %u lines of %u bytes each.\n"),
dcache_size,
- last_cache ? (unsigned) last_cache->line_size
+ dcache ? (unsigned) dcache->line_size
: dcache_line_size);
- if (!last_cache || ptid_equal (last_cache->ptid, null_ptid))
+ if (dcache == NULL || dcache->ptid == null_ptid)
{
printf_filtered (_("No data cache available.\n"));
return;
}
printf_filtered (_("Contains data for %s\n"),
- target_pid_to_str (last_cache->ptid));
+ target_pid_to_str (dcache->ptid).c_str ());
refcount = 0;
- n = splay_tree_min (last_cache->tree);
+ n = splay_tree_min (dcache->tree);
i = 0;
while (n)
i++;
refcount += db->refs;
- n = splay_tree_successor (last_cache->tree, n->key);
+ n = splay_tree_successor (dcache->tree, n->key);
}
printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount);
}
static void
-set_dcache_size (char *args, int from_tty,
+info_dcache_command (const char *exp, int tty)
+{
+ dcache_info_1 (target_dcache_get (), exp);
+}
+
+static void
+set_dcache_size (const char *args, int from_tty,
struct cmd_list_element *c)
{
if (dcache_size == 0)
dcache_size = DCACHE_DEFAULT_SIZE;
error (_("Dcache size must be greater than 0."));
}
- if (last_cache)
- dcache_invalidate (last_cache);
+ target_dcache_invalidate ();
}
static void
-set_dcache_line_size (char *args, int from_tty,
+set_dcache_line_size (const char *args, int from_tty,
struct cmd_list_element *c)
{
if (dcache_line_size < 2
dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
error (_("Invalid dcache line size: %u (must be power of 2)."), d);
}
- if (last_cache)
- dcache_invalidate (last_cache);
+ target_dcache_invalidate ();
}
static void
-set_dcache_command (char *arg, int from_tty)
+set_dcache_command (const char *arg, int from_tty)
{
printf_unfiltered (
"\"set dcache\" must be followed by the name of a subcommand.\n");
- help_list (dcache_set_list, "set dcache ", -1, gdb_stdout);
+ help_list (dcache_set_list, "set dcache ", all_commands, gdb_stdout);
}
static void
-show_dcache_command (char *args, int from_tty)
+show_dcache_command (const char *args, int from_tty)
{
cmd_show_list (dcache_show_list, from_tty, "");
}
show_dcache_enabled_p,
&setlist, &showlist);
- add_info ("dcache", dcache_info,
+ add_info ("dcache", info_dcache_command,
_("\
Print information on the dcache performance.\n\
+Usage: info dcache [LINENUMBER]\n\
With no arguments, this command prints the cache configuration and a\n\
-summary of each line in the cache. Use \"info dcache <lineno> to dump\"\n\
-the contents of a given line."));
+summary of each line in the cache. With an argument, dump\"\n\
+the contents of the given line."));
add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\
Use this command to set number of lines in dcache and line-size."),