/* Caching code for GDB, the GNU debugger.
- Copyright (C) 1992-2013 Free Software Foundation, Inc.
+ Copyright (C) 1992-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "dcache.h"
#include "gdbcmd.h"
-#include <string.h>
#include "gdbcore.h"
#include "target-dcache.h"
#include "inferior.h"
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.
+ The caller should have written the data through to target memory
+ already.
- 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.
+ 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. */
- Always return 1 (meaning success) to simplify dcache_xfer_memory. */
-
-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,
}
-/* 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. */
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. */
{
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