Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

YCP Debugger!

Author:    Stanislav Visnovsky <visnov@suse.cz>
The second public version, as sent in
http://lists.opensuse.org/yast-devel/2011-07/msg00045.html

svn path=/trunk/core/; revision=65256
  • Loading branch information...
commit 34e51d59e7d9ebfeefa56d5f1ceb70fe3fe26877 1 parent 67e2a15
@mvidner mvidner authored
Showing with 1,306 additions and 36 deletions.
  1. +1 −1  SUBDIRS
  2. +1 −0  base/src/Makefile.am
  3. +1 −0  base/tools/ycpc/Makefile.am
  4. +559 −0 debugger/Debugger.cc
  5. +116 −0 debugger/Debugger.h
  6. +20 −0 debugger/Makefile.am
  7. +11 −0 debugger/TODO
  8. +11 −0 debugger/client/Makefile.am
  9. +107 −0 debugger/client/ycp-debugger
  10. +1 −0  liby2/src/Makefile.am
  11. +50 −3 liby2/src/genericfrontend.cc
  12. +2 −0  liby2/src/include/y2/Y2Namespace.h
  13. +4 −4 libycp/src/ExecutionEnvironment.cc
  14. +4 −2 libycp/src/Makefile.am
  15. +46 −2 libycp/src/YBlock.cc
  16. +153 −0 libycp/src/YBreakpoint.cc
  17. +15 −3 libycp/src/YCode.cc
  18. +4 −4 libycp/src/YExpression.cc
  19. +11 −5 libycp/src/include/ycp/ExecutionEnvironment.h
  20. +1 −1  libycp/src/include/ycp/Makefile.am
  21. +1 −1  libycp/src/include/ycp/YBlock.h
  22. +136 −0 libycp/src/include/ycp/YBreakpoint.h
  23. +7 −3 libycp/src/include/ycp/YCode.h
  24. +1 −0  libycp/src/include/ycp/YCodePtr.h
  25. +3 −3 libycp/testsuite/Makefile.am
  26. +3 −3 libycp/testsuite/tests/builtin/Backtrace.err
  27. +22 −1 wfm/src/Y2WFMComponent.cc
  28. +2 −0  wfm/testsuite/Makefile.am
  29. +13 −0 yast2-core.spec.in
