From 4e5d721fc0b3a9de5764a7b3bf3d6be4132ab67b Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Mon, 31 Aug 2009 20:18:46 +0000 Subject: [PATCH] Implement TARGET_OBJECT_STACK_MEMORY. * NEWS: Add note on new "set stack-cache" option. * corefile.c (read_stack): New function. * dcache.c (dcache_struct): New member ptid. (dcache_enable_p): Mark as obsolete. (show_dcache_enabled_p): Flag option as deprecated. (dcache_invalidate): Update ptid. (dcache_invalidate_line): New function. (dcache_read_line): No longer check cacheable attribute, stack accesses get cached despite attribute. (dcache_init): Set ptid. (dcache_xfer_memory): Flush cache if from different ptid than before. Update cache after write. (dcache_update): New function. (dcache_info): Report ptid. (_initialize_dcache): Update text for `remotecache' to indicate it is obsolete. * dcache.h (dcache_update): Declare. * dwarf2loc.c (dwarf2_evaluate_loc_desc): Mark values on stack with set_value_stack. * frame-unwind.c (frame_unwind_got_memory): Ditto. * gdbcore.h (read_stack): Declare. * memattr.c (mem_enable_command): Call target_dcache_invalidate instead of dcache_invalidate. (mem_disable_command, mem_delete_command): Ditto. * target.c (stack_cache_enabled_p_1): New static global. (stack_cache_enabled_p): New static global. (set_stack_cache_enabled_p): New function. (show_stack_cache_enabled_p): New function. (target_dcache): Make static. (target_dcache_invalidate): New function. (target_load, target_resume): Call target_dcache_invalidate instead of dcache_invalidate. (memory_xfer_partial): New arg object, all callers updated. Check for existing inferior before calling dcache routines. When writing non-TARGET_OBJECT_STACK_MEMORY, notify dcache. (target_xfer_partial): Call memory_xfer_partial for TARGET_OBJECT_STACK_MEMORY. (target_read_stack): New function. (initialize_targets): Install new option `stack-cache'. * target.h: Remove #include of dcache.h. (enum target_object): New value TARGET_OBJECT_STACK_MEMORY. (target_dcache): Delete. (target_dcache_invalidate): Declare. (target_read_stack): Declare. * top.c (prepare_execute_command): New function. (execute_command): Call prepare_execute_command instead of free_all_values. * top.h (prepare_execute_command): Declare. * valops.c (get_value_at): New function. (value_at): Guts moved to get_value_at. (value_at_lazy): Similarly. (value_fetch_lazy): Call read_stack for stack values. * value.c (struct value): New member `stack'. (value_stack, set_value_stack): New functions. * value.h (value_stack, set_value_stack): Declare. * mi/mi-main.c (mi_cmd_execute): Call prepare_execute_command instead of free_all_values. doc/ * gdb.texinfo (Caching Data of Remote Targets): Update text. Mark `set/show remotecache' options as obsolete. Document new `set/show stack-cache' option. Update text for `info dcache'. --- gdb/ChangeLog | 62 +++++++++++++++++++++++++++ gdb/NEWS | 6 +++ gdb/corefile.c | 12 ++++++ gdb/dcache.c | 88 +++++++++++++++++++++++++++++++------- gdb/dcache.h | 3 ++ gdb/doc/ChangeLog | 8 ++++ gdb/doc/gdb.texinfo | 41 ++++++++++++------ gdb/dwarf2loc.c | 1 + gdb/frame-unwind.c | 4 +- gdb/gdbcore.h | 4 ++ gdb/memattr.c | 6 +-- gdb/mi/mi-main.c | 3 +- gdb/target.c | 102 ++++++++++++++++++++++++++++++++++++++++---- gdb/target.h | 10 ++++- gdb/top.c | 17 +++++++- gdb/top.h | 4 ++ gdb/valops.c | 59 ++++++++++++++----------- gdb/value.c | 16 +++++++ gdb/value.h | 3 ++ 19 files changed, 378 insertions(+), 71 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 32fcf5dcae..19c41517f2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,65 @@ +2009-08-31 Jacob Potter + Doug Evans + + Implement TARGET_OBJECT_STACK_MEMORY. + * NEWS: Add note on new "set stack-cache" option. + * corefile.c (read_stack): New function. + * dcache.c (dcache_struct): New member ptid. + (dcache_enable_p): Mark as obsolete. + (show_dcache_enabled_p): Flag option as deprecated. + (dcache_invalidate): Update ptid. + (dcache_invalidate_line): New function. + (dcache_read_line): No longer check cacheable attribute, stack + accesses get cached despite attribute. + (dcache_init): Set ptid. + (dcache_xfer_memory): Flush cache if from different ptid than before. + Update cache after write. + (dcache_update): New function. + (dcache_info): Report ptid. + (_initialize_dcache): Update text for `remotecache' to indicate it + is obsolete. + * dcache.h (dcache_update): Declare. + * dwarf2loc.c (dwarf2_evaluate_loc_desc): Mark values on stack with + set_value_stack. + * frame-unwind.c (frame_unwind_got_memory): Ditto. + * gdbcore.h (read_stack): Declare. + * memattr.c (mem_enable_command): Call target_dcache_invalidate + instead of dcache_invalidate. + (mem_disable_command, mem_delete_command): Ditto. + * target.c (stack_cache_enabled_p_1): New static global. + (stack_cache_enabled_p): New static global. + (set_stack_cache_enabled_p): New function. + (show_stack_cache_enabled_p): New function. + (target_dcache): Make static. + (target_dcache_invalidate): New function. + (target_load, target_resume): Call target_dcache_invalidate + instead of dcache_invalidate. + (memory_xfer_partial): New arg object, all callers updated. + Check for existing inferior before calling dcache routines. + When writing non-TARGET_OBJECT_STACK_MEMORY, notify dcache. + (target_xfer_partial): Call memory_xfer_partial for + TARGET_OBJECT_STACK_MEMORY. + (target_read_stack): New function. + (initialize_targets): Install new option `stack-cache'. + * target.h: Remove #include of dcache.h. + (enum target_object): New value TARGET_OBJECT_STACK_MEMORY. + (target_dcache): Delete. + (target_dcache_invalidate): Declare. + (target_read_stack): Declare. + * top.c (prepare_execute_command): New function. + (execute_command): Call prepare_execute_command + instead of free_all_values. + * top.h (prepare_execute_command): Declare. + * valops.c (get_value_at): New function. + (value_at): Guts moved to get_value_at. + (value_at_lazy): Similarly. + (value_fetch_lazy): Call read_stack for stack values. + * value.c (struct value): New member `stack'. + (value_stack, set_value_stack): New functions. + * value.h (value_stack, set_value_stack): Declare. + * mi/mi-main.c (mi_cmd_execute): Call prepare_execute_command + instead of free_all_values. + 2009-08-29 Hui Zhu * i386-tdep.c (i386_process_record): Fix the error of string diff --git a/gdb/NEWS b/gdb/NEWS index 179c977773..e3e67741c4 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -394,6 +394,12 @@ show schedule-multiple Allow GDB to resume all threads of all processes or only threads of the current process. +set stack-cache +show stack-cache + Use more aggressive caching for accesses to the stack. This improves + performance of remote debugging (particularly backtraces) without + affecting correctness. + * Removed commands info forks diff --git a/gdb/corefile.c b/gdb/corefile.c index 6de0772584..e70688ee31 100644 --- a/gdb/corefile.c +++ b/gdb/corefile.c @@ -228,6 +228,7 @@ memory_error (int status, CORE_ADDR memaddr) } /* Same as target_read_memory, but report an error if can't read. */ + void read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) { @@ -237,6 +238,17 @@ read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) memory_error (status, memaddr); } +/* Same as target_read_stack, but report an error if can't read. */ + +void +read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) +{ + int status; + status = target_read_stack (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + /* Argument / return result struct for use with do_captured_read_memory_integer(). MEMADDR and LEN are filled in by gdb_read_memory_integer(). RESULT is the contents that were diff --git a/gdb/dcache.c b/gdb/dcache.c index 17c948a4d2..52375f092a 100644 --- a/gdb/dcache.c +++ b/gdb/dcache.c @@ -24,6 +24,7 @@ #include "gdb_string.h" #include "gdbcore.h" #include "target.h" +#include "inferior.h" #include "splay-tree.h" /* The data cache could lead to incorrect results because it doesn't @@ -103,6 +104,9 @@ struct dcache_struct /* The number of in-use lines in the cache. */ int size; + + /* The ptid of last inferior to use cache or null_ptid. */ + ptid_t ptid; }; static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr); @@ -117,16 +121,15 @@ static void dcache_info (char *exp, int tty); void _initialize_dcache (void); -static int dcache_enabled_p = 0; +static int dcache_enabled_p = 0; /* OBSOLETE */ static void show_dcache_enabled_p (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Cache use for remote targets is %s.\n"), value); + fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value); } - static DCACHE *last_cache; /* Used by info dcache */ /* Free all the data cache blocks, thus discarding all cached data. */ @@ -152,6 +155,23 @@ dcache_invalidate (DCACHE *dcache) dcache->oldest = NULL; dcache->newest = NULL; dcache->size = 0; + dcache->ptid = null_ptid; +} + +/* Invalidate the line associated with ADDR. */ + +static void +dcache_invalidate_line (DCACHE *dcache, CORE_ADDR addr) +{ + struct dcache_block *db = dcache_hit (dcache, addr); + + if (db) + { + splay_tree_remove (dcache->tree, (splay_tree_key) db->addr); + db->newer = dcache->freelist; + dcache->freelist = db; + --dcache->size; + } } /* If addr is present in the dcache, return the address of the block @@ -198,8 +218,9 @@ dcache_read_line (DCACHE *dcache, struct dcache_block *db) else reg_len = region->hi - memaddr; - /* Skip non-cacheable/non-readable regions. */ - if (!region->attrib.cache || region->attrib.mode == MEM_WO) + /* Skip non-readable regions. The cache attribute can be ignored, + since we may be loading this for a stack access. */ + if (region->attrib.mode == MEM_WO) { memaddr += reg_len; myaddr += reg_len; @@ -296,7 +317,7 @@ dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) an area of memory which wasn't present in the cache doesn't cause it to be loaded in. - Always return 1 to simplify dcache_xfer_memory. */ + Always return 1 (meaning success) to simplify dcache_xfer_memory. */ static int dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) @@ -338,6 +359,7 @@ dcache_init (void) dcache->newest = NULL; dcache->freelist = NULL; dcache->size = 0; + dcache->ptid = null_ptid; last_cache = dcache; return dcache; @@ -366,7 +388,7 @@ dcache_free (DCACHE *dcache) to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is nonzero. - Returns length of data written or read; 0 for error. */ + The meaning of the result is the same as for target_write. */ int dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, @@ -378,6 +400,15 @@ dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr); xfunc = should_write ? dcache_poke_byte : dcache_peek_byte; + /* If this is a different inferior from what we've recorded, + flush the cache. */ + + if (! ptid_equal (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. */ @@ -385,14 +416,25 @@ dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, { res = target_write (ops, TARGET_OBJECT_RAW_MEMORY, NULL, myaddr, memaddr, len); - if (res < len) - return 0; + 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)) - return 0; + { + /* 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; + } } return len; @@ -407,6 +449,18 @@ dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, "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. */ + +void +dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len) +{ + int i; + for (i = 0; i < len; i++) + dcache_poke_byte (dcache, memaddr + i, myaddr + i); +} + static void dcache_print_line (int index) { @@ -474,12 +528,15 @@ dcache_info (char *exp, int tty) printf_filtered (_("Dcache line width %d, maximum size %d\n"), LINE_SIZE, DCACHE_SIZE); - if (!last_cache) + if (!last_cache || ptid_equal (last_cache->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)); + refcount = 0; n = splay_tree_min (last_cache->tree); @@ -507,11 +564,10 @@ _initialize_dcache (void) &dcache_enabled_p, _("\ Set cache use for remote targets."), _("\ Show cache use for remote targets."), _("\ -When on, use data caching for remote targets. For many remote targets\n\ -this option can offer better throughput for reading target memory.\n\ -Unfortunately, gdb does not currently know anything about volatile\n\ -registers and thus data caching will produce incorrect results with\n\ -volatile registers are in use. By default, this option is off."), +This used to enable the data cache for remote targets. The cache\n\ +functionality is now controlled by the memory region system and the\n\ +\"stack-cache\" flag; \"remotecache\" now does nothing and\n\ +exists only for compatibility reasons."), NULL, show_dcache_enabled_p, &setlist, &showlist); diff --git a/gdb/dcache.h b/gdb/dcache.h index 3f7400cbdb..a141b85a57 100644 --- a/gdb/dcache.h +++ b/gdb/dcache.h @@ -38,4 +38,7 @@ void dcache_free (DCACHE *); int dcache_xfer_memory (struct target_ops *ops, DCACHE *cache, CORE_ADDR mem, gdb_byte *my, int len, int should_write); +void dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, + int len); + #endif /* DCACHE_H */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 3423ee2163..8831e0aa76 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,11 @@ +2009-08-31 Jacob Potter + Doug Evans + + * gdb.texinfo (Caching Data of Remote Targets): Update text. + Mark `set/show remotecache' options as obsolete. + Document new `set/show stack-cache' option. + Update text for `info dcache'. + 2009-08-27 Doug Evans * gdb.texinfo (Symbols): Delete `set print symbol-loading'. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index cc66d12847..0e9fd449bd 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -8421,32 +8421,47 @@ character. @section Caching Data of Remote Targets @cindex caching data of remote targets -@value{GDBN} can cache data exchanged between the debugger and a +@value{GDBN} caches data exchanged between the debugger and a remote target (@pxref{Remote Debugging}). Such caching generally improves performance, because it reduces the overhead of the remote protocol by -bundling memory reads and writes into large chunks. Unfortunately, -@value{GDBN} does not currently know anything about volatile -registers, and thus data caching will produce incorrect results when -volatile registers are in use. +bundling memory reads and writes into large chunks. Unfortunately, simply +caching everything would lead to incorrect results, since @value{GDBN} +does not necessarily know anything about volatile values, memory-mapped I/O +addresses, etc. Therefore, by default, @value{GDBN} only caches data +known to be on the stack. Other regions of memory can be explicitly marked +cacheable; see @pxref{Memory Region Attributes}. @table @code @kindex set remotecache @item set remotecache on @itemx set remotecache off -Set caching state for remote targets. When @code{ON}, use data -caching. By default, this option is @code{OFF}. +This option no longer does anything; it exists for compatibility +with old scripts. @kindex show remotecache @item show remotecache -Show the current state of data caching for remote targets. +Show the current state of the obsolete remotecache flag. + +@kindex set stack-cache +@item set stack-cache on +@itemx set stack-cache off +Enable or disable caching of stack accesses. When @code{ON}, use +caching. By default, this option is @code{ON}. + +@kindex show stack-cache +@item show stack-cache +Show the current state of data caching for memory accesses. @kindex info dcache -@item info dcache +@item info dcache @r{[}line@r{]} Print the information about the data cache performance. The -information displayed includes: the dcache width and depth; and for -each cache line, how many times it was referenced, and its data and -state (invalid, dirty, valid). This command is useful for debugging -the data cache operation. +information displayed includes the dcache width and depth, and for +each cache line, its number, address, and how many times it was +referenced. This command is useful for debugging the data cache +operation. + +If a line number is specified, the contents of that line will be +printed in hex. @end table @node Searching Memory diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 1df6a9f05c..b6c9b1104f 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -280,6 +280,7 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = lval_memory; set_value_lazy (retval, 1); + set_value_stack (retval, 1); set_value_address (retval, address); } diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index 238c6a1b56..f0c2a64c78 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -153,8 +153,10 @@ struct value * frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr) { struct gdbarch *gdbarch = frame_unwind_arch (frame); + struct value *v = value_at_lazy (register_type (gdbarch, regnum), addr); - return value_at_lazy (register_type (gdbarch, regnum), addr); + set_value_stack (v, 1); + return v; } /* Return a value which indicates that FRAME's saved version of diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h index e339c0baa5..7a7dcb2b3a 100644 --- a/gdb/gdbcore.h +++ b/gdb/gdbcore.h @@ -47,6 +47,10 @@ extern void memory_error (int status, CORE_ADDR memaddr); extern void read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len); +/* Like target_read_stack, but report an error if can't read. */ + +extern void read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len); + /* Read an integer from debugged memory, given address and number of bytes. */ diff --git a/gdb/memattr.c b/gdb/memattr.c index 356b4d6194..0d2fea2c3c 100644 --- a/gdb/memattr.c +++ b/gdb/memattr.c @@ -571,7 +571,7 @@ mem_enable_command (char *args, int from_tty) require_user_regions (from_tty); - dcache_invalidate (target_dcache); + target_dcache_invalidate (); if (p == 0) { @@ -625,7 +625,7 @@ mem_disable_command (char *args, int from_tty) require_user_regions (from_tty); - dcache_invalidate (target_dcache); + target_dcache_invalidate (); if (p == 0) { @@ -686,7 +686,7 @@ mem_delete_command (char *args, int from_tty) require_user_regions (from_tty); - dcache_invalidate (target_dcache); + target_dcache_invalidate (); if (p == 0) { diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 6aa1d08db9..857a5d5125 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -1353,7 +1353,8 @@ mi_cmd_execute (struct mi_parse *parse) struct cleanup *cleanup; int i; - free_all_values (); + prepare_execute_command (); + cleanup = make_cleanup (null_cleanup, NULL); if (parse->frame != -1 && parse->thread == -1) diff --git a/gdb/target.c b/gdb/target.c index 040087b0aa..d828332883 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -210,7 +210,45 @@ show_targetdebug (struct ui_file *file, int from_tty, static void setup_target_debug (void); -DCACHE *target_dcache; +/* The option sets this. */ +static int stack_cache_enabled_p_1 = 1; +/* And set_stack_cache_enabled_p updates this. + The reason for the separation is so that we don't flush the cache for + on->on transitions. */ +static int stack_cache_enabled_p = 1; + +/* This is called *after* the stack-cache has been set. + Flush the cache for off->on and on->off transitions. + There's no real need to flush the cache for on->off transitions, + except cleanliness. */ + +static void +set_stack_cache_enabled_p (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (stack_cache_enabled_p != stack_cache_enabled_p_1) + target_dcache_invalidate (); + + stack_cache_enabled_p = stack_cache_enabled_p_1; +} + +static void +show_stack_cache_enabled_p (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Cache use for stack accesses is %s.\n"), value); +} + +/* Cache of memory operations, to speed up remote access. */ +static DCACHE *target_dcache; + +/* Invalidate the target dcache. */ + +void +target_dcache_invalidate (void) +{ + dcache_invalidate (target_dcache); +} /* The user just typed 'target' without the name of a target. */ @@ -413,7 +451,7 @@ target_kill (void) void target_load (char *arg, int from_tty) { - dcache_invalidate (target_dcache); + target_dcache_invalidate (); (*current_target.to_load) (arg, from_tty); } @@ -1143,12 +1181,14 @@ target_section_by_addr (struct target_ops *target, CORE_ADDR addr) value are just as for target_xfer_partial. */ static LONGEST -memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf, - ULONGEST memaddr, LONGEST len) +memory_xfer_partial (struct target_ops *ops, enum target_object object, + void *readbuf, const void *writebuf, ULONGEST memaddr, + LONGEST len) { LONGEST res; int reg_len; struct mem_region *region; + struct inferior *inf; /* Zero length requests are ok and require no work. */ if (len == 0) @@ -1223,7 +1263,11 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf return -1; } - if (region->attrib.cache) + inf = find_inferior_pid (ptid_get_pid (inferior_ptid)); + + if (inf != NULL + && (region->attrib.cache + || (stack_cache_enabled_p && object == TARGET_OBJECT_STACK_MEMORY))) { if (readbuf != NULL) res = dcache_xfer_memory (ops, target_dcache, memaddr, readbuf, @@ -1245,6 +1289,19 @@ memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf } } + /* Make sure the cache gets updated no matter what - if we are writing + to the stack, even if this write is not tagged as such, we still need + to update the cache. */ + + if (inf != NULL + && readbuf == NULL + && !region->attrib.cache + && stack_cache_enabled_p + && object != TARGET_OBJECT_STACK_MEMORY) + { + dcache_update (target_dcache, memaddr, (void *) writebuf, reg_len); + } + /* If none of those methods found the memory we wanted, fall back to a target partial transfer. Normally a single call to to_xfer_partial is enough; if it doesn't recognize an object @@ -1308,8 +1365,9 @@ target_xfer_partial (struct target_ops *ops, /* If this is a memory transfer, let the memory-specific code have a look at it instead. Memory transfers are more complicated. */ - if (object == TARGET_OBJECT_MEMORY) - retval = memory_xfer_partial (ops, readbuf, writebuf, offset, len); + if (object == TARGET_OBJECT_MEMORY || object == TARGET_OBJECT_STACK_MEMORY) + retval = memory_xfer_partial (ops, object, readbuf, + writebuf, offset, len); else { enum target_object raw_object = object; @@ -1391,6 +1449,23 @@ target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) return EIO; } +/* Like target_read_memory, but specify explicitly that this is a read from + the target's stack. This may trigger different cache behavior. */ + +int +target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) +{ + /* Dispatch to the topmost target, not the flattened current_target. + Memory accesses check target->to_has_(all_)memory, and the + flattened target doesn't inherit those. */ + + if (target_read (current_target.beneath, TARGET_OBJECT_STACK_MEMORY, NULL, + myaddr, memaddr, len) == len) + return 0; + else + return EIO; +} + int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) { @@ -2055,7 +2130,7 @@ target_resume (ptid_t ptid, int step, enum target_signal signal) { struct target_ops *t; - dcache_invalidate (target_dcache); + target_dcache_invalidate (); for (t = current_target.beneath; t != NULL; t = t->beneath) { @@ -3479,5 +3554,16 @@ Tells gdb whether to control the inferior in asynchronous mode."), &setlist, &showlist); + add_setshow_boolean_cmd ("stack-cache", class_support, + &stack_cache_enabled_p, _("\ +Set cache use for stack access."), _("\ +Show cache use for stack access."), _("\ +When on, use the data cache for all stack access, regardless of any\n\ +configured memory regions. This improves remote performance significantly.\n\ +By default, caching for stack access is on."), + set_stack_cache_enabled_p, + show_stack_cache_enabled_p, + &setlist, &showlist); + target_dcache = dcache_init (); } diff --git a/gdb/target.h b/gdb/target.h index 2c743e93fc..c210fea3b1 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -53,7 +53,6 @@ struct target_section_table; #include "bfd.h" #include "symtab.h" -#include "dcache.h" #include "memattr.h" #include "vec.h" #include "gdb_signals.h" @@ -203,6 +202,10 @@ enum target_object Target implementations of to_xfer_partial never need to handle this object, and most callers should not use it. */ TARGET_OBJECT_RAW_MEMORY, + /* Memory known to be part of the target's stack. This is cached even + if it is not in a region marked as such, since it is known to be + "normal" RAM. */ + TARGET_OBJECT_STACK_MEMORY, /* Kernel Unwind Table. See "ia64-tdep.c". */ TARGET_OBJECT_UNWIND_TABLE, /* Transfer auxilliary vector. */ @@ -671,12 +674,15 @@ extern void target_store_registers (struct regcache *regcache, int regs); #define target_supports_multi_process() \ (*current_target.to_supports_multi_process) () -extern DCACHE *target_dcache; +/* Invalidate all target dcaches. */ +extern void target_dcache_invalidate (void); extern int target_read_string (CORE_ADDR, char **, int, int *); extern int target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len); +extern int target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len); + extern int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len); diff --git a/gdb/top.c b/gdb/top.c index d1fe69bbfc..b98fa9a745 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -345,6 +345,19 @@ do_chdir_cleanup (void *old_dir) } #endif +void +prepare_execute_command (void) +{ + free_all_values (); + + /* With multiple threads running while the one we're examining is stopped, + the dcache can get stale without us being able to detect it. + For the duration of the command, though, use the dcache to help + things like backtrace. */ + if (non_stop) + target_dcache_invalidate (); +} + /* Execute the line P as a command, in the current user context. Pass FROM_TTY as second argument to the defining function. */ @@ -374,8 +387,8 @@ execute_command (char *p, int from_tty) #endif } } - - free_all_values (); + + prepare_execute_command (); /* Force cleanup of any alloca areas if using C alloca instead of a builtin alloca. */ diff --git a/gdb/top.h b/gdb/top.h index 0a752355d2..070a62e7cd 100644 --- a/gdb/top.h +++ b/gdb/top.h @@ -49,6 +49,10 @@ extern void quit_command (char *, int); extern int quit_cover (void *); extern void execute_command (char *, int); +/* Prepare for execution of a command. + Call this before every command, CLI or MI. */ +extern void prepare_execute_command (void); + /* This function returns a pointer to the string that is used by gdb for its command prompt. */ extern char *get_prompt (void); diff --git a/gdb/valops.c b/gdb/valops.c index 5e5c4edeb3..b64cb21eac 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -565,6 +565,32 @@ value_one (struct type *type, enum lval_type lv) return val; } +/* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */ + +static struct value * +get_value_at (struct type *type, CORE_ADDR addr, int lazy) +{ + struct value *val; + + if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) + error (_("Attempt to dereference a generic pointer.")); + + if (lazy) + { + val = allocate_value_lazy (type); + } + else + { + val = allocate_value (type); + read_memory (addr, value_contents_all_raw (val), TYPE_LENGTH (type)); + } + + VALUE_LVAL (val) = lval_memory; + set_value_address (val, addr); + + return val; +} + /* Return a value with type TYPE located at ADDR. Call value_at only if the data needs to be fetched immediately; @@ -580,19 +606,7 @@ value_one (struct type *type, enum lval_type lv) struct value * value_at (struct type *type, CORE_ADDR addr) { - struct value *val; - - if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) - error (_("Attempt to dereference a generic pointer.")); - - val = allocate_value (type); - - read_memory (addr, value_contents_all_raw (val), TYPE_LENGTH (type)); - - VALUE_LVAL (val) = lval_memory; - set_value_address (val, addr); - - return val; + return get_value_at (type, addr, 0); } /* Return a lazy value with type TYPE located at ADDR (cf. value_at). */ @@ -600,17 +614,7 @@ value_at (struct type *type, CORE_ADDR addr) struct value * value_at_lazy (struct type *type, CORE_ADDR addr) { - struct value *val; - - if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) - error (_("Attempt to dereference a generic pointer.")); - - val = allocate_value_lazy (type); - - VALUE_LVAL (val) = lval_memory; - set_value_address (val, addr); - - return val; + return get_value_at (type, addr, 1); } /* Called only from the value_contents and value_contents_all() @@ -656,7 +660,12 @@ value_fetch_lazy (struct value *val) int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val))); if (length) - read_memory (addr, value_contents_all_raw (val), length); + { + if (value_stack (val)) + read_stack (addr, value_contents_all_raw (val), length); + else + read_memory (addr, value_contents_all_raw (val), length); + } } else if (VALUE_LVAL (val) == lval_register) { diff --git a/gdb/value.c b/gdb/value.c index f26e16c7d6..589e03b149 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -196,6 +196,10 @@ struct value /* If value is a variable, is it initialized or not. */ int initialized; + /* If value is from the stack. If this is set, read_stack will be + used instead of read_memory to enable extra caching. */ + int stack; + /* Actual contents of the value. Target byte-order. NULL or not valid if lazy is nonzero. */ gdb_byte *contents; @@ -424,6 +428,18 @@ set_value_lazy (struct value *value, int val) value->lazy = val; } +int +value_stack (struct value *value) +{ + return value->stack; +} + +void +set_value_stack (struct value *value, int val) +{ + value->stack = val; +} + const gdb_byte * value_contents (struct value *value) { diff --git a/gdb/value.h b/gdb/value.h index 6f6b756085..51e6960ab8 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -215,6 +215,9 @@ extern void *value_computed_closure (struct value *value); extern int value_lazy (struct value *); extern void set_value_lazy (struct value *value, int val); +extern int value_stack (struct value *); +extern void set_value_stack (struct value *value, int val); + /* value_contents() and value_contents_raw() both return the address of the gdb buffer used to hold a copy of the contents of the lval. value_contents() is used when the contents of the buffer are needed -- 2.34.1