]> git.tdb.fi Git - gldbg.git/blob - source/process.cpp
e198df2d10e63d6914a61b23cdb2b5f36b7b861e
[gldbg.git] / source / process.cpp
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2009, 2011  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <stdexcept>
9 #include <cstdlib>
10 #include <cerrno>
11 #include <cstring>
12 #include <sys/ptrace.h>
13 #include <sys/wait.h>
14 #include "process.h"
15 #include "strformat.h"
16
17 using namespace std;
18
19 Process::Process(const vector<string> &a):
20         args(a),
21         pid(-1),
22         state(INACTIVE)
23 { }
24
25 void Process::setenv(const string &key, const string &value)
26 {
27         env[key] = value;
28 }
29
30 void Process::launch()
31 {
32         if(state!=INACTIVE)
33                 throw logic_error("Program is already running");
34
35         pid = fork();
36         if(pid==0)
37         {
38                 for(map<string, string>::const_iterator i=env.begin(); i!=env.end(); ++i)
39                         ::setenv(i->first.c_str(), i->second.c_str(), true);
40                 std::vector<char *> argv(args.size()+1);
41                 for(unsigned i=0; i<args.size(); ++i)
42                         argv[i] = strdup(args[i].c_str());
43                 argv[args.size()] = 0;
44                 ::ptrace(PTRACE_TRACEME, 0, 0, 0);
45                 execvp(argv[0], &argv[0]);
46                 ::exit(255);
47         }
48         else if(pid>0)
49                 state = STARTING;
50         else
51                 throw runtime_error(strformat("Could not launch process: %s", strerror(errno)));
52 }
53
54 int Process::check()
55 {
56         int status;
57         int ret = waitpid(pid, &status, WNOHANG);
58         if(ret==pid)
59         {
60                 if(WIFEXITED(status))
61                 {
62                         int code = WEXITSTATUS(status);
63                         state = INACTIVE;
64                         return 0x100|code;
65                 }
66                 else if(WIFSIGNALED(status))
67                 {
68                         state = INACTIVE;
69                         return 0x200|WTERMSIG(status);
70                 }
71                 else if(WIFSTOPPED(status))
72                 {
73                         int sig = WSTOPSIG(status);
74                         if(sig==SIGTRAP && state==STARTING)
75                         {
76                                 ptrace(PTRACE_CONT, 0, 0);
77                                 state = RUNNING;
78                         }
79                         else
80                         {
81                                 state = STOPPED;
82                                 return 0x300|sig;
83                         }
84                 }
85         }
86
87         return 0;
88 }
89
90 void Process::resume(int sig)
91 {
92         if(state!=STOPPED)
93                 throw logic_error("Program is not stopped");
94         ptrace(PTRACE_CONT, 0, (void *)sig);
95         state = RUNNING;
96 }
97
98 void Process::kill()
99 {
100         if(state==INACTIVE)
101                 throw logic_error("Program is not running");
102         ptrace(PTRACE_KILL, 0, 0);
103         // Make the debugger wait() for us
104         state = RUNNING;
105 }
106
107 long Process::ptrace(int req, void *addr, void *data)
108 {
109         int ret = ::ptrace((__ptrace_request)req, pid, addr, data);
110         if(ret==-1 && ((req!=PTRACE_PEEKTEXT && req!=PTRACE_PEEKDATA && req!=PTRACE_PEEKUSER) || errno))
111                 throw runtime_error(strformat("ptrace error: %s", strerror(errno)));
112         return ret;
113 }