[nemiver/varobjs-support] Initial backend support for GDB Variable Objects
- From: Dodji Seketeli <dodji src gnome org>
- To: svn-commits-list gnome org
- Subject: [nemiver/varobjs-support] Initial backend support for GDB Variable Objects
- Date: Fri, 20 Mar 2009 18:32:30 -0400 (EDT)
commit b4f00ae37fa16727a71447b8853f8559eb4e3b8a
Author: Dodji Seketeli <dodji redhat com>
Date: Sun Mar 15 01:15:03 2009 +0100
Initial backend support for GDB Variable Objects
* nmv-dynamic-module.[cc|h] (DynamicModule::set_name,
DynamicModule::get_name, load_iface_using_context, ): New entry
points.
* src/dbgengine/nmv-dbg-common.h (Command::has_slot, Command::set_slot,
Command::get_slot, Command::number_of_variables_deleted,
ResultRecord::has_variable_children,
ResultRecord::has_variable_children): New entry points.
* src/dbgengine/nmv-i-debugger.h (IDebugger::Variable::internal_name): New
entry point to adapt the current variable type to gdb variable
objects.
(IDebugger::Variable::to_string): Print the internal name of the
variable as well as its name.
(IDebugger::variable_created_signal,
IDebugger::variable_deleted_signal,
IDebugger::variable_unfolded_signal,
IDebugger::build_qualified_internal_name,
IDebugger::Variable::num_expected_children,
IDebugger::Variable::has_expected_children,
IDebugger::create_variable,
IDebugger::delete_variable,
IDebugger::unfold_variable): New interfaces entry points.
* src/dbgengine/nmv-gdb-engine.h (GDBEngine::variable_created_signal,
GDBEngine::variable_deleted_signal,
GDBEngine::variable_unfolded_signal, GDBEngine::create_variable,
GDBEngine::delete_variable, GDBEngine::unfold_variable): Declare the
implementation of the new interface entry points.
* src/dbgengine/nmv-gdb-engine.cc (GDBEngine::variable_created_signal,
GDBEngine::variable_deleted_signal, GDBEngine::variable_unfolded_signal,
GDBEngine::variable_unfolded_signal, GDBEngine::create_variable,
GDBEngine::delete_variable, GDBEngine::unfold_variable): Implement the
new interface entry points.
(OnCreateVariableHandler, OnDeleteVariableHandler,
OnUnfoldVariableHandler): New output handlers to act upon the result of
GDBEngine::create_variable, GDBEngine::delete_engine and
GDBEngine::unfold_variable
(GDBEngine::init_output_handlers): Register the new output handlers.
* src/dbgengine/nmv-gdbmi-parser.[cc,h] (GDBMIParser::parse_variable,
GDBMIParser::parse_variables_deleted): New entry points to parse the
GDB/MI result of variable object creation and deletion.
(GDBMIParser::parse_var_list_children): New entry point to parse MI
result of -var-list-children.
(GDBMIParser::parse_result_record): Use GDBMIParser::parse_variable and
GDBMIParser::parse_variables_delete, and
GDBMIParser::parse_var_list_children to parse the output
records of -var-list-create, -var-list-delete and -var-list-children.
* tests/test-vars.cc: New test case to test (in live)
IDebugger::create_variable, IDebugger::delete_variable,
IDebugger::unfold_variable.
* tests/Makefile.am: Add new test-vars.c to the build system.
* tests/fooprog.cc: Adjust this test case.
* tests/test-gdbmi.cc: Add test cases for parsing the result
of IDebugger::create_variable, IDebugger::delete_variable,
IDebugger::unfold_variable.
---
src/common/nmv-dynamic-module.cc | 17 ++
src/common/nmv-dynamic-module.h | 39 +++++
src/dbgengine/nmv-dbg-common.h | 152 ++++++++++++++----
src/dbgengine/nmv-gdb-engine.cc | 292 ++++++++++++++++++++++++++++++++++-
src/dbgengine/nmv-gdb-engine.h | 30 ++++-
src/dbgengine/nmv-gdbmi-parser.cc | 314 ++++++++++++++++++++++++++++++++++++-
src/dbgengine/nmv-gdbmi-parser.h | 13 ++
src/dbgengine/nmv-i-debugger.h | 82 +++++++++-
tests/Makefile.am | 6 +-
tests/fooprog.cc | 4 +-
tests/test-gdbmi.cc | 50 ++++++
tests/test-vars.cc | 195 +++++++++++++++++++++++
12 files changed, 1149 insertions(+), 45 deletions(-)
diff --git a/src/common/nmv-dynamic-module.cc b/src/common/nmv-dynamic-module.cc
index 984f809..0a5caa6 100644
--- a/src/common/nmv-dynamic-module.cc
+++ b/src/common/nmv-dynamic-module.cc
@@ -397,6 +397,7 @@ public:
struct DynamicModule::Priv {
UString real_library_path ;
+ UString name;
DynamicModule::Loader *loader ;
Priv () :
@@ -428,6 +429,20 @@ DynamicModule::set_real_library_path (const UString &a_path)
}
void
+DynamicModule::set_name (const UString &a_name)
+{
+ THROW_IF_FAIL (m_priv) ;
+ m_priv->name = a_name;
+}
+
+const UString&
+DynamicModule::get_name () const
+{
+ THROW_IF_FAIL (m_priv) ;
+ return m_priv->name;
+}
+
+void
DynamicModule::set_module_loader (DynamicModule::Loader *a_loader)
{
THROW_IF_FAIL (m_priv) ;
@@ -488,6 +503,8 @@ DynamicModuleManager::load_module (const UString &a_name,
LOG_REF_COUNT (module, a_name) ;
module->set_module_loader (&a_loader) ;
+ module->set_name (a_name);
+ module->set_real_library_path (a_loader.module_library_path (a_name));
a_loader.set_dynamic_module_manager (this) ;
LOG_REF_COUNT (module, a_name) ;
diff --git a/src/common/nmv-dynamic-module.h b/src/common/nmv-dynamic-module.h
index f384384..27c543c 100644
--- a/src/common/nmv-dynamic-module.h
+++ b/src/common/nmv-dynamic-module.h
@@ -152,6 +152,8 @@ private:
void set_real_library_path (const UString &a_path) ;
+ void set_name (const UString &a_name) ;
+
void set_module_loader (Loader *a_loader) ;
@@ -166,6 +168,9 @@ public:
/// \return the path of the library the module has been instanciated from.
const UString& get_real_library_path () const ;
+ /// \brief gets the (short) name of this dynmod
+ const UString& get_name () const;
+
/// \brief destructor
virtual ~DynamicModule () ;
@@ -390,6 +395,40 @@ DynamicModuleManager::load_iface_with_default_manager
return get_default_manager ().load_iface<T> (a_mod_name, a_iface_name) ;
}
+/// This is a shortcut method to load an interface
+/// using the same module_manager that was used to load
+/// a_iface.
+template<class T>
+SafePtr<T, ObjectRef, ObjectUnref>
+load_iface_using_context (DynModIface &a_iface,
+ const UString &a_iface_name)
+{
+ DynamicModuleManager *manager =
+ a_iface.get_dynamic_module ().get_module_loader ()
+ ->get_dynamic_module_manager ();
+ THROW_IF_FAIL (manager);
+ SafePtr<T, ObjectRef, ObjectUnref> iface =
+ manager->load_iface<T> (a_iface.get_dynamic_module ().get_name (),
+ a_iface_name);
+ THROW_IF_FAIL (iface);
+ return iface;
+}
+
+template<class T>
+SafePtr<T, ObjectRef, ObjectUnref>
+load_iface_using_context (DynamicModule &a_dynmod,
+ const UString &a_iface_name)
+{
+ DynamicModuleManager *manager =
+ a_dynmod.get_module_loader () ->get_dynamic_module_manager ();
+
+ THROW_IF_FAIL (manager);
+ SafePtr<T, ObjectRef, ObjectUnref> iface =
+ manager->load_iface<T> (a_dynmod.get_name (), a_iface_name);
+ THROW_IF_FAIL (iface);
+ return iface;
+}
+
NEMIVER_END_NAMESPACE (common)
NEMIVER_END_NAMESPACE (nemiver)
diff --git a/src/dbgengine/nmv-dbg-common.h b/src/dbgengine/nmv-dbg-common.h
index a0d4dd6..0ae7ec4 100644
--- a/src/dbgengine/nmv-dbg-common.h
+++ b/src/dbgengine/nmv-dbg-common.h
@@ -36,20 +36,27 @@ class Command {
UString m_tag1 ;
UString m_cookie ;
IDebugger::VariableSafePtr m_var ;
+ sigc::slot_base m_slot;
public:
- Command () {clear ();}
+ Command () :
+ m_slot (0)
+ {
+ clear ();
+ }
/// \param a_value a textual command to send to the debugger.
Command (const UString &a_value) :
- m_value (a_value)
+ m_value (a_value),
+ m_slot (0)
{
}
Command (const UString &a_name, const UString &a_value) :
m_name (a_name),
- m_value (a_value)
+ m_value (a_value),
+ m_slot (0)
{
}
@@ -58,7 +65,8 @@ public:
const UString &a_cookie) :
m_name (a_name),
m_value (a_value),
- m_cookie (a_cookie)
+ m_cookie (a_cookie),
+ m_slot (0)
{
}
@@ -84,6 +92,23 @@ public:
void variable (const IDebugger::VariableSafePtr a_in) {m_var = a_in;}
IDebugger::VariableSafePtr variable () const {return m_var;}
+ bool has_slot () const
+ {
+ return m_slot;
+ }
+
+ template<class T>
+ void set_slot (T &a_slot)
+ {
+ m_slot = a_slot;
+ }
+
+ template<class T>
+ const T& get_slot () const
+ {
+ return reinterpret_cast<const T&> (m_slot);
+ }
+
/// @}
void clear ()
@@ -361,10 +386,56 @@ public:
size_t m_memory_address;
bool m_has_memory_values;
+ // Variable Object
+ IDebugger::VariableSafePtr m_variable;
+ bool m_has_variable;
+
+ // Variable Object deletion information
+ int m_nb_variable_deleted;
+
+ // Children variables of a given variable.
+ vector<IDebugger::VariableSafePtr> m_variable_children;
+ bool m_has_variable_children;
public:
ResultRecord () {clear () ;}
+ /// blank out everything
+ void clear ()
+ {
+ m_kind = UNDEFINED ;
+ m_breakpoints.clear () ;
+ m_attrs.clear () ;
+ m_call_stack.clear () ;
+ m_has_call_stack = false ;
+ m_frames_parameters.clear () ;
+ m_has_frames_parameters = false ;
+ m_local_variables.clear () ;
+ m_has_local_variables = false ;
+ m_variable_value.reset () ;
+ m_has_variable_value = false ;
+ m_thread_list.clear () ;
+ m_has_thread_list = false ;
+ m_thread_id = 0;
+ m_frame_in_thread.clear () ;
+ m_thread_id_got_selected = false;
+ m_file_list.clear () ;
+ m_has_file_list = false ;
+ m_has_current_frame_in_core_stack_trace = false ;
+ m_has_changed_registers = false;
+ m_changed_registers.clear ();
+ m_has_register_values = false;
+ m_register_values.clear ();
+ m_has_register_names = false;
+ m_register_names.clear ();
+ m_memory_values.clear ();
+ m_memory_address = 0;
+ m_has_memory_values = false;
+ m_has_variable = false;
+ m_nb_variable_deleted = 0;
+ m_has_variable_children = false;
+ }
+
/// \name accessors
/// @{
@@ -530,39 +601,52 @@ public:
m_has_current_frame_in_core_stack_trace = a_in ;
}
- /// @}
+ bool has_variable () {return m_has_variable; }
+ void has_variable (bool a_in) {m_has_variable = a_in;}
- void clear ()
+ IDebugger::VariableSafePtr variable () const
{
- m_kind = UNDEFINED ;
- m_breakpoints.clear () ;
- m_attrs.clear () ;
- m_call_stack.clear () ;
- m_has_call_stack = false ;
- m_frames_parameters.clear () ;
- m_has_frames_parameters = false ;
- m_local_variables.clear () ;
- m_has_local_variables = false ;
- m_variable_value.reset () ;
- m_has_variable_value = false ;
- m_thread_list.clear () ;
- m_has_thread_list = false ;
- m_thread_id = 0;
- m_frame_in_thread.clear () ;
- m_thread_id_got_selected = false;
- m_file_list.clear () ;
- m_has_file_list = false ;
- m_has_current_frame_in_core_stack_trace = false ;
- m_has_changed_registers = false;
- m_changed_registers.clear ();
- m_has_register_values = false;
- m_register_values.clear ();
- m_has_register_names = false;
- m_register_names.clear ();
- m_memory_values.clear ();
- m_memory_address = 0;
- m_has_memory_values = false;
+ return m_variable;
+ }
+ void variable (const IDebugger::VariableSafePtr a_var)
+ {
+ m_variable = a_var;
+ has_variable (true);
+ }
+
+ int number_of_variables_deleted () const
+ {
+ return m_nb_variable_deleted;
+ }
+
+ void number_of_variables_deleted (int a_nb)
+ {
+ m_nb_variable_deleted = a_nb;
+ }
+
+ bool has_variable_children () const
+ {
+ return m_has_variable_children;
+ }
+ void has_variable_children (bool a_in)
+ {
+ m_has_variable_children = a_in;
+ }
+
+ const vector<IDebugger::VariableSafePtr>&
+ variable_children () const
+ {
+ return m_variable_children;
+ }
+ void
+ variable_children (const vector<IDebugger::VariableSafePtr> &a_vars)
+ {
+ m_variable_children = a_vars;
+ has_variable_children (true);
}
+
+ /// @}
+
};//end class ResultRecord
private:
diff --git a/src/dbgengine/nmv-gdb-engine.cc b/src/dbgengine/nmv-gdb-engine.cc
index c5fd75b..18d8862 100644
--- a/src/dbgengine/nmv-gdb-engine.cc
+++ b/src/dbgengine/nmv-gdb-engine.cc
@@ -227,6 +227,14 @@ public:
read_memory_signal;
mutable sigc::signal <void, size_t, const std::vector<uint8_t>&, const UString& >
set_memory_signal;
+ mutable sigc::signal<void, const VariableSafePtr, const UString&>
+ variable_created_signal;
+
+ mutable sigc::signal<void, const VariableSafePtr, const UString&>
+ variable_deleted_signal;
+
+ mutable sigc::signal<void, const VariableSafePtr, const UString&>
+ variable_unfolded_signal;
//***********************
//</GDBEngine attributes>
@@ -2012,6 +2020,144 @@ struct OnErrorHandler : OutputHandler {
}
};//struct OnErrorHandler
+struct OnCreateVariableHandler : public OutputHandler
+{
+ GDBEngine *m_engine;
+
+ OnCreateVariableHandler (GDBEngine *a_engine) :
+ m_engine (a_engine)
+ {
+ }
+
+ bool can_handle (CommandAndOutput &a_in)
+ {
+ if (a_in.output ().has_result_record ()
+ && (a_in.output ().result_record ().kind ()
+ == Output::ResultRecord::DONE)
+ && (a_in.command ().name () == "create-variable")
+ && (a_in.output ().result_record ().has_variable ())) {
+ LOG_DD ("handler selected");
+ return true;
+ }
+ return false;
+ }
+
+ void do_handle (CommandAndOutput &a_in __attribute__ ((unused)))
+ {
+ // Set the name of the variable to the name that got stored
+ // in the tag0 member of the command.
+ a_in.output ().result_record ().variable ()->name
+ (a_in.command ().tag0 ());
+
+ // Call the slot associated to IDebugger::create_variable (), if
+ // any.
+ if (a_in.command ().has_slot ()) {
+ typedef sigc::slot<void, IDebugger::VariableSafePtr> SlotType;
+ SlotType slot = a_in.command ().get_slot<SlotType> ();
+ slot (a_in.output ().result_record ().variable ());
+ }
+ // Emit the general IDebugger::variable_create_signal () signal
+ m_engine->variable_created_signal ().emit
+ (a_in.output ().result_record ().variable (),
+ a_in.command ().cookie ());
+ if (m_engine->get_state () != IDebugger::PROGRAM_EXITED
+ || m_engine->get_state () != IDebugger::NOT_STARTED) {
+ m_engine->set_state (IDebugger::READY);
+ }
+ }
+};// end OnCreateVariableHandler
+
+struct OnDeleteVariableHandler : public OutputHandler {
+ GDBEngine *m_engine;
+
+ OnDeleteVariableHandler (GDBEngine *a_engine) :
+ m_engine (a_engine)
+ {
+ }
+
+ bool can_handle (CommandAndOutput &a_in)
+ {
+ if (a_in.output ().has_result_record ()
+ && (a_in.output ().result_record ().kind ()
+ == Output::ResultRecord::DONE)
+ && (a_in.command ().name () == "delete-variable")
+ && (a_in.output ().result_record ().number_of_variables_deleted ())) {
+ LOG_DD ("handler selected");
+ return true;
+ }
+ return false;
+ }
+
+ void do_handle (CommandAndOutput &a_in)
+ {
+ THROW_IF_FAIL (a_in.command ().variable ());
+ THROW_IF_FAIL (m_engine);
+
+ // Call the slot associated to IDebugger::delete_variable (), if
+ // Any.
+ if (a_in.command ().has_slot ()) {
+ typedef sigc::slot<void, const IDebugger::VariableSafePtr> SlotType;
+ SlotType slot = a_in.command ().get_slot<SlotType> ();
+ slot (a_in.command ().variable ());
+ }
+ // Emit the general IDebugger::variable_deleted_signal ().
+ m_engine->variable_deleted_signal ().emit
+ (a_in.command ().variable (),
+ a_in.command ().cookie ());
+ }
+}; // end OnDeleteVariableHandler
+
+struct OnUnfoldVariableHandler : public OutputHandler {
+ GDBEngine *m_engine;
+
+ OnUnfoldVariableHandler (GDBEngine *a_engine) :
+ m_engine (a_engine)
+ {
+ }
+
+ bool can_handle (CommandAndOutput &a_in)
+ {
+ if ((a_in.output ().result_record ().kind ()
+ == Output::ResultRecord::DONE)
+ && a_in.output ().result_record ().has_variable_children ()
+ && a_in.command ().name () == "unfold-variable") {
+ LOG_DD ("handler selected");
+ return true;
+ }
+ return false;
+ }
+
+ void do_handle (CommandAndOutput &a_in)
+ {
+ // *************************************************************
+ // append the unfolded variable children to the parent variable
+ // supplied by the client code.
+ // *************************************************************
+ IDebugger::VariableSafePtr parent_var = a_in.command ().variable ();
+ THROW_IF_FAIL (parent_var);
+ typedef vector<IDebugger::VariableSafePtr> Variables;
+ Variables children_vars =
+ a_in.output ().result_record ().variable_children ();
+ for (Variables::const_iterator it = children_vars.begin ();
+ it != children_vars.end ();
+ ++it) {
+ parent_var->append (*it);
+ }
+
+ // Call the slot associated to IDebugger::unfold_variable (), if
+ // any.
+ if (a_in.command ().has_slot ()) {
+ typedef sigc::slot<void, const IDebugger::VariableSafePtr> SlotType;
+ SlotType slot = a_in.command ().get_slot<SlotType> ();
+ slot (a_in.command ().variable ());
+ }
+
+ // Now tell the world we have an unfolded variable.
+ m_engine->variable_unfolded_signal ().emit
+ (parent_var, a_in.command ().cookie ());
+ }
+};// End struct OnUnfoldVariableHandler
+
//****************************
//</GDBengine output handlers
//***************************
@@ -2286,6 +2432,12 @@ GDBEngine::init_output_handlers ()
(OutputHandlerSafePtr (new OnReadMemoryHandler (this)));
m_priv->output_handler_list.add
(OutputHandlerSafePtr (new OnSetMemoryHandler (this)));
+ m_priv->output_handler_list.add
+ (OutputHandlerSafePtr (new OnCreateVariableHandler (this)));
+ m_priv->output_handler_list.add
+ (OutputHandlerSafePtr (new OnDeleteVariableHandler (this)));
+ m_priv->output_handler_list.add
+ (OutputHandlerSafePtr (new OnUnfoldVariableHandler (this)));
}
sigc::signal<void, Output&>&
@@ -2537,6 +2689,24 @@ GDBEngine::state_changed_signal () const
return m_priv->state_changed_signal;
}
+sigc::signal<void, const IDebugger::VariableSafePtr, const UString&>&
+GDBEngine::variable_created_signal () const
+{
+ return m_priv->variable_created_signal;
+}
+
+sigc::signal<void, const IDebugger::VariableSafePtr, const UString&>&
+GDBEngine::variable_deleted_signal () const
+{
+ return m_priv->variable_deleted_signal;
+}
+
+sigc::signal<void, const IDebugger::VariableSafePtr, const UString&>&
+GDBEngine::variable_unfolded_signal () const
+{
+ return m_priv->variable_unfolded_signal;
+}
+
//******************
//<signal handlers>
//******************
@@ -3613,16 +3783,134 @@ GDBEngine::set_memory (size_t a_addr,
iter != a_bytes.end (); ++iter)
{
UString cmd_str;
- cmd_str.printf ("-data-evaluate-expression \"*(unsigned char*)%zu = 0x%X\"",
+ cmd_str.printf ("-data-evaluate-expression "
+ "\"*(unsigned char*)%zu = 0x%X\"",
a_addr++,
*iter);
- Command command("set-memory", cmd_str, a_cookie);
+ Command command ("set-memory", cmd_str, a_cookie);
command.tag0 ("set-memory");
command.tag1 (UString ().printf ("0x%X",a_addr));
queue_command (command);
}
}
+void
+GDBEngine::create_variable (const UString &a_name,
+ const UString &a_cookie)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ if (a_name.empty ()) {
+ LOG ("got empty name");
+ return;
+ }
+
+ Command command ("create-variable",
+ "-var-create - * " + a_name,
+ a_cookie);
+ command.tag0 (a_name);
+
+ queue_command (Command ("create-variable",
+ "-var-create - * " + a_name,
+ a_cookie));
+}
+
+void
+GDBEngine::create_variable (const UString &a_name ,
+ const sigc::slot<void, const VariableSafePtr> &a_slot)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ if (a_name.empty ()) {
+ LOG ("got empty name");
+ return;
+ }
+
+ Command command ("create-variable",
+ "-var-create - * " + a_name);
+ command.tag0 (a_name);
+ command.set_slot (a_slot);
+
+ queue_command (command);
+}
+
+void
+GDBEngine::delete_variable (const VariableSafePtr a_var,
+ const UString &a_cookie)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ THROW_IF_FAIL (a_var);
+ THROW_IF_FAIL (!a_var->internal_name ().empty ());
+
+ Command command ("delete-variable",
+ "-var-delete " + a_var->internal_name (),
+ a_cookie);
+ command.variable (a_var);
+ queue_command (command);
+}
+
+void
+GDBEngine::delete_variable (const VariableSafePtr a_var,
+ const sigc::slot<void,const VariableSafePtr> &a_slot)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ THROW_IF_FAIL (a_var);
+ THROW_IF_FAIL (!a_var->internal_name ().empty ());
+
+ Command command ("delete-variable",
+ "-var-delete " + a_var->internal_name ());
+ command.variable (a_var);
+ command.set_slot (a_slot);
+
+ queue_command (command);
+}
+
+void
+GDBEngine::unfold_variable (const VariableSafePtr a_var,
+ const UString &a_cookie)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ THROW_IF_FAIL (a_var);
+ if (a_var->internal_name ().empty ()) {
+ UString qname;
+ a_var->build_qualified_internal_name (qname);
+ a_var->internal_name (qname);
+ }
+ THROW_IF_FAIL (!a_var->internal_name ().empty ());
+
+ Command command ("unfold-variable",
+ "-var-list-children" + a_var->internal_name (),
+ a_cookie);
+ command.variable (a_var);
+
+ queue_command (command);
+}
+
+void
+GDBEngine::unfold_variable (const VariableSafePtr a_var,
+ const sigc::slot<void, const VariableSafePtr> &a_slot)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ THROW_IF_FAIL (a_var);
+ if (a_var->internal_name ().empty ()) {
+ UString qname;
+ a_var->build_qualified_internal_name (qname);
+ a_var->internal_name (qname);
+ }
+ THROW_IF_FAIL (!a_var->internal_name ().empty ());
+
+ Command command ("unfold-variable",
+ "-var-list-children " + a_var->internal_name ());
+ command.variable (a_var);
+ command.set_slot (a_slot);
+
+ queue_command (command);
+}
+
//****************************
//</GDBEngine methods>
//****************************
diff --git a/src/dbgengine/nmv-gdb-engine.h b/src/dbgengine/nmv-gdb-engine.h
index 833ec75..aaeda62 100644
--- a/src/dbgengine/nmv-gdb-engine.h
+++ b/src/dbgengine/nmv-gdb-engine.h
@@ -173,6 +173,15 @@ public:
read_memory_signal () const;
sigc::signal <void, size_t, const std::vector<uint8_t>&, const UString& >&
set_memory_signal () const;
+
+ sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_created_signal () const;
+
+ sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_deleted_signal () const;
+
+ sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_unfolded_signal () const;
//*************
//</signals>
//*************
@@ -290,7 +299,7 @@ public:
map<int, IDebugger::BreakPoint>& get_cached_breakpoints () ;
void set_catch (const UString &a_event,
- const UString &a_cookie) ;
+ const UString &a_cookie) ;
void enable_breakpoint (gint a_break_num,
const UString &a_cookie="");
@@ -359,7 +368,8 @@ public:
int &a_proc_pid,
UString &a_exe_path) ;
- typedef std::map<UString, std::list<IDebugger::VariableSafePtr> > VarsPerFilesMap ;
+ typedef std::map<UString, std::list<IDebugger::VariableSafePtr> >
+ VarsPerFilesMap ;
bool extract_global_variable_list (Output &a_output,
VarsPerFilesMap &a_vars) ;
@@ -382,6 +392,22 @@ public:
void set_memory (size_t a_addr,
const std::vector<uint8_t>& a_bytes,
const UString& a_cookie="");
+
+ void create_variable (const UString &a_name,
+ const UString &a_cookie="");
+ void create_variable (const UString &a_name,
+ const sigc::slot<void, const VariableSafePtr>&);
+
+ void delete_variable (const VariableSafePtr a_var,
+ const UString &a_cookie);
+
+ void delete_variable (const VariableSafePtr a_var,
+ const sigc::slot<void,const VariableSafePtr>&);
+
+ void unfold_variable (VariableSafePtr a_var,
+ const UString &a_cookie);
+ void unfold_variable (VariableSafePtr a_var,
+ const sigc::slot<void, const VariableSafePtr> &);
};//end class GDBEngine
NEMIVER_END_NAMESPACE (nemiver)
diff --git a/src/dbgengine/nmv-gdbmi-parser.cc b/src/dbgengine/nmv-gdbmi-parser.cc
index 741051b..83404dc 100644
--- a/src/dbgengine/nmv-gdbmi-parser.cc
+++ b/src/dbgengine/nmv-gdbmi-parser.cc
@@ -111,6 +111,8 @@ while (!m_priv->index_passed_end (a_from) && isblank (RAW_CHAR_AT (a_from))) { \
#define RAW_INPUT m_priv->input.raw ()
+#define END_OF_INPUT(cur) m_priv->index_passed_end (cur)
+
using namespace std;
using namespace nemiver::common;
@@ -139,6 +141,11 @@ const char* PREFIX_REGISTER_VALUES = "register-values=";
const char* PREFIX_MEMORY_VALUES = "addr=";
const char* PREFIX_RUNNING_ASYNC_OUTPUT = "*running,";
const char* PREFIX_STOPPED_ASYNC_OUTPUT = "*stopped,";
+const char* PREFIX_NAME = "name=\"";
+const char* PREFIX_VARIABLE_DELETED = "ndeleted=\"";
+const char* NDELETED = "ndeleted";
+const char* PREFIX_NUMCHILD= "numchild=\"";
+const char* NUMCHILD= "numchild";
bool parse_c_string_body (const UString &a_input,
UString::size_type a_from,
@@ -4721,7 +4728,8 @@ fetch_gdbmi_result:
parse_gdbmi_result (cur, cur, result);
THROW_IF_FAIL (result);
LOG_D ("parsed result", GDBMI_PARSING_DOMAIN);
- } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_STACK_ARGS),
+ } else if (!m_priv->input.raw ().compare (cur,
+ strlen (PREFIX_STACK_ARGS),
PREFIX_STACK_ARGS)) {
map<int, list<IDebugger::VariableSafePtr> > frames_args;
if (!parse_stack_arguments (cur, cur, frames_args)) {
@@ -4796,6 +4804,39 @@ fetch_gdbmi_result:
LOG_D ("parsed memory values", GDBMI_PARSING_DOMAIN);
result_record.memory_values (addr, values);
}
+ } else if (!RAW_INPUT.compare (cur,
+ strlen (PREFIX_NAME),
+ PREFIX_NAME)) {
+ IDebugger::VariableSafePtr var;
+ if (!parse_variable (cur, cur, var)) {
+ LOG_PARSING_ERROR2 (cur);
+ } else {
+ THROW_IF_FAIL (var);
+ LOG_D ("parsed variable, name: "
+ << var->name ()
+ << "internal name: "
+ << var->internal_name (),
+ GDBMI_PARSING_DOMAIN);
+ result_record.variable (var);
+ }
+ } else if (!RAW_INPUT.compare (cur, strlen (PREFIX_VARIABLE_DELETED),
+ PREFIX_VARIABLE_DELETED)) {
+ unsigned int nb_variables_deleted = 0;
+ if (parse_variables_deleted (cur, cur, nb_variables_deleted)
+ && nb_variables_deleted) {
+ result_record.number_of_variables_deleted
+ (nb_variables_deleted);
+ } else {
+ LOG_PARSING_ERROR2 (cur);
+ }
+ } else if (!RAW_INPUT.compare (cur, strlen (PREFIX_NUMCHILD),
+ PREFIX_NUMCHILD)) {
+ vector<IDebugger::VariableSafePtr> vars;
+ if (parse_var_list_children (cur, cur, vars)) {
+ result_record.variable_children (vars);
+ } else {
+ LOG_PARSING_ERROR2 (cur);
+ }
} else {
GDBMIResultSafePtr result;
if (!parse_gdbmi_result (cur, cur, result)
@@ -5998,6 +6039,215 @@ GDBMIParser::parse_variable_value (const UString::size_type a_from,
}
bool
+GDBMIParser::parse_variables_deleted (UString::size_type a_from,
+ UString::size_type &a_to,
+ unsigned int &a_nb_vars_deleted)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+ UString::size_type cur = a_from;
+ CHECK_END2 (cur);
+
+ if (RAW_INPUT.compare (cur, strlen (PREFIX_VARIABLE_DELETED),
+ PREFIX_VARIABLE_DELETED)) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ GDBMIResultSafePtr result;
+ if (!parse_gdbmi_result (cur, cur, result) || !result) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ if (result->variable () != NDELETED) {
+ LOG_ERROR ("expected gdbmi variable " << NDELETED << ", got: "
+ << result->variable () << "\'");
+ return false;
+ }
+ if (!result->value ()
+ || result->value ()->content_type () != GDBMIValue::STRING_TYPE) {
+ LOG_ERROR ("expected a string value for "
+ "the GDBMI variable " << NDELETED);
+ return false;
+ }
+ UString val = result->value ()->get_string_content ();
+ a_nb_vars_deleted = val.empty () ? 0 : atoi (val.c_str ());
+ a_to = cur;
+ return true;
+}
+
+bool
+GDBMIParser::parse_var_list_children
+ (UString::size_type a_from,
+ UString::size_type &a_to,
+ std::vector<IDebugger::VariableSafePtr> &a_vars)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+ UString::size_type cur = a_from;
+ CHECK_END2 (cur);
+
+
+ if (RAW_INPUT.compare (cur, strlen (PREFIX_NUMCHILD),
+ PREFIX_NUMCHILD)) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ GDBMIResultSafePtr result;
+ if (!parse_gdbmi_result (cur, cur, result) || !result) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ if (result->variable () != NUMCHILD) {
+ LOG_ERROR ("expected gdbmi variable " << NUMCHILD<< ", got: "
+ << result->variable () << "\'");
+ return false;
+ }
+ if (!result->value ()
+ || result->value ()->content_type () != GDBMIValue::STRING_TYPE) {
+ LOG_ERROR ("expected a string value for "
+ "the GDBMI variable " << NUMCHILD);
+ return false;
+ }
+ UString s = result->value ()->get_string_content ();
+ unsigned num_children = s.empty () ? 0 : atoi (s.c_str ());
+
+ if (!num_children) {
+ LOG_D ("Variable has zero children",
+ GDBMI_PARSING_DOMAIN);
+ a_to = cur;
+ return true;
+ }
+
+ SKIP_BLANK2 (cur);
+ if (RAW_CHAR_AT (cur) != ',') {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ ++cur;
+ SKIP_BLANK2 (cur);
+ result.reset ();
+ if (!parse_gdbmi_result (cur, cur, result) || !result) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+ if (result->variable () != "children") {
+ LOG_ERROR ("expected gdbmi variable " << "children" << ", got: "
+ << result->variable () << "\'");
+ return false;
+ }
+ if (!result->value ()
+ || result->value ()->content_type () != GDBMIValue::LIST_TYPE) {
+ LOG_ERROR ("expected a LIST value for "
+ "the GDBMI variable " << "children");
+ return false;
+ }
+ GDBMIListSafePtr children = result->value ()->get_list_content ();
+ THROW_IF_FAIL (children);
+
+ if (children->empty ()) {
+ a_to = cur;
+ return true;
+ }
+ if (children->content_type () != GDBMIList::RESULT_TYPE) {
+ LOG_ERROR ("Expected the elements of the 'children' LIST to be "
+ "of kind RESULT");
+ return false;
+ }
+ list<GDBMIResultSafePtr> children_results;
+ children->get_result_content (children_results);
+
+ if (children_results.empty ()) {
+ a_to = cur;
+ return true;
+ }
+
+ // Walk the children variables, that are packed in the children_result
+ // list of RESULT. Each RESULT represents a variable, that is a child
+ // of a_var.
+ typedef list<GDBMIResultSafePtr>::const_iterator ResultsIter;
+ for (ResultsIter result_it = children_results.begin ();
+ result_it != children_results.end ();
+ ++result_it) {
+ if (!*result_it) {
+ LOG_ERROR ("Got NULL RESULT in the list of children variables.");
+ continue;
+ }
+ if ((*result_it)->variable () != "child") {
+ LOG_ERROR ("Expected the name of the child result to be 'child'."
+ "Got " << (*result_it)->variable ());
+ return false;
+ }
+ if ((*result_it)->value ()->content_type () != GDBMIValue::TUPLE_TYPE) {
+ LOG_ERROR ("Values of the 'child' result must be a kind TYPE");
+ return false;
+ }
+ // The components of a given variable result_it are packed into
+ // the list of RESULT below.
+ list<GDBMIResultSafePtr> child_comps =
+ (*result_it)->value ()->get_tuple_content ()->content ();
+
+ // Walk the list of the components of the current child of a_var.
+ // At this end of this walk, we will be able to build a child
+ // of a_var, instance of IDebugger::Variable.
+ UString s, v, name, internal_name, value, type;
+ unsigned int numchildren = 0;
+ for (ResultsIter it = child_comps.begin ();
+ it != child_comps.end ();
+ ++it) {
+ if (!(*it)) {
+ LOG_ERROR ("Got a NULL RESULT as a variable component");
+ continue;
+ }
+ v = (*it)->variable ();
+ s = (*it)->value ()->get_string_content ();
+ if (v == "name") {
+ if ((*it)->value ()->content_type ()
+ != GDBMIValue::STRING_TYPE) {
+ LOG_ERROR ("Variable internal name should "
+ "have a string value");
+ continue;
+ }
+ internal_name = s;
+ } else if (v == "exp") {
+ if ((*it)->value ()->content_type ()
+ != GDBMIValue::STRING_TYPE) {
+ LOG_ERROR ("Variable name should "
+ "have a string value");
+ continue;
+ }
+ name = s;
+ } else if (v == "value") {
+ value = s;
+ } else if (v == "type") {
+ if ((*it)->value ()->content_type ()
+ != GDBMIValue::STRING_TYPE) {
+ LOG_ERROR ("Variable type should "
+ "have a string value");
+ continue;
+ }
+ type = s;
+ } else if (v == "numchild") {
+ numchildren = atoi (s.c_str ());
+ }
+ }
+ if (!name.empty ()
+ && !internal_name.empty ()
+ /* We don't require type to be non empty
+ * because members might have empty types. For instance,
+ * GDB considers the 'public' or 'protected' keywords of a class
+ * to be a member without type.
+ * We don't require value to be non empty either, as
+ * members that have children won't have any value. */) {
+ IDebugger::VariableSafePtr var
+ (new IDebugger::Variable (internal_name,
+ name, value, type));
+ var->num_expected_children (numchildren);
+ a_vars.push_back (var);
+ }
+ }
+ a_to = cur;
+ return true;
+}
+
+bool
GDBMIParser::parse_register_names (UString::size_type a_from,
UString::size_type &a_to,
std::map<IDebugger::register_id_t,
@@ -6304,6 +6554,68 @@ GDBMIParser::parse_memory_values (UString::size_type a_from,
}
bool
+GDBMIParser::parse_variable (UString::size_type a_from,
+ UString::size_type &a_to,
+ IDebugger::VariableSafePtr &a_var)
+{
+ LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+ UString::size_type cur=a_from;
+
+ if (RAW_INPUT.compare (cur, strlen (PREFIX_NAME), PREFIX_NAME)) {
+ LOG_PARSING_ERROR2 (cur);
+ return false;
+ }
+
+ IDebugger::VariableSafePtr var (new IDebugger::Variable);
+ // Okay, this is going to be a sequence of RESULT (name=value), where
+ // RESULTs are separated by a comma, e.g:
+ // name="var1", numchild="0", value="0",type="int"
+ GDBMIResultSafePtr result;
+ UString value;
+ bool got_variable = false;
+ SKIP_BLANK2 (cur);
+ while (!END_OF_INPUT (cur)
+ && RAW_CHAR_AT (cur) != '\n'
+ && parse_gdbmi_result (cur, cur, result)
+ && result) {
+ LOG_D ("result variable name: " << result->variable (),
+ GDBMI_PARSING_DOMAIN);
+ // the value of result must be a string
+ THROW_IF_FAIL (result->value ()
+ && (result->value ()->content_type ()
+ == GDBMIValue::STRING_TYPE));
+ value = result->value ()->get_string_content ();
+ if (result->variable () == "name") {
+ var->internal_name (value);
+ got_variable = true;
+ } else if (result->variable () == "value") {
+ var->value (value);
+ } else if (result->variable () == "numchild") {
+ int s = atoi (value.c_str ());
+ LOG_D ("num children: " << s, GDBMI_PARSING_DOMAIN);
+ } else if (result->variable () == "type") {
+ var->type (value);
+ } else {
+ LOG_D ("hugh? unknown result variable: " << result->variable (),
+ GDBMI_PARSING_DOMAIN);
+ }
+ SKIP_BLANK2 (cur);
+ if (RAW_CHAR_AT (cur) == ',') {
+ cur++;
+ }
+ SKIP_BLANK2 (cur);
+ }
+
+ if (got_variable) {
+ a_to = cur;
+ a_var = var;
+ return true;
+ }
+ return false;
+}
+
+bool
GDBMIParser::parse_overloads_choice_prompt
(UString::size_type a_from,
UString::size_type &a_to,
diff --git a/src/dbgengine/nmv-gdbmi-parser.h b/src/dbgengine/nmv-gdbmi-parser.h
index 202e86c..01afbe6 100644
--- a/src/dbgengine/nmv-gdbmi-parser.h
+++ b/src/dbgengine/nmv-gdbmi-parser.h
@@ -783,6 +783,18 @@ public:
size_t& a_start_addr,
std::vector<uint8_t> &a_values);
+ bool parse_variable (UString::size_type a_from,
+ UString::size_type &a_to,
+ IDebugger::VariableSafePtr &a_var);
+
+ bool parse_variables_deleted (UString::size_type a_from,
+ UString::size_type &a_to,
+ unsigned int &a_nb_vars_deleted);
+
+ bool parse_var_list_children (UString::size_type a_from,
+ UString::size_type &a_to,
+ vector<IDebugger::VariableSafePtr> &a_vars);
+
bool parse_result_record (UString::size_type a_from,
UString::size_type &a_to,
Output::ResultRecord &a_record);
@@ -791,6 +803,7 @@ public:
bool parse_output_record (UString::size_type a_from,
UString::size_type &a_to,
Output &a_output);
+
//*********************
//</Parsing entry points.>
//*********************
diff --git a/src/dbgengine/nmv-i-debugger.h b/src/dbgengine/nmv-i-debugger.h
index 35ed562..ff56f93 100644
--- a/src/dbgengine/nmv-i-debugger.h
+++ b/src/dbgengine/nmv-i-debugger.h
@@ -279,6 +279,7 @@ public:
typedef SafePtr<Variable, ObjectRef, ObjectUnref> VariableSafePtr;
class Variable : public Object {
list<VariableSafePtr> m_members;
+ UString m_internal_name;
UString m_name;
UString m_name_caption;
UString m_value;
@@ -288,8 +289,22 @@ public:
//it can be dereferenced. The variable
//it points to is stored in m_dereferenced
VariableSafePtr m_dereferenced;
+ unsigned int m_num_expected_children;
public:
+ Variable (const UString &a_internal_name,
+ const UString &a_name,
+ const UString &a_value,
+ const UString &a_type) :
+ m_internal_name (a_internal_name),
+ m_name (a_name),
+ m_value (a_value),
+ m_type (a_type),
+ m_parent (0),
+ m_num_expected_children (0)
+
+ {
+ }
Variable (const UString &a_name,
const UString &a_value,
@@ -297,14 +312,16 @@ public:
m_name (a_name),
m_value (a_value),
m_type (a_type),
- m_parent (0)
+ m_parent (0),
+ m_num_expected_children (0)
{
}
Variable (const UString &a_name) :
m_name (a_name),
- m_parent (0)
+ m_parent (0),
+ m_num_expected_children (0)
{}
Variable () :
@@ -320,6 +337,9 @@ public:
a_var->parent (this);
}
+ const UString& internal_name () const {return m_internal_name;}
+ void internal_name (const UString &a_in) {m_internal_name = a_in;}
+
const UString& name () const {return m_name;}
void name (const UString &a_name)
{
@@ -351,6 +371,10 @@ public:
if (name () != "") {
a_str += a_indent_str + name ();
}
+
+ if (!internal_name ().empty ()) {
+ a_str += "(" + internal_name () + ")";
+ }
}
if (value () != "") {
if (a_show_var_name) {
@@ -395,6 +419,21 @@ public:
}
}
+ void build_qualified_internal_name (UString &a_qname) const
+ {
+ UString qname;
+ if (parent () == 0) {
+ a_qname = internal_name ();
+ } else if (parent ()) {
+ parent ()->build_qname (qname);
+ qname.chomp ();
+ qname += "." + name ();
+ a_qname = qname;
+ } else {
+ THROW ("should not be reached");
+ }
+ }
+
void set_dereferenced (VariableSafePtr a_derefed)
{
m_dereferenced = a_derefed;
@@ -468,6 +507,21 @@ public:
append (var);
}
}
+
+ unsigned int num_expected_children () const
+ {
+ return m_num_expected_children;
+ }
+
+ void num_expected_children (unsigned int a_in)
+ {
+ m_num_expected_children = a_in;
+ }
+
+ bool has_expected_children () const
+ {
+ return m_num_expected_children != 0;
+ }
};//end class Variable
enum State {
@@ -681,6 +735,15 @@ public:
const std::vector<uint8_t>&,/*values*/
const UString& >&
set_memory_signal () const = 0;
+
+ virtual sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_created_signal () const = 0;
+
+ virtual sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_deleted_signal () const = 0;
+
+ virtual sigc::signal<void, const VariableSafePtr, const UString&>&
+ variable_unfolded_signal () const = 0;
/// @}
virtual void do_init (IConfMgrSafePtr &a_conf_mgr) = 0;
@@ -845,7 +908,20 @@ public:
const std::vector<uint8_t>& a_bytes,
const UString& a_cookie="") = 0;
-
+ virtual void create_variable (const UString &a_name,
+ const UString &a_cookie="") = 0;
+ virtual void create_variable (const UString &a_name,
+ const sigc::slot<void,
+ const VariableSafePtr>&) = 0;
+ virtual void delete_variable (const VariableSafePtr a_var,
+ const UString &a_cookie="") = 0;
+ virtual void delete_variable (const VariableSafePtr a_var,
+ const sigc::slot<void,
+ const VariableSafePtr>&) = 0;
+ virtual void unfold_variable (VariableSafePtr a_var,
+ const UString &a_cookie) = 0;
+ virtual void unfold_variable (VariableSafePtr a_var,
+ const sigc::slot<void, const VariableSafePtr> &) = 0;
};//end IDebugger
NEMIVER_END_NAMESPACE (nemiver)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7c8998a..14e44e4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,7 +6,7 @@ if AUTOTESTS
#runtestglobalvariables
TESTS=\
runtestgdbmi runtestunicode \
-runtestcpptrait runtestvarlist \
+runtestvars runtestcpptrait runtestvarlist \
runtestvarwalker runtestbreakpoint \
runtestderef \
runtestlocalvarslist runtestcpplexer \
@@ -71,6 +71,10 @@ runtestunicode_LDADD= NEMIVERCOMMON_LIBS@ \
@BOOST_UNIT_TEST_FRAMEWORK_STATIC_LIB@ \
$(top_builddir)/src/common/libnemivercommon.la
+runtestvars_SOURCES=test-vars.cc
+runtestvars_LDADD= NEMIVERCOMMON_LIBS@ \
+$(top_builddir)/src/common/libnemivercommon.la
+
runtestvarlist_SOURCES=test-var-list.cc
runtestvarlist_LDADD= NEMIVERCOMMON_LIBS@ @BOOST_TEST_EXEC_MONITOR_LIB@ \
$(top_builddir)/src/common/libnemivercommon.la
diff --git a/tests/fooprog.cc b/tests/fooprog.cc
index 62c01d1..f1be621 100644
--- a/tests/fooprog.cc
+++ b/tests/fooprog.cc
@@ -85,9 +85,9 @@ func4 (Person &a_person)
}
int
-main (int a_argc, char *a_argv[])
+main (int a_argc __attribute__((unused)),
+ char *a_argv[] __attribute__((unused)))
{
- if (a_argc || a_argv) {}
Person person ("Bob", "Barton", 15) ;
func1 () ;
diff --git a/tests/test-gdbmi.cc b/tests/test-gdbmi.cc
index 2561e61..ce2c3cb 100644
--- a/tests/test-gdbmi.cc
+++ b/tests/test-gdbmi.cc
@@ -48,6 +48,11 @@ static const char *gv_output_record2=
"(gdb)";
static const char *gv_output_record3="^done,thread-ids={thread-id=\"1\"},current-thread-id=\"1\",number-of-threads=\"1\"\n";
+static const char *gv_output_record4="^done,name=\"var1\",numchild=\"1\",value=\"{...}\",type=\"Person\"\n";
+
+static const char *gv_output_record5="^done,ndeleted=\"2\"\n";
+
+static const char *gv_output_record6="^done,numchild=\"3\",children=[child={name=\"var2.public.m_first_name\",exp=\"m_first_name\",numchild=\"2\",type=\"string\"},child={name=\"var2.public.m_family_name\",exp=\"m_family_name\",numchild=\"2\",type=\"string\"},child={name=\"var2.public.m_age\",exp=\"m_age\",numchild=\"0\",type=\"unsigned int\"}]\n";
//the partial result of a gdbmi command: -stack-list-argument 1 command
//this command is used to implement IDebugger::list_frames_arguments()
@@ -273,6 +278,51 @@ test_output_record ()
parser.push_input (gv_output_record3);
is_ok = parser.parse_output_record (0, to, output);
BOOST_REQUIRE (is_ok) ;
+
+ // gv_output_record4 should result in a variable.
+ parser.push_input (gv_output_record4);
+ is_ok = parser.parse_output_record (0, to, output);
+ BOOST_REQUIRE (is_ok);
+ BOOST_REQUIRE (output.has_result_record ());
+ BOOST_REQUIRE (output.result_record ().has_variable ());
+ BOOST_REQUIRE (output.result_record ().variable ());
+ BOOST_REQUIRE (output.result_record ().variable ()->name ().empty ());
+ BOOST_REQUIRE (output.result_record ().variable ()->internal_name ()
+ == "var1");
+ BOOST_REQUIRE (output.result_record ().variable ()->type () == "Person");
+
+ // gv_output_record4 should result in 2 deleted variables.
+ parser.push_input (gv_output_record5);
+ is_ok = parser.parse_output_record (0, to, output);
+ BOOST_REQUIRE (is_ok);
+ BOOST_REQUIRE (output.result_record ().number_of_variables_deleted () == 2);
+
+ // gv_output_record5 should result in 3 children variables.
+ parser.push_input (gv_output_record6);
+ is_ok = parser.parse_output_record (0, to, output);
+ BOOST_REQUIRE (is_ok);
+ BOOST_REQUIRE (output.result_record ().has_variable_children ());
+ vector<IDebugger::VariableSafePtr> v =
+ output.result_record ().variable_children ();
+ BOOST_REQUIRE (v.size () == 3);
+
+ int i = 0;
+ BOOST_REQUIRE (v[i]
+ && v[i]->name () == "m_first_name"
+ && v[i]->type () == "string"
+ && v[i]->internal_name () == "var2.public.m_first_name");
+
+ i = 1;
+ BOOST_REQUIRE (v[i]
+ && v[i]->name () == "m_family_name"
+ && v[i]->type () == "string"
+ && v[i]->internal_name () == "var2.public.m_family_name");
+
+ i = 2;
+ BOOST_REQUIRE (v[i]
+ && v[i]->name () == "m_age"
+ && v[i]->type () == "unsigned int"
+ && v[i]->internal_name () == "var2.public.m_age");
}
void
diff --git a/tests/test-vars.cc b/tests/test-vars.cc
new file mode 100644
index 0000000..c431d71
--- /dev/null
+++ b/tests/test-vars.cc
@@ -0,0 +1,195 @@
+#include <iostream>
+#include <map>
+#include <string>
+#include <boost/test/minimal.hpp>
+#include <glibmm.h>
+#include "common/nmv-initializer.h"
+#include "common/nmv-exception.h"
+#include "nmv-i-var-list-walker.h"
+
+using namespace nemiver ;
+using namespace nemiver::common ;
+
+Glib::RefPtr<Glib::MainLoop> s_loop =
+ Glib::MainLoop::create (Glib::MainContext::get_default ()) ;
+static int nb_vars_created;
+static int nb_vars_created2;
+static int nb_vars_deleted;
+static int nb_vars_deleted2;
+static int unfold_requests;
+static IDebugger::VariableSafePtr var_to_delete;
+
+void on_variable_deleted_signal (const IDebugger::VariableSafePtr a_var);
+void on_variable_unfolded_signal (const IDebugger::VariableSafePtr a_var,
+ IDebuggerSafePtr a_debugger);
+
+void
+on_command_done_signal (const UString&, const UString&)
+{
+}
+
+void
+on_engine_died_signal ()
+{
+ s_loop->quit ();
+}
+
+void
+on_program_finished_signal ()
+{
+ s_loop->quit ();
+}
+
+void
+on_running_signal ()
+{
+}
+
+void
+on_variable_created_signal (IDebugger::VariableSafePtr a_var)
+{
+ MESSAGE ("variable created: " << a_var->name ());
+ nb_vars_created++;
+ if (a_var->name () == "person") {
+ // put the variable aside so that we
+ // can delete it later
+ var_to_delete = a_var;
+ }
+}
+
+void
+on_variable_created_signal2 (IDebugger::VariableSafePtr a_var,
+ const UString &,
+ IDebuggerSafePtr a_debugger)
+{
+ UString var_str;
+ a_var->to_string (var_str, true /*show var name*/);
+ MESSAGE ("variable created: " << var_str);
+ nb_vars_created2++;
+
+ unfold_requests++;
+ a_debugger->unfold_variable (a_var,
+ sigc::bind (&on_variable_unfolded_signal,
+ a_debugger));
+}
+
+void
+on_variable_unfolded_signal (const IDebugger::VariableSafePtr a_var,
+ IDebuggerSafePtr a_debugger)
+{
+ unfold_requests--;
+ UString var_str;
+ a_var->to_string (var_str, true /*show var name*/);
+ MESSAGE ("variable unfolded: " << var_str);
+ typedef list<IDebugger::VariableSafePtr>::const_iterator VarIter;
+ for (VarIter it = a_var->members ().begin ();
+ it != a_var->members ().end ();
+ ++it) {
+ if ((*it)->has_expected_children ()) {
+ unfold_requests++;
+ a_debugger->unfold_variable (*it,
+ sigc::bind (&on_variable_unfolded_signal,
+ a_debugger));
+ }
+ }
+ if (unfold_requests == 0 && var_to_delete)
+ a_debugger->delete_variable (var_to_delete,
+ &on_variable_deleted_signal);
+}
+
+void
+on_variable_deleted_signal (const IDebugger::VariableSafePtr a_var)
+{
+ MESSAGE ("variable deleted. Name: "
+ << a_var->name ()
+ << ", Internal Name: "
+ << a_var->internal_name ());
+ nb_vars_deleted++;
+}
+
+void
+on_variable_deleted_signal2 (const IDebugger::VariableSafePtr a_var,
+ const UString&)
+{
+ MESSAGE ("variable deleted. Name: "
+ << a_var->name ()
+ << ", Internal Name: "
+ << a_var->internal_name ());
+ nb_vars_deleted2++;
+}
+
+void
+on_stopped_signal (IDebugger::StopReason /*a_reason*/,
+ bool,
+ const IDebugger::Frame&,
+ int,
+ int,
+ const UString&,
+ IDebuggerSafePtr &debugger)
+{
+ static int nb_stops = 0;
+
+ nb_stops++;
+ MESSAGE ("stopped " << nb_stops << " times");
+
+ if (nb_stops == 2) {
+ // Okay we stepped once, now we can now create the variable
+ // for the person variable.
+ debugger->create_variable ("person",
+ &on_variable_created_signal);
+ MESSAGE ("Requested creation of variable 'person'");
+ }
+ debugger->step_over ();
+}
+
+NEMIVER_API int
+test_main (int argc __attribute__((unused)),
+ char **argv __attribute__ ((unused)))
+{
+ NEMIVER_TRY
+
+ Initializer::do_init ();
+
+ //load the IDebugger interface
+ IDebuggerSafePtr debugger =
+ DynamicModuleManager::load_iface_with_default_manager<IDebugger>
+ ("gdbengine",
+ "IDebugger");
+ //setup the debugger with the glib mainloop
+ debugger->set_event_loop_context (Glib::MainContext::get_default ());
+
+ //*******************************
+ //<connect to IDebugger events>
+ //******************************
+ debugger->command_done_signal ().connect (&on_command_done_signal);
+ debugger->engine_died_signal ().connect (&on_engine_died_signal);
+ debugger->program_finished_signal ().connect (&on_program_finished_signal);
+ debugger->running_signal ().connect (&on_running_signal);
+ debugger->stopped_signal ().connect (sigc::bind (&on_stopped_signal,
+ debugger));
+ debugger->variable_created_signal ().connect (sigc::bind
+ (&on_variable_created_signal2,
+ debugger));
+ debugger->variable_deleted_signal ().connect (&on_variable_deleted_signal2);
+ //*******************************
+ //</connect to IDebugger events>
+ //******************************
+ debugger->load_program ("fooprog", ".");
+ debugger->set_breakpoint ("main");
+ debugger->run ();
+
+ //****************************************
+ //run the event loop.
+ //****************************************
+ s_loop->run ();
+
+ NEMIVER_CATCH_AND_RETURN_NOX (-1)
+
+ BOOST_REQUIRE (nb_vars_created == nb_vars_created2);
+ BOOST_REQUIRE (nb_vars_created > 0);
+ BOOST_REQUIRE (nb_vars_deleted == nb_vars_deleted2);
+ BOOST_REQUIRE (nb_vars_deleted > 0);
+
+ return 0;
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]