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