/* * See the dyninst/COPYRIGHT file for copyright information. * * We provide the Paradyn Tools (below described as "Paradyn") * on an AS IS basis, and do not warrant its validity or performance. * We reserve the right to update, modify, or discontinue this * software at any time. We shall have no obligation to supply such * updates or modifications or any other form of support to you. * * By your use of Paradyn, you understand and agree that we (or any * other person or entity with proprietary rights in Paradyn) are * under no obligation to provide either maintenance services, * update services, notices of latent defects, or correction of * defects for Paradyn. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // $Id: mapped_object.h,v 1.23 2008/10/27 17:23:53 mlam Exp $ #if !defined(_mapped_object_h) #define _mapped_object_h #include #include #include #include #include #include #include "dyninstAPI/src/image.h" #include "dyninstAPI/h/BPatch_enums.h" #include #include "dyninstAPI/src/Relocation/DynObject.h" #include "PCProcess.h" class block_instance; class func_instance; class edge_instance; // we really do not want to have this defined, but I'm defining it for the moment to get thru paradyn seperation #define CHECK_ALL_CALL_POINTS // we depend on this for Paradyn using namespace std; using namespace Dyninst; using Dyninst::PatchAPI::DynCFGMaker; class mapped_module; class int_symbol { public: int_symbol(SymtabAPI::Symbol *sym, Address base) : addr_(base + sym->getOffset()), sym_(sym) {} int_symbol() : addr_(0), sym_(NULL) {} Address getAddr() const { return addr_; } unsigned getSize() const { return sym_->getSize(); } string symTabName() const { return sym_->getMangledName(); } string prettyName() const { return sym_->getPrettyName(); } string typedName() const { return sym_->getTypedName(); } const SymtabAPI::Symbol *sym() const { return sym_; } private: Address addr_; const SymtabAPI::Symbol *sym_; }; class int_variable { // Should subclass this and function off the same thing... private: int_variable() {} public: int_variable(image_variable *var, Address base, mapped_module *mod); int_variable(int_variable *parVar, mapped_module *child); Address getAddress() const { return addr_; } // Can variables have multiple names? string symTabName() const; SymtabAPI::Aggregate::name_iter pretty_names_begin() const; SymtabAPI::Aggregate::name_iter pretty_names_end() const; SymtabAPI::Aggregate::name_iter symtab_names_begin() const; SymtabAPI::Aggregate::name_iter symtab_names_end() const; //const vector& prettyNameVector() const; //const vector& symTabNameVector() const; mapped_module *mod() const { return mod_; } //AddressSpace *as() const { return mod()->proc(); } const image_variable *ivar() const { return ivar_; } Address addr_{}; unsigned size_{}; // type? image_variable *ivar_{}; mapped_module *mod_{}; }; struct edgeStub { edgeStub(block_instance *s, Address t, EdgeTypeEnum y) { src = s; trg = t; type = y; } edgeStub(block_instance* s, Address t, EdgeTypeEnum y, bool b) : src(s), trg(t), type(y), checked(b) { } block_instance* src; Address trg; EdgeTypeEnum type; bool checked{}; }; /* * A class for link map information about a shared object that is mmapped * by the dynamic linker into the applications address space at runtime. */ #define SHAREDOBJECT_NOCHANGE 0 #define SHAREDOBJECT_ADDED 1 #define SHAREDOBJECT_REMOVED 2 // mapped_object represents a file in memory. It will be a collection // of modules (basically, .o's) that are referred to as a unit and // loaded as a unit. The big reason for this is 1) per-process // specialization and 2) a way to reduce memory; to create objects for // all functions ahead of time is wasteful and expensive. So // basically, the mapped_object "wins" if it can return useful // information without having to allocate memory. class mapped_object : public codeRange, public Dyninst::PatchAPI::DynObject { friend class mapped_module; // for findFunction friend class func_instance; friend class block_instance; // Adds to codeRangesByAddr_ friend class edge_instance; friend class DynCFGMaker; private: mapped_object(); mapped_object(fileDescriptor fileDesc, image *img, AddressSpace *proc, BPatch_hybridMode mode = BPatch_normalMode); public: // We need a way to check for errors; hence a "get" method static mapped_object *createMappedObject(fileDescriptor &desc, AddressSpace *p, BPatch_hybridMode m = BPatch_normalMode, bool parseGaps = true); static mapped_object *createMappedObject(ProcControlAPI::Library::const_ptr lib, AddressSpace *p, BPatch_hybridMode m = BPatch_normalMode, bool parseGaps = true); // Copy constructor: for forks mapped_object(const mapped_object *par_obj, AddressSpace *child); // Will delete all func_instances which were originally part of this object; including // any that were relocated (we can always follow the "I was relocated" pointer). ~mapped_object(); bool analyze(); bool isAnalyzed() { return analyzed_; } const fileDescriptor &getFileDesc() const { return desc_; } // Full name, including path const string &fullName() const { return fullName_; } string fileName() const; Address codeAbs() const; Address codeBase() const { return codeBase_; } Address imageOffset() const { return parse_img()->imageOffset(); } unsigned imageSize() const { return parse_img()->imageLength(); } unsigned memoryEnd(); // largest allocated memory address + 1 // 32-bit math safe! bool isCode(Address addr) const; bool isData(Address addr) const; Address getBaseAddress() const { return codeBase(); } Address dataAbs() const; Address dataBase() const { return dataBase_; } Address dataOffset() const { return parse_img()->dataOffset(); } unsigned dataSize() const { return parse_img()->dataLength(); } Address getTOCBaseAddress() const {return tocBase;} void setTOCBaseAddress(Address addr) {tocBase = addr;} image *parse_img() const { return image_; } bool isSharedLib() const; bool isStaticExec() const; static bool isSystemLib(const std::string &name); bool isMemoryImg() const { return memoryImg_; } void setMemoryImg() { memoryImg_ = true; } // Return an appropriate identification string for debug purposes. // Will eventually be required by a debug base class. const std::string debugString() const; // Used for codeRange ONLY! DON'T USE THIS! BAD USER! Address get_address() const { return codeAbs(); } void *get_local_ptr() const; unsigned get_size() const { return imageSize(); } AddressSpace *proc() const; mapped_module *findModule(string m_name, bool wildcard = false); mapped_module *findModule(pdmodule *mod); mapped_module *getDefaultModule(); func_instance *findFuncByEntry(const Address addr); func_instance *findFuncByEntry(const block_instance *blk); bool getInfHeapList(std::vector &infHeaps); void getInferiorHeaps(vector > &infHeaps); bool findFuncsByAddr(const Address addr, std::set &funcs); bool findBlocksByAddr(const Address addr, std::set &blocks); block_instance *findBlockByEntry(const Address addr); block_instance *findOneBlockByAddr(const Address addr); // codeRange method void *getPtrToInstruction(Address addr) const; void *getPtrToData(Address addr) const; // Try to avoid using these if you can, since they'll trigger // parsing and allocation. bool getAllFunctions(std::vector &funcs); bool getAllVariables(std::vector &vars); const std::vector &getModules(); // begin exploratory and defensive mode functions // BPatch_hybridMode hybridMode() { return analysisMode_; } void enableDefensiveMode(bool on = true) { analysisMode_ = on ? BPatch_defensiveMode : BPatch_normalMode; } bool isExploratoryModeOn(); bool parseNewEdges(const std::vector& sources); bool parseNewFunctions(std::vector
&funcEntryAddrs); bool updateCodeBytesIfNeeded(Address entryAddr); // ret true if was needed void updateCodeBytes(const std::list > &owRanges ); void setCodeBytesUpdated(bool); void addProtectedPage(Address pageAddr); // adds to protPages_ void removeProtectedPage(Address pageAddr); void removeEmptyPages(); void remove(func_instance *func); void remove(instPoint *p); void splitBlock(block_instance *first, block_instance *second); bool findBlocksByRange(Address startAddr, Address endAddr, std::list &pageBlocks); void findFuncsByRange(Address startAddr, Address endAddr, std::set &pageFuncs); void addEmulInsn(Address insnAddr, Register effective_addr); bool isEmulInsn(Address insnAddr); Register getEmulInsnReg(Address insnAddr); void setEmulInsnVal(Address insnAddr, void * val); int codeByteUpdates() { return codeByteUpdates_; } void replacePLTStub(SymtabAPI::Symbol *PLTsym, func_instance *func, Address newAddr); private: // helper functions void updateCodeBytes(SymtabAPI::Region *reg); bool isUpdateNeeded(Address entryAddr); bool isExpansionNeeded(Address entryAddr); void expandCodeBytes(SymtabAPI::Region *reg); // end exploratory and defensive mode functions // public: bool getSymbolInfo(const std::string &n, int_symbol &sym); // All name lookup functions are vectorized, because you can have // multiple overlapping names for all sorts of reasons. // Demangled/"pretty": easy overlap (overloaded funcs, etc.). // Mangled: multiple modules with static/private functions and // we've lost the module name. const std::vector *findFuncVectorByPretty(const std::string &funcname); const std::vector *findFuncVectorByMangled(const std::string &funcname); bool findFuncsByAddr(std::vector &funcs); bool findBlocksByAddr(std::vector &blocks); const std::vector *findVarVectorByPretty(const std::string &varname); const std::vector *findVarVectorByMangled(const std::string &varname); const int_variable *getVariable(const std::string &varname); //this marks the shared object as dirty, mutated //so it needs saved back to disk void setDirty(){ dirty_=true;} bool isDirty() { return dirty_; } func_instance *findFunction(ParseAPI::Function *img_func); int_variable *findVariable(image_variable *img_var); block_instance *findBlock(ParseAPI::Block *); // If we already know the source or target hand them in for efficiency edge_instance *findEdge(ParseAPI::Edge *, block_instance *src = NULL, block_instance *trg = NULL); // These methods should be invoked to find the global constructor and // destructor functions in stripped, static binaries func_instance *findGlobalConstructorFunc(const std::string &ctorHandler); func_instance *findGlobalDestructorFunc(const std::string &dtorHandler); // We store callee names at the mapped_object level for // efficiency std::string getCalleeName(block_instance *); void setCalleeName(block_instance *, std::string name); void setCallee(const block_instance *, func_instance *); func_instance *getCallee(const block_instance *) const; void destroy(PatchAPI::PatchFunction *f); void destroy(PatchAPI::PatchBlock *b); // void destroy(PatchAPI::PatchEdge *e); // don't need to destroy anything private: // // PRIVATE DATA MEMBERS // fileDescriptor desc_; // full file descriptor string fullName_; // full file name of the shared object string fileName_; // name of shared object as it should be identified // in mdl, e.g. as used for "exclude".... // Address codeBase_; // The OS offset where the text segment is loaded; // there is a corresponding codeOffset_ in the image class. // For example, an a.out often has a codeBase of 0, and a // codeOffset of 0x. Libraries are the reverse; codeBase_ // of , codeOffset of 0. All of our incoming functions, // etc. from the image class have codeOffset built in. Address dataBase_; // Where the data starts... Address tocBase; void set_short_name(); std::vector everyModule; typedef std::unordered_map *> func_index_t; typedef std::unordered_map *> var_index_t; std::unordered_map everyUniqueVariable; func_index_t allFunctionsByMangledName; func_index_t allFunctionsByPrettyName; var_index_t allVarsByMangledName; var_index_t allVarsByPrettyName; codeRangeTree codeRangesByAddr_; // And those call... void addFunction(func_instance *func); void addVariable(int_variable *var); // Add a name after-the-fact typedef enum { mangledName = 1, prettyName = 2, typedName = 4 } nameType_t; void addFunctionName(func_instance *func, const std::string newName, func_index_t &index); bool dirty_; // marks the shared object as dirty bool dirtyCalled_;//see comment for setDirtyCalled image *image_; // pointer to image if processed is true bool dlopenUsed; //mark this shared object as opened by dlopen AddressSpace *proc_; // Parent process bool analyzed_; // Prevent multiple adds // exploratory and defensive mode variables typedef enum { PROTECTED, REPROTECTED, UNPROTECTED, } WriteableStatus; BPatch_hybridMode analysisMode_; map protPages_; std::set expansionCheckedRegions_; bool pagesUpdated_; int codeByteUpdates_; typedef std::map > EmulInsnMap; EmulInsnMap emulInsns_; Address memEnd_; // size of object in memory mapped_module *getOrCreateForkedModule(mapped_module *mod); bool memoryImg_; std::map calleeNames_; std::map callees_; }; // Aggravation: a mapped object might very well occupy multiple "ranges". class mappedObjData : public codeRange { public: mappedObjData(mapped_object *obj_) : obj(obj_) {} Address get_address() const { return obj->dataAbs(); } unsigned get_size() const { return obj->dataSize(); } mapped_object *obj; }; #endif