Prototype of ParseAPI modification callback system; still needs work but compiles...
[dyninst.git] / dyninstAPI / src / BPatch_module.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 <ctype.h>
34 #include <string>
35
36 #define BPATCH_FILE
37
38 #include "process.h"
39 #include "function.h"
40 #include "debug.h"
41 #include "BPatch.h"
42 #include "BPatch_module.h"
43 #include "BPatch_libInfo.h"
44 #include "BPatch_function.h"
45 #include "BPatch_point.h"
46 #include "BPatch_statement.h"
47 #include "BPatch_collections.h"
48 #include "symtabAPI/h/Type.h"    // For BPatch_type related stuff
49
50 #include "mapped_module.h"
51 #include "mapped_object.h"
52 #include "instPoint.h"
53
54 using namespace SymtabAPI;
55
56 std::string current_func_name;
57 std::string current_mangled_func_name;
58 BPatch_function *current_func = NULL;
59
60 /*
61  * BPatch_module::getSourceObj()
62  *
63  * Return the contained source objects (e.g. functions).
64  *
65  */
66
67 bool BPatch_module::getSourceObj(BPatch_Vector<BPatch_sourceObj *> &vect)
68 {
69    if (!mod) return false;
70
71    BPatch_Vector<BPatch_function *> temp;
72    bool result = getProcedures(temp);
73    if (!result)
74       return false;
75
76    for (unsigned int i = 0; i < temp.size(); ++i) {
77       vect.push_back((BPatch_sourceObj*) temp[i]);
78    }
79    return true;
80 }
81
82 /*
83  * BPatch_function::getObjParent()
84  *
85  * Return the parent of the function (i.e. the image)
86  *
87  */
88 BPatch_sourceObj *BPatch_module::getObjParent()
89 {
90    return (BPatch_sourceObj *) img;
91 }
92
93 char *BPatch_module::getNameInt(char *buffer, int length)
94 {
95    if (!mod)
96       return NULL;
97
98    string str = mod->fileName();
99
100    strncpy(buffer, str.c_str(), length);
101
102    return buffer;
103 }
104
105 const char *BPatch_module::libraryNameInt()
106 {
107    if (!mod)
108       return NULL;
109
110    if (isSharedLib())      
111       return mod->fullName().c_str();
112
113    return NULL;
114 }
115
116 char *BPatch_module::getFullNameInt(char *buffer, int length)
117 {
118    if (!mod)
119       return NULL;
120    string str = mod->fullName();
121
122    strncpy(buffer, str.c_str(), length);
123
124    return buffer;
125 }
126
127
128 BPatch_module::BPatch_module(BPatch_addressSpace *_addSpace, 
129                              AddressSpace *as,
130                              mapped_module *_mod,
131                              BPatch_image *_img ) :
132    addSpace(_addSpace), 
133    lladdSpace(as),
134    mod(_mod),
135    img(_img), 
136    moduleTypes(NULL),
137    full_func_parse(false),
138    full_var_parse(false)
139 {
140    _srcType = BPatch_sourceModule;
141
142    switch(mod->language()) {
143       case lang_C:
144          setLanguage( BPatch_c );
145          break;
146
147       case lang_CPlusPlus:
148       case lang_GnuCPlusPlus:
149          setLanguage( BPatch_cPlusPlus );
150          break;
151
152       case lang_Fortran_with_pretty_debug:
153          setLanguage( BPatch_f90_demangled_stabstr );
154          break;
155
156       case lang_Fortran:
157       case lang_CMFortran:
158          setLanguage( BPatch_fortran );
159          break;
160
161       case lang_Assembly:
162          setLanguage( BPatch_assembly );
163          break;
164
165       case lang_Unknown: 
166       default:
167          setLanguage( BPatch_unknownLanguage );
168          break;
169    }; /* end language switch */
170
171 } /* end BPatch_module() */
172
173 // Public 'destructor' function...
174 void BPatch_module::handleUnload() 
175 {
176    // Hrm... what to do. For now, mark us as "deleted" so that
177    // any other calls return an error.
178
179    // Brainstorm: we can set mod to NULL (as it really is, 
180    // having been deleted...) and key off that. Saves a boolean.
181
182    mod = NULL;
183 }
184
185 bool BPatch_module::isValidInt() 
186 {
187    return mod != NULL;
188 }
189
190 BPatch_module::~BPatch_module()
191 {
192    if (moduleTypes) {
193       BPatch_typeCollection::freeTypeCollection(moduleTypes);
194    }
195
196    // XXX The odd while-loop structures allow the
197    //     destructors for map objects to remove themselves
198    //     from the maps; otherwise the iterators will
199    //     become invalidated
200
201    BPatch_funcMap::iterator fi = func_map.begin();
202    BPatch_funcMap::iterator tmp_f;
203    while(fi != func_map.end()) {
204       tmp_f = fi;
205       ++fi;
206       delete (*tmp_f).second;
207    }
208
209    BPatch_instpMap::iterator ii = instp_map.begin();
210    BPatch_instpMap::iterator tmp_i;
211    while(ii != instp_map.end()) {
212       tmp_i = ii;
213       ++ii; 
214       delete (*tmp_i).second;
215    }
216
217    BPatch_varMap::iterator vi = var_map.begin();
218    BPatch_varMap::iterator tmp_v;
219    while(vi != var_map.end()) {
220       tmp_v = vi;
221       ++vi;
222       delete (*tmp_v).second;
223    }
224
225    func_map.clear();
226    instp_map.clear();
227    var_map.clear();
228 }
229
230 bool BPatch_module::parseTypesIfNecessary() 
231 {
232         if ( moduleTypes != NULL ) 
233                 return false;
234
235         if (!isValid())
236                 return false;
237
238         bool is64 = (mod->pmod()->imExec()->codeObject()->cs()->getAddressWidth() == 8);
239
240         if (sizeof(void *) == 8 && !is64) 
241         {
242                 // Terrible Hack:
243                 //   If mutatee and mutator address width is different,
244                 //   we need to patch up certain standard types.
245                 BPatch_type *typePtr;
246
247                 typePtr = BPatch::bpatch->builtInTypes->findBuiltInType(-10);
248                 typePtr->getSymtabType()->setSize(4);
249
250                 typePtr = BPatch::bpatch->builtInTypes->findBuiltInType(-19);
251                 typePtr->getSymtabType()->setSize(4);
252         }
253
254         mod->pmod()->mod()->exec()->parseTypesNow();
255         moduleTypes = BPatch_typeCollection::getModTypeCollection(this);
256
257         vector<Type *> *modtypes = mod->pmod()->mod()->getAllTypes();
258
259         if (!modtypes)
260                 return false;
261
262         for (unsigned i=0; i<modtypes->size(); i++) 
263         {
264                 Type *typ = (*modtypes)[i];
265                 BPatch_type *type = new BPatch_type(typ);
266                 moduleTypes->addType(type);
267         }
268
269         vector<pair<string, Type *> > *globalVars = mod->pmod()->mod()->getAllGlobalVars();
270
271         if (!globalVars)
272                 return false;
273
274         for (unsigned i=0; i<globalVars->size(); i++)
275         {
276                 BPatch_type *var_type = NULL;
277                 extern AnnotationClass<BPatch_type> TypeUpPtrAnno;
278
279                 Type *ll_var_type = (*globalVars)[i].second;
280                 std::string &var_name = (*globalVars)[i].first;
281
282                 assert(ll_var_type);
283
284                 if (!ll_var_type->getAnnotation(var_type, TypeUpPtrAnno))
285                 {
286                         var_type = new BPatch_type((*globalVars)[i].second);
287                 }
288                 else
289                 {
290                         assert(var_type);
291                 }
292
293                 moduleTypes->addGlobalVariable(var_name.c_str(), var_type);
294 #if 0
295                 if (!(*globalVars)[i].second->getUpPtr())
296                 {
297                         new BPatch_type((*globalVars)[i].second);
298                 }
299
300                 moduleTypes->addGlobalVariable((*globalVars)[i].first.c_str(), 
301                                 (BPatch_type *)(*globalVars)[i].second->getUpPtr());
302 #endif
303         }
304         return true; 
305 }
306
307 BPatch_typeCollection *BPatch_module::getModuleTypesInt() 
308 {
309         parseTypesIfNecessary();
310         return moduleTypes;
311 }
312
313 /*
314  * BPatch_module::getProcedures
315  *
316  * Returns a list of all procedures in the module upon success, and NULL
317  * upon failure.
318  */
319 BPatch_Vector<BPatch_function *> *
320         BPatch_module::getProceduresInt(bool incUninstrumentable) {
321                 if (!isValid())
322                         return NULL;
323
324    BPatch_Vector<BPatch_function*> *funcs = new BPatch_Vector<BPatch_function*>();
325    bool result = getProceduresInt(*funcs, incUninstrumentable);
326    if (!result) {
327       delete funcs;
328       return NULL;
329    }
330
331    return funcs;
332 }
333
334 bool BPatch_module::getProceduresInt(BPatch_Vector<BPatch_function*> &funcs,
335                                      bool incUninstrumentable)
336 {
337    if (!isValid())
338       return false;
339
340    if (!full_func_parse || func_map.size() != mod->getFuncVectorSize()) {
341       const pdvector<func_instance*> &funcs = mod->getAllFunctions();
342       for (unsigned i=0; i<funcs.size(); i++) {
343          if (!func_map.count(funcs[i])) {
344             addSpace->findOrCreateBPFunc(funcs[i], this);
345          }
346       }
347       full_func_parse = true;
348    }      
349
350    BPatch_funcMap::iterator i = func_map.begin();
351    for (; i != func_map.end(); i++) {
352       if (incUninstrumentable || (*i).first->isInstrumentable())
353          funcs.push_back((*i).second);
354    }
355    return true;
356 }
357
358 /*
359  * BPatch_module::findFunction
360  *
361  * Returns a vector of BPatch_function* with the same name that is provided or
362  * NULL if no function with that name is in the module.  This function
363  * searches the BPatch_function vector of the module followed by
364  * the func_instance of the module.  If a func_instance is found
365  * a BPatch_function is created and added to the BPatch_function vector of
366  * the module.
367  * name The name of function to look up.
368  */
369
370    BPatch_Vector<BPatch_function *> *
371 BPatch_module::findFunctionInt(const char *name, 
372       BPatch_Vector<BPatch_function *> & funcs,
373       bool notify_on_failure, bool regex_case_sensitive,
374       bool incUninstrumentable, bool dont_use_regex)
375 {
376    if (!isValid())
377       return NULL;
378
379    unsigned size = funcs.size();
380
381    if (!name) {
382       char msg[512];
383       sprintf(msg, "%s[%d]:  Module %s: findFunction(NULL)...  failing",
384             __FILE__, __LINE__, mod->fileName().c_str());
385       BPatch_reportError(BPatchSerious, 100, msg);
386       return NULL;
387    }
388
389    // Do we want regex?
390    if (dont_use_regex 
391          ||  (NULL == strpbrk(name, REGEX_CHARSET))) {
392       pdvector<func_instance *> int_funcs;
393       if (mod->findFuncVectorByPretty(name, int_funcs)) {
394          for (unsigned piter = 0; piter < int_funcs.size(); piter++) {
395             if (incUninstrumentable || int_funcs[piter]->isInstrumentable()) 
396             {
397                BPatch_function * bpfunc = addSpace->findOrCreateBPFunc(int_funcs[piter], this);
398                funcs.push_back(bpfunc);
399             }
400          }
401       }
402       else {
403          if (mod->findFuncVectorByMangled(name,
404                   int_funcs)) {
405             for (unsigned miter = 0; miter < int_funcs.size(); miter++) {
406                if (incUninstrumentable || int_funcs[miter]->isInstrumentable()) 
407                {
408                   BPatch_function * bpfunc = addSpace->findOrCreateBPFunc(int_funcs[miter], this);
409                   //                                            BPatch_function * bpfunc = proc->findOrCreateBPFunc(int_funcs[miter], this);
410                   funcs.push_back(bpfunc);
411                }
412             }
413          }
414       }
415       if (size != funcs.size())
416          return &funcs;
417    }
418    else {
419       // Regular expression search. As with BPatch_image, we handle it here
420
421 #if !defined(os_windows)
422       // REGEX falls through:
423       regex_t comp_pat;
424       int err, cflags = REG_NOSUB | REG_EXTENDED;
425
426       if ( !regex_case_sensitive )
427          cflags |= REG_ICASE;
428
429       //cerr << "compiling regex: " <<name<<endl;
430
431       if (0 != (err = regcomp( &comp_pat, name, cflags ))) {
432          char errbuf[80];
433          regerror( err, &comp_pat, errbuf, 80 );
434          if (notify_on_failure) {
435             cerr << __FILE__ << ":" << __LINE__ << ":  REGEXEC ERROR: "<< errbuf << endl;
436             std::string msg = std::string("Image: Unable to find function pattern: ") 
437                + std::string(name) + ": regex error --" + std::string(errbuf);
438             BPatch_reportError(BPatchSerious, 100, msg.c_str());
439          }
440          return NULL;
441       }
442
443       // Regular expression search. This used to be handled at the image
444       // class level, but was moved up here to simplify semantics. We
445       // have to iterate over every function known to the process at some
446       // point, so it might as well be top-level. This is also an
447       // excellent candidate for a "value-added" library.
448
449       const pdvector<func_instance *> &int_funcs = mod->getAllFunctions();
450
451       for (unsigned ai = 0; ai < int_funcs.size(); ai++) {
452          func_instance *func = int_funcs[ai];
453          // If it matches, push onto the vector
454          // Check all pretty names (and then all mangled names if there is no match)
455          bool found_match = false;
456          for (unsigned piter = 0; piter < func->prettyNameVector().size(); piter++) {
457             const string &pName = func->prettyNameVector()[piter];
458             int err;     
459             if (0 == (err = regexec(&comp_pat, pName.c_str(), 1, NULL, 0 ))){
460                if (func->isInstrumentable() || incUninstrumentable) {
461                   BPatch_function *foo = addSpace->findOrCreateBPFunc(func, NULL);
462                   //       BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL);
463                   funcs.push_back(foo);
464                }
465                found_match = true;
466                break;
467             }
468          }
469          if (found_match) continue; // Don't check mangled names
470
471          for (unsigned miter = 0; miter < func->symTabNameVector().size(); miter++) {
472             const string &mName = func->symTabNameVector()[miter];
473             int err;
474
475             if (0 == (err = regexec(&comp_pat, mName.c_str(), 1, NULL, 0 ))){
476                if (func->isInstrumentable() || incUninstrumentable) {
477                   BPatch_function *foo = addSpace->findOrCreateBPFunc(func, NULL);
478                   //       BPatch_function *foo = proc->findOrCreateBPFunc(func, NULL);
479                   funcs.push_back(foo);
480                }
481                found_match = true;
482                break;
483             }
484          }
485       }
486
487       regfree(&comp_pat);
488
489       if (funcs.size() != size) {
490          return &funcs;
491       } 
492
493       if (notify_on_failure) {
494          std::string msg = std::string("Unable to find pattern: ") + std::string(name);
495          BPatch_reportError(BPatchSerious, 100, msg.c_str());
496       }
497 #endif
498    }
499
500    if (notify_on_failure) {
501       char msg[1024];
502       sprintf(msg, "%s[%d]:  Module %s: unable to find function %s",
503             __FILE__, __LINE__, mod->fileName().c_str(), name);
504       BPatch_reportError(BPatchSerious, 100, msg);
505
506    }
507    return &funcs;
508 }
509
510    BPatch_Vector<BPatch_function *> *
511 BPatch_module::findFunctionByAddressInt(void *addr, BPatch_Vector<BPatch_function *> &funcs,
512       bool notify_on_failure, 
513       bool incUninstrumentable)
514 {
515    if (!isValid()) {
516       if (notify_on_failure) {
517          using namespace std;
518          string msg = string("Module is not valid: ") + string(mod->fileName());
519          BPatch_reportError(BPatchSerious, 100, msg.c_str());
520       }
521       return NULL;
522    }
523
524    BPatch_function *bpfunc = NULL;
525    std::set<func_instance *> ifuncs;
526    mod->findFuncsByAddr((Address) addr, ifuncs);
527
528    for (std::set<func_instance *>::iterator iter = ifuncs.begin(); 
529        iter != ifuncs.end(); ++iter) {
530         func_instance *pdfunc = *iter; 
531         if (incUninstrumentable || pdfunc->isInstrumentable()) {
532            bpfunc = addSpace->findOrCreateBPFunc(pdfunc, this);
533           if (bpfunc) {
534                funcs.push_back(bpfunc);
535            }
536         }
537    }
538    if (funcs.empty() && notify_on_failure) {
539        std::string msg = std::string("No functions at: "
540            + (Address)addr + mod->fileName());
541        BPatch_reportError(BPatchSerious, 100, msg.c_str());
542    }
543
544    return &funcs;
545 }
546
547 BPatch_function * BPatch_module::findFunctionByMangledInt(const char *mangled_name,
548       bool incUninstrumentable)
549 {
550    if (!isValid()) return NULL;
551
552    BPatch_function *bpfunc = NULL;
553
554    pdvector<func_instance *> int_funcs;
555    std::string mangled_str(mangled_name);
556
557    if (!mod->findFuncVectorByMangled(mangled_str,
558             int_funcs))
559       return NULL;
560
561    if (int_funcs.size() > 1) {
562       fprintf(stderr, "%s[%d]: Warning: found multiple name matches for %s, returning first\n",
563             FILE__, __LINE__, mangled_name);
564    }
565
566    func_instance *pdfunc = int_funcs[0];
567
568    if (incUninstrumentable || pdfunc->isInstrumentable()) {
569       bpfunc = addSpace->findOrCreateBPFunc(pdfunc, this);
570    }
571
572    return bpfunc;
573 }
574
575 bool BPatch_module::dumpMangledInt(char * prefix)
576 {
577    mod->dumpMangled(prefix);
578    return true;
579 }
580
581 bool BPatch_module::removeFunction(BPatch_function *bpfunc, bool deepRemoval)
582 {
583     func_instance *func = bpfunc->lowlevel_func();
584
585     bool foundIt = false;
586     BPatch_funcMap::iterator fmap_iter = func_map.find(func);
587     if (func_map.end() != fmap_iter) {
588         foundIt = true;
589     }
590
591     if (!foundIt) {
592         return false;
593     }
594
595     if (deepRemoval) {
596         std::map<func_instance*,block_instance*> newFuncEntries;
597
598         //remove instrumentation from dead function
599         bpfunc->removeInstrumentation(true);
600         bool dontcare=false;
601         addSpace->finalizeInsertionSet(false,&dontcare);
602
603         // delete completely dead functions
604         using namespace ParseAPI;
605         vector<pair<block_instance*,Edge*> > deadFuncCallers; // build up list of live callers
606         Address funcAddr = func->addr();
607         mal_printf("Removing function at %lx from mod %s\n", funcAddr, 
608                    mod->fileName().c_str());
609
610         // nuke all call edges, assert that there's a sink edge, otherwise we'll 
611         // have to fill in the code for direct transfers, creating unresolved points
612         // at the source blocks
613         Block::edgelist &callEdges = func->ifunc()->entryBlock()->sources();
614         Block::edgelist::iterator eit = callEdges.begin();
615         CFGFactory *fact = func->ifunc()->img()->codeObject()->fact();
616         bool foundSinkEdge = false;
617         for( ; eit != callEdges.end(); ++eit) {
618             if ( (*eit)->sinkEdge() ) {
619                 foundSinkEdge = true;
620             }
621             else if (CALL == (*eit)->type()) {// includes tail calls
622                 (*eit)->uninstall();
623                 ParseAPI::Edge::destroy(*eit);
624             }
625         }
626         assert(foundSinkEdge);
627  
628         //remove dead function
629         func->removeFromAll();
630
631     } // end deepRemoval
632
633     this->func_map.erase(fmap_iter);
634
635     return true;
636 }
637
638 void BPatch_module::parseTypes() 
639 {
640    mod->pmod()->mod()->exec()->parseTypesNow();
641 }
642 // This is done by analogy with BPatch_module::getVariables,
643 // not BPatch_image::findVariable.  This should result in consistent
644 // behavior at the module level.
645 BPatch_variableExpr* BPatch_module::findVariableInt(const char* name)
646 {
647    parseTypesIfNecessary();
648    const pdvector<int_variable *> &allVars = mod->getAllVariables();
649
650    for (unsigned i = 0; i < allVars.size(); i++) {
651      if(strcmp(allVars[i]->symTabName().c_str(), name) == 0)
652      {
653         return addSpace->findOrCreateVariable(allVars[i]);
654      }
655    }
656
657    return NULL;
658 }
659
660 bool BPatch_module::getVariablesInt(BPatch_Vector<BPatch_variableExpr *> &vars)
661 {
662    if (!isValid())
663       return false;
664    if (!full_var_parse) {
665       const pdvector<int_variable*> &vars = mod->getAllVariables();
666       for (unsigned i=0; i<vars.size(); i++) {
667          if (!var_map.count(vars[i])) {
668             addSpace->findOrCreateVariable(vars[i]);
669          }
670       }
671       full_var_parse = true;
672    }      
673
674    BPatch_varMap::iterator i = var_map.begin();
675    for (; i != var_map.end(); i++) {
676       vars.push_back((*i).second);
677    }
678
679    return true;
680 }
681
682
683 bool BPatch_module::getSourceLinesInt(unsigned long addr, 
684       BPatch_Vector< BPatch_statement> &lines) 
685 {
686    if (!isValid()) 
687    {
688       fprintf(stderr, "%s[%d]:  failed to getSourceLines: invalid\n", FILE__, __LINE__);
689       return false;
690    }
691
692    unsigned int originalSize = lines.size();
693    std::vector<Statement *> lines_ll;
694
695    Module *stmod = mod->pmod()->mod();
696    assert(stmod);
697
698    if (!stmod->getSourceLines(lines_ll, addr - mod->obj()->codeBase()))
699    {
700       return false;
701    }
702
703    for (unsigned int j = 0; j < lines_ll.size(); ++j)
704    {
705            Statement *t = lines_ll[j];
706            lines.push_back(BPatch_statement(this, t));
707    }
708
709    return (lines.size() != originalSize);
710 } /* end getSourceLines() */
711
712 bool BPatch_module::getStatementsInt(BPatch_Vector<BPatch_statement> &statements)
713 {
714         // Iterate over each address range in the line information
715         SymtabAPI::Module *stmod = mod->pmod()->mod();
716         assert(stmod);
717         std::vector<SymtabAPI::Statement *> statements_ll;
718
719         if (!stmod->getStatements(statements_ll))
720         {
721                 return false;
722         }
723
724         for (unsigned int i = 0; i < statements_ll.size(); ++i)
725         {
726                 // Form a BPatch_statement object for this entry
727                 // Note:  Line information stores offsets, so we need to adjust to
728                 //  addresses
729                 SymtabAPI::Statement *stm = statements_ll[i];
730                 BPatch_statement statement(this, stm);
731
732                 // Add this statement
733                 statements.push_back(statement);
734
735         }
736         return true;
737
738 }
739
740 bool BPatch_module::getAddressRangesInt( const char * fileName, 
741                 unsigned int lineNo, std::vector< std::pair< Address, Address > > & ranges ) 
742 {
743         unsigned int starting_size = ranges.size();
744
745    if (!isValid()) 
746    {
747       fprintf(stderr, "%s[%d]:  module is not valid\n", FILE__, __LINE__);
748       return false;
749    }
750
751    if ( fileName == NULL )
752    {
753            fileName = mod->fileName().c_str();
754    }
755
756    if (!mod->pmod()->mod()->getAddressRanges(ranges, std::string(fileName), lineNo))
757    {
758            return false;
759    }
760
761
762    //  Iterate over the returned offset ranges to turn them into addresses
763    for (unsigned int i = starting_size; i < ranges.size(); ++i)
764    {
765            ranges[i].first += mod->obj()->codeBase();
766            ranges[i].second += mod->obj()->codeBase();
767    }
768
769    return true;
770
771 } /* end getAddressRanges() */
772
773 bool BPatch_module::isSharedLibInt() 
774 {
775         return mod->obj()->isSharedLib();
776 }
777
778 /*
779  * BPatch_module::getBaseAddr
780  *
781  * Returns the starting address of the module.
782  */
783 void *BPatch_module::getBaseAddrInt()
784 {
785    return (void *)mod->obj()->codeAbs();
786 }
787
788 /*
789  * BPatch_module::getSize
790  *
791  * Returns the size of the module in bytes.
792  */
793 unsigned long BPatch_module::getSizeInt() 
794 {
795    if (!mod) return 0;
796    return (unsigned long) mod->obj()->imageSize();
797 }
798
799 Dyninst::ParseAPI::CodeObject *
800 BPatch_module::getCodeObjectInt()
801 {
802     if(!mod) return NULL;
803     return mod->obj()->parse_img()->codeObject();
804 }
805
806
807 bool BPatch_module::isNativeCompilerInt()
808 {
809    if (!mod) return false;
810    return mod->obj()->parse_img()->isNativeCompiler();
811 }
812
813 size_t BPatch_module::getAddressWidthInt()
814 {
815    if (!mod) return 0;
816    return mod->obj()->parse_img()->getObject()->getAddressWidth();
817 }
818
819 void BPatch_module::setDefaultNamespacePrefix(char * /*name*/) 
820
821 }
822
823 bool BPatch_module::isSystemLib() 
824 {
825    if (!mod) return false;
826    return mod->obj()->isSystemLib(mod->obj()->fullName());
827 }
828
829 AddressSpace *BPatch_module::getAS()
830 {
831    return lladdSpace;
832 }
833
834 BPatch_hybridMode BPatch_module::getHybridModeInt()
835 {
836     if (!mod || !getAS()->proc()) {
837         return BPatch_normalMode;
838     }
839     return mod->obj()->hybridMode();
840 }
841
842 bool BPatch_module::isExploratoryModeOn()
843
844     if (!mod || !getAS()->proc()) {
845         return false;
846     }
847
848     BPatch_hybridMode mode = mod->obj()->hybridMode();
849     if (BPatch_exploratoryMode == mode || BPatch_defensiveMode == mode) 
850         return true;
851
852     return false;
853 }
854
855 /* Protect analyzed code in the module that has been loaded into the 
856  * process's address space.  Returns false if failure, true even 
857  * if there's no analyzed code in the module and it doesn't
858  * actually wind up protecting anything, doesn't trigger analysis
859  * in the module
860  */ 
861 bool BPatch_module::setAnalyzedCodeWriteable(bool writeable)
862 {
863     // only implemented for processes and only needed for defensive 
864     // BPatch_modules
865     if ( !getAS()->proc() || BPatch_defensiveMode != getHybridMode() ) {
866         return false;
867     }
868
869     // see if we've analyzed code in the module without triggering analysis
870     if ( ! lowlevel_mod()->getFuncVectorSize() ) {
871         return true;
872     }
873
874     // build up list of memory pages that contain analyzed code
875     std::set<Address> pageAddrs;
876     lowlevel_mod()->getAnalyzedCodePages(pageAddrs);
877     // get lwp from which we can call changeMemoryProtections
878     process *proc = ((BPatch_process*)addSpace)->lowlevel_process();
879     dyn_lwp *stoppedlwp = proc->query_for_stopped_lwp();
880     if ( ! stoppedlwp ) {
881         bool wasRunning = true;
882         stoppedlwp = proc->stop_an_lwp(&wasRunning);
883         if ( ! stoppedlwp ) {
884             return false;
885         }
886     }
887
888     // add protected pages to the mapped_object's hash table, and
889     // aggregate adjacent pages into regions and apply protection
890     std::set<Address>::iterator piter = pageAddrs.begin();
891     int pageSize = getAS()->proc()->getMemoryPageSize();
892     while (piter != pageAddrs.end()) {
893         Address start, end;
894         start = (*piter);
895         end = start + pageSize;
896
897         while(1) // extend region if possible
898         {
899             // add the current page addr to mapped_object's hash table
900             // of protected code pages
901             if (writeable) {
902                 mod->obj()->removeProtectedPage( *piter );
903             } else {
904                 mod->obj()->addProtectedPage( *piter );
905             }
906
907             piter++;
908
909             if (pageAddrs.end() == piter) {
910                 break; // last region
911             }
912             if ( end != (*piter) ) {
913                 break; // there's a gap, add new region
914             }
915             // extend current region
916             end += pageSize;
917         } 
918
919 #if defined(os_windows)
920         int newRights = PAGE_EXECUTE_READ;
921         if (writeable) {
922             newRights = PAGE_EXECUTE_READWRITE;
923         }
924         stoppedlwp->changeMemoryProtections(start, end - start, newRights, true);
925 #else
926         assert(0 && "unimplemented!");
927 #endif
928
929     }
930     return true;
931 }
932
933 Address BPatch_module::getLoadAddrInt()
934 {
935    return mod->obj()->codeBase();
936 }
937
938 BPatchSnippetHandle* BPatch_module::insertInitCallbackInt(BPatch_snippet& callback)
939 {
940     BPatch_Vector<BPatch_function*> init_funcs;
941     findFunction("_init", init_funcs);    
942     if(!init_funcs.empty())
943     {
944         assert(init_funcs[0]);
945         BPatch_Vector<BPatch_point*>* init_entry = init_funcs[0]->findPoint(BPatch_entry);
946         if(init_entry && !init_entry->empty() && (*init_entry)[0])
947         {
948             startup_printf("\tinserting init snippet at 0x%lx\n", (*init_entry)[0]->getAddress());
949             return addSpace->insertSnippet(callback, *((*init_entry)[0]));
950         }
951     }
952     return NULL;
953 }
954
955 BPatchSnippetHandle* BPatch_module::insertFiniCallbackInt(BPatch_snippet& callback)
956 {
957     BPatch_Vector<BPatch_function*> fini_funcs;
958     findFunction("_fini", fini_funcs);
959     if(!fini_funcs.empty())
960     {
961         assert(fini_funcs[0]);
962         BPatch_Vector<BPatch_point*>* fini_exit = fini_funcs[0]->findPoint(BPatch_exit);
963         if(fini_exit && !fini_exit->empty() && (*fini_exit)[0])
964         {
965             startup_printf("\tinserting fini snippet at 0x%lx\n", (*fini_exit)[0]->getAddress());
966             return addSpace->insertSnippet(callback, *((*fini_exit)[0]));
967         }
968     }
969     return NULL;
970 }
971
972 BPatch_function *BPatch_module::findFunctionByEntryInt(Dyninst::Address entry)
973 {
974     BPatch_function* func = addSpace->findFunctionByEntry(entry);
975     if (func && func->getModule() == this) {
976         return func;
977     }
978
979     return NULL;
980 }
981
982
983 #ifdef IBM_BPATCH_COMPAT
984
985 bool BPatch_module::getLineNumbersInt( unsigned int & startLine, unsigned int & endLine )
986 {
987    /* I don't think this function has ever returned nonzeroes.  Approximate a better 
988       result by with the line numbers for the first and last addresses in the module. */
989    if (!mod) return false;
990
991    void * startAddr, * endAddr;
992    if( ! getAddressRangeInt( startAddr, endAddr ) ) {
993       return false;
994    }
995
996    bool setAValue = false;
997    BPatch_Vector<BPatch_statement> lines;
998    getSourceLines( (Address)startAddr, lines );
999    if( lines.size() != 0 ) {
1000       startLine = lines[0].lineNumber();
1001       setAValue = true;
1002    }
1003
1004    lines.clear();
1005    getSourceLines( (Address)endAddr, lines );
1006    if( lines.size() != 0 ) {
1007       endLine = lines[0].lineNumber();
1008       setAValue = true;
1009    }
1010
1011    return setAValue;
1012 }
1013
1014 bool BPatch_module::getAddressRangeInt(void * &start, void * &end)
1015 {
1016    // Code? Data? We'll do code for now...
1017    if (!mod) return false;
1018    start = (void *)(mod->obj()->codeAbs());
1019    end = (void *)(mod->obj()->codeAbs() + mod->obj()->imageSize());
1020    return true;
1021 }
1022 char *BPatch_module::getUniqueStringInt(char *buffer, int length)
1023 {
1024    // Use "<program_name>|<module_name>" as the unique name if this module is
1025    // part of the executable and "<module_name>" if it is not.
1026    if (!mod) return NULL;
1027    if(isSharedLib())
1028       snprintf(buffer, length, "%s", mod->fileName().c_str());
1029    else {
1030       char prog[1024];
1031       addSpace->getImage()->getProgramFileName(prog, 1024);
1032       snprintf(buffer, length, "%s|%s",
1033             prog, mod->fileName().c_str());
1034    }
1035    // Return the unique name to the caller
1036    return buffer;
1037 }
1038
1039 int BPatch_module::getSharedLibTypeInt()        
1040 {
1041    return 0;
1042 }
1043
1044 int BPatch_module::getBindingTypeInt()
1045 {
1046    return 0;
1047 }
1048
1049 std::vector<struct BPatch_module::Statement> BPatch_module::getStatementsInt()
1050 {
1051    std::vector<struct BPatch_module::Statement> statements;
1052    if (!mod) return statements;
1053
1054    Module *stmod = mod->pmod()->mod();
1055    assert(stmod);
1056    if (!stmod->getStatements(statements_ll))
1057    {
1058            return statements;
1059    }
1060
1061    for (unsigned int i = 0; i < statements_ll.size(); ++i)
1062    {
1063            // Form a BPatch_statement object for this entry
1064            // Note:  Line information stores offsets, so we need to adjust to
1065            //  addresses
1066            SymtabAPI::Statement &stm = statements_ll[i];
1067            BPatch_statement statement(this, stm.file().c_str(), stm.line(),
1068                            stm.column(), (void *)(mod->obj()->codeBase() + stm.startAddr()),
1069                            (void *)(mod->obj()->codeBase() + stm.endAddr()));
1070
1071            // Add this statement
1072            statements.push_back(statement);
1073    }
1074
1075    // Return the statements to the caller
1076    return statements;
1077
1078 }
1079 #endif