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