Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions dyninstAPI/src/Relocation/DynCFGMaker.C
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ PatchFunction* DynCFGMaker::makeFunction(Function* f,
PatchObject* obj) {
Address code_base = obj->codeBase();
mapped_object* mo = SCAST_MO(obj);

// func_instance being constructed is unusable without blocks
if (!f->entry()) mo->analyzeIfDeferred();

parse_func* img_func = SCAST_PF(f);
if (!img_func) return NULL;
assert(img_func->getSymtabFunction());
Expand Down
24 changes: 24 additions & 0 deletions dyninstAPI/src/dynProcess.C
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,30 @@ void PCProcess::installInstrRequests(const std::vector<instMapping*> &requests)
FILE__, __LINE__, matchingFuncs.size(), req->func.c_str(), req->lib.c_str());
}

// Matches in libraries that import the symbol are PLT stubs that
// jump to the definition, so instrumenting the definition covers them.
// Dropping them also avoids relocate()'s overlap check, whose
// Block::getFuncs() forces a full CFG parse of the stub's library.
// If nothing is left, every match was a stub and we keep them all,
// since then only the stub can carry the probe. Static binaries have
// no stubs and are unaffected.
if (!matchingFuncs.empty()) {
std::vector<func_instance *> definitions;
for (func_instance *func : matchingFuncs) {
if (func && func->ifunc() && !func->ifunc()->isPLTFunction())
definitions.push_back(func);
}

if (!definitions.empty() && definitions.size() < matchingFuncs.size()) {
inst_printf("%s[%d]: %lu of %lu matches for %s are PLT stubs, "
"instrumenting the definition(s) only\n",
FILE__, __LINE__,
matchingFuncs.size() - definitions.size(),
matchingFuncs.size(), req->func.c_str());
matchingFuncs.swap(definitions);
}
}

