1) Cmake support for PPC64LE builds
[dyninst.git] / common / src / MappedFile.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 #include "common/src/MappedFile.h"
31 #include "common/src/pathName.h"
32 #include <iostream>
33 using namespace std;
34
35 dyn_hash_map<std::string, MappedFile *> MappedFile::mapped_files;
36
37 MappedFile *MappedFile::createMappedFile(std::string fullpath_)
38 {
39    //fprintf(stderr, "%s[%d]:  createMappedFile %s\n", FILE__, __LINE__, fullpath_.c_str());
40    if (mapped_files.find(fullpath_) != mapped_files.end()) {
41       //fprintf(stderr, "%s[%d]:  mapped file exists for %s\n", FILE__, __LINE__, fullpath_.c_str());
42       MappedFile  *ret = mapped_files[fullpath_];
43       if (ret->can_share) {
44          ret->refCount++;
45          return ret;
46       }
47    }
48
49    bool ok = false;
50    MappedFile *mf = new MappedFile(fullpath_, ok);
51    if (!mf) {
52        return NULL;
53    }
54
55    if (!ok) {
56
57 #if defined(os_vxworks)
58       // vxWorks may request to open files that exist only on the remote
59       // target.  Return a placeholder mapped file to hold filename only.
60       mf->remote_file = true;
61       mf->can_share = true;
62       mf->map_addr = 0x0;
63       mf->fd = -1;
64
65       ok = true;
66 #elif defined(os_windows)
67       if (std::string::npos != fullpath_.find(".dll") &&
68           std::string::npos == fullpath_.find("\\"))
69       {
70           size_t envLen = 64;
71           char *buf = (char*) malloc(envLen);
72           bool repeat = false;
73           do {
74               repeat = false;
75               if (getenv_s(&envLen, buf, envLen, "windir")) {
76                   if (envLen > 64) { // error due to size problem
77                       repeat = true;
78                       free(buf);
79                       buf = (char*) malloc(envLen);
80                   }
81               }
82           } while(repeat); // repeat once if needed
83           fullpath_ = buf + ("\\system32\\" + fullpath_);
84           free(buf);
85           return MappedFile::createMappedFile(fullpath_);
86       }
87           else {
88                   delete mf;
89                   return NULL;
90           }
91 #else
92       delete mf;
93       return NULL;
94 #endif
95    }
96
97    mapped_files[fullpath_] = mf;
98
99    //fprintf(stderr, "%s[%d]:  MMAPFILE %s: mapped_files.size() =  %d\n", FILE__, __LINE__, fullpath_.c_str(), mapped_files.size());
100    return mf;
101 }
102
103 MappedFile::MappedFile(std::string fullpath_, bool &ok) :
104    fullpath(fullpath_),
105            map_addr(NULL),
106 #if defined(os_windows)
107            hMap(NULL),
108            hFile(NULL),
109 #else
110            fd(-1),
111 #endif
112    remote_file(false),
113    did_mmap(false),
114    did_open(false),
115    can_share(true),
116    refCount(1)
117 {
118   ok = check_path(fullpath);
119   if (!ok) {
120           return;
121   }
122   ok = open_file();
123   if (!ok) return;
124   ok = map_file();
125
126   //  I think on unixes we can close the fd after mapping the file, 
127   //  but is this really somehow better?
128 }
129
130 MappedFile *MappedFile::createMappedFile(void *loc, unsigned long size_, const std::string &name)
131 {
132    bool ok = false;
133    MappedFile *mf = new MappedFile(loc, size_, name, ok);
134    if (!mf || !ok) {
135       if (mf)
136          delete mf;
137       return NULL;
138   }
139
140   return mf;
141 }
142
143 MappedFile::MappedFile(void *loc, unsigned long size_, const std::string &name, bool &ok) :
144    fullpath(name),
145         map_addr(NULL),
146 #if defined(os_windows)
147         hMap(NULL),
148         hFile(NULL),
149 #endif
150            remote_file(false),
151    did_mmap(false),
152    did_open(false),
153    can_share(true),
154    refCount(1)
155 {
156   ok = open_file(loc, size_);
157 #if defined(os_windows)  
158   if (!ok) {
159           return;
160   }
161   //ok = map_file();
162   map_addr = loc;
163   this->file_size = size_;
164 #endif
165 }
166
167 void MappedFile::closeMappedFile(MappedFile *&mf)
168 {
169    if (!mf) 
170    {
171       fprintf(stderr, "%s[%d]:  BAD NEWS:  called closeMappedFile(NULL)\n", FILE__, __LINE__);
172       return;
173    }
174
175   //fprintf(stderr, "%s[%d]:  welcome to closeMappedFile() refCount = %d\n", FILE__, __LINE__, mf->refCount);
176    mf->refCount--;
177
178    if (mf->refCount <= 0) 
179    {
180       dyn_hash_map<std::string, MappedFile *>::iterator iter;
181       iter = mapped_files.find(mf->pathname());
182
183       if (iter != mapped_files.end()) 
184       {
185          mapped_files.erase(iter);
186       }
187
188       //fprintf(stderr, "%s[%d]:  DELETING mapped file\n", FILE__, __LINE__);
189       //  dtor handles unmap and close
190
191       delete mf;
192       mf = NULL;
193    }
194 }
195
196 bool MappedFile::clean_up()
197 {
198    if (did_mmap) {
199       if (!unmap_file()) goto err;
200    }
201    if (did_open) {
202       if (!close_file()) goto err;
203    }
204    return true;
205
206 err:
207    fprintf(stderr, "%s[%d]:  error unmapping file %s\n", 
208          FILE__, __LINE__, fullpath.c_str() );
209    return false;
210 }
211
212 MappedFile::~MappedFile()
213 {
214   //  warning, destructor should not allowed to throw exceptions
215    if (did_mmap)  {
216       //fprintf(stderr, "%s[%d]: unmapping %s\n", FILE__, __LINE__, fullpath.c_str());
217       unmap_file();
218    }
219    if (did_open) 
220       close_file();
221 }
222
223 bool MappedFile::check_path(std::string &filename)
224 {
225    struct stat statbuf;
226    if (0 != stat(filename.c_str(), &statbuf)) {
227       char ebuf[1024];
228 #if defined(os_windows)
229       LPVOID lpMsgBuf;
230       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
231             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
232             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
233             &lpMsgBuf,    0,    NULL );
234
235       sprintf(ebuf, "stat: %s", (char *) lpMsgBuf);
236       LocalFree(lpMsgBuf);
237 #else
238       sprintf(ebuf, "stat: %s", strerror(errno));
239 #endif
240       goto err;
241    }
242
243    file_size = statbuf.st_size;
244
245    return true;
246
247 err:
248    return false;
249 }
250
251 bool MappedFile::open_file(void *loc, unsigned long size_)
252 {
253 #if defined(os_windows)
254    hFile = LocalHandle( loc );  //For a mem image
255    if (!hFile) {
256       LPVOID lpMsgBuf;
257       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
258                     FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
259                     GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
260                     (LPTSTR) &lpMsgBuf, 0, NULL);
261
262       char ebuf[1024];
263       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
264       LocalFree(lpMsgBuf);
265       goto err;
266    }
267    did_open = true;
268
269    return true;
270 err:
271    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
272    return false;
273 #else
274    map_addr = loc;
275    file_size = size_;
276    did_open = false;
277    fd = -1;
278    return true;
279 #endif
280 }
281
282 bool MappedFile::open_file()
283 {
284 #if defined(os_windows)
285    hFile = CreateFile(fullpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
286          NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
287    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
288       LPVOID lpMsgBuf;
289       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
290             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
291             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
292             &lpMsgBuf,    0,    NULL );
293
294       char ebuf[1024];
295       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
296       LocalFree(lpMsgBuf);
297       goto err;
298    }
299 #else
300    fd = open(fullpath.c_str(), O_RDONLY);
301    if (-1 == fd) {
302       char ebuf[1024];
303       sprintf(ebuf, "open(%s) failed: %s", fullpath.c_str(), strerror(errno));
304       goto err;
305    }
306 #endif
307
308    did_open = true;
309    return true;
310 err:
311    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
312    return false;
313 }
314
315 bool MappedFile::map_file()
316 {
317    char ebuf[1024];
318 #if defined(os_windows)
319
320    // map the file to our address space
321    // first, create a file mapping object
322    
323    hMap = CreateFileMapping( hFile,
324          NULL,           // security attrs
325          PAGE_READONLY,  // protection flags
326          0,              // max size - high DWORD
327          0,              // max size - low DWORD
328          NULL );         // mapping name - not used
329
330    if (!hMap) {
331            LPVOID lpMsgBuf;
332       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
333             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
334             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
335             &lpMsgBuf,    0,    NULL );
336
337       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
338       LocalFree(lpMsgBuf);
339       goto err;
340    }
341
342    // next, map the file to our address space
343
344    map_addr = MapViewOfFileEx( hMap,             // mapping object
345          FILE_MAP_COPY,  // desired access
346          0,              // loc to map - hi DWORD
347          0,              // loc to map - lo DWORD
348          0,              // #bytes to map - 0=all
349          NULL );         // suggested map addr
350    if (!map_addr) {
351             LPVOID lpMsgBuf;
352       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
353             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
354             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
355             &lpMsgBuf,    0,    NULL );
356
357       sprintf(ebuf, "MapViewOfFileEx failed: %s", (char *) lpMsgBuf);
358       LocalFree(lpMsgBuf);
359       goto err;
360    }
361
362 #else
363
364    int mmap_prot  = PROT_READ;
365    int mmap_flags = MAP_SHARED;
366
367 #if defined(os_vxworks)   
368    // VxWorks kernel modules have relocations which need to be
369    // overwritten in memory.
370    //
371    // XXX - We don't overwrite our memory image with relocations from the
372    // target memory space yet due to performance concerns.  If we decide
373    // to go this route, it would simplify a lot of the Dyninst internals.
374    mmap_prot  = PROT_READ | PROT_WRITE;
375    mmap_flags = MAP_PRIVATE;
376 #endif
377
378    map_addr = mmap(0, file_size, mmap_prot, mmap_flags, fd, 0);
379    if (MAP_FAILED == map_addr) {
380       sprintf(ebuf, "mmap(0, %lu, prot=0x%x, flags=0x%x, %d, 0): %s", 
381             file_size, mmap_prot, mmap_flags, fd, strerror(errno));
382       goto err;
383    }
384
385 #endif
386
387    did_mmap = true;
388    return true;
389 err:
390    return false;
391 }
392
393 bool MappedFile::unmap_file()
394 {
395    if (remote_file) {
396       return true;
397    }
398
399 #if defined(os_windows)
400
401    UnmapViewOfFile(map_addr);
402    CloseHandle(hMap);
403
404 #else
405
406    if ( 0 != munmap(map_addr, file_size))  {
407       fprintf(stderr, "%s[%d]: failed to unmap file\n", FILE__, __LINE__);
408       return false;
409    }
410    
411    map_addr = NULL;
412 #endif
413    return true;
414 }
415
416 bool MappedFile::close_file()
417 {
418    if (remote_file) {
419       return true;
420    }
421
422 #if defined (os_windows)
423
424    CloseHandle(hFile);
425
426 #else
427
428    if (-1 == close(fd)) {
429       fprintf(stderr, "%s[%d]: failed to close file\n", FILE__, __LINE__);
430       return false;
431    }
432
433 #endif
434    return true;
435 }
436
437 std::string MappedFile::pathname() 
438 {
439         return fullpath;
440 }
441
442 std::string MappedFile::filename() 
443 {
444         return extract_pathname_tail(fullpath);
445 }
446
447 void MappedFile::setSharing(bool s)
448 {
449    can_share = s;
450 }
451
452 bool MappedFile::canBeShared()
453 {
454    return can_share;
455 }