00001 #include <SectHeader.h>
00002 #include <Iterator.h>
00003 #include <Function.h>
00004 #include <LineInfoFinder.h>
00005 #include <XCoffFile.h>
00006 #include <BasicBlockTracer.h>
00007
00008 bool BasicBlockTracer::filterBlockForInst(BasicBlock* bb){
00009 if (!bb)
00010 return true;
00011 if (bb->isTrace() || bb->isJumpTable())
00012 return true;
00013 return false;
00014 }
00015
00016
00017
00018 void BasicBlockTracer::initializeReservedData(DataSection* dataSect,BaseGen* gen){
00019 uint32_t lineno = 0;
00020 char* functionNameOfBlock = NULL;
00021 LineInfoFinder* LIF = ((TextSection*)xcoffFile->getRawSection(xcoffFile->getTextSectionIndex()))->getLineInfoFinder();
00022 uint64_t baseAddress;
00023
00024 for (uint32_t i = 0; i < numberOfInstPoints; i++){
00025
00026 baseAddress = blocksToInstrument[i]->getBaseAddress();
00027 if (LIF){
00028 lineno = LIF->getLineNumberInFunction(baseAddress);
00029 functionNameOfBlock = LIF->getFunctionName(baseAddress);
00030 }
00031
00032
00033 gen->writeWord(allBlockInfo[i]-dataSect->getSectHeader()->GET(s_vaddr),i);
00034 gen->writeWord(allBlockInfo[i]-dataSect->getSectHeader()->GET(s_vaddr)+sizeof(uint32_t),lineno);
00035 gen->writeString(allBlockInfo[i]-dataSect->getSectHeader()->GET(s_vaddr)+(2*sizeof(uint32_t)),functionNameOfBlock,strlen(functionNameOfBlock));
00036 gen->writeString(allBlockInfo[i]-dataSect->getSectHeader()->GET(s_vaddr)+(2*sizeof(uint32_t))+strlen(functionNameOfBlock),"\0",sizeof(char));
00037
00038 PRINT_DEBUG("Writing [%d,%d,%s] (length %d) to data section at location %#lx", i, lineno, functionNameOfBlock,
00039 (2*sizeof(uint32_t))+strlen(functionNameOfBlock)+sizeof(char), allBlockInfo[i]);
00040 }
00041 }
00042
00043 uint32_t BasicBlockTracer::generateSharedLibFuncWrapper(
00044 uint32_t libFuncIdx,uint64_t funcCallAddr,uint32_t genBufferOffset,BaseGen* gen)
00045 {
00046 uint32_t insnCount = 0;
00047 Instruction* insnBuffer = new Instruction[byteCountForSharedLibFuncWrappers() / sizeof(uint32_t)];
00048
00049 PRINT_DEBUG("Generating library stub for library function at %#llx", funcCallAddr);
00050
00051 uint32_t scratchReg = 6;
00052 uint32_t fpScratchReg = 3;
00053 uint32_t savedReg = 31;
00054 uint32_t tocHoldReg = 30;
00055 uint32_t firstArgReg = 3;
00056
00057 ASSERT(scratchReg == 6);
00058 ASSERT(fpScratchReg == 3);
00059 ASSERT(savedReg == 31);
00060 ASSERT(tocHoldReg == 30);
00061 ASSERT(firstArgReg == 3);
00062
00063 int32_t saveOffset = 0x0;
00064
00065 updateTOCRegister(insnBuffer,&insnCount);
00066
00067 for (uint32_t i = 0; i <= LAST_VOLATILE_REG; i++){
00068 saveOffset = getGPRSaveOffset(i);
00069 insnBuffer[insnCount++] = Instruction::generateStoreDouble(i,REG_TOC,saveOffset);
00070 }
00071 for (uint32_t i = 0; i <= LAST_VOLATILE_REG; i++){
00072 saveOffset = getFPRSaveOffset(i);
00073 insnBuffer[insnCount++] = Instruction::generateStoreDoubleFloat(i,REG_TOC,saveOffset);
00074 }
00075
00076 saveCTRRegister(insnBuffer,&insnCount,scratchReg);
00077 saveEXRRegister(insnBuffer,&insnCount,scratchReg);
00078 saveFPSCRRegister(insnBuffer,&insnCount,fpScratchReg);
00079
00080
00081 insnBuffer[insnCount++] = Instruction::generateLoadDouble(scratchReg,REG_TOC,getBlockPointerOffsetSaveOffset());
00082
00083 insnBuffer[insnCount++] = Instruction::generateMoveReg(REG_TOC,firstArgReg);
00084
00085 insnBuffer[insnCount++] = Instruction::generateAdd(firstArgReg,firstArgReg,scratchReg);
00086
00087 insnBuffer[insnCount++] = Instruction::generateMoveFromSPR(savedReg,REG_LNK);
00088 insnBuffer[insnCount++] = Instruction::generateMoveReg(REG_TOC,tocHoldReg);
00089
00090
00091 int32_t callOffset = funcCallAddr - execTOCAddress - tocDistUpdateVal;
00092 if (xcoffFile->is64Bit()){
00093 insnBuffer[insnCount++] = Instruction::generateSPIncrementDouble(-SAFE_FRAME_LOC*sizeof(uint64_t));
00094 insnBuffer[insnCount++] = Instruction::generateLoadDouble(scratchReg,REG_TOC,callOffset);
00095 insnBuffer[insnCount++] = Instruction::generateLoadDouble(REG_TOC,scratchReg,sizeof(uint64_t));
00096 insnBuffer[insnCount++] = Instruction::generateLoadDouble(scratchReg,scratchReg,0);
00097 } else {
00098 insnBuffer[insnCount++] = Instruction::generateSPIncrementWord(-SAFE_FRAME_LOC*sizeof(uint64_t));
00099 insnBuffer[insnCount++] = Instruction::generateLoadWord(scratchReg,REG_TOC,callOffset);
00100 insnBuffer[insnCount++] = Instruction::generateLoadWord(REG_TOC,scratchReg,sizeof(uint32_t));
00101 insnBuffer[insnCount++] = Instruction::generateLoadWord(scratchReg,scratchReg,0);
00102 }
00103 insnBuffer[insnCount++] = Instruction::generateMoveToSPR(scratchReg,REG_CTR);
00104 insnBuffer[insnCount++] = Instruction::generateCallToCTR();
00105
00106 insnBuffer[insnCount++] = Instruction::generateMoveReg(tocHoldReg,REG_TOC);
00107 insnBuffer[insnCount++] = Instruction::generateMoveToSPR(savedReg,REG_LNK);
00108
00109 restFPSCRRegister(insnBuffer,&insnCount,fpScratchReg);
00110 restEXRRegister(insnBuffer,&insnCount,scratchReg);
00111 restCTRRegister(insnBuffer,&insnCount,scratchReg);
00112
00113 for (uint32_t i = 0; i <= LAST_VOLATILE_REG; i++){
00114 saveOffset = getFPRSaveOffset(i);
00115 insnBuffer[insnCount++] = Instruction::generateLoadDoubleFloat(i,REG_TOC,saveOffset);
00116 }
00117 for (uint32_t i = 0; i <= LAST_VOLATILE_REG; i++){
00118 saveOffset = getGPRSaveOffset(i);
00119 insnBuffer[insnCount++] = Instruction::generateLoadDouble(i,REG_TOC,saveOffset);
00120 }
00121 updateTOCRegister(insnBuffer,&insnCount);
00122
00123 insnBuffer[insnCount++] = Instruction::generateReturnToLnk();
00124
00125 gen->writeInstructions(genBufferOffset,insnCount,insnBuffer);
00126
00127 delete[] insnBuffer;
00128
00129 return (insnCount*sizeof(uint32_t));
00130 }
00131
00132 void BasicBlockTracer::reserveDataForInstrumentation(){
00133
00134 extendedDataSize = 0;
00135 extendedBeginAddr = 0;
00136 dataBufferEntryCount = 0;
00137
00138 uint64_t dataSectionBeginAddr = xcoffFile->getDataSectionVAddr();
00139 uint32_t dataSectionSize = xcoffFile->getDataSectionSize();
00140
00141 execTOCAddress = xcoffFile->getTOCAddress();
00142
00143 uint64_t currentFreeAddress = dataSectionBeginAddr + dataSectionSize;
00144
00145 uint32_t incrementSize = 0;
00146 if (xcoffFile->is64Bit()){
00147 currentFreeAddress = nextAlignAddressDouble(currentFreeAddress);
00148 incrementSize = sizeof(uint64_t);
00149 } else {
00150 currentFreeAddress = nextAlignAddressWord(currentFreeAddress);
00151 incrementSize = sizeof(uint32_t);
00152 }
00153
00154 extendedBeginAddr = currentFreeAddress;
00155
00156 for (uint32_t i = 0; i < getNumOfSharedLibFuncs(); i++){
00157 libraryFunctionStubAddrLocs[i] = currentFreeAddress;
00158 currentFreeAddress += incrementSize;
00159 }
00160
00161 currentFreeAddress = nextAlignAddressWord(currentFreeAddress);
00162
00163 saveAddressCondReg = currentFreeAddress;
00164 currentFreeAddress += sizeof(uint32_t);
00165 saveAddressFPCondReg = currentFreeAddress;
00166 currentFreeAddress += sizeof(uint32_t);
00167
00168 currentFreeAddress = nextAlignAddressDouble(currentFreeAddress);
00169
00170 saveAddressLinkReg = currentFreeAddress;
00171 currentFreeAddress += sizeof(uint64_t);
00172 saveAddressCtrReg = currentFreeAddress;
00173 currentFreeAddress += sizeof(uint64_t);
00174 saveAddressExpReg = currentFreeAddress;
00175 currentFreeAddress += sizeof(uint64_t);
00176
00177 saveAddressGprRegs = currentFreeAddress;
00178 currentFreeAddress += (sizeof(uint64_t) * NUM_OF_GPR_REGS);
00179 saveAddressFprRegs = currentFreeAddress;
00180 currentFreeAddress += (sizeof(uint64_t) * NUM_OF_FPR_REGS);
00181
00182 currentFreeAddress = nextAlignAddressDouble(currentFreeAddress);
00183
00184
00185
00186 blockPointerOffset = currentFreeAddress;
00187 currentFreeAddress += sizeof(uint64_t);
00188
00189
00190 allBlockInfo = new uint32_t[numberOfInstPoints];
00191 uint32_t totalNameSizes = 0;
00192 char* functionNameOfBlock = NULL;
00193 uint32_t lineno = 0;
00194 LineInfoFinder* LIF = ((TextSection*)xcoffFile->getRawSection(xcoffFile->getTextSectionIndex()))->getLineInfoFinder();
00195
00196 for (uint32_t i = 0; i < numberOfInstPoints; i++){
00197 uint64_t baseAddress = blocksToInstrument[i]->getBaseAddress();
00198 if (LIF){
00199 lineno = LIF->getLineNumberInFunction(baseAddress);
00200 functionNameOfBlock = LIF->getFunctionName(baseAddress);
00201 }
00202 totalNameSizes += (strlen(functionNameOfBlock) + 1);
00203 currentFreeAddress = nextAlignAddressWord(currentFreeAddress);
00204 allBlockInfo[i] = currentFreeAddress;
00205 currentFreeAddress += ((2 * sizeof(uint32_t)) + strlen(functionNameOfBlock) + 1);
00206 }
00207
00208 currentFreeAddress = nextAlignAddressDouble(currentFreeAddress);
00209 extendedDataSize = currentFreeAddress - (dataSectionBeginAddr + dataSectionSize);
00210
00211 tocXorUpdateVal = 0;
00212 if (!Instruction::isInLoadOffsetInsnRange((int32_t)(dataBufferAddress-execTOCAddress))){
00213 tocXorUpdateVal = (uint32_t)(extendedBeginAddr ^ execTOCAddress);
00214 tocDistUpdateVal = (uint32_t)(extendedBeginAddr - execTOCAddress);
00215 }
00216 }
00217
00218 BasicBlockTracer::BasicBlockTracer(XCoffFile* xcoff,char* extension,uint32_t phaseNo)
00219 : CommonMethods(xcoff,extension,phaseNo,1,NULL)
00220 {
00221 }
00222
00223 void BasicBlockTracer::selectInstrumentationPoints(char* inpFile){
00224
00225 terminationBlock = findTerminationBlock();
00226 ASSERT(terminationBlock && "FATAL : There is no exit block");
00227
00228 uint32_t allBlocksCount = xcoffFile->getNumberOfBlocks();
00229
00230 bool insertAppExitBlock = true;
00231
00232 if (allBlocksCount){
00233 blocksToInstrument = new BasicBlock*[allBlocksCount];
00234 xcoffFile->getAllBlocks(blocksToInstrument);
00235
00236 for (uint32_t i = 0; i < allBlocksCount; i++){
00237 BasicBlock* bb = blocksToInstrument[i];
00238 if (filterBlockForInst(bb)){
00239 PRINT_DEBUG("Filtering basic block %#12llx",bb->getHashCode().getValue());
00240 numOfBlocksFiltered++;
00241 continue;
00242 }
00243 if (insertAppExitBlock && (bb == terminationBlock)){
00244 PRINT_INFOR("The exit block sequence id will be %#x",numberOfInstPoints);
00245 insertAppExitBlock = false;
00246 }
00247 blocksToInstrument[numberOfInstPoints++] = bb;
00248 }
00249 } else {
00250 PRINT_ERROR("There is no basic block identified in the executable yet, is executable parsed");
00251 }
00252
00253 if (!numberOfInstPoints){
00254 PRINT_ERROR("There is no basic block passed the filter");
00255 }
00256
00257 if (insertAppExitBlock){
00258 blocksToInstrument[numberOfInstPoints++] = terminationBlock;
00259 }
00260 PRINT_INFOR("**** Number of basic blocks considered in instrumentation %d ******",numberOfInstPoints);
00261 }
00262
00263 uint32_t BasicBlockTracer::byteCountForInst(uint32_t instPointIdx,uint64_t instStubAddress,TextSection* textSect){
00264
00265 BasicBlock* block = blocksToInstrument[instPointIdx];
00266 ASSERT(block);
00267 ASSERT(extendedDataSize);
00268
00269 uint64_t instPointAddress = 0;
00270
00271 if (!block->findFirstInstPoint(&instPointAddress)){
00272 PRINT_INFOR("Basic Block %#18llx does not have suitable location for inst",
00273 block->getHashCode().getValue());
00274 return 0;
00275 }
00276 ASSERT(textSect->inRange(instPointAddress));
00277
00278 if (!Instruction::isInJumpInsnRange(instPointAddress,instStubAddress)){
00279 PRINT_INFOR("Basic Block %#18llx can not be instrumented due to branch offset limit",
00280 block->getHashCode().getValue());
00281 return 0;
00282 }
00283 uint32_t numberOfInstructions = 0;
00284
00285 uint32_t origInstructionSize = 0;
00286 uint32_t updateTOCSize = 0;
00287 uint32_t saveRestSize = 0;
00288 uint32_t blockPointSize = 0;
00289 uint32_t funcCallSize = 0;
00290
00291 origInstructionSize++;
00292
00293 uint16_t tocUpdateValLow = FIRST_HALFWORD(tocXorUpdateVal);
00294 uint16_t tocUpdateValHigh = SECOND_HALFWORD(tocXorUpdateVal);
00295 if(tocXorUpdateVal){
00296 if(tocUpdateValHigh){
00297 updateTOCSize += 4;
00298 }
00299 updateTOCSize += 4;
00300 }
00301
00302 saveRestSize += 2;
00303 blockPointSize += 3;
00304 funcCallSize += 9;
00305 saveRestSize += 2;
00306 funcCallSize += 2;
00307
00308 numberOfInstructions = origInstructionSize + updateTOCSize + saveRestSize + blockPointSize + funcCallSize;
00309 PRINT_DEBUG("Found %d instructions in the stub for inst point %d", numberOfInstructions, instPointIdx);
00310
00311 return numberOfInstructions * sizeof(uint32_t);
00312 }
00313
00314 uint32_t BasicBlockTracer::generateCodeForInst(uint32_t instPointIdx,
00315 uint64_t instStubAddress,TextSection* textSect,
00316 BaseGen* gen,uint32_t genBufferOffset)
00317 {
00318 ASSERT(gen->getParsedBase() == (Base*)textSect);
00319 BasicBlock* block = blocksToInstrument[instPointIdx];
00320 ASSERT(block);
00321 ASSERT(extendedDataSize);
00322
00323 uint64_t instPointAddress = 0;
00324
00325 if (!block->findFirstInstPoint(&instPointAddress)){
00326 PRINT_INFOR("Basic Block %#18llx does not have suitable location for inst",
00327 block->getHashCode().getValue());
00328 return 0;
00329 }
00330 ASSERT(textSect->inRange(instPointAddress));
00331
00332 if (!Instruction::isInJumpInsnRange(instPointAddress,instStubAddress)){
00333 PRINT_INFOR("Basic Block %#18llx can not be instrumented due to branch offset limit",
00334 block->getHashCode().getValue());
00335 return 0;
00336 }
00337
00338 AddressIterator ait = block->getInstructionIterator();
00339 ait.skipTo(instPointAddress);
00340 Instruction origInsn = textSect->readInstruction(&ait);
00341
00342 bool isApplicationExit = (block == terminationBlock);
00343
00344 uint32_t savedReg = 31;
00345 uint32_t scratchReg = 30;
00346 ASSERT(savedReg > LAST_VOLATILE_REG);
00347 ASSERT(scratchReg > LAST_VOLATILE_REG);
00348
00349 int32_t savedRegSaveOffset = getGPRSaveOffset(savedReg);
00350 int32_t scratchRegSaveOffset = getGPRSaveOffset(scratchReg);
00351 int32_t blockPointerOffsetSaveOffset = getBlockPointerOffsetSaveOffset();
00352 int32_t blockPointerOffset = getBlockPointerOffset(instPointIdx);
00353
00354 uint32_t maxInsnCount = (maxByteCountPerInst() / sizeof(uint32_t));
00355
00356 uint32_t insnCount = 0;
00357 Instruction* insnBuffer = new Instruction[maxInsnCount];
00358
00359 insnBuffer[insnCount++] = origInsn;
00360
00361 updateTOCRegister(insnBuffer,&insnCount);
00362
00363 insnBuffer[insnCount++] = Instruction::generateStoreDouble(savedReg,REG_TOC,savedRegSaveOffset);
00364 insnBuffer[insnCount++] = Instruction::generateStoreDouble(scratchReg,REG_TOC,scratchRegSaveOffset);
00365
00366 insnBuffer[insnCount++] = Instruction::generateLoad32BitHigh(scratchReg,blockPointerOffset);
00367 insnBuffer[insnCount++] = Instruction::generateLoad32BitLow(scratchReg,blockPointerOffset);
00368 insnBuffer[insnCount++] = Instruction::generateStoreDouble(scratchReg,REG_TOC,blockPointerOffsetSaveOffset);
00369
00370 generateFuncCallFull(insnBuffer,&insnCount,savedReg,instStubAddress,libraryFuncStubAddrs[0]);
00371
00372 insnBuffer[insnCount++] = Instruction::generateLoadDouble(scratchReg,REG_TOC,scratchRegSaveOffset);
00373 insnBuffer[insnCount++] = Instruction::generateLoadDouble(savedReg,REG_TOC,savedRegSaveOffset);
00374
00375 updateTOCRegister(insnBuffer,&insnCount);
00376
00377 uint64_t fromAddr = instStubAddress + (insnCount * sizeof(uint32_t));
00378 uint64_t toAddr = instPointAddress + sizeof(uint32_t);
00379 insnBuffer[insnCount++] = Instruction::generateJumpInsn(fromAddr,toAddr);
00380 insnBuffer[insnCount++] = Instruction(instPointIdx);
00381
00382 ASSERT(insnCount <= maxInsnCount);
00383
00384 gen->writeInstructions(genBufferOffset,insnCount,insnBuffer);
00385
00386 delete[] insnBuffer;
00387
00388 fromAddr = instPointAddress;
00389 toAddr = instStubAddress;
00390 Instruction origJumpToStub = Instruction::generateJumpInsn(fromAddr,toAddr);
00391 gen->writeWord(instPointAddress-textSect->getSectHeader()->GET(s_vaddr),origJumpToStub.bits());
00392
00393 PRINT_DEBUG("Generating function stub with %d instructions", insnCount);
00394 return (insnCount*sizeof(uint32_t));
00395 }
00396
00397 void BasicBlockTracer::getSharedLibraryPathAndObj(char** path,char** name,char** obj){
00398 *path = getPathToInstLib();
00399 *obj = "";
00400 if(xcoffFile->is64Bit()){
00401 *name = "libtracFunc_64.a";
00402 } else {
00403 *name = "libtracFunc.a";
00404 }
00405 ASSERT(path && name && obj);
00406 }
00407
00408