Hi!

Since there was interest in still providing YCP debugger, I gave it a shot and 
here is a first prototype. I did not test it to actually trace a real module, 
but it provides the basic functionality and I need feedback what needs to be 
improved, possibly reporting bugs.

The patch for yast2-core is attached, the packages for openSUSE 11.4 are 
available in my home project:

  home:visnov:branches:openSUSE:11.4:Update:Test

Usage:

1) zypper install yast2-core-debugger
2) start YaST2 process with --debugger option:

   /usr/lib/YaST2/bin/y2base --debugger <YCP-client> <frontend>

3) start debugger:
  /usr/lib/YaST2/bin/ycp-debugger

The currently supported commands:

yast-dbg> help
Available commands:

q               quit
help            this help
s               step
n               next
c               continue
p <var>         print variable value
b <fnc>         set breakpoint
rb <fnc>        remove breakpoint
bt              backtrace
v <var>=<val>   set variable value
attach          attach to current YaST process
detach          detach from current YaST process

WARNING: if you enter non-existent/empty command, the communication will go 
out of sync and you have to start over!


TODO:
Infrastructure:                                                                 
                                   
- enable debugger at runtime                                                    
                                   
- secure socket creation
 
Client:
- make it robust, most likely a complete rewrite is a way to go

Breakpoints:                                                                    
                                   
- set breakpoint to filename:linenumber                                         
                                   
- list breakpoints                                                              
                                   
                                                                                
                                   
Any feedback is welcome!

Stano

