Implement function wrapping for rewriting static binaries (as requested by Rice)
[dyninst.git] / symtabAPI / src / Symtab-edit.C
1 /*
2  * Copyright (c) 1996-2011 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 #include <stdio.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <algorithm>
37
38 #include "common/h/Timer.h"
39 #include "common/h/debugOstream.h"
40 #include "common/h/serialize.h"
41 #include "common/h/pathName.h"
42
43 #include "Serialization.h"
44 #include "Symtab.h"
45 #include "Symbol.h"
46 #include "Module.h"
47 #include "Collections.h"
48 #include "Function.h"
49 #include "Variable.h"
50
51 #include "symtabAPI/src/Object.h"
52
53 using namespace Dyninst;
54 using namespace Dyninst::SymtabAPI;
55 using namespace std;
56
57 static Symbol deletedSymbol(std::string("DeletedSymbol"), Symbol::ST_DELETED, Symbol::SL_UNKNOWN, Symbol::SV_UNKNOWN, 0);
58 /*
59  * We're changing the type of a symbol. Therefore we need to rip it out of the indices
60  * for whatever it used to be (also, aggregations) and put it in the new ones. 
61  * Oy. 
62  */
63
64 bool Symtab::changeType(Symbol *sym, Symbol::SymbolType oldType)
65 {
66     switch (oldType) {
67     case Symbol::ST_FUNCTION: {
68         Function *func = NULL;
69         if (findFuncByEntryOffset(func, sym->getAddr())) {
70             // Remove this symbol from the function
71             func->removeSymbol(sym);
72             // What if we removed the last symbol from the function?
73             // Argh. Ah, well. Users may do that - leave it there for now.
74         break;
75         }
76     }
77     case Symbol::ST_TLS:
78     case Symbol::ST_OBJECT: {
79         Variable *var = NULL;
80         if (findVariableByOffset(var, sym->getAddr())) {
81             var->removeSymbol(sym);
82             // See above
83         }
84         break;
85     }
86     case Symbol::ST_MODULE: {
87         // TODO Module should be an Aggregation
88         break;
89     }
90     default:
91         break;
92     }
93
94     addSymbolToIndices(sym);
95     addSymbolToAggregates(sym);
96
97     return true;
98 }
99
100 bool Symtab::deleteFunction(Function *func) {
101     // First, remove the function
102     everyFunction.erase(std::remove(everyFunction.begin(), everyFunction.end(), func), everyFunction.end());
103 /*    std::vector<Function *>::iterator iter;
104     for (iter = everyFunction.begin(); iter != everyFunction.end(); iter++) {
105         if ((*iter) == func) {
106             everyFunction.erase(iter);
107         }
108     }
109 */
110     funcsByOffset.erase(func->getOffset());
111
112     // Now handle the Aggregate stuff
113     return deleteAggregate(func);
114 }
115
116 bool Symtab::deleteVariable(Variable *var) {
117     // First, remove the function
118     everyVariable.erase(std::remove(everyVariable.begin(), everyVariable.end(), var), everyVariable.end());
119
120     varsByOffset.erase(var->getOffset());
121     return deleteAggregate(var);
122 }
123
124 bool Symtab::deleteAggregate(Aggregate *agg) {
125     std::vector<Symbol *> syms;
126     agg->getSymbols(syms);
127
128     bool ret = true;
129     for (unsigned i = 0; i < syms.size(); i++) {
130         if (!deleteSymbolFromIndices(syms[i]))
131             ret = false;
132     }
133     return ret;
134 }
135
136 bool Symtab::deleteSymbolFromIndices(Symbol *sym) {
137     // Remove from global indices
138     std::vector<Symbol *>::iterator iter;
139
140     // everyDefinedSymbol
141     for (iter = everyDefinedSymbol.begin(); iter != everyDefinedSymbol.end(); iter++) 
142     {
143         //  we use indexes in this vector as a unique id for symbols, so mark
144         //  as deleted w/out changing vector
145         if ((*iter) == sym) (*iter) = &deletedSymbol;
146     }
147
148     // userAddedSymbols
149     userAddedSymbols.erase(std::remove(userAddedSymbols.begin(), userAddedSymbols.end(), sym), userAddedSymbols.end());
150     undefDynSyms[sym->getMangledName()].erase(std::remove(undefDynSyms[sym->getMangledName()].begin(),
151         undefDynSyms[sym->getMangledName()].end(), sym), undefDynSyms[sym->getMangledName()].end());
152     symsByOffset[sym->getOffset()].erase(std::remove(symsByOffset[sym->getOffset()].begin(), symsByOffset[sym->getOffset()].end(),
153         sym), symsByOffset[sym->getOffset()].end());
154     symsByMangledName[sym->getMangledName()].erase(std::remove(symsByMangledName[sym->getMangledName()].begin(),
155         symsByMangledName[sym->getMangledName()].end(), sym), symsByMangledName[sym->getMangledName()].end());
156     symsByPrettyName[sym->getPrettyName()].erase(std::remove(symsByPrettyName[sym->getPrettyName()].begin(),
157         symsByPrettyName[sym->getPrettyName()].end(), sym), symsByPrettyName[sym->getPrettyName()].end());
158     symsByTypedName[sym->getTypedName()].erase(std::remove(symsByTypedName[sym->getTypedName()].begin(),
159         symsByTypedName[sym->getTypedName()].end(), sym), symsByTypedName[sym->getTypedName()].end());
160
161
162     return true;
163 }
164
165 bool Symtab::deleteSymbol(Symbol *sym)
166 {
167     if (sym->aggregate_) {
168         sym->aggregate_->removeSymbol(sym);
169     }
170
171     return deleteSymbolFromIndices(sym);
172 }
173
174 bool Symtab::changeSymbolOffset(Symbol *sym, Offset newOffset) {
175     // If we aren't part of an aggregate, change the symbol offset
176     // and update symsByOffset.
177     // If we are part of an aggregate and the only symbol element,
178     // do that and update funcsByOffset or varsByOffset.
179     // If we are and not the only symbol, do 1), remove from 
180     // the aggregate, and make a new aggregate.
181
182     Offset oldOffset = sym->offset_;
183     std::vector<Symbol *>::iterator iter;
184     for (iter = symsByOffset[oldOffset].begin();
185          iter != symsByOffset[oldOffset].end();
186          iter++) {
187         if ((*iter) == sym) {
188             symsByOffset[oldOffset].erase(iter);
189             break;
190         }
191     }
192     sym->offset_ = newOffset;
193     symsByOffset[newOffset].push_back(sym);
194
195     if (sym->aggregate_ == NULL) return true;
196     else 
197         return sym->aggregate_->changeSymbolOffset(sym);
198
199 }
200
201 bool Symtab::changeAggregateOffset(Aggregate *agg, Offset oldOffset, Offset newOffset) {
202     Function *func = dynamic_cast<Function *>(agg);
203     Variable *var = dynamic_cast<Variable *>(agg);
204
205     if (func) {
206         funcsByOffset.erase(oldOffset);
207         if (funcsByOffset.find(newOffset) == funcsByOffset.end())
208             funcsByOffset[newOffset] = func;
209         else {
210             // Already someone there... odd, so don't do anything.
211         }
212     }
213     if (var) {
214         varsByOffset.erase(oldOffset);
215         if (varsByOffset.find(newOffset) == varsByOffset.end())
216             varsByOffset[newOffset] = var;
217         else {
218             // Already someone there... odd, so don't do anything.
219         }
220     }
221     return true;
222 }
223
224 bool Symtab::addSymbol(Symbol *newSym, Symbol *referringSymbol) 
225 {
226     if (!newSym || !referringSymbol ) return false;
227
228     if( !referringSymbol->getSymtab()->isStaticBinary() ) {
229         if (!newSym->isInDynSymtab()) return false;
230
231         newSym->setReferringSymbol(referringSymbol);
232
233         string filename = referringSymbol->getModule()->exec()->name();
234         vector<string> *vers, *newSymVers = new vector<string>;
235         newSym->setVersionFileName(filename);
236         std::string rstr;
237
238         bool ret = newSym->getVersionFileName(rstr);
239         if (!ret) 
240         {
241            fprintf(stderr, "%s[%d]:  failed to getVersionFileName(%s)\n", 
242                  FILE__, __LINE__, rstr.c_str());
243         }
244
245         if (referringSymbol->getVersions(vers) && vers != NULL && vers->size() > 0) 
246         {
247             newSymVers->push_back((*vers)[0]);
248             newSym->setVersions(*newSymVers);
249         }
250     }else{
251         newSym->setReferringSymbol(referringSymbol);
252     }
253
254     return addSymbol(newSym);
255 }
256
257 bool Symtab::addSymbol(Symbol *newSym) 
258 {
259    if (!newSym) {
260         return false;
261    }
262     // Expected default behavior: if there is no
263     // module use the default.
264     if (newSym->getModule() == NULL) {
265         newSym->setModule(getDefaultModule());
266     }
267
268     // If there aren't any pretty names, create them
269     if (newSym->getPrettyName() == "") {
270         demangleSymbol(newSym);
271     }
272
273     // Add to appropriate indices
274     addSymbolToIndices(newSym);
275
276     // And to aggregates
277     addSymbolToAggregates(newSym);
278
279     // And to "new symbols added by user"
280     userAddedSymbols.push_back(newSym);
281
282     return true;
283 }
284
285
286 Function *Symtab::createFunction(std::string name, 
287                                  Offset offset, 
288                                  size_t sz,
289                                  Module *mod)
290 {
291     Region *reg = NULL;
292     
293     if (!findRegion(reg, ".text") && !isDefensiveBinary()) {
294         assert(0 && "could not find text region");
295         fprintf(stderr, "%s[%d]:  could not find text region\n", FILE__, __LINE__);
296         return NULL;
297     }
298     
299     if (!reg) {
300         reg = findEnclosingRegion(offset);
301     }
302
303     if (!reg) {
304         fprintf(stderr, "%s[%d]:  could not find region for func at %lx\n", 
305                 FILE__, __LINE__,offset);
306         return NULL;
307     }
308     
309     // Let's get the module hammered out. 
310     if (mod == NULL) {
311         mod = getDefaultModule();
312     }
313
314     // Check to see if we contain this module...
315     bool found = false;
316     for (unsigned i = 0; i < _mods.size(); i++) {
317         if (_mods[i] == mod) {
318             found = true;
319             break;
320         }
321     }
322     if (!found) {
323         fprintf(stderr, "Mod is %p/%s\n",
324                 mod, mod->fileName().c_str());
325         for (unsigned i = 0; i < _mods.size(); i++) {
326             fprintf(stderr, "Matched against %p/%s\n",
327                     _mods[i], _mods[i]->fileName().c_str());
328         }
329         fprintf(stderr, "This %p; mod symtab %p\n",
330                 this, mod->exec());
331
332         assert(0 && "passed invalid module\n");
333         return NULL;
334     }
335     
336     Symbol *statSym = new Symbol(name, 
337                                  Symbol::ST_FUNCTION, 
338                                  Symbol::SL_GLOBAL,
339                                  Symbol::SV_DEFAULT, 
340                                  offset, 
341                                  mod,
342                                  reg, 
343                                  sz,
344                                  false,
345                                  false);
346     Symbol *dynSym = new Symbol(name,
347                                 Symbol::ST_FUNCTION,
348                                 Symbol::SL_GLOBAL,
349                                 Symbol::SV_DEFAULT,
350                                 offset,
351                                 mod,
352                                 reg,
353                                 sz,
354                                 true,
355                                 false);
356
357     if (!addSymbol(statSym) || !addSymbol(dynSym)) {
358         assert(0 && "failed to add symbol\n");
359         fprintf(stderr, "%s[%d]:  symtab failed to addSymbol\n", FILE__, __LINE__);
360         return NULL;
361     }
362     
363     Function *func = statSym->getFunction();
364     if (!func) {                
365         assert(0 && "failed aggregate creation");
366         fprintf(stderr, "%s[%d]:  symtab failed to create function\n", FILE__, __LINE__);
367         return NULL;
368     }
369     
370     return func;
371 }
372
373
374
375 Variable *Symtab::createVariable(std::string name, 
376                                  Offset offset, 
377                                  size_t sz,
378                                  Module *mod)
379 {
380     Region *reg = NULL;
381 #if 0    
382     if (!findRegion(reg, ".data") {
383         fprintf(stderr, "%s[%d]:  could not find %s region\n", FILE__, __LINE__, regionName.c_str());
384         return NULL;
385     }
386     
387     if (!reg) {
388         fprintf(stderr, "%s[%d]:  could not find data region\n", FILE__, __LINE__);
389         return NULL;
390     }
391 #endif    
392     // Let's get the module hammered out. 
393     if (mod == NULL) {
394         mod = getDefaultModule();
395     }
396     // Check to see if we contain this module...
397     bool found = false;
398     for (unsigned i = 0; i < _mods.size(); i++) {
399         if (_mods[i] == mod) {
400             found = true;
401             break;
402         }
403     }
404     if (!found) return NULL;
405     
406     Symbol *statSym = new Symbol(name, 
407                                  Symbol::ST_OBJECT, 
408                                  Symbol::SL_GLOBAL,
409                                  Symbol::SV_DEFAULT, 
410                                  offset, 
411                                  mod,
412                                  reg, 
413                                  sz,
414                                  false,
415                                  false);
416     Symbol *dynSym = new Symbol(name,
417                                 Symbol::ST_OBJECT,
418                                 Symbol::SL_GLOBAL,
419                                 Symbol::SV_DEFAULT,
420                                 offset,
421                                 mod,
422                                 reg,
423                                 sz,
424                                 true,
425                                 false);
426     
427     statSym->setModule(mod);
428     dynSym->setModule(mod);
429
430     if (!addSymbol(statSym) || !addSymbol(dynSym)) {
431         fprintf(stderr, "%s[%d]:  symtab failed to addSymbol\n", FILE__, __LINE__);
432         return NULL;
433     }
434     
435     Variable *var = statSym->getVariable();
436     if (!var) {         
437         fprintf(stderr, "%s[%d]:  symtab failed to create var\n", FILE__, __LINE__);
438         return NULL;
439     }
440     
441     return var;
442 }
443
444 SYMTAB_EXPORT bool Symtab::updateRelocations(Address start,
445                                              Address end,
446                                              Symbol *oldsym,
447                                              Symbol *newsym) {
448    for (unsigned i = 0; i < codeRegions_.size(); ++i) {
449       codeRegions_[i]->updateRelocations(start, end, oldsym, newsym);
450    }
451    return true;
452 }
453
454
455