new file: .syntastic_cpp_config
[dyninst.git] / proccontrol / src / unix.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "proccontrol/src/unix.h"
32 #include "proccontrol/src/snippets.h"
33 #include "proccontrol/src/procpool.h"
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/mman.h>
41
42 #include <string>
43 #include "common/src/Types.h"
44 #if defined(os_linux)
45 #include "common/src/linuxKludges.h"
46 #elif defined(os_freebsd)
47 #include "common/src/freebsdKludges.h"
48 #endif
49
50 using namespace std;
51
52 unix_process::unix_process(Dyninst::PID p, std::string e, std::vector<std::string> a,
53                            std::vector<std::string> envp, std::map<int,int> f) :
54    int_process(p, e, a, envp, f)
55 {
56 }
57
58 unix_process::unix_process(Dyninst::PID pid_, int_process *p) :
59    int_process(pid_, p)
60 {
61 }
62
63 unix_process::~unix_process()
64 {
65 }
66
67 void unix_process::plat_execv() {
68     // Never returns
69     typedef const char * const_str;
70
71     const_str *new_argv = (const_str *) calloc(argv.size()+2, sizeof(char *));
72     for (unsigned i=0; i<argv.size(); ++i) {
73         new_argv[i] = argv[i].c_str();
74     }
75     new_argv[argv.size()] = (char *) NULL;
76
77     const_str *new_env = (const_str *) calloc(env.size()+1, sizeof(char *));
78     for (unsigned i=0; i < env.size(); ++i) {
79        new_env[i] = env[i].c_str();
80     }
81     new_env[env.size()] = (char *) NULL;
82
83     for(std::map<int,int>::iterator fdit = fds.begin(),
84             fdend = fds.end();
85             fdit != fdend;
86             ++fdit) {
87         int oldfd = fdit->first;
88         int newfd = fdit->second;
89
90         int result = close(newfd);
91         if (result == -1) {
92             pthrd_printf("Could not close old file descriptor to redirect.\n");
93             setLastError(err_internal, "Unable to close file descriptor for redirection");
94             exit(-1);
95         }
96
97         result = dup2(oldfd, newfd);
98         if (result == -1) {
99             pthrd_printf("Could not redirect file descriptor.\n");
100             setLastError(err_internal, "Failed dup2 call.");
101             exit(-1);
102         }
103         pthrd_printf("DEBUG redirected file!\n");
104     }
105
106     if( env.size() ) {
107         execve(executable.c_str(), const_cast<char * const *>(new_argv),
108                 const_cast<char * const *>(new_env));
109     }else{
110         execv(executable.c_str(), const_cast<char * const*>(new_argv));
111     }
112     int errnum = errno;
113     pthrd_printf("Failed to exec %s: %s\n", executable.c_str(), strerror(errnum));
114     if (errnum == ENOENT)
115         setLastError(err_nofile, "No such file");
116     if (errnum == EPERM || errnum == EACCES)
117         setLastError(err_prem, "Permission denied");
118     else
119         setLastError(err_internal, "Unable to exec process");
120     exit(-1);
121 }
122
123 bool unix_process::post_forked()
124 {
125    ProcPool()->condvar()->lock();
126
127    int_thread *thrd = threadPool()->initialThread();
128    //The new process is currently stopped, but should be moved to
129    // a running state when handlers complete.
130    pthrd_printf("Setting state of initial thread after fork in %d\n",
131                 getPid());
132    thrd->getGeneratorState().setState(int_thread::stopped);
133    thrd->getHandlerState().setState(int_thread::stopped);
134    thrd->getUserState().setState(int_thread::running);
135
136    ProcPool()->condvar()->broadcast();
137    ProcPool()->condvar()->unlock();
138
139    //TODO: Remove this and make have the translate layers' fork
140    // constructors do the work.
141    std::set<response::ptr> async_responses;
142    async_ret_t result = initializeAddressSpace(async_responses);
143    if (result == aret_async) {
144       //Not going to do proper async handling here.  BG is the async platform
145       //and BG doesn't have fork.  Going to just do a sync block
146       //for testing purposes, but this shouldn't run in production.
147       waitForAsyncEvent(async_responses);
148       return true;
149    }
150    return (result == aret_success);
151 }
152
153 unsigned unix_process::getTargetPageSize() {
154     static unsigned pgSize = 0;
155     if( !pgSize ) pgSize = getpagesize();
156     return pgSize;
157 }
158
159 bool unix_process::plat_decodeMemoryRights(Process::mem_perm& perm,
160                                            unsigned long rights) {
161     switch (rights) {
162       default:                                 return false;
163       case PROT_NONE:                          perm.clrR().clrW().clrX(); break;
164       case PROT_READ:                          perm.setR().clrW().clrX(); break;
165       case PROT_EXEC:                          perm.clrR().clrW().setX(); break;
166       case PROT_READ | PROT_WRITE:             perm.setR().setW().clrX(); break;
167       case PROT_READ | PROT_EXEC:              perm.setR().clrW().setX(); break;
168       case PROT_READ | PROT_WRITE | PROT_EXEC: perm.setR().setW().setX(); break;
169     }
170
171     return true;
172 }
173
174 bool unix_process::plat_encodeMemoryRights(Process::mem_perm perm,
175                                            unsigned long& rights) {
176     if (perm.isNone()) {
177         rights = PROT_NONE;
178     } else if (perm.isR()) {
179         rights = PROT_READ;
180     } else if (perm.isX()) {
181         rights = PROT_EXEC;
182     } else if (perm.isRW()) {
183         rights = PROT_READ | PROT_WRITE;
184     } else if (perm.isRX()) {
185         rights = PROT_READ | PROT_EXEC;
186     } else if (perm.isRWX()) {
187         rights = PROT_READ | PROT_WRITE | PROT_EXEC;
188     } else {
189         return false;
190     }
191
192     return true;
193 }
194
195 bool unix_process::plat_getMemoryAccessRights(Dyninst::Address addr,
196                                               Process::mem_perm& perm) {
197     (void)addr;
198     (void)perm;
199     perr_printf("Called getMemoryAccessRights on unspported platform\n");
200     setLastError(err_unsupported, "Get Memory Permission not supported on this platform\n");
201     // ZUYU TODO
202     // parse /proc/self/maps manually for permission of given address
203     return false;
204 }
205
206 bool unix_process::plat_setMemoryAccessRights(Dyninst::Address addr,
207                                               size_t size,
208                                               Process::mem_perm perm,
209                                               Process::mem_perm& oldPerm) {
210     unsigned long rights;
211     if (!plat_encodeMemoryRights(perm, rights)) {
212         pthrd_printf("ERROR: unsupported rights for page %lx\n", addr);
213         return false;
214     }
215
216     if (!mprotect((void*)addr, size, (int)rights)) {
217         pthrd_printf("ERROR: failed to set access rights for page %lx\n", addr);
218         switch (errno) {
219           case EACCES:
220               setLastError(err_prem, "Permission denied");
221               break;
222           case EINVAL:
223               setLastError(err_badparam,
224                       "Given page address is invalid or not page-aligned");
225               break;
226           case ENOMEM:
227               setLastError(err_badparam, "Insufficient memory, "
228                       "or the given memory region contains invalid address space");
229               break;
230           default:
231               setLastError(err_unsupported, "Unknown error code");
232               break;
233         }
234         return false;
235     }
236
237     if (!plat_getMemoryAccessRights(addr, oldPerm)) {
238         pthrd_printf("ERROR: failed to get access rights for page %lx\n", addr);
239         return false;
240     }
241
242     return true;
243 }
244
245 bool unix_process::plat_findAllocatedRegionAround(Dyninst::Address addr,
246                                                   Process::MemoryRegion& memRegion) {
247     (void)addr;
248     memRegion.first  = 0;
249     memRegion.second = 0;
250     perr_printf("Called findAllocatedRegionAround on unspported platform\n");
251     setLastError(err_unsupported, "Find Allocated Memory Region not supported on this platform\n");
252     return false;
253 }
254 //I'm not sure that unix_process is the proper place for this--it's really based on whether
255 // /proc/PID/maps exists.  Currently, that matches our platforms that use unix_process, so
256 // I'll leave it be for now.
257 Dyninst::Address unix_process::plat_mallocExecMemory(Dyninst::Address min, unsigned size) {
258     Dyninst::Address result = 0x0;
259     bool found_result = false;
260     unsigned maps_size;
261     map_entries *maps = getVMMaps(getPid(), maps_size);
262     assert(maps); //TODO, Perhaps go to libraries for address map if no /proc/
263     for (unsigned i=0; i<maps_size; i++) {
264         if (!(maps[i].prems & PREMS_EXEC))
265             continue;
266         if (min + size > maps[i].end)
267             continue;
268         if (maps[i].end - maps[i].start < size)
269             continue;
270
271         if (maps[i].start > min)
272             result = maps[i].start;
273         else
274             result = min;
275         found_result = true;
276         break;
277     }
278     assert(found_result);
279     free(maps);
280     return result;
281 }
282
283 bool unix_process::plat_supportFork()
284 {
285    return true;
286 }
287
288 bool unix_process::plat_supportExec()
289 {
290    return true;
291 }
292
293 std::string int_process::plat_canonicalizeFileName(std::string path)
294 {
295    char *result = realpath(path.c_str(), NULL);
296    if (result) {
297       string sresult(result);
298       free(result);
299       return sresult;
300    }
301    else {
302       return path;
303    }
304 }