diff --git a/SUBDIRS b/SUBDIRS
index 866cdc3..f0ffba4 100644
--- a/SUBDIRS
+++ b/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
diff --git a/base/src/Makefile.am b/base/src/Makefile.am
index d6eff40..cc61425 100644
--- a/base/src/Makefile.am
+++ b/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		
 
 
diff --git a/base/tools/ycpc/Makefile.am b/base/tools/ycpc/Makefile.am
index b82501c..377e504 100644
--- a/base/tools/ycpc/Makefile.am
+++ b/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
diff --git a/debugger/Debugger.cc b/debugger/Debugger.cc
new file mode 100644
index 0000000..943b38b
--- /dev/null
+++ b/debugger/Debugger.cc
@@ -0,0 +1,460 @@
+/*---------------------------------------------------------------------\
+|								       |
+|		       __   __	  ____ _____ ____		       |
+|		       \ \ / /_ _/ ___|_   _|___ \		       |
+|			\ V / _` \___ \ | |   __) |		       |
+|			 | | (_| |___) || |  / __/		       |
+|			 |_|\__,_|____/ |_| |_____|		       |
+|								       |
+|				core system			       |
+|							 (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+   File:	Debugger.cc
+
+   Basic infrastructure for YCP debugger
+
+   Author:	Stanislav Visnovsky <[email protected]>
+   Maintainer:	Stanislav Visnovsky <[email protected]>
+
+/-*/
+
+#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 <stdio.h>
+
+#define ADDRESS     "/tmp/yast.socket"	/* addr to connect */
+
+extern ExecutionEnvironment ee;
+
+Debugger::Debugger () : 
+  m_socket (-1),
+  m_descriptor (NULL)
+{}
+
+Debugger::~Debugger ()
+{
+    // close the controll socket
+    if (m_socket) 
+	close (m_socket);
+    m_socket = -1;
+}
+
+bool Debugger::initialize()
+{
+  socklen_t fromlen;
+  int ns, len;
+  struct sockaddr_un saun, fsaun;
+
+  // FIXME: possible leak
+  m_socket = -1;
+  m_descriptor = NULL;
+  /*
+   *      * Get a socket to work with.  This socket will
+   *           * be in the UNIX domain, and will be a
+   *                * stream socket.
+   *                     */
+  if ((m_socket = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
+    {
+      return false;
+    }
+
+  /*
+   *      * Create the address we will be binding to.
+   *           */
+  saun.sun_family = AF_UNIX;
+  strcpy (saun.sun_path, ADDRESS);
+
+  // FIXME: Security!!!
+  unlink (ADDRESS);
+  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)
+  {
+    y2internal ("Debugger: listen failed");
+    return false;
+  }
+  fromlen = 108;
+
+  if ((ns = accept (m_socket, (struct sockaddr *) &fsaun, &fromlen)) < 0)
+  {
+    y2internal ("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;
+}
+
+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());
+	
+	    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 )
+	{
+	    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 
+    {
+	// 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<Y2Namespace*>::iterator blk = m_blockstack.begin(); blk != m_blockstack.end (); blk++)
+	{
+	    sentry = (*blk)->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)
+    {
+	string context = statement->toString ()+" \n\n";
+	y2milestone ("sending context: %s", context.c_str());
+	send (m_ns, context.c_str (), strlen( context.c_str ()), 0);
+    }
+    else
+    {
+	y2warning ("sending no context");
+	send (m_ns, "no code\n\n", strlen( "no_code\n\n"), 0);
+    }
+    
+    // clean up for next command
+    s = "";
+    args.clear();
+
+    while ((c = fgetc (m_descriptor)) != EOF)
+    {
+	if (c == '\n')
+	{
+	    break;
+	}
+	s += c;
+    }
+    
+    if (s.empty ())
+    {
+	y2internal ("Communication with debugged UI closed");
+	close (m_socket);
+	m_socket = -1;
+	m_descriptor = NULL;
+	return false;
+    }
+    
+    command = c_unknown;
+    // FIXME: I said flex!
+    if (s == "c")
+    {
+    y2internal ("Set command to continue");
+	command = Debugger::c_continue;
+    }
+    else if (s == "n")
+    {
+    y2internal ("Set command to next");
+	command = Debugger::c_next;
+    }
+    else if (s == "s")
+    {
+    y2internal ("Set command to step");
+	command = Debugger::c_step;
+    }
+    else if (s == "bt")
+    {
+    y2internal ("Set command to backtrace");
+	command = Debugger::c_backtrace;
+    }
+    else if (s[0] == 'v')
+    {
+    y2internal ("Set command to setvalue");
+	command = Debugger::c_setvalue;
+	args.push_back(s.substr(2));
+    }
+    else if ( s[0] == 'b' )
+    {
+        y2internal ("Set command to breakpoint");
+	command = Debugger::c_breakpoint;
+	args.push_back(s.substr(2));
+    }
+    else if ( s[0] == 'r' && s[1] == 'b')
+    {
+        y2internal ("Set command to remove breakpoint");
+	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));
+	y2internal ("Set command to print of '%s'",args.front().c_str());
+    }
+    
+    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 )
+{
+    y2internal ("Sending out output %s", output.c_str() );
+    if( output.empty() )
+	output = " ";
+    output = output + "\n\n";
+    send (m_ns, output.c_str (), strlen( output.c_str ()), 0);
+    return true;
+}
+
+void Debugger::pushBlock (Y2Namespace* block)
+{
+    m_blockstack.push_front (block);
+}
+
+void Debugger::popBlock ()
+{
+    m_blockstack.pop_front ();
+}
diff --git a/debugger/Debugger.h b/debugger/Debugger.h
new file mode 100644
index 0000000..040fa38
--- /dev/null
+++ b/debugger/Debugger.h
@@ -0,0 +1,96 @@
+/*---------------------------------------------------------------------\
+|                                                                      |  
+|                      __   __    ____ _____ ____                      |  
+|                      \ \ / /_ _/ ___|_   _|___ \                     |  
+|                       \ V / _` \___ \ | |   __) |                    |  
+|                        | | (_| |___) || |  / __/                     |  
+|                        |_|\__,_|____/ |_| |_____|                    |  
+|                                                                      |  
+|                               core system                            | 
+|                                                        (C) SuSE GmbH |  
+\----------------------------------------------------------------------/ 
+
+   File:       Debugger.h
+
+   Author:     Stanislav Visnovsky <[email protected]>
+   Maintainer: Stanislav Visnovsky <[email protected]>
+
+/-*/
+// -*- 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::list<Y2Namespace*> m_blockstack;
+
+public:
+
+    Debugger ();
+
+    ~Debugger ();
+
+    /**
+     * Initialize the socket and reset the communication
+     */
+    bool initialize ();
+
+    /**
+     * @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 );
+    
+    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 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 pushBlock (Y2Namespace* block);
+    void popBlock ();
+    
+private:
+    SymbolEntryPtr findSymbol (std::string name);
+};
+
+#endif	// Debugger_h
diff --git a/debugger/Makefile.am b/debugger/Makefile.am
new file mode 100644
index 0000000..4975639
--- /dev/null
+++ b/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}
diff --git a/debugger/TODO b/debugger/TODO
new file mode 100644
index 0000000..aadfa7e
--- /dev/null
+++ b/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
+
diff --git a/debugger/client/Makefile.am b/debugger/client/Makefile.am
new file mode 100644
index 0000000..b90c482
--- /dev/null
+++ b/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)
+
diff --git a/debugger/client/ycp-debugger b/debugger/client/ycp-debugger
new file mode 100755
index 0000000..8c7aa7f
--- /dev/null
+++ b/debugger/client/ycp-debugger
@@ -0,0 +1,99 @@
+#!/usr/bin/ruby
+
+require 'socket'
+
+socket = UNIXsocket.new( "/tmp/yast.socket" );
+
+def get_output(socket)
+			begin
+				res = socket.gets
+				puts(res)
+			end until ( res == "\n" )
+end
+
+def wait_socket
+	begin
+		print( "yast-dbg (detached)> ");
+		input = 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 = 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 = 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
+
+
diff --git a/liby2/src/Makefile.am b/liby2/src/Makefile.am
index 9644a09..7425b24 100644
--- a/liby2/src/Makefile.am
+++ b/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}
diff --git a/liby2/src/genericfrontend.cc b/liby2/src/genericfrontend.cc
index a7f049c..6724f58 100644
--- a/liby2/src/genericfrontend.cc
+++ b/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,8 @@ static bool has_parens (const char* arg);
 
 int signal_log_fd;		// fd to use for logging in signal handler
 
+bool debugger = false;
+
 static
 void
 signal_log_to_fd (int fd, const char * cs)
@@ -710,6 +714,19 @@ 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;
+	
+	// initialize the Debugger instance
+	debugger_instance = new Debugger ();
+	debugger_instance->initialize ();
+    }
+
+
     // 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 +764,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 +844,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);
diff --git a/liby2/src/include/y2/Y2Namespace.h b/liby2/src/include/y2/Y2Namespace.h
index 92ccf0b..681001c 100644
--- a/liby2/src/include/y2/Y2Namespace.h
+++ b/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 @@ protected:
     symbols_t m_symbols;
     
     friend class SymbolTable;
+    friend class Debugger;
 
     // add symbol to namespace, it now belongs here
     // returns the index into m_symbols
diff --git a/libycp/src/ExecutionEnvironment.cc b/libycp/src/ExecutionEnvironment.cc
index a462d7f..eacc202 100644
--- a/libycp/src/ExecutionEnvironment.cc
+++ b/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;
     };
 
diff --git a/libycp/src/Makefile.am b/libycp/src/Makefile.am
index 9c326cd..d2112bf 100644
--- a/libycp/src/Makefile.am
+++ b/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)
 
diff --git a/libycp/src/YBlock.cc b/libycp/src/YBlock.cc
index 2f3d5a3..184b836 100644
--- a/libycp/src/YBlock.cc
+++ b/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;
 
 // ------------------------------------------------------------------
 
@@ -64,6 +67,7 @@ YBlock::YBlock (const std::string & filename, YBlock::blockkind_t kind)
     , m_includes (0)
     , m_type (Type::Unspec)
     , m_running (false)
+    , m_debug (false)
 {
 #if DO_DEBUG
     y2debug ("YBlock::YBlock [%p] (%s)", this, filename.c_str());
@@ -89,6 +93,7 @@ YBlock::YBlock (const Point *point)
     , m_includes (0)
     , m_type (Type::Unspec)
     , m_running (false)
+    , m_debug (false)
 {
 }
 
@@ -575,6 +580,13 @@ YBlock::evaluate (bool cse)
     y2debug ("YBlock::evaluate([%d]%s)\n", (int)m_kind, toString().c_str());
 #endif
 
+    if (debugger_instance)
+    {
+	m_debug = debugger_instance->lastCommand() == Debugger::c_step;
+	
+	debugger_instance->pushBlock (this);
+    }
+
     // recursion handling - not used for modules
     if (! isModule () && m_running)
     {
@@ -600,10 +612,25 @@ YBlock::evaluate (bool cse)
 #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;
+	    }
+	}
+	
+
 	value = statement->evaluate ();
 
+	// If we get continue from inner evaluation, we have to respect it
+        if (debugger_instance && m_debug)
+	    m_debug = debugger_instance->lastCommand() != Debugger::c_continue;
+
 	if (!value.isNull())
 	{
 #if DO_DEBUG
@@ -626,6 +653,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,6 +676,11 @@ YBlock::evaluate (bool cse)
     return value;
 }
 
+void
+YBlock::setDebug (bool debug)
+{
+    m_debug = debug;
+}
 
 // FIXME: consolidate duplicate code of different 'evaluate'
 YCPValue
@@ -807,6 +842,7 @@ YBlock::YBlock (bytecodeistream & str)
     , m_last_statement (0)
     , m_includes (0)
     , m_running (false)
+    , m_debug (false)
 {
     Bytecode::readString (str, m_name);		// read name
 
diff --git a/libycp/src/YBreakpoint.cc b/libycp/src/YBreakpoint.cc
new file mode 100644
index 0000000..5f2dd74
--- /dev/null
+++ b/libycp/src/YBreakpoint.cc
@@ -0,0 +1,153 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ V / _` \___ \ | |   __) |                    |
+|                        | | (_| |___) || |  / __/                     |
+|                        |_|\__,_|____/ |_| |_____|                    |
+|                                                                      |
+|                               core system                            |
+|                                                        (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+   File:	YBreakpoint.cc
+
+   Author:	Klaus Kaempf <[email protected]>
+   Maintainer:	Klaus Kaempf <[email protected]>
+
+/-*/
+// -*- 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) : YCode()
+    , m_code (code)
+    , m_enabled (true)
+{
+}
+
+
+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
+    y2internal ("Debugger: breakpoint hit");
+    if (debugger_instance && m_enabled)
+    {
+    	if (m_code->isBlock()) {
+    	    ((YBlockPtr)m_code)->setDebug(true);
+	    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
diff --git a/libycp/src/YCode.cc b/libycp/src/YCode.cc
index 531cf6c..da872fc 100644
--- a/libycp/src/YCode.cc
+++ b/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)
 	{
diff --git a/libycp/src/YExpression.cc b/libycp/src/YExpression.cc
index bb8742c..d3f9852 100644
--- a/libycp/src/YExpression.cc
+++ b/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 ();
 
diff --git a/libycp/src/include/ycp/ExecutionEnvironment.h b/libycp/src/include/ycp/ExecutionEnvironment.h
index 5c1aab5..fcf6d5f 100644
--- a/libycp/src/include/ycp/ExecutionEnvironment.h
+++ b/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 @@ public:
      *
      * @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.
diff --git a/libycp/src/include/ycp/Makefile.am b/libycp/src/include/ycp/Makefile.am
index ffff5d8..1435a40 100644
--- a/libycp/src/include/ycp/Makefile.am
+++ b/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
diff --git a/libycp/src/include/ycp/YBlock.h b/libycp/src/include/ycp/YBlock.h
index 019d11a..8e68104 100644
--- a/libycp/src/include/ycp/YBlock.h
+++ b/libycp/src/include/ycp/YBlock.h
@@ -129,6 +129,9 @@ private:
     constTypePtr m_type;
     
     bool m_running;
+    
+    // trace the statements?
+    bool m_debug; 
 
 public:
     //---------------------------------------------------------------
@@ -160,6 +163,9 @@ public:
     // evaluate the complete block
     virtual YCPValue evaluate (bool cse = false);
     
+    // enable/disable tracing of the statements of this block
+    void setDebug(bool debug);
+    
     // evaluate the block from the given statement (switch)
     YCPValue evaluateFrom (int statement_index);
 
diff --git a/libycp/src/include/ycp/YBreakpoint.h b/libycp/src/include/ycp/YBreakpoint.h
new file mode 100644
index 0000000..1245cb2
--- /dev/null
+++ b/libycp/src/include/ycp/YBreakpoint.h
@@ -0,0 +1,135 @@
+/*-----------------------------------------------------------*- c++ -*-\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ V / _` \___ \ | |   __) |                    |
+|                        | | (_| |___) || |  / __/                     |
+|                        |_|\__,_|____/ |_| |_____|                    |
+|                                                                      |
+|                               core system                            |
+|                                                        (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+   File:	YBreakpoint.h
+
+   Author:	Stanislav Visnovsky <[email protected]>
+   Maintainer:	Stanislav Visnovsky <[email protected]>
+
+/-*/
+// -*- 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;
+public:
+
+    /**
+     * Creates a new YCode element
+     */
+    YBreakpoint (YCodePtr wrapped_ycp);
+
+    /**
+     * 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
diff --git a/libycp/src/include/ycp/YCode.h b/libycp/src/include/ycp/YCode.h
index 9ee9ac2..97705cb 100644
--- a/libycp/src/include/ycp/YCode.h
+++ b/libycp/src/include/ycp/YCode.h
@@ -143,7 +143,10 @@ public:
 	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 @@ public:
     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);
 
diff --git a/libycp/src/include/ycp/YCodePtr.h b/libycp/src/include/ycp/YCodePtr.h
index 5c0d28c..beeb050 100644
--- a/libycp/src/include/ycp/YCodePtr.h
+++ b/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);
diff --git a/libycp/testsuite/Makefile.am b/libycp/testsuite/Makefile.am
index ad1c9b4..1cdf6b9 100644
--- a/libycp/testsuite/Makefile.am
+++ b/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
 
diff --git a/libycp/testsuite/tests/builtin/Backtrace.err b/libycp/testsuite/tests/builtin/Backtrace.err
index 3ed5062..c827411 100644
--- a/libycp/testsuite/tests/builtin/Backtrace.err
+++ b/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 ---------------
diff --git a/wfm/src/Y2WFMComponent.cc b/wfm/src/Y2WFMComponent.cc
index 2a871db..1d668f5 100644
--- a/wfm/src/Y2WFMComponent.cc
+++ b/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 ()));
 
     YCPValue v = script->asCode ()->evaluate ();
 
diff --git a/wfm/testsuite/Makefile.am b/wfm/testsuite/Makefile.am
index c33fff1..c29f80b 100644
--- a/wfm/testsuite/Makefile.am
+++ b/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}
 
diff --git a/yast2-core.spec.in b/yast2-core.spec.in
index 064592a..22e41e6 100644
--- a/yast2-core.spec.in
+++ b/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

Reply via email to