View
2  SUBDIRS
@@ -1 +1 @@
-liby2util-r liby2 libycp libscr agent-dummy scr agent-system agent-any agent-ini agent-modules agent-resolver agents-non-y2 agents-perl wfm agent-process base autodocs
+liby2util-r liby2 debugger libycp libscr agent-dummy scr agent-system agent-any agent-ini agent-modules agent-resolver agents-non-y2 agents-perl wfm agent-process base autodocs
View
1  base/src/Makefile.am
@@ -12,6 +12,7 @@ YAST2CORE = \
../../libycp/src/libycp.la \
../../libycp/src/libycpvalues.la \
../../liby2/src/liby2.la \
+ ../../debugger/liby2debug.la \
../../libscr/src/libscr.la
View
1  base/tools/ycpc/Makefile.am
@@ -20,6 +20,7 @@ ycpc_LDADD = $(top_builddir)/libycp/src/libycp.la \
$(top_builddir)/liby2/src/liby2.la \
$(top_builddir)/libscr/src/libscr.la \
$(top_builddir)/scr/src/libpy2scr.la \
+ $(top_builddir)/debugger/liby2debug.la \
${Y2UTIL_LIBS}
ybin_SCRIPTS = ybcdump
View
559 debugger/Debugger.cc
@@ -0,0 +1,559 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: Debugger.cc
+
+ Basic infrastructure for YCP debugger
+
+ Author: Stanislav Visnovsky <visnov@suse.de>
+ Maintainer: Stanislav Visnovsky <visnov@suse.de>
+
+/-*/
+
+#include <y2/Y2ComponentBroker.h>
+#include <y2/Y2Component.h>
+#include <y2/Y2Namespace.h>
+#include <ycp/y2log.h>
+#include <ycp/ExecutionEnvironment.h>
+#include <ycp/YBlock.h>
+#include <ycp/YBreakpoint.h>
+#include <ycp/Parser.h>
+#include <y2util/stringutil.h>
+#include "Debugger.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#define ADDRESS "/tmp/yast.socket"
+#define PORT 16384
+
+extern ExecutionEnvironment ee;
+
+Debugger::Debugger () :
+ m_socket (-1),
+ m_descriptor (NULL),
+ m_outputstash (""),
+ m_tracing (false),
+ m_remote (false)
+{}
+
+Debugger::~Debugger ()
+{
+ // close the controll socket
+ if (m_socket)
+ {
+ close (m_socket);
+ if (m_remote)
+ unlink (ADDRESS);
+ }
+ m_socket = -1;
+}
+
+bool Debugger::initialize(bool remote)
+{
+ m_remote = remote;
+ return remote ? initializeRemote() : initializeLocal();
+}
+
+bool Debugger::initializeLocal()
+{
+ socklen_t fromlen;
+ int ns, len;
+ struct sockaddr_un saun, fsaun;
+
+ // FIXME: possible leak
+ m_socket = -1;
+ m_descriptor = NULL;
+
+ if ((m_socket = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ return false;
+ }
+
+ saun.sun_family = AF_UNIX;
+ strcpy (saun.sun_path, ADDRESS);
+
+ int res = access (ADDRESS, F_OK);
+ if ( res == 0 || errno != ENOENT )
+ {
+ y2security ("Cannot create debugger socket: %s", res == 0 ? "File exists" : strerror (errno) );
+ return false;
+ }
+
+ len = sizeof (saun.sun_family) + strlen (saun.sun_path);
+
+ if (bind (m_socket,(struct sockaddr *) &saun, len) < 0)
+ {
+ return false;
+ }
+
+ // wait for connection
+ if (listen (m_socket, 1) < 0)
+ {
+ y2error ("Debugger: listen failed");
+ return false;
+ }
+ fromlen = 108;
+
+ if ((ns = accept (m_socket, (struct sockaddr *) &fsaun, &fromlen)) < 0)
+ {
+ y2error ("Debugger: accept failed");
+ return false;
+ }
+
+ m_descriptor = fdopen (ns, "r");
+ m_last_command = c_step; // step to enable debugging from the start
+ m_ns = ns;
+
+ return true;
+}
+
+bool Debugger::initializeRemote()
+{
+ socklen_t fromlen;
+ int ns;
+ struct sockaddr_in sain, fsain;
+
+ // FIXME: possible leak
+ m_socket = -1;
+ m_descriptor = NULL;
+
+ if ((m_socket = socket (PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ return false;
+ }
+
+ sain.sin_family = PF_UNIX;
+ sain.sin_addr.s_addr=htonl(INADDR_ANY);
+ sain.sin_port=htons(PORT);
+
+ if (bind (m_socket,(struct sockaddr *) &sain, sizeof (sain)) < 0)
+ {
+ y2error ("Debugger: bind failed");
+ return false;
+ }
+
+ // wait for connection
+ if (listen (m_socket, 1) < 0)
+ {
+ y2error ("Debugger: listen failed");
+ return false;
+ }
+
+ fromlen = sizeof(fsain);
+
+ if ((ns = accept (m_socket, (struct sockaddr *) &fsain, &fromlen)) < 0)
+ {
+ y2error ("Debugger: accept failed");
+ return false;
+ }
+
+ m_descriptor = fdopen (ns, "r");
+ m_last_command = c_step; // step to enable debugging from the start
+ m_ns = ns;
+
+ return true;
+}
+
+void Debugger::setTracing()
+{
+ m_last_command = c_step;
+ m_tracing = true;
+}
+
+void Debugger::setBreakpoint (std::list<std::string> &args)
+{
+ SymbolEntryPtr sentry = findSymbol (args.front ());
+
+ if (sentry)
+ {
+ if( !sentry->isFunction ())
+ sendOutput ("Identifier is not a function");
+ else
+ {
+ YFunctionPtr fnc = ((YFunctionPtr)((YSymbolEntryPtr)sentry)->code());
+
+ // set the breakpoint wrapper
+ if (fnc->definition ()->kind () == YCode::yiBreakpoint)
+ {
+ ((YBreakpointPtr)fnc->definition ())->setEnabled (true);
+ sendOutput ("Breakpoint enabled");
+ return;
+ }
+
+ YBreakpointPtr bp = new YBreakpoint (fnc->definition(), args.front () );
+
+ fnc->setDefinition (bp);
+ std::string result = "Set breakpoint to " + sentry->toString();
+ sendOutput (result);
+ }
+ }
+ else
+ sendOutput ("Identifier not found");
+}
+
+void Debugger::removeBreakpoint (std::list<std::string> &args)
+{
+ SymbolEntryPtr sentry = findSymbol (args.front ());
+
+ if (sentry)
+ {
+ if( !sentry->isFunction ())
+ sendOutput ("Identifier is not a function");
+ else
+ {
+ YFunctionPtr fnc = ((YFunctionPtr)((YSymbolEntryPtr)sentry)->code());
+
+ if (fnc->definition ()->kind () == YCode::yiBreakpoint)
+ {
+ // disable the breakpoint wrapper
+ ((YBreakpointPtr)fnc->definition ())->setEnabled (false);
+ sendOutput ("Breakpoint disabled");
+ return;
+ }
+ sendOutput ("Breakpoint not found");
+ }
+ }
+ else
+ sendOutput ("Identifier not found");
+}
+
+void Debugger::generateBacktrace ()
+{
+ std::string result = "Call stack:";
+ ExecutionEnvironment::CallStack stack = ee.callstack();
+ ExecutionEnvironment::CallStack::const_reverse_iterator it = stack.rbegin();
+ while (it != stack.rend())
+ {
+ result = result
+ + "\n"
+ + ( (*it)->filename )
+ + ":"
+ + stringutil::numstring((*it)->linenumber)
+ + ": "
+ + ((*it)->function->entry()->toString());
+
+ int paramcount = ((constFunctionTypePtr)((*it)->function->entry()->type()))->parameterCount();
+ if( paramcount > 0 )
+ result += " with paramters: ";
+ for( int i = 0; i < paramcount ; i++ )
+ {
+ result += (*it)->params[0]->toString() + " ";
+ }
+ ++it;
+ };
+
+ sendOutput (result);
+}
+
+SymbolEntryPtr Debugger::findSymbol (std::string arg)
+{
+ std::vector<std::string> words;
+ SymbolEntryPtr sentry = NULL;
+
+ stringutil::split(arg, words, ":");
+
+ if (words.size () > 1)
+ {
+ // name contains namespace, handle here
+ std::string ns_name = words[0];
+ std::string name = words[1];
+ Y2Component* c = Y2ComponentBroker::getNamespaceComponent (ns_name.c_str());
+ if( c )
+ {
+ if (c->name () == "wfm")
+ {
+ Y2Namespace* ns = c->import (ns_name.c_str());
+ if (ns)
+ // this returns NULL in case the name was not found
+ return ns->lookupSymbol (name.c_str());
+ }
+ else
+ return NULL; // this is not YCP symbol
+ }
+ }
+ else
+ {
+ // try parameters
+ ExecutionEnvironment::CallStack stack = ee.callstack();
+
+ if( stack.size() > 0 )
+ {
+ ExecutionEnvironment::CallStack::const_reverse_iterator it = stack.rbegin();
+
+ YSymbolEntryPtr ysentry = (YSymbolEntryPtr)((*it)->function->entry());
+
+ // this returns NULL in case the name was not found
+ sentry = ((YFunctionPtr)ysentry->code())->declaration ()->lookupSymbol (words[0].c_str());
+
+ if (sentry)
+ return sentry;
+ }
+
+ // try block stack
+ for( std::list<stackitem_t>::iterator blk = m_blockstack.begin(); blk != m_blockstack.end (); blk++)
+ {
+ sentry = blk->ns->lookupSymbol (words[0].c_str());
+ if (sentry)
+ return sentry;
+ }
+ }
+
+ // not found
+ return NULL;
+}
+
+void Debugger::printVariable (std::string arg)
+{
+ SymbolEntryPtr sentry = findSymbol (arg);
+
+ if (sentry)
+ {
+ if( !sentry->isVariable ())
+ sendOutput ("Identifier is not a variable");
+ else
+ {
+ if( sentry->value().isNull() )
+ sendOutput ("nil");
+ else
+ sendOutput (sentry->value()->toString());
+ }
+ }
+ else
+ sendOutput ("Identifier not found");
+}
+
+void Debugger::setVariable (std::string assign)
+{
+ // first, split by '='
+ std::vector<std::string> words;
+ stringutil::split(assign, words, "=");
+
+ if( words.size() != 2 )
+ {
+ sendOutput ("Set variable format is <name>=<constant>");
+ return;
+ }
+
+ SymbolEntryPtr sentry = findSymbol (words.front ());
+
+ if (sentry)
+ {
+ if( !sentry->isVariable ())
+ sendOutput ("Identifier is not a variable");
+ else
+ {
+ // set the new value
+ Parser parser (words[1].c_str()); // set parser to value
+
+ YCodePtr pc = parser.parse ();
+ if (!pc )
+ {
+ sendOutput ("Cannot parse new value");
+ }
+ else
+ {
+ sentry->setValue (pc->evaluate (true)); // set the new value
+ sendOutput ( std::string(sentry->name ()) + " = " + sentry->value ()->toString () );
+ }
+ }
+ }
+ else
+ sendOutput ("Identifier not found");
+}
+
+bool Debugger::processInput (command_t &command, std::list<std::string> &arguments)
+{
+ char c;
+ std::string s;
+ std::list<std::string> args;
+
+ // FIXME: use flex
+ if (m_descriptor == NULL)
+ return false;
+
+ // First, send the current context
+ YStatementPtr statement = ee.statement ();
+
+after_internal:
+ if (statement)
+ sendOutput (ee.filename() + ":" + stringutil::numstring(ee.linenumber()) + " >>> " + statement->toString ());
+ else
+ sendOutput ("no code");
+
+ // clean up for next command
+ s = "";
+ args.clear();
+
+ while ((c = fgetc (m_descriptor)) != EOF)
+ {
+ if (c == '\n')
+ {
+ break;
+ }
+ s += c;
+ }
+
+ if (s.empty ())
+ {
+ y2error ("Communication with debugging UI closed");
+ close (m_socket);
+
+ if (m_remote)
+ unlink (ADDRESS);
+
+ m_socket = -1;
+ m_descriptor = NULL;
+ return false;
+ }
+
+ command = c_unknown;
+ // FIXME: I said flex!
+ if (s == "c")
+ {
+ command = Debugger::c_continue;
+ }
+ else if (s == "n")
+ {
+ command = Debugger::c_next;
+ }
+ else if (s == "s")
+ {
+ command = Debugger::c_step;
+ }
+ else if (s == "bt")
+ {
+ command = Debugger::c_backtrace;
+ }
+ else if (s[0] == 'v')
+ {
+ command = Debugger::c_setvalue;
+ args.push_back(s.substr(2));
+ }
+ else if ( s[0] == 'b' )
+ {
+ command = Debugger::c_breakpoint;
+ args.push_back(s.substr(2));
+ }
+ else if ( s[0] == 'r' && s[1] == 'b')
+ {
+ command = Debugger::c_removebreakpoint;
+ args.push_back(s.substr(3));
+ }
+ else if (s[0] == 'p')
+ {
+ command = Debugger::c_print;
+ args.push_back(s.substr(2));
+ }
+
+ if (command == Debugger::c_print)
+ {
+ printVariable (args.front () );
+ goto after_internal;
+ }
+
+ if (command == Debugger::c_breakpoint)
+ {
+ setBreakpoint (args);
+ goto after_internal;
+ }
+
+ if (command == Debugger::c_removebreakpoint)
+ {
+ removeBreakpoint (args);
+ goto after_internal;
+ }
+
+ if (command == Debugger::c_backtrace)
+ {
+ generateBacktrace ();
+ goto after_internal;
+ }
+
+ if (command == Debugger::c_setvalue)
+ {
+ setVariable (args.front () );
+ goto after_internal;
+ }
+
+ arguments = args;
+ m_last_command = command;
+
+ return true;
+}
+
+bool Debugger::sendOutput( std::string output )
+{
+ output = m_outputstash + output;
+ y2debug ("Sending out output %s", output.c_str() );
+ if( output.empty() )
+ output = " ";
+ output = output + "\n<EOF>\n";
+ send (m_ns, output.c_str (), strlen( output.c_str ()), 0);
+
+ // clean up the output stash, it's sent already
+ m_outputstash = "";
+ return true;
+}
+
+void Debugger::stashOutput( std::string output )
+{
+ m_outputstash += output;
+}
+
+void Debugger::enableTracing (Y2Namespace* block, bool enable)
+ {
+ for( std::list<stackitem_t>::iterator it = m_blockstack.begin (); it != m_blockstack.end (); it++)
+ {
+ if ( it->ns == block )
+ it->tracing = enable;
+ return;
+ }
+}
+
+bool Debugger::tracing (Y2Namespace* block) const
+{
+ for( std::list<stackitem_t>::const_iterator it = m_blockstack.begin (); it != m_blockstack.end (); it++)
+ {
+ if ( it->ns == block )
+ return it->tracing;
+ }
+ return false;
+}
+
+void Debugger::pushBlock (Y2Namespace* block, bool tracing)
+{
+ stackitem_t si;
+ si.ns = block;
+ si.tracing = tracing;
+
+ m_blockstack.push_front (si);
+}
+
+void Debugger::popBlock ()
+{
+ m_blockstack.pop_front ();
+}
+
+bool Debugger::tracing () const
+{
+ return m_tracing;
+}
+
+void Debugger::setTracing (bool enable)
+{
+ m_tracing = enable;
+}
+
View
116 debugger/Debugger.h
@@ -0,0 +1,116 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: Debugger.h
+
+ Author: Stanislav Visnovsky <visnov@suse.cz>
+ Maintainer: Stanislav Visnovsky <visnov@suse.cz>
+
+/-*/
+// -*- c++ -*-
+
+#ifndef Debugger_h
+#define Debugger_h
+
+#include <stdio.h>
+#include <list>
+#include <string>
+#include <y2/SymbolEntry.h>
+
+class Y2Namespace;
+
+/**
+ * @short Debugger singleton to keep debugging-related status
+ */
+class Debugger
+{
+public:
+ typedef enum {
+ c_unknown,
+ c_next,
+ c_step,
+ c_continue,
+ c_print,
+ c_backtrace,
+ c_breakpoint,
+ c_removebreakpoint,
+ c_setvalue
+ } command_t;
+
+private:
+ int m_socket, m_ns;
+ FILE *m_descriptor;
+ command_t m_last_command;
+ std::string m_outputstash;
+
+ bool m_tracing;
+
+ typedef struct {
+ Y2Namespace* ns;
+ bool tracing;
+ } stackitem_t;
+
+ std::list<stackitem_t> m_blockstack;
+
+ bool m_remote;
+
+public:
+
+ Debugger ();
+
+ ~Debugger ();
+
+ /**
+ * Initialize the socket and reset the communication
+ */
+ bool initialize (bool remote);
+ bool initializeRemote ();
+ bool initializeLocal ();
+
+ /**
+ * @short Read the input from controlling socket and act accordingly.
+ *
+ * For actions needed to be done in context of YCP code being run,
+ * return the information to the caller.
+ */
+ bool processInput (command_t &command, std::list<std::string> &arguments);
+
+ bool sendOutput (std::string output );
+
+ // save the text for the next output sending
+ void stashOutput (std::string output );
+
+ command_t lastCommand () const { return m_last_command; }
+
+ // sets the last command to be c_step, enables tracing of the next block to be
+ // entered
+ void setTracing ();
+ void setTracing (bool enable);
+
+ void setBreakpoint (std::list<std::string> &arguments);
+ void removeBreakpoint (std::list<std::string> &arguments);
+ void generateBacktrace ();
+ void printVariable (std::string variable_name);
+ void setVariable (std::string arg);
+
+ void enableTracing (Y2Namespace* block, bool enable);
+ bool tracing (Y2Namespace* block) const;
+ bool tracing () const;
+
+ void pushBlock (Y2Namespace* block, bool tracing);
+ void popBlock ();
+
+private:
+ SymbolEntryPtr findSymbol (std::string name);
+};
+
+#endif // Debugger_h
View
20 debugger/Makefile.am
@@ -0,0 +1,20 @@
+#
+# Makefile.am for core/debugger
+#
+SUBDIRS=client
+
+AM_CXXFLAGS = -DY2LOG=\"debugger\"
+
+noinst_LTLIBRARIES = liby2debug.la
+
+liby2debug_la_SOURCES = \
+ Debugger.h \
+ Debugger.cc
+
+#liby2debug_la_LIBADD = @AGENT_LIBADD@
+
+INCLUDES = \
+ -I$(srcdir)/../libycp/src/include \
+ -I$(srcdir)/../liby2/src/include \
+ -I$(srcdir)/../liby2util-r/src/include \
+ ${Y2UTIL_CFLAGS}
View
11 debugger/TODO
@@ -0,0 +1,11 @@
+This are the items we still might want to implement in the debugger. Please, keep this file
+up-to-date, remove the finished items.
+
+
+Breakpoints:
+- set breakpoint to filename:linenumber
+- list breakpoints
+
+Infrastructure:
+- enable debugger at runtime
+
View
11 debugger/client/Makefile.am
@@ -0,0 +1,11 @@
+#
+# Makefile.am for core/debugger/client
+#
+
+pkgdatadir = ${prefix}/lib/YaST2/bin/
+
+pkgdata_SCRIPTS = \
+ ycp-debugger
+
+EXTRA_DIST = $(pkgdata_SCRIPTS)
+
View
107 debugger/client/ycp-debugger
@@ -0,0 +1,107 @@
+#!/usr/bin/ruby
+
+require 'socket'
+
+socket = nil;
+
+if (ARGV.size == 1)
+ socket = TCPsocket.new( ARGV[0], 16384 );
+else
+ socket = UNIXsocket.new( "/tmp/yast.socket" );
+end
+
+def get_output(socket)
+ begin
+ res = socket.gets
+ if (res != "<EOF>\n")
+ puts(res)
+ end
+ end until ( res == "<EOF>\n" )
+end
+
+def wait_socket
+ begin
+ print( "yast-dbg (detached)> ");
+ input = STDIN.gets().chomp();
+ if (input == "q")
+ puts "Bye!"
+ exit 0
+ end
+
+ if (input =="attach")
+ socket = UNIXsocket.new( "/tmp/yast.socket" );
+ puts "Attached to YaST process"
+ return socket
+ end
+
+ puts "You must attach to YaST process first using 'attach'"
+ end until false;
+end
+
+while !socket.eof? do
+ get_output(socket);
+ print( "yast-dbg> ");
+ input = STDIN.gets().chomp();
+
+ if (input == "help")
+ puts "Available commands:"
+ puts
+ puts "q quit"
+ puts "help this help"
+ puts "s step"
+ puts "n next"
+ puts "c continue"
+ puts "p <var> print variable value"
+ puts "b <fnc> set breakpoint"
+ puts "rb <fnc> remove breakpoint"
+ puts "bt backtrace"
+ puts "v <var>=<val> set variable value"
+ puts "attach attach to current YaST process"
+ puts "detach detach from current YaST process"
+ puts
+ print( "yast-dbg> ");
+ input = STDIN.gets().chomp();
+ end
+
+ if (input == "q")
+ puts "Bye!"
+ exit 0
+ end
+
+ if (input == "detach")
+ puts "Closing socket"
+ socket.close();
+ socket = wait_socket();
+ next
+ end
+
+ begin
+ socket.puts(input)
+ rescue Exception => e
+ puts e
+ exit 0
+ end;
+
+ # if printing value, show it, then get another output
+ if( input.split.first=="p" )
+ get_output(socket);
+ end
+
+ if( input=="bt" )
+ get_output(socket);
+ end
+
+ if( input.split.first=="b" )
+ get_output(socket);
+ end
+
+ if( input.split.first=="rb" )
+ get_output(socket);
+ end
+
+ if( input.split.first=="v" )
+ get_output(socket);
+ end
+end
+
+
View
1  liby2/src/Makefile.am
@@ -34,4 +34,5 @@ INCLUDES = \
-I$(srcdir)/../../libycp/src/include \
-I$(srcdir)/include \
-I$(srcdir)/include/y2 \
+ -I$(srcdir)/../debugger \
${Y2UTIL_CFLAGS}
View
53 liby2/src/genericfrontend.cc
@@ -105,6 +105,7 @@
#include <ycp/Parser.h>
#include <ycp/pathsearch.h>
#include "exitcodes.h"
+#include <debugger/Debugger.h>
/// number of symbols that are handled as error codes
#define MAX_YCP_ERROR_EXIT_SYMBOLS 2
@@ -117,6 +118,7 @@ const char* ycp_error_exit_symbols[MAX_YCP_ERROR_EXIT_SYMBOLS] = {
using std::string;
ExecutionEnvironment ee;
+Debugger *debugger_instance;
/// fallback name of the program
static const char *progname = "genericfrontend";
@@ -128,6 +130,9 @@ static bool has_parens (const char* arg);
int signal_log_fd; // fd to use for logging in signal handler
+bool debugger = false;
+bool debugger_remote = false;
+
static
void
signal_log_to_fd (int fd, const char * cs)
@@ -710,6 +715,42 @@ main (int argc, char **argv)
// FIXME the whole option parsing sucks **** !
+ // Check, if debugger should be enabled
+ if (!strcmp(argv[arg], "--debugger"))
+ {
+ // set the flag
+ debugger = true;
+ arg+=1;
+ }
+
+ if (!strcmp(argv[arg], "--debugger-remote"))
+ {
+ // set the flag
+ debugger = true;
+ debugger_remote = true;
+ arg+=1;
+ }
+
+ // also handle environment variable
+ if( getenv ("Y2DEBUGGER") )
+ {
+ if (strcmp (getenv ("Y2DEBUGGER"), "1")==0 )
+ debugger = true;
+ else if (strcmp (getenv ("Y2DEBUGGER"), "2")==0 )
+ {
+ debugger = true;
+ debugger_remote = true;
+ }
+ }
+
+ if (debugger)
+ {
+ // initialize the Debugger instance
+ debugger_instance = new Debugger ();
+ debugger_instance->initialize (debugger_remote);
+ }
+
+
// list of -I / -M pathes
// will be pushed to YCPPathSearch later to keep correct order
// (the last added path to YCPPathSearch will be searched first)
@@ -747,6 +788,9 @@ main (int argc, char **argv)
char * client_name;
YCPList arglist;
parse_client_and_options (argc, argv, arg, client_name, arglist);
+ // add debugger information if needed
+ if (debugger)
+ arglist->add ( YCPSymbol("debugger") );
// "arg" and these two are output params
char * server_name;
@@ -824,8 +868,9 @@ main (int argc, char **argv)
y2milestone ("YAST_IS_RUNNING is %s", getenv ("YAST_IS_RUNNING"));
+ YCPValue result = YCPVoid();
// Now start communication
- YCPValue result = client->doActualWork(arglist, server); // give arglist collected above
+ result = client->doActualWork(arglist, server); // give arglist collected above
// get result
server->result(result);
@@ -877,17 +922,19 @@ static void
print_help()
{
fprintf (stderr, "\n"
- "Usage: %s [LogOpts] Client [ClientOpts] Server [Generic ServerOpts] "
+ "Usage: %s [GenericOpts] Client [ClientOpts] Server [Generic ServerOpts] "
"[Specific ServerOpts]\n",
progname);
fprintf (stderr,
- "LogOptions are:\n"
+ "GenericOptions are:\n"
" -l | --logfile LogFile : Set logfile\n"
" -c | --logconf ConfFile : Configure logging\n"
" -n Namespace=Component : Override component for namespace\n"
" -I Path : Add include search path\n"
" -M Path : Add module search path\n"
+ " --debugger : Start local debugger\n"
+ " --debugger-remote : Start remote debugger\n"
"ClientOptions are:\n"
" -s : Get options as one YCPList from stdin\n"
" -f FileName : Get YCPValue(s) from file\n"
View
2  liby2/src/include/y2/Y2Namespace.h
@@ -34,6 +34,7 @@ class Point;
class Y2Function;
class StaticDeclaration;
class SymbolTable;
+class Debugger;
/**
* Y2Namespace implements a hash(?) table of nested(?) SymbolEntries and
@@ -48,6 +49,7 @@ class Y2Namespace {
symbols_t m_symbols;
friend class SymbolTable;
+ friend class Debugger;
// add symbol to namespace, it now belongs here
// returns the index into m_symbols
View
8 libycp/src/ExecutionEnvironment.cc
@@ -100,10 +100,10 @@ ExecutionEnvironment::endlessRecursion ()
}
void
-ExecutionEnvironment::pushframe (string called_function)
+ExecutionEnvironment::pushframe (YECallPtr function, YCPValue m_params[])
{
- y2debug ("Push frame %s", called_function.c_str ());
- CallFrame* frame = new CallFrame (filename(), linenumber (), called_function);
+ y2debug ("Push frame %s", function->entry()->name());
+ CallFrame* frame = new CallFrame (filename(), linenumber (), function, m_params);
m_backtrace.push_back (frame);
// backtrace( LOG_MILESTONE, 0 );
}
@@ -134,7 +134,7 @@ ExecutionEnvironment::backtrace (loglevel_t level, uint omit) const
while (it != m_backtrace.rend())
{
ycp2log (level, (*it)->filename.c_str (), (*it)->linenumber
- , "", "%s", (*it)->called_function.c_str ());
+ , "", "%s", (*it)->function->entry()->toString().c_str());
++it;
};
View
6 libycp/src/Makefile.am
@@ -36,6 +36,7 @@ libycp_la_SOURCES = \
ExecutionEnvironment.cc \
StaticDeclaration.cc YCode.cc YCPCode.cc \
YExpression.cc YStatement.cc YBlock.cc \
+ YBreakpoint.cc \
SymbolTable.cc \
Scanner.cc Parser.cc \
parser.yy scanner.ll \
@@ -59,14 +60,15 @@ BUILT_SOURCES = parser.h
AM_YFLAGS = -d -v
-INCLUDES = -I$(srcdir)/include -I$(srcdir)/include/ycp -I$(top_srcdir)/liby2/src/include ${Y2UTIL_CFLAGS}
+INCLUDES = -I$(srcdir)/include -I$(srcdir)/include/ycp -I$(top_srcdir)/liby2/src/include ${Y2UTIL_CFLAGS} \
+ -I$(top_srcdir)/debugger
# CURRENT:REVISION:AGE
libycpvalues_la_LDFLAGS = -version-info 3:0:0
libycpvalues_la_LIBADD = ${Y2UTIL_LIBS}
libycp_la_LDFLAGS = -version-info 3:0:0
-libycp_la_LIBADD = ${Y2UTIL_LIBS} -lxcrypt libycpvalues.la
+libycp_la_LIBADD = ${Y2UTIL_LIBS} -lxcrypt libycpvalues.la $(top_builddir)/debugger/liby2debug.la
CLEANFILES = parser.output parser.cc scanner.cc $(BUILT_SOURCES)
View
48 libycp/src/YBlock.cc
@@ -43,7 +43,10 @@
#include "ycp/y2log.h"
#include "ExecutionEnvironment.h"
+#include <Debugger.h>
+
extern ExecutionEnvironment ee;
+extern Debugger* debugger_instance;
// ------------------------------------------------------------------
@@ -575,6 +578,15 @@ YBlock::evaluate (bool cse)
y2debug ("YBlock::evaluate([%d]%s)\n", (int)m_kind, toString().c_str());
#endif
+ bool m_debug = false;
+
+ if (debugger_instance)
+ {
+ m_debug = debugger_instance->tracing();
+
+ debugger_instance->pushBlock (this, m_debug);
+ }
+
// recursion handling - not used for modules
if (! isModule () && m_running)
{
@@ -595,14 +607,44 @@ YBlock::evaluate (bool cse)
YCPValue value = YCPVoid ();
while (stmt)
{
+ bool next_hit = false;
YStatementPtr statement = stmt->stmt;
#if DO_DEBUG
y2debug ("%d: %s", statement->line (), statement->toString ().c_str ());
#endif
-
ee.setStatement (statement);
+
+ if (m_debug && statement->kind() != ysFunction )
+ {
+ Debugger::command_t command;
+ std::list<std::string> args;
+ if (debugger_instance->processInput (command, args) && command==Debugger::c_continue)
+ {
+ m_debug = false;
+ debugger_instance->setTracing (false);
+ }
+ else if (command == Debugger::c_next)
+ {
+ next_hit = true;
+ debugger_instance->setTracing (false);
+ }
+ }
+
+
value = statement->evaluate ();
+
+ // If we get continue from inner evaluation, we have to respect it
+ if (debugger_instance)
+ {
+ if (m_debug)
+ {
+ m_debug = debugger_instance->lastCommand() != Debugger::c_continue;
+ debugger_instance->setTracing (m_debug);
+ }
+ else
+ m_debug = debugger_instance->tracing ();
+ }
if (!value.isNull())
{
@@ -626,6 +668,9 @@ YBlock::evaluate (bool cse)
{
popFromStack ();
}
+
+ if (debugger_instance)
+ debugger_instance->popBlock ();
#if DO_DEBUG
y2debug ("YBlock::evaluate done (stmt %p, kind %d, value '%s')\n", stmt, m_kind, value.isNull() ? "NULL" : value->toString().c_str());
@@ -646,7 +691,6 @@ YBlock::evaluate (bool cse)
return value;
}
-
// FIXME: consolidate duplicate code of different 'evaluate'
YCPValue
YBlock::evaluateFrom (int statement_index)
View
153 libycp/src/YBreakpoint.cc
@@ -0,0 +1,153 @@
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: YBreakpoint.cc
+
+ Author: Klaus Kaempf <kkaempf@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+/-*/
+// -*- c++ -*-
+
+#ifndef DO_DEBUG
+#define DO_DEBUG 0
+#endif
+
+#include <libintl.h>
+#include <debugger/Debugger.h>
+
+#include "ycp/YBreakpoint.h"
+
+#include "ycp/Bytecode.h"
+#include "ycp/Xmlcode.h"
+
+#include "ycp/y2log.h"
+#include "ycp/ExecutionEnvironment.h"
+
+extern Debugger *debugger_instance;
+
+// ------------------------------------------------------------------
+
+IMPL_DERIVED_POINTER(YBreakpoint, YCode);
+
+// ------------------------------------------------------------------
+// YBreakpoint
+
+YBreakpoint::YBreakpoint (YCodePtr code, std::string name) : YCode()
+ , m_code (code)
+ , m_enabled (true)
+ , m_name (name)
+{
+}
+
+
+YBreakpoint::~YBreakpoint ()
+{
+ m_code = 0;
+}
+
+
+bool
+YBreakpoint::isConstant() const
+{
+ return m_code->isConstant();
+}
+
+
+bool
+YBreakpoint::isStatement() const
+{
+ return m_code->isStatement();
+}
+
+
+bool
+YBreakpoint::isBlock () const
+{
+ return m_code->isBlock();
+}
+
+
+bool
+YBreakpoint::isReferenceable () const
+{
+ return m_code->isReferenceable ();
+}
+
+
+string
+YBreakpoint::toString() const
+{
+ return m_code->toString ();
+}
+
+YCodePtr
+YBreakpoint::code() const
+{
+ return m_code;
+}
+
+// write to stream, see Bytecode for read
+std::ostream &
+YBreakpoint::toStream (std::ostream & str) const
+{
+ return m_code->toStream(str);
+}
+
+
+std::ostream &
+YBreakpoint::toXml (std::ostream & str, int indent ) const
+{
+ return m_code->toXml(str, indent);
+}
+
+
+YCPValue
+YBreakpoint::evaluate (bool cse)
+{
+#if DO_DEBUG
+ y2debug ("evaluate(%s) = nil", toString().c_str());
+#endif
+ if (debugger_instance && m_enabled)
+ {
+ debugger_instance->stashOutput ("Breakpoint hit at " + m_name + "\n");
+ if (m_code->isBlock()) {
+ debugger_instance->setTracing();
+ }
+ else
+ y2internal ("Debugger: process input failed");
+ }
+
+ return m_code->evaluate (cse);
+}
+
+
+constTypePtr
+YBreakpoint::type () const
+{
+ return m_code->type ();
+}
+
+bool
+YBreakpoint::enabled () const
+{
+ return m_enabled;
+}
+
+void
+YBreakpoint::setEnabled (bool enable)
+{
+ m_enabled = enable;
+}
+
+
+// EOF
View
18 libycp/src/YCode.cc
@@ -38,6 +38,7 @@
#include "ycp/YCPCode.h"
#include "ycp/YBlock.h"
+#include "ycp/YBreakpoint.h"
#include "ycp/Bytecode.h"
#include "ycp/Xmlcode.h"
@@ -598,7 +599,7 @@ YFunction::~YFunction ()
}
-YBlockPtr
+YCodePtr
YFunction::definition() const
{
return m_definition;
@@ -622,6 +623,15 @@ YFunction::setDefinition (YBlockPtr definition)
void
+YFunction::setDefinition (YBreakpointPtr definition)
+{
+ m_definition = definition;
+ // skip setKind call, we are just setting a breakpoint wrapper here
+ return;
+}
+
+
+void
YFunction::setDefinition (bytecodeistream & str)
{
if (Bytecode::readBool (str))
@@ -634,9 +644,11 @@ YFunction::setDefinition (bytecodeistream & str)
{
Bytecode::pushNamespace (m_declaration->nameSpace());
}
+
+ YBlockPtr def = (YBlockPtr)Bytecode::readCode (str);
+ def->setKind (YBlock::b_definition);
- m_definition = (YBlockPtr)Bytecode::readCode (str);
- m_definition->setKind (YBlock::b_definition);
+ m_definition = def;
if (m_declaration != 0)
{
View
8 libycp/src/YExpression.cc
@@ -3085,7 +3085,7 @@ YEFunction::evaluate (bool cse)
}
}
- YCPValue m_params [m_next_param_id];
+ YCPValue evaluated_params [m_next_param_id];
for (unsigned int p = 0; p < m_next_param_id ; p++)
{
@@ -3103,13 +3103,13 @@ YEFunction::evaluate (bool cse)
y2debug ("parameter %d = (%s)", p, value->toString().c_str());
#endif
- m_params [p] = value;
+ evaluated_params [p] = value;
}
// set the parameters for Y2Function
for (unsigned int p = 0; p < m_next_param_id ; p++)
{
- m_functioncall->attachParameter (m_params[p], p);
+ m_functioncall->attachParameter (evaluated_params[p], p);
}
extern ExecutionEnvironment ee;
@@ -3124,7 +3124,7 @@ YEFunction::evaluate (bool cse)
return YCPVoid ();
}
- ee.pushframe (toString ());
+ ee.pushframe ((YECallPtr)this, evaluated_params);
YCPValue value = m_functioncall->evaluateCall ();
View
16 libycp/src/include/ycp/ExecutionEnvironment.h
@@ -20,20 +20,26 @@
#include "y2log.h"
#include "ycp/YStatement.h"
+#include "ycp/YExpression.h"
+
+#include <ycp/YCPValue.h>
using namespace std;
/// Function and source location, for backtraces
struct CallFrame {
- string called_function;
+ YECallPtr function;
string filename;
int linenumber;
+ YCPValue* params;
- CallFrame (string f, int l, string func):
- called_function (func),
+ CallFrame (string f, int l, YECallPtr func, YCPValue* p):
+ function (func),
filename (f),
linenumber (l)
- {}
+ {
+ params = p;
+ }
};
/**
@@ -107,7 +113,7 @@ class ExecutionEnvironment {
*
* @param called_function name of the function to be called at this point
*/
- void pushframe (string called_function);
+ void pushframe (YECallPtr called_function, YCPValue params[]);
/**
* Pop the top call frame from the backtrace stack.
View
2  libycp/src/include/ycp/Makefile.am
@@ -32,7 +32,7 @@ pkginclude_HEADERS = \
Bytecode.h Import.h Point.h \
YExpression.h YStatement.h YBlock.h \
SymbolTable.h Scanner.h Parser.h \
- YSymbolEntry.h \
+ YSymbolEntry.h YBreakpoint.h \
y2log.h ycpless.h pathsearch.h \
y2string.h \
ExecutionEnvironment.h
View
2  libycp/src/include/ycp/YBlock.h
@@ -129,7 +129,7 @@ class YBlock : public YCode, public Y2Namespace
constTypePtr m_type;
bool m_running;
-
+
public:
//---------------------------------------------------------------
// Constructor / Destructor
View
136 libycp/src/include/ycp/YBreakpoint.h
@@ -0,0 +1,136 @@
+/*-----------------------------------------------------------*- c++ -*-\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: YBreakpoint.h
+
+ Author: Stanislav Visnovsky <visnov@suse.cz>
+ Maintainer: Stanislav Visnovsky <visnov@suse.cz>
+
+/-*/
+// -*- c++ -*-
+
+#ifndef YBreakpoint_h
+#define YBreakpoint_h
+
+#include <string>
+using std::string;
+
+#include "ycp/YCode.h"
+#include "ycp/YCodePtr.h"
+
+#include "ycp/YCPValue.h"
+#include "ycp/YCPString.h"
+#include "ycp/Type.h"
+#include "ycp/YSymbolEntry.h"
+
+/**
+ * \brief YBreakpoint wrapper for YCP debugger
+ *
+ * A class representing a breakpoint in YCP code.
+ */
+class YBreakpoint : public YCode
+{
+ REP_BODY(YBreakpoint);
+
+ YCodePtr m_code;
+ bool m_enabled;
+ string m_name;
+public:
+
+ /**
+ * Creates a new YCode element
+ */
+ YBreakpoint (YCodePtr wrapped_ycp, string name);
+
+ /**
+ * Destructor
+ */
+ virtual ~YBreakpoint();
+
+ /**
+ * Kind of this \ref YCode.
+ *
+ * \return the YCode kind
+ */
+ virtual ykind kind() const { return yiBreakpoint; }
+
+ /**
+ * Return ASCII represtation of this YCP code. Actually no-op.
+ *
+ * \return ASCII string representation
+ */
+ virtual string toString() const;
+
+ /**
+ * Write YCP code to a byte stream (bytecode implementation). No-op.
+ */
+ virtual std::ostream & toStream (std::ostream & str) const;
+
+ /**
+ * Write YCP code as XML representation. No-op.
+ * \param str string stream to store into
+ * \param indend indentation level for pretty print
+ * \return string stream for chaining writing XML (str)
+ */
+ virtual std::ostream & toXml (std::ostream & str, int indent ) const;
+
+ /**
+ * Is this code constant?
+ *
+ * \return true if the \ref YCode represents a constant
+ */
+ virtual bool isConstant () const;
+
+ /**
+ * Is this a YCP statement (e.g. if, while, ...)
+ *
+ * \return true if the \ref YCode represents a statement
+ */
+ virtual bool isStatement () const;
+
+ /**
+ * Is this a YCP block?
+ *
+ * \return true if the \ref YCode represents a block
+ */
+ virtual bool isBlock () const;
+
+ /**
+ * Can this code be stored in a variable of a type reference?
+ *
+ * \return true if the \ref YCode represents something we can reference to
+ */
+ virtual bool isReferenceable () const;
+
+ /**
+ * Execute YCP code to get the resulting \ref YCPValue. Every inherited class of YCode should reimplement
+ * this method.
+ *
+ * \return \ref YCPValue after executing the code
+ * \param cse should the evaluation be done for parse time evaluation (i.e. constant subexpression elimination)
+ */
+ virtual YCPValue evaluate (bool cse = false);
+
+ /**
+ * Return type of this YCP code (interesting mostly for function calls).
+ *
+ * \return type of the value to be returned after calling \ref evaluate
+ */
+ virtual constTypePtr type () const;
+
+ YCodePtr code () const;
+
+ bool enabled () const;
+ void setEnabled (bool enable);
+};
+
+#endif // YBreakpoint_h
View
10 libycp/src/include/ycp/YCode.h
@@ -143,7 +143,10 @@ class YCode : public Rep
ysImport, // import
ysBlock, // a block as statement
ysSwitch, // switch (since 10.0)
- ysStatement // [54] -- placeholder --
+ ysStatement, // [54] -- placeholder --
+
+ // internal
+ yiBreakpoint // [55] -- debugger breakpoint
};
public:
@@ -361,7 +364,7 @@ class YFunction : public YCode
YBlockPtr m_declaration;
// the function definition ('body') is the block defining this function
- YBlockPtr m_definition;
+ YCodePtr m_definition;
bool m_is_global;
@@ -377,8 +380,9 @@ class YFunction : public YCode
SymbolEntryPtr parameter (unsigned int position) const;
// access to definition block (= 0 if declaration only)
- YBlockPtr definition () const;
+ YCodePtr definition () const;
void setDefinition (YBlockPtr body);
+ void setDefinition (YBreakpointPtr body);
// read definition from stream
void setDefinition (bytecodeistream & str);
View
1  libycp/src/include/ycp/YCodePtr.h
@@ -30,6 +30,7 @@ DEFINE_DERIVED_POINTER(YError, YCode);
DEFINE_DERIVED_POINTER(YConst, YCode);
DEFINE_DERIVED_POINTER(YLocale, YCode);
DEFINE_DERIVED_POINTER(YFunction, YCode);
+DEFINE_DERIVED_POINTER(YBreakpoint, YCode);
// needed in YCode.h already
DEFINE_DERIVED_POINTER(YBlock, YCode);
View
6 libycp/testsuite/Makefile.am
@@ -14,13 +14,13 @@ libdir = ../src/.libs
noinst_PROGRAMS = testSignature runc runycp
runc_SOURCES = runc.cc
-runc_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ${Y2UTIL_LIBS}
+runc_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ../../debugger/liby2debug.la ${Y2UTIL_LIBS}
runycp_SOURCES = runycp.cc
-runycp_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ${Y2UTIL_LIBS}
+runycp_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ../../debugger/liby2debug.la ${Y2UTIL_LIBS}
testSignature_SOURCES = testSignature.cc
-testSignature_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ${Y2UTIL_LIBS}
+testSignature_LDADD = ../src/libycp.la ../src/libycpvalues.la ../../liby2/src/liby2.la ../../debugger/liby2debug.la ${Y2UTIL_LIBS}
PACKAGE=libycp
View
6 libycp/testsuite/tests/builtin/Backtrace.err
@@ -22,7 +22,7 @@ Parsed:
----------------------------------------------------------------------
[YCP] tests/builtin/Backtrace.ycp:6 My test
[libycp] ExecutionEnvironment.cc(backtrace):132 ------------- Backtrace begin -------------
-[YCP] tests/builtin/Backtrace.ycp:10 aoo ((value + 1))
-[YCP] tests/builtin/Backtrace.ycp:14 boo ((foo_val + 1))
-[YCP] tests/builtin/Backtrace.ycp:17 foo (41)
+[YCP] tests/builtin/Backtrace.ycp:10 void aoo (integer value)
+[YCP] tests/builtin/Backtrace.ycp:14 void boo (integer value)
+[YCP] tests/builtin/Backtrace.ycp:17 void foo (integer foo_val)
[libycp] ExecutionEnvironment.cc(backtrace):141 ------------- Backtrace end ---------------
View
23 wfm/src/Y2WFMComponent.cc
@@ -34,6 +34,7 @@
#include <ycp/Parser.h>
#include <ycp/Bytecode.h>
#include <ycp/YBlock.h>
+#include <ycp/YBreakpoint.h>
#include <scr/SCRAgent.h>
#include <scr/SCR.h>
@@ -135,13 +136,30 @@ YCPValue
Y2WFMComponent::doActualWork (const YCPList& arglist, Y2Component *displayserver)
{
y2debug( "Starting evaluation" );
+
+ bool debugger = false;
+ YCPList client_arglist = arglist;
+
+ // hack: look only at the last entry, if it's debugger or not
+ if (arglist->size () > 0)
+ {
+ YCPValue last = arglist->value (arglist->size ()-1);
+ if (last->isSymbol () && last->asSymbol()->symbol() == "debugger")
+ {
+ y2debug ("Enabling debugger");
+ debugger = true;
+
+ // remove the flag from the arguments
+ client_arglist->remove (arglist->size ()-1);
+ }
+ }
// Prepare the arguments. It has the form [script, [clientargs...]]
YCPList wfm_arglist;
wfm_arglist->add(script);
wfm_arglist->add(YCPString(name()));
wfm_arglist->add (YCPString (fullname));
- wfm_arglist->add(arglist);
+ wfm_arglist->add(client_arglist);
// store the old arguments and module name to preserve reentrancy
YCPList old_arguments = argumentlist;
@@ -175,6 +193,9 @@ Y2WFMComponent::doActualWork (const YCPList& arglist, Y2Component *displayserver
y2debug ("Script is: %s", script->toString().c_str());
y2debug ("Y2WFMComponent @ %p, displayserver @ %p", this, displayserver);
+
+ if (debugger)
+ script = YCPCode ((YCodePtr)new YBreakpoint (script->asCode ()->code (), "code start"));
YCPValue v = script->asCode ()->evaluate ();
View
2  wfm/testsuite/Makefile.am
@@ -27,6 +27,7 @@ runwfm_LDADD = \
$(top_builddir)/libycp/src/libycp.la \
$(top_builddir)/libycp/src/libycpvalues.la \
$(top_builddir)/liby2/src/liby2.la \
+ $(top_builddir)/debugger/liby2debug.la \
${Y2UTIL_LIBS}
runc_SOURCES = runc.cc
@@ -36,6 +37,7 @@ runc_LDADD = ../src/libpy2wfm.la \
$(top_builddir)/libscr/src/libscr.la \
$(top_builddir)/libycp/src/libycp.la \
$(top_builddir)/libycp/src/libycpvalues.la \
+ $(top_builddir)/debugger/liby2debug.la \
$(top_builddir)/liby2/src/liby2.la \
${Y2UTIL_LIBS}
View
13 yast2-core.spec.in
@@ -48,8 +48,17 @@ Requires: flex
This package contains include and documentation files for developing
applications using the YaST2 YCP interpreter.
+%package debugger
+Requires: yast2-core = %version
+Group: Development/Libraries
+Summary: YaST2 - Core Libraries
+
+%description debugger
+YCP debugger client.
+
@PREP@
+
%build
%ifarch %arm
@@ -131,3 +140,7 @@ fi
%doc @docdir@
%doc %{_datadir}/doc/yastdoc
@ydatadir@/devtools/bin/generateYCPWrappers
+
+%files debugger
+%defattr(-,root,root)
+%attr(0755,-,-) /usr/lib/YaST2/bin/ycp-debugger
Please sign in to comment.
Something went wrong with that request. Please try again.