You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
7.1 KiB
210 lines
7.1 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/**
|
|
* This tool writes the region/s of every image loaded during the lifetime
|
|
* of the application.
|
|
* This information is then compared with the actual load addresses of the
|
|
* segments as the application views them (split_image_app).
|
|
* The comparison is done using the python script region_compare.py.
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <string.h>
|
|
#include <vector>
|
|
#include "pin.H"
|
|
using std::istringstream;
|
|
using std::pair;
|
|
using std::vector;
|
|
using std::string;
|
|
using std::ifstream;
|
|
|
|
|
|
FILE *fp = 0;
|
|
|
|
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "split_image.out", "specify output file name");
|
|
|
|
KNOB<bool> KnobVerbose(KNOB_MODE_WRITEONCE, "pintool",
|
|
"verbose", "0", "verbose output");
|
|
|
|
vector<pair<string, ADDRESS_RANGE> > allImages;
|
|
vector<pair<string, ADDRESS_RANGE> > allRegions;
|
|
|
|
/*
|
|
* The application that this tool is instrumenting as part of the test is linked so there
|
|
* is a big hole in its address space between the code region and the data region.
|
|
* This function tries to locate the starting address of this hole
|
|
*/
|
|
void* locate_app_image_hole(void* address_in_app)
|
|
{
|
|
ifstream infile("/proc/self/maps");
|
|
string line;
|
|
void* app_end = NULL;
|
|
while (std::getline(infile, line))
|
|
{
|
|
istringstream iss(line);
|
|
string range;
|
|
if (iss >> range)
|
|
{
|
|
size_t pos = range.find("-");
|
|
if (pos != string::npos)
|
|
{
|
|
void* start, *end;
|
|
start = (void*)strtoll(range.substr(0, pos).c_str(), NULL, 16);
|
|
end = (void*)strtoll(range.substr(pos + 1).c_str(), NULL, 16);
|
|
if ((start <= address_in_app && end > address_in_app) || app_end == start)
|
|
app_end = end;
|
|
else if (app_end != NULL)
|
|
return app_end;
|
|
}
|
|
}
|
|
}
|
|
return app_end;
|
|
}
|
|
|
|
/*
|
|
* This function is instrumented right before the mmap() function of the loader.
|
|
* When the loader first tries to map the test library, we catch it and force the memory mapping
|
|
* to be in the address we want it to.
|
|
*/
|
|
void mmap_replacement(void** start, ADDRINT flags, ADDRINT fd)
|
|
{
|
|
if (KnobVerbose)
|
|
{
|
|
fprintf(stderr, "Intercepted mmap for the loader with start=%p, flags=%x, fd=%d\n", *start, (int)flags, (int)fd);
|
|
}
|
|
if (NULL == *start && fd >= 0 && !(flags & MAP_ANON))
|
|
{
|
|
static const char* toFind = "/libsplit_image_linux_lib.so";
|
|
static const int toFindLen = strlen(toFind);
|
|
char buf[4096];
|
|
sprintf(buf, "/proc/self/fd/%d", (int)fd);
|
|
int len = readlink(buf, buf, sizeof(buf));
|
|
if (strstr(buf, toFind) == buf + len - toFindLen)
|
|
{
|
|
// 0x200000 is the start address of the executable's code region - we took care of that when we linked the executable.
|
|
*start = locate_app_image_hole((void*)0x200000);
|
|
if (KnobVerbose)
|
|
{
|
|
fprintf(stderr, "The hold in the app's image is at %p\n", *start);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if the provided memory region collides with all other known existing regions.
|
|
* If it does: trigger an assertion.
|
|
* If it doesn't: Add the region to the known regions
|
|
*/
|
|
void checkRegion(string type, vector<pair<string, ADDRESS_RANGE> >& all, string newName, ADDRESS_RANGE newRange)
|
|
{
|
|
for (vector<pair<string, ADDRESS_RANGE> >::iterator it = all.begin(); it != all.end(); it++)
|
|
{
|
|
ADDRESS_RANGE& other = it->second;
|
|
if ((other._low >= newRange._low && other._low <= newRange._high)
|
|
|| (other._high >= newRange._low && other._high <= newRange._high)
|
|
|| (newRange._low >= other._low && newRange._low <= other._high)
|
|
|| (newRange._high >= other._low && newRange._high <= other._high))
|
|
{
|
|
ASSERT(false, "Found two intersecting "+ type + ":\n"
|
|
+ newName + " at [" + newRange.String() + "],\nand "
|
|
+ it->first + " at [" + other.String() + "]");
|
|
}
|
|
}
|
|
all.push_back(pair<string, ADDRESS_RANGE>(newName, newRange));
|
|
}
|
|
|
|
VOID ImageLoad (IMG img, VOID *v)
|
|
{
|
|
if (IMG_Name(img).find("ld-linux") != string::npos)
|
|
{
|
|
RTN rtn = RTN_FindByName(img, "mmap");
|
|
if (RTN_Valid(rtn))
|
|
{
|
|
RTN_Open(rtn);
|
|
RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)mmap_replacement,
|
|
IARG_FUNCARG_ENTRYPOINT_REFERENCE, 0,
|
|
IARG_FUNCARG_ENTRYPOINT_VALUE, 3,
|
|
IARG_FUNCARG_ENTRYPOINT_VALUE, 4,
|
|
IARG_END);
|
|
RTN_Close(rtn);
|
|
}
|
|
}
|
|
ASSERT(IMG_NumRegions(img) != 0, "Zero regions for image " + IMG_Name(img));
|
|
|
|
// check that there are no intersecting images
|
|
checkRegion("images", allImages, IMG_Name(img), ADDRESS_RANGE(IMG_LowAddress(img), IMG_HighAddress(img)));
|
|
if (IMG_NumRegions(img) == 1)
|
|
{
|
|
fprintf(fp, "%s, %p-%p\n", IMG_Name(img).c_str(), Addrint2VoidStar(IMG_LowAddress(img)), Addrint2VoidStar(IMG_HighAddress(img)));
|
|
}
|
|
else
|
|
{
|
|
ADDRINT imgLow = IMG_LowAddress(img);
|
|
ADDRINT imgHigh = IMG_HighAddress(img);
|
|
bool foundHigh = false, foundLow = false;
|
|
for(UINT32 i = 0; i < IMG_NumRegions(img); i++)
|
|
{
|
|
ADDRINT high = IMG_RegionHighAddress(img, i);
|
|
ADDRINT low = IMG_RegionLowAddress(img, i);
|
|
if (low <= imgLow && high >= imgLow) foundLow = true;
|
|
if (low <= imgHigh && high >= imgHigh) foundHigh = true;
|
|
// check that there are no intersecting regions
|
|
checkRegion("regions", allRegions, IMG_Name(img) + " region #" + decstr(i), ADDRESS_RANGE(low, high));
|
|
fprintf(fp, "%s, %p-%p\n", IMG_Name(img).c_str(), Addrint2VoidStar(low), Addrint2VoidStar(high));
|
|
}
|
|
|
|
// flush 'fp' in case the assertions below will be triggered.
|
|
fflush(fp);
|
|
ASSERT(foundLow, "IMG_LowAddress() 0x" + hexstr(imgLow) + " is not within any region of the image");
|
|
ASSERT(foundHigh, "IMG_HighAddress() 0x" + hexstr(imgHigh) + " is not within any region of the image");
|
|
}
|
|
}
|
|
|
|
// This function is called when the application exits
|
|
VOID Fini(INT32 code, VOID *v)
|
|
{
|
|
fclose(fp);
|
|
}
|
|
|
|
int main(int argc, char * argv[])
|
|
{
|
|
PIN_InitSymbols();
|
|
PIN_Init(argc, argv);
|
|
|
|
fp = fopen(KnobOutputFile.Value().c_str(), "w");
|
|
if (fp == NULL)
|
|
{
|
|
fprintf(stderr, "Couldn't open %s for output\n", KnobOutputFile.Value().c_str());
|
|
exit(1);
|
|
}
|
|
|
|
IMG_AddInstrumentFunction(ImageLoad, 0);
|
|
|
|
// Register Fini to be called when the application exits
|
|
PIN_AddFiniFunction(Fini, 0);
|
|
|
|
// Start the program, never returns
|
|
PIN_StartProgram();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|