--- /dev/null
+/* $Id$
+
+This file is part of gldbg
+Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#include <cstdlib>
+#include <cerrno>
+#include <cstring>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <msp/core/except.h>
+#include "process.h"
+
+using namespace std;
+using namespace Msp;
+
+Process::Process(const vector<string> &a):
+ args(a),
+ pid(-1),
+ state(INACTIVE)
+{ }
+
+void Process::setenv(const string &key, const string &value)
+{
+ env[key] = value;
+}
+
+void Process::launch()
+{
+ if(state!=INACTIVE)
+ throw InvalidState("Program is already running");
+
+ pid = fork();
+ if(pid==0)
+ {
+ for(map<string, string>::const_iterator i=env.begin(); i!=env.end(); ++i)
+ ::setenv(i->first.c_str(), i->second.c_str(), true);
+ std::vector<char *> argv(args.size()+1);
+ for(unsigned i=0; i<args.size(); ++i)
+ argv[i] = strdup(args[i].c_str());
+ argv[args.size()] = 0;
+ ::ptrace(PTRACE_TRACEME, 0, 0, 0);
+ execvp(argv[0], &argv[0]);
+ ::exit(255);
+ }
+ else if(pid>0)
+ state = STARTING;
+ else
+ throw SystemError("Could not launch process", errno);
+}
+
+int Process::check()
+{
+ int status;
+ int ret = waitpid(pid, &status, WNOHANG);
+ if(ret==pid)
+ {
+ if(WIFEXITED(status))
+ {
+ int code = WEXITSTATUS(status);
+ state = INACTIVE;
+ return 0x100|code;
+ }
+ else if(WIFSIGNALED(status))
+ {
+ state = INACTIVE;
+ return 0x200|WTERMSIG(status);
+ }
+ else if(WIFSTOPPED(status))
+ {
+ int sig = WSTOPSIG(status);
+ if(sig==SIGTRAP && state==STARTING)
+ {
+ ptrace(PTRACE_CONT, 0, 0);
+ state = RUNNING;
+ }
+ else
+ {
+ state = STOPPED;
+ return 0x300|sig;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void Process::resume(int sig)
+{
+ if(state!=STOPPED)
+ throw InvalidState("Program is not stopped");
+ ptrace(PTRACE_CONT, 0, (void *)sig);
+ state = RUNNING;
+}
+
+void Process::kill()
+{
+ if(state==INACTIVE)
+ throw InvalidState("Program is not running");
+ ptrace(PTRACE_KILL, 0, 0);
+}
+
+long Process::ptrace(int req, void *addr, void *data)
+{
+ int ret = ::ptrace((__ptrace_request)req, pid, addr, data);
+ if(ret==-1 && ((req!=PTRACE_PEEKTEXT && req!=PTRACE_PEEKDATA && req!=PTRACE_PEEKUSER) || errno))
+ throw SystemError("ptrace error", errno);
+ return ret;
+}