CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
425 lines
16 KiB
C++
425 lines
16 KiB
C++
/*
|
|
* 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 <string>
|
|
#include <map>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include "dyninstAPI/src/image.h"
|
|
#include "dyninstAPI/h/BPatch_enums.h"
|
|
#include <list>
|
|
#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<string>& prettyNameVector() const;
|
|
//const vector<string>& 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<heapDescriptor> &infHeaps);
|
|
void getInferiorHeaps(vector<pair<string, Address> > &infHeaps);
|
|
|
|
bool findFuncsByAddr(const Address addr, std::set<func_instance *> &funcs);
|
|
bool findBlocksByAddr(const Address addr, std::set<block_instance *> &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<func_instance *> &funcs);
|
|
bool getAllVariables(std::vector<int_variable *> &vars);
|
|
|
|
const std::vector<mapped_module *> &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<edgeStub>& sources);
|
|
bool parseNewFunctions(std::vector<Address> &funcEntryAddrs);
|
|
bool updateCodeBytesIfNeeded(Address entryAddr); // ret true if was needed
|
|
void updateCodeBytes(const std::list<std::pair<Address,Address> > &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<block_instance*> &pageBlocks);
|
|
void findFuncsByRange(Address startAddr,
|
|
Address endAddr,
|
|
std::set<func_instance*> &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<func_instance *> *findFuncVectorByPretty(const std::string &funcname);
|
|
const std::vector<func_instance *> *findFuncVectorByMangled(const std::string &funcname);
|
|
|
|
bool findFuncsByAddr(std::vector<func_instance *> &funcs);
|
|
bool findBlocksByAddr(std::vector<block_instance *> &blocks);
|
|
|
|
const std::vector<int_variable *> *findVarVectorByPretty(const std::string &varname);
|
|
const std::vector<int_variable *> *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<valid>. Libraries are the reverse; codeBase_
|
|
// of <valid>, 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<mapped_module *> everyModule;
|
|
typedef std::unordered_map<std::string, std::vector<func_instance *> *> func_index_t;
|
|
typedef std::unordered_map<std::string, std::vector<int_variable *> *> var_index_t;
|
|
|
|
std::unordered_map<const image_variable *, int_variable *> 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<Address,WriteableStatus> protPages_;
|
|
std::set<SymtabAPI::Region*> expansionCheckedRegions_;
|
|
bool pagesUpdated_;
|
|
int codeByteUpdates_;
|
|
typedef std::map<Address, std::pair<Register,void*> > EmulInsnMap;
|
|
EmulInsnMap emulInsns_;
|
|
|
|
Address memEnd_; // size of object in memory
|
|
|
|
mapped_module *getOrCreateForkedModule(mapped_module *mod);
|
|
|
|
bool memoryImg_;
|
|
|
|
std::map<block_instance *, std::string> calleeNames_;
|
|
std::map<const block_instance *, func_instance *> 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
|