diff options
author | Chris Johns <chrisj@rtems.org> | 2014-05-09 21:50:37 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-06-18 16:48:08 +1200 |
commit | 100f517ab37265acdf067e36b6860020ec8b2184 (patch) | |
tree | 2316c8b888e11dcbcfbfc66a0c1e31991ea20656 /tester/covoar/ObjdumpProcessor.cc | |
parent | 4.11: Add ntp patch. (diff) | |
download | rtems-tools-100f517ab37265acdf067e36b6860020ec8b2184.tar.bz2 |
covoar: Merger the covoar source from rtems-testing.git.
Use waf to build covoar.
Diffstat (limited to 'tester/covoar/ObjdumpProcessor.cc')
-rw-r--r-- | tester/covoar/ObjdumpProcessor.cc | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/tester/covoar/ObjdumpProcessor.cc b/tester/covoar/ObjdumpProcessor.cc new file mode 100644 index 0000000..486c720 --- /dev/null +++ b/tester/covoar/ObjdumpProcessor.cc @@ -0,0 +1,465 @@ +/*! @file ObjdumpProcessor.cc + * @brief ObjdumpProcessor Implementation + * + * This file contains the implementation of the functions supporting + * the reading of an objdump output file and adding nops to a + * coverage map. + */ + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <algorithm> +#include <string> + +#include "app_common.h" +#include "ObjdumpProcessor.h" +#include "CoverageMap.h" +#include "ExecutableInfo.h" +#include "SymbolTable.h" +#include "TargetFactory.h" + +namespace Coverage { + + void finalizeSymbol( + ExecutableInfo* const executableInfo, + std::string& symbolName, + uint32_t lowAddress, + uint32_t highAddress, + ObjdumpProcessor::objdumpLines_t instructions + ) { + + CoverageMapBase* aCoverageMap = NULL; + uint32_t endAddress = highAddress; + ObjdumpProcessor::objdumpLines_t::iterator itr, fnop, lnop; + ObjdumpProcessor::objdumpLines_t::reverse_iterator ritr; + SymbolInformation* symbolInfo = NULL; + SymbolTable* theSymbolTable; + + // + // Remove trailing nop instructions. + // + + // First find the last instruction. + for (ritr = instructions.rbegin(); + ritr != instructions.rend(); + ritr++) { + if (ritr->isInstruction) + break; + } + + // If an instruction was found and it is a nop, ... + if ((ritr != instructions.rend()) && (ritr->isNop)) { + + // save it as the last nop. Note that we must account for + // the difference between a forward and a reverse iterator. + lnop = ritr.base(); + lnop--; + endAddress -= lnop->nopSize; + + // Now look for the first nop in the sequence of trailing nops. + fnop = lnop; + ritr++; + for (; ritr != instructions.rend(); ritr++) { + if (ritr->isNop) { + fnop = ritr.base(); + fnop--; + endAddress -= fnop->nopSize; + } + else + break; + } + + // Erase trailing nops. The erase operation wants the first + // parameter to point to the first item to erase and the second + // parameter to point to the item beyond the last item to erase. + if ( fnop == lnop ) + instructions.erase( fnop ); + else + instructions.erase( fnop, ++lnop ); + } + + // If there are NOT already saved instructions, save them. + symbolInfo = SymbolsToAnalyze->find( symbolName ); + if (symbolInfo->instructions.empty()) { + symbolInfo->sourceFile = executableInfo; + symbolInfo->baseAddress = lowAddress; + symbolInfo->instructions = instructions; + } + + // Add the symbol to this executable's symbol table. + theSymbolTable = executableInfo->getSymbolTable(); + theSymbolTable->addSymbol( + symbolName, lowAddress, endAddress - lowAddress + 1 + ); + + // Create a coverage map for the symbol. + aCoverageMap = executableInfo->createCoverageMap( + symbolName, lowAddress, endAddress + ); + + if (aCoverageMap) { + + // Mark the start of each instruction in the coverage map. + for (itr = instructions.begin(); + itr != instructions.end(); + itr++ ) { + + aCoverageMap->setIsStartOfInstruction( itr->address ); + } + + // Create a unified coverage map for the symbol. + SymbolsToAnalyze->createCoverageMap( + symbolName, endAddress - lowAddress + 1 + ); + } + } + + ObjdumpProcessor::ObjdumpProcessor() + { + } + + ObjdumpProcessor::~ObjdumpProcessor() + { + } + + uint32_t ObjdumpProcessor::determineLoadAddress( + ExecutableInfo* theExecutable + ) + { + #define METHOD "ERROR: ObjdumpProcessor::determineLoadAddress - " + FILE* loadAddressFile = NULL; + char* cStatus; + uint32_t offset; + + // This method should only be call for a dynamic library. + if (!theExecutable->hasDynamicLibrary()) + return 0; + + std::string dlinfoName = theExecutable->getFileName(); + uint32_t address; + char inLibName[128]; + std::string Library = theExecutable->getLibraryName(); + + dlinfoName += ".dlinfo"; + // Read load address. + loadAddressFile = fopen( dlinfoName.c_str(), "r" ); + if (!loadAddressFile) { + fprintf( stderr, METHOD "unable to open %s\n", dlinfoName.c_str() ); + exit( -1 ); + } + + // Process the dlinfo file. + while ( 1 ) { + + // Get a line. + cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, loadAddressFile ); + if (cStatus == NULL) { + fprintf( + stderr, + METHOD "library %s not found in %s\n", + Library.c_str(), + dlinfoName.c_str() + ); + fclose( loadAddressFile ); + exit( -1 ); + } + sscanf( inputBuffer, "%s %x", inLibName, &offset ); + std::string tmp = inLibName; + if ( tmp.find( Library ) != tmp.npos ) { + // fprintf( stderr, "%s - 0x%08x\n", inLibName, offset ); + address = offset; + break; + } + } + + fclose( loadAddressFile ); + return address; + + #undef METHOD + } + + bool ObjdumpProcessor::IsBranch( + const char *instruction + ) + { + if ( !TargetInfo ) { + fprintf( + stderr, + "ERROR: ObjdumpProcessor::IsBranch - unknown architecture\n" + ); + assert(0); + return false; + } + + return TargetInfo->isBranch( instruction ); + } + + bool ObjdumpProcessor::isBranchLine( + const char* const line + ) + { + if ( !TargetInfo ) { + fprintf( + stderr, + "ERROR: ObjdumpProcessor::isBranchLine - unknown architecture\n" + ); + assert(0); + return false; + } + + return TargetInfo->isBranchLine( line ); + } + + bool ObjdumpProcessor::isNop( + const char* const line, + int& size + ) + { + if ( !TargetInfo ){ + fprintf( + stderr, + "ERROR: ObjdumpProcessor::isNop - unknown architecture\n" + ); + assert(0); + return false; + } + + return TargetInfo->isNopLine( line, size ); + } + + FILE* ObjdumpProcessor::getFile( std::string fileName ) + { + char dumpFile[128]; + FILE* objdumpFile; + char buffer[ 512 ]; + int status; + + sprintf( dumpFile, "%s.dmp", fileName.c_str() ); + + // Generate the objdump. + if (FileIsNewer( fileName.c_str(), dumpFile )) { + sprintf( + buffer, + "%s -Cda --section=.text --source %s | sed -e \'s/ *$//\' >%s", + TargetInfo->getObjdump(), + fileName.c_str(), + dumpFile + ); + + status = system( buffer ); + if (status) { + fprintf( + stderr, + "ERROR: ObjdumpProcessor::getFile - command (%s) failed with %d\n", + buffer, + status + ); + exit( -1 ); + } + } + + // Open the objdump file. + objdumpFile = fopen( dumpFile, "r" ); + if (!objdumpFile) { + fprintf( + stderr, + "ERROR: ObjdumpProcessor::getFile - unable to open %s\n", + dumpFile + ); + exit(-1); + } + + return objdumpFile; + } + + uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address ) + { + objdumpFile_t::iterator itr; + + itr = find ( objdumpList.begin(), objdumpList.end(), address ); + if (itr == objdumpList.end()) { + return 0; + } + + itr++; + if (itr == objdumpList.end()) { + return 0; + } + + return (*itr); + + } + + void ObjdumpProcessor::loadAddressTable ( + ExecutableInfo* const executableInformation + ) + { + char* cStatus; + int items; + FILE* objdumpFile; + uint32_t offset; + char terminator; + + // Obtain the objdump file. + if (!executableInformation->hasDynamicLibrary()) + objdumpFile = getFile( executableInformation->getFileName() ); + else + objdumpFile = getFile( executableInformation->getLibraryName() ); + + // Process all lines from the objdump file. + while ( 1 ) { + + // Get the line. + cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile ); + if (cStatus == NULL) { + break; + } + inputBuffer[ strlen(inputBuffer) - 1] = '\0'; + + // See if it is the dump of an instruction. + items = sscanf( + inputBuffer, + "%x%c", + &offset, &terminator + ); + + // If it looks like an instruction ... + if ((items == 2) && (terminator == ':')){ + objdumpList.push_back( + executableInformation->getLoadAddress() + offset + ); + } + } + } + + void ObjdumpProcessor::load( + ExecutableInfo* const executableInformation + ) + { + char* cStatus; + std::string currentSymbol = ""; + uint32_t endAddress; + uint32_t instructionOffset; + int items; + objdumpLine_t lineInfo; + FILE* objdumpFile; + uint32_t offset; + bool processSymbol = false; + uint32_t startAddress = 0; + char symbol[ MAX_LINE_LENGTH ]; + char terminator1; + char terminator2; + objdumpLines_t theInstructions; + + // Obtain the objdump file. + if (!executableInformation->hasDynamicLibrary()) + objdumpFile = getFile( executableInformation->getFileName() ); + else + objdumpFile = getFile( executableInformation->getLibraryName() ); + + // Process all lines from the objdump file. + while ( 1 ) { + + // Get the line. + cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile ); + if (cStatus == NULL) { + + // If we are currently processing a symbol, finalize it. + if (processSymbol) { + finalizeSymbol( + executableInformation, + currentSymbol, + startAddress, + executableInformation->getLoadAddress() + offset, + theInstructions + ); + fprintf( + stderr, + "WARNING: ObjdumpProcessor::load - analysis of symbol %s \n" + " may be incorrect. It was the last symbol in %s\n" + " and the length of its last instruction is assumed " + " to be one.\n", + currentSymbol.c_str(), + executableInformation->getFileName().c_str() + ); + } + break; + } + + inputBuffer[ strlen(inputBuffer) - 1] = '\0'; + + lineInfo.line = inputBuffer; + lineInfo.address = 0xffffffff; + lineInfo.isInstruction = false; + lineInfo.isNop = false; + lineInfo.nopSize = 0; + lineInfo.isBranch = false; + + // Look for the start of a symbol's objdump and extract + // offset and symbol (i.e. offset <symbolname>:). + items = sscanf( + inputBuffer, + "%x <%[^>]>%c", + &offset, symbol, &terminator1 + ); + + // If all items found, we are at the beginning of a symbol's objdump. + if ((items == 3) && (terminator1 == ':')) { + + endAddress = executableInformation->getLoadAddress() + offset - 1; + + // If we are currently processing a symbol, finalize it. + if (processSymbol) { + finalizeSymbol( + executableInformation, + currentSymbol, + startAddress, + endAddress, + theInstructions + ); + } + + // Start processing of a new symbol. + startAddress = 0; + currentSymbol = ""; + processSymbol = false; + theInstructions.clear(); + + // See if the new symbol is one that we care about. + if (SymbolsToAnalyze->isDesired( symbol )) { + startAddress = executableInformation->getLoadAddress() + offset; + currentSymbol = symbol; + processSymbol = true; + theInstructions.push_back( lineInfo ); + } + } + + else if (processSymbol) { + + // See if it is the dump of an instruction. + items = sscanf( + inputBuffer, + "%x%c\t%*[^\t]%c", + &instructionOffset, &terminator1, &terminator2 + ); + + // If it looks like an instruction ... + if ((items == 3) && (terminator1 == ':') && (terminator2 == '\t')) { + + // update the line's information, save it and ... + lineInfo.address = + executableInformation->getLoadAddress() + instructionOffset; + lineInfo.isInstruction = true; + lineInfo.isNop = isNop( inputBuffer, lineInfo.nopSize ); + lineInfo.isBranch = isBranchLine( inputBuffer ); + } + + // Always save the line. + theInstructions.push_back( lineInfo ); + } + } + } +} |