aboutsummaryrefslogtreecommitdiff
path: root/gdb/parser-defs.h
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2017-10-18 20:07:19 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2018-01-21 15:46:51 +0000
commitae45162705fb76ee534336474a67b11373209c62 (patch)
tree98bcdeaea5194a0c7c240fe3610100f248b94df9 /gdb/parser-defs.h
parentaee1fcdf979d65c7623533ddd6d871767be9de13 (diff)
downloadgdb-ae45162705fb76ee534336474a67b11373209c62.zip
gdb-ae45162705fb76ee534336474a67b11373209c62.tar.gz
gdb-ae45162705fb76ee534336474a67b11373209c62.tar.bz2
gdb: PR mi/20395: Fix -var-update for registers in frames 1 and up
This patch fixes a problem with using the MI -var-update command to access the values of registers in frames other than the current frame. The patch includes a test that demonstrates the problem: * run so there are several frames on the stack * create a fixed varobj for $pc in each frame, #'s 1 and above * step one instruction, to modify the value of $pc * call -var-update for each of the previously created varobjs to verify that they are not reported as having changed. Without the patch, the -var-update command reported that $pc for all frames 1 and above had changed to the value of $pc in frame 0. A varobj is created as either fixed, the expression is evaluated within the context of a specific frame, or floating, the expression is evaluated within the current frame, whatever that may be. When a varobj is created by -var-create we set two fields of the varobj to track the context in which the varobj was created, these two fields are varobj->root->frame and var->root->valid_block. If a varobj is of type fixed, then, when we subsequently try to reevaluate the expression associated with the varobj we must determine if the original frame (and block) is still available, if it is not then the varobj can no longer be evaluated. The problem is that for register expressions varobj->root->valid_block is not set correctly. This block tracking is done using the global 'innermost_block' which is set in the various parser files (for example c-exp.y). However, this is not set for register expressions. The fix then seems like it should be to just update the innermost block when parsing register expressions, however, that solution causes several test regressions. The problem is that in some cases we rely on the expression parsing code not updating the innermost block for registers, one example is when we parse the expression for a 'display' command. The display commands treats registers like floating varobjs, but symbols are treated like fixed varobjs. So 'display $reg_name' will always show the value of '$reg_name' even as the user moves from frame to frame, while 'display my_variable' will only show 'my_variable' while it is in the current frame and/or block, when the user moves to a new frame and/or block (even one with a different 'my_variable' in) then the display of 'my_variable' stops. For the case of 'display', without the option to force fixed or floating expressions, the current behaviour is probably the best choice. For the varobj system though, we can choose between floating and fixed, and we should try to make this work for registers. There's only one existing test case that needs to be updated, in that test a fixed varobj is created using a register, the MI output now include the thread-id in which the varobj should be evaluated, which I believe is correct behaviour. I also added a new floating test case into the same test script, however, right now this also includes the thread-id in the expected output, which I believe is an existing gdb bug, which I plan to fix next. Tested on x86_64 Linux native and native-gdbserver, no regressions. gdb/ChangeLog: PR mi/20395 * ada-exp.y (write_var_from_sym): Pass extra parameter when updating innermost block. * parse.c (innermost_block_tracker::update): Take extra type parameter, and check types match before updating innermost block. (write_dollar_variable): Update innermost block for registers. * parser-defs.h (enum innermost_block_tracker_type): New enum. (innermost_block_tracker::innermost_block_tracker): Initialise m_types member. (innermost_block_tracker::reset): Take type parameter. (innermost_block_tracker::update): Take type parameter, and pass type through as needed. (innermost_block_tracker::m_types): New member. * varobj.c (varobj_create): Pass type when reseting innermost block. gdb/testsuite/ChangeLog: * gdb.mi/basics.c: Add new global. * gdb.mi/mi-frame-regs.exp: New file. * gdb.mi/mi-var-create-rtti.exp: Update expected results, add new case.
Diffstat (limited to 'gdb/parser-defs.h')
-rw-r--r--gdb/parser-defs.h47
1 files changed, 38 insertions, 9 deletions
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 01ac0cd..c67b8d56 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -75,6 +75,24 @@ extern const struct block *expression_context_block;
then look up the macro definitions active at that point. */
extern CORE_ADDR expression_context_pc;
+/* While parsing expressions we need to track the innermost lexical block
+ that we encounter. In some situations we need to track the innermost
+ block just for symbols, and in other situations we want to track the
+ innermost block for symbols and registers. These flags are used by the
+ innermost block tracker to control which blocks we consider for the
+ innermost block. These flags can be combined together as needed. */
+
+enum innermost_block_tracker_type
+{
+ /* Track the innermost block for symbols within an expression. */
+ INNERMOST_BLOCK_FOR_SYMBOLS = (1 << 0),
+
+ /* Track the innermost block for registers within an expression. */
+ INNERMOST_BLOCK_FOR_REGISTERS = (1 << 1)
+};
+DEF_ENUM_FLAGS_TYPE (enum innermost_block_tracker_type,
+ innermost_block_tracker_types);
+
/* When parsing expressions we track the innermost block that was
referenced. */
@@ -82,24 +100,32 @@ class innermost_block_tracker
{
public:
innermost_block_tracker ()
- : m_innermost_block (NULL)
+ : m_types (INNERMOST_BLOCK_FOR_SYMBOLS),
+ m_innermost_block (NULL)
{ /* Nothing. */ }
/* Reset the currently stored innermost block. Usually called before
- parsing a new expression. */
- void reset ()
+ parsing a new expression. As the most common case is that we only
+ want to gather the innermost block for symbols in an expression, this
+ becomes the default block tracker type. */
+ void reset (innermost_block_tracker_types t = INNERMOST_BLOCK_FOR_SYMBOLS)
{
- m_innermost_block = nullptr;
+ m_types = t;
+ m_innermost_block = NULL;
}
/* Update the stored innermost block if the new block B is more inner
- than the currently stored block, or if no block is stored yet. */
- void update (const struct block *b);
+ than the currently stored block, or if no block is stored yet. The
+ type T tells us whether the block B was for a symbol or for a
+ register. The stored innermost block is only updated if the type T is
+ a type we are interested in, the types we are interested in are held
+ in M_TYPES and set during RESET. */
+ void update (const struct block *b, innermost_block_tracker_types t);
/* Overload of main UPDATE method which extracts the block from BS. */
void update (const struct block_symbol &bs)
{
- update (bs.block);
+ update (bs.block, INNERMOST_BLOCK_FOR_SYMBOLS);
}
/* Return the stored innermost block. Can be nullptr if no symbols or
@@ -111,13 +137,16 @@ public:
}
private:
+ /* The type of innermost block being looked for. */
+ innermost_block_tracker_types m_types;
+
/* The currently stored innermost block found while parsing an
expression. */
const struct block *m_innermost_block;
};
-/* The innermost context required by the stack and register variables we've
- encountered so far. This should be cleared before parsing an
+/* The innermost context required by the stack and register variables
+ we've encountered so far. This should be cleared before parsing an
expression, and queried once the parse is complete. */
extern innermost_block_tracker innermost_block;