for (unsigned funcIter = 0; funcIter < matchingFuncs.size(); funcIter++) {
func_instance *func = matchingFuncs[funcIter];
if (!func) {
Expand Down
58 changes: 51 additions & 7 deletions dyninstAPI/src/image.C
Original file line number Diff line number Diff line change
Expand Up @@ -1071,15 +1071,13 @@ image::getAllFunctions()

const std::vector<image_variable*> &image::getAllVariables()
{
analyzeIfNeeded();
return everyUniqueVariable;
}

const std::vector<image_variable*> &image::getExportedVariables() const { return exportedVariables; }

const std::vector<image_variable*> &image::getCreatedVariables()
{
analyzeIfNeeded();
return createdVariables;
}

Expand Down Expand Up @@ -1152,7 +1150,8 @@ unsigned int int_addrHash(const Address& addr) {

image *image::parseImage(fileDescriptor &desc,
BPatch_hybridMode mode,
bool parseGaps)
bool parseGaps,
bool delayedParse)
{
/*
* Check to see if we have parsed this image before. We will
Expand Down Expand Up @@ -1186,7 +1185,7 @@ image *image::parseImage(fileDescriptor &desc,
#endif

startup_printf("%s[%d]: about to create image\n", FILE__, __LINE__);
image *ret = new image(desc, err, mode, parseGaps);
image *ret = new image(desc, err, mode, parseGaps, delayedParse);
startup_printf("%s[%d]: created image\n", FILE__, __LINE__);

if (ret->isSharedObject())
Expand Down Expand Up @@ -1290,6 +1289,11 @@ void image::analyzeIfNeeded() {
}
}

void image::analyzeIfDeferred() {
if (deferredParse_)
analyzeIfNeeded();
}

static bool CheckForPowerPreamble(parse_block* entryBlock, Address &tocBase) {
ParseAPI::Block::Insns insns;
entryBlock->getInsns(insns);
Expand Down Expand Up @@ -1390,7 +1394,8 @@ void image::analyzeImage() {
image::image(fileDescriptor &desc,
bool &err,
BPatch_hybridMode mode,
bool parseGaps) :
bool parseGaps,
bool delayedParse) :
desc_(desc),
imageOffset_(0),
imageLen_(0),
Expand All @@ -1413,9 +1418,11 @@ image::image(fileDescriptor &desc,
trackNewBlocks_(false),
refCount(1),
parseState_(unparsed),
deferredParse_(false),
parseGaps_(parseGaps),
mode_(mode),
arch(Dyninst::Arch_none)
arch(Dyninst::Arch_none),
pltStubAddrsInitialized_(false)
{
#if defined(os_linux) || defined(os_freebsd)
string file = desc_.file().c_str();
Expand Down Expand Up @@ -1523,7 +1530,13 @@ image::image(fileDescriptor &desc,
// fprintf(stderr, "#### create CodeObject for %s\n", desc.file().c_str());
img_fact_ = new DynCFGFactory(this);
parse_cb_ = new DynParseCallback(this);
obj_ = new CodeObject(cs_,img_fact_,parse_cb_,BPatch_defensiveMode == mode);

// Only normal mode defers CFG when delayedParsing is enabled.
// ppc64 is excluded because the code below walks functions and their entry
// blocks, which requires a parsed CFG.
const bool is_ppc64 = (cs_->getArch() == Arch_ppc64);
deferredParse_ = delayedParse && (mode == BPatch_normalMode) && !is_ppc64;
obj_ = new CodeObject(cs_,img_fact_,parse_cb_,BPatch_defensiveMode == mode, deferredParse_);

if (obj_->cs()->getArch() == Arch_ppc64) {
// The PowerPC new ABI typically generate two entries per function.
Expand Down Expand Up @@ -1878,6 +1891,28 @@ const std::vector<parse_func *> *image::findFuncVectorByPretty(const std::string
}
}

// A PLT stub has no symbol of its own, so only parsing creates its parse_func
bool image::parsePltStubs(const std::string &name)
{
// linkage() is address -> name; we need name -> addresses. Build it once
if (!pltStubAddrsInitialized_) {
pltStubAddrsInitialized_ = true;
for (auto const &entry : cs_->linkage()) {
pltStubAddrs_[entry.second].push_back(entry.first);
}
}

// The parser names stubs from this same table, so absent means none exists
auto iter = pltStubAddrs_.find(name);
if (iter == pltStubAddrs_.end())
return false;

for (Address stub : iter->second) {
codeObject()->parse(stub, false);
}
return true;
}

// Return the vector of functions associated with a mangled name
// Very well might be more than one! -- multiple static functions in different .o files

Expand All @@ -1900,6 +1935,15 @@ const std::vector <parse_func *> *image::findFuncVectorByMangled(const std::stri
if (res->empty()) {
// Lookup PLT stubs
auto it = plt_parse_funcs.find(name);

// A miss here can be a false negative: only parsing fills
// plt_parse_funcs, and the image may not have been parsed yet.
// Parse just the stubs rather than the whole image.
if (it == plt_parse_funcs.end() && deferredParse_ && !isParsed()) {
if (parsePltStubs(name))
it = plt_parse_funcs.find(name);
}

if (it != plt_parse_funcs.end()) {
res->push_back(it->second);
}
Expand Down
14 changes: 12 additions & 2 deletions dyninstAPI/src/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ class image : public codeRange {
public:
static image *parseImage(fileDescriptor &desc,
BPatch_hybridMode mode,
bool parseGaps);
bool parseGaps,
bool delayedParse);

// And to get rid of them if we need to re-parse
static void removeImage(image *img);
Expand All @@ -266,9 +267,11 @@ class image : public codeRange {

image(fileDescriptor &desc, bool &err,
BPatch_hybridMode mode,
bool parseGaps);
bool parseGaps,
bool delayedParse);

void analyzeIfNeeded();
void analyzeIfDeferred();
bool isParsed() { return parseState_ == analyzed; }
parse_func* addFunction(Address functionEntryAddr, const char *name=NULL);

Expand Down Expand Up @@ -422,6 +425,10 @@ class image : public codeRange {
bool determineImageType();
bool addSymtabVariables();

// Parse the PLT stubs for an external name, located via the linkage table so
// no CFG is needed. False when the name is not linked through a stub.
bool parsePltStubs(const std::string &name);

void setModuleLanguages(std::unordered_map<std::string, SymtabAPI::supportedLanguages> *mod_langs);

// We have a _lot_ of lookup types; this handles proper entry
Expand Down Expand Up @@ -504,11 +511,14 @@ class image : public codeRange {

int refCount;
imageParseState_t parseState_;
bool deferredParse_;
bool parseGaps_;
BPatch_hybridMode mode_;
Dyninst::Architecture arch;

dyn_hash_map<string, parse_func*> plt_parse_funcs;
std::map<std::string, std::vector<Address> > pltStubAddrs_;
bool pltStubAddrsInitialized_;

};

Expand Down
8 changes: 7 additions & 1 deletion dyninstAPI/src/mapped_object.C
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "Parsing.h"
#include "instPoint.h"
#include <dyncompat/tuple/tuple.hpp>
#include "BPatch.h"
#include "BPatch_image.h"
#include "PatchCFG.h"
#include "PCProcess.h"
Expand Down Expand Up @@ -151,7 +152,9 @@ mapped_object *mapped_object::createMappedObject(fileDescriptor &desc,
startup_printf("%s[%d]: about to parseImage\n", FILE__, __LINE__);
startup_printf("%s[%d]: name %s, codeBase 0x%lx, dataBase 0x%lx\n",
FILE__, __LINE__, desc.file().c_str(), desc.code(), desc.data());
image *img = image::parseImage( desc, analysisMode, parseGaps);
const bool delayedParse =
BPatch::bpatch != NULL && BPatch::bpatch->delayedParsingOn();
image *img = image::parseImage( desc, analysisMode, parseGaps, delayedParse);
if (!img) {
startup_printf("%s[%d]: failed to parseImage\n", FILE__, __LINE__);
return NULL;
Expand Down Expand Up @@ -648,6 +651,9 @@ func_instance *mapped_object::findFuncByEntry(const Address addr) {
return NULL;
}

void mapped_object::analyzeIfDeferred() { parse_img()->analyzeIfDeferred(); }

void mapped_object::ensureParsed() { analyzeIfDeferred(); }

const std::vector<mapped_module *> &mapped_object::getModules() {
// everyModule may be out of date...
Expand Down
7 changes: 7 additions & 0 deletions dyninstAPI/src/mapped_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ class mapped_object : public codeRange, public Dyninst::PatchAPI::DynObject {

func_instance *findFunction(ParseAPI::Function *img_func);

// Builds the CFG of an image whose parse was deferred. No-op otherwise.
void analyzeIfDeferred();

int_variable *findVariable(image_variable *img_var);

block_instance *findBlock(ParseAPI::Block *);
Expand All @@ -331,6 +334,10 @@ class mapped_object : public codeRange, public Dyninst::PatchAPI::DynObject {
void destroy(PatchAPI::PatchBlock *b);
// void destroy(PatchAPI::PatchEdge *e); // don't need to destroy anything

protected:
// Builds the CFG of a deferred image before PatchObject walks its functions.
void ensureParsed() override;

private:
//
// PRIVATE DATA MEMBERS
Expand Down
27 changes: 26 additions & 1 deletion parseAPI/src/Parser.C
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,31 @@ Parser::parse_at(
return;
}

// Nothing has consumed hint_funcs yet, so the clear below would strand every
// unparsed function and the COMPLETE downgrade would lock parse() out for good.
// Park the seeds and put them back once this targeted parse has finalized its
// own batch; re-queuing them here instead would double-finalize them.
struct parked_seeds {
Parser &parser;
const bool active;
dyn_c_vector<Function *> hints;
dyn_c_vector<Function *> discovered;

parked_seeds(Parser &p, bool a) : parser(p), active(a) {
if (active) {
hints.swap(parser.hint_funcs);
discovered.swap(parser.discover_funcs);
}
}
~parked_seeds() {
if (active) {
parser.hint_funcs.swap(hints);
parser.discover_funcs.swap(discovered);
parser._parse_state = UNPARSED;
}
}
} seeds(*this, _parse_state == UNPARSED);

// Reset parser status
_parse_state = PARTIAL;
hint_funcs.clear();
Expand Down Expand Up @@ -245,7 +270,7 @@ Parser::parse_at(
finalize();

// downgrade state if necessary
if(_parse_state > COMPLETE)
if(!seeds.active && _parse_state > COMPLETE)
_parse_state = COMPLETE;

}
Expand Down
4 changes: 4 additions & 0 deletions patchAPI/h/PatchObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class PATCHAPI_EXPORT PatchObject {
void copyCFG(PatchObject* par_obj);
bool splitBlock(PatchBlock *first, ParseAPI::Block *second);

// Allows a subclass to build its CFG before createFuncs() runs.
// createFuncs() walks co()->funcs(), requiring a full parse
virtual void ensureParsed() {}

void createFuncs();
void createBlocks();
void createEdges();
Expand Down
1 change: 1 addition & 0 deletions patchAPI/src/PatchObject.C
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ Address PatchObject::codeOffsetToAddr(Address offset) const {
}

void PatchObject::createFuncs() {
ensureParsed();
for (auto iter = co()->funcs().begin(); iter != co()->funcs().end(); ++iter) {
getFunc(*iter, true);
}
Expand Down