Update copyright to LGPL on all files
[dyninst.git] / valueAdded / sharedMem / src / shmMgr.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 /* $Id: shmMgr.C,v 1.1 2006/11/22 21:44:59 bernat Exp $
33  * shmMgr: an interface to allocating/freeing memory in the 
34  * shared segment. Will eventually support allocating a new
35  * shared segment and attaching to it.
36  */
37
38 #include "BPatch_Vector.h"
39 #include "BPatch.h"
40 #include "BPatch_process.h"
41 #include "BPatch_snippet.h"
42 #include "BPatch_type.h"
43 #include "../h/SharedMem.h"
44 #include "sharedMemInternal.h"
45 #include "shmSegment.h"
46
47 extern void addLibraryCallback(BPatch_process *, BPatch_module *, bool);
48
49 shmMgr::shmMgr(BPatch_process *proc, key_t shmSegKey, unsigned shmSize_, bool freeWhenDel) :
50         nextKeyToTry(shmSegKey), shmSegSize(shmSize_), totalShmSize(0), freespace(0),
51         app(proc), freeWhenDeleted(freeWhenDel)
52 {
53 }
54
55 shmMgr *shmMgr::createSharedManager(BPatch_process *proc,
56                                     key_t shmSegKey,
57                                     unsigned defaultSegmentSize,
58                                     bool automaticFree) {
59     shmMgr *shm = new shmMgr(proc, shmSegKey, defaultSegmentSize, automaticFree);
60     if (shm == NULL) return NULL;
61     if (!shm->initialize()) {
62         delete shm;
63         return NULL;
64     }
65     return shm;
66 }
67
68
69 bool shmMgr::initialize() {
70         // Get the name of the shared memory library (if specified in environment)
71    const char *shm_lib_name = getenv("DYNINSTAPI_SHM_LIB");
72    if (!shm_lib_name)
73       shm_lib_name = SHARED_MUTATEE_LIB;
74
75    //getBPatch().registerDynLibraryCallback((BPatchDynLibraryCallback) (addLibraryCallback));
76    // Load the shared memory library via Dyninst's loadLibrary
77    if (!app->loadLibrary(shm_lib_name, true)) {
78       fprintf(stderr, "Failed to load shared memory library\n");
79       return false;
80    }
81    BPatch_Vector<BPatch_module *> * mods = app->getImage()->getModules();
82    static char mnamebuf[512];
83    BPatch_module *shm_mod = NULL;
84    for (unsigned int i = 0; i < mods->size(); ++i) {
85       (*mods)[i]->getName(mnamebuf, 512);
86       if (!strcmp(mnamebuf, shm_lib_name)) {
87          shm_mod = (*mods)[i];
88          break;
89       }
90    }
91    if (!shm_mod) {
92       fprintf(stderr, "%s[%d}:  Could not find module %s\n", __FILE__, __LINE__, shm_lib_name);
93    } 
94
95    // Proactively make the first segment
96    ShmSegment *new_seg = ShmSegment::Create(nextKeyToTry, shmSegSize, freeWhenDeleted);
97    if (new_seg == NULL) {
98       // No luck
99       fprintf(stderr, "%s[%d]: shared memory manager: failed creation\n");
100       return false;
101    }
102    if (!new_seg->attach(app)) {
103       fprintf(stderr, "%s[%d]: shared memory manager: failed attach\n");
104       return false;
105    }
106    
107    nextKeyToTry++;
108    totalShmSize += shmSegSize;
109    freespace += shmSegSize;
110    theShms.push_back(new_seg);
111    return true;
112 }
113
114
115 shmMgr::shmMgr(const shmMgr *par, BPatch_process *child) :
116         nextKeyToTry(par->nextKeyToTry), shmSegSize(par->shmSegSize), 
117         totalShmSize(par->totalShmSize), freespace(par->freespace),
118         app(child), freeWhenDeleted(par->freeWhenDeleted)
119 {  
120
121     for (unsigned iter = 0; iter < par->theShms.size(); iter++) {
122         ShmSegment *new_seg = par->theShms[iter]->Copy(app, true);
123         if (new_seg) {
124             theShms.push_back(new_seg);
125         }
126         else {
127             assert(0 && "Failed to copy parent's shared memory segment");            
128         }
129     }
130 }
131
132 shmMgr::~shmMgr()
133 {
134   // free the preMalloced memory
135   for (unsigned iter = 0; iter < theShms.size(); iter++) {
136       delete theShms[iter];
137   }  
138 }
139
140 Dyninst::Address shmMgr::malloc_int(unsigned size, bool /* align = true*/) {
141     Dyninst::Address retAddr = 0;
142     
143     if (freespace < size) {
144         // No way to get any allocation, try to allocate new shared memory segment
145         ShmSegment *new_seg = ShmSegment::Create(nextKeyToTry, shmSegSize, freeWhenDeleted);
146         if (new_seg == NULL) {
147             // No luck
148             fprintf(stderr, "shmMgr: unable to allocate: unsufficient space, failed to allocate new segment\n");
149             return 0;
150         }
151         if (!new_seg->attach(app)) {
152             fprintf(stderr, "shmMgr: unable to allocate: unsufficient space, failed to attach to new segment\n");
153             return 0;
154         }
155         
156         nextKeyToTry++;
157         totalShmSize += shmSegSize;
158         freespace += shmSegSize;
159         theShms.push_back(new_seg);
160     }
161     
162     // Pass it to our shared memory segments
163
164     for (unsigned iter = 0; iter < theShms.size(); iter++) {
165         retAddr = (Dyninst::Address) theShms[iter]->malloc(size);
166         if (retAddr != 0) {
167             freespace -= size;
168             return retAddr;
169         }
170     }
171
172     assert(retAddr == 0);
173     return 0;
174 }
175
176 void shmMgr::free(shMallocHandle *handle) 
177 {
178     assert(handle);
179     Dyninst::Address addr = (Dyninst::Address) handle->addressInMutator();
180
181     delete handle;
182
183     // Pass along to the shared segments
184     for (unsigned iter = 0; iter < theShms.size(); iter++) {
185         if (theShms[iter]->addrInSegmentDaemon(addr)) {
186             theShms[iter]->free(addr);
187             return;
188         }
189     }
190 }
191
192 shMallocHandle *shmMgr::malloc(unsigned size, bool align /* = true*/, BPatch_type *type /* = NULL */) {
193     Dyninst::Address retAddr = malloc_int(size, align);
194     if (retAddr == 0) return 0;
195
196     char buffer[1024];
197     snprintf(buffer, 1024, "%s-%p-%d", "shMemVar", retAddr, size);
198
199     if (type == NULL) {
200         assert(BPatch::getBPatch());
201         type = BPatch::getBPatch()->createScalar(buffer, size);
202         assert(type);
203     }
204     
205     // Okay, we've got an address. Let's wrap it up and go.
206     BPatch_variableExpr *expr = app->createVariable(buffer, 
207                                                     daemonToApplic(retAddr),
208                                                     type);
209     if (expr == NULL) return NULL;
210
211     return new shMallocHandle(retAddr, expr);
212 }
213
214 // Assumption: the vectors of shared segments in each manager
215 // are equivalent
216 Dyninst::Address  shmMgr::translateFromParentDaemon(Dyninst::Address vaddr, const shmMgr *parShmMgr) {
217     Dyninst::Address addr = (Dyninst::Address) vaddr;
218     for (unsigned i = 0; i < parShmMgr->theShms.size(); i++) {
219         if (parShmMgr->theShms[i]->addrInSegmentDaemon(addr)) {
220             Dyninst::Address offset = parShmMgr->theShms[i]->offsetInDaemon(addr);
221             assert(theShms.size() > i);
222             return (Dyninst::Address )theShms[i]->getAddrInDaemon(offset);
223         }
224     }
225     assert(0 && "Translation failed");
226     return 0;
227 }
228
229
230
231 // Assumption: the vectors of shared segments in each manager
232 // are equivalent
233 Dyninst::Address shmMgr::translateFromParentApplic(Dyninst::Address vaddr, const shmMgr *parShmMgr) {
234     Dyninst::Address addr = (Dyninst::Address) vaddr;
235     for (unsigned i = 0; i < parShmMgr->theShms.size(); i++) {
236         if (parShmMgr->theShms[i]->addrInSegmentApplic(addr)) {
237             Dyninst::Address offset = parShmMgr->theShms[i]->offsetInApplic(addr);
238             assert(theShms.size() > i);
239             return (Dyninst::Address )theShms[i]->getAddrInApplic(offset);
240         }
241     }
242     assert(0 && "Translation failed");
243     return 0;
244 }
245
246 Dyninst::Address  shmMgr::applicToDaemon(Dyninst::Address vapplic) const {
247     Dyninst::Address applic = (Dyninst::Address) vapplic;
248     for (unsigned i = 0; i < theShms.size(); i++)
249         if (theShms[i]->addrInSegmentApplic(applic)) {
250             Dyninst::Address ret = theShms[i]->applicToDaemon(applic);
251
252             return (Dyninst::Address )ret;
253         }
254     return 0;
255 }
256
257 Dyninst::Address shmMgr::daemonToApplic(Dyninst::Address vdaemon) const {
258     Dyninst::Address daemon = (Dyninst::Address) vdaemon;
259     for (unsigned i = 0; i < theShms.size(); i++)
260         if (theShms[i]->addrInSegmentDaemon(daemon)) {
261             Dyninst::Address ret = theShms[i]->daemonToApplic(daemon);
262             return (Dyninst::Address )ret;
263         }
264     return 0;
265 }
266
267 shmMgr *shmMgr::handleFork(BPatch_process *childProc) {
268     return new shmMgr(this, childProc);
269     // If we kept internal handles, we'd want to duplicate... but
270     // for now we force the user to call getChildHandle(...)
271 }
272
273 Dyninst::Address shMallocHandle::addressInMutatee() const {
274     if (!expr_) return 0;
275     return (Dyninst::Address) expr_->getBaseAddr();
276 }
277
278 shMallocHandle::~shMallocHandle() {
279     if (expr_)
280         delete expr_;
281 }
